965262ebd9136996a72e55429cf92d3837edde79
[vlc.git] / modules / codec / videotoolbox.m
1 /*****************************************************************************
2  * videotoolbox.m: Video Toolbox decoder
3  *****************************************************************************
4  * Copyright © 2014-2015 VideoLabs SAS
5  *
6  * Authors: Felix Paul Kühne <fkuehne # videolan.org>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #pragma mark preamble
24
25 #ifdef HAVE_CONFIG_H
26 # import "config.h"
27 #endif
28
29 #import <vlc_common.h>
30 #import <vlc_plugin.h>
31 #import <vlc_codec.h>
32 #import "hxxx_helper.h"
33 #import <vlc_bits.h>
34 #import <vlc_boxes.h>
35 #import "../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"
40
41 #import <VideoToolbox/VideoToolbox.h>
42 #import <VideoToolbox/VTErrors.h>
43
44 #import <Foundation/Foundation.h>
45 #import <TargetConditionals.h>
46
47 #import <sys/types.h>
48 #import <sys/sysctl.h>
49 #import <mach/machine.h>
50
51 #if TARGET_OS_IPHONE
52 #import <UIKit/UIKit.h>
53
54 /* support iOS SDKs < v9.1 */
55 #ifndef CPUFAMILY_ARM_TWISTER
56 #define CPUFAMILY_ARM_TWISTER 0x92fb37c8
57 #endif
58
59 #endif
60
61 #pragma mark - module descriptor
62
63 static int OpenDecoder(vlc_object_t *);
64 static void CloseDecoder(vlc_object_t *);
65
66 #if MAC_OS_X_VERSION_MIN_ALLOWED < 1090
67 const CFStringRef kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder = CFSTR("EnableHardwareAcceleratedVideoDecoder");
68 const CFStringRef kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder = CFSTR("RequireHardwareAcceleratedVideoDecoder");
69 #endif
70
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.")
74
75 vlc_module_begin()
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)
81
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)
84 vlc_module_end()
85
86 #pragma mark - local prototypes
87
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();
101
102 struct picture_sys_t {
103     CFTypeRef pixelBuffer;
104 };
105
106 typedef struct frame_info_t frame_info_t;
107
108 struct frame_info_t
109 {
110     picture_t *p_picture;
111     int i_poc;
112     int i_foc;
113     bool b_flush;
114     bool b_field;
115     bool b_progressive;
116     bool b_top_field_first;
117     uint8_t i_num_ts;
118     unsigned i_length;
119     frame_info_t *p_next;
120 };
121
122 #pragma mark - decoder structure
123
124 #define H264_MAX_DPB 16
125
126 struct decoder_sys_t
127 {
128     CMVideoCodecType            codec;
129     struct                      hxxx_helper hh;
130
131     bool                        b_vt_feed;
132     bool                        b_vt_flush;
133     VTDecompressionSessionRef   session;
134     CMVideoFormatDescriptionRef videoFormatDescription;
135     CFMutableDictionaryRef      decoderConfiguration;
136     CFMutableDictionaryRef      destinationPixelBufferAttributes;
137     CFMutableDictionaryRef      extradataInfo;
138
139     vlc_mutex_t                 lock;
140     frame_info_t               *p_pic_reorder;
141     uint8_t                     i_pic_reorder;
142     uint8_t                     i_pic_reorder_max;
143     bool                        b_invalid_pic_reorder_max;
144     bool                        b_poc_based_reorder;
145     bool                        b_enable_temporal_processing;
146
147     bool                        b_format_propagated;
148     bool                        b_abort;
149
150     poc_context_t               pocctx;
151     date_t                      pts;
152 };
153
154 #pragma mark - start & stop
155
156 static void GetSPSPPS(uint8_t i_pps_id, void *priv,
157                       const h264_sequence_parameter_set_t **pp_sps,
158                       const h264_picture_parameter_set_t **pp_pps)
159 {
160     decoder_sys_t *p_sys = priv;
161
162     *pp_pps = p_sys->hh.h264.pps_list[i_pps_id].h264_pps;
163     if(*pp_pps == NULL)
164         *pp_sps = NULL;
165     else
166         *pp_sps = p_sys->hh.h264.sps_list[(*pp_pps)->i_sps_id].h264_sps;
167 }
168
169 struct sei_callback_s
170 {
171     uint8_t i_pic_struct;
172     const h264_sequence_parameter_set_t *p_sps;
173 };
174
175 static bool ParseH264SEI(const hxxx_sei_data_t *p_sei_data, void *priv)
176 {
177
178     if(p_sei_data->i_type == HXXX_SEI_PIC_TIMING)
179     {
180         struct sei_callback_s *s = priv;
181         if(s->p_sps && s->p_sps->vui.b_valid)
182         {
183             if(s->p_sps->vui.b_hrd_parameters_present_flag)
184             {
185                 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_cpb_removal_delay_length_minus1 + 1);
186                 bs_read(p_sei_data->p_bs, s->p_sps->vui.i_dpb_output_delay_length_minus1 + 1);
187             }
188
189             if(s->p_sps->vui.b_pic_struct_present_flag)
190                s->i_pic_struct = bs_read( p_sei_data->p_bs, 4);
191         }
192         return false;
193     }
194
195     return true;
196 }
197
198 static bool ParseH264NAL(decoder_t *p_dec,
199                          const uint8_t *p_buffer, size_t i_buffer,
200                          uint8_t i_nal_length_size, frame_info_t *p_info)
201 {
202     decoder_sys_t *p_sys = p_dec->p_sys;
203     hxxx_iterator_ctx_t itctx;
204     hxxx_iterator_init(&itctx, p_buffer, i_buffer, i_nal_length_size);
205
206     const uint8_t *p_nal; size_t i_nal;
207     const uint8_t *p_sei_nal = NULL; size_t i_sei_nal = 0;
208     while(hxxx_iterate_next(&itctx, &p_nal, &i_nal))
209     {
210         if(i_nal < 2)
211             continue;
212
213         const enum h264_nal_unit_type_e i_nal_type = p_nal[0] & 0x1F;
214
215         if (i_nal_type <= H264_NAL_SLICE_IDR && i_nal_type != H264_NAL_UNKNOWN)
216         {
217             h264_slice_t slice;
218             if(!h264_decode_slice(p_nal, i_nal, GetSPSPPS, p_sys, &slice))
219                 return false;
220
221             const h264_sequence_parameter_set_t *p_sps;
222             const h264_picture_parameter_set_t *p_pps;
223             GetSPSPPS(slice.i_pic_parameter_set_id, p_sys, &p_sps, &p_pps);
224             if(p_sps)
225             {
226                 if(!p_sys->b_invalid_pic_reorder_max && i_nal_type == H264_NAL_SLICE_IDR)
227                 {
228                     unsigned dummy;
229                     uint8_t i_reorder;
230                     h264_get_dpb_values(p_sps, &i_reorder, &dummy);
231                     vlc_mutex_lock(&p_sys->lock);
232                     p_sys->i_pic_reorder_max = i_reorder;
233                     vlc_mutex_unlock(&p_sys->lock);
234                 }
235
236                 int bFOC;
237                 h264_compute_poc(p_sps, &slice, &p_sys->pocctx,
238                                  &p_info->i_poc, &p_info->i_foc, &bFOC);
239
240                 p_info->b_flush = (slice.type == H264_SLICE_TYPE_I) || slice.has_mmco5;
241                 p_info->b_field = slice.i_field_pic_flag;
242                 p_info->b_progressive = !p_sps->mb_adaptive_frame_field_flag &&
243                                         !slice.i_field_pic_flag;
244
245                 struct sei_callback_s sei;
246                 sei.p_sps = p_sps;
247                 sei.i_pic_struct = UINT8_MAX;
248
249                 if(p_sei_nal)
250                     HxxxParseSEI(p_sei_nal, i_sei_nal, 1, ParseH264SEI, &sei);
251
252                 p_info->i_num_ts = h264_get_num_ts(p_sps, &slice, sei.i_pic_struct,
253                                                    p_info->i_foc, bFOC);
254
255                 if(!p_info->b_progressive)
256                     p_info->b_top_field_first = (sei.i_pic_struct % 2 == 1);
257
258                 /* Set frame rate for timings in case of missing rate */
259                 if( (!p_dec->fmt_in.video.i_frame_rate_base ||
260                      !p_dec->fmt_in.video.i_frame_rate) &&
261                     p_sps->vui.i_time_scale && p_sps->vui.i_num_units_in_tick )
262                 {
263                     date_Change( &p_sys->pts, p_sps->vui.i_time_scale,
264                                               p_sps->vui.i_num_units_in_tick );
265                 }
266             }
267
268             return true; /* No need to parse further NAL */
269         }
270         else if(i_nal_type == H264_NAL_SEI)
271         {
272             p_sei_nal = p_nal;
273             i_sei_nal = i_nal;
274         }
275     }
276
277     return false;
278 }
279
280 static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
281 {
282     frame_info_t **pp_lead_in = &p_sys->p_pic_reorder;
283
284     for( ;; pp_lead_in = & ((*pp_lead_in)->p_next))
285     {
286         bool b_insert;
287         if(*pp_lead_in == NULL)
288             b_insert = true;
289         else if(p_sys->b_poc_based_reorder)
290             b_insert = ((*pp_lead_in)->i_foc > p_info->i_foc);
291         else
292             b_insert = ((*pp_lead_in)->p_picture->date >= p_info->p_picture->date);
293
294         if(b_insert)
295         {
296             p_info->p_next = *pp_lead_in;
297             *pp_lead_in = p_info;
298             p_sys->i_pic_reorder += (p_info->b_field) ? 1 : 2;
299             break;
300         }
301     }
302 #if 0
303     for(frame_info_t *p_in=p_sys->p_pic_reorder; p_in; p_in = p_in->p_next)
304         printf(" %d", p_in->i_foc);
305     printf("\n");
306 #endif
307 }
308
309 static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
310 {
311     frame_info_t *p_info = p_sys->p_pic_reorder;
312     if(p_info == NULL)
313         return NULL;
314
315     const int i_framepoc = p_info->i_poc;
316
317     picture_t *p_ret = NULL;
318     picture_t **pp_ret_last = &p_ret;
319     bool b_dequeue;
320
321     do
322     {
323         picture_t *p_field = p_info->p_picture;
324
325         /* Compute time if missing */
326         if (p_field->date == VLC_TS_INVALID)
327             p_field->date = date_Get(&p_sys->pts);
328         else
329             date_Set(&p_sys->pts, p_field->date);
330
331         /* Set next picture time, in case it is missing */
332         if (p_info->i_length)
333             date_Set(&p_sys->pts, p_field->date + p_info->i_length);
334         else
335             date_Increment(&p_sys->pts, p_info->i_num_ts);
336
337         *pp_ret_last = p_field;
338         pp_ret_last = &p_field->p_next;
339
340         p_sys->i_pic_reorder -= (p_info->b_field) ? 1 : 2;
341
342         p_sys->p_pic_reorder = p_info->p_next;
343         free(p_info);
344         p_info = p_sys->p_pic_reorder;
345
346         if (p_info)
347         {
348             if (p_sys->b_poc_based_reorder)
349                 b_dequeue = (p_info->i_poc == i_framepoc);
350             else
351                 b_dequeue = (p_field->date == p_info->p_picture->date);
352         }
353         else b_dequeue = false;
354
355     } while(b_dequeue);
356
357     return p_ret;
358 }
359
360 static void DrainDPB(decoder_t *p_dec)
361 {
362     decoder_sys_t *p_sys = p_dec->p_sys;
363     for( ;; )
364     {
365         picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
366         if (p_fields == NULL)
367             break;
368         do
369         {
370             picture_t *p_next = p_fields->p_next;
371             p_fields->p_next = NULL;
372             decoder_QueueVideo(p_dec, p_fields);
373             p_fields = p_next;
374         } while(p_fields != NULL);
375     }
376 }
377
378 static frame_info_t * CreateReorderInfo(decoder_t *p_dec, const block_t *p_block)
379 {
380     decoder_sys_t *p_sys = p_dec->p_sys;
381     frame_info_t *p_info = calloc(1, sizeof(*p_info));
382     if (!p_info)
383         return NULL;
384
385     if (p_sys->b_poc_based_reorder)
386     {
387         if(p_sys->codec != kCMVideoCodecType_H264 ||
388            !ParseH264NAL(p_dec, p_block->p_buffer, p_block->i_buffer, 4, p_info))
389         {
390             assert(p_sys->codec == kCMVideoCodecType_H264);
391             free(p_info);
392             return NULL;
393         }
394     }
395     else
396     {
397         p_info->i_num_ts = 2;
398         p_info->b_progressive = true;
399         p_info->b_field = false;
400     }
401
402     p_info->i_length = p_block->i_length;
403
404     if (date_Get(&p_sys->pts) == VLC_TS_INVALID)
405         date_Set(&p_sys->pts, p_block->i_dts);
406
407     return p_info;
408 }
409
410 static void OnDecodedFrame(decoder_t *p_dec, frame_info_t *p_info)
411 {
412     decoder_sys_t *p_sys = p_dec->p_sys;
413     assert(p_info->p_picture);
414     while(p_info->b_flush || p_sys->i_pic_reorder >= (p_sys->i_pic_reorder_max * 2))
415     {
416         /* First check if DPB sizing was correct before removing one frame */
417         if (p_sys->p_pic_reorder && !p_info->b_flush &&
418             p_sys->i_pic_reorder_max < H264_MAX_DPB)
419         {
420             if(p_sys->b_poc_based_reorder && p_sys->p_pic_reorder->i_foc > p_info->i_foc)
421             {
422                 p_sys->b_invalid_pic_reorder_max = true;
423                 p_sys->i_pic_reorder_max++;
424                 msg_Info(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
425                 break;
426             }
427             else if (!p_sys->b_poc_based_reorder &&
428                      p_info->p_picture->date > VLC_TS_INVALID &&
429                      p_sys->p_pic_reorder->p_picture->date > p_info->p_picture->date)
430             {
431                 p_sys->b_invalid_pic_reorder_max = true;
432                 p_sys->i_pic_reorder_max++;
433                 msg_Info(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
434                 break;
435             }
436         }
437
438         picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
439         if (p_fields == NULL)
440             break;
441         do
442         {
443             picture_t *p_next = p_fields->p_next;
444             p_fields->p_next = NULL;
445             decoder_QueueVideo(p_dec, p_fields);
446             p_fields = p_next;
447         } while(p_fields != NULL);
448     }
449
450     InsertIntoDPB(p_sys, p_info);
451 }
452
453 static CMVideoCodecType CodecPrecheck(decoder_t *p_dec)
454 {
455     uint8_t i_profile = 0xFF, i_level = 0xFF;
456     bool b_ret = false;
457     CMVideoCodecType codec;
458
459     /* check for the codec we can and want to decode */
460     switch (p_dec->fmt_in.i_codec) {
461         case VLC_CODEC_H264:
462             codec = kCMVideoCodecType_H264;
463
464             b_ret = h264_get_profile_level(&p_dec->fmt_in, &i_profile, &i_level, NULL);
465             if (!b_ret) {
466                 msg_Warn(p_dec, "H264 profile and level parsing failed because it didn't arrive yet");
467                 return kCMVideoCodecType_H264;
468             }
469
470             msg_Dbg(p_dec, "trying to decode MPEG-4 Part 10: profile %" PRIx8 ", level %" PRIx8, i_profile, i_level);
471
472             switch (i_profile) {
473                 case PROFILE_H264_BASELINE:
474                 case PROFILE_H264_MAIN:
475                 case PROFILE_H264_HIGH:
476                     break;
477
478                 case PROFILE_H264_HIGH_10:
479                 {
480                     if (deviceSupportsAdvancedProfiles())
481                         break;
482                 }
483
484                 default:
485                 {
486                     msg_Dbg(p_dec, "unsupported H264 profile %" PRIx8, i_profile);
487                     return -1;
488                 }
489             }
490
491 #if !TARGET_OS_IPHONE
492             /* a level higher than 5.2 was not tested, so don't dare to
493              * try to decode it*/
494             if (i_level > 52) {
495                 msg_Dbg(p_dec, "unsupported H264 level %" PRIx8, i_level);
496                 return -1;
497             }
498 #else
499             /* on SoC A8, 4.2 is the highest specified profile */
500             if (i_level > 42) {
501                 /* on Twister, we can do up to 5.2 */
502                 if (!deviceSupportsAdvancedLevels() || i_level > 52) {
503                     msg_Dbg(p_dec, "unsupported H264 level %" PRIx8, i_level);
504                     return -1;
505                 }
506             }
507 #endif
508
509             break;
510         case VLC_CODEC_MP4V:
511         {
512             if (p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'X','V','I','D' )) {
513                 msg_Warn(p_dec, "XVID decoding not implemented, fallback on software");
514                 return -1;
515             }
516
517             msg_Dbg(p_dec, "Will decode MP4V with original FourCC '%4.4s'", (char *)&p_dec->fmt_in.i_original_fourcc);
518             codec = kCMVideoCodecType_MPEG4Video;
519
520             break;
521         }
522 #if !TARGET_OS_IPHONE
523         case VLC_CODEC_H263:
524             codec = kCMVideoCodecType_H263;
525             break;
526
527             /* there are no DV or ProRes decoders on iOS, so bailout early */
528         case VLC_CODEC_PRORES:
529             /* the VT decoder can't differenciate between the ProRes flavors, so we do it */
530             switch (p_dec->fmt_in.i_original_fourcc) {
531                 case VLC_FOURCC( 'a','p','4','c' ):
532                 case VLC_FOURCC( 'a','p','4','h' ):
533                     codec = kCMVideoCodecType_AppleProRes4444;
534                     break;
535
536                 case VLC_FOURCC( 'a','p','c','h' ):
537                     codec = kCMVideoCodecType_AppleProRes422HQ;
538                     break;
539
540                 case VLC_FOURCC( 'a','p','c','s' ):
541                     codec = kCMVideoCodecType_AppleProRes422LT;
542                     break;
543
544                 case VLC_FOURCC( 'a','p','c','o' ):
545                     codec = kCMVideoCodecType_AppleProRes422Proxy;
546                     break;
547
548                 default:
549                     codec = kCMVideoCodecType_AppleProRes422;
550                     break;
551             }
552             if (codec != 0)
553                 break;
554
555         case VLC_CODEC_DV:
556             /* the VT decoder can't differenciate between PAL and NTSC, so we need to do it */
557             switch (p_dec->fmt_in.i_original_fourcc) {
558                 case VLC_FOURCC( 'd', 'v', 'c', ' '):
559                 case VLC_FOURCC( 'd', 'v', ' ', ' '):
560                     msg_Dbg(p_dec, "Decoding DV NTSC");
561                     codec = kCMVideoCodecType_DVCNTSC;
562                     break;
563
564                 case VLC_FOURCC( 'd', 'v', 's', 'd'):
565                 case VLC_FOURCC( 'd', 'v', 'c', 'p'):
566                 case VLC_FOURCC( 'D', 'V', 'S', 'D'):
567                     msg_Dbg(p_dec, "Decoding DV PAL");
568                     codec = kCMVideoCodecType_DVCPAL;
569                     break;
570
571                 default:
572                     break;
573             }
574             if (codec != 0)
575                 break;
576 #endif
577             /* mpgv / mp2v needs fixing, so disable it for now */
578 #if 0
579         case VLC_CODEC_MPGV:
580             codec = kCMVideoCodecType_MPEG1Video;
581             break;
582         case VLC_CODEC_MP2V:
583             codec = kCMVideoCodecType_MPEG2Video;
584             break;
585 #endif
586
587         default:
588 #ifndef NDEBUG
589             msg_Err(p_dec, "'%4.4s' is not supported", (char *)&p_dec->fmt_in.i_codec);
590 #endif
591             return -1;
592     }
593
594     return codec;
595 }
596
597 static int StartVideoToolbox(decoder_t *p_dec)
598 {
599     decoder_sys_t *p_sys = p_dec->p_sys;
600     OSStatus status;
601
602     assert(p_sys->extradataInfo != nil);
603
604     p_sys->decoderConfiguration =
605         CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
606                                   &kCFTypeDictionaryKeyCallBacks,
607                                   &kCFTypeDictionaryValueCallBacks);
608     if (p_sys->decoderConfiguration == NULL)
609         return VLC_ENOMEM;
610
611     CFDictionarySetValue(p_sys->decoderConfiguration,
612                          kCVImageBufferChromaLocationBottomFieldKey,
613                          kCVImageBufferChromaLocation_Left);
614     CFDictionarySetValue(p_sys->decoderConfiguration,
615                          kCVImageBufferChromaLocationTopFieldKey,
616                          kCVImageBufferChromaLocation_Left);
617
618     CFDictionarySetValue(p_sys->decoderConfiguration,
619                          kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms,
620                          p_sys->extradataInfo);
621
622     /* pixel aspect ratio */
623     CFMutableDictionaryRef pixelaspectratio =
624         CFDictionaryCreateMutable(kCFAllocatorDefault, 2,
625                                   &kCFTypeDictionaryKeyCallBacks,
626                                   &kCFTypeDictionaryValueCallBacks);
627
628     const unsigned i_video_width = p_dec->fmt_out.video.i_width;
629     const unsigned i_video_height = p_dec->fmt_out.video.i_height;
630     const unsigned i_sar_num = p_dec->fmt_out.video.i_sar_num;
631     const unsigned i_sar_den = p_dec->fmt_out.video.i_sar_den;
632
633     if( p_dec->fmt_in.video.i_frame_rate_base && p_dec->fmt_in.video.i_frame_rate )
634     {
635         date_Init( &p_sys->pts, p_dec->fmt_in.video.i_frame_rate * 2,
636                                 p_dec->fmt_in.video.i_frame_rate_base );
637     }
638     else date_Init( &p_sys->pts, 2 * 30000, 1001 );
639
640     VTDictionarySetInt32(pixelaspectratio,
641                          kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
642                          i_sar_num);
643     VTDictionarySetInt32(pixelaspectratio,
644                          kCVImageBufferPixelAspectRatioVerticalSpacingKey,
645                          i_sar_den);
646     CFDictionarySetValue(p_sys->decoderConfiguration,
647                          kCVImageBufferPixelAspectRatioKey,
648                          pixelaspectratio);
649     CFRelease(pixelaspectratio);
650
651     /* enable HW accelerated playback, since this is optional on OS X
652      * note that the backend may still fallback on software mode if no
653      * suitable hardware is available */
654     CFDictionarySetValue(p_sys->decoderConfiguration,
655                          kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder,
656                          kCFBooleanTrue);
657
658     /* on OS X, we can force VT to fail if no suitable HW decoder is available,
659      * preventing the aforementioned SW fallback */
660     if (var_InheritInteger(p_dec, "videotoolbox-hw-decoder-only"))
661         CFDictionarySetValue(p_sys->decoderConfiguration,
662                              kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder,
663                              kCFBooleanTrue);
664
665     if (p_sys->b_enable_temporal_processing)
666     {
667         msg_Dbg(p_dec, "Interlaced content detected, inserting temporal deinterlacer");
668         CFDictionarySetValue(p_sys->decoderConfiguration,
669                              kVTDecompressionPropertyKey_FieldMode,
670                              kVTDecompressionProperty_FieldMode_DeinterlaceFields);
671         CFDictionarySetValue(p_sys->decoderConfiguration,
672                              kVTDecompressionPropertyKey_DeinterlaceMode,
673                              kVTDecompressionProperty_DeinterlaceMode_Temporal);
674     }
675
676     /* create video format description */
677     status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
678                                             p_sys->codec,
679                                             i_video_width,
680                                             i_video_height,
681                                             p_sys->decoderConfiguration,
682                                             &p_sys->videoFormatDescription);
683     if (status) {
684         CFRelease(p_sys->decoderConfiguration);
685         msg_Err(p_dec, "video format description creation failed (%i)", (int)status);
686         return VLC_EGENERIC;
687     }
688
689     /* destination pixel buffer attributes */
690     p_sys->destinationPixelBufferAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault,
691                                                                         2,
692                                                                         &kCFTypeDictionaryKeyCallBacks,
693                                                                         &kCFTypeDictionaryValueCallBacks);
694
695 #if !TARGET_OS_IPHONE
696     CFDictionarySetValue(p_sys->destinationPixelBufferAttributes,
697                          kCVPixelBufferIOSurfaceOpenGLTextureCompatibilityKey,
698                          kCFBooleanTrue);
699 #else
700     CFDictionarySetValue(p_sys->destinationPixelBufferAttributes,
701                          kCVPixelBufferOpenGLESCompatibilityKey,
702                          kCFBooleanTrue);
703 #endif
704
705     VTDictionarySetInt32(p_sys->destinationPixelBufferAttributes,
706                          kCVPixelBufferWidthKey,
707                          i_video_width);
708     VTDictionarySetInt32(p_sys->destinationPixelBufferAttributes,
709                          kCVPixelBufferHeightKey,
710                          i_video_height);
711     VTDictionarySetInt32(p_sys->destinationPixelBufferAttributes,
712                          kCVPixelBufferBytesPerRowAlignmentKey,
713                          i_video_width * 2);
714
715     /* setup decoder callback record */
716     VTDecompressionOutputCallbackRecord decoderCallbackRecord;
717     decoderCallbackRecord.decompressionOutputCallback = DecoderCallback;
718     decoderCallbackRecord.decompressionOutputRefCon = p_dec;
719
720     /* create decompression session */
721     status = VTDecompressionSessionCreate(kCFAllocatorDefault,
722                                           p_sys->videoFormatDescription,
723                                           p_sys->decoderConfiguration,
724                                           p_sys->destinationPixelBufferAttributes,
725                                           &decoderCallbackRecord, &p_sys->session);
726
727     if (HandleVTStatus(p_dec, status) != VLC_SUCCESS)
728         return VLC_EGENERIC;
729
730     return VLC_SUCCESS;
731 }
732
733 static void StopVideoToolbox(decoder_t *p_dec, bool b_reset_format)
734 {
735     decoder_sys_t *p_sys = p_dec->p_sys;
736
737     if (p_sys->session != nil)
738     {
739         VTDecompressionSessionInvalidate(p_sys->session);
740         CFRelease(p_sys->session);
741         p_sys->session = nil;
742
743         if (b_reset_format)
744         {
745             p_sys->b_format_propagated = false;
746             p_dec->fmt_out.i_codec = 0;
747         }
748         DrainDPB( p_dec );
749     }
750
751     if (p_sys->videoFormatDescription != nil) {
752         CFRelease(p_sys->videoFormatDescription);
753         p_sys->videoFormatDescription = nil;
754     }
755     if (p_sys->decoderConfiguration != nil) {
756         CFRelease(p_sys->decoderConfiguration);
757         p_sys->decoderConfiguration = nil;
758     }
759     if (p_sys->destinationPixelBufferAttributes != nil) {
760         CFRelease(p_sys->destinationPixelBufferAttributes);
761         p_sys->destinationPixelBufferAttributes = nil;
762     }
763 }
764
765 static int RestartVideoToolbox(decoder_t *p_dec, bool b_reset_format)
766 {
767     decoder_sys_t *p_sys = p_dec->p_sys;
768
769     msg_Dbg(p_dec, "Restarting decoder session");
770
771     if (p_sys->session != nil)
772         StopVideoToolbox(p_dec, b_reset_format);
773
774     return StartVideoToolbox(p_dec);
775 }
776
777 #pragma mark - module open and close
778
779 static int SetupDecoderExtradata(decoder_t *p_dec)
780 {
781     decoder_sys_t *p_sys = p_dec->p_sys;
782     CFMutableDictionaryRef extradata_info = NULL;
783
784     if (p_sys->codec == kCMVideoCodecType_H264)
785     {
786         hxxx_helper_init(&p_sys->hh, VLC_OBJECT(p_dec),
787                          p_dec->fmt_in.i_codec, true);
788         int i_ret = hxxx_helper_set_extra(&p_sys->hh, p_dec->fmt_in.p_extra,
789                                           p_dec->fmt_in.i_extra);
790         if (i_ret != VLC_SUCCESS)
791             return i_ret;
792         assert(p_sys->hh.pf_process_block != NULL);
793
794         if (p_dec->fmt_in.p_extra)
795         {
796             int i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"),
797                                             p_dec->fmt_in.p_extra,
798                                             p_dec->fmt_in.i_extra);
799             if (i_ret != VLC_SUCCESS)
800                 return i_ret;
801         }
802         /* else: AnnexB case, we'll get extradata from first input blocks */
803     }
804     else if (p_sys->codec == kCMVideoCodecType_MPEG4Video)
805     {
806         if (!p_dec->fmt_in.i_extra)
807             return VLC_EGENERIC;
808         int i_ret = ESDSCreate(p_dec, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra);
809         if (i_ret != VLC_SUCCESS)
810             return i_ret;
811     }
812     else
813     {
814         int i_ret = ExtradataInfoCreate(p_dec, NULL, NULL, 0);
815         if (i_ret != VLC_SUCCESS)
816             return i_ret;
817     }
818
819     return VLC_SUCCESS;
820 }
821
822 static int OpenDecoder(vlc_object_t *p_this)
823 {
824     decoder_t *p_dec = (decoder_t *)p_this;
825
826 #if TARGET_OS_IPHONE
827     if (unlikely([[UIDevice currentDevice].systemVersion floatValue] < 8.0)) {
828         msg_Warn(p_dec, "decoder skipped as OS is too old");
829         return VLC_EGENERIC;
830     }
831 #endif
832
833     if (p_dec->fmt_in.i_cat != VIDEO_ES)
834         return VLC_EGENERIC;
835
836     /* Fail if this module already failed to decode this ES */
837     if (var_Type(p_dec, "videotoolbox-failed") != 0)
838         return VLC_EGENERIC;
839
840     /* check quickly if we can digest the offered data */
841     CMVideoCodecType codec;
842     codec = CodecPrecheck(p_dec);
843     if (codec == -1)
844         return VLC_EGENERIC;
845
846     /* now that we see a chance to decode anything, allocate the
847      * internals and start the decoding session */
848     decoder_sys_t *p_sys;
849     p_sys = malloc(sizeof(*p_sys));
850     if (!p_sys)
851         return VLC_ENOMEM;
852     p_dec->p_sys = p_sys;
853     p_sys->session = nil;
854     p_sys->b_vt_feed = false;
855     p_sys->b_vt_flush = false;
856     p_sys->codec = codec;
857     p_sys->videoFormatDescription = nil;
858     p_sys->decoderConfiguration = nil;
859     p_sys->destinationPixelBufferAttributes = nil;
860     p_sys->extradataInfo = nil;
861     p_sys->p_pic_reorder = NULL;
862     p_sys->i_pic_reorder = 0;
863     p_sys->i_pic_reorder_max = 4;
864     p_sys->b_invalid_pic_reorder_max = false;
865     p_sys->b_poc_based_reorder = false;
866     p_sys->b_format_propagated = false;
867     p_sys->b_abort = false;
868     p_sys->b_enable_temporal_processing = false;
869     h264_poc_context_init( &p_sys->pocctx );
870     vlc_mutex_init(&p_sys->lock);
871
872     /* return our proper VLC internal state */
873     p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
874     p_dec->fmt_out.video = p_dec->fmt_in.video;
875     if (!p_dec->fmt_out.video.i_sar_num || !p_dec->fmt_out.video.i_sar_den)
876     {
877         p_dec->fmt_out.video.i_sar_num = 1;
878         p_dec->fmt_out.video.i_sar_den = 1;
879     }
880     if (!p_dec->fmt_out.video.i_visible_width
881      || !p_dec->fmt_out.video.i_visible_height)
882     {
883         p_dec->fmt_out.video.i_visible_width = p_dec->fmt_out.video.i_width;
884         p_dec->fmt_out.video.i_visible_height = p_dec->fmt_out.video.i_height;
885     }
886     else
887     {
888         p_dec->fmt_out.video.i_width = p_dec->fmt_out.video.i_visible_width;
889         p_dec->fmt_out.video.i_height = p_dec->fmt_out.video.i_visible_height;
890     }
891
892     p_dec->fmt_out.i_codec = 0;
893
894     if( codec == kCMVideoCodecType_H264 )
895         p_sys->b_poc_based_reorder = true;
896
897     int i_ret = SetupDecoderExtradata(p_dec);
898     if (i_ret != VLC_SUCCESS)
899         goto error;
900
901     if (p_sys->extradataInfo != nil)
902     {
903         i_ret = StartVideoToolbox(p_dec);
904         if (i_ret != VLC_SUCCESS)
905             goto error;
906     } /* else: late opening */
907
908     p_dec->pf_decode = DecodeBlock;
909     p_dec->pf_flush  = Flush;
910
911     msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'", (char *)&p_dec->fmt_in.i_codec);
912
913     return VLC_SUCCESS;
914
915 error:
916     CloseDecoder(p_this);
917     return i_ret;
918 }
919
920 static void CloseDecoder(vlc_object_t *p_this)
921 {
922     decoder_t *p_dec = (decoder_t *)p_this;
923     decoder_sys_t *p_sys = p_dec->p_sys;
924
925     StopVideoToolbox(p_dec, true);
926
927     if (p_sys->codec == kCMVideoCodecType_H264)
928         hxxx_helper_clean(&p_sys->hh);
929
930     vlc_mutex_destroy(&p_sys->lock);
931     free(p_sys);
932 }
933
934 #pragma mark - helpers
935
936 static BOOL deviceSupportsAdvancedProfiles()
937 {
938 #if TARGET_IPHONE_SIMULATOR
939     return NO;
940 #endif
941 #if TARGET_OS_IPHONE
942     size_t size;
943     cpu_type_t type;
944
945     size = sizeof(type);
946     sysctlbyname("hw.cputype", &type, &size, NULL, 0);
947
948     /* Support for H264 profile HIGH 10 was introduced with the first 64bit Apple ARM SoC, the A7 */
949     if (type == CPU_TYPE_ARM64)
950         return YES;
951
952     return NO;
953 #else
954     return NO;
955 #endif
956 }
957
958 static BOOL deviceSupportsAdvancedLevels()
959 {
960 #if TARGET_IPHONE_SIMULATOR
961     return YES;
962 #endif
963 #if TARGET_OS_IPHONE
964     size_t size;
965     int32_t cpufamily;
966
967     size = sizeof(cpufamily);
968     sysctlbyname("hw.cpufamily", &cpufamily, &size, NULL, 0);
969
970     /* Proper 4K decoding requires a Twister SoC
971      * Everything below will kill the decoder daemon */
972     if (cpufamily == CPUFAMILY_ARM_TWISTER) {
973         return YES;
974     }
975
976     return NO;
977 #else
978     return YES;
979 #endif
980 }
981
982 static inline void bo_add_mp4_tag_descr(bo_t *p_bo, uint8_t tag, uint32_t size)
983 {
984     bo_add_8(p_bo, tag);
985     for (int i = 3; i>0; i--)
986         bo_add_8(p_bo, (size>>(7*i)) | 0x80);
987     bo_add_8(p_bo, size & 0x7F);
988 }
989
990 static int ESDSCreate(decoder_t *p_dec, uint8_t *p_buf, uint32_t i_buf_size)
991 {
992     int full_size = 3 + 5 +13 + 5 + i_buf_size + 3;
993     int config_size = 13 + 5 + i_buf_size;
994     int padding = 12;
995
996     bo_t bo;
997     bool status = bo_init(&bo, 1024);
998     if (status != true)
999         return VLC_EGENERIC;
1000
1001     bo_add_8(&bo, 0);       // Version
1002     bo_add_24be(&bo, 0);    // Flags
1003
1004     // elementary stream description tag
1005     bo_add_mp4_tag_descr(&bo, 0x03, full_size);
1006     bo_add_16be(&bo, 0);    // esid
1007     bo_add_8(&bo, 0);       // stream priority (0-3)
1008
1009     // decoder configuration description tag
1010     bo_add_mp4_tag_descr(&bo, 0x04, config_size);
1011     bo_add_8(&bo, 32);      // object type identification (32 == MPEG4)
1012     bo_add_8(&bo, 0x11);    // stream type
1013     bo_add_24be(&bo, 0);    // buffer size
1014     bo_add_32be(&bo, 0);    // max bitrate
1015     bo_add_32be(&bo, 0);    // avg bitrate
1016
1017     // decoder specific description tag
1018     bo_add_mp4_tag_descr(&bo, 0x05, i_buf_size);
1019     bo_add_mem(&bo, i_buf_size, p_buf);
1020
1021     // sync layer configuration description tag
1022     bo_add_8(&bo, 0x06);    // tag
1023     bo_add_8(&bo, 0x01);    // length
1024     bo_add_8(&bo, 0x02);    // no SL
1025
1026     int i_ret = ExtradataInfoCreate(p_dec, CFSTR("esds"), bo.b->p_buffer,
1027                                     bo.b->i_buffer);
1028     bo_deinit(&bo);
1029     return i_ret;
1030 }
1031
1032 static int avcCFromAnnexBCreate(decoder_t *p_dec)
1033 {
1034     decoder_sys_t *p_sys = p_dec->p_sys;
1035
1036     if (p_sys->hh.h264.i_sps_count == 0 || p_sys->hh.h264.i_pps_count == 0)
1037         return VLC_EGENERIC;
1038
1039     unsigned i_h264_width, i_h264_height, i_video_width, i_video_height;
1040     int i_sar_num, i_sar_den, i_ret;
1041     i_ret = h264_helper_get_current_picture_size(&p_sys->hh,
1042                                                  &i_h264_width, &i_h264_height,
1043                                                  &i_video_width, &i_video_height);
1044     if (i_ret != VLC_SUCCESS)
1045         return i_ret;
1046     i_ret = h264_helper_get_current_sar(&p_sys->hh, &i_sar_num, &i_sar_den);
1047     if (i_ret != VLC_SUCCESS)
1048         return i_ret;
1049
1050     p_dec->fmt_out.video.i_visible_width =
1051     p_dec->fmt_out.video.i_width = i_video_width;
1052     p_dec->fmt_out.video.i_visible_height =
1053     p_dec->fmt_out.video.i_height = i_video_height;
1054     p_dec->fmt_out.video.i_sar_num = i_sar_num;
1055     p_dec->fmt_out.video.i_sar_den = i_sar_den;
1056
1057     block_t *p_avcC = h264_helper_get_avcc_config(&p_sys->hh);
1058     if (!p_avcC)
1059         return VLC_EGENERIC;
1060
1061     i_ret = ExtradataInfoCreate(p_dec, CFSTR("avcC"), p_avcC->p_buffer,
1062                                 p_avcC->i_buffer);
1063     block_Release(p_avcC);
1064     return i_ret;
1065 }
1066
1067 static int ExtradataInfoCreate(decoder_t *p_dec, CFStringRef name, void *p_data,
1068                                size_t i_data)
1069 {
1070     decoder_sys_t *p_sys = p_dec->p_sys;
1071
1072     p_sys->extradataInfo =
1073         CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
1074                                   &kCFTypeDictionaryKeyCallBacks,
1075                                   &kCFTypeDictionaryValueCallBacks);
1076     if (p_sys->extradataInfo == nil)
1077         return VLC_EGENERIC;
1078
1079     if (p_data == NULL)
1080         return VLC_SUCCESS;
1081
1082     CFDataRef extradata = CFDataCreate(kCFAllocatorDefault, p_data, i_data);
1083     if (extradata == nil)
1084     {
1085         CFRelease(p_sys->extradataInfo);
1086         p_sys->extradataInfo = nil;
1087         return VLC_EGENERIC;
1088     }
1089     CFDictionarySetValue(p_sys->extradataInfo, name, extradata);
1090     CFRelease(extradata);
1091     return VLC_SUCCESS;
1092 }
1093
1094 static CMSampleBufferRef VTSampleBufferCreate(decoder_t *p_dec,
1095                                               CMFormatDescriptionRef fmt_desc,
1096                                               block_t *p_block)
1097 {
1098     OSStatus status;
1099     CMBlockBufferRef  block_buf = NULL;
1100     CMSampleBufferRef sample_buf = NULL;
1101     CMTime pts;
1102     if(!p_dec->p_sys->b_poc_based_reorder && p_block->i_pts == VLC_TS_INVALID)
1103         pts = CMTimeMake(p_block->i_dts, CLOCK_FREQ);
1104     else
1105         pts = CMTimeMake(p_block->i_pts, CLOCK_FREQ);
1106
1107     CMSampleTimingInfo timeInfoArray[1] = { {
1108         .duration = CMTimeMake(p_block->i_length, 1),
1109         .presentationTimeStamp = pts,
1110         .decodeTimeStamp = CMTimeMake(p_block->i_dts, CLOCK_FREQ),
1111     } };
1112
1113     status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault,// structureAllocator
1114                                                 p_block->p_buffer,  // memoryBlock
1115                                                 p_block->i_buffer,  // blockLength
1116                                                 kCFAllocatorNull,   // blockAllocator
1117                                                 NULL,               // customBlockSource
1118                                                 0,                  // offsetToData
1119                                                 p_block->i_buffer,  // dataLength
1120                                                 false,              // flags
1121                                                 &block_buf);
1122
1123     if (!status) {
1124         status = CMSampleBufferCreate(kCFAllocatorDefault,  // allocator
1125                                       block_buf,            // dataBuffer
1126                                       TRUE,                 // dataReady
1127                                       0,                    // makeDataReadyCallback
1128                                       0,                    // makeDataReadyRefcon
1129                                       fmt_desc,             // formatDescription
1130                                       1,                    // numSamples
1131                                       1,                    // numSampleTimingEntries
1132                                       timeInfoArray,        // sampleTimingArray
1133                                       0,                    // numSampleSizeEntries
1134                                       NULL,                 // sampleSizeArray
1135                                       &sample_buf);
1136         if (status != noErr)
1137             msg_Warn(p_dec, "sample buffer creation failure %i", (int)status);
1138     } else
1139         msg_Warn(p_dec, "cm block buffer creation failure %i", (int)status);
1140
1141     if (block_buf != nil)
1142         CFRelease(block_buf);
1143     block_buf = nil;
1144
1145     return sample_buf;
1146 }
1147
1148 void VTDictionarySetInt32(CFMutableDictionaryRef dict, CFStringRef key, int value)
1149 {
1150     CFNumberRef number;
1151     number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
1152     CFDictionarySetValue(dict, key, number);
1153     CFRelease(number);
1154 }
1155
1156 static void copy420YpCbCr8Planar(picture_t *p_pic,
1157                                  CVPixelBufferRef buffer,
1158                                  unsigned i_width,
1159                                  unsigned i_height)
1160 {
1161     uint8_t *pp_plane[2];
1162     size_t pi_pitch[2];
1163
1164     if (!buffer || i_width == 0 || i_height == 0)
1165         return;
1166
1167     CVPixelBufferLockBaseAddress(buffer, kCVPixelBufferLock_ReadOnly);
1168
1169     for (int i = 0; i < 2; i++) {
1170         pp_plane[i] = CVPixelBufferGetBaseAddressOfPlane(buffer, i);
1171         pi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane(buffer, i);
1172     }
1173
1174     CopyFromNv12ToI420(p_pic, pp_plane, pi_pitch, i_height);
1175
1176     CVPixelBufferUnlockBaseAddress(buffer, kCVPixelBufferLock_ReadOnly);
1177 }
1178
1179 static int HandleVTStatus(decoder_t *p_dec, OSStatus status)
1180 {
1181 #define VTERRCASE(x) \
1182     case x: msg_Err(p_dec, "vt session error: '" #x "'"); break;
1183
1184     switch (status)
1185     {
1186         case 0:
1187             return VLC_SUCCESS;
1188
1189         VTERRCASE(kVTPropertyNotSupportedErr)
1190         VTERRCASE(kVTPropertyReadOnlyErr)
1191         VTERRCASE(kVTParameterErr)
1192         VTERRCASE(kVTInvalidSessionErr)
1193         VTERRCASE(kVTAllocationFailedErr)
1194         VTERRCASE(kVTPixelTransferNotSupportedErr)
1195         VTERRCASE(kVTCouldNotFindVideoDecoderErr)
1196         VTERRCASE(kVTCouldNotCreateInstanceErr)
1197         VTERRCASE(kVTCouldNotFindVideoEncoderErr)
1198         VTERRCASE(kVTVideoDecoderBadDataErr)
1199         VTERRCASE(kVTVideoDecoderUnsupportedDataFormatErr)
1200         VTERRCASE(kVTVideoDecoderMalfunctionErr)
1201         VTERRCASE(kVTVideoEncoderMalfunctionErr)
1202         VTERRCASE(kVTVideoDecoderNotAvailableNowErr)
1203         VTERRCASE(kVTImageRotationNotSupportedErr)
1204         VTERRCASE(kVTVideoEncoderNotAvailableNowErr)
1205         VTERRCASE(kVTFormatDescriptionChangeNotSupportedErr)
1206         VTERRCASE(kVTInsufficientSourceColorDataErr)
1207         VTERRCASE(kVTCouldNotCreateColorCorrectionDataErr)
1208         VTERRCASE(kVTColorSyncTransformConvertFailedErr)
1209         VTERRCASE(kVTVideoDecoderAuthorizationErr)
1210         VTERRCASE(kVTVideoEncoderAuthorizationErr)
1211         VTERRCASE(kVTColorCorrectionPixelTransferFailedErr)
1212         VTERRCASE(kVTMultiPassStorageIdentifierMismatchErr)
1213         VTERRCASE(kVTMultiPassStorageInvalidErr)
1214         VTERRCASE(kVTFrameSiloInvalidTimeStampErr)
1215         VTERRCASE(kVTFrameSiloInvalidTimeRangeErr)
1216         VTERRCASE(kVTCouldNotFindTemporalFilterErr)
1217         VTERRCASE(kVTPixelTransferNotPermittedErr)
1218         case -12219:
1219             msg_Err(p_dec, "vt session error: "
1220                     "'kVTColorCorrectionImageRotationFailedErr'");
1221             break;
1222         default:
1223             msg_Err(p_dec, "unknown vt session error (%i)", (int)status);
1224     }
1225 #undef VTERRCASE
1226     return VLC_EGENERIC;
1227 }
1228
1229 #pragma mark - actual decoding
1230
1231 static void Flush(decoder_t *p_dec)
1232 {
1233     decoder_sys_t *p_sys = p_dec->p_sys;
1234
1235     /* There is no Flush in VT api, ask to restart VT from next DecodeBlock if
1236      * we already feed some input blocks (it's better to not restart here in
1237      * order to avoid useless restart just before a close). */
1238     p_sys->b_vt_flush = p_sys->b_vt_feed;
1239 }
1240
1241 static void Drain(decoder_t *p_dec)
1242 {
1243     decoder_sys_t *p_sys = p_dec->p_sys;
1244
1245     /* draining: return last pictures of the reordered queue */
1246     if (p_sys->session)
1247         VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
1248
1249     vlc_mutex_lock(&p_sys->lock);
1250     DrainDPB( p_dec );
1251     vlc_mutex_unlock(&p_sys->lock);
1252 }
1253
1254 static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
1255 {
1256     decoder_sys_t *p_sys = p_dec->p_sys;
1257
1258     if (p_sys->b_vt_flush) {
1259         RestartVideoToolbox(p_dec, false);
1260         p_sys->b_vt_flush = false;
1261     }
1262
1263     if (p_block == NULL)
1264     {
1265         Drain(p_dec);
1266         return VLCDEC_SUCCESS;
1267     }
1268
1269     vlc_mutex_lock(&p_sys->lock);
1270     if (p_sys->b_abort) { /* abort from output thread (DecoderCallback) */
1271         vlc_mutex_unlock(&p_sys->lock);
1272         /* Add an empty variable so that videotoolbox won't be loaded again for
1273         * this ES */
1274         var_Create(p_dec, "videotoolbox-failed", VLC_VAR_VOID);
1275         return VLCDEC_RELOAD;
1276     }
1277     vlc_mutex_unlock(&p_sys->lock);
1278
1279     if (unlikely(p_block->i_flags&(BLOCK_FLAG_CORRUPTED)))
1280     {
1281         if (p_sys->b_vt_feed)
1282         {
1283             Drain(p_dec);
1284             RestartVideoToolbox(p_dec, false);
1285         }
1286         goto skip;
1287     }
1288
1289     bool b_config_changed = false;
1290     if (p_sys->codec == kCMVideoCodecType_H264)
1291     {
1292         p_block = p_sys->hh.pf_process_block(&p_sys->hh, p_block, &b_config_changed);
1293         if (!p_block)
1294             return VLCDEC_SUCCESS;
1295     }
1296
1297     if (b_config_changed)
1298     {
1299         /* decoding didn't start yet, which is ok for H264, let's see
1300          * if we can use this block to get going */
1301         assert(p_sys->codec == kCMVideoCodecType_H264);
1302         if (p_sys->session)
1303         {
1304             msg_Dbg(p_dec, "SPS/PPS changed: draining H264 decoder");
1305             Drain(p_dec);
1306             msg_Dbg(p_dec, "SPS/PPS changed: restarting H264 decoder");
1307             StopVideoToolbox(p_dec, true);
1308         }
1309
1310         int i_ret = avcCFromAnnexBCreate(p_dec);
1311         if (i_ret == VLC_SUCCESS)
1312         {
1313             if ((p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK)
1314              && var_InheritBool(p_dec, "videotoolbox-temporal-deinterlacing"))
1315                 p_sys->b_enable_temporal_processing = true;
1316
1317             msg_Dbg(p_dec, "Got SPS/PPS: late opening of H264 decoder");
1318             StartVideoToolbox(p_dec);
1319         }
1320         if (!p_sys->session)
1321             goto skip;
1322     }
1323
1324     frame_info_t *p_info = CreateReorderInfo(p_dec, p_block);
1325     if(unlikely(!p_info))
1326         goto skip;
1327
1328     CMSampleBufferRef sampleBuffer =
1329         VTSampleBufferCreate(p_dec, p_sys->videoFormatDescription, p_block);
1330     if (unlikely(!sampleBuffer))
1331     {
1332         free(p_info);
1333         goto skip;
1334     }
1335
1336     VTDecodeInfoFlags flagOut;
1337     VTDecodeFrameFlags decoderFlags = kVTDecodeFrame_EnableAsynchronousDecompression;
1338     if (unlikely(p_sys->b_enable_temporal_processing))
1339         decoderFlags |= kVTDecodeFrame_EnableTemporalProcessing;
1340
1341     OSStatus status =
1342         VTDecompressionSessionDecodeFrame(p_sys->session, sampleBuffer,
1343                                           decoderFlags, p_info, &flagOut);
1344     if (HandleVTStatus(p_dec, status) == VLC_SUCCESS)
1345         p_sys->b_vt_feed = true;
1346     else
1347     {
1348         bool b_abort = false;
1349         switch (status)
1350         {
1351             case -8960 /* codecErr */:
1352             case kCVReturnInvalidArgument:
1353             case kVTVideoDecoderMalfunctionErr:
1354                 b_abort = true;
1355                 break;
1356             case -8969 /* codecBadDataErr */:
1357             case kVTVideoDecoderBadDataErr:
1358                 if (RestartVideoToolbox(p_dec, true) == VLC_SUCCESS)
1359                 {
1360                     status = VTDecompressionSessionDecodeFrame(p_sys->session,
1361                                     sampleBuffer, decoderFlags, p_info, &flagOut);
1362
1363                     if (status != 0)
1364                     {
1365                         free( p_info );
1366                         b_abort = true;
1367                     }
1368                 }
1369                 break;
1370             case kVTInvalidSessionErr:
1371                 RestartVideoToolbox(p_dec, true);
1372                 break;
1373         }
1374         if (b_abort)
1375         {
1376             msg_Err(p_dec, "decoder failure, Abort.");
1377             /* The decoder module will be reloaded next time since we already
1378              * modified the input block */
1379             vlc_mutex_lock(&p_sys->lock);
1380             p_dec->p_sys->b_abort = true;
1381             vlc_mutex_unlock(&p_sys->lock);
1382         }
1383     }
1384     CFRelease(sampleBuffer);
1385
1386 skip:
1387     block_Release(p_block);
1388     return VLCDEC_SUCCESS;
1389 }
1390
1391 static int UpdateVideoFormat(decoder_t *p_dec, CVPixelBufferRef imageBuffer)
1392 {
1393     CFDictionaryRef attachments = CVBufferGetAttachments(imageBuffer, kCVAttachmentMode_ShouldPropagate);
1394     NSDictionary *attachmentDict = (NSDictionary *)attachments;
1395 #ifndef NDEBUG
1396     NSLog(@"%@", attachments);
1397 #endif
1398     if (attachmentDict == nil || attachmentDict.count == 0)
1399         return -1;
1400
1401     NSString *colorSpace = attachmentDict[(NSString *)kCVImageBufferYCbCrMatrixKey];
1402     if (colorSpace != nil) {
1403         if ([colorSpace isEqualToString:(NSString *)kCVImageBufferYCbCrMatrix_ITU_R_601_4])
1404             p_dec->fmt_out.video.space = COLOR_SPACE_BT601;
1405         else if ([colorSpace isEqualToString:(NSString *)kCVImageBufferYCbCrMatrix_ITU_R_709_2])
1406             p_dec->fmt_out.video.space = COLOR_SPACE_BT709;
1407         else
1408             p_dec->fmt_out.video.space = COLOR_SPACE_UNDEF;
1409     }
1410
1411     NSString *colorprimary = attachmentDict[(NSString *)kCVImageBufferColorPrimariesKey];
1412     if (colorprimary != nil) {
1413         if ([colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_SMPTE_C] ||
1414             [colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_EBU_3213])
1415             p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT601_625;
1416         else if ([colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_ITU_R_709_2])
1417             p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_BT709;
1418         else if ([colorprimary isEqualToString:(NSString *)kCVImageBufferColorPrimaries_P22])
1419             p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_DCI_P3;
1420         else
1421             p_dec->fmt_out.video.primaries = COLOR_PRIMARIES_UNDEF;
1422     }
1423
1424     NSString *transfer = attachmentDict[(NSString *)kCVImageBufferTransferFunctionKey];
1425     if (transfer != nil) {
1426         if ([transfer isEqualToString:(NSString *)kCVImageBufferTransferFunction_ITU_R_709_2] ||
1427             [transfer isEqualToString:(NSString *)kCVImageBufferTransferFunction_SMPTE_240M_1995])
1428             p_dec->fmt_out.video.transfer = TRANSFER_FUNC_BT709;
1429         else
1430             p_dec->fmt_out.video.transfer = TRANSFER_FUNC_UNDEF;
1431     }
1432
1433     NSString *chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationTopFieldKey];
1434     if (chromaLocation != nil) {
1435         if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Left] ||
1436             [chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_DV420])
1437             p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_LEFT;
1438         else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Center])
1439             p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_CENTER;
1440         else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_TopLeft])
1441             p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_LEFT;
1442         else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Top])
1443             p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_TOP_CENTER;
1444         else
1445             p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_UNDEF;
1446     }
1447     if (p_dec->fmt_out.video.chroma_location == CHROMA_LOCATION_UNDEF) {
1448         chromaLocation = attachmentDict[(NSString *)kCVImageBufferChromaLocationBottomFieldKey];
1449         if (chromaLocation != nil) {
1450             if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_BottomLeft])
1451                 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_LEFT;
1452             else if ([chromaLocation isEqualToString:(NSString *)kCVImageBufferChromaLocation_Bottom])
1453                 p_dec->fmt_out.video.chroma_location = CHROMA_LOCATION_BOTTOM_CENTER;
1454         }
1455     }
1456
1457     uint32_t cvfmt = CVPixelBufferGetPixelFormatType(imageBuffer);
1458     switch (cvfmt)
1459     {
1460         case kCVPixelFormatType_422YpCbCr8:
1461         case 'yuv2':
1462             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_UYVY;
1463             assert(CVPixelBufferIsPlanar(imageBuffer) == false);
1464             break;
1465         case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
1466         case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
1467             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_NV12;
1468             assert(CVPixelBufferIsPlanar(imageBuffer) == true);
1469             break;
1470         case kCVPixelFormatType_420YpCbCr8Planar:
1471             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_I420;
1472             assert(CVPixelBufferIsPlanar(imageBuffer) == true);
1473             break;
1474         case kCVPixelFormatType_32BGRA:
1475             p_dec->fmt_out.i_codec = VLC_CODEC_CVPX_BGRA;
1476             assert(CVPixelBufferIsPlanar(imageBuffer) == false);
1477             break;
1478         default:
1479             p_dec->p_sys->b_abort = true;
1480             return -1;
1481     }
1482     return decoder_UpdateVideoFormat(p_dec);
1483 }
1484
1485 static void DecoderCallback(void *decompressionOutputRefCon,
1486                             void *sourceFrameRefCon,
1487                             OSStatus status,
1488                             VTDecodeInfoFlags infoFlags,
1489                             CVPixelBufferRef imageBuffer,
1490                             CMTime pts,
1491                             CMTime duration)
1492 {
1493     VLC_UNUSED(duration);
1494     decoder_t *p_dec = (decoder_t *)decompressionOutputRefCon;
1495     decoder_sys_t *p_sys = p_dec->p_sys;
1496     frame_info_t *p_info = (frame_info_t *) sourceFrameRefCon;
1497
1498     if (status != noErr) {
1499         msg_Warn(p_dec, "decoding of a frame failed (%i, %u)", (int)status, (unsigned int) infoFlags);
1500         if( status != kVTVideoDecoderBadDataErr && status != -8969 )
1501             free(p_info);
1502         return;
1503     }
1504     assert(imageBuffer);
1505
1506     if (unlikely(!p_sys->b_format_propagated)) {
1507         vlc_mutex_lock(&p_sys->lock);
1508         p_sys->b_format_propagated =
1509             UpdateVideoFormat(p_dec, imageBuffer) == VLC_SUCCESS;
1510         vlc_mutex_unlock(&p_sys->lock);
1511
1512         if (!p_sys->b_format_propagated)
1513         {
1514             free(p_info);
1515             return;
1516         }
1517         assert(p_dec->fmt_out.i_codec != 0);
1518     }
1519
1520     if (infoFlags & kVTDecodeInfo_FrameDropped)
1521     {
1522         /* We can't trust VT, some decoded frames can be marked as dropped */
1523         msg_Dbg(p_dec, "decoder dropped frame");
1524     }
1525
1526     if (!CMTIME_IS_VALID(pts))
1527     {
1528         free(p_info);
1529         return;
1530     }
1531
1532     if (CVPixelBufferGetDataSize(imageBuffer) == 0)
1533     {
1534         free(p_info);
1535         return;
1536     }
1537
1538     if(likely(p_info))
1539     {
1540         picture_t *p_pic = decoder_NewPicture(p_dec);
1541         if (!p_pic)
1542         {
1543             free(p_info);
1544             return;
1545         }
1546
1547         if (unlikely(!p_pic->p_sys)) {
1548             vlc_mutex_lock(&p_sys->lock);
1549             p_dec->p_sys->b_abort = true;
1550             vlc_mutex_unlock(&p_sys->lock);
1551             picture_Release(p_pic);
1552             free(p_info);
1553             return;
1554         }
1555
1556         /* Can happen if the pic was discarded */
1557         if (p_pic->p_sys->pixelBuffer != nil)
1558             CFRelease(p_pic->p_sys->pixelBuffer);
1559
1560         /* will be freed by the vout */
1561         p_pic->p_sys->pixelBuffer = CVPixelBufferRetain(imageBuffer);
1562
1563         p_info->p_picture = p_pic;
1564
1565         p_pic->date = pts.value;
1566         p_pic->b_progressive = p_info->b_progressive;
1567         if(!p_pic->b_progressive)
1568         {
1569             p_pic->i_nb_fields = p_info->i_num_ts;
1570             p_pic->b_top_field_first = p_info->b_top_field_first;
1571         }
1572
1573         vlc_mutex_lock(&p_sys->lock);
1574         OnDecodedFrame( p_dec, p_info );
1575         vlc_mutex_unlock(&p_sys->lock);
1576     }
1577
1578     return;
1579 }