Hi all,

I'm back on work on transcode, slowly as usual because the spare time
always too low. Stuck on my ~FIFO[1] TODO, I've recently merged yait
code.

I've also performed a little deeper code review on filter_yait.c, and I
like ot submit it here (especially to Allan's attention) before to merge
it on CVS. Please check out attached patch[0], and point out my
mistakes.

There is a few comments and some tiny code logic changes (nothing
serious of course, just initialization reorder, some code factorization
and constantization and stuff like that). Please let me know if I broke
something. I can't test it new version now or soon due to lack of NTSC
material and, most important, time.

A review and STYLE-ification of tcyait will be follow into near future.

A word about of STYLE. I know that can be annoying (everyone has it's
own style and everyone wants to keep it), but I strongly believe that
having a consistent codebase helps significantly in keeping codebase
safe and fun to hack in. So submitted code -like yait- will be
STYLE-ificated[2].
I've already seen too much horrors in the past, even (especially?) into
our own codebase :)

Thoughts?

+++

[0] yeah, it's big. That's mainly due to tab removal.
[1] Please bug me if a task starts to starve (i.e., recent configure
patches to Os X, that was my bad)
[2] Resistance is futile, you will be STYLE-ificated :)

Bests,

-- 
Francesco Romani
Index: filter/filter_yait.c
===================================================================
RCS file: /cvstc/transcode/filter/filter_yait.c,v
retrieving revision 1.1
diff -u -r1.1 filter_yait.c
--- filter/filter_yait.c	26 May 2007 15:52:10 -0000	1.1
+++ filter/filter_yait.c	27 May 2007 09:28:47 -0000
@@ -20,10 +20,10 @@
  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define	MOD_NAME	"filter_yait.so"
-#define	MOD_VERSION	"v0.1 (2007-02-14)"
-#define	MOD_CAP		"Yet Another Inverse Telecine filter"
-#define	MOD_AUTHOR	"Allan Snider"
+#define MOD_NAME    "filter_yait.so"
+#define MOD_VERSION "v0.2 (2007-05-26)"
+#define MOD_CAP     "Yet Another Inverse Telecine filter"
+#define MOD_AUTHOR  "Allan Snider"
 
 #include "transcode.h"
 #include "filter.h"
