Merge pull request #5101 from FernetMenta/ffmpeg-threads
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / CrystalHD.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "system.h"
22 #if defined(TARGET_WINDOWS)
23 #include "WIN32Util.h"
24 #include "util.h"
25 #include "dialogs/GUIDialogKaiToast.h"
26 #include "guilib/LocalizeStrings.h"
27 #endif
28
29 #if defined(HAVE_LIBCRYSTALHD)
30 #include "CrystalHD.h"
31
32 #include "DVDClock.h"
33 #include "DynamicDll.h"
34 #include "utils/SystemInfo.h"
35 #include "threads/Atomics.h"
36 #include "threads/Thread.h"
37 #include "utils/log.h"
38 #include "utils/fastmemcpy.h"
39 #include "DllSwScale.h"
40 #include "utils/TimeUtils.h"
41 #include "windowing/WindowingFactory.h"
42
43 namespace BCM
44 {
45   #if defined(TARGET_WINDOWS)
46     typedef void                *HANDLE;
47   #else
48     #ifndef __LINUX_USER__
49       #define __LINUX_USER__
50     #endif
51   #endif
52
53   #include <libcrystalhd/bc_dts_types.h>
54   #include <libcrystalhd/bc_dts_defs.h>
55   #include <libcrystalhd/libcrystalhd_if.h>
56 };
57
58 #define __MODULE_NAME__ "CrystalHD"
59 //#define USE_CHD_SINGLE_THREADED_API
60 class DllLibCrystalHDInterface
61 {
62 public:
63   virtual ~DllLibCrystalHDInterface() {}
64   virtual BCM::BC_STATUS DtsDeviceOpen(void *hDevice, uint32_t mode)=0;
65   virtual BCM::BC_STATUS DtsDeviceClose(void *hDevice)=0;
66   virtual BCM::BC_STATUS DtsOpenDecoder(void *hDevice, uint32_t StreamType)=0;
67   virtual BCM::BC_STATUS DtsCloseDecoder(void *hDevice)=0;
68   virtual BCM::BC_STATUS DtsStartDecoder(void *hDevice)=0;
69   virtual BCM::BC_STATUS DtsSetVideoParams(void *hDevice, uint32_t videoAlg, int FGTEnable, int MetaDataEnable, int Progressive, uint32_t OptFlags)=0;
70   virtual BCM::BC_STATUS DtsStartCapture(void *hDevice)=0;
71   virtual BCM::BC_STATUS DtsFlushRxCapture(void *hDevice, int bDiscardOnly)=0;
72   virtual BCM::BC_STATUS DtsSetFFRate(void *hDevice, uint32_t rate)=0;
73   virtual BCM::BC_STATUS DtsGetDriverStatus(void *hDevice, BCM::BC_DTS_STATUS *pStatus)=0;
74   virtual BCM::BC_STATUS DtsProcInput(void *hDevice, uint8_t *pUserData, uint32_t ulSizeInBytes, uint64_t timeStamp, int encrypted)=0;
75   virtual BCM::BC_STATUS DtsProcOutput(void *hDevice, uint32_t milliSecWait, BCM::BC_DTS_PROC_OUT *pOut)=0;
76   virtual BCM::BC_STATUS DtsProcOutputNoCopy(void *hDevice, uint32_t milliSecWait, BCM::BC_DTS_PROC_OUT *pOut)=0;
77   virtual BCM::BC_STATUS DtsReleaseOutputBuffs(void *hDevice, void *Reserved, int fChange)=0;
78   virtual BCM::BC_STATUS DtsSetSkipPictureMode(void *hDevice, uint32_t Mode)=0;
79   virtual BCM::BC_STATUS DtsFlushInput(void *hDevice, uint32_t SkipMode)=0;
80
81 #if (HAVE_LIBCRYSTALHD == 2)
82   // new function calls, only present in new driver/library so manually load them
83   virtual BCM::BC_STATUS DtsGetVersion(void *hDevice, uint32_t *DrVer, uint32_t *DilVer)=0;
84   virtual BCM::BC_STATUS DtsSetInputFormat(void *hDevice, BCM::BC_INPUT_FORMAT *pInputFormat)=0;
85   virtual BCM::BC_STATUS DtsGetColorPrimaries(void *hDevice, uint32_t *colorPrimaries)=0;
86   virtual BCM::BC_STATUS DtsSetColorSpace(void *hDevice, BCM::BC_OUTPUT_FORMAT Mode422)=0;
87   virtual BCM::BC_STATUS DtsGetCapabilities(void *hDevice, BCM::BC_HW_CAPS *CapsBuffer)=0;
88   virtual BCM::BC_STATUS DtsSetScaleParams(void *hDevice, BCM::BC_SCALING_PARAMS *ScaleParams)=0;
89   virtual BCM::BC_STATUS DtsIsEndOfStream(void *hDevice, uint8_t* bEOS)=0;
90   virtual BCM::BC_STATUS DtsCrystalHDVersion(void *hDevice, BCM::BC_INFO_CRYSTAL *CrystalInfo)=0;
91 #endif
92 };
93
94 class DllLibCrystalHD : public DllDynamic, DllLibCrystalHDInterface
95 {
96   DECLARE_DLL_WRAPPER(DllLibCrystalHD, DLL_PATH_LIBCRYSTALHD)
97
98   DEFINE_METHOD2(BCM::BC_STATUS, DtsDeviceOpen,      (void *p1, uint32_t p2))
99   DEFINE_METHOD1(BCM::BC_STATUS, DtsDeviceClose,     (void *p1))
100   DEFINE_METHOD2(BCM::BC_STATUS, DtsOpenDecoder,     (void *p1, uint32_t p2))
101   DEFINE_METHOD1(BCM::BC_STATUS, DtsCloseDecoder,    (void *p1))
102   DEFINE_METHOD1(BCM::BC_STATUS, DtsStartDecoder,    (void *p1))
103   DEFINE_METHOD1(BCM::BC_STATUS, DtsStopDecoder,     (void *p1))
104   DEFINE_METHOD6(BCM::BC_STATUS, DtsSetVideoParams,  (void *p1, uint32_t p2, int p3, int p4, int p5, uint32_t p6))
105   DEFINE_METHOD1(BCM::BC_STATUS, DtsStartCapture,    (void *p1))
106   DEFINE_METHOD2(BCM::BC_STATUS, DtsFlushRxCapture,  (void *p1, int p2))
107   DEFINE_METHOD2(BCM::BC_STATUS, DtsSetFFRate,       (void *p1, uint32_t p2))
108   DEFINE_METHOD2(BCM::BC_STATUS, DtsGetDriverStatus, (void *p1, BCM::BC_DTS_STATUS *p2))
109   DEFINE_METHOD5(BCM::BC_STATUS, DtsProcInput,       (void *p1, uint8_t *p2, uint32_t p3, uint64_t p4, int p5))
110   DEFINE_METHOD3(BCM::BC_STATUS, DtsProcOutput,      (void *p1, uint32_t p2, BCM::BC_DTS_PROC_OUT *p3))
111   DEFINE_METHOD3(BCM::BC_STATUS, DtsProcOutputNoCopy,(void *p1, uint32_t p2, BCM::BC_DTS_PROC_OUT *p3))
112   DEFINE_METHOD3(BCM::BC_STATUS, DtsReleaseOutputBuffs,(void *p1, void *p2, int p3))
113   DEFINE_METHOD2(BCM::BC_STATUS, DtsSetSkipPictureMode,(void *p1, uint32_t p2))
114   DEFINE_METHOD2(BCM::BC_STATUS, DtsFlushInput,      (void *p1, uint32_t p2))
115
116 #if (HAVE_LIBCRYSTALHD == 2)
117   DEFINE_METHOD3(BCM::BC_STATUS, DtsGetVersion,      (void *p1, uint32_t *p2, uint32_t *p3))
118   DEFINE_METHOD2(BCM::BC_STATUS, DtsSetInputFormat,  (void *p1, BCM::BC_INPUT_FORMAT *p2))
119   DEFINE_METHOD2(BCM::BC_STATUS, DtsGetColorPrimaries,(void *p1, uint32_t *p2))
120   DEFINE_METHOD2(BCM::BC_STATUS, DtsSetColorSpace,   (void *p1, BCM::BC_OUTPUT_FORMAT p2))
121   DEFINE_METHOD2(BCM::BC_STATUS, DtsGetCapabilities, (void *p1, BCM::BC_HW_CAPS *p2))
122   DEFINE_METHOD2(BCM::BC_STATUS, DtsSetScaleParams,  (void *p1, BCM::BC_SCALING_PARAMS *p2))
123   DEFINE_METHOD2(BCM::BC_STATUS, DtsIsEndOfStream,   (void *p1, uint8_t *p2))
124   DEFINE_METHOD2(BCM::BC_STATUS, DtsCrystalHDVersion,(void *p1, BCM::BC_INFO_CRYSTAL *p2))
125 #endif
126
127   BEGIN_METHOD_RESOLVE()
128     RESOLVE_METHOD_RENAME(DtsDeviceOpen,      DtsDeviceOpen)
129     RESOLVE_METHOD_RENAME(DtsDeviceClose,     DtsDeviceClose)
130     RESOLVE_METHOD_RENAME(DtsOpenDecoder,     DtsOpenDecoder)
131     RESOLVE_METHOD_RENAME(DtsCloseDecoder,    DtsCloseDecoder)
132     RESOLVE_METHOD_RENAME(DtsStartDecoder,    DtsStartDecoder)
133     RESOLVE_METHOD_RENAME(DtsStopDecoder,     DtsStopDecoder)
134     RESOLVE_METHOD_RENAME(DtsSetVideoParams,  DtsSetVideoParams)
135     RESOLVE_METHOD_RENAME(DtsStartCapture,    DtsStartCapture)
136     RESOLVE_METHOD_RENAME(DtsFlushRxCapture,  DtsFlushRxCapture)
137     RESOLVE_METHOD_RENAME(DtsSetFFRate,       DtsSetFFRate)
138     RESOLVE_METHOD_RENAME(DtsGetDriverStatus, DtsGetDriverStatus)
139     RESOLVE_METHOD_RENAME(DtsProcInput,       DtsProcInput)
140     RESOLVE_METHOD_RENAME(DtsProcOutput,      DtsProcOutput)
141     RESOLVE_METHOD_RENAME(DtsProcOutputNoCopy,DtsProcOutputNoCopy)
142     RESOLVE_METHOD_RENAME(DtsReleaseOutputBuffs,DtsReleaseOutputBuffs)
143     RESOLVE_METHOD_RENAME(DtsSetSkipPictureMode,DtsSetSkipPictureMode)
144     RESOLVE_METHOD_RENAME(DtsFlushInput,      DtsFlushInput)
145   END_METHOD_RESOLVE()
146   
147 public:
148   bool LoadNewLibFunctions(void)
149   {
150 #if (HAVE_LIBCRYSTALHD == 2)
151     int rtn;
152     rtn  = m_dll->ResolveExport("DtsGetVersion",       (void**)&m_DtsGetVersion_ptr, false);
153     rtn &= m_dll->ResolveExport("DtsSetInputFormat",   (void**)&m_DtsSetInputFormat_ptr, false);
154     rtn &= m_dll->ResolveExport("DtsGetColorPrimaries",(void**)&m_DtsGetColorPrimaries_ptr, false);
155     rtn &= m_dll->ResolveExport("DtsSetColorSpace",    (void**)&m_DtsSetColorSpace_ptr, false);
156     rtn &= m_dll->ResolveExport("DtsGetCapabilities",  (void**)&m_DtsGetCapabilities_ptr, false);
157     rtn &= m_dll->ResolveExport("DtsSetScaleParams",   (void**)&m_DtsSetScaleParams_ptr, false);
158     rtn &= m_dll->ResolveExport("DtsIsEndOfStream",    (void**)&m_DtsIsEndOfStream_ptr, false);
159     rtn &= m_dll->ResolveExport("DtsCrystalHDVersion", (void**)&m_DtsCrystalHDVersion_ptr, false);
160     rtn &= m_dll->ResolveExport("DtsSetInputFormat",   (void**)&m_DtsSetInputFormat_ptr, false);
161     return(rtn == 1);
162 #else
163     return false;
164 #endif
165   };
166 };
167
168 void PrintFormat(BCM::BC_PIC_INFO_BLOCK &pib);
169 void BcmDebugLog( BCM::BC_STATUS lResult, CStdString strFuncName="");
170
171 const char* g_DtsStatusText[] = {
172         "BC_STS_SUCCESS",
173         "BC_STS_INV_ARG",
174         "BC_STS_BUSY",          
175         "BC_STS_NOT_IMPL",              
176         "BC_STS_PGM_QUIT",              
177         "BC_STS_NO_ACCESS",     
178         "BC_STS_INSUFF_RES",    
179         "BC_STS_IO_ERROR",              
180         "BC_STS_NO_DATA",               
181         "BC_STS_VER_MISMATCH",
182         "BC_STS_TIMEOUT",               
183         "BC_STS_FW_CMD_ERR",    
184         "BC_STS_DEC_NOT_OPEN",
185         "BC_STS_ERR_USAGE",
186         "BC_STS_IO_USER_ABORT",
187         "BC_STS_IO_XFR_ERROR",
188         "BC_STS_DEC_NOT_STARTED",
189         "BC_STS_FWHEX_NOT_FOUND",
190         "BC_STS_FMT_CHANGE",
191         "BC_STS_HIF_ACCESS",
192         "BC_STS_CMD_CANCELLED",
193         "BC_STS_FW_AUTH_FAILED",
194         "BC_STS_BOOTLOADER_FAILED",
195         "BC_STS_CERT_VERIFY_ERROR",
196         "BC_STS_DEC_EXIST_OPEN",
197         "BC_STS_PENDING",
198         "BC_STS_CLK_NOCHG"
199 };
200
201 ////////////////////////////////////////////////////////////////////////////////////////////
202 class CMPCOutputThread : public CThread
203 {
204 public:
205   CMPCOutputThread(void *device, DllLibCrystalHD *dll, bool has_bcm70015);
206   virtual ~CMPCOutputThread();
207
208   unsigned int        GetReadyCount(void);
209   unsigned int        GetFreeCount(void);
210   CPictureBuffer*     ReadyListPop(void);
211   void                FreeListPush(CPictureBuffer* pBuffer);
212   bool                WaitOutput(unsigned int msec);
213
214 protected:
215   void                DoFrameRateTracking(double timestamp);
216   void                SetFrameRate(uint32_t resolution);
217   void                SetAspectRatio(BCM::BC_PIC_INFO_BLOCK *pic_info);
218   void                CopyOutAsNV12(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride);
219   void                CopyOutAsNV12DeInterlace(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride);
220   void                CopyOutAsYV12(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride);
221   void                CopyOutAsYV12DeInterlace(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride);
222   void                CheckUpperLeftGreenPixelHack(CPictureBuffer *pBuffer);
223   bool                GetDecoderOutput(void);
224   virtual void        Process(void);
225
226   CSyncPtrQueue<CPictureBuffer> m_FreeList;
227   CSyncPtrQueue<CPictureBuffer> m_ReadyList;
228
229   DllLibCrystalHD     *m_dll;
230   void                *m_device;
231   bool                m_has_bcm70015;
232   unsigned int        m_timeout;
233   bool                m_format_valid;
234   bool                m_is_live_stream;
235   int                 m_width;
236   int                 m_height;
237   uint64_t            m_timestamp;
238   bool                m_output_YV12;
239   uint64_t            m_PictureNumber;
240   uint8_t             m_color_space;
241   unsigned int        m_color_range;
242   unsigned int        m_color_matrix;
243   int                 m_interlace;
244   bool                m_framerate_tracking;
245   uint64_t            m_framerate_cnt;
246   double              m_framerate_timestamp;
247   double              m_framerate;
248   int                 m_aspectratio_x;
249   int                 m_aspectratio_y;
250   CEvent              m_ready_event;
251   DllSwScale          *m_dllSwScale;
252   struct SwsContext   *m_sw_scale_ctx;
253 };
254
255 ////////////////////////////////////////////////////////////////////////////////////////////
256 #if defined(TARGET_DARWIN)
257 #pragma mark -
258 #endif
259 CPictureBuffer::CPictureBuffer(ERenderFormat format, int width, int height)
260 {
261   m_width = width;
262   m_height = height;
263   m_field = CRYSTALHD_FIELD_FULL;
264   m_interlace = false;
265   m_timestamp = DVD_NOPTS_VALUE;
266   m_PictureNumber = 0;
267   m_color_space = BCM::MODE420;
268   m_color_range = 0;
269   m_color_matrix = 4;
270   m_format = format;
271   m_framerate = 0;
272   
273   switch(m_format)
274   {
275     default:
276     case RENDER_FMT_NV12:
277       // setup y plane
278       m_y_buffer_size = m_width * m_height;
279       m_y_buffer_ptr = (unsigned char*)_aligned_malloc(m_y_buffer_size, 16);
280   
281       m_u_buffer_size = 0;
282       m_v_buffer_size = 0;
283       m_u_buffer_ptr = NULL;
284       m_v_buffer_ptr = NULL;
285       m_uv_buffer_size = m_y_buffer_size / 2;
286       m_uv_buffer_ptr = (unsigned char*)_aligned_malloc(m_uv_buffer_size, 16);
287     break;
288     case RENDER_FMT_YUYV422:
289       // setup y plane
290       m_y_buffer_size = (2 * m_width) * m_height;
291       m_y_buffer_ptr = (unsigned char*)_aligned_malloc(m_y_buffer_size, 16);
292   
293       m_uv_buffer_size = 0;
294       m_uv_buffer_ptr = NULL;
295       m_u_buffer_size = 0;
296       m_v_buffer_size = 0;
297       m_u_buffer_ptr = NULL;
298       m_v_buffer_ptr = NULL;
299     break;
300     case RENDER_FMT_YUV420P:
301       // setup y plane
302       m_y_buffer_size = m_width * m_height;
303       m_y_buffer_ptr = (unsigned char*)_aligned_malloc(m_y_buffer_size, 16);
304   
305       m_uv_buffer_size = 0;
306       m_uv_buffer_ptr = NULL;
307       m_u_buffer_size = m_y_buffer_size / 4;
308       m_v_buffer_size = m_y_buffer_size / 4;
309       m_u_buffer_ptr = (unsigned char*)_aligned_malloc(m_u_buffer_size, 16);
310       m_v_buffer_ptr = (unsigned char*)_aligned_malloc(m_v_buffer_size, 16);
311     break;
312   }
313 }
314
315 CPictureBuffer::~CPictureBuffer()
316 {
317   if (m_y_buffer_ptr) _aligned_free(m_y_buffer_ptr);
318   if (m_u_buffer_ptr) _aligned_free(m_u_buffer_ptr);
319   if (m_v_buffer_ptr) _aligned_free(m_v_buffer_ptr);
320   if (m_uv_buffer_ptr) _aligned_free(m_uv_buffer_ptr);
321 }
322
323 /////////////////////////////////////////////////////////////////////////////////////////////
324 #if defined(TARGET_DARWIN)
325 #pragma mark -
326 #endif
327 CMPCOutputThread::CMPCOutputThread(void *device, DllLibCrystalHD *dll, bool has_bcm70015) :
328   CThread("MPCOutput"),
329   m_dll(dll),
330   m_device(device),
331   m_has_bcm70015(has_bcm70015),
332   m_timeout(20),
333   m_format_valid(false),
334   m_is_live_stream(false),
335   m_width(0),
336   m_height(0),
337   m_timestamp(0),
338   m_PictureNumber(0),
339   m_color_space(0),
340   m_color_range(0),
341   m_color_matrix(0),
342   m_interlace(0),
343   m_framerate_tracking(false),
344   m_framerate_cnt(0),
345   m_framerate_timestamp(0.0),
346   m_framerate(0.0),
347   m_aspectratio_x(1),
348   m_aspectratio_y(1)
349 {
350   m_sw_scale_ctx = NULL;
351   m_dllSwScale = new DllSwScale;
352   m_dllSwScale->Load();
353
354   
355   if (g_Windowing.GetRenderQuirks() & RENDER_QUIRKS_YV12_PREFERED)
356     m_output_YV12 = true;
357   else
358     m_output_YV12 = false;
359 }
360
361 CMPCOutputThread::~CMPCOutputThread()
362 {
363   while(m_ReadyList.Count())
364     delete m_ReadyList.Pop();
365   while(m_FreeList.Count())
366     delete m_FreeList.Pop();
367     
368   if (m_sw_scale_ctx)
369     m_dllSwScale->sws_freeContext(m_sw_scale_ctx);
370   delete m_dllSwScale;
371 }
372
373 unsigned int CMPCOutputThread::GetReadyCount(void)
374 {
375   return m_ReadyList.Count();
376 }
377
378 unsigned int CMPCOutputThread::GetFreeCount(void)
379 {
380   return m_FreeList.Count();
381 }
382
383 CPictureBuffer* CMPCOutputThread::ReadyListPop(void)
384 {
385   CPictureBuffer *pBuffer = m_ReadyList.Pop();
386   return pBuffer;
387 }
388
389 void CMPCOutputThread::FreeListPush(CPictureBuffer* pBuffer)
390 {
391   m_FreeList.Push(pBuffer);
392 }
393
394 bool CMPCOutputThread::WaitOutput(unsigned int msec)
395 {
396   return m_ready_event.WaitMSec(msec);
397 }
398
399 void CMPCOutputThread::DoFrameRateTracking(double timestamp)
400 {
401   if (timestamp != DVD_NOPTS_VALUE)
402   {
403     double duration;
404     // if timestamp does not start at a low value we 
405     // came in the middle of an online live stream
406     // 250 ms is a fourth of a 25fps source
407     // if timestamp is larger than that at the beginning
408     // we are much more out of sync than with the rough 
409     // calculation. To cover these 250 ms we need
410     // roughly 5 seconds of video stream to get back
411     // in sync
412     if (m_framerate_cnt == 0 && timestamp > 250000.0)
413       m_is_live_stream = true;
414     
415     duration = timestamp - m_framerate_timestamp;
416     if (duration > 0.0)
417     {
418       double framerate;
419       // cnt count has to be done here, cause we miss frames
420       // if framerate will not calculated correctly and
421       // duration has to be > 0.0 so we do not calc images twice
422       m_framerate_cnt++;
423
424       m_framerate_timestamp += duration;
425       framerate = DVD_TIME_BASE / duration;
426       // qualify framerate, we don't care about absolute value, just
427       // want to to verify range. Timestamp could be borked so ignore
428       // anything that does not verify.
429       // 60, 59.94 -> 60
430       // 50, 49.95 -> 50
431       // 30, 29.97 -> 30
432       // 25, 24.975 -> 25
433       // 24, 23.976 -> 24
434       switch ((int)(0.5 + framerate))
435       {
436         case 60:
437         case 50:
438         case 30:
439         case 25:
440         case 24:
441           // if we have such a live stream framerate is more exact than calculating
442           // cause of m_framerate_cnt and timestamp do not match in any way
443           m_framerate = m_is_live_stream ? framerate : DVD_TIME_BASE / (m_framerate_timestamp/m_framerate_cnt);
444         break;
445       }
446     }
447   }
448 }
449
450 void CMPCOutputThread::SetFrameRate(uint32_t resolution)
451 {
452   m_interlace = FALSE;
453
454   switch (resolution)
455   {
456     case BCM::vdecRESOLUTION_1080p30:
457       m_framerate = 30.0;
458     break;
459     case BCM::vdecRESOLUTION_1080p29_97:
460       m_framerate = 30.0 * 1000.0 / 1001.0;
461     break;
462     case BCM::vdecRESOLUTION_1080p25 :
463       m_framerate = 25.0;
464     break;
465     case BCM::vdecRESOLUTION_1080p24:
466       m_framerate = 24.0;
467     break;
468     case BCM::vdecRESOLUTION_1080p23_976:
469       m_framerate = 24.0 * 1000.0 / 1001.0;
470     break;
471     case BCM::vdecRESOLUTION_1080p0:
472       // 1080p0 is ambiguious, could be 23.976 or 29.97 fps, decoder
473       // just does not know. 1080p@23_976 is more common but this
474       // will mess up 1080p@29_97 playback. We really need to verify
475       // which framerate with duration tracking.
476       m_framerate_tracking = true;
477       m_framerate = 24.0 * 1000.0 / 1001.0;
478     break;
479     
480     case BCM::vdecRESOLUTION_1080i29_97:
481       m_framerate = 30.0 * 1000.0 / 1001.0;
482       m_interlace = TRUE;
483     break;
484     case BCM::vdecRESOLUTION_1080i0:
485       m_framerate = 30.0 * 1000.0 / 1001.0;
486       m_interlace = TRUE;
487     break;
488     case BCM::vdecRESOLUTION_1080i:
489       m_framerate = 30.0 * 1000.0 / 1001.0;
490       m_interlace = TRUE;
491     break;
492     case BCM::vdecRESOLUTION_1080i25:
493       m_framerate = 25.0 * 1000.0 / 1001.0;
494       m_interlace = TRUE;
495     break;
496     
497     case BCM::vdecRESOLUTION_720p59_94:
498       m_framerate = 60.0 * 1000.0 / 1001.0;
499     break;
500     case BCM::vdecRESOLUTION_720p:
501       m_framerate = 60.0 * 1000.0 / 1001.0;
502     break;
503     case BCM::vdecRESOLUTION_720p50:
504       m_framerate = 50.0 * 1000.0 / 1001.0;
505     break;
506     case BCM::vdecRESOLUTION_720p29_97:
507       m_framerate = 30.0 * 1000.0 / 1001.0;
508     break;
509     case BCM::vdecRESOLUTION_720p24:
510       m_framerate = 24.0;
511     break;
512     case BCM::vdecRESOLUTION_720p23_976:
513       // some 720p/25 will be identifed as this, enable tracking.
514       m_framerate_tracking = true;
515       m_framerate = 24.0 * 1000.0 / 1001.0;
516     break;
517     case BCM::vdecRESOLUTION_720p0:
518       // 720p0 is ambiguious, could be 23.976, 29.97 or 59.97 fps, decoder
519       // just does not know. 720p@23_976 is more common but this
520       // will mess up other playback. We really need to verify
521       // which framerate with duration tracking.
522       m_framerate_tracking = true;
523       m_framerate = 24.0 * 1000.0 / 1001.0;
524     break;
525     
526     case BCM::vdecRESOLUTION_576p25:
527       m_framerate = 25.0;
528     break;
529     case BCM::vdecRESOLUTION_576p0:
530       m_framerate = 25.0;
531     break;
532     case BCM::vdecRESOLUTION_PAL1:
533       m_framerate = 25.0 * 1000.0 / 1001.0;
534       m_interlace = TRUE;
535     break;
536     
537     case BCM::vdecRESOLUTION_480p0:
538       m_framerate = 60.0;
539     break;
540     case BCM::vdecRESOLUTION_480p:
541       m_framerate = 60.0 * 1000.0 / 1001.0;
542     break;
543     case BCM::vdecRESOLUTION_480p29_97:
544       m_framerate = 30.0 * 1000.0 / 1001.0;
545     break;
546     case BCM::vdecRESOLUTION_480p23_976:
547       m_framerate = 24.0 * 1000.0 / 1001.0;
548     break;
549     
550     case BCM::vdecRESOLUTION_480i0:
551       m_framerate = 30.0 * 1000.0 / 1001.0;
552       m_interlace = TRUE;
553     break;
554     case BCM::vdecRESOLUTION_480i:
555       m_framerate = 30.0 * 1000.0 / 1001.0;
556       m_interlace = TRUE;
557     break;
558     case BCM::vdecRESOLUTION_NTSC:
559       m_framerate = 30.0 * 1000.0 / 1001.0;
560       m_interlace = TRUE;
561     break;
562     
563     default:
564       m_framerate_tracking = true;
565       m_framerate = 24.0 * 1000.0 / 1001.0;
566     break;
567   }
568
569   CLog::Log(LOGDEBUG, "%s: resolution = %x  interlace = %d", __MODULE_NAME__, resolution, m_interlace);
570 }
571
572 void CMPCOutputThread::SetAspectRatio(BCM::BC_PIC_INFO_BLOCK *pic_info)
573 {
574         switch(pic_info->aspect_ratio)
575   {
576     case BCM::vdecAspectRatioSquare:
577       m_aspectratio_x = 1;
578       m_aspectratio_y = 1;
579     break;
580     case BCM::vdecAspectRatio12_11:
581       m_aspectratio_x = 12;
582       m_aspectratio_y = 11;
583     break;
584     case BCM::vdecAspectRatio10_11:
585       m_aspectratio_x = 10;
586       m_aspectratio_y = 11;
587     break;
588     case BCM::vdecAspectRatio16_11:
589       m_aspectratio_x = 16;
590       m_aspectratio_y = 11;
591     break;
592     case BCM::vdecAspectRatio40_33:
593       m_aspectratio_x = 40;
594       m_aspectratio_y = 33;
595     break;
596     case BCM::vdecAspectRatio24_11:
597       m_aspectratio_x = 24;
598       m_aspectratio_y = 11;
599     break;
600     case BCM::vdecAspectRatio20_11:
601       m_aspectratio_x = 20;
602       m_aspectratio_y = 11;
603     break;
604     case BCM::vdecAspectRatio32_11:
605       m_aspectratio_x = 32;
606       m_aspectratio_y = 11;
607     break;
608     case BCM::vdecAspectRatio80_33:
609       m_aspectratio_x = 80;
610       m_aspectratio_y = 33;
611     break;
612     case BCM::vdecAspectRatio18_11:
613       m_aspectratio_x = 18;
614       m_aspectratio_y = 11;
615     break;
616     case BCM::vdecAspectRatio15_11:
617       m_aspectratio_x = 15;
618       m_aspectratio_y = 11;
619     break;
620     case BCM::vdecAspectRatio64_33:
621       m_aspectratio_x = 64;
622       m_aspectratio_y = 33;
623     break;
624     case BCM::vdecAspectRatio160_99:
625       m_aspectratio_x = 160;
626       m_aspectratio_y = 99;
627     break;
628     case BCM::vdecAspectRatio4_3:
629       m_aspectratio_x = 4;
630       m_aspectratio_y = 3;
631     break;
632     case BCM::vdecAspectRatio16_9:
633       m_aspectratio_x = 16;
634       m_aspectratio_y = 9;
635     break;
636     case BCM::vdecAspectRatio221_1:
637       m_aspectratio_x = 221;
638       m_aspectratio_y = 1;
639     break;
640     case BCM::vdecAspectRatioUnknown:
641       m_aspectratio_x = 0;
642       m_aspectratio_y = 0;
643     break;
644
645     case BCM::vdecAspectRatioOther:
646       m_aspectratio_x = pic_info->custom_aspect_ratio_width_height & 0x0000ffff;
647       m_aspectratio_y = pic_info->custom_aspect_ratio_width_height >> 16;
648     break;
649   }
650   if(m_aspectratio_x == 0)
651   {
652     m_aspectratio_x = 1;
653     m_aspectratio_y = 1;
654   }
655
656   CLog::Log(LOGDEBUG, "%s: dec_par x = %d, dec_par y = %d", __MODULE_NAME__, m_aspectratio_x, m_aspectratio_y);
657 }
658
659 void CMPCOutputThread::CopyOutAsYV12(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
660 {
661   // copy y
662   if (w == stride)
663   {
664     fast_memcpy(pBuffer->m_y_buffer_ptr, procOut->Ybuff, w * h);
665   }
666   else
667   {
668     uint8_t *s_y = procOut->Ybuff;
669     uint8_t *d_y = pBuffer->m_y_buffer_ptr;
670     for (int y = 0; y < h; y++, s_y += stride, d_y += w)
671       fast_memcpy(d_y, s_y, w);
672   }
673   //copy chroma
674   //copy uv packed to u,v planes (1/2 the width and 1/2 the height of y)
675   uint8_t *d_u = pBuffer->m_u_buffer_ptr;
676   uint8_t *d_v = pBuffer->m_v_buffer_ptr;
677   for (int y = 0; y < h/2; y++)
678   {
679     uint8_t *s_uv = procOut->UVbuff + (y * stride);
680     for (int x = 0; x < w/2; x++)
681     {
682       *d_u++ = *s_uv++;
683       *d_v++ = *s_uv++;
684     }
685   }
686 }
687
688 void CMPCOutputThread::CopyOutAsYV12DeInterlace(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
689 {
690   // copy luma
691   uint8_t *s_y = procOut->Ybuff;
692   uint8_t *d_y = pBuffer->m_y_buffer_ptr;
693   for (int y = 0; y < h/2; y++, s_y += stride)
694   {
695     fast_memcpy(d_y, s_y, w);
696     d_y += w;
697     fast_memcpy(d_y, s_y, w);
698     d_y += w;
699   }
700   //copy chroma
701   //copy uv packed to u,v planes (1/2 the width and 1/2 the height of y)
702   uint8_t *d_u = pBuffer->m_u_buffer_ptr;
703   uint8_t *d_v = pBuffer->m_v_buffer_ptr;
704   for (int y = 0; y < h/4; y++)
705   {
706     uint8_t *s_uv = procOut->UVbuff + (y * stride);
707     for (int x = 0; x < w/2; x++)
708     {
709       *d_u++ = *s_uv++;
710       *d_v++ = *s_uv++;
711     }
712     s_uv = procOut->UVbuff + (y * stride);
713     for (int x = 0; x < w/2; x++)
714     {
715       *d_u++ = *s_uv++;
716       *d_v++ = *s_uv++;
717     }
718   }
719
720   pBuffer->m_interlace = false;
721 }
722
723 void CMPCOutputThread::CopyOutAsNV12(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
724 {
725   if (w == stride)
726   {
727     int bytes = w * h;
728     // copy y
729     fast_memcpy(pBuffer->m_y_buffer_ptr, procOut->Ybuff, bytes);
730     // copy uv
731     fast_memcpy(pBuffer->m_uv_buffer_ptr, procOut->UVbuff, bytes/2 );
732   }
733   else
734   {
735     // copy y
736     uint8_t *s = procOut->Ybuff;
737     uint8_t *d = pBuffer->m_y_buffer_ptr;
738     for (int y = 0; y < h; y++, s += stride, d += w)
739       fast_memcpy(d, s, w);
740     // copy uv
741     s = procOut->UVbuff;
742     d = pBuffer->m_uv_buffer_ptr;
743     for (int y = 0; y < h/2; y++, s += stride, d += w)
744       fast_memcpy(d, s, w);
745   }
746 }
747
748 void CMPCOutputThread::CopyOutAsNV12DeInterlace(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
749 {
750   // do simple line doubling de-interlacing.
751   // copy luma
752   uint8_t *s_y = procOut->Ybuff;
753   uint8_t *d_y = pBuffer->m_y_buffer_ptr;
754   for (int y = 0; y < h/2; y++, s_y += stride)
755   {
756     fast_memcpy(d_y, s_y, w);
757     d_y += w;
758     fast_memcpy(d_y, s_y, w);
759     d_y += w;
760   }
761   //copy chroma
762   uint8_t *s_uv = procOut->UVbuff;
763   uint8_t *d_uv = pBuffer->m_uv_buffer_ptr;
764   for (int y = 0; y < h/4; y++, s_uv += stride) {
765     fast_memcpy(d_uv, s_uv, w);
766     d_uv += w;
767     fast_memcpy(d_uv, s_uv, w);
768     d_uv += w;
769   }
770   pBuffer->m_interlace = false;
771 }
772
773 void CMPCOutputThread::CheckUpperLeftGreenPixelHack(CPictureBuffer *pBuffer)
774 {
775   // crystalhd driver sends internal info in 1st pixel location, then restores
776   // original pixel value but sometimes, the info is broked and the
777   // driver cannot do the restore and zeros the pixel. This is wrong for
778   // yuv color space, uv values should be set to 128 otherwise we get a
779   // bright green pixel in upper left.
780   // We fix this by replicating the 2nd pixel to the 1st.
781   switch(pBuffer->m_format)
782   {
783     default:
784     case RENDER_FMT_YUV420P:
785     {
786       uint8_t *d_y = pBuffer->m_y_buffer_ptr;
787       uint8_t *d_u = pBuffer->m_u_buffer_ptr;
788       uint8_t *d_v = pBuffer->m_v_buffer_ptr;
789       d_y[0] = d_y[1];
790       d_u[0] = d_u[1];
791       d_v[0] = d_v[1];
792     }
793     break;
794
795     case RENDER_FMT_NV12:
796     {
797       uint8_t  *d_y  = pBuffer->m_y_buffer_ptr;
798       uint16_t *d_uv = (uint16_t*)pBuffer->m_uv_buffer_ptr;
799       d_y[0] = d_y[1];
800       d_uv[0] = d_uv[1];
801     }
802     break;
803
804     case RENDER_FMT_YUYV422:
805     {
806       uint32_t *d_yuyv = (uint32_t*)pBuffer->m_y_buffer_ptr;
807       d_yuyv[0] = d_yuyv[1];
808     }
809     break;
810   }
811 }
812
813 bool CMPCOutputThread::GetDecoderOutput(void)
814 {
815   BCM::BC_STATUS ret;
816   BCM::BC_DTS_PROC_OUT procOut;
817   CPictureBuffer *pBuffer = NULL;
818   bool got_picture = false;
819
820   // Setup output struct
821   memset(&procOut, 0, sizeof(BCM::BC_DTS_PROC_OUT));
822
823   // Fetch data from the decoder
824   ret = m_dll->DtsProcOutputNoCopy(m_device, m_timeout, &procOut);
825
826   switch (ret)
827   {
828     case BCM::BC_STS_SUCCESS:
829       if (m_format_valid && (procOut.PoutFlags & BCM::BC_POUT_FLAGS_PIB_VALID))
830       {
831         if (procOut.PicInfo.timeStamp && 
832           m_timestamp != procOut.PicInfo.timeStamp &&
833           m_width == (int)procOut.PicInfo.width && 
834           m_height == (int)procOut.PicInfo.height)
835         {
836           m_timestamp = procOut.PicInfo.timeStamp;
837           m_PictureNumber = procOut.PicInfo.picture_number;
838
839           if (m_framerate_tracking)
840             DoFrameRateTracking((double)m_timestamp / 1000.0);
841
842           // do not let FreeList to get greater than 10
843           if (m_FreeList.Count() > 10)
844             delete m_FreeList.Pop();
845
846           // Get next output buffer from the free list
847           pBuffer = m_FreeList.Pop();
848           if (!pBuffer)
849           {
850             // No free pre-allocated buffers so make one
851             if (m_output_YV12)
852             {
853               // output YV12, nouveau driver has slow NV12, YUY2 capability.
854               pBuffer = new CPictureBuffer(RENDER_FMT_YUV420P, m_width, m_height);
855             }
856             else
857             {
858               if (m_color_space == BCM::MODE422_YUY2)
859                 pBuffer = new CPictureBuffer(RENDER_FMT_YUYV422, m_width, m_height);
860               else
861                 pBuffer = new CPictureBuffer(RENDER_FMT_NV12, m_width, m_height);
862             }
863
864             CLog::Log(LOGDEBUG, "%s: Added a new Buffer, ReadyListCount: %d", __MODULE_NAME__, m_ReadyList.Count());
865             while (!m_bStop && m_ReadyList.Count() > 10)
866               Sleep(1);
867           }
868
869           pBuffer->m_width = m_width;
870           pBuffer->m_height = m_height;
871           pBuffer->m_field = CRYSTALHD_FIELD_FULL;
872           pBuffer->m_interlace = m_interlace > 0 ? true : false;
873           pBuffer->m_framerate = m_framerate;
874           pBuffer->m_timestamp = m_timestamp;
875           pBuffer->m_color_space = m_color_space;
876           pBuffer->m_color_range = m_color_range;
877           pBuffer->m_color_matrix = m_color_matrix;
878           pBuffer->m_PictureNumber = m_PictureNumber;
879
880           int w = m_width;
881           int h = m_height;
882           // frame that are not equal in width to 720, 1280 or 1920
883           // need to be copied by a quantized stride (possible lib/driver bug) so force it.
884           int stride = m_width;
885           if (!m_has_bcm70015)
886           {
887             // bcm70012 uses quantized strides
888             if (w <= 720)
889               stride = 720;
890             else if (w <= 1280)
891               stride = 1280;
892             else
893               stride = 1920;
894           }
895
896           if (pBuffer->m_color_space == BCM::MODE420)
897           {
898             switch(pBuffer->m_format)
899             {
900               case RENDER_FMT_NV12:
901                 if (pBuffer->m_interlace)
902                   CopyOutAsNV12DeInterlace(pBuffer, &procOut, w, h, stride);
903                 else
904                   CopyOutAsNV12(pBuffer, &procOut, w, h, stride);
905               break;
906               case RENDER_FMT_YUV420P:
907                 if (pBuffer->m_interlace)
908                   CopyOutAsYV12DeInterlace(pBuffer, &procOut, w, h, stride);
909                 else
910                   CopyOutAsYV12(pBuffer, &procOut, w, h, stride);
911               break;
912               default:
913               break;
914             }
915           }
916           else
917           {
918             switch(pBuffer->m_format)
919             {
920               case RENDER_FMT_YUYV422:
921                 if (pBuffer->m_interlace)
922                 {
923                   // do simple line doubling de-interlacing.
924                   // copy luma
925                   int yuy2_w = w * 2;
926                   int yuy2_stride = stride*2;
927                   uint8_t *s_y = procOut.Ybuff;
928                   uint8_t *d_y = pBuffer->m_y_buffer_ptr;
929                   for (int y = 0; y < h/2; y++, s_y += yuy2_stride)
930                   {
931                     fast_memcpy(d_y, s_y, yuy2_w);
932                     d_y += yuy2_w;
933                     fast_memcpy(d_y, s_y, yuy2_w);
934                     d_y += yuy2_w;
935                   }
936                   pBuffer->m_interlace = false;
937                 }
938                 else
939                 {
940                   fast_memcpy(pBuffer->m_y_buffer_ptr,  procOut.Ybuff, pBuffer->m_y_buffer_size);
941                 }
942               break;
943               case RENDER_FMT_YUV420P:
944                 // TODO: deinterlace for yuy2 -> yv12, icky
945                 {
946                   // Perform the color space conversion.
947                   uint8_t* src[] =       { procOut.Ybuff, NULL, NULL, NULL };
948                   int      srcStride[] = { stride*2, 0, 0, 0 };
949                   uint8_t* dst[] =       { pBuffer->m_y_buffer_ptr, pBuffer->m_u_buffer_ptr, pBuffer->m_v_buffer_ptr, NULL };
950                   int      dstStride[] = { pBuffer->m_width, pBuffer->m_width/2, pBuffer->m_width/2, 0 };
951
952                   m_sw_scale_ctx = m_dllSwScale->sws_getCachedContext(m_sw_scale_ctx,
953                     pBuffer->m_width, pBuffer->m_height, PIX_FMT_YUYV422,
954                     pBuffer->m_width, pBuffer->m_height, PIX_FMT_YUV420P,
955                     SWS_FAST_BILINEAR | SwScaleCPUFlags(), NULL, NULL, NULL);
956                   m_dllSwScale->sws_scale(m_sw_scale_ctx, src, srcStride, 0, pBuffer->m_height, dst, dstStride);
957                 }
958               break;
959               default:
960               break;
961             }
962           }
963
964           CheckUpperLeftGreenPixelHack(pBuffer);
965           m_ReadyList.Push(pBuffer);
966           m_ready_event.Set();
967           got_picture = true;
968         }
969         else
970         {
971           if (m_PictureNumber != procOut.PicInfo.picture_number)
972             CLog::Log(LOGDEBUG, "%s: No timestamp detected: %"PRIu64, __MODULE_NAME__, procOut.PicInfo.timeStamp);
973           m_PictureNumber = procOut.PicInfo.picture_number;
974         }
975       }
976
977       m_dll->DtsReleaseOutputBuffs(m_device, NULL, FALSE);
978     break;
979
980     case BCM::BC_STS_FMT_CHANGE:
981       CLog::Log(LOGDEBUG, "%s: Format Change Detected. Flags: 0x%08x", __MODULE_NAME__, procOut.PoutFlags);
982       if ((procOut.PoutFlags & BCM::BC_POUT_FLAGS_PIB_VALID) && (procOut.PoutFlags & BCM::BC_POUT_FLAGS_FMT_CHANGE))
983       {
984         PrintFormat(procOut.PicInfo);
985
986         if (procOut.PicInfo.height == 1088) {
987           procOut.PicInfo.height = 1080;
988         }
989         m_width = procOut.PicInfo.width;
990         m_height = procOut.PicInfo.height;
991         m_timestamp = DVD_NOPTS_VALUE;
992         m_color_space = procOut.b422Mode;
993         m_color_range = 0;
994         m_color_matrix = procOut.PicInfo.colour_primaries;
995         SetAspectRatio(&procOut.PicInfo);
996         SetFrameRate(procOut.PicInfo.frame_rate);
997         if (procOut.PicInfo.flags & VDEC_FLAG_INTERLACED_SRC)
998         {
999           m_interlace = true;
1000         }
1001         m_timeout = 2000;
1002         m_format_valid = true;
1003         m_ready_event.Set();
1004       }
1005     break;
1006
1007     case BCM::BC_STS_DEC_NOT_OPEN:
1008     break;
1009
1010     case BCM::BC_STS_DEC_NOT_STARTED:
1011     break;
1012
1013     case BCM::BC_STS_IO_USER_ABORT:
1014     break;
1015
1016     case BCM::BC_STS_NO_DATA:
1017     break;
1018
1019     case BCM::BC_STS_TIMEOUT:
1020     break;
1021
1022     default:
1023       if (ret > 26)
1024         CLog::Log(LOGDEBUG, "%s: DtsProcOutput returned %d.", __MODULE_NAME__, ret);
1025       else
1026         CLog::Log(LOGDEBUG, "%s: DtsProcOutput returned %s.", __MODULE_NAME__, g_DtsStatusText[ret]);
1027     break;
1028   }
1029   
1030   return got_picture;
1031 }
1032
1033 void CMPCOutputThread::Process(void)
1034 {
1035   BCM::BC_STATUS ret;
1036   BCM::BC_DTS_STATUS decoder_status;
1037
1038   m_PictureNumber = 0;
1039
1040   CLog::Log(LOGDEBUG, "%s: Output Thread Started...", __MODULE_NAME__);
1041
1042   // wait for decoder startup, calls into DtsProcOutputXXCopy will
1043   // return immediately until decoder starts getting input packets. 
1044   while (!m_bStop)
1045   {
1046     memset(&decoder_status, 0, sizeof(decoder_status));
1047     ret = m_dll->DtsGetDriverStatus(m_device, &decoder_status);
1048     if (ret == BCM::BC_STS_SUCCESS && decoder_status.ReadyListCount)
1049     {
1050       GetDecoderOutput();
1051       break;
1052     }
1053     Sleep(10);
1054   }
1055
1056   // decoder is primed so now calls in DtsProcOutputXXCopy will block
1057   while (!m_bStop)
1058   {
1059     memset(&decoder_status, 0, sizeof(decoder_status));
1060     ret = m_dll->DtsGetDriverStatus(m_device, &decoder_status);
1061     if (ret == BCM::BC_STS_SUCCESS && decoder_status.ReadyListCount != 0)
1062       GetDecoderOutput();
1063     else
1064       Sleep(1);
1065
1066 #ifdef USE_CHD_SINGLE_THREADED_API
1067     while (!m_bStop)
1068     {
1069       ret = m_dll->DtsGetDriverStatus(m_device, &decoder_status);
1070       if (ret == BCM::BC_STS_SUCCESS && decoder_status.ReadyListCount != 0)
1071       {
1072         double pts = (double)decoder_status.NextTimeStamp / 1000.0;
1073         fprintf(stdout, "cpbEmptySize(%d), NextTimeStamp(%f)\n", decoder_status.cpbEmptySize, pts);
1074         break;
1075       }
1076       Sleep(10);
1077     }
1078 #endif
1079   }
1080   CLog::Log(LOGDEBUG, "%s: Output Thread Stopped...", __MODULE_NAME__);
1081 }
1082
1083 ////////////////////////////////////////////////////////////////////////////////////////////
1084 #if defined(TARGET_DARWIN)
1085 #pragma mark -
1086 #endif
1087 CCrystalHD* CCrystalHD::m_pInstance = NULL;
1088
1089 CCrystalHD::CCrystalHD() :
1090   m_device(NULL),
1091   m_device_preset(false),
1092   m_new_lib(false),
1093   m_decoder_open(false),
1094   m_has_bcm70015(false),
1095   m_color_space(BCM::MODE420),
1096   m_drop_state(false),
1097   m_skip_state(false),
1098   m_timeout(0),
1099   m_wait_timeout(0),
1100   m_field(0),
1101   m_width(0),
1102   m_height(0),
1103   m_reset(0),
1104   m_last_pict_num(0),
1105   m_last_demuxer_pts(0.0),
1106   m_last_decoder_pts(0.0),
1107   m_pOutputThread(NULL),
1108   m_sps_pps_size(0),
1109   m_convert_bitstream(false)
1110 {
1111 #if (HAVE_LIBCRYSTALHD == 2)
1112   memset(&m_bc_info_crystal, 0, sizeof(m_bc_info_crystal));
1113 #endif
1114
1115   memset(&m_chd_params, 0, sizeof(m_chd_params));
1116   memset(&m_sps_pps_context, 0, sizeof(m_sps_pps_context));
1117
1118   m_dll = new DllLibCrystalHD;
1119 #ifdef TARGET_WINDOWS
1120   CStdString  strDll;
1121   if(CWIN32Util::GetCrystalHDLibraryPath(strDll) && m_dll->SetFile(strDll) && m_dll->Load() && m_dll->IsLoaded() )
1122 #else
1123   if (m_dll->Load() && m_dll->IsLoaded() )
1124 #endif
1125   {
1126 #if (HAVE_LIBCRYSTALHD == 2)
1127     m_new_lib = m_dll->LoadNewLibFunctions();
1128 #endif
1129
1130     OpenDevice();
1131     
1132 #if (HAVE_LIBCRYSTALHD == 2)
1133     if (m_device && m_new_lib)
1134     {
1135       m_dll->DtsCrystalHDVersion(m_device, (BCM::PBC_INFO_CRYSTAL)&m_bc_info_crystal);
1136       m_has_bcm70015 = (m_bc_info_crystal.device == 1);
1137       // bcm70012 can do nv12 (420), yuy2 (422) and uyvy (422)
1138       // bcm70015 can do only yuy2 (422)
1139       if (m_has_bcm70015)
1140         m_color_space = BCM::OUTPUT_MODE422_YUY2;
1141     }
1142 #endif
1143   }
1144
1145   // delete dll if device open fails, minimizes ram footprint
1146   if (!m_device)
1147   {
1148     delete m_dll;
1149     m_dll = NULL;
1150     CLog::Log(LOGDEBUG, "%s: broadcom crystal hd not found", __MODULE_NAME__);
1151   }
1152   else
1153   {
1154     // we know there's a device present now, close the device until doing playback
1155     CloseDevice();
1156   }
1157 }
1158
1159
1160 CCrystalHD::~CCrystalHD()
1161 {
1162   if (m_decoder_open)
1163     CloseDecoder();
1164
1165   if (m_device)
1166     CloseDevice();
1167
1168   if (m_dll)
1169     delete m_dll;
1170 }
1171
1172
1173 bool CCrystalHD::DevicePresent(void)
1174 {
1175   return m_device_preset;
1176 }
1177
1178 void CCrystalHD::RemoveInstance(void)
1179 {
1180   if (m_pInstance)
1181   {
1182     delete m_pInstance;
1183     m_pInstance = NULL;
1184   }
1185 }
1186
1187 CCrystalHD* CCrystalHD::GetInstance(void)
1188 {
1189   if (!m_pInstance)
1190   {
1191     m_pInstance = new CCrystalHD();
1192   }
1193   return m_pInstance;
1194 }
1195
1196 void CCrystalHD::OpenDevice()
1197 {
1198   uint32_t mode = BCM::DTS_PLAYBACK_MODE          |
1199                   BCM::DTS_LOAD_FILE_PLAY_FW      |
1200 #ifdef USE_CHD_SINGLE_THREADED_API
1201                   BCM::DTS_SINGLE_THREADED_MODE   |
1202 #endif
1203                   BCM::DTS_SKIP_TX_CHK_CPB        |
1204                   BCM::DTS_PLAYBACK_DROP_RPT_MODE |
1205                   DTS_DFLT_RESOLUTION(BCM::vdecRESOLUTION_720p23_976);
1206
1207   BCM::BC_STATUS res= m_dll->DtsDeviceOpen(&m_device, mode);
1208   if (res != BCM::BC_STS_SUCCESS)
1209   {
1210     m_device = NULL;
1211     if( res == BCM::BC_STS_DEC_EXIST_OPEN )
1212       CLog::Log(LOGDEBUG, "%s: device owned by another application", __MODULE_NAME__);
1213     else
1214       CLog::Log(LOGDEBUG, "%s: device open failed , returning(0x%x)", __MODULE_NAME__, res);
1215     m_device_preset = false;
1216   }
1217   else
1218   {
1219     #if (HAVE_LIBCRYSTALHD == 2)
1220       if (m_new_lib)
1221         CLog::Log(LOGDEBUG, "%s(new API): device opened", __MODULE_NAME__);
1222       else
1223         CLog::Log(LOGDEBUG, "%s(old API): device opened", __MODULE_NAME__);
1224     #else
1225       CLog::Log(LOGDEBUG, "%s: device opened", __MODULE_NAME__);
1226     #endif
1227     m_device_preset = true;
1228   }
1229 }
1230
1231 void CCrystalHD::CloseDevice()
1232 {
1233   if (m_device)
1234   {
1235     m_dll->DtsDeviceClose(m_device);
1236     m_device = NULL;
1237     CLog::Log(LOGDEBUG, "%s: device closed", __MODULE_NAME__);
1238   }
1239 }
1240
1241 bool CCrystalHD::OpenDecoder(CRYSTALHD_CODEC_TYPE codec_type, CDVDStreamInfo &hints)
1242 {
1243   BCM::BC_STATUS res;
1244   uint32_t StreamType;
1245 #if (HAVE_LIBCRYSTALHD == 2)
1246   BCM::BC_MEDIA_SUBTYPE Subtype;
1247 #endif
1248
1249   if (!m_device_preset)
1250     return false;
1251
1252   if (m_decoder_open)
1253     CloseDecoder();
1254     
1255   OpenDevice();
1256   if (!m_device)
1257     return false;
1258
1259 #if (HAVE_LIBCRYSTALHD == 2) && defined(TARGET_WINDOWS)
1260   // Drivers prior to 3.6.9.32 don't have proper support for CRYSTALHD_CODEC_ID_AVC1
1261   // The internal version numbers are different for some reason...
1262   if (   (m_bc_info_crystal.dilVersion.dilRelease < 3)
1263       || (m_bc_info_crystal.dilVersion.dilRelease == 3 && m_bc_info_crystal.dilVersion.dilMajor < 22)
1264       || (m_bc_info_crystal.drvVersion.drvRelease < 3)
1265       || (m_bc_info_crystal.drvVersion.drvRelease == 3 && m_bc_info_crystal.drvVersion.drvMajor < 7) )
1266   {
1267     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, "CrystalHD", g_localizeStrings.Get(2101));
1268     CLog::Log(LOGWARNING, "CrystalHD drivers too old, please upgrade to 3.6.9 or later. Make sure to uninstall the old version first or the upgrade won't work.");
1269
1270     if (codec_type == CRYSTALHD_CODEC_ID_AVC1)
1271       return false;
1272   }
1273 #endif
1274
1275   uint32_t videoAlg = 0;
1276   switch (codec_type)
1277   {
1278     case CRYSTALHD_CODEC_ID_VC1:
1279       videoAlg = BCM::BC_VID_ALGO_VC1;
1280       StreamType = BCM::BC_STREAM_TYPE_ES;
1281       m_convert_bitstream = false;
1282     break;
1283     case CRYSTALHD_CODEC_ID_WVC1:
1284       videoAlg = BCM::BC_VID_ALGO_VC1MP;
1285       StreamType = BCM::BC_STREAM_TYPE_ES;
1286       m_convert_bitstream = false;
1287     break;
1288     case CRYSTALHD_CODEC_ID_WMV3:
1289       if (!m_has_bcm70015)
1290         return false;
1291       videoAlg = BCM::BC_VID_ALGO_VC1MP;
1292       StreamType = BCM::BC_STREAM_TYPE_ES;
1293       m_convert_bitstream = false;
1294     break;
1295     case CRYSTALHD_CODEC_ID_H264:
1296       videoAlg = BCM::BC_VID_ALGO_H264;
1297       StreamType = BCM::BC_STREAM_TYPE_ES;
1298       m_convert_bitstream = false;
1299     break;
1300     case CRYSTALHD_CODEC_ID_AVC1:
1301       videoAlg = BCM::BC_VID_ALGO_H264;
1302       StreamType = BCM::BC_STREAM_TYPE_ES;
1303       if (!m_new_lib)
1304         m_convert_bitstream = bitstream_convert_init((uint8_t*)hints.extradata, hints.extrasize);
1305       else
1306         m_convert_bitstream = false;
1307     break;
1308     case CRYSTALHD_CODEC_ID_MPEG2:
1309       videoAlg = BCM::BC_VID_ALGO_MPEG2;
1310       StreamType = BCM::BC_STREAM_TYPE_ES;
1311       m_convert_bitstream = false;
1312     break;
1313     //BC_VID_ALGO_DIVX:
1314     //BC_VID_ALGO_VC1MP:
1315     default:
1316       return false;
1317     break;
1318   }
1319   
1320 #if (HAVE_LIBCRYSTALHD == 2)
1321   uint8_t *pMetaData = NULL;
1322   uint32_t metaDataSz = 0;
1323   uint32_t startCodeSz = 4;
1324   m_chd_params.sps_pps_buf = NULL;
1325   switch (codec_type)
1326   {
1327     case CRYSTALHD_CODEC_ID_VC1:
1328       Subtype = BCM::BC_MSUBTYPE_VC1;
1329       pMetaData = (uint8_t*)hints.extradata;
1330       metaDataSz = hints.extrasize;
1331     break;
1332     case CRYSTALHD_CODEC_ID_WVC1:
1333       Subtype = BCM::BC_MSUBTYPE_WVC1;
1334     break;
1335     case CRYSTALHD_CODEC_ID_WMV3:
1336       Subtype = BCM::BC_MSUBTYPE_WMV3;
1337       pMetaData = (uint8_t*)hints.extradata;
1338       metaDataSz = hints.extrasize;
1339     break;
1340     case CRYSTALHD_CODEC_ID_H264:
1341       Subtype = BCM::BC_MSUBTYPE_H264;
1342       pMetaData = (uint8_t*)hints.extradata;
1343       metaDataSz = hints.extrasize;
1344     break;
1345     case CRYSTALHD_CODEC_ID_AVC1:
1346       Subtype = BCM::BC_MSUBTYPE_AVC1;
1347       m_chd_params.sps_pps_buf = (uint8_t*)malloc(1000);
1348                         if (!extract_sps_pps_from_avcc(hints.extrasize, hints.extradata))
1349       {
1350         free(m_chd_params.sps_pps_buf);
1351         m_chd_params.sps_pps_buf = NULL;
1352                         }
1353       else
1354       {
1355         pMetaData = m_chd_params.sps_pps_buf;
1356         metaDataSz = m_chd_params.sps_pps_size;
1357         startCodeSz = m_chd_params.nal_size_bytes;
1358       }
1359     break;
1360     case CRYSTALHD_CODEC_ID_MPEG2:
1361       Subtype = BCM::BC_MSUBTYPE_MPEG2VIDEO;
1362       pMetaData = (uint8_t*)hints.extradata;
1363       metaDataSz = hints.extrasize;
1364     break;
1365     //BC_VID_ALGO_DIVX:
1366     //BC_VID_ALGO_VC1MP:
1367   }
1368 #endif
1369
1370   do
1371   {
1372 #if (HAVE_LIBCRYSTALHD == 2)
1373     if (m_new_lib)
1374     {
1375       BCM::BC_INPUT_FORMAT bcm_input_format;
1376       memset(&bcm_input_format, 0, sizeof(BCM::BC_INPUT_FORMAT));
1377
1378       bcm_input_format.FGTEnable = FALSE;
1379       bcm_input_format.Progressive = TRUE;
1380       bcm_input_format.OptFlags = 0x80000000 | BCM::vdecFrameRate23_97;
1381       #ifdef USE_CHD_SINGLE_THREADED_API
1382         bcm_input_format.OptFlags |= 0x80;
1383       #endif
1384       
1385       bcm_input_format.width = hints.width;
1386       bcm_input_format.height = hints.height;
1387       bcm_input_format.mSubtype = Subtype;
1388       bcm_input_format.pMetaData = pMetaData;
1389       bcm_input_format.metaDataSz = metaDataSz;
1390       bcm_input_format.startCodeSz = startCodeSz;
1391
1392       res = m_dll->DtsSetInputFormat(m_device, &bcm_input_format);
1393       if (res != BCM::BC_STS_SUCCESS)
1394       {
1395         CLog::Log(LOGERROR, "%s: set input format failed", __MODULE_NAME__);
1396         break;
1397       }
1398
1399       res = m_dll->DtsOpenDecoder(m_device, StreamType);
1400       if (res != BCM::BC_STS_SUCCESS)
1401       {
1402         CLog::Log(LOGERROR, "%s: open decoder failed", __MODULE_NAME__);
1403         break;
1404       }
1405
1406       if (m_has_bcm70015)
1407         res = m_dll->DtsSetColorSpace(m_device, BCM::OUTPUT_MODE422_YUY2); 
1408       else
1409         res = m_dll->DtsSetColorSpace(m_device, BCM::OUTPUT_MODE420); 
1410       if (res != BCM::BC_STS_SUCCESS)
1411       { 
1412         CLog::Log(LOGERROR, "%s: set color space failed", __MODULE_NAME__); 
1413         break; 
1414       }
1415     }
1416     else
1417 #endif
1418     {
1419       res = m_dll->DtsOpenDecoder(m_device, StreamType);
1420       if (res != BCM::BC_STS_SUCCESS)
1421       {
1422         CLog::Log(LOGERROR, "%s: open decoder failed", __MODULE_NAME__);
1423         break;
1424       }
1425
1426       uint32_t OptFlags = 0x80000000 | BCM::vdecFrameRate23_97;
1427       res = m_dll->DtsSetVideoParams(m_device, videoAlg, FALSE, FALSE, TRUE, OptFlags);
1428       if (res != BCM::BC_STS_SUCCESS)
1429       {
1430         CLog::Log(LOGERROR, "%s: set video params failed", __MODULE_NAME__);
1431         break;
1432       }
1433     }
1434     
1435     res = m_dll->DtsStartDecoder(m_device);
1436     if (res != BCM::BC_STS_SUCCESS)
1437     {
1438       CLog::Log(LOGERROR, "%s: start decoder failed", __MODULE_NAME__);
1439       break;
1440     }
1441
1442     res = m_dll->DtsStartCapture(m_device);
1443     if (res != BCM::BC_STS_SUCCESS)
1444     {
1445       CLog::Log(LOGERROR, "%s: start capture failed", __MODULE_NAME__);
1446       break;
1447     }
1448
1449     m_pOutputThread = new CMPCOutputThread(m_device, m_dll, m_has_bcm70015);
1450     m_pOutputThread->Create();
1451
1452     m_drop_state = false;
1453     m_skip_state = false;
1454     m_decoder_open = true;
1455     // set output timeout to 1ms during startup,
1456     // this will get reset once we get a picture back.
1457     // the effect is to speed feeding demux packets during startup.
1458     m_wait_timeout = 1;
1459     m_reset = 0;
1460     m_last_pict_num = 0;
1461     m_last_demuxer_pts = DVD_NOPTS_VALUE;
1462     m_last_decoder_pts = DVD_NOPTS_VALUE;
1463   } while(false);
1464
1465   return m_decoder_open;
1466 }
1467
1468 void CCrystalHD::CloseDecoder(void)
1469 {
1470   if (m_pOutputThread)
1471   {
1472     while(m_BusyList.Count())
1473       m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1474
1475     m_pOutputThread->StopThread();
1476     delete m_pOutputThread;
1477     m_pOutputThread = NULL;
1478   }
1479
1480   if (m_convert_bitstream)
1481   {
1482     if (m_sps_pps_context.sps_pps_data)
1483     {
1484       free(m_sps_pps_context.sps_pps_data);
1485       m_sps_pps_context.sps_pps_data = NULL;
1486     }
1487   }
1488 #if (HAVE_LIBCRYSTALHD == 2)
1489         if (m_chd_params.sps_pps_buf)
1490   {
1491                 free(m_chd_params.sps_pps_buf);
1492                 m_chd_params.sps_pps_buf = NULL;
1493         }
1494 #endif
1495
1496   if (m_decoder_open)
1497   {
1498     // DtsFlushRxCapture must release internal queues when
1499     // calling DtsStopDecoder/DtsCloseDecoder or the next
1500     // DtsStartCapture will fail. This is a driver/lib bug
1501     // with new chd driver. The existing driver ignores the
1502     // bDiscardOnly arg.
1503     if (!m_has_bcm70015)
1504       m_dll->DtsFlushRxCapture(m_device, false);
1505     m_dll->DtsStopDecoder(m_device);
1506     m_dll->DtsCloseDecoder(m_device);
1507     m_decoder_open = false;
1508   }
1509   
1510   CloseDevice();
1511 }
1512
1513 void CCrystalHD::Reset(void)
1514 {
1515   if (!m_has_bcm70015)
1516   {
1517     // Calling for non-error flush, Flushes all the decoder
1518     //  buffers, input, decoded and to be decoded. 
1519     m_reset = 10;
1520     m_wait_timeout = 1;
1521     m_dll->DtsFlushInput(m_device, 2);
1522   }
1523
1524   while (m_BusyList.Count())
1525     m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1526
1527   while (m_pOutputThread->GetReadyCount())
1528   {
1529     ::Sleep(1);
1530     m_pOutputThread->FreeListPush( m_pOutputThread->ReadyListPop() );
1531   }
1532 }
1533
1534 bool CCrystalHD::AddInput(unsigned char *pData, size_t size, double dts, double pts)
1535 {
1536   if (pData)
1537   {
1538     BCM::BC_STATUS ret;
1539     uint64_t int_pts = pts * 1000;
1540     int demuxer_bytes = size;
1541     uint8_t *demuxer_content = pData;
1542     bool free_demuxer_content  = false;
1543
1544     if (m_convert_bitstream)
1545     {
1546       // convert demuxer packet from bitstream (AVC1) to bytestream (AnnexB)
1547       int bytestream_size = 0;
1548       uint8_t *bytestream_buff = NULL;
1549
1550       bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size);
1551       if (bytestream_buff && (bytestream_size > 0))
1552       {
1553         if (bytestream_buff != demuxer_content)
1554           free_demuxer_content = true;
1555         demuxer_bytes = bytestream_size;
1556         demuxer_content = bytestream_buff;
1557       }
1558     }
1559
1560     do
1561     {
1562       ret = m_dll->DtsProcInput(m_device, demuxer_content, demuxer_bytes, int_pts, 0);
1563       if (ret == BCM::BC_STS_SUCCESS)
1564       {
1565         m_last_demuxer_pts = pts;
1566       }
1567       else if (ret == BCM::BC_STS_BUSY)
1568       {
1569         CLog::Log(LOGDEBUG, "%s: DtsProcInput returned BC_STS_BUSY", __MODULE_NAME__);
1570         ::Sleep(1); // Buffer is full, sleep it empty
1571       }
1572     } while (ret != BCM::BC_STS_SUCCESS);
1573
1574     if (free_demuxer_content)
1575       free(demuxer_content);
1576
1577     if (!m_has_bcm70015)
1578     {
1579       if (m_reset)
1580       {
1581         m_reset--;
1582         if (!m_skip_state)
1583         {
1584           m_skip_state = true;
1585           m_dll->DtsSetSkipPictureMode(m_device, 1);
1586         }
1587       }
1588       else
1589       {
1590         if (m_skip_state)
1591         {
1592           m_skip_state = false;
1593           m_dll->DtsSetSkipPictureMode(m_device, 0);
1594         }
1595       }
1596     }
1597
1598     if (m_pOutputThread->GetReadyCount() < 1)
1599       m_pOutputThread->WaitOutput(m_wait_timeout);
1600   }
1601
1602   return true;
1603 }
1604
1605 int CCrystalHD::GetReadyCount(void)
1606 {
1607   if (m_pOutputThread)
1608     return m_pOutputThread->GetReadyCount();
1609   else
1610     return 0;
1611 }
1612
1613 void CCrystalHD::BusyListFlush(void)
1614 {
1615   if (m_pOutputThread)
1616   {
1617     while ( m_BusyList.Count())
1618       m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1619   }
1620 }
1621
1622 bool CCrystalHD::GetPicture(DVDVideoPicture *pDvdVideoPicture)
1623 {
1624   CPictureBuffer* pBuffer = m_pOutputThread->ReadyListPop();
1625
1626   if (!pBuffer)
1627     return false;
1628
1629   // default both dts/pts to DVD_NOPTS_VALUE, if crystalhd drops a frame,
1630   // we can't tell so we can not track dts through the decoder or with
1631   // and external queue. pts will get set from m_timestamp.
1632   pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
1633   pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
1634
1635   if (pBuffer->m_timestamp != 0)
1636     pDvdVideoPicture->pts = (double)pBuffer->m_timestamp / 1000.0;
1637
1638   pDvdVideoPicture->iWidth = pBuffer->m_width;
1639   pDvdVideoPicture->iHeight = pBuffer->m_height;
1640   pDvdVideoPicture->iDisplayWidth = pBuffer->m_width;
1641   pDvdVideoPicture->iDisplayHeight = pBuffer->m_height;
1642
1643   switch(pBuffer->m_format)
1644   {
1645     default:
1646     case RENDER_FMT_NV12:
1647       // Y plane
1648       pDvdVideoPicture->data[0] = (uint8_t*)pBuffer->m_y_buffer_ptr;
1649       pDvdVideoPicture->iLineSize[0] = pBuffer->m_width;
1650       // UV packed plane
1651       pDvdVideoPicture->data[1] = (uint8_t*)pBuffer->m_uv_buffer_ptr;
1652       pDvdVideoPicture->iLineSize[1] = pBuffer->m_width;
1653       // unused
1654       pDvdVideoPicture->data[2] = NULL;
1655       pDvdVideoPicture->iLineSize[2] = 0;
1656     break;
1657     case RENDER_FMT_YUYV422:
1658       // YUV packed plane
1659       pDvdVideoPicture->data[0] = (uint8_t*)pBuffer->m_y_buffer_ptr;
1660       pDvdVideoPicture->iLineSize[0] = pBuffer->m_width * 2;
1661       // unused
1662       pDvdVideoPicture->data[1] = NULL;
1663       pDvdVideoPicture->iLineSize[1] = 0;
1664       // unused
1665       pDvdVideoPicture->data[2] = NULL;
1666       pDvdVideoPicture->iLineSize[2] = 0;
1667     break;
1668     case RENDER_FMT_YUV420P:
1669       // Y plane
1670       pDvdVideoPicture->data[0] = (uint8_t*)pBuffer->m_y_buffer_ptr;
1671       pDvdVideoPicture->iLineSize[0] = pBuffer->m_width;
1672       // U plane
1673       pDvdVideoPicture->data[1] = (uint8_t*)pBuffer->m_u_buffer_ptr;
1674       pDvdVideoPicture->iLineSize[1] = pBuffer->m_width / 2;
1675       // V plane
1676       pDvdVideoPicture->data[2] = (uint8_t*)pBuffer->m_v_buffer_ptr;
1677       pDvdVideoPicture->iLineSize[2] = pBuffer->m_width / 2;
1678     break;
1679   }
1680
1681   pDvdVideoPicture->iRepeatPicture = 0;
1682   pDvdVideoPicture->iDuration = DVD_TIME_BASE / pBuffer->m_framerate;
1683   m_wait_timeout = pDvdVideoPicture->iDuration/2000;
1684   pDvdVideoPicture->color_range = pBuffer->m_color_range;
1685   pDvdVideoPicture->color_matrix = pBuffer->m_color_matrix;
1686   pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
1687   pDvdVideoPicture->iFlags |= m_drop_state ? DVP_FLAG_DROPPED : 0;
1688   pDvdVideoPicture->format = pBuffer->m_format;
1689
1690   m_last_pict_num = pBuffer->m_PictureNumber;
1691   m_last_decoder_pts = pDvdVideoPicture->pts;
1692
1693   while( m_BusyList.Count())
1694     m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1695
1696   m_BusyList.Push(pBuffer);
1697   return true;
1698 }
1699
1700 void CCrystalHD::SetDropState(bool bDrop)
1701 {
1702   if (m_drop_state != bDrop)
1703   {
1704     m_drop_state = bDrop;
1705     
1706     if (!m_has_bcm70015)
1707     {
1708       if (!m_reset)
1709       {
1710         if (m_drop_state)
1711         {
1712           if (!m_skip_state)
1713           {
1714             m_skip_state = true;
1715             m_dll->DtsSetSkipPictureMode(m_device, 1);
1716             Sleep(1);
1717           }
1718         }
1719         else
1720         {
1721           if (m_skip_state)
1722           {
1723             m_skip_state = false;
1724             m_dll->DtsSetSkipPictureMode(m_device, 0);
1725             Sleep(1);
1726           }
1727         }
1728       }
1729     }
1730   }
1731   /*
1732   CLog::Log(LOGDEBUG, "%s: m_drop_state(%d), GetFreeCount(%d), GetReadyCount(%d)", __MODULE_NAME__, 
1733       m_drop_state, m_pOutputThread->GetFreeCount(), m_pOutputThread->GetReadyCount());
1734   */
1735 }
1736 ////////////////////////////////////////////////////////////////////////////////////////////
1737 bool CCrystalHD::extract_sps_pps_from_avcc(int extradata_size, void *extradata)
1738 {
1739   // based on gstbcmdec.c (bcmdec_insert_sps_pps)
1740   // which is Copyright(c) 2008 Broadcom Corporation.
1741   // and Licensed LGPL 2.1
1742
1743   uint8_t *data = (uint8_t*)extradata;
1744   uint32_t data_size = extradata_size;
1745   int profile;
1746   unsigned int nal_size;
1747   unsigned int num_sps, num_pps;
1748
1749   m_chd_params.sps_pps_size = 0;
1750
1751   profile = (data[1] << 16) | (data[2] << 8) | data[3];
1752   CLog::Log(LOGDEBUG, "%s: profile %06x", __MODULE_NAME__, profile);
1753
1754   m_chd_params.nal_size_bytes = (data[4] & 0x03) + 1;
1755
1756   CLog::Log(LOGDEBUG, "%s: nal size %d", __MODULE_NAME__, m_chd_params.nal_size_bytes);
1757
1758   num_sps = data[5] & 0x1f;
1759   CLog::Log(LOGDEBUG, "%s: num sps %d", __MODULE_NAME__, num_sps);
1760
1761   data += 6;
1762   data_size -= 6;
1763
1764   for (unsigned int i = 0; i < num_sps; i++)
1765   {
1766     if (data_size < 2)
1767       return false;
1768
1769     nal_size = (data[0] << 8) | data[1];
1770     data += 2;
1771     data_size -= 2;
1772
1773     if (data_size < nal_size)
1774                         return false;
1775
1776     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size + 0] = 0;
1777     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size + 1] = 0;
1778     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size + 2] = 0;
1779     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size + 3] = 1;
1780
1781     m_chd_params.sps_pps_size += 4;
1782
1783     memcpy(m_chd_params.sps_pps_buf + m_chd_params.sps_pps_size, data, nal_size);
1784     m_chd_params.sps_pps_size += nal_size;
1785
1786     data += nal_size;
1787     data_size -= nal_size;
1788   }
1789
1790   if (data_size < 1)
1791     return false;
1792
1793   num_pps = data[0];
1794   data += 1;
1795   data_size -= 1;
1796
1797   for (unsigned int i = 0; i < num_pps; i++)
1798   {
1799     if (data_size < 2)
1800       return false;
1801
1802     nal_size = (data[0] << 8) | data[1];
1803     data += 2;
1804     data_size -= 2;
1805
1806     if (data_size < nal_size)
1807       return false;
1808
1809     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size+0] = 0;
1810     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size+1] = 0;
1811     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size+2] = 0;
1812     m_chd_params.sps_pps_buf[m_chd_params.sps_pps_size+3] = 1;
1813
1814     m_chd_params.sps_pps_size += 4;
1815
1816     memcpy(m_chd_params.sps_pps_buf + m_chd_params.sps_pps_size, data, nal_size);
1817     m_chd_params.sps_pps_size += nal_size;
1818
1819     data += nal_size;
1820     data_size -= nal_size;
1821   }
1822
1823   CLog::Log(LOGDEBUG, "%s: data size at end = %d ", __MODULE_NAME__, data_size);
1824
1825   return true;
1826 }
1827
1828
1829 ////////////////////////////////////////////////////////////////////////////////////////////
1830 bool CCrystalHD::bitstream_convert_init(void *in_extradata, int in_extrasize)
1831 {
1832   // based on h264_mp4toannexb_bsf.c (ffmpeg)
1833   // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
1834   // and Licensed GPL 2.1 or greater
1835
1836   m_sps_pps_size = 0;
1837   m_sps_pps_context.sps_pps_data = NULL;
1838   
1839   // nothing to filter
1840   if (!in_extradata || in_extrasize < 6)
1841     return false;
1842
1843   uint16_t unit_size;
1844   uint32_t total_size = 0;
1845   uint8_t *out = NULL, unit_nb, sps_done = 0;
1846   const uint8_t *extradata = (uint8_t*)in_extradata + 4;
1847   static const uint8_t nalu_header[4] = {0, 0, 0, 1};
1848
1849   // retrieve length coded size
1850   m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1;
1851   if (m_sps_pps_context.length_size == 3)
1852     return false;
1853
1854   // retrieve sps and pps unit(s)
1855   unit_nb = *extradata++ & 0x1f;  // number of sps unit(s)
1856   if (!unit_nb)
1857   {
1858     unit_nb = *extradata++;       // number of pps unit(s)
1859     sps_done++;
1860   }
1861   while (unit_nb--)
1862   {
1863     unit_size = extradata[0] << 8 | extradata[1];
1864     total_size += unit_size + 4;
1865     if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) )
1866     {
1867       free(out);
1868       return false;
1869     }
1870     uint8_t* new_out = (uint8_t*)realloc(out, total_size);
1871     if (new_out)
1872     {
1873       out = new_out;
1874     }
1875     else
1876     {
1877       CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out",  __FUNCTION__);
1878       free(out);
1879       return false;
1880     }
1881
1882     memcpy(out + total_size - unit_size - 4, nalu_header, 4);
1883     memcpy(out + total_size - unit_size, extradata + 2, unit_size);
1884     extradata += 2 + unit_size;
1885
1886     if (!unit_nb && !sps_done++)
1887       unit_nb = *extradata++;     // number of pps unit(s)
1888   }
1889
1890   m_sps_pps_context.sps_pps_data = out;
1891   m_sps_pps_context.size = total_size;
1892   m_sps_pps_context.first_idr = 1;
1893
1894   return true;
1895 }
1896
1897 bool CCrystalHD::bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size)
1898 {
1899   // based on h264_mp4toannexb_bsf.c (ffmpeg)
1900   // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
1901   // and Licensed GPL 2.1 or greater
1902
1903   uint8_t *buf = pData;
1904   uint32_t buf_size = iSize;
1905   uint8_t  unit_type;
1906   int32_t  nal_size;
1907   uint32_t cumul_size = 0;
1908   const uint8_t *buf_end = buf + buf_size;
1909
1910   do
1911   {
1912     if (buf + m_sps_pps_context.length_size > buf_end)
1913       goto fail;
1914
1915     if (m_sps_pps_context.length_size == 1)
1916       nal_size = buf[0];
1917     else if (m_sps_pps_context.length_size == 2)
1918       nal_size = buf[0] << 8 | buf[1];
1919     else
1920       nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
1921
1922     buf += m_sps_pps_context.length_size;
1923     unit_type = *buf & 0x1f;
1924
1925     if (buf + nal_size > buf_end || nal_size < 0)
1926       goto fail;
1927
1928     // prepend only to the first type 5 NAL unit of an IDR picture
1929     if (m_sps_pps_context.first_idr && unit_type == 5)
1930     {
1931       bitstream_alloc_and_copy(poutbuf, poutbuf_size,
1932         m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size);
1933       m_sps_pps_context.first_idr = 0;
1934     }
1935     else
1936     {
1937       bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size);
1938       if (!m_sps_pps_context.first_idr && unit_type == 1)
1939           m_sps_pps_context.first_idr = 1;
1940     }
1941
1942     buf += nal_size;
1943     cumul_size += nal_size + m_sps_pps_context.length_size;
1944   } while (cumul_size < buf_size);
1945
1946   return true;
1947
1948 fail:
1949   free(*poutbuf);
1950   *poutbuf = NULL;
1951   *poutbuf_size = 0;
1952   return false;
1953 }
1954
1955 void CCrystalHD::bitstream_alloc_and_copy(
1956   uint8_t **poutbuf,      int *poutbuf_size,
1957   const uint8_t *sps_pps, uint32_t sps_pps_size,
1958   const uint8_t *in,      uint32_t in_size)
1959 {
1960   // based on h264_mp4toannexb_bsf.c (ffmpeg)
1961   // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
1962   // and Licensed GPL 2.1 or greater
1963
1964   #define CHD_WB32(p, d) { \
1965     ((uint8_t*)(p))[3] = (d); \
1966     ((uint8_t*)(p))[2] = (d) >> 8; \
1967     ((uint8_t*)(p))[1] = (d) >> 16; \
1968     ((uint8_t*)(p))[0] = (d) >> 24; }
1969
1970   uint32_t offset = *poutbuf_size;
1971   uint8_t nal_header_size = offset ? 3 : 4;
1972
1973   *poutbuf_size += sps_pps_size + in_size + nal_header_size;
1974   *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size);
1975   if (sps_pps)
1976     memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
1977
1978   memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
1979   if (!offset)
1980   {
1981     CHD_WB32(*poutbuf + sps_pps_size, 1);
1982   }
1983   else
1984   {
1985     (*poutbuf + offset + sps_pps_size)[0] = 0;
1986     (*poutbuf + offset + sps_pps_size)[1] = 0;
1987     (*poutbuf + offset + sps_pps_size)[2] = 1;
1988   }
1989 }
1990
1991 ////////////////////////////////////////////////////////////////////////////////////////////
1992 void PrintFormat(BCM::BC_PIC_INFO_BLOCK &pib)
1993 {
1994   CLog::Log(LOGDEBUG, "----------------------------------\n%s","");
1995   CLog::Log(LOGDEBUG, "\tTimeStamp: %"PRIu64"\n", pib.timeStamp);
1996   CLog::Log(LOGDEBUG, "\tPicture Number: %d\n", pib.picture_number);
1997   CLog::Log(LOGDEBUG, "\tWidth: %d\n", pib.width);
1998   CLog::Log(LOGDEBUG, "\tHeight: %d\n", pib.height);
1999   CLog::Log(LOGDEBUG, "\tChroma: 0x%03x\n", pib.chroma_format);
2000   CLog::Log(LOGDEBUG, "\tPulldown: %d\n", pib.pulldown);
2001   CLog::Log(LOGDEBUG, "\tFlags: 0x%08x\n", pib.flags);
2002   CLog::Log(LOGDEBUG, "\tFrame Rate/Res: %d\n", pib.frame_rate);
2003   CLog::Log(LOGDEBUG, "\tAspect Ratio: %d\n", pib.aspect_ratio);
2004   CLog::Log(LOGDEBUG, "\tColor Primaries: %d\n", pib.colour_primaries);
2005   CLog::Log(LOGDEBUG, "\tMetaData: %d\n", pib.picture_meta_payload);
2006   CLog::Log(LOGDEBUG, "\tSession Number: %d\n", pib.sess_num);
2007   CLog::Log(LOGDEBUG, "\tTimeStamp: %d\n", pib.ycom);
2008   CLog::Log(LOGDEBUG, "\tCustom Aspect: %d\n", pib.custom_aspect_ratio_width_height);
2009   CLog::Log(LOGDEBUG, "\tFrames to Drop: %d\n", pib.n_drop);
2010   CLog::Log(LOGDEBUG, "\tH264 Valid Fields: 0x%08x\n", pib.other.h264.valid);
2011 }
2012
2013 #endif