aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.cpp475
-rw-r--r--xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.h67
2 files changed, 542 insertions, 0 deletions
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.cpp
new file mode 100644
index 0000000000..b7edbf2791
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#if defined(__APPLE__)
+#if (defined HAVE_CONFIG_H)
+ #include "config.h"
+#endif
+
+#include "DynamicDll.h"
+#include "GUISettings.h"
+#include "DVDClock.h"
+#include "DVDStreamInfo.h"
+#include "DVDVideoCodecVDA.h"
+#include "utils/log.h"
+#include "utils/TimeUtils.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreVideo/CoreVideo.h>
+
+// missing in 10.4/10.5 SDKs
+#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060)
+#include "dlfcn.h"
+enum {
+ // Component Y'CbCr 8-bit 4:2:2, ordered Cb Y'0 Cr Y'1
+ kCVPixelFormatType_422YpCbCr8 = FourCharCode('2vuy')
+};
+enum {
+ // Planar Component Y'CbCr 8-bit 4:2:0
+ kCVPixelFormatType_420YpCbCr8Planar = FourCharCode('y420')
+};
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////
+//#include <VideoDecodeAcceleration/VDADecoder.h>
+// http://developer.apple.com/mac/library/technotes/tn2010/tn2267.html
+// VDADecoder API (keep this until VDADecoder.h is public)
+enum {
+ kVDADecoderNoErr = 0,
+ kVDADecoderHardwareNotSupportedErr = -12470,
+ kVDADecoderFormatNotSupportedErr = -12471,
+ kVDADecoderConfigurationError = -12472,
+ kVDADecoderDecoderFailedErr = -12473,
+};
+
+enum {
+ kVDADecodeInfo_Asynchronous = 1UL << 0,
+ kVDADecodeInfo_FrameDropped = 1UL << 1
+};
+enum {
+ // tells the decoder not to bother returning
+ // a CVPixelBuffer in the outputCallback. The
+ // output callback will still be called.
+ kVDADecoderDecodeFlags_DontEmitFrame = 1 << 0
+};
+enum {
+ // decode and return buffers for all frames currently in flight
+ kVDADecoderFlush_EmitFrames = 1 << 0
+};
+typedef struct OpaqueVDADecoder* VDADecoder;
+
+typedef void (*VDADecoderOutputCallback)(
+ void *decompressionOutputRefCon,
+ CFDictionaryRef frameInfo,
+ OSStatus status,
+ uint32_t infoFlags,
+ CVImageBufferRef imageBuffer );
+
+class DllLibVDADecoderInterface
+{
+public:
+ virtual ~DllLibVDADecoderInterface() {}
+ virtual OSStatus VDADecoderCreate(
+ CFDictionaryRef decoderConfiguration, CFDictionaryRef destinationImageBufferAttributes,
+ VDADecoderOutputCallback *outputCallback, void *decoderOutputCallbackRefcon, VDADecoder *decoderOut) = 0;
+ virtual OSStatus VDADecoderDecode(
+ VDADecoder decoder, uint32_t decodeFlags, CFTypeRef compressedBuffer, CFDictionaryRef frameInfo) = 0;
+ virtual OSStatus VDADecoderFlush(VDADecoder decoder, uint32_t flushFlags) = 0;
+ virtual OSStatus VDADecoderDestroy(VDADecoder decoder)= 0;
+ virtual CFStringRef Get_kVDADecoderConfiguration_Height() = 0;
+ virtual CFStringRef Get_kVDADecoderConfiguration_Width() = 0;
+ virtual CFStringRef Get_kVDADecoderConfiguration_SourceFormat() = 0;
+ virtual CFStringRef Get_kVDADecoderConfiguration_avcCData() = 0;
+};
+
+class DllLibVDADecoder : public DllDynamic, DllLibVDADecoderInterface
+{
+ DECLARE_DLL_WRAPPER(DllLibVDADecoder, "/System/Frameworks/VideoDecodeAcceleration.framework/VideoDecodeAcceleration")
+
+ DEFINE_METHOD5(OSStatus, VDADecoderCreate, (CFDictionaryRef p1, CFDictionaryRef p2, VDADecoderOutputCallback* p3, void* p4, VDADecoder* p5))
+ DEFINE_METHOD4(OSStatus, VDADecoderDecode, (VDADecoder p1, uint32_t p2, CFTypeRef p3, CFDictionaryRef p4))
+ DEFINE_METHOD2(OSStatus, VDADecoderFlush, (VDADecoder p1, uint32_t p2))
+ DEFINE_METHOD1(OSStatus, VDADecoderDestroy, (VDADecoder p1))
+ DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_Height)
+ DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_Width)
+ DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_SourceFormat)
+ DEFINE_GLOBAL(CFStringRef, kVDADecoderConfiguration_avcCData)
+ BEGIN_METHOD_RESOLVE()
+ RESOLVE_METHOD(VDADecoderCreate)
+ RESOLVE_METHOD(VDADecoderDecode)
+ RESOLVE_METHOD(VDADecoderFlush)
+ RESOLVE_METHOD(VDADecoderDestroy)
+ RESOLVE_METHOD(kVDADecoderConfiguration_Height)
+ RESOLVE_METHOD(kVDADecoderConfiguration_Width)
+ RESOLVE_METHOD(kVDADecoderConfiguration_SourceFormat)
+ RESOLVE_METHOD(kVDADecoderConfiguration_avcCData)
+ END_METHOD_RESOLVE()
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// helper function that wraps a time into a dictionary
+static CFDictionaryRef MakeDictionaryWithDisplayTime(double inFrameDisplayTime)
+{
+ CFStringRef key = CFSTR("VideoDisplayTimeKey");
+ CFNumberRef value = CFNumberCreate(
+ kCFAllocatorDefault, kCFNumberDoubleType, &inFrameDisplayTime);
+
+ return CFDictionaryCreate(
+ kCFAllocatorDefault,
+ (const void **)&key,
+ (const void **)&value,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+}
+
+// helper function to extract a time from a dictionary
+static double GetFrameDisplayTimeFromDictionary(CFDictionaryRef inFrameInfoDictionary)
+{
+ CFNumberRef timeNumber = NULL;
+ double outValue = 0.0;
+
+ if (NULL == inFrameInfoDictionary) return 0.0;
+
+ timeNumber = (CFNumberRef)CFDictionaryGetValue(inFrameInfoDictionary, CFSTR("VideoDisplayTimeKey"));
+ if (timeNumber) CFNumberGetValue(timeNumber, kCFNumberDoubleType, &outValue);
+
+ return outValue;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+static void VDADecoderCallback(
+ void *decompressionOutputRefCon,
+ CFDictionaryRef frameInfo,
+ OSStatus status,
+ uint32_t infoFlags,
+ CVImageBufferRef imageBuffer)
+{
+ CDVDVideoCodecVDA *ctx = (CDVDVideoCodecVDA *)decompressionOutputRefCon;
+
+ if (NULL == imageBuffer)
+ {
+ printf("myDecoderOutputCallback - NULL image buffer!\n");
+ if (kVDADecodeInfo_FrameDropped & infoFlags) {
+ printf("myDecoderOutputCallback - frame dropped!\n");
+ }
+ return;
+ }
+
+ if (kCVPixelFormatType_420YpCbCr8Planar != CVPixelBufferGetPixelFormatType(imageBuffer)) {
+ printf("myDecoderOutputCallback - image buffer format not 'yv12'!\n");
+ return;
+ }
+
+ // allocate a new frame and populate it with some information
+ // this pointer to a frame_queue type keeps track of the newest decompressed frame
+ // and is then inserted into a linked list of frame pointers depending on the display time
+ // parsed out of the bitstream and stored in the frameInfo dictionary by the client
+ frame_queue *newFrame = (frame_queue*)calloc(sizeof(frame_queue), 1);
+ newFrame->nextframe = NULL;
+ newFrame->frame = CVPixelBufferRetain(imageBuffer);
+ newFrame->frametime = GetFrameDisplayTimeFromDictionary(frameInfo);
+
+ // since the frames we get may be in decode order rather than presentation order
+ // our hypothetical callback places them in a queue of frames which will
+ // hold them in display order for display on another thread
+ pthread_mutex_lock(&ctx->m_queue_mutex);
+
+ frame_queue *queueWalker = ctx->m_display_queue;
+ if (!queueWalker || (newFrame->frametime < queueWalker->frametime)) {
+ // we have an empty queue, or this frame earlier than the current queue head
+ newFrame->nextframe = queueWalker;
+ ctx->m_display_queue = newFrame;
+ } else {
+ // walk the queue and insert this frame where it belongs in display order
+ Boolean frameInserted = false;
+ frame_queue *nextFrame = NULL;
+
+ while (!frameInserted) {
+ nextFrame = queueWalker->nextframe;
+ if (!nextFrame || (newFrame->frametime < nextFrame->frametime)) {
+ // if the next frame is the tail of the queue, or our new frame is ealier
+ newFrame->nextframe = nextFrame;
+ queueWalker->nextframe = newFrame;
+ frameInserted = true;
+ }
+ queueWalker = nextFrame;
+ }
+ }
+
+ ctx->m_queue_depth++;
+
+ pthread_mutex_unlock(&ctx->m_queue_mutex);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////
+CDVDVideoCodecVDA::CDVDVideoCodecVDA() : CDVDVideoCodec()
+{
+ m_pFormatName = "vda-h264";
+
+ m_dll = NULL;
+ m_vda_decoder = NULL;
+
+ m_queue_depth = 0;
+ m_display_queue = NULL;
+ pthread_mutex_init(&m_queue_mutex, NULL);
+
+ memset(&m_pVideoBuffer, 0, sizeof(DVDVideoPicture));
+ m_dll = new DllLibVDADecoder;
+ m_dll->Load();
+}
+
+CDVDVideoCodecVDA::~CDVDVideoCodecVDA()
+{
+ Dispose();
+
+ if (m_dll)
+ delete m_dll;
+}
+
+// need to export this as it's only present (CVPixelBuffer.h) in 10.6SDK.
+CV_EXPORT const CFStringRef kCVPixelBufferIOSurfacePropertiesKey;
+
+bool CDVDVideoCodecVDA::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
+{
+ if (g_guiSettings.GetBool("videoplayer.usevda") && !hints.software)
+ {
+ switch (hints.codec)
+ {
+ case CODEC_ID_H264:
+ // source must be H.264 with valid avcC atom in extradata
+ if (hints.extrasize < 7 || hints.extradata == NULL)
+ return FALSE;
+ m_pFormatName = "vda-h264";
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ CFMutableDictionaryRef decoderConfiguration = (CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 4,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+
+ SInt32 width = (SInt32)hints.width;
+ SInt32 height = (SInt32)hints.height;
+ SInt32 format = 'avc1';
+
+ CFNumberRef avcWidth = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width);
+ CFNumberRef avcHeight = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height);
+ CFNumberRef avcFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &format);
+ CFDataRef avcCData = CFDataCreate(kCFAllocatorDefault, (const uint8_t*)hints.extradata, hints.extrasize);
+
+ CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_Height(), avcHeight);
+ CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_Width(), avcWidth);
+ CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_SourceFormat(), avcFormat);
+ CFDictionarySetValue(decoderConfiguration, m_dll->Get_kVDADecoderConfiguration_avcCData(), avcCData);
+
+ // create a CFDictionary describing the desired destination image buffer
+ CFMutableDictionaryRef destinationImageBufferAttributes = CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060)
+ CFStringRef kCVPixelBufferIOSurfacePropertiesKey = (CFStringRef)dlsym(RTLD_NEXT, "kCVPixelBufferIOSurfacePropertiesKey");
+#endif
+ OSType cvPixelFormatType = kCVPixelFormatType_420YpCbCr8Planar;
+ CFNumberRef pixelFormat = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &cvPixelFormatType);
+ CFDictionaryRef emptyDictionary = CFDictionaryCreate(
+ kCFAllocatorDefault, // our empty IOSurface properties dictionary
+ NULL,
+ NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ //
+ CFDictionarySetValue(
+ destinationImageBufferAttributes,
+ kCVPixelBufferPixelFormatTypeKey,
+ pixelFormat);
+ //
+ CFDictionarySetValue(
+ destinationImageBufferAttributes,
+ kCVPixelBufferIOSurfacePropertiesKey,
+ emptyDictionary);
+
+ // create the hardware decoder object
+ OSStatus status = m_dll->VDADecoderCreate(
+ decoderConfiguration,
+ destinationImageBufferAttributes,
+ (VDADecoderOutputCallback *)&VDADecoderCallback,
+ this,
+ (VDADecoder*)&m_vda_decoder);
+
+ if (kVDADecoderNoErr != status)
+ {
+ CLog::Log(LOGERROR, "%s: Failed to open Broadcom Crystal HD Codec", __func__);
+ return FALSE;
+ }
+
+ //First make sure all properties are reset
+ memset(&m_pVideoBuffer, 0, sizeof(DVDVideoPicture));
+
+ //Allocate for YV12 frame
+ unsigned int iPixels = width*height;
+ unsigned int iChromaPixels = iPixels/4;
+
+ m_pVideoBuffer.iWidth = width;
+ m_pVideoBuffer.iHeight = height;
+
+ m_pVideoBuffer.iLineSize[0] = width; //Y
+ m_pVideoBuffer.iLineSize[1] = width/2; //U
+ m_pVideoBuffer.iLineSize[2] = width/2; //V
+ m_pVideoBuffer.iLineSize[3] = 0;
+
+ m_pVideoBuffer.data[0] = (BYTE*)_aligned_malloc(iPixels, 16); //Y
+ m_pVideoBuffer.data[1] = (BYTE*)_aligned_malloc(iChromaPixels, 16); //U
+ m_pVideoBuffer.data[2] = (BYTE*)_aligned_malloc(iChromaPixels, 16); //V
+ m_pVideoBuffer.data[3] = NULL;
+
+ //Set all data to 0 for less artifacts.. hmm.. what is black in YUV??
+ memset( m_pVideoBuffer.data[0], 0, iPixels );
+ memset( m_pVideoBuffer.data[1], 0, iChromaPixels );
+ memset( m_pVideoBuffer.data[2], 0, iChromaPixels );
+ m_pVideoBuffer.pts = DVD_NOPTS_VALUE;
+ m_pVideoBuffer.iFlags = DVP_FLAG_ALLOCATED;
+
+ if (decoderConfiguration) CFRelease(decoderConfiguration);
+ if (destinationImageBufferAttributes) CFRelease(destinationImageBufferAttributes);
+ if (emptyDictionary) CFRelease(emptyDictionary);
+
+ return true;
+ }
+
+ return false;
+}
+
+void CDVDVideoCodecVDA::Dispose()
+{
+ if (m_vda_decoder)
+ {
+ m_dll->VDADecoderDestroy((VDADecoder)m_vda_decoder);
+ m_vda_decoder = NULL;
+
+ if( !(m_pVideoBuffer.iFlags & DVP_FLAG_ALLOCATED) )
+ {
+ _aligned_free(m_pVideoBuffer.data[0]);
+ _aligned_free(m_pVideoBuffer.data[1]);
+ _aligned_free(m_pVideoBuffer.data[2]);
+ }
+ }
+}
+
+void CDVDVideoCodecVDA::SetDropState(bool bDrop)
+{
+}
+
+int CDVDVideoCodecVDA::Decode(BYTE* pData, int iSize, double dts, double pts)
+{
+ OSStatus status;
+
+ //
+ CFDictionaryRef avc_pts = MakeDictionaryWithDisplayTime(pts);
+ CFDataRef avc_demux = CFDataCreate(kCFAllocatorDefault, pData, iSize);
+
+ status = m_dll->VDADecoderDecode((VDADecoder)m_vda_decoder, 0, avc_demux, avc_pts);
+
+ CFRelease(avc_pts);
+ CFRelease(avc_demux);
+
+ if (status = kVDADecoderNoErr)
+ {
+ CLog::Log(LOGERROR, "VDADecoderDecode failed. err: %d\n", (int)status);
+ return VC_ERROR;
+ }
+
+ // todo: queue depth is related to the number of reference frames in encoded h.264
+ // so we need to buffer until we get N ref frames + 1
+ if (m_queue_depth < 16)
+ return VC_BUFFER;
+
+ return VC_PICTURE | VC_BUFFER;
+}
+
+void CDVDVideoCodecVDA::Reset(void)
+{
+ m_dll->VDADecoderFlush((VDADecoder)m_vda_decoder, 0);
+
+ while (m_queue_depth)
+ DisplayQueuePop();
+}
+
+bool CDVDVideoCodecVDA::GetPicture(DVDVideoPicture* pDvdVideoPicture)
+{
+ CVPixelBufferRef yuvframe;
+
+ // clone the video picture buffer settings
+ memcpy(pDvdVideoPicture, &m_pVideoBuffer, sizeof(DVDVideoPicture));
+
+ // get the top yuv frame, we risk getting the wrong frame if the frame queue
+ // depth is less than the number of encoded reference frames. If queue depth
+ // is greater than the number of encoded reference frames, then the top frame
+ // will never change and we can just grab a ref to the frame/pts. This way
+ // we don't lockout the vdadecoder while doing the memcpy of planes out.
+ pthread_mutex_lock(&m_queue_mutex);
+ yuvframe = m_display_queue->frame;
+ pDvdVideoPicture->pts = m_display_queue->frametime;
+ pthread_mutex_unlock(&m_queue_mutex);
+
+ // lock the yuvframe down
+ CVPixelBufferLockBaseAddress(yuvframe, 0);
+ for (size_t i = 0; i < 3; i++)
+ {
+ UInt32 width = CVPixelBufferGetBytesPerRowOfPlane(yuvframe, i);
+ UInt32 height = CVPixelBufferGetHeightOfPlane(yuvframe, i);
+
+ void *plane_ptr = CVPixelBufferGetBaseAddressOfPlane(yuvframe, i);
+ memcpy(pDvdVideoPicture->data[i], plane_ptr, width * height);
+ }
+ // unlock the pixel buffer
+ CVPixelBufferUnlockBaseAddress(yuvframe, 0);
+
+ // now we can pop the top frame
+ DisplayQueuePop();
+
+ return VC_PICTURE | VC_BUFFER;
+}
+
+void CDVDVideoCodecVDA::DisplayQueuePop(void)
+{
+ if (!m_display_queue || m_queue_depth == 0) return;
+
+ // pop the current frame off the queue
+ pthread_mutex_lock(&m_queue_mutex);
+ frame_queue *top_frame = m_display_queue;
+ m_display_queue = m_display_queue->nextframe;
+ m_queue_depth--;
+ pthread_mutex_unlock(&m_queue_mutex);
+
+ // release the frame buffer
+ CVPixelBufferRelease(top_frame->frame);
+ free(top_frame);
+}
+#endif
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.h
new file mode 100644
index 0000000000..7bb668d116
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecVDA.h
@@ -0,0 +1,67 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#if defined(__APPLE__)
+
+#include "DVDVideoCodec.h"
+#include <CoreVideo/CoreVideo.h>
+
+// tracks a frame in and output queue in display order
+typedef struct frame_queue {
+ double frametime;
+ CVPixelBufferRef frame;
+ struct frame_queue *nextframe;
+} frame_queue;
+
+class DllLibVDADecoder;
+class CDVDVideoCodecVDA : public CDVDVideoCodec
+{
+public:
+ CDVDVideoCodecVDA();
+ virtual ~CDVDVideoCodecVDA();
+
+ // Required overrides
+ virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
+ virtual void Dispose(void);
+ virtual int Decode(BYTE *pData, int iSize, double dts, double pts);
+ virtual void Reset(void);
+ virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
+ virtual void SetDropState(bool bDrop);
+ virtual const char* GetName(void) { return (const char*)m_pFormatName; }
+
+ pthread_mutex_t m_queue_mutex; // mutex protecting queue manipulation
+ frame_queue *m_display_queue; // display-order queue - next display frame is always at the queue head
+ int32_t m_queue_depth; // we will try to keep the queue depth around 10 frames
+
+protected:
+ void DisplayQueuePop(void);
+
+ DllLibVDADecoder *m_dll;
+ void *m_vda_decoder; // opaque vdadecoder reference
+ const char *m_pFormatName;
+
+
+ DVDVideoPicture m_pVideoBuffer;
+
+};
+
+#endif