Esempio n. 1
0
static int deshake_init(TCModuleInstance *self, uint32_t features)
{
  DeshakeData* sd = NULL;
  TC_MODULE_SELF_CHECK(self, "init");
  TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);

  sd = tc_zalloc(sizeof(DeshakeData)); // allocation with zero values
  if (!sd) {
    if (verbose > TC_INFO)
      tc_log_error(MOD_NAME, "init: out of memory!");
    return TC_ERROR;
  }

  sd->vob = tc_get_vob();
  if (!sd->vob)
    return TC_ERROR;

  /**** Initialise private data structure */

  self->userdata = sd;
  if (verbose & TC_INFO){
    tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
  }

  return TC_OK;
}
static int doublefps_init(TCModuleInstance *self, uint32_t features)
{
    DfpsPrivateData *pd;
    vob_t *vob = tc_get_vob();

    TC_MODULE_SELF_CHECK(self, "init");
    TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);

    self->userdata = pd = tc_malloc(sizeof(DfpsPrivateData));
    if (!pd) {
        tc_log_error(MOD_NAME, "init: out of memory!");
        return TC_ERROR;
    }
    pd->topfirst = -1;
    pd->fullheight = 0;
    pd->have_first_frame = pd->saved_width = pd->saved_height = 0;

    /* FIXME: we need a proper way for filters to tell the core that
     * they're changing the export parameters */
    if (!(vob->export_attributes
          & (TC_EXPORT_ATTRIBUTE_FPS | TC_EXPORT_ATTRIBUTE_FRC))
    ) {
        vob->ex_fps *= 2;
        switch (vob->ex_frc) {
            case  3: vob->ex_frc =  6; break;
            case  4: vob->ex_frc =  7; break;
            case  5: vob->ex_frc =  8; break;
            case 10: vob->ex_frc = 11; break;
            case 12: vob->ex_frc =  2; break;
            case 13: vob->ex_frc =  5; break;
            default: vob->ex_frc =  0; break;
        }
    }
    if (verbose) {
        tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
    }
    return TC_OK;
}
Esempio n. 3
0
static int query_new_module(TCModule module,
                            const char *modcfg, const char *modarg)
{
    const char *answer = NULL;
    int status = STATUS_OK;

    if (verbose >= TC_DEBUG) {
        tc_log_info(EXE, "using new module system");
    }
    if (strlen(modcfg) > 0) {
        TCModuleExtraData *xdata[] = { NULL, NULL };
        int ret = tc_module_configure(module, modcfg, tc_get_vob(), xdata);
        if (ret == TC_OK) {
            status = STATUS_OK;
        } else {
            status = STATUS_MODULE_FAILED;
            tc_log_error(EXE, "configure returned error");
        }
        tc_module_stop(module);
    } else {
        if (verbose >= TC_INFO) {
            /* overview and options */
            tc_module_inspect(module, "help", &answer);
            puts(answer);
            /* module capabilities */
            tc_module_show_info(module, verbose);
        }
        if (strlen(modarg) > 0) {
            tc_log_info(EXE, "informations about '%s' for "
                             "module:", modarg);
            tc_module_inspect(module, modarg, &answer);
            puts(answer);
        }
        status = STATUS_OK;
    }

    return status;
}
int tc_filter(frame_list_t *ptr_, char *options){
	vframe_list_t *		ptr = (vframe_list_t *)ptr_;
	int 			frame_slot = 0;
	static 			vob_t *vob=NULL;
	static int		slots[TC_FRAME_THREADS_MAX];

  if(ptr->tag & TC_FILTER_GET_CONFIG) {

	optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Julien Tierny", "VRYMO", "1");
    optstr_param (options, "font", "Valid PSF font file (provided with the `aart` package)", "%s", "default8x9.psf");
	optstr_param (options, "pallete", "Valid pallete file (provided with the `aart` package)", "%s", "colors.pal");
	optstr_param(options, "threads", "Use multiple-threaded routine for picture rendering", "%d", "0", "1", "oo");

	/* Boolean parameter */
	optstr_param(options, "buffer", "Use `aart` internal buffer for output", "", "-1");

	return 0;
  }

  //----------------------------------
  //
  // filter init
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_INIT) {

    if((vob = tc_get_vob())==NULL)
		return(-1);

	/* aart sanity check */
	if (tc_test_program("aart") !=0 )
		return -1;

	/* Now, let's handle the options ... */
	if((parameters = tc_malloc (sizeof(parameter_struct))) == NULL){
		tc_log_error(MOD_NAME, "Out of memory !!!");
		return -1;
	}

	/* Filter default options */
	if (verbose & TC_DEBUG)
		tc_log_info(MOD_NAME, "Preparing default options.");
	strncpy(parameters->aart_font, "default8x9.psf", strlen("default8x9.psf"));
	if (verbose & TC_DEBUG)
		tc_log_info(MOD_NAME, "Default options correctly formated.");
	strncpy(parameters->aart_pallete, "colors.pal", strlen("colors.pal"));
	parameters->aart_threads 		= 1;
	parameters->aart_buffer 		= -1;
	parameters->tcvhandle			= 0;

	if (options){
		/* Get filter options via transcode core */
		if (verbose & TC_DEBUG)
			tc_log_info(MOD_NAME, "Merging options from transcode.");
		optstr_get(options, "font",			"%s",		parameters->aart_font);
		clean_parameter(parameters->aart_font);
		optstr_get(options, "pallete",		"%s",		parameters->aart_pallete);
		clean_parameter(parameters->aart_pallete);
		optstr_get(options, "threads",   	"%d",		&parameters->aart_threads);

		if (optstr_lookup(options, "buffer") != NULL)
			parameters->aart_buffer=1;
		if (optstr_lookup(options, "help") != NULL)
			help_optstr();
		if (verbose & TC_DEBUG)
			tc_log_info(MOD_NAME, "Options correctly merged.");
	}

	if (vob->im_v_codec == CODEC_YUV){
		if (!(parameters->tcvhandle = tcv_init())) {
			tc_log_error(MOD_NAME, "Error at image conversion initialization.");
			return(-1);
		}
	}

	/* Init thread slots (multithread support)*/
	init_slots(slots);

	if(verbose)
		tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

    return(0);
  }

  //----------------------------------
  //
  // filter close
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_CLOSE) {

  	/*
	 * TODO :
	 * Provide a `aart` kill routine in case of cancel.
	 * For the moment, transcode waits for the `aart`
	 * process to finish before exiting.
	 */

	tcv_free(parameters->tcvhandle);

	/* Let's free the parameter structure */
	free(parameters);
	parameters = NULL;

    return(0);
  }

  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------

	if(ptr->tag & TC_POST_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

		frame_slot = find_empty_slot(ptr->id, slots);
		switch(vob->im_v_codec){
			case CODEC_RGB:
				return aart_render(ptr->video_buf, ptr->v_width, ptr->v_height, frame_slot, parameters->aart_font, parameters->aart_pallete, parameters->aart_threads, parameters->aart_buffer);
				break;

			case CODEC_YUV:

				if (!tcv_convert(parameters->tcvhandle, ptr->video_buf, ptr->video_buf, ptr->v_width, ptr->v_height, IMG_YUV_DEFAULT, IMG_RGB24)){
					tc_log_error(MOD_NAME, "cannot convert YUV stream to RGB format !");
					return -1;
				}

				if (aart_render(ptr->video_buf, ptr->v_width, ptr->v_height, frame_slot, parameters->aart_font, parameters->aart_pallete, parameters->aart_threads, parameters->aart_buffer) == -1){return -1;}
				if (!tcv_convert(parameters->tcvhandle, ptr->video_buf, ptr->video_buf, ptr->v_width, ptr->v_height, IMG_RGB24, IMG_YUV_DEFAULT)){
					tc_log_error(MOD_NAME, "cannot convert RGB stream to YUV format !");
					return -1;
				}
				break;

			default:
				tc_log_error(MOD_NAME, "Internal video codec is not supported.");
				return -1;
		}
		free_slot(ptr->id, slots);
	}
	return(0);
}
int tc_filter(frame_list_t *ptr_, char *options)
{
  aframe_list_t *ptr = (aframe_list_t *)ptr_;
  int n;
  double sum;

  short *s;

  vob_t *vob=NULL;

  if(ptr->tag & TC_FILTER_GET_CONFIG) {
      optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Thomas Oestreich", "AE", "1");
      optstr_param (options, "level", "The audio must be under this level to be skipped", "%d", "10", "0", "255");
      optstr_param (options, "range", "Number of samples over level will be keyframes", "%d", "25", "0", "255");
      return 0;
  }

  //----------------------------------
  //
  // filter init
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_INIT) {

    if((vob = tc_get_vob())==NULL) return(-1);

    // filter init ok.

    if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

    if(verbose) tc_log_info(MOD_NAME, "options=%s", options);

    if(options!=NULL) {
	if (!is_optstr(options)) {
	    n=sscanf(options,"%d:%d", &level, &range);
	} else {
	    optstr_get (options, "level", "%d", &level);
	    optstr_get (options, "range", "%d", &range);
	}
    }

    range_ctr=range;

    return(0);
  }

  //----------------------------------
  //
  // filter close
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_CLOSE) {

    return(0);
  }

  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------

  if(verbose & TC_STATS)
    tc_log_info(MOD_NAME, "%s/%s %s %s",
                vob->mod_path, MOD_NAME, MOD_VERSION, MOD_CAP);

  // tag variable indicates, if we are called before
  // transcodes internal video/audo frame processing routines
  // or after and determines video/audio context

  if(ptr->tag & TC_PRE_S_PROCESS && ptr->tag & TC_AUDIO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

    total += (uint64_t) ptr->audio_size;

    s=(short *) ptr->audio_buf;

    sum=0;

    for(n=0; n<ptr->audio_size>>1; ++n) {
      sum+=(double) ((int)(*s) * (int)(*s));
      s++;
    }

    if(ptr->audio_size>0) sum = sqrt(sum)/(ptr->audio_size>>1);

    sum *= 1000;

    if(verbose & TC_DEBUG) tc_log_info(MOD_NAME, "frame=%d sum=%f", ptr->id, sum);

    if(sum<level) {

      if(range_ctr == range) {

	ptr->attributes |= TC_FRAME_IS_SKIPPED;
	skip_mode=1;
      } else ++range_ctr;

    } else {

      if(skip_mode) ptr->attributes |= TC_FRAME_IS_KEYFRAME;
      skip_mode = 0;
      range_ctr = 0;
    }
  }
