[vlc-commits] codec: videotoolbox: refactor for other codecs support

Francois Cartegnie git at videolan.org
Fri Nov 24 13:12:02 CET 2017


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Tue Oct  3 17:18:27 2017 +0200| [e96c4427790ca7ae8847f30bea32345fc6d5b72a] | committer: Thomas Guillem

codec: videotoolbox: refactor for other codecs support

Signed-off-by: Thomas Guillem <thomas at gllm.fr>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e96c4427790ca7ae8847f30bea32345fc6d5b72a
---

 modules/codec/videotoolbox.m | 680 +++++++++++++++++++++++--------------------
 1 file changed, 367 insertions(+), 313 deletions(-)

diff --git a/modules/codec/videotoolbox.m b/modules/codec/videotoolbox.m
index 8200d59ff5..e5f862d71f 100644
--- a/modules/codec/videotoolbox.m
+++ b/modules/codec/videotoolbox.m
@@ -99,10 +99,10 @@ enum vtsession_status
     VTSESSION_STATUS_ABORT,
 };
 
-static int SetH264DecoderInfo(decoder_t *, CFMutableDictionaryRef);
+static int ConfigureVout(decoder_t *);
 static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *, uint8_t *, uint32_t);
 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef, void *, size_t);
-static CFMutableDictionaryRef H264ExtradataInfoCreate(const struct hxxx_helper *hh);
+static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *, unsigned, unsigned);
 static int HandleVTStatus(decoder_t *, OSStatus, enum vtsession_status *);
 static int DecodeBlock(decoder_t *, block_t *);
 static void RequestFlush(decoder_t *);
@@ -138,11 +138,25 @@ struct decoder_sys_t
     CMVideoCodecType            codec;
     struct                      hxxx_helper hh;
 
+    /* Codec specific callbacks */
+    bool                        (*pf_codec_init)(decoder_t *);
+    void                        (*pf_codec_clean)(decoder_t *);
+    bool                        (*pf_codec_supported)(decoder_t *);
+    bool                        (*pf_late_start)(decoder_t *);
+    block_t*                    (*pf_process_block)(decoder_t *,
+                                                    block_t *, bool *);
+    bool                        (*pf_need_restart)(decoder_t *,
+                                                   VTDecompressionSessionRef);
+    bool                        (*pf_configure_vout)(decoder_t *);
+    CFMutableDictionaryRef      (*pf_get_extradata)(decoder_t *);
+    bool                        (*pf_fill_reorder_info)(decoder_t *, const block_t *,
+                                                        frame_info_t *);
+    /* !Codec specific callbacks */
+
     bool                        b_vt_feed;
     bool                        b_vt_flush;
     VTDecompressionSessionRef   session;
     CMVideoFormatDescriptionRef videoFormatDescription;
-    CFMutableDictionaryRef      extradataInfo;
 
     vlc_mutex_t                 lock;
     frame_info_t               *p_pic_reorder;
@@ -159,13 +173,15 @@ struct decoder_sys_t
 
     int                         i_forced_cvpx_format;
 
-    h264_poc_context_t          pocctx;
+    h264_poc_context_t          h264_pocctx;
     date_t                      pts;
 };
 
 #pragma mark - start & stop
 
