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"
35 #import "../packetizer/h264_nal.h"
36 #import "../packetizer/h264_slice.h"
37 #import "../packetizer/hxxx_nal.h"
38 #import "../packetizer/hxxx_sei.h"
39 #import "../video_chroma/copy.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>
52 #import <UIKit/UIKit.h>
54 /* support iOS SDKs < v9.1 */
55 #ifndef CPUFAMILY_ARM_TWISTER
56 #define CPUFAMILY_ARM_TWISTER 0x92fb37c8
61 #pragma mark - module descriptor
63 static int OpenDecoder(vlc_object_t *);
64 static void CloseDecoder(vlc_object_t *);
66 #if MAC_OS_X_VERSION_MIN_ALLOWED < 1090
67 const CFStringRef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFSTR("EnableHardwareAcceleratedVideoDecoder");
68 const CFStringRef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder = CFSTR("RequireHardwareAcceleratedVideoDecoder");
71 #define VT_REQUIRE_HW_DEC N_("Use Hardware decoders only")
72 #define VT_TEMPO_DEINTERLACE N_("Deinterlacing")
73 #define VT_TEMPO_DEINTERLACE_LONG N_("If interlaced content is detected, temporal deinterlacing is enabled at the expense of a pipeline delay.")
76 set_category(CAT_INPUT)
77 set_subcategory(SUBCAT_INPUT_VCODEC)
78 set_description(N_("VideoToolbox video decoder"))
79 set_capability("decoder",800)
80 set_callbacks(OpenDecoder, CloseDecoder)
82 add_bool("videotoolbox-temporal-deinterlacing", true, VT_TEMPO_DEINTERLACE, VT_TEMPO_DEINTERLACE_LONG, false)
83 add_bool("videotoolbox-hw-decoder-only", false, VT_REQUIRE_HW_DEC, VT_REQUIRE_HW_DEC, false)
86 #pragma mark - local prototypes
88 static int ESDSCreate(decoder_t *, uint8_t *, uint32_t);
89 static int avcCFromAnnexBCreate(decoder_t *);
90 static int ExtradataInfoCreate(decoder_t *, CFStringRef, void *, size_t);
91 static int HandleVTStatus(decoder_t *, OSStatus);
92 static int DecodeBlock(decoder_t *, block_t *);
93 static void Flush(decoder_t *);
94 static void DecoderCallback(void *, void *, OSStatus, VTDecodeInfoFlags,
95 CVPixelBufferRef, CMTime, CMTime);
96 void VTDictionarySetInt32(CFMutableDictionaryRef, CFStringRef, int);
97 static void copy420YpCbCr8Planar(picture_t *, CVPixelBufferRef buffer,
98 unsigned i_width, unsigned i_height);
99 static BOOL deviceSupportsAdvancedProfiles();
100 static BOOL deviceSupportsAdvancedLevels();
102 struct picture_sys_t {
103 CFTypeRef pixelBuffer;
106 typedef struct frame_info_t frame_info_t;
110 picture_t *p_picture;
118 frame_info_t *p_next;
121 #pragma mark - decoder structure
123 #define H264_MAX_DPB 16
127 CMVideoCodecType codec;
128 struct hxxx_helper hh;
132 VTDecompressionSessionRef session;
133 CMVideoFormatDescriptionRef videoFormatDescription;
134 CFMutableDictionaryRef decoderConfiguration;
135 CFMutableDictionaryRef destinationPixelBufferAttributes;
136 CFMutableDictionaryRef extradataInfo;
139 frame_info_t *p_pic_reorder;
140 uint8_t i_pic_reorder;
141 uint8_t i_pic_reorder_max;
142 bool b_poc_based_reorder;
143 bool b_enable_temporal_processing;
145 bool b_format_propagated;
148 poc_context_t pocctx;
152 #pragma mark - start & stop
154 static void GetSPSPPS(uint8_t i_pps_id, void *priv,
155 const h264_sequence_parameter_set_t **pp_sps,
156 const h264_picture_parameter_set_t **pp_pps)
158 decoder_sys_t *p_sys = priv;
160 *pp_pps = p_sys->hh.h264.pps_list[i_pps_id].h264_pps;
164 *pp_sps = p_sys->hh.h264.sps_list[(*pp_pps)->i_sps_id].h264_sps;
167 struct sei_callback_s
169 uint8_t i_pic_struct;
170 const h264_sequence_parameter_set_t *p_sps;
173 static bool ParseH264SEI(const hxxx_sei_data_t *p_sei_data, void *priv)
176 if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
178 struct sei_callback_s *s = priv;
179 if(s->p_sps && s->p_sps->vui.b_valid)
181 if(s->p_sps->vui.b_hrd_parameters_present_flag)
183 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_cpb_removal_delay_length_minus1 + 1);
184 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_dpb_output_delay_length_minus1 + 1);
187 if(s->p_sps->vui.b_pic_struct_present_flag)
188 s->i_pic_struct = bs_read( p_sei_data->p_bs, 4);
196 static bool ParseH264NAL(decoder_sys_t *p_sys,
197 const uint8_t *p_buffer, size_t i_buffer,
198 uint8_t i_nal_length_size, frame_info_t *p_info)
200 hxxx_iterator_ctx_t itctx;
201 hxxx_iterator_init(&itctx, p_buffer, i_buffer, i_nal_length_size);
203 const uint8_t *p_nal; size_t i_nal;
204 const uint8_t *p_sei_nal = NULL; size_t i_sei_nal = 0;
205 while(hxxx_iterate_next(&itctx, &p_nal, &i_nal))
210 const enum h264_nal_unit_type_e i_nal_type = p_nal[0] & 0x1F;
212 if (i_nal_type <= H264_NAL_SLICE_IDR && i_nal_type != H264_NAL_UNKNOWN)
215 if(!h264_decode_slice(p_nal, i_nal, GetSPSPPS, p_sys, &slice))
218 const h264_sequence_parameter_set_t *p_sps;
219 const h264_picture_parameter_set_t *p_pps;
220 GetSPSPPS(slice.i_pic_parameter_set_id, p_sys, &p_sps, &p_pps);
225 h264_get_dpb_values(p_sps, &i_reorder, &dummy);
226 vlc_mutex_lock(&p_sys->lock);
227 p_sys->i_pic_reorder_max = i_reorder;
228 vlc_mutex_unlock(&p_sys->lock);
231 h264_compute_poc(p_sps, &slice, &p_sys->pocctx,
232 &p_info->i_poc, &p_info->i_foc, &bFOC);
234 p_info->b_flush = (slice.type == H264_SLICE_TYPE_I) || slice.has_mmco5;
235 p_info->b_field = slice.i_field_pic_flag;
236 p_info->b_progressive = !p_sps->mb_adaptive_frame_field_flag &&
237 !slice.i_field_pic_flag;
239 struct sei_callback_s sei;
241 sei.i_pic_struct = UINT8_MAX;
244 HxxxParseSEI(p_sei_nal, i_sei_nal, 1, ParseH264SEI, &sei);
246 p_info->i_num_ts = h264_get_num_ts(p_sps, &slice, sei.i_pic_struct,
247 p_info->i_foc, bFOC);
250 return true; /* No need to parse further NAL */
252 else if(i_nal_type == H264_NAL_SEI)
262 static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
264 frame_info_t **pp_lead_in = &p_sys->p_pic_reorder;
266 for( ;; pp_lead_in = & ((*pp_lead_in)->p_next))
269 if(*pp_lead_in == NULL)
271 else if(p_sys->b_poc_based_reorder)
272 b_insert = ((*pp_lead_in)->i_foc > p_info->i_foc);
274 b_insert = ((*pp_lead_in)->p_picture->date >= p_info->p_picture->date);
278 p_info->p_next = *pp_lead_in;
279 *pp_lead_in = p_info;
280 p_sys->i_pic_reorder += (p_info->b_field) ? 1 : 2;
285 for(frame_info_t *p_in=p_sys->p_pic_reorder; p_in; p_in = p_in->p_next)
286 printf(" %d", p_in->i_foc);
291 static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
293 frame_info_t *p_info = p_sys->p_pic_reorder;
297 const int i_framepoc = p_info->i_poc;
299 picture_t *p_ret = NULL;
300 picture_t **pp_ret_last = &p_ret;
305 picture_t *p_field = p_info->p_picture;
307 /* Compute time if missing */
308 if (p_field->date == VLC_TS_INVALID)
309 p_field->date = date_Get(&p_sys->pts);
311 date_Set(&p_sys->pts, p_field->date);
313 /* Set next picture time, in case it is missing */
314 if (p_info->i_length)
315 date_Set(&p_sys->pts, p_field->date + p_info->i_length);
317 date_Increment(&p_sys->pts, p_info->i_num_ts);
319 *pp_ret_last = p_field;
320 pp_ret_last = &p_field->p_next;
322 p_sys->i_pic_reorder -= (p_info->b_field) ? 1 : 2;
324 p_sys->p_pic_reorder = p_info->p_next;
326 p_info = p_sys->p_pic_reorder;
330 if (p_sys->b_poc_based_reorder)
331 b_dequeue = (p_info->i_poc == i_framepoc);
333 b_dequeue = (p_field->date == p_info->p_picture->date);
335 else b_dequeue = false;
342 static void FlushDPB(decoder_t *p_dec)
344 decoder_sys_t *p_sys = p_dec->p_sys;
347 picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
348 if (p_fields == NULL)
352 picture_t *p_next = p_fields->p_next;
353 p_fields->p_next = NULL;
354 decoder_QueueVideo(p_dec, p_fields);
356 } while(p_fields != NULL);
360 static frame_info_t * CreateReorderInfo(decoder_sys_t *p_sys, const block_t *p_block)
362 frame_info_t *p_info = calloc(1, sizeof(*p_info));
366 if (p_sys->b_poc_based_reorder)
368 if(p_sys->codec != kCMVideoCodecType_H264 ||
369 !ParseH264NAL(p_sys, p_block->p_buffer, p_block->i_buffer, 4, p_info))
371 assert(p_sys->codec == kCMVideoCodecType_H264);
378 p_info->i_num_ts = 2;
379 p_info->b_progressive = true;
380 p_info->b_field = false;
383 p_info->i_length = p_block->i_length;
385 if (date_Get(&p_sys->pts) == VLC_TS_INVALID)
386 date_Set(&p_sys->pts, p_block->i_dts);
391 static void OnDecodedFrame(decoder_t *p_dec, frame_info_t *p_info)
393 decoder_sys_t *p_sys = p_dec->p_sys;
394 assert(p_info->p_picture);
395 while(p_info->b_flush || p_sys->i_pic_reorder == (p_sys->i_pic_reorder_max * 2))
397 picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
398 if (p_fields == NULL)
402 picture_t *p_next = p_fields->p_next;
403 p_fields->p_next = NULL;
404 decoder_QueueVideo(p_dec, p_fields);
406 } while(p_fields != NULL);
409 InsertIntoDPB(p_sys, p_info);
412 static CMVideoCodecType CodecPrecheck(decoder_t *p_dec)
414 uint8_t i_profile = 0xFF, i_level = 0xFF;
416 CMVideoCodecType codec;
418 /* check for the codec we can and want to decode */
419 switch (p_dec->fmt_in.i_codec) {
421 codec = kCMVideoCodecType_H264;
423 b_ret = h264_get_profile_level(&p_dec->fmt_in, &i_profile, &i_level, NULL);
425 msg_Warn(p_dec, "H264 profile and level parsing failed because it didn't arrive yet");
426 return kCMVideoCodecType_H264;
429 msg_Dbg(p_dec, "trying to decode MPEG-4 Part 10: profile %" PRIx8 ", level %" PRIx8, i_profile, i_level);
432 case PROFILE_H264_BASELINE:
433 case PROFILE_H264_MAIN:
434 case PROFILE_H264_HIGH:
437 case PROFILE_H264_HIGH_10:
439 if (deviceSupportsAdvancedProfiles())
445 msg_Dbg(p_dec, "unsupported H264 profile %" PRIx8, i_profile);
450 #if !TARGET_OS_IPHONE
451 /* a level higher than 5.2 was not tested, so don't dare to
454 msg_Dbg(p_dec, "unsupported H264 level %" PRIx8, i_level);
458 /* on SoC A8, 4.2 is the highest specified profile */
460 /* on Twister, we can do up to 5.2 */
461 if (!deviceSupportsAdvancedLevels() || i_level > 52) {
462 msg_Dbg(p_dec, "unsupported H264 level %" PRIx8, i_level);
471 if (p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'X','V','I','D' )) {
472 msg_Warn(p_dec, "XVID decoding not implemented, fallback on software");
476 msg_Dbg(p_dec, "Will decode MP4V with original FourCC '%4.4s'", (char *)&p_dec->fmt_in.i_original_fourcc);
477 codec = kCMVideoCodecType_MPEG4Video;
481 #if !TARGET_OS_IPHONE
483 codec = kCMVideoCodecType_H263;
486 /* there are no DV or ProRes decoders on iOS, so bailout early */
487 case VLC_CODEC_PRORES:
488 /* the VT decoder can't differenciate between the ProRes flavors, so we do it */
489 switch (p_dec->fmt_in.i_original_fourcc) {
490 case VLC_FOURCC( 'a','p','4','c' ):
491 case VLC_FOURCC( 'a','p','4','h' ):
492 codec = kCMVideoCodecType_AppleProRes4444;
495 case VLC_FOURCC( 'a','p','c','h' ):
496 codec = kCMVideoCodecType_AppleProRes422HQ;
499 case VLC_FOURCC( 'a','p','c','s' ):
500 codec = kCMVideoCodecType_AppleProRes422LT;
503 case VLC_FOURCC( 'a','p','c','o' ):
504 codec = kCMVideoCodecType_AppleProRes422Proxy;
508 codec = kCMVideoCodecType_AppleProRes422;
515 /* the VT decoder can't differenciate between PAL and NTSC, so we need to do it */
516 switch (p_dec->fmt_in.i_original_fourcc) {
517 case VLC_FOURCC( 'd', 'v', 'c', ' '):
518 case VLC_FOURCC( 'd', 'v', ' ', ' '):
519 msg_Dbg(p_dec, "Decoding DV NTSC");
520 codec = kCMVideoCodecType_DVCNTSC;
523 case VLC_FOURCC( 'd', 'v', 's', 'd'):
524 case VLC_FOURCC( 'd', 'v', 'c', 'p'):
525 case VLC_FOURCC( 'D', 'V', 'S', 'D'):
526 msg_Dbg(p_dec, "Decoding DV PAL");
527 codec = kCMVideoCodecType_DVCPAL;
536 /* mpgv / mp2v needs fixing, so disable it for now */
539 codec = kCMVideoCodecType_MPEG1Video;
542 codec = kCMVideoCodecType_MPEG2Video;
548 msg_Err(p_dec, "'%4.4s' is not supported", (char *)&p_dec->fmt_in.i_codec);
556 static int StartVideoToolbox(decoder_t *p_dec)
558 decoder_sys_t *p_sys = p_dec->p_sys;
561 assert(p_sys->extradataInfo != nil);
563 p_sys->decoderConfiguration =
564 CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
565 &kCFTypeDictionaryKeyCallBacks,
566 &kCFTypeDictionaryValueCallBacks);
567 if (p_sys->decoderConfiguration == NULL)
570 CFDictionarySetValue(p_sys->decoderConfiguration,
571 kCVImageBufferChromaLocationBottomFieldKey,
572 kCVImageBufferChromaLocation_Left);
573 CFDictionarySetValue(p_sys->decoderConfiguration,
574 kCVImageBufferChromaLocationTopFieldKey,
575 kCVImageBufferChromaLocation_Left);
577 CFDictionarySetValue(p_sys->decoderConfiguration,
578 kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
579 p_sys->extradataInfo);
581 /* pixel aspect ratio */
582 CFMutableDictionaryRef pixelaspectratio =
583 CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
584 &kCFTypeDictionaryKeyCallBacks,
585 &kCFTypeDictionaryValueCallBacks);
587 const unsigned i_video_width = p_dec->fmt_out.video.i_width;
588 const unsigned i_video_height = p_dec->fmt_out.video.i_height;
589 const unsigned i_sar_num = p_dec->fmt_out.video.i_sar_num;
590 const unsigned i_sar_den = p_dec->fmt_out.video.i_sar_den;
593 date_Init( &p_sys->pts, p_dec->fmt_in.video.i_frame_rate * 2, p_dec->fmt_in.video.i_frame_rate_base );
595 VTDictionarySetInt32(pixelaspectratio,
596 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
598 VTDictionarySetInt32(pixelaspectratio,
599 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
601 CFDictionarySetValue(p_sys->decoderConfiguration,
602 kCVImageBufferPixelAspectRatioKey,
604 CFRelease(pixelaspectratio);
606 /* enable HW accelerated playback, since this is optional on OS X
607 * note that the backend may still fallback on software mode if no
608 * suitable hardware is available */
609 CFDictionarySetValue(p_sys->decoderConfiguration,
610 kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
613 /* on OS X, we can force VT to fail if no suitable HW decoder is available,
614 * preventing the aforementioned SW fallback */
615 if (var_InheritInteger(p_dec, "videotoolbox-hw-decoder-only"))
616 CFDictionarySetValue(p_sys->decoderConfiguration,
617 kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder,
620 if (p_sys->b_enable_temporal_processing)
622 msg_Dbg(p_dec, "Interlaced content detected, inserting temporal deinterlacer");
623 CFDictionarySetValue(p_sys->decoderConfiguration,
624 kVTDecompressionPropertyKey_FieldMode,
625 kVTDecompressionProperty_FieldMode_DeinterlaceFields);
626 CFDictionarySetValue(p_sys->decoderConfiguration,
627 kVTDecompressionPropertyKey_DeinterlaceMode,
628 kVTDecompressionProperty_DeinterlaceMode_Temporal);
631 /* create video format description */
632 status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
636 p_sys->decoderConfiguration,
637 &p_sys->videoFormatDescription);
639 CFRelease(p_sys->decoderConfiguration);
640 msg_Err(p_dec, "video format description creation failed (%i)", (int)status);
644 /* destination pixel buffer attributes */
645 p_sys->destinationPixelBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
647 &kCFTypeDictionaryKeyCallBacks,
648 &kCFTypeDictionaryValueCallBacks);
650 #if !TARGET_OS_IPHONE
651 CFDictionarySetValue(p_sys->destinationPixelBufferAttributes,
652 kCVPixelBufferIOSurfaceOpenGLTextureCompatibilityKey,
655 CFDictionarySetValue(p_sys->destinationPixelBufferAttributes,
656 kCVPixelBufferOpenGLESCompatibilityKey,
660 VTDictionarySetInt32(p_sys->destinationPixelBufferAttributes,
661 kCVPixelBufferWidthKey,
663 VTDictionarySetInt32(p_sys->destinationPixelBufferAttributes,
664 kCVPixelBufferHeightKey,
666 VTDictionarySetInt32(p_sys->destinationPixelBufferAttributes,
667 kCVPixelBufferBytesPerRowAlignmentKey,
670 /* setup decoder callback record */
671 VTDecompressionOutputCallbackRecord decoderCallbackRecord;
672 decoderCallbackRecord.decompressionOutputCallback = DecoderCallback;
673 decoderCallbackRecord.decompressionOutputRefCon = p_dec;
675 /* create decompression session */
676 status = VTDecompressionSessionCreate(kCFAllocatorDefault,
677 p_sys->videoFormatDescription,
678 p_sys->decoderConfiguration,
679 p_sys->destinationPixelBufferAttributes,
680 &decoderCallbackRecord, &p_sys->session);
682 if (HandleVTStatus(p_dec, status) != VLC_SUCCESS)
688 static void StopVideoToolbox(decoder_t *p_dec, bool b_reset_format)
690 decoder_sys_t *p_sys = p_dec->p_sys;
692 if (p_sys->session != nil)
694 VTDecompressionSessionInvalidate(p_sys->session);
695 CFRelease(p_sys->session);
696 p_sys->session = nil;
700 p_sys->b_format_propagated = false;
701 p_dec->fmt_out.i_codec = 0;
706 if (p_sys->videoFormatDescription != nil) {
707 CFRelease(p_sys->videoFormatDescription);
708 p_sys->videoFormatDescription = nil;
710 if (p_sys->decoderConfiguration != nil) {
711 CFRelease(p_sys->decoderConfiguration);
712 p_sys->decoderConfiguration = nil;
714 if (p_sys->destinationPixelBufferAttributes != nil) {
715 CFRelease(p_sys->destinationPixelBufferAttributes);
716 p_sys->destinationPixelBufferAttributes = nil;
720 static int RestartVideoToolbox(decoder_t *p_dec, bool b_reset_format)
722 decoder_sys_t *p_sys = p_dec->p_sys;
724 msg_Dbg(p_dec, "Restarting decoder session");
726 if (p_sys->session != nil)
727 StopVideoToolbox(p_dec, b_reset_format);
729 return StartVideoToolbox(p_dec);
732 #pragma mark - module open and close
734 static int SetupDecoderExtradata(decoder_t *p_dec)
736 decoder_sys_t *p_sys = p_dec->p_sys;
737 CFMutableDictionaryRef extradata_info = NULL;
739 if (p_sys->codec == kCMVideoCodecType_H264)
741 hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
742 p_dec->fmt_in.i_codec, true);
743 int i_ret = hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
744 p_dec->fmt_in.i_extra);
745 if (i_ret != VLC_SUCCESS)
748 if (p_dec->fmt_in.p_extra)
750 int i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"),
751 p_dec->fmt_in.p_extra,
752 p_dec->fmt_in.i_extra);
753 if (i_ret != VLC_SUCCESS)
756 /* else: AnnexB case, we'll get extradata from first input blocks */
758 else if (p_sys->codec == kCMVideoCodecType_MPEG4Video)
760 if (!p_dec->fmt_in.i_extra)
762 int i_ret = ESDSCreate(p_dec, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra);
763 if (i_ret != VLC_SUCCESS)
768 int i_ret = ExtradataInfoCreate(p_dec, NULL, NULL, 0);
769 if (i_ret != VLC_SUCCESS)
776 static int OpenDecoder(vlc_object_t *p_this)
778 decoder_t *p_dec = (decoder_t *)p_this;
781 if (unlikely([[UIDevice currentDevice].systemVersion floatValue] < 8.0)) {
782 msg_Warn(p_dec, "decoder skipped as OS is too old");
787 if (p_dec->fmt_in.i_cat != VIDEO_ES)
790 /* Fail if this module already failed to decode this ES */
791 if (var_Type(p_dec, "videotoolbox-failed") != 0)
794 /* check quickly if we can digest the offered data */
795 CMVideoCodecType codec;
796 codec = CodecPrecheck(p_dec);
800 /* now that we see a chance to decode anything, allocate the
801 * internals and start the decoding session */
802 decoder_sys_t *p_sys;
803 p_sys = malloc(sizeof(*p_sys));
806 p_dec->p_sys = p_sys;
807 p_sys->session = nil;
808 p_sys->b_vt_feed = false;
809 p_sys->b_vt_flush = false;
810 p_sys->codec = codec;
811 p_sys->videoFormatDescription = nil;
812 p_sys->decoderConfiguration = nil;
813 p_sys->destinationPixelBufferAttributes = nil;
814 p_sys->extradataInfo = nil;
815 p_sys->p_pic_reorder = NULL;
816 p_sys->i_pic_reorder = 0;
817 p_sys->i_pic_reorder_max = 4;
818 p_sys->b_poc_based_reorder = false;
819 p_sys->b_format_propagated = false;
820 p_sys->b_abort = false;
821 p_sys->b_enable_temporal_processing = false;
822 h264_poc_context_init( &p_sys->pocctx );
823 vlc_mutex_init(&p_sys->lock);
825 /* return our proper VLC internal state */
826 p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
827 p_dec->fmt_out.video = p_dec->fmt_in.video;
828 if (!p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den)
830 p_dec->fmt_out.video.i_sar_num = 1;
831 p_dec->fmt_out.video.i_sar_den = 1;
833 if (!p_dec->fmt_out.video.i_visible_width
834 || !p_dec->fmt_out.video.i_visible_height)
836 p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width;
837 p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height;
841 p_dec->fmt_out.video.i_width = p_dec->fmt_out.video.i_visible_width;
842 p_dec->fmt_out.video.i_height = p_dec->fmt_out.video.i_visible_height;
845 p_dec->fmt_out.i_codec = 0;
847 if( codec == kCMVideoCodecType_H264 )
848 p_sys->b_poc_based_reorder = true;
850 int i_ret = SetupDecoderExtradata(p_dec);
851 if (i_ret != VLC_SUCCESS)
854 if (p_sys->extradataInfo != nil)
856 i_ret = StartVideoToolbox(p_dec);
857 if (i_ret != VLC_SUCCESS)
859 } /* else: late opening */
861 p_dec->pf_decode = DecodeBlock;
862 p_dec->pf_flush = Flush;
864 msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'", (char *)&p_dec->fmt_in.i_codec);
869 CloseDecoder(p_this);
873 static void CloseDecoder(vlc_object_t *p_this)
875 decoder_t *p_dec = (decoder_t *)p_this;
876 decoder_sys_t *p_sys = p_dec->p_sys;
878 StopVideoToolbox(p_dec, true);
880 if (p_sys->codec == kCMVideoCodecType_H264)
881 hxxx_helper_clean(&p_sys->hh);
883 vlc_mutex_destroy(&p_sys->lock);
887 #pragma mark - helpers
889 static BOOL deviceSupportsAdvancedProfiles()
891 #if TARGET_IPHONE_SIMULATOR
899 sysctlbyname("hw.cputype", &type, &size, NULL, 0);
901 /* Support for H264 profile HIGH 10 was introduced with the first 64bit Apple ARM SoC, the A7 */
902 if (type == CPU_TYPE_ARM64)
911 static BOOL deviceSupportsAdvancedLevels()
913 #if TARGET_IPHONE_SIMULATOR
920 size = sizeof(cpufamily);
921 sysctlbyname("hw.cpufamily", &cpufamily, &size, NULL, 0);
923 /* Proper 4K decoding requires a Twister SoC
924 * Everything below will kill the decoder daemon */
925 if (cpufamily == CPUFAMILY_ARM_TWISTER) {
935 static inline void bo_add_mp4_tag_descr(bo_t *p_bo, uint8_t tag, uint32_t size)
938 for (int i = 3; i>0; i--)
939 bo_add_8(p_bo, (size>>(7*i)) | 0x80);
940 bo_add_8(p_bo, size & 0x7F);
943 static int ESDSCreate(decoder_t *p_dec, uint8_t *p_buf, uint32_t i_buf_size)
945 int full_size = 3 + 5 +13 + 5 + i_buf_size + 3;
946 int config_size = 13 + 5 + i_buf_size;
950 bool status = bo_init(&bo, 1024);
954 bo_add_8(&bo, 0); // Version
955 bo_add_24be(&bo, 0); // Flags
957 // elementary stream description tag
958 bo_add_mp4_tag_descr(&bo, 0x03, full_size);
959 bo_add_16be(&bo, 0); // esid
960 bo_add_8(&bo, 0); // stream priority (0-3)
962 // decoder configuration description tag
963 bo_add_mp4_tag_descr(&bo, 0x04, config_size);
964 bo_add_8(&bo, 32); // object type identification (32 == MPEG4)
965 bo_add_8(&bo, 0x11); // stream type
966 bo_add_24be(&bo, 0); // buffer size
967 bo_add_32be(&bo, 0); // max bitrate
968 bo_add_32be(&bo, 0); // avg bitrate
970 // decoder specific description tag
971 bo_add_mp4_tag_descr(&bo, 0x05, i_buf_size);
972 bo_add_mem(&bo, i_buf_size, p_buf);
974 // sync layer configuration description tag
975 bo_add_8(&bo, 0x06); // tag
976 bo_add_8(&bo, 0x01); // length
977 bo_add_8(&bo, 0x02); // no SL
979 int i_ret = ExtradataInfoCreate(p_dec, CFSTR("esds"), bo.b->p_buffer,
985 static int avcCFromAnnexBCreate(decoder_t *p_dec)
987 decoder_sys_t *p_sys = p_dec->p_sys;
989 if (p_sys->hh.h264.i_sps_count == 0 || p_sys->hh.h264.i_pps_count == 0)
992 unsigned i_h264_width, i_h264_height, i_video_width, i_video_height;
993 int i_sar_num, i_sar_den, i_ret;
994 i_ret = h264_helper_get_current_picture_size(&p_sys->hh,
995 &i_h264_width, &i_h264_height,
996 &i_video_width, &i_video_height);
997 if (i_ret != VLC_SUCCESS)
999 i_ret = h264_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den);
1000 if (i_ret != VLC_SUCCESS)
1003 p_dec->fmt_out.video.i_visible_width =
1004 p_dec->fmt_out.video.i_width = i_video_width;
1005 p_dec->fmt_out.video.i_visible_height =
1006 p_dec->fmt_out.video.i_height = i_video_height;
1007 p_dec->fmt_out.video.i_sar_num = i_sar_num;
1008 p_dec->fmt_out.video.i_sar_den = i_sar_den;
1010 block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh);
1012 return VLC_EGENERIC;
1014 i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"), p_avcC->p_buffer,
1016 block_Release(p_avcC);
1020 static int ExtradataInfoCreate(decoder_t *p_dec, CFStringRef name, void *p_data,
1023 decoder_sys_t *p_sys = p_dec->p_sys;
1025 p_sys->extradataInfo =
1026 CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
1027 &kCFTypeDictionaryKeyCallBacks,
1028 &kCFTypeDictionaryValueCallBacks);
1029 if (p_sys->extradataInfo == nil)
1030 return VLC_EGENERIC;
1035 CFDataRef extradata = CFDataCreate(kCFAllocatorDefault, p_data, i_data);
1036 if (extradata == nil)
1038 CFRelease(p_sys->extradataInfo);
1039 p_sys->extradataInfo = nil;
1040 return VLC_EGENERIC;
1042 CFDictionarySetValue(p_sys->extradataInfo, name, extradata);
1043 CFRelease(extradata);
1047 static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec,
1048 CMFormatDescriptionRef fmt_desc,
1052 CMBlockBufferRef block_buf = NULL;
1053 CMSampleBufferRef sample_buf = NULL;
1055 if(!p_dec->p_sys->b_poc_based_reorder && p_block->i_pts == VLC_TS_INVALID)
1056 pts = CMTimeMake(p_block->i_dts, CLOCK_FREQ);
1058 pts = CMTimeMake(p_block->i_pts, CLOCK_FREQ);
1060 CMSampleTimingInfo timeInfoArray[1] = { {
1061 .duration = CMTimeMake(p_block->i_length, 1),
1062 .presentationTimeStamp = pts,
1063 .decodeTimeStamp = CMTimeMake(p_block->i_dts, CLOCK_FREQ),
1066 status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
1067 p_block->p_buffer, // memoryBlock
1068 p_block->i_buffer, // blockLength
1069 kCFAllocatorNull, // blockAllocator
1070 NULL, // customBlockSource
1072 p_block->i_buffer, // dataLength
1077 status = CMSampleBufferCreate(kCFAllocatorDefault, // allocator
1078 block_buf, // dataBuffer
1080 0, // makeDataReadyCallback
1081 0, // makeDataReadyRefcon
1082 fmt_desc, // formatDescription
1084 1, // numSampleTimingEntries
1085 timeInfoArray, // sampleTimingArray
1086 0, // numSampleSizeEntries
1087 NULL, // sampleSizeArray
1089 if (status != noErr)
1090 msg_Warn(p_dec, "sample buffer creation failure %i", (int)status);
1092 msg_Warn(p_dec, "cm block buffer creation failure %i", (int)status);
1094 if (block_buf != nil)
1095 CFRelease(block_buf);
1101 void VTDictionarySetInt32(CFMutableDictionaryRef dict, CFStringRef key, int value)
1104 number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
1105 CFDictionarySetValue(dict, key, number);
1109 static void copy420YpCbCr8Planar(picture_t *p_pic,
1110 CVPixelBufferRef buffer,
1114 uint8_t *pp_plane[2];
1117 if (!buffer || i_width == 0 || i_height == 0)
1120 CVPixelBufferLockBaseAddress(buffer, kCVPixelBufferLock_ReadOnly);
1122 for (int i = 0; i < 2; i++) {
1123 pp_plane[i] = CVPixelBufferGetBaseAddressOfPlane(buffer, i);
1124 pi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane(buffer, i);
1127 CopyFromNv12ToI420(p_pic, pp_plane, pi_pitch, i_height);
1129 CVPixelBufferUnlockBaseAddress(buffer, kCVPixelBufferLock_ReadOnly);
1132 static int HandleVTStatus(decoder_t *p_dec, OSStatus status)
1134 #define VTERRCASE(x) \
1135 case x: msg_Err(p_dec, "vt session error: '" #x "'"); break;
1142 VTERRCASE(kVTPropertyNotSupportedErr)
1143 VTERRCASE(kVTPropertyReadOnlyErr)
1144 VTERRCASE(kVTParameterErr)
1145 VTERRCASE(kVTInvalidSessionErr)
1146 VTERRCASE(kVTAllocationFailedErr)
1147 VTERRCASE(kVTPixelTransferNotSupportedErr)
1148 VTERRCASE(kVTCouldNotFindVideoDecoderErr)
1149 VTERRCASE(kVTCouldNotCreateInstanceErr)
1150 VTERRCASE(kVTCouldNotFindVideoEncoderErr)
1151 VTERRCASE(kVTVideoDecoderBadDataErr)
1152 VTERRCASE(kVTVideoDecoderUnsupportedDataFormatErr)
1153 VTERRCASE(kVTVideoDecoderMalfunctionErr)
1154 VTERRCASE(kVTVideoEncoderMalfunctionErr)
1155 VTERRCASE(kVTVideoDecoderNotAvailableNowErr)
1156 VTERRCASE(kVTImageRotationNotSupportedErr)
1157 VTERRCASE(kVTVideoEncoderNotAvailableNowErr)
1158 VTERRCASE(kVTFormatDescriptionChangeNotSupportedErr)
1159 VTERRCASE(kVTInsufficientSourceColorDataErr)
1160 VTERRCASE(kVTCouldNotCreateColorCorrectionDataErr)
1161 VTERRCASE(kVTColorSyncTransformConvertFailedErr)
1162 VTERRCASE(kVTVideoDecoderAuthorizationErr)
1163 VTERRCASE(kVTVideoEncoderAuthorizationErr)
1164 VTERRCASE(kVTColorCorrectionPixelTransferFailedErr)
1165 VTERRCASE(kVTMultiPassStorageIdentifierMismatchErr)
1166 VTERRCASE(kVTMultiPassStorageInvalidErr)
1167 VTERRCASE(kVTFrameSiloInvalidTimeStampErr)
1168 VTERRCASE(kVTFrameSiloInvalidTimeRangeErr)
1169 VTERRCASE(kVTCouldNotFindTemporalFilterErr)
1170 VTERRCASE(kVTPixelTransferNotPermittedErr)
1171 VTERRCASE(kVTColorCorrectionImageRotationFailedErr)
1174 msg_Err(p_dec, "unknown vt session error (%i)", (int)status);
1177 return VLC_EGENERIC;
1180 #pragma mark - actual decoding
1182 static void Flush(decoder_t *p_dec)
1184 decoder_sys_t *p_sys = p_dec->p_sys;
1186 /* There is no Flush in VT api, ask to restart VT from next DecodeBlock if
1187 * we already feed some input blocks (it's better to not restart here in
1188 * order to avoid useless restart just before a close). */
1189 p_sys->b_vt_flush = p_sys->b_vt_feed;
1192 static void Drain(decoder_t *p_dec)
1194 decoder_sys_t *p_sys = p_dec->p_sys;
1196 /* draining: return last pictures of the reordered queue */
1198 VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
1200 vlc_mutex_lock(&p_sys->lock);
1202 vlc_mutex_unlock(&p_sys->lock);
1205 static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
1207 decoder_sys_t *p_sys = p_dec->p_sys;
1208 frame_info_t *p_info = NULL;
1210 if (p_sys->b_vt_flush) {
1211 RestartVideoToolbox(p_dec, false);
1212 p_sys->b_vt_flush = false;
1215 if (p_block == NULL)
1218 return VLCDEC_SUCCESS;
1221 vlc_mutex_lock(&p_sys->lock);
1222 if (p_sys->b_abort) { /* abort from output thread (DecoderCallback) */
1223 vlc_mutex_unlock(&p_sys->lock);
1226 vlc_mutex_unlock(&p_sys->lock);
1228 if (unlikely(p_block->i_flags&(BLOCK_FLAG_CORRUPTED)))
1230 if (p_sys->b_vt_feed)
1233 RestartVideoToolbox(p_dec, false);
1238 bool b_config_changed = false;
1239 if (p_sys->codec == kCMVideoCodecType_H264 && p_sys->hh.pf_process_block)
1241 p_block = p_sys->hh.pf_process_block(&p_sys->hh, p_block, &b_config_changed);
1243 return VLCDEC_SUCCESS;
1246 if (b_config_changed)
1248 /* decoding didn't start yet, which is ok for H264, let's see
1249 * if we can use this block to get going */
1250 assert(p_sys->codec == kCMVideoCodecType_H264 && !p_sys->hh.b_is_xvcC);
1253 msg_Dbg(p_dec, "SPS/PPS changed: draining H264 decoder");
1255 msg_Dbg(p_dec, "SPS/PPS changed: restarting H264 decoder");
1256 StopVideoToolbox(p_dec, true);
1259 int i_ret = avcCFromAnnexBCreate(p_dec);
1260 if (i_ret == VLC_SUCCESS)
1262 if ((p_block->i_flags & BLOCK_FLAG_TOP_FIELD_FIRST
1263 || p_block->i_flags & BLOCK_FLAG_BOTTOM_FIELD_FIRST)
1264 && var_InheritBool(p_dec, "videotoolbox-temporal-deinterlacing"))
1265 p_sys->b_enable_temporal_processing = true;
1267 msg_Dbg(p_dec, "Got SPS/PPS: late opening of H264 decoder");
1268 StartVideoToolbox(p_dec);
1270 if (!p_sys->session)
1275 p_info = CreateReorderInfo(p_sys, p_block);
1276 if(unlikely(!p_info))
1279 CMSampleBufferRef sampleBuffer =
1280 VTSampleBufferCreate(p_dec, p_sys->videoFormatDescription, p_block);
1281 if (unlikely(!sampleBuffer))
1284 VTDecodeInfoFlags flagOut;
1285 VTDecodeFrameFlags decoderFlags = kVTDecodeFrame_EnableAsynchronousDecompression;
1286 if (unlikely(p_sys->b_enable_temporal_processing))
1287 decoderFlags |= kVTDecodeFrame_EnableTemporalProcessing;
1290 VTDecompressionSessionDecodeFrame(p_sys->session, sampleBuffer,
1291 decoderFlags, p_info, &flagOut);
1292 if (HandleVTStatus(p_dec, status) == VLC_SUCCESS)
1294 p_sys->b_vt_feed = true;
1301 case kCVReturnInvalidArgument:
1302 msg_Err(p_dec, "decoder failure: invalid argument");
1303 /* The decoder module will be reloaded next time since we already
1304 * modified the input block */
1305 vlc_mutex_lock(&p_sys->lock);
1306 p_dec->p_sys->b_abort = true;
1307 vlc_mutex_unlock(&p_sys->lock);
1309 case -8969 /* codecBadDataErr */:
1310 case kVTVideoDecoderBadDataErr:
1311 if (RestartVideoToolbox(p_dec, true) == VLC_SUCCESS)
1313 status = VTDecompressionSessionDecodeFrame(p_sys->session,
1314 sampleBuffer, decoderFlags, p_info, &flagOut);
1319 StopVideoToolbox(p_dec, true);
1323 case -8960 /* codecErr */:
1324 case kVTVideoDecoderMalfunctionErr:
1325 case kVTInvalidSessionErr:
1326 RestartVideoToolbox(p_dec, true);
1331 CFRelease(sampleBuffer);
1335 block_Release(p_block);
1336 return VLCDEC_SUCCESS;
1339 /* Add an empty variable so that videotoolbox won't be loaded again for
1341 var_Create(p_dec, "videotoolbox-failed", VLC_VAR_VOID);
1342 return VLCDEC_RELOAD;
1345 static int UpdateVideoFormat(decoder_t *p_dec, CVPixelBufferRef imageBuffer)
1347 CFDictionaryRef attachments = CVBufferGetAttachments(imageBuffer, kCVAttachmentMode_ShouldPropagate);
1348 NSDictionary *attachmentDict = (NSDictionary *)attachments;
1350 NSLog(@"%@", attachments);
1352 if (attachmentDict == nil || attachmentDict.count == 0)
1355 NSString *colorSpace = attachmentDict[(NSString *)kCVImageBufferYCbCrMatrixKey];
1356 if (colorSpace != nil) {
1357 if ([colorSpace isEqualToString:(NSString *)kCVImageBufferYCbCrMatrix_ITU_R_601_4])
1358 p_dec->fmt_out.video.space = COLOR_SPACE_BT601;
1359 else if ([colorSpace isEqualToString:(NSString *)kCVImageBufferYCbCrMatrix_ITU_R_709_2])
1360 p_dec->fmt_out.video.space = COLOR_SPACE_BT709;
1362 p_dec->fmt_out.video.space = COLOR_SPACE_UNDEF;
1365 NSString *colorprimary = attachmentDict[(NSString *)kCVImageBufferColorPrimariesKey];
1366 if (colorprimary != nil) {
1367 if ([colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_SMPTE_C] ||
1368 [colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_EBU_3213])
1369 p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT601_625;
1370 else if ([colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_ITU_R_709_2])
1371 p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT709;
1372 else if ([colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_P22])
1373 p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_DCI_P3;
1375 p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_UNDEF;
1378 NSString *transfer = attachmentDict[(NSString *)kCVImageBufferTransferFunctionKey];
1379 if (transfer != nil) {
1380 if ([transfer isEqualToString:(NSString *)kCVImageBufferTransferFunction_ITU_R_709_2] ||
1381 [transfer isEqualToString:(NSString *)kCVImageBufferTransferFunction_SMPTE_240M_1995])
1382 p_dec->fmt_out.video.transfer = TRANSFER_FUNC_BT709;
1384 p_dec->fmt_out.video.transfer = TRANSFER_FUNC_UNDEF;
1387 NSString *chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationTopFieldKey];
1388 if (chromaLocation != nil) {
1389 if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Left] ||
1390 [chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_DV420])
1391 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_LEFT;
1392 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Center])
1393 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_CENTER;
1394 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_TopLeft])
1395 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_LEFT;
1396 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Top])
1397 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_CENTER;
1399 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_UNDEF;
1401 if (p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF) {
1402 chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationBottomFieldKey];
1403 if (chromaLocation != nil) {
1404 if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_BottomLeft])
1405 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_LEFT;
1406 else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Bottom])
1407 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_CENTER;
1411 uint32_t cvfmt = CVPixelBufferGetPixelFormatType(imageBuffer);
1414 case kCVPixelFormatType_422YpCbCr8:
1416 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_UYVY;
1417 assert(CVPixelBufferIsPlanar(imageBuffer) == false);
1419 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
1420 case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
1421 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_NV12;
1422 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
1424 case kCVPixelFormatType_420YpCbCr8Planar:
1425 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_I420;
1426 assert(CVPixelBufferIsPlanar(imageBuffer) == true);
1428 case kCVPixelFormatType_32BGRA:
1429 p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_BGRA;
1430 assert(CVPixelBufferIsPlanar(imageBuffer) == false);
1433 p_dec->p_sys->b_abort = true;
1436 return decoder_UpdateVideoFormat(p_dec);
1439 static void DecoderCallback(void *decompressionOutputRefCon,
1440 void *sourceFrameRefCon,
1442 VTDecodeInfoFlags infoFlags,
1443 CVPixelBufferRef imageBuffer,
1447 VLC_UNUSED(duration);
1448 decoder_t *p_dec = (decoder_t *)decompressionOutputRefCon;
1449 decoder_sys_t *p_sys = p_dec->p_sys;
1450 frame_info_t *p_info = (frame_info_t *) sourceFrameRefCon;
1452 if (status != noErr) {
1453 msg_Warn(p_dec, "decoding of a frame failed (%i, %u)", (int)status, (unsigned int) infoFlags);
1454 if( status != kVTVideoDecoderBadDataErr && status != -8969 )
1458 assert(imageBuffer);
1460 if (unlikely(!p_sys->b_format_propagated)) {
1461 vlc_mutex_lock(&p_sys->lock);
1462 p_sys->b_format_propagated =
1463 UpdateVideoFormat(p_dec, imageBuffer) == VLC_SUCCESS;
1464 vlc_mutex_unlock(&p_sys->lock);
1466 if (!p_sys->b_format_propagated)
1471 assert(p_dec->fmt_out.i_codec != 0);
1474 if (infoFlags & kVTDecodeInfo_FrameDropped)
1476 printf("OUT %ld\n", pts.value);
1477 msg_Dbg(p_dec, "decoder dropped frame");
1482 if (!CMTIME_IS_VALID(pts))
1488 if (CVPixelBufferGetDataSize(imageBuffer) == 0)
1496 picture_t *p_pic = decoder_NewPicture(p_dec);
1503 if (unlikely(!p_pic->p_sys)) {
1504 vlc_mutex_lock(&p_sys->lock);
1505 p_dec->p_sys->b_abort = true;
1506 vlc_mutex_unlock(&p_sys->lock);
1507 picture_Release(p_pic);
1512 /* Can happen if the pic was discarded */
1513 if (p_pic->p_sys->pixelBuffer != nil)
1514 CFRelease(p_pic->p_sys->pixelBuffer);
1516 /* will be freed by the vout */
1517 p_pic->p_sys->pixelBuffer = CVPixelBufferRetain(imageBuffer);
1519 p_info->p_picture = p_pic;
1521 p_pic->date = pts.value;
1522 p_pic->b_progressive = p_info->b_progressive;
1524 vlc_mutex_lock(&p_sys->lock);
1525 OnDecodedFrame( p_dec, p_info );
1526 vlc_mutex_unlock(&p_sys->lock);