int tc_filter(frame_list_t *ptr_, char *options)
{
	vframe_list_t *ptr = (vframe_list_t *)ptr_;
	int instance = ptr->filter_id;
	Image *pattern, *resized, *orig = 0;
	ImageInfo *image_info;

	PixelPacket *pixel_packet;
	pixelsMask *pixel_last;
	ExceptionInfo exception_info;

	if(ptr->tag & TC_FILTER_GET_CONFIG) {
		char buf[128];
		optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION,
				   MOD_AUTHOR, "VRYMO", "1");

		tc_snprintf(buf, 128, "/dev/null");
		optstr_param(options, "pattern", "Pattern image file path", "%s", buf);
		tc_snprintf(buf, 128, "results.dat");
		optstr_param(options, "results", "Results file path" , "%s", buf);
		tc_snprintf(buf, 128, "%f", compare[instance]->delta);
		optstr_param(options, "delta", "Delta error", "%f",buf,"0.0", "100.0");
		return 0;
	}

	//----------------------------------
	//
	// filter init
	//
	//----------------------------------


	if(ptr->tag & TC_FILTER_INIT)
	{

		unsigned int t,r,index;
		pixelsMask *temp;

		compare[instance] = tc_malloc(sizeof(compareData));
		if(compare[instance] == NULL)
			return (-1);

		compare[instance]->vob = tc_get_vob();
		if(compare[instance]->vob ==NULL)
            return(-1);

		compare[instance]->delta=DELTA_COLOR;
		compare[instance]->step=1;
		compare[instance]->width=0;
		compare[instance]->height=0;
		compare[instance]->frames = 0;
		compare[instance]->pixel_mask = NULL;
		pixel_last = NULL;

		compare[instance]->width = compare[instance]->vob->ex_v_width;
		compare[instance]->height = compare[instance]->vob->ex_v_height;

		if (options != NULL) {
			char pattern_name[PATH_MAX];
			char results_name[PATH_MAX];
			memset(pattern_name,0,PATH_MAX);
			memset(results_name,0,PATH_MAX);

			if(verbose) tc_log_info(MOD_NAME, "options=%s", options);

			optstr_get(options, "pattern", "%[^:]", pattern_name);
			optstr_get(options, "results", "%[^:]", results_name);
			optstr_get(options, "delta", "%f", &compare[instance]->delta);

			if (verbose > 1) {
				tc_log_info(MOD_NAME, "Compare Image Settings:");
				tc_log_info(MOD_NAME, "      pattern = %s\n", pattern_name);
				tc_log_info(MOD_NAME, "      results = %s\n", results_name);
				tc_log_info(MOD_NAME, "        delta = %f\n", compare[instance]->delta);
			}

			if (strlen(results_name) == 0) {
				// Ponemos el nombre del fichero al original con extension dat
				strlcpy(results_name, "/tmp/compare.dat", sizeof(results_name));

			}
			if (!(compare[instance]->results = fopen(results_name, "w")))
			{
				tc_log_perror(MOD_NAME, "could not open file for writing");
			}

			InitializeMagick("");
			if (verbose > 1)
                tc_log_info(MOD_NAME, "Magick Initialized successfully");

			GetExceptionInfo(&exception_info);
			image_info = CloneImageInfo ((ImageInfo *) NULL);
			strlcpy(image_info->filename, pattern_name, MaxTextExtent);
			if (verbose > 1)
			     tc_log_info(MOD_NAME, "Trying to open image");
			orig = ReadImage(image_info,
					 &exception_info);

			if (orig == (Image *) NULL) {
				MagickWarning(exception_info.severity,
					      exception_info.reason,
					      exception_info.description);
				strlcpy(pattern_name, "/dev/null", sizeof(pattern_name));
			}else{
			       if (verbose > 1)
			       		tc_log_info(MOD_NAME, "Image loaded successfully");
			     }
		}

		else{
			tc_log_perror(MOD_NAME, "Not image provided");
		}

		if (options != NULL)
			if (optstr_lookup (options, "help")) {
				help_optstr();
			}


		fprintf(compare[instance]->results,"#fps:%f\n",compare[instance]->vob->fps);

		if (orig != NULL){
                        // Flip and resize
			if (compare[instance]->vob->im_v_codec == CODEC_YUV)
				TransformRGBImage(orig,YCbCrColorspace);
			if (verbose > 1) tc_log_info(MOD_NAME, "Resizing the Image");
			resized = ResizeImage(orig,
					      compare[instance]->width,
					      compare[instance]->height,
					      GaussianFilter,
					      1,
					      &exception_info);
			if (verbose > 1)
				tc_log_info(MOD_NAME, "Flipping the Image");
			pattern = FlipImage(resized, &exception_info);
			if (pattern == (Image *) NULL) {
				MagickError (exception_info.severity,
					     exception_info.reason,
					     exception_info.description);
			}

			// Filling the matrix with the pixels values not
			// alpha

			if (verbose > 1) tc_log_info(MOD_NAME, "GetImagePixels");
			pixel_packet = GetImagePixels(pattern,0,0,
						      pattern->columns,
						      pattern->rows);

			if (verbose > 1) tc_log_info(MOD_NAME, "Filling the Image matrix");
			for (t = 0; t < pattern->rows; t++)
				for (r = 0; r < pattern->columns; r++){
					index = t*pattern->columns + r;
					if (pixel_packet[index].opacity == 0){
						temp=tc_malloc(sizeof(struct pixelsMask));
						temp->row=t;
						temp->col=r;
						temp->r = (uint8_t)ScaleQuantumToChar(pixel_packet[index].red);
						temp->g = (uint8_t)ScaleQuantumToChar(pixel_packet[index].green);
						temp->b = (uint8_t)ScaleQuantumToChar(pixel_packet[index].blue);
						temp->next=NULL;

						if (pixel_last == NULL){
							pixel_last = temp;
							compare[instance]->pixel_mask = temp;
						}else{
							pixel_last->next = temp;
							pixel_last = temp;
						}
					}
				}

			if (verbose)
                tc_log_info(MOD_NAME, "%s %s",
					    MOD_VERSION, MOD_CAP);
		}
		return(0);
	}


	//----------------------------------
	//
	// filter close
	//
	//----------------------------------


	if(ptr->tag & TC_FILTER_CLOSE) {

		if (compare[instance] != NULL) {
			fclose(compare[instance]->results);
			free(compare[instance]);
		}
		DestroyMagick();
		compare[instance]=NULL;

		return(0);

	} /* filter close */

	//----------------------------------
	//
	// filter frame routine
	//
	//----------------------------------


	// tag variable indicates, if we are called before
	// transcodes internal video/audio frame processing routines
	// or after and determines video/audio context

	if((ptr->tag & TC_POST_M_PROCESS) && (ptr->tag & TC_VIDEO))  {
		// For now I only support RGB color space
		pixelsMask *item = NULL;
		double sr,sg,sb;
		double avg_dr,avg_dg,avg_db;

		if (compare[instance]->vob->im_v_codec == CODEC_RGB){

			int r,g,b,c;
			double width_long;

			if (compare[instance]->pixel_mask != NULL)
			{
				item = compare[instance]->pixel_mask;
				c = 0;

				sr = 0.0;
				sg = 0.0;
				sb = 0.0;

				width_long = compare[instance]->width*3;
				while(item){
					r = item->row*width_long + item->col*3;
					g = item->row*width_long
						+ item->col*3 + 1;
					b = item->row*width_long
						+ item->col*3 + 2;

				// diff between points
				// Interchange RGB values if necesary
					sr = sr + (double)abs((unsigned char)ptr->video_buf[r] - item->r);
					sg = sg + (double)abs((unsigned char)ptr->video_buf[g] - item->g);
					sb = sb + (double)abs((unsigned char)ptr->video_buf[b] - item->b);
					item = item->next;
					c++;
				}

				avg_dr = sr/(double)c;
				avg_dg = sg/(double)c;
				avg_db = sb/(double)c;

				if ((avg_dr < compare[instance]->delta) && (avg_dg < compare[instance]->delta) && (avg_db < compare[instance]->delta))
					fprintf(compare[instance]->results,"1");
				else
					fprintf(compare[instance]->results,"n");
				fflush(compare[instance]->results);
			}
			compare[instance]->frames++;
			return(0);
		}else{

                        // The colospace is YUV

                        // FIXME: Doesn't works, I need to code all this part
			// again

			int Y,Cr,Cb,c;

			if (compare[instance]->pixel_mask != NULL)
			{
				item = compare[instance]->pixel_mask;
				c = 0;

				sr = 0.0;
				sg = 0.0;
				sb = 0.0;

				while(item){
					Y  = item->row*compare[instance]->width + item->col;
					Cb = compare[instance]->height*compare[instance]->width
						+ (int)((item->row*compare[instance]->width + item->col)/4);
					Cr = compare[instance]->height*compare[instance]->width
						+ (int)((compare[instance]->height*compare[instance]->width)/4)
						+ (int)((item->row*compare[instance]->width + item->col)/4);

				        // diff between points
				        // Interchange RGB values if necesary

					sr = sr + (double)abs((unsigned char)ptr->video_buf[Y] - item->r);
					sg = sg + (double)abs((unsigned char)ptr->video_buf[Cb] - item->g);
					sb = sb + (double)abs((unsigned char)ptr->video_buf[Cr] - item->b);
					item = item->next;
					c++;
				}

				avg_dr = sr/(double)c;
				avg_dg = sg/(double)c;
				avg_db = sb/(double)c;

				if ((avg_dr < compare[instance]->delta) && (avg_dg < compare[instance]->delta) && (avg_db < compare[instance]->delta))
					fprintf(compare[instance]->results,"1");
				else
					fprintf(compare[instance]->results,"n");
			}
			compare[instance]->frames++;
			return(0);

		}
	}

	return(0);
}
static int
parse_options(char *options, int *pre, double *infps, double *outfps)
{
	char	*p, *pbase, *q, *r;
	size_t	len;
	vob_t	*vob;
	int	default_pre, i;

	/* defaults from -f and --export_fps */
	vob = tc_get_vob();
	if (!vob) return -1;
	*infps = vob->fps;
	*outfps = vob->ex_fps;
	default_pre = 1;

	if (!options || !*options) return 0;
	if (!strcmp(options, "help")) {
		tc_log_info(MOD_NAME, "(%s) help\n"
"This filter converts the video frame rate, by repeating or dropping frames.\n"
"options: <input fps>:<output fps>\n"
"example: -J fps=25:29.97 will convert from PAL to NTSC\n"
"In addition to the frame rate options, you may also specify pre or post.\n"
"If no rate options are given, defaults or -f/--export_fps/--export_frc will\n"
"be used.\n"
"If no pre or post options are given, decreasing rates will preprocess and\n"
"increasing rates will postprocess.\n"
			    , MOD_CAP);
		return -1;
	}

	len = strlen(options);
	p = pbase = malloc(len + 1);
	ac_memcpy(p, options, len);
	p[len] = '\0';

	i = 0;
	do {
		q = memchr(p, ':', len);
		if (q) *q++ = '\0';
		if (!strcmp(p, "pre")) {
			*pre = 1;
			default_pre = 0;
		} else if (!strncmp(p, "pre=", 4) && *(p + 4)) {
			*pre = strtol(p + 4, &r, 0);
			if (r == p) return -1;
			default_pre = 0;
		} else if (!strcmp(p, "post")) {
			*pre = 0;
			default_pre = 0;
		} else if (!strncmp(p, "post=", 5) && *(p + 5)) {
			*pre = !strtol(p + 4, &r, 0);
			if (r == p) return -1;
			default_pre = 0;
		} else {
			if (i == 0) {
				*infps = strtod(p, &r);
				if (r == p) return -1;
			} else if (i == 1) {
				*outfps = strtod(p, &r);
				if (r == p) return -1;
			} else return -1;
			i++;
		}
	} while (q && (p = q));

	free(pbase);

	if (default_pre) {
		if (*infps > *outfps) *pre = 1;
		else if (*infps < *outfps) *pre = 0;
	}

	return 0;
}
Esempio n. 8
0
static void dump_vob(int sock)
{
    vob_t *vob = tc_get_vob();
    char buf[TC_BUF_MAX];
    int n;

#define SEND(field,fmt) \
    n = tc_snprintf(buf, sizeof(buf), "%s=" fmt "\n", #field, vob->field); \
    if (n > 0) \
        sendall(sock, buf, n);

    /* Generated via find-and-replace from vob_t definition in transcode.h */
    SEND(vmod_probed, "%s");
    SEND(amod_probed, "%s");
    SEND(vmod_probed_xml, "%s");
    SEND(amod_probed_xml, "%s");
    SEND(verbose, "%d");
    SEND(video_in_file, "%s");
    SEND(audio_in_file, "%s");
    SEND(nav_seek_file, "%s");
    SEND(has_audio, "%d");
    SEND(has_audio_track, "%d");
    SEND(has_video, "%d");
    SEND(lang_code, "%d");
    SEND(a_track, "%d");
    SEND(v_track, "%d");
    SEND(s_track, "%d");
    SEND(sync, "%d");
    SEND(sync_ms, "%d");
    SEND(dvd_title, "%d");
    SEND(dvd_chapter1, "%d");
    SEND(dvd_chapter2, "%d");
    SEND(dvd_max_chapters, "%d");
    SEND(dvd_angle, "%d");
    SEND(ps_unit, "%d");
    SEND(ps_seq1, "%d");
    SEND(ps_seq2, "%d");
    SEND(ts_pid1, "%d");
    SEND(ts_pid2, "%d");
    SEND(vob_offset, "%d");
    SEND(vob_chunk, "%d");
    SEND(vob_chunk_num1, "%d");
    SEND(vob_chunk_num2, "%d");
    SEND(vob_chunk_max, "%d");
    SEND(vob_percentage, "%d");
    SEND(vob_psu_num1, "%d");
    SEND(vob_psu_num2, "%d");
    SEND(vob_info_file, "%s");
    SEND(pts_start, "%f");
    SEND(psu_offset, "%f");
    SEND(demuxer, "%d");
    SEND(v_format_flag, "%ld");
    SEND(v_codec_flag, "%ld");
    SEND(a_format_flag, "%ld");
    SEND(a_codec_flag, "%ld");
    SEND(quality, "%d");
    SEND(a_stream_bitrate, "%d");
    SEND(a_chan, "%d");
    SEND(a_bits, "%d");
    SEND(a_rate, "%d");
    SEND(a_padrate, "%d");
    SEND(im_a_size, "%d");
    SEND(ex_a_size, "%d");
    SEND(im_a_codec, "%d");
    SEND(a_leap_frame, "%d");
    SEND(a_leap_bytes, "%d");
    SEND(a_vbr, "%d");
    SEND(a52_mode, "%d");
    SEND(dm_bits, "%d");
    SEND(dm_chan, "%d");
    SEND(v_stream_bitrate, "%d");
    SEND(fps, "%f");
    SEND(im_frc, "%d");
    SEND(ex_fps, "%f");
    SEND(ex_frc, "%d");
    SEND(hard_fps_flag, "%d");
    SEND(pulldown, "%d");
    SEND(im_v_height, "%d");
    SEND(im_v_width, "%d");
    SEND(im_v_size, "%d");
    SEND(im_asr, "%d");
    SEND(im_par, "%d");
    SEND(im_par_width, "%d");
    SEND(im_par_height, "%d");
    SEND(ex_asr, "%d");
    SEND(ex_par, "%d");
    SEND(ex_par_width, "%d");
    SEND(ex_par_height, "%d");
    SEND(attributes, "%d");
    SEND(im_v_codec, "%d");
    SEND(encode_fields, "%d");
    SEND(dv_yuy2_mode, "%d");
    SEND(volume, "%f");
    SEND(ac3_gain[0], "%f");
    SEND(ac3_gain[1], "%f");
    SEND(ac3_gain[2], "%f");
    SEND(clip_count, "%d");
    SEND(ex_v_width, "%d");
    SEND(ex_v_height, "%d");
    SEND(ex_v_size, "%d");
    SEND(reduce_h, "%d");
    SEND(reduce_w, "%d");
    SEND(resize1_mult, "%d");
    SEND(vert_resize1, "%d");
    SEND(hori_resize1, "%d");
    SEND(resize2_mult, "%d");
    SEND(vert_resize2, "%d");
    SEND(hori_resize2, "%d");
    SEND(zoom_width, "%d");
    SEND(zoom_height, "%d");
    SEND(zoom_interlaced, "%d");
    SEND(zoom_filter, "%d");
    SEND(antialias, "%d");
    SEND(deinterlace, "%d");
    SEND(decolor, "%d");
    SEND(aa_weight, "%f");
    SEND(aa_bias, "%f");
    SEND(gamma, "%f");
    SEND(ex_clip_top, "%d");
    SEND(ex_clip_bottom, "%d");
    SEND(ex_clip_left, "%d");
    SEND(ex_clip_right, "%d");
    SEND(im_clip_top, "%d");
    SEND(im_clip_bottom, "%d");
    SEND(im_clip_left, "%d");
    SEND(im_clip_right, "%d");
    SEND(post_ex_clip_top, "%d");
    SEND(post_ex_clip_bottom, "%d");
    SEND(post_ex_clip_left, "%d");
    SEND(post_ex_clip_right, "%d");
    SEND(pre_im_clip_top, "%d");
    SEND(pre_im_clip_bottom, "%d");
    SEND(pre_im_clip_left, "%d");
    SEND(pre_im_clip_right, "%d");
    SEND(video_out_file, "%s");
    SEND(audio_out_file, "%s");
    SEND(avifile_in, "%p");  // not sure if there's any point sending these...
    SEND(avifile_out, "%p");
    SEND(avi_comment_fd, "%d");
    SEND(audio_file_flag, "%d");
    SEND(divxbitrate, "%d");
    SEND(divxkeyframes, "%d");
    SEND(divxquality, "%d");
    SEND(divxcrispness, "%d");
    SEND(divxmultipass, "%d");
    SEND(video_max_bitrate, "%d");
    SEND(divxlogfile, "%s");
    SEND(min_quantizer, "%d");
    SEND(max_quantizer, "%d");
    SEND(mp3bitrate, "%d");
    SEND(mp3frequency, "%d");
    SEND(mp3quality, "%f");
    SEND(mp3mode, "%d");
    SEND(audiologfile, "%s");
    SEND(ex_a_codec, "%d");
    SEND(ex_v_codec, "%d");
    SEND(ex_v_fcc, "%s");
    SEND(ex_a_fcc, "%s");
    SEND(ex_profile_name, "%s");
    SEND(pass_flag, "%d");
    SEND(encoder_flush, "%d");
    SEND(mod_path, "%s");
    SEND(ttime, "%p");  // format this as a -c style string?
    SEND(frame_interval, "%u");
    SEND(im_v_string, "%s");
    SEND(im_a_string, "%s");
    SEND(ex_v_string, "%s");
    SEND(ex_a_string, "%s");
    SEND(ex_m_string, "%s");
    SEND(m2v_requant, "%f");
    SEND(export_attributes, "%u");

#undef SEND
}
Esempio n. 9
0
int tc_filter(frame_list_t *ptr_, char *options)
{
  vframe_list_t *ptr = (vframe_list_t *)ptr_;
  static vob_t *vob=NULL;
  int instance = ptr->filter_id;


  //----------------------------------
  //
  // filter init
  //
  //----------------------------------


  if( (ptr->tag & TC_AUDIO))
	  return 0;

  if(ptr->tag & TC_FRAME_IS_SKIPPED)
	  return 0;

  if(ptr->tag & TC_FILTER_INIT)
  {
    char *c;
    int len=0;

    if((vob = tc_get_vob())==NULL) return(-1);

    if (vob->im_v_codec == CODEC_RGB)
    {
      tc_log_error(MOD_NAME, "filter is not capable for RGB-Mode !");
      return(-1);
    }

    if (!options || !(len=strlen(options)))
    {
      tc_log_error(MOD_NAME, "this filter needs options !");
      return(-1);
    }


    if (!no_optstr(options)) {
	do_optstr(options);
    }

    // if "pre" is found, delete it
    if ( (c=pp_lookup(options, "pre")) ) {
	memmove (c, c+3, &options[len]-c);
	pre[instance] = 1;
    }

    if ( (c=pp_lookup(options, "help")) ) {
	memmove (c, c+4, &options[len]-c);
	optstr_help();
    }

    if (pre[instance]) {
      width[instance] = vob->im_v_width;
      height[instance]= vob->im_v_height;
    } else {
      width[instance] = vob->ex_v_width;
      height[instance]= vob->ex_v_height;
    }

    //tc_log_msg(MOD_NAME, "after pre (%s)", options);

    mode[instance] = pp_get_mode_by_name_and_quality(options, PP_QUALITY_MAX);

    if(mode[instance]==NULL) {
      tc_log_error(MOD_NAME, "internal error (pp_get_mode_by_name_and_quality)");
      return(-1);
    }

    if(tc_accel & AC_MMXEXT)
      context[instance] = pp_get_context(width[instance], height[instance], PP_CPU_CAPS_MMX2);
    else if(tc_accel & AC_3DNOW)
      context[instance] = pp_get_context(width[instance], height[instance], PP_CPU_CAPS_3DNOW);
    else if(tc_accel & AC_MMX)
      context[instance] = pp_get_context(width[instance], height[instance], PP_CPU_CAPS_MMX);
    else
      context[instance] = pp_get_context(width[instance], height[instance], 0);

    if(context[instance]==NULL) {
      tc_log_error(MOD_NAME, "internal error (pp_get_context) (instance=%d)", instance);
      return(-1);
    }

    // filter init ok.
    if(verbose) tc_log_info(MOD_NAME, "%s %s #%d", MOD_VERSION, MOD_CAP, ptr->filter_id);
    return(0);
  }

  //----------------------------------
  //
  // filter configure
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_GET_CONFIG)
  {
      do_getconfig (options);
      return 0;
  }

  //----------------------------------
  //
  // filter close
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_CLOSE)
  {
    if (mode[instance])
      pp_free_mode(mode[instance]);
    mode[instance] = NULL;
    if (context[instance])
      pp_free_context(context[instance]);
    context[instance] = NULL;

    return(0);
  }

  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------


  // tag variable indicates, if we are called before
  // transcodes internal video/audo frame processing routines
  // or after and determines video/audio context

  if(((ptr->tag & TC_PRE_M_PROCESS  && pre[instance]) ||
	  (ptr->tag & TC_POST_M_PROCESS && !pre[instance])) &&
	  !(ptr->attributes & TC_FRAME_IS_SKIPPED))
  {
    unsigned char *pp_page[3];
    int ppStride[3];

      pp_page[0] = ptr->video_buf;
      pp_page[1] = pp_page[0] + (width[instance] * height[instance]);
      pp_page[2] = pp_page[1] + (width[instance] * height[instance])/4;

      ppStride[0] = width[instance];
      ppStride[1] = ppStride[2] = width[instance]>>1;

      pp_postprocess((void *)pp_page, ppStride,
		     pp_page, ppStride,
		     width[instance], height[instance],
		     NULL, 0, mode[instance], context[instance], 0);
  }