-static void GetSPSPPS(uint8_t i_pps_id, void *priv,
+/* Codec Specific */
+
+static void GetxPSH264(uint8_t i_pps_id, void *priv,
                       const h264_sequence_parameter_set_t **pp_sps,
                       const h264_picture_parameter_set_t **pp_pps)
 {
@@ -178,7 +194,7 @@ static void GetSPSPPS(uint8_t i_pps_id, void *priv,
         *pp_sps = p_sys->hh.h264.sps_list[(*pp_pps)->i_sps_id].h264_sps;
 }
 
-struct sei_callback_s
+struct sei_callback_h264_s
 {
     uint8_t i_pic_struct;
     const h264_sequence_parameter_set_t *p_sps;
@@ -186,10 +202,9 @@ struct sei_callback_s
 
 static bool ParseH264SEI(const hxxx_sei_data_t *p_sei_data, void *priv)
 {
-
     if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
     {
-        struct sei_callback_s *s = priv;
+        struct sei_callback_h264_s *s = priv;
         if(s->p_sps && s->p_sps->vui.b_valid)
         {
             if(s->p_sps->vui.b_hrd_parameters_present_flag)
@@ -207,13 +222,13 @@ static bool ParseH264SEI(const hxxx_sei_data_t *p_sei_data, void *priv)
     return true;
 }
 
-static bool ParseH264NAL(decoder_t *p_dec,
-                         const uint8_t *p_buffer, size_t i_buffer,
-                         uint8_t i_nal_length_size, frame_info_t *p_info)
+static bool FillReorderInfoH264(decoder_t *p_dec, const block_t *p_block,
+                                frame_info_t *p_info)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     hxxx_iterator_ctx_t itctx;
-    hxxx_iterator_init(&itctx, p_buffer, i_buffer, i_nal_length_size);
+    hxxx_iterator_init(&itctx, p_block->p_buffer, p_block->i_buffer,
+                       p_sys->hh.i_nal_length_size);
 
     const uint8_t *p_nal; size_t i_nal;
     const uint8_t *p_sei_nal = NULL; size_t i_sei_nal = 0;
@@ -227,12 +242,12 @@ static bool ParseH264NAL(decoder_t *p_dec,
         if (i_nal_type <= H264_NAL_SLICE_IDR && i_nal_type != H264_NAL_UNKNOWN)
         {
             h264_slice_t slice;
-            if(!h264_decode_slice(p_nal, i_nal, GetSPSPPS, p_sys, &slice))
+            if(!h264_decode_slice(p_nal, i_nal, GetxPSH264, p_sys, &slice))
                 return false;
 
             const h264_sequence_parameter_set_t *p_sps;
             const h264_picture_parameter_set_t *p_pps;
-            GetSPSPPS(slice.i_pic_parameter_set_id, p_sys, &p_sps, &p_pps);
+            GetxPSH264(slice.i_pic_parameter_set_id, p_sys, &p_sps, &p_pps);
             if(p_sps)
             {
                 if(!p_sys->b_invalid_pic_reorder_max && i_nal_type == H264_NAL_SLICE_IDR)
@@ -246,7 +261,7 @@ static bool ParseH264NAL(decoder_t *p_dec,
                 }
 
                 int bFOC;
-                h264_compute_poc(p_sps, &slice, &p_sys->pocctx,
+                h264_compute_poc(p_sps, &slice, &p_sys->h264_pocctx,
                                  &p_info->i_poc, &p_info->i_foc, &bFOC);
 
                 p_info->b_flush = (slice.type == H264_SLICE_TYPE_I) || slice.has_mmco5;
@@ -254,7 +269,7 @@ static bool ParseH264NAL(decoder_t *p_dec,
                 p_info->b_progressive = !p_sps->mb_adaptive_frame_field_flag &&
                                         !slice.i_field_pic_flag;
 
-                struct sei_callback_s sei;
+                struct sei_callback_h264_s sei;
                 sei.p_sps = p_sps;
                 sei.i_pic_struct = UINT8_MAX;
 
@@ -289,6 +304,225 @@ static bool ParseH264NAL(decoder_t *p_dec,
     return false;
 }
 
+
+static block_t *ProcessBlockH264(decoder_t *p_dec, block_t *p_block, bool *pb_config_changed)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    return p_sys->hh.pf_process_block(&p_sys->hh, p_block, pb_config_changed);
+}
+
+
+static bool InitH264(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    h264_poc_context_init(&p_sys->h264_pocctx);
+    hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
+                     p_dec->fmt_in.i_codec, true);
+    return hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
+                                             p_dec->fmt_in.i_extra) == VLC_SUCCESS;
+}
+
+static void CleanH264(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    hxxx_helper_clean(&p_sys->hh);
+}
+
+static CFMutableDictionaryRef GetDecoderExtradataH264(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    CFMutableDictionaryRef extradata = nil;
+    if(p_dec->fmt_in.i_extra) /* copy DecoderConfiguration */
+    {
+        extradata = ExtradataInfoCreate(CFSTR("avcC"),
+                                        p_dec->fmt_in.p_extra,
+                                        p_dec->fmt_in.i_extra);
+    }
+    else if (p_sys->hh.h264.i_pps_count && p_sys->hh.h264.i_sps_count)
+    {
+        /* build DecoderConfiguration from gathered */
+        block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh);
+        if (p_avcC)
+        {
+            extradata = ExtradataInfoCreate(CFSTR("avcC"),
+                                            p_avcC->p_buffer,
+                                            p_avcC->i_buffer);
+            block_Release(p_avcC);
+        }
+    }
+    return extradata;
+}
+
+static bool CodecSupportedH264(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    uint8_t i_profile, i_level;
+    if (hxxx_helper_get_current_profile_level(&p_sys->hh, &i_profile, &i_level))
+	return true;
+
+    switch (i_profile) {
+        case PROFILE_H264_BASELINE:
+        case PROFILE_H264_MAIN:
+        case PROFILE_H264_HIGH:
+            break;
+
+        case PROFILE_H264_HIGH_10:
+        {
+            if (deviceSupportsAdvancedProfiles())
+            {
+                /* FIXME: There is no YUV420 10bits chroma. The
+                 * decoder seems to output RGBA when decoding 10bits
+                 * content, but there is an unknown crash when
+                 * displaying such output, so force NV12 for now. */
+                if (p_dec->p_sys->i_forced_cvpx_format == 0)
+                    p_dec->p_sys->i_forced_cvpx_format =
+                        kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+                break;
+            }
+            else
+            {
+                msg_Err(p_dec, "current device doesn't support H264 10bits");
+                return false;
+            }
+        }
+
+        default:
+        {
+            msg_Warn(p_dec, "unknown H264 profile %" PRIx8, i_profile);
+            return false;
+        }
+    }
+
+    /* A level higher than 5.2 was not tested, so don't dare to try to decode
+     * it. On SoC A8, 4.2 is the highest specified profile. on Twister, we can
+     * do up to 5.2 */
+    if (i_level > 52 || (i_level > 42 && !deviceSupportsAdvancedLevels()))
+    {
+        msg_Err(p_dec, "current device doesn't support this H264 level: %"
+                PRIx8, i_level);
+        return false;
+    }
+
+    return true;
+}
+
+static bool LateStartH264(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    return (p_dec->fmt_in.i_extra == 0 &&
+            (!p_sys->hh.h264.i_pps_count || !p_sys->hh.h264.i_sps_count) );
+}
+
+static bool ConfigureVoutH264(decoder_t *p_dec)
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if(p_dec->fmt_in.video.primaries == COLOR_PRIMARIES_UNDEF)
+    {
+        video_color_primaries_t primaries;
+        video_transfer_func_t transfer;
+        video_color_space_t colorspace;
+        bool full_range;
+        if (hxxx_helper_get_colorimetry(&p_sys->hh,
+                                        &primaries,
+                                        &transfer,
+                                        &colorspace,
+                                        &full_range) == VLC_SUCCESS)
+        {
+            p_dec->fmt_out.video.primaries = primaries;
+            p_dec->fmt_out.video.transfer = transfer;
+            p_dec->fmt_out.video.space = colorspace;
+            p_dec->fmt_out.video.b_color_range_full = full_range;
+        }
+    }
+
+    if (!p_dec->fmt_in.video.i_visible_width || !p_dec->fmt_in.video.i_visible_height)
+    {
+        unsigned i_width, i_height, i_vis_width, i_vis_height;
+        if(VLC_SUCCESS ==
+           hxxx_helper_get_current_picture_size(&p_sys->hh,
+                                                &i_width, &i_height,
+                                                &i_vis_width, &i_vis_height))
+        {
+            p_dec->fmt_out.video.i_visible_width = i_vis_width;
+            p_dec->fmt_out.video.i_width = ALIGN_16( i_vis_width );
+            p_dec->fmt_out.video.i_visible_height = i_vis_height;
+            p_dec->fmt_out.video.i_height = ALIGN_16( i_vis_height );
+        }
+        else return false;
+    }
+
+    if(!p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den)
+    {
+        int i_sar_num, i_sar_den;
+        if (VLC_SUCCESS ==
+            hxxx_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den))
+        {
+            p_dec->fmt_out.video.i_sar_num = i_sar_num;
+            p_dec->fmt_out.video.i_sar_den = i_sar_den;
+        }
+    }
+
+    return true;
+}
+
+static bool VideoToolboxNeedsToRestartH264(decoder_t *p_dec,
+                                           VTDecompressionSessionRef session)
+{
+    const struct hxxx_helper *hh = &p_dec->p_sys->hh;
+
+    unsigned w, h, vw, vh;
+    int sarn, sard;
+
+    if (hxxx_helper_get_current_picture_size(hh, &w, &h, &vw, &vh) != VLC_SUCCESS)
+        return true;
+
+    if (hxxx_helper_get_current_sar(hh, &sarn, &sard) != VLC_SUCCESS)
+        return true;
+
+    bool b_ret = true;
+
+    CFMutableDictionaryRef decoderConfiguration =
+            CreateSessionDescriptionFormat(p_dec, sarn, sard);
+    if (decoderConfiguration != nil)
+    {
+        CMFormatDescriptionRef newvideoFormatDesc;
+        /* create new video format description */
+        OSStatus status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
+                                                         kCMVideoCodecType_H264,
+                                                         vw, vh,
+                                                         decoderConfiguration,
+                                                         &newvideoFormatDesc);
+        if (!status)
+        {
+            b_ret = !VTDecompressionSessionCanAcceptFormatDescription(session,
+                                                                      newvideoFormatDesc);
+            CFRelease(newvideoFormatDesc);
+        }
+        CFRelease(decoderConfiguration);
+    }
+
+    return b_ret;
+}
+
+static CFMutableDictionaryRef GetDecoderExtradataMPEG4(decoder_t *p_dec)
+{
+    if (p_dec->fmt_in.i_extra)
+        return ESDSExtradataInfoCreate(p_dec, p_dec->fmt_in.p_extra,
+                                              p_dec->fmt_in.i_extra);
+    else
+        return nil; /* MPEG4 without esds ? */
+}
+
+static CFMutableDictionaryRef GetDecoderExtradataDefault(decoder_t *p_dec)
+{
+    return ExtradataInfoCreate(NULL, NULL, 0); /* Empty Needed ? */
+}
+
+/* !Codec Specific */
+
 static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
 {
     frame_info_t **pp_lead_in = &p_sys->p_pic_reorder;
@@ -397,13 +631,10 @@ static frame_info_t * CreateReorderInfo(decoder_t *p_dec, const block_t *p_block
     if (!p_info)
         return NULL;
 
-    if (p_sys->b_poc_based_reorder)
+    if (p_sys->pf_fill_reorder_info)
     {
-        if (p_sys->codec != kCMVideoCodecType_H264 ||
-            !ParseH264NAL(p_dec, p_block->p_buffer, p_block->i_buffer,
-                          p_sys->hh.i_nal_length_size , p_info))
+        if(!p_sys->pf_fill_reorder_info(p_dec, p_block, p_info))
         {
-            assert(p_sys->codec == kCMVideoCodecType_H264);
             free(p_info);
             return NULL;
         }
@@ -548,15 +779,27 @@ static CMVideoCodecType CodecPrecheck(decoder_t *p_dec)
     vlc_assert_unreachable();
 }
 
-
 static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
                                                              unsigned i_sar_num,
                                                              unsigned i_sar_den)
 {
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
     CFMutableDictionaryRef decoderConfiguration = cfdict_create(2);
     if (decoderConfiguration == NULL)
         return nil;
 
+    CFMutableDictionaryRef extradata = p_sys->pf_get_extradata
+                                     ? p_sys->pf_get_extradata(p_dec) : nil;
+    if(extradata)
+    {
+        /* then decoder will also fail if required, no need to handle it */
+        CFDictionarySetValue(decoderConfiguration,
+                             kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
+                             extradata);
+        CFRelease(extradata);
+    }
+
     CFDictionarySetValue(decoderConfiguration,
                          kCVImageBufferChromaLocationBottomFieldKey,
                          kCVImageBufferChromaLocation_Left);
@@ -565,23 +808,26 @@ static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
                          kCVImageBufferChromaLocation_Left);
 
     /* pixel aspect ratio */
-    CFMutableDictionaryRef pixelaspectratio = cfdict_create(2);
-    if(pixelaspectratio == NULL)
+    if(i_sar_num && i_sar_den)
     {
-        CFRelease(decoderConfiguration);
-        return nil;
-    }
+        CFMutableDictionaryRef pixelaspectratio = cfdict_create(2);
+        if(pixelaspectratio == NULL)
+        {
+            CFRelease(decoderConfiguration);
+            return nil;
+        }
 
-    cfdict_set_int32(pixelaspectratio,
-                     kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
-                     i_sar_num);
-    cfdict_set_int32(pixelaspectratio,
-                     kCVImageBufferPixelAspectRatioVerticalSpacingKey,
-                     i_sar_den);
-    CFDictionarySetValue(decoderConfiguration,
-                         kCVImageBufferPixelAspectRatioKey,
-                         pixelaspectratio);
-    CFRelease(pixelaspectratio);
+        cfdict_set_int32(pixelaspectratio,
+                         kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
+                         i_sar_num);
+        cfdict_set_int32(pixelaspectratio,
+                         kCVImageBufferPixelAspectRatioVerticalSpacingKey,
+                         i_sar_den);
+        CFDictionarySetValue(decoderConfiguration,
+                             kCVImageBufferPixelAspectRatioKey,
+                             pixelaspectratio);
+        CFRelease(pixelaspectratio);
+    }
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wpartial-availability"
@@ -612,55 +858,20 @@ static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
     return decoderConfiguration;
 }
 
-static bool VideoToolboxNeedsToRestartH264(decoder_t *p_dec,
-                                           VTDecompressionSessionRef session,
-                                           const struct hxxx_helper *hh)
+static int StartVideoToolbox(decoder_t *p_dec)
 {
-    unsigned w, h, vw, vh;
-    int sarn, sard;
-
-    if (hxxx_helper_get_current_picture_size(hh, &w, &h, &vw, &vh) != VLC_SUCCESS)
-        return true;
-
-    if (hxxx_helper_get_current_sar(hh, &sarn, &sard) != VLC_SUCCESS)
-        return true;
-
-    CFMutableDictionaryRef extradataInfo = H264ExtradataInfoCreate(hh);
-    if(extradataInfo == nil)
-        return true;
-
-    bool b_ret = true;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-    CFMutableDictionaryRef decoderConfiguration =
-            CreateSessionDescriptionFormat(p_dec, sarn, sard);
-    if (decoderConfiguration != nil)
+    /* Late starts */
+    if(p_sys->pf_late_start && p_sys->pf_late_start(p_dec))
     {
-        CFDictionarySetValue(decoderConfiguration,
-                             kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
-                             extradataInfo);
-        CMFormatDescriptionRef newvideoFormatDesc;
-        /* create new video format description */
-        OSStatus status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
-                                                         kCMVideoCodecType_H264,
-                                                         vw, vh,
-                                                         decoderConfiguration,
-                                                         &newvideoFormatDesc);
-        if (!status)
-        {
-            b_ret = !VTDecompressionSessionCanAcceptFormatDescription(session,
-                                                                      newvideoFormatDesc);
-            CFRelease(newvideoFormatDesc);
-        }
-        CFRelease(decoderConfiguration);
+        assert(p_sys->session == NULL);
+        return VLC_SUCCESS;
     }
-    CFRelease(extradataInfo);
 
-    return b_ret;
-}
-
-static int StartVideoToolbox(decoder_t *p_dec)
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    /* Fills fmt_out (from extradata if any) */
+    if(ConfigureVout(p_dec) != VLC_SUCCESS)
+        return VLC_EGENERIC;
 
     /* destination pixel buffer attributes */
     CFMutableDictionaryRef destinationPixelBufferAttributes = cfdict_create(2);
@@ -677,13 +888,6 @@ static int StartVideoToolbox(decoder_t *p_dec)
         return VLC_EGENERIC;
     }
 
