2 * Copyright (C) 2005-2013 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, see
17 * <http://www.gnu.org/licenses/>.
22 #if defined(TARGET_WINDOWS)
23 #include "WIN32Util.h"
25 #include "dialogs/GUIDialogKaiToast.h"
26 #include "guilib/LocalizeStrings.h"
29 #if defined(HAVE_LIBCRYSTALHD)
30 #include "CrystalHD.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"
45 #if defined(TARGET_WINDOWS)
48 #ifndef __LINUX_USER__
49 #define __LINUX_USER__
53 #include <libcrystalhd/bc_dts_types.h>
54 #include <libcrystalhd/bc_dts_defs.h>
55 #include <libcrystalhd/libcrystalhd_if.h>
58 #define __MODULE_NAME__ "CrystalHD"
59 //#define USE_CHD_SINGLE_THREADED_API
60 class DllLibCrystalHDInterface
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;
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;
94 class DllLibCrystalHD : public DllDynamic, DllLibCrystalHDInterface
96 DECLARE_DLL_WRAPPER(DllLibCrystalHD, DLL_PATH_LIBCRYSTALHD)
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))
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))
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)
148 bool LoadNewLibFunctions(void)
150 #if (HAVE_LIBCRYSTALHD == 2)
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);
168 void PrintFormat(BCM::BC_PIC_INFO_BLOCK &pib);
169 void BcmDebugLog( BCM::BC_STATUS lResult, CStdString strFuncName="");
171 const char* g_DtsStatusText[] = {
181 "BC_STS_VER_MISMATCH",
184 "BC_STS_DEC_NOT_OPEN",
186 "BC_STS_IO_USER_ABORT",
187 "BC_STS_IO_XFR_ERROR",
188 "BC_STS_DEC_NOT_STARTED",
189 "BC_STS_FWHEX_NOT_FOUND",
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",
201 ////////////////////////////////////////////////////////////////////////////////////////////
202 class CMPCOutputThread : public CThread
205 CMPCOutputThread(void *device, DllLibCrystalHD *dll, bool has_bcm70015);
206 virtual ~CMPCOutputThread();
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);
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);
226 CSyncPtrQueue<CPictureBuffer> m_FreeList;
227 CSyncPtrQueue<CPictureBuffer> m_ReadyList;
229 DllLibCrystalHD *m_dll;
232 unsigned int m_timeout;
234 bool m_is_live_stream;
237 uint64_t m_timestamp;
239 uint64_t m_PictureNumber;
240 uint8_t m_color_space;
241 unsigned int m_color_range;
242 unsigned int m_color_matrix;
244 bool m_framerate_tracking;
245 uint64_t m_framerate_cnt;
246 double m_framerate_timestamp;
250 CEvent m_ready_event;
251 DllSwScale *m_dllSwScale;
252 struct SwsContext *m_sw_scale_ctx;
255 ////////////////////////////////////////////////////////////////////////////////////////////
256 #if defined(TARGET_DARWIN)
259 CPictureBuffer::CPictureBuffer(ERenderFormat format, int width, int height)
263 m_field = CRYSTALHD_FIELD_FULL;
265 m_timestamp = DVD_NOPTS_VALUE;
267 m_color_space = BCM::MODE420;
276 case RENDER_FMT_NV12:
278 m_y_buffer_size = m_width * m_height;
279 m_y_buffer_ptr = (unsigned char*)_aligned_malloc(m_y_buffer_size, 16);
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);
288 case RENDER_FMT_YUYV422:
290 m_y_buffer_size = (2 * m_width) * m_height;
291 m_y_buffer_ptr = (unsigned char*)_aligned_malloc(m_y_buffer_size, 16);
293 m_uv_buffer_size = 0;
294 m_uv_buffer_ptr = NULL;
297 m_u_buffer_ptr = NULL;
298 m_v_buffer_ptr = NULL;
300 case RENDER_FMT_YUV420P:
302 m_y_buffer_size = m_width * m_height;
303 m_y_buffer_ptr = (unsigned char*)_aligned_malloc(m_y_buffer_size, 16);
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);
315 CPictureBuffer::~CPictureBuffer()
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);
323 /////////////////////////////////////////////////////////////////////////////////////////////
324 #if defined(TARGET_DARWIN)
327 CMPCOutputThread::CMPCOutputThread(void *device, DllLibCrystalHD *dll, bool has_bcm70015) :
328 CThread("MPCOutput"),
331 m_has_bcm70015(has_bcm70015),
333 m_format_valid(false),
334 m_is_live_stream(false),
343 m_framerate_tracking(false),
345 m_framerate_timestamp(0.0),
350 m_sw_scale_ctx = NULL;
351 m_dllSwScale = new DllSwScale;
352 m_dllSwScale->Load();
355 if (g_Windowing.GetRenderQuirks() & RENDER_QUIRKS_YV12_PREFERED)
356 m_output_YV12 = true;
358 m_output_YV12 = false;
361 CMPCOutputThread::~CMPCOutputThread()
363 while(m_ReadyList.Count())
364 delete m_ReadyList.Pop();
365 while(m_FreeList.Count())
366 delete m_FreeList.Pop();
369 m_dllSwScale->sws_freeContext(m_sw_scale_ctx);
373 unsigned int CMPCOutputThread::GetReadyCount(void)
375 return m_ReadyList.Count();
378 unsigned int CMPCOutputThread::GetFreeCount(void)
380 return m_FreeList.Count();
383 CPictureBuffer* CMPCOutputThread::ReadyListPop(void)
385 CPictureBuffer *pBuffer = m_ReadyList.Pop();
389 void CMPCOutputThread::FreeListPush(CPictureBuffer* pBuffer)
391 m_FreeList.Push(pBuffer);
394 bool CMPCOutputThread::WaitOutput(unsigned int msec)
396 return m_ready_event.WaitMSec(msec);
399 void CMPCOutputThread::DoFrameRateTracking(double timestamp)
401 if (timestamp != DVD_NOPTS_VALUE)
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
412 if (m_framerate_cnt == 0 && timestamp > 250000.0)
413 m_is_live_stream = true;
415 duration = timestamp - m_framerate_timestamp;
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
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.
434 switch ((int)(0.5 + framerate))
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);
450 void CMPCOutputThread::SetFrameRate(uint32_t resolution)
456 case BCM::vdecRESOLUTION_1080p30:
459 case BCM::vdecRESOLUTION_1080p29_97:
460 m_framerate = 30.0 * 1000.0 / 1001.0;
462 case BCM::vdecRESOLUTION_1080p25 :
465 case BCM::vdecRESOLUTION_1080p24:
468 case BCM::vdecRESOLUTION_1080p23_976:
469 m_framerate = 24.0 * 1000.0 / 1001.0;
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;
480 case BCM::vdecRESOLUTION_1080i29_97:
481 m_framerate = 30.0 * 1000.0 / 1001.0;
484 case BCM::vdecRESOLUTION_1080i0:
485 m_framerate = 30.0 * 1000.0 / 1001.0;
488 case BCM::vdecRESOLUTION_1080i:
489 m_framerate = 30.0 * 1000.0 / 1001.0;
492 case BCM::vdecRESOLUTION_1080i25:
493 m_framerate = 25.0 * 1000.0 / 1001.0;
497 case BCM::vdecRESOLUTION_720p59_94:
498 m_framerate = 60.0 * 1000.0 / 1001.0;
500 case BCM::vdecRESOLUTION_720p:
501 m_framerate = 60.0 * 1000.0 / 1001.0;
503 case BCM::vdecRESOLUTION_720p50:
504 m_framerate = 50.0 * 1000.0 / 1001.0;
506 case BCM::vdecRESOLUTION_720p29_97:
507 m_framerate = 30.0 * 1000.0 / 1001.0;
509 case BCM::vdecRESOLUTION_720p24:
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;
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;
526 case BCM::vdecRESOLUTION_576p25:
529 case BCM::vdecRESOLUTION_576p0:
532 case BCM::vdecRESOLUTION_PAL1:
533 m_framerate = 25.0 * 1000.0 / 1001.0;
537 case BCM::vdecRESOLUTION_480p0:
540 case BCM::vdecRESOLUTION_480p:
541 m_framerate = 60.0 * 1000.0 / 1001.0;
543 case BCM::vdecRESOLUTION_480p29_97:
544 m_framerate = 30.0 * 1000.0 / 1001.0;
546 case BCM::vdecRESOLUTION_480p23_976:
547 m_framerate = 24.0 * 1000.0 / 1001.0;
550 case BCM::vdecRESOLUTION_480i0:
551 m_framerate = 30.0 * 1000.0 / 1001.0;
554 case BCM::vdecRESOLUTION_480i:
555 m_framerate = 30.0 * 1000.0 / 1001.0;
558 case BCM::vdecRESOLUTION_NTSC:
559 m_framerate = 30.0 * 1000.0 / 1001.0;
564 m_framerate_tracking = true;
565 m_framerate = 24.0 * 1000.0 / 1001.0;
569 CLog::Log(LOGDEBUG, "%s: resolution = %x interlace = %d", __MODULE_NAME__, resolution, m_interlace);
572 void CMPCOutputThread::SetAspectRatio(BCM::BC_PIC_INFO_BLOCK *pic_info)
574 switch(pic_info->aspect_ratio)
576 case BCM::vdecAspectRatioSquare:
580 case BCM::vdecAspectRatio12_11:
581 m_aspectratio_x = 12;
582 m_aspectratio_y = 11;
584 case BCM::vdecAspectRatio10_11:
585 m_aspectratio_x = 10;
586 m_aspectratio_y = 11;
588 case BCM::vdecAspectRatio16_11:
589 m_aspectratio_x = 16;
590 m_aspectratio_y = 11;
592 case BCM::vdecAspectRatio40_33:
593 m_aspectratio_x = 40;
594 m_aspectratio_y = 33;
596 case BCM::vdecAspectRatio24_11:
597 m_aspectratio_x = 24;
598 m_aspectratio_y = 11;
600 case BCM::vdecAspectRatio20_11:
601 m_aspectratio_x = 20;
602 m_aspectratio_y = 11;
604 case BCM::vdecAspectRatio32_11:
605 m_aspectratio_x = 32;
606 m_aspectratio_y = 11;
608 case BCM::vdecAspectRatio80_33:
609 m_aspectratio_x = 80;
610 m_aspectratio_y = 33;
612 case BCM::vdecAspectRatio18_11:
613 m_aspectratio_x = 18;
614 m_aspectratio_y = 11;
616 case BCM::vdecAspectRatio15_11:
617 m_aspectratio_x = 15;
618 m_aspectratio_y = 11;
620 case BCM::vdecAspectRatio64_33:
621 m_aspectratio_x = 64;
622 m_aspectratio_y = 33;
624 case BCM::vdecAspectRatio160_99:
625 m_aspectratio_x = 160;
626 m_aspectratio_y = 99;
628 case BCM::vdecAspectRatio4_3:
632 case BCM::vdecAspectRatio16_9:
633 m_aspectratio_x = 16;
636 case BCM::vdecAspectRatio221_1:
637 m_aspectratio_x = 221;
640 case BCM::vdecAspectRatioUnknown:
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;
650 if(m_aspectratio_x == 0)
656 CLog::Log(LOGDEBUG, "%s: dec_par x = %d, dec_par y = %d", __MODULE_NAME__, m_aspectratio_x, m_aspectratio_y);
659 void CMPCOutputThread::CopyOutAsYV12(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
664 fast_memcpy(pBuffer->m_y_buffer_ptr, procOut->Ybuff, w * h);
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);
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++)
679 uint8_t *s_uv = procOut->UVbuff + (y * stride);
680 for (int x = 0; x < w/2; x++)
688 void CMPCOutputThread::CopyOutAsYV12DeInterlace(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
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)
695 fast_memcpy(d_y, s_y, w);
697 fast_memcpy(d_y, s_y, w);
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++)
706 uint8_t *s_uv = procOut->UVbuff + (y * stride);
707 for (int x = 0; x < w/2; x++)
712 s_uv = procOut->UVbuff + (y * stride);
713 for (int x = 0; x < w/2; x++)
720 pBuffer->m_interlace = false;
723 void CMPCOutputThread::CopyOutAsNV12(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
729 fast_memcpy(pBuffer->m_y_buffer_ptr, procOut->Ybuff, bytes);
731 fast_memcpy(pBuffer->m_uv_buffer_ptr, procOut->UVbuff, bytes/2 );
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);
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);
748 void CMPCOutputThread::CopyOutAsNV12DeInterlace(CPictureBuffer *pBuffer, BCM::BC_DTS_PROC_OUT *procOut, int w, int h, int stride)
750 // do simple line doubling de-interlacing.
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)
756 fast_memcpy(d_y, s_y, w);
758 fast_memcpy(d_y, s_y, w);
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);
767 fast_memcpy(d_uv, s_uv, w);
770 pBuffer->m_interlace = false;
773 void CMPCOutputThread::CheckUpperLeftGreenPixelHack(CPictureBuffer *pBuffer)
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)
784 case RENDER_FMT_YUV420P:
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;
795 case RENDER_FMT_NV12:
797 uint8_t *d_y = pBuffer->m_y_buffer_ptr;
798 uint16_t *d_uv = (uint16_t*)pBuffer->m_uv_buffer_ptr;
804 case RENDER_FMT_YUYV422:
806 uint32_t *d_yuyv = (uint32_t*)pBuffer->m_y_buffer_ptr;
807 d_yuyv[0] = d_yuyv[1];
813 bool CMPCOutputThread::GetDecoderOutput(void)
816 BCM::BC_DTS_PROC_OUT procOut;
817 CPictureBuffer *pBuffer = NULL;
818 bool got_picture = false;
820 // Setup output struct
821 memset(&procOut, 0, sizeof(BCM::BC_DTS_PROC_OUT));
823 // Fetch data from the decoder
824 ret = m_dll->DtsProcOutputNoCopy(m_device, m_timeout, &procOut);
828 case BCM::BC_STS_SUCCESS:
829 if (m_format_valid && (procOut.PoutFlags & BCM::BC_POUT_FLAGS_PIB_VALID))
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)
836 m_timestamp = procOut.PicInfo.timeStamp;
837 m_PictureNumber = procOut.PicInfo.picture_number;
839 if (m_framerate_tracking)
840 DoFrameRateTracking((double)m_timestamp / 1000.0);
842 // do not let FreeList to get greater than 10
843 if (m_FreeList.Count() > 10)
844 delete m_FreeList.Pop();
846 // Get next output buffer from the free list
847 pBuffer = m_FreeList.Pop();
850 // No free pre-allocated buffers so make one
853 // output YV12, nouveau driver has slow NV12, YUY2 capability.
854 pBuffer = new CPictureBuffer(RENDER_FMT_YUV420P, m_width, m_height);
858 if (m_color_space == BCM::MODE422_YUY2)
859 pBuffer = new CPictureBuffer(RENDER_FMT_YUYV422, m_width, m_height);
861 pBuffer = new CPictureBuffer(RENDER_FMT_NV12, m_width, m_height);
864 CLog::Log(LOGDEBUG, "%s: Added a new Buffer, ReadyListCount: %d", __MODULE_NAME__, m_ReadyList.Count());
865 while (!m_bStop && m_ReadyList.Count() > 10)
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;
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;
887 // bcm70012 uses quantized strides
896 if (pBuffer->m_color_space == BCM::MODE420)
898 switch(pBuffer->m_format)
900 case RENDER_FMT_NV12:
901 if (pBuffer->m_interlace)
902 CopyOutAsNV12DeInterlace(pBuffer, &procOut, w, h, stride);
904 CopyOutAsNV12(pBuffer, &procOut, w, h, stride);
906 case RENDER_FMT_YUV420P:
907 if (pBuffer->m_interlace)
908 CopyOutAsYV12DeInterlace(pBuffer, &procOut, w, h, stride);
910 CopyOutAsYV12(pBuffer, &procOut, w, h, stride);
918 switch(pBuffer->m_format)
920 case RENDER_FMT_YUYV422:
921 if (pBuffer->m_interlace)
923 // do simple line doubling de-interlacing.
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)
931 fast_memcpy(d_y, s_y, yuy2_w);
933 fast_memcpy(d_y, s_y, yuy2_w);
936 pBuffer->m_interlace = false;
940 fast_memcpy(pBuffer->m_y_buffer_ptr, procOut.Ybuff, pBuffer->m_y_buffer_size);
943 case RENDER_FMT_YUV420P:
944 // TODO: deinterlace for yuy2 -> yv12, icky
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 };
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);
964 CheckUpperLeftGreenPixelHack(pBuffer);
965 m_ReadyList.Push(pBuffer);
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;
977 m_dll->DtsReleaseOutputBuffs(m_device, NULL, FALSE);
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))
984 PrintFormat(procOut.PicInfo);
986 if (procOut.PicInfo.height == 1088) {
987 procOut.PicInfo.height = 1080;
989 m_width = procOut.PicInfo.width;
990 m_height = procOut.PicInfo.height;
991 m_timestamp = DVD_NOPTS_VALUE;
992 m_color_space = procOut.b422Mode;
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)
1002 m_format_valid = true;
1003 m_ready_event.Set();
1007 case BCM::BC_STS_DEC_NOT_OPEN:
1010 case BCM::BC_STS_DEC_NOT_STARTED:
1013 case BCM::BC_STS_IO_USER_ABORT:
1016 case BCM::BC_STS_NO_DATA:
1019 case BCM::BC_STS_TIMEOUT:
1024 CLog::Log(LOGDEBUG, "%s: DtsProcOutput returned %d.", __MODULE_NAME__, ret);
1026 CLog::Log(LOGDEBUG, "%s: DtsProcOutput returned %s.", __MODULE_NAME__, g_DtsStatusText[ret]);
1033 void CMPCOutputThread::Process(void)
1036 BCM::BC_DTS_STATUS decoder_status;
1038 m_PictureNumber = 0;
1040 CLog::Log(LOGDEBUG, "%s: Output Thread Started...", __MODULE_NAME__);
1042 // wait for decoder startup, calls into DtsProcOutputXXCopy will
1043 // return immediately until decoder starts getting input packets.
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)
1056 // decoder is primed so now calls in DtsProcOutputXXCopy will block
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)
1066 #ifdef USE_CHD_SINGLE_THREADED_API
1069 ret = m_dll->DtsGetDriverStatus(m_device, &decoder_status);
1070 if (ret == BCM::BC_STS_SUCCESS && decoder_status.ReadyListCount != 0)
1072 double pts = (double)decoder_status.NextTimeStamp / 1000.0;
1073 fprintf(stdout, "cpbEmptySize(%d), NextTimeStamp(%f)\n", decoder_status.cpbEmptySize, pts);
1080 CLog::Log(LOGDEBUG, "%s: Output Thread Stopped...", __MODULE_NAME__);
1083 ////////////////////////////////////////////////////////////////////////////////////////////
1084 #if defined(TARGET_DARWIN)
1087 CCrystalHD* CCrystalHD::m_pInstance = NULL;
1089 CCrystalHD::CCrystalHD() :
1091 m_device_preset(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),
1105 m_last_demuxer_pts(0.0),
1106 m_last_decoder_pts(0.0),
1107 m_pOutputThread(NULL),
1109 m_convert_bitstream(false)
1111 #if (HAVE_LIBCRYSTALHD == 2)
1112 memset(&m_bc_info_crystal, 0, sizeof(m_bc_info_crystal));
1115 memset(&m_chd_params, 0, sizeof(m_chd_params));
1116 memset(&m_sps_pps_context, 0, sizeof(m_sps_pps_context));
1118 m_dll = new DllLibCrystalHD;
1119 #ifdef TARGET_WINDOWS
1121 if(CWIN32Util::GetCrystalHDLibraryPath(strDll) && m_dll->SetFile(strDll) && m_dll->Load() && m_dll->IsLoaded() )
1123 if (m_dll->Load() && m_dll->IsLoaded() )
1126 #if (HAVE_LIBCRYSTALHD == 2)
1127 m_new_lib = m_dll->LoadNewLibFunctions();
1132 #if (HAVE_LIBCRYSTALHD == 2)
1133 if (m_device && m_new_lib)
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)
1140 m_color_space = BCM::OUTPUT_MODE422_YUY2;
1145 // delete dll if device open fails, minimizes ram footprint
1150 CLog::Log(LOGDEBUG, "%s: broadcom crystal hd not found", __MODULE_NAME__);
1154 // we know there's a device present now, close the device until doing playback
1160 CCrystalHD::~CCrystalHD()
1173 bool CCrystalHD::DevicePresent(void)
1175 return m_device_preset;
1178 void CCrystalHD::RemoveInstance(void)
1187 CCrystalHD* CCrystalHD::GetInstance(void)
1191 m_pInstance = new CCrystalHD();
1196 void CCrystalHD::OpenDevice()
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 |
1203 BCM::DTS_SKIP_TX_CHK_CPB |
1204 BCM::DTS_PLAYBACK_DROP_RPT_MODE |
1205 DTS_DFLT_RESOLUTION(BCM::vdecRESOLUTION_720p23_976);
1207 BCM::BC_STATUS res= m_dll->DtsDeviceOpen(&m_device, mode);
1208 if (res != BCM::BC_STS_SUCCESS)
1211 if( res == BCM::BC_STS_DEC_EXIST_OPEN )
1212 CLog::Log(LOGDEBUG, "%s: device owned by another application", __MODULE_NAME__);
1214 CLog::Log(LOGDEBUG, "%s: device open failed , returning(0x%x)", __MODULE_NAME__, res);
1215 m_device_preset = false;
1219 #if (HAVE_LIBCRYSTALHD == 2)
1221 CLog::Log(LOGDEBUG, "%s(new API): device opened", __MODULE_NAME__);
1223 CLog::Log(LOGDEBUG, "%s(old API): device opened", __MODULE_NAME__);
1225 CLog::Log(LOGDEBUG, "%s: device opened", __MODULE_NAME__);
1227 m_device_preset = true;
1231 void CCrystalHD::CloseDevice()
1235 m_dll->DtsDeviceClose(m_device);
1237 CLog::Log(LOGDEBUG, "%s: device closed", __MODULE_NAME__);
1241 bool CCrystalHD::OpenDecoder(CRYSTALHD_CODEC_TYPE codec_type, CDVDStreamInfo &hints)
1244 uint32_t StreamType;
1245 #if (HAVE_LIBCRYSTALHD == 2)
1246 BCM::BC_MEDIA_SUBTYPE Subtype;
1249 if (!m_device_preset)
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) )
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.");
1270 if (codec_type == CRYSTALHD_CODEC_ID_AVC1)
1275 uint32_t videoAlg = 0;
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;
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;
1288 case CRYSTALHD_CODEC_ID_WMV3:
1289 if (!m_has_bcm70015)
1291 videoAlg = BCM::BC_VID_ALGO_VC1MP;
1292 StreamType = BCM::BC_STREAM_TYPE_ES;
1293 m_convert_bitstream = false;
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;
1300 case CRYSTALHD_CODEC_ID_AVC1:
1301 videoAlg = BCM::BC_VID_ALGO_H264;
1302 StreamType = BCM::BC_STREAM_TYPE_ES;
1304 m_convert_bitstream = bitstream_convert_init((uint8_t*)hints.extradata, hints.extrasize);
1306 m_convert_bitstream = false;
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;
1314 //BC_VID_ALGO_VC1MP:
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;
1327 case CRYSTALHD_CODEC_ID_VC1:
1328 Subtype = BCM::BC_MSUBTYPE_VC1;
1329 pMetaData = (uint8_t*)hints.extradata;
1330 metaDataSz = hints.extrasize;
1332 case CRYSTALHD_CODEC_ID_WVC1:
1333 Subtype = BCM::BC_MSUBTYPE_WVC1;
1335 case CRYSTALHD_CODEC_ID_WMV3:
1336 Subtype = BCM::BC_MSUBTYPE_WMV3;
1337 pMetaData = (uint8_t*)hints.extradata;
1338 metaDataSz = hints.extrasize;
1340 case CRYSTALHD_CODEC_ID_H264:
1341 Subtype = BCM::BC_MSUBTYPE_H264;
1342 pMetaData = (uint8_t*)hints.extradata;
1343 metaDataSz = hints.extrasize;
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))
1350 free(m_chd_params.sps_pps_buf);
1351 m_chd_params.sps_pps_buf = NULL;
1355 pMetaData = m_chd_params.sps_pps_buf;
1356 metaDataSz = m_chd_params.sps_pps_size;
1357 startCodeSz = m_chd_params.nal_size_bytes;
1360 case CRYSTALHD_CODEC_ID_MPEG2:
1361 Subtype = BCM::BC_MSUBTYPE_MPEG2VIDEO;
1362 pMetaData = (uint8_t*)hints.extradata;
1363 metaDataSz = hints.extrasize;
1366 //BC_VID_ALGO_VC1MP:
1372 #if (HAVE_LIBCRYSTALHD == 2)
1375 BCM::BC_INPUT_FORMAT bcm_input_format;
1376 memset(&bcm_input_format, 0, sizeof(BCM::BC_INPUT_FORMAT));
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;
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;
1392 res = m_dll->DtsSetInputFormat(m_device, &bcm_input_format);
1393 if (res != BCM::BC_STS_SUCCESS)
1395 CLog::Log(LOGERROR, "%s: set input format failed", __MODULE_NAME__);
1399 res = m_dll->DtsOpenDecoder(m_device, StreamType);
1400 if (res != BCM::BC_STS_SUCCESS)
1402 CLog::Log(LOGERROR, "%s: open decoder failed", __MODULE_NAME__);
1407 res = m_dll->DtsSetColorSpace(m_device, BCM::OUTPUT_MODE422_YUY2);
1409 res = m_dll->DtsSetColorSpace(m_device, BCM::OUTPUT_MODE420);
1410 if (res != BCM::BC_STS_SUCCESS)
1412 CLog::Log(LOGERROR, "%s: set color space failed", __MODULE_NAME__);
1419 res = m_dll->DtsOpenDecoder(m_device, StreamType);
1420 if (res != BCM::BC_STS_SUCCESS)
1422 CLog::Log(LOGERROR, "%s: open decoder failed", __MODULE_NAME__);
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)
1430 CLog::Log(LOGERROR, "%s: set video params failed", __MODULE_NAME__);
1435 res = m_dll->DtsStartDecoder(m_device);
1436 if (res != BCM::BC_STS_SUCCESS)
1438 CLog::Log(LOGERROR, "%s: start decoder failed", __MODULE_NAME__);
1442 res = m_dll->DtsStartCapture(m_device);
1443 if (res != BCM::BC_STS_SUCCESS)
1445 CLog::Log(LOGERROR, "%s: start capture failed", __MODULE_NAME__);
1449 m_pOutputThread = new CMPCOutputThread(m_device, m_dll, m_has_bcm70015);
1450 m_pOutputThread->Create();
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.
1460 m_last_pict_num = 0;
1461 m_last_demuxer_pts = DVD_NOPTS_VALUE;
1462 m_last_decoder_pts = DVD_NOPTS_VALUE;
1465 return m_decoder_open;
1468 void CCrystalHD::CloseDecoder(void)
1470 if (m_pOutputThread)
1472 while(m_BusyList.Count())
1473 m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1475 m_pOutputThread->StopThread();
1476 delete m_pOutputThread;
1477 m_pOutputThread = NULL;
1480 if (m_convert_bitstream)
1482 if (m_sps_pps_context.sps_pps_data)
1484 free(m_sps_pps_context.sps_pps_data);
1485 m_sps_pps_context.sps_pps_data = NULL;
1488 #if (HAVE_LIBCRYSTALHD == 2)
1489 if (m_chd_params.sps_pps_buf)
1491 free(m_chd_params.sps_pps_buf);
1492 m_chd_params.sps_pps_buf = NULL;
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;
1513 void CCrystalHD::Reset(void)
1515 if (!m_has_bcm70015)
1517 // Calling for non-error flush, Flushes all the decoder
1518 // buffers, input, decoded and to be decoded.
1521 m_dll->DtsFlushInput(m_device, 2);
1524 while (m_BusyList.Count())
1525 m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1527 while (m_pOutputThread->GetReadyCount())
1530 m_pOutputThread->FreeListPush( m_pOutputThread->ReadyListPop() );
1534 bool CCrystalHD::AddInput(unsigned char *pData, size_t size, double dts, double pts)
1539 uint64_t int_pts = pts * 1000;
1540 int demuxer_bytes = size;
1541 uint8_t *demuxer_content = pData;
1542 bool free_demuxer_content = false;
1544 if (m_convert_bitstream)
1546 // convert demuxer packet from bitstream (AVC1) to bytestream (AnnexB)
1547 int bytestream_size = 0;
1548 uint8_t *bytestream_buff = NULL;
1550 bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size);
1551 if (bytestream_buff && (bytestream_size > 0))
1553 if (bytestream_buff != demuxer_content)
1554 free_demuxer_content = true;
1555 demuxer_bytes = bytestream_size;
1556 demuxer_content = bytestream_buff;
1562 ret = m_dll->DtsProcInput(m_device, demuxer_content, demuxer_bytes, int_pts, 0);
1563 if (ret == BCM::BC_STS_SUCCESS)
1565 m_last_demuxer_pts = pts;
1567 else if (ret == BCM::BC_STS_BUSY)
1569 CLog::Log(LOGDEBUG, "%s: DtsProcInput returned BC_STS_BUSY", __MODULE_NAME__);
1570 ::Sleep(1); // Buffer is full, sleep it empty
1572 } while (ret != BCM::BC_STS_SUCCESS);
1574 if (free_demuxer_content)
1575 free(demuxer_content);
1577 if (!m_has_bcm70015)
1584 m_skip_state = true;
1585 m_dll->DtsSetSkipPictureMode(m_device, 1);
1592 m_skip_state = false;
1593 m_dll->DtsSetSkipPictureMode(m_device, 0);
1598 if (m_pOutputThread->GetReadyCount() < 1)
1599 m_pOutputThread->WaitOutput(m_wait_timeout);
1605 int CCrystalHD::GetReadyCount(void)
1607 if (m_pOutputThread)
1608 return m_pOutputThread->GetReadyCount();
1613 void CCrystalHD::BusyListFlush(void)
1615 if (m_pOutputThread)
1617 while ( m_BusyList.Count())
1618 m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1622 bool CCrystalHD::GetPicture(DVDVideoPicture *pDvdVideoPicture)
1624 CPictureBuffer* pBuffer = m_pOutputThread->ReadyListPop();
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;
1635 if (pBuffer->m_timestamp != 0)
1636 pDvdVideoPicture->pts = (double)pBuffer->m_timestamp / 1000.0;
1638 pDvdVideoPicture->iWidth = pBuffer->m_width;
1639 pDvdVideoPicture->iHeight = pBuffer->m_height;
1640 pDvdVideoPicture->iDisplayWidth = pBuffer->m_width;
1641 pDvdVideoPicture->iDisplayHeight = pBuffer->m_height;
1643 switch(pBuffer->m_format)
1646 case RENDER_FMT_NV12:
1648 pDvdVideoPicture->data[0] = (uint8_t*)pBuffer->m_y_buffer_ptr;
1649 pDvdVideoPicture->iLineSize[0] = pBuffer->m_width;
1651 pDvdVideoPicture->data[1] = (uint8_t*)pBuffer->m_uv_buffer_ptr;
1652 pDvdVideoPicture->iLineSize[1] = pBuffer->m_width;
1654 pDvdVideoPicture->data[2] = NULL;
1655 pDvdVideoPicture->iLineSize[2] = 0;
1657 case RENDER_FMT_YUYV422:
1659 pDvdVideoPicture->data[0] = (uint8_t*)pBuffer->m_y_buffer_ptr;
1660 pDvdVideoPicture->iLineSize[0] = pBuffer->m_width * 2;
1662 pDvdVideoPicture->data[1] = NULL;
1663 pDvdVideoPicture->iLineSize[1] = 0;
1665 pDvdVideoPicture->data[2] = NULL;
1666 pDvdVideoPicture->iLineSize[2] = 0;
1668 case RENDER_FMT_YUV420P:
1670 pDvdVideoPicture->data[0] = (uint8_t*)pBuffer->m_y_buffer_ptr;
1671 pDvdVideoPicture->iLineSize[0] = pBuffer->m_width;
1673 pDvdVideoPicture->data[1] = (uint8_t*)pBuffer->m_u_buffer_ptr;
1674 pDvdVideoPicture->iLineSize[1] = pBuffer->m_width / 2;
1676 pDvdVideoPicture->data[2] = (uint8_t*)pBuffer->m_v_buffer_ptr;
1677 pDvdVideoPicture->iLineSize[2] = pBuffer->m_width / 2;
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;
1690 m_last_pict_num = pBuffer->m_PictureNumber;
1691 m_last_decoder_pts = pDvdVideoPicture->pts;
1693 while( m_BusyList.Count())
1694 m_pOutputThread->FreeListPush( m_BusyList.Pop() );
1696 m_BusyList.Push(pBuffer);
1700 void CCrystalHD::SetDropState(bool bDrop)
1702 if (m_drop_state != bDrop)
1704 m_drop_state = bDrop;
1706 if (!m_has_bcm70015)
1714 m_skip_state = true;
1715 m_dll->DtsSetSkipPictureMode(m_device, 1);
1723 m_skip_state = false;
1724 m_dll->DtsSetSkipPictureMode(m_device, 0);
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());
1736 ////////////////////////////////////////////////////////////////////////////////////////////
1737 bool CCrystalHD::extract_sps_pps_from_avcc(int extradata_size, void *extradata)
1739 // based on gstbcmdec.c (bcmdec_insert_sps_pps)
1740 // which is Copyright(c) 2008 Broadcom Corporation.
1741 // and Licensed LGPL 2.1
1743 uint8_t *data = (uint8_t*)extradata;
1744 uint32_t data_size = extradata_size;
1746 unsigned int nal_size;
1747 unsigned int num_sps, num_pps;
1749 m_chd_params.sps_pps_size = 0;
1751 profile = (data[1] << 16) | (data[2] << 8) | data[3];
1752 CLog::Log(LOGDEBUG, "%s: profile %06x", __MODULE_NAME__, profile);
1754 m_chd_params.nal_size_bytes = (data[4] & 0x03) + 1;
1756 CLog::Log(LOGDEBUG, "%s: nal size %d", __MODULE_NAME__, m_chd_params.nal_size_bytes);
1758 num_sps = data[5] & 0x1f;
1759 CLog::Log(LOGDEBUG, "%s: num sps %d", __MODULE_NAME__, num_sps);
1764 for (unsigned int i = 0; i < num_sps; i++)
1769 nal_size = (data[0] << 8) | data[1];
1773 if (data_size < nal_size)
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;
1781 m_chd_params.sps_pps_size += 4;
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;
1787 data_size -= nal_size;
1797 for (unsigned int i = 0; i < num_pps; i++)
1802 nal_size = (data[0] << 8) | data[1];
1806 if (data_size < nal_size)
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;
1814 m_chd_params.sps_pps_size += 4;
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;
1820 data_size -= nal_size;
1823 CLog::Log(LOGDEBUG, "%s: data size at end = %d ", __MODULE_NAME__, data_size);
1829 ////////////////////////////////////////////////////////////////////////////////////////////
1830 bool CCrystalHD::bitstream_convert_init(void *in_extradata, int in_extrasize)
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
1837 m_sps_pps_context.sps_pps_data = NULL;
1839 // nothing to filter
1840 if (!in_extradata || in_extrasize < 6)
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};
1849 // retrieve length coded size
1850 m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1;
1851 if (m_sps_pps_context.length_size == 3)
1854 // retrieve sps and pps unit(s)
1855 unit_nb = *extradata++ & 0x1f; // number of sps unit(s)
1858 unit_nb = *extradata++; // number of pps unit(s)
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) )
1870 uint8_t* new_out = (uint8_t*)realloc(out, total_size);
1877 CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out", __FUNCTION__);
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;
1886 if (!unit_nb && !sps_done++)
1887 unit_nb = *extradata++; // number of pps unit(s)
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;
1897 bool CCrystalHD::bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size)
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
1903 uint8_t *buf = pData;
1904 uint32_t buf_size = iSize;
1907 uint32_t cumul_size = 0;
1908 const uint8_t *buf_end = buf + buf_size;
1912 if (buf + m_sps_pps_context.length_size > buf_end)
1915 if (m_sps_pps_context.length_size == 1)
1917 else if (m_sps_pps_context.length_size == 2)
1918 nal_size = buf[0] << 8 | buf[1];
1920 nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
1922 buf += m_sps_pps_context.length_size;
1923 unit_type = *buf & 0x1f;
1925 if (buf + nal_size > buf_end || nal_size < 0)
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)
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;
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;
1943 cumul_size += nal_size + m_sps_pps_context.length_size;
1944 } while (cumul_size < buf_size);
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)
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
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; }
1970 uint32_t offset = *poutbuf_size;
1971 uint8_t nal_header_size = offset ? 3 : 4;
1973 *poutbuf_size += sps_pps_size + in_size + nal_header_size;
1974 *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size);
1976 memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
1978 memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
1981 CHD_WB32(*poutbuf + sps_pps_size, 1);
1985 (*poutbuf + offset + sps_pps_size)[0] = 0;
1986 (*poutbuf + offset + sps_pps_size)[1] = 0;
1987 (*poutbuf + offset + sps_pps_size)[2] = 1;
1991 ////////////////////////////////////////////////////////////////////////////////////////////
1992 void PrintFormat(BCM::BC_PIC_INFO_BLOCK &pib)
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);