# HG changeset patch # User luran # Date 1068632836 0 # Node ID fef5c880a61ca4c6b577720ec0b2805ba6046890 # Parent db63c2ec4d55b7c049d36ab2203a43aceb62c96e seek in realmedia files diff -r db63c2ec4d55 -r fef5c880a61c libmpdemux/demux_real.c --- a/libmpdemux/demux_real.c Wed Nov 12 10:27:08 2003 +0000 +++ b/libmpdemux/demux_real.c Wed Nov 12 10:27:16 2003 +0000 @@ -50,11 +50,16 @@ /* 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 @@ 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 @@ { 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 @@ /* 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 @@ } } #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 @@ 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 @@ 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 @@ // 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 @@ 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 @@ } 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 @@ 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 @@ /* 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 @@ 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 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 @@ /* seek absolute */ priv->current_apacket = priv->current_vpacket = 0; + 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; + 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; + if (streams & 1) + rel_seek_frames = (int)(sh_video->fps*rel_seek_secs); + else if (streams & 2) + rel_seek_frames = (int)(rel_seek_secs); - /* 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++; - 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("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; + } +} diff -r db63c2ec4d55 -r fef5c880a61c libmpdemux/demuxer.c --- a/libmpdemux/demuxer.c Wed Nov 12 10:27:08 2003 +0000 +++ b/libmpdemux/demuxer.c Wed Nov 12 10:27:16 2003 +0000 @@ -1559,6 +1559,9 @@ 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; }