-    if(p_sys->extradataInfo)
-    {
-        CFDictionarySetValue(decoderConfiguration,
-                             kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
-                             p_sys->extradataInfo);
-    }
-
     /* create video format description */
     OSStatus status = CMVideoFormatDescriptionCreate(
                                             kCFAllocatorDefault,
@@ -811,48 +1015,6 @@ static int RestartVideoToolbox(decoder_t *p_dec, bool b_reset_format)
 
 #pragma mark - module open and close
 
-static int SetupDecoderExtradata(decoder_t *p_dec)
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    CFMutableDictionaryRef extradata_info = NULL;
-
-    assert(p_sys->extradataInfo == nil);
-    if (p_sys->codec == kCMVideoCodecType_H264)
-    {
-        hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
-                         p_dec->fmt_in.i_codec, true);
-        int i_ret = hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
-                                          p_dec->fmt_in.i_extra);
-        if (i_ret != VLC_SUCCESS)
-            return i_ret;
-        assert(p_sys->hh.pf_process_block != NULL);
-
-        if (p_dec->fmt_in.p_extra)
-        {
-            p_sys->extradataInfo = ExtradataInfoCreate(CFSTR("avcC"),
-                                            p_dec->fmt_in.p_extra,
-                                            p_dec->fmt_in.i_extra);
-            if (SetH264DecoderInfo(p_dec, p_sys->extradataInfo) != VLC_SUCCESS)
-                return VLC_EGENERIC;
-        }
-        else
-        {
-            /* AnnexB case, we'll get extradata from first input blocks */
-            return VLC_SUCCESS;
-        }
-    }
-    else if (p_sys->codec == kCMVideoCodecType_MPEG4Video)
-    {
-        if (!p_dec->fmt_in.i_extra)
-            return VLC_EGENERIC;
-        p_sys->extradataInfo = ESDSExtradataInfoCreate(p_dec, p_dec->fmt_in.p_extra,
-                                                       p_dec->fmt_in.i_extra);
-    }
-    else
-        p_sys->extradataInfo = ExtradataInfoCreate(NULL, NULL, 0);
-
-    return p_sys->extradataInfo != nil ? VLC_SUCCESS : VLC_EGENERIC;
-}
 
 static int OpenDecoder(vlc_object_t *p_this)
 {
@@ -879,22 +1041,14 @@ static int OpenDecoder(vlc_object_t *p_this)
     /* now that we see a chance to decode anything, allocate the
      * internals and start the decoding session */
     decoder_sys_t *p_sys;
-    p_sys = malloc(sizeof(*p_sys));
+    p_sys = calloc(1, sizeof(*p_sys));
     if (!p_sys)
         return VLC_ENOMEM;
     p_dec->p_sys = p_sys;
     p_sys->session = nil;
-    p_sys->b_vt_feed = false;
-    p_sys->b_vt_flush = false;
     p_sys->codec = codec;
     p_sys->videoFormatDescription = nil;
-    p_sys->extradataInfo = nil;
-    p_sys->p_pic_reorder = NULL;
-    p_sys->i_pic_reorder = 0;
     p_sys->i_pic_reorder_max = 4;
-    p_sys->b_invalid_pic_reorder_max = false;
-    p_sys->b_poc_based_reorder = false;
-    p_sys->b_format_propagated = false;
     p_sys->vtsession_status = VTSESSION_STATUS_OK;
     p_sys->b_enable_temporal_processing =
         var_InheritBool(p_dec, "videotoolbox-temporal-deinterlacing");
@@ -913,53 +1067,52 @@ static int OpenDecoder(vlc_object_t *p_this)
         p_sys->i_forced_cvpx_format = ntohl(p_sys->i_forced_cvpx_format);
         free(cvpx_chroma);
     }
