static void uninit(struct vo *vo) { struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); forget_frames(p->ctx, true); p->ctx->img_params = (struct mp_image_params){0}; p->ctx->reconfigured = true; p->ctx->active = NULL; update(p); pthread_mutex_unlock(&p->ctx->lock); } static int preinit(struct vo *vo) { struct vo_priv *p = vo->priv; p->vo = vo; p->ctx = vo->extra.opengl_cb_context; if (!p->ctx) { MP_FATAL(vo, "No context set.\n"); return -1; } pthread_mutex_lock(&p->ctx->lock); if (!p->ctx->initialized) { MP_FATAL(vo, "OpenGL context not initialized.\n"); pthread_mutex_unlock(&p->ctx->lock); return -1; } p->ctx->active = vo; p->ctx->reconfigured = true; p->ctx->update_new_opts = true; copy_vo_opts(vo); pthread_mutex_unlock(&p->ctx->lock); return 0; } #define OPT_BASE_STRUCT struct vo_priv static const struct m_option options[] = { OPT_FLAG("debug", use_gl_debug, 0), OPT_INTRANGE("frame-queue-size", frame_queue_size, 0, 1, 100, OPTDEF_INT(2)), OPT_CHOICE("frame-drop-mode", frame_drop_mode, 0, ({"pop", FRAME_DROP_POP}, {"clear", FRAME_DROP_CLEAR},
int i = 0; af->control=control; af->filter_frame = filter; af_drc_t *priv = af->priv; priv->mul = MUL_INIT; priv->lastavg = ((float)SHRT_MAX) * DEFAULT_TARGET; priv->idx = 0; for (i = 0; i < NSAMPLES; i++) { priv->mem[i].len = 0; priv->mem[i].avg = 0; } priv->mid_s16 = ((float)SHRT_MAX) * priv->mid_float; return AF_OK; } #define OPT_BASE_STRUCT af_drc_t const struct af_info af_info_drc = { .info = "Dynamic range compression filter", .name = "drc", .flags = AF_FLAGS_NOT_REENTRANT, .open = af_open, .priv_size = sizeof(af_drc_t), .options = (const struct m_option[]) { OPT_INTRANGE("method", method, 0, 1, 2, OPTDEF_INT(1)), OPT_FLOAT("target", mid_float, 0, OPTDEF_FLOAT(DEFAULT_TARGET)), {0} }, };
vf->control = control; vf->uninit = uninit; p->max_requests = p->cfg_maxrequests; if (p->max_requests < 0) p->max_requests = av_cpu_count(); MP_VERBOSE(vf, "using %d concurrent requests.\n", p->max_requests); int maxbuffer = p->cfg_maxbuffer * p->max_requests; p->buffered = talloc_array(vf, struct mp_image *, maxbuffer); p->requested = talloc_zero_array(vf, struct mp_image *, p->max_requests); return 1; } #define OPT_BASE_STRUCT struct vf_priv_s static const m_option_t vf_opts_fields[] = { OPT_STRING("file", cfg_file, M_OPT_FILE), OPT_INTRANGE("buffered-frames", cfg_maxbuffer, 0, 1, 9999, OPTDEF_INT(4)), OPT_CHOICE_OR_INT("concurrent-frames", cfg_maxrequests, 0, 1, 99, ({"auto", -1}), OPTDEF_INT(-1)), {0} }; #if HAVE_VAPOURSYNTH #include <VSScript.h> static int drv_vss_init(struct vf_instance *vf) { if (!vsscript_init()) { MP_FATAL(vf, "Could not initialize VapourSynth scripting.\n"); return -1; }
flush(vf); return CONTROL_OK; } return CONTROL_UNKNOWN; } static void uninit(vf_instance_t *vf) { flush(vf); } static int vf_open(vf_instance_t *vf) { vf->filter_ext = filter_ext; vf->control = control; vf->uninit = uninit; return 1; } #define OPT_BASE_STRUCT struct vf_priv_s const vf_info_t vf_info_buffer = { .description = "buffer a number of frames", .name = "buffer", .open = vf_open, .priv_size = sizeof(struct vf_priv_s), .options = (const struct m_option[]){ OPT_INTRANGE("num", cfg_num, 0, 1, MAX_Q, OPTDEF_INT(2)), {0} }, };
#define INITIAL_PROBE_SIZE STREAM_BUFFER_SIZE #define PROBE_BUF_SIZE FFMIN(STREAM_MAX_BUFFER_SIZE, 2 * 1024 * 1024) #define OPT_BASE_STRUCT struct MPOpts // Should correspond to IO_BUFFER_SIZE in libavformat/aviobuf.c (not public) // libavformat (almost) always reads data in blocks of this size. #define BIO_BUFFER_SIZE 32768 const m_option_t lavfdopts_conf[] = { OPT_INTRANGE("probesize", lavfdopts.probesize, 0, 32, INT_MAX), OPT_STRING("format", lavfdopts.format, 0), OPT_FLOATRANGE("analyzeduration", lavfdopts.analyzeduration, 0, 0, 3600), OPT_INTRANGE("buffersize", lavfdopts.buffersize, 0, 1, 10 * 1024 * 1024, OPTDEF_INT(BIO_BUFFER_SIZE)), OPT_FLAG("allow-mimetype", lavfdopts.allow_mimetype, 0), OPT_INTRANGE("probescore", lavfdopts.probescore, 0, 0, 100), OPT_STRING("cryptokey", lavfdopts.cryptokey, 0), OPT_CHOICE("genpts-mode", lavfdopts.genptsmode, 0, ({"lavf", 1}, {"no", 0})), OPT_STRING("o", lavfdopts.avopt, 0), {NULL, NULL, 0, 0, 0, 0, NULL} }; #define MAX_PKT_QUEUE 50 typedef struct lavf_priv { char *filename; const struct format_hack *format_hack; AVInputFormat *avif;
if (ch >= AF_NCH) { MP_FATAL(af, "[channels] Can't have more than %d routes.\n", AF_NCH); return AF_ERROR; } sscanf(cp, "%i-%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n); MP_VERBOSE(af, "[channels] Routing from channel %i to" " channel %i\n",s->route[ch][FR],s->route[ch][TO]); cp = &cp[n]; ch++; } while(*cp == ',' && *(cp++)); s->nr = ch; if (s->nr > 0) s->router = 1; } return AF_OK; } #define OPT_BASE_STRUCT af_channels_t struct af_info af_info_channels = { .info = "Insert or remove channels", .name = "channels", .open = af_open, .priv_size = sizeof(af_channels_t), .options = (const struct m_option[]) { OPT_INTRANGE("nch", nch, 0, 1, AF_NCH, OPTDEF_INT(2)), OPT_STRING("routes", routes, 0), {0} }, };
af audio filter instance returns AF_OK or AF_ERROR */ static int af_open( struct af_instance* af ) { af->control = control; af->uninit = uninit; af->filter_frame = filter; af_export_t *priv = af->priv; if (!priv->filename || !priv->filename[0]) { MP_FATAL(af, "no export filename given"); return AF_ERROR; } return AF_OK; } #define OPT_BASE_STRUCT af_export_t const struct af_info af_info_export = { .info = "Sound export filter", .name = "export", .open = af_open, .priv_size = sizeof(af_export_t), .options = (const struct m_option[]) { OPT_STRING("filename", filename, 0), OPT_INTRANGE("buffersamples", sz, 0, 1, 2048, OPTDEF_INT(DEF_SZ)), {0} }, };
static void VS_CC infiltInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi) { struct vf_instance *vf = *instanceData; struct vf_priv_s *p = vf->priv; // Note: this is called from createFilter, so no need for locking. VSVideoInfo fmt = { .format = p->vsapi->getFormatPreset(mp_to_vs(p->fmt_in.imgfmt), p->vscore), .width = p->fmt_in.w, .height = p->fmt_in.h, }; if (!fmt.format) { p->vsapi->setError(out, "Unsupported input format.\n"); return; } p->vsapi->setVideoInfo(&fmt, 1, node); p->in_node_active = true; } static const VSFrameRef *VS_CC infiltGetFrame(int frameno, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { struct vf_instance *vf = *instanceData; struct vf_priv_s *p = vf->priv; VSFrameRef *ret = NULL; pthread_mutex_lock(&p->lock); while (1) { if (p->shutdown) break; if (frameno < p->in_frameno) { p->vsapi->setFilterError("Requesting a frame too far in the past. " "Try increasing the maxbuffer suboption", frameCtx); break; } if (frameno >= p->in_frameno + MP_TALLOC_ELEMS(p->buffered)) { // Too far in the future. Remove frames, so that the main thread can // queue new frames. if (p->num_buffered) { drain_oldest_buffered_frame(p); pthread_cond_broadcast(&p->wakeup); continue; } } if (frameno < p->in_frameno + p->num_buffered) { struct mp_image *img = p->buffered[frameno - p->in_frameno]; const VSFormat *vsfmt = vsapi->getFormatPreset(mp_to_vs(img->imgfmt), core); ret = vsapi->newVideoFrame(vsfmt, img->w, img->h, NULL, core); if (!ret) { p->vsapi->setFilterError("Could not allocate VS frame", frameCtx); break; } struct mp_image vsframe = map_vs_frame(p, ret, true); mp_image_copy(&vsframe, img); VSMap *map = p->vsapi->getFramePropsRW(ret); if (map) { int res = 1e6; int dur = img->pts * res + 0.5; p->vsapi->propSetInt(map, "_DurationNum", dur, 0); p->vsapi->propSetInt(map, "_DurationDen", res, 0); copy_mp_to_vs_frame_props(p, map, img); } break; } pthread_cond_wait(&p->wakeup, &p->lock); } pthread_mutex_unlock(&p->lock); return ret; } static void VS_CC infiltFree(void *instanceData, VSCore *core, const VSAPI *vsapi) { struct vf_instance *vf = instanceData; struct vf_priv_s *p = vf->priv; pthread_mutex_lock(&p->lock); p->in_node_active = false; pthread_cond_broadcast(&p->wakeup); pthread_mutex_unlock(&p->lock); } static void destroy_vs(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; // Wait until our frame callback returns. pthread_mutex_lock(&p->lock); p->shutdown = true; pthread_cond_broadcast(&p->wakeup); while (p->getting_frame) pthread_cond_wait(&p->wakeup, &p->lock); pthread_mutex_unlock(&p->lock); if (p->in_node) p->vsapi->freeNode(p->in_node); if (p->out_node) p->vsapi->freeNode(p->out_node); p->in_node = p->out_node = NULL; if (p->se) vsscript_freeScript(p->se); p->se = NULL; p->vsapi = NULL; p->vscore = NULL; assert(!p->in_node_active); p->shutdown = false; talloc_free(p->got_frame); p->got_frame = NULL; // Kill queued frames too for (int n = 0; n < p->num_buffered; n++) talloc_free(p->buffered[n]); p->num_buffered = 0; talloc_free(p->next_image); p->next_image = NULL; p->prev_pts = MP_NOPTS_VALUE; p->out_frameno = p->in_frameno = 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); // First load an empty script to get a VSScript, so that we get the vsapi // and vscore. if (vsscript_evaluateScript(&p->se, "", NULL, 0)) goto error; p->vsapi = vsscript_getVSApi(); p->vscore = vsscript_getCore(p->se); if (!p->vsapi || !p->vscore) 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) goto error; if (p->vsapi->propSetNode(vars, "video_in", p->in_node, 0)) goto error; vsscript_setVariable(p->se, vars); if (vsscript_evaluateFile(&p->se, p->cfg_file, 0)) { MP_FATAL(vf, "Script evaluation failed:\n%s\n", vsscript_getError(p->se)); goto error; } p->out_node = vsscript_getOutput(p->se, 0); if (!p->out_node) 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; } 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; } static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int fmt) { struct vf_priv_s *p = vf->priv; p->fmt_in = (struct mp_image_params){ .imgfmt = fmt, .w = width, .h = height, }; if (reinit_vs(vf) < 0) return 0; const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); fmt = mp_from_vs(vi->format->id); if (!fmt) { MP_FATAL(vf, "Unsupported output format.\n"); destroy_vs(vf); return 0; } vf_rescale_dsize(&d_width, &d_height, width, height, vi->width, vi->height); return vf_next_config(vf, vi->width, vi->height, d_width, d_height, flags, fmt); } static int query_format(struct vf_instance *vf, unsigned int fmt) { return mp_to_vs(fmt) != pfNone ? VFCAP_CSP_SUPPORTED : 0; } static int control(vf_instance_t *vf, int request, void *data) { switch (request) { case VFCTRL_SEEK_RESET: if (reinit_vs(vf) < 0) return CONTROL_ERROR; return CONTROL_OK; } return CONTROL_UNKNOWN; } static void uninit(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; destroy_vs(vf); vsscript_finalize(); pthread_cond_destroy(&p->wakeup); pthread_mutex_destroy(&p->lock); } static int vf_open(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; if (!vsscript_init()) { MP_FATAL(vf, "Could not initialize VapourSynth scripting.\n"); return 0; } if (!p->cfg_file || !p->cfg_file[0]) { MP_FATAL(vf, "'file' parameter must be set.\n"); return 0; } pthread_mutex_init(&p->lock, NULL); pthread_cond_init(&p->wakeup, NULL); vf->reconfig = NULL; vf->config = config; vf->filter_ext = filter_ext; vf->filter = NULL; vf->query_format = query_format; vf->control = control; vf->uninit = uninit; p->buffered = talloc_array(vf, struct mp_image *, p->cfg_maxbuffer); return 1; } #define OPT_BASE_STRUCT struct vf_priv_s static const m_option_t vf_opts_fields[] = { OPT_STRING("file", cfg_file, 0), OPT_INTRANGE("maxbuffer", cfg_maxbuffer, 0, 1, 9999, OPTDEF_INT(5)), {0} }; const vf_info_t vf_info_vapoursynth = { .description = "vapoursynth bridge", .name = "vapoursynth", .open = vf_open, .priv_size = sizeof(struct vf_priv_s), .options = vf_opts_fields, };
uninit(vo); return -1; } static int validate_backend_opt(const m_option_t *opt, struct bstr name, struct bstr param) { char s[20]; snprintf(s, sizeof(s), "%.*s", BSTR_P(param)); return mpgl_find_backend(s) >= -1 ? 1 : M_OPT_INVALID; } #define OPT_BASE_STRUCT struct gl_priv const struct m_option options[] = { OPT_FLAG("glfinish", use_glFinish, 0), OPT_INT("swapinterval", swap_interval, 0, OPTDEF_INT(1)), OPT_FLAG("debug", use_gl_debug, 0), OPT_STRING_VALIDATE("backend", backend, 0, validate_backend_opt), OPT_FLAG("sw", allow_sw, 0), OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), OPT_SUBSTRUCT("", icc_opts, mp_icc_conf, 0), {0}, }; static const char help_text[]; const struct vo_driver video_out_opengl = { .info = &(const vo_info_t) { "Extended OpenGL Renderer", "opengl",
register int i; // Run filter for(i=0;i<len;i+=nch){ // Average left and right a[i+ch] = (a[i]/2) + (a[i+1]/2); } return 0; } // Allocate memory and set function pointers static int af_open(struct af_instance* af){ af->control=control; af->filter=filter; return AF_OK; } #define OPT_BASE_STRUCT af_center_t struct af_info af_info_center = { .info = "Audio filter for adding a center channel", .name = "center", .flags = AF_FLAGS_NOT_REENTRANT, .open = af_open, .priv_size = sizeof(af_center_t), .options = (const struct m_option[]) { OPT_INTRANGE("channel", ch, 0, 0, AF_NCH - 1, OPTDEF_INT(1)), {0} }, };
pthread_cond_init(&p->wakeup, NULL); vf->reconfig = NULL; vf->config = config; vf->filter_ext = filter_ext; vf->filter = NULL; vf->query_format = query_format; vf->control = control; vf->uninit = uninit; int maxbuffer = p->cfg_maxbuffer * p->cfg_maxrequests; p->buffered = talloc_array(vf, struct mp_image *, maxbuffer); p->max_requests = p->cfg_maxrequests; p->requested = talloc_zero_array(vf, struct mp_image *, p->max_requests); return 1; } #define OPT_BASE_STRUCT struct vf_priv_s static const m_option_t vf_opts_fields[] = { OPT_STRING("file", cfg_file, 0), OPT_INTRANGE("buffered-frames", cfg_maxbuffer, 0, 1, 9999, OPTDEF_INT(4)), OPT_INTRANGE("concurrent-frames", cfg_maxrequests, 0, 1, 99, OPTDEF_INT(2)), {0} }; const vf_info_t vf_info_vapoursynth = { .description = "vapoursynth bridge", .name = "vapoursynth", .open = vf_open, .priv_size = sizeof(struct vf_priv_s), .options = vf_opts_fields, };
struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); forget_frames(p->ctx); p->ctx->img_params = *params; p->ctx->reconfigured = true; pthread_mutex_unlock(&p->ctx->lock); return 0; } // list of options which can be changed at runtime #define OPT_BASE_STRUCT struct vo_priv static const struct m_option change_opts[] = { OPT_FLAG("debug", use_gl_debug, 0), OPT_INTRANGE("frame-queue-size", frame_queue_size, 0, 1, 100, OPTDEF_INT(2)), OPT_CHOICE("frame-drop-mode", frame_drop_mode, 0, ({"pop", FRAME_DROP_POP}, {"clear", FRAME_DROP_CLEAR})), OPT_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), {0} }; #undef OPT_BASE_STRUCT static bool reparse_cmdline(struct vo_priv *p, char *args) { struct m_config *cfg = NULL; struct vo_priv *opts = NULL; int r = 0; pthread_mutex_lock(&p->ctx->lock);
MP_WARN(vf, "%s", VF_LW_REPLACE); if (vf_lw_set_graph(vf, p->lw_opts, NULL, "%s", rot[p->angle]) >= 0) { vf_lw_set_reconfig_cb(vf, lavfi_reconfig); return 1; } return 0; } #define OPT_BASE_STRUCT struct vf_priv_s const vf_info_t vf_info_rotate = { .description = "rotate", .name = "rotate", .open = vf_open, .priv_size = sizeof(struct vf_priv_s), .options = (const struct m_option[]){ OPT_CHOICE("angle", angle, 0, ({"0", 0}, {"90", 1}, {"180", 2}, {"270", 3}, {"auto", 4})), OPT_FLAG("warn", warn, 0, OPTDEF_INT(1)), OPT_SUBSTRUCT("", lw_opts, vf_lw_conf, 0), {0} }, }; //===========================================================================//