static int tc_im_configure(TCModuleInstance *self, const char *options, vob_t *vob, TCModuleExtraData *xdata[]) { TCCodecID id = TC_CODEC_ERROR; TCIMPrivateData *pd = NULL; int ret = 0; TC_MODULE_SELF_CHECK(self, "configure"); pd = self->userdata; pd->quality = DEFAULT_QUALITY; pd->width = vob->ex_v_width; pd->height = vob->ex_v_height; pd->img_fmt[0] = '\0'; ret = optstr_get(options, "format", "%15s", pd->img_fmt); if (ret != 1) { /* missing option, let's use the default */ strlcpy(pd->img_fmt, DEFAULT_FORMAT, sizeof(pd->img_fmt)); } else { /* the user gave us something */ id = tc_codec_from_string(pd->img_fmt); if (id == TC_CODEC_ERROR) { tc_log_error(MOD_NAME, "unknown format: `%s'", pd->img_fmt); return TC_ERROR; } if (!is_supported(id)) { tc_log_error(MOD_NAME, "unsupported format: `%s'", pd->img_fmt); return TC_ERROR; } } ret = optstr_get(options, "quality", "%lu", &pd->quality); if (ret != 1) { pd->quality = DEFAULT_QUALITY; } if (verbose >= TC_INFO) { tc_log_info(MOD_NAME, "encoding %s with quality %lu", pd->img_fmt, pd->quality); } ret = tc_magick_init(&pd->magick, pd->quality); if (ret != TC_OK) { tc_log_error(MOD_NAME, "cannot create Magick context"); return ret; } return TC_OK; }
static int tc_x11_configure(TCModuleInstance *self, const char *options, vob_t *vob) { TCX11PrivateData *priv = NULL; int ret = 0, skew_lim = SKEW_LIM_DEFAULT; TC_MODULE_SELF_CHECK(self, "configure"); priv = self->userdata; if (options != NULL) { optstr_get(options, "skew_limit", "%i", &skew_lim); if (skew_lim < SKEW_LIM_MIN || skew_lim > SKEW_LIM_MAX) { tc_log_warn(MOD_NAME, "skew limit value out of range," " reset to defaults [%i]", SKEW_LIM_DEFAULT); } } priv->skew = 0; priv->reftime = 0; priv->expired = 0; priv->frame_delay = (uint64_t)(1000000.0 / vob->fps); /* microseconds */ priv->skew_limit = priv->frame_delay / frame_delay_divs[skew_lim]; if (verbose >= TC_DEBUG) { tc_log_info(MOD_NAME, "frame delay: %lu ms", (unsigned long)priv->frame_delay); tc_log_info(MOD_NAME, "skew limit: %li ms", (long)priv->skew_limit); } ret = tc_timer_init_soft(&priv->timer, 0); if (ret != 0) { tc_log_error(MOD_NAME, "configure: can't initialize timer"); return TC_ERROR; } /* nothing to do here, yet */ ret = tc_x11source_is_display_name(vob->video_in_file); if (ret == TC_FALSE) { tc_log_error(MOD_NAME, "configure: given source doesn't look like" " a DISPLAY specifier"); return TC_ERROR; } ret = tc_x11source_open(&priv->src, vob->video_in_file, TC_X11_MODE_BEST, vob->im_v_codec); if (ret != 0) { tc_log_error(MOD_NAME, "configure: failed to open X11 connection" " to '%s'", vob->video_in_file); return TC_ERROR; } return TC_OK; }
static int doublefps_configure(TCModuleInstance *self, const char *options, vob_t *vob) { DfpsPrivateData *pd; int new_topfirst = -1; TC_MODULE_SELF_CHECK(self, "configure"); pd = self->userdata; if (options) { if (optstr_get(options, "shiftEven", "%d", &pd->topfirst) == 1) { tc_log_warn(MOD_NAME, "The \"shiftEven\" option name is obsolete;" " please use \"topfirst\" instead."); } optstr_get(options, "topfirst", "%d", &new_topfirst); optstr_get(options, "fullheight", "%d", &pd->fullheight); } if (new_topfirst == -1) { if (pd->topfirst == -1) pd->topfirst = (vob->im_v_height == 480 ? 0 : 1); } else { pd->topfirst = new_topfirst; } if (!pd->fullheight) { if (vob->encode_fields == TC_ENCODE_FIELDS_TOP_FIRST || vob->encode_fields == TC_ENCODE_FIELDS_BOTTOM_FIRST ) { pd->topfirst = (vob->encode_fields == TC_ENCODE_FIELDS_TOP_FIRST); if (vob->export_attributes & TC_EXPORT_ATTRIBUTE_FIELDS) { tc_log_warn(MOD_NAME, "Use \"-J doublefps=topfirst=%d\"," " not \"--encode_fields %c\"", pd->topfirst, pd->topfirst ? 't' : 'b'); } } vob->encode_fields = TC_ENCODE_FIELDS_PROGRESSIVE; vob->export_attributes |= TC_EXPORT_ATTRIBUTE_FIELDS; } return TC_OK; }
static int flogo_parse_options(LogoPrivateData *pd, const char *options, char *logo_file) { /* default */ strlcpy(logo_file, DEFAULT_LOGO_FILE, PATH_MAX); optstr_get(options, "file", "%[^:]", logo_file); optstr_get(options, "posdef", "%d", (int *)&pd->pos); optstr_get(options, "pos", "%dx%d", &pd->posx, &pd->posy); optstr_get(options, "range", "%u-%u", &pd->start, &pd->end); optstr_get(options, "fade", "%u-%u", &pd->fadein, &pd->fadeout); if (optstr_lookup(options, "ignoredelay") != NULL) pd->ignoredelay = !pd->ignoredelay; if (optstr_lookup(options, "flip") != NULL) pd->flip = !pd->flip; if (optstr_lookup(options, "rgbswap") != NULL) pd->rgbswap = !pd->rgbswap; if (optstr_lookup(options, "grayout") != NULL) pd->grayout = !pd->grayout; if (optstr_lookup(options, "hqconv") != NULL) pd->hqconv = !pd->hqconv; if (verbose) { tc_log_info(MOD_NAME, " Logo renderer Settings:"); tc_log_info(MOD_NAME, " file = %s", logo_file); tc_log_info(MOD_NAME, " posdef = %d", pd->pos); tc_log_info(MOD_NAME, " pos = %dx%d", pd->posx, pd->posy); tc_log_info(MOD_NAME, " range = %u-%u", pd->start, pd->end); tc_log_info(MOD_NAME, " fade = %u-%u", pd->fadein, pd->fadeout); tc_log_info(MOD_NAME, " flip = %d", pd->flip); tc_log_info(MOD_NAME, " ignoredelay = %d", pd->ignoredelay); tc_log_info(MOD_NAME, " rgbswap = %d", pd->rgbswap); tc_log_info(MOD_NAME, " grayout = %d", pd->grayout); tc_log_info(MOD_NAME, " hqconv = %d", pd->hqconv); } return TC_OK; }
static int astat_configure(TCModuleInstance *self, const char *options, vob_t *vob) { AStatPrivateData *pd = NULL; TC_MODULE_SELF_CHECK(self, "configure"); pd = self->userdata; /* re-enforce defaults */ pd->min = 0; pd->max = 0; pd->filepath = NULL; pd->silence_limit = SILENCE_MAX_VALUE; if (options) { char buf[1024]; int ret = optstr_get(options, "file", "%[^:]", buf); // XXX if (ret > 0) { pd->filepath = tc_strdup(buf); if (pd->filepath == NULL) { return TC_ERROR; } if (verbose) { tc_log_info(MOD_NAME, "saving audio scale value to '%s'", pd->filepath); } } optstr_get(options, "silence_limit", "%u", &pd->silence_limit); if (verbose) { tc_log_info(MOD_NAME, "silence threshold value: %i", pd->silence_limit); } } return TC_OK; }
static int lowpass_configure(TCModuleInstance *self, const char *options, TCJob *vob, TCModuleExtraData *xdata[]) { LowPassPrivateData *pd = NULL; TC_MODULE_SELF_CHECK(self, "configure"); pd = self->userdata; if (vob->a_bits != 16) { tc_log_error(MOD_NAME, "This filter only supports 16 bit samples"); return TC_ERROR; } pd->taps = 30; pd->highpass = 0; pd->p = 0; pd->is_mono = (vob->a_chan == 1); if (options != NULL) { optstr_get(options, "taps", "%i", &pd->taps); } if (pd->taps < 0) { pd->taps = -pd->taps; pd->highpass = 1; } pd->array_r = tc_zalloc(pd->taps * sizeof(int16_t)); pd->array_l = tc_zalloc(pd->taps * sizeof(int16_t)); if (!pd->array_r || !pd->array_l) { return TC_ERROR; } if (verbose) { tc_log_info(MOD_NAME, "taps = %i (%spass)", pd->taps, (pd->highpass) ?"high" :"low"); } return TC_OK; }
static int invert_configure(TCModuleInstance *self, const char *options, vob_t *vob) { InvertPrivateData *mfd = NULL; TC_MODULE_SELF_CHECK(vob, "configure"); TC_MODULE_SELF_CHECK(self, "configure"); mfd = self->userdata; /* setup defaults */ mfd->start = 0; mfd->end = (unsigned int)-1; mfd->step = 1; if (options != NULL) { if(verbose >= TC_STATS){ tc_log_info(MOD_NAME, "options=%s", options); } optstr_get(options, "range", "%u-%u/%d", &mfd->start, &mfd->end, &mfd->step); } if (verbose > TC_INFO) { tc_log_info(MOD_NAME, " Invert Image Settings:"); tc_log_info(MOD_NAME, " range = %u-%u", mfd->start, mfd->end); tc_log_info(MOD_NAME, " step = %u", mfd->step); } if (mfd->start % mfd->step == 0) mfd->boolstep = 0; else mfd->boolstep = 1; return TC_OK; }
static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; FilterData *fd = ctx->priv; FILE* f; // char* filenamecopy, *filebasename; const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[inlink->format]; TransformData* td = &(fd->td); VSFrameInfo fi_src; VSFrameInfo fi_dest; if(!initFrameInfo(&fi_src, inlink->w, inlink->h, AV2OurPixelFormat(ctx,inlink->format)) || !initFrameInfo(&fi_dest, inlink->w, inlink->h, AV2OurPixelFormat(ctx, inlink->format))){ av_log(ctx, AV_LOG_ERROR, "unknown pixel format: %i (%s)", inlink->format, desc->name); return AVERROR(EINVAL); } // check if(fi_src.bytesPerPixel != av_get_bits_per_pixel(desc)/8 || fi_src.log2ChromaW != desc->log2_chroma_w || fi_src.log2ChromaH != desc->log2_chroma_h){ av_log(ctx, AV_LOG_ERROR, "pixel-format error: bpp %i<>%i ", fi_src.bytesPerPixel, av_get_bits_per_pixel(desc)/8); av_log(ctx, AV_LOG_ERROR, "chroma_subsampl: w: %i<>%i h: %i<>%i\n", fi_src.log2ChromaW, desc->log2_chroma_w, fi_src.log2ChromaH, desc->log2_chroma_h); return AVERROR(EINVAL); } if(initTransformData(td, &fi_src, &fi_dest, "transform") != VS_OK){ av_log(ctx, AV_LOG_ERROR, "initialization of TransformData failed\n"); return AVERROR(EINVAL); } td->verbose=1; // TODO: get from somewhere /// TODO: find out input name // fd->input = (char*)av_malloc(VS_INPUT_MAXLEN); // filenamecopy = strndup(fd->vob->video_in_file); // filebasename = basename(filenamecopy); // if (strlen(filebasename) < VS_INPUT_MAXLEN - 4) { // snprintf(fd->result, VS_INPUT_MAXLEN, "%s.trf", filebasename); //} else { // av_log(ctx, AV_LOG_WARN, "input name too long, using default `%s'", // DEFAULT_TRANS_FILE_NAME); snprintf(fd->input, VS_INPUT_MAXLEN, DEFAULT_TRANS_FILE_NAME); // } if (fd->options != NULL) { if(optstr_lookup(fd->options, "help")) { av_log(ctx, AV_LOG_INFO, transform_help); return AVERROR(EINVAL); } optstr_get(fd->options, "input", "%[^:]", fd->input); optstr_get(fd->options, "maxshift", "%d", &td->maxShift); optstr_get(fd->options, "maxangle", "%lf", &td->maxAngle); optstr_get(fd->options, "smoothing", "%d", &td->smoothing); optstr_get(fd->options, "crop" , "%d", &td->crop); optstr_get(fd->options, "invert" , "%d", &td->invert); optstr_get(fd->options, "relative" , "%d", &td->relative); optstr_get(fd->options, "zoom" , "%lf",&td->zoom); optstr_get(fd->options, "optzoom" , "%d", &td->optZoom); optstr_get(fd->options, "interpol" , "%d", (int*)(&td->interpolType)); optstr_get(fd->options, "sharpen" , "%lf",&td->sharpen); if(optstr_lookup(fd->options, "tripod")){ av_log(ctx,AV_LOG_INFO, "Virtual tripod mode: relative=False, smoothing=0"); td->relative=0; td->smoothing=0; } } if(configureTransformData(td)!= VS_OK){ av_log(ctx, AV_LOG_ERROR, "configuration of Tranform failed\n"); return AVERROR(EINVAL); } av_log(ctx, AV_LOG_INFO, "Image Transformation/Stabilization Settings:\n"); av_log(ctx, AV_LOG_INFO, " input = %s\n", fd->input); av_log(ctx, AV_LOG_INFO, " smoothing = %d\n", td->smoothing); av_log(ctx, AV_LOG_INFO, " maxshift = %d\n", td->maxShift); av_log(ctx, AV_LOG_INFO, " maxangle = %f\n", td->maxAngle); av_log(ctx, AV_LOG_INFO, " crop = %s\n", td->crop ? "Black" : "Keep"); av_log(ctx, AV_LOG_INFO, " relative = %s\n", td->relative ? "True": "False"); av_log(ctx, AV_LOG_INFO, " invert = %s\n", td->invert ? "True" : "False"); av_log(ctx, AV_LOG_INFO, " zoom = %f\n", td->zoom); av_log(ctx, AV_LOG_INFO, " optzoom = %s\n", td->optZoom ? "On" : "Off"); av_log(ctx, AV_LOG_INFO, " interpol = %s\n", interpolTypes[td->interpolType]); av_log(ctx, AV_LOG_INFO, " sharpen = %f\n", td->sharpen); f = fopen(fd->input, "r"); if (f == NULL) { av_log(ctx, AV_LOG_ERROR, "cannot open input file %s!\n", fd->input); } else { ManyLocalMotions mlms; if(readLocalMotionsFile(f,&mlms)==VS_OK){ // calculate the actual transforms from the localmotions if(localmotions2TransformsSimple(td, &mlms,&fd->trans)!=VS_OK) av_log(ctx, AV_LOG_ERROR, "calculating transformations failed!\n"); }else{ // try to read old format if (!readOldTransforms(td, f, &fd->trans)) { /* read input file */ av_log(ctx, AV_LOG_ERROR, "error parsing input file %s!\n", fd->input); } } } fclose(f); if (preprocessTransforms(td, &fd->trans)!= VS_OK ) { av_log(ctx, AV_LOG_ERROR, "error while preprocessing transforms\n"); return AVERROR(EINVAL); } // TODO: add sharpening 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); }
int bktr_parse_options(char *options) { char format[128]; char vsource[128]; char asource[128]; char tuner[128]; int i; if (optstr_lookup(options, "help") != NULL) { bktr_usage(); return(1); } if (optstr_lookup(options, "hwfps") != NULL) bktr_hwfps = 1; if (optstr_lookup(options, "mute") != NULL) bktr_mute = 1; if (optstr_get(options, "format", "%[^:]", &format) >= 0) { for (i = 0; formats[i].name; i++) if (strncmp(formats[i].name, format, 128) == 0) break; if (formats[i].name) bktr_format = formats[i].format; else { tc_log_warn(MOD_NAME, "invalid format: %s", format); return(1); } } if (optstr_get(options, "vsource", "%[^:]", &vsource) >= 0) { for (i = 0; vsources[i].name; i++) if (strncmp(vsources[i].name, vsource, 128) == 0) break; if (vsources[i].name) bktr_vsource = vsources[i].vsource; else { tc_log_warn(MOD_NAME, "invalid vsource: %s", vsource); return(1); } } if (optstr_get(options, "asource", "%[^:]", &asource) >= 0) { for (i = 0; asources[i].name; i++) if (strncmp(asources[i].name, asource, 128) == 0) break; if (asources[i].name) bktr_asource = asources[i].asource; else { tc_log_warn(MOD_NAME, "invalid asource: %s", asource); return(1); } } if (optstr_get(options, "tunerdev", "%[^:]", &tuner) >= 0) strlcpy(bktr_tuner, tuner, sizeof(bktr_tuner)); return(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); }
/** * transform_configure: Configure this instance of the module. See * tcmodule-data.h for function details. */ static int transform_configure(TCModuleInstance *self, const char *options, vob_t *vob) { FilterData *fd = NULL; char* filenamecopy, *filebasename; FILE* f; TC_MODULE_SELF_CHECK(self, "configure"); fd = self->userdata; VSTransformData* td = &(fd->td); fd->vob = vob; if (!fd->vob) return TC_ERROR; /* cannot happen */ /**** Initialise private data structure */ VSFrameInfo fi_src; VSFrameInfo fi_dest; vsFrameInfoInit(&fi_src, fd->vob->ex_v_width, fd->vob->ex_v_height, transcode2ourPF(fd->vob->im_v_codec)); vsFrameInfoInit(&fi_dest, fd->vob->ex_v_width, fd->vob->ex_v_height, transcode2ourPF(fd->vob->im_v_codec)); VSTransformConfig conf = vsTransformGetDefaultConfig(MOD_NAME); conf.verbose = verbose; fd->sharpen = 0.8; vsTransformationsInit(&fd->trans); filenamecopy = tc_strdup(fd->vob->video_in_file); filebasename = basename(filenamecopy); if (strlen(filebasename) < TC_BUF_LINE - 4) { tc_snprintf(fd->input, TC_BUF_LINE, "%s.trf", filebasename); } else { tc_log_warn(MOD_NAME, "input name too long, using default `%s'", DEFAULT_TRANS_FILE_NAME); tc_snprintf(fd->input, TC_BUF_LINE, DEFAULT_TRANS_FILE_NAME); } /* process remaining options */ if (options != NULL) { // We support also the help option. if(optstr_lookup(options, "help")) { tc_log_info(MOD_NAME,vs_transform_help); return(TC_IMPORT_ERROR); } optstr_get(options, "input", "%[^:]", (char*)&fd->input); optstr_get(options, "maxshift", "%d", &conf.maxShift); optstr_get(options, "maxangle", "%lf", &conf.maxAngle); optstr_get(options, "smoothing", "%d", &conf.smoothing); optstr_get(options, "invert" , "%d", &conf.invert); optstr_get(options, "relative" , "%d", &conf.relative); optstr_get(options, "zoom" ,"%lf", &conf.zoom); optstr_get(options, "optzoom" , "%d", &conf.optZoom); optstr_get(options, "zoomspeed", "%lf",&conf.zoomSpeed); optstr_get(options, "interpol" , "%d", (int*)(&conf.interpolType)); optstr_get(options, "sharpen" ,"%lf", &fd->sharpen); if(optstr_lookup(options, "tripod")){ tc_log_info(MOD_NAME,"Virtual tripod mode: relative=False, smoothing=0"); conf.relative=0; conf.smoothing=0; } } if(vsTransformDataInit(td, &conf, &fi_src, &fi_dest) != VS_OK){ tc_log_error(MOD_NAME, "initialization of VSTransformData failed"); return TC_ERROR; } vsTransformGetConfig(&conf,td); if (verbose) { tc_log_info(MOD_NAME, "Image Transformation/Stabilization Settings:"); tc_log_info(MOD_NAME, " input = %s", fd->input); tc_log_info(MOD_NAME, " smoothing = %d", conf.smoothing); tc_log_info(MOD_NAME, " maxshift = %d", conf.maxShift); tc_log_info(MOD_NAME, " maxangle = %f", conf.maxAngle); tc_log_info(MOD_NAME, " crop = %s", conf.crop ? "Black" : "Keep"); tc_log_info(MOD_NAME, " relative = %s", conf.relative ? "True": "False"); tc_log_info(MOD_NAME, " invert = %s", conf.invert ? "True" : "False"); tc_log_info(MOD_NAME, " zoom = %f", conf.zoom); tc_log_info(MOD_NAME, " optzoom = %d", conf.optZoom); if(conf.optZoom==2){ tc_log_info(MOD_NAME, " zoomspeed = %f", conf.zoomSpeed); } tc_log_info(MOD_NAME, " interpol = %s", getInterpolationTypeName(conf.interpolType)); tc_log_info(MOD_NAME, " sharpen = %f", fd->sharpen); } f = fopen(fd->input, "r"); if (f == NULL) { tc_log_error(MOD_NAME, "cannot open input file %s!\n", fd->input); /* return (-1); when called using tcmodinfo this will fail */ } else { VSManyLocalMotions mlms; if(vsReadLocalMotionsFile(f,&mlms)==VS_OK){ // calculate the actual transforms from the localmotions if(vsLocalmotions2Transforms(td, &mlms,&fd->trans)!=VS_OK) tc_log_error(MOD_NAME, "calculating transformations failed!\n"); }else{ // try to read old format if (!vsReadOldTransforms(td, f, &fd->trans)) { /* read input file */ tc_log_error(MOD_NAME, "error parsing input file %s!\n", fd->input); } } } fclose(f); if (vsPreprocessTransforms(td, &fd->trans)!= VS_OK ) { tc_log_error(MOD_NAME, "error while preprocessing transforms!"); return TC_ERROR; } // sharpen is still in transcode... /* Is this the right point to add the filter? Seems to be the case.*/ if(fd->sharpen>0){ /* load unsharp filter */ char unsharp_param[256]; sprintf(unsharp_param,"luma=%f:%s:chroma=%f:%s", fd->sharpen, "luma_matrix=5x5", fd->sharpen/2, "chroma_matrix=5x5"); if (!tc_filter_add("unsharp", unsharp_param)) { tc_log_warn(MOD_NAME, "cannot load unsharp filter!"); } } return TC_OK; }
static int faac_configure(TCModuleInstance *self, const char *options, TCJob *vob, TCModuleExtraData *xdata[]) { PrivateData *pd; int samplerate = vob->mp3frequency ? vob->mp3frequency : vob->a_rate; int ret; unsigned long dummy; faacEncConfiguration conf; TC_MODULE_SELF_CHECK(self, "configure"); pd = self->userdata; /* Save bytes per sample */ pd->bps = (vob->dm_chan * vob->dm_bits) / 8; /* Create FAAC handle (freeing any old one that might be left over) */ if (pd->handle) faacEncClose(pd->handle); pd->handle = faacEncOpen(samplerate, vob->dm_chan, &pd->framesize, &dummy); if (!pd->handle) { tc_log_error(MOD_NAME, "FAAC initialization failed"); return TC_ERROR; } /* Set up our default audio parameters */ /* why can't just use a pointer here? -- FR */ /* Because the function returns a pointer to an internal buffer --AC */ conf = *faacEncGetCurrentConfiguration(pd->handle); conf.mpegVersion = MPEG4; conf.aacObjectType = MAIN; conf.allowMidside = 1; conf.useLfe = 0; conf.useTns = 1; conf.bitRate = vob->mp3bitrate / vob->dm_chan; conf.bandWidth = 0; // automatic configuration conf.quantqual = 100; // FIXME: quality should be a per-module setting conf.outputFormat = 1; if (vob->dm_bits != 16) { tc_log_error(MOD_NAME, "Only 16-bit samples supported"); return TC_ERROR; } conf.inputFormat = FAAC_INPUT_16BIT; conf.shortctl = SHORTCTL_NORMAL; ret = optstr_get(options, "quality", "%li", &conf.quantqual); if (ret >= 0) { if (verbose >= TC_INFO) { tc_log_info(MOD_NAME, "using quality=%li", conf.quantqual); } } if (!faacEncSetConfiguration(pd->handle, &conf)) { tc_log_error(MOD_NAME, "Failed to set FAAC configuration"); faacEncClose(pd->handle); pd->handle = 0; return TC_ERROR; } /* Allocate local audio buffer */ if (pd->audiobuf) free(pd->audiobuf); pd->audiobuf = tc_malloc(pd->framesize * pd->bps); if (!pd->audiobuf) { tc_log_error(MOD_NAME, "Unable to allocate audio buffer"); faacEncClose(pd->handle); pd->handle = 0; return TC_ERROR; } pd->need_flush = TC_FALSE; return TC_OK; }
/* * 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; }
/* * deshake_configure: Configure this instance of the module. See * tcmodule-data.h for function details. */ static int deshake_configure(TCModuleInstance *self, const char *options, vob_t *vob) { DeshakeData *sd = NULL; TC_MODULE_SELF_CHECK(self, "configure"); char* filenamecopy, *filebasename; sd = self->userdata; /* sd->framesize = sd->vob->im_v_width * MAX_PLANES * sizeof(char) * 2 * sd->vob->im_v_height * 2; */ MotionDetect* md = &(sd->md); TransformData* td = &(sd->td); // init MotionDetect part VSFrameInfo fi; initFrameInfo(&fi, sd->vob->ex_v_width, sd->vob->ex_v_height, transcode2ourPF(sd->vob->im_v_codec)); if(initMotionDetect(md, &fi, MOD_NAME) != VS_OK){ tc_log_error(MOD_NAME, "initialization of Motion Detection failed"); return TC_ERROR; } sd->result = tc_malloc(TC_BUF_LINE); filenamecopy = tc_strdup(sd->vob->video_in_file); filebasename = basename(filenamecopy); if (strlen(filebasename) < TC_BUF_LINE - 4) { tc_snprintf(sd->result, TC_BUF_LINE, "%s.trf", filebasename); } else { tc_log_warn(MOD_NAME, "input name too long, using default `%s'", DEFAULT_TRANS_FILE_NAME); tc_snprintf(sd->result, TC_BUF_LINE, DEFAULT_TRANS_FILE_NAME); } // init trasform part VSFrameInfo fi_dest; initFrameInfo(&fi_dest, sd->vob->ex_v_width, sd->vob->ex_v_height, transcode2ourPF(sd->vob->im_v_codec)); if(initTransformData(td, &fi, &fi_dest, MOD_NAME) != VS_OK){ tc_log_error(MOD_NAME, "initialization of TransformData failed"); return TC_ERROR; } td->verbose=verbose; if (options != NULL) { // for some reason this plugin is called in the old fashion // (not with inspect). Anyway we support both ways of getting help. if(optstr_lookup(options, "help")) { tc_log_info(MOD_NAME,deshake_help); return(TC_IMPORT_ERROR); } optstr_get(options, "result", "%[^:]", sd->result); optstr_get(options, "shakiness", "%d", &md->shakiness); optstr_get(options, "accuracy", "%d", &md->accuracy); optstr_get(options, "stepsize", "%d", &md->stepSize); optstr_get(options, "algo", "%d", &md->algo); optstr_get(options, "mincontrast","%lf",&md->contrastThreshold); md->show = 0; optstr_get(options, "maxshift", "%d", &td->maxShift); optstr_get(options, "maxangle", "%lf", &td->maxAngle); optstr_get(options, "smoothing", "%d", &td->smoothing); optstr_get(options, "crop" , "%d", (int*)&td->crop); optstr_get(options, "zoom" , "%lf",&td->zoom); optstr_get(options, "optzoom" , "%d", &td->optZoom); optstr_get(options, "interpol" , "%d", (int*)(&td->interpolType)); optstr_get(options, "sharpen" , "%lf",&td->sharpen); td->relative=1; td->invert=0; } if(configureMotionDetect(md)!= VS_OK){ tc_log_error(MOD_NAME, "configuration of Motion Detection failed"); return TC_ERROR; } if(configureTransformData(td)!= VS_OK){ tc_log_error(MOD_NAME, "configuration of Tranform failed"); return TC_ERROR; } if (verbose) { tc_log_info(MOD_NAME, "Video Deshake Settings:"); tc_log_info(MOD_NAME, " smoothing = %d", td->smoothing); tc_log_info(MOD_NAME, " shakiness = %d", md->shakiness); tc_log_info(MOD_NAME, " accuracy = %d", md->accuracy); tc_log_info(MOD_NAME, " stepsize = %d", md->stepSize); tc_log_info(MOD_NAME, " algo = %d", md->algo); tc_log_info(MOD_NAME, " mincontrast = %f", md->contrastThreshold); tc_log_info(MOD_NAME, " show = %d", md->show); tc_log_info(MOD_NAME, " result = %s", sd->result); tc_log_info(MOD_NAME, " maxshift = %d", td->maxShift); tc_log_info(MOD_NAME, " maxangle = %f", td->maxAngle); tc_log_info(MOD_NAME, " crop = %s", td->crop ? "Black" : "Keep"); tc_log_info(MOD_NAME, " zoom = %f", td->zoom); tc_log_info(MOD_NAME, " optzoom = %s", td->optZoom ? "On" : "Off"); tc_log_info(MOD_NAME, " interpol = %s", interpolTypes[td->interpolType]); tc_log_info(MOD_NAME, " sharpen = %f", td->sharpen); } sd->avg.initialized=0; sd->f = fopen(sd->result, "w"); if (sd->f == NULL) { tc_log_error(MOD_NAME, "cannot open result file %s!\n", sd->result); return TC_ERROR; } return TC_OK; }
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); }
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 *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_; 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); }
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) { 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 *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); }
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", ¶meters->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) { 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); }
// 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]); }