[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [30502] trunk/blender/source/blender/imbuf /intern/anim.c: == FFMPEG ==

Peter Schlaile peter at schlaile.de
Mon Jul 19 18:27:32 CEST 2010


Revision: 30502
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=30502
Author:   schlaile
Date:     2010-07-19 18:27:31 +0200 (Mon, 19 Jul 2010)

Log Message:
-----------
== FFMPEG ==

This is a fix for the following issues in ffmpeg movie reader:

* mpeg transport stream seeking (HDV) failed completely, since ffmpeg
  doesn't want to seek by timestamp (those aren't guaranteed to be 
  strictly monotonic within those file formats)

  We therefore seek by byte and use the bitrate in those cases. 
  This isn't a real fix,
  I will add a seperate index building process, soon, so that we can
  finally seek by timecode properly (optionally with "free run timecode"
  on consumer video camcorders, stay tuned :) )

* Recent versions of ffmpeg do set the ALPHA channel to 0xff properly,
  so we test the first pixel for proper ALPHA and then workaround
  optionally.

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

Modified: trunk/blender/source/blender/imbuf/intern/anim.c
===================================================================
--- trunk/blender/source/blender/imbuf/intern/anim.c	2010-07-19 15:39:12 UTC (rev 30501)
+++ trunk/blender/source/blender/imbuf/intern/anim.c	2010-07-19 16:27:31 UTC (rev 30502)
@@ -685,6 +685,116 @@
 	return (0);
 }
 
+static void ffmpeg_postprocess(struct anim * anim, ImBuf * ibuf,
+			       int * filter_y)
+{
+	AVFrame * input = anim->pFrame;
+
+	/* This means the data wasnt read properly, 
+	   this check stops crashing */
+	if (input->data[0]==0 && input->data[1]==0 
+	    && input->data[2]==0 && input->data[3]==0){
+		fprintf(stderr, "ffmpeg_fetchibuf: "
+			"data not read properly...\n");
+		return;
+	}
+
+	if (anim->ib_flags & IB_animdeinterlace) {
+		if (avpicture_deinterlace(
+			    (AVPicture*) 
+			    anim->pFrameDeinterlaced,
+			    (const AVPicture*)
+			    anim->pFrame,
+			    anim->pCodecCtx->pix_fmt,
+			    anim->pCodecCtx->width,
+			    anim->pCodecCtx->height)
+		    < 0) {
+			*filter_y = 1;
+		} else {
+			input = anim->pFrameDeinterlaced;
+		}
+	}
+	
+	if (ENDIAN_ORDER == B_ENDIAN) {
+		int * dstStride   = anim->pFrameRGB->linesize;
+		uint8_t** dst     = anim->pFrameRGB->data;
+		int dstStride2[4] = { dstStride[0], 0, 0, 0 };
+		uint8_t* dst2[4]  = { dst[0], 0, 0, 0 };
+		int x,y,h,w;
+		unsigned char* bottom;
+		unsigned char* top;
+		
+		sws_scale(anim->img_convert_ctx,
+			  (const uint8_t * const *)input->data,
+			  input->linesize,
+			  0,
+			  anim->pCodecCtx->height,
+			  dst2,
+			  dstStride2);
+		
+		/* workaround: sws_scale bug
+		   sets alpha = 0 and compensate
+		   for altivec-bugs and flipy... */
+		
+		bottom = (unsigned char*) ibuf->rect;
+		top = bottom + ibuf->x * (ibuf->y-1) * 4;
+		
+		h = (ibuf->y + 1) / 2;
+		w = ibuf->x;
+		
+		for (y = 0; y < h; y++) {
+			unsigned char tmp[4];
+			unsigned int * tmp_l =
+				(unsigned int*) tmp;
+			tmp[3] = 0xff;
+			
+			for (x = 0; x < w; x++) {
+				tmp[0] = bottom[0];
+				tmp[1] = bottom[1];
+				tmp[2] = bottom[2];
+				
+				bottom[0] = top[0];
+				bottom[1] = top[1];
+				bottom[2] = top[2];
+				bottom[3] = 0xff;
+				
+				*(unsigned int*) top = *tmp_l;
+				
+				bottom +=4;
+				top += 4;
+			}
+			top -= 8 * w;
+		}
+	} else {
+		int * dstStride   = anim->pFrameRGB->linesize;
+		uint8_t** dst     = anim->pFrameRGB->data;
+		int dstStride2[4] = { -dstStride[0], 0, 0, 0 };
+		uint8_t* dst2[4]  = { dst[0] + (anim->y - 1)*dstStride[0],
+				      0, 0, 0 };
+		int i;
+		unsigned char* r;
+		
+		sws_scale(anim->img_convert_ctx,
+			  (const uint8_t * const *)input->data,
+			  input->linesize,
+			  0,
+			  anim->pCodecCtx->height,
+			  dst2,
+			  dstStride2);
+		
+		r = (unsigned char*) ibuf->rect;
+		
+		/* workaround sws_scale bug: older version of 
+		   sws_scale set alpha = 0... */
+		if (r[3] == 0) {
+			for (i = 0; i < ibuf->x * ibuf->y; i++) {
+				r[3] = 0xff;
+				r += 4;
+			}
+		}
+	}
+}
+
 static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
 	ImBuf * ibuf;
 	int frameFinished;
