static int init(struct ao *ao) { float position[3] = {0, 0, 0}; float direction[6] = {0, 0, 1, 0, -1, 0}; ALCdevice *dev = NULL; ALCcontext *ctx = NULL; ALCint freq = 0; ALCint attribs[] = {ALC_FREQUENCY, ao->samplerate, 0, 0}; int i; struct priv *p = ao->priv; if (ao_data) { MP_FATAL(ao, "Not reentrant!\n"); return -1; } ao_data = ao; ao->no_persistent_volume = true; struct mp_chmap_sel sel = {0}; for (i = 0; speaker_pos[i].id != -1; i++) mp_chmap_sel_add_speaker(&sel, speaker_pos[i].id); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) goto err_out; struct speaker speakers[MAX_CHANS]; for (i = 0; i < ao->channels.num; i++) { speakers[i].id = -1; for (int n = 0; speaker_pos[n].id >= 0; n++) { if (speaker_pos[n].id == ao->channels.speaker[i]) speakers[i] = speaker_pos[n]; } if (speakers[i].id < 0) { MP_FATAL(ao, "Unknown channel layout\n"); goto err_out; } } dev = alcOpenDevice(p->cfg_device && p->cfg_device[0] ? p->cfg_device : NULL); if (!dev) { MP_FATAL(ao, "could not open device\n"); goto err_out; } ctx = alcCreateContext(dev, attribs); alcMakeContextCurrent(ctx); alListenerfv(AL_POSITION, position); alListenerfv(AL_ORIENTATION, direction); alGenSources(ao->channels.num, sources); for (i = 0; i < ao->channels.num; i++) { cur_buf[i] = 0; unqueue_buf[i] = 0; alGenBuffers(NUM_BUF, buffers[i]); alSourcefv(sources[i], AL_POSITION, speakers[i].pos); alSource3f(sources[i], AL_VELOCITY, 0, 0, 0); } alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq); if (alcGetError(dev) == ALC_NO_ERROR && freq) ao->samplerate = freq; ao->format = AF_FORMAT_S16_NE; tmpbuf = malloc(CHUNK_SIZE); return 0; err_out: return -1; }
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; 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; }
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; p->fmt_in = *in; if (reinit_vs(vf) < 0) return -1; const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); out->w = vi->width; out->h = vi->height; out->imgfmt = mp_from_vs(vi->format->id); if (!out->imgfmt) { MP_FATAL(vf, "Unsupported output format.\n"); destroy_vs(vf); return -1; } struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(in->imgfmt); if (in->w % desc.align_x || in->h % desc.align_y) { MP_FATAL(vf, "VapourSynth does not allow unaligned/cropped video sizes.\n"); destroy_vs(vf); return -1; } return 0; }
static bool create_context_egl(MPGLContext *ctx, EGLConfig config, EGLNativeWindowType window, bool es) { struct priv *p = ctx->priv; EGLint context_attributes[] = { // aka EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION, es ? 2 : 3, EGL_NONE }; p->egl_surface = eglCreateWindowSurface(p->egl_display, config, window, NULL); if (p->egl_surface == EGL_NO_SURFACE) { MP_FATAL(ctx->vo, "Could not create EGL surface!\n"); return false; } p->egl_context = eglCreateContext(p->egl_display, config, EGL_NO_CONTEXT, context_attributes); if (p->egl_context == EGL_NO_CONTEXT) { MP_FATAL(ctx->vo, "Could not create EGL context!\n"); return false; } eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, p->egl_context); return true; }
static EGLConfig select_fb_config_egl(struct MPGLContext *ctx, bool es) { struct priv *p = ctx->priv; const EGLint attributes[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, 1, EGL_RENDERABLE_TYPE, es ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT, EGL_NONE }; EGLint config_count; EGLConfig config; if (!eglChooseConfig(p->egl.display, attributes, &config, 1, &config_count)) { MP_FATAL(ctx->vo, "Failed to configure EGL.\n"); return NULL; } if (!config_count) { MP_FATAL(ctx->vo, "Could not find EGL configuration!\n"); return NULL; } return config; }
static void uninit(struct vo *vo) { struct vo_priv *p = vo->priv; pthread_mutex_lock(&p->ctx->lock); mp_image_unrefp(&p->ctx->next_frame); mp_image_unrefp(&p->ctx->waiting_frame); p->ctx->img_params = (struct mp_image_params){0}; p->ctx->reconfigured = true; p->ctx->active = NULL; 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; assert(vo->osd == p->ctx->osd); 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_SUBSTRUCT("", renderer_opts, gl_video_conf, 0), {0}, }; const struct vo_driver video_out_opengl_cb = { .description = "OpenGL Callbacks for libmpv", .name = "opengl-cb", .caps = VO_CAP_ROTATE90, .preinit = preinit, .query_format = query_format, .reconfig = reconfig, .control = control, .draw_image = draw_image, .flip_page = flip_page, .uninit = uninit, .priv_size = sizeof(struct vo_priv), .options = options, };
int mp_egl_rpi_init(struct mp_egl_rpi *p, DISPMANX_ELEMENT_HANDLE_T window, int w, int h) { p->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (!eglInitialize(p->egl_display, NULL, NULL)) { MP_FATAL(p, "EGL failed to initialize.\n"); goto fail; } eglBindAPI(EGL_OPENGL_ES_API); EGLConfig config = select_fb_config_egl(p); if (!config) goto fail; p->egl_window = (EGL_DISPMANX_WINDOW_T){ .element = window, .width = w, .height = h, }; p->egl_surface = eglCreateWindowSurface(p->egl_display, config, &p->egl_window, NULL); if (p->egl_surface == EGL_NO_SURFACE) { MP_FATAL(p, "Could not create EGL surface!\n"); goto fail; } EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; p->egl_context = eglCreateContext(p->egl_display, config, EGL_NO_CONTEXT, context_attributes); if (p->egl_context == EGL_NO_CONTEXT) { MP_FATAL(p, "Could not create EGL context!\n"); goto fail; } eglMakeCurrent(p->egl_display, p->egl_surface, p->egl_surface, p->egl_context); p->gl = talloc_zero(NULL, struct GL); const char *exts = eglQueryString(p->egl_display, EGL_EXTENSIONS); mpgl_load_functions(p->gl, get_proc_address, exts, p->log); if (!p->gl->version && !p->gl->es) goto fail; return 0; fail: mp_egl_rpi_destroy(p); return -1; }
static bool create_context_x11_old(struct MPGLContext *ctx) { struct glx_context *glx_ctx = ctx->priv; Display *display = ctx->vo->x11->display; struct vo *vo = ctx->vo; GL *gl = ctx->gl; if (glx_ctx->context) return true; GLXContext new_context = glXCreateContext(display, glx_ctx->vinfo, NULL, True); if (!new_context) { MP_FATAL(vo, "Could not create GLX context!\n"); return false; } if (!glXMakeCurrent(display, ctx->vo->x11->window, new_context)) { MP_FATAL(vo, "Could not set GLX context!\n"); glXDestroyContext(display, new_context); return false; } void *(*getProcAddress)(const GLubyte *); getProcAddress = mp_getdladdr("glXGetProcAddress"); if (!getProcAddress) getProcAddress = mp_getdladdr("glXGetProcAddressARB"); const char *glxstr = ""; const char *(*glXExtStr)(Display *, int) = mp_getdladdr("glXQueryExtensionsString"); if (glXExtStr) glxstr = glXExtStr(display, ctx->vo->x11->screen); mpgl_load_functions(gl, getProcAddress, glxstr, vo->log); if (!gl->GenPrograms && gl->GetString && gl->version < MPGL_VER(3, 0) && strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) { MP_WARN(vo, "Broken glXGetProcAddress detected, trying workaround\n"); mpgl_load_functions(gl, NULL, glxstr, vo->log); } glx_ctx->context = new_context; if (!glXIsDirect(vo->x11->display, new_context)) ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW; return true; }
struct lavc_conv *lavc_conv_create(struct mp_log *log, const char *codec_name, char *extradata, int extradata_len) { struct lavc_conv *priv = talloc_zero(NULL, struct lavc_conv); priv->log = log; priv->cur_list = talloc_array(priv, char*, 0); priv->codec = talloc_strdup(priv, codec_name); AVCodecContext *avctx = NULL; const char *fmt = get_lavc_format(priv->codec); AVCodec *codec = avcodec_find_decoder(mp_codec_to_av_codec_id(fmt)); if (!codec) goto error; avctx = avcodec_alloc_context3(codec); if (!avctx) goto error; avctx->extradata_size = extradata_len; avctx->extradata = talloc_memdup(priv, extradata, extradata_len); if (avcodec_open2(avctx, codec, NULL) < 0) goto error; // Documented as "set by libavcodec", but there is no other way avctx->time_base = (AVRational) {1, 1000}; priv->avctx = avctx; priv->extradata = talloc_strndup(priv, avctx->subtitle_header, avctx->subtitle_header_size); disable_styles(bstr0(priv->extradata)); return priv; error: MP_FATAL(priv, "Could not open libavcodec subtitle converter\n"); av_free(avctx); talloc_free(priv); return NULL; }
static int control(struct af_instance *af, int cmd, void *arg) { struct priv *p = af->priv; switch (cmd) { case AF_CONTROL_REINIT: { struct mp_audio *in = arg; struct mp_audio orig_in = *in; struct mp_audio *out = af->data; in->format = AF_FORMAT_FLOATP; mp_audio_copy_config(out, in); if (p->rubber) rubberband_delete(p->rubber); int opts = p->opt_transients | p->opt_detector | p->opt_phase | p->opt_window | p->opt_smoothing | p->opt_formant | p->opt_pitch | p-> opt_channels | RubberBandOptionProcessRealTime; p->rubber = rubberband_new(in->rate, in->channels.num, opts, 1.0, 1.0); if (!p->rubber) { MP_FATAL(af, "librubberband initialization failed.\n"); return AF_ERROR; } update_speed(af, p->speed); update_pitch(af, p->pitch); control(af, AF_CONTROL_RESET, NULL); return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; } case AF_CONTROL_SET_PLAYBACK_SPEED: { update_speed(af, *(double *)arg); return AF_OK; } case AF_CONTROL_RESET: if (p->rubber) rubberband_reset(p->rubber); talloc_free(p->pending); p->pending = NULL; p->rubber_delay = 0; return AF_OK; case AF_CONTROL_COMMAND: { char **args = arg; if (!strcmp(args[0], "set-pitch")) { char *endptr; double pitch = strtod(args[1], &endptr); if (*endptr || pitch < 0.01 || pitch > 100.0) return CONTROL_ERROR; update_pitch(af, pitch); return CONTROL_OK; } else { return CONTROL_ERROR; } } } return AF_UNKNOWN; }
static int init(struct sd *sd) { struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); enum AVCodecID cid = mp_codec_to_av_codec_id(sd->codec); AVCodecContext *ctx = NULL; AVCodec *sub_codec = avcodec_find_decoder(cid); if (!sub_codec) goto error; ctx = avcodec_alloc_context3(sub_codec); if (!ctx) goto error; mp_lavc_set_extradata(ctx, sd->extradata, sd->extradata_len); if (avcodec_open2(ctx, sub_codec, NULL) < 0) goto error; priv->avctx = ctx; sd->priv = priv; priv->displayed_id = -1; return 0; error: MP_FATAL(sd, "Could not open libavcodec subtitle decoder\n"); av_free(ctx); talloc_free(priv); return -1; }
static void read_pad_input(struct lavfi *c, struct lavfi_pad *pad) { assert(pad->dir == MP_PIN_IN); if (pad->pending.type || c->draining_recover) return; pad->pending = mp_pin_out_read(pad->pin); if (pad->pending.type && pad->pending.type != MP_FRAME_EOF && pad->pending.type != pad->type) { MP_FATAL(c, "unknown frame %s\n", mp_frame_type_str(pad->pending.type)); mp_frame_unref(&pad->pending); } if (mp_frame_is_data(pad->pending) && pad->in_fmt.type && !is_format_ok(pad->pending, pad->in_fmt)) { if (!c->draining_recover) MP_VERBOSE(c, "format change on %s\n", pad->name); c->draining_recover = true; if (c->initialized) send_global_eof(c); } }
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, .d_w = d_width, .d_h = d_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 open_f(stream_t *stream) { stream->fill_buffer = fill_buffer; stream->seek = seek; stream->seekable = true; stream->control = control; stream->read_chunk = 1024 * 1024; struct priv *p = talloc_zero(stream, struct priv); stream->priv = p; // Initial data bstr data = bstr0(stream->url); bool use_hex = bstr_eatstart0(&data, "hex://"); if (!use_hex) bstr_eatstart0(&data, "memory://"); stream_control(stream, STREAM_CTRL_SET_CONTENTS, &data); if (use_hex && !bstr_decode_hex(stream, p->data, &p->data)) { MP_FATAL(stream, "Invalid data.\n"); return STREAM_ERROR; } return STREAM_OK; }
static int init(struct sd *sd) { struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); AVCodecContext *avctx = NULL; const char *fmt = get_lavc_format(sd->codec); AVCodec *codec = avcodec_find_decoder(mp_codec_to_av_codec_id(fmt)); if (!codec) goto error; avctx = avcodec_alloc_context3(codec); if (!avctx) goto error; avctx->extradata_size = sd->extradata_len; avctx->extradata = sd->extradata; if (avcodec_open2(avctx, codec, NULL) < 0) goto error; // Documented as "set by libavcodec", but there is no other way avctx->time_base = (AVRational) {1, 1000}; priv->avctx = avctx; sd->priv = priv; sd->output_codec = "ssa"; sd->output_extradata = avctx->subtitle_header; sd->output_extradata_len = avctx->subtitle_header_size; if (sd->output_extradata) { sd->output_extradata = talloc_memdup(sd, sd->output_extradata, sd->output_extradata_len); disable_styles((bstr){sd->output_extradata, sd->output_extradata_len}); } return 0; error: MP_FATAL(sd, "Could not open libavcodec subtitle converter\n"); av_free(avctx); talloc_free(priv); return -1; }
static bool create_context_x11_gl3(struct MPGLContext *ctx, int vo_flags, int gl_version, bool es) { struct glx_context *glx_ctx = ctx->priv; struct vo *vo = ctx->vo; if (glx_ctx->context) return true; glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); const char *glxstr = glXQueryExtensionsString(vo->x11->display, vo->x11->screen); bool have_ctx_ext = glxstr && !!strstr(glxstr, "GLX_ARB_create_context"); if (!(have_ctx_ext && glXCreateContextAttribsARB)) { return false; } int ctx_flags = vo_flags & VOFLAG_GL_DEBUG ? GLX_CONTEXT_DEBUG_BIT_ARB : 0; int profile_mask = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; if (es) { profile_mask = GLX_CONTEXT_ES2_PROFILE_BIT_EXT; if (!(glxstr && strstr(glxstr, "GLX_EXT_create_context_es2_profile"))) return false; } int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), GLX_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), GLX_CONTEXT_PROFILE_MASK_ARB, profile_mask, GLX_CONTEXT_FLAGS_ARB, ctx_flags, None }; vo_x11_silence_xlib(1); GLXContext context = glXCreateContextAttribsARB(vo->x11->display, glx_ctx->fbc, 0, True, context_attribs); vo_x11_silence_xlib(-1); if (!context) { MP_VERBOSE(vo, "Could not create GL3 context. Retrying with legacy context.\n"); return false; } // set context if (!glXMakeCurrent(vo->x11->display, vo->x11->window, context)) { MP_FATAL(vo, "Could not set GLX context!\n"); glXDestroyContext(vo->x11->display, context); return false; } glx_ctx->context = context; mpgl_load_functions(ctx->gl, (void *)glXGetProcAddressARB, glxstr, vo->log); return true; }
static int init(struct ao *ao) { struct priv *priv = ao->priv; ao->untimed = priv->untimed; struct mp_chmap_sel sel = {.tmp = ao}; if (priv->channel_layouts) { for (int n = 0; priv->channel_layouts[n]; n++) { struct mp_chmap map = {0}; if (!mp_chmap_from_str(&map, bstr0(priv->channel_layouts[n]))) { MP_FATAL(ao, "Invalid channel map in option.\n"); return -1; } mp_chmap_sel_add_map(&sel, &map); } } else { mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) mp_chmap_from_channels(&ao->channels, 2); priv->latency = priv->latency_sec * ao->samplerate; // A "buffer" for this many seconds of audio int bursts = (int)(ao->samplerate * priv->bufferlen + 1) / priv->outburst; priv->buffersize = priv->outburst * bursts + priv->latency; priv->last_time = mp_time_sec(); return 0; }
// Allocate memory and set function pointers static int af_open(struct af_instance* af){ af->control=control; af->filter=filter; af_channels_t *s = af->priv; // If router scan commandline for routing pairs if(s->routes && s->routes[0]){ char* cp = s->routes; int ch = 0; // Scan for pairs on commandline do { int n = 0; 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; }
static bool create_gl_context(struct MPGLContext *ctx) { struct cgl_context *p = ctx->priv; CGLError err; CGLOpenGLProfile gl_versions[] = { kCGLOGLPVersion_3_2_Core, kCGLOGLPVersion_Legacy, }; for (int n = 0; n < MP_ARRAY_SIZE(gl_versions); n++) { err = test_gl_version(ctx->vo, &p->ctx, &p->pix, gl_versions[n]); if (err == kCGLNoError) break; } if (err != kCGLNoError) { MP_FATAL(ctx->vo, "error creating CGL context: %s (%d)\n", CGLErrorString(err), err); return false; } vo_cocoa_set_opengl_ctx(ctx->vo, p->ctx); CGLSetCurrentContext(p->ctx); ctx->depth_r = ctx->depth_g = ctx->depth_b = cgl_color_size(ctx); mpgl_load_functions(ctx->gl, (void *)cocoa_glgetaddr, NULL, ctx->vo->log); CGLReleasePixelFormat(p->pix); return true; }
static int vf_open(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; #if LIBAVFILTER_VERSION_MICRO >= 100 const char *mode[] = {"send_frame", "send_field", "send_frame_nospatial", "send_field_nospatial"}; if (vf_lw_set_graph(vf, p->lw_opts, "yadif", "mode=%s:deint=%s", mode[p->mode], p->interlaced_only ? "interlaced" : "all") >= 0) { return 1; } #else // Libav numeric modes happen to match ours, but keep it explicit. const char *mode[] = {"0", "1", "2", "3"}; if (vf_lw_set_graph(vf, p->lw_opts, "yadif", "mode=%s:auto=%d", mode[p->mode], p->interlaced_only) >= 0) { return 1; } #endif MP_FATAL(vf, "This version of libavfilter has no 'yadif' filter.\n"); return 0; }
static int vf_open(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; if (p->drv->init(vf) < 0) return 0; if (!p->cfg_file || !p->cfg_file[0]) { MP_FATAL(vf, "'file' parameter must be set.\n"); return 0; } talloc_steal(vf, p->cfg_file); p->cfg_file = mp_get_user_path(vf, vf->chain->global, p->cfg_file); pthread_mutex_init(&p->lock, NULL); pthread_cond_init(&p->wakeup, NULL); vf->reconfig = reconfig; vf->filter_ext = filter_ext; vf->filter_out = filter_out; vf->needs_input = needs_input; vf->query_format = query_format; 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; }
// Iterate entries. The first call establishes the first entry. Returns false // if no entry found, otherwise returns true and sets mpa->entry/entry_filename. bool mp_archive_next_entry(struct mp_archive *mpa) { mpa->entry = NULL; talloc_free(mpa->entry_filename); mpa->entry_filename = NULL; while (!mp_cancel_test(mpa->primary_src->cancel)) { struct archive_entry *entry; int r = archive_read_next_header(mpa->arch, &entry); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) MP_ERR(mpa, "%s\n", archive_error_string(mpa->arch)); if (r < ARCHIVE_WARN) { MP_FATAL(mpa, "could not read archive entry\n"); break; } if (archive_entry_filetype(entry) != AE_IFREG) continue; // Some archives may have no filenames, or libarchive won't return some. const char *fn = archive_entry_pathname(entry); char buf[64]; if (!fn || bstr_validate_utf8(bstr0(fn)) < 0) { snprintf(buf, sizeof(buf), "mpv_unknown#%d", mpa->entry_num); fn = buf; } mpa->entry = entry; mpa->entry_filename = talloc_strdup(mpa, fn); mpa->entry_num += 1; return true; } return false; }
static int init(struct sd *sd) { enum AVCodecID cid = mp_codec_to_av_codec_id(sd->codec->codec); // Supported codecs must be known to decode to paletted bitmaps switch (cid) { case AV_CODEC_ID_DVB_SUBTITLE: case AV_CODEC_ID_HDMV_PGS_SUBTITLE: case AV_CODEC_ID_XSUB: case AV_CODEC_ID_DVD_SUBTITLE: break; default: return -1; } struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); AVCodecContext *ctx = NULL; AVCodec *sub_codec = avcodec_find_decoder(cid); if (!sub_codec) goto error; ctx = avcodec_alloc_context3(sub_codec); if (!ctx) goto error; mp_lavc_set_extradata(ctx, sd->codec->extradata, sd->codec->extradata_size); #if LIBAVCODEC_VERSION_MICRO >= 100 if (cid == AV_CODEC_ID_HDMV_PGS_SUBTITLE) { // We don't always want to set this, because the ridiculously shitty // libavcodec API will mess with certain fields (end_display_time) // when setting it. On the other hand, PGS in particular needs PTS // mangling. While the PGS decoder doesn't modify the timestamps (just // reorder it), the ridiculously shitty libavcodec wants a timebase // anyway and for no good reason. It always sets end_display_time to // UINT32_MAX (which is a broken and undocumented way to say "unknown"), // which coincidentally won't be overridden by the ridiculously shitty // pkt_timebase code. also, Libav doesn't have the pkt_timebase field, // because Libav tends to avoid _adding_ ridiculously shitty APIs. priv->pkt_timebase = (AVRational){1, AV_TIME_BASE}; ctx->pkt_timebase = priv->pkt_timebase; } else { // But old ffmpeg releases have a buggy pkt_timebase check, because the // shit above wasn't bad enough! ctx->pkt_timebase = (AVRational){0, 0}; } #endif if (avcodec_open2(ctx, sub_codec, NULL) < 0) goto error; priv->avctx = ctx; sd->priv = priv; priv->displayed_id = -1; priv->current_pts = MP_NOPTS_VALUE; priv->packer = talloc_zero(priv, struct bitmap_packer); return 0; error: MP_FATAL(sd, "Could not open libavcodec subtitle decoder\n"); av_free(ctx); talloc_free(priv); return -1; }
// Supposedly we're not allowed to continue reading on FATAL returns. Otherwise // crashes and other UB is possible. Assume calling the close/free functions is // still ok. Return true if it was fatal and the archive was closed. static bool mp_archive_check_fatal(struct mp_archive *mpa, int r) { if (r > ARCHIVE_FATAL) return false; MP_FATAL(mpa, "fatal error received - closing archive\n"); mp_archive_close(mpa); return true; }
static int drv_vss_init(struct vf_instance *vf) { if (!vsscript_init()) { MP_FATAL(vf, "Could not initialize VapourSynth scripting.\n"); return -1; } return 0; }
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 video_reconfig_filters(struct dec_video *d_video, const struct mp_image_params *params) { struct MPOpts *opts = d_video->opts; struct mp_image_params p = *params; struct sh_video *sh = d_video->header->video; // While mp_image_params normally always have to have d_w/d_h set, the // decoder signals unknown bitstream aspect ratio with both set to 0. float dec_aspect = p.d_w > 0 && p.d_h > 0 ? p.d_w / (float)p.d_h : 0; if (d_video->initial_decoder_aspect == 0) d_video->initial_decoder_aspect = dec_aspect; bool use_container = true; switch (opts->aspect_method) { case 0: // We normally prefer the container aspect, unless the decoder aspect // changes at least once. if (dec_aspect > 0 && d_video->initial_decoder_aspect != dec_aspect) { MP_VERBOSE(d_video, "Using bitstream aspect ratio.\n"); // Even if the aspect switches back, don't use container aspect again. d_video->initial_decoder_aspect = -1; use_container = false; } break; case 1: use_container = false; break; } if (use_container && sh->aspect > 0) { MP_VERBOSE(d_video, "Using container aspect ratio.\n"); vf_set_dar(&p.d_w, &p.d_h, p.w, p.h, sh->aspect); } float force_aspect = opts->movie_aspect; if (force_aspect >= 0.0) { MP_VERBOSE(d_video, "Forcing user-set aspect ratio.\n"); vf_set_dar(&p.d_w, &p.d_h, p.w, p.h, force_aspect); } // Assume square pixels if no aspect ratio is set at all. if (p.d_w <= 0 || p.d_h <= 0) { p.d_w = p.w; p.d_h = p.h; } // Detect colorspace from resolution. mp_image_params_guess_csp(&p); if (vf_reconfig(d_video->vfilter, params, &p) < 0) { MP_FATAL(d_video, "Cannot initialize video filters.\n"); return -1; } return 0; }
static bool create_context_x11_gl3(struct MPGLContext *ctx, bool debug) { struct glx_context *glx_ctx = ctx->priv; struct vo *vo = ctx->vo; if (glx_ctx->context) return true; glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); const char *glxstr = ""; const char *(*glXExtStr)(Display *, int) = mp_getdladdr("glXQueryExtensionsString"); if (glXExtStr) glxstr = glXExtStr(vo->x11->display, vo->x11->screen); bool have_ctx_ext = glxstr && !!strstr(glxstr, "GLX_ARB_create_context"); if (!(have_ctx_ext && glXCreateContextAttribsARB)) { return false; } int gl_version = ctx->requested_gl_version; int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), GLX_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB, debug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0, None }; GLXContext context = glXCreateContextAttribsARB(vo->x11->display, glx_ctx->fbc, 0, True, context_attribs); if (!context) { MP_ERR(vo, "Could not create GL3 context. Retrying with legacy context.\n"); return false; } // set context if (!glXMakeCurrent(vo->x11->display, vo->x11->window, context)) { MP_FATAL(vo, "Could not set GLX context!\n"); glXDestroyContext(vo->x11->display, context); return false; } glx_ctx->context = context; mpgl_load_functions(ctx->gl, (void *)glXGetProcAddress, glxstr, vo->log); if (!glXIsDirect(vo->x11->display, context)) ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW; return true; }
// Returns true if more args, false if all parsed or an error occurred. static bool split_opt(struct parse_state *p) { int r = split_opt_silent(p); if (r >= 0) return r == 0; p->error = true; MP_FATAL(p->config, "Error parsing command line option '%.*s': %s\n", BSTR_P(p->arg), m_option_strerror(r)); return false; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { af_delay_t* s = af->priv; switch(cmd) { case AF_CONTROL_REINIT: { int i; struct mp_audio *in = arg; if (in->bps != 1 && in->bps != 2 && in->bps != 4) { MP_FATAL(af, "Sample format not supported\n"); return AF_ERROR; } // Free prevous delay queues for(i=0; i<af->data->nch; i++) free(s->q[i]); mp_audio_force_interleaved_format(in); mp_audio_copy_config(af->data, in); // Allocate new delay queues for(i=0; i<af->data->nch; i++) { s->q[i] = calloc(L,af->data->bps); if(NULL == s->q[i]) MP_FATAL(af, "Out of memory\n"); } if(AF_OK != af_from_ms(AF_NCH, s->d, s->wi, af->data->rate, 0.0, 1000.0)) return AF_ERROR; s->ri = 0; for(i=0; i<AF_NCH; i++) { MP_DBG(af, "Channel %i delayed by %0.3fms\n", i,MPCLAMP(s->d[i],0.0,1000.0)); MP_TRACE(af, "Channel %i delayed by %i samples\n", i,s->wi[i]); } return AF_OK; } } return AF_UNKNOWN; }