X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fvideo_output%2Fvideo_output.c;h=430876185cbef148db8f099ef817d60c05df592e;hb=dce1d72bb05d1126c6c808b77b5444190fd264a6;hp=31bd7cbb9e5e60c0a0ea99ec0ef0582eb13c8642;hpb=41d4b8bd7df6a2a2814e29e84efb10bebda6faf2;p=vlc diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c index 31bd7cbb9e..430876185c 100644 --- a/src/video_output/video_output.c +++ b/src/video_output/video_output.c @@ -44,6 +44,7 @@ #include #include +#include #include #include "vout_internal.h" @@ -74,7 +75,8 @@ static void VoutDestructor(vlc_object_t *); static int VoutValidateFormat(video_format_t *dst, const video_format_t *src) { - if (src->i_width <= 0 || src->i_height <= 0) + if (src->i_width <= 0 || src->i_width > 8192 || + src->i_height <= 0 || src->i_height > 8192) return VLC_EGENERIC; if (src->i_sar_num <= 0 || src->i_sar_den <= 0) return VLC_EGENERIC; @@ -91,6 +93,22 @@ static int VoutValidateFormat(video_format_t *dst, video_format_FixRgb(dst); return VLC_SUCCESS; } +static void VideoFormatCopyCropAr(video_format_t *dst, + const video_format_t *src) +{ + video_format_CopyCrop(dst, src); + dst->i_sar_num = src->i_sar_num; + dst->i_sar_den = src->i_sar_den; +} +static bool VideoFormatIsCropArEqual(video_format_t *dst, + const video_format_t *src) +{ + return dst->i_sar_num * src->i_sar_den == dst->i_sar_den * src->i_sar_num && + dst->i_x_offset == src->i_x_offset && + dst->i_y_offset == src->i_y_offset && + dst->i_visible_width == src->i_visible_width && + dst->i_visible_height == src->i_visible_height; +} static vout_thread_t *VoutCreate(vlc_object_t *object, const vout_configuration_t *cfg) @@ -130,7 +148,7 @@ static vout_thread_t *VoutCreate(vlc_object_t *object, vlc_object_attach(vout, object); /* Initialize subpicture unit */ - vout->p->p_spu = spu_Create(vout); + vout->p->spu = spu_Create(vout); /* Take care of some "interface/control" related initialisations */ vout_IntfInit(vout); @@ -140,13 +158,11 @@ static vout_thread_t *VoutCreate(vlc_object_t *object, vout->p->title.position = var_GetInteger(vout, "video-title-position"); /* Get splitter name if present */ - char *splitter_name = var_GetNonEmptyString(vout, "vout-filter"); - if (splitter_name) { - if (asprintf(&vout->p->splitter_name, "%s,none", splitter_name) < 0) - vout->p->splitter_name = NULL; - free(splitter_name); + char *splitter_name = var_InheritString(vout, "video-splitter"); + if (splitter_name && *splitter_name) { + vout->p->splitter_name = splitter_name; } else { - vout->p->splitter_name = NULL; + free(splitter_name); } /* */ @@ -158,7 +174,7 @@ static vout_thread_t *VoutCreate(vlc_object_t *object, /* */ if (vlc_clone(&vout->p->thread, Thread, vout, VLC_THREAD_PRIORITY_OUTPUT)) { - spu_Destroy(vout->p->p_spu); + spu_Destroy(vout->p->spu); vlc_object_release(vout); return NULL; } @@ -173,7 +189,7 @@ static vout_thread_t *VoutCreate(vlc_object_t *object, vout->p->input = cfg->input; if (vout->p->input) - spu_Attach(vout->p->p_spu, vout->p->input, true); + spu_Attach(vout->p->spu, vout->p->input, true); return vout; } @@ -192,10 +208,10 @@ vout_thread_t *(vout_Request)(vlc_object_t *object, if (vout) { if (vout->p->input != cfg->input) { if (vout->p->input) - spu_Attach(vout->p->p_spu, vout->p->input, false); + spu_Attach(vout->p->spu, vout->p->input, false); vout->p->input = cfg->input; if (vout->p->input) - spu_Attach(vout->p->p_spu, vout->p->input, true); + spu_Attach(vout->p->spu, vout->p->input, true); } if (cfg->change_fmt) { @@ -223,7 +239,7 @@ void vout_Close(vout_thread_t *vout) assert(vout); if (vout->p->input) - spu_Attach(vout->p->p_spu, vout->p->input, false); + spu_Attach(vout->p->spu, vout->p->input, false); vout_snapshot_End(&vout->p->snapshot); @@ -231,8 +247,8 @@ void vout_Close(vout_thread_t *vout) vlc_join(vout->p->thread, NULL); vlc_mutex_lock(&vout->p->spu_lock); - spu_Destroy(vout->p->p_spu); - vout->p->p_spu = NULL; + spu_Destroy(vout->p->spu); + vout->p->spu = NULL; vlc_mutex_unlock(&vout->p->spu_lock); } @@ -358,8 +374,8 @@ int vout_RegisterSubpictureChannel( vout_thread_t *vout ) int channel = SPU_DEFAULT_CHANNEL; vlc_mutex_lock(&vout->p->spu_lock); - if (vout->p->p_spu) - channel = spu_RegisterChannel(vout->p->p_spu); + if (vout->p->spu) + channel = spu_RegisterChannel(vout->p->spu); vlc_mutex_unlock(&vout->p->spu_lock); return channel; @@ -386,7 +402,7 @@ picture_t *vout_GetPicture(vout_thread_t *vout) picture_t *picture = picture_pool_Get(vout->p->decoder_pool); if (picture) { picture_Reset(picture); - picture->p_next = NULL; + VideoFormatCopyCropAr(&picture->format, &vout->p->original); } vlc_mutex_unlock(&vout->p->picture_lock); @@ -440,6 +456,40 @@ void vout_HoldPicture(vout_thread_t *vout, picture_t *picture) vlc_mutex_unlock(&vout->p->picture_lock); } +/* */ +int vout_GetSnapshot(vout_thread_t *vout, + block_t **image_dst, picture_t **picture_dst, + video_format_t *fmt, + const char *type, mtime_t timeout) +{ + picture_t *picture = vout_snapshot_Get(&vout->p->snapshot, timeout); + if (!picture) { + msg_Err(vout, "Failed to grab a snapshot"); + return VLC_EGENERIC; + } + + if (image_dst) { + vlc_fourcc_t codec = VLC_CODEC_PNG; + if (type && image_Type2Fourcc(type)) + codec = image_Type2Fourcc(type); + + const int override_width = var_GetInteger(vout, "snapshot-width"); + const int override_height = var_GetInteger(vout, "snapshot-height"); + + if (picture_Export(VLC_OBJECT(vout), image_dst, fmt, + picture, codec, override_width, override_height)) { + msg_Err(vout, "Failed to convert image for snapshot"); + picture_Release(picture); + return VLC_EGENERIC; + } + } + if (picture_dst) + *picture_dst = picture; + else + picture_Release(picture); + return VLC_SUCCESS; +} + /* vout_Control* are usable by anyone at anytime */ void vout_ControlChangeFullscreen(vout_thread_t *vout, bool fullscreen) { @@ -478,10 +528,10 @@ void vout_ControlChangeCropWindow(vout_thread_t *vout, { vout_control_cmd_t cmd; vout_control_cmd_Init(&cmd, VOUT_CONTROL_CROP_WINDOW); - cmd.u.window.x = x; - cmd.u.window.y = y; - cmd.u.window.width = width; - cmd.u.window.height = height; + cmd.u.window.x = __MAX(x, 0); + cmd.u.window.y = __MAX(y, 0); + cmd.u.window.width = __MAX(width, 0); + cmd.u.window.height = __MAX(height, 0); vout_control_Push(&vout->p->control, &cmd); } @@ -490,10 +540,10 @@ void vout_ControlChangeCropBorder(vout_thread_t *vout, { vout_control_cmd_t cmd; vout_control_cmd_Init(&cmd, VOUT_CONTROL_CROP_BORDER); - cmd.u.border.left = left; - cmd.u.border.top = top; - cmd.u.border.right = right; - cmd.u.border.bottom = bottom; + cmd.u.border.left = __MAX(left, 0); + cmd.u.border.top = __MAX(top, 0); + cmd.u.border.right = __MAX(right, 0); + cmd.u.border.bottom = __MAX(bottom, 0); vout_control_Push(&vout->p->control, &cmd); } @@ -502,6 +552,11 @@ void vout_ControlChangeFilters(vout_thread_t *vout, const char *filters) vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_FILTERS, filters); } +void vout_ControlChangeSubSources(vout_thread_t *vout, const char *filters) +{ + vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_SUB_SOURCES, + filters); +} void vout_ControlChangeSubFilters(vout_thread_t *vout, const char *filters) { vout_control_PushString(&vout->p->control, VOUT_CONTROL_CHANGE_SUB_FILTERS, @@ -608,12 +663,16 @@ void vout_DeleteDisplayWindow(vout_thread_t *vout, vout_display_t *vd, } /* */ - static picture_t *VoutVideoFilterInteractiveNewPicture(filter_t *filter) { vout_thread_t *vout = (vout_thread_t*)filter->p_owner; - return picture_pool_Get(vout->p->private_pool); + picture_t *picture = picture_pool_Get(vout->p->private_pool); + if (picture) { + picture_Reset(picture); + VideoFormatCopyCropAr(&picture->format, &filter->fmt_out.video); + } + return picture; } static picture_t *VoutVideoFilterStaticNewPicture(filter_t *filter) { @@ -622,6 +681,7 @@ static picture_t *VoutVideoFilterStaticNewPicture(filter_t *filter) vlc_assert_locked(&vout->p->filter.lock); if (filter_chain_GetLength(vout->p->filter.chain_interactive) == 0) return VoutVideoFilterInteractiveNewPicture(filter); + return picture_NewFromFormat(&filter->fmt_out.video); } static void VoutVideoFilterDelPicture(filter_t *filter, picture_t *picture) @@ -643,6 +703,118 @@ static int VoutVideoFilterInteractiveAllocationSetup(filter_t *filter, void *dat filter->p_owner = data; /* vout */ return VLC_SUCCESS; } +static void ThreadFilterFlush(vout_thread_t *vout, bool is_locked) +{ + if (vout->p->displayed.current) + picture_Release( vout->p->displayed.current ); + vout->p->displayed.current = NULL; + + if (vout->p->displayed.next) + picture_Release( vout->p->displayed.next ); + vout->p->displayed.next = NULL; + + if (!is_locked) + vlc_mutex_lock(&vout->p->filter.lock); + filter_chain_VideoFlush(vout->p->filter.chain_static); + filter_chain_VideoFlush(vout->p->filter.chain_interactive); + if (!is_locked) + vlc_mutex_unlock(&vout->p->filter.lock); +} + +typedef struct { + char *name; + config_chain_t *cfg; +} vout_filter_t; + +static void ThreadChangeFilters(vout_thread_t *vout, + const video_format_t *source, + const char *filters, + bool is_locked) +{ + ThreadFilterFlush(vout, is_locked); + + vlc_array_t array_static; + vlc_array_t array_interactive; + + vlc_array_init(&array_static); + vlc_array_init(&array_interactive); + char *current = filters ? strdup(filters) : NULL; + while (current) { + config_chain_t *cfg; + char *name; + char *next = config_ChainCreate(&name, &cfg, current); + + if (name && *name) { + vout_filter_t *e = xmalloc(sizeof(*e)); + e->name = name; + e->cfg = cfg; + if (!strcmp(e->name, "deinterlace") || + !strcmp(e->name, "postproc")) { + vlc_array_append(&array_static, e); + } else { + vlc_array_append(&array_interactive, e); + } + } else { + if (cfg) + config_ChainDestroy(cfg); + free(name); + } + free(current); + current = next; + } + + if (!is_locked) + vlc_mutex_lock(&vout->p->filter.lock); + + es_format_t fmt_target; + es_format_InitFromVideo(&fmt_target, source ? source : &vout->p->filter.format); + + es_format_t fmt_current = fmt_target; + + for (int a = 0; a < 2; a++) { + vlc_array_t *array = a == 0 ? &array_static : + &array_interactive; + filter_chain_t *chain = a == 0 ? vout->p->filter.chain_static : + vout->p->filter.chain_interactive; + + filter_chain_Reset(chain, &fmt_current, &fmt_current); + for (int i = 0; i < vlc_array_count(array); i++) { + vout_filter_t *e = vlc_array_item_at_index(array, i); + msg_Dbg(vout, "Adding '%s' as %s", e->name, a == 0 ? "static" : "interactive"); + if (!filter_chain_AppendFilter(chain, e->name, e->cfg, NULL, NULL)) { + msg_Err(vout, "Failed to add filter '%s'", e->name); + config_ChainDestroy(e->cfg); + } + free(e->name); + free(e); + } + fmt_current = *filter_chain_GetFmtOut(chain); + vlc_array_clear(array); + } + VideoFormatCopyCropAr(&fmt_target.video, &fmt_current.video); + if (!es_format_IsSimilar(&fmt_current, &fmt_target)) { + msg_Dbg(vout, "Adding a filter to compensate for format changes"); + if (!filter_chain_AppendFilter(vout->p->filter.chain_interactive, NULL, NULL, + &fmt_current, &fmt_target)) { + msg_Err(vout, "Failed to compensate for the format changes, removing all filters"); + filter_chain_Reset(vout->p->filter.chain_static, &fmt_target, &fmt_target); + filter_chain_Reset(vout->p->filter.chain_interactive, &fmt_target, &fmt_target); + } + } + + if (vout->p->filter.configuration != filters) { + free(vout->p->filter.configuration); + vout->p->filter.configuration = filters ? strdup(filters) : NULL; + } + if (source) { + video_format_Clean(&vout->p->filter.format); + video_format_Copy(&vout->p->filter.format, source); + } + + if (!is_locked) + vlc_mutex_unlock(&vout->p->filter.lock); +} + /* */ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_late_dropped) @@ -672,6 +844,9 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_ msg_Dbg(vout, "picture might be displayed late (missing %d ms)", (int)(late/1000)); } } + if (decoded && + !VideoFormatIsCropArEqual(&decoded->format, &vout->p->filter.format)) + ThreadChangeFilters(vout, &decoded->format, vout->p->filter.configuration, true); } if (!decoded) break; @@ -704,6 +879,7 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool is_ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) { + vout_thread_sys_t *sys = vout->p; vout_display_t *vd = vout->p->display.vd; picture_t *torender = picture_Hold(vout->p->displayed.current); @@ -721,18 +897,74 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) msg_Warn(vout, "Unsupported timestamp modifications done by chain_interactive"); /* - * Check for subpictures to display + * Get the subpicture to be displayed */ const bool do_snapshot = vout_snapshot_IsRequested(&vout->p->snapshot); - mtime_t spu_render_time = is_forced ? mdate() : filtered->date; + mtime_t render_subtitle_date; if (vout->p->pause.is_on) - spu_render_time = vout->p->pause.date; + render_subtitle_date = vout->p->pause.date; else - spu_render_time = filtered->date > 1 ? filtered->date : mdate(); + render_subtitle_date = filtered->date > 1 ? filtered->date : mdate(); + mtime_t render_osd_date = mdate(); /* FIXME wrong */ + + /* + * Get the subpicture to be displayed + */ + const bool do_dr_spu = !do_snapshot && + vd->info.subpicture_chromas && + *vd->info.subpicture_chromas != 0; + const bool do_early_spu = !do_dr_spu && + (vd->info.is_slow || + sys->display.use_dr || + do_snapshot || + !vout_IsDisplayFiltered(vd) || + vd->fmt.i_width * vd->fmt.i_height <= vd->source.i_width * vd->source.i_height); + + const vlc_fourcc_t *subpicture_chromas; + video_format_t fmt_spu; + if (do_dr_spu) { + vout_display_place_t place; + vout_display_PlacePicture(&place, &vd->source, vd->cfg, false); + + fmt_spu = vd->source; + if (fmt_spu.i_width * fmt_spu.i_height < place.width * place.height) { + fmt_spu.i_sar_num = vd->cfg->display.sar.num; + fmt_spu.i_sar_den = vd->cfg->display.sar.den; + fmt_spu.i_width = + fmt_spu.i_visible_width = place.width; + fmt_spu.i_height = + fmt_spu.i_visible_height = place.height; + } + subpicture_chromas = vd->info.subpicture_chromas; + } else { + if (do_early_spu) { + fmt_spu = vd->source; + } else { + fmt_spu = vd->fmt; + fmt_spu.i_sar_num = vd->cfg->display.sar.num; + fmt_spu.i_sar_den = vd->cfg->display.sar.den; + } + subpicture_chromas = NULL; + + if (vout->p->spu_blend && + vout->p->spu_blend->fmt_out.video.i_chroma != fmt_spu.i_chroma) { + filter_DeleteBlend(vout->p->spu_blend); + vout->p->spu_blend = NULL; + vout->p->spu_blend_chroma = 0; + } + if (!vout->p->spu_blend && vout->p->spu_blend_chroma != fmt_spu.i_chroma) { + vout->p->spu_blend_chroma = fmt_spu.i_chroma; + vout->p->spu_blend = filter_NewBlend(VLC_OBJECT(vout), &fmt_spu); + if (!vout->p->spu_blend) + msg_Err(vout, "Failed to create blending filter, OSD/Subtitles will not work"); + } + } - subpicture_t *subpic = spu_SortSubpictures(vout->p->p_spu, - spu_render_time, - do_snapshot); + subpicture_t *subpic = spu_Render(vout->p->spu, + subpicture_chromas, &fmt_spu, + &vd->source, + render_subtitle_date, render_osd_date, + do_snapshot); /* * Perform rendering * @@ -740,41 +972,41 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) * - be sure to end up with a direct buffer. * - blend subtitles, and in a fast access buffer */ - picture_t *direct = NULL; - if (filtered && - (vout->p->decoder_pool != vout->p->display_pool || subpic)) { - picture_t *render; - if (vout->p->is_decoder_pool_slow) - render = picture_NewFromFormat(&vd->source); - else if (vout->p->decoder_pool != vout->p->display_pool) - render = picture_pool_Get(vout->p->display_pool); - else - render = picture_pool_Get(vout->p->private_pool); - - if (render) { - picture_Copy(render, filtered); - - spu_RenderSubpictures(vout->p->p_spu, - render, &vd->source, - subpic, &vd->source, spu_render_time); + bool is_direct = vout->p->decoder_pool == vout->p->display_pool; + picture_t *todisplay = filtered; + if (do_early_spu && subpic) { + todisplay = picture_pool_Get(vout->p->private_pool); + if (todisplay) { + VideoFormatCopyCropAr(&todisplay->format, &filtered->format); + picture_Copy(todisplay, filtered); + if (vout->p->spu_blend) + picture_BlendSubpicture(todisplay, vout->p->spu_blend, subpic); } - if (vout->p->is_decoder_pool_slow) { - direct = picture_pool_Get(vout->p->display_pool); - if (direct) - picture_Copy(direct, render); - picture_Release(render); + picture_Release(filtered); + subpicture_Delete(subpic); + subpic = NULL; - } else { - direct = render; + if (!todisplay) + return VLC_EGENERIC; + } + + picture_t *direct; + if (!is_direct && todisplay) { + direct = picture_pool_Get(vout->p->display_pool); + if (direct) { + VideoFormatCopyCropAr(&direct->format, &todisplay->format); + picture_Copy(direct, todisplay); } - picture_Release(filtered); - filtered = NULL; + picture_Release(todisplay); } else { - direct = filtered; + direct = todisplay; } - if (!direct) + if (!direct) { + if (subpic) + subpicture_Delete(subpic); return VLC_EGENERIC; + } /* * Take a snapshot if requested @@ -782,8 +1014,23 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) if (do_snapshot) vout_snapshot_Set(&vout->p->snapshot, &vd->source, direct); - /* Render the direct buffer returned by vout_RenderPicture */ - vout_RenderWrapper(vout, direct); + /* Render the direct buffer */ + assert(vout_IsDisplayFiltered(vd) == !sys->display.use_dr); + vout_UpdateDisplaySourceProperties(vd, &direct->format); + if (sys->display.use_dr) { + vout_display_Prepare(vd, direct, subpic); + } else { + sys->display.filtered = vout_FilterDisplay(vd, direct); + if (sys->display.filtered) { + if (!do_dr_spu && !do_early_spu && vout->p->spu_blend && subpic) + picture_BlendSubpicture(sys->display.filtered, vout->p->spu_blend, subpic); + vout_display_Prepare(vd, sys->display.filtered, do_dr_spu ? subpic : NULL); + } + if (!do_dr_spu && subpic) + subpicture_Delete(subpic); + if (!sys->display.filtered) + return VLC_EGENERIC; + } vout_chrono_Stop(&vout->p->render); #if 0 @@ -806,8 +1053,11 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced) /* Display the direct buffer returned by vout_RenderPicture */ vout->p->displayed.date = mdate(); - - vout_DisplayWrapper(vout, direct); + vout_display_Display(vd, + sys->display.filtered ? sys->display.filtered + : direct, + subpic); + sys->display.filtered = NULL; vout_statistic_Update(&vout->p->statistic, 1, 0); @@ -909,12 +1159,12 @@ static void ThreadManage(vout_thread_t *vout, static void ThreadDisplaySubpicture(vout_thread_t *vout, subpicture_t *subpicture) { - spu_DisplaySubpicture(vout->p->p_spu, subpicture); + spu_PutSubpicture(vout->p->spu, subpicture); } static void ThreadFlushSubpicture(vout_thread_t *vout, int channel) { - spu_ClearChannel(vout->p->p_spu, channel); + spu_ClearChannel(vout->p->spu, channel); } static void ThreadDisplayOsdTitle(vout_thread_t *vout, const char *string) @@ -927,99 +1177,19 @@ static void ThreadDisplayOsdTitle(vout_thread_t *vout, const char *string) string); } -static void ThreadFilterFlush(vout_thread_t *vout) +static void ThreadChangeSubSources(vout_thread_t *vout, const char *filters) { - if (vout->p->displayed.current) - picture_Release( vout->p->displayed.current ); - vout->p->displayed.current = NULL; - - if (vout->p->displayed.next) - picture_Release( vout->p->displayed.next ); - vout->p->displayed.next = NULL; - - vlc_mutex_lock(&vout->p->filter.lock); - filter_chain_VideoFlush(vout->p->filter.chain_static); - filter_chain_VideoFlush(vout->p->filter.chain_interactive); - vlc_mutex_unlock(&vout->p->filter.lock); -} - -typedef struct { - char *name; - config_chain_t *cfg; -} vout_filter_t; - -static void ThreadChangeFilters(vout_thread_t *vout, const char *filters) -{ - ThreadFilterFlush(vout); - - vlc_array_t array_static; - vlc_array_t array_interactive; - - vlc_array_init(&array_static); - vlc_array_init(&array_interactive); - char *current = filters ? strdup(filters) : NULL; - while (current) { - config_chain_t *cfg; - char *name; - char *next = config_ChainCreate(&name, &cfg, current); - - if (name && *name) { - vout_filter_t *e = xmalloc(sizeof(*e)); - e->name = name; - e->cfg = cfg; - if (!strcmp(e->name, "deinterlace") || - !strcmp(e->name, "postproc")) { - vlc_array_append(&array_static, e); - } else { - vlc_array_append(&array_interactive, e); - } - } else { - if (cfg) - config_ChainDestroy(cfg); - free(name); - } - free(current); - current = next; - } - - es_format_t fmt; - es_format_Init(&fmt, VIDEO_ES, vout->p->original.i_chroma); - fmt.video = vout->p->original; - - vlc_mutex_lock(&vout->p->filter.lock); - - filter_chain_Reset(vout->p->filter.chain_static, &fmt, &fmt); - filter_chain_Reset(vout->p->filter.chain_interactive, &fmt, &fmt); - - for (int a = 0; a < 2; a++) { - vlc_array_t *array = a == 0 ? &array_static : - &array_interactive; - filter_chain_t *chain = a == 0 ? vout->p->filter.chain_static : - vout->p->filter.chain_interactive; - - for (int i = 0; i < vlc_array_count(array); i++) { - vout_filter_t *e = vlc_array_item_at_index(array, i); - msg_Dbg(vout, "Adding '%s' as %s", e->name, a == 0 ? "static" : "interactive"); - if (!filter_chain_AppendFilter(chain, e->name, e->cfg, NULL, NULL)) { - msg_Err(vout, "Failed to add filter '%s'", e->name); - config_ChainDestroy(e->cfg); - } - free(e->name); - free(e); - } - vlc_array_clear(array); - } - - vlc_mutex_unlock(&vout->p->filter.lock); + spu_ChangeSources(vout->p->spu, filters); } static void ThreadChangeSubFilters(vout_thread_t *vout, const char *filters) { - spu_ChangeFilters(vout->p->p_spu, filters); + spu_ChangeFilters(vout->p->spu, filters); } + static void ThreadChangeSubMargin(vout_thread_t *vout, int margin) { - spu_ChangeMargin(vout->p->p_spu, margin); + spu_ChangeMargin(vout->p->spu, margin); } static void ThreadChangePause(vout_thread_t *vout, bool is_paused, mtime_t date) @@ -1036,9 +1206,9 @@ static void ThreadChangePause(vout_thread_t *vout, bool is_paused, mtime_t date) picture_fifo_OffsetDate(vout->p->decoder_fifo, duration); if (vout->p->displayed.decoded) vout->p->displayed.decoded->date += duration; - spu_OffsetSubtitleDate(vout->p->p_spu, duration); + spu_OffsetSubtitleDate(vout->p->spu, duration); - ThreadFilterFlush(vout); + ThreadFilterFlush(vout, false); } else { vout->p->step.timestamp = VLC_TS_INVALID; vout->p->step.last = VLC_TS_INVALID; @@ -1052,7 +1222,7 @@ static void ThreadFlush(vout_thread_t *vout, bool below, mtime_t date) vout->p->step.timestamp = VLC_TS_INVALID; vout->p->step.last = VLC_TS_INVALID; - ThreadFilterFlush(vout); /* FIXME too much */ + ThreadFilterFlush(vout, false); /* FIXME too much */ picture_t *last = vout->p->displayed.decoded; if (last) { @@ -1133,51 +1303,31 @@ static void ThreadChangeZoom(vout_thread_t *vout, int num, int den) static void ThreadChangeAspectRatio(vout_thread_t *vout, unsigned num, unsigned den) { - const video_format_t *source = &vout->p->original; - - if (num > 0 && den > 0) { - num *= source->i_visible_height; - den *= source->i_visible_width; - vlc_ureduce(&num, &den, num, den, 0); - } vout_SetDisplayAspect(vout->p->display.vd, num, den); } static void ThreadExecuteCropWindow(vout_thread_t *vout, - unsigned crop_num, unsigned crop_den, unsigned x, unsigned y, unsigned width, unsigned height) { - const video_format_t *source = &vout->p->original; - - vout_SetDisplayCrop(vout->p->display.vd, - crop_num, crop_den, - source->i_x_offset + x, - source->i_y_offset + y, - width, height); + vout_SetDisplayCrop(vout->p->display.vd, 0, 0, + x, y, width, height); } static void ThreadExecuteCropBorder(vout_thread_t *vout, unsigned left, unsigned top, unsigned right, unsigned bottom) { - const video_format_t *source = &vout->p->original; - ThreadExecuteCropWindow(vout, 0, 0, - left, - top, - /* At worst, it becomes < 0 (but unsigned) and will be rejected */ - source->i_visible_width - (left + right), - source->i_visible_height - (top + bottom)); + msg_Err(vout, "ThreadExecuteCropBorder %d.%d %dx%d", left, top, right, bottom); + vout_SetDisplayCrop(vout->p->display.vd, 0, 0, + left, top, -(int)right, -(int)bottom); } static void ThreadExecuteCropRatio(vout_thread_t *vout, unsigned num, unsigned den) { - const video_format_t *source = &vout->p->original; - ThreadExecuteCropWindow(vout, num, den, - 0, 0, - source->i_visible_width, - source->i_visible_height); + vout_SetDisplayCrop(vout->p->display.vd, num, den, + 0, 0, 0, 0); } static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state) @@ -1188,11 +1338,13 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state) vout->p->display_pool = NULL; vout->p->private_pool = NULL; + vout->p->filter.configuration = NULL; + video_format_Copy(&vout->p->filter.format, &vout->p->original); vout->p->filter.chain_static = - filter_chain_New( vout, "video filter2", false, + filter_chain_New( vout, "video filter2", true, VoutVideoFilterStaticAllocationSetup, NULL, vout); vout->p->filter.chain_interactive = - filter_chain_New( vout, "video filter2", false, + filter_chain_New( vout, "video filter2", true, VoutVideoFilterInteractiveAllocationSetup, NULL, vout); vout_display_state_t state_default; @@ -1223,12 +1375,18 @@ static int ThreadStart(vout_thread_t *vout, const vout_display_state_t *state) vout->p->step.last = VLC_TS_INVALID; vout->p->step.timestamp = VLC_TS_INVALID; + vout->p->spu_blend_chroma = 0; + vout->p->spu_blend = NULL; + video_format_Print(VLC_OBJECT(vout), "original format", &vout->p->original); return VLC_SUCCESS; } static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state) { + if (vout->p->spu_blend) + filter_DeleteBlend(vout->p->spu_blend); + /* Destroy translation tables */ if (vout->p->display.vd) { if (vout->p->decoder_pool) { @@ -1241,6 +1399,8 @@ static void ThreadStop(vout_thread_t *vout, vout_display_state_t *state) /* Destroy the video filters2 */ filter_chain_Delete(vout->p->filter.chain_interactive); filter_chain_Delete(vout->p->filter.chain_static); + video_format_Clean(&vout->p->filter.format); + free(vout->p->filter.configuration); if (vout->p->decoder_fifo) picture_fifo_Delete(vout->p->decoder_fifo); @@ -1279,6 +1439,8 @@ static int ThreadReinit(vout_thread_t *vout, ThreadClean(vout); return VLC_EGENERIC; } + /* We ignore crop/ar changes at this point, they are dynamically supported */ + VideoFormatCopyCropAr(&vout->p->original, &original); if (video_format_IsSimilar(&original, &vout->p->original)) { if (cfg->dpb_size <= vout->p->dpb_size) return VLC_SUCCESS; @@ -1362,7 +1524,10 @@ static void *Thread(void *object) ThreadDisplayOsdTitle(vout, cmd.u.string); break; case VOUT_CONTROL_CHANGE_FILTERS: - ThreadChangeFilters(vout, cmd.u.string); + ThreadChangeFilters(vout, NULL, cmd.u.string, false); + break; + case VOUT_CONTROL_CHANGE_SUB_SOURCES: + ThreadChangeSubSources(vout, cmd.u.string); break; case VOUT_CONTROL_CHANGE_SUB_FILTERS: ThreadChangeSubFilters(vout, cmd.u.string); @@ -1401,7 +1566,7 @@ static void *Thread(void *object) ThreadExecuteCropRatio(vout, cmd.u.pair.a, cmd.u.pair.b); break; case VOUT_CONTROL_CROP_WINDOW: - ThreadExecuteCropWindow(vout, 0, 0, + ThreadExecuteCropWindow(vout, cmd.u.window.x, cmd.u.window.y, cmd.u.window.width, cmd.u.window.height); break;