-    else
-        p_dec->p_sys->i_forced_cvpx_format = 0;
 
-    h264_poc_context_init( &p_sys->pocctx );
     vlc_mutex_init(&p_sys->lock);
 
-    /* return our proper VLC internal state */
-    p_dec->fmt_out.video = p_dec->fmt_in.video;
-    if (!p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den)
-    {
-        p_dec->fmt_out.video.i_sar_num = 1;
-        p_dec->fmt_out.video.i_sar_den = 1;
-    }
-    if (!p_dec->fmt_out.video.i_visible_width
-     || !p_dec->fmt_out.video.i_visible_height)
-    {
-        p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width;
-        p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height;
-    }
-    p_dec->fmt_out.video.i_width = ALIGN_16( p_dec->fmt_out.video.i_visible_width );
-    p_dec->fmt_out.video.i_height = ALIGN_16( p_dec->fmt_out.video.i_visible_height );
-
-    p_dec->fmt_out.i_codec = 0;
-
-    if( codec == kCMVideoCodecType_H264 )
-        p_sys->b_poc_based_reorder = true;
-
-    int i_ret = SetupDecoderExtradata(p_dec);
-    if (i_ret != VLC_SUCCESS)
-        goto error;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = RequestFlush;
 
-    if (p_sys->extradataInfo != nil)
+    switch(codec)
     {
-        i_ret = StartVideoToolbox(p_dec);
-        if (i_ret != VLC_SUCCESS)
-            goto error;
-    } /* else: late opening */
+        case kCMVideoCodecType_H264:
+            p_sys->pf_codec_init = InitH264;
+            p_sys->pf_codec_clean = CleanH264;
+            p_sys->pf_codec_supported = CodecSupportedH264;
+            p_sys->pf_late_start = LateStartH264;
+            p_sys->pf_process_block = ProcessBlockH264;
+            p_sys->pf_need_restart = VideoToolboxNeedsToRestartH264;
+            p_sys->pf_configure_vout = ConfigureVoutH264;
+            p_sys->pf_get_extradata = GetDecoderExtradataH264;
+            p_sys->pf_fill_reorder_info = FillReorderInfoH264;
+            p_sys->b_poc_based_reorder = true;
+            break;
 
