1 /*****************************************************************************
2 * videotoolbox.m: Video Toolbox decoder
3 *****************************************************************************
4 * Copyright © 2014-2015 VideoLabs SAS
6 * Authors: Felix Paul Kühne <fkuehne # videolan.org>
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.
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.
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 *****************************************************************************/
29 #import <vlc_common.h>
30 #import <vlc_plugin.h>
32 #import "hxxx_helper.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>
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
55 #import <UIKit/UIKit.h>
57 /* support iOS SDKs < v9.1 */
58 #ifndef CPUFAMILY_ARM_TWISTER
59 #define CPUFAMILY_ARM_TWISTER 0x92fb37c8
64 // Define stuff for older SDKs
65 #if (TARGET_OS_OSX && MAC_OS_X_VERSION_MAX_ALLOWED < 101100) || \
66 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < 90000) || \
67 (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED < 90000)
68 enum { kCMVideoCodecType_HEVC = 'hvc1' };
71 #if (!TARGET_OS_OSX || MAC_OS_X_VERSION_MAX_ALLOWED < 1090)
72 const CFStringRef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFSTR("EnableHardwareAcceleratedVideoDecoder");
73 const CFStringRef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder = CFSTR("RequireHardwareAcceleratedVideoDecoder");
76 #pragma mark - module descriptor
78 static int OpenDecoder(vlc_object_t *);
79 static void CloseDecoder(vlc_object_t *);
81 #define VT_REQUIRE_HW_DEC N_("Use Hardware decoders only")
82 #define VT_FORCE_CVPX_CHROMA "Force the VT decoder CVPX chroma"
83 #define VT_FORCE_CVPX_CHROMA_LONG "Values can be 'BGRA', 'y420', '420f', '420v', '2vuy'. \
84 By Default, the best chroma is choosen by the VT decoder."
87 set_category(CAT_INPUT)
88 set_subcategory(SUBCAT_INPUT_VCODEC)
89 set_description(N_("VideoToolbox video decoder"))
90 set_capability("video decoder",800)
91 set_callbacks(OpenDecoder, CloseDecoder)
93 add_obsolete_bool("videotoolbox-temporal-deinterlacing")
94 add_bool("videotoolbox-hw-decoder-only", true, VT_REQUIRE_HW_DEC, VT_REQUIRE_HW_DEC, false)
95 add_string("videotoolbox-cvpx-chroma", "", VT_FORCE_CVPX_CHROMA, VT_FORCE_CVPX_CHROMA_LONG, true);
98 #pragma mark - local prototypes
100 enum vtsession_status
103 VTSESSION_STATUS_RESTART,
104 VTSESSION_STATUS_ABORT,
107 static int ConfigureVout(decoder_t *);
108 static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *, uint8_t *, uint32_t);
109 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef, void *, size_t);
110 static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *, unsigned, unsigned);
111 static int HandleVTStatus(decoder_t *, OSStatus, enum vtsession_status *);
112 static int DecodeBlock(decoder_t *, block_t *);
113 static void RequestFlush(decoder_t *);
114 static void Drain(decoder_t *p_dec, bool flush);
115 static void DecoderCallback(void *, void *, OSStatus, VTDecodeInfoFlags,
116 CVPixelBufferRef, CMTime, CMTime);
117 static BOOL deviceSupportsHEVC();
118 static BOOL deviceSupportsAdvancedProfiles();
119 static BOOL deviceSupportsAdvancedLevels();
121 typedef struct frame_info_t frame_info_t;
125 picture_t *p_picture;
133 bool b_top_field_first;
136 frame_info_t *p_next;
139 #pragma mark - decoder structure
141 #define H264_MAX_DPB 16
142 #define VT_MAX_SEI_COUNT 16
146 CMVideoCodecType codec;
147 struct hxxx_helper hh;
149 /* Codec specific callbacks */
150 bool (*pf_codec_init)(decoder_t *);
151 void (*pf_codec_clean)(decoder_t *);
152 bool (*pf_codec_supported)(decoder_t *);
153 bool (*pf_late_start)(decoder_t *);
154 block_t* (*pf_process_block)(decoder_t *,
156 bool (*pf_need_restart)(decoder_t *,
157 VTDecompressionSessionRef);
158 bool (*pf_configure_vout)(decoder_t *);
159 CFMutableDictionaryRef (*pf_get_extradata)(decoder_t *);
160 bool (*pf_fill_reorder_info)(decoder_t *, const block_t *,
162 /* !Codec specific callbacks */
166 VTDecompressionSessionRef session;
167 CMVideoFormatDescriptionRef videoFormatDescription;
170 frame_info_t *p_pic_reorder;
171 uint8_t i_pic_reorder;
172 uint8_t i_pic_reorder_max;
173 bool b_invalid_pic_reorder_max;
174 bool b_poc_based_reorder;
176 bool b_format_propagated;
178 enum vtsession_status vtsession_status;
179 unsigned i_restart_count;
182 bool b_cvpx_format_forced;
184 h264_poc_context_t h264_pocctx;
185 hevc_poc_ctx_t hevc_pocctx;
189 struct pic_holder *pic_holder;
197 uint8_t nb_field_out;
198 uint8_t field_reorder_max;
201 static void pic_holder_update_reorder_max(struct pic_holder *, uint8_t, uint8_t);
203 #pragma mark - start & stop
207 static void HXXXGetBestChroma(decoder_t *p_dec)
209 decoder_sys_t *p_sys = p_dec->p_sys;
211 if (p_sys->i_cvpx_format != 0)
214 uint8_t i_chroma_format, i_depth_luma, i_depth_chroma;
215 if (hxxx_helper_get_chroma_chroma(&p_sys->hh, &i_chroma_format, &i_depth_luma,
216 &i_depth_chroma) != VLC_SUCCESS)
219 if (i_chroma_format == 1 /* YUV 4:2:0 */)
221 if (i_depth_luma == 8 && i_depth_chroma == 8)
222 p_sys->i_cvpx_format = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
223 #if !TARGET_OS_IPHONE
224 /* Not for iOS since there is no 10bits textures with the old iOS
225 * openGLES version, and therefore no P010 shaders */
226 else if (i_depth_luma == 10 && i_depth_chroma == 10 && deviceSupportsHEVC())
227 p_sys->i_cvpx_format = 'x420'; /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
232 static void GetxPSH264(uint8_t i_pps_id, void *priv,
233 const h264_sequence_parameter_set_t **pp_sps,
234 const h264_picture_parameter_set_t **pp_pps)
236 decoder_sys_t *p_sys = priv;
238 *pp_pps = p_sys->hh.h264.pps_list[i_pps_id].h264_pps;
242 *pp_sps = p_sys->hh.h264.sps_list[(*pp_pps)->i_sps_id].h264_sps;
245 struct sei_callback_h264_s
247 uint8_t i_pic_struct;
248 const h264_sequence_parameter_set_t *p_sps;
251 static bool ParseH264SEI(const hxxx_sei_data_t *p_sei_data, void *priv)
253 if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
255 struct sei_callback_h264_s *s = priv;
256 if(s->p_sps && s->p_sps->vui.b_valid)
258 if(s->p_sps->vui.b_hrd_parameters_present_flag)
260 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_cpb_removal_delay_length_minus1 + 1);
261 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_dpb_output_delay_length_minus1 + 1);
264 if(s->p_sps->vui.b_pic_struct_present_flag)
265 s->i_pic_struct = bs_read( p_sei_data->p_bs, 4);
273 static bool FillReorderInfoH264(decoder_t *p_dec, const block_t *p_block,
274 frame_info_t *p_info)
276 decoder_sys_t *p_sys = p_dec->p_sys;
277 hxxx_iterator_ctx_t itctx;
278 hxxx_iterator_init(&itctx, p_block->p_buffer, p_block->i_buffer,
279 p_sys->hh.i_nal_length_size);
281 const uint8_t *p_nal; size_t i_nal;
284 const uint8_t *p_nal;
286 } sei_array[VT_MAX_SEI_COUNT];
287 size_t i_sei_count = 0;
288 while(hxxx_iterate_next(&itctx, &p_nal, &i_nal))
293 const enum h264_nal_unit_type_e i_nal_type = p_nal[0] & 0x1F;
295 if (i_nal_type <= H264_NAL_SLICE_IDR && i_nal_type != H264_NAL_UNKNOWN)
298 if(!h264_decode_slice(p_nal, i_nal, GetxPSH264, p_sys, &slice))
301 const h264_sequence_parameter_set_t *p_sps;
302 const h264_picture_parameter_set_t *p_pps;
303 GetxPSH264(slice.i_pic_parameter_set_id, p_sys, &p_sps, &p_pps);
307 h264_compute_poc(p_sps, &slice, &p_sys->h264_pocctx,
308 &p_info->i_poc, &p_info->i_foc, &bFOC);
310 p_info->b_keyframe = slice.type == H264_SLICE_TYPE_I;
311 p_info->b_flush = (slice.type == H264_SLICE_TYPE_I) || slice.has_mmco5;
312 p_info->b_field = slice.i_field_pic_flag;
313 p_info->b_progressive = !p_sps->mb_adaptive_frame_field_flag &&
314 !slice.i_field_pic_flag;
316 struct sei_callback_h264_s sei;
318 sei.i_pic_struct = UINT8_MAX;
320 for(size_t i=0; i<i_sei_count; i++)
321 HxxxParseSEI(sei_array[i].p_nal, sei_array[i].i_nal, 1,
324 p_info->i_num_ts = h264_get_num_ts(p_sps, &slice, sei.i_pic_struct,
325 p_info->i_foc, bFOC);
327 if(!p_info->b_progressive)
328 p_info->b_top_field_first = (sei.i_pic_struct % 2 == 1);
330 /* Set frame rate for timings in case of missing rate */
331 if( (!p_dec->fmt_in.video.i_frame_rate_base ||
332 !p_dec->fmt_in.video.i_frame_rate) &&
333 p_sps->vui.i_time_scale && p_sps->vui.i_num_units_in_tick )
335 date_Change( &p_sys->pts, p_sps->vui.i_time_scale,
336 p_sps->vui.i_num_units_in_tick );
339 if(!p_sys->b_invalid_pic_reorder_max && i_nal_type == H264_NAL_SLICE_IDR)
343 h264_get_dpb_values(p_sps, &i_reorder, &dummy);
344 vlc_mutex_lock(&p_sys->lock);
345 p_sys->i_pic_reorder_max = i_reorder;
346 pic_holder_update_reorder_max(p_sys->pic_holder,
347 p_sys->i_pic_reorder_max,
349 vlc_mutex_unlock(&p_sys->lock);
354 return true; /* No need to parse further NAL */
356 else if(i_nal_type == H264_NAL_SEI)
358 if(i_sei_count < VT_MAX_SEI_COUNT)
360 sei_array[i_sei_count].p_nal = p_nal;
361 sei_array[i_sei_count++].i_nal = i_nal;
370 static block_t *ProcessBlockH264(decoder_t *p_dec, block_t *p_block, bool *pb_config_changed)
372 decoder_sys_t *p_sys = p_dec->p_sys;
373 return p_sys->hh.pf_process_block(&p_sys->hh, p_block, pb_config_changed);
377 static bool InitH264(decoder_t *p_dec)
379 decoder_sys_t *p_sys = p_dec->p_sys;
380 h264_poc_context_init(&p_sys->h264_pocctx);
381 hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
382 p_dec->fmt_in.i_codec, true);
383 return hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
384 p_dec->fmt_in.i_extra) == VLC_SUCCESS;
387 static void CleanH264(decoder_t *p_dec)
389 decoder_sys_t *p_sys = p_dec->p_sys;
390 hxxx_helper_clean(&p_sys->hh);
393 static CFMutableDictionaryRef GetDecoderExtradataH264(decoder_t *p_dec)
395 decoder_sys_t *p_sys = p_dec->p_sys;
397 CFMutableDictionaryRef extradata = nil;
398 if (p_dec->fmt_in.i_extra && p_sys->hh.b_is_xvcC)
400 /* copy DecoderConfiguration */
401 extradata = ExtradataInfoCreate(CFSTR("avcC"),
402 p_dec->fmt_in.p_extra,
403 p_dec->fmt_in.i_extra);
405 else if (p_sys->hh.h264.i_pps_count && p_sys->hh.h264.i_sps_count)
407 /* build DecoderConfiguration from gathered */
408 block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh);
411 extradata = ExtradataInfoCreate(CFSTR("avcC"),
414 block_Release(p_avcC);
420 static bool CodecSupportedH264(decoder_t *p_dec)
422 decoder_sys_t *p_sys = p_dec->p_sys;
424 uint8_t i_profile, i_level;
425 if (hxxx_helper_get_current_profile_level(&p_sys->hh, &i_profile, &i_level))
429 case PROFILE_H264_BASELINE:
430 case PROFILE_H264_MAIN:
431 case PROFILE_H264_HIGH:
434 case PROFILE_H264_HIGH_10:
436 if (deviceSupportsAdvancedProfiles())
440 msg_Err(p_dec, "current device doesn't support H264 10bits");
447 msg_Warn(p_dec, "unknown H264 profile %" PRIx8, i_profile);
452 /* A level higher than 5.2 was not tested, so don't dare to try to decode
453 * it. On SoC A8, 4.2 is the highest specified profile. on Twister, we can
455 if (i_level > 52 || (i_level > 42 && !deviceSupportsAdvancedLevels()))
457 msg_Err(p_dec, "current device doesn't support this H264 level: %"
462 HXXXGetBestChroma(p_dec);
467 static bool LateStartH264(decoder_t *p_dec)
469 decoder_sys_t *p_sys = p_dec->p_sys;
470 return (p_dec->fmt_in.i_extra == 0 &&
471 (!p_sys->hh.h264.i_pps_count || !p_sys->hh.h264.i_sps_count) );
474 static bool ConfigureVoutH264(decoder_t *p_dec)
476 decoder_sys_t *p_sys = p_dec->p_sys;
478 if(p_dec->fmt_in.video.primaries == COLOR_PRIMARIES_UNDEF)
480 video_color_primaries_t primaries;
481 video_transfer_func_t transfer;
482 video_color_space_t colorspace;
484 if (hxxx_helper_get_colorimetry(&p_sys->hh,
488 &full_range) == VLC_SUCCESS)
490 p_dec->fmt_out.video.primaries = primaries;
491 p_dec->fmt_out.video.transfer = transfer;
492 p_dec->fmt_out.video.space = colorspace;
493 p_dec->fmt_out.video.b_color_range_full = full_range;
497 if (!p_dec->fmt_in.video.i_visible_width || !p_dec->fmt_in.video.i_visible_height)
499 unsigned i_width, i_height, i_vis_width, i_vis_height;
501 hxxx_helper_get_current_picture_size(&p_sys->hh,
503 &i_vis_width, &i_vis_height))
505 p_dec->fmt_out.video.i_visible_width = i_vis_width;
506 p_dec->fmt_out.video.i_width = ALIGN_16( i_vis_width );
507 p_dec->fmt_out.video.i_visible_height = i_vis_height;
508 p_dec->fmt_out.video.i_height = ALIGN_16( i_vis_height );
513 if(!p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den)
515 int i_sar_num, i_sar_den;
517 hxxx_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den))
519 p_dec->fmt_out.video.i_sar_num = i_sar_num;
520 p_dec->fmt_out.video.i_sar_den = i_sar_den;
527 static bool VideoToolboxNeedsToRestartH264(decoder_t *p_dec,
528 VTDecompressionSessionRef session)
530 decoder_sys_t *p_sys = p_dec->p_sys;
531 const struct hxxx_helper *hh = &p_sys->hh;
533 unsigned w, h, vw, vh;
536 if (hxxx_helper_get_current_picture_size(hh, &w, &h, &vw, &vh) != VLC_SUCCESS)
539 if (hxxx_helper_get_current_sar(hh, &sarn, &sard) != VLC_SUCCESS)
544 CFMutableDictionaryRef decoderConfiguration =
545 CreateSessionDescriptionFormat(p_dec, sarn, sard);
546 if (decoderConfiguration != nil)
548 CMFormatDescriptionRef newvideoFormatDesc;
549 /* create new video format description */
550 OSStatus status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
553 decoderConfiguration,
554 &newvideoFormatDesc);
557 b_ret = !VTDecompressionSessionCanAcceptFormatDescription(session,
559 CFRelease(newvideoFormatDesc);
561 CFRelease(decoderConfiguration);
567 static bool InitHEVC(decoder_t *p_dec)
569 decoder_sys_t *p_sys = p_dec->p_sys;
570 hevc_poc_cxt_init(&p_sys->hevc_pocctx);
571 hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
572 p_dec->fmt_in.i_codec, true);
573 return hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
574 p_dec->fmt_in.i_extra) == VLC_SUCCESS;
577 #define CleanHEVC CleanH264
579 static void GetxPSHEVC(uint8_t i_id, void *priv,
580 hevc_picture_parameter_set_t **pp_pps,
581 hevc_sequence_parameter_set_t **pp_sps,
582 hevc_video_parameter_set_t **pp_vps)
584 decoder_sys_t *p_sys = priv;
586 *pp_pps = p_sys->hh.hevc.pps_list[i_id].hevc_pps;
594 uint8_t i_sps_id = hevc_get_pps_sps_id(*pp_pps);
595 *pp_sps = p_sys->hh.hevc.sps_list[i_sps_id].hevc_sps;
600 uint8_t i_vps_id = hevc_get_sps_vps_id(*pp_sps);
601 *pp_vps = p_sys->hh.hevc.vps_list[i_vps_id].hevc_vps;
606 struct hevc_sei_callback_s
608 hevc_sei_pic_timing_t *p_timing;
609 const hevc_sequence_parameter_set_t *p_sps;
612 static bool ParseHEVCSEI(const hxxx_sei_data_t *p_sei_data, void *priv)
614 if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
616 struct hevc_sei_callback_s *s = priv;
618 s->p_timing = hevc_decode_sei_pic_timing(p_sei_data->p_bs, s->p_sps);
624 static bool FillReorderInfoHEVC(decoder_t *p_dec, const block_t *p_block,
625 frame_info_t *p_info)
627 decoder_sys_t *p_sys = p_dec->p_sys;
628 hxxx_iterator_ctx_t itctx;
629 hxxx_iterator_init(&itctx, p_block->p_buffer, p_block->i_buffer,
630 p_sys->hh.i_nal_length_size);
632 const uint8_t *p_nal; size_t i_nal;
635 const uint8_t *p_nal;
637 } sei_array[VT_MAX_SEI_COUNT];
638 size_t i_sei_count = 0;
640 while(hxxx_iterate_next(&itctx, &p_nal, &i_nal))
642 if(i_nal < 2 || hevc_getNALLayer(p_nal) > 0)
645 const enum hevc_nal_unit_type_e i_nal_type = hevc_getNALType(p_nal);
646 if (i_nal_type <= HEVC_NAL_IRAP_VCL23)
648 hevc_slice_segment_header_t *p_sli =
649 hevc_decode_slice_header(p_nal, i_nal, true, GetxPSHEVC, p_sys);
653 /* XXX: Work-around a VT bug on recent devices (iPhone X, MacBook
654 * Pro 2017). The VT session will report a BadDataErr if you send a
655 * RASL frame just after a CRA one. Indeed, RASL frames are
656 * corrupted if the decoding start at an IRAP frame (IDR/CRA), VT
657 * is likely failing to handle this case. */
658 if (!p_sys->b_vt_feed && (i_nal_type != HEVC_NAL_IDR_W_RADL &&
659 i_nal_type != HEVC_NAL_IDR_N_LP))
660 p_sys->b_drop_blocks = true;
661 else if (p_sys->b_drop_blocks)
663 if (i_nal_type == HEVC_NAL_RASL_N || i_nal_type == HEVC_NAL_RASL_R)
665 hevc_rbsp_release_slice_header(p_sli);
669 p_sys->b_drop_blocks = false;
672 p_info->b_keyframe = i_nal_type >= HEVC_NAL_BLA_W_LP;
674 hevc_sequence_parameter_set_t *p_sps;
675 hevc_picture_parameter_set_t *p_pps;
676 hevc_video_parameter_set_t *p_vps;
677 GetxPSHEVC(hevc_get_slice_pps_id(p_sli), p_sys, &p_pps, &p_sps, &p_vps);
680 struct hevc_sei_callback_s sei;
684 const int POC = hevc_compute_picture_order_count(p_sps, p_sli,
685 &p_sys->hevc_pocctx);
687 for(size_t i=0; i<i_sei_count; i++)
688 HxxxParseSEI(sei_array[i].p_nal, sei_array[i].i_nal,
689 2, ParseHEVCSEI, &sei);
692 p_info->i_foc = POC; /* clearly looks wrong :/ */
693 p_info->i_num_ts = hevc_get_num_clock_ts(p_sps, sei.p_timing);
694 p_info->b_flush = (POC == 0);
695 p_info->b_field = (p_info->i_num_ts == 1);
696 p_info->b_progressive = hevc_frame_is_progressive(p_sps, sei.p_timing);
698 /* Set frame rate for timings in case of missing rate */
699 if( (!p_dec->fmt_in.video.i_frame_rate_base ||
700 !p_dec->fmt_in.video.i_frame_rate) )
703 if(hevc_get_frame_rate(p_sps, p_vps, &num, &den))
704 date_Change(&p_sys->pts, num, den);
708 hevc_release_sei_pic_timing(sei.p_timing);
710 if(!p_sys->b_invalid_pic_reorder_max && p_vps)
712 vlc_mutex_lock(&p_sys->lock);
713 p_sys->i_pic_reorder_max = hevc_get_max_num_reorder(p_vps);
714 pic_holder_update_reorder_max(p_sys->pic_holder,
715 p_sys->i_pic_reorder_max,
717 vlc_mutex_unlock(&p_sys->lock);
722 hevc_rbsp_release_slice_header(p_sli);
723 return true; /* No need to parse further NAL */
725 else if(i_nal_type == HEVC_NAL_PREF_SEI)
727 if(i_sei_count < VT_MAX_SEI_COUNT)
729 sei_array[i_sei_count].p_nal = p_nal;
730 sei_array[i_sei_count++].i_nal = i_nal;
738 static CFMutableDictionaryRef GetDecoderExtradataHEVC(decoder_t *p_dec)
740 decoder_sys_t *p_sys = p_dec->p_sys;
742 CFMutableDictionaryRef extradata = nil;
743 if (p_dec->fmt_in.i_extra && p_sys->hh.b_is_xvcC)
745 /* copy DecoderConfiguration */
746 extradata = ExtradataInfoCreate(CFSTR("hvcC"),
747 p_dec->fmt_in.p_extra,
748 p_dec->fmt_in.i_extra);
750 else if (p_sys->hh.hevc.i_pps_count &&
751 p_sys->hh.hevc.i_sps_count &&
752 p_sys->hh.hevc.i_vps_count)
754 /* build DecoderConfiguration from gathered */
755 block_t *p_hvcC = hevc_helper_get_hvcc_config(&p_sys->hh);
758 extradata = ExtradataInfoCreate(CFSTR("hvcC"),
761 block_Release(p_hvcC);
767 static bool LateStartHEVC(decoder_t *p_dec)
769 decoder_sys_t *p_sys = p_dec->p_sys;
770 return (p_dec->fmt_in.i_extra == 0 &&
771 (!p_sys->hh.hevc.i_pps_count ||
772 !p_sys->hh.hevc.i_sps_count ||
773 !p_sys->hh.hevc.i_vps_count) );
776 static bool CodecSupportedHEVC(decoder_t *p_dec)
778 HXXXGetBestChroma(p_dec);
783 #define ConfigureVoutHEVC ConfigureVoutH264
784 #define ProcessBlockHEVC ProcessBlockH264
785 #define VideoToolboxNeedsToRestartHEVC VideoToolboxNeedsToRestartH264
787 static CFMutableDictionaryRef GetDecoderExtradataMPEG4(decoder_t *p_dec)
789 if (p_dec->fmt_in.i_extra)
790 return ESDSExtradataInfoCreate(p_dec, p_dec->fmt_in.p_extra,
791 p_dec->fmt_in.i_extra);
793 return nil; /* MPEG4 without esds ? */
796 static CFMutableDictionaryRef GetDecoderExtradataDefault(decoder_t *p_dec)
798 return ExtradataInfoCreate(NULL, NULL, 0); /* Empty Needed ? */
801 /* !Codec Specific */
803 static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
805 frame_info_t **pp_lead_in = &p_sys->p_pic_reorder;
807 for( ;; pp_lead_in = & ((*pp_lead_in)->p_next))
810 if(*pp_lead_in == NULL)
812 else if(p_sys->b_poc_based_reorder)
813 b_insert = ((*pp_lead_in)->i_foc > p_info->i_foc);
815 b_insert = ((*pp_lead_in)->p_picture->date >= p_info->p_picture->date);
819 p_info->p_next = *pp_lead_in;
820 *pp_lead_in = p_info;
821 p_sys->i_pic_reorder += (p_info->b_field) ? 1 : 2;
826 for(frame_info_t *p_in=p_sys->p_pic_reorder; p_in; p_in = p_in->p_next)
827 printf(" %d", p_in->i_foc);
832 static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
834 frame_info_t *p_info = p_sys->p_pic_reorder;
838 const int i_framepoc = p_info->i_poc;
840 picture_t *p_ret = NULL;
841 picture_t **pp_ret_last = &p_ret;
846 picture_t *p_field = p_info->p_picture;
848 /* Compute time if missing */
849 if (p_field->date == VLC_TS_INVALID)
850 p_field->date = date_Get(&p_sys->pts);
852 date_Set(&p_sys->pts, p_field->date);
854 /* Set next picture time, in case it is missing */
855 if (p_info->i_length)
856 date_Set(&p_sys->pts, p_field->date + p_info->i_length);
858 date_Increment(&p_sys->pts, p_info->i_num_ts);
860 *pp_ret_last = p_field;
861 pp_ret_last = &p_field->p_next;
863 p_sys->i_pic_reorder -= (p_info->b_field) ? 1 : 2;
865 p_sys->p_pic_reorder = p_info->p_next;
867 p_info = p_sys->p_pic_reorder;
871 if (p_sys->b_poc_based_reorder)
872 b_dequeue = (p_info->i_poc == i_framepoc);
874 b_dequeue = (p_field->date == p_info->p_picture->date);
876 else b_dequeue = false;
883 static void DrainDPBLocked(decoder_t *p_dec, bool flush)
885 decoder_sys_t *p_sys = p_dec->p_sys;
888 picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
889 if (p_fields == NULL)
893 picture_t *p_next = p_fields->p_next;
894 p_fields->p_next = NULL;
896 picture_Release(p_fields);
898 decoder_QueueVideo(p_dec, p_fields);
900 } while(p_fields != NULL);
904 static frame_info_t * CreateReorderInfo(decoder_t *p_dec, const block_t *p_block)
906 decoder_sys_t *p_sys = p_dec->p_sys;
907 frame_info_t *p_info = calloc(1, sizeof(*p_info));
911 if (p_sys->pf_fill_reorder_info)
913 if(!p_sys->pf_fill_reorder_info(p_dec, p_block, p_info))
921 p_info->i_num_ts = 2;
922 p_info->b_progressive = true;
923 p_info->b_field = false;
924 p_info->b_keyframe = true;
927 p_info->i_length = p_block->i_length;
929 /* required for still pictures/menus */
930 p_info->b_forced = (p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE);
932 if (date_Get(&p_sys->pts) == VLC_TS_INVALID)
933 date_Set(&p_sys->pts, p_block->i_dts);
938 static void OnDecodedFrame(decoder_t *p_dec, frame_info_t *p_info)
940 decoder_sys_t *p_sys = p_dec->p_sys;
941 assert(p_info->p_picture);
942 while(p_info->b_flush || p_sys->i_pic_reorder >= (p_sys->i_pic_reorder_max * 2))
944 /* First check if DPB sizing was correct before removing one frame */
945 if (p_sys->p_pic_reorder && !p_info->b_flush &&
946 p_sys->i_pic_reorder_max < H264_MAX_DPB)
948 if(p_sys->b_poc_based_reorder && p_sys->p_pic_reorder->i_foc > p_info->i_foc)
950 p_sys->b_invalid_pic_reorder_max = true;
951 p_sys->i_pic_reorder_max++;
952 pic_holder_update_reorder_max(p_sys->pic_holder,
953 p_sys->i_pic_reorder_max, p_info->i_num_ts);
954 msg_Info(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
957 else if (!p_sys->b_poc_based_reorder &&
958 p_info->p_picture->date > VLC_TS_INVALID &&
959 p_sys->p_pic_reorder->p_picture->date > p_info->p_picture->date)
961 p_sys->b_invalid_pic_reorder_max = true;
962 p_sys->i_pic_reorder_max++;
963 pic_holder_update_reorder_max(p_sys->pic_holder,
964 p_sys->i_pic_reorder_max, p_info->i_num_ts);
965 msg_Info(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
970 picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
971 if (p_fields == NULL)
975 picture_t *p_next = p_fields->p_next;
976 p_fields->p_next = NULL;
977 decoder_QueueVideo(p_dec, p_fields);
979 } while(p_fields != NULL);
982 InsertIntoDPB(p_sys, p_info);
985 static CMVideoCodecType CodecPrecheck(decoder_t *p_dec)
987 decoder_sys_t *p_sys = p_dec->p_sys;
989 /* check for the codec we can and want to decode */
990 switch (p_dec->fmt_in.i_codec) {
992 return kCMVideoCodecType_H264;
995 if (!deviceSupportsHEVC())
997 msg_Warn(p_dec, "device doesn't support HEVC");
1000 return kCMVideoCodecType_HEVC;
1002 case VLC_CODEC_MP4V:
1004 if (p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'X','V','I','D' )) {
1005 msg_Warn(p_dec, "XVID decoding not implemented, fallback on software");
1009 msg_Dbg(p_dec, "Will decode MP4V with original FourCC '%4.4s'", (char *)&p_dec->fmt_in.i_original_fourcc);
1010 return kCMVideoCodecType_MPEG4Video;
1012 #if !TARGET_OS_IPHONE
1013 case VLC_CODEC_H263:
1014 return kCMVideoCodecType_H263;
1016 /* there are no DV or ProRes decoders on iOS, so bailout early */
1017 case VLC_CODEC_PRORES:
1018 /* the VT decoder can't differenciate between the ProRes flavors, so we do it */
1019 switch (p_dec->fmt_in.i_original_fourcc) {
1020 case VLC_FOURCC( 'a','p','4','c' ):
1021 case VLC_FOURCC( 'a','p','4','h' ):
1022 return kCMVideoCodecType_AppleProRes4444;
1024 case VLC_FOURCC( 'a','p','c','h' ):
1025 return kCMVideoCodecType_AppleProRes422HQ;
1027 case VLC_FOURCC( 'a','p','c','s' ):
1028 return kCMVideoCodecType_AppleProRes422LT;
1030 case VLC_FOURCC( 'a','p','c','o' ):
1031 return kCMVideoCodecType_AppleProRes422Proxy;
1034 return kCMVideoCodecType_AppleProRes422;
1038 /* the VT decoder can't differenciate between PAL and NTSC, so we need to do it */
1039 switch (p_dec->fmt_in.i_original_fourcc) {
1040 case VLC_FOURCC( 'd', 'v', 'c', ' '):
1041 case VLC_FOURCC( 'd', 'v', ' ', ' '):
1042 msg_Dbg(p_dec, "Decoding DV NTSC");
1043 return kCMVideoCodecType_DVCNTSC;
1045 case VLC_FOURCC( 'd', 'v', 's', 'd'):
1046 case VLC_FOURCC( 'd', 'v', 'c', 'p'):
1047 case VLC_FOURCC( 'D', 'V', 'S', 'D'):
1048 msg_Dbg(p_dec, "Decoding DV PAL");
1049 return kCMVideoCodecType_DVCPAL;
1054 /* mpgv / mp2v needs fixing, so disable it for now */
1056 case VLC_CODEC_MPGV:
1057 return kCMVideoCodecType_MPEG1Video;
1058 case VLC_CODEC_MP2V:
1059 return kCMVideoCodecType_MPEG2Video;
1064 msg_Err(p_dec, "'%4.4s' is not supported", (char *)&p_dec->fmt_in.i_codec);
1069 vlc_assert_unreachable();
1072 static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
1076 decoder_sys_t *p_sys = p_dec->p_sys;
1078 CFMutableDictionaryRef decoderConfiguration = cfdict_create(0);
1079 if (decoderConfiguration == NULL)
1082 CFMutableDictionaryRef extradata = p_sys->pf_get_extradata
1083 ? p_sys->pf_get_extradata(p_dec) : nil;
1086 /* then decoder will also fail if required, no need to handle it */
1087 CFDictionarySetValue(decoderConfiguration,
1088 kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
1090 CFRelease(extradata);
1093 CFDictionarySetValue(decoderConfiguration,
1094 kCVImageBufferChromaLocationBottomFieldKey,
1095 kCVImageBufferChromaLocation_Left);
1096 CFDictionarySetValue(decoderConfiguration,
1097 kCVImageBufferChromaLocationTopFieldKey,
1098 kCVImageBufferChromaLocation_Left);
1100 /* pixel aspect ratio */
1101 if(i_sar_num && i_sar_den)
1103 CFMutableDictionaryRef pixelaspectratio = cfdict_create(2);
1104 if(pixelaspectratio == NULL)
1106 CFRelease(decoderConfiguration);
1110 cfdict_set_int32(pixelaspectratio,
1111 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
1113 cfdict_set_int32(pixelaspectratio,
1114 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
1116 CFDictionarySetValue(decoderConfiguration,
1117 kCVImageBufferPixelAspectRatioKey,
1119 CFRelease(pixelaspectratio);
1122 /* Setup YUV->RGB matrix since VT can output BGRA directly. Don't setup
1123 * transfer and primaries since the transformation is done via the GL
1124 * fragment shader. */
1125 CFStringRef yuvmatrix;
1126 switch (p_dec->fmt_out.video.space)
1128 case COLOR_SPACE_BT601:
1129 yuvmatrix = kCVImageBufferYCbCrMatrix_ITU_R_601_4;
1131 case COLOR_SPACE_BT2020:
1132 #pragma clang diagnostic push
1133 #pragma clang diagnostic ignored "-Wpartial-availability"
1134 if (&kCVImageBufferColorPrimaries_ITU_R_2020 != nil)
1136 yuvmatrix = kCVImageBufferColorPrimaries_ITU_R_2020;
1139 #pragma clang diagnostic pop
1141 case COLOR_SPACE_BT709:
1143 yuvmatrix = kCVImageBufferColorPrimaries_ITU_R_709_2;
1146 CFDictionarySetValue(decoderConfiguration, kCVImageBufferYCbCrMatrixKey,
1149 #pragma clang diagnostic push
1150 #pragma clang diagnostic ignored "-Wpartial-availability"
1152 /* enable HW accelerated playback, since this is optional on OS X
1153 * note that the backend may still fallback on software mode if no
1154 * suitable hardware is available */
1155 CFDictionarySetValue(decoderConfiguration,
1156 kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
1159 /* on OS X, we can force VT to fail if no suitable HW decoder is available,
1160 * preventing the aforementioned SW fallback */
1161 if (var_InheritBool(p_dec, "videotoolbox-hw-decoder-only"))
1162 CFDictionarySetValue(decoderConfiguration,
1163 kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder,
1166 #pragma clang diagnostic pop
1168 CFDictionarySetValue(decoderConfiguration,
1169 kVTDecompressionPropertyKey_FieldMode,
1170 kVTDecompressionProperty_FieldMode_DeinterlaceFields);
1171 CFDictionarySetValue(decoderConfiguration,
1172 kVTDecompressionPropertyKey_DeinterlaceMode,
1173 kVTDecompressionProperty_DeinterlaceMode_Temporal);
1175 return decoderConfiguration;
1178 static void PtsInit(decoder_t *p_dec)
1180 decoder_sys_t *p_sys = p_dec->p_sys;
1182 if( p_dec->fmt_in.video.i_frame_rate_base && p_dec->fmt_in.video.i_frame_rate )
1184 date_Init( &p_sys->pts, p_dec->fmt_in.video.i_frame_rate * 2,
1185 p_dec->fmt_in.video.i_frame_rate_base );
1187 else date_Init( &p_sys->pts, 2 * 30000, 1001 );
1190 static int StartVideoToolbox(decoder_t *p_dec)
1192 decoder_sys_t *p_sys = p_dec->p_sys;
1195 if(p_sys->pf_late_start && p_sys->pf_late_start(p_dec))
1197 assert(p_sys->session == NULL);
1201 /* Fills fmt_out (from extradata if any) */
1202 if(ConfigureVout(p_dec) != VLC_SUCCESS)
1203 return VLC_EGENERIC;
1205 /* destination pixel buffer attributes */
1206 CFMutableDictionaryRef destinationPixelBufferAttributes = cfdict_create(0);
1207 if(destinationPixelBufferAttributes == nil)
1208 return VLC_EGENERIC;
1210 CFMutableDictionaryRef decoderConfiguration =
1211 CreateSessionDescriptionFormat(p_dec,
1212 p_dec->fmt_out.video.i_sar_num,
1213 p_dec->fmt_out.video.i_sar_den);
1214 if(decoderConfiguration == nil)
1216 CFRelease(destinationPixelBufferAttributes);
1217 return VLC_EGENERIC;
1220 /* create video format description */
1221 OSStatus status = CMVideoFormatDescriptionCreate(
1222 kCFAllocatorDefault,
1224 p_dec->fmt_out.video.i_visible_width,
1225 p_dec->fmt_out.video.i_visible_height,
1226 decoderConfiguration,
1227 &p_sys->videoFormatDescription);
1230 CFRelease(destinationPixelBufferAttributes);
1231 CFRelease(decoderConfiguration);
1232 msg_Err(p_dec, "video format description creation failed (%i)", (int)status);
1233 return VLC_EGENERIC;
1236 #if !TARGET_OS_IPHONE
1237 CFDictionarySetValue(destinationPixelBufferAttributes,
1238 kCVPixelBufferIOSurfaceOpenGLTextureCompatibilityKey,
1241 CFDictionarySetValue(destinationPixelBufferAttributes,
1242 kCVPixelBufferOpenGLESCompatibilityKey,
1246 cfdict_set_int32(destinationPixelBufferAttributes,
1247 kCVPixelBufferWidthKey, p_dec->fmt_out.video.i_visible_width);
1248 cfdict_set_int32(destinationPixelBufferAttributes,
1249 kCVPixelBufferHeightKey, p_dec->fmt_out.video.i_visible_height);
1251 if (p_sys->i_cvpx_format != 0)
1253 int chroma = htonl(p_sys->i_cvpx_format);
1254 msg_Warn(p_dec, "forcing CVPX format: %4.4s", (const char *) &chroma);
1255 cfdict_set_int32(destinationPixelBufferAttributes,
1256 kCVPixelBufferPixelFormatTypeKey,
1257 p_sys->i_cvpx_format);
1260 cfdict_set_int32(destinationPixelBufferAttributes,
1261 kCVPixelBufferBytesPerRowAlignmentKey, 16);
1263 /* setup decoder callback record */
1264 VTDecompressionOutputCallbackRecord decoderCallbackRecord;
1265 decoderCallbackRecord.decompressionOutputCallback = DecoderCallback;
1266 decoderCallbackRecord.decompressionOutputRefCon = p_dec;
1268 /* create decompression session */
1269 status = VTDecompressionSessionCreate(kCFAllocatorDefault,
1270 p_sys->videoFormatDescription,
1271 decoderConfiguration,
1272 destinationPixelBufferAttributes,
1273 &decoderCallbackRecord, &p_sys->session);
1274 CFRelease(decoderConfiguration);
1275 CFRelease(destinationPixelBufferAttributes);
1277 if (HandleVTStatus(p_dec, status, NULL) != VLC_SUCCESS)
1278 return VLC_EGENERIC;
1285 static void StopVideoToolbox(decoder_t *p_dec)
1287 decoder_sys_t *p_sys = p_dec->p_sys;
1289 if (p_sys->session != nil)
1293 VTDecompressionSessionInvalidate(p_sys->session);
1294 CFRelease(p_sys->session);
1295 p_sys->session = nil;
1297 #if TARGET_OS_IPHONE
1298 /* In case of 4K 10bits (BGRA), we can easily reach the device max
1299 * memory when flushing. Indeed, we'll create a new VT session that
1300 * will reallocate frames while previous frames are still used by the
1301 * vout (and not released). To work-around this issue, we force a vout
1303 if (p_dec->fmt_out.i_codec == VLC_CODEC_CVPX_BGRA
1304 && p_dec->fmt_out.video.i_width * p_dec->fmt_out.video.i_height >= 8000000)
1306 const video_format_t orig = p_dec->fmt_out.video;
1307 p_dec->fmt_out.video.i_width = p_dec->fmt_out.video.i_height =
1308 p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_visible_height = 64;
1309 (void) decoder_UpdateVideoFormat(p_dec);
1310 p_dec->fmt_out.video = orig;
1314 p_sys->b_format_propagated = false;
1315 p_dec->fmt_out.i_codec = 0;
1318 if (p_sys->videoFormatDescription != nil) {
1319 CFRelease(p_sys->videoFormatDescription);
1320 p_sys->videoFormatDescription = nil;
1322 p_sys->b_vt_feed = false;
1323 p_sys->b_drop_blocks = false;
1326 #pragma mark - module open and close
1329 static int OpenDecoder(vlc_object_t *p_this)
1331 decoder_t *p_dec = (decoder_t *)p_this;
1333 #if TARGET_OS_IPHONE
1334 if (unlikely([[UIDevice currentDevice].systemVersion floatValue] < 8.0)) {
1335 msg_Warn(p_dec, "decoder skipped as OS is too old");
1336 return VLC_EGENERIC;
1340 /* Fail if this module already failed to decode this ES */
1341 if (var_Type(p_dec, "videotoolbox-failed") != 0)
1342 return VLC_EGENERIC;
1344 /* check quickly if we can digest the offered data */
1345 CMVideoCodecType codec;
1347 codec = CodecPrecheck(p_dec);
1349 return VLC_EGENERIC;
1351 /* now that we see a chance to decode anything, allocate the
1352 * internals and start the decoding session */
1353 decoder_sys_t *p_sys;
1354 p_sys = calloc(1, sizeof(*p_sys));
1357 p_dec->p_sys = p_sys;
1358 p_sys->session = nil;
1359 p_sys->codec = codec;
1360 p_sys->videoFormatDescription = nil;
1361 p_sys->i_pic_reorder_max = 4;
1362 p_sys->vtsession_status = VTSESSION_STATUS_OK;
1363 p_sys->b_cvpx_format_forced = false;
1365 char *cvpx_chroma = var_InheritString(p_dec, "videotoolbox-cvpx-chroma");
1366 if (cvpx_chroma != NULL)
1368 if (strlen(cvpx_chroma) != 4)
1370 msg_Err(p_dec, "invalid videotoolbox-cvpx-chroma option");
1373 return VLC_EGENERIC;
1375 memcpy(&p_sys->i_cvpx_format, cvpx_chroma, 4);
1376 p_sys->i_cvpx_format = ntohl(p_sys->i_cvpx_format);
1377 p_sys->b_cvpx_format_forced = true;
1381 p_sys->pic_holder = malloc(sizeof(struct pic_holder));
1382 if (!p_sys->pic_holder)
1388 vlc_mutex_init(&p_sys->pic_holder->lock);
1389 vlc_cond_init(&p_sys->pic_holder->wait);
1390 p_sys->pic_holder->nb_field_out = 0;
1391 p_sys->pic_holder->closed = false;
1392 p_sys->pic_holder->field_reorder_max = p_sys->i_pic_reorder_max * 2;
1394 vlc_mutex_init(&p_sys->lock);
1396 p_dec->pf_decode = DecodeBlock;
1397 p_dec->pf_flush = RequestFlush;
1401 case kCMVideoCodecType_H264:
1402 p_sys->pf_codec_init = InitH264;
1403 p_sys->pf_codec_clean = CleanH264;
1404 p_sys->pf_codec_supported = CodecSupportedH264;
1405 p_sys->pf_late_start = LateStartH264;
1406 p_sys->pf_process_block = ProcessBlockH264;
1407 p_sys->pf_need_restart = VideoToolboxNeedsToRestartH264;
1408 p_sys->pf_configure_vout = ConfigureVoutH264;
1409 p_sys->pf_get_extradata = GetDecoderExtradataH264;
1410 p_sys->pf_fill_reorder_info = FillReorderInfoH264;
1411 p_sys->b_poc_based_reorder = true;
1414 case kCMVideoCodecType_HEVC:
1415 p_sys->pf_codec_init = InitHEVC;
1416 p_sys->pf_codec_clean = CleanHEVC;
1417 p_sys->pf_codec_supported = CodecSupportedHEVC;
1418 p_sys->pf_late_start = LateStartHEVC;
1419 p_sys->pf_process_block = ProcessBlockHEVC;
1420 p_sys->pf_need_restart = VideoToolboxNeedsToRestartHEVC;
1421 p_sys->pf_configure_vout = ConfigureVoutHEVC;
1422 p_sys->pf_get_extradata = GetDecoderExtradataHEVC;
1423 p_sys->pf_fill_reorder_info = FillReorderInfoHEVC;
1424 p_sys->b_poc_based_reorder = true;
1427 case kCMVideoCodecType_MPEG4Video:
1428 p_sys->pf_get_extradata = GetDecoderExtradataMPEG4;
1432 p_sys->pf_get_extradata = GetDecoderExtradataDefault;
1436 if (p_sys->pf_codec_init && !p_sys->pf_codec_init(p_dec))
1438 CloseDecoder(p_this);
1439 return VLC_EGENERIC;
1441 if (p_sys->pf_codec_supported && !p_sys->pf_codec_supported(p_dec))
1443 CloseDecoder(p_this);
1444 return VLC_EGENERIC;
1447 int i_ret = StartVideoToolbox(p_dec);
1448 if (i_ret == VLC_SUCCESS)
1449 msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'",
1450 (char *)&p_dec->fmt_in.i_codec);
1452 CloseDecoder(p_this);
1456 static void pic_holder_clean(struct pic_holder *pic_holder)
1458 vlc_mutex_destroy(&pic_holder->lock);
1459 vlc_cond_destroy(&pic_holder->wait);
1463 static void CloseDecoder(vlc_object_t *p_this)
1465 decoder_t *p_dec = (decoder_t *)p_this;
1466 decoder_sys_t *p_sys = p_dec->p_sys;
1468 StopVideoToolbox(p_dec);
1470 if(p_sys->pf_codec_clean)
1471 p_sys->pf_codec_clean(p_dec);
1473 vlc_mutex_destroy(&p_sys->lock);
1475 vlc_mutex_lock(&p_sys->pic_holder->lock);
1476 if (p_sys->pic_holder->nb_field_out == 0)
1478 vlc_mutex_unlock(&p_sys->pic_holder->lock);
1479 pic_holder_clean(p_sys->pic_holder);
1483 p_sys->pic_holder->closed = true;
1484 vlc_mutex_unlock(&p_sys->pic_holder->lock);
1489 #pragma mark - helpers
1491 static BOOL deviceSupportsHEVC()
1493 #pragma clang diagnostic push
1494 #pragma clang diagnostic ignored "-Wpartial-availability"
1496 #if (TARGET_OS_OSX && MAC_OS_X_VERSION_MAX_ALLOWED >= 101300) || \
1497 (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000) || \
1498 (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 110000)
1499 if (VTIsHardwareDecodeSupported != nil)
1500 return VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC);
1503 #pragma clang diagnostic pop
1507 static BOOL deviceSupportsAdvancedProfiles()
1509 #if TARGET_OS_IPHONE
1513 size = sizeof(type);
1514 sysctlbyname("hw.cputype", &type, &size, NULL, 0);
1516 /* Support for H264 profile HIGH 10 was introduced with the first 64bit Apple ARM SoC, the A7 */
1517 if (type == CPU_TYPE_ARM64)
1522 /* Assume that the CPU support advanced profiles if it can handle HEVC */
1523 return deviceSupportsHEVC();
1527 static BOOL deviceSupportsAdvancedLevels()
1529 #if TARGET_OS_IPHONE
1533 size = sizeof(cpufamily);
1534 sysctlbyname("hw.cpufamily", &cpufamily, &size, NULL, 0);
1536 /* Proper 4K decoding requires a Twister SoC
1537 * Everything below will kill the decoder daemon */
1538 if (cpufamily == CPUFAMILY_ARM_CYCLONE || cpufamily == CPUFAMILY_ARM_TYPHOON) {
1544 /* we need a 64bit SoC for advanced levels */
1552 static inline void bo_add_mp4_tag_descr(bo_t *p_bo, uint8_t tag, uint32_t size)
1554 bo_add_8(p_bo, tag);
1555 for (int i = 3; i>0; i--)
1556 bo_add_8(p_bo, (size>>(7*i)) | 0x80);
1557 bo_add_8(p_bo, size & 0x7F);
1560 static CFMutableDictionaryRef ESDSExtradataInfoCreate(decoder_t *p_dec,
1562 uint32_t i_buf_size)
1564 decoder_sys_t *p_sys = p_dec->p_sys;
1566 int full_size = 3 + 5 +13 + 5 + i_buf_size + 3;
1567 int config_size = 13 + 5 + i_buf_size;
1571 bool status = bo_init(&bo, 1024);
1575 bo_add_8(&bo, 0); // Version
1576 bo_add_24be(&bo, 0); // Flags
1578 // elementary stream description tag
1579 bo_add_mp4_tag_descr(&bo, 0x03, full_size);
1580 bo_add_16be(&bo, 0); // esid
1581 bo_add_8(&bo, 0); // stream priority (0-3)
1583 // decoder configuration description tag
1584 bo_add_mp4_tag_descr(&bo, 0x04, config_size);
1585 bo_add_8(&bo, 32); // object type identification (32 == MPEG4)
1586 bo_add_8(&bo, 0x11); // stream type
1587 bo_add_24be(&bo, 0); // buffer size
1588 bo_add_32be(&bo, 0); // max bitrate
1589 bo_add_32be(&bo, 0); // avg bitrate
1591 // decoder specific description tag
1592 bo_add_mp4_tag_descr(&bo, 0x05, i_buf_size);
1593 bo_add_mem(&bo, i_buf_size, p_buf);
1595 // sync layer configuration description tag
1596 bo_add_8(&bo, 0x06); // tag
1597 bo_add_8(&bo, 0x01); // length
1598 bo_add_8(&bo, 0x02); // no SL
1600 CFMutableDictionaryRef extradataInfo =
1601 ExtradataInfoCreate(CFSTR("esds"), bo.b->p_buffer, bo.b->i_buffer);
1603 return extradataInfo;
1606 static int ConfigureVout(decoder_t *p_dec)
1608 /* return our proper VLC internal state */
1609 p_dec->fmt_out.video = p_dec->fmt_in.video;
1610 p_dec->fmt_out.video.p_palette = NULL;
1611 p_dec->fmt_out.i_codec = 0;
1613 if(p_dec->p_sys->pf_configure_vout &&
1614 !p_dec->p_sys->pf_configure_vout(p_dec))
1615 return VLC_EGENERIC;
1617 if (!p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den)
1619 p_dec->fmt_out.video.i_sar_num = 1;
1620 p_dec->fmt_out.video.i_sar_den = 1;
1623 if (!p_dec->fmt_out.video.i_visible_width || !p_dec->fmt_out.video.i_visible_height)
1625 p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width;
1626 p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height;
1629 p_dec->fmt_out.video.i_width = ALIGN_16( p_dec->fmt_out.video.i_visible_width );
1630 p_dec->fmt_out.video.i_height = ALIGN_16( p_dec->fmt_out.video.i_visible_height );
1635 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef name,
1636 void *p_data, size_t i_data)
1638 CFMutableDictionaryRef extradataInfo = cfdict_create(1);
1639 if (extradataInfo == nil)
1645 CFDataRef extradata = CFDataCreate(kCFAllocatorDefault, p_data, i_data);
1646 if (extradata == nil)
1648 CFRelease(extradataInfo);
1651 CFDictionarySetValue(extradataInfo, name, extradata);
1652 CFRelease(extradata);
1653 return extradataInfo;
1656 static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec,
1657 CMFormatDescriptionRef fmt_desc,
1661 CMBlockBufferRef block_buf = NULL;
1662 CMSampleBufferRef sample_buf = NULL;
1664 if(!p_dec->p_sys->b_poc_based_reorder && p_block->i_pts == VLC_TS_INVALID)
1665 pts = CMTimeMake(p_block->i_dts, CLOCK_FREQ);
1667 pts = CMTimeMake(p_block->i_pts, CLOCK_FREQ);
1669 CMSampleTimingInfo timeInfoArray[1] = { {
1670 .duration = CMTimeMake(p_block->i_length, 1),
1671 .presentationTimeStamp = pts,
1672 .decodeTimeStamp = CMTimeMake(p_block->i_dts, CLOCK_FREQ),
1675 status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
1676 p_block->p_buffer, // memoryBlock
1677 p_block->i_buffer, // blockLength
1678 kCFAllocatorNull, // blockAllocator
1679 NULL, // customBlockSource
1681 p_block->i_buffer, // dataLength
1686 status = CMSampleBufferCreate(kCFAllocatorDefault, // allocator
1687 block_buf, // dataBuffer
1689 0, // makeDataReadyCallback
1690 0, // makeDataReadyRefcon
1691 fmt_desc, // formatDescription
1693 1, // numSampleTimingEntries
1694 timeInfoArray, // sampleTimingArray
1695 0, // numSampleSizeEntries
1696 NULL, // sampleSizeArray
1698 if (status != noErr)
1699 msg_Warn(p_dec, "sample buffer creation failure %i", (int)status);
1701 msg_Warn(p_dec, "cm block buffer creation failure %i", (int)status);
1703 if (block_buf != nil)
1704 CFRelease(block_buf);
1710 static int HandleVTStatus(decoder_t *p_dec, OSStatus status,
1711 enum vtsession_status * p_vtsession_status)
1713 decoder_sys_t *p_sys = p_dec->p_sys;
1715 #define VTERRCASE(x) \
1716 case x: msg_Warn(p_dec, "vt session error: '" #x "'"); break;
1723 VTERRCASE(kVTPropertyNotSupportedErr)
1724 VTERRCASE(kVTPropertyReadOnlyErr)
1725 VTERRCASE(kVTParameterErr)
1726 VTERRCASE(kVTInvalidSessionErr)
1727 VTERRCASE(kVTAllocationFailedErr)
1728 VTERRCASE(kVTPixelTransferNotSupportedErr)
1729 VTERRCASE(kVTCouldNotFindVideoDecoderErr)
1730 VTERRCASE(kVTCouldNotCreateInstanceErr)
1731 VTERRCASE(kVTCouldNotFindVideoEncoderErr)
1732 VTERRCASE(kVTVideoDecoderBadDataErr)
1733 VTERRCASE(kVTVideoDecoderUnsupportedDataFormatErr)
1734 VTERRCASE(kVTVideoDecoderMalfunctionErr)
1735 VTERRCASE(kVTVideoEncoderMalfunctionErr)
1736 VTERRCASE(kVTVideoDecoderNotAvailableNowErr)
1737 VTERRCASE(kVTImageRotationNotSupportedErr)
1738 VTERRCASE(kVTVideoEncoderNotAvailableNowErr)
1739 VTERRCASE(kVTFormatDescriptionChangeNotSupportedErr)
1740 VTERRCASE(kVTInsufficientSourceColorDataErr)
1741 VTERRCASE(kVTCouldNotCreateColorCorrectionDataErr)
1742 VTERRCASE(kVTColorSyncTransformConvertFailedErr)
1743 VTERRCASE(kVTVideoDecoderAuthorizationErr)
1744 VTERRCASE(kVTVideoEncoderAuthorizationErr)
1745 VTERRCASE(kVTColorCorrectionPixelTransferFailedErr)
1746 VTERRCASE(kVTMultiPassStorageIdentifierMismatchErr)
1747 VTERRCASE(kVTMultiPassStorageInvalidErr)
1748 VTERRCASE(kVTFrameSiloInvalidTimeStampErr)
1749 VTERRCASE(kVTFrameSiloInvalidTimeRangeErr)
1750 VTERRCASE(kVTCouldNotFindTemporalFilterErr)
1751 VTERRCASE(kVTPixelTransferNotPermittedErr)
1753 msg_Warn(p_dec, "vt session error: "
1754 "'kVTColorCorrectionImageRotationFailedErr'");
1757 msg_Warn(p_dec, "unknown vt session error (%i)", (int)status);
1761 if (p_vtsession_status)
1765 case kVTParameterErr:
1766 case kCVReturnInvalidArgument:
1767 *p_vtsession_status = VTSESSION_STATUS_ABORT;
1769 case -8960 /* codecErr */:
1770 case kVTVideoDecoderMalfunctionErr:
1771 case -8969 /* codecBadDataErr */:
1772 case kVTVideoDecoderBadDataErr:
1773 case kVTInvalidSessionErr:
1774 *p_vtsession_status = VTSESSION_STATUS_RESTART;
1777 *p_vtsession_status = VTSESSION_STATUS_OK;
1781 return VLC_EGENERIC;
1784 #pragma mark - actual decoding
1786 static void RequestFlush(decoder_t *p_dec)
1788 decoder_sys_t *p_sys = p_dec->p_sys;
1790 vlc_mutex_lock(&p_sys->lock);
1791 p_sys->b_vt_flush = true;
1792 vlc_mutex_unlock(&p_sys->lock);
1795 static void Drain(decoder_t *p_dec, bool flush)
1797 decoder_sys_t *p_sys = p_dec->p_sys;
1799 /* draining: return last pictures of the reordered queue */
1800 vlc_mutex_lock(&p_sys->lock);
1801 p_sys->b_vt_flush = true;
1802 DrainDPBLocked(p_dec, flush);
1803 vlc_mutex_unlock(&p_sys->lock);
1805 if (p_sys->session && p_sys->b_vt_feed)
1806 VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
1808 vlc_mutex_lock(&p_sys->lock);
1809 assert(RemoveOneFrameFromDPB(p_sys) == NULL);
1810 p_sys->b_vt_flush = false;
1811 p_sys->b_vt_feed = false;
1812 p_sys->b_drop_blocks = false;
1813 vlc_mutex_unlock(&p_sys->lock);
1816 static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
1818 decoder_sys_t *p_sys = p_dec->p_sys;
1820 if (p_sys->b_vt_flush)
1826 if (p_block == NULL)
1828 Drain(p_dec, false);
1829 return VLCDEC_SUCCESS;
1832 vlc_mutex_lock(&p_sys->lock);
1834 if (p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK)
1836 #if TARGET_OS_IPHONE
1837 msg_Warn(p_dec, "VT decoder doesn't handle deinterlacing on iOS, "
1839 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1841 if (!p_sys->b_cvpx_format_forced
1842 && p_sys->i_cvpx_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
1844 /* In case of interlaced content, force VT to output I420 since our
1845 * SW deinterlacer handle this chroma natively. This avoids having
1846 * 2 extra conversions (CVPX->I420 then I420->CVPX). */
1848 p_sys->i_cvpx_format = kCVPixelFormatType_420YpCbCr8Planar;
1849 msg_Warn(p_dec, "Interlaced content: forcing VT to output I420");
1850 if (p_sys->session != nil && p_sys->vtsession_status == VTSESSION_STATUS_OK)
1852 msg_Warn(p_dec, "restarting vt session (color changed)");
1853 vlc_mutex_unlock(&p_sys->lock);
1855 /* Drain before stopping */
1856 Drain(p_dec, false);
1857 StopVideoToolbox(p_dec);
1859 vlc_mutex_lock(&p_sys->lock);
1865 if (p_sys->vtsession_status == VTSESSION_STATUS_RESTART)
1867 if (p_sys->i_restart_count <= VT_RESTART_MAX)
1869 msg_Warn(p_dec, "restarting vt session (dec callback failed)");
1870 vlc_mutex_unlock(&p_sys->lock);
1872 /* Session will be started by Late Start code block */
1873 StopVideoToolbox(p_dec);
1874 if (p_dec->fmt_in.i_extra == 0)
1876 /* Clean old parameter sets since they may be corrupt */
1877 hxxx_helper_clean(&p_sys->hh);
1880 vlc_mutex_lock(&p_sys->lock);
1881 p_sys->vtsession_status = VTSESSION_STATUS_OK;
1885 msg_Warn(p_dec, "too many vt failure...");
1886 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1890 if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
1892 vlc_mutex_unlock(&p_sys->lock);
1894 msg_Err(p_dec, "decoder failure, Abort.");
1895 /* Add an empty variable so that videotoolbox won't be loaded again for
1897 var_Create(p_dec, "videotoolbox-failed", VLC_VAR_VOID);
1898 return VLCDEC_RELOAD;
1900 vlc_mutex_unlock(&p_sys->lock);
1902 if (unlikely(p_block->i_flags&(BLOCK_FLAG_CORRUPTED)))
1904 if (p_sys->b_vt_feed)
1906 Drain(p_dec, false);
1912 bool b_config_changed = false;
1913 if(p_sys->pf_process_block)
1915 p_block = p_sys->pf_process_block(p_dec, p_block, &b_config_changed);
1917 return VLCDEC_SUCCESS;
1920 frame_info_t *p_info = CreateReorderInfo(p_dec, p_block);
1921 if(unlikely(!p_info))
1924 if (!p_sys->session /* Late Start */||
1925 (b_config_changed && p_info->b_flush))
1927 if (p_sys->session &&
1928 p_sys->pf_need_restart &&
1929 p_sys->pf_need_restart(p_dec,p_sys->session))
1931 msg_Dbg(p_dec, "parameters sets changed: draining decoder");
1932 Drain(p_dec, false);
1933 msg_Dbg(p_dec, "parameters sets changed: restarting decoder");
1934 StopVideoToolbox(p_dec);
1939 if ((p_sys->pf_codec_supported && !p_sys->pf_codec_supported(p_dec))
1940 || StartVideoToolbox(p_dec) != VLC_SUCCESS)
1942 /* The current device doesn't handle the profile/level, abort */
1943 vlc_mutex_lock(&p_sys->lock);
1944 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1945 vlc_mutex_unlock(&p_sys->lock);
1949 if (!p_sys->session) /* Start Failed */
1956 if (!p_sys->b_vt_feed && !p_info->b_keyframe)
1962 CMSampleBufferRef sampleBuffer =
1963 VTSampleBufferCreate(p_dec, p_sys->videoFormatDescription, p_block);
1964 if (unlikely(!sampleBuffer))
1970 VTDecodeInfoFlags flagOut;
1971 VTDecodeFrameFlags decoderFlags = kVTDecodeFrame_EnableAsynchronousDecompression;
1974 VTDecompressionSessionDecodeFrame(p_sys->session, sampleBuffer,
1975 decoderFlags, p_info, &flagOut);
1977 enum vtsession_status vtsession_status;
1978 if (HandleVTStatus(p_dec, status, &vtsession_status) == VLC_SUCCESS)
1980 p_sys->b_vt_feed = true;
1981 if( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE )
1982 Drain( p_dec, false );
1986 vlc_mutex_lock(&p_sys->lock);
1987 if (vtsession_status == VTSESSION_STATUS_RESTART)
1988 p_sys->i_restart_count++;
1989 p_sys->vtsession_status = vtsession_status;
1990 /* In case of abort, the decoder module will be reloaded next time
1991 * since we already modified the input block */
1992 vlc_mutex_unlock(&p_sys->lock);
1994 CFRelease(sampleBuffer);
1997 block_Release(p_block);
1998 return VLCDEC_SUCCESS;
2001 static int UpdateVideoFormat(decoder_t *p_dec, CVPixelBufferRef imageBuffer)
2003 NSDictionary *attachmentDict =
2004 (__bridge NSDictionary *)CVBufferGetAttachments(imageBuffer, kCVAttachmentMode_ShouldPropagate);
2006 if (attachmentDict != nil && attachmentDict.count > 0
2007 && p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF)
2009 NSString *chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationTopFieldKey];
2010 if (chromaLocation != nil) {
2011 if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Left] ||
2012 [chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_DV420])
2013 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_LEFT;
2014 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Center])
2015 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_CENTER;
2016 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_TopLeft])
2017 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_LEFT;
2018 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Top])
2019 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_CENTER;
2021 if (p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF)
2023 chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationBottomFieldKey];
2024 if (chromaLocation != nil) {
2025 if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_BottomLeft])
2026 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_LEFT;
2027 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Bottom])
2028 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_CENTER;
2033 uint32_t cvfmt = CVPixelBufferGetPixelFormatType(imageBuffer);
2034 msg_Info(p_dec, "vt cvpx chroma: %4.4s",
2035 (const char *)&(uint32_t) { htonl(cvfmt) });
2038 case kCVPixelFormatType_422YpCbCr8:
2040 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_UYVY;
2041 assert(CVPixelBufferIsPlanar(imageBuffer) == false);
2043 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
2044 case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
2045 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_NV12;
2046 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2048 case 'xf20': /* kCVPixelFormatType_420YpCbCr10BiPlanarFullRange */
2049 case 'x420': /* kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange */
2050 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_P010;
2051 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2053 case kCVPixelFormatType_420YpCbCr8Planar:
2054 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_I420;
2055 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2057 case kCVPixelFormatType_32BGRA:
2058 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_BGRA;
2059 assert(CVPixelBufferIsPlanar(imageBuffer) == false);
2062 p_dec->p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2065 p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
2066 if (decoder_UpdateVideoFormat(p_dec) != 0)
2068 p_dec->p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2075 pic_holder_on_cvpx_released(CVPixelBufferRef cvpx, void *data, unsigned nb_fields)
2077 struct pic_holder *pic_holder = data;
2079 vlc_mutex_lock(&pic_holder->lock);
2080 assert((int) pic_holder->nb_field_out - nb_fields >= 0);
2081 pic_holder->nb_field_out -= nb_fields;
2082 if (pic_holder->nb_field_out == 0 && pic_holder->closed)
2084 vlc_mutex_unlock(&pic_holder->lock);
2085 pic_holder_clean(pic_holder);
2089 vlc_cond_broadcast(&pic_holder->wait);
2090 vlc_mutex_unlock(&pic_holder->lock);
2095 pic_holder_update_reorder_max(struct pic_holder *pic_holder, uint8_t pic_reorder_max,
2098 vlc_mutex_lock(&pic_holder->lock);
2100 pic_holder->field_reorder_max = pic_reorder_max * (nb_field < 2 ? 2 : nb_field);
2101 vlc_cond_signal(&pic_holder->wait);
2103 vlc_mutex_unlock(&pic_holder->lock);
2106 static int pic_holder_wait(struct pic_holder *pic_holder, const picture_t *pic)
2108 const uint8_t reserved_fields = 2 * (pic->i_nb_fields < 2 ? 2 : pic->i_nb_fields);
2110 vlc_mutex_lock(&pic_holder->lock);
2112 /* Wait 200 ms max. We can't really know what the video output will do with
2113 * output pictures (will they be rendered immediately ?), so don't wait
2114 * infinitely. The output will be paced anyway by the vlc_cond_timedwait()
2116 mtime_t deadline = mdate() + INT64_C(200000);
2118 while (ret == 0 && pic_holder->field_reorder_max != 0
2119 && pic_holder->nb_field_out >= pic_holder->field_reorder_max + reserved_fields)
2120 ret = vlc_cond_timedwait(&pic_holder->wait, &pic_holder->lock, deadline);
2121 pic_holder->nb_field_out += pic->i_nb_fields;
2123 vlc_mutex_unlock(&pic_holder->lock);
2128 static void DecoderCallback(void *decompressionOutputRefCon,
2129 void *sourceFrameRefCon,
2131 VTDecodeInfoFlags infoFlags,
2132 CVPixelBufferRef imageBuffer,
2136 VLC_UNUSED(duration);
2137 decoder_t *p_dec = (decoder_t *)decompressionOutputRefCon;
2138 decoder_sys_t *p_sys = p_dec->p_sys;
2139 frame_info_t *p_info = (frame_info_t *) sourceFrameRefCon;
2141 vlc_mutex_lock(&p_sys->lock);
2142 if (p_sys->b_vt_flush)
2145 enum vtsession_status vtsession_status;
2146 if (HandleVTStatus(p_dec, status, &vtsession_status) != VLC_SUCCESS)
2148 if (p_sys->vtsession_status != VTSESSION_STATUS_ABORT)
2150 p_sys->vtsession_status = vtsession_status;
2151 if (vtsession_status == VTSESSION_STATUS_RESTART)
2152 p_sys->i_restart_count++;
2156 if (unlikely(!imageBuffer))
2158 msg_Err(p_dec, "critical: null imageBuffer with a valid status");
2159 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2163 if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
2166 if (unlikely(!p_sys->b_format_propagated)) {
2167 p_sys->b_format_propagated =
2168 UpdateVideoFormat(p_dec, imageBuffer) == VLC_SUCCESS;
2170 if (!p_sys->b_format_propagated)
2172 assert(p_dec->fmt_out.i_codec != 0);
2175 if (infoFlags & kVTDecodeInfo_FrameDropped)
2177 /* We can't trust VT, some decoded frames can be marked as dropped */
2178 msg_Dbg(p_dec, "decoder dropped frame");
2181 if (!CMTIME_IS_VALID(pts))
2184 if (CVPixelBufferGetDataSize(imageBuffer) == 0)
2189 /* Unlock the mutex because decoder_NewPicture() is blocking. Indeed,
2190 * it can wait indefinitely when the input is paused. */
2192 vlc_mutex_unlock(&p_sys->lock);
2194 picture_t *p_pic = decoder_NewPicture(p_dec);
2197 vlc_mutex_lock(&p_sys->lock);
2201 p_info->p_picture = p_pic;
2203 p_pic->date = pts.value;
2204 p_pic->b_force = p_info->b_forced;
2205 p_pic->b_progressive = p_info->b_progressive;
2206 if(!p_pic->b_progressive)
2208 p_pic->i_nb_fields = p_info->i_num_ts;
2209 p_pic->b_top_field_first = p_info->b_top_field_first;
2212 if (cvpxpic_attach_with_cb(p_pic, imageBuffer, pic_holder_on_cvpx_released,
2213 p_sys->pic_holder) != VLC_SUCCESS)
2215 vlc_mutex_lock(&p_sys->lock);
2219 /* VT is not pacing frame allocation. If we are not fast enough to
2220 * render (release) the output pictures, the VT session can end up
2221 * allocating way too many frames. This can be problematic for 4K
2222 * 10bits. To fix this issue, we ensure that we don't have too many
2223 * output frames allocated by waiting for the vout to release them.
2225 * FIXME: A proper way to fix this issue is to allow decoder modules to
2226 * specify the dpb and having the vout re-allocating output frames when
2227 * this number changes. */
2228 if (pic_holder_wait(p_sys->pic_holder, p_pic))
2229 msg_Warn(p_dec, "pic_holder_wait timed out");
2232 vlc_mutex_lock(&p_sys->lock);
2234 if (p_sys->b_vt_flush)
2236 picture_Release(p_pic);
2240 p_sys->i_restart_count = 0;
2242 OnDecodedFrame( p_dec, p_info );
2248 vlc_mutex_unlock(&p_sys->lock);