codec: subsdec: fix variable shadowing
[vlc.git] / modules / codec / videotoolbox.m
blobb01b5d4511f597175ca5c143b19fe3cec755e3a4
1 /*****************************************************************************
2  * videotoolbox.m: Video Toolbox decoder
3  *****************************************************************************
4  * Copyright © 2014-2015 VideoLabs SAS
5  *
6  * Authors: Felix Paul Kühne <fkuehne # videolan.org>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
23 #pragma mark preamble
25 #ifdef HAVE_CONFIG_H
26 # import "config.h"
27 #endif
29 #import <vlc_common.h>
30 #import <vlc_plugin.h>
31 #import <vlc_codec.h>
32 #import "hxxx_helper.h"
33 #import <vlc_bits.h>
34 #import <vlc_boxes.h>
35 #import "vt_utils.h"
36 #import "../packetizer/h264_nal.h"
37 #import "../packetizer/h264_slice.h"
38 #import "../packetizer/hxxx_nal.h"
39 #import "../packetizer/hxxx_sei.h"
41 #import <VideoToolbox/VideoToolbox.h>
42 #import <VideoToolbox/VTErrors.h>
44 #import <Foundation/Foundation.h>
45 #import <TargetConditionals.h>
47 #import <sys/types.h>
48 #import <sys/sysctl.h>
49 #import <mach/machine.h>
51 #define ALIGN_16( x ) ( ( ( x ) + 15 ) / 16 * 16 )
52 #define VT_RESTART_MAX 1
54 #if TARGET_OS_IPHONE
55 #import <UIKit/UIKit.h>
57 /* support iOS SDKs < v9.1 */
58 #ifndef CPUFAMILY_ARM_TWISTER
59 #define CPUFAMILY_ARM_TWISTER 0x92fb37c8
60 #endif
62 #endif
65 #if (!TARGET_OS_OSX)
66 const CFStringRef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFSTR("EnableHardwareAcceleratedVideoDecoder");
67 const CFStringRef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder = CFSTR("RequireHardwareAcceleratedVideoDecoder");
68 #endif
70 #pragma mark - module descriptor
72 static int OpenDecoder(vlc_object_t *);
73 static void CloseDecoder(vlc_object_t *);
75 #define VT_ENABLE_TEXT N_("Enable hardware acceleration")
76 #define VT_REQUIRE_HW_DEC N_("Use Hardware decoders only")
77 #define VT_FORCE_CVPX_CHROMA "Force the VT decoder CVPX chroma"
78 #define VT_FORCE_CVPX_CHROMA_LONG "Values can be 'BGRA', 'y420', '420f', '420v', '2vuy'. \
79     By Default, the best chroma is choosen by the VT decoder."
81 vlc_module_begin()
82 set_category(CAT_INPUT)
83 set_subcategory(SUBCAT_INPUT_VCODEC)
84 set_description(N_("VideoToolbox video decoder"))
85 set_capability("video decoder",800)
86 set_callbacks(OpenDecoder, CloseDecoder)
88 add_obsolete_bool("videotoolbox-temporal-deinterlacing")
89 add_bool("videotoolbox", true, VT_ENABLE_TEXT, NULL, false)
90 add_bool("videotoolbox-hw-decoder-only", true, VT_REQUIRE_HW_DEC, VT_REQUIRE_HW_DEC, false)
91 add_string("videotoolbox-cvpx-chroma", "", VT_FORCE_CVPX_CHROMA, VT_FORCE_CVPX_CHROMA_LONG, true);
92 vlc_module_end()
94 #pragma mark - local prototypes
96 enum vtsession_status
98     VTSESSION_STATUS_OK,
99     VTSESSION_STATUS_RESTART,
100     VTSESSION_STATUS_RESTART_CHROMA,
101     VTSESSION_STATUS_ABORT,
104 static int ConfigureVout(decoder_t *);
105 static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *, uint8_t *, uint32_t);
106 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef, void *, size_t);
107 static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *, unsigned, unsigned);
108 static int HandleVTStatus(decoder_t *, OSStatus, enum vtsession_status *);
109 static int DecodeBlock(decoder_t *, block_t *);
110 static void RequestFlush(decoder_t *);
111 static void Drain(decoder_t *p_dec, bool flush);
112 static void DecoderCallback(void *, void *, OSStatus, VTDecodeInfoFlags,
113                             CVPixelBufferRef, CMTime, CMTime);
114 static BOOL deviceSupportsHEVC();
115 static BOOL deviceSupportsAdvancedProfiles();
116 static BOOL deviceSupportsAdvancedLevels();
118 typedef struct frame_info_t frame_info_t;
120 struct frame_info_t
122     picture_t *p_picture;
123     int i_poc;
124     int i_foc;
125     bool b_flush;
126     bool b_eos;
127     bool b_keyframe;
128     bool b_field;
129     bool b_progressive;
130     bool b_top_field_first;
131     uint8_t i_num_ts;
132     unsigned i_length;
133     frame_info_t *p_next;
136 #pragma mark - decoder structure
138 #define H264_MAX_DPB 16
139 #define VT_MAX_SEI_COUNT 16
141 typedef struct decoder_sys_t
143     CMVideoCodecType            codec;
144     struct                      hxxx_helper hh;
146     /* Codec specific callbacks */
147     bool                        (*pf_codec_init)(decoder_t *);
148     void                        (*pf_codec_clean)(decoder_t *);
149     bool                        (*pf_codec_supported)(decoder_t *);
150     bool                        (*pf_late_start)(decoder_t *);
151     block_t*                    (*pf_process_block)(decoder_t *,
152                                                     block_t *, bool *);
153     bool                        (*pf_need_restart)(decoder_t *,
154                                                    VTDecompressionSessionRef);
155     bool                        (*pf_configure_vout)(decoder_t *);
156     CFMutableDictionaryRef      (*pf_get_extradata)(decoder_t *);
157     bool                        (*pf_fill_reorder_info)(decoder_t *, const block_t *,
158                                                         frame_info_t *);
159     /* !Codec specific callbacks */
161     bool                        b_vt_feed;
162     bool                        b_vt_flush;
163     bool                        b_vt_need_keyframe;
164     VTDecompressionSessionRef   session;
165     CMVideoFormatDescriptionRef videoFormatDescription;
167     vlc_mutex_t                 lock;
168     frame_info_t               *p_pic_reorder;
169     uint8_t                     i_pic_reorder;
170     uint8_t                     i_pic_reorder_max;
171     bool                        b_invalid_pic_reorder_max;
172     bool                        b_poc_based_reorder;
174     bool                        b_format_propagated;
176     enum vtsession_status       vtsession_status;
177     unsigned                    i_restart_count;
179     int                         i_cvpx_format;
180     bool                        b_cvpx_format_forced;
182     h264_poc_context_t          h264_pocctx;
183     hevc_poc_ctx_t              hevc_pocctx;
184     bool                        b_drop_blocks;
185     date_t                      pts;
187     struct pic_holder          *pic_holder;
188 } decoder_sys_t;
190 struct pic_holder
192     bool        closed;
193     vlc_mutex_t lock;
194     vlc_cond_t  wait;
195     uint8_t     nb_field_out;
196     uint8_t     field_reorder_max;
199 static void pic_holder_update_reorder_max(struct pic_holder *, uint8_t, uint8_t);
201 #pragma mark - start & stop
203 /* Codec Specific */
205 static void HXXXGetBestChroma(decoder_t *p_dec)
207     decoder_sys_t *p_sys = p_dec->p_sys;
209     if (p_sys->i_cvpx_format != 0 || p_sys->b_cvpx_format_forced)
210         return;
212     uint8_t i_chroma_format, i_depth_luma, i_depth_chroma;
213     if (hxxx_helper_get_chroma_chroma(&p_sys->hh, &i_chroma_format, &i_depth_luma,
214                                       &i_depth_chroma) != VLC_SUCCESS)
215         return;
217     if (i_chroma_format == 1 /* YUV 4:2:0 */)
218     {
219         if (i_depth_luma == 8 && i_depth_chroma == 8)
220             p_sys->i_cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
221 #if !TARGET_OS_IPHONE
222         /* Not for iOS since there is no 10bits textures with the old iOS
223          * openGLES version, and therefore no P010 shaders */
224         else if (i_depth_luma == 10 && i_depth_chroma == 10 && deviceSupportsHEVC())
225             p_sys->i_cvpx_format = 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
226 #endif
227     }
230 static void GetxPSH264(uint8_t i_pps_id, void *priv,
231                       const h264_sequence_parameter_set_t **pp_sps,
232                       const h264_picture_parameter_set_t **pp_pps)
234     decoder_sys_t *p_sys = priv;
236     *pp_pps = p_sys->hh.h264.pps_list[i_pps_id].h264_pps;
237     if(*pp_pps == NULL)
238         *pp_sps = NULL;
239     else
240         *pp_sps = p_sys->hh.h264.sps_list[(*pp_pps)->i_sps_id].h264_sps;
243 struct sei_callback_h264_s
245     uint8_t i_pic_struct;
246     const h264_sequence_parameter_set_t *p_sps;
249 static bool ParseH264SEI(const hxxx_sei_data_t *p_sei_data, void *priv)
251     if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
252     {
253         struct sei_callback_h264_s *s = priv;
254         if(s->p_sps && s->p_sps->vui.b_valid)
255         {
256             if(s->p_sps->vui.b_hrd_parameters_present_flag)
257             {
258                 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_cpb_removal_delay_length_minus1 + 1);
259                 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_dpb_output_delay_length_minus1 + 1);
260             }
262             if(s->p_sps->vui.b_pic_struct_present_flag)
263                s->i_pic_struct = bs_read( p_sei_data->p_bs, 4);
264         }
265         return false;
266     }
268     return true;
271 static bool FillReorderInfoH264(decoder_t *p_dec, const block_t *p_block,
272                                 frame_info_t *p_info)
274     decoder_sys_t *p_sys = p_dec->p_sys;
275     hxxx_iterator_ctx_t itctx;
276     hxxx_iterator_init(&itctx, p_block->p_buffer, p_block->i_buffer,
277                        p_sys->hh.i_nal_length_size);
279     const uint8_t *p_nal; size_t i_nal;
280     struct
281     {
282         const uint8_t *p_nal;
283         size_t i_nal;
284     } sei_array[VT_MAX_SEI_COUNT];
285     size_t i_sei_count = 0;
286     while(hxxx_iterate_next(&itctx, &p_nal, &i_nal))
287     {
288         if(i_nal < 2)
289             continue;
291         const enum h264_nal_unit_type_e i_nal_type = p_nal[0] & 0x1F;
293         if (i_nal_type <= H264_NAL_SLICE_IDR && i_nal_type != H264_NAL_UNKNOWN)
294         {
295             h264_slice_t slice;
296             if(!h264_decode_slice(p_nal, i_nal, GetxPSH264, p_sys, &slice))
297                 return false;
299             const h264_sequence_parameter_set_t *p_sps;
300             const h264_picture_parameter_set_t *p_pps;
301             GetxPSH264(slice.i_pic_parameter_set_id, p_sys, &p_sps, &p_pps);
302             if(p_sps)
303             {
304                 int bFOC;
305                 h264_compute_poc(p_sps, &slice, &p_sys->h264_pocctx,
306                                  &p_info->i_poc, &p_info->i_foc, &bFOC);
308                 p_info->b_keyframe = slice.type == H264_SLICE_TYPE_I;
309                 p_info->b_flush = (slice.type == H264_SLICE_TYPE_I) || slice.has_mmco5;
310                 p_info->b_field = slice.i_field_pic_flag;
311                 p_info->b_progressive = !p_sps->mb_adaptive_frame_field_flag &&
312                                         !slice.i_field_pic_flag;
314                 struct sei_callback_h264_s sei;
315                 sei.p_sps = p_sps;
316                 sei.i_pic_struct = UINT8_MAX;
318                 for(size_t i=0; i<i_sei_count; i++)
319                     HxxxParseSEI(sei_array[i].p_nal, sei_array[i].i_nal, 1,
320                                  ParseH264SEI, &sei);
322                 p_info->i_num_ts = h264_get_num_ts(p_sps, &slice, sei.i_pic_struct,
323                                                    p_info->i_foc, bFOC);
325                 if(!p_info->b_progressive)
326                     p_info->b_top_field_first = (sei.i_pic_struct % 2 == 1);
328                 /* Set frame rate for timings in case of missing rate */
329                 if( (!p_dec->fmt_in.video.i_frame_rate_base ||
330                      !p_dec->fmt_in.video.i_frame_rate) &&
331                     p_sps->vui.i_time_scale && p_sps->vui.i_num_units_in_tick )
332                 {
333                     date_Change( &p_sys->pts, p_sps->vui.i_time_scale,
334                                               p_sps->vui.i_num_units_in_tick );
335                 }
337                 if(!p_sys->b_invalid_pic_reorder_max && i_nal_type == H264_NAL_SLICE_IDR)
338                 {
339                     unsigned dummy;
340                     uint8_t i_reorder;
341                     h264_get_dpb_values(p_sps, &i_reorder, &dummy);
342                     vlc_mutex_lock(&p_sys->lock);
343                     p_sys->i_pic_reorder_max = i_reorder;
344                     pic_holder_update_reorder_max(p_sys->pic_holder,
345                                                   p_sys->i_pic_reorder_max,
346                                                   p_info->i_num_ts);
347                     vlc_mutex_unlock(&p_sys->lock);
348                 }
350             }
352             return true; /* No need to parse further NAL */
353         }
354         else if(i_nal_type == H264_NAL_SEI)
355         {
356             if(i_sei_count < VT_MAX_SEI_COUNT)
357             {
358                 sei_array[i_sei_count].p_nal = p_nal;
359                 sei_array[i_sei_count++].i_nal = i_nal;
360             }
361         }
362     }
364     return false;
368 static block_t *ProcessBlockH264(decoder_t *p_dec, block_t *p_block, bool *pb_config_changed)
370     decoder_sys_t *p_sys = p_dec->p_sys;
371     return p_sys->hh.pf_process_block(&p_sys->hh, p_block, pb_config_changed);
375 static bool InitH264(decoder_t *p_dec)
377     decoder_sys_t *p_sys = p_dec->p_sys;
378     h264_poc_context_init(&p_sys->h264_pocctx);
379     hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
380                      p_dec->fmt_in.i_codec, true);
381     return hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
382                                              p_dec->fmt_in.i_extra) == VLC_SUCCESS;
385 static void CleanH264(decoder_t *p_dec)
387     decoder_sys_t *p_sys = p_dec->p_sys;
388     hxxx_helper_clean(&p_sys->hh);
391 static CFMutableDictionaryRef GetDecoderExtradataH264(decoder_t *p_dec)
393     decoder_sys_t *p_sys = p_dec->p_sys;
395     CFMutableDictionaryRef extradata = nil;
396     if (p_dec->fmt_in.i_extra && p_sys->hh.b_is_xvcC)
397     {
398         /* copy DecoderConfiguration */
399         extradata = ExtradataInfoCreate(CFSTR("avcC"),
400                                         p_dec->fmt_in.p_extra,
401                                         p_dec->fmt_in.i_extra);
402     }
403     else if (p_sys->hh.h264.i_pps_count && p_sys->hh.h264.i_sps_count)
404     {
405         /* build DecoderConfiguration from gathered */
406         block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh);
407         if (p_avcC)
408         {
409             extradata = ExtradataInfoCreate(CFSTR("avcC"),
410                                             p_avcC->p_buffer,
411                                             p_avcC->i_buffer);
412             block_Release(p_avcC);
413         }
414     }
415     return extradata;
418 static bool CodecSupportedH264(decoder_t *p_dec)
420     decoder_sys_t *p_sys = p_dec->p_sys;
422     uint8_t i_profile, i_level;
423     if (hxxx_helper_get_current_profile_level(&p_sys->hh, &i_profile, &i_level))
424         return true;
426     switch (i_profile) {
427         case PROFILE_H264_BASELINE:
428         case PROFILE_H264_MAIN:
429         case PROFILE_H264_HIGH:
430             break;
432         case PROFILE_H264_HIGH_10:
433         {
434             if (deviceSupportsAdvancedProfiles())
435                 break;
436             else
437             {
438                 msg_Err(p_dec, "current device doesn't support H264 10bits");
439                 return false;
440             }
441         }
443         default:
444         {
445             msg_Warn(p_dec, "unknown H264 profile %" PRIx8, i_profile);
446             return false;
447         }
448     }
450     /* A level higher than 5.2 was not tested, so don't dare to try to decode
451      * it. On SoC A8, 4.2 is the highest specified profile. on Twister, we can
452      * do up to 5.2 */
453     if (i_level > 52 || (i_level > 42 && !deviceSupportsAdvancedLevels()))
454     {
455         msg_Err(p_dec, "current device doesn't support this H264 level: %"
456                 PRIx8, i_level);
457         return false;
458     }
460     HXXXGetBestChroma(p_dec);
462     return true;
465 static bool LateStartH264(decoder_t *p_dec)
467     decoder_sys_t *p_sys = p_dec->p_sys;
468     return (p_dec->fmt_in.i_extra == 0 &&
469             (!p_sys->hh.h264.i_pps_count || !p_sys->hh.h264.i_sps_count) );
472 static bool ConfigureVoutH264(decoder_t *p_dec)
474     decoder_sys_t *p_sys = p_dec->p_sys;
476     if(p_dec->fmt_in.video.primaries == COLOR_PRIMARIES_UNDEF)
477     {
478         video_color_primaries_t primaries;
479         video_transfer_func_t transfer;
480         video_color_space_t colorspace;
481         video_color_range_t full_range;
482         if (hxxx_helper_get_colorimetry(&p_sys->hh,
483                                         &primaries,
484                                         &transfer,
485                                         &colorspace,
486                                         &full_range) == VLC_SUCCESS)
487         {
488             p_dec->fmt_out.video.primaries = primaries;
489             p_dec->fmt_out.video.transfer = transfer;
490             p_dec->fmt_out.video.space = colorspace;
491             p_dec->fmt_out.video.color_range = full_range;
492         }
493     }
495     if (!p_dec->fmt_in.video.i_visible_width || !p_dec->fmt_in.video.i_visible_height)
496     {
497         unsigned i_width, i_height, i_vis_width, i_vis_height;
498         if(VLC_SUCCESS ==
499            hxxx_helper_get_current_picture_size(&p_sys->hh,
500                                                 &i_width, &i_height,
501                                                 &i_vis_width, &i_vis_height))
502         {
503             p_dec->fmt_out.video.i_visible_width = i_vis_width;
504             p_dec->fmt_out.video.i_width = ALIGN_16( i_vis_width );
505             p_dec->fmt_out.video.i_visible_height = i_vis_height;
506             p_dec->fmt_out.video.i_height = ALIGN_16( i_vis_height );
507         }
508         else return false;
509     }
511     if(!p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den)
512     {
513         int i_sar_num, i_sar_den;
514         if (VLC_SUCCESS ==
515             hxxx_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den))
516         {
517             p_dec->fmt_out.video.i_sar_num = i_sar_num;
518             p_dec->fmt_out.video.i_sar_den = i_sar_den;
519         }
520     }
522     return true;
525 static bool VideoToolboxNeedsToRestartH264(decoder_t *p_dec,
526                                            VTDecompressionSessionRef session)
528     decoder_sys_t *p_sys = p_dec->p_sys;
529     const struct hxxx_helper *hh = &p_sys->hh;
531     unsigned w, h, vw, vh;
532     int sarn, sard;
534     if (hxxx_helper_get_current_picture_size(hh, &w, &h, &vw, &vh) != VLC_SUCCESS)
535         return true;
537     if (hxxx_helper_get_current_sar(hh, &sarn, &sard) != VLC_SUCCESS)
538         return true;
540     bool b_ret = true;
542     CFMutableDictionaryRef decoderConfiguration =
543             CreateSessionDescriptionFormat(p_dec, sarn, sard);
544     if (decoderConfiguration != nil)
545     {
546         CMFormatDescriptionRef newvideoFormatDesc;
547         /* create new video format description */
548         OSStatus status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
549                                                          p_sys->codec,
550                                                          vw, vh,
551                                                          decoderConfiguration,
552                                                          &newvideoFormatDesc);
553         if (!status)
554         {
555             b_ret = !VTDecompressionSessionCanAcceptFormatDescription(session,
556                                                                       newvideoFormatDesc);
557             CFRelease(newvideoFormatDesc);
558         }
559         CFRelease(decoderConfiguration);
560     }
562     return b_ret;
565 static bool InitHEVC(decoder_t *p_dec)
567     decoder_sys_t *p_sys = p_dec->p_sys;
568     hevc_poc_cxt_init(&p_sys->hevc_pocctx);
569     hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
570                      p_dec->fmt_in.i_codec, true);
571     return hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
572                                              p_dec->fmt_in.i_extra) == VLC_SUCCESS;
575 #define CleanHEVC CleanH264
577 static void GetxPSHEVC(uint8_t i_id, void *priv,
578                        hevc_picture_parameter_set_t **pp_pps,
579                        hevc_sequence_parameter_set_t **pp_sps,
580                        hevc_video_parameter_set_t **pp_vps)
582     decoder_sys_t *p_sys = priv;
584     *pp_pps = p_sys->hh.hevc.pps_list[i_id].hevc_pps;
585     if (*pp_pps == NULL)
586     {
587         *pp_vps = NULL;
588         *pp_sps = NULL;
589     }
590     else
591     {
592         uint8_t i_sps_id = hevc_get_pps_sps_id(*pp_pps);
593         *pp_sps = p_sys->hh.hevc.sps_list[i_sps_id].hevc_sps;
594         if (*pp_sps == NULL)
595             *pp_vps = NULL;
596         else
597         {
598             uint8_t i_vps_id = hevc_get_sps_vps_id(*pp_sps);
599             *pp_vps = p_sys->hh.hevc.vps_list[i_vps_id].hevc_vps;
600         }
601     }
604 struct hevc_sei_callback_s
606     hevc_sei_pic_timing_t *p_timing;
607     const hevc_sequence_parameter_set_t *p_sps;
610 static bool ParseHEVCSEI(const hxxx_sei_data_t *p_sei_data, void *priv)
612     if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
613     {
614         struct hevc_sei_callback_s *s = priv;
615         if(likely(s->p_sps))
616             s->p_timing = hevc_decode_sei_pic_timing(p_sei_data->p_bs, s->p_sps);
617         return false;
618     }
619     return true;
622 static bool FillReorderInfoHEVC(decoder_t *p_dec, const block_t *p_block,
623                                 frame_info_t *p_info)
625     decoder_sys_t *p_sys = p_dec->p_sys;
626     hxxx_iterator_ctx_t itctx;
627     hxxx_iterator_init(&itctx, p_block->p_buffer, p_block->i_buffer,
628                        p_sys->hh.i_nal_length_size);
630     const uint8_t *p_nal; size_t i_nal;
631     struct
632     {
633         const uint8_t *p_nal;
634         size_t i_nal;
635     } sei_array[VT_MAX_SEI_COUNT];
636     size_t i_sei_count = 0;
638     while(hxxx_iterate_next(&itctx, &p_nal, &i_nal))
639     {
640         if(i_nal < 2 || hevc_getNALLayer(p_nal) > 0)
641             continue;
643         const enum hevc_nal_unit_type_e i_nal_type = hevc_getNALType(p_nal);
644         if (i_nal_type <= HEVC_NAL_IRAP_VCL23)
645         {
646             hevc_slice_segment_header_t *p_sli =
647                     hevc_decode_slice_header(p_nal, i_nal, true, GetxPSHEVC, p_sys);
648             if(!p_sli)
649                 return false;
651             /* XXX: Work-around a VT bug on recent devices (iPhone X, MacBook
652              * Pro 2017). The VT session will report a BadDataErr if you send a
653              * RASL frame just after a CRA one. Indeed, RASL frames are
654              * corrupted if the decoding start at an IRAP frame (IDR/CRA), VT
655              * is likely failing to handle this case. */
656             if (!p_sys->b_vt_feed && (i_nal_type != HEVC_NAL_IDR_W_RADL &&
657                                       i_nal_type != HEVC_NAL_IDR_N_LP))
658                 p_sys->b_drop_blocks = true;
659             else if (p_sys->b_drop_blocks)
660             {
661                 if (i_nal_type == HEVC_NAL_RASL_N || i_nal_type == HEVC_NAL_RASL_R)
662                 {
663                     hevc_rbsp_release_slice_header(p_sli);
664                     return false;
665                 }
666                 else
667                     p_sys->b_drop_blocks = false;
668             }
670             p_info->b_keyframe = i_nal_type >= HEVC_NAL_BLA_W_LP;
671             enum hevc_slice_type_e slice_type;
672             if(hevc_get_slice_type(p_sli, &slice_type))
673             {
674                 p_info->b_keyframe |= (slice_type == HEVC_SLICE_TYPE_I);
675             }
677             hevc_sequence_parameter_set_t *p_sps;
678             hevc_picture_parameter_set_t *p_pps;
679             hevc_video_parameter_set_t *p_vps;
680             GetxPSHEVC(hevc_get_slice_pps_id(p_sli), p_sys, &p_pps, &p_sps, &p_vps);
681             if(p_sps)
682             {
683                 struct hevc_sei_callback_s sei;
684                 sei.p_sps = p_sps;
685                 sei.p_timing = NULL;
687                 const int POC = hevc_compute_picture_order_count(p_sps, p_sli,
688                                                                  &p_sys->hevc_pocctx);
690                 for(size_t i=0; i<i_sei_count; i++)
691                     HxxxParseSEI(sei_array[i].p_nal, sei_array[i].i_nal,
692                                  2, ParseHEVCSEI, &sei);
694                 p_info->i_poc = POC;
695                 p_info->i_foc = POC; /* clearly looks wrong :/ */
696                 p_info->i_num_ts = hevc_get_num_clock_ts(p_sps, sei.p_timing);
697                 p_info->b_flush = (POC == 0);
698                 p_info->b_field = (p_info->i_num_ts == 1);
699                 p_info->b_progressive = hevc_frame_is_progressive(p_sps, sei.p_timing);
701                 /* Set frame rate for timings in case of missing rate */
702                 if( (!p_dec->fmt_in.video.i_frame_rate_base ||
703                      !p_dec->fmt_in.video.i_frame_rate) )
704                 {
705                     unsigned num, den;
706                     if(hevc_get_frame_rate(p_sps, p_vps, &num, &den))
707                         date_Change(&p_sys->pts, num, den);
708                 }
710                 if(sei.p_timing)
711                     hevc_release_sei_pic_timing(sei.p_timing);
713                 if(!p_sys->b_invalid_pic_reorder_max && p_vps)
714                 {
715                     vlc_mutex_lock(&p_sys->lock);
716                     p_sys->i_pic_reorder_max = hevc_get_max_num_reorder(p_vps);
717                     pic_holder_update_reorder_max(p_sys->pic_holder,
718                                                   p_sys->i_pic_reorder_max,
719                                                   p_info->i_num_ts);
720                     vlc_mutex_unlock(&p_sys->lock);
721                 }
723             }
725             hevc_rbsp_release_slice_header(p_sli);
726             return true; /* No need to parse further NAL */
727         }
728         else if(i_nal_type == HEVC_NAL_PREF_SEI)
729         {
730             if(i_sei_count < VT_MAX_SEI_COUNT)
731             {
732                 sei_array[i_sei_count].p_nal = p_nal;
733                 sei_array[i_sei_count++].i_nal = i_nal;
734             }
735         }
736     }
738     return false;
741 static CFMutableDictionaryRef GetDecoderExtradataHEVC(decoder_t *p_dec)
743     decoder_sys_t *p_sys = p_dec->p_sys;
745     CFMutableDictionaryRef extradata = nil;
746     if (p_dec->fmt_in.i_extra && p_sys->hh.b_is_xvcC)
747     {
748         /* copy DecoderConfiguration */
749         extradata = ExtradataInfoCreate(CFSTR("hvcC"),
750                                         p_dec->fmt_in.p_extra,
751                                         p_dec->fmt_in.i_extra);
752     }
753     else if (p_sys->hh.hevc.i_pps_count &&
754              p_sys->hh.hevc.i_sps_count &&
755              p_sys->hh.hevc.i_vps_count)
756     {
757         /* build DecoderConfiguration from gathered */
758         block_t *p_hvcC = hevc_helper_get_hvcc_config(&p_sys->hh);
759         if (p_hvcC)
760         {
761             extradata = ExtradataInfoCreate(CFSTR("hvcC"),
762                                             p_hvcC->p_buffer,
763                                             p_hvcC->i_buffer);
764             block_Release(p_hvcC);
765         }
766     }
767     return extradata;
770 static bool LateStartHEVC(decoder_t *p_dec)
772     decoder_sys_t *p_sys = p_dec->p_sys;
773     return (p_dec->fmt_in.i_extra == 0 &&
774             (!p_sys->hh.hevc.i_pps_count ||
775              !p_sys->hh.hevc.i_sps_count ||
776              !p_sys->hh.hevc.i_vps_count) );
779 static bool CodecSupportedHEVC(decoder_t *p_dec)
781     HXXXGetBestChroma(p_dec);
783     return true;
786 #define ConfigureVoutHEVC ConfigureVoutH264
787 #define ProcessBlockHEVC ProcessBlockH264
788 #define VideoToolboxNeedsToRestartHEVC VideoToolboxNeedsToRestartH264
790 static CFMutableDictionaryRef GetDecoderExtradataMPEG4(decoder_t *p_dec)
792     if (p_dec->fmt_in.i_extra)
793         return ESDSExtradataInfoCreate(p_dec, p_dec->fmt_in.p_extra,
794                                               p_dec->fmt_in.i_extra);
795     else
796         return nil; /* MPEG4 without esds ? */
799 static CFMutableDictionaryRef GetDecoderExtradataDefault(decoder_t *p_dec)
801     return ExtradataInfoCreate(NULL, NULL, 0); /* Empty Needed ? */
804 /* !Codec Specific */
806 static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
808     frame_info_t **pp_lead_in = &p_sys->p_pic_reorder;
810     for( ;; pp_lead_in = & ((*pp_lead_in)->p_next))
811     {
812         bool b_insert;
813         if(*pp_lead_in == NULL)
814             b_insert = true;
815         else if(p_sys->b_poc_based_reorder)
816             b_insert = ((*pp_lead_in)->i_foc > p_info->i_foc);
817         else
818             b_insert = ((*pp_lead_in)->p_picture->date >= p_info->p_picture->date);
820         if(b_insert)
821         {
822             p_info->p_next = *pp_lead_in;
823             *pp_lead_in = p_info;
824             p_sys->i_pic_reorder += (p_info->b_field) ? 1 : 2;
825             break;
826         }
827     }
828 #if 0
829     for(frame_info_t *p_in=p_sys->p_pic_reorder; p_in; p_in = p_in->p_next)
830         printf(" %d", p_in->i_foc);
831     printf("\n");
832 #endif
835 static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
837     frame_info_t *p_info = p_sys->p_pic_reorder;
838     if(p_info == NULL)
839         return NULL;
841     const int i_framepoc = p_info->i_poc;
843     picture_t *p_ret = NULL;
844     picture_t **pp_ret_last = &p_ret;
845     bool b_dequeue;
847     do
848     {
849         picture_t *p_field = p_info->p_picture;
851         /* Compute time if missing */
852         if (p_field->date == VLC_TICK_INVALID)
853             p_field->date = date_Get(&p_sys->pts);
854         else
855             date_Set(&p_sys->pts, p_field->date);
857         /* Set next picture time, in case it is missing */
858         if (p_info->i_length)
859             date_Set(&p_sys->pts, p_field->date + p_info->i_length);
860         else
861             date_Increment(&p_sys->pts, p_info->i_num_ts);
863         *pp_ret_last = p_field;
864         pp_ret_last = &p_field->p_next;
866         p_sys->i_pic_reorder -= (p_info->b_field) ? 1 : 2;
868         p_sys->p_pic_reorder = p_info->p_next;
869         free(p_info);
870         p_info = p_sys->p_pic_reorder;
872         if (p_info)
873         {
874             if (p_sys->b_poc_based_reorder)
875                 b_dequeue = (p_info->i_poc == i_framepoc);
876             else
877                 b_dequeue = (p_field->date == p_info->p_picture->date);
878         }
879         else b_dequeue = false;
881     } while(b_dequeue);
883     return p_ret;
886 static void DrainDPBLocked(decoder_t *p_dec, bool flush)
888     decoder_sys_t *p_sys = p_dec->p_sys;
889     for( ;; )
890     {
891         picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
892         if (p_fields == NULL)
893             break;
894         do
895         {
896             picture_t *p_next = p_fields->p_next;
897             p_fields->p_next = NULL;
898             if (flush)
899                 picture_Release(p_fields);
900             else
901                 decoder_QueueVideo(p_dec, p_fields);
902             p_fields = p_next;
903         } while(p_fields != NULL);
904     }
907 static frame_info_t * CreateReorderInfo(decoder_t *p_dec, const block_t *p_block)
909     decoder_sys_t *p_sys = p_dec->p_sys;
910     frame_info_t *p_info = calloc(1, sizeof(*p_info));
911     if (!p_info)
912         return NULL;
914     if (p_sys->pf_fill_reorder_info)
915     {
916         if(!p_sys->pf_fill_reorder_info(p_dec, p_block, p_info))
917         {
918             free(p_info);
919             return NULL;
920         }
921     }
922     else
923     {
924         p_info->i_num_ts = 2;
925         p_info->b_progressive = true;
926         p_info->b_field = false;
927         p_info->b_keyframe = true;
928     }
930     p_info->i_length = p_block->i_length;
932     /* required for still pictures/menus */
933     p_info->b_eos = (p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE);
935     if (date_Get(&p_sys->pts) == VLC_TICK_INVALID)
936         date_Set(&p_sys->pts, p_block->i_dts);
938     return p_info;
941 static void OnDecodedFrame(decoder_t *p_dec, frame_info_t *p_info)
943     decoder_sys_t *p_sys = p_dec->p_sys;
944     assert(p_info->p_picture);
945     while(p_info->b_flush || p_sys->i_pic_reorder >= (p_sys->i_pic_reorder_max * 2))
946     {
947         /* First check if DPB sizing was correct before removing one frame */
948         if (p_sys->p_pic_reorder && !p_info->b_flush &&
949             p_sys->i_pic_reorder_max < H264_MAX_DPB)
950         {
951             if(p_sys->b_poc_based_reorder && p_sys->p_pic_reorder->i_foc > p_info->i_foc)
952             {
953                 p_sys->b_invalid_pic_reorder_max = true;
954                 p_sys->i_pic_reorder_max++;
955                 pic_holder_update_reorder_max(p_sys->pic_holder,
956                                               p_sys->i_pic_reorder_max, p_info->i_num_ts);
957                 msg_Info(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
958                 break;
959             }
960             else if (!p_sys->b_poc_based_reorder &&
961                      p_info->p_picture->date > VLC_TICK_INVALID &&
962                      p_sys->p_pic_reorder->p_picture->date > p_info->p_picture->date)
963             {
964                 p_sys->b_invalid_pic_reorder_max = true;
965                 p_sys->i_pic_reorder_max++;
966                 pic_holder_update_reorder_max(p_sys->pic_holder,
967                                               p_sys->i_pic_reorder_max, p_info->i_num_ts);
968                 msg_Info(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
969                 break;
970             }
971         }
973         picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
974         if (p_fields == NULL)
975             break;
976         do
977         {
978             picture_t *p_next = p_fields->p_next;
979             p_fields->p_next = NULL;
980             decoder_QueueVideo(p_dec, p_fields);
981             p_fields = p_next;
982         } while(p_fields != NULL);
983     }
985     InsertIntoDPB(p_sys, p_info);
988 static CMVideoCodecType CodecPrecheck(decoder_t *p_dec)
990     decoder_sys_t *p_sys = p_dec->p_sys;
992     /* check for the codec we can and want to decode */
993     switch (p_dec->fmt_in.i_codec) {
994         case VLC_CODEC_H264:
995             return kCMVideoCodecType_H264;
997         case VLC_CODEC_HEVC:
998             if (!deviceSupportsHEVC())
999             {
1000                 msg_Warn(p_dec, "device doesn't support HEVC");
1001                 return -1;
1002             }
1003             return kCMVideoCodecType_HEVC;
1005         case VLC_CODEC_MP4V:
1006         {
1007             if (p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'X','V','I','D' )) {
1008                 msg_Warn(p_dec, "XVID decoding not implemented, fallback on software");
1009                 return -1;
1010             }
1012             msg_Dbg(p_dec, "Will decode MP4V with original FourCC '%4.4s'", (char *)&p_dec->fmt_in.i_original_fourcc);
1013             return kCMVideoCodecType_MPEG4Video;
1014         }
1015 #if !TARGET_OS_IPHONE
1016         case VLC_CODEC_H263:
1017             return kCMVideoCodecType_H263;
1019             /* there are no DV or ProRes decoders on iOS, so bailout early */
1020         case VLC_CODEC_PRORES:
1021             /* the VT decoder can't differenciate between the ProRes flavors, so we do it */
1022             switch (p_dec->fmt_in.i_original_fourcc) {
1023                 case VLC_FOURCC( 'a','p','4','c' ):
1024                 case VLC_FOURCC( 'a','p','4','h' ):
1025                 case VLC_FOURCC( 'a','p','4','x' ):
1026                     return kCMVideoCodecType_AppleProRes4444;
1028                 case VLC_FOURCC( 'a','p','c','h' ):
1029                     return kCMVideoCodecType_AppleProRes422HQ;
1031                 case VLC_FOURCC( 'a','p','c','s' ):
1032                     return kCMVideoCodecType_AppleProRes422LT;
1034                 case VLC_FOURCC( 'a','p','c','o' ):
1035                     return kCMVideoCodecType_AppleProRes422Proxy;
1037                 default:
1038                     return kCMVideoCodecType_AppleProRes422;
1039             }
1041         case VLC_CODEC_DV:
1042             /* the VT decoder can't differenciate between PAL and NTSC, so we need to do it */
1043             switch (p_dec->fmt_in.i_original_fourcc) {
1044                 case VLC_FOURCC( 'd', 'v', 'c', ' '):
1045                 case VLC_FOURCC( 'd', 'v', ' ', ' '):
1046                     msg_Dbg(p_dec, "Decoding DV NTSC");
1047                     return kCMVideoCodecType_DVCNTSC;
1049                 case VLC_FOURCC( 'd', 'v', 's', 'd'):
1050                 case VLC_FOURCC( 'd', 'v', 'c', 'p'):
1051                 case VLC_FOURCC( 'D', 'V', 'S', 'D'):
1052                     msg_Dbg(p_dec, "Decoding DV PAL");
1053                     return kCMVideoCodecType_DVCPAL;
1054                 default:
1055                     return -1;
1056             }
1057 #endif
1058             /* mpgv / mp2v needs fixing, so disable it for now */
1059 #if 0
1060         case VLC_CODEC_MPGV:
1061             return kCMVideoCodecType_MPEG1Video;
1062         case VLC_CODEC_MP2V:
1063             return kCMVideoCodecType_MPEG2Video;
1064 #endif
1066         default:
1067 #ifndef NDEBUG
1068             msg_Err(p_dec, "'%4.4s' is not supported", (char *)&p_dec->fmt_in.i_codec);
1069 #endif
1070             return -1;
1071     }
1073     vlc_assert_unreachable();
1076 static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
1077                                                              unsigned i_sar_num,
1078                                                              unsigned i_sar_den)
1080     decoder_sys_t *p_sys = p_dec->p_sys;
1082     CFMutableDictionaryRef decoderConfiguration = cfdict_create(0);
1083     if (decoderConfiguration == NULL)
1084         return nil;
1086     CFMutableDictionaryRef extradata = p_sys->pf_get_extradata
1087                                      ? p_sys->pf_get_extradata(p_dec) : nil;
1088     if(extradata)
1089     {
1090         /* then decoder will also fail if required, no need to handle it */
1091         CFDictionarySetValue(decoderConfiguration,
1092                              kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
1093                              extradata);
1094         CFRelease(extradata);
1095     }
1097     CFDictionarySetValue(decoderConfiguration,
1098                          kCVImageBufferChromaLocationBottomFieldKey,
1099                          kCVImageBufferChromaLocation_Left);
1100     CFDictionarySetValue(decoderConfiguration,
1101                          kCVImageBufferChromaLocationTopFieldKey,
1102                          kCVImageBufferChromaLocation_Left);
1104     /* pixel aspect ratio */
1105     if(i_sar_num && i_sar_den)
1106     {
1107         CFMutableDictionaryRef pixelaspectratio = cfdict_create(2);
1108         if(pixelaspectratio == NULL)
1109         {
1110             CFRelease(decoderConfiguration);
1111             return nil;
1112         }
1114         cfdict_set_int32(pixelaspectratio,
1115                          kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
1116                          i_sar_num);
1117         cfdict_set_int32(pixelaspectratio,
1118                          kCVImageBufferPixelAspectRatioVerticalSpacingKey,
1119                          i_sar_den);
1120         CFDictionarySetValue(decoderConfiguration,
1121                              kCVImageBufferPixelAspectRatioKey,
1122                              pixelaspectratio);
1123         CFRelease(pixelaspectratio);
1124     }
1126     /* Setup YUV->RGB matrix since VT can output BGRA directly. Don't setup
1127      * transfer and primaries since the transformation is done via the GL
1128      * fragment shader. */
1129     CFStringRef yuvmatrix;
1130     switch (p_dec->fmt_out.video.space)
1131     {
1132         case COLOR_SPACE_BT601:
1133             yuvmatrix = kCVImageBufferYCbCrMatrix_ITU_R_601_4;
1134             break;
1135         case COLOR_SPACE_BT2020:
1136             yuvmatrix = kCVImageBufferColorPrimaries_ITU_R_2020;
1137             break;
1138         case COLOR_SPACE_BT709:
1139         default:
1140             yuvmatrix = kCVImageBufferColorPrimaries_ITU_R_709_2;
1141             break;
1142     }
1143     CFDictionarySetValue(decoderConfiguration, kCVImageBufferYCbCrMatrixKey,
1144                          yuvmatrix);
1146     /* enable HW accelerated playback, since this is optional on OS X
1147      * note that the backend may still fallback on software mode if no
1148      * suitable hardware is available */
1149     CFDictionarySetValue(decoderConfiguration,
1150                          kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
1151                          kCFBooleanTrue);
1153     /* on OS X, we can force VT to fail if no suitable HW decoder is available,
1154      * preventing the aforementioned SW fallback */
1155     if (var_InheritBool(p_dec, "videotoolbox-hw-decoder-only"))
1156         CFDictionarySetValue(decoderConfiguration,
1157                              kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder,
1158                              kCFBooleanTrue);
1160     CFDictionarySetValue(decoderConfiguration,
1161                          kVTDecompressionPropertyKey_FieldMode,
1162                          kVTDecompressionProperty_FieldMode_DeinterlaceFields);
1163     CFDictionarySetValue(decoderConfiguration,
1164                          kVTDecompressionPropertyKey_DeinterlaceMode,
1165                          kVTDecompressionProperty_DeinterlaceMode_Temporal);
1167     return decoderConfiguration;
1170 static void PtsInit(decoder_t *p_dec)
1172     decoder_sys_t *p_sys = p_dec->p_sys;
1174     if( p_dec->fmt_in.video.i_frame_rate_base && p_dec->fmt_in.video.i_frame_rate )
1175     {
1176         date_Init( &p_sys->pts, p_dec->fmt_in.video.i_frame_rate * 2,
1177                    p_dec->fmt_in.video.i_frame_rate_base );
1178     }
1179     else date_Init( &p_sys->pts, 2 * 30000, 1001 );
1182 static int StartVideoToolbox(decoder_t *p_dec)
1184     decoder_sys_t *p_sys = p_dec->p_sys;
1186     /* Late starts */
1187     if(p_sys->pf_late_start && p_sys->pf_late_start(p_dec))
1188     {
1189         assert(p_sys->session == NULL);
1190         return VLC_SUCCESS;
1191     }
1193     /* Fills fmt_out (from extradata if any) */
1194     if(ConfigureVout(p_dec) != VLC_SUCCESS)
1195         return VLC_EGENERIC;
1197     /* destination pixel buffer attributes */
1198     CFMutableDictionaryRef destinationPixelBufferAttributes = cfdict_create(0);
1199     if(destinationPixelBufferAttributes == nil)
1200         return VLC_EGENERIC;
1202     CFMutableDictionaryRef decoderConfiguration =
1203         CreateSessionDescriptionFormat(p_dec,
1204                                        p_dec->fmt_out.video.i_sar_num,
1205                                        p_dec->fmt_out.video.i_sar_den);
1206     if(decoderConfiguration == nil)
1207     {
1208         CFRelease(destinationPixelBufferAttributes);
1209         return VLC_EGENERIC;
1210     }
1212     /* create video format description */
1213     OSStatus status = CMVideoFormatDescriptionCreate(
1214                                             kCFAllocatorDefault,
1215                                             p_sys->codec,
1216                                             p_dec->fmt_out.video.i_visible_width,
1217                                             p_dec->fmt_out.video.i_visible_height,
1218                                             decoderConfiguration,
1219                                             &p_sys->videoFormatDescription);
1220     if (status)
1221     {
1222         CFRelease(destinationPixelBufferAttributes);
1223         CFRelease(decoderConfiguration);
1224         msg_Err(p_dec, "video format description creation failed (%i)", (int)status);
1225         return VLC_EGENERIC;
1226     }
1228 #if !TARGET_OS_IPHONE
1229     CFDictionarySetValue(destinationPixelBufferAttributes,
1230                          kCVPixelBufferIOSurfaceOpenGLTextureCompatibilityKey,
1231                          kCFBooleanTrue);
1232 #else
1233     CFDictionarySetValue(destinationPixelBufferAttributes,
1234                          kCVPixelBufferOpenGLESCompatibilityKey,
1235                          kCFBooleanTrue);
1236 #endif
1238     cfdict_set_int32(destinationPixelBufferAttributes,
1239                      kCVPixelBufferWidthKey, p_dec->fmt_out.video.i_visible_width);
1240     cfdict_set_int32(destinationPixelBufferAttributes,
1241                      kCVPixelBufferHeightKey, p_dec->fmt_out.video.i_visible_height);
1243     if (p_sys->i_cvpx_format != 0)
1244     {
1245         int chroma = htonl(p_sys->i_cvpx_format);
1246         msg_Warn(p_dec, "forcing CVPX format: %4.4s", (const char *) &chroma);
1247         cfdict_set_int32(destinationPixelBufferAttributes,
1248                          kCVPixelBufferPixelFormatTypeKey,
1249                          p_sys->i_cvpx_format);
1250     }
1252     cfdict_set_int32(destinationPixelBufferAttributes,
1253                      kCVPixelBufferBytesPerRowAlignmentKey, 16);
1255     /* setup decoder callback record */
1256     VTDecompressionOutputCallbackRecord decoderCallbackRecord;
1257     decoderCallbackRecord.decompressionOutputCallback = DecoderCallback;
1258     decoderCallbackRecord.decompressionOutputRefCon = p_dec;
1260     /* create decompression session */
1261     status = VTDecompressionSessionCreate(kCFAllocatorDefault,
1262                                           p_sys->videoFormatDescription,
1263                                           decoderConfiguration,
1264                                           destinationPixelBufferAttributes,
1265                                           &decoderCallbackRecord, &p_sys->session);
1266     CFRelease(decoderConfiguration);
1267     CFRelease(destinationPixelBufferAttributes);
1269     if (HandleVTStatus(p_dec, status, NULL) != VLC_SUCCESS)
1270         return VLC_EGENERIC;
1272     PtsInit(p_dec);
1274     return VLC_SUCCESS;
1277 static void StopVideoToolbox(decoder_t *p_dec)
1279     decoder_sys_t *p_sys = p_dec->p_sys;
1281     if (p_sys->session != nil)
1282     {
1283         Drain(p_dec, true);
1285         VTDecompressionSessionInvalidate(p_sys->session);
1286         CFRelease(p_sys->session);
1287         p_sys->session = nil;
1289 #if TARGET_OS_IPHONE
1290         /* In case of 4K 10bits (BGRA), we can easily reach the device max
1291          * memory when flushing. Indeed, we'll create a new VT session that
1292          * will reallocate frames while previous frames are still used by the
1293          * vout (and not released). To work-around this issue, we force a vout
1294          * change. */
1295         if (p_dec->fmt_out.i_codec == VLC_CODEC_CVPX_BGRA
1296          && p_dec->fmt_out.video.i_width * p_dec->fmt_out.video.i_height >= 8000000)
1297         {
1298             const video_format_t orig = p_dec->fmt_out.video;
1299             p_dec->fmt_out.video.i_width = p_dec->fmt_out.video.i_height =
1300             p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_visible_height = 64;
1301             (void) decoder_UpdateVideoFormat(p_dec);
1302             p_dec->fmt_out.video = orig;
1303         }
1304 #endif
1306         p_sys->b_format_propagated = false;
1307         p_dec->fmt_out.i_codec = 0;
1308     }
1310     if (p_sys->videoFormatDescription != nil) {
1311         CFRelease(p_sys->videoFormatDescription);
1312         p_sys->videoFormatDescription = nil;
1313     }
1314     p_sys->b_vt_feed = false;
1315     p_sys->b_drop_blocks = false;
1318 #pragma mark - module open and close
1321 static int OpenDecoder(vlc_object_t *p_this)
1323     decoder_t *p_dec = (decoder_t *)p_this;
1325     if (!var_InheritBool(p_dec, "videotoolbox"))
1326         return VLC_EGENERIC;
1328 #if TARGET_OS_IPHONE
1329     if (unlikely([[UIDevice currentDevice].systemVersion floatValue] < 8.0)) {
1330         msg_Warn(p_dec, "decoder skipped as OS is too old");
1331         return VLC_EGENERIC;
1332     }
1333 #endif
1335     /* Fail if this module already failed to decode this ES */
1336     if (var_Type(p_dec, "videotoolbox-failed") != 0)
1337         return VLC_EGENERIC;
1339     /* check quickly if we can digest the offered data */
1340     CMVideoCodecType codec;
1342     codec = CodecPrecheck(p_dec);
1343     if (codec == -1)
1344         return VLC_EGENERIC;
1346     /* now that we see a chance to decode anything, allocate the
1347      * internals and start the decoding session */
1348     decoder_sys_t *p_sys;
1349     p_sys = calloc(1, sizeof(*p_sys));
1350     if (!p_sys)
1351         return VLC_ENOMEM;
1352     p_dec->p_sys = p_sys;
1353     p_sys->session = nil;
1354     p_sys->codec = codec;
1355     p_sys->videoFormatDescription = nil;
1356     p_sys->i_pic_reorder_max = 4;
1357     p_sys->vtsession_status = VTSESSION_STATUS_OK;
1358     p_sys->b_cvpx_format_forced = false;
1360     char *cvpx_chroma = var_InheritString(p_dec, "videotoolbox-cvpx-chroma");
1361     if (cvpx_chroma != NULL)
1362     {
1363         if (strlen(cvpx_chroma) != 4)
1364         {
1365             msg_Err(p_dec, "invalid videotoolbox-cvpx-chroma option");
1366             free(cvpx_chroma);
1367             free(p_sys);
1368             return VLC_EGENERIC;
1369         }
1370         memcpy(&p_sys->i_cvpx_format, cvpx_chroma, 4);
1371         p_sys->i_cvpx_format = ntohl(p_sys->i_cvpx_format);
1372         p_sys->b_cvpx_format_forced = true;
1373         free(cvpx_chroma);
1374     }
1376     p_sys->pic_holder = malloc(sizeof(struct pic_holder));
1377     if (!p_sys->pic_holder)
1378     {
1379         free(p_sys);
1380         return VLC_ENOMEM;
1381     }
1383     vlc_mutex_init(&p_sys->pic_holder->lock);
1384     vlc_cond_init(&p_sys->pic_holder->wait);
1385     p_sys->pic_holder->nb_field_out = 0;
1386     p_sys->pic_holder->closed = false;
1387     p_sys->pic_holder->field_reorder_max = p_sys->i_pic_reorder_max * 2;
1388     p_sys->b_vt_need_keyframe = false;
1390     vlc_mutex_init(&p_sys->lock);
1392     p_dec->pf_decode = DecodeBlock;
1393     p_dec->pf_flush  = RequestFlush;
1395     switch(codec)
1396     {
1397         case kCMVideoCodecType_H264:
1398             p_sys->pf_codec_init = InitH264;
1399             p_sys->pf_codec_clean = CleanH264;
1400             p_sys->pf_codec_supported = CodecSupportedH264;
1401             p_sys->pf_late_start = LateStartH264;
1402             p_sys->pf_process_block = ProcessBlockH264;
1403             p_sys->pf_need_restart = VideoToolboxNeedsToRestartH264;
1404             p_sys->pf_configure_vout = ConfigureVoutH264;
1405             p_sys->pf_get_extradata = GetDecoderExtradataH264;
1406             p_sys->pf_fill_reorder_info = FillReorderInfoH264;
1407             p_sys->b_poc_based_reorder = true;
1408             p_sys->b_vt_need_keyframe = true;
1409             break;
1411         case kCMVideoCodecType_HEVC:
1412             p_sys->pf_codec_init = InitHEVC;
1413             p_sys->pf_codec_clean = CleanHEVC;
1414             p_sys->pf_codec_supported = CodecSupportedHEVC;
1415             p_sys->pf_late_start = LateStartHEVC;
1416             p_sys->pf_process_block = ProcessBlockHEVC;
1417             p_sys->pf_need_restart = VideoToolboxNeedsToRestartHEVC;
1418             p_sys->pf_configure_vout = ConfigureVoutHEVC;
1419             p_sys->pf_get_extradata = GetDecoderExtradataHEVC;
1420             p_sys->pf_fill_reorder_info = FillReorderInfoHEVC;
1421             p_sys->b_poc_based_reorder = true;
1422             p_sys->b_vt_need_keyframe = true;
1423             break;
1425         case kCMVideoCodecType_MPEG4Video:
1426             p_sys->pf_get_extradata = GetDecoderExtradataMPEG4;
1427             break;
1429         default:
1430             p_sys->pf_get_extradata = GetDecoderExtradataDefault;
1431             break;
1432     }
1434     if (p_sys->pf_codec_init && !p_sys->pf_codec_init(p_dec))
1435     {
1436         CloseDecoder(p_this);
1437         return VLC_EGENERIC;
1438     }
1439     if (p_sys->pf_codec_supported && !p_sys->pf_codec_supported(p_dec))
1440     {
1441         CloseDecoder(p_this);
1442         return VLC_EGENERIC;
1443     }
1445     int i_ret = StartVideoToolbox(p_dec);
1446     if (i_ret == VLC_SUCCESS)
1447         msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'",
1448                         (char *)&p_dec->fmt_in.i_codec);
1449     else
1450         CloseDecoder(p_this);
1451     return i_ret;
1454 static void pic_holder_clean(struct pic_holder *pic_holder)
1456     vlc_mutex_destroy(&pic_holder->lock);
1457     vlc_cond_destroy(&pic_holder->wait);
1458     free(pic_holder);
1461 static void CloseDecoder(vlc_object_t *p_this)
1463     decoder_t *p_dec = (decoder_t *)p_this;
1464     decoder_sys_t *p_sys = p_dec->p_sys;
1466     StopVideoToolbox(p_dec);
1468     if(p_sys->pf_codec_clean)
1469         p_sys->pf_codec_clean(p_dec);
1471     vlc_mutex_destroy(&p_sys->lock);
1473     vlc_mutex_lock(&p_sys->pic_holder->lock);
1474     if (p_sys->pic_holder->nb_field_out == 0)
1475     {
1476         vlc_mutex_unlock(&p_sys->pic_holder->lock);
1477         pic_holder_clean(p_sys->pic_holder);
1478     }
1479     else
1480     {
1481         p_sys->pic_holder->closed = true;
1482         vlc_mutex_unlock(&p_sys->pic_holder->lock);
1483     }
1484     free(p_sys);
1487 #pragma mark - helpers
1489 static BOOL deviceSupportsHEVC()
1491     if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *))
1492         return VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
1493     else
1494         return NO;
1497 static BOOL deviceSupportsAdvancedProfiles()
1499 #if TARGET_OS_IPHONE
1500     size_t size;
1501     cpu_type_t type;
1503     size = sizeof(type);
1504     sysctlbyname("hw.cputype", &type, &size, NULL, 0);
1506     /* Support for H264 profile HIGH 10 was introduced with the first 64bit Apple ARM SoC, the A7 */
1507     if (type == CPU_TYPE_ARM64)
1508         return YES;
1510 #endif
1511     return NO;
1514 static BOOL deviceSupportsAdvancedLevels()
1516 #if TARGET_OS_IPHONE
1517     #ifdef __LP64__
1518         size_t size;
1519         int32_t cpufamily;
1520         size = sizeof(cpufamily);
1521         sysctlbyname("hw.cpufamily", &cpufamily, &size, NULL, 0);
1523         /* Proper 4K decoding requires a Twister SoC
1524          * Everything below will kill the decoder daemon */
1525         if (cpufamily == CPUFAMILY_ARM_CYCLONE || cpufamily == CPUFAMILY_ARM_TYPHOON) {
1526             return NO;
1527         }
1529         return YES;
1530     #else
1531         /* we need a 64bit SoC for advanced levels */
1532         return NO;
1533     #endif
1534 #else
1535     return YES;
1536 #endif
1539 static inline void bo_add_mp4_tag_descr(bo_t *p_bo, uint8_t tag, uint32_t size)
1541     bo_add_8(p_bo, tag);
1542     for (int i = 3; i>0; i--)
1543         bo_add_8(p_bo, (size>>(7*i)) | 0x80);
1544     bo_add_8(p_bo, size & 0x7F);
1547 static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *p_dec,
1548                                                       uint8_t *p_buf,
1549                                                       uint32_t i_buf_size)
1551     decoder_sys_t *p_sys = p_dec->p_sys;
1553     int full_size = 3 + 5 +13 + 5 + i_buf_size + 3;
1554     int config_size = 13 + 5 + i_buf_size;
1555     int padding = 12;
1557     bo_t bo;
1558     bool status = bo_init(&bo, 1024);
1559     if (status != true)
1560         return nil;
1562     bo_add_8(&bo, 0);       // Version
1563     bo_add_24be(&bo, 0);    // Flags
1565     // elementary stream description tag
1566     bo_add_mp4_tag_descr(&bo, 0x03, full_size);
1567     bo_add_16be(&bo, 0);    // esid
1568     bo_add_8(&bo, 0);       // stream priority (0-3)
1570     // decoder configuration description tag
1571     bo_add_mp4_tag_descr(&bo, 0x04, config_size);
1572     bo_add_8(&bo, 32);      // object type identification (32 == MPEG4)
1573     bo_add_8(&bo, 0x11);    // stream type
1574     bo_add_24be(&bo, 0);    // buffer size
1575     bo_add_32be(&bo, 0);    // max bitrate
1576     bo_add_32be(&bo, 0);    // avg bitrate
1578     // decoder specific description tag
1579     bo_add_mp4_tag_descr(&bo, 0x05, i_buf_size);
1580     bo_add_mem(&bo, i_buf_size, p_buf);
1582     // sync layer configuration description tag
1583     bo_add_8(&bo, 0x06);    // tag
1584     bo_add_8(&bo, 0x01);    // length
1585     bo_add_8(&bo, 0x02);    // no SL
1587     CFMutableDictionaryRef extradataInfo =
1588         ExtradataInfoCreate(CFSTR("esds"), bo.b->p_buffer, bo.b->i_buffer);
1589     bo_deinit(&bo);
1590     return extradataInfo;
1593 static int ConfigureVout(decoder_t *p_dec)
1595     decoder_sys_t *p_sys = p_dec->p_sys;
1597     /* return our proper VLC internal state */
1598     p_dec->fmt_out.video = p_dec->fmt_in.video;
1599     p_dec->fmt_out.video.p_palette = NULL;
1600     p_dec->fmt_out.i_codec = 0;
1602     if(p_sys->pf_configure_vout &&
1603        !p_sys->pf_configure_vout(p_dec))
1604         return VLC_EGENERIC;
1606     if (!p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den)
1607     {
1608         p_dec->fmt_out.video.i_sar_num = 1;
1609         p_dec->fmt_out.video.i_sar_den = 1;
1610     }
1612     if (!p_dec->fmt_out.video.i_visible_width || !p_dec->fmt_out.video.i_visible_height)
1613     {
1614         p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width;
1615         p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height;
1616     }
1618     p_dec->fmt_out.video.i_width = ALIGN_16( p_dec->fmt_out.video.i_visible_width );
1619     p_dec->fmt_out.video.i_height = ALIGN_16( p_dec->fmt_out.video.i_visible_height );
1621     return VLC_SUCCESS;
1624 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef name,
1625                                                   void *p_data, size_t i_data)
1627     CFMutableDictionaryRef extradataInfo = cfdict_create(1);
1628     if (extradataInfo == nil)
1629         return nil;
1631     if (p_data == NULL)
1632         return nil;
1634     CFDataRef extradata = CFDataCreate(kCFAllocatorDefault, p_data, i_data);
1635     if (extradata == nil)
1636     {
1637         CFRelease(extradataInfo);
1638         return nil;
1639     }
1640     CFDictionarySetValue(extradataInfo, name, extradata);
1641     CFRelease(extradata);
1642     return extradataInfo;
1645 static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec,
1646                                               CMFormatDescriptionRef fmt_desc,
1647                                               block_t *p_block)
1649     decoder_sys_t *p_sys = p_dec->p_sys;
1650     OSStatus status;
1651     CMBlockBufferRef  block_buf = NULL;
1652     CMSampleBufferRef sample_buf = NULL;
1653     CMTime pts;
1654     if(!p_sys->b_poc_based_reorder && p_block->i_pts == VLC_TICK_INVALID)
1655         pts = CMTimeMake(p_block->i_dts, CLOCK_FREQ);
1656     else
1657         pts = CMTimeMake(p_block->i_pts, CLOCK_FREQ);
1659     CMSampleTimingInfo timeInfoArray[1] = { {
1660         .duration = CMTimeMake(p_block->i_length, 1),
1661         .presentationTimeStamp = pts,
1662         .decodeTimeStamp = CMTimeMake(p_block->i_dts, CLOCK_FREQ),
1663     } };
1665     status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
1666                                                 p_block->p_buffer,  // memoryBlock
1667                                                 p_block->i_buffer,  // blockLength
1668                                                 kCFAllocatorNull,   // blockAllocator
1669                                                 NULL,               // customBlockSource
1670                                                 0,                  // offsetToData
1671                                                 p_block->i_buffer,  // dataLength
1672                                                 false,              // flags
1673                                                 &block_buf);
1675     if (!status) {
1676         status = CMSampleBufferCreate(kCFAllocatorDefault,  // allocator
1677                                       block_buf,            // dataBuffer
1678                                       TRUE,                 // dataReady
1679                                       0,                    // makeDataReadyCallback
1680                                       0,                    // makeDataReadyRefcon
1681                                       fmt_desc,             // formatDescription
1682                                       1,                    // numSamples
1683                                       1,                    // numSampleTimingEntries
1684                                       timeInfoArray,        // sampleTimingArray
1685                                       0,                    // numSampleSizeEntries
1686                                       NULL,                 // sampleSizeArray
1687                                       &sample_buf);
1688         if (status != noErr)
1689             msg_Warn(p_dec, "sample buffer creation failure %i", (int)status);
1690     } else
1691         msg_Warn(p_dec, "cm block buffer creation failure %i", (int)status);
1693     if (block_buf != nil)
1694         CFRelease(block_buf);
1695     block_buf = nil;
1697     return sample_buf;
1700 static int HandleVTStatus(decoder_t *p_dec, OSStatus status,
1701                           enum vtsession_status * p_vtsession_status)
1703     decoder_sys_t *p_sys = p_dec->p_sys;
1705 #define VTERRCASE(x) \
1706     case x: msg_Warn(p_dec, "vt session error: '" #x "'"); break;
1708     switch (status)
1709     {
1710         case noErr:
1711             return VLC_SUCCESS;
1713         VTERRCASE(kVTPropertyNotSupportedErr)
1714         VTERRCASE(kVTPropertyReadOnlyErr)
1715         VTERRCASE(kVTParameterErr)
1716         VTERRCASE(kVTInvalidSessionErr)
1717         VTERRCASE(kVTAllocationFailedErr)
1718         VTERRCASE(kVTPixelTransferNotSupportedErr)
1719         VTERRCASE(kVTCouldNotFindVideoDecoderErr)
1720         VTERRCASE(kVTCouldNotCreateInstanceErr)
1721         VTERRCASE(kVTCouldNotFindVideoEncoderErr)
1722         VTERRCASE(kVTVideoDecoderBadDataErr)
1723         VTERRCASE(kVTVideoDecoderUnsupportedDataFormatErr)
1724         VTERRCASE(kVTVideoDecoderMalfunctionErr)
1725         VTERRCASE(kVTVideoEncoderMalfunctionErr)
1726         VTERRCASE(kVTVideoDecoderNotAvailableNowErr)
1727         VTERRCASE(kVTImageRotationNotSupportedErr)
1728         VTERRCASE(kVTVideoEncoderNotAvailableNowErr)
1729         VTERRCASE(kVTFormatDescriptionChangeNotSupportedErr)
1730         VTERRCASE(kVTInsufficientSourceColorDataErr)
1731         VTERRCASE(kVTCouldNotCreateColorCorrectionDataErr)
1732         VTERRCASE(kVTColorSyncTransformConvertFailedErr)
1733         VTERRCASE(kVTVideoDecoderAuthorizationErr)
1734         VTERRCASE(kVTVideoEncoderAuthorizationErr)
1735         VTERRCASE(kVTColorCorrectionPixelTransferFailedErr)
1736         VTERRCASE(kVTMultiPassStorageIdentifierMismatchErr)
1737         VTERRCASE(kVTMultiPassStorageInvalidErr)
1738         VTERRCASE(kVTFrameSiloInvalidTimeStampErr)
1739         VTERRCASE(kVTFrameSiloInvalidTimeRangeErr)
1740         VTERRCASE(kVTCouldNotFindTemporalFilterErr)
1741         VTERRCASE(kVTPixelTransferNotPermittedErr)
1742         case -12219:
1743             msg_Warn(p_dec, "vt session error: "
1744                      "'kVTColorCorrectionImageRotationFailedErr'");
1745             break;
1746         default:
1747             msg_Warn(p_dec, "unknown vt session error (%i)", (int)status);
1748     }
1749 #undef VTERRCASE
1751     if (p_vtsession_status)
1752     {
1753         switch (status)
1754         {
1755             case kVTPixelTransferNotSupportedErr:
1756             case kVTPixelTransferNotPermittedErr:
1757                 *p_vtsession_status = VTSESSION_STATUS_RESTART_CHROMA;
1758                 break;
1759             case -8960 /* codecErr */:
1760             case kVTVideoDecoderMalfunctionErr:
1761             case kVTInvalidSessionErr:
1762                 *p_vtsession_status = VTSESSION_STATUS_RESTART;
1763                 break;
1764             case -8969 /* codecBadDataErr */:
1765             case kVTVideoDecoderBadDataErr:
1766             default:
1767                 *p_vtsession_status = VTSESSION_STATUS_ABORT;
1768                 break;
1769         }
1770     }
1771     return VLC_EGENERIC;
1774 #pragma mark - actual decoding
1776 static void RequestFlush(decoder_t *p_dec)
1778     decoder_sys_t *p_sys = p_dec->p_sys;
1780     vlc_mutex_lock(&p_sys->lock);
1781     p_sys->b_vt_flush = true;
1782     vlc_mutex_unlock(&p_sys->lock);
1785 static void Drain(decoder_t *p_dec, bool flush)
1787     decoder_sys_t *p_sys = p_dec->p_sys;
1789     /* draining: return last pictures of the reordered queue */
1790     vlc_mutex_lock(&p_sys->lock);
1791     p_sys->b_vt_flush = true;
1792     DrainDPBLocked(p_dec, flush);
1793     vlc_mutex_unlock(&p_sys->lock);
1795     if (p_sys->session && p_sys->b_vt_feed)
1796         VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
1798     vlc_mutex_lock(&p_sys->lock);
1799     assert(RemoveOneFrameFromDPB(p_sys) == NULL);
1800     p_sys->b_vt_flush = false;
1801     p_sys->b_vt_feed = false;
1802     p_sys->b_drop_blocks = false;
1803     vlc_mutex_unlock(&p_sys->lock);
1806 static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
1808     decoder_sys_t *p_sys = p_dec->p_sys;
1810     if (p_sys->b_vt_flush)
1811     {
1812         Drain(p_dec, true);
1813         PtsInit(p_dec);
1814     }
1816     if (p_block == NULL)
1817     {
1818         Drain(p_dec, false);
1819         return VLCDEC_SUCCESS;
1820     }
1822     vlc_mutex_lock(&p_sys->lock);
1824     if (p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK)
1825     {
1826 #if TARGET_OS_IPHONE
1827         msg_Warn(p_dec, "VT decoder doesn't handle deinterlacing on iOS, "
1828                  "aborting...");
1829         p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1830 #else
1831         if (!p_sys->b_cvpx_format_forced
1832          && p_sys->i_cvpx_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
1833         {
1834             /* In case of interlaced content, force VT to output I420 since our
1835              * SW deinterlacer handle this chroma natively. This avoids having
1836              * 2 extra conversions (CVPX->I420 then I420->CVPX). */
1838             p_sys->i_cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
1839             msg_Warn(p_dec, "Interlaced content: forcing VT to output I420");
1840             if (p_sys->session != nil && p_sys->vtsession_status == VTSESSION_STATUS_OK)
1841             {
1842                 msg_Warn(p_dec, "restarting vt session (color changed)");
1843                 vlc_mutex_unlock(&p_sys->lock);
1845                 /* Drain before stopping */
1846                 Drain(p_dec, false);
1847                 StopVideoToolbox(p_dec);
1849                 vlc_mutex_lock(&p_sys->lock);
1850             }
1851         }
1852 #endif
1853     }
1855     if (p_sys->vtsession_status == VTSESSION_STATUS_RESTART ||
1856         p_sys->vtsession_status == VTSESSION_STATUS_RESTART_CHROMA)
1857     {
1858         bool do_restart;
1859         if (p_sys->vtsession_status == VTSESSION_STATUS_RESTART_CHROMA)
1860         {
1861             if (p_sys->i_cvpx_format == 0 && p_sys->b_cvpx_format_forced)
1862             {
1863                 /* Already tried to fallback to the original chroma, aborting... */
1864                 do_restart = false;
1865             }
1866             else
1867             {
1868                 p_sys->i_cvpx_format = 0;
1869                 p_sys->b_cvpx_format_forced = true;
1870                 do_restart = true;
1871             }
1872         }
1873         else
1874             do_restart = p_sys->i_restart_count <= VT_RESTART_MAX;
1876         if (do_restart)
1877         {
1878             msg_Warn(p_dec, "restarting vt session (dec callback failed)");
1879             vlc_mutex_unlock(&p_sys->lock);
1881             /* Session will be started by Late Start code block */
1882             StopVideoToolbox(p_dec);
1884             vlc_mutex_lock(&p_sys->lock);
1885             p_sys->vtsession_status = VTSESSION_STATUS_OK;
1886         }
1887         else
1888         {
1889             msg_Warn(p_dec, "too many vt failure...");
1890             p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1891         }
1892     }
1894     if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
1895     {
1896         vlc_mutex_unlock(&p_sys->lock);
1898         msg_Err(p_dec, "decoder failure, Abort.");
1899         /* Add an empty variable so that videotoolbox won't be loaded again for
1900          * this ES */
1901         var_Create(p_dec, "videotoolbox-failed", VLC_VAR_VOID);
1902         return VLCDEC_RELOAD;
1903     }
1904     vlc_mutex_unlock(&p_sys->lock);
1906     if (unlikely(p_block->i_flags&(BLOCK_FLAG_CORRUPTED)))
1907     {
1908         if (p_sys->b_vt_feed)
1909         {
1910             Drain(p_dec, false);
1911             PtsInit(p_dec);
1912         }
1913         goto skip;
1914     }
1916     bool b_config_changed = false;
1917     if(p_sys->pf_process_block)
1918     {
1919         p_block = p_sys->pf_process_block(p_dec, p_block, &b_config_changed);
1920         if (!p_block)
1921             return VLCDEC_SUCCESS;
1922     }
1924     frame_info_t *p_info = CreateReorderInfo(p_dec, p_block);
1925     if(unlikely(!p_info))
1926         goto skip;
1928     if (!p_sys->session /* Late Start */||
1929         (b_config_changed && p_info->b_flush))
1930     {
1931         if (p_sys->session &&
1932             p_sys->pf_need_restart &&
1933             p_sys->pf_need_restart(p_dec,p_sys->session))
1934         {
1935             msg_Dbg(p_dec, "parameters sets changed: draining decoder");
1936             Drain(p_dec, false);
1937             msg_Dbg(p_dec, "parameters sets changed: restarting decoder");
1938             StopVideoToolbox(p_dec);
1939         }
1941         if(!p_sys->session)
1942         {
1943             if ((p_sys->pf_codec_supported && !p_sys->pf_codec_supported(p_dec))
1944               || StartVideoToolbox(p_dec) != VLC_SUCCESS)
1945             {
1946                 /* The current device doesn't handle the profile/level, abort */
1947                 vlc_mutex_lock(&p_sys->lock);
1948                 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1949                 vlc_mutex_unlock(&p_sys->lock);
1950             }
1951         }
1953         if (!p_sys->session) /* Start Failed */
1954         {
1955             free(p_info);
1956             goto skip;
1957         }
1958     }
1960     if (!p_sys->b_vt_feed && p_sys->b_vt_need_keyframe && !p_info->b_keyframe)
1961     {
1962         free(p_info);
1963         goto skip;
1964     }
1966     CMSampleBufferRef sampleBuffer =
1967         VTSampleBufferCreate(p_dec, p_sys->videoFormatDescription, p_block);
1968     if (unlikely(!sampleBuffer))
1969     {
1970         free(p_info);
1971         goto skip;
1972     }
1974     VTDecodeInfoFlags flagOut;
1975     VTDecodeFrameFlags decoderFlags = kVTDecodeFrame_EnableAsynchronousDecompression;
1977     OSStatus status =
1978         VTDecompressionSessionDecodeFrame(p_sys->session, sampleBuffer,
1979                                           decoderFlags, p_info, &flagOut);
1981     enum vtsession_status vtsession_status;
1982     if (HandleVTStatus(p_dec, status, &vtsession_status) == VLC_SUCCESS)
1983     {
1984         p_sys->b_vt_feed = true;
1985         if( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE )
1986             Drain( p_dec, false );
1987     }
1988     else
1989     {
1990         vlc_mutex_lock(&p_sys->lock);
1991         if (vtsession_status == VTSESSION_STATUS_RESTART)
1992             p_sys->i_restart_count++;
1993         p_sys->vtsession_status = vtsession_status;
1994         /* In case of abort, the decoder module will be reloaded next time
1995          * since we already modified the input block */
1996         vlc_mutex_unlock(&p_sys->lock);
1997     }
1998     CFRelease(sampleBuffer);
2000 skip:
2001     block_Release(p_block);
2002     return VLCDEC_SUCCESS;
2005 static int UpdateVideoFormat(decoder_t *p_dec, CVPixelBufferRef imageBuffer)
2007     decoder_sys_t *p_sys = p_dec->p_sys;
2008     NSDictionary *attachmentDict =
2009         (__bridge NSDictionary *)CVBufferGetAttachments(imageBuffer, kCVAttachmentMode_ShouldPropagate);
2011     if (attachmentDict != nil && attachmentDict.count > 0
2012      && p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF)
2013     {
2014         NSString *chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationTopFieldKey];
2015         if (chromaLocation != nil) {
2016             if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Left] ||
2017                 [chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_DV420])
2018                 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_LEFT;
2019             else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Center])
2020                 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_CENTER;
2021             else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_TopLeft])
2022                 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_LEFT;
2023             else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Top])
2024                 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_CENTER;
2025         }
2026         if (p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF)
2027         {
2028             chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationBottomFieldKey];
2029             if (chromaLocation != nil) {
2030                 if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_BottomLeft])
2031                     p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_LEFT;
2032                 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Bottom])
2033                     p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_CENTER;
2034             }
2035         }
2036     }
2038     uint32_t cvfmt = CVPixelBufferGetPixelFormatType(imageBuffer);
2039     msg_Info(p_dec, "vt cvpx chroma: %4.4s",
2040              (const char *)&(uint32_t) { htonl(cvfmt) });
2041     switch (cvfmt)
2042     {
2043         case kCVPixelFormatType_422YpCbCr8:
2044         case 'yuv2':
2045             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_UYVY;
2046             assert(CVPixelBufferIsPlanar(imageBuffer) == false);
2047             break;
2048         case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
2049         case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
2050             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_NV12;
2051             assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2052             break;
2053         case 'xf20': /* kCVPixelFormatType_420YpCbCr10BiPlanarFullRange */
2054         case 'x420': /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
2055             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_P010;
2056             assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2057             break;
2058         case kCVPixelFormatType_420YpCbCr8Planar:
2059             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_I420;
2060             assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2061             break;
2062         case kCVPixelFormatType_32BGRA:
2063             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_BGRA;
2064             assert(CVPixelBufferIsPlanar(imageBuffer) == false);
2065             break;
2066         default:
2067             p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2068             return -1;
2069     }
2070     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
2071     if (decoder_UpdateVideoFormat(p_dec) != 0)
2072     {
2073         p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2074         return -1;
2075     }
2076     return 0;
2079 static void
2080 pic_holder_on_cvpx_released(CVPixelBufferRef cvpx, void *data, unsigned nb_fields)
2082     struct pic_holder *pic_holder = data;
2084     vlc_mutex_lock(&pic_holder->lock);
2085     assert((int) pic_holder->nb_field_out - nb_fields >= 0);
2086     pic_holder->nb_field_out -= nb_fields;
2087     if (pic_holder->nb_field_out == 0 && pic_holder->closed)
2088     {
2089         vlc_mutex_unlock(&pic_holder->lock);
2090         pic_holder_clean(pic_holder);
2091     }
2092     else
2093     {
2094         vlc_cond_broadcast(&pic_holder->wait);
2095         vlc_mutex_unlock(&pic_holder->lock);
2096     }
2099 static void
2100 pic_holder_update_reorder_max(struct pic_holder *pic_holder, uint8_t pic_reorder_max,
2101                               uint8_t nb_field)
2103     vlc_mutex_lock(&pic_holder->lock);
2105     pic_holder->field_reorder_max = pic_reorder_max * (nb_field < 2 ? 2 : nb_field);
2106     vlc_cond_signal(&pic_holder->wait);
2108     vlc_mutex_unlock(&pic_holder->lock);
2111 static int pic_holder_wait(struct pic_holder *pic_holder, const picture_t *pic)
2113     const uint8_t reserved_fields = 2 * (pic->i_nb_fields < 2 ? 2 : pic->i_nb_fields);
2115     vlc_mutex_lock(&pic_holder->lock);
2117     /* Wait 200 ms max. We can't really know what the video output will do with
2118      * output pictures (will they be rendered immediately ?), so don't wait
2119      * infinitely. The output will be paced anyway by the vlc_cond_timedwait()
2120      * call. */
2121     vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_MS(200);
2122     int ret = 0;
2123     while (ret == 0 && pic_holder->field_reorder_max != 0
2124         && pic_holder->nb_field_out >= pic_holder->field_reorder_max + reserved_fields)
2125         ret = vlc_cond_timedwait(&pic_holder->wait, &pic_holder->lock, deadline);
2126     pic_holder->nb_field_out += pic->i_nb_fields;
2128     vlc_mutex_unlock(&pic_holder->lock);
2130     return ret;
2133 static void DecoderCallback(void *decompressionOutputRefCon,
2134                             void *sourceFrameRefCon,
2135                             OSStatus status,
2136                             VTDecodeInfoFlags infoFlags,
2137                             CVPixelBufferRef imageBuffer,
2138                             CMTime pts,
2139                             CMTime duration)
2141     VLC_UNUSED(duration);
2142     decoder_t *p_dec = (decoder_t *)decompressionOutputRefCon;
2143     decoder_sys_t *p_sys = p_dec->p_sys;
2144     frame_info_t *p_info = (frame_info_t *) sourceFrameRefCon;
2146     vlc_mutex_lock(&p_sys->lock);
2147     if (p_sys->b_vt_flush)
2148         goto end;
2150     enum vtsession_status vtsession_status;
2151     if (HandleVTStatus(p_dec, status, &vtsession_status) != VLC_SUCCESS)
2152     {
2153         if (p_sys->vtsession_status != VTSESSION_STATUS_ABORT)
2154         {
2155             p_sys->vtsession_status = vtsession_status;
2156             if (vtsession_status == VTSESSION_STATUS_RESTART)
2157                 p_sys->i_restart_count++;
2158         }
2159         goto end;
2160     }
2161     if (unlikely(!imageBuffer))
2162     {
2163         msg_Err(p_dec, "critical: null imageBuffer with a valid status");
2164         p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2165         goto end;
2166     }
2168     if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
2169         goto end;
2171     if (unlikely(!p_sys->b_format_propagated)) {
2172         p_sys->b_format_propagated =
2173             UpdateVideoFormat(p_dec, imageBuffer) == VLC_SUCCESS;
2175         if (!p_sys->b_format_propagated)
2176             goto end;
2177         assert(p_dec->fmt_out.i_codec != 0);
2178     }
2180     if (infoFlags & kVTDecodeInfo_FrameDropped)
2181     {
2182         /* We can't trust VT, some decoded frames can be marked as dropped */
2183         msg_Dbg(p_dec, "decoder dropped frame");
2184     }
2186     if (!CMTIME_IS_VALID(pts))
2187         goto end;
2189     if (CVPixelBufferGetDataSize(imageBuffer) == 0)
2190         goto end;
2192     if(likely(p_info))
2193     {
2194         /* Unlock the mutex because decoder_NewPicture() is blocking. Indeed,
2195          * it can wait indefinitely when the input is paused. */
2197         vlc_mutex_unlock(&p_sys->lock);
2199         picture_t *p_pic = decoder_NewPicture(p_dec);
2200         if (!p_pic)
2201         {
2202             vlc_mutex_lock(&p_sys->lock);
2203             goto end;
2204         }
2206         p_info->p_picture = p_pic;
2208         p_pic->date = pts.value;
2209         p_pic->b_force = p_info->b_eos;
2210         p_pic->b_still = p_info->b_eos;
2211         p_pic->b_progressive = p_info->b_progressive;
2212         if(!p_pic->b_progressive)
2213         {
2214             p_pic->i_nb_fields = p_info->i_num_ts;
2215             p_pic->b_top_field_first = p_info->b_top_field_first;
2216         }
2218         if (cvpxpic_attach_with_cb(p_pic, imageBuffer, pic_holder_on_cvpx_released,
2219                                    p_sys->pic_holder) != VLC_SUCCESS)
2220         {
2221             vlc_mutex_lock(&p_sys->lock);
2222             goto end;
2223         }
2225         /* VT is not pacing frame allocation. If we are not fast enough to
2226          * render (release) the output pictures, the VT session can end up
2227          * allocating way too many frames. This can be problematic for 4K
2228          * 10bits. To fix this issue, we ensure that we don't have too many
2229          * output frames allocated by waiting for the vout to release them.
2230          *
2231          * FIXME: A proper way to fix this issue is to allow decoder modules to
2232          * specify the dpb and having the vout re-allocating output frames when
2233          * this number changes. */
2234         if (pic_holder_wait(p_sys->pic_holder, p_pic))
2235             msg_Warn(p_dec, "pic_holder_wait timed out");
2238         vlc_mutex_lock(&p_sys->lock);
2240         if (p_sys->b_vt_flush)
2241         {
2242             picture_Release(p_pic);
2243             goto end;
2244         }
2246         p_sys->i_restart_count = 0;
2248         OnDecodedFrame( p_dec, p_info );
2249         p_info = NULL;
2250     }
2252 end:
2253     free(p_info);
2254     vlc_mutex_unlock(&p_sys->lock);
2255     return;