int tc_filter(frame_list_t *ptr_, char *options)
{
  vframe_list_t *ptr = (vframe_list_t *)ptr_;
  int instance=ptr->filter_id;


  //----------------------------------
  //
  // filter get config
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_GET_CONFIG && options) {

    char buf[255];
    optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VRYOM", "1");

    tc_snprintf (buf, sizeof(buf), "%u-%u", data[instance]->start, data[instance]->end);
    optstr_param (options, "range",  "Frame Range",                         "%d-%d",     buf, "0", "oo",    "0", "oo");

    tc_snprintf (buf, sizeof(buf), "%dx%d", data[instance]->xpos, data[instance]->ypos);
    optstr_param (options, "pos",    "Position of logo",                    "%dx%d",     buf, "0", "width", "0", "height");

    tc_snprintf (buf, sizeof(buf), "%dx%d", data[instance]->width, data[instance]->height);
    optstr_param (options, "size",   "Size of logo",                        "%dx%d",     buf, "0", "width", "0", "height");

    tc_snprintf (buf, sizeof(buf), "%d", data[instance]->mode);
    optstr_param (options, "mode",   "Filter Mode (0=none,1=solid,2=xy,3=shape)", "%d",  buf, "0", "3");

    tc_snprintf (buf, sizeof(buf), "%d",  data[instance]->border);
    optstr_param (options, "border", "Visible Border",                      "",          buf);

    tc_snprintf (buf, sizeof(buf), "%d",  data[instance]->dump);
    optstr_param (options, "dump", "Dump filterarea to file",               "",          buf);

    tc_snprintf (buf, sizeof(buf), "%d", data[instance]->xweight);
    optstr_param (options, "xweight","X-Y Weight(0%-100%)",                 "%d",        buf, "0", "100");

    tc_snprintf (buf, sizeof(buf), "%x%x%x", data[instance]->rcolor, data[instance]->gcolor, data[instance]->bcolor);
    optstr_param (options, "fill",   "Solid Fill Color(RGB)",               "%2x%2x%2x", buf, "00", "FF",   "00", "FF", "00", "FF");

    tc_snprintf (buf, sizeof(buf), "%s",  data[instance]->file);
    optstr_param (options, "file",   "Image with alpha/shape information",  "%s",        buf);

    return 0;
  }


  //----------------------------------
  //
  // filter init
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_INIT) {

    if((vob = tc_get_vob())==NULL) return(-1);

    if((data[instance] = tc_malloc (sizeof(logoaway_data))) == NULL) {
      tc_log_error(MOD_NAME, "can't allocate filter data");
      return (-1);
    }

    data[instance]->start    = 0;
    data[instance]->end      = (unsigned int)-1;
    data[instance]->xpos     = -1;
    data[instance]->ypos     = -1;
    data[instance]->width    = -1;
    data[instance]->height   = -1;
    data[instance]->mode     = 0;
    data[instance]->border   = 0;
    data[instance]->xweight  = 50;
    data[instance]->yweight  = 50;
    data[instance]->rcolor   = 0;
    data[instance]->gcolor   = 0;
    data[instance]->bcolor   = 0;
    data[instance]->ycolor   = 16;
    data[instance]->ucolor   = 128;
    data[instance]->vcolor   = 128;
    data[instance]->alpha    = 0;
    data[instance]->dump     = 0;

    // filter init ok.

    if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

    if(options!=NULL) {
      optstr_get     (options,  "range",   "%d-%d",     &data[instance]->start,  &data[instance]->end);
      optstr_get     (options,  "pos",     "%dx%d",     &data[instance]->xpos,   &data[instance]->ypos);
      optstr_get     (options,  "size",    "%dx%d",     &data[instance]->width,  &data[instance]->height);
        data[instance]->width += data[instance]->xpos; data[instance]->height += data[instance]->ypos;
      optstr_get     (options,  "mode",    "%d",        &data[instance]->mode);
      if (optstr_lookup (options,  "border") != NULL)
        data[instance]->border = 1;
      if (optstr_lookup (options,  "help") != NULL)
        help_optstr();
      optstr_get     (options,  "xweight", "%d",        &data[instance]->xweight);
        data[instance]->yweight = 100 - data[instance]->xweight;
      optstr_get     (options,  "fill",    "%2x%2x%2x", &data[instance]->rcolor, &data[instance]->gcolor, &data[instance]->bcolor);
        data[instance]->ycolor =  (0.257 * data[instance]->rcolor) + (0.504 * data[instance]->gcolor) + (0.098 * data[instance]->bcolor) + 16;
        data[instance]->ucolor =  (0.439 * data[instance]->rcolor) - (0.368 * data[instance]->gcolor) - (0.071 * data[instance]->bcolor) + 128;
        data[instance]->vcolor = -(0.148 * data[instance]->rcolor) - (0.291 * data[instance]->gcolor) + (0.439 * data[instance]->bcolor) + 128;
      if (optstr_get (options,  "file",    "%[^:]",     data[instance]->file) >= 0)
        data[instance]->alpha = 1;
      if (optstr_lookup (options,  "dump") != NULL)
        data[instance]->dump = 1;
    }

    if(verbose) tc_log_info(MOD_NAME, "instance(%d) options=%s", instance, options);
    if(verbose > 1) {
      tc_log_info (MOD_NAME, " LogoAway Filter Settings:");
      tc_log_info (MOD_NAME, "            pos = %dx%d", data[instance]->xpos, data[instance]->ypos);
      tc_log_info (MOD_NAME, "           size = %dx%d", data[instance]->width-data[instance]->xpos, data[instance]->height-data[instance]->ypos);
      tc_log_info (MOD_NAME, "           mode = %d(%s)", data[instance]->mode, modes[data[instance]->mode]);
      tc_log_info (MOD_NAME, "         border = %d", data[instance]->border);
      tc_log_info (MOD_NAME, "     x-y weight = %d:%d", data[instance]->xweight, data[instance]->yweight);
      tc_log_info (MOD_NAME, "     fill color = %2X%2X%2X", data[instance]->rcolor, data[instance]->gcolor, data[instance]->bcolor);
      if(data[instance]->alpha)
        tc_log_info (MOD_NAME, "           file = %s", data[instance]->file);
      if(data[instance]->dump)
        tc_log_info (MOD_NAME, "           dump = %d", data[instance]->dump);
    }

    if( (data[instance]->xpos > vob->im_v_width) || (data[instance]->ypos > vob->im_v_height) || (data[instance]->xpos < 0) || (data[instance]->ypos < 0) )  {
      tc_log_error(MOD_NAME, "invalid position");
      return(-1);
    }
    if( (data[instance]->width > vob->im_v_width) || (data[instance]->height > vob->im_v_height) || (data[instance]->width-data[instance]->xpos < 0) || (data[instance]->height-data[instance]->ypos < 0) ) {
      tc_log_error(MOD_NAME, "invalid size");
      return(-1);
    }
    if( (data[instance]->xweight > 100) || (data[instance]->xweight < 0) ) {
      tc_log_error(MOD_NAME, "invalid x weight");
      return(-1);
    }
    if( (data[instance]->mode < 0) || (data[instance]->mode > 3) ) {
      tc_log_error(MOD_NAME, "invalid mode");
      return(-1);
    }
    if( (data[instance]->mode == 3) && (data[instance]->alpha == 0) ) {
      tc_log_error(MOD_NAME, "alpha/shape file needed for SHAPE-mode");
      return(-1);
    }

    if((data[instance]->alpha) || (data[instance]->dump)) {
      InitializeMagick("");
      GetExceptionInfo(&data[instance]->exception_info);

      if(data[instance]->alpha) {
        data[instance]->image_info = CloneImageInfo((ImageInfo *) NULL);

        strlcpy(data[instance]->image_info->filename, data[instance]->file, MaxTextExtent);
        data[instance]->image = ReadImage(data[instance]->image_info, &data[instance]->exception_info);
        if (data[instance]->image == (Image *) NULL) {
          tc_log_error(MOD_NAME, "\n");
          MagickWarning (data[instance]->exception_info.severity, data[instance]->exception_info.reason, data[instance]->exception_info.description);
          return(-1);
        }

        if ((data[instance]->image->columns != (data[instance]->width-data[instance]->xpos)) || (data[instance]->image->rows != (data[instance]->height-data[instance]->ypos))) {
          tc_log_error(MOD_NAME, "\"%s\" has incorrect size", data[instance]->file);

          return(-1);
        }

        data[instance]->pixel_packet = GetImagePixels(data[instance]->image, 0, 0, data[instance]->image->columns, data[instance]->image->rows);
      }
      if(data[instance]->dump) {
        if((data[instance]->dump_buf = tc_malloc ((data[instance]->width-data[instance]->xpos)*(data[instance]->height-data[instance]->ypos)*3)) == NULL)
          tc_log_error(MOD_NAME, "out of memory");

        data[instance]->dumpimage_info = CloneImageInfo((ImageInfo *) NULL);
      }
    }

    return(0);
  }


  //----------------------------------
  //
  // filter close
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_CLOSE) {

    if (data[instance]->image != (Image *)NULL) {
      DestroyImage(data[instance]->image);
      DestroyImageInfo(data[instance]->image_info);
    }
    if (data[instance]->dumpimage != (Image *)NULL) {
      DestroyImage(data[instance]->dumpimage);
      DestroyImageInfo(data[instance]->dumpimage_info);
      DestroyConstitute();
    }
    DestroyExceptionInfo(&data[instance]->exception_info);
    DestroyMagick();

    if(data[instance]->dump_buf) free(data[instance]->dump_buf);
    if(data[instance]) free(data[instance]);
    data[instance] = NULL;

    return(0);
  }


  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------


  if(ptr->tag & TC_PRE_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

    if (ptr->id < data[instance]->start || ptr->id > data[instance]->end) return (0);

    if(vob->im_v_codec==TC_CODEC_RGB24) {
      work_with_rgb_frame(ptr->video_buf, vob->im_v_width, vob->im_v_height, instance);
    } else {
      work_with_yuv_frame(ptr->video_buf, vob->im_v_width, vob->im_v_height, instance);
    }
  }
  return(0);
}
Esempio n. 11
0
int tc_filter(frame_list_t *ptr_, char *options)
{
    vframe_list_t *ptr = (vframe_list_t *)ptr_;
    vob_t *vob = NULL;

    int pre = 0, vid = 0;
    int vol = 0, vop = 0, is_key = 0;

    if (ptr->tag & TC_FILTER_GET_CONFIG) {
        optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION,
                           "Thomas Oestreich", "VE", "1");
        return 0;
    }

    if (ptr->tag & TC_FILTER_INIT) {
        vob = tc_get_vob();
        if (vob == NULL)
            return -1;

        if (verbose) {
            tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
            tc_log_info(MOD_NAME, "options=%s", options);
            tc_log_info(MOD_NAME, "divxkey");
        }

        return 0;
    }

    if (ptr->tag & TC_FILTER_CLOSE) {
        return 0;
    } 

    if (verbose & TC_STATS)
        tc_log_info(MOD_NAME, "%s/%s %s %s",
                    vob->mod_path, MOD_NAME, MOD_VERSION, MOD_CAP);

    // tag variable indicates, if we are called before
    // transcodes internal video/audo frame processing routines
    // or after and determines video/audio context

    pre = (ptr->tag & TC_PRE_M_PROCESS)? 1:0;
    vid = (ptr->tag & TC_VIDEO)? 1:0;

    if(pre && vid) {
        bs_init_tc(&bs, (char*)ptr->video_buf);

        vol = bs_vol(&bs, &dec);
        vop = bs_vop(&bs, &dec, &rounding, &quant, &fcode);

        if (verbose & TC_STATS)
            tc_log_info(MOD_NAME, "frame=%d vop=%d vol=%d (%d %d %d)",
                        ptr->id, vop, vol, rounding, quant, fcode);

         // DivX ;-)
         if (vob->v_codec_flag == TC_CODEC_DIVX3) {
            if (ptr->video_size > 4)
                is_key = quicktime_divx3_is_key(ptr->video_buf);
            if (is_key)
                ptr->attributes |= TC_FRAME_IS_KEYFRAME;
        }

        // DivX
        if (vob->v_codec_flag == TC_CODEC_DIVX4 || vob->v_codec_flag == TC_CODEC_DIVX5) {
            is_key = quicktime_divx4_is_key(ptr->video_buf, (long)ptr->video_size);
            if (is_key  && vop == I_VOP)
                ptr->attributes |= TC_FRAME_IS_KEYFRAME;
        }

        if ((verbose >= TC_DEBUG) && (ptr->attributes & TC_FRAME_IS_KEYFRAME)) {
            tc_log_info(MOD_NAME, "key (intra) @ %d", ptr->id);
        }
    }

    return 0;
}
Esempio n. 12
0
// main filter routine
int tc_filter(frame_list_t *ptr_, char *options)
{
  vframe_list_t *ptr = (vframe_list_t *)ptr_;
  static vob_t *vob=NULL;
  /* FIXME: these use the filter ID as an index--the ID can grow
   * arbitrarily large, so this needs to be fixed */
  static MyFilterData *mfd[100];
  static char *buffer[100];
  int instance = ptr->filter_id;


  if(ptr->tag & TC_AUDIO)
      return 0;

  if(ptr->tag & TC_FILTER_GET_CONFIG) {

      char buf[128];
      optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VYMOE", "2");

      tc_snprintf(buf, 128, "%f", PARAM1_DEFAULT);
      optstr_param (options, "luma", "spatial luma strength", "%f", buf, "0.0", "100.0" );

      tc_snprintf(buf, 128, "%f", PARAM2_DEFAULT);
      optstr_param (options, "chroma", "spatial chroma strength", "%f", buf, "0.0", "100.0" );

      tc_snprintf(buf, 128, "%f", PARAM3_DEFAULT);
      optstr_param (options, "luma_strength", "temporal luma strength", "%f", buf, "0.0", "100.0" );

      tc_snprintf(buf, 128, "%f", PARAM3_DEFAULT*PARAM2_DEFAULT/PARAM1_DEFAULT);
      optstr_param (options, "chroma_strength", "temporal chroma strength", "%f", buf, "0.0", "100.0" );
      tc_snprintf(buf, 128, "%d", mfd[instance]->pre);
      optstr_param (options, "pre", "run as a pre filter", "%d", buf, "0", "1" );

      return 0;
  }

  if(ptr->tag & TC_FILTER_INIT) {

      double LumSpac, LumTmp, ChromSpac, ChromTmp;
      double Param1=0.0, Param2=0.0, Param3=0.0, Param4=0.0;

      if((vob = tc_get_vob())==NULL) return(-1);

      if (vob->im_v_codec != TC_CODEC_YUV420P) {
	  tc_log_error(MOD_NAME, "This filter is only capable of YUV 4:2:0 mode");
	  return -1;
      }

      mfd[instance] = tc_zalloc(sizeof(MyFilterData));

      if (mfd[instance]) {
	  mfd[instance]->Line = tc_zalloc(TC_MAX_V_FRAME_WIDTH*sizeof(int));
      }

      buffer[instance] = tc_zalloc(SIZE_RGB_FRAME);

      if (!mfd[instance] || !mfd[instance]->Line || !buffer[instance]) {
	  tc_log_error(MOD_NAME, "Malloc failed");
	  return -1;
      }


      // defaults

      LumSpac = PARAM1_DEFAULT;
      LumTmp = PARAM3_DEFAULT;

      ChromSpac = PARAM2_DEFAULT;
      ChromTmp = LumTmp * ChromSpac / LumSpac;

      if (options) {

	  if (optstr_lookup (options, "help")) {
	      help_optstr();
	  }

	  optstr_get (options, "luma",           "%lf",    &Param1);
	  optstr_get (options, "luma_strength",  "%lf",    &Param3);
	  optstr_get (options, "chroma",         "%lf",    &Param2);
	  optstr_get (options, "chroma_strength","%lf",    &Param4);
	  optstr_get (options, "pre", "%d",    &mfd[instance]->pre);

	  // recalculate only the needed params

	  if (Param1!=0.0) {

	      LumSpac = Param1;
	      LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT;

	      ChromSpac = PARAM2_DEFAULT * Param1 / PARAM1_DEFAULT;
	      ChromTmp = LumTmp * ChromSpac / LumSpac;
	  }
	  if (Param2!=0.0) {

	      ChromSpac = Param2;
	      ChromTmp = LumTmp * ChromSpac / LumSpac;
	  }
	  if (Param3!=0.0) {

	      LumTmp = Param3;
	      ChromTmp = LumTmp * ChromSpac / LumSpac;

	  }
	  if (Param4!=0.0) {

	      ChromTmp = Param4;
	  }

      }

      PrecalcCoefs(mfd[instance]->Coefs[0], LumSpac);
      PrecalcCoefs(mfd[instance]->Coefs[1], LumTmp);
      PrecalcCoefs(mfd[instance]->Coefs[2], ChromSpac);
      PrecalcCoefs(mfd[instance]->Coefs[3], ChromTmp);


      if(verbose) {
	  tc_log_info(MOD_NAME, "%s %s #%d", MOD_VERSION, MOD_CAP, instance);
	  tc_log_info(MOD_NAME, "Settings luma=%.2f chroma=%.2f luma_strength=%.2f chroma_strength=%.2f",
		  LumSpac, ChromSpac, LumTmp, ChromTmp);
      }
      return 0;
  }



  //----------------------------------
  //
  // filter close
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_CLOSE) {

      if (buffer[instance]) {free(buffer[instance]); buffer[instance]=NULL;}
      if (mfd[instance]) {
	  if(mfd[instance]->Line){free(mfd[instance]->Line);mfd[instance]->Line=NULL;}
	  if(mfd[instance]->Frame[0]){free(mfd[instance]->Frame[0]);mfd[instance]->Frame[0]=NULL;}
	  if(mfd[instance]->Frame[1]){free(mfd[instance]->Frame[1]);mfd[instance]->Frame[1]=NULL;}
	  if(mfd[instance]->Frame[2]){free(mfd[instance]->Frame[2]);mfd[instance]->Frame[2]=NULL;}
	  free(mfd[instance]);
      }
      mfd[instance]=NULL;

      return(0);

  } /* filter close */

  //actually do the filter

  if(((ptr->tag & TC_PRE_M_PROCESS  && mfd[instance]->pre) ||
	  (ptr->tag & TC_POST_M_PROCESS && !mfd[instance]->pre)) &&
	  !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

      ac_memcpy (buffer[instance], ptr->video_buf, ptr->video_size);

      deNoise(buffer[instance],                                  ptr->video_buf,
	      mfd[instance]->Line, &mfd[instance]->Frame[0], ptr->v_width, ptr->v_height,
	      ptr->v_width,  ptr->v_width,
	      mfd[instance]->Coefs[0], mfd[instance]->Coefs[0], mfd[instance]->Coefs[1]);

      deNoise(buffer[instance] + ptr->v_width*ptr->v_height,     ptr->video_buf + ptr->v_width*ptr->v_height,
	      mfd[instance]->Line, &mfd[instance]->Frame[1], ptr->v_width>>1, ptr->v_height>>1,
	      ptr->v_width>>1,  ptr->v_width>>1,
	      mfd[instance]->Coefs[2], mfd[instance]->Coefs[2], mfd[instance]->Coefs[3]);

      deNoise(buffer[instance] + 5*ptr->v_width*ptr->v_height/4, ptr->video_buf + 5*ptr->v_width*ptr->v_height/4,
	      mfd[instance]->Line, &mfd[instance]->Frame[2], ptr->v_width>>1, ptr->v_height>>1,
	      ptr->v_width>>1,  ptr->v_width>>1,
	      mfd[instance]->Coefs[2], mfd[instance]->Coefs[2], mfd[instance]->Coefs[3]);

  }
