[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [50474] trunk/blender/source/blender/imbuf /intern: == FFMPEG ==

Peter Schlaile peter at schlaile.de
Fri Sep 7 23:41:39 CEST 2012


Revision: 50474
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=50474
Author:   schlaile
Date:     2012-09-07 21:41:38 +0000 (Fri, 07 Sep 2012)
Log Message:
-----------
== FFMPEG ==

This fixes [#32399] VSE doesn't show last 3 frames of Quicktime movie.

Some decoders store frames internally until EOF.
So one has to feed the decoding engine with empty packets after EOF
until all frames could be extracted properly.

Modified Paths:
--------------
    trunk/blender/source/blender/imbuf/intern/anim_movie.c
    trunk/blender/source/blender/imbuf/intern/indexer.c

Modified: trunk/blender/source/blender/imbuf/intern/anim_movie.c
===================================================================
--- trunk/blender/source/blender/imbuf/intern/anim_movie.c	2012-09-07 17:59:45 UTC (rev 50473)
+++ trunk/blender/source/blender/imbuf/intern/anim_movie.c	2012-09-07 21:41:38 UTC (rev 50474)
@@ -801,6 +801,34 @@
 		anim->next_packet.stream_index = -1;
 	}
 	
+	if (rval == AVERROR_EOF) {
+		anim->next_packet.size = 0;
+		anim->next_packet.data = 0;
+
+		anim->pFrameComplete = 0;
+
+		avcodec_decode_video2(
+			anim->pCodecCtx,
+			anim->pFrame, &anim->pFrameComplete,
+			&anim->next_packet);
+
+		if (anim->pFrameComplete) {
+			anim->next_pts = av_get_pts_from_frame(
+				anim->pFormatCtx, anim->pFrame);
+
+			av_log(anim->pFormatCtx,
+			       AV_LOG_DEBUG,
+			       "  FRAME DONE (after EOF): next_pts=%lld "
+			       "pkt_pts=%lld, guessed_pts=%lld\n",
+			       (anim->pFrame->pts == AV_NOPTS_VALUE) ?
+			       -1 : (long long int)anim->pFrame->pts,
+			       (anim->pFrame->pkt_pts == AV_NOPTS_VALUE) ?
+			       -1 : (long long int)anim->pFrame->pkt_pts,
+			       (long long int)anim->next_pts);
+			rval = 0;
+		}
+	}
+
 	if (rval < 0) {
 		anim->next_packet.stream_index = -1;
 

Modified: trunk/blender/source/blender/imbuf/intern/indexer.c
===================================================================
--- trunk/blender/source/blender/imbuf/intern/indexer.c	2012-09-07 17:59:45 UTC (rev 50473)
+++ trunk/blender/source/blender/imbuf/intern/indexer.c	2012-09-07 21:41:38 UTC (rev 50474)
@@ -723,6 +723,17 @@
 
 	IMB_Timecode_Type tcs_in_use;
 	IMB_Proxy_Size proxy_sizes_in_use;
+
+	unsigned long long seek_pos;
+	unsigned long long last_seek_pos;
+	unsigned long long seek_pos_dts;
+	unsigned long long seek_pos_pts;
+	unsigned long long last_seek_pos_dts;
+	unsigned long long start_pts;
+	double frame_rate;
+	double pts_time_base;
+	int frameno, frameno_gapless;
+	int start_pts_set;
 } FFmpegIndexBuilderContext;
 
 static IndexBuildContext *index_ffmpeg_create_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
@@ -839,20 +850,63 @@
 	MEM_freeN(context);
 }
 
