seek in realmedia files

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@11442 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
luran
2003-11-12 10:27:16 +00:00
parent 74f7957814
commit 72f330c8a0
2 changed files with 179 additions and 49 deletions
+176 -49
View File
@@ -50,11 +50,16 @@ typedef struct {
/* for seeking */
int index_chunk_offset;
real_index_table_t *index_table[MAX_STREAMS];
// int *index_table[MAX_STREAMS];
int index_table_size[MAX_STREAMS];
int data_chunk_offset;
int num_of_packets;
int current_packet;
// need for seek
int audio_need_keyframe;
int video_after_seek;
int current_apacket;
int current_vpacket;
@@ -64,6 +69,7 @@ typedef struct {
int kf_pts; // timestamp of next video keyframe
int a_pts; // previous audio timestamp
float v_pts; // previous video timestamp
unsigned long duration;
/* stream id table */
// int last_a_stream;
@@ -142,7 +148,12 @@ read_index:
{
printf("Something went wrong, no index chunk found on given address (%d)\n",
next_header_pos);
goto end;
index_mode = -1;
if (i == -256)
stream_reset(demuxer->stream);
stream_seek(demuxer->stream, origpos);
return 0;
//goto end;
}
printf("Reading index table from index chunk (%d)\n",
@@ -439,6 +450,8 @@ int demux_real_fill_buffer(demuxer_t *demuxer)
/* check stream_id: */
if(demuxer->audio->id==stream_id){
if (priv->audio_need_keyframe == 1&& flags != 0x2)
goto discard;
got_audio:
ds=demuxer->audio;
mp_dbg(MSGT_DEMUX,MSGL_DBG2, "packet is audio (id: %d)\n", stream_id);
@@ -483,12 +496,20 @@ got_audio:
}
}
#endif
dp->pts = (priv->a_pts==timestamp) ? 0 : (timestamp/1000.0f);
if (priv->audio_need_keyframe == 1) {
dp->pts = 0;
priv->audio_need_keyframe = 0;
}else
dp->pts = (priv->a_pts==timestamp) ? 0 : (timestamp/1000.0f);
priv->a_pts=timestamp;
dp->pos = demuxer->filepos;
dp->flags = (flags & 0x2) ? 0x10 : 0;
ds_add_packet(ds, dp);
}
// we will not use audio index if we use -idx and have a video
if(!demuxer->video->sh && index_mode == 2)
while (timestamp > priv->index_table[demuxer->audio->id][priv->current_apacket].timestamp)
priv->current_apacket += 1;
return 1;
}
@@ -584,6 +605,12 @@ got_video:
if(ds->asf_seq!=vpkg_seqnum){
// this fragment is for new packet, close the old one
mp_msg(MSGT_DEMUX,MSGL_DBG2, "closing probably incomplete packet, len: %d \n",dp->len);
if(priv->video_after_seek){
dp->pts=timestamp;
priv->kf_base = 0;
priv->kf_pts = dp_hdr->timestamp;
priv->video_after_seek = 0;
} else
dp->pts=(dp_hdr->len<3)?0:
real_fix_timestamp(priv,dp_data,dp_hdr->timestamp,sh_video->frametime,sh_video->format);
ds_add_packet(ds,dp);
@@ -614,6 +641,12 @@ got_video:
len-=vpkg_offset;
mp_dbg(MSGT_DEMUX,MSGL_DBG2, "fragment (%d bytes) appended, %d bytes left\n",vpkg_offset,len);
// we know that this is the last fragment -> we can close the packet!
if(priv->video_after_seek){
dp->pts=timestamp;
priv->kf_base = 0;
priv->kf_pts = dp_hdr->timestamp;
priv->video_after_seek = 0;
} else
dp->pts=(dp_hdr->len<3)?0:
real_fix_timestamp(priv,dp_data,dp_hdr->timestamp,sh_video->frametime,sh_video->format);
ds_add_packet(ds,dp);
@@ -656,6 +689,12 @@ got_video:
// whole packet (not fragmented):
dp_hdr->len=vpkg_length; len-=vpkg_length;
stream_read(demuxer->stream, dp_data, vpkg_length);
if(priv->video_after_seek){
dp->pts=timestamp;
priv->kf_base = 0;
priv->kf_pts = dp_hdr->timestamp;
priv->video_after_seek = 0;
} else
dp->pts=(dp_hdr->len<3)?0:
real_fix_timestamp(priv,dp_data,dp_hdr->timestamp,sh_video->frametime,sh_video->format);
ds_add_packet(ds,dp);
@@ -667,6 +706,9 @@ got_video:
if(len>0) stream_skip(demuxer->stream, len);
}
}
if (index_mode == 1 || index_mode == 2)
while (timestamp > priv->index_table[demuxer->video->id][priv->current_vpacket + 1].timestamp)
priv->current_vpacket += 1;
return 1;
}
@@ -694,6 +736,7 @@ if(stream_id<256){
}
mp_msg(MSGT_DEMUX,MSGL_DBG2, "unknown stream id (%d)\n", stream_id);
discard:
stream_skip(demuxer->stream, len);
}// goto loop;
}
@@ -746,7 +789,8 @@ void demux_open_real(demuxer_t* demuxer)
stream_skip(demuxer->stream, 4); /* max packet size */
stream_skip(demuxer->stream, 4); /* avg packet size */
stream_skip(demuxer->stream, 4); /* nb packets */
stream_skip(demuxer->stream, 4); /* duration */
priv->duration = stream_read_dword(demuxer->stream)/1000; /* duration */
//stream_skip(demuxer->stream, 4); /* duration */
stream_skip(demuxer->stream, 4); /* preroll */
priv->index_chunk_offset = stream_read_dword(demuxer->stream);
mp_msg(MSGT_DEMUX,MSGL_V,"First index chunk offset: 0x%x\n", priv->index_chunk_offset);
@@ -1175,6 +1219,9 @@ header_end:
/* disable seeking */
demuxer->seekable = 0;
priv->audio_need_keyframe = 0;
priv->video_after_seek = 0;
if (index_mode == 2)
generate_index(demuxer);
else if (priv->index_chunk_offset && (index_mode == 1))
@@ -1213,6 +1260,8 @@ void demux_close_real(demuxer_t *demuxer)
return;
}
extern void resync_audio_stream(sh_audio_t * sh_audio);
/* please upload RV10 samples WITH INDEX CHUNK */
int demux_seek_real(demuxer_t *demuxer, float rel_seek_secs, int flags)
{
@@ -1224,6 +1273,7 @@ int demux_seek_real(demuxer_t *demuxer, float rel_seek_secs, int flags)
int vid = d_video->id, aid = d_audio->id;
int next_offset = 0;
int rel_seek_frames = 0;
int cur_timestamp = 0;
int streams = 0;
if ((index_mode != 1) && (index_mode != 2))
@@ -1243,55 +1293,132 @@ int demux_seek_real(demuxer_t *demuxer, float rel_seek_secs, int flags)
/* seek absolute */
priv->current_apacket = priv->current_vpacket = 0;
/* flags & 2 ? */
if (streams & 1)
rel_seek_frames = (int)(sh_video->fps*rel_seek_secs);
else if (streams & 2)
rel_seek_frames = (int)(rel_seek_secs);
// printf("rel_seek_frames: %d\n", rel_seek_frames);
if (streams & 2)
priv->current_apacket += rel_seek_frames;
if (streams & 1)
priv->current_vpacket += rel_seek_frames;
if (
((streams & 2) && (priv->current_apacket > priv->index_table_size[aid])) ||
((streams & 1) && (priv->current_vpacket > priv->index_table_size[vid])) )
return 0;
/* both video and audio stream */
if (streams == 3)
{
// if (priv->current_apacket > priv->current_vpacket)
// {
/* search keyframe */
while (!(priv->index_table[vid][priv->current_vpacket].flags & 0x2))
priv->current_vpacket++;
next_offset = priv->index_table[vid][priv->current_vpacket].offset;
// }
// else
// {
// next_offset = priv->index_table[aid][priv->current_apacket].offset;
// }
}
else
{
if (streams & 1)
{
/* search keyframe */
while (!(priv->index_table[vid][priv->current_vpacket].flags & 0x2))
priv->current_vpacket++;
if (index_mode == 1) {
if (streams & 1) {// use the video index if we have one
cur_timestamp = priv->index_table[vid][priv->current_vpacket].timestamp;
if (rel_seek_secs > 0)
while ((priv->index_table[vid][priv->current_vpacket].timestamp - cur_timestamp) < rel_seek_secs * 1000){
priv->current_vpacket += 1;
if (priv->current_vpacket >= priv->index_table_size[vid]) {
priv->current_vpacket = priv->index_table_size[vid] - 1;
break;
}
}
else if (rel_seek_secs < 0)
while ((cur_timestamp - priv->index_table[vid][priv->current_vpacket].timestamp) < - rel_seek_secs * 1000){
priv->current_vpacket -= 1;
if (priv->current_vpacket < 0) {
priv->current_vpacket = 0;
break;
}
}
next_offset = priv->index_table[vid][priv->current_vpacket].offset;
}
else if (streams & 2)
{
priv->audio_need_keyframe = 1;
priv->video_after_seek = 1;
}
else if (streams & 2) {
cur_timestamp = priv->index_table[aid][priv->current_apacket].timestamp;
if (rel_seek_secs > 0)
while ((priv->index_table[aid][priv->current_apacket].timestamp - cur_timestamp) < rel_seek_secs * 1000){
priv->current_apacket += 1;
if (priv->current_apacket >= priv->index_table_size[aid]) {
priv->current_apacket = priv->index_table_size[aid] - 1;
break;
}
}
else if (rel_seek_secs < 0)
while ((cur_timestamp - priv->index_table[aid][priv->current_apacket].timestamp) < - rel_seek_secs * 1000){
priv->current_apacket -= 1;
if (priv->current_apacket < 0) {
priv->current_apacket = 0;
break;
}
}
next_offset = priv->index_table[aid][priv->current_apacket].offset;
}
}
}
else if (index_mode == 2) {
/* flags & 2 ? */
if (streams & 1)
rel_seek_frames = (int)(sh_video->fps*rel_seek_secs);
else if (streams & 2)
rel_seek_frames = (int)(rel_seek_secs);
// printf("rel_seek_frames: %d\n", rel_seek_frames);
if (streams & 2)
priv->current_apacket += rel_seek_frames;
if (streams & 1)
priv->current_vpacket += rel_seek_frames;
if (
((streams & 2) && (priv->current_apacket > priv->index_table_size[aid])) ||
((streams & 1) && (priv->current_vpacket > priv->index_table_size[vid])) )
return 0;
/* both video and audio stream */
if (streams == 3)
{
// if (priv->current_apacket > priv->current_vpacket)
// {
/* search keyframe */
while (!(priv->index_table[vid][priv->current_vpacket].flags & 0x2))
priv->current_vpacket++;
next_offset = priv->index_table[vid][priv->current_vpacket].offset;
priv->audio_need_keyframe = 1;
priv->video_after_seek = 1;
// }
// else
// {
// next_offset = priv->index_table[aid][priv->current_apacket].offset;
// }
}
else
{
if (streams & 1)
{
/* search keyframe */
while (!(priv->index_table[vid][priv->current_vpacket].flags & 0x2))
priv->current_vpacket++;
next_offset = priv->index_table[vid][priv->current_vpacket].offset;
}
else if (streams & 2)
{
next_offset = priv->index_table[aid][priv->current_apacket].offset;
}
}
}
// printf("seek: pos: %d, current packets: a: %d, v: %d\n",
// next_offset, priv->current_apacket, priv->current_vpacket);
return stream_seek(demuxer->stream, next_offset);
stream_seek(demuxer->stream, next_offset);
demux_real_fill_buffer(demuxer);
if (sh_audio)
resync_audio_stream(sh_audio);
return 1;
}
int demux_real_control(demuxer_t *demuxer, int cmd, void *arg)
{
real_priv_t *priv = demuxer->priv;
int lastpts = priv->v_pts ? priv->v_pts : priv->a_pts;
switch (cmd) {
case DEMUXER_CTRL_GET_TIME_LENGTH:
if (priv->duration == 0)
return DEMUXER_CTRL_DONTKNOW;
*((unsigned long *)arg) = priv->duration;
return DEMUXER_CTRL_OK;
case DEMUXER_CTRL_GET_PERCENT_POS:
if (priv->duration == 0)
return DEMUXER_CTRL_DONTKNOW;
*((int *)arg) = (int)(100 * lastpts / priv->duration);
return DEMUXER_CTRL_OK;
default:
return DEMUXER_CTRL_NOTIMPL;
}
}
+3
View File
@@ -1559,6 +1559,9 @@ int demux_control(demuxer_t *demuxer, int cmd, void *arg) {
case DEMUXER_TYPE_MATROSKA:
return demux_mkv_control(demuxer,cmd,arg);
#endif
case DEMUXER_TYPE_REAL:
return demux_real_control(demuxer, cmd, arg);
default:
return DEMUXER_CTRL_NOTIMPL;
}