-    p_dec->pf_decode = DecodeBlock;
-    p_dec->pf_flush  = RequestFlush;
+        case kCMVideoCodecType_MPEG4Video:
+            p_sys->pf_get_extradata = GetDecoderExtradataMPEG4;
+            break;
 
-    msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'", (char *)&p_dec->fmt_in.i_codec);
+        default:
+            p_sys->pf_get_extradata = GetDecoderExtradataDefault;
+            break;
+    }
 
-    return VLC_SUCCESS;
+    if(p_sys->pf_codec_init && !p_sys->pf_codec_init(p_dec))
+    {
+        CloseDecoder(p_this);
+        return VLC_EGENERIC;
+    }
 
-error:
-    CloseDecoder(p_this);
+    int i_ret = StartVideoToolbox(p_dec);
+    if(i_ret == VLC_SUCCESS)
+    {
+        msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'",
+                        (char *)&p_dec->fmt_in.i_codec);
+    }
+    else
+    {
+        CloseDecoder(p_this);
+    }
     return i_ret;
 }
 
@@ -969,11 +1122,9 @@ static void CloseDecoder(vlc_object_t *p_this)
     decoder_sys_t *p_sys = p_dec->p_sys;
 
     StopVideoToolbox(p_dec, true);
-    if (p_sys->extradataInfo)
-        CFRelease(p_sys->extradataInfo);
 