+static void index_rebuild_ffmpeg_proc_decoded_frame(
+	FFmpegIndexBuilderContext *context, 
+	AVPacket * curr_packet,
+	AVFrame *in_frame)
+{
+	int i;
+	unsigned long long s_pos = context->seek_pos;
+	unsigned long long s_dts = context->seek_pos_dts;
+	unsigned long long pts = av_get_pts_from_frame(context->iFormatCtx, in_frame);
+
+	for (i = 0; i < context->num_proxy_sizes; i++) {
+		add_to_proxy_output_ffmpeg(context->proxy_ctx[i], in_frame);
+	}
+
+	if (!context->start_pts_set) {
+		context->start_pts = pts;
+		context->start_pts_set = TRUE;
+	}
+
+	context->frameno = floor((pts - context->start_pts) 
+				 * context->pts_time_base 
+				 * context->frame_rate + 0.5f);
+
+	/* decoding starts *always* on I-Frames,
+	 * so: P-Frames won't work, even if all the
+	 * information is in place, when we seek
+	 * to the I-Frame presented *after* the P-Frame,
+	 * but located before the P-Frame within
+	 * the stream */
+
+	if (pts < context->seek_pos_pts) {
+		s_pos = context->last_seek_pos;
+		s_dts = context->last_seek_pos_dts;
+	}
+
+	for (i = 0; i < context->num_indexers; i++) {
+		if (context->tcs_in_use & tc_types[i]) {
+			int tc_frameno = context->frameno;
+
+			if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
+				tc_frameno = context->frameno_gapless;
+			
+			IMB_index_builder_proc_frame(
+				context->indexer[i],
+				curr_packet->data,
+				curr_packet->size,
+				tc_frameno,
+				s_pos, s_dts, pts);
+		}
+	}
+	
+	context->frameno_gapless++;
+}
+
 static int index_rebuild_ffmpeg(FFmpegIndexBuilderContext *context,
                                 short *stop, short *do_update, float *progress)
 {
-	int i;
-	unsigned long long seek_pos = 0;
-	unsigned long long last_seek_pos = 0;
-	unsigned long long seek_pos_dts = 0;
-	unsigned long long seek_pos_pts = 0;
-	unsigned long long last_seek_pos_dts = 0;
-	unsigned long long start_pts = 0;
-	double frame_rate;
-	double pts_time_base;
-	int frameno = 0, frameno_gapless = 0;
-	int start_pts_set = FALSE;
 	AVFrame *in_frame = 0;
 	AVPacket next_packet;
 	uint64_t stream_size;
@@ -861,8 +915,8 @@
 
 	stream_size = avio_size(context->iFormatCtx->pb);
 
-	frame_rate = av_q2d(context->iStream->r_frame_rate);
-	pts_time_base = av_q2d(context->iStream->time_base);
+	context->frame_rate = av_q2d(context->iStream->r_frame_rate);
+	context->pts_time_base = av_q2d(context->iStream->time_base);
 
 	while (av_read_frame(context->iFormatCtx, &next_packet) >= 0) {
 		int frame_finished = 0;
@@ -881,11 +935,11 @@
 
 		if (next_packet.stream_index == context->videoStream) {
 			if (next_packet.flags & AV_PKT_FLAG_KEY) {
-				last_seek_pos = seek_pos;
-				last_seek_pos_dts = seek_pos_dts;
-				seek_pos = next_packet.pos;
-				seek_pos_dts = next_packet.dts;
-				seek_pos_pts = next_packet.pts;
+				context->last_seek_pos = context->seek_pos;
+				context->last_seek_pos_dts = context->seek_pos_dts;
+				context->seek_pos = next_packet.pos;
+				context->seek_pos_dts = next_packet.dts;
+				context->seek_pos_pts = next_packet.pts;
 			}
 
 			avcodec_decode_video2(
@@ -894,54 +948,34 @@
 		}
 
 		if (frame_finished) {
-			unsigned long long s_pos = seek_pos;
-			unsigned long long s_dts = seek_pos_dts;
-			unsigned long long pts = av_get_pts_from_frame(context->iFormatCtx, in_frame);
+			index_rebuild_ffmpeg_proc_decoded_frame(
+				context, &next_packet, in_frame);
+		}
+		av_free_packet(&next_packet);
+	}
 
-			for (i = 0; i < context->num_proxy_sizes; i++) {
-				add_to_proxy_output_ffmpeg(
-				        context->proxy_ctx[i], in_frame);
-			}
+	/* process pictures still stuck in decoder engine after EOF
+	   according to ffmpeg docs using 0-size packets. 
 
-			if (!start_pts_set) {
-				start_pts = pts;
-				start_pts_set = TRUE;
-			}
+	   At least, if we haven't already stopped... */
+	if (!*stop) {
+		int frame_finished;
 
-			frameno = floor((pts - start_pts) *
-			                pts_time_base * frame_rate + 0.5f);
+		next_packet.size = 0;
+		next_packet.data = 0;
 
-			/* decoding starts *always* on I-Frames,
-			 * so: P-Frames won't work, even if all the
-			 * information is in place, when we seek
-			 * to the I-Frame presented *after* the P-Frame,
-			 * but located before the P-Frame within
-			 * the stream */
+		do {
+			frame_finished = 0;
 
-			if (pts < seek_pos_pts) {
-				s_pos = last_seek_pos;
-				s_dts = last_seek_pos_dts;
-			}
+			avcodec_decode_video2(
+				context->iCodecCtx, in_frame, &frame_finished,
+				&next_packet);
 
-			for (i = 0; i < context->num_indexers; i++) {
-				if (context->tcs_in_use & tc_types[i]) {
-					int tc_frameno = frameno;
-
-					if (tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
-						tc_frameno = frameno_gapless;
-
-					IMB_index_builder_proc_frame(
-					        context->indexer[i],
-					        next_packet.data,
-					        next_packet.size,
-					        tc_frameno,
-					        s_pos, s_dts, pts);
-				}
+			if (frame_finished) {
+				index_rebuild_ffmpeg_proc_decoded_frame(
+					context, &next_packet, in_frame);
 			}
-
-			frameno_gapless++;
-		}
-		av_free_packet(&next_packet);
+		} while (frame_finished);
 	}
 
 	av_free(in_frame);




More information about the Bf-blender-cvs mailing list