@@ -692,6 +802,8 @@
 	int64_t pts_to_search = 0;
 	int pos_found = 1;
 	int filter_y = 0;
+	int seek_by_bytes= 0;
+	int preseek_count = 0;
 
 	if (anim == 0) return (0);
 
@@ -724,6 +836,8 @@
 		}
 	}
 
+	seek_by_bytes = !!(anim->pFormatCtx->iformat->flags & AVFMT_TS_DISCONT);
+
 	if (position != anim->curposition + 1) { 
 #ifdef FFMPEG_OLD_FRAME_RATE
 		double frame_rate = 
@@ -737,22 +851,42 @@
 		double time_base = 
 			av_q2d(anim->pFormatCtx->streams[anim->videoStream]
 				   ->time_base);
-		long long pos = (long long) (position - anim->preseek) 
-			* AV_TIME_BASE / frame_rate;
+		long long pos;
 		long long st_time = anim->pFormatCtx
 			->streams[anim->videoStream]->start_time;
+		int ret;
 
-		if (pos < 0) {
-			pos = 0;
+		if (seek_by_bytes) {
+			pos = position - anim->preseek;
+			if (pos < 0) {
+				pos = 0;
+			}
+			preseek_count = position - pos;
+
+			pos *= anim->pFormatCtx->bit_rate / frame_rate;
+			pos /= 8;
+		} else {
+			pos = (long long) (position - anim->preseek) 
+				* AV_TIME_BASE / frame_rate;
+			if (pos < 0) {
+				pos = 0;
+			}
+
+			if (st_time != AV_NOPTS_VALUE) {
+				pos += st_time * AV_TIME_BASE * time_base;
+			}
 		}
 
-		if (st_time != AV_NOPTS_VALUE) {
-			pos += st_time * AV_TIME_BASE * time_base;
+		ret = av_seek_frame(anim->pFormatCtx, -1, 
+				    pos, 
+				    AVSEEK_FLAG_BACKWARD | (
+					    seek_by_bytes 
+					    ? AVSEEK_FLAG_ANY 
+					    | AVSEEK_FLAG_BYTE : 0));
+		if (ret < 0) {
+			fprintf(stderr, "error while seeking: %d\n", ret);
 		}
 
-		av_seek_frame(anim->pFormatCtx, -1, 
-				  pos, AVSEEK_FLAG_BACKWARD);
-
 		pts_to_search = (long long) 
 			(((double) position) / time_base / frame_rate);
 		if (st_time != AV_NOPTS_VALUE) {
@@ -769,132 +903,28 @@
 						 anim->pFrame, &frameFinished, 
 						 packet.data, packet.size);
 
+			if (seek_by_bytes && preseek_count > 0) {
+				preseek_count--;
+			}
+
 			if (frameFinished && !pos_found) {
-				if (packet.dts >= pts_to_search) {
-					pos_found = 1;
-					anim->curposition = position;
+				if (seek_by_bytes) {
+					if (!preseek_count) {
+						pos_found = 1;
+						anim->curposition = position;
+					}
+				} else {
+					if (packet.dts >= pts_to_search) {
+						pos_found = 1;
+						anim->curposition = position;
+					}
 				}
 			} 
 
 			if(frameFinished && pos_found == 1) {
-				AVFrame * input = anim->pFrame;
-
-				/* This means the data wasnt read properly, 
-				   this check stops crashing */
-				if (input->data[0]==0 && input->data[1]==0 
-					&& input->data[2]==0 && input->data[3]==0){
-					av_free_packet(&packet);
-					break;
-				}
-
-				if (anim->ib_flags & IB_animdeinterlace) {
-					if (avpicture_deinterlace(
-							(AVPicture*) 
-							anim->pFrameDeinterlaced,
-							(const AVPicture*)
-							anim->pFrame,
-							anim->pCodecCtx->pix_fmt,
-							anim->pCodecCtx->width,
-							anim->pCodecCtx->height)
-						< 0) {
-						filter_y = 1;
-					} else {
-						input = anim->pFrameDeinterlaced;
-					}
-				}
-
-				if (ENDIAN_ORDER == B_ENDIAN) {
-					int * dstStride 
-						= anim->pFrameRGB->linesize;
-					uint8_t** dst = anim->pFrameRGB->data;
-					int dstStride2[4]
-						= { dstStride[0], 0, 0, 0 };
-					uint8_t* dst2[4]= {
-						dst[0],	0, 0, 0 };
-					int x,y,h,w;
-					unsigned char* bottom;
-					unsigned char* top;
-
-					sws_scale(anim->img_convert_ctx,
-						  (const uint8_t * const *)input->data,
-						  input->linesize,
-						  0,
-						  anim->pCodecCtx->height,
-						  dst2,
-						  dstStride2);
-				
-					/* workaround: sws_scale 
-					   sets alpha = 0 and compensate
-					   for altivec-bugs and flipy... */
-				
-					bottom = (unsigned char*) ibuf->rect;
-					top = bottom 
-						+ ibuf->x * (ibuf->y-1) * 4;
-
-					h = (ibuf->y + 1) / 2;
-					w = ibuf->x;
-
-					for (y = 0; y < h; y++) {
-						unsigned char tmp[4];
-						unsigned int * tmp_l =
-							(unsigned int*) tmp;
-						tmp[3] = 0xff;
-
-						for (x = 0; x < w; x++) {
-							tmp[0] = bottom[0];
-							tmp[1] = bottom[1];
-							tmp[2] = bottom[2];
-
-							bottom[0] = top[0];
-							bottom[1] = top[1];
-							bottom[2] = top[2];
-							bottom[3] = 0xff;
-								
-							*(unsigned int*) top
-								= *tmp_l;
-
-							bottom +=4;
-							top += 4;
-						}
-						top -= 8 * w;
-					}
-
-					av_free_packet(&packet);
-					break;
-				} else {
-					int * dstStride 
-						= anim->pFrameRGB->linesize;
-					uint8_t** dst = anim->pFrameRGB->data;
-					int dstStride2[4]
-						= { -dstStride[0], 0, 0, 0 };
-					uint8_t* dst2[4]= {
-						dst[0] 
-						+ (anim->y - 1)*dstStride[0],
-						0, 0, 0 };
-					int i;
-					unsigned char* r;
-	
-					sws_scale(anim->img_convert_ctx,
-						  (const uint8_t * const *)input->data,
-						  input->linesize,
-						  0,
-						  anim->pCodecCtx->height,
-						  dst2,
-						  dstStride2);
-
-					/* workaround: sws_scale
-					   sets alpha = 0... */
-					
-					r = (unsigned char*) ibuf->rect;
-					
-					for (i = 0; i < ibuf->x * ibuf->y;i++){
-						r[3] = 0xff;
-						r+=4;
-					}
-
-					av_free_packet(&packet);
-					break;
-				}
+				ffmpeg_postprocess(anim, ibuf, &filter_y);
+				av_free_packet(&packet);
+				break;
 			}
 		}
 





More information about the Bf-blender-cvs mailing list