[vlc-commits] [Git][videolan/vlc][master] 11 commits: avcodec: pass the whole es_format when looking for a codec.

Steve Lhomme (@robUx4) gitlab at videolan.org
Tue Feb 6 12:31:21 UTC 2024



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
8828f7d7 by Steve Lhomme at 2024-02-06T11:53:38+00:00
avcodec: pass the whole es_format when looking for a codec.

- - - - -
62056349 by Steve Lhomme at 2024-02-06T11:53:38+00:00
omxil: pass the whole es_format when looking for a video codec.

- - - - -
442723ed by Steve Lhomme at 2024-02-06T11:53:38+00:00
mmal: pass the whole es_format when looking for a codec.

- - - - -
18278324 by Steve Lhomme at 2024-02-06T11:53:38+00:00
chromecast: pass the whole es_format when looking for a codec

- - - - -
b2309174 by Steve Lhomme at 2024-02-06T11:53:38+00:00
fourcc: add codec FourCC for VP8/VP9 with alpha

They need 2 parallel decoders to handle the planes.

- - - - -
f459d4ed by Steve Lhomme at 2024-02-06T11:53:38+00:00
core: add ancillary data for VPX alpha channel

- - - - -
27350e78 by Steve Lhomme at 2024-02-06T11:53:38+00:00
codec: add a pseudo-decoder for VP8/VP9 with alpha

It uses 2 decoders in parallel and then merges the planes on output.
Only software decoders are supported for now.

- - - - -
652d8c08 by Steve Lhomme at 2024-02-06T11:53:38+00:00
vpx: allow decoding of the alpha channel bitstream

libavcodec is enable to do it without VPX.  And when it does, it uses libvpx.
So we can just use libvpx directly.

- - - - -
ac942ef0 by Steve Lhomme at 2024-02-06T11:53:38+00:00
avcodec: handle the VP9 alpha channel as a VP9 stream

It can decode it in hardware and software.

- - - - -
62200d31 by Steve Lhomme at 2024-02-06T11:53:38+00:00
mkv: check the AlphaMode of the video tracks

When the flag is set the BlockAdditional Element with BlockAddID of "1"
contains alpha channel data.

See https://www.ietf.org/archive/id/draft-ietf-cellar-matroska-15.html#section-5.1.4.1.29.4

- - - - -
2367cf2e by Steve Lhomme at 2024-02-06T11:53:38+00:00
mkv: handle alpha BlockAddId for VP8/VP9

- - - - -


25 changed files:

- include/vlc_ancillary.h
- include/vlc_fourcc.h
- modules/codec/Makefile.am
- modules/codec/avcodec/avcodec.c
- modules/codec/avcodec/avcodec.h
- modules/codec/avcodec/encoder.c
- modules/codec/avcodec/fourcc.c
- modules/codec/gstreamer/gstdecode.c
- modules/codec/meson.build
- modules/codec/omxil/mediacodec.c
- modules/codec/omxil/omxil.c
- modules/codec/omxil/omxil_utils.h
- modules/codec/omxil/utils.c
- modules/codec/vpx.c
- + modules/codec/vpx_alpha.c
- modules/demux/avformat/mux.c
- modules/demux/mkv/matroska_segment_parse.cpp
- modules/demux/mkv/mkv.cpp
- modules/demux/mkv/mkv.hpp
- modules/hw/mmal/codec.c
- modules/hw/nvdec/nvdec.c
- modules/packetizer/avparser.c
- modules/stream_out/chromecast/cast.cpp
- modules/stream_out/rtpfmt.c
- src/misc/fourcc_list.h


Changes:

=====================================
include/vlc_ancillary.h
=====================================
@@ -217,5 +217,17 @@ typedef struct vlc_icc_profile_t
     uint8_t data[]; /* binary profile data, see ICC.1:2022 (or later) */
 } vlc_icc_profile_t;
 
+/**
+ * VPx alpha data
+ */
+
+#define VLC_ANCILLARY_ID_VPX_ALPHA VLC_FOURCC('v','p','x','A')
+
+typedef struct vlc_vpx_alpha_t
+{
+    size_t  size;
+    uint8_t *data;
+} vlc_vpx_alpha_t;
+
 /** @} */
 #endif /* VLC_ANCILLARY_H */


=====================================
include/vlc_fourcc.h
=====================================
@@ -122,7 +122,9 @@
 #define VLC_CODEC_VP4             VLC_FOURCC('V','P','4','0')
 #define VLC_CODEC_VP7             VLC_FOURCC('V','P','7','0')
 #define VLC_CODEC_VP8             VLC_FOURCC('V','P','8','0')
+#define VLC_CODEC_VP8ALPHA_ES     VLC_FOURCC('V','P','8','a')
 #define VLC_CODEC_VP9             VLC_FOURCC('V','P','9','0')
+#define VLC_CODEC_VP9ALPHA_ES     VLC_FOURCC('V','P','9','a')
 #define VLC_CODEC_VP10            VLC_FOURCC('V','P',':','0')
 #define VLC_CODEC_AV1             VLC_FOURCC('a','v','0','1')
 #define VLC_CODEC_JPEG2000        VLC_FOURCC('J','P','2','K')


=====================================
modules/codec/Makefile.am
=====================================
@@ -568,6 +568,9 @@ libvpx_plugin_la_LIBADD = $(VPX_LIBS)
 EXTRA_LTLIBRARIES += libvpx_plugin.la
 codec_LTLIBRARIES += $(LTLIBvpx)
 
+libvpx_alpha_plugin_la_SOURCES = codec/vpx_alpha.c
+codec_LTLIBRARIES += libvpx_alpha_plugin.la
+
 libaom_plugin_la_SOURCES = codec/aom.c \
                            packetizer/iso_color_tables.h
 libaom_plugin_la_CPPFLAGS = $(AM_CPPFLAGS)