int tc_filter(frame_list_t *ptr_, char *options)
{
  vframe_list_t *ptr = (vframe_list_t *)ptr_;

  if(ptr->tag & TC_FILTER_GET_CONFIG) {

      optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Thomas Oestreich", "VRYE", "1");
      optstr_param (options, "mode",   "Choose the test pattern (0-4 interlaced, 5 colorfull)", "%d", "0", "0", "5");
  }

  //----------------------------------
  //
  // filter init
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_INIT) {

    if((vob = tc_get_vob())==NULL) return(-1);

    // filter init ok.

    if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

    if(verbose) tc_log_info(MOD_NAME, "options=%s", options);

    if (options) {
	if (is_optstr(options)) {
	    optstr_get(options, "mode", "%d", &mode);
	} else
	    sscanf(options, "%d", &mode);
    }

    if(mode <0) { tc_log_error(MOD_NAME, "Invalid mode"); return(-1); }

    return(0);
  }

  //----------------------------------
  //
  // filter close
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_CLOSE) {
    return(0);
  }

  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------

  // tag variable indicates, if we are called before
  // transcodes internal video/audo frame processing routines
  // or after and determines video/audio context

  if(ptr->tag & TC_PRE_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

    if(vob->im_v_codec==CODEC_RGB) {
      generate_rgb_frame(ptr->video_buf, ptr->v_width, ptr->v_height);
    } else {
      generate_yuv_frame(ptr->video_buf, ptr->v_width, ptr->v_height);
    }
  }
  return(0);
}
Esempio n. 14
0
int tc_filter(frame_list_t *ptr_, char *options)
{
    vframe_list_t *ptr = (vframe_list_t *)ptr_;
    static vob_t *vob = NULL;
    static char *lastFrames[FRBUFSIZ];
    static int frameIn = 0;
    static int frameCount = 0;
    static int field = 0;
    static int magic = 0;

    //----------------------------------
    //
    // filter init
    //
    //----------------------------------


    if (ptr->tag & TC_FILTER_GET_CONFIG) {
	if (options) {
	    optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Thanassis Tsiodras", "VYE", "1");
	    optstr_param (options, "verbose", "print verbose information", "", "0");
	    optstr_param (options, "field", "which field to replace (0=top 1=bottom)",  "%d", "0",  "0", "1");
	    optstr_param (options, "magic", "perform magic? (0=no 1=yes)",  "%d", "0",  "0", "1");
	}
    }

    if (ptr->tag & TC_FILTER_INIT) {

	int i;

	if ((vob = tc_get_vob()) == NULL)
	    return (-1);

	if (vob->im_v_codec != TC_CODEC_YUV420P) {
		tc_log_error(MOD_NAME, "Sorry, only YUV 420 input allowed for now");
		return (-1);
	}

	// filter init ok.
	if (options != NULL) {

	    if (optstr_lookup (options, "verbose") != NULL) {
		show_results=1;
	    }

	    optstr_get(options, "field", "%d", &field);
	    optstr_get(options, "magic", "%d", &magic);

	}

	if (verbose)
	    tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

	for(i=0; i<FRBUFSIZ; i++) {
	    lastFrames[i] = tc_malloc(SIZE_RGB_FRAME);
    	}

	return (0);
    }
    //----------------------------------
    //
    // filter close
    //
    //----------------------------------


    if (ptr->tag & TC_FILTER_CLOSE) {
	int i;

	for(i=0; i<FRBUFSIZ; i++)
	    free(lastFrames[i]);
	return (0);
    }
    //----------------------------------
    //
    // filter frame routine
    //
    //----------------------------------


    // tag variable indicates, if we are called before
    // transcodes internal video/audio frame processing routines
    // or after and determines video/audio context

    if ((ptr->tag & TC_PRE_S_PROCESS) && (ptr->tag & TC_VIDEO)) {

	ac_memcpy(	lastFrames[frameIn],
		ptr->video_buf,
		ptr->v_width*ptr->v_height*3);
	if (show_results)
	    tc_log_info(MOD_NAME, "Inserted frame %d into slot %d",
		    frameCount, frameIn);
	frameIn = (frameIn+1) % FRBUFSIZ;
	frameCount++;

	// The first 2 frames are not output - they are only buffered
	if (frameCount <= 2) {
	    ptr->attributes |= TC_FRAME_IS_SKIPPED;
	} else {
	    // We have the last 3 frames in the buffer...
	    //
	    //		Previous Current Next
	    //
	    // OK, time to work...

	    unsigned char *curr,
		*pprev, *pnext, *cprev, *cnext, *nprev, *nnext, *dstp;
	    int idxp, idxc, idxn;
	    int p, c, n, lowest, chosen;
	    int C, x, y;
	    int comb;

	    idxn = frameIn-1; while(idxn<0) idxn+=FRBUFSIZ;
	    idxc = frameIn-2; while(idxc<0) idxc+=FRBUFSIZ;
	    idxp = frameIn-3; while(idxp<0) idxp+=FRBUFSIZ;

            y = (field ? 2 : 1) * ptr->v_width;

	    // bottom field of current
	    curr =  &lastFrames[idxc][y];
	    // top field of previous
	    pprev = &lastFrames[idxp][y - ptr->v_width];
	    // top field of previous - 2nd scanline
	    pnext = &lastFrames[idxp][y + ptr->v_width];
	    // top field of current
	    cprev = &lastFrames[idxc][y - ptr->v_width];
	    // top field of current - 2nd scanline
	    cnext = &lastFrames[idxc][y + ptr->v_width];
	    // top field of next
	    nprev = &lastFrames[idxn][y - ptr->v_width];
	    // top field of next - 2nd scanline
	    nnext = &lastFrames[idxn][y + ptr->v_width];

	    // Blatant copy begins...

	    p = c = n = 0;
	    /* Try to match the top field of the current frame to the
	       bottom fields of the previous, current, and next frames.
	       Output the assembled frame that matches up best. For
	       matching, subsample the frames in the x dimension
	       for speed. */
	    for (y = 0; y < ptr->v_height-2; y+=4)
	    {
		for (x = 0; x < ptr->v_width;)
		{
		    C = curr[x];
#define T 100
		    /* This combing metric is based on
		       an original idea of Gunnar Thalin. */
		    comb = ((long)pprev[x] - C) * ((long)pnext[x] - C);
		    if (comb > T) p++;

		    comb = ((long)cprev[x] - C) * ((long)cnext[x] - C);
		    if (comb > T) c++;

		    comb = ((long)nprev[x] - C) * ((long)nnext[x] - C);
		    if (comb > T) n++;

		    if (!(++x&3)) x += 12;
		}
		curr  += ptr->v_width*4;
		pprev += ptr->v_width*4;
		pnext += ptr->v_width*4;
		cprev += ptr->v_width*4;
		cnext += ptr->v_width*4;
		nprev += ptr->v_width*4;
		nnext += ptr->v_width*4;
	    }

	    lowest = c;
	    chosen = 1;
	    if (p < lowest)
	    {
		    lowest = p;
		    chosen = 0;
	    }
	    if (n < lowest)
	    {
		    lowest = n;
		    chosen = 2;
	    }

	    if (magic && c < 50 && abs(lowest - c) < 10 && (p+c+n) > 1000) {
		lowest = c;
		chosen = 1;
            }

	    // Blatant copy ends... :)

	    if (show_results)
		tc_log_info(MOD_NAME,
		    "Telecide => frame %d: p=%u  c=%u  n=%u [using %d]",
		    frameCount, p, c, n, chosen);

	    // Set up the pointers in preparation to output final frame.

	    // First, the Y plane
	    if (chosen == 0)
		curr = lastFrames[idxp];
	    else if (chosen == 1)
		curr = lastFrames[idxc];
	    else
		curr = lastFrames[idxn];

	    dstp = ptr->video_buf;

	    // First output the top field selected
	    // from the set of three stored frames.
	    ivtc_copy_field(dstp, curr, ptr, field);

	    // The bottom field of the current frame unchanged
	    ivtc_copy_field(dstp, lastFrames[idxc], ptr, 1-field);

	}
    }

    return (0);
}
Esempio n. 15
0
int tc_filter(frame_list_t *ptr_, char *options)
{
    vframe_list_t *ptr = (vframe_list_t *)ptr_;
    vob_t         *vob = NULL;

    int instance = ptr->filter_id;
    MyFilterData  *mfd = mfd_all[instance];

    if (mfd != NULL) {
        vob = mfd->vob;
    }

    //----------------------------------
    //
    // filter init
    //
    //----------------------------------


    if (ptr->tag & TC_FILTER_GET_CONFIG) {
        optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VRYO", "1");
        // buf, name, comment, format, val, from, to
        optstr_param(options, "file",   "Image filename",    "%s",    "logo.png");
        optstr_param(options, "posdef", "Position (0=None, 1=TopL, 2=TopR, 3=BotL, 4=BotR, 5=Center)",  "%d", "0", "0", "5");
        optstr_param(options, "pos",    "Position (0-width x 0-height)",  "%dx%d", "0x0", "0", "width", "0", "height");
        optstr_param(options, "range",  "Restrict rendering to framerange",  "%u-%u", "0-0", "0", "oo", "0", "oo");
        optstr_param(options, "fade",   "Fade image in/out (# of frames)",  "%u-%u", "0-0", "0", "oo", "0", "oo");
        // bools
        optstr_param(options, "ignoredelay", "Ignore delay specified in animations", "", "0");
        optstr_param(options, "rgbswap", "Swap red/blue colors", "", "0");
        optstr_param(options, "grayout", "YUV only: don't write Cb and Cr, makes a nice effect", "",  "0");
        optstr_param(options, "hqconv",  "YUV only: do high quality rgb->yuv img conversion", "",  "0");
        optstr_param(options, "flip",    "Mirror image",  "", "0");

        return 0;
    }

    if (ptr->tag & TC_FILTER_INIT) {
        Image         *timg;
        Image         *nimg;
        ImageInfo     *image_info;
        ExceptionInfo  exception_info;

        int rgb_off = 0;

        vob_t *tmpvob;

        tmpvob = tc_get_vob();
        if (tmpvob == NULL)
            return -1;
        mfd_all[instance] = tc_zalloc(sizeof(MyFilterData));
        if (mfd_all[instance] == NULL)
            return -1;

        mfd = mfd_all[instance];

        strlcpy(mfd->file, "logo.png", PATH_MAX);
        mfd->end = (unsigned int)-1;
        mfd->vob = tmpvob;
        vob      = mfd->vob;

        if (options != NULL) {
            if (verbose)
                tc_log_info(MOD_NAME, "options=%s", options);

            optstr_get(options, "file",     "%[^:]", mfd->file);
            optstr_get(options, "posdef",   "%d",    (int *)&mfd->pos);
            optstr_get(options, "pos",      "%dx%d", &mfd->posx,  &mfd->posy);
            optstr_get(options, "range",    "%u-%u", &mfd->start, &mfd->end);
            optstr_get(options, "fade",     "%u-%u", &mfd->fadein, &mfd->fadeout);

            if (optstr_lookup(options, "ignoredelay") != NULL)
                mfd->ignoredelay = !mfd->ignoredelay;
            if (optstr_lookup(options, "flip") != NULL)
                mfd->flip    = !mfd->flip;
            if (optstr_lookup(options, "rgbswap") != NULL)
                mfd->rgbswap = !mfd->rgbswap;
            if (optstr_lookup(options, "grayout") != NULL)
                mfd->grayout = !mfd->grayout;
            if (optstr_lookup(options, "hqconv") != NULL)
                mfd->hqconv  = !mfd->hqconv;

            if (optstr_lookup (options, "help") != NULL)
                flogo_help_optstr();
        }

        if (verbose > 1) {
            tc_log_info(MOD_NAME, " Logo renderer Settings:");
            tc_log_info(MOD_NAME, "         file = %s",    mfd->file);
            tc_log_info(MOD_NAME, "       posdef = %d",    mfd->pos);
            tc_log_info(MOD_NAME, "          pos = %dx%d", mfd->posx,
                                                           mfd->posy);
            tc_log_info(MOD_NAME, "        range = %u-%u", mfd->start,
                                                           mfd->end);
            tc_log_info(MOD_NAME, "         fade = %u-%u", mfd->fadein,
                                                           mfd->fadeout);
            tc_log_info(MOD_NAME, "         flip = %d",    mfd->flip);
            tc_log_info(MOD_NAME, "  ignoredelay = %d",    mfd->ignoredelay);
            tc_log_info(MOD_NAME, "      rgbswap = %d",    mfd->rgbswap);
            tc_log_info(MOD_NAME, "      grayout = %d",    mfd->grayout);
            tc_log_info(MOD_NAME, "       hqconv = %d",    mfd->hqconv);
        }

        /* Transcode serializes module execution, so this does not need a
         * semaphore.
         */
        magick_usecount++;
        if (!IsMagickInstantiated()) {
            InitializeMagick("");
        }

        GetExceptionInfo(&exception_info);
        image_info = CloneImageInfo((ImageInfo *) NULL);
        strlcpy(image_info->filename, mfd->file, MaxTextExtent);

        mfd->image = ReadImage(image_info, &exception_info);
        if (mfd->image == (Image *) NULL) {
            MagickWarning(exception_info.severity,
                          exception_info.reason,
                          exception_info.description);
            strlcpy(mfd->file, "/dev/null", PATH_MAX);
            return 0;
        }
        DestroyImageInfo(image_info);

        if (mfd->image->columns > vob->ex_v_width
         || mfd->image->rows    > vob->ex_v_height
        ) {
            tc_log_error(MOD_NAME, "\"%s\" is too large", mfd->file);
            return -1;
        }

        if (vob->im_v_codec == TC_CODEC_YUV420P) {
            if ((mfd->image->columns & 1) || (mfd->image->rows & 1)) {
                tc_log_error(MOD_NAME, "\"%s\" has odd sizes", mfd->file);
                return -1;
            }
        }

        mfd->images = (Image *)GetFirstImageInList(mfd->image);
        nimg = NewImageList();

        while (mfd->images != (Image *)NULL) {
            if (mfd->flip || flip) {
                timg = FlipImage(mfd->images, &exception_info);
                if (timg == (Image *) NULL) {
                    MagickError(exception_info.severity,
                                exception_info.reason,
                                exception_info.description);
                    return -1;
                }
                AppendImageToList(&nimg, timg);
            }

            mfd->images = GetNextImageInList(mfd->images);
            mfd->nr_of_images++;
        }

        // check for memleaks;
        //DestroyImageList(image);
        if (mfd->flip || flip) {
            mfd->image = nimg;
        }

        /* initial delay. real delay = 1/100 sec * delay */
        mfd->cur_delay = mfd->image->delay*vob->fps/100;

        if (verbose & TC_DEBUG)
            tc_log_info(MOD_NAME, "Nr: %d Delay: %d mfd->image->del %lu|",
                        mfd->nr_of_images, mfd->cur_delay, mfd->image->delay);

        if (vob->im_v_codec == TC_CODEC_YUV420P) {
            /* convert Magick RGB image format to YUV */
            /* todo: convert the magick image if it's not rgb! (e.g. cmyk) */
            Image   *image;
            uint8_t *yuv_hqbuf = NULL;

            /* Round up for odd-size images */
            unsigned long width  = mfd->image->columns;
            unsigned long height = mfd->image->rows;
            int do_rgbswap  = (rgbswap || mfd->rgbswap);
            int i;

            /* Allocate buffers for the YUV420P frames. mfd->nr_of_images
             * will be 1 unless this is an animated GIF or MNG.
             * This buffer needs to be large enough to store a temporary
             * 24-bit RGB image (extracted from the ImageMagick handle).
             */
            mfd->yuv = flogo_yuvbuf_alloc(width*height * 3, mfd->nr_of_images);
            if (mfd->yuv == NULL) {
                tc_log_error(MOD_NAME, "(%d) out of memory\n", __LINE__);
                return -1;
            }

            if (mfd->hqconv) {
                /* One temporary buffer, to hold full Y, U, and V planes. */
                yuv_hqbuf = tc_malloc(width*height * 3);
                if (yuv_hqbuf == NULL) {
                    tc_log_error(MOD_NAME, "(%d) out of memory\n", __LINE__);
                    return -1;
                }
            }

            mfd->tcvhandle = tcv_init();
            if (mfd->tcvhandle == NULL) {
                tc_log_error(MOD_NAME, "image conversion init failed");
                return -1;
            }

            image = GetFirstImageInList(mfd->image);

            for (i = 0; i < mfd->nr_of_images; i++) {
                if (!mfd->hqconv) {
                    flogo_convert_image(mfd->tcvhandle, image, mfd->yuv[i],
                                        IMG_YUV420P, do_rgbswap);
                } else {
                    flogo_convert_image(mfd->tcvhandle, image, yuv_hqbuf,
                                        IMG_YUV444P, do_rgbswap);

                    // Copy over Y data from the 444 image
                    ac_memcpy(mfd->yuv[i], yuv_hqbuf, width * height);

                    // Resize U plane by 1/2 in each dimension, into the
                    // mfd YUV buffer
                    tcv_zoom(mfd->tcvhandle,
                             yuv_hqbuf + (width * height),
                             mfd->yuv[i] + (width * height),
                             width,
                             height,
                             1,
                             width / 2,
                             height / 2,
                             TCV_ZOOM_LANCZOS3
                    );

                    // Do the same with the V plane
                    tcv_zoom(mfd->tcvhandle,
                             yuv_hqbuf + 2*width*height,
                             mfd->yuv[i] + width*height + (width/2)*(height/2),
                             width,
                             height,
                             1,
                             width / 2,
                             height / 2,
                             TCV_ZOOM_LANCZOS3
                    );
                }
                image = GetNextImageInList(image);
            }

            if (mfd->hqconv)
                tc_free(yuv_hqbuf);

            tcv_free(mfd->tcvhandle);
        } else {
            /* for RGB format is origin bottom left */
            /* for RGB, rgbswap is done in the frame routine */
            rgb_off = vob->ex_v_height - mfd->image->rows;
            mfd->posy = rgb_off - mfd->posy;
        }

        switch (mfd->pos) {
          case NONE: /* 0 */
            break;
          case TOP_LEFT:
            mfd->posx = 0;
            mfd->posy = rgb_off;
            break;
          case TOP_RIGHT:
            mfd->posx = vob->ex_v_width  - mfd->image->columns;
            break;
          case BOT_LEFT:
            mfd->posy = vob->ex_v_height - mfd->image->rows - rgb_off;
            break;
          case BOT_RIGHT:
            mfd->posx = vob->ex_v_width  - mfd->image->columns;
            mfd->posy = vob->ex_v_height - mfd->image->rows - rgb_off;
            break;
          case CENTER:
            mfd->posx = (vob->ex_v_width - mfd->image->columns)/2;
            mfd->posy = (vob->ex_v_height- mfd->image->rows)/2;
            /* align to not cause color disruption */
            if (mfd->posx & 1)
                mfd->posx++;
            if (mfd->posy & 1)
                mfd->posy++;
            break;
        }


        if (mfd->posy < 0 || mfd->posx < 0
         || (mfd->posx + mfd->image->columns) > vob->ex_v_width
         || (mfd->posy + mfd->image->rows)    > vob->ex_v_height) {
            tc_log_error(MOD_NAME, "invalid position");
            return -1;
        }

        /* for running through image sequence */
        mfd->images = mfd->image;


        /* Set up image/video coefficient lookup tables */
        if (img_coeff_lookup[0] < 0) {
            int i;
            float maxrgbval = (float)MaxRGB; // from ImageMagick

            for (i = 0; i <= MAX_UINT8_VAL; i++) {
                float x = (float)ScaleCharToQuantum(i);

                /* Alternatively:
                 *  img_coeff = (maxrgbval - x) / maxrgbval;
                 *  vid_coeff = x / maxrgbval;
                 */
                img_coeff_lookup[i] = 1.0 - (x / maxrgbval);
                vid_coeff_lookup[i] = 1.0 - img_coeff_lookup[i];
            }
        }

        // filter init ok.
        if (verbose)
            tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

        return 0;
    }


    //----------------------------------
    //
    // filter close
    //
    //----------------------------------
    if (ptr->tag & TC_FILTER_CLOSE) {
        if (mfd) {
            flogo_yuvbuf_free(mfd->yuv, mfd->nr_of_images);
            mfd->yuv = NULL;

            if (mfd->image) {
                DestroyImage(mfd->image);
            }

            tc_free(mfd);
            mfd = NULL;
            mfd_all[instance] = NULL;
        }

        magick_usecount--;
        if (magick_usecount == 0 && IsMagickInstantiated()) {
            DestroyMagick();
        }

        return 0;
    } /* filter close */


    //----------------------------------
    //
    // filter frame routine
    //
    //----------------------------------


    // tag variable indicates, if we are called before
    // transcodes internal video/audo frame processing routines
    // or after and determines video/audio context

    if ((ptr->tag & TC_POST_M_PROCESS)
        && (ptr->tag & TC_VIDEO)
        && !(ptr->attributes & TC_FRAME_IS_SKIPPED)
    ) {
        PixelPacket *pixel_packet;
        uint8_t     *video_buf;

        int   do_fade    = 0;
        float fade_coeff = 0.0;
        float img_coeff, vid_coeff;

        /* Note: ImageMagick defines opacity = 0 as fully visible, and
         * opacity = MaxRGB as fully transparent.
         */
        Quantum opacity;

        int row, col;

        if (ptr->id < mfd->start || ptr->id > mfd->end)
            return 0;

        if (strcmp(mfd->file, "/dev/null") == 0)
            return 0;

        if (ptr->id - mfd->start < mfd->fadein) {
            // fading-in
            fade_coeff = (float)(mfd->start - ptr->id + mfd->fadein) / (float)(mfd->fadein);
            do_fade = 1;
        } else if (mfd->end - ptr->id < mfd->fadeout) {
            // fading-out
            fade_coeff = (float)(ptr->id - mfd->end + mfd->fadeout) / (float)(mfd->fadeout);
            do_fade = 1;
        }

        mfd->cur_delay--;

        if (mfd->cur_delay < 0 || mfd->ignoredelay) {
            int seq;

            mfd->cur_seq = (mfd->cur_seq + 1) % mfd->nr_of_images;

            mfd->images = mfd->image;
            for (seq=0; seq<mfd->cur_seq; seq++)
                mfd->images = mfd->images->next;

            mfd->cur_delay = mfd->images->delay * vob->fps/100;
        }

        pixel_packet = GetImagePixels(mfd->images, 0, 0,
                                      mfd->images->columns,
                                      mfd->images->rows);

        if (vob->im_v_codec == TC_CODEC_RGB24) {
            unsigned long r_off, g_off, b_off;

            if (!(rgbswap || mfd->rgbswap)) {
                r_off = 0;
                b_off = 2;
            } else {
                r_off = 2;
                b_off = 0;
            }
            g_off = 1;

            for (row = 0; row < mfd->image->rows; row++) {
                video_buf = ptr->video_buf + 3 * ((row + mfd->posy) * vob->ex_v_width + mfd->posx);

                for (col = 0; col < mfd->image->columns; col++) {
                    opacity = pixel_packet->opacity;

                    if (do_fade)
                        opacity += (Quantum)((MaxRGB - opacity) * fade_coeff);

                    if (opacity == 0) {
                        *(video_buf + r_off) = ScaleQuantumToChar(pixel_packet->red);
                        *(video_buf + g_off) = ScaleQuantumToChar(pixel_packet->green);
                        *(video_buf + b_off) = ScaleQuantumToChar(pixel_packet->blue);
                    } else if (opacity < MaxRGB) {
                        unsigned char opacity_uchar = ScaleQuantumToChar(opacity);
                        img_coeff = img_coeff_lookup[opacity_uchar];
                        vid_coeff = vid_coeff_lookup[opacity_uchar];

                        *(video_buf + r_off) = (uint8_t)((*(video_buf + r_off)) * vid_coeff)
                                                + (uint8_t)(ScaleQuantumToChar(pixel_packet->red)   * img_coeff);
                        *(video_buf + g_off) = (uint8_t)((*(video_buf + g_off)) * vid_coeff)
                                                + (uint8_t)(ScaleQuantumToChar(pixel_packet->green) * img_coeff);
                        *(video_buf + b_off) = (uint8_t)((*(video_buf + b_off)) * vid_coeff)
                                                + (uint8_t)(ScaleQuantumToChar(pixel_packet->blue)  * img_coeff);
                    }

                    video_buf += 3;
                    pixel_packet++;
                }
            }
        } else { /* !RGB */
            unsigned long vid_size = vob->ex_v_width * vob->ex_v_height;
            unsigned long img_size = mfd->images->columns * mfd->images->rows;

            uint8_t *img_pixel_Y, *img_pixel_U, *img_pixel_V;
            uint8_t *vid_pixel_Y, *vid_pixel_U, *vid_pixel_V;

            img_pixel_Y = mfd->yuv[mfd->cur_seq];
            img_pixel_U = img_pixel_Y + img_size;
            img_pixel_V = img_pixel_U + img_size/4;

            for (row = 0; row < mfd->images->rows; row++) {
                vid_pixel_Y = ptr->video_buf + (row + mfd->posy)*mfd->vob->ex_v_width + mfd->posx;
                vid_pixel_U = ptr->video_buf + vid_size + (row/2 + mfd->posy/2)*(mfd->vob->ex_v_width/2) + mfd->posx/2;
                vid_pixel_V = vid_pixel_U + vid_size/4;
                for (col = 0; col < mfd->images->columns; col++) {
                    int do_UV_pixels = (mfd->grayout == 0 && !(row % 2) && !(col % 2)) ? 1 : 0;
                    opacity = pixel_packet->opacity;

                    if (do_fade)
                        opacity += (Quantum)((MaxRGB - opacity) * fade_coeff);

                    if (opacity == 0) {
                        *vid_pixel_Y = *img_pixel_Y;
                        if (do_UV_pixels) {
                                *vid_pixel_U = *img_pixel_U;
                                *vid_pixel_V = *img_pixel_V;
                        }
                    } else if (opacity < MaxRGB) {
                        unsigned char opacity_uchar = ScaleQuantumToChar(opacity);
                        img_coeff = img_coeff_lookup[opacity_uchar];
                        vid_coeff = vid_coeff_lookup[opacity_uchar];

                        *vid_pixel_Y = (uint8_t)(*vid_pixel_Y * vid_coeff) + (uint8_t)(*img_pixel_Y * img_coeff);

                        if (do_UV_pixels) {
                            *vid_pixel_U = (uint8_t)(*vid_pixel_U * vid_coeff) + (uint8_t)(*img_pixel_U * img_coeff);
                            *vid_pixel_V = (uint8_t)(*vid_pixel_V * vid_coeff) + (uint8_t)(*img_pixel_V * img_coeff);
                        }
                    }

                    vid_pixel_Y++;
                    img_pixel_Y++;
                    if (do_UV_pixels) {
                        vid_pixel_U++;
                        img_pixel_U++;
                        vid_pixel_V++;
                        img_pixel_V++;
                    }
                    pixel_packet++;
                }
            }
        }
    }

    return 0;
}
int tc_filter(frame_list_t *ptr_, char *options)
{
  vframe_list_t *ptr = (vframe_list_t *)ptr_;
  static vob_t *vob=NULL;

  int is_interlaced = 0;
  int instance = ptr->filter_id;

  //----------------------------------
  //
  // filter init
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_GET_CONFIG) {
      char buf[255];
      optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Thomas", "VRYMEO", "1");

      tc_snprintf(buf, sizeof(buf), "%d", THRESHOLD);
      optstr_param (options, "threshold", "Interlace detection threshold", "%d", buf, "0", "255");

      tc_snprintf(buf, sizeof(buf), "%d", THRESHOLD/2);
      optstr_param (options, "chromathres", "Interlace detection chroma threshold", "%d", buf, "0", "255");

      tc_snprintf(buf, sizeof(buf), "%d", COLOR_EQUAL);
      optstr_param (options, "equal", "threshold for equal colors", "%d", buf, "0", "255");

      tc_snprintf(buf, sizeof(buf), "%d", COLOR_EQUAL/2);
      optstr_param (options, "chromaeq", "threshold for equal chroma", "%d", buf, "0", "255");

      tc_snprintf(buf, sizeof(buf), "%d", COLOR_DIFF);
      optstr_param (options, "diff", "threshold for different colors", "%d", buf, "0", "255");

      tc_snprintf(buf, sizeof(buf), "%d", COLOR_DIFF/2);
      optstr_param (options, "chromadi", "threshold for different chroma", "%d", buf, "0", "255");

      optstr_param (options, "force_mode", "set internal force de-interlace flag with mode -I N",
	      "%d", "0", "0", "5");

      optstr_param (options, "pre", "run as pre filter", "%d", "1", "0", "1");
      optstr_param (options, "verbose", "show results", "", "0");
      return (0);
  }

  if(ptr->tag & TC_FILTER_INIT) {

      if((vob = tc_get_vob())==NULL) return(-1);

      color_diff_threshold1[instance]  = COLOR_EQUAL;
      chroma_diff_threshold1[instance] = COLOR_EQUAL/2;
      color_diff_threshold2[instance]  = COLOR_DIFF;
      chroma_diff_threshold2[instance] = COLOR_DIFF/2;
      threshold[instance]              = THRESHOLD;
      chroma_threshold[instance]       = THRESHOLD/2;
      show_results[instance]           = 0;
      pre[instance]                    = 1;

      // filter init ok.

      if(verbose) tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

      // process filter options:

      if (options != NULL) {

	  if(verbose) tc_log_info(MOD_NAME, "options=%s", options);

	  optstr_get (options, "threshold", "%d",  &threshold[instance]);
	  optstr_get (options, "chromathres", "%d",  &chroma_threshold[instance]);
	  optstr_get (options, "force_mode", "%d",  &force_mode);
	  optstr_get (options, "equal", "%d",  &color_diff_threshold1[instance]);
	  optstr_get (options, "chromaeq", "%d",  &chroma_diff_threshold1[instance]);
	  optstr_get (options, "diff", "%d",  &color_diff_threshold2[instance]);
	  optstr_get (options, "chromadi", "%d",  &chroma_diff_threshold2[instance]);
	  optstr_get (options, "pre", "%d",  &pre[instance]);

	  if (optstr_lookup (options, "verbose") != NULL) {
	      show_results[instance]=1;
	  }

	  if (optstr_lookup (options, "help") != NULL) {
	      help_optstr();
	  }
      }

      return(0);
  }

  //----------------------------------
  //
  // filter close
  //
  //----------------------------------


  if(ptr->tag & TC_FILTER_CLOSE) {
    return(0);
  }

  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------


  // tag variable indicates, if we are called before
  // transcodes internal video/audo frame processing routines
  // or after and determines video/audio context

  if (!(ptr->tag & TC_VIDEO))
	  return (0);

  //if((ptr->tag & TC_PRE_M_PROCESS) && (ptr->tag & TC_VIDEO))  {
  if(((ptr->tag & TC_PRE_M_PROCESS  && pre[instance]) ||
	  (ptr->tag & TC_POST_M_PROCESS && !pre[instance])) && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

    //if (ptr->tag & TC_PRE_M_PROCESS) tc_log_msg(MOD_NAME, "32#%d pre (%d)", instance, ptr->id);
    //if (ptr->tag & TC_POST_M_PROCESS) tc_log_msg(MOD_NAME, "32#%d post (%d)", instance, ptr->id);

    if(vob->im_v_codec==CODEC_RGB) {
	is_interlaced = interlace_test(ptr->video_buf, 3*ptr->v_width, ptr->v_height, ptr->id, instance,
		threshold[instance], color_diff_threshold1[instance], color_diff_threshold2[instance]);
    } else {
	is_interlaced += interlace_test(ptr->video_buf, ptr->v_width, ptr->v_height, ptr->id, instance,
		threshold[instance], color_diff_threshold1[instance], color_diff_threshold2[instance]);
	is_interlaced += interlace_test(ptr->video_buf+ptr->v_width*ptr->v_height, ptr->v_width/2, ptr->v_height/2, ptr->id, instance,
		chroma_threshold[instance], chroma_diff_threshold1[instance], chroma_diff_threshold2[instance]);
	is_interlaced += interlace_test(ptr->video_buf+ptr->v_width*ptr->v_height*5/4, ptr->v_width/2, ptr->v_height/2, ptr->id, instance,
		chroma_threshold[instance], chroma_diff_threshold1[instance], chroma_diff_threshold2[instance]);
    }

    //force de-interlacing?
    if(force_mode && is_interlaced) {
	ptr->attributes  |= TC_FRAME_IS_INTERLACED;
	ptr->deinter_flag = force_mode;
    }

    //reset
    is_interlaced=0;

  }

  return(0);
}
Esempio n. 17
0
int main(int argc, char *argv[])
{
    int ch;
    const char *filename = NULL;
    const char *modpath = MOD_PATH;
#ifdef ENABLE_EXPERIMENTAL    
    const char *modtype = "filter";
    const char *modarg = ""; /* nothing */
    const char *modcfg = ""; /* nothing */
#endif
    const char *socketfile = NULL;
    char options[OPTS_SIZE] = { '\0', };
    int print_mod = 0;
    int connect_socket = 0;
    int ret = 0;
    int status = STATUS_NO_MODULE;

    /* needed by filter modules */
    TCVHandle tcv_handle = tcv_init();
#ifdef ENABLE_EXPERIMENTAL
    TCFactory factory = NULL;
    TCModule module = NULL;
#endif

    vframe_list_t ptr;

    memset(&ptr, 0, sizeof(ptr));

    ac_init(AC_ALL);
    tc_config_set_dir(NULL);

    if (argc == 1) {
        usage();
        return STATUS_BAD_PARAM;
    }

    libtc_init(&argc, &argv);

    while (1) {
#ifdef ENABLE_EXPERIMENTAL
        ch = getopt(argc, argv, "C:d:i:?vhpm:M:s:t:");
#else /* !ENABLE_EXPERIMENTAL */
        ch = getopt(argc, argv, "d:i:?vhps:");
#endif
        if (ch == -1) {
            break;
        }

        switch (ch) {
          case 'd':
            if (optarg[0] == '-') {
                usage();
                return STATUS_BAD_PARAM;
            }
            verbose = atoi(optarg);
            break;
          case 'i':
            if (optarg[0] == '-') {
                usage();
                return STATUS_BAD_PARAM;
            }
            filename = optarg;
            break;
#ifdef ENABLE_EXPERIMENTAL
          case 'C':
            modcfg = optarg;
            break;
          case 'm':
            modpath = optarg;
            break;
          case 'M':
            modarg = optarg;
            break;
          case 't':
            if (!optarg) {
                usage();
                return STATUS_BAD_PARAM;
            }
            if (!strcmp(optarg, "filter")
             || !strcmp(optarg, "encode")
             || !strcmp(optarg, "multiplex")) {
                modtype = optarg;
            } else {
                modtype = NULL;
            }
            break;
#endif
          case 's':
            if (optarg[0] == '-') {
                usage();
                return STATUS_BAD_PARAM;
            }
            connect_socket = 1;
            socketfile = optarg;
            break;
          case 'p':
            print_mod = 1;
            break;
          case 'v':
            version();
            return STATUS_OK;
          case '?': /* fallthrough */
          case 'h': /* fallthrough */
          default:
            usage();
            return STATUS_OK;
        }
    }

    if (print_mod) {
        printf("%s\n", modpath);
        return STATUS_OK;
    }

    if (connect_socket) {
        do_connect_socket(socketfile);
        return STATUS_OK;
    }

    if (!filename) {
        usage();
        return STATUS_BAD_PARAM;
    }

#ifdef ENABLE_EXPERIMENTAL
    if (!modtype || !strcmp(modtype, "import")) {
        tc_log_error(EXE, "Unknown module type (not in filter, encode, multiplex)");
        return STATUS_BAD_PARAM;
    }

    if (strlen(modcfg) > 0 && strlen(modarg) > 0) {
        tc_log_error(EXE, "Cannot configure and inspect module on the same time");
        return STATUS_BAD_PARAM;
    }

    /* 
     * we can't distinguish from OMS and NMS modules at glance, so try
     * first using new module system
     */
    factory = tc_new_module_factory(modpath, TC_MAX(verbose - 4, 0));
    module = tc_new_module(factory, modtype, filename, TC_NONE);

    if (module != NULL) {
        const char *answer = NULL;

        if (verbose >= TC_DEBUG) {
            tc_log_info(EXE, "using new module system");
        }
        if (strlen(modcfg) > 0) {
            int ret = tc_module_configure(module, modcfg, tc_get_vob());
            if (ret == TC_OK) {
                status = STATUS_OK;
            } else {
                status = STATUS_MODULE_FAILED;
                tc_log_error(EXE, "configure returned error");
            }
            tc_module_stop(module);
        } else {
            if (verbose >= TC_INFO) {
                /* overview and options */
                tc_module_inspect(module, "help", &answer);
                puts(answer);
                /* module capabilities */
                tc_module_show_info(module, verbose);
            }
            if (strlen(modarg) > 0) {
                tc_log_info(EXE, "informations about '%s' for "
                                 "module:", modarg);
                tc_module_inspect(module, modarg, &answer);
                puts(answer);
            }
            status = STATUS_OK;
        }
        tc_del_module(factory, module);
    } else if (!strcmp(modtype, "filter")) 
#endif /* ENABLE_EXPERIMENTAL */
    {
        char namebuf[NAME_LEN];
#ifdef ENABLE_EXPERIMENTAL
        /* compatibility support only for filters */
        if (verbose >= TC_DEBUG) {
            tc_log_info(EXE, "using old module system");
        }
#endif
        /* ok, fallback to old module system */
        strlcpy(namebuf, filename, NAME_LEN);
        filter[0].name = namebuf;
    
        ret = load_plugin(modpath, 0, verbose);
        if (ret != 0) {
            tc_log_error(__FILE__, "unable to load filter `%s' (path=%s)",
                                   filter[0].name, modpath);
            status = STATUS_NO_MODULE;
        } else {
            strlcpy(options, "help", OPTS_SIZE);
            ptr.tag = TC_FILTER_INIT;
            if ((ret = filter[0].entry(&ptr, options)) != 0) {
                status = STATUS_MODULE_ERROR;
            } else {
                memset(options, 0, OPTS_SIZE);
                ptr.tag = TC_FILTER_GET_CONFIG;
                ret = filter[0].entry(&ptr, options);

                if (ret == 0) {
                    if (verbose >= TC_INFO) {
                        fputs("START\n", stdout);
                        fputs(options, stdout);
                        fputs("END\n", stdout);
                    }
                    status = STATUS_OK;
                }
            }
        }
   }

#ifdef ENABLE_EXPERIMENTAL
   ret = tc_del_module_factory(factory);
#endif
   tcv_free(tcv_handle);
   return status;
}
Esempio n. 18
0
int tc_filter(frame_list_t *ptr_, char *options)
{
  vframe_list_t *ptr = (vframe_list_t *)ptr_;
  static vob_t *vob=NULL;
  /* FIXME: these use the filter ID as an index--the ID can grow
   * arbitrarily large, so this needs to be fixed */
  static int cdiff[100], ldiff[100], range[100];
  static float strength[100];
  int instance = ptr->filter_id;


  //----------------------------------
  //
  // filter print configure
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_GET_CONFIG) {

      char buf[32];
      optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VYEM", "1");

      // buf, name, comment, format, val, from, to
      tc_snprintf (buf, 32, "%.2f", strength[instance]);
      optstr_param (options, "strength", "Blending factor",                 "%f", buf, "0.0", "0.9");

      tc_snprintf (buf, 32, "%d", cdiff[instance]);
      optstr_param (options, "cdiff",    "Max difference in chroma values", "%d", buf, "0", "16");

      tc_snprintf (buf, 32, "%d", ldiff[instance]);
      optstr_param (options, "ldiff",    "Max difference in luma value",    "%d", buf, "0", "16");

      tc_snprintf (buf, 32, "%d", range[instance]);
      optstr_param (options, "range",    "Search Range",                    "%d", buf, "0", "16");

	return 0;
  }

  //----------------------------------
  //
  // filter init
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_INIT) {

    if((vob = tc_get_vob())==NULL) return(-1);

    // filter init ok.

    // set defaults

    strength[instance] = 0.25;	/* Blending factor.  Do not exceed 2 ever */
    cdiff[instance] = 6;		/* Max difference in UV values */
    ldiff[instance] = 8;		/* Max difference in Y value */
    range[instance] = 4;		/* Search range */

    if (options != NULL) {
    	if(verbose) tc_log_info(MOD_NAME, "options=%s", options);

	optstr_get (options, "strength",  "%f", &strength[instance]);
	optstr_get (options, "cdiff",  "%d", &cdiff[instance]);
	optstr_get (options, "ldiff",  "%d", &ldiff[instance]);
	optstr_get (options, "range",  "%d", &range[instance]);
    }

    tbuf[instance] = tc_malloc(SIZE_RGB_FRAME);
    if (strength[instance]> 0.9) strength[instance] = 0.9;
    memset(tbuf[instance], 0, SIZE_RGB_FRAME);

    if (vob->im_v_codec == TC_CODEC_RGB24) {
	if (verbose) tc_log_error(MOD_NAME, "only capable of YUV mode");
	return -1;
    }

    if(verbose) tc_log_info(MOD_NAME, "%s %s #%d", MOD_VERSION, MOD_CAP, ptr->filter_id);

    return(0);
  }

  //----------------------------------
  //
  // filter close
  //
  //----------------------------------

  if(ptr->tag & TC_FILTER_CLOSE) {
    if (tbuf[instance])
      free(tbuf[instance]);
    tbuf[instance] = NULL;

    return(0);
  }

  //----------------------------------
  //
  // filter frame routine
  //
  //----------------------------------

  // tag variable indicates, if we are called before
  // transcodes internal video/audo frame processing routines
  // or after and determines video/audio context

  if(ptr->tag & TC_PRE_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {

	if (vob->im_v_codec == TC_CODEC_YUV420P)
		smooth_yuv(ptr->video_buf, ptr->v_width, ptr->v_height, cdiff[instance],
		    ldiff[instance], range[instance], strength[instance], instance);

  }

  return(0);
}
int tc_filter(frame_list_t *ptr_, char *options)
{
    vframe_list_t *ptr = (vframe_list_t *)ptr_;
    vob_t *vob = NULL;
    tomsmocomp_t *tmc = tmc_global;

    //----------------------------------
    // filter init
    //----------------------------------

    if (ptr->tag & TC_FILTER_INIT) {

	if (! (vob = tc_get_vob ()))
	    return -1;

	if (! (tmc = tmc_global = tc_zalloc (sizeof (tomsmocomp_t)))) {
	    return -1;
	}

	if (! (tmc->tcvhandle = tcv_init())) {
	    tc_log_error(MOD_NAME, "tcv_init() failed");
	    return -1;
	}

	if (verbose)
	    tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

	/* default values */
	tmc->SearchEffort   = 11;
	tmc->UseStrangeBob  = 0;
	tmc->TopFirst       = 1;

	/* video parameters */
	switch (vob->im_v_codec) {
	case CODEC_YUY2:
	case CODEC_YUV:
	case CODEC_YUV422:
	    break;
	default:
	    tc_log_error (MOD_NAME, "only working with YUV (4:2:2 and 4:2:0) and YUY2 frame data...");
	    return -1;
	}
	tmc->codec     = vob->im_v_codec;
	tmc->width     = vob->im_v_width;
	tmc->height    = vob->im_v_height;
	tmc->size      = vob->im_v_width * vob->im_v_height * 2;
	tmc->cpuflags  = tc_accel;

	tmc->rowsize   = vob->im_v_width * 2;

	if (options) {
	    optstr_get (options, "topfirst",       "%d",
			&tmc->TopFirst);
	    optstr_get (options, "searcheffort",   "%d",
			&tmc->SearchEffort);
	    optstr_get (options, "usestrangebob",  "%d",
			&tmc->UseStrangeBob);
	    optstr_get (options, "cpuflags",  "%x",
			&tmc->cpuflags);

	    if (optstr_lookup(options, "help")) {
		help_optstr ();
	    }
	}

	/* frame memory */
	if (! (tmc->framePrev = calloc (1, tmc->size)) ||
	    ! (tmc->frameIn   = calloc (1, tmc->size)) ||
	    ! (tmc->frameOut  = calloc (1, tmc->size))) {
	    tc_log_msg(MOD_NAME, "calloc() failed");
	    return -1;
	}

	tmc->DSinfo.Overlay      = tmc->frameOut;
	tmc->DSinfo.OverlayPitch = tmc->rowsize;
	tmc->DSinfo.LineLength   = tmc->rowsize;
	tmc->DSinfo.FrameWidth   = tmc->width;
	tmc->DSinfo.FrameHeight  = tmc->height;
	tmc->DSinfo.FieldHeight  = tmc->height / 2;
	tmc->DSinfo.InputPitch   = 2* tmc->rowsize;

	tmc->DSinfo.pMemcpy = ac_memcpy;

	if (verbose) {
	    tc_log_info(MOD_NAME, "topfirst %s,  searcheffort %d,  usestrangebob %s",
		   tmc->TopFirst ? "True":"False", tmc->SearchEffort,
		   tmc->UseStrangeBob ? "True":"False");
	    tc_log_info(MOD_NAME, "cpuflags%s%s%s%s",
		   tmc->cpuflags & AC_SSE ? " SSE":"",
		   tmc->cpuflags & AC_3DNOW ? " 3DNOW":"",
		   tmc->cpuflags & AC_MMX ? " MMX":"",
		   !(tmc->cpuflags & (AC_SSE|AC_3DNOW|AC_MMX)) ? " None":"");
	}

	return 0;
    }

    //----------------------------------
    // filter close
    //----------------------------------

    if (ptr->tag & TC_FILTER_CLOSE) {
	free (tmc->framePrev);
	free (tmc->frameIn);
	free (tmc->frameOut);
	tmc->framePrev = tmc->frameIn = tmc->frameOut = NULL;
	tcv_free(tmc->tcvhandle);
	tmc->tcvhandle = 0;
	return 0;
    }

    //----------------------------------
    // filter description
    //----------------------------------
    if (ptr->tag & TC_FILTER_GET_CONFIG) {
	char buf[255];
	optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION,
			    MOD_AUTHOR, "VY4E", "1");
	tc_snprintf (buf, sizeof(buf), "%d", tmc->TopFirst);
	optstr_param (options, "topfirst", "Assume the top field should be displayed first" ,"%d", buf, "0", "1");
	tc_snprintf (buf, sizeof(buf), "%d", tmc->SearchEffort);
	optstr_param (options, "searcheffort", "CPU time used to find moved pixels" ,"%d", buf, "0", "30");
	tc_snprintf (buf, sizeof(buf), "%d", tmc->UseStrangeBob);
	optstr_param (options, "usestrangebob", "?Unknown?" ,"%d", buf, "0", "1");
	tc_snprintf (buf, sizeof(buf), "%02x", tmc->cpuflags);
	optstr_param (options, "cpuflags", "Manual specification of CPU capabilities" ,"%x", buf, "00", "ff");
    }

    //----------------------------------
    // filter frame routine
    //----------------------------------

    // need to process frames in-order
    if ((ptr->tag & TC_PRE_S_PROCESS) && (ptr->tag & TC_VIDEO)) {

	uint8_t *tmp;
	uint8_t *planes[3];
	YUV_INIT_PLANES(planes, ptr->video_buf, IMG_YUV_DEFAULT,
			tmc->width, tmc->height);

	/* Convert / Copy to yuy2 */
	switch (tmc->codec) {
	case CODEC_YUY2:
	    ac_memcpy (tmc->frameIn, ptr->video_buf, tmc->size);
	    break;
	case CODEC_YUV:
	    tcv_convert(tmc->tcvhandle, ptr->video_buf, tmc->frameIn,
			tmc->width, tmc->height, IMG_YUV_DEFAULT, IMG_YUY2);
	    break;
	case CODEC_YUV422:
	    tcv_convert(tmc->tcvhandle, ptr->video_buf, tmc->frameIn,
			tmc->width, tmc->height, IMG_YUV422P, IMG_YUY2);
	    break;
	}

	if (! (ptr->tag & TC_FRAME_IS_SKIPPED)) {

	    /* Do the deinterlacing */
	    do_deinterlace (tmc);

	    /* Now convert back */
	    switch (tmc->codec) {
	    case CODEC_YUY2:
		ac_memcpy (ptr->video_buf, tmc->frameOut, tmc->size);
		break;
	    case CODEC_YUV:
		tcv_convert(tmc->tcvhandle, tmc->frameOut,  ptr->video_buf,
			    tmc->width, tmc->height, IMG_YUY2, IMG_YUV_DEFAULT);
		break;
	    case CODEC_YUV422:
		tcv_convert(tmc->tcvhandle, tmc->frameOut,  ptr->video_buf,
			    tmc->width, tmc->height, IMG_YUY2, IMG_YUV422P);
		break;
	    default:
		tc_log_error(MOD_NAME, "codec: %x\n", tmc->codec);
		assert (0);
	    }
	}

	// The current frame gets the next previous frame
	tmp = tmc->framePrev;
	tmc->framePrev = tmc->frameIn;
	tmc->frameIn   = tmp;
    }

    return 0;
}
int tc_filter(frame_list_t *vframe_, char * options)
{
	vframe_list_t *vframe = (vframe_list_t *)vframe_;
	int instance;
	int tag = vframe->tag;
	dn3d_private_data_t * pd;

	if(tag & TC_AUDIO)
		return(0);

	instance	= vframe->filter_id;
	pd			= &dn3d_private_data[instance];

	if(tag & TC_FILTER_GET_CONFIG)
	{
		char buf[128];
		optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VYMOE", "2");

		tc_snprintf(buf, 128, "%f", DEFAULT_LUMA_SPATIAL);
		optstr_param(options, "luma", "spatial luma strength", "%f", buf, "0.0", "100.0" );

		tc_snprintf(buf, 128, "%f", DEFAULT_CHROMA_SPATIAL);
		optstr_param(options, "chroma", "spatial chroma strength", "%f", buf, "0.0", "100.0" );

		tc_snprintf(buf, 128, "%f", DEFAULT_LUMA_TEMPORAL);
		optstr_param(options, "luma_strength", "temporal luma strength", "%f", buf, "0.0", "100.0" );

		tc_snprintf(buf, 128, "%f", DEFAULT_CHROMA_TEMPORAL);
		optstr_param(options, "chroma_strength", "temporal chroma strength", "%f", buf, "0.0", "100.0" );

		tc_snprintf(buf, 128, "%d", dn3d_private_data[instance].prefilter);
		optstr_param(options, "pre", "run as a pre filter", "%d", buf, "0", "1" );
	}

	if(tag & TC_FILTER_INIT)
	{
		int format_index, plane_index, found;
		const dn3d_layout_t * lp;
		size_t size;

		if(!(pd->vob = tc_get_vob()))
			return(TC_IMPORT_ERROR);

		pd->parameter.luma_spatial		= 0;
		pd->parameter.luma_temporal		= 0;
		pd->parameter.chroma_spatial	= 0;
		pd->parameter.chroma_temporal	= 0;

		if(!options)
		{
			tc_log_error(MOD_NAME, "options not set!");
			return(TC_IMPORT_ERROR);
		}

		if(optstr_lookup(options, "help"))
		{
			help_optstr();
			return(TC_IMPORT_ERROR);
	  	}

		optstr_get(options, "luma",				"%lf",	&pd->parameter.luma_spatial);
		optstr_get(options, "luma_strength",	"%lf",	&pd->parameter.luma_temporal);
		optstr_get(options, "chroma",			"%lf",	&pd->parameter.chroma_spatial);
		optstr_get(options, "chroma_strength",	"%lf",	&pd->parameter.chroma_temporal);
		optstr_get(options, "pre",				"%d",	&dn3d_private_data[instance].prefilter);

		if((pd->parameter.luma_spatial < 0) || (pd->parameter.luma_temporal < 0))
			pd->enable_luma = 0;
		else
		{
			pd->enable_luma = 1;

			if(pd->parameter.luma_spatial == 0)
			{
				if(pd->parameter.luma_temporal == 0)
				{
					pd->parameter.luma_spatial	= DEFAULT_LUMA_SPATIAL;
					pd->parameter.luma_temporal	= DEFAULT_LUMA_TEMPORAL;
				}
				else
				{
					pd->parameter.luma_spatial = pd->parameter.luma_temporal * 3 / 2;
				}
			}
			else
			{
				if(pd->parameter.luma_temporal == 0)
				{
					pd->parameter.luma_temporal = pd->parameter.luma_spatial * 2 / 3;
				}
			}
		}

		if((pd->parameter.chroma_spatial < 0) || (pd->parameter.chroma_temporal < 0))
			pd->enable_chroma = 0;
		else
		{
			pd->enable_chroma = 1;

			if(pd->parameter.chroma_spatial == 0)
			{
				if(pd->parameter.chroma_temporal == 0)
				{
					pd->parameter.chroma_spatial	= DEFAULT_CHROMA_SPATIAL;
					pd->parameter.chroma_temporal	= DEFAULT_CHROMA_TEMPORAL;
				}
				else
				{
					pd->parameter.chroma_spatial = pd->parameter.chroma_temporal * 3 / 2;
				}
			}
			else
			{
				if(pd->parameter.chroma_temporal == 0)
				{
					pd->parameter.chroma_temporal = pd->parameter.chroma_spatial * 2 / 3;
				}
			}
		}

		for(format_index = 0, found = 0; format_index < (sizeof(dn3d_layout) / sizeof(*dn3d_layout)); format_index++)
		{
			if(pd->vob->im_v_codec == dn3d_layout[format_index].tc_fmt)
			{
				found = 1;
				break;
			}
		}

		if(!found)
		{
			tc_log_error(MOD_NAME, "This filter is only capable of YUV, YUV422 and RGB mode");
	  		return(TC_IMPORT_ERROR);
		}

		lp = &dn3d_layout[format_index];
		pd->layout_data = *lp;

		for(plane_index = 0; plane_index < MAX_PLANES; plane_index++)
		{
			if((pd->layout_data.layout[plane_index].plane_type == dn3d_luma) && !pd->enable_luma)
				pd->layout_data.layout[plane_index].plane_type = dn3d_disabled;

			if((pd->layout_data.layout[plane_index].plane_type == dn3d_chroma) && !pd->enable_chroma)
				pd->layout_data.layout[plane_index].plane_type = dn3d_disabled;
		}

		size = pd->vob->im_v_width * MAX_PLANES * sizeof(char) * 2;

		pd->lineant = tc_zalloc(size);
		if(pd->lineant == NULL)
			tc_log_error(MOD_NAME, "Malloc failed");

		size *= pd->vob->im_v_height * 2;

		pd->previous = tc_zalloc(size);
		if(pd->previous == NULL)
			tc_log_error(MOD_NAME, "Malloc failed");

		PrecalcCoefs(pd->coefficients[0], pd->parameter.luma_spatial);
		PrecalcCoefs(pd->coefficients[1], pd->parameter.luma_temporal);
		PrecalcCoefs(pd->coefficients[2], pd->parameter.chroma_spatial);
		PrecalcCoefs(pd->coefficients[3], pd->parameter.chroma_temporal);

		if(verbose)
		{
			tc_log_info(MOD_NAME, "%s %s #%d", MOD_VERSION, MOD_CAP, instance);
			tc_log_info(MOD_NAME, "Settings luma (spatial): %.2f "
                                  "luma_strength (temporal): %.2f "
                                  "chroma (spatial): %.2f "
                                  "chroma_strength (temporal): %.2f",
				        pd->parameter.luma_spatial,
        				pd->parameter.luma_temporal,
		        		pd->parameter.chroma_spatial,
				        pd->parameter.chroma_temporal);
			tc_log_info(MOD_NAME, "luma enabled: %s, chroma enabled: %s",
		                pd->enable_luma ? "yes" : "no",
                        pd->enable_chroma ? "yes" : "no");
		}
	}

	if(((tag & TC_PRE_M_PROCESS  && pd->prefilter) || (tag & TC_POST_M_PROCESS && !pd->prefilter)) &&
		!(vframe->attributes & TC_FRAME_IS_SKIPPED))
	{
		int plane_index, coef[2];
		int offset = 0;
		const dn3d_single_layout_t * lp;

		for(plane_index = 0; plane_index < MAX_PLANES; plane_index++)
		{
			lp = &pd->layout_data.layout[plane_index];

			if(lp->plane_type != dn3d_disabled)
			{
				// if(plane_index != 2) // debug
				//	continue;

				coef[0] = (lp->plane_type == dn3d_luma) ? 0 : 2;
				coef[1] = coef[0] + 1;

				switch(lp->offset)
				{
					case(dn3d_off_r):		offset = 0; break;
					case(dn3d_off_g):		offset = 1; break;
					case(dn3d_off_b):		offset = 2; break;

					case(dn3d_off_y420):	offset = vframe->v_width * vframe->v_height * 0 / 4; break;
					case(dn3d_off_u420):	offset = vframe->v_width * vframe->v_height * 4 / 4; break;
					case(dn3d_off_v420):	offset = vframe->v_width * vframe->v_height * 5 / 4; break;

					case(dn3d_off_y422):	offset = vframe->v_width * vframe->v_height * 0 / 2; break;
					case(dn3d_off_u422):	offset = vframe->v_width * vframe->v_height * 2 / 2; break;
					case(dn3d_off_v422):	offset = vframe->v_width * vframe->v_height * 3 / 2; break;

				}

				deNoise(vframe->video_buf,			// frame
					pd->previous,					// previous (saved) frame
					pd->lineant,					// line buffer
					vframe->v_width / lp->scale_x,	// width (pixels)
					vframe->v_height / lp->scale_y,	// height (pixels) // debug
					pd->coefficients[coef[0]],		// horizontal (spatial) strength
					pd->coefficients[coef[0]],		// vertical (spatial) strength
					pd->coefficients[coef[1]],		// temporal strength
					offset,							// offset in bytes of first relevant pixel in frame
					lp->skip						// skip this amount of bytes between two pixels
				);
			}
		}
	}

	if(tag & TC_FILTER_CLOSE)
	{
		if(pd->previous)
		{
			free(pd->previous);
			pd->previous = 0;
		}

		if(pd->lineant)
		{
			free(pd->lineant);
			pd->lineant = 0;
		}
	}

	return(0);
}
/*
 * transcode API
 */
