struct mp_image *convert_image(struct mp_image *image, int destfmt, struct mp_log *log) { int d_w, d_h; mp_image_params_get_dsize(&image->params, &d_w, &d_h); bool is_anamorphic = image->w != d_w || image->h != d_h; // Caveat: no colorspace/levels conversion done if pixel formats equal // it's unclear what colorspace/levels the target wants if (image->imgfmt == destfmt && !is_anamorphic) return mp_image_new_ref(image); struct mp_image *dst = mp_image_alloc(destfmt, d_w, d_h); if (!dst) { mp_err(log, "Out of memory.\n"); return NULL; } mp_image_copy_attributes(dst, image); if (mp_image_swscale(dst, image, mp_sws_hq_flags) < 0) { mp_err(log, "Error when converting image.\n"); talloc_free(dst); return NULL; } return dst; }
void mp_get_src_dst_rects(struct mp_log *log, struct mp_vo_opts *opts, int vo_caps, struct mp_image_params *video, int window_w, int window_h, double monitor_par, struct mp_rect *out_src, struct mp_rect *out_dst, struct mp_osd_res *out_osd) { int src_w = video->w; int src_h = video->h; int src_dw, src_dh; mp_image_params_get_dsize(video, &src_dw, &src_dh); if (video->rotate % 180 == 90 && (vo_caps & VO_CAP_ROTATE90)) { MPSWAP(int, src_w, src_h); MPSWAP(int, src_dw, src_dh); } window_w = MPMAX(1, window_w); window_h = MPMAX(1, window_h); struct mp_rect dst = {0, 0, window_w, window_h}; struct mp_rect src = {0, 0, src_w, src_h}; struct mp_osd_res osd = { .w = window_w, .h = window_h, .display_par = monitor_par, }; if (opts->keepaspect) { int scaled_width, scaled_height; aspect_calc_panscan(log, opts, src_w, src_h, src_dw, src_dh, window_w, window_h, monitor_par, &scaled_width, &scaled_height); src_dst_split_scaling(src_w, window_w, scaled_width, opts->unscaled, opts->zoom, opts->align_x, opts->pan_x, &src.x0, &src.x1, &dst.x0, &dst.x1, &osd.ml, &osd.mr); src_dst_split_scaling(src_h, window_h, scaled_height, opts->unscaled, opts->zoom, opts->align_y, opts->pan_y, &src.y0, &src.y1, &dst.y0, &dst.y1, &osd.mt, &osd.mb); } *out_src = src; *out_dst = dst; *out_osd = osd; int sw = src.x1 - src.x0, sh = src.y1 - src.y0; int dw = dst.x1 - dst.x0, dh = dst.y1 - dst.y0; mp_verbose(log, "Window size: %dx%d\n", window_w, window_h); mp_verbose(log, "Video source: %dx%d (%d:%d)\n", video->w, video->h, video->p_w, video->p_h); mp_verbose(log, "Video display: (%d, %d) %dx%d -> (%d, %d) %dx%d\n", src.x0, src.y0, sw, sh, dst.x0, dst.y0, dw, dh); mp_verbose(log, "Video scale: %f/%f\n", (double)dw / sw, (double)dh / sh); mp_verbose(log, "OSD borders: l=%d t=%d r=%d b=%d\n", osd.ml, osd.mt, osd.mr, osd.mb); mp_verbose(log, "Video borders: l=%d t=%d r=%d b=%d\n", dst.x0, dst.y0, window_w - dst.x1, window_h - dst.y1); }
static int reconfig(struct vf_instance *vf, struct mp_image_params *in, struct mp_image_params *out) { struct vf_priv_s *p = vf->priv; *out = *in; if (p->outfmt) out->imgfmt = p->outfmt; if (p->colormatrix) out->colorspace = p->colormatrix; if (p->colorlevels) out->colorlevels = p->colorlevels; if (p->primaries) out->primaries = p->primaries; if (p->gamma) out->gamma = p->gamma; if (p->chroma_location) out->chroma_location = p->chroma_location; if (p->stereo_in) out->stereo_in = p->stereo_in; if (p->stereo_out) out->stereo_out = p->stereo_out; if (p->rotate >= 0) out->rotate = p->rotate; AVRational dsize; mp_image_params_get_dsize(out, &dsize.num, &dsize.den); if (p->dw > 0) dsize.num = p->dw; if (p->dh > 0) dsize.den = p->dh; if (p->dar > 0) dsize = av_d2q(p->dar, INT_MAX); mp_image_params_set_dsize(out, dsize.num, dsize.den); // Make sure the user-overrides are consistent (no RGB csp for YUV, etc.). mp_image_params_guess_csp(out); return 0; }
static int reinit_vs(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; VSMap *vars = NULL, *in = NULL, *out = NULL; int res = -1; destroy_vs(vf); MP_DBG(vf, "initializing...\n"); p->initializing = true; if (p->drv->load_core(vf) < 0 || !p->vsapi || !p->vscore) { MP_FATAL(vf, "Could not get vapoursynth API handle.\n"); goto error; } in = p->vsapi->createMap(); out = p->vsapi->createMap(); vars = p->vsapi->createMap(); if (!in || !out || !vars) goto error; p->vsapi->createFilter(in, out, "Input", infiltInit, infiltGetFrame, infiltFree, fmSerial, 0, vf, p->vscore); int vserr; p->in_node = p->vsapi->propGetNode(out, "clip", 0, &vserr); if (!p->in_node) { MP_FATAL(vf, "Could not get our own input node.\n"); goto error; } if (p->vsapi->propSetNode(vars, "video_in", p->in_node, 0)) goto error; int d_w, d_h; mp_image_params_get_dsize(&p->fmt_in, &d_w, &d_h); p->vsapi->propSetInt(vars, "video_in_dw", d_w, 0); p->vsapi->propSetInt(vars, "video_in_dh", d_h, 0); p->vsapi->propSetFloat(vars, "container_fps", vf->chain->container_fps, 0); p->vsapi->propSetFloat(vars, "display_fps", vf->chain->display_fps, 0); if (p->drv->load(vf, vars) < 0) goto error; if (!p->out_node) { MP_FATAL(vf, "Could not get script output node.\n"); goto error; } const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); if (!isConstantFormat(vi)) { MP_FATAL(vf, "Video format is required to be constant.\n"); goto error; } pthread_mutex_lock(&p->lock); p->initializing = false; pthread_mutex_unlock(&p->lock); MP_DBG(vf, "initialized.\n"); res = 0; error: if (p->vsapi) { p->vsapi->freeMap(in); p->vsapi->freeMap(out); p->vsapi->freeMap(vars); } if (res < 0) destroy_vs(vf); return res; }
struct mp_image *convert_image(struct mp_image *image, int destfmt, struct mp_log *log) { int d_w, d_h; mp_image_params_get_dsize(&image->params, &d_w, &d_h); struct mp_image_params p = { .imgfmt = destfmt, .w = d_w, .h = d_h, .p_w = 1, .p_h = 1, }; mp_image_params_guess_csp(&p); // If RGB, just assume everything is correct. if (p.color.space != MP_CSP_RGB) { // Currently, assume what FFmpeg's jpg encoder needs. // Of course this works only for non-HDR (no HDR support in libswscale). p.color.levels = MP_CSP_LEVELS_PC; p.color.space = MP_CSP_BT_601; p.chroma_location = MP_CHROMA_CENTER; mp_image_params_guess_csp(&p); } if (mp_image_params_equal(&p, &image->params)) return mp_image_new_ref(image); struct mp_image *dst = mp_image_alloc(p.imgfmt, p.w, p.h); if (!dst) { mp_err(log, "Out of memory.\n"); return NULL; } mp_image_copy_attributes(dst, image); dst->params = p; if (mp_image_swscale(dst, image, mp_sws_hq_flags) < 0) { mp_err(log, "Error when converting image.\n"); talloc_free(dst); return NULL; } return dst; } bool write_image(struct mp_image *image, const struct image_writer_opts *opts, const char *filename, struct mp_log *log) { struct image_writer_opts defs = image_writer_opts_defaults; if (!opts) opts = &defs; struct image_writer_ctx ctx = { log, opts, image->fmt }; bool (*write)(struct image_writer_ctx *, mp_image_t *, FILE *) = write_lavc; int destfmt = 0; #if HAVE_JPEG if (opts->format == AV_CODEC_ID_MJPEG) { write = write_jpeg; destfmt = IMGFMT_RGB24; } #endif if (!destfmt) destfmt = get_target_format(&ctx); struct mp_image *dst = convert_image(image, destfmt, log); if (!dst) return false; FILE *fp = fopen(filename, "wb"); bool success = false; if (fp == NULL) { mp_err(log, "Error opening '%s' for writing!\n", filename); } else { success = write(&ctx, dst, fp); success = !fclose(fp) && success; if (!success) mp_err(log, "Error writing file '%s'!\n", filename); } talloc_free(dst); return success; } void dump_png(struct mp_image *image, const char *filename, struct mp_log *log) { struct image_writer_opts opts = image_writer_opts_defaults; opts.format = AV_CODEC_ID_PNG; write_image(image, &opts, filename, log); }