2 * Copyright (C) 2005-2010 Team XBMC
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)
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.
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
22 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
26 #if defined(HAVE_LIBVDADECODER)
27 #include "DynamicDll.h"
28 #include "GUISettings.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>
40 * if extradata size is greater than 7, then have a valid quicktime
43 * -: avcC atom header :-
44 * -----------------------------------
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
51 * ( 0 - 1 byte; 1 - 2 bytes; 3 - 4 bytes)
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
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
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)
71 // missing in 10.4/10.5 SDKs.
72 #if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060)
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')
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>
87 kVDADecoderHardwareNotSupportedErr = -12470,
88 kVDADecoderFormatNotSupportedErr = -12471,
89 kVDADecoderConfigurationError = -12472,
90 kVDADecoderDecoderFailedErr = -12473,
93 kVDADecodeInfo_Asynchronous = 1UL << 0,
94 kVDADecodeInfo_FrameDropped = 1UL << 1
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
102 // decode and return buffers for all frames currently in flight.
103 kVDADecoderFlush_EmitFrames = 1 << 0
106 typedef struct OpaqueVDADecoder* VDADecoder;
108 typedef void (*VDADecoderOutputCallback)(
109 void *decompressionOutputRefCon,
110 CFDictionaryRef frameInfo,
113 CVImageBufferRef imageBuffer);
115 ////////////////////////////////////////////////////////////////////////////////////////////
116 class DllLibVDADecoderInterface
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;
133 class DllLibVDADecoder : public DllDynamic, DllLibVDADecoderInterface
135 DECLARE_DLL_WRAPPER(DllLibVDADecoder, DLL_PATH_LIBVDADECODER)
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)
157 ////////////////////////////////////////////////////////////////////////////////////////////
158 // helper function that wraps dts/pts into a dictionary
159 static CFDictionaryRef CreateDictionaryWithDisplayTime(double time, double dts, double pts)
161 CFStringRef key[3] = {
162 CFSTR("VideoDisplay_TIME"),
163 CFSTR("VideoDisplay_DTS"),
164 CFSTR("VideoDisplay_PTS")};
165 CFNumberRef value[3];
166 CFDictionaryRef display_time;
168 value[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &time);
169 value[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &dts);
170 value[2] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &pts);
172 display_time = CFDictionaryCreate(
173 kCFAllocatorDefault, (const void **)&key, (const void **)&value, 3,
174 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
183 // helper function to extract dts/pts from a dictionary
184 static void GetFrameDisplayTimeFromDictionary(
185 CFDictionaryRef inFrameInfoDictionary, frame_queue *frame)
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)
194 CFNumberRef value[3];
196 value[0] = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplay_TIME"));
198 CFNumberGetValue(value[0], kCFNumberDoubleType, &frame->sort_time);
199 value[1] = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplay_DTS"));
201 CFNumberGetValue(value[1], kCFNumberDoubleType, &frame->dts);
202 value[2] = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplay_PTS"));
204 CFNumberGetValue(value[2], kCFNumberDoubleType, &frame->pts);
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])
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])
228 static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
230 const uint8_t *a = p + 4 - ((intptr_t)p & 3);
232 for (end -= 3; p < a && p < end; p++)
234 if (p[0] == 0 && p[1] == 0 && p[2] == 1)
238 for (end -= 3; p < end; p += 4)
240 uint32_t x = *(const uint32_t*)p;
241 if ((x - 0x01010101) & (~x) & 0x80808080) // generic
245 if (p[0] == 0 && p[2] == 1)
247 if (p[2] == 0 && p[3] == 1)
252 if (p[2] == 0 && p[4] == 1)
254 if (p[4] == 0 && p[5] == 1)
260 for (end += 3; p < end; p++)
262 if (p[0] == 0 && p[1] == 0 && p[2] == 1)
269 const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end)
271 const uint8_t *out= avc_find_startcode_internal(p, end);
272 if (p<out && out<end && !out[-1])
277 const int avc_parse_nal_units(DllAvFormat *av_format_ctx,
278 ByteIOContext *pb, const uint8_t *buf_in, int size)
280 const uint8_t *p = buf_in;
281 const uint8_t *end = p + size;
282 const uint8_t *nal_start, *nal_end;
285 nal_start = avc_find_startcode(p, end);
286 while (nal_start < end)
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;
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)
302 int ret = av_format_ctx->url_open_dyn_buf(&pb);
306 avc_parse_nal_units(av_format_ctx, pb, buf_in, *size);
308 av_util_ctx->av_freep(buf);
309 *size = av_format_ctx->url_close_dyn_buf(pb, buf);
313 const int isom_write_avcc(DllAvUtil *av_util_ctx, DllAvFormat *av_format_ctx,
314 ByteIOContext *pb, const uint8_t *data, int len)
316 // extradata from bytestream h264, convert to avcC atom data for bitstream
319 /* check for h264 start code */
320 if (VDA_RB32(data) == 0x00000001 || VDA_RB24(data) == 0x000001)
322 uint8_t *buf=NULL, *end, *start;
323 uint32_t sps_size=0, pps_size=0;
324 uint8_t *sps=0, *pps=0;
326 int ret = avc_parse_nal_units_buf(av_util_ctx, av_format_ctx, data, &buf, &len);
332 /* look for sps and pps */
337 size = VDA_RB32(buf);
338 nal_type = buf[4] & 0x1f;
339 if (nal_type == 7) /* SPS */
344 else if (nal_type == 8) /* PPS */
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) */
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);
370 av_format_ctx->put_buffer(pb, data, len);
376 static DllLibVDADecoder *g_DllLibVDADecoder = (DllLibVDADecoder*)-1;
377 ////////////////////////////////////////////////////////////////////////////////////////////
378 ////////////////////////////////////////////////////////////////////////////////////////////
379 CDVDVideoCodecVDA::CDVDVideoCodecVDA() : CDVDVideoCodec()
381 if (g_DllLibVDADecoder == (DllLibVDADecoder*)-1)
383 m_dll = new DllLibVDADecoder;
387 m_dll = g_DllLibVDADecoder;
389 m_vda_decoder = NULL;
390 m_pFormatName = "vda-";
393 m_display_queue = NULL;
394 pthread_mutex_init(&m_queue_mutex, NULL);
396 m_convert_bytestream = false;
398 m_dllAvFormat = NULL;
400 memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
403 CDVDVideoCodecVDA::~CDVDVideoCodecVDA()
406 pthread_mutex_destroy(&m_queue_mutex);
410 bool CDVDVideoCodecVDA::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
412 if (g_guiSettings.GetBool("videoplayer.usevda") && !hints.software)
415 int32_t width, height, profile, level;
417 uint8_t *extradata; // extra data for codec to use
418 unsigned int extrasize; // size of extra data
422 height = hints.height;
424 profile = hints.profile;
425 extrasize = hints.extrasize;
426 extradata = (uint8_t*)hints.extradata;
428 if (Cocoa_GPUForDisplayIsNvidiaPureVideo3())
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++)
438 if (((width + 15) / 16) == macroblocksize[i])
440 CLog::Log(LOGNOTICE, "%s - Nvidia 9400 GPU hardware limitation, cannot decode a width of %d",
441 __FUNCTION__, width);
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)
454 CLog::Log(LOGNOTICE, "%s - avcC atom too data small or missing", __FUNCTION__);
457 // valid avcC atom data always starts with the value 1 (version)
458 if ( *extradata != 1 )
460 if (extradata[0] == 0 && extradata[1] == 0 && extradata[2] == 0 && extradata[3] == 1)
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())
472 if (m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
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
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);
491 CLog::Log(LOGNOTICE, "%s - invalid avcC atom data", __FUNCTION__);
497 // CFDataCreate makes a copy of extradata contents
498 avcCData = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)extradata, extrasize);
502 m_pFormatName = "vda-h264";
509 // input stream is qualified, now we can load dlls.
510 m_dllSwScale = new DllSwScale;
511 if (!m_dllSwScale->Load())
517 // setup the decoder configuration dict
518 CFMutableDictionaryRef decoderConfiguration = CFDictionaryCreateMutable(
519 kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
521 CFNumberRef avcWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width);
522 CFNumberRef avcHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height);
523 CFNumberRef avcFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &m_format);
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);
530 // release the retained object refs, decoderConfiguration owns them now
532 CFRelease(avcHeight);
533 CFRelease(avcFormat);
536 // setup the destination image buffer dict, vda will output this pict format
537 CFMutableDictionaryRef destinationImageBufferAttributes = CFDictionaryCreateMutable(
538 kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
540 OSType cvPixelFormatType = kCVPixelFormatType_422YpCbCr8;
541 CFNumberRef pixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &cvPixelFormatType);
542 CFDictionarySetValue(destinationImageBufferAttributes, kCVPixelBufferPixelFormatTypeKey, pixelFormat);
544 // create the VDADecoder object
548 status = m_dll->VDADecoderCreate(decoderConfiguration, destinationImageBufferAttributes,
549 (VDADecoderOutputCallback *)VDADecoderCallback, this, (VDADecoder*)&m_vda_decoder);
553 CLog::Log(LOGERROR, "%s - exception",__FUNCTION__);
554 status = kVDADecoderDecoderFailedErr;
556 CFRelease(decoderConfiguration);
557 CFRelease(destinationImageBufferAttributes);
558 if (status != kVDADecoderNoErr)
560 CLog::Log(LOGNOTICE, "%s - VDADecoder Codec failed to open, status(%d), profile(%d), level(%d)",
561 __FUNCTION__, (int)status, profile, level);
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;
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;
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;
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;
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);
596 m_DropPictures = false;
597 m_sort_time_offset = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency();
605 void CDVDVideoCodecVDA::Dispose()
610 m_dll->VDADecoderDestroy((VDADecoder)m_vda_decoder);
611 m_vda_decoder = NULL;
613 if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED)
615 free(m_videobuffer.data[0]);
616 free(m_videobuffer.data[1]);
617 free(m_videobuffer.data[2]);
618 m_videobuffer.iFlags = 0;
627 delete m_dllAvFormat;
628 m_dllAvFormat = NULL;
637 void CDVDVideoCodecVDA::SetDropState(bool bDrop)
639 m_DropPictures = bDrop;
642 int CDVDVideoCodecVDA::Decode(BYTE* pData, int iSize, double dts, double pts)
650 uint32_t avc_flags = 0;
652 CFDictionaryRef avc_time;
654 if (m_convert_bytestream)
656 // convert demuxer packet from bytestream (AnnexB) to bitstream
659 uint8_t *demuxer_content;
661 if(m_dllAvFormat->url_open_dyn_buf(&pb) < 0)
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);
672 avc_demux = CFDataCreate(kCFAllocatorDefault, pData, iSize);
674 sort_time = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency();
675 avc_time = CreateDictionaryWithDisplayTime(sort_time - m_sort_time_offset, dts, pts);
678 avc_flags = kVDADecoderDecodeFlags_DontEmitFrame;
680 status = m_dll->VDADecoderDecode((VDADecoder)m_vda_decoder, avc_flags, avc_demux, avc_time);
682 CFRelease(avc_demux);
683 if (status != kVDADecoderNoErr)
685 CLog::Log(LOGNOTICE, "%s - VDADecoderDecode failed, status(%d)", __FUNCTION__, (int)status);
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)
697 return VC_PICTURE | VC_BUFFER;
700 void CDVDVideoCodecVDA::Reset(void)
703 m_dll->VDADecoderFlush((VDADecoder)m_vda_decoder, 0);
705 while (m_queue_depth)
708 m_sort_time_offset = (CurrentHostCounter() * 1000.0) / CurrentHostFrequency();
711 bool CDVDVideoCodecVDA::GetPicture(DVDVideoPicture* pDvdVideoPicture)
714 FourCharCode pixel_buffer_format;
715 CVPixelBufferRef picture_buffer_ref;
717 // clone the video picture buffer settings.
718 *pDvdVideoPicture = m_videobuffer;
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);
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);
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);
743 // unlock the CVPixelBuffer
744 CVPixelBufferUnlockBaseAddress(picture_buffer_ref, 0);
746 // now we can pop the top frame.
749 //CLog::Log(LOGNOTICE, "%s - VDADecoderDecode dts(%f), pts(%f)", __FUNCTION__,
750 // pDvdVideoPicture->dts, pDvdVideoPicture->pts);
752 return VC_PICTURE | VC_BUFFER;
755 void CDVDVideoCodecVDA::UYVY422_to_YUV420P(uint8_t *yuv422_ptr, int yuv422_stride, DVDVideoPicture *picture)
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);
764 uint8_t *src[] = { yuv422_ptr, 0, 0, 0 };
765 int srcStride[] = { yuv422_stride, 0, 0, 0 };
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 };
770 m_dllSwScale->sws_scale(swcontext, src, srcStride, 0, picture->iHeight, dst, dstStride);
771 m_dllSwScale->sws_freeContext(swcontext);
775 void CDVDVideoCodecVDA::BGRA_to_YUV420P(uint8_t *bgra_ptr, int bgra_stride, DVDVideoPicture *picture)
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);
784 uint8_t *src[] = { bgra_ptr, 0, 0, 0 };
785 int srcStride[] = { bgra_stride, 0, 0, 0 };
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 };
790 m_dllSwScale->sws_scale(swcontext, src, srcStride, 0, picture->iHeight, dst, dstStride);
791 m_dllSwScale->sws_freeContext(swcontext);
795 void CDVDVideoCodecVDA::DisplayQueuePop(void)
798 if (!m_display_queue || m_queue_depth == 0)
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;
806 pthread_mutex_unlock(&m_queue_mutex);
809 CVPixelBufferRelease(top_frame->pixel_buffer_ref);
813 void CDVDVideoCodecVDA::VDADecoderCallback(
814 void *decompressionOutputRefCon,
815 CFDictionaryRef frameInfo,
818 CVImageBufferRef imageBuffer)
821 // Warning, this is an async callback. There can be multiple frames in flight.
822 CDVDVideoCodecVDA *ctx = (CDVDVideoCodecVDA*)decompressionOutputRefCon;
824 if (imageBuffer == NULL)
826 //CLog::Log(LOGDEBUG, "%s - imageBuffer is NULL", __FUNCTION__);
829 OSType format_type = CVPixelBufferGetPixelFormatType(imageBuffer);
830 if ((format_type != kCVPixelFormatType_422YpCbCr8) && (format_type != kCVPixelFormatType_32BGRA) )
832 CLog::Log(LOGERROR, "%s - imageBuffer format is not '2vuy' or 'BGRA',is reporting 0x%x",
833 __FUNCTION__, format_type);
836 if (kVDADecodeInfo_FrameDropped & infoFlags)
838 CLog::Log(LOGDEBUG, "%s - frame dropped", __FUNCTION__);
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);
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))
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;
859 newFrame->sort_time = newFrame->pts;
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);
867 frame_queue *queueWalker = ctx->m_display_queue;
868 if (!queueWalker || (newFrame->sort_time < queueWalker->sort_time))
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;
874 // walk the queue and insert this frame where it belongs in display order.
875 bool frameInserted = false;
876 frame_queue *nextFrame = NULL;
878 while (!frameInserted)
880 nextFrame = queueWalker->nextframe;
881 if (!nextFrame || (newFrame->sort_time < nextFrame->sort_time))
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;
888 queueWalker = nextFrame;
891 ctx->m_queue_depth++;
893 pthread_mutex_unlock(&ctx->m_queue_mutex);