void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, struct sub_bitmap **parts, struct sub_bitmaps *res) { int changed; ASS_Image *imgs = ass_render_frame(renderer, track, time, &changed); if (changed) res->change_id++; res->format = SUBBITMAP_LIBASS; res->parts = *parts; res->num_parts = 0; int num_parts_alloc = MP_TALLOC_AVAIL(res->parts); for (struct ass_image *img = imgs; img; img = img->next) { if (img->w == 0 || img->h == 0) continue; if (res->num_parts >= num_parts_alloc) { num_parts_alloc = MPMAX(num_parts_alloc * 2, 32); res->parts = talloc_realloc(NULL, res->parts, struct sub_bitmap, num_parts_alloc); } struct sub_bitmap *p = &res->parts[res->num_parts]; p->bitmap = img->bitmap; p->stride = img->stride; p->libass.color = img->color; p->dw = p->w = img->w; p->dh = p->h = img->h; p->x = img->dst_x; p->y = img->dst_y; res->num_parts++; }
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; // The number of frames of our input node is obviously unknown. The user // could for example seek any time, randomly "ending" the clip. // This specific value was suggested by the VapourSynth developer. int enough_for_everyone = INT_MAX / 16; // 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, .numFrames = enough_for_everyone, }; 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); MP_TRACE(vf, "VS asking for frame %d (at %d)\n", frameno, p->in_frameno); while (1) { if (p->shutdown) { p->vsapi->setFilterError("EOF or filter reinit/uninit", frameCtx); MP_DBG(vf, "returning error on EOF/reset\n"); break; } if (p->initializing) { MP_WARN(vf, "Frame requested during init! This is unsupported.\n" "Returning black dummy frame with 0 duration.\n"); ret = alloc_vs_frame(p, &vf->fmt_in); if (!ret) { p->vsapi->setFilterError("Could not allocate VS frame", frameCtx); break; } struct mp_image vsframe = map_vs_frame(p, ret, true); mp_image_clear(&vsframe, 0, 0, vf->fmt_in.w, vf->fmt_in.h); struct mp_image dummy = {0}; mp_image_set_params(&dummy, &vf->fmt_in); set_vs_frame_props(p, ret, &dummy, 0, 1); break; } if (frameno < p->in_frameno) { char msg[180]; snprintf(msg, sizeof(msg), "Frame %d requested, but only have frames starting from %d. " "Try increasing the buffered-frames suboption.", frameno, p->in_frameno); MP_FATAL(vf, "%s\n", msg); p->vsapi->setFilterError(msg, frameCtx); break; } if (frameno >= p->in_frameno + MP_TALLOC_AVAIL(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); if (vf->chain->wakeup_callback) vf->chain->wakeup_callback(vf->chain->wakeup_callback_ctx); continue; } } if (frameno >= p->in_frameno + p->num_buffered) { // If we think EOF was reached, don't wait for new input, and assume // the VS filter has reached EOF. if (p->eof) { p->shutdown = true; continue; } } if (frameno < p->in_frameno + p->num_buffered) { struct mp_image *img = p->buffered[frameno - p->in_frameno]; ret = alloc_vs_frame(p, &img->params); 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); int res = 1e6; int dur = img->pts * res + 0.5; set_vs_frame_props(p, ret, img, dur, res); break; } pthread_cond_wait(&p->wakeup, &p->lock); } pthread_cond_broadcast(&p->wakeup); 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); } // number of getAsyncFrame calls in progress // must be called with p->lock held static int num_requested(struct vf_priv_s *p) { int r = 0; for (int n = 0; n < p->max_requests; n++) r += p->requested[n] == &dummy_img; return r; }
static bool locked_need_input(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; return p->num_buffered < MP_TALLOC_AVAIL(p->buffered); }