@@ -36,729 +36,686 @@
 
 
 /*
- *	yait:
- *		Yet Another Inverse Telecine filter.
+ *  yait:
+ *      Yet Another Inverse Telecine filter.
  *
- *	Usage:
- *		-J yait=log[=file] (-y null)
- *		-J yait=ops[=file]
- *
- *	Description:
- *
- *		This filter is designed specifically to handle mixed progressive and NTSC
- *	telecined data (2:3 pulldown), converting from NTSC_VIDEO (29.97 fps) to NTSC_FILM
- *	(23.976 fps).  It uses row save and copy operations to reconstruct progressive
- *	frames.  It is provided as an alternative to the -J ivtc,32detect,decimate method.
- *
- *		For those who don't care how much cpu is used but are interested only
- *	in trying to achieve the best quality rendering, then read on.  If not, then stop
- *	reading right now, as this filter requires a complete separate pass on the video
- *	stream and an external analysis tool to be run.
- *
- *		The main advantage of using a separate pass is that it provides a much
- *	larger window of frames to examine when deciding what frames need to be dropped
- *	or de-interlaced.  The video stream is read at 30 fps (--hard_fps).  Duplicate
- *	frames are inserted by the demuxer to keep the frame rate at 30 when progressive
- *	data is encountered.  These frames can appear quite early or late, far beyond the
- *	five frame local window used by ivtc, etc.  This approach allows drop frames to
- *	be credited, and debited, (up to a point), making better drop frame choices.  The
- *	result is a (noticeably) smoother video.
- *
- *		Another advantage of using a large frame window is to provide context
- *	for determining interlace patterns.  Local interlace patterns (eg. a 5 frame
- *	window) can sometimes be impossible to determine.  When able to look ahead or
- *	behind for existing patterns, usually the correct pattern can be inherited.
- *
- *		The filter guarantees one drop frame per 5 frames.  No more, no less.
- *
- *	Using the filter:
- *
- *	    Pass 1:
- *
- *		-J yait=log -y null
- *
- *		The first pass is used only to generate row (even/odd) delta information.
- *		This is written as a text log file (called yait.log by default).  (The
- *		file name can be specified using yait=log=file).  This is the only data
- *		required by this pass, so no video (or audio) frames need to be encoded.
- *		You do need to specify the demuxer_sync method however.  (It must be 2).
- *
- *		Alternatively (for debug purposes), you may want to generate a frame
- *		labeled video file, then compare the yait analysis to the original video.
- *		In this case use something like:
- *			-H 10 -x vob -i ...
- *			--export_fps 0,4 --demuxer_sync 2 -y xvid4,null -o label.ogm
- *			-J yait=log -J text=frame:posdef=8
- *
- * 	    Running the tcyait tool:
- *
- * 		Pass 1 created a yait.log file.  The analysis tool 'tcyait' is then run
- * 		which reads the log file and determines which areas are telecined and
- * 		progressive and detects the telecine patterns.  A yait frame operations
- * 		file is then written (yait.ops by default).  It is a text file containing
- * 		instructions for each frame, such as nop, save even or odd rows, copy rows,
- * 		drop frames, or blend a frame.  The usage of the tool is as follows:
- *
- *		tcyait [-d] [-l log] [-o ops] [-m mode]
- *		        -d              Print debug information to stdout.
- *		        -l log          Specify input yait log file name [yait.log].
- *		        -o ops          Specify output yait frame ops file name [yait.ops].
- *		        -m mode         Specify transcode de-interlace method [3].
- *
- *		I typically run it as:
- *			tcyait -d > yait.info
- *
- *		One could query why pass 1 doesn't just create the .ops file directly.  That
- *		is, run the analysis at TC_FILTER_CLOSE time and save the user from having
- *		to run the tool directly.  The main reason is that the tcyait code is alpha
- *		and still undergoing a lot of fine tuning.  I would not want to have to
- *		regenerate the row delta information every time I tweaked the analysis
- *		portion.  So, it exists as a separate tool for now.
- *
- *	    Pass 2 (and 3): 		
- *
- *		-J yait=ops -y ...
- *
- * 		The second pass (or third for -R 1 and -R 2), reads the frame operations file
- * 		generated by tcyait, (called yait.ops by default).  (The file name can be
- * 		specified using yait=ops=file).  This file instructs the filter to save or
- * 		copy rows, skip frames, or de-interlace frames, and causes the pre filtering
- * 		to reduce the frame rate to 24 fps.  Hence, you must specify the export fps
- * 		as 24, or will get truncated audio, (ie. --export_fps 24,1).  The frame
- * 		sequence seen by the filter must match exactly what pass 1 saw.  That is, you
- * 		cannot specify a frame range or audio track in pass 1, but not pass 2, and
- * 		visa versa.  Here is an example invocation:
- *
- *			transcode -H 10 -a 0 -x vob -i ... -w 1800,50 -b 192,0,0 -Z ...
- *				-R 1 -y xvid4,null --demuxer_sync 2 --export_fps 24,1
- *				-J yait=ops --progress_rate 25
- *
- *			transcode -H 10 -a 0 -x vob -i ... -w 1800,50 -b 192,0,0 -Z ...
- *				-R 2 -y xvid4 --demuxer_sync 2 --export_fps 24,1 -o ...
- *				-J yait=ops --progress_rate 25
- *
- *		The import frame rate and --hard_fps flags are forced by the filter and
- *		need not be specified.
- *
- *	DISCLAIMER:
- *
- *		This is a work in progress.  For non-NTSC telecine patterns, PAL, or purely
- *	interlaced material, you are going to get nonsense results.  Best stick to 'ivtc' or
- *	'smartyuv' for those.
- *
- *		For some video, remarkably good results were obtained.  (I was quite pleased and
- *	hence felt obliged to distribute this).  In a few cases I had video constantly switching
- *	frame rates, with single or small grouped telecine, both even and odd patterns, and was
- *	able to reconstruct the original 24 fps progressive film for the entire file, without
- *	blending a single frame.  For others, not so good.  The analysis tool can sometimes
- *	generate a lot of false positives for interlace detection and specify needless frame
- *	blending.  Generally, wherever a frame blend is specified, something went wrong.  I
- *	usually step frame by frame in the original (frame labelled) .ogm and edit/correct
- *	the .ops file manually.
- *
- *		There is much work to be done still (especially documentation), but here it
- *	is, such as it is.
- *						Allan
+ *  Usage:
+ *      -J yait=log[=file] (-y null)
+ *      -J yait=ops[=file]
+ *
+ *  Description:
+ *
+ *      This filter is designed specifically to handle mixed progressive and NTSC
+ *  telecined data (2:3 pulldown), converting from NTSC_VIDEO (29.97 fps) to NTSC_FILM
+ *  (23.976 fps).  It uses row save and copy operations to reconstruct progressive
+ *  frames.  It is provided as an alternative to the -J ivtc,32detect,decimate method.
+ *
+ *      For those who don't care how much cpu is used but are interested only
+ *  in trying to achieve the best quality rendering, then read on.  If not, then stop
+ *  reading right now, as this filter requires a complete separate pass on the video
+ *  stream and an external analysis tool to be run.
+ *
+ *      The main advantage of using a separate pass is that it provides a much
+ *  larger window of frames to examine when deciding what frames need to be dropped
+ *  or de-interlaced.  The video stream is read at 30 fps (--hard_fps).  Duplicate
+ *  frames are inserted by the demuxer to keep the frame rate at 30 when progressive
+ *  data is encountered.  These frames can appear quite early or late, far beyond the
+ *  five frame local window used by ivtc, etc.  This approach allows drop frames to
+ *  be credited, and debited, (up to a point), making better drop frame choices.  The
+ *  result is a (noticeably) smoother video.
+ *
+ *      Another advantage of using a large frame window is to provide context
+ *  for determining interlace patterns.  Local interlace patterns (eg. a 5 frame
+ *  window) can sometimes be impossible to determine.  When able to look ahead or
+ *  behind for existing patterns, usually the correct pattern can be inherited.
+ *
+ *      The filter guarantees one drop frame per 5 frames.  No more, no less.
+ *
+ *  Using the filter:
+ *
+ *      Pass 1:
+ *
+ *      -J yait=log -y null
+ *
+ *      The first pass is used only to generate row (even/odd) delta information.
+ *      This is written as a text log file (called yait.log by default).  (The
+ *      file name can be specified using yait=log=file).  This is the only data
+ *      required by this pass, so no video (or audio) frames need to be encoded.
+ *      You do need to specify the demuxer_sync method however.  (It must be 2).
+ *
+ *      Alternatively (for debug purposes), you may want to generate a frame
+ *      labeled video file, then compare the yait analysis to the original video.
+ *      In this case use something like:
+ *          -H 10 -x vob -i ...
+ *          --export_fps 0,4 --demuxer_sync 2 -y xvid4,null -o label.ogm
+ *          -J yait=log -J text=frame:posdef=8
+ *
+ *      Running the tcyait tool:
+ *
+ *      Pass 1 created a yait.log file.  The analysis tool 'tcyait' is then run
+ *      which reads the log file and determines which areas are telecined and
+ *      progressive and detects the telecine patterns.  A yait frame operations
+ *      file is then written (yait.ops by default).  It is a text file containing
+ *      instructions for each frame, such as nop, save even or odd rows, copy rows,
+ *      drop frames, or blend a frame.  The usage of the tool is as follows:
+ *
+ *      tcyait [-d] [-l log] [-o ops] [-m mode]
+ *              -d              Print debug information to stdout.
+ *              -l log          Specify input yait log file name [yait.log].
+ *              -o ops          Specify output yait frame ops file name [yait.ops].
+ *              -m mode         Specify transcode de-interlace method [3].
+ *
+ *      I typically run it as:
+ *          tcyait -d > yait.info
+ *
+ *      One could query why pass 1 doesn't just create the .ops file directly.  That
+ *      is, run the analysis at TC_FILTER_CLOSE time and save the user from having
+ *      to run the tool directly.  The main reason is that the tcyait code is alpha
+ *      and still undergoing a lot of fine tuning.  I would not want to have to
+ *      regenerate the row delta information every time I tweaked the analysis
+ *      portion.  So, it exists as a separate tool for now.
+ *
+ *      Pass 2 (and 3):         
+ *
+ *      -J yait=ops -y ...
+ *
+ *      The second pass (or third for -R 1 and -R 2), reads the frame operations file
+ *      generated by tcyait, (called yait.ops by default).  (The file name can be
+ *      specified using yait=ops=file).  This file instructs the filter to save or
+ *      copy rows, skip frames, or de-interlace frames, and causes the pre filtering
+ *      to reduce the frame rate to 24 fps.  Hence, you must specify the export fps
+ *      as 24, or will get truncated audio, (ie. --export_fps 24,1).  The frame
+ *      sequence seen by the filter must match exactly what pass 1 saw.  That is, you
+ *      cannot specify a frame range or audio track in pass 1, but not pass 2, and
+ *      visa versa.  Here is an example invocation:
+ *
+ *          transcode -H 10 -a 0 -x vob -i ... -w 1800,50 -b 192,0,0 -Z ...
+ *              -R 1 -y xvid4,null --demuxer_sync 2 --export_fps 24,1
+ *              -J yait=ops --progress_rate 25
+ *
+ *          transcode -H 10 -a 0 -x vob -i ... -w 1800,50 -b 192,0,0 -Z ...
+ *              -R 2 -y xvid4 --demuxer_sync 2 --export_fps 24,1 -o ...
+ *              -J yait=ops --progress_rate 25
+ *
+ *      The import frame rate and --hard_fps flags are forced by the filter and
+ *      need not be specified.
+ *
+ *  DISCLAIMER:
+ *
+ *      This is a work in progress.  For non-NTSC telecine patterns, PAL, or purely
+ *  interlaced material, you are going to get nonsense results.  Best stick to 'ivtc' or
+ *  'smartyuv' for those.
+ *
+ *      For some video, remarkably good results were obtained.  (I was quite pleased and
+ *  hence felt obliged to distribute this).  In a few cases I had video constantly switching
+ *  frame rates, with single or small grouped telecine, both even and odd patterns, and was
+ *  able to reconstruct the original 24 fps progressive film for the entire file, without
+ *  blending a single frame.  For others, not so good.  The analysis tool can sometimes
+ *  generate a lot of false positives for interlace detection and specify needless frame
+ *  blending.  Generally, wherever a frame blend is specified, something went wrong.  I
+ *  usually step frame by frame in the original (frame labelled) .ogm and edit/correct
+ *  the .ops file manually.
+ *
+ *      There is much work to be done still (especially documentation), but here it
+ *  is, such as it is.
+ *                      Allan
  */
 
 
 /*
- *	Defines:
+ *  Defines:
  */
 