int tc_filter(frame_list_t *ptr_, char *options)
{
    vframe_list_t *ptr = (vframe_list_t *)ptr_;
    vob_t *vob = NULL;
    myfilter_t *myf = myf_global;

    /*
     * filter init
     */
    if (ptr->tag & TC_FILTER_INIT) {

	if (! (vob = tc_get_vob ()))
	    return -1;

	if (! (myf = myf_global = tc_zalloc (sizeof (myfilter_t)))) {
	    return -1;
	}

	if (! (myf->tcvhandle = tcv_init())) {
	    tc_log_error(MOD_NAME, "tcv_init() failed");
	    free(myf);
	    myf = myf_global = NULL;
	    return -1;
	}

	if (verbose)			/* global verbose */
	    tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);

	/* default values */
	myf->interlaceDiff       = 1.1;
	myf->unknownDiff         = 1.5;
	myf->progressiveDiff     = 8;
	myf->progressiveChange   = 0.2;
	myf->changedIfMore       = 10;

	myf->forceTelecineDetect = 0;
	myf->verbose             = 0;
	myf->outDiff             = 0;

	/* video parameters */
	switch (vob->im_v_codec) {
	case TC_CODEC_YUY2:
	case TC_CODEC_YUV420P:
	case TC_CODEC_YUV422P:
	case TC_CODEC_RGB24:
	    break;
	default:
	    tc_log_error(MOD_NAME,
                     "Unsupported codec - need one of RGB24 YUV420P YUY2 YUV422P");
	    return -1;
	}
	myf->codec     = vob->im_v_codec;
	myf->width     = vob->im_v_width;
	myf->height    = vob->im_v_height;
	myf->fps       = vob->fps;
	myf->size = myf->width * myf->height;

	if (options) {
	    optstr_get (options, "interlacediff",     "%lf",
			&myf->interlaceDiff);
	    optstr_get (options, "unknowndiff",       "%lf",
			&myf->unknownDiff);
	    optstr_get (options, "progressivediff",   "%lf",
			&myf->progressiveDiff);
	    optstr_get (options, "progressivechange", "%lf",
			&myf->progressiveChange);
	    optstr_get (options, "changedifmore",     "%lf",
			&myf->changedIfMore);
	    optstr_get (options, "forcetelecinedetect",
		        "%d", &myf->forceTelecineDetect);
	    optstr_get (options, "verbose",          "%d", &myf->verbose);
	    optstr_get (options, "outdiff",          "%d", &myf->outDiff);

	    if (optstr_lookup (options, "help") != NULL) {
		tc_log_info (MOD_NAME, "(%s) help\n"
"* Overview:\n"
"  'fieldanalysis' scans video for interlacing artifacts and\n"
"  detects progressive / interlaced / telecined video.\n"
"  It also determines the major field for interlaced video.\n"
"* Verbose Output:   [PtPb c t stsb]\n"
"  Pt, Pb:   progressivediff succeeded, per field.\n"
"  pt, pb:   unknowndiff succeeded, progressivediff failed.\n"
"  c:        progressivechange succeeded.\n"
"  t:        topFieldFirst / b: bottomFieldFirst detected.\n"
"  st, sb:   changedifmore failed (fields are similar to last frame).\n"
			     , MOD_CAP);
	    }
	}

	/* frame memory */
	if (! (myf->lumIn    = calloc (1, myf->size)) ||
	    ! (myf->lumPrev  = calloc (1, myf->size)) ||
	    ! (myf->lumInT   = calloc (1, myf->size)) ||
	    ! (myf->lumInB   = calloc (1, myf->size)) ||
	    ! (myf->lumPrevT = calloc (1, myf->size)) ||
	    ! (myf->lumPrevB = calloc (1, myf->size))) {
	    tc_log_error(MOD_NAME, "calloc() failed");
	    return -1;
	}

	if (verbose) {			/* global verbose */
	    tc_log_info(MOD_NAME, "interlacediff %.2f,  unknowndiff %.2f,  progressivediff %.2f",
		                        myf->interlaceDiff, myf->unknownDiff, myf->progressiveDiff);
        tc_log_info(MOD_NAME, "progressivechange %.2f, changedifmore %.2f",
                    		   myf->progressiveChange, myf->changedIfMore);
        tc_log_info(MOD_NAME, "forcetelecinedetect %s, verbose %d, outdiff %d",
                    		   myf->forceTelecineDetect ? "True":"False", myf->verbose,
                               myf->outDiff);
	}

	return 0;
    }

    /*
     * filter close
     */

    if (ptr->tag & TC_FILTER_CLOSE) {

	int total = myf->numFrames - myf->unknownFrames;
	int totalfields = myf->topFirstFrames + myf->bottomFirstFrames;

	/* Cleanup */
	free (myf->lumIn);
	free (myf->lumPrev);
	free (myf->lumInT);
	free (myf->lumInB);
	free (myf->lumPrevT);
	free (myf->lumPrevB);
	myf->lumIn = myf->lumPrev = myf->lumInT = myf->lumInB =
	    myf->lumPrevT = myf->lumPrevB = NULL;

	/* Output results */
	if (totalfields < 1)
	    totalfields = 1;
	tc_log_info(MOD_NAME, "RESULTS: Frames:      %d (100%%)  Unknown:      %d (%.3g%%)",
		                myf->numFrames, myf->unknownFrames,
                		100.0 * myf->unknownFrames / (double)myf->numFrames);
    tc_log_info(MOD_NAME, "RESULTS: Progressive: %d (%.3g%%)  Interlaced:   %d (%.3g%%)",
		myf->progressiveFrames, 100.0 * myf->progressiveFrames / (double)myf->numFrames,
		myf->interlacedFrames, 100.0 * myf->interlacedFrames / (double)myf->numFrames);
    tc_log_info(MOD_NAME, "RESULTS: FieldShift:  %d (%.3g%%)  Telecined:    %d (%.3g%%)",
		myf->fieldShiftFrames, 100.0 * myf->fieldShiftFrames / (double)myf->numFrames,
		myf->telecineFrames, 100.0 * myf->telecineFrames / (double)myf->numFrames);
    tc_log_info(MOD_NAME, "RESULTS: MajorField: TopFirst %d (%.3g%%)  BottomFirst %d (%.3g%%)",
		myf->topFirstFrames, 100.0 * myf->topFirstFrames / (double)totalfields,
		myf->bottomFirstFrames, 100.0 * myf->bottomFirstFrames / (double)totalfields);

	if (total < 50)
	    tc_log_warn (MOD_NAME, "less than 50 frames analyzed correctly, no conclusion.");
	else if (myf->unknownFrames * 10 > myf->numFrames * 9)
	    tc_log_warn (MOD_NAME, "less than 10%% frames analyzed correctly, no conclusion.");
	else if (myf->progressiveFrames * 8 > total * 7)
	    tc_log_info (MOD_NAME, "CONCLUSION: progressive video.");
	else if (myf->topFirstFrames * 8 > myf->bottomFirstFrames &&
		 myf->bottomFirstFrames * 8 > myf->topFirstFrames)
	    tc_log_info (MOD_NAME, "major field unsure, no conclusion. Use deinterlacer for processing.");
	else if (myf->telecineFrames * 4 > total * 3)
	    tc_log_info (MOD_NAME, "CONCLUSION: telecined video, %s field first.",
                        myf->topFirstFrames > myf->bottomFirstFrames ? "top" : "bottom");
	else if (myf->fieldShiftFrames * 4 > total * 3)
	    tc_log_info (MOD_NAME, "CONCLUSION: field shifted progressive video, %s field first.",
                        myf->topFirstFrames > myf->bottomFirstFrames ? "top" : "bottom");
	else if (myf->interlacedFrames > myf->fieldShiftFrames &&
		 (myf->interlacedFrames+myf->fieldShiftFrames) * 8 > total * 7)
	    tc_log_info (MOD_NAME, "CONCLUSION: interlaced video, %s field first.",
                        myf->topFirstFrames > myf->bottomFirstFrames ? "top" : "bottom");
	else
	    tc_log_info (MOD_NAME, "mixed video, no conclusion. Use deinterlacer for processing.");

	tcv_free(myf->tcvhandle);
	myf->tcvhandle = 0;

	return 0;
    }

    /*
     * filter description
     */
    if (ptr->tag & TC_FILTER_GET_CONFIG) {
	char buf[255];
	optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION,
			    MOD_AUTHOR, "VRY4E", "2");
	tc_snprintf (buf, sizeof(buf), "%g", myf->interlaceDiff);
	optstr_param (options, "interlacediff", "Minimum temporal inter-field difference for detecting interlaced video", "%f", buf, "1.0", "inf");
	tc_snprintf (buf, sizeof(buf), "%g", myf->unknownDiff);
	optstr_param (options, "unknowndiff", "Maximum inter-frame change vs. detail differences for neglecting interlaced video", "%f", buf, "1.0", "inf");
	tc_snprintf (buf, sizeof(buf), "%g", myf->progressiveDiff);
	optstr_param (options, "progressivediff", "Minimum inter-frame change vs. detail differences for detecting progressive video" ,"%f", buf, "unknowndiff", "inf");
	tc_snprintf (buf, sizeof(buf), "%g", myf->progressiveChange);
	optstr_param (options, "progressivechange", "Minimum temporal change needed for detecting progressive video" ,"%f", buf, "0", "inf");
	tc_snprintf (buf, sizeof(buf), "%g", myf->changedIfMore);
	optstr_param (options, "changedifmore", "Minimum temporal change for detecting truly changed frames" ,"%f", buf, "0", "65025");
	tc_snprintf (buf, sizeof(buf), "%d", myf->forceTelecineDetect);
	optstr_param (options, "forcetelecinedetect", "Detect telecine even on non-NTSC (29.97fps) video", "%d", buf, "0", "1");
	tc_snprintf (buf, sizeof(buf), "%d", myf->verbose);
	optstr_param (options, "verbose", "Output analysis for every frame", "%d", buf, "0", "2");
	tc_snprintf (buf, sizeof(buf), "%d", myf->outDiff);
	optstr_param (options, "outdiff", "Output internal debug frames as luminance of YUV video (see source)", "%d", buf, "0", "11");
    }

    /*
     * filter frame routine
     */
    /* need to process frames in-order */
    if ((ptr->tag & TC_PRE_S_PROCESS) && (ptr->tag & TC_VIDEO)) {

	uint8_t *tmp;
	int i, j;

	assert (ptr->free == 0 || ptr->free == 1);
	assert (ptr->video_buf_Y[!ptr->free] == ptr->video_buf);

	/* Convert / Copy to luminance only */
	switch (myf->codec) {
	case TC_CODEC_RGB24:
	    tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn,
			myf->width, myf->height, IMG_RGB_DEFAULT, IMG_Y8);
	    break;
	case TC_CODEC_YUY2:
	    tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn,
			myf->width, myf->height, IMG_YUY2, IMG_Y8);
	    break;
	case TC_CODEC_YUV420P:
	    tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn,
			myf->width, myf->height, IMG_YUV_DEFAULT, IMG_Y8);
	    break;
	case TC_CODEC_YUV422P:
	    tcv_convert(myf->tcvhandle, ptr->video_buf, myf->lumIn,
			myf->width, myf->height, IMG_YUV422P, IMG_Y8);
	    break;
	default:
	    assert (0);
	}

	/* Bob Top field */
	bob_field (myf->lumIn, myf->lumInT, myf->width, myf->height/2-1);
	/* Bob Bottom field */
	ac_memcpy (myf->lumInB, myf->lumIn + myf->width, myf->width);
	bob_field (myf->lumIn + myf->width, myf->lumInB + myf->width,
	           myf->width, myf->height/2-1);
	/* last copied line is ignored, buffer is large enough */

	if (myf->numFrames == 0)
	    myf->numFrames++;
	else if (! (ptr->tag & TC_FRAME_IS_SKIPPED)) {
	    /* check_it */
	    check_interlace (myf, ptr->id);
	}

	/* only works with YUV data correctly */
	switch (myf->outDiff) {
	case 1:				/* lumIn */
	    ac_memcpy (ptr->video_buf, myf->lumIn, myf->size);
	    break;
	case 2:				/* field shift */
	    for (i = 0 ; i < myf->height-2; i += 2)
		for (j = 0; j < myf->width; j++) {
		    ptr->video_buf [myf->width*i+j] =
			myf->lumIn [myf->width*i+j];
		    ptr->video_buf [myf->width*(i+1)+j] =
			myf->lumPrev [myf->width*(i+1)+j];
		}
	    break;
	case 3:				/* lumInT */
	    ac_memcpy (ptr->video_buf, myf->lumInT, myf->size);
	    break;
	case 4:				/* lumInB */
	    ac_memcpy (ptr->video_buf, myf->lumInB, myf->size);
	    break;
	case 5:				/* lumPrevT */
	    ac_memcpy (ptr->video_buf, myf->lumPrevT, myf->size);
	    break;
	case 6:				/* lumPrevB */
	    ac_memcpy (ptr->video_buf, myf->lumPrevB, myf->size);
	    break;
	case 7:				/* pixDiff */
	    pic_diff (myf->lumInT, myf->lumInB,   ptr->video_buf, myf->size,4);
	    break;
	case 8:				/* pixShiftChangedT */
	    pic_diff (myf->lumInT, myf->lumPrevB, ptr->video_buf, myf->size,4);
	    break;
	case 9:				/* pixShiftChangedB */
	    pic_diff (myf->lumInB, myf->lumPrevT, ptr->video_buf, myf->size,4);
	    break;
	case 10:			/* pixLastT */
	    pic_diff (myf->lumInT, myf->lumPrevT, ptr->video_buf, myf->size,4);
	    break;
	case 11:			/* pixLastB */
	    pic_diff (myf->lumInB, myf->lumPrevB, ptr->video_buf, myf->size,4);
	    break;
	}

	/* The current frame gets the next previous frame :-P */
	tmp = myf->lumPrev;   myf->lumPrev  = myf->lumIn;   myf->lumIn  = tmp;
	tmp = myf->lumPrevT;  myf->lumPrevT = myf->lumInT;  myf->lumInT = tmp;
	tmp = myf->lumPrevB;  myf->lumPrevB = myf->lumInB;  myf->lumInB = tmp;
    }

    return 0;
}