[vlc-devel] [PATCH] vout: add derived chroma support

Thomas Guillem thomas at gllm.fr
Tue Apr 18 15:02:13 CEST 2017


Hardware decoders that output opaque pictures can now specify a chroma that
could by used by CPU video filters. If no opaque video filters are found (like
vdpau interlace/adjust/sharpen), two video converter modules will be inserted
in the filter chain. One opaque to derived converter will be inserted when
first needed, and a derived to opaque converter will be inserted at the end.

Hardware video filters are still preferred, this feature will be used only as
fallback in the worst case scenario (when no hardware filters could be used).

Using a hardware decoder with opaque pictures and 2 video converters can be
slower that just using a software decoder. The main advantage of this feature
is the ability to add any CPU filters without any vout reconfiguration.

Refs #18078
---
 include/vlc_es.h                | 10 +++++++++
 src/video_output/video_output.c | 46 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/include/vlc_es.h b/include/vlc_es.h
index 57610dd661..7db347e403 100644
--- a/include/vlc_es.h
+++ b/include/vlc_es.h
@@ -309,6 +309,16 @@ struct video_format_t
 {
     vlc_fourcc_t i_chroma;                               /**< picture chroma */
 
+    /**
+     * The chroma that can be derived from the picture chroma.
+     *
+     * 0 by default, used by the vout_thread and set by video decoder modules.
+     * When configuring the output format, a decoder module could specify this
+     * value in order to specify a chroma that could be used by cpu video
+     * filters. The vout_thread will automatically try to convert i_chroma to
+     * i_derive_chroma and vice-versa if a hardware video filter is missing. */
+    vlc_fourcc_t i_derive_chroma;
+
     unsigned int i_width;                                 /**< picture width */
     unsigned int i_height;                               /**< picture height */
     unsigned int i_x_offset;               /**< start offset of visible area */
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 8b48a1cc8a..6d9f9b1369 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -653,6 +653,10 @@ static picture_t *VoutVideoFilterInteractiveNewPicture(filter_t *filter)
 {
     vout_thread_t *vout = filter->owner.sys;
 
+    /* This can happen when deriving */
+    if (filter->fmt_out.video.i_chroma != vout->p->filter.format.i_chroma)
+        return picture_NewFromFormat(&filter->fmt_out.video);
+
     picture_t *picture = picture_pool_Get(vout->p->private_pool);
     if (picture) {
         picture_Reset(picture);
@@ -695,6 +699,37 @@ typedef struct {
     config_chain_t *cfg;
 } vout_filter_t;
 
+static int ThreadFilterInsertDerived(vout_thread_t *vout, filter_chain_t *chain,
+                                     const char *name)
+{
+    /* This function is called when a filter insertion failed. This function
+     * will try to append a converter to convert from video.i_chroma to
+     * video.i_derive_chroma. In case of success, the filter that failed should
+     * be inserted again. At the end of the chains, a video.i_derive_chroma to
+     * video.i_chroma converter will be automatically added, see
+     * es_format_IsSimilar() test at the end of ThreadChangeFilters().  */
+
+    const es_format_t *fmt_in = filter_chain_GetFmtOut(chain);
+    if (fmt_in->video.i_derive_chroma == 0
+     || fmt_in->video.i_chroma == fmt_in->video.i_derive_chroma)
+        return VLC_EGENERIC;
+
+    vlc_fourcc_t i_orig_chroma = fmt_in->video.i_chroma;
+    es_format_t fmt_derive = *fmt_in;
+    fmt_derive.video.i_chroma = fmt_in->video.i_derive_chroma;
+    if (filter_chain_AppendConverter(chain, fmt_in, &fmt_derive) != 0)
+    {
+        msg_Err(vout, "Failed to derive from '%4.4s' to '%4.4s'",
+                (const char *) &i_orig_chroma,
+                (const char *) &fmt_derive.video.i_chroma);
+        return VLC_EGENERIC;
+    }
+    msg_Dbg(vout, "adding '%4.4s' -> '%4.4s' derive converter needed by '%s'"
+            " filter", (const char *) &i_orig_chroma,
+            (const char *) &fmt_derive.video.i_chroma, name);
+    return VLC_SUCCESS;
+}
+
 static void ThreadChangeFilters(vout_thread_t *vout,
                                 const video_format_t *source,
                                 const char *filters,
@@ -750,9 +785,14 @@ static void ThreadChangeFilters(vout_thread_t *vout,
         for (size_t 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);
+            if (!filter_chain_AppendFilter(chain, e->name, e->cfg, NULL, NULL))
+            {
+                if (ThreadFilterInsertDerived(vout, chain, e->name) != VLC_SUCCESS
+                 || !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);
-- 
2.11.0



More information about the vlc-devel mailing list