-#define	FALSE			0
-#define	TRUE			1
-
-#define	Y_LOG_FN		"yait.log"	/* log file read */
-#define	Y_OPS_FN		"yait.ops"	/* frame operation file written */
+#define Y_LOG_FN        "yait.log"  /* log file read */
+#define Y_OPS_FN        "yait.ops"  /* frame operation file written */
 
 /* frame ops */
-#define	Y_OP_ODD		0x10
-#define	Y_OP_EVEN		0x20
-#define	Y_OP_PAT		0x30
-
-#define	Y_OP_NOP		0x0
-#define	Y_OP_SAVE		0x1
-#define	Y_OP_COPY		0x2
-#define	Y_OP_DROP		0x4
-#define	Y_OP_DEINT		0x8
-
-
-/*
- *	Globals:
- */
-
-FILE *Log_fp;			/* output log file */
-FILE *Ops_fp;			/* input frame ops file */
-
-uint8_t *Fbuf;			/* video frame buffer */
-int Codec;			/* internal codec */
-int Fn;				/* frame number */
-
-
-/*
- *	Prototypes:
- */
-
-static int yait_get_config( char* );
-static int yait_init( char* );
-static int yait_fini( void );
-static int yait_process( vframe_list_t* );
-
-static void yait_compare( vframe_list_t*, uint8_t*, int );
-static void yait_cmp_rgb( uint8_t*, uint8_t*, int, int, int*, int* );
-static void yait_cmp_yuv( uint8_t*, uint8_t*, int, int, int*, int* );
-static int yait_ops( vframe_list_t* );
-static int yait_ops_chk( void );
-static int yait_ops_get( char*, int, int* );
-static int yait_ops_decode( char*, int* );
-static void yait_put_rows( uint8_t*, uint8_t*, int, int, int );
-
-
-/*
- *	tc_filter:
- *		YAIT filter main entry point.  Single instance.
- */
-
-int
-tc_filter( frame_list_t *ptr_, char *opt )
-	{
-	vframe_list_t *ptr = (vframe_list_t*) ptr_;
-
-	if( ptr->tag & TC_AUDIO )
-		return( 0 );
-
-	if( ptr->tag & TC_FILTER_GET_CONFIG )
-		return( yait_get_config(opt) );
-
-	if( ptr->tag & TC_FILTER_INIT )
-		return( yait_init(opt) );
-
-	if( ptr->tag & TC_FILTER_CLOSE )
-		return( yait_fini() );
-
-	if( ptr->tag & TC_PRE_S_PROCESS )
-		return( yait_process(ptr) );
-
-	return( 0 );
-	}
-
-
-/*
- *	yait_get_config:
- */
-
-static int
-yait_get_config( char *opt )
-	{
-	optstr_filter_desc( opt, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VRYE", "1" );
-	optstr_param( opt, "log", "Compute and write yait delta log file", "%s", "" );
-	optstr_param( opt, "ops", "Read and apply yait frame operation file", "%s", "" );
-
-	return( 0 );
-	}
-
-
-/*
- *	yait_init:
- */
-
-static int
-yait_init( char *opt )
-	{
-	static vob_t *vob;
-	char buf[256], *fn;
-	const char *p;
-	int n;
-
-	if( verbose )
-		{
-		tc_log_info( MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP );
-		tc_log_info( MOD_NAME, "options=%s", opt );
-		}
-
-	vob = tc_get_vob();
-	if( !vob )
-		{
-		tc_log_error( MOD_NAME, "cannot get VOB info." );
-		return( -1 );
-		}
-
-	Codec = vob->im_v_codec;
-	fn = NULL;
-
-	/* log file */
-        p = optstr_lookup( opt, "log" );
-	if( p )
-		{
-		fn = Y_LOG_FN;
-		n = optstr_get( opt, "log", "%[^:]", buf );
-		if( n > 0 )
-			fn = buf;
-
-		Log_fp = fopen( fn, "w" );
-		if( !Log_fp )
-			{
-			perror( "fopen" );
-			tc_log_error( MOD_NAME, "cannot create log file, '%s'", buf );
-			return( -1 );
-			}
-		}
-
-	/* ops file */
-	p = optstr_lookup( opt, "ops" );
-	if( p )
-		{
-		fn = Y_OPS_FN;
-		n = optstr_get( opt, "ops", "%[^:]", buf );
-		if( n > 0 )
-			fn = buf;
-
-		Ops_fp = fopen( fn, "r" );
-		if( !Ops_fp )
-			{
-			perror( "fopen" );
-			tc_log_error( MOD_NAME, "cannot open yait ops file, '%s'", buf );
-			return( -1 );
-			}
-
-		if( !yait_ops_chk() )
-			{
-			tc_log_error( MOD_NAME, "invalid yait ops file" );
-			return( -1 );
-			}
-		}
-
-	if( !Log_fp && !Ops_fp )
-		{
-		tc_log_error( MOD_NAME, "at least one operation (log|ops) must be specified" );
-		return( -1 );
-		}
-
-	if( Log_fp && Ops_fp )
-		{
-		tc_log_error( MOD_NAME, "only one operation (log|ops) may be specified" );
-		return( -1 );
-		}
-
-	if( Log_fp )
-		{
-		tc_log_info( MOD_NAME, "Generating YAIT delta log file '%s'", fn );
-		tc_log_info( MOD_NAME, "Forcing --hard_fps, -f 30,4, --export_fps 30,4" );
-
-		/* try to lock everything in at 30 fps */
-	  	vob->hard_fps_flag = TC_TRUE;
-		vob->im_frc = 4;
-		vob->ex_frc = 4;
-		vob->fps = NTSC_VIDEO;
-		vob->ex_fps = NTSC_VIDEO;
-		}
-
-	if( Ops_fp )
-		{
-		tc_log_info( MOD_NAME, "Applying YAIT frame operations file '%s'", fn );
-		tc_log_info( MOD_NAME, "Forcing --hard_fps, -f 30,4, --export_fps 24,1" );
-
-		/* try to lock import at 30 fps, export at 24 fps */
-	  	vob->hard_fps_flag = TC_TRUE;
-		vob->im_frc = 4;
-		vob->ex_frc = 1;
-		vob->fps = NTSC_VIDEO;
-		vob->ex_fps = NTSC_FILM;
-		}
-
-	Fbuf = tc_malloc( SIZE_RGB_FRAME );
-	if( !Fbuf )
-		{
-		perror( "tc_malloc" );
-		tc_log_error( MOD_NAME, "cannot allocate frame buffer" );
-		return( -1 );
-		}
-
-	memset( Fbuf, 0, SIZE_RGB_FRAME );
-
-	Fn = -1;
-
-	return( 0 );
-	}
-
-
-/*
- *	yait_fini:
- */
-
-static int
-yait_fini( void )
-	{
-	if( Log_fp )
-		fclose( Log_fp );
-	if( Ops_fp )
-		fclose( Ops_fp );
-	if( Fbuf )
-		free( Fbuf );
-
-	Log_fp = NULL;
-	Ops_fp = NULL;
-	Fbuf = NULL;
-
-	return( 0 );
-	}
-
-
-/*
- *	yait_process:
- */
-
-static int
-yait_process( vframe_list_t *ptr )
-	{
-	if( Fn == -1 )
-		{
-		Fn = ptr->id;
-		ac_memcpy( Fbuf, ptr->video_buf, ptr->video_size );
-		}
-
-	if( ptr->id != Fn )
-		{
-		tc_log_error( MOD_NAME, "inconsistent frame numbers" );
-		yait_fini();
-		return( -1 );
-		}
-
-	if( Log_fp )
-		{
-		yait_compare( ptr, Fbuf, Fn );
-		ac_memcpy( Fbuf, ptr->video_buf, ptr->video_size );
-		}
-
-	if( Ops_fp )
-		if( !yait_ops(ptr) )
-			{
-			yait_fini();
-			return( -1 );
-			}
-
-	Fn++;
-	return( 0 );
-	}
-
-
-/*
- *	yait_compare:
- */
-
-static void
-yait_compare( vframe_list_t *ptr, uint8_t *lv, int fn )
-	{
-	uint8_t *cv;
-	int ed, od;
-	int w, h;
-
-	cv = ptr->video_buf;
-	w = ptr->v_width;
-	h = ptr->v_height;
-
-	if( Codec == CODEC_RGB )
-		yait_cmp_rgb( lv, cv, w, h, &ed, &od );
-	else
-		yait_cmp_yuv( lv, cv, w, h, &ed, &od );
-
-	fprintf( Log_fp, "%d: e: %d, o: %d\n", fn, ed, od );
-
-	/* BUG: until the blocked tcdecode pipe problem is fixed... */
-	if( !(fn%5) )
-		fflush( Log_fp );
-	}
-
-
-/*
- *	yait_cmp_rgb:
- */
-
-static void
-yait_cmp_rgb( uint8_t *lv, uint8_t *cv, int w, int h, int *ed, int *od )
-	{
-	uint8_t *lp, *cp;
-	int x, y, p;
-	int e, o;
-
-	/* even row delta */
-	e = 0;
-	for( y=0; y<h; y+=2 )
-		{
-		p = y * w * 3;
-		lp = lv + p;
-		cp = cv + p;
-		for( x=0; x<w; x++ )
-			{
-			e += abs( *lp++ - *cp++ );
-			e += abs( *lp++ - *cp++ );
-			e += abs( *lp++ - *cp++ );
-			}
-		}
-
-	/* odd row delta */
-	o = 0;
-	for( y=1; y<h; y+=2 )
-		{
-		p = y * w * 3;
-		lp = lv + p;
-		cp = cv + p;
-		for( x=0; x<w; x++ )
-			{
-			o += abs( *lp++ - *cp++ );
-			o += abs( *lp++ - *cp++ );
-			o += abs( *lp++ - *cp++ );
-			}
-		}
-
-	*ed = e;
-	*od = o;
-	}
-
-
-/*
- *	yait_cmp_yuv:
- */
-
-static void
-yait_cmp_yuv( uint8_t *lv, uint8_t *cv, int w, int h, int *ed, int *od )
-	{
-	uint8_t *lp, *cp;
-	int x, y, p;
-	int e, o;
-
-	/* even row delta */
-	e = 0;
-	for( y=0; y<h; y+=2 )
-		{
-		/* y */
-		p = y * w;
-		lp = lv + p;
-		cp = cv + p;
-		for( x=0; x<w; x++ )
-			e += abs( *lp++ - *cp++ );
-
-		/* uv */
-		p = w*h + y * w/2;
-		lp = lv + p;
-		cp = cv + p;
-		for( x=0; x<w/2; x++ )
-			e += abs( *lp++ - *cp++ );
-		}
-
-	/* odd row delta */
-	o = 0;
-	for( y=1; y<h; y+=2 )
-		{
-		/* y */
-		p = y * w;
-		lp = lv + p;
-		cp = cv + p;
-		for( x=0; x<w; x++ )
-			o += abs( *lp++ - *cp++ );
-
-		/* uv */
-		p = w*h + y * w/2;
-		lp = lv + p;
-		cp = cv + p;
-		for( x=0; x<w/2; x++ )
-			o += abs( *lp++ - *cp++ );
-		}
-
-	*ed = e;
-	*od = o;
-	}
-
-
-/*
- *	yait_ops:
- */
-
-static int
-yait_ops( vframe_list_t *ptr )
-	{
-	char buf[256];
-	uint8_t *v;
-	int mode, op;
-	int w, h;
-
-	v = ptr->video_buf;
-	w = ptr->v_width;
-	h = ptr->v_height;
-
-	fgets( buf, 256, Ops_fp );
-	op = yait_ops_get( buf, Fn, &mode );
-
-	if( op < 0 )
-		return( FALSE );
-
-	if( op & Y_OP_SAVE )
-		yait_put_rows( Fbuf, v, w, h, op&Y_OP_PAT );
-
-	if( op & Y_OP_COPY )
-		yait_put_rows( v, Fbuf, w, h, op&Y_OP_PAT );
-
-	if( op & Y_OP_DROP )
-		ptr->attributes |= TC_FRAME_IS_SKIPPED;
-
-	if( op & Y_OP_DEINT )
-		{
-		ptr->attributes |= TC_FRAME_IS_INTERLACED;
-		ptr->deinter_flag = mode;
-		}
-
-	return( TRUE );
-	}
-
-
-/*
- *	yait_ops_chk:
- */
-
-static int
-yait_ops_chk( void )
-	{
-	char buf[256], *p;
-	int fn, op;
-
-	fscanf( Ops_fp, "%d:", &fn );
-	rewind( Ops_fp );
-	for( ;; )
-		{
-		p = fgets( buf, 256, Ops_fp );
-		if( !p )
-			break;
-
-		op = yait_ops_get( buf, fn, NULL );
-		if( op < 0 )
-			return( FALSE );
-		fn++;
-		}
-
-	rewind( Ops_fp );
-	return( TRUE );
-	}
-
-
-/*
- *	yait_ops_get:
- */
-
-static int
-yait_ops_get( char *buf, int fn, int *mode )
-	{
-	char str[256];
-	int op, f, n;
-
-	f = -1;
-	str[0] = 0;
-
-	n = sscanf( buf, "%d: %s\n", &f, str );
-	if( n < 1 )
-		{
-		if( feof(Ops_fp) )
-			tc_log_error( MOD_NAME, "truncated yait ops file, frame: %d", fn );
-		else
-			tc_log_error( MOD_NAME, "invalid yait ops format, frame: %d", fn );
-		return( -1 );
-		}
-
-	if( f != fn )
-		{
-		tc_log_error( MOD_NAME, "invalid yait ops frame number, frame: %d", fn );
-		return( -1 );
-		}
-
-	op = yait_ops_decode( str, mode );
-	if( op < 0 )
-		{
-		tc_log_error( MOD_NAME, "invalid yait ops code, frame: %d", fn );
-		return( -1 );
-		}
-
-	return( op );
-	}
-
-
-/*
- *	yait_ops_decode:
- */
-
-static int
-yait_ops_decode( char *str, int *mode )
-	{
-	int op, c;
-
-	op = 0;
-	while( *str )
-		{
-		c = *str++;
-		if( c>='1' && c<='5' )
-			{
-			op |= Y_OP_DEINT;
-			if( mode )
-				*mode = c - '0';
-			continue;
-			}
-
-		switch( c )
-			{
-			case 'o':
-				op |= Y_OP_ODD;
-				break;
-			case 'e':
-				op |= Y_OP_EVEN;
-				break;
-			case 's':
-				op |= Y_OP_SAVE;
-				break;
-			case 'c':
-				op |= Y_OP_COPY;
-				break;
-			case 'd':
-				op |= Y_OP_DROP;
-				break;
-			default:
-				return( -1 );
-				break;
-			}
-		}
-
-	return( op );
-	}
-
-
-/*
- *	yait_put_rows:
- */
-
-static void
-yait_put_rows( uint8_t *dst, uint8_t *src, int w, int h, int flg )
-	{
-	int y, o;
-
-	y = (flg==Y_OP_EVEN) ? 0 : 1;
-
-	if( Codec == CODEC_RGB )
-		{
-		for( ; y<h; y+=2 )
-			{
-			o = y * w * 3;
-			ac_memcpy( dst+o, src+o, w*3 );
-			}
-		}
-	else
-		{
-		for( ; y<h; y+=2 )
-			{
-			/* y (luminance) */
-			o = y * w;
-			ac_memcpy( dst+o, src+o, w );
-
-			/* 2 * h/2 blocks (u and v) = h */
-			o = w*h + y * w/2;
-			ac_memcpy( dst+o, src+o, w/2 );
-			}
-		}
-	}
+enum {
+    Y_OP_ODD  = 0x10,
+    Y_OP_EVEN = 0x20,
+    Y_OP_PAT  = 0x30,
+};
+
+enum {
+    Y_OP_NOP   = 0x0,
+    Y_OP_SAVE  = 0x1,
+    Y_OP_COPY  = 0x2,
+    Y_OP_DROP  = 0x4,
+    Y_OP_DEINT = 0x8,
+};
+
+
+typedef void (*yait_cmp_hook_fn)(const uint8_t *lv, const uint8_t *cv,
+                                 int w, int h, int *ed , int *od);
+
+
+/*
+ *  Globals:
+ */
+
+FILE *Log_fp = NULL;             /* output log file */
+FILE *Ops_fp = NULL;             /* input frame ops file */
+
+uint8_t *Fbuf = NULL;            /* video frame buffer */
+int Codec;                       /* internal codec */
+int Frame_num;                   /* frame number */
+yait_cmp_hook_fn cmp_fn = NULL;  /* real compare function (saves one if()) */
+
+
+/*
+ *  Prototypes:
+ */
+
+static int yait_get_config(char* opt);
+static int yait_init(const char* opt);
+static int yait_fini(void);
+static int yait_process(vframe_list_t* ptr);
+
+static void yait_compare(vframe_list_t* ptr, const uint8_t* lv, int fn);
+static void yait_cmp_rgb(const uint8_t *lv, const uint8_t *cv,
+                         int w, int h, int *ed, int *od);
+static void yait_cmp_yuv(const uint8_t *lv, const uint8_t *cv,
+                         int w, int h, int *ed, int *od);
+static int yait_ops(vframe_list_t* ptr);
+static int yait_ops_chk(void);
+static int yait_ops_get(const char* buf, int fn, int* mode);
+static int yait_ops_decode(const char *str, int *mode);
+static void yait_put_rows(uint8_t *dst, const uint8_t *src,
+                          int w, int h, int flag);
+
+
+/*
+ *  tc_filter:
+ *      YAIT filter main entry point.  Single instance.
+ */
+int tc_filter(frame_list_t *ptr_, char *opt)
+{
+    vframe_list_t *ptr = (vframe_list_t*) ptr_;
+
+    if (ptr->tag & TC_AUDIO)
+        return TC_ERROR;
+
+    if (ptr->tag & TC_FILTER_GET_CONFIG)
+        return yait_get_config(opt);
+
+    if (ptr->tag & TC_FILTER_INIT)
+        return yait_init(opt);
+
+    if (ptr->tag & TC_FILTER_CLOSE)
+        return yait_fini();
+
+    if (ptr->tag & TC_PRE_S_PROCESS)
+        return yait_process(ptr);
+
+    return TC_ERROR;
+}
+
+
+/*
+ *  yait_get_config:
+ */
+static int yait_get_config(char *opt)
+{
+    optstr_filter_desc(opt, MOD_NAME, MOD_CAP, MOD_VERSION,
+                       MOD_AUTHOR, "VRYE", "1");
+    optstr_param(opt, "log", "Compute and write yait delta log file",
+                 "%s", "");
+    optstr_param(opt, "ops", "Read and apply yait frame operation file",
+                 "%s", "");
+
+    return TC_OK;
+}
+
+
+/*
+ *  yait_init:
+ */
+static int yait_init(const char *opt) 
+{
+    vob_t *vob = tc_get_vob();
+    char buf[256], *fn = NULL;
+    const char *p = NULL;
+    int n;
+
+    if (verbose) {
+        tc_log_info( MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP );
+        tc_log_info( MOD_NAME, "options=%s", opt );
+    }
+
+    /* FIXME: options=help handling still missing */
+
+    if (!vob) { 
+        /* can't happen */
+        tc_log_error(MOD_NAME, "cannot get VOB info.");
+        return TC_ERROR;
+    }
+
+    Frame_num = -1;
+    Codec = vob->im_v_codec;
+    if (Codec == CODEC_RGB)
+        cmp_fn = yait_cmp_rgb;
+    else
+        cmp_fn = yait_cmp_yuv;
+
+    /* log file */
+    p = optstr_lookup(opt, "log");
+    if (p != NULL) {
+        fn = Y_LOG_FN;
+        n = optstr_get(p, "log", "%[^:]", buf); // XXX
+        if (n > 0)
+            fn = buf;
+
+        Log_fp = fopen(fn, "w");
+        if (!Log_fp) {
+            tc_log_error(MOD_NAME, "cannot create log file, '%s'", buf);
+            return TC_ERROR;
+        }
+    }
+
+    /* ops file */
+    p = optstr_lookup(opt, "ops");
+    if (p != NULL) {
+        fn = Y_OPS_FN;
+        n = optstr_get(p, "ops", "%[^:]", buf); // XXX
+        if (n > 0)
+            fn = buf;
+
+        Ops_fp = fopen(fn, "r");
+        if(!Ops_fp) {
+            tc_log_error(MOD_NAME,
+                         "cannot open yait ops file, '%s'", buf);
+            return TC_ERROR;
+        }
+
+        if (!yait_ops_chk()) {
+            tc_log_error(MOD_NAME, "invalid yait ops file");
+            return TC_ERROR;
+        }
+    }
+
+    if (!Log_fp && !Ops_fp) {
+        tc_log_error(MOD_NAME,
+                     "at least one operation (log|ops) must be specified");
+        return TC_ERROR;
+    }
+
+    if (Log_fp && Ops_fp) {
+        tc_log_error(MOD_NAME,
+                     "only one operation (log|ops) may be specified");
+        return TC_ERROR;
+    }
+
+    /* try to lock import at 30 fps (needed by both modes ) */
+    vob->hard_fps_flag = TC_TRUE;
+    vob->im_frc = 4;
+    vob->fps = NTSC_VIDEO;
+
+    if (Log_fp) {
+        tc_log_info(MOD_NAME, "Generating YAIT delta log file '%s'", fn);
+        tc_log_info(MOD_NAME,
+                    "Forcing --hard_fps, -f 30,4, --export_fps 30,4");
+
+        /* try to lock export too at 30 fps */
+        vob->ex_fps = NTSC_VIDEO;
+        vob->ex_frc = 4;
+    }
+
+    if (Ops_fp) {
+        tc_log_info(MOD_NAME,
+                    "Applying YAIT frame operations file '%s'", fn);
+        tc_log_info(MOD_NAME,
+                    "Forcing --hard_fps, -f 30,4, --export_fps 24,1");
+
+        /* try to lock export at 24 fps */
+        vob->ex_fps = NTSC_FILM;
+        vob->ex_frc = 1;
+    }
+
+    Fbuf = tc_zalloc(SIZE_RGB_FRAME);
+    if  (!Fbuf) {
+        tc_log_error(MOD_NAME, "cannot allocate frame buffer");
+        return TC_ERROR;
+    }
+    return TC_OK;
+}
+
+
+/*
+ *  yait_fini:
+ */
+static int yait_fini(void)
+{
+    if (Log_fp != NULL) {
+        fclose(Log_fp);
+        Log_fp = NULL;
+    }
+    if (Ops_fp != NULL) {
+        fclose(Ops_fp);
+        Ops_fp = NULL;
+    }
+    if (Fbuf != NULL) {
+        tc_free(Fbuf);
+        Fbuf = NULL;
+    }
+
+    return TC_OK;
+}
+
+
+/*
+ *  yait_process:
+ */
+static int yait_process(vframe_list_t *ptr)
+{
+    if (Frame_num == -1) {
+        /* first run */
+        Frame_num = ptr->id;
+        ac_memcpy(Fbuf, ptr->video_buf, ptr->video_size);
+    }
+
+    if (ptr->id != Frame_num) {
+        tc_log_error( MOD_NAME, "inconsistent frame numbers" );
+        yait_fini();
+        return  TC_ERROR;
+    }
+
+    if (Log_fp != NULL) {
+        yait_compare(ptr, Fbuf, Frame_num);
+        ac_memcpy(Fbuf, ptr->video_buf, ptr->video_size);
+    }
+
+    if (Ops_fp != NULL) {
+        if (!yait_ops(ptr)) {
+            yait_fini();
+            return TC_ERROR;
+        }
+    }
+
+    Frame_num++;
+    return TC_OK;
+}
+
+
+/*
+ *  yait_compare:
+ */
+static void yait_compare(vframe_list_t *ptr, const uint8_t *lv, int fn)
+{
+    const uint8_t *cv = ptr->video_buf;      // XXX: checking?
+    int w = ptr->v_width, h = ptr->v_height; // XXX: checking?
+    int ed, od;
+
+    cmp_fn(lv, cv, w, h, &ed, &od);
+    fprintf(Log_fp, "%d: e: %d, o: %d\n", fn, ed, od); // XXX: write check?
+
+    /* FIXME BUG: until the blocked tcdecode pipe problem is fixed... */
+    if (!(fn % 5))
+        fflush(Log_fp); // XXX: write check?
+}
+
+
+/*
+ *  yait_cmp_rgb:
+ */
+static void yait_cmp_rgb(const uint8_t *lv, const uint8_t *cv,
+                         int w, int h, int *ed, int *od)
+{
+    const uint8_t *lp = NULL, *cp = NULL;
+    int x, y, p;
+    int e, o; /* we really need those two? */
+
+    /* even row delta */
+    e = 0;
+    for (y = 0; y < h; y += 2) {
+        p = y * w * 3;
+        lp = lv + p;
+        cp = cv + p;
+        for (x = 0; x < w; x++) {
+            e += abs(*lp++ - *cp++);
+            e += abs(*lp++ - *cp++);
+            e += abs(*lp++ - *cp++);
+        }
+    }
+
+    /* odd row delta */
+    o = 0;
+    for (y = 1; y < h; y += 2) { 
+        p = y * w * 3;
+        lp = lv + p;
+        cp = cv + p;
+        for (x = 0; x < w; x++) {
+            o += abs(*lp++ - *cp++);
+            o += abs(*lp++ - *cp++);
+            o += abs(*lp++ - *cp++);
+        }
+    }
+
+    *ed = e;
+    *od = o;
+}
+
+
+/*
+ *  yait_mp_yuv:
+ */
+static void yait_cmp_yuv(const uint8_t *lv, const uint8_t *cv,
+                         int w, int h, int *ed, int *od)
+{
+    const uint8_t *lp = NULL, *cp = NULL;
+    int x, y, p;
+    int e, o; /* we really need those two? */
+
+    /* even row delta */
+    e = 0;
+    for (y = 0; y < h; y += 2) {
+        /* y */
+        p = y * w;
+        lp = lv + p;
+        cp = cv + p;
+        for (x = 0; x < w; x++)
+            e += abs(*lp++ - *cp++);
+
+        /* uv */
+        p = w * h + y * w/2;
+        lp = lv + p;
+        cp = cv + p;
+        for (x = 0; x < w/2; x++)
+            e += abs(*lp++ - *cp++);
+    }
+
+    /* odd row delta */
+    o = 0;
+    for (y = 1; y < h; y += 2) {
+        /* y */
+        p = y * w;
+        lp = lv + p;
+        cp = cv + p;
+        for (x = 0; x < w; x++)
+            o += abs(*lp++ - *cp++);
+
+        /* uv */
+        p = w * h + y * w/2;
+        lp = lv + p;
+        cp = cv + p;
+        for(x = 0; x < w/2; x++)
+            o += abs(*lp++ - *cp++);
+    }
+
+    *ed = e;
+    *od = o;
+}
+
+
+/*
+ *  yait_ops:
+ */
+static int yait_ops(vframe_list_t *ptr)
+{
+    char buf[TC_BUF_LINE];
+    int mode, op;
+    uint8_t *v = ptr->video_buf;
+    int w = ptr->v_width, h = ptr->v_height;
+
+    fgets(buf, TC_BUF_LINE, Ops_fp);
+    op = yait_ops_get(buf, Frame_num, &mode);
+
+    if (op < 0)
+        return TC_FALSE;
+
+    if (op & Y_OP_SAVE)
+        yait_put_rows(Fbuf, v, w, h, op & Y_OP_PAT);
+
+    if (op & Y_OP_COPY)
+        yait_put_rows(v, Fbuf, w, h, op & Y_OP_PAT);
+
+    if (op & Y_OP_DROP)
+        ptr->attributes |= TC_FRAME_IS_SKIPPED;
+
+    if (op & Y_OP_DEINT) {
+        ptr->attributes |= TC_FRAME_IS_INTERLACED;
+        ptr->deinter_flag = mode;
+    }
+
+    return TC_TRUE;
+}
+
+
+/*
+ *  yait_ops_chk:
+ */
+static int yait_ops_chk(void)
+{
+    char buf[TC_BUF_LINE], *p = NULL;
+    int fn, op;
+
+    fscanf(Ops_fp, "%d:", &fn);
+    rewind(Ops_fp);
+    for (;;) {
+        p = fgets(buf, TC_BUF_LINE, Ops_fp);
+        if (!p)
+            break;
+
+        op = yait_ops_get(buf, fn, NULL);
+        if (op < 0)
+            return TC_FALSE;
+        fn++;
+    }
+
+    rewind(Ops_fp);
+    return TC_TRUE;
+}
+
+
+/*
+ *  yait_ops_get:
+ */
+static int yait_ops_get(const char *buf, int fn, int *mode)
+{
+    char str[TC_BUF_LINE];
+    int op, f = -1, n;
+
+    str[0] = 0; // XXX
+
+    n = sscanf(buf, "%d: %s\n", &f, str);
+    if (n < 1) {
+        if (feof(Ops_fp))
+            tc_log_error(MOD_NAME, "truncated yait ops file, frame: %d", fn);
+        else
+            tc_log_error(MOD_NAME, "invalid yait ops format, frame: %d", fn);
+        return -1;
+    }
+
+    if (f != fn) {
+        tc_log_error(MOD_NAME,
+                     "invalid yait ops frame number, frame: %d", fn);
+        return -1;
+    }
+
+    op = yait_ops_decode(str, mode);
+    if (op < 0) {
+        tc_log_error(MOD_NAME, "invalid yait ops code, frame: %d", fn);
+        return -1;
+    }
+
+    return op;
+}
+
+
+/*
+ *  yait_ops_decode:
+ */
+static int yait_ops_decode(const char *str, int *mode)
+{
+    int op = 0, c;
+
+    while (*str) {
+        c = *str++;
+        if (c >= '1' && c <= '5') {
+            op |= Y_OP_DEINT;
+            if (mode)
+                *mode = c - '0';
+            continue;
+        }
+
+        switch (c) {
+          case 'o':
+            op |= Y_OP_ODD;
+            break;
+          case 'e':
+            op |= Y_OP_EVEN;
+            break;
+          case 's':
+            op |= Y_OP_SAVE;
+            break;
+          case 'c':
+            op |= Y_OP_COPY;
+            break;
+          case 'd':
+            op |= Y_OP_DROP;
+            break;
+          default:
+            return -1;
+        }
+    }
+
+    return op;
+}
+
+
+/*
+ *  yait_put_rows:
+ */
+static void yait_put_rows(uint8_t *dst, const uint8_t *src, int w, int h, int flag)
+{
+    int y = ((flag == Y_OP_EVEN) ?0 :1), o;
+
+    if (Codec == CODEC_RGB) {
+        for(; y < h; y += 2) {
+            o = y * w * 3;
+            ac_memcpy(dst + o, src + o, w * 3);
+        }
+    } else {
+        for(; y < h; y += 2) {
+            /* y (luminance) */
+            o = y * w;
+            ac_memcpy(dst + o, src + o, w);
+
+            /* 2 * h/2 blocks (u and v) = h */
+            o = w * h + y * w/2;
+            ac_memcpy(dst + o, src + o, w/2);
+        }
+    }
+}
+
+
+/*************************************************************************/
+
+/*
+ * Local variables:
+ *   c-file-style: "stroustrup"
+ *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
+ *   indent-tabs-mode: nil
+ * End:
+ *
+ * vim: expandtab shiftwidth=4:
+ */

Reply via email to