[osx] fixed, vda decoder under 10.6.4+. reserving 16 ref frames is silly. request...
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / DVDVideoCodecVDA.cpp
1 /*
2  *      Copyright (C) 2005-2010 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
23   #include "config.h"
24 #endif
25
26 #if defined(HAVE_LIBVDADECODER)
27 #include "DynamicDll.h"
28 #include "GUISettings.h"
29 #include "DVDClock.h"
30 #include "DVDStreamInfo.h"
31 #include "DVDVideoCodecVDA.h"
32 #include "Codecs/DllAvFormat.h"
33 #include "Codecs/DllSwScale.h"
34 #include "utils/log.h"
35 #include "utils/TimeUtils.h"
36 #include "osx/CocoaInterface.h"
37 #include <CoreFoundation/CoreFoundation.h>
38
39 /*
40  * if extradata size is greater than 7, then have a valid quicktime 
41  * avcC atom header.
42  *
43  *      -: avcC atom header :-
44  *  -----------------------------------
45  *  1 byte  - version
46  *  1 byte  - h.264 stream profile
47  *  1 byte  - h.264 compatible profiles
48  *  1 byte  - h.264 stream level
49  *  6 bits  - reserved set to 63
50  *  2 bits  - NAL length 
51  *            ( 0 - 1 byte; 1 - 2 bytes; 3 - 4 bytes)
52  *  3 bit   - reserved
53  *  5 bits  - number of SPS 
54  *  for (i=0; i < number of SPS; i++) {
55  *      2 bytes - SPS length
56  *      SPS length bytes - SPS NAL unit
57  *  }
58  *  1 byte  - number of PPS
59  *  for (i=0; i < number of PPS; i++) {
60  *      2 bytes - PPS length 
61  *      PPS length bytes - PPS NAL unit 
62  *  }
63  
64  how to detect the interlacing used on an existing stream:
65 - progressive is signalled by setting frame_mbs_only_flag: 1 in the SPS
66 - interlaced is signalled by setting frame_mbs_only_flag: 0 in the SPS and field_pic_flag: 1 on all frames
67 - paff is signalled by setting frame_mbs_only_flag: 0 in the SPS and field_pic_flag: 1 on all frames that get interlaced and field_pic_flag: 0 on all frames that get progressive
68 - mbaff is signalled by setting frame_mbs_only_flag: 0 and mb_adaptive_frame_field_flag: 1 in the SPS and field_pic_flag: 0 on the frames (field_pic_flag: 1 would indicate a normal interlaced frame)
69 */
70
71 // missing in 10.4/10.5 SDKs.
72 #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060)
73 #include "dlfcn.h"
74 enum {
75   // component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1 .
76   kCVPixelFormatType_422YpCbCr8 = FourCharCode('2vuy'),
77   kCVPixelFormatType_32BGRA = FourCharCode('BGRA')
78 };
79 #endif
80
81 ////////////////////////////////////////////////////////////////////////////////////////////
82 // http://developer.apple.com/mac/library/technotes/tn2010/tn2267.html
83 // VDADecoder API (keep this until VDADecoder.h is public).
84 // #include <VideoDecodeAcceleration/VDADecoder.h>
85 enum {
86   kVDADecoderNoErr = 0,
87   kVDADecoderHardwareNotSupportedErr = -12470,
88   kVDADecoderFormatNotSupportedErr = -12471,
89   kVDADecoderConfigurationError = -12472,
90   kVDADecoderDecoderFailedErr = -12473,
91 };
92 enum {
93   kVDADecodeInfo_Asynchronous = 1UL << 0,
94   kVDADecodeInfo_FrameDropped = 1UL << 1
95 };
96 enum {
97   // tells the decoder not to bother returning a CVPixelBuffer
98   // in the outputCallback. The output callback will still be called.
99   kVDADecoderDecodeFlags_DontEmitFrame = 1 << 0
100 };
101 enum {
102   // decode and return buffers for all frames currently in flight.
103   kVDADecoderFlush_EmitFrames = 1 << 0          
104 };
105
106 typedef struct OpaqueVDADecoder* VDADecoder;
107
108 typedef void (*VDADecoderOutputCallback)(
109   void *decompressionOutputRefCon,
110   CFDictionaryRef frameInfo,
111   OSStatus status,
112   uint32_t infoFlags,
113   CVImageBufferRef imageBuffer);
114
115 ////////////////////////////////////////////////////////////////////////////////////////////
116 class DllLibVDADecoderInterface
117 {
118 public:
119   virtual ~DllLibVDADecoderInterface() {}
120   virtual OSStatus VDADecoderCreate(
121     CFDictionaryRef decoderConfiguration, CFDictionaryRef destinationImageBufferAttributes,
122     VDADecoderOutputCallback *outputCallback, void *decoderOutputCallbackRefcon, VDADecoder *decoderOut) = 0;
123   virtual OSStatus VDADecoderDecode(
124     VDADecoder decoder, uint32_t decodeFlags, CFTypeRef compressedBuffer, CFDictionaryRef frameInfo) = 0;
125   virtual OSStatus VDADecoderFlush(VDADecoder decoder, uint32_t flushFlags) = 0;
126   virtual OSStatus VDADecoderDestroy(VDADecoder decoder) = 0;
127   virtual CFStringRef Get_kVDADecoderConfiguration_Height() = 0;
128   virtual CFStringRef Get_kVDADecoderConfiguration_Width() = 0;
129   virtual CFStringRef Get_kVDADecoderConfiguration_SourceFormat() = 0;
130   virtual CFStringRef Get_kVDADecoderConfiguration_avcCData() = 0;
131 };
132
133 class DllLibVDADecoder : public DllDynamic, DllLibVDADecoderInterface
134 {
135   DECLARE_DLL_WRAPPER(DllLibVDADecoder, DLL_PATH_LIBVDADECODER)
136
137   DEFINE_METHOD5(OSStatus, VDADecoderCreate, (CFDictionaryRef p1, CFDictionaryRef p2, VDADecoderOutputCallback* p3, void* p4, VDADecoder* p5))
138   DEFINE_METHOD4(OSStatus, VDADecoderDecode, (VDADecoder p1, uint32_t p2, CFTypeRef p3, CFDictionaryRef p4))
139   DEFINE_METHOD2(OSStatus, VDADecoderFlush, (VDADecoder p1, uint32_t p2))
140   DEFINE_METHOD1(OSStatus, VDADecoderDestroy, (VDADecoder p1))
141   DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_Height)
142   DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_Width)
143   DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_SourceFormat)
144   DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_avcCData)
145   BEGIN_METHOD_RESOLVE()
146     RESOLVE_METHOD(VDADecoderCreate)
147     RESOLVE_METHOD(VDADecoderDecode)
148     RESOLVE_METHOD(VDADecoderFlush)
149     RESOLVE_METHOD(VDADecoderDestroy)
150     RESOLVE_METHOD(kVDADecoderConfiguration_Height)
151     RESOLVE_METHOD(kVDADecoderConfiguration_Width)
152     RESOLVE_METHOD(kVDADecoderConfiguration_SourceFormat)
153     RESOLVE_METHOD(kVDADecoderConfiguration_avcCData)
154   END_METHOD_RESOLVE()
155 };
156
157 ////////////////////////////////////////////////////////////////////////////////////////////
158 // helper function that wraps dts/pts into a dictionary
159 static CFDictionaryRef CreateDictionaryWithDisplayTime(double time, double dts, double pts)
160 {
161   CFStringRef key[3] = {
162     CFSTR("VideoDisplay_TIME"),
163     CFSTR("VideoDisplay_DTS"),
164     CFSTR("VideoDisplay_PTS")};
165   CFNumberRef value[3];
166   CFDictionaryRef display_time;
167
168   value[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &time);
169   value[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &dts);
170   value[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &pts);
171
172   display_time = CFDictionaryCreate(
173     kCFAllocatorDefault, (const void **)&key, (const void **)&value, 3,
174     &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
175   
176   CFRelease(value[0]);
177   CFRelease(value[1]);
178   CFRelease(value[2]);
179
180   return display_time;
181 }
182
183 // helper function to extract dts/pts from a dictionary
184 static void GetFrameDisplayTimeFromDictionary(
185   CFDictionaryRef inFrameInfoDictionary, frame_queue *frame)
186 {
187   // default to DVD_NOPTS_VALUE
188   frame->sort_time = -1.0;
189   frame->dts = DVD_NOPTS_VALUE;
190   frame->pts = DVD_NOPTS_VALUE;
191   if (inFrameInfoDictionary == NULL)
192     return;
193
194   CFNumberRef value[3];
195   //
196   value[0] = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplay_TIME"));
197   if (value[0])
198     CFNumberGetValue(value[0], kCFNumberDoubleType, &frame->sort_time);
199   value[1] = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplay_DTS"));
200   if (value[1])
201     CFNumberGetValue(value[1], kCFNumberDoubleType, &frame->dts);
202   value[2] = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplay_PTS"));
203   if (value[2])
204     CFNumberGetValue(value[2], kCFNumberDoubleType, &frame->pts);
205
206   return;
207 }
208
209 ////////////////////////////////////////////////////////////////////////////////////////////
210 // TODO: refactor this so as not to need these ffmpeg routines.
211 // These are not exposed in ffmpeg's API so we dupe them here.
212 // AVC helper functions for muxers,
213 //  * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
214 // This is part of FFmpeg
215 //  * License as published by the Free Software Foundation; either
216 //  * version 2.1 of the License, or (at your option) any later version.
217 #define VDA_RB24(x)                          \
218   ((((const uint8_t*)(x))[0] << 16) |        \
219    (((const uint8_t*)(x))[1] <<  8) |        \
220    ((const uint8_t*)(x))[2])
221
222 #define VDA_RB32(x)                          \
223   ((((const uint8_t*)(x))[0] << 24) |        \
224    (((const uint8_t*)(x))[1] << 16) |        \
225    (((const uint8_t*)(x))[2] <<  8) |        \
226    ((const uint8_t*)(x))[3])
227
228 static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
229 {
230   const uint8_t *a = p + 4 - ((intptr_t)p & 3);
231
232   for (end -= 3; p < a && p < end; p++)
233   {
234     if (p[0] == 0 && p[1] == 0 && p[2] == 1)
235       return p;
236   }
237
238   for (end -= 3; p < end; p += 4)
239   {
240     uint32_t x = *(const uint32_t*)p;
241     if ((x - 0x01010101) & (~x) & 0x80808080) // generic
242     {
243       if (p[1] == 0)
244       {
245         if (p[0] == 0 && p[2] == 1)
246           return p;
247         if (p[2] == 0 && p[3] == 1)
248           return p+1;
249       }
250       if (p[3] == 0)
251       {
252         if (p[2] == 0 && p[4] == 1)
253           return p+2;
254         if (p[4] == 0 && p[5] == 1)
255           return p+3;
256       }
257     }
258   }
259
260   for (end += 3; p < end; p++)
261   {
262     if (p[0] == 0 && p[1] == 0 && p[2] == 1)
263       return p;
264   }
265
266   return end + 3;
267 }
268
269 const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end)
270 {
271   const uint8_t *out= avc_find_startcode_internal(p, end);
272   if (p<out && out<end && !out[-1])
273     out--;
274   return out;
275 }
276
277 const int avc_parse_nal_units(DllAvFormat *av_format_ctx,
278   ByteIOContext *pb, const uint8_t *buf_in, int size)
279 {
280   const uint8_t *p = buf_in;
281   const uint8_t *end = p + size;
282   const uint8_t *nal_start, *nal_end;
283
284   size = 0;
285   nal_start = avc_find_startcode(p, end);
286   while (nal_start < end)
287   {
288     while (!*(nal_start++));
289     nal_end = avc_find_startcode(nal_start, end);
290     av_format_ctx->put_be32(pb, nal_end - nal_start);
291     av_format_ctx->put_buffer(pb, nal_start, nal_end - nal_start);
292     size += 4 + nal_end - nal_start;
293     nal_start = nal_end;
294   }
295   return size;
296 }
297
298 const int avc_parse_nal_units_buf(DllAvUtil *av_util_ctx, DllAvFormat *av_format_ctx,
299   const uint8_t *buf_in, uint8_t **buf, int *size)
300 {
301   ByteIOContext *pb;
302   int ret = av_format_ctx->url_open_dyn_buf(&pb);
303   if (ret < 0)
304     return ret;
305
306   avc_parse_nal_units(av_format_ctx, pb, buf_in, *size);
307
308   av_util_ctx->av_freep(buf);
309   *size = av_format_ctx->url_close_dyn_buf(pb, buf);
310   return 0;
311 }
312
313 const int isom_write_avcc(DllAvUtil *av_util_ctx, DllAvFormat *av_format_ctx,
314   ByteIOContext *pb, const uint8_t *data, int len)
315 {
316   // extradata from bytestream h264, convert to avcC atom data for bitstream
317   if (len > 6)
318   {
319     /* check for h264 start code */
320     if (VDA_RB32(data) == 0x00000001 || VDA_RB24(data) == 0x000001)
321     {
322       uint8_t *buf=NULL, *end, *start;
323       uint32_t sps_size=0, pps_size=0;
324       uint8_t *sps=0, *pps=0;
325
326       int ret = avc_parse_nal_units_buf(av_util_ctx, av_format_ctx, data, &buf, &len);
327       if (ret < 0)
328         return ret;
329       start = buf;
330       end = buf + len;
331
332       /* look for sps and pps */
333       while (buf < end)
334       {
335         unsigned int size;
336         uint8_t nal_type;
337         size = VDA_RB32(buf);
338         nal_type = buf[4] & 0x1f;
339         if (nal_type == 7) /* SPS */
340         {
341           sps = buf + 4;
342           sps_size = size;
343         }
344         else if (nal_type == 8) /* PPS */
345         {
346           pps = buf + 4;
347           pps_size = size;
348         }
349         buf += size + 4;
350       }
351       assert(sps);
352       assert(pps);
353
354       av_format_ctx->put_byte(pb, 1); /* version */
355       av_format_ctx->put_byte(pb, sps[1]); /* profile */
356       av_format_ctx->put_byte(pb, sps[2]); /* profile compat */
357       av_format_ctx->put_byte(pb, sps[3]); /* level */
358       av_format_ctx->put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
359       av_format_ctx->put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
360
361       av_format_ctx->put_be16(pb, sps_size);
362       av_format_ctx->put_buffer(pb, sps, sps_size);
363       av_format_ctx->put_byte(pb, 1); /* number of pps */
364       av_format_ctx->put_be16(pb, pps_size);
365       av_format_ctx->put_buffer(pb, pps, pps_size);
366       av_util_ctx->av_free(start);
367     }
368     else
369     {
370       av_format_ctx->put_buffer(pb, data, len);
371     }
372   }
373   return 0;
374 }
375
376 static DllLibVDADecoder *g_DllLibVDADecoder = (DllLibVDADecoder*)-1;
377 ////////////////////////////////////////////////////////////////////////////////////////////
378 ////////////////////////////////////////////////////////////////////////////////////////////
379 CDVDVideoCodecVDA::CDVDVideoCodecVDA() : CDVDVideoCodec()
380 {
381   if (g_DllLibVDADecoder == (DllLibVDADecoder*)-1)
382   {
383     m_dll = new DllLibVDADecoder;
384     m_dll->Load();
385   }
386   else
387     m_dll = g_DllLibVDADecoder;
388
389   m_vda_decoder = NULL;
390   m_pFormatName = "vda-";
391
392   m_queue_depth = 0;
393   m_display_queue = NULL;
394   pthread_mutex_init(&m_queue_mutex, NULL);
395
396   m_convert_bytestream = false;
397   m_dllAvUtil = NULL;
398   m_dllAvFormat = NULL;
399   m_dllSwScale = NULL;
400   memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
401 }
402
403 CDVDVideoCodecVDA::~CDVDVideoCodecVDA()
404 {
405   Dispose();
406   pthread_mutex_destroy(&m_queue_mutex);
407   //delete m_dll;
408 }
409
410 bool CDVDVideoCodecVDA::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
411 {
412   if (g_guiSettings.GetBool("videoplayer.usevda") && !hints.software)
413   {
414     CCocoaAutoPool pool;
415     int32_t width, height, profile, level;
416     CFDataRef avcCData;
417     uint8_t *extradata; // extra data for codec to use
418     unsigned int extrasize; // size of extra data
419
420     //
421     width  = hints.width;
422     height = hints.height;
423     level  = hints.level;
424     profile = hints.profile;
425     extrasize = hints.extrasize;
426     extradata = (uint8_t*)hints.extradata;
427  
428     if (Cocoa_GPUForDisplayIsNvidiaPureVideo3())
429     {
430       // known hardware limitation of purevideo 3. (the Nvidia 9400 is a purevideo 3 chip)
431       // from nvidia's linux vdpau README: All current third generation PureVideo hardware
432       // (G98, MCP77, MCP78, MCP79, MCP7A) cannot decode H.264 for the following horizontal resolutions:
433       // 769-784, 849-864, 929-944, 1009–1024, 1793–1808, 1873–1888, 1953–1968 and 2033-2048 pixel.
434       // This relates to the following macroblock sizes.
435       int macroblocksize[] = {49, 54, 59, 64, 113, 118, 123, 128};
436       for (size_t i = 0; i < sizeof(macroblocksize)/sizeof(macroblocksize[0]); i++)
437       {
438         if (((width + 15) / 16) == macroblocksize[i])
439         {
440           CLog::Log(LOGNOTICE, "%s - Nvidia 9400 GPU hardware limitation, cannot decode a width of %d",
441             __FUNCTION__, width);
442           return false;
443         }
444       }
445     }
446
447     switch (hints.codec)
448     {
449       case CODEC_ID_H264:
450         // TODO: need to quality h264 encoding (profile, level and number of reference frame)
451         // source must be H.264 with valid avcC atom data in extradata
452         if (extrasize < 7 || extradata == NULL)
453         {
454           CLog::Log(LOGNOTICE, "%s - avcC atom too data small or missing", __FUNCTION__);
455           return false;
456         }
457         // valid avcC atom data always starts with the value 1 (version)
458         if ( *extradata != 1 )
459         {
460           if (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 && extradata[3] == 1)
461           {
462             // video content is from x264 or from bytestream h264 (AnnexB format)
463             // NAL reformating to bitstream format needed
464             m_dllAvUtil = new DllAvUtil;
465             m_dllAvFormat = new DllAvFormat;
466             if (!m_dllAvUtil->Load() || !m_dllAvFormat->Load())
467             {
468               return false;
469             }
470
471             ByteIOContext *pb;
472             if (m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
473             {
474               return false;
475             }
476
477             m_convert_bytestream = true;
478             // create a valid avcC atom data from ffmpeg's extradata
479             isom_write_avcc(m_dllAvUtil, m_dllAvFormat, pb, extradata, extrasize);
480             // unhook from ffmpeg's extradata
481             extradata = NULL;
482             // extract the avcC atom data into extradata then write it into avcCData for VDADecoder
483             extrasize = m_dllAvFormat->url_close_dyn_buf(pb, &extradata);
484             // CFDataCreate makes a copy of extradata contents
485             avcCData = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)extradata, extrasize);
486             // done with the converted extradata, we MUST free using av_free
487             m_dllAvUtil->av_free(extradata);
488           }
489           else
490           {
491             CLog::Log(LOGNOTICE, "%s - invalid avcC atom data", __FUNCTION__);
492             return false;
493           }
494         }
495         else
496         {
497           // CFDataCreate makes a copy of extradata contents
498           avcCData = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)extradata, extrasize);
499         }
500
501         m_format = 'avc1';
502         m_pFormatName = "vda-h264";
503       break;
504       default:
505         return false;
506       break;
507     }
508
509     // input stream is qualified, now we can load dlls.
510     m_dllSwScale = new DllSwScale;
511     if (!m_dllSwScale->Load())
512     {
513       CFRelease(avcCData);
514       return false;
515     }
516
517     // setup the decoder configuration dict
518     CFMutableDictionaryRef decoderConfiguration = CFDictionaryCreateMutable(
519       kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
520
521     CFNumberRef avcWidth  = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width);
522     CFNumberRef avcHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height);
523     CFNumberRef avcFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &m_format);
524
525     CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_Height(), avcHeight);
526     CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_Width(),  avcWidth);
527     CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_SourceFormat(), avcFormat);
528     CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_avcCData(), avcCData);
529
530     // release the retained object refs, decoderConfiguration owns them now
531     CFRelease(avcWidth);
532     CFRelease(avcHeight);
533     CFRelease(avcFormat);
534     CFRelease(avcCData);
535
536     // setup the destination image buffer dict, vda will output this pict format
537     CFMutableDictionaryRef destinationImageBufferAttributes = CFDictionaryCreateMutable(
538       kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
539
540     OSType cvPixelFormatType = kCVPixelFormatType_422YpCbCr8;
541     CFNumberRef pixelFormat  = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &cvPixelFormatType);
542     CFDictionarySetValue(destinationImageBufferAttributes, kCVPixelBufferPixelFormatTypeKey, pixelFormat);
543
544     // create the VDADecoder object
545     OSStatus status;
546     try
547     {
548       status = m_dll->VDADecoderCreate(decoderConfiguration, destinationImageBufferAttributes,
549         (VDADecoderOutputCallback *)VDADecoderCallback, this, (VDADecoder*)&m_vda_decoder);
550     }
551     catch (...)
552     {
553       CLog::Log(LOGERROR, "%s - exception",__FUNCTION__);
554       status = kVDADecoderDecoderFailedErr;
555     }
556     CFRelease(decoderConfiguration);
557     CFRelease(destinationImageBufferAttributes);
558     if (status != kVDADecoderNoErr)
559     {
560       CLog::Log(LOGNOTICE, "%s - VDADecoder Codec failed to open, status(%d), profile(%d), level(%d)",
561         __FUNCTION__, (int)status, profile, level);
562       return false;
563     }
564
565     // allocate a YV12 DVDVideoPicture buffer.
566     // first make sure all properties are reset.
567     memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
568     unsigned int iPixels = width * height;
569     unsigned int iChromaPixels = iPixels/4;
570
571     m_videobuffer.pts = DVD_NOPTS_VALUE;
572     m_videobuffer.iFlags = DVP_FLAG_ALLOCATED;
573     m_videobuffer.format = DVDVideoPicture::FMT_YUV420P;
574     m_videobuffer.color_range  = 0;
575     m_videobuffer.color_matrix = 4;
576     m_videobuffer.iWidth  = width;
577     m_videobuffer.iHeight = height;
578     m_videobuffer.iDisplayWidth  = width;
579     m_videobuffer.iDisplayHeight = height;
580
581     m_videobuffer.iLineSize[0] = width;   //Y
582     m_videobuffer.iLineSize[1] = width/2; //U
583     m_videobuffer.iLineSize[2] = width/2; //V
584     m_videobuffer.iLineSize[3] = 0;
585
586     m_videobuffer.data[0] = (BYTE*)malloc(iPixels);       //Y
587     m_videobuffer.data[1] = (BYTE*)malloc(iChromaPixels); //U
588     m_videobuffer.data[2] = (BYTE*)malloc(iChromaPixels); //V
589     m_videobuffer.data[3] = NULL;
590
591     // set all data to 0 for less artifacts.. hmm.. what is black in YUV??
592     memset(m_videobuffer.data[0], 0, iPixels);
593     memset(m_videobuffer.data[1], 0, iChromaPixels);
594     memset(m_videobuffer.data[2], 0, iChromaPixels);
595
596     m_DropPictures = false;
597     m_sort_time_offset = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency();
598
599     return true;
600   }
601
602   return false;
603 }
604
605 void CDVDVideoCodecVDA::Dispose()
606 {
607   CCocoaAutoPool pool;
608   if (m_vda_decoder)
609   {
610     m_dll->VDADecoderDestroy((VDADecoder)m_vda_decoder);
611     m_vda_decoder = NULL;
612   }
613   if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED)
614   {
615     free(m_videobuffer.data[0]);
616     free(m_videobuffer.data[1]);
617     free(m_videobuffer.data[2]);
618     m_videobuffer.iFlags = 0;
619   }
620   if (m_dllAvUtil)
621   {
622     delete m_dllAvUtil;
623     m_dllAvUtil = NULL;
624   }
625   if (m_dllAvFormat)
626   {
627     delete m_dllAvFormat;
628     m_dllAvFormat = NULL;
629   }
630   if (m_dllSwScale)
631   {
632     delete m_dllSwScale;
633     m_dllSwScale = NULL;
634   }
635 }
636
637 void CDVDVideoCodecVDA::SetDropState(bool bDrop)
638 {
639   m_DropPictures = bDrop;
640 }
641
642 int CDVDVideoCodecVDA::Decode(BYTE* pData, int iSize, double dts, double pts)
643 {
644   CCocoaAutoPool pool;
645   //
646   if (pData)
647   {
648     OSStatus status;
649     double sort_time;
650     uint32_t avc_flags = 0;
651     CFDataRef avc_demux;
652     CFDictionaryRef avc_time;
653
654     if (m_convert_bytestream)
655     {
656       // convert demuxer packet from bytestream (AnnexB) to bitstream
657       ByteIOContext *pb;
658       int demuxer_bytes;
659       uint8_t *demuxer_content;
660
661       if(m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
662       {
663         return VC_ERROR;
664       }
665       demuxer_bytes = avc_parse_nal_units(m_dllAvFormat, pb, pData, iSize);
666       demuxer_bytes = m_dllAvFormat->url_close_dyn_buf(pb, &demuxer_content);
667       avc_demux = CFDataCreate(kCFAllocatorDefault, demuxer_content, demuxer_bytes);
668       m_dllAvUtil->av_free(demuxer_content);
669     }
670     else
671     {
672       avc_demux = CFDataCreate(kCFAllocatorDefault, pData, iSize);
673     }
674     sort_time = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency();
675     avc_time = CreateDictionaryWithDisplayTime(sort_time - m_sort_time_offset, dts, pts);
676
677     if (m_DropPictures)
678       avc_flags = kVDADecoderDecodeFlags_DontEmitFrame;
679
680     status = m_dll->VDADecoderDecode((VDADecoder)m_vda_decoder, avc_flags, avc_demux, avc_time);
681     CFRelease(avc_time);
682     CFRelease(avc_demux);
683     if (status != kVDADecoderNoErr)
684     {
685       CLog::Log(LOGNOTICE, "%s - VDADecoderDecode failed, status(%d)", __FUNCTION__, (int)status);
686       return VC_ERROR;
687     }
688   }
689
690   // TODO: queue depth is related to the number of reference frames in encoded h.264.
691   // so we need to buffer until we get N ref frames + 1.
692   if (m_queue_depth < 4)
693   {
694     return VC_BUFFER;
695   }
696
697   return VC_PICTURE | VC_BUFFER;
698 }
699
700 void CDVDVideoCodecVDA::Reset(void)
701 {
702   CCocoaAutoPool pool;
703   m_dll->VDADecoderFlush((VDADecoder)m_vda_decoder, 0);
704
705   while (m_queue_depth)
706     DisplayQueuePop();
707
708   m_sort_time_offset = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency();
709 }
710
711 bool CDVDVideoCodecVDA::GetPicture(DVDVideoPicture* pDvdVideoPicture)
712 {
713   CCocoaAutoPool pool;
714   FourCharCode pixel_buffer_format;
715   CVPixelBufferRef picture_buffer_ref;
716
717   // clone the video picture buffer settings.
718   *pDvdVideoPicture = m_videobuffer;
719
720   // get the top yuv frame, we risk getting the wrong frame if the frame queue
721   // depth is less than the number of encoded reference frames. If queue depth
722   // is greater than the number of encoded reference frames, then the top frame
723   // will never change and we can just grab a ref to the top frame. This way
724   // we don't lockout the vdadecoder while doing color format convert.
725   pthread_mutex_lock(&m_queue_mutex);
726   picture_buffer_ref = m_display_queue->pixel_buffer_ref;
727   pixel_buffer_format = m_display_queue->pixel_buffer_format;
728   pDvdVideoPicture->dts = m_display_queue->dts;
729   pDvdVideoPicture->pts = m_display_queue->pts;
730   pthread_mutex_unlock(&m_queue_mutex);
731
732   // lock the CVPixelBuffer down
733   CVPixelBufferLockBaseAddress(picture_buffer_ref, 0);
734   int row_stride = CVPixelBufferGetBytesPerRowOfPlane(picture_buffer_ref, 0);
735   uint8_t *base_ptr = (uint8_t*)CVPixelBufferGetBaseAddressOfPlane(picture_buffer_ref, 0);
736   if (base_ptr)
737   {
738     if (pixel_buffer_format == kCVPixelFormatType_422YpCbCr8)
739       UYVY422_to_YUV420P(base_ptr, row_stride, pDvdVideoPicture);
740     else if (pixel_buffer_format == kCVPixelFormatType_32BGRA)
741       BGRA_to_YUV420P(base_ptr, row_stride, pDvdVideoPicture);
742   }
743   // unlock the CVPixelBuffer
744   CVPixelBufferUnlockBaseAddress(picture_buffer_ref, 0);
745
746   // now we can pop the top frame.
747   DisplayQueuePop();
748
749   //CLog::Log(LOGNOTICE, "%s - VDADecoderDecode dts(%f), pts(%f)", __FUNCTION__,
750   //  pDvdVideoPicture->dts, pDvdVideoPicture->pts);
751
752   return VC_PICTURE | VC_BUFFER;
753 }
754
755 void CDVDVideoCodecVDA::UYVY422_to_YUV420P(uint8_t *yuv422_ptr, int yuv422_stride, DVDVideoPicture *picture)
756 {
757   // convert PIX_FMT_UYVY422 to PIX_FMT_YUV420P.
758   struct SwsContext *swcontext = m_dllSwScale->sws_getContext(
759     m_videobuffer.iWidth, m_videobuffer.iHeight, PIX_FMT_UYVY422, 
760     m_videobuffer.iWidth, m_videobuffer.iHeight, PIX_FMT_YUV420P, 
761     SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
762   if (swcontext)
763   {
764     uint8_t  *src[] = { yuv422_ptr, 0, 0, 0 };
765     int srcStride[] = { yuv422_stride, 0, 0, 0 };
766
767     uint8_t  *dst[] = { picture->data[0], picture->data[1], picture->data[2], 0 };
768     int dstStride[] = { picture->iLineSize[0], picture->iLineSize[1], picture->iLineSize[2], 0 };
769
770     m_dllSwScale->sws_scale(swcontext, src, srcStride, 0, picture->iHeight, dst, dstStride);
771     m_dllSwScale->sws_freeContext(swcontext);
772   }
773 }
774
775 void CDVDVideoCodecVDA::BGRA_to_YUV420P(uint8_t *bgra_ptr, int bgra_stride, DVDVideoPicture *picture)
776 {
777   // convert PIX_FMT_BGRA to PIX_FMT_YUV420P.
778   struct SwsContext *swcontext = m_dllSwScale->sws_getContext(
779     m_videobuffer.iWidth, m_videobuffer.iHeight, PIX_FMT_BGRA, 
780     m_videobuffer.iWidth, m_videobuffer.iHeight, PIX_FMT_YUV420P, 
781     SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
782   if (swcontext)
783   {
784     uint8_t  *src[] = { bgra_ptr, 0, 0, 0 };
785     int srcStride[] = { bgra_stride, 0, 0, 0 };
786
787     uint8_t  *dst[] = { picture->data[0], picture->data[1], picture->data[2], 0 };
788     int dstStride[] = { picture->iLineSize[0], picture->iLineSize[1], picture->iLineSize[2], 0 };
789
790     m_dllSwScale->sws_scale(swcontext, src, srcStride, 0, picture->iHeight, dst, dstStride);
791     m_dllSwScale->sws_freeContext(swcontext);
792   }
793 }
794
795 void CDVDVideoCodecVDA::DisplayQueuePop(void)
796 {
797   CCocoaAutoPool pool;
798   if (!m_display_queue || m_queue_depth == 0)
799     return;
800
801   // pop the top frame off the queue
802   pthread_mutex_lock(&m_queue_mutex);
803   frame_queue *top_frame = m_display_queue;
804   m_display_queue = m_display_queue->nextframe;
805   m_queue_depth--;
806   pthread_mutex_unlock(&m_queue_mutex);
807
808   // and release it
809   CVPixelBufferRelease(top_frame->pixel_buffer_ref);
810   free(top_frame);
811 }
812
813 void CDVDVideoCodecVDA::VDADecoderCallback(
814   void                *decompressionOutputRefCon,
815    CFDictionaryRef    frameInfo,
816    OSStatus           status,
817    uint32_t           infoFlags,
818    CVImageBufferRef   imageBuffer)
819 {
820   CCocoaAutoPool pool;
821   // Warning, this is an async callback. There can be multiple frames in flight.
822   CDVDVideoCodecVDA *ctx = (CDVDVideoCodecVDA*)decompressionOutputRefCon;
823
824   if (imageBuffer == NULL)
825   {
826     //CLog::Log(LOGDEBUG, "%s - imageBuffer is NULL", __FUNCTION__);
827     return;
828   }
829   OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer);
830   if ((format_type != kCVPixelFormatType_422YpCbCr8) && (format_type != kCVPixelFormatType_32BGRA) )
831   {
832     CLog::Log(LOGERROR, "%s - imageBuffer format is not '2vuy' or 'BGRA',is reporting 0x%x",
833       __FUNCTION__, format_type);
834     return;
835   }
836   if (kVDADecodeInfo_FrameDropped & infoFlags)
837   {
838     CLog::Log(LOGDEBUG, "%s - frame dropped", __FUNCTION__);
839     return;
840   }
841
842   // allocate a new frame and populate it with some information.
843   // this pointer to a frame_queue type keeps track of the newest decompressed frame
844   // and is then inserted into a linked list of frame pointers depending on the display time
845   // parsed out of the bitstream and stored in the frameInfo dictionary by the client
846   frame_queue *newFrame = (frame_queue*)calloc(sizeof(frame_queue), 1);
847   newFrame->nextframe = NULL;
848   newFrame->pixel_buffer_format = format_type;
849   newFrame->pixel_buffer_ref = CVPixelBufferRetain(imageBuffer);
850   GetFrameDisplayTimeFromDictionary(frameInfo, newFrame);
851
852   // if both dts or pts are good we use those, else use decoder insert time for frame sort
853   if ((newFrame->pts != DVD_NOPTS_VALUE) || (newFrame->dts != DVD_NOPTS_VALUE))
854   {
855     // if pts is borked (stupid avi's), use dts for frame sort
856     if (newFrame->pts == DVD_NOPTS_VALUE)
857       newFrame->sort_time = newFrame->dts;
858     else
859       newFrame->sort_time = newFrame->pts;
860   }
861
862   // since the frames we get may be in decode order rather than presentation order
863   // our hypothetical callback places them in a queue of frames which will
864   // hold them in display order for display on another thread
865   pthread_mutex_lock(&ctx->m_queue_mutex);
866   //
867   frame_queue *queueWalker = ctx->m_display_queue;
868   if (!queueWalker || (newFrame->sort_time < queueWalker->sort_time))
869   {
870     // we have an empty queue, or this frame earlier than the current queue head.
871     newFrame->nextframe = queueWalker;
872     ctx->m_display_queue = newFrame;
873   } else {
874     // walk the queue and insert this frame where it belongs in display order.
875     bool frameInserted = false;
876     frame_queue *nextFrame = NULL;
877     //
878     while (!frameInserted)
879     {
880       nextFrame = queueWalker->nextframe;
881       if (!nextFrame || (newFrame->sort_time < nextFrame->sort_time))
882       {
883         // if the next frame is the tail of the queue, or our new frame is earlier.
884         newFrame->nextframe = nextFrame;
885         queueWalker->nextframe = newFrame;
886         frameInserted = true;
887       }
888       queueWalker = nextFrame;
889     }
890   }
891   ctx->m_queue_depth++;
892   //
893   pthread_mutex_unlock(&ctx->m_queue_mutex);    
894 }
895
896 #endif