mirror of
https://github.com/mpv-player/mpv.git
synced 2026-10-23 19:38:51 +08:00
seek in realmedia files
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@11442 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
+176
-49
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user