-    if (p_sys->codec == kCMVideoCodecType_H264)
-        hxxx_helper_clean(&p_sys->hh);
+    if(p_sys->pf_codec_clean)
+        p_sys->pf_codec_clean(p_dec);
 
     vlc_mutex_destroy(&p_sys->lock);
     free(p_sys);
@@ -1085,125 +1236,33 @@ static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *p_dec,
     return extradataInfo;
 }
 
-static CFMutableDictionaryRef H264ExtradataInfoCreate(const struct hxxx_helper *hh)
-{
-    CFMutableDictionaryRef extradataInfo = nil;
-    block_t *p_avcC = h264_helper_get_avcc_config(hh);
-    if (p_avcC)
-    {
-        extradataInfo = ExtradataInfoCreate(CFSTR("avcC"),
-                                            p_avcC->p_buffer, p_avcC->i_buffer);
-        block_Release(p_avcC);
-    }
-    return extradataInfo;
-}
-
-static bool IsH264ProfileLevelSupported(decoder_t *p_dec, uint8_t i_profile,
-                                        uint8_t i_level)
+static int ConfigureVout(decoder_t *p_dec)
 {
-    switch (i_profile) {
-        case PROFILE_H264_BASELINE:
-        case PROFILE_H264_MAIN:
-        case PROFILE_H264_HIGH:
-            break;
-
-        case PROFILE_H264_HIGH_10:
-        {
-            if (deviceSupportsAdvancedProfiles())
-            {
-                /* FIXME: There is no YUV420 10bits chroma. The
-                 * decoder seems to output RGBA when decoding 10bits
-                 * content, but there is an unknown crash when
-                 * displaying such output, so force NV12 for now. */
-                if (p_dec->p_sys->i_forced_cvpx_format == 0)
-                    p_dec->p_sys->i_forced_cvpx_format =
-                        kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
-                break;
-            }
-            else
-            {
-                msg_Err(p_dec, "current device doesn't support H264 10bits");
-                return false;
-            }
-        }
-
-        default:
-        {
-            msg_Warn(p_dec, "unknown H264 profile %" PRIx8, i_profile);
-            return false;
-        }
-    }
-
-    /* A level higher than 5.2 was not tested, so don't dare to try to decode
-     * it. On SoC A8, 4.2 is the highest specified profile. on Twister, we can
-     * do up to 5.2 */
-    if (i_level > 52 || (i_level > 42 && !deviceSupportsAdvancedLevels()))
-    {
-        msg_Err(p_dec, "current device doesn't support this H264 level: %"
-                PRIx8, i_level);
-        return false;
-    }
-
-    return true;
-}
-
-static int SetH264DecoderInfo(decoder_t *p_dec, CFMutableDictionaryRef extradataInfo)
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    /* return our proper VLC internal state */
+    p_dec->fmt_out.video = p_dec->fmt_in.video;
+    p_dec->fmt_out.video.p_palette = NULL;
+    p_dec->fmt_out.i_codec = 0;
 