=====================================
modules/codec/avcodec/avcodec.c
=====================================
@@ -230,8 +230,7 @@ AVCodecContext *ffmpeg_AllocContext( decoder_t *p_dec,
     const AVCodec *p_codec = NULL;
 
     /* *** determine codec type *** */
-    if( !GetFfmpegCodec( p_dec->fmt_in->i_cat, p_dec->fmt_in->i_codec,
-                         &i_codec_id, &psz_namecodec ) ||
+    if( !GetFfmpegCodec( p_dec->fmt_in, &i_codec_id, &psz_namecodec ) ||
          i_codec_id == AV_CODEC_ID_RAWVIDEO )
          return NULL;
 


=====================================
modules/codec/avcodec/avcodec.h
=====================================
@@ -24,7 +24,7 @@
 #include "avcommon.h"
 
 /* VLC <-> avcodec tables */
-bool GetFfmpegCodec( enum es_format_category_e cat, vlc_fourcc_t i_fourcc,
+bool GetFfmpegCodec( const es_format_t *,
                      enum AVCodecID *pi_ffmpeg_codec, const char **ppsz_name );
 vlc_fourcc_t GetVlcFourcc( enum AVCodecID i_ffmpeg_codec );
 vlc_fourcc_t GetVlcAudioFormat( int i_sample_fmt );


=====================================
modules/codec/avcodec/encoder.c
=====================================
@@ -336,8 +336,7 @@ int InitVideoEnc( vlc_object_t *p_this )
                 psz_namecodec = "MPEG-1 video";
                 break;
             }
-            if( GetFfmpegCodec( VIDEO_ES, p_enc->fmt_out.i_codec, &i_codec_id,
-                                &psz_namecodec ) )
+            if( GetFfmpegCodec( &p_enc->fmt_out, &i_codec_id, &psz_namecodec ) )
                 break;
             bool uv_flipped;
             if( FindFfmpegChroma( p_enc->fmt_out.i_codec, &uv_flipped ) != AV_PIX_FMT_NONE )
@@ -350,8 +349,7 @@ int InitVideoEnc( vlc_object_t *p_this )
 
         case AUDIO_ES:
             encoder_ops = &audio_ops;
-            if( GetFfmpegCodec( AUDIO_ES, p_enc->fmt_out.i_codec, &i_codec_id,
-                                &psz_namecodec ) )
+            if( GetFfmpegCodec( &p_enc->fmt_out, &i_codec_id, &psz_namecodec ) )
                 break;
             /* fall through */
         default:


=====================================
modules/codec/avcodec/fourcc.c
=====================================
@@ -251,6 +251,7 @@ static const struct vlc_avcodec_fourcc video_codecs[] =
     { VLC_CODEC_CLLC, AV_CODEC_ID_CLLC },
     { VLC_CODEC_MSS2, AV_CODEC_ID_MSS2 },
     { VLC_CODEC_VP9, AV_CODEC_ID_VP9 },
+    { VLC_CODEC_VP9ALPHA_ES, AV_CODEC_ID_VP9 },
 #if LIBAVCODEC_VERSION_CHECK( 57, 83, 101 )
     { VLC_CODEC_AV1, AV_CODEC_ID_AV1 },
 #endif
@@ -556,13 +557,18 @@ static const struct vlc_avcodec_fourcc spu_codecs[] =
     /* ffmpeg only: AV_CODEC_ID_ASS */
 };
 
-bool GetFfmpegCodec( enum es_format_category_e cat, vlc_fourcc_t i_fourcc,
+bool GetFfmpegCodec( const es_format_t *es,
                      enum AVCodecID *pi_ffmpeg_codec, const char **ppsz_name )
 {
     const struct vlc_avcodec_fourcc *base;
     size_t count;
 
-    switch( cat )
+    if (es->i_codec == VLC_CODEC_VP8 && es->i_level) // contains alpha extradata
+        return false;
+    if (es->i_codec == VLC_CODEC_VP9 && es->i_level) // contains alpha extradata
+        return false;
+
+    switch( es->i_cat )
     {
         case VIDEO_ES:
             base = video_codecs;
@@ -581,7 +587,7 @@ bool GetFfmpegCodec( enum es_format_category_e cat, vlc_fourcc_t i_fourcc,
             count = 0;
     }
 
-    i_fourcc = vlc_fourcc_GetCodec( cat, i_fourcc );
+    vlc_fourcc_t i_fourcc = vlc_fourcc_GetCodec( es->i_cat, es->i_codec );
 
     for( size_t i = 0; i < count; i++ )
     {
@@ -590,7 +596,7 @@ bool GetFfmpegCodec( enum es_format_category_e cat, vlc_fourcc_t i_fourcc,
             if( pi_ffmpeg_codec != NULL )
                 *pi_ffmpeg_codec = base[i].i_codec;
             if( ppsz_name )
-                *ppsz_name = vlc_fourcc_GetDescription( cat, i_fourcc );
+                *ppsz_name = vlc_fourcc_GetDescription( es->i_cat, i_fourcc );
             return true;
         }
     }


=====================================
modules/codec/gstreamer/gstdecode.c
=====================================
@@ -408,9 +408,13 @@ static GstStructure* vlc_to_gst_fmt( const es_format_t *p_fmt )
                 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL );
         break;
     case VLC_CODEC_VP8:
+        if (p_fmt->i_level) // contains alpha extradata
+            return NULL;
         p_str = gst_structure_new_empty( "video/x-vp8" );
         break;
     case VLC_CODEC_VP9:
+        if (p_fmt->i_level) // contains alpha extradata
+            return NULL;
         p_str = gst_structure_new_empty( "video/x-vp9" );
         break;
     case VLC_CODEC_AV1:


=====================================
modules/codec/meson.build
=====================================
@@ -810,6 +810,13 @@ if vpx_dep.found()
   }
 endif
 
+# VP8/VP9 with alpha pseudo-decoder
+vlc_modules += {
+    'name' : 'vpx_alpha',
+    'sources' : files('vpx_alpha.c')
+}
+
+
 # libaom AV1 codec
 aom_dep = dependency('aom', required: get_option('aom'))
 if aom_dep.found()


=====================================
modules/codec/omxil/mediacodec.c
=====================================
@@ -808,8 +808,14 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
             break;
         case VLC_CODEC_WMV3: mime = "video/x-ms-wmv"; break;
         case VLC_CODEC_VC1:  mime = "video/wvc1"; break;
-        case VLC_CODEC_VP8:  mime = "video/x-vnd.on2.vp8"; break;
-        case VLC_CODEC_VP9:  mime = "video/x-vnd.on2.vp9"; break;
+        case VLC_CODEC_VP8:
+            if (p_dec->fmt_in->i_level) // contains alpha extradata
+                return VLC_ENOTSUP;
+            mime = "video/x-vnd.on2.vp8"; break;
+        case VLC_CODEC_VP9:
+            if (p_dec->fmt_in->i_level) // contains alpha extradata
+                return VLC_ENOTSUP;
+            mime = "video/x-vnd.on2.vp9"; break;
         }
     }
     else


