PageRenderTime 119ms CodeModel.GetById 3ms app.highlight 104ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/cores/dvdplayer/DVDCodecs/Video/CrystalHD.cpp

http://github.com/xbmc/xbmc
C++ | 2013 lines | 1656 code | 208 blank | 149 comment | 225 complexity | 2f08eeefd1e1997a6b56941b9059cbbc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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
  43namespace 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
  60class DllLibCrystalHDInterface
  61{
  62public:
  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
  94class 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  
 147public:
 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
 168void PrintFormat(BCM::BC_PIC_INFO_BLOCK &pib);
 169void BcmDebugLog( BCM::BC_STATUS lResult, CStdString strFuncName="");
 170
 171const 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////////////////////////////////////////////////////////////////////////////////////////////
 202class CMPCOutputThread : public CThread
 203{
 204public:
 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
 214protected:
 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
 259CPictureBuffer::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
 315CPictureBuffer::~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
 327CMPCOutputThread::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
 361CMPCOutputThread::~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
 373unsigned int CMPCOutputThread::GetReadyCount(void)
 374{
 375  return m_ReadyList.Count();
 376}
 377
 378unsigned int CMPCOutputThread::GetFreeCount(void)
 379{
 380  return m_FreeList.Count();
 381}
 382
 383CPictureBuffer* CMPCOutputThread::ReadyListPop(void)
 384{
 385  CPictureBuffer *pBuffer = m_ReadyList.Pop();
 386  return pBuffer;
 387}
 388
 389void CMPCOutputThread::FreeListPush(CPictureBuffer* pBuffer)
 390{
 391  m_FreeList.Push(pBuffer);
 392}
 393
 394bool CMPCOutputThread::WaitOutput(unsigned int msec)
 395{
 396  return m_ready_event.WaitMSec(msec);
 397}
 398
 399void 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
 450void 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
 572void 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
 659void 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
 688void 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
 723void 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
 748void 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
 773void 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
 813bool 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
1033void 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
1087CCrystalHD* CCrystalHD::m_pInstance = NULL;
1088
1089CCrystalHD::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
1160CCrystalHD::~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
1173bool CCrystalHD::DevicePresent(void)
1174{
1175  return m_device_preset;
1176}
1177
1178void CCrystalHD::RemoveInstance(void)
1179{
1180  if (m_pInstance)
1181  {
1182    delete m_pInstance;
1183    m_pInstance = NULL;
1184  }
1185}
1186
1187CCrystalHD* CCrystalHD::GetInstance(void)
1188{
1189  if (!m_pInstance)
1190  {
1191    m_pInstance = new CCrystalHD();
1192  }
1193  return m_pInstance;
1194}
1195
1196void 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
1231void 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
1241bool 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
1468void 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
1513void 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
1534bool 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->GetRea

Large files files are truncated, but you can click here to view the full file