changeset 11441:fef5c880a61c

seek in realmedia files
author luran
date Wed, 12 Nov 2003 10:27:16 +0000
parents db63c2ec4d55
children 8fae2ef16894
files libmpdemux/demux_real.c libmpdemux/demuxer.c
diffstat 2 files changed, 180 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- 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;
+    }
+}
--- 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;
     }