=====================================
modules/codec/omxil/omxil.c
=====================================
@@ -211,7 +211,7 @@ static OMX_ERRORTYPE SetPortDefinition(decoder_t *p_dec, OmxPort *p_port,
                   def->format.video.nFrameHeight * 2;
             p_port->i_frame_size = def->nBufferSize;
 
-            def->format.video.eCompressionFormat = GetOmxVideoFormat(p_fmt->i_codec);
+            def->format.video.eCompressionFormat = GetOmxVideoFormat(p_fmt);
             if( def->format.video.eCompressionFormat == OMX_VIDEO_CodingUnused)
             {
                 def->format.video.eColorFormat = GetOmxChromaFormat(p_fmt->i_codec);


=====================================
modules/codec/omxil/omxil_utils.h
=====================================
@@ -225,7 +225,7 @@ int OMXCodec_GetQuirks( enum es_format_category_e i_cat, vlc_fourcc_t i_codec,
 /*****************************************************************************
  * fourcc -> omx id mapping
  *****************************************************************************/
-OMX_VIDEO_CODINGTYPE GetOmxVideoFormat( vlc_fourcc_t i_fourcc );
+OMX_VIDEO_CODINGTYPE GetOmxVideoFormat( const es_format_t * );
 vlc_fourcc_t GetVlcVideoFormat( OMX_VIDEO_CODINGTYPE i_omx_codec );
 OMX_AUDIO_CODINGTYPE GetOmxAudioFormat( vlc_fourcc_t i_fourcc );
 vlc_fourcc_t OmxToVlcAudioFormat( OMX_AUDIO_CODINGTYPE i_omx_codec );


=====================================
modules/codec/omxil/utils.c
=====================================
@@ -588,13 +588,23 @@ static const struct
     { VLC_CODEC_VYUY, OMX_COLOR_FormatCrYCbY, 4, 2, 0 },
 };
 
-OMX_VIDEO_CODINGTYPE GetOmxVideoFormat( vlc_fourcc_t i_fourcc )
+OMX_VIDEO_CODINGTYPE GetOmxVideoFormat( const es_format_t *es )
 {
-    i_fourcc = vlc_fourcc_GetCodec( VIDEO_ES, i_fourcc );
+    if ( unlikely( es->i_cat != VIDEO_ES ) )
+        return OMX_VIDEO_CodingUnused;
+
+    vlc_fourcc_t i_fourcc = vlc_fourcc_GetCodec( VIDEO_ES, es->i_codec );
 
     for( size_t i = 0; i < ARRAY_SIZE(video_format_table); i++ )
         if( video_format_table[i].i_fourcc == i_fourcc )
+        {
+            if (es->i_codec == VLC_CODEC_VP8 && es->i_level) // contains alpha extradata
+                continue;
+            if (es->i_codec == VLC_CODEC_VP9 && es->i_level) // contains alpha extradata
+                continue;
+
             return video_format_table[i].i_codec;
+        }
 
     return OMX_VIDEO_CodingUnused;
 }
@@ -608,13 +618,23 @@ vlc_fourcc_t GetVlcVideoFormat( OMX_VIDEO_CODINGTYPE i_omx_codec )
     return 0;
 }
 
-static const char *GetOmxVideoRole( vlc_fourcc_t i_fourcc )
+static const char *GetOmxVideoRole( const es_format_t *es )
 {
-    i_fourcc = vlc_fourcc_GetCodec( VIDEO_ES, i_fourcc );
+    if ( unlikely( es->i_cat != VIDEO_ES ) )
+        return NULL;
+
+    vlc_fourcc_t i_fourcc = vlc_fourcc_GetCodec( VIDEO_ES, es->i_codec );
 
     for( size_t i = 0; i < ARRAY_SIZE(video_format_table); i++ )
         if( video_format_table[i].i_fourcc == i_fourcc )
+        {
+            if (es->i_codec == VLC_CODEC_VP8 && es->i_level) // contains alpha extradata
+                continue;
+            if (es->i_codec == VLC_CODEC_VP9 && es->i_level) // contains alpha extradata
+                continue;
+
             return video_format_table[i].psz_role;
+        }
 
     return NULL;
 }
@@ -682,7 +702,7 @@ const char *GetOmxRole( const es_format_t *es,
             GetOmxVideoEncRole( es->i_codec ) : GetOmxAudioEncRole( es->i_codec );
 
     return es->i_cat == VIDEO_ES ?
-        GetOmxVideoRole( es->i_codec ) : GetOmxAudioRole( es->i_codec );
+        GetOmxVideoRole( es ) : GetOmxAudioRole( es->i_codec );
 }
 
 OMX_COLOR_FORMATTYPE GetOmxChromaFormat( vlc_fourcc_t i_fourcc )


=====================================
modules/codec/vpx.c
=====================================
@@ -309,14 +309,22 @@ static int OpenDecoder(vlc_object_t *p_this)
     switch (dec->fmt_in->i_codec)
     {
 #ifdef ENABLE_VP8_DECODER
-    case VLC_CODEC_WEBP:
     case VLC_CODEC_VP8:
+        if (dec->fmt_in->i_level) // contains alpha extradata
+            return VLC_ENOTSUP;
+        // fallthrough
+    case VLC_CODEC_WEBP:
+    case VLC_CODEC_VP8ALPHA_ES:
         iface = &vpx_codec_vp8_dx_algo;
         vp_version = 8;
         break;
 #endif
 #ifdef ENABLE_VP9_DECODER
     case VLC_CODEC_VP9:
+        if (dec->fmt_in->i_level) // contains alpha extradata
+            return VLC_ENOTSUP;
+        // fallthrough
+    case VLC_CODEC_VP9ALPHA_ES:
         iface = &vpx_codec_vp9_dx_algo;
         vp_version = 9;
         break;
@@ -404,14 +412,19 @@ static int OpenEncoder(vlc_object_t *p_this)
     switch (p_enc->fmt_out.i_codec)
     {
 #ifdef ENABLE_VP8_ENCODER
-    case VLC_CODEC_WEBP:
     case VLC_CODEC_VP8:
+        if (p_enc->fmt_out.i_level) // contains alpha extradata
+            return VLC_ENOTSUP;
+        // fallthrough
+    case VLC_CODEC_WEBP:
         iface = &vpx_codec_vp8_cx_algo;
         vp_version = 8;
         break;
 #endif
 #ifdef ENABLE_VP9_ENCODER
     case VLC_CODEC_VP9:
+        if (p_enc->fmt_out.i_level) // contains alpha extradata
+            return VLC_ENOTSUP;
         iface = &vpx_codec_vp9_cx_algo;
         vp_version = 9;
         break;


=====================================
modules/codec/vpx_alpha.c
=====================================
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+// vpx_alpha.c : pseudo-decoder for VP8/VP9 streams with alpha side-channel
+// Copyright © 2023 VideoLabs, VLC authors and VideoLAN
+
+// Authors: Steve Lhomme <robux4 at videolabs.io>
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+#include <vlc_ancillary.h>
+#include <vlc_modules.h>
+#include <vlc_atomic.h>
+#include <vlc_picture_pool.h>
+
+static int OpenDecoder(vlc_object_t *);
+static void CloseDecoder(vlc_object_t *);
+
+vlc_module_begin ()
+    set_description(N_("VPx+alpha video decoder"))
+    set_capability("video decoder", 150)
+    set_callbacks(OpenDecoder, CloseDecoder)
+    set_subcategory(SUBCAT_INPUT_VCODEC)
+vlc_module_end ()
+
+struct vp_decoder
+{
+    decoder_t           dec;
+    es_format_t         fmt_in;
+    es_format_t         fmt_out;
+    vlc_picture_chain_t decoded;
+};
+
+typedef struct
+{
+    struct vp_decoder *opaque;
+    struct vp_decoder *alpha;
+    vlc_mutex_t       lock;
+    vlc_video_context *vctx;
+    picture_t *(*pf_combine)(decoder_t *, picture_t *opaque, picture_t *alpha, vlc_video_context *);
+
+    picture_pool_t    *pool;
+} vpx_alpha;
+
+
+static vlc_decoder_device *GetDevice( decoder_t *dec )
+{
+    decoder_t *bdec = container_of(vlc_object_parent(dec), decoder_t, obj);
+    vpx_alpha *p_sys = bdec->p_sys;
+    vlc_mutex_lock(&p_sys->lock);
+    vlc_decoder_device *res = decoder_GetDecoderDevice(bdec);
+    vlc_mutex_unlock(&p_sys->lock);
+    return res;
+}
+
+struct cpu_alpha_context
+{
+    picture_context_t  ctx;
+    picture_t          *opaque;
+    picture_t          *alpha;
+};
+
+static void cpu_alpha_destroy(picture_context_t *ctx)
+{
+    struct cpu_alpha_context *pctx = container_of(ctx, struct cpu_alpha_context, ctx);
+    picture_Release(pctx->opaque);
+    picture_Release(pctx->alpha);
+    free(pctx);
+}
+
+static picture_context_t *cpu_alpha_copy(picture_context_t *src)
+{
+    struct cpu_alpha_context *pctx = container_of(src, struct cpu_alpha_context, ctx);
+    struct cpu_alpha_context *alpha_ctx = calloc(1, sizeof(*alpha_ctx));
+    if (unlikely(alpha_ctx == NULL))
+        return NULL;
+    alpha_ctx->ctx = *src;
+    alpha_ctx->opaque = picture_Hold(pctx->opaque);
+    alpha_ctx->alpha  = picture_Hold(pctx->alpha);
+    return &alpha_ctx->ctx;
+}
+
+static picture_t *CombinePicturesCPU(decoder_t *bdec, picture_t *opaque, picture_t *alpha, vlc_video_context *vctx)
+{
+    assert(vctx == NULL); VLC_UNUSED(vctx);
+    vpx_alpha *p_sys = bdec->p_sys;
+    picture_t *out = picture_pool_Wait(p_sys->pool);
+    if (out == NULL)
+        return NULL;
+
+    struct cpu_alpha_context *alpha_ctx = calloc(1, sizeof(*alpha_ctx));
+    if (unlikely(alpha_ctx == NULL))
+    {
+        picture_Release(out);
+        return NULL;
+    }
+    alpha_ctx->ctx = (picture_context_t) {
+        cpu_alpha_destroy, cpu_alpha_copy, NULL
+    };
+    alpha_ctx->opaque = picture_Hold(opaque);
+    alpha_ctx->alpha  = picture_Hold(alpha);
+    out->context = &alpha_ctx->ctx;
+
+    for (int i=0; i<opaque->i_planes; i++)
+        out->p[i] = opaque->p[i];
+    out->p[opaque->i_planes] = alpha->p[0];
+    return out;
+}
+
+static int SetupCPU(decoder_t *bdec)
+{
+    vpx_alpha *p_sys = bdec->p_sys;
+    picture_t *pics[4];
+    size_t i=0;
+
+    if (p_sys->pool)
+    {
+        picture_pool_Release(p_sys->pool);
+        p_sys->pool = NULL;
+    }
+
+    for (; i<ARRAY_SIZE(pics); i++)
+    {
+        pics[i] = picture_NewFromResource(&bdec->fmt_out.video, &(picture_resource_t){0});
+        if (pics[i] == NULL)
+            goto error;
+    }
+    p_sys->pool = picture_pool_New(ARRAY_SIZE(pics), pics);
+    if (p_sys->pool)
+        return VLC_SUCCESS;
+
+error:
+    while (i-- > 0)
+        picture_Release(pics[i]);
+    return VLC_EGENERIC;
+}
+
+static picture_t *CombineKeepAlpha(decoder_t *bdec, picture_t *opaque, picture_t *alpha, vlc_video_context *vctx)
+{
+    VLC_UNUSED(bdec); VLC_UNUSED(opaque); VLC_UNUSED(vctx);
+    return picture_Hold(alpha);
+}
+
+static picture_t *CombineKeepOpaque(decoder_t *bdec, picture_t *opaque, picture_t *alpha, vlc_video_context *vctx)
+{
+    VLC_UNUSED(bdec); VLC_UNUSED(alpha); VLC_UNUSED(vctx);
+    return picture_Hold(opaque);
+}
+
+static int FormatUpdate( decoder_t *dec, vlc_video_context *vctx )
+{
+    decoder_t *bdec = container_of(vlc_object_parent(dec), decoder_t, obj);
+    vpx_alpha *p_sys = bdec->p_sys;
+    vlc_mutex_lock(&p_sys->lock);
+
+    int res = VLC_SUCCESS;
+    if (dec == &p_sys->alpha->dec)
+    {
+        if (es_format_IsSimilar(&p_sys->alpha->fmt_out, &dec->fmt_out))
+            // nothing changed
+            goto done;
+        es_format_Clean(&p_sys->alpha->fmt_out);
+        es_format_Copy(&p_sys->alpha->fmt_out, &dec->fmt_out);
+        if (p_sys->opaque->dec.fmt_out.video.i_chroma == 0)
+        {
+            // not ready
+            bdec->fmt_out.video.i_chroma = bdec->fmt_out.i_codec = dec->fmt_out.video.i_chroma;
+            p_sys->pf_combine = CombineKeepAlpha;
+            goto done;
+        }
+    }
+    else
+    {
+        if (es_format_IsSimilar(&p_sys->opaque->fmt_out, &dec->fmt_out))
+            // nothing changed
+            goto done;
+        es_format_Clean(&p_sys->opaque->fmt_out);
+        es_format_Copy(&p_sys->opaque->fmt_out, &dec->fmt_out);
+        if (p_sys->alpha->dec.fmt_out.video.i_chroma == 0)
+        {
+            // not ready
+            bdec->fmt_out.video.i_chroma = bdec->fmt_out.i_codec = dec->fmt_out.video.i_chroma;
+            p_sys->pf_combine = CombineKeepOpaque;
+            goto done;
+        }
+    }
+    es_format_Clean(&bdec->fmt_out);
+    es_format_Copy(&bdec->fmt_out, &dec->fmt_out);
+
+    switch (dec->fmt_out.video.i_chroma)
+    {
+        case VLC_CODEC_I420:
+            // TODO support other formats
+            bdec->fmt_out.video.i_chroma = bdec->fmt_out.i_codec = VLC_CODEC_YUV420A;
+            res = SetupCPU(bdec);
+            if (res == VLC_SUCCESS)
+            {
+                p_sys->pf_combine = CombinePicturesCPU;
+            }
+            break;
+        default:
+            msg_Err(dec, "unsupported decoder output %4.4s", (char*)&dec->fmt_out.video.i_chroma);
+            res = VLC_EGENERIC;
+            break;
+    }
+    if (res == VLC_SUCCESS)
+        res = decoder_UpdateVideoOutput(bdec, vctx);
+
+done:
+    vlc_mutex_unlock(&p_sys->lock);
+    return res;
+}
+
+static bool SendMergedLocked(decoder_t *bdec)
+{
+    vpx_alpha *p_sys = bdec->p_sys;
+
+    picture_t *opaque = vlc_picture_chain_PeekFront(&p_sys->opaque->decoded);
+    picture_t *alpha  = vlc_picture_chain_PeekFront(&p_sys->alpha->decoded);
+    while (opaque != NULL && alpha != NULL)
+    {
+        if (opaque->date == alpha->date)
+        {
+            // dequeue if both first of the queue match DTS/PTS
+            // merge alpha and opaque pictures with same DTS/PTS and send them
+            picture_t *out = p_sys->pf_combine(bdec, opaque, alpha, p_sys->vctx);
+            if (out != NULL)
+            {
+                video_format_CopyCropAr(&out->format, &opaque->format);
+                picture_CopyProperties(out, opaque);
+            }
+
+            vlc_picture_chain_PopFront(&p_sys->opaque->decoded);
+            picture_Release(opaque);
+
+            vlc_picture_chain_PopFront(&p_sys->alpha->decoded);
+            picture_Release(alpha);
+
+            if (out == NULL)
+                return false;
+
+            decoder_QueueVideo(bdec, out);
+            return true;
+        }
+
+        // in case decoders drop some frames
+        if (opaque->date > alpha->date)
+        {
+            msg_Dbg(bdec, "missing decoded opaque at %" PRId64 " dropping alpha", alpha->date);
+            vlc_picture_chain_PopFront(&p_sys->alpha->decoded);
+            picture_Release(alpha);
+        }
+        else
+        {
+            msg_Dbg(bdec, "missing decoded alpha at %" PRId64 " dropping opaque", opaque->date);
+            vlc_picture_chain_PopFront(&p_sys->opaque->decoded);
+            picture_Release(opaque);
+        }
+        opaque = vlc_picture_chain_PeekFront(&p_sys->opaque->decoded);
+        alpha  = vlc_picture_chain_PeekFront(&p_sys->alpha->decoded);
+    }
+    return false;
+}
+
+static void QueuePic( decoder_t *dec, picture_t *pic )
+{
+    decoder_t *bdec = container_of(vlc_object_parent(dec), decoder_t, obj);
+    vpx_alpha *p_sys = bdec->p_sys;
+
+    vlc_mutex_lock(&p_sys->lock);
+    if (dec == &p_sys->alpha->dec)
+    {
+        vlc_picture_chain_Append(&p_sys->alpha->decoded, pic);
+    }
+    else
+    {
+        vlc_picture_chain_Append(&p_sys->opaque->decoded, pic);
+    }
+
+    SendMergedLocked(bdec);
+    vlc_mutex_unlock(&p_sys->lock);
+}
+
+static vlc_tick_t GetDisplayDate( decoder_t *dec, vlc_tick_t sys_now, vlc_tick_t ts)
+{
+    decoder_t *bdec = container_of(vlc_object_parent(dec), decoder_t, obj);
+    return decoder_GetDisplayDate(bdec, sys_now, ts);
+}
+
+static float GetDisplayRate( decoder_t *dec )
+{
+    decoder_t *bdec = container_of(vlc_object_parent(dec), decoder_t, obj);
+    return decoder_GetDisplayRate(bdec);
+}
+
+static int GetAttachments( decoder_t *dec,
+                            input_attachment_t ***ppp_attachment,
+                            int *pi_attachment )
+{
+    decoder_t *bdec = container_of(vlc_object_parent(dec), decoder_t, obj);
+    return decoder_GetInputAttachments(bdec, ppp_attachment, pi_attachment);
+}
+
+struct alpha_frame
+{
+    vlc_atomic_rc_t rc;
+    vlc_frame_t     *frame; // source frame
+    vlc_frame_t     opaque; // opaque bitstream
+    vlc_frame_t     alpha;  // alpha bitstream
+};
+
+static void ReleaseAlphaFrame(vlc_frame_t *frame)
+{
+    struct alpha_frame *alpha_frame = container_of(frame, struct alpha_frame, alpha);
+
+    if (vlc_atomic_rc_dec(&alpha_frame->rc))
+    {
+        vlc_frame_Release(alpha_frame->frame);
+        free(alpha_frame);
+    }
+}
+
+static void ReleaseOpaqueFrame(vlc_frame_t *frame)
+{
+    struct alpha_frame *alpha_frame = container_of(frame, struct alpha_frame, opaque);
+
+    if (vlc_atomic_rc_dec(&alpha_frame->rc))
+    {
+        vlc_frame_Release(alpha_frame->frame);
+        free(alpha_frame);
+    }
+}
+
+static int Decode( decoder_t *dec, vlc_frame_t *frame )
+{
+    vpx_alpha *p_sys = dec->p_sys;
+
+    int res;
+    if (frame != NULL)
+    {
+        struct vlc_ancillary *p_alpha;
+        p_alpha = vlc_frame_GetAncillary(frame, VLC_ANCILLARY_ID_VPX_ALPHA);
+        if (p_alpha == NULL)
+        {
+            msg_Err(dec, "missing alpha data");
+            return VLCDEC_ECRITICAL;
+        }
+
+        struct alpha_frame *alpha_frame = malloc(sizeof(*alpha_frame));
+        if (unlikely(alpha_frame == NULL))
+            return VLCDEC_ECRITICAL;
+
+        vlc_vpx_alpha_t *alpha = vlc_ancillary_GetData(p_alpha);
+
+        static const struct vlc_frame_callbacks cbs_alpha = {
+            ReleaseAlphaFrame,
+        };
+
+        static const struct vlc_frame_callbacks cbs_opaque = {
+            ReleaseOpaqueFrame,
+        };
+
+        alpha_frame->frame = frame;
+        vlc_atomic_rc_init(&alpha_frame->rc);
+
+        vlc_frame_Init(&alpha_frame->alpha, &cbs_alpha, alpha->data, alpha->size);
+        vlc_atomic_rc_inc(&alpha_frame->rc);
+        alpha_frame->alpha.i_dts = frame->i_dts;
+        alpha_frame->alpha.i_pts = frame->i_pts;
+        alpha_frame->alpha.i_length = frame->i_length;
+        alpha_frame->alpha.i_flags = frame->i_flags;
+
+        vlc_frame_Init(&alpha_frame->opaque, &cbs_opaque, frame->p_buffer, frame->i_buffer);
+        alpha_frame->opaque.i_dts = frame->i_dts;
+        alpha_frame->opaque.i_pts = frame->i_pts;
+        alpha_frame->opaque.i_length = frame->i_length;
+        alpha_frame->opaque.i_flags = frame->i_flags;
+
+        res = p_sys->opaque->dec.pf_decode(&p_sys->opaque->dec, &alpha_frame->opaque);
+        if (res != VLCDEC_SUCCESS)
+        {
+            ReleaseOpaqueFrame(&alpha_frame->opaque);
+            return VLCDEC_ECRITICAL;
+        }
+
+        res = p_sys->alpha->dec.pf_decode(&p_sys->alpha->dec, &alpha_frame->alpha);
+        if (res != VLCDEC_SUCCESS)
+        {
+            ReleaseAlphaFrame(&alpha_frame->alpha);
+            return VLCDEC_ECRITICAL;
+        }
+    }
+    else
+    {
+        // drain
+        vlc_mutex_lock(&p_sys->lock);
+        while ( !vlc_picture_chain_IsEmpty(&p_sys->opaque->decoded) &&
+                !vlc_picture_chain_IsEmpty(&p_sys->alpha->decoded) )
+            SendMergedLocked(dec);
+
+        // drain remaining pushed pictures from one decoder
+        picture_t *picture;
+        while ((picture = vlc_picture_chain_PopFront(&p_sys->alpha->decoded)) != NULL)
+            picture_Release(picture);
+        while ((picture = vlc_picture_chain_PopFront(&p_sys->opaque->decoded)) != NULL)
+            picture_Release(picture);
+        vlc_mutex_unlock(&p_sys->lock);
+    }
+
+    return VLCDEC_SUCCESS;
+}
+
+static void Flush( decoder_t *dec )
+{
+    vpx_alpha *p_sys = dec->p_sys;
+    vlc_mutex_lock(&p_sys->lock);
+
+    if ( p_sys->opaque->dec.pf_flush != NULL )
+        p_sys->opaque->dec.pf_flush( &p_sys->opaque->dec );
+
+    if ( p_sys->alpha->dec.pf_flush != NULL )
+        p_sys->alpha->dec.pf_flush( &p_sys->alpha->dec );
+
+    picture_t *picture;
+    while ((picture = vlc_picture_chain_PopFront(&p_sys->opaque->decoded)) != NULL)
+        picture_Release(picture);
+    while ((picture = vlc_picture_chain_PopFront(&p_sys->alpha->decoded)) != NULL)
+        picture_Release(picture);
+    vlc_mutex_unlock(&p_sys->lock);
+}
+
+int OpenDecoder(vlc_object_t *o)
+{
+    decoder_t *dec = container_of(o, decoder_t, obj);
+    if (dec->fmt_in->i_codec != VLC_CODEC_VP8 && dec->fmt_in->i_codec != VLC_CODEC_VP9)
+        return VLC_ENOTSUP;
+    if (dec->fmt_in->i_level == 0)
+        return VLC_ENOTSUP;
+
+    vpx_alpha *p_sys = vlc_obj_calloc(o, 1, sizeof(*p_sys));
+    if (unlikely(p_sys == NULL))
+        return VLC_ENOMEM;
+
+    p_sys->opaque = vlc_object_create( o, sizeof( *p_sys->opaque ) );
+    if (unlikely(p_sys->opaque == NULL))
+        return VLC_EGENERIC;
+    p_sys->alpha = vlc_object_create( o, sizeof( *p_sys->alpha ) );
+    if (unlikely(p_sys->alpha == NULL))
+    {
+        vlc_object_delete(&p_sys->opaque->dec);
+        return VLC_EGENERIC;
+    }
+
+    es_format_t fmt;
+    es_format_Copy(&fmt, dec->fmt_in);
+    if (dec->fmt_in->i_codec == VLC_CODEC_VP8)
+        fmt.i_codec = VLC_CODEC_VP8;
+    else
+        fmt.i_codec = VLC_CODEC_VP9;
+    decoder_Init( &p_sys->opaque->dec, &p_sys->opaque->fmt_in, &fmt );
+    vlc_picture_chain_Init(&p_sys->opaque->decoded);
+    es_format_Init(&p_sys->opaque->fmt_out, VIDEO_ES, 0);
+
+    if (dec->fmt_in->i_codec == VLC_CODEC_VP8)
+        fmt.i_codec = VLC_CODEC_VP8ALPHA_ES;
+    else
+        fmt.i_codec = VLC_CODEC_VP9ALPHA_ES;
+    decoder_Init( &p_sys->alpha->dec,  &p_sys->alpha->fmt_in,  &fmt );
+    vlc_picture_chain_Init(&p_sys->alpha->decoded);
+    es_format_Init(&p_sys->alpha->fmt_out, VIDEO_ES, 0);
+
+    vlc_mutex_init(&p_sys->lock);
+    dec->p_sys = p_sys;
+
+    static const struct decoder_owner_callbacks dec_cbs =
+    {
+        .video = {
+            .get_device = GetDevice,
+            .format_update = FormatUpdate,
+            .queue = QueuePic,
+            .get_display_date = GetDisplayDate,
+            .get_display_rate = GetDisplayRate,
+        },
+        .get_attachments = GetAttachments,
+    };
+
+    p_sys->opaque->dec.cbs = &dec_cbs;
+    p_sys->opaque->dec.p_module =
+        module_need_var( &p_sys->opaque->dec, "video decoder", "codec" );
+    if (p_sys->opaque->dec.p_module == NULL)
+    {
+        decoder_Destroy(&p_sys->alpha->dec);
+        decoder_Destroy(&p_sys->opaque->dec);
+        return VLC_EGENERIC;
+    }
+    p_sys->alpha->dec.cbs = &dec_cbs;
+    p_sys->alpha->dec.p_module =
+        module_need_var( &p_sys->alpha->dec, "video decoder", "codec" );
+    if (p_sys->alpha->dec.p_module == NULL)
+    {
+        decoder_Destroy(&p_sys->alpha->dec);
+        decoder_Destroy(&p_sys->opaque->dec);
+        return VLC_EGENERIC;
+    }
+
+    dec->pf_decode = Decode;
+    dec->pf_flush = Flush;
+
+    return VLC_SUCCESS;
+}
+
+void CloseDecoder(vlc_object_t *o)
+{
+    decoder_t *dec = container_of(o, decoder_t, obj);
+    vpx_alpha *p_sys = dec->p_sys;
+
+    es_format_Clean(&p_sys->opaque->fmt_out);
+    decoder_Destroy(&p_sys->opaque->dec);
+    es_format_Clean(&p_sys->alpha->fmt_out);
+    decoder_Destroy(&p_sys->alpha->dec);
+
+    if (p_sys->pool)
+        picture_pool_Release(p_sys->pool);
+
+    if (p_sys->vctx)
+        vlc_video_context_Release(p_sys->vctx);
+}


=====================================
modules/demux/avformat/mux.c
=====================================
@@ -204,7 +204,7 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
 
     msg_Dbg( p_mux, "adding input" );
 
-    if( !GetFfmpegCodec( fmt->i_cat, fmt->i_codec, &i_codec_id, NULL )
+    if( !GetFfmpegCodec( fmt, &i_codec_id, NULL )
      || i_codec_id == AV_CODEC_ID_NONE )
     {
         msg_Dbg( p_mux, "couldn't find codec for fourcc '%4.4s'",


=====================================
modules/demux/mkv/matroska_segment_parse.cpp
=====================================
@@ -580,6 +580,14 @@ void matroska_segment_c::ParseTrackEntry( const KaxTrackEntry *m )
                 }
             }
         }
+#if LIBMATROSKA_VERSION >= 0x010400
+        E_CASE( KaxVideoAlphaMode, mode )
+        {
+            ONLY_FMT(VIDEO);
+            debug( vars, "Track Video Alpha Mode %u", static_cast<uint8>( mode ) ) ;
+            vars.tk->b_has_alpha = static_cast<uint8>( mode ) == 1;
+        }
+#endif
 #if LIBMATROSKA_VERSION >= 0x010406
         E_CASE( KaxVideoProjection, proj )
         {
@@ -1765,10 +1773,14 @@ bool matroska_segment_c::TrackInit( mkv_track_t * p_tk )
         }
         S_CASE("V_VP8") {
             vars.p_fmt->i_codec = VLC_CODEC_VP8;
+            if (vars.p_tk->b_has_alpha)
+                vars.p_fmt->i_level = 0x1000; // mark as containing alpha data
             vars.p_tk->b_pts_only = true;
         }
         S_CASE("V_VP9") {
             vars.p_fmt->i_codec = VLC_CODEC_VP9;
+            if (vars.p_tk->b_has_alpha)
+                vars.p_fmt->i_level = 0x1000; // mark as containing alpha data
             vars.p_fmt->b_packetized = false;
             vars.p_tk->b_pts_only = true;
 


=====================================
modules/demux/mkv/mkv.cpp
=====================================
@@ -39,6 +39,7 @@ extern "C" {
 
 #include <vlc_fs.h>
 #include <vlc_url.h>
+#include <vlc_ancillary.h>
 
 /*****************************************************************************
  * Module descriptor
@@ -534,6 +535,13 @@ static int Seek( demux_t *p_demux, vlc_tick_t i_mk_date, double f_percent, virtu
     return p_vsegment->Seek( *p_demux, i_mk_date, p_vchapter, b_precise ) ? VLC_SUCCESS : VLC_EGENERIC;
 }
 
+static void ReleaseVpxAlpha(void *opaque)
+{
+    auto alpha = static_cast<vlc_vpx_alpha_t*>(opaque);
+    free(alpha->data);
+    delete alpha;
+}
+
 /* Needed by matroska_segment::Seek() and Seek */
 void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock,
                   KaxBlockAdditions *additions,
@@ -698,6 +706,52 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
             if( unlikely( !p_block ) )
                 continue;
             break;
+
+        case VLC_CODEC_VP8:
+        case VLC_CODEC_VP9:
+            if (additions && track.fmt.i_level) // contains alpha extradata
+            {
+                KaxBlockMore *blockMore = FindChild<KaxBlockMore>(*additions);
+                if(blockMore == nullptr)
+                    break;
+                KaxBlockAddID *addId = FindChild<KaxBlockAddID>(*blockMore);
+                if(addId == nullptr)
+                    break;
+                if (static_cast<uint64>(*addId) != 1)
+                    break;
+
+                KaxBlockAdditional *addition = FindChild<KaxBlockAdditional>(*blockMore);
+                if(addition == nullptr)
+                    break;
+
+                auto alpha_data = new(std::nothrow) vlc_vpx_alpha_t();
+                if (unlikely(alpha_data == nullptr))
+                {
+                    block_Release( p_block );
+                    return;
+                }
+                alpha_data->data = static_cast<uint8_t*>(malloc(addition->GetSize()));
+                if (unlikely(alpha_data->data == nullptr))
+                {
+                    delete alpha_data;
+                    block_Release( p_block );
+                    return;
+                }
+                alpha_data->size = addition->GetSize();
+                memcpy(alpha_data->data, addition->GetBuffer(), addition->GetSize());
+                vlc_ancillary *alpha =
+                    vlc_ancillary_CreateWithFreeCb(alpha_data, VLC_ANCILLARY_ID_VPX_ALPHA,
+                                                   ReleaseVpxAlpha);
+                if (likely(alpha != NULL))
+                    vlc_frame_AttachAncillary(p_block, alpha);
+                else
+                {
+                    ReleaseVpxAlpha(alpha_data);
+                    block_Release( p_block );
+                    return;
+                }
+            }
+            break;
         }
 
         if( track.fmt.i_cat != VIDEO_ES )
@@ -884,6 +938,7 @@ mkv_track_t::mkv_track_t(enum es_format_category_e es_cat) :
   ,i_chans_to_reorder(0)
   ,p_sys(NULL)
   ,b_discontinuity(false)
+  ,b_has_alpha(false)
   ,i_compression_type(MATROSKA_COMPRESSION_NONE)
   ,i_encoding_scope(MATROSKA_ENCODING_SCOPE_ALL_FRAMES)
   ,p_compression_data(NULL)


=====================================
modules/demux/mkv/mkv.hpp
=====================================
@@ -191,6 +191,7 @@ class mkv_track_t
         PrivateTrackData *p_sys;
 
         bool            b_discontinuity;
+        bool            b_has_alpha;
 
         /* informative */
         std::string str_codec_name;


=====================================
modules/hw/mmal/codec.c
=====================================
@@ -132,9 +132,9 @@ static bool set_and_test_enc_supported(vlc_object_t *obj, supported_mmal_enc_t *
     return is_enc_supported(support, fcc);
 }
 
-static MMAL_FOURCC_T vlc_to_mmal_es_fourcc(const unsigned int fcc)
+static MMAL_FOURCC_T vlc_to_mmal_es_fourcc(const es_format_t *es)
 {
-    switch (fcc){
+    switch (es->i_codec){
     case VLC_CODEC_MJPG:
         return MMAL_ENCODING_MJPEG;
     case VLC_CODEC_MP1V:
@@ -151,6 +151,8 @@ static MMAL_FOURCC_T vlc_to_mmal_es_fourcc(const unsigned int fcc)
     case VLC_CODEC_VP6:
         return MMAL_ENCODING_VP6;
     case VLC_CODEC_VP8:
+        if (es->i_level) // contains alpha extradata
+            return 0;
         return MMAL_ENCODING_VP8;
     case VLC_CODEC_WMV1:
         return MMAL_ENCODING_WMV1;
@@ -594,7 +596,7 @@ static int OpenDecoder(vlc_object_t *p_this)
     int ret = VLC_EGENERIC;
     decoder_sys_t *sys;
     MMAL_STATUS_T status;
-    const MMAL_FOURCC_T in_fcc = vlc_to_mmal_es_fourcc(dec->fmt_in->i_codec);
+    const MMAL_FOURCC_T in_fcc = vlc_to_mmal_es_fourcc(dec->fmt_in);
     if (in_fcc == 0) {
         msg_Dbg(p_this, "codec %4.4s not supported", (const char*)&dec->fmt_in->i_codec);
         return VLC_EGENERIC;


=====================================
modules/hw/nvdec/nvdec.c
=====================================
@@ -813,7 +813,10 @@ static int OpenDecoder(vlc_object_t *p_this)
         case VLC_CODEC_MP2V:
         case VLC_CODEC_MPGV:
         case VLC_CODEC_MP4V:
+            break;
         case VLC_CODEC_VP8:
+            if (p_dec->fmt_in->i_level) // contains alpha extradata
+                goto early_exit;
             break;
         case VLC_CODEC_VP9:
             if (p_dec->fmt_in->i_profile != 0 && p_dec->fmt_in->i_profile != 2)
@@ -821,6 +824,8 @@ static int OpenDecoder(vlc_object_t *p_this)
                 msg_Warn(p_dec, "Unsupported VP9 profile %d", p_dec->fmt_in->i_profile);
                 goto early_exit;
             }
+            if (p_dec->fmt_in->i_level) // contains alpha extradata
+                goto early_exit;
             break;
         default:
             goto early_exit;


=====================================
modules/packetizer/avparser.c
=====================================
@@ -87,12 +87,13 @@ int avparser_OpenPacketizer( vlc_object_t *p_this )
 
     /* Restrict to VP9 for now */
     if( p_dec->fmt_in->i_codec != VLC_CODEC_VP9 )
-        return VLC_EGENERIC;
+        return VLC_ENOTSUP;
+    if( p_dec->fmt_in->i_level ) // contains alpha extradata
+        return VLC_ENOTSUP;
 
     enum AVCodecID i_avcodec_id;
 
-    if( !GetFfmpegCodec( p_dec->fmt_in->i_cat, p_dec->fmt_in->i_codec,
-                         &i_avcodec_id, NULL ) )
+    if( !GetFfmpegCodec( p_dec->fmt_in, &i_avcodec_id, NULL ) )
         return VLC_EGENERIC;
 
     /* init avcodec */


=====================================
modules/stream_out/chromecast/cast.cpp
=====================================
@@ -116,7 +116,7 @@ struct sout_stream_sys_t
     {
     }
 
-    bool canDecodeVideo( vlc_fourcc_t i_codec ) const;
+    bool canDecodeVideo( const es_format_t * ) const;
     bool canDecodeAudio( sout_stream_t* p_stream, vlc_fourcc_t i_codec,
                          const audio_format_t* p_fmt ) const;
     bool startSoutChain(sout_stream_t* p_stream,
@@ -763,16 +763,22 @@ static void Del(sout_stream_t *p_stream, void *_id)
  * Supported formats: https://developers.google.com/cast/docs/media
  */
 
-bool sout_stream_sys_t::canDecodeVideo( vlc_fourcc_t i_codec ) const
+bool sout_stream_sys_t::canDecodeVideo( const es_format_t *es ) const
 {
     if( transcoding_state & TRANSCODING_VIDEO )
         return false;
-    switch( i_codec )
+    switch( es->i_codec )
     {
         case VLC_CODEC_H264:
         case VLC_CODEC_HEVC:
+            return true;
         case VLC_CODEC_VP8:
+            if (es->i_level) // contains alpha extradata
+                return false;
+            return true;
         case VLC_CODEC_VP9:
+            if (es->i_level) // contains alpha extradata
+                return false;
             return true;
         default:
             return false;
@@ -986,7 +992,7 @@ bool sout_stream_sys_t::UpdateOutput( sout_stream_t *p_stream )
         {
             if (p_es->i_cat == VIDEO_ES && p_original_video == NULL)
             {
-                if (!canDecodeVideo( p_es->i_codec ))
+                if (!canDecodeVideo( p_es ))
                 {
                     msg_Dbg( p_stream, "can't remux video track %d codec %4.4s",
                              p_es->i_id, (const char*)&p_es->i_codec );


=====================================
modules/stream_out/rtpfmt.c
=====================================
@@ -644,6 +644,8 @@ int rtp_get_fmt( vlc_object_t *obj, const es_format_t *p_fmt, const char *mux,
                 rtp_fmt->fmtp = strdup( "sprop-stereo=1" );
             break;
         case VLC_CODEC_VP8:
+            if (p_fmt->i_level) // contains alpha extradata
+                return VLC_ENOTSUP;
             rtp_fmt->ptname = "VP8";
             rtp_fmt->pf_packetize = rtp_packetize_vp8;
             break;


=====================================
src/misc/fourcc_list.h
=====================================
@@ -521,9 +521,15 @@ static const staticentry_t p_list_video[] = {
     B(VLC_CODEC_VP8, "Google/On2's VP8 Video"),
         A("VP80"),
 
+    B(VLC_CODEC_VP8ALPHA_ES, "Google/On2's VP8 Alpha"),
+        A("VP8a"),
+
     B(VLC_CODEC_VP9, "Google/On2's VP9 Video"),
         A("VP90"),
 
+    B(VLC_CODEC_VP9ALPHA_ES, "Google/On2's VP9 Alpha"),
+        A("VP9a"),
+
     B(VLC_CODEC_AV1, "AOMedia's AV1 Video"),
         A("av10"),
         A("AV01"),



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/dc3d6b67a75418051667b0f9e597604a4074826e...2367cf2e9e1436cdf9bc02df34bc8e3c0c10fd0e

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/dc3d6b67a75418051667b0f9e597604a4074826e...2367cf2e9e1436cdf9bc02df34bc8e3c0c10fd0e
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list