changeset 21467:dd765bcd83aa

added generalized teleciner by Donald Graft
author nicodvb
date Mon, 04 Dec 2006 00:02:15 +0000
parents abfc5854e80a
children f6554710e21b
files libmpdemux/muxer_mpeg.c
diffstat 1 files changed, 61 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/muxer_mpeg.c	Sun Dec 03 21:43:57 2006 +0000
+++ b/libmpdemux/muxer_mpeg.c	Mon Dec 04 00:02:15 2006 +0000
@@ -58,6 +58,8 @@
 static char ftypes[] = {'?', 'I', 'P', 'B'}; 
 #define FTYPE(x) (ftypes[(x)])
 
+#define MAX_PATTERN_LENGTH 2000000
+static unsigned char bff_mask[MAX_PATTERN_LENGTH];	//2 million frames are enough
 
 static const char *framerates[] = {
 	"unchanged", "23.976", "24", "25", "29.97", "30", "50", "59.94", "60"
@@ -81,6 +83,8 @@
 static int conf_vbuf_size = 0;
 static int conf_drop = 0;
 static int conf_telecine = 0;
+static float conf_telecine_src = 0;
+static float conf_telecine_dest = 0;
 
 enum FRAME_TYPE {
 	I_FRAME = 1,
@@ -165,6 +169,7 @@
 	int max_tr;
 	uint8_t id, is_mpeg12, telecine;
 	uint64_t vframes;
+	uint64_t display_frame;
 	uint8_t trf;
 	mp_mpeg_header_t picture;
 	int max_buffer_size;
@@ -180,6 +185,7 @@
 
 #define PULLDOWN32 1
 #define TELECINE_FILM2PAL 2
+#define TELECINE_DGPULLDOWN 3
 
 m_option_t mpegopts_conf[] = {
 	{"format", &(conf_mux), CONF_TYPE_STRING, 0, 0 ,0, NULL},
@@ -201,6 +207,8 @@
 	{"tsaf", &conf_ts_allframes, CONF_TYPE_FLAG, 0, 0, 1, NULL},
 	{"telecine", &conf_telecine, CONF_TYPE_FLAG, 0, 0, PULLDOWN32, NULL},
 	{"film2pal", &conf_telecine, CONF_TYPE_FLAG, 0, 0, TELECINE_FILM2PAL, NULL},
+	{"tele_src", &(conf_telecine_src), CONF_TYPE_FLOAT, 0, 0, 0, NULL},
+	{"tele_dest", &(conf_telecine_dest), CONF_TYPE_FLOAT, 0, 0, 0, NULL},
 	{NULL, NULL, 0, 0, 0, 0, NULL}
 };
 
@@ -1559,7 +1567,7 @@
 }
 
 
-static int soft_telecine(muxer_headers_t *vpriv, uint8_t *fps_ptr, uint8_t *se_ptr, uint8_t *pce_ptr, int n)
+static int soft_telecine(muxer_priv_t *priv, muxer_headers_t *vpriv, uint8_t *fps_ptr, uint8_t *se_ptr, uint8_t *pce_ptr, int n)
 {
 	uint8_t fps, tff, rff; 
 	int period; 
@@ -1571,7 +1579,7 @@
 	if(fps_ptr != NULL)
 	{
 		fps = *fps_ptr & 0x0f;
-		if((!fps) || (fps > FRAMERATE_24))
+		if(((!fps) || (fps > FRAMERATE_24)) && vpriv->telecine != TELECINE_DGPULLDOWN)
 		{
 			mp_msg(MSGT_MUXER, MSGL_ERR, "\nERROR! FRAMERATE IS INVALID: %d, disabling telecining\n", (int) fps);
 			vpriv->telecine = 0;
@@ -1582,6 +1590,11 @@
 			*fps_ptr = (*fps_ptr & 0xf0) | FRAMERATE_25;
 			vpriv->nom_delta_pts = parse_fps(25.0);
 		}
+		else if(vpriv->telecine == TELECINE_DGPULLDOWN)
+		{
+			*fps_ptr = (*fps_ptr & 0xf0) | priv->vframerate;
+			vpriv->nom_delta_pts = parse_fps(conf_vframerate);
+		}
 		else
 		{
 			*fps_ptr = (*fps_ptr & 0xf0) | (fps + 3);
@@ -1655,6 +1668,10 @@
 		
 		pce_ptr[3] = (pce_ptr[3] & 0xfd) | rff;
 	}
+	else if(vpriv->telecine == TELECINE_DGPULLDOWN)
+	{
+		pce_ptr[3] = (pce_ptr[3] & 0xfd) | bff_mask[vpriv->display_frame % MAX_PATTERN_LENGTH];
+	}
 	else
 	{
 		tff = (vpriv->trf & 0x2) ? 0x80 : 0;
@@ -1664,7 +1681,7 @@
 	pce_ptr[4] |= 0x80;	//sets progressive frame
 	mp_msg(MSGT_MUXER, MSGL_DBG2, "\nTRF: %d, TFF: %d, RFF: %d, n: %d\n", vpriv->trf, tff >> 7, rff >> 1, n);
 	
-	
+	vpriv->display_frame += n;
 	if(! vpriv->vframes)
 		mp_msg(MSGT_MUXER, MSGL_INFO, "\nENABLED SOFT TELECINING, FPS=%s, INITIAL PATTERN IS TFF:%d, RFF:%d\n", 
 		framerates[(vpriv->telecine == TELECINE_FILM2PAL) ? FRAMERATE_25 : fps+3], tff >> 7, rff >> 1);
@@ -1804,7 +1821,7 @@
 				{
 					pce_ptr = &(s->buffer[ptr+4]);
 					if(spriv->telecine)
-						soft_telecine(spriv, fps_ptr, se_ptr, pce_ptr, frames_diff);
+						soft_telecine(priv, spriv, fps_ptr, se_ptr, pce_ptr, frames_diff);
 					spriv->picture.display_time = 100;
 					mp_header_process_extension(&(spriv->picture), &(s->buffer[ptr+4]));
 					if(spriv->picture.display_time >= 50 && spriv->picture.display_time <= 300) 
@@ -2525,6 +2542,29 @@
 		priv->sys_info.cnt = 0;
 }
 
+/* excerpt from DGPulldown Copyright (C) 2005-2006, Donald Graft */
+static void generate_flags(int source, int target)
+{
+	unsigned int i, trfp;
+	uint64_t dfl,tfl;
+	
+	dfl = (target - source) << 1;
+	tfl = source >> 1;
+	
+	trfp = 0;
+	for(i = 0; i < MAX_PATTERN_LENGTH; i++)
+	{
+		tfl += dfl;
+		if(tfl >= source)
+		{
+			tfl -= source;
+			bff_mask[i] = trfp + 1;
+			trfp ^= 2;
+		}
+		else
+			bff_mask[i] = trfp;
+	}
+}
 
 int muxer_init_muxer_mpeg(muxer_t *muxer){
   muxer_priv_t *priv;
@@ -2624,6 +2664,23 @@
   	mp_msg(MSGT_MUXER, MSGL_ERR, "ERROR: options 'telecine' and 'vframerate' are mutually exclusive, vframerate disabled\n");
 	conf_vframerate = 0;
   }
+
+  if(conf_telecine_src>0 && conf_telecine_dest>0 && conf_telecine_src < conf_telecine_dest)
+  {
+	int snum, sden, tnum, tden, sfps, tfps;
+	
+	sfps = (int) (conf_telecine_src * 1001 + 0.5);
+	tfps = (int) (conf_telecine_dest * 1001 + 0.5);
+	if(sfps % 2 || tfps % 2)
+	{
+		sfps *= 2;
+		tfps *= 2;
+	}
+	
+	generate_flags(sfps, tfps);
+	conf_telecine = TELECINE_DGPULLDOWN;
+	conf_vframerate = conf_telecine_dest;
+  }
   
   if(conf_vframerate)
   {