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
66 const CFStringRef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFSTR("EnableHardwareAcceleratedVideoDecoder");
67 const CFStringRef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder = CFSTR("RequireHardwareAcceleratedVideoDecoder");
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."
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);
94 #pragma mark - local prototypes
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;
122 picture_t *p_picture;
130 bool b_top_field_first;
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 *,
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 *,
159 /* !Codec specific callbacks */
163 bool b_vt_need_keyframe;
164 VTDecompressionSessionRef session;
165 CMVideoFormatDescriptionRef videoFormatDescription;
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;
180 bool b_cvpx_format_forced;
182 h264_poc_context_t h264_pocctx;
183 hevc_poc_ctx_t hevc_pocctx;
187 struct pic_holder *pic_holder;
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
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)
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)
217 if (i_chroma_format == 1 /* YUV 4:2:0 */)
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 */
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;
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)
253 struct sei_callback_h264_s *s = priv;
254 if(s->p_sps && s->p_sps->vui.b_valid)
256 if(s->p_sps->vui.b_hrd_parameters_present_flag)
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);
262 if(s->p_sps->vui.b_pic_struct_present_flag)
263 s->i_pic_struct = bs_read( p_sei_data->p_bs, 4);
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;
282 const uint8_t *p_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))
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)
296 if(!h264_decode_slice(p_nal, i_nal, GetxPSH264, p_sys, &slice))
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);
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;
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,
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 )
333 date_Change( &p_sys->pts, p_sps->vui.i_time_scale,
334 p_sps->vui.i_num_units_in_tick );
337 if(!p_sys->b_invalid_pic_reorder_max && i_nal_type == H264_NAL_SLICE_IDR)
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,
347 vlc_mutex_unlock(&p_sys->lock);
352 return true; /* No need to parse further NAL */
354 else if(i_nal_type == H264_NAL_SEI)
356 if(i_sei_count < VT_MAX_SEI_COUNT)
358 sei_array[i_sei_count].p_nal = p_nal;
359 sei_array[i_sei_count++].i_nal = i_nal;
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)
398 /* copy DecoderConfiguration */
399 extradata = ExtradataInfoCreate(CFSTR("avcC"),
400 p_dec->fmt_in.p_extra,
401 p_dec->fmt_in.i_extra);
403 else if (p_sys->hh.h264.i_pps_count && p_sys->hh.h264.i_sps_count)
405 /* build DecoderConfiguration from gathered */
406 block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh);
409 extradata = ExtradataInfoCreate(CFSTR("avcC"),
412 block_Release(p_avcC);
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))
427 case PROFILE_H264_BASELINE:
428 case PROFILE_H264_MAIN:
429 case PROFILE_H264_HIGH:
432 case PROFILE_H264_HIGH_10:
434 if (deviceSupportsAdvancedProfiles())
438 msg_Err(p_dec, "current device doesn't support H264 10bits");
445 msg_Warn(p_dec, "unknown H264 profile %" PRIx8, i_profile);
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
453 if (i_level > 52 || (i_level > 42 && !deviceSupportsAdvancedLevels()))
455 msg_Err(p_dec, "current device doesn't support this H264 level: %"
460 HXXXGetBestChroma(p_dec);
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)
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,
486 &full_range) == VLC_SUCCESS)
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;
495 if (!p_dec->fmt_in.video.i_visible_width || !p_dec->fmt_in.video.i_visible_height)
497 unsigned i_width, i_height, i_vis_width, i_vis_height;
499 hxxx_helper_get_current_picture_size(&p_sys->hh,
501 &i_vis_width, &i_vis_height))
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 );
511 if(!p_dec->fmt_in.video.i_sar_num || !p_dec->fmt_in.video.i_sar_den)
513 int i_sar_num, i_sar_den;
515 hxxx_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den))
517 p_dec->fmt_out.video.i_sar_num = i_sar_num;
518 p_dec->fmt_out.video.i_sar_den = i_sar_den;
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;
534 if (hxxx_helper_get_current_picture_size(hh, &w, &h, &vw, &vh) != VLC_SUCCESS)
537 if (hxxx_helper_get_current_sar(hh, &sarn, &sard) != VLC_SUCCESS)
542 CFMutableDictionaryRef decoderConfiguration =
543 CreateSessionDescriptionFormat(p_dec, sarn, sard);
544 if (decoderConfiguration != nil)
546 CMFormatDescriptionRef newvideoFormatDesc;
547 /* create new video format description */
548 OSStatus status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
551 decoderConfiguration,
552 &newvideoFormatDesc);
555 b_ret = !VTDecompressionSessionCanAcceptFormatDescription(session,
557 CFRelease(newvideoFormatDesc);
559 CFRelease(decoderConfiguration);
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;
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;
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;
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)
614 struct hevc_sei_callback_s *s = priv;
616 s->p_timing = hevc_decode_sei_pic_timing(p_sei_data->p_bs, s->p_sps);
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;
633 const uint8_t *p_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))
640 if(i_nal < 2 || hevc_getNALLayer(p_nal) > 0)
643 const enum hevc_nal_unit_type_e i_nal_type = hevc_getNALType(p_nal);
644 if (i_nal_type <= HEVC_NAL_IRAP_VCL23)
646 hevc_slice_segment_header_t *p_sli =
647 hevc_decode_slice_header(p_nal, i_nal, true, GetxPSHEVC, p_sys);
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)
661 if (i_nal_type == HEVC_NAL_RASL_N || i_nal_type == HEVC_NAL_RASL_R)
663 hevc_rbsp_release_slice_header(p_sli);
667 p_sys->b_drop_blocks = false;
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))
674 p_info->b_keyframe |= (slice_type == HEVC_SLICE_TYPE_I);
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);
683 struct hevc_sei_callback_s sei;
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);
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) )
706 if(hevc_get_frame_rate(p_sps, p_vps, &num, &den))
707 date_Change(&p_sys->pts, num, den);
711 hevc_release_sei_pic_timing(sei.p_timing);
713 if(!p_sys->b_invalid_pic_reorder_max && p_vps)
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,
720 vlc_mutex_unlock(&p_sys->lock);
725 hevc_rbsp_release_slice_header(p_sli);
726 return true; /* No need to parse further NAL */
728 else if(i_nal_type == HEVC_NAL_PREF_SEI)
730 if(i_sei_count < VT_MAX_SEI_COUNT)
732 sei_array[i_sei_count].p_nal = p_nal;
733 sei_array[i_sei_count++].i_nal = i_nal;
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)
748 /* copy DecoderConfiguration */
749 extradata = ExtradataInfoCreate(CFSTR("hvcC"),
750 p_dec->fmt_in.p_extra,
751 p_dec->fmt_in.i_extra);
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)
757 /* build DecoderConfiguration from gathered */
758 block_t *p_hvcC = hevc_helper_get_hvcc_config(&p_sys->hh);
761 extradata = ExtradataInfoCreate(CFSTR("hvcC"),
764 block_Release(p_hvcC);
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);
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);
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))
813 if(*pp_lead_in == NULL)
815 else if(p_sys->b_poc_based_reorder)
816 b_insert = ((*pp_lead_in)->i_foc > p_info->i_foc);
818 b_insert = ((*pp_lead_in)->p_picture->date >= p_info->p_picture->date);
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;
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);
835 static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
837 frame_info_t *p_info = p_sys->p_pic_reorder;
841 const int i_framepoc = p_info->i_poc;
843 picture_t *p_ret = NULL;
844 picture_t **pp_ret_last = &p_ret;
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);
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);
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;
870 p_info = p_sys->p_pic_reorder;
874 if (p_sys->b_poc_based_reorder)
875 b_dequeue = (p_info->i_poc == i_framepoc);
877 b_dequeue = (p_field->date == p_info->p_picture->date);
879 else b_dequeue = false;
886 static void DrainDPBLocked(decoder_t *p_dec, bool flush)
888 decoder_sys_t *p_sys = p_dec->p_sys;
891 picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
892 if (p_fields == NULL)
896 picture_t *p_next = p_fields->p_next;
897 p_fields->p_next = NULL;
899 picture_Release(p_fields);
901 decoder_QueueVideo(p_dec, p_fields);
903 } while(p_fields != NULL);
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));
914 if (p_sys->pf_fill_reorder_info)
916 if(!p_sys->pf_fill_reorder_info(p_dec, p_block, p_info))
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;
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);
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))
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)
951 if(p_sys->b_poc_based_reorder && p_sys->p_pic_reorder->i_foc > p_info->i_foc)
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);
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)
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);
973 picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
974 if (p_fields == NULL)
978 picture_t *p_next = p_fields->p_next;
979 p_fields->p_next = NULL;
980 decoder_QueueVideo(p_dec, p_fields);
982 } while(p_fields != NULL);
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) {
995 return kCMVideoCodecType_H264;
998 if (!deviceSupportsHEVC())
1000 msg_Warn(p_dec, "device doesn't support HEVC");
1003 return kCMVideoCodecType_HEVC;
1005 case VLC_CODEC_MP4V:
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");
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;
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;
1038 return kCMVideoCodecType_AppleProRes422;
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;
1058 /* mpgv / mp2v needs fixing, so disable it for now */
1060 case VLC_CODEC_MPGV:
1061 return kCMVideoCodecType_MPEG1Video;
1062 case VLC_CODEC_MP2V:
1063 return kCMVideoCodecType_MPEG2Video;
1068 msg_Err(p_dec, "'%4.4s' is not supported", (char *)&p_dec->fmt_in.i_codec);
1073 vlc_assert_unreachable();
1076 static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
1080 decoder_sys_t *p_sys = p_dec->p_sys;
1082 CFMutableDictionaryRef decoderConfiguration = cfdict_create(0);
1083 if (decoderConfiguration == NULL)
1086 CFMutableDictionaryRef extradata = p_sys->pf_get_extradata
1087 ? p_sys->pf_get_extradata(p_dec) : nil;
1090 /* then decoder will also fail if required, no need to handle it */
1091 CFDictionarySetValue(decoderConfiguration,
1092 kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
1094 CFRelease(extradata);
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)
1107 CFMutableDictionaryRef pixelaspectratio = cfdict_create(2);
1108 if(pixelaspectratio == NULL)
1110 CFRelease(decoderConfiguration);
1114 cfdict_set_int32(pixelaspectratio,
1115 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
1117 cfdict_set_int32(pixelaspectratio,
1118 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
1120 CFDictionarySetValue(decoderConfiguration,
1121 kCVImageBufferPixelAspectRatioKey,
1123 CFRelease(pixelaspectratio);
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)
1132 case COLOR_SPACE_BT601:
1133 yuvmatrix = kCVImageBufferYCbCrMatrix_ITU_R_601_4;
1135 case COLOR_SPACE_BT2020:
1136 yuvmatrix = kCVImageBufferColorPrimaries_ITU_R_2020;
1138 case COLOR_SPACE_BT709:
1140 yuvmatrix = kCVImageBufferColorPrimaries_ITU_R_709_2;
1143 CFDictionarySetValue(decoderConfiguration, kCVImageBufferYCbCrMatrixKey,
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,
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,
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 )
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 );
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;
1187 if(p_sys->pf_late_start && p_sys->pf_late_start(p_dec))
1189 assert(p_sys->session == NULL);
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)
1208 CFRelease(destinationPixelBufferAttributes);
1209 return VLC_EGENERIC;
1212 /* create video format description */
1213 OSStatus status = CMVideoFormatDescriptionCreate(
1214 kCFAllocatorDefault,
1216 p_dec->fmt_out.video.i_visible_width,
1217 p_dec->fmt_out.video.i_visible_height,
1218 decoderConfiguration,
1219 &p_sys->videoFormatDescription);
1222 CFRelease(destinationPixelBufferAttributes);
1223 CFRelease(decoderConfiguration);
1224 msg_Err(p_dec, "video format description creation failed (%i)", (int)status);
1225 return VLC_EGENERIC;
1228 #if !TARGET_OS_IPHONE
1229 CFDictionarySetValue(destinationPixelBufferAttributes,
1230 kCVPixelBufferIOSurfaceOpenGLTextureCompatibilityKey,
1233 CFDictionarySetValue(destinationPixelBufferAttributes,
1234 kCVPixelBufferOpenGLESCompatibilityKey,
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)
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);
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;
1277 static void StopVideoToolbox(decoder_t *p_dec)
1279 decoder_sys_t *p_sys = p_dec->p_sys;
1281 if (p_sys->session != nil)
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
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)
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;
1306 p_sys->b_format_propagated = false;
1307 p_dec->fmt_out.i_codec = 0;
1310 if (p_sys->videoFormatDescription != nil) {
1311 CFRelease(p_sys->videoFormatDescription);
1312 p_sys->videoFormatDescription = nil;
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;
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);
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));
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)
1363 if (strlen(cvpx_chroma) != 4)
1365 msg_Err(p_dec, "invalid videotoolbox-cvpx-chroma option");
1368 return VLC_EGENERIC;
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;
1376 p_sys->pic_holder = malloc(sizeof(struct pic_holder));
1377 if (!p_sys->pic_holder)
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;
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;
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;
1425 case kCMVideoCodecType_MPEG4Video:
1426 p_sys->pf_get_extradata = GetDecoderExtradataMPEG4;
1430 p_sys->pf_get_extradata = GetDecoderExtradataDefault;
1434 if (p_sys->pf_codec_init && !p_sys->pf_codec_init(p_dec))
1436 CloseDecoder(p_this);
1437 return VLC_EGENERIC;
1439 if (p_sys->pf_codec_supported && !p_sys->pf_codec_supported(p_dec))
1441 CloseDecoder(p_this);
1442 return VLC_EGENERIC;
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);
1450 CloseDecoder(p_this);
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);
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)
1476 vlc_mutex_unlock(&p_sys->pic_holder->lock);
1477 pic_holder_clean(p_sys->pic_holder);
1481 p_sys->pic_holder->closed = true;
1482 vlc_mutex_unlock(&p_sys->pic_holder->lock);
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);
1497 static BOOL deviceSupportsAdvancedProfiles()
1499 #if TARGET_OS_IPHONE
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)
1514 static BOOL deviceSupportsAdvancedLevels()
1516 #if TARGET_OS_IPHONE
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) {
1531 /* we need a 64bit SoC for advanced levels */
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,
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;
1558 bool status = bo_init(&bo, 1024);
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);
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)
1608 p_dec->fmt_out.video.i_sar_num = 1;
1609 p_dec->fmt_out.video.i_sar_den = 1;
1612 if (!p_dec->fmt_out.video.i_visible_width || !p_dec->fmt_out.video.i_visible_height)
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;
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 );
1624 static CFMutableDictionaryRef ExtradataInfoCreate(CFStringRef name,
1625 void *p_data, size_t i_data)
1627 CFMutableDictionaryRef extradataInfo = cfdict_create(1);
1628 if (extradataInfo == nil)
1634 CFDataRef extradata = CFDataCreate(kCFAllocatorDefault, p_data, i_data);
1635 if (extradata == nil)
1637 CFRelease(extradataInfo);
1640 CFDictionarySetValue(extradataInfo, name, extradata);
1641 CFRelease(extradata);
1642 return extradataInfo;
1645 static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec,
1646 CMFormatDescriptionRef fmt_desc,
1649 decoder_sys_t *p_sys = p_dec->p_sys;
1651 CMBlockBufferRef block_buf = NULL;
1652 CMSampleBufferRef sample_buf = NULL;
1654 if(!p_sys->b_poc_based_reorder && p_block->i_pts == VLC_TICK_INVALID)
1655 pts = CMTimeMake(p_block->i_dts, CLOCK_FREQ);
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),
1665 status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
1666 p_block->p_buffer, // memoryBlock
1667 p_block->i_buffer, // blockLength
1668 kCFAllocatorNull, // blockAllocator
1669 NULL, // customBlockSource
1671 p_block->i_buffer, // dataLength
1676 status = CMSampleBufferCreate(kCFAllocatorDefault, // allocator
1677 block_buf, // dataBuffer
1679 0, // makeDataReadyCallback
1680 0, // makeDataReadyRefcon
1681 fmt_desc, // formatDescription
1683 1, // numSampleTimingEntries
1684 timeInfoArray, // sampleTimingArray
1685 0, // numSampleSizeEntries
1686 NULL, // sampleSizeArray
1688 if (status != noErr)
1689 msg_Warn(p_dec, "sample buffer creation failure %i", (int)status);
1691 msg_Warn(p_dec, "cm block buffer creation failure %i", (int)status);
1693 if (block_buf != nil)
1694 CFRelease(block_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;
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)
1743 msg_Warn(p_dec, "vt session error: "
1744 "'kVTColorCorrectionImageRotationFailedErr'");
1747 msg_Warn(p_dec, "unknown vt session error (%i)", (int)status);
1751 if (p_vtsession_status)
1755 case kVTPixelTransferNotSupportedErr:
1756 case kVTPixelTransferNotPermittedErr:
1757 *p_vtsession_status = VTSESSION_STATUS_RESTART_CHROMA;
1759 case -8960 /* codecErr */:
1760 case kVTVideoDecoderMalfunctionErr:
1761 case kVTInvalidSessionErr:
1762 *p_vtsession_status = VTSESSION_STATUS_RESTART;
1764 case -8969 /* codecBadDataErr */:
1765 case kVTVideoDecoderBadDataErr:
1767 *p_vtsession_status = VTSESSION_STATUS_ABORT;
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)
1816 if (p_block == NULL)
1818 Drain(p_dec, false);
1819 return VLCDEC_SUCCESS;
1822 vlc_mutex_lock(&p_sys->lock);
1824 if (p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK)
1826 #if TARGET_OS_IPHONE
1827 msg_Warn(p_dec, "VT decoder doesn't handle deinterlacing on iOS, "
1829 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1831 if (!p_sys->b_cvpx_format_forced
1832 && p_sys->i_cvpx_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)
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)
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);
1855 if (p_sys->vtsession_status == VTSESSION_STATUS_RESTART ||
1856 p_sys->vtsession_status == VTSESSION_STATUS_RESTART_CHROMA)
1859 if (p_sys->vtsession_status == VTSESSION_STATUS_RESTART_CHROMA)
1861 if (p_sys->i_cvpx_format == 0 && p_sys->b_cvpx_format_forced)
1863 /* Already tried to fallback to the original chroma, aborting... */
1868 p_sys->i_cvpx_format = 0;
1869 p_sys->b_cvpx_format_forced = true;
1874 do_restart = p_sys->i_restart_count <= VT_RESTART_MAX;
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;
1889 msg_Warn(p_dec, "too many vt failure...");
1890 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
1894 if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
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
1901 var_Create(p_dec, "videotoolbox-failed", VLC_VAR_VOID);
1902 return VLCDEC_RELOAD;
1904 vlc_mutex_unlock(&p_sys->lock);
1906 if (unlikely(p_block->i_flags&(BLOCK_FLAG_CORRUPTED)))
1908 if (p_sys->b_vt_feed)
1910 Drain(p_dec, false);
1916 bool b_config_changed = false;
1917 if(p_sys->pf_process_block)
1919 p_block = p_sys->pf_process_block(p_dec, p_block, &b_config_changed);
1921 return VLCDEC_SUCCESS;
1924 frame_info_t *p_info = CreateReorderInfo(p_dec, p_block);
1925 if(unlikely(!p_info))
1928 if (!p_sys->session /* Late Start */||
1929 (b_config_changed && p_info->b_flush))
1931 if (p_sys->session &&
1932 p_sys->pf_need_restart &&
1933 p_sys->pf_need_restart(p_dec,p_sys->session))
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);
1943 if ((p_sys->pf_codec_supported && !p_sys->pf_codec_supported(p_dec))
1944 || StartVideoToolbox(p_dec) != VLC_SUCCESS)
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);
1953 if (!p_sys->session) /* Start Failed */
1960 if (!p_sys->b_vt_feed && p_sys->b_vt_need_keyframe && !p_info->b_keyframe)
1966 CMSampleBufferRef sampleBuffer =
1967 VTSampleBufferCreate(p_dec, p_sys->videoFormatDescription, p_block);
1968 if (unlikely(!sampleBuffer))
1974 VTDecodeInfoFlags flagOut;
1975 VTDecodeFrameFlags decoderFlags = kVTDecodeFrame_EnableAsynchronousDecompression;
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)
1984 p_sys->b_vt_feed = true;
1985 if( p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE )
1986 Drain( p_dec, false );
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);
1998 CFRelease(sampleBuffer);
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)
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;
2026 if (p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF)
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;
2038 uint32_t cvfmt = CVPixelBufferGetPixelFormatType(imageBuffer);
2039 msg_Info(p_dec, "vt cvpx chroma: %4.4s",
2040 (const char *)&(uint32_t) { htonl(cvfmt) });
2043 case kCVPixelFormatType_422YpCbCr8:
2045 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_UYVY;
2046 assert(CVPixelBufferIsPlanar(imageBuffer) == false);
2048 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
2049 case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
2050 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_NV12;
2051 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
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);
2058 case kCVPixelFormatType_420YpCbCr8Planar:
2059 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_I420;
2060 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
2062 case kCVPixelFormatType_32BGRA:
2063 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_BGRA;
2064 assert(CVPixelBufferIsPlanar(imageBuffer) == false);
2067 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2070 p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
2071 if (decoder_UpdateVideoFormat(p_dec) != 0)
2073 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
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)
2089 vlc_mutex_unlock(&pic_holder->lock);
2090 pic_holder_clean(pic_holder);
2094 vlc_cond_broadcast(&pic_holder->wait);
2095 vlc_mutex_unlock(&pic_holder->lock);
2100 pic_holder_update_reorder_max(struct pic_holder *pic_holder, uint8_t pic_reorder_max,
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()
2121 vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_MS(200);
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);
2133 static void DecoderCallback(void *decompressionOutputRefCon,
2134 void *sourceFrameRefCon,
2136 VTDecodeInfoFlags infoFlags,
2137 CVPixelBufferRef imageBuffer,
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)
2150 enum vtsession_status vtsession_status;
2151 if (HandleVTStatus(p_dec, status, &vtsession_status) != VLC_SUCCESS)
2153 if (p_sys->vtsession_status != VTSESSION_STATUS_ABORT)
2155 p_sys->vtsession_status = vtsession_status;
2156 if (vtsession_status == VTSESSION_STATUS_RESTART)
2157 p_sys->i_restart_count++;
2161 if (unlikely(!imageBuffer))
2163 msg_Err(p_dec, "critical: null imageBuffer with a valid status");
2164 p_sys->vtsession_status = VTSESSION_STATUS_ABORT;
2168 if (p_sys->vtsession_status == VTSESSION_STATUS_ABORT)
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)
2177 assert(p_dec->fmt_out.i_codec != 0);
2180 if (infoFlags & kVTDecodeInfo_FrameDropped)
2182 /* We can't trust VT, some decoded frames can be marked as dropped */
2183 msg_Dbg(p_dec, "decoder dropped frame");
2186 if (!CMTIME_IS_VALID(pts))
2189 if (CVPixelBufferGetDataSize(imageBuffer) == 0)
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);
2202 vlc_mutex_lock(&p_sys->lock);
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)
2214 p_pic->i_nb_fields = p_info->i_num_ts;
2215 p_pic->b_top_field_first = p_info->b_top_field_first;
2218 if (cvpxpic_attach_with_cb(p_pic, imageBuffer, pic_holder_on_cvpx_released,
2219 p_sys->pic_holder) != VLC_SUCCESS)
2221 vlc_mutex_lock(&p_sys->lock);
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.
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)
2242 picture_Release(p_pic);
2246 p_sys->i_restart_count = 0;
2248 OnDecodedFrame( p_dec, p_info );
2254 vlc_mutex_unlock(&p_sys->lock);