sigmaplayer/src/media.cpp

648 lines
13 KiB
C++

//////////////////////////////////////////////////////////////////////////
/**
* SigmaPlayer source project - media access source file. Uses libdvdnav.
* \file media.cpp
* \author bombur
* \version 0.1
* \date 2.08.2004
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/
//////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libsp/sp_misc.h>
#include <libsp/sp_msg.h>
#include <libsp/sp_khwl.h>
#include <libsp/sp_fip.h>
#include <libsp/sp_mpeg.h>
#include <libsp/sp_cdrom.h>
#include "player.h"
#include "dvd.h"
#include "audio.h"
#include "video.h"
#include "cdda.h"
#include "media.h"
static int cur_bufpos = 0, cur_bufleft = -1;
static int cur_chunkleft = -1;
static BYTE *cur_copybuf = NULL;
static MEDIA_TYPES media_type = MEDIA_TYPE_UNKNOWN;
// fip 'disc' index
static int fipdisc_i = 0;
static int update_counter = 0;
static int fd = -1;
static int numread = 0;
static LONGLONG file_pos = 0;
#ifdef INTERNAL_VIDEO_PLAYER
static VIDEO_CHUNK_TYPE chtype = VIDEO_CHUNK_UNKNOWN;
#endif
int media_open(const char *path, MEDIA_TYPES mtype)
{
cur_bufleft = -1;
media_type = mtype;
numread = 0;
file_pos = 0;
if (mtype == MEDIA_TYPE_DVD)
{
MPEG_PACKET_LENGTH = 2048;
MPEG_NUM_PACKETS = 512;
if (dvd_open(path) < 0)
return -1;
}
else if (mtype == MEDIA_TYPE_CDDA)
{
MPEG_PACKET_LENGTH = 2352;
MPEG_NUM_PACKETS = 512;
if (!cdda_open())
{
msg_error("Media: Couldn't open CDDA: %s\n", path);
return -1;
}
}
#ifdef INTERNAL_VIDEO_PLAYER
else if (mtype == MEDIA_TYPE_VIDEO)
{
MPEG_PACKET_LENGTH = 0; // use variable packet size
MPEG_NUM_PACKETS = 2048;
if (!video_open(path))
{
video_close();
msg_error("Media: Couldn't open video: %s\n", path);
return -1;
}
}
#endif
#ifdef INTERNAL_AUDIO_PLAYER
else if (mtype == MEDIA_TYPE_AUDIO)
{
MPEG_PACKET_LENGTH = 4096;
MPEG_NUM_PACKETS = 512;
if (!audio_open(path))
{
audio_close();
msg_error("Media: Couldn't open audio: %s\n", path);
return -1;
}
}
#endif
cur_bufpos = 0;
cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1);
cur_chunkleft = cur_bufleft;
cur_copybuf = NULL;
fipdisc_i = 0;
fip_write_special(FIP_SPECIAL_CIRCLE_1 + fipdisc_i, 1);
return 1;
}
void set_media_type(MEDIA_TYPES mtype)
{
media_type = mtype;
}
inline int media_get_next_free(const MPEG_BUFFER which, MEDIA_EVENT *event, bool &update_fip)
{
int ret = mpeg_find_free_blocks(which);
if (ret == 0)
{
// the buffer is not ready yet - wait...
*event = MEDIA_EVENT_NOP;
return 0;
}
cur_bufpos = 0;
cur_bufleft = mpeg_getbufsize(which);
cur_chunkleft = cur_bufleft;
if (update_counter++ >= 8)
{
update_fip = true;
update_counter = 0;
}
return ret;
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//extern int num_packets;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int media_get_next_block(BYTE **buf, MEDIA_EVENT *event, int *len)
{
if (cur_bufleft < 0)
{
cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1);
}
bool update_fip = false;
*event = MEDIA_EVENT_OK;
if (media_type == MEDIA_TYPE_DVD)
{
*len = MPEG_PACKET_LENGTH;
if (cur_bufleft < MPEG_PACKET_LENGTH)
{
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
}
BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
BYTE *bb = tmpbuf + cur_bufpos;
int ret = dvd_get_next_block(&bb, (int *)event, len);
if (ret < 0)
return -1;
else if (ret)
media_accept_block();
*buf = bb;
}
#ifdef INTERNAL_VIDEO_MPEG_PLAYER
else if (media_type == MEDIA_TYPE_MPEG)
{
*len = MPEG_PACKET_LENGTH;
if (cur_bufleft < MPEG_PACKET_LENGTH)
{
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
}
BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
if (cur_bufpos == 0)
{
//numread = read(fd, tmpbuf, mpeg_getbufsize(MPEG_BUFFER_1));
numread = video_read(tmpbuf, mpeg_getbufsize(MPEG_BUFFER_1));
file_pos += numread;
if (update_counter++ >= 8)
{
update_fip = true;
update_counter = 0;
}
// sorry, we won't show the last few bytes...
numread &= ~(MPEG_PACKET_LENGTH - 1);
MPEG_PACKET_LENGTH = numread;
}
if (cur_bufpos + MPEG_PACKET_LENGTH > numread || numread < 1)
{
if (numread < 1 || video_eof())
{
*buf = tmpbuf + cur_bufpos;
*event = MEDIA_EVENT_STOP;
return 1;
}
else
{
*event = MEDIA_EVENT_NOP; // retry?
return 0;
}
}
*buf = tmpbuf + cur_bufpos;
media_accept_block();
}
#endif
else if (media_type == MEDIA_TYPE_CDDA)
{
*len = MPEG_PACKET_LENGTH;
if (cur_bufleft < MPEG_PACKET_LENGTH)
{
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
}
BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
if (cur_bufpos == 0)
{
numread = cdda_read(tmpbuf, mpeg_getbufsize(MPEG_BUFFER_1) / MPEG_PACKET_LENGTH);
numread *= MPEG_PACKET_LENGTH;
if (update_counter++ >= 6)
{
update_fip = true;
update_counter = 0;
}
}
else if (cur_bufpos + MPEG_PACKET_LENGTH > numread)
{
if (cdda_feof())
{
*event = MEDIA_EVENT_STOP;
}
else
{
*event = MEDIA_EVENT_NOP; // retry?
return 0;
}
}
*buf = tmpbuf + cur_bufpos;
media_accept_block();
}
#ifdef INTERNAL_VIDEO_PLAYER
else if (media_type == MEDIA_TYPE_VIDEO)
{
if (cur_bufleft < 1)
{
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
cur_copybuf = NULL;
}
BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
fragmented:
if (cur_bufleft < 16)
{
// read one more buffer
/*
numread = mpeg_getbufsize(MPEG_BUFFER_1) - cur_bufleft;
if (cur_copybuf == NULL)
cur_copybuf = tmpbuf + cur_bufpos;
int len = cur_bufleft;
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
*buf = tmpbuf + cur_bufpos;
memcpy(tmpbuf, cur_copybuf, len);
cur_copybuf = NULL;
if ((numread = video_read(tmpbuf + len, numread)) == 0)
{
*event = MEDIA_EVENT_STOP;
return 1;
}
numread += len;
video_shiftpos(len);
*/
if (media_skip_buffer(&tmpbuf) == 0)
return 0;
numread = mpeg_getbufsize(MPEG_BUFFER_1);
} else
{
*buf = tmpbuf + cur_bufpos;
if (cur_bufpos == 0)
{
numread = mpeg_getbufsize(MPEG_BUFFER_1);
}
}
for (;;)
{
chtype = video_getnext(tmpbuf + cur_bufpos, numread, &cur_bufpos, &cur_bufleft, &MPEG_PACKET_LENGTH);
if (chtype == VIDEO_CHUNK_FRAGMENT)
goto fragmented;
if (chtype != VIDEO_CHUNK_UNKNOWN)
break;
if (media_skip_buffer(&tmpbuf) == 0)
return 0;
numread = mpeg_getbufsize(MPEG_BUFFER_1);
}
*buf = tmpbuf + cur_bufpos;
if (chtype == VIDEO_CHUNK_EOF)
{
*event = MEDIA_EVENT_STOP;
return 1;
}
if (chtype == VIDEO_CHUNK_RECOVERY)
{
if (cur_bufpos > 0)
media_skip_buffer(&tmpbuf);
return 0;
}
else if (chtype == VIDEO_CHUNK_AUDIO)
*event = MEDIA_EVENT_AUDIO;
else if (chtype == VIDEO_CHUNK_VIDEO)
*event = MEDIA_EVENT_VIDEO;
else if (chtype == VIDEO_CHUNK_AUDIO_PARTIAL)
*event = MEDIA_EVENT_AUDIO_PARTIAL;
else if (chtype == VIDEO_CHUNK_VIDEO_PARTIAL)
*event = MEDIA_EVENT_VIDEO_PARTIAL;
if (update_counter++ >= 6)
{
update_fip = true;
update_counter = 0;
}
*len = MPEG_PACKET_LENGTH;
MPEG_PACKET_LENGTH = PAD_EVEN(MPEG_PACKET_LENGTH);
media_accept_block();
if ((*event & MEDIA_EVENT_PARTIAL) == 0)
{
cur_chunkleft = cur_bufleft;
}
}
#endif
#ifdef INTERNAL_AUDIO_PLAYER
else if (media_type == MEDIA_TYPE_AUDIO)
{
if (cur_bufleft < 1)
{
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
}
BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
*buf = tmpbuf + cur_bufpos;
if (cur_bufpos == 0)
{
numread = mpeg_getbufsize(MPEG_BUFFER_1);
if (audio_read(tmpbuf, &numread) == 0)
{
*event = MEDIA_EVENT_STOP;
return 1;
}
}
if (cur_bufpos + MPEG_PACKET_LENGTH > numread)
*len = MAX(numread - cur_bufpos, 0);
else
*len = MPEG_PACKET_LENGTH;
*buf = tmpbuf + cur_bufpos;
if (update_counter++ >= 6)
{
update_fip = true;
update_counter = 0;
}
media_accept_block();
}
#endif
// update FIP
if (update_fip)
{
media_update_fip();
}
return 1;
}
int media_update_fip()
{
fip_write_special(FIP_SPECIAL_CIRCLE_1 + fipdisc_i, 0);
fipdisc_i++;
if (fipdisc_i >= 12)
fipdisc_i = 0;
fip_write_special(FIP_SPECIAL_CIRCLE_1 + fipdisc_i, 1);
return 0;
}
int media_skip_buffer(BYTE **buf)
{
int ret = mpeg_find_free_blocks(MPEG_BUFFER_1);
if (ret == 0) // sorry, out of buffers...
return 0;
cur_bufpos = 0;
cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1);
cur_chunkleft = cur_bufleft;
if (buf != NULL)
*buf = mpeg_getcurbuf(MPEG_BUFFER_1);
return 1;
}
int media_seek_curleft()
{
#ifdef INTERNAL_VIDEO_PLAYER
video_lseek(-cur_chunkleft, SEEK_CUR);
media_skip_buffer(NULL);
#endif
return 0;
}
LONGLONG media_get_filepos()
{
return file_pos;
}
void media_set_filepos(LONGLONG fp)
{
file_pos = fp;
}
int media_read_block(BYTE **buf, MEDIA_EVENT *event, int *len)
{
#ifdef INTERNAL_VIDEO_PLAYER
*event = MEDIA_EVENT_NOP;
if (media_type == MEDIA_TYPE_VIDEO)
{
if (len == NULL || *len == 0)
{
*buf = mpeg_getcurbuf(MPEG_BUFFER_1);
*event = MEDIA_EVENT_STOP;
return 1;
}
bool update_fip = false;
MPEG_PACKET_LENGTH = PAD_EVEN(*len);
if (cur_bufleft < 16 || (MPEG_PACKET_LENGTH > cur_bufleft))
{
if (media_get_next_free(MPEG_BUFFER_1, event, update_fip) == 0)
return 0;
}
BYTE *tmpbuf = mpeg_getcurbuf(MPEG_BUFFER_1);
*buf = tmpbuf + cur_bufpos;
int numread = MIN(cur_bufleft, MPEG_PACKET_LENGTH);
if ((numread = video_read(*buf, numread)) == 0)
{
*event = MEDIA_EVENT_STOP;
return 1;
}
if (numread < *len)
{
*len = numread;
MPEG_PACKET_LENGTH = numread;
}
*event = MEDIA_EVENT_OK;
media_accept_block();
media_update_fip();
return 1;
}
#endif
return -1;
}
int media_accept_block()
{
cur_bufleft -= MPEG_PACKET_LENGTH;
cur_bufpos += MPEG_PACKET_LENGTH;
return 1;
}
int media_free_block(BYTE *data)
{
if (media_type == MEDIA_TYPE_DVD)
{
if (dvd_free_block(data) < 0)
return -1;
}
else if (media_type == MEDIA_TYPE_MPEG)
{
}
else if (media_type == MEDIA_TYPE_CDDA)
{
}
else if (media_type == MEDIA_TYPE_VIDEO)
{
}
else if (media_type == MEDIA_TYPE_AUDIO)
{
}
return 1;
}
int media_close()
{
if (media_type == MEDIA_TYPE_DVD)
{
if (dvd_close() < 0)
return -1;
}
#ifdef INTERNAL_VIDEO_MPEG_PLAYER
else if (media_type == MEDIA_TYPE_MPEG)
{
video_close();
}
#endif
else if (media_type == MEDIA_TYPE_CDDA)
{
// we'll close when disc changes
//cdda_close();
}
#ifdef INTERNAL_VIDEO_PLAYER
else if (media_type == MEDIA_TYPE_VIDEO)
{
video_close();
}
#endif
#ifdef INTERNAL_AUDIO_PLAYER
else if (media_type == MEDIA_TYPE_AUDIO)
{
audio_close();
}
#endif
return 1;
}
int media_seek(int blockid, int from)
{
if (media_type == MEDIA_TYPE_DVD)
{
// not used
return -1;
}
else if (media_type == MEDIA_TYPE_MPEG)
{
if (lseek(fd, blockid * mpeg_getbufsize(MPEG_BUFFER_1), from) != 0)
return -1;
}
else if (media_type == MEDIA_TYPE_CDDA)
{
// TODO:
return -1;
}
else if (media_type == MEDIA_TYPE_VIDEO)
{
// TODO:
return -1;
}
else if (media_type == MEDIA_TYPE_AUDIO)
{
// TODO:
return -1;
}
return 1;
}
int media_rewind()
{
cur_bufpos = 0;
cur_bufleft = mpeg_getbufsize(MPEG_BUFFER_1);
cur_chunkleft = cur_bufleft;
if (media_type == MEDIA_TYPE_DVD)
{
if (dvd_reset() < 0)
return -1;
}
else if (media_type == MEDIA_TYPE_MPEG)
{
lseek(fd, 0, SEEK_SET);
}
else if (media_type == MEDIA_TYPE_CDDA)
{
// TODO:
return -1;
}
else if (media_type == MEDIA_TYPE_VIDEO)
{
// TODO:
return -1;
}
else if (media_type == MEDIA_TYPE_AUDIO)
{
// TODO:
return -1;
}
return 1;
}
const char *media_geterror()
{
if (media_type == MEDIA_TYPE_DVD)
{
return dvd_error_string();
}
else if (media_type == MEDIA_TYPE_MPEG)
{
static char tmp[15];
sprintf(tmp, "%d", 0);
return tmp;
}
else if (media_type == MEDIA_TYPE_CDDA)
{
// TODO:
return "";
}
else if (media_type == MEDIA_TYPE_VIDEO)
{
// TODO:
return "";
}
else if (media_type == MEDIA_TYPE_AUDIO)
{
// TODO:
return "";
}
return "";
}