summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorluran <luran@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-11-12 10:27:16 +0000
committerluran <luran@b3059339-0415-0410-9bf9-f77b7e298cf2>2003-11-12 10:27:16 +0000
commit72f330c8a0675e9e34514e5728e92a0e79a172c8 (patch)
tree5396a70de02143425c2d78777cb28bb3aee2ba64
parent74f7957814337a5869448b7f84c1dc99917d8c72 (diff)
downloadmpv-72f330c8a0675e9e34514e5728e92a0e79a172c8.tar.bz2
mpv-72f330c8a0675e9e34514e5728e92a0e79a172c8.tar.xz
seek in realmedia files
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@11442 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r--libmpdemux/demux_real.c225
-rw-r--r--libmpdemux/demuxer.c3
2 files changed, 179 insertions, 49 deletions
diff --git a/libmpdemux/demux_real.c b/libmpdemux/demux_real.c
index 6d368affe8..afd564cef4 100644
--- a/libmpdemux/demux_real.c
+++ b/libmpdemux/demux_real.c
@@ -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;
+ }
}
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index d8fab9068e..194620730c 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -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;
}