-    if (p_sys->hh.h264.i_sps_count == 0 || p_sys->hh.h264.i_pps_count == 0)
+    if(p_dec->p_sys->pf_configure_vout &&
+       !p_dec->p_sys->pf_configure_vout(p_dec))
         return VLC_EGENERIC;
 
-    uint8_t i_profile, i_level;
-    unsigned i_h264_width, i_h264_height, i_video_width, i_video_height;
-    int i_sar_num, i_sar_den, i_ret;
-
-    i_ret = hxxx_helper_get_current_profile_level(&p_sys->hh, &i_profile, &i_level);
-    if (i_ret != VLC_SUCCESS)
-        return i_ret;
-    if (!IsH264ProfileLevelSupported(p_dec, i_profile, i_level))
-        return VLC_ENOMOD; /* This error is critical */
-
-    i_ret = hxxx_helper_get_current_picture_size(&p_sys->hh,
-                                                 &i_h264_width, &i_h264_height,
-                                                 &i_video_width, &i_video_height);
-    if (i_ret != VLC_SUCCESS)
-        return i_ret;
-
-    i_ret = hxxx_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den);
-    if (i_ret != VLC_SUCCESS)
-        return i_ret;
-
-    video_color_primaries_t primaries;
-    video_transfer_func_t transfer;
-    video_color_space_t colorspace;
-    bool full_range;
-    if (hxxx_helper_get_colorimetry(&p_sys->hh, &primaries, &transfer,
-                                    &colorspace, &full_range) == VLC_SUCCESS
-      && primaries != COLOR_PRIMARIES_UNDEF && transfer != TRANSFER_FUNC_UNDEF
-      && colorspace != COLOR_SPACE_UNDEF)
+    if (!p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den)
     {
-        p_dec->fmt_out.video.primaries = primaries;
-        p_dec->fmt_out.video.transfer = transfer;
-        p_dec->fmt_out.video.space = colorspace;
-        p_dec->fmt_out.video.b_color_range_full = full_range;
+        p_dec->fmt_out.video.i_sar_num = 1;
+        p_dec->fmt_out.video.i_sar_den = 1;
     }
 
-    p_dec->fmt_out.video.i_visible_width = i_video_width;
-    p_dec->fmt_out.video.i_width = ALIGN_16( i_video_width );
-    p_dec->fmt_out.video.i_visible_height = i_video_height;
-    p_dec->fmt_out.video.i_height = ALIGN_16( i_video_height );
-    p_dec->fmt_out.video.i_sar_num = i_sar_num;
-    p_dec->fmt_out.video.i_sar_den = i_sar_den;
-
-    if (extradataInfo == nil)
+    if (!p_dec->fmt_out.video.i_visible_width || !p_dec->fmt_out.video.i_visible_height)
     {
-        if (p_sys->extradataInfo != nil)
-            CFRelease(p_sys->extradataInfo);
-        p_sys->extradataInfo = H264ExtradataInfoCreate(&p_sys->hh);
+        p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width;
+        p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height;
     }
 
-    return (p_sys->extradataInfo == nil) ? VLC_EGENERIC: VLC_SUCCESS;
+    p_dec->fmt_out.video.i_width = ALIGN_16( p_dec->fmt_out.video.i_visible_width );
+    p_dec->fmt_out.video.i_height = ALIGN_16( p_dec->fmt_out.video.i_visible_height );
+
+    return VLC_SUCCESS;
 }
 
 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef name,
@@ -1440,9 +1499,9 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
     }
 
     bool b_config_changed = false;
-    if (p_sys->codec == kCMVideoCodecType_H264)
+    if(p_sys->pf_process_block)
     {
-        p_block = p_sys->hh.pf_process_block(&p_sys->hh, p_block, &b_config_changed);
+        p_block = p_sys->pf_process_block(p_dec, p_block, &b_config_changed);
         if (!p_block)
             return VLCDEC_SUCCESS;
     }
@@ -1451,40 +1510,35 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
     if(unlikely(!p_info))
         goto skip;
 
-    if (b_config_changed && p_info->b_flush)
+    if (!p_sys->session /* Late Start */||
+        (b_config_changed && p_info->b_flush))
     {
-        assert(p_sys->codec == kCMVideoCodecType_H264);
-        if (!p_sys->session ||
-            VideoToolboxNeedsToRestartH264(p_dec,p_sys->session, &p_sys->hh))
+        if (p_sys->session &&
+            p_sys->pf_need_restart &&
+            p_sys->pf_need_restart(p_dec,p_sys->session))
         {
-            if (p_sys->session)
-            {
-                msg_Dbg(p_dec, "SPS/PPS changed: draining H264 decoder");
-                Drain(p_dec, false);
-                msg_Dbg(p_dec, "SPS/PPS changed: restarting H264 decoder");
-                StopVideoToolbox(p_dec, true);
-            }
-            /* else decoding didn't start yet, which is ok for H264, let's see
-             * if we can use this block to get going */
+            msg_Dbg(p_dec, "parameters sets changed: draining decoder");
+            Drain(p_dec, false);
+            msg_Dbg(p_dec, "parameters sets changed: restarting decoder");
+            StopVideoToolbox(p_dec, true);
+        }
 
-            int i_ret = SetH264DecoderInfo(p_dec, nil);
-            if (i_ret == VLC_SUCCESS)
+        if(!p_sys->session)
+        {
+            if(!p_sys->pf_codec_supported || p_sys->pf_codec_supported(p_dec))
             {
-                msg_Dbg(p_dec, "Got SPS/PPS: late opening of H264 decoder");
                 StartVideoToolbox(p_dec);
             }
-            else if (i_ret == VLC_ENOMOD)
+            else
             {
-                /* The current device doesn't handle the h264 profile/level,
-                 * abort */
+                /* The current device doesn't handle the profile/level, abort */
                 vlc_mutex_lock(&p_sys->lock);
                 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
                 vlc_mutex_unlock(&p_sys->lock);
-                goto skip;
             }
         }
 
-        if (!p_sys->session)
+        if (!p_sys->session) /* Start Failed */
         {
             free(p_info);
             goto skip;



More information about the vlc-commits mailing list