add DVDVideoCodecAmlogic
authordavilla <davilla@4pi.com>
Sun, 5 May 2013 02:32:09 +0000 (22:32 -0400)
committerdavilla <davilla@4pi.com>
Sun, 5 May 2013 02:54:57 +0000 (22:54 -0400)
15 files changed:
configure.in
xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.cpp
xbmc/cores/AudioEngine/Sinks/AESinkAUDIOTRACK.h
xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp [new file with mode: 0644]
xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.h [new file with mode: 0644]
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp [new file with mode: 0644]
xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h [new file with mode: 0644]
xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
xbmc/cores/dvdplayer/DVDStreamInfo.cpp
xbmc/cores/dvdplayer/DVDStreamInfo.h

index d89353c..2676dc0 100644 (file)
@@ -30,6 +30,21 @@ AC_DEFUN([XB_ADD_PLAYER],
   esac
 ])
 
+# check for enabling additional codecs
+AC_DEFUN([XB_ADD_CODEC],
+[
+  AC_MSG_CHECKING([for $2])
+  case $add_codecs in
+    *$2*)
+      AC_SUBST([USE_$1], 1)
+      AC_DEFINE([HAS_$1], 1, [using $2])
+      AC_MSG_RESULT([enabling $2])
+      ;;
+    *)
+      AC_MSG_RESULT([$2 is not enabled])
+  esac
+])
+
 # check for library basenames
 AC_DEFUN([XB_FIND_SONAME],
 [
@@ -513,6 +528,12 @@ AC_ARG_ENABLE([gtest],
   [configure_gtest=$enableval],
   [configure_gtest=no])
 
+AC_ARG_ENABLE([codec],
+  [AS_HELP_STRING([--enable-codec],
+  [enable additional codecs from a list of comma separated names, (default is none, choices are amcodec)])],
+  [add_codecs=$enableval],
+  [add_codecs=no])
+
 ### External libraries options
 AC_ARG_ENABLE([external-libraries],
   [AS_HELP_STRING([--enable-external-libraries],
@@ -1878,6 +1899,14 @@ case $add_players in
       ;;
 esac
 
+# additional internal codecs
+case $add_codecs in
+  *amcodec*)
+      AC_CHECK_HEADER([amlplayer/codec_error.h],, AC_MSG_ERROR($missing_headers))
+      XB_ADD_CODEC([LIBAMCODEC], [amcodec])
+      ;;
+esac
+
 # platform specific bin utilities
 if test "$build_vendor" != "apple" ; then
   AC_CHECK_PROG(HAVE_GAWK,gawk,"yes","no",)
index 10a6a6a..93ee569 100644 (file)
@@ -146,7 +146,7 @@ bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
     m_channelLayout = GetChannelLayout(format);
     m_passthrough   = false;
   }
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
   if (aml_present())
   {
     aml_set_audio_passthrough(m_passthrough);
index 34f6e97..ffb5f30 100644 (file)
@@ -23,8 +23,8 @@
 #include "Utils/AERingBuffer.h"
 #include "android/activity/XBMCApp.h"
 #include "utils/log.h"
-#if defined(HAS_AMLPLAYER)
-#include "cores/amlplayer/AMLUtils.h"
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
+#include "utils/AMLUtils.h"
 #endif
 
 #include <jni.h>
@@ -83,14 +83,14 @@ CAESinkAUDIOTRACK::CAESinkAUDIOTRACK()
   m_audiotrackbuffer_sec = 0.0;
   m_audiotrack_empty_sec = 0.0;
   m_volume = 0.0;
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
   aml_cpufreq_limit(true);
 #endif
 }
 
 CAESinkAUDIOTRACK::~CAESinkAUDIOTRACK()
 {
-#if defined(HAS_AMLPLAYER)
+#if defined(HAS_AMLPLAYER) || defined(HAS_LIBAMCODEC)
   aml_cpufreq_limit(false);
 #endif
 }
@@ -99,6 +99,16 @@ bool CAESinkAUDIOTRACK::Initialize(AEAudioFormat &format, std::string &device)
 {
   m_format = format;
 
+  if (AE_IS_RAW(m_format.m_dataFormat))
+    m_passthrough = true;
+  else
+    m_passthrough = false;
+
+#if defined(HAS_LIBAMCODEC)
+  if (aml_present())
+    aml_set_audio_passthrough(m_passthrough);
+#endif
+
   // default to 44100, all android devices support it.
   // then check if we can support the requested rate.
   unsigned int sampleRate = 44100;
@@ -173,7 +183,12 @@ double CAESinkAUDIOTRACK::GetDelay()
   // AudioMixer (if any) and audio hardware driver.
 
   double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer->GetReadSize();
-  return sinkbuffer_seconds_to_empty + m_audiotrack_empty_sec;
+  sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec;
+#if defined(HAS_LIBAMCODEC)
+  if (sinkbuffer_seconds_to_empty > 0.0)
+    sinkbuffer_seconds_to_empty += 0.250;
+#endif
+  return sinkbuffer_seconds_to_empty;
 }
 
 double CAESinkAUDIOTRACK::GetCacheTime()
@@ -182,7 +197,12 @@ double CAESinkAUDIOTRACK::GetCacheTime()
   // to underrun the buffer if no sample is added.
 
   double sinkbuffer_seconds_to_empty = m_sinkbuffer_sec_per_byte * (double)m_sinkbuffer->GetReadSize();
-  return sinkbuffer_seconds_to_empty + m_audiotrack_empty_sec;
+  sinkbuffer_seconds_to_empty += m_audiotrack_empty_sec;
+#if defined(HAS_LIBAMCODEC)
+  if (sinkbuffer_seconds_to_empty > 0.0)
+    sinkbuffer_seconds_to_empty += 0.250;
+#endif
+  return sinkbuffer_seconds_to_empty;
 }
 
 double CAESinkAUDIOTRACK::GetCacheTotal()
@@ -244,7 +264,8 @@ void  CAESinkAUDIOTRACK::SetVolume(float scale)
   // Android uses fixed steps, reverse scale back to percent
   float gain = CAEUtil::ScaleToGain(scale);
   m_volume = CAEUtil::GainToPercent(gain);
-  m_volume_changed = true;
+  if (!m_passthrough)
+    m_volume_changed = true;
 }
 
 void CAESinkAUDIOTRACK::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
@@ -313,6 +334,12 @@ void CAESinkAUDIOTRACK::Process()
     min_buffer_size,
     GetStaticIntField(jenv, "AudioTrack", "MODE_STREAM"));
 
+  // Set the initial volume
+  float volume = 1.0;
+  if (!m_passthrough)
+    volume = m_volume;
+  CXBMCApp::SetSystemVolume(jenv, volume);
+
   // The AudioTrack object has been created and waiting to play,
   m_inited.Set();
   // yield to give other threads a chance to do some work.
@@ -329,7 +356,7 @@ void CAESinkAUDIOTRACK::Process()
 
   while (!m_bStop)
   {
-    if (m_volume_changed)
+    if (m_volume_changed && !m_passthrough)
     {
       // check of volume changes and make them,
       // do it here to keep jni calls local to this thread.
index 4ba78ce..d07ab8d 100644 (file)
@@ -62,6 +62,8 @@ private:
   CEvent             m_wake;
   CEvent             m_inited;
   volatile bool      m_draining;
+  bool               m_passthrough;
+
   double             m_audiotrackbuffer_sec;
   double             m_audiotrack_empty_sec;
 };
index 03429b5..100cb22 100644 (file)
@@ -38,6 +38,9 @@
 #if defined(HAVE_LIBCRYSTALHD)
 #include "Video/DVDVideoCodecCrystalHD.h"
 #endif
+#if defined(HAS_LIBAMCODEC)
+#include "Video/DVDVideoCodecAmlogic.h"
+#endif
 #include "Audio/DVDAudioCodecFFmpeg.h"
 #include "Audio/DVDAudioCodecLibMad.h"
 #include "Audio/DVDAudioCodecPcm.h"
@@ -151,6 +154,11 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
 #else
   hwSupport += "CrystalHD:no ";
 #endif
+#if defined(HAS_LIBAMCODEC)
+  hwSupport += "AMCodec:yes ";
+#else
+  hwSupport += "AMCodec:no ";
+#endif
 #if defined(HAVE_LIBOPENMAX) && defined(_LINUX)
   hwSupport += "OpenMax:yes ";
 #elif defined(_LINUX)
@@ -173,12 +181,14 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
 #endif
 
   CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
-
+#if !defined(HAS_LIBAMCODEC)
   // dvd's have weird still-frames in it, which is not fully supported in ffmpeg
   if(hint.stills && (hint.codec == CODEC_ID_MPEG2VIDEO || hint.codec == CODEC_ID_MPEG1VIDEO))
   {
     if( (pCodec = OpenCodec(new CDVDVideoCodecLibMpeg2(), hint, options)) ) return pCodec;
   }
+#endif
+
 #if defined(HAVE_LIBVDADECODER)
   if (!hint.software && CSettings::Get().GetBool("videoplayer.usevda"))
   {
@@ -235,6 +245,14 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
   }
 #endif
 
+#if defined(HAS_LIBAMCODEC)
+  if (!hint.software)
+  {
+    CLog::Log(LOGINFO, "Amlogic Video Decoder...");
+    if ( (pCodec = OpenCodec(new CDVDVideoCodecAmlogic(), hint, options)) ) return pCodec;
+  }
+#endif
+
 #if defined(HAVE_LIBOPENMAX)
   if (CSettings::Get().GetBool("videoplayer.useomx") && !hint.software )
   {
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.cpp
new file mode 100644 (file)
index 0000000..46b1726
--- /dev/null
@@ -0,0 +1,2175 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+
+#include "AMLCodec.h"
+#include "DynamicDll.h"
+
+#include "cores/dvdplayer/DVDClock.h"
+#include "cores/VideoRenderers/RenderManager.h"
+#include "guilib/GraphicContext.h"
+#include "settings/MediaSettings.h"
+#include "settings/Settings.h"
+#include "utils/AMLUtils.h"
+#include "utils/log.h"
+#include "utils/TimeUtils.h"
+
+#include <unistd.h>
+#include <queue>
+#include <vector>
+#include <signal.h>
+#include <semaphore.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+// amcodec include
+extern "C" {
+#include <codec.h>
+}  // extern "C"
+
+class DllLibamCodecInterface
+{
+public:
+  virtual ~DllLibamCodecInterface() {};
+
+  virtual int codec_init(codec_para_t *pcodec)=0;
+  virtual int codec_close(codec_para_t *pcodec)=0;
+  virtual int codec_reset(codec_para_t *pcodec)=0;
+  virtual int codec_pause(codec_para_t *pcodec)=0;
+  virtual int codec_resume(codec_para_t *pcodec)=0;
+  virtual int codec_write(codec_para_t *pcodec, void *buffer, int len)=0;
+  virtual int codec_checkin_pts(codec_para_t *pcodec, unsigned long pts)=0;
+  virtual int codec_get_vbuf_state(codec_para_t *pcodec, struct buf_status *buf)=0;
+  virtual int codec_get_vdec_state(codec_para_t *pcodec, struct vdec_status *vdec)=0;
+
+  virtual int codec_init_cntl(codec_para_t *pcodec)=0;
+  virtual int codec_poll_cntl(codec_para_t *pcodec)=0;
+  virtual int codec_set_cntl_mode(codec_para_t *pcodec, unsigned int mode)=0;
+  virtual int codec_set_cntl_avthresh(codec_para_t *pcodec, unsigned int avthresh)=0;
+  virtual int codec_set_cntl_syncthresh(codec_para_t *pcodec, unsigned int syncthresh)=0;
+
+  // grab these from libamplayer
+  virtual int h263vld(unsigned char *inbuf, unsigned char *outbuf, int inbuf_len, int s263)=0;
+  virtual int decodeble_h263(unsigned char *buf)=0;
+
+  // grab this from amffmpeg so we do not have to load DllAvUtil
+  virtual AVRational av_d2q(double d, int max)=0;
+};
+
+class DllLibAmCodec : public DllDynamic, DllLibamCodecInterface
+{
+  // libamcodec is static linked into libamplayer.so
+  DECLARE_DLL_WRAPPER(DllLibAmCodec, "libamplayer.so")
+
+  DEFINE_METHOD1(int, codec_init,               (codec_para_t *p1))
+  DEFINE_METHOD1(int, codec_close,              (codec_para_t *p1))
+  DEFINE_METHOD1(int, codec_reset,              (codec_para_t *p1))
+  DEFINE_METHOD1(int, codec_pause,              (codec_para_t *p1))
+  DEFINE_METHOD1(int, codec_resume,             (codec_para_t *p1))
+  DEFINE_METHOD3(int, codec_write,              (codec_para_t *p1, void *p2, int p3))
+  DEFINE_METHOD2(int, codec_checkin_pts,        (codec_para_t *p1, unsigned long p2))
+  DEFINE_METHOD2(int, codec_get_vbuf_state,     (codec_para_t *p1, struct buf_status * p2))
+  DEFINE_METHOD2(int, codec_get_vdec_state,     (codec_para_t *p1, struct vdec_status * p2))
+
+  DEFINE_METHOD1(int, codec_init_cntl,          (codec_para_t *p1))
+  DEFINE_METHOD1(int, codec_poll_cntl,          (codec_para_t *p1))
+  DEFINE_METHOD2(int, codec_set_cntl_mode,      (codec_para_t *p1, unsigned int p2))
+  DEFINE_METHOD2(int, codec_set_cntl_avthresh,  (codec_para_t *p1, unsigned int p2))
+  DEFINE_METHOD2(int, codec_set_cntl_syncthresh,(codec_para_t *p1, unsigned int p2))
+
+  DEFINE_METHOD4(int, h263vld,                  (unsigned char *p1, unsigned char *p2, int p3, int p4))
+  DEFINE_METHOD1(int, decodeble_h263,           (unsigned char *p1))
+
+  DEFINE_METHOD2(AVRational, av_d2q,            (double p1, int p2))
+
+  BEGIN_METHOD_RESOLVE()
+    RESOLVE_METHOD(codec_init)
+    RESOLVE_METHOD(codec_close)
+    RESOLVE_METHOD(codec_reset)
+    RESOLVE_METHOD(codec_pause)
+    RESOLVE_METHOD(codec_resume)
+    RESOLVE_METHOD(codec_write)
+    RESOLVE_METHOD(codec_checkin_pts)
+    RESOLVE_METHOD(codec_get_vbuf_state)
+    RESOLVE_METHOD(codec_get_vdec_state)
+
+    RESOLVE_METHOD(codec_init_cntl)
+    RESOLVE_METHOD(codec_poll_cntl)
+    RESOLVE_METHOD(codec_set_cntl_mode)
+    RESOLVE_METHOD(codec_set_cntl_avthresh)
+    RESOLVE_METHOD(codec_set_cntl_syncthresh)
+
+    RESOLVE_METHOD(h263vld)
+    RESOLVE_METHOD(decodeble_h263)
+
+    RESOLVE_METHOD(av_d2q)
+  END_METHOD_RESOLVE()
+};
+
+//-----------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------------
+// AppContext - Application state
+#define PTS_FREQ        90000
+#define UNIT_FREQ       96000
+#define AV_SYNC_THRESH  PTS_FREQ*30
+
+#define TRICKMODE_NONE  0x00
+#define TRICKMODE_I     0x01
+#define TRICKMODE_FFFB  0x02
+
+// same as AV_NOPTS_VALUE
+#define INT64_0         INT64_C(0x8000000000000000)
+
+#define EXTERNAL_PTS    (1)
+#define SYNC_OUTSIDE    (2)
+
+// missing tags
+#define CODEC_TAG_VC_1  (0x312D4356)
+#define CODEC_TAG_RV30  (0x30335652)
+#define CODEC_TAG_RV40  (0x30345652)
+#define CODEC_TAG_MJPEG (0x47504a4d)
+#define CODEC_TAG_mjpeg (0x47504a4c)
+#define CODEC_TAG_jpeg  (0x6765706a)
+#define CODEC_TAG_mjpa  (0x61706a6d)
+
+#define RW_WAIT_TIME    (20 * 1000) // 20ms
+
+#define P_PRE           (0x02000000)
+#define F_PRE           (0x03000000)
+#define PLAYER_SUCCESS          (0)
+#define PLAYER_FAILED           (-(P_PRE|0x01))
+#define PLAYER_NOMEM            (-(P_PRE|0x02))
+#define PLAYER_EMPTY_P          (-(P_PRE|0x03))
+
+#define PLAYER_WR_FAILED        (-(P_PRE|0x21))
+#define PLAYER_WR_EMPTYP        (-(P_PRE|0x22))
+#define PLAYER_WR_FINISH        (P_PRE|0x1)
+
+#define PLAYER_PTS_ERROR        (-(P_PRE|0x31))
+#define PLAYER_UNSUPPORT        (-(P_PRE|0x35))
+#define PLAYER_CHECK_CODEC_ERROR  (-(P_PRE|0x39))
+
+#define HDR_BUF_SIZE 1024
+typedef struct hdr_buf {
+    char *data;
+    int size;
+} hdr_buf_t;
+
+typedef struct am_packet {
+    AVPacket      avpkt;
+    int64_t       avpts;
+    int64_t       avdts;
+    int           avduration;
+    int           isvalid;
+    int           newflag;
+    int64_t       lastpts;
+    unsigned char *data;
+    unsigned char *buf;
+    int           data_size;
+    int           buf_size;
+    hdr_buf_t     *hdr;
+    codec_para_t  *codec;
+} am_packet_t;
+
+typedef enum {
+    AM_STREAM_UNKNOWN = 0,
+    AM_STREAM_TS,
+    AM_STREAM_PS,
+    AM_STREAM_ES,
+    AM_STREAM_RM,
+    AM_STREAM_AUDIO,
+    AM_STREAM_VIDEO,
+} pstream_type;
+
+typedef union {
+    int64_t      total_bytes;
+    unsigned int vpkt_num;
+    unsigned int spkt_num;
+} read_write_size;
+
+typedef  struct {
+    unsigned int read_end_flag: 1;
+    unsigned int end_flag: 1;
+    unsigned int reset_flag: 1;
+    int check_lowlevel_eagain_cnt;
+} p_ctrl_info_t;
+
+typedef struct am_private_t
+{
+  am_packet_t       am_pkt;
+  codec_para_t      vcodec;
+
+  pstream_type      stream_type;
+  p_ctrl_info_t     playctrl_info;
+
+  read_write_size   read_size;
+  read_write_size   write_size;
+  int               check_first_pts;
+
+  vformat_t         video_format;
+  int               video_pid;
+  unsigned int      video_codec_id;
+  unsigned int      video_codec_tag;
+  vdec_type_t       video_codec_type;
+  unsigned int      video_width;
+  unsigned int      video_height;
+  unsigned int      video_ratio;
+  unsigned int      video_ratio64;
+  unsigned int      video_rate;
+  unsigned int      video_rotation_degree;
+  int               flv_flag;
+  int               h263_decodable;
+  int               extrasize;
+  uint8_t           *extradata;
+  DllLibAmCodec     *m_dll;
+} am_private_t;
+
+/*************************************************************************/
+static int64_t get_pts_video()
+{
+  int fd = open("/sys/class/tsync/pts_video", O_RDONLY);
+  if (fd >= 0)
+  {
+    char pts_str[16];
+    int size = read(fd, pts_str, sizeof(pts_str));
+    close(fd);
+    if (size > 0)
+    {
+      unsigned long pts = strtoul(pts_str, NULL, 16);
+      return pts;
+    }
+  }
+
+  CLog::Log(LOGERROR, "get_pts_video: open /tsync/event error");
+  return -1;
+}
+
+static int set_pts_pcrscr(int64_t value)
+{
+  int fd = open("/sys/class/tsync/pts_pcrscr", O_WRONLY);
+  if (fd >= 0)
+  {
+    char pts_str[64];
+    unsigned long pts = (unsigned long)value;
+    sprintf(pts_str, "0x%lx", pts);
+    write(fd, pts_str, strlen(pts_str));
+    close(fd);
+    return 0;
+  }
+
+  CLog::Log(LOGERROR, "set_pts_pcrscr: open pts_pcrscr error");
+  return -1;
+}
+
+static vformat_t codecid_to_vformat(enum CodecID id)
+{
+  vformat_t format;
+  switch (id)
+  {
+    case CODEC_ID_MPEG1VIDEO:
+    case CODEC_ID_MPEG2VIDEO:
+    case CODEC_ID_MPEG2VIDEO_XVMC:
+      format = VFORMAT_MPEG12;
+      break;
+    case CODEC_ID_H263:
+    case CODEC_ID_MPEG4:
+    case CODEC_ID_H263P:
+    case CODEC_ID_H263I:
+    case CODEC_ID_MSMPEG4V2:
+    case CODEC_ID_MSMPEG4V3:
+    case CODEC_ID_FLV1:
+      format = VFORMAT_MPEG4;
+      break;
+    case CODEC_ID_RV10:
+    case CODEC_ID_RV20:
+    case CODEC_ID_RV30:
+    case CODEC_ID_RV40:
+      format = VFORMAT_REAL;
+      break;
+    case CODEC_ID_H264:
+      format = VFORMAT_H264;
+      break;
+    /*
+    case CODEC_ID_H264MVC:
+      // H264 Multiview Video Coding (3d blurays)
+      format = VFORMAT_H264MVC;
+      break;
+    */
+    case CODEC_ID_MJPEG:
+      format = VFORMAT_MJPEG;
+      break;
+    case CODEC_ID_VC1:
+    case CODEC_ID_WMV3:
+      format = VFORMAT_VC1;
+      break;
+    case CODEC_ID_AVS:
+    case CODEC_ID_CAVS:
+      format = VFORMAT_AVS;
+      break;
+
+    default:
+      format = VFORMAT_UNSUPPORT;
+      break;
+  }
+
+  CLog::Log(LOGDEBUG, "codecid_to_vformat, id(%d) -> vformat(%d)", (int)id, format);
+  return format;
+}
+
+static vdec_type_t codec_tag_to_vdec_type(unsigned int codec_tag)
+{
+  vdec_type_t dec_type;
+  switch (codec_tag)
+  {
+    case CODEC_TAG_MJPEG:
+    case CODEC_TAG_mjpeg:
+    case CODEC_TAG_jpeg:
+    case CODEC_TAG_mjpa:
+      // mjpeg
+      dec_type = VIDEO_DEC_FORMAT_MJPEG;
+      break;
+    case CODEC_TAG_XVID:
+    case CODEC_TAG_xvid:
+    case CODEC_TAG_XVIX:
+      // xvid
+      dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+      break;
+    case CODEC_TAG_COL1:
+    case CODEC_TAG_DIV3:
+    case CODEC_TAG_MP43:
+      // divx3.11
+      dec_type = VIDEO_DEC_FORMAT_MPEG4_3;
+      break;
+    case CODEC_TAG_DIV4:
+    case CODEC_TAG_DIVX:
+      // divx4
+      dec_type = VIDEO_DEC_FORMAT_MPEG4_4;
+      break;
+    case CODEC_TAG_DIV5:
+    case CODEC_TAG_DX50:
+    case CODEC_TAG_M4S2:
+    case CODEC_TAG_FMP4:
+      // divx5
+      dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+      break;
+    case CODEC_TAG_DIV6:
+      // divx6
+      dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+      break;
+    case CODEC_TAG_MP4V:
+    case CODEC_TAG_RMP4:
+    case CODEC_TAG_MPG4:
+    case CODEC_TAG_mp4v:
+    case CODEC_ID_MPEG4:
+      // mp4
+      dec_type = VIDEO_DEC_FORMAT_MPEG4_5;
+      break;
+    case CODEC_ID_H263:
+    case CODEC_TAG_H263:
+    case CODEC_TAG_h263:
+    case CODEC_TAG_s263:
+    case CODEC_TAG_F263:
+      // h263
+      dec_type = VIDEO_DEC_FORMAT_H263;
+      break;
+    case CODEC_TAG_AVC1:
+    case CODEC_TAG_avc1:
+    case CODEC_TAG_H264:
+    case CODEC_TAG_h264:
+    case CODEC_ID_H264:
+      // h264
+      dec_type = VIDEO_DEC_FORMAT_H264;
+      break;
+    /*
+    case CODEC_ID_H264MVC:
+      dec_type = VIDEO_DEC_FORMAT_H264;
+      break;
+    */
+    case CODEC_ID_RV30:
+    case CODEC_TAG_RV30:
+      // realmedia 3
+      dec_type = VIDEO_DEC_FORMAT_REAL_8;
+      break;
+    case CODEC_ID_RV40:
+    case CODEC_TAG_RV40:
+      // realmedia 4
+      dec_type = VIDEO_DEC_FORMAT_REAL_9;
+      break;
+    case CODEC_TAG_WMV3:
+      // wmv3
+      dec_type = VIDEO_DEC_FORMAT_WMV3;
+      break;
+    case CODEC_ID_VC1:
+    case CODEC_TAG_VC_1:
+    case CODEC_TAG_WVC1:
+    case CODEC_TAG_WMVA:
+      // vc1
+      dec_type = VIDEO_DEC_FORMAT_WVC1;
+      break;
+    case CODEC_ID_VP6F:
+      // vp6
+      dec_type = VIDEO_DEC_FORMAT_SW;
+      break;
+    case CODEC_ID_CAVS:
+    case CODEC_ID_AVS:
+      // avs
+      dec_type = VIDEO_DEC_FORMAT_AVS;
+      break;
+    default:
+      dec_type = VIDEO_DEC_FORMAT_UNKNOW;
+      break;
+  }
+
+  CLog::Log(LOGDEBUG, "codec_tag_to_vdec_type, codec_tag(%d) -> vdec_type(%d)", codec_tag, dec_type);
+  return dec_type;
+}
+
+static void am_packet_init(am_packet_t *pkt)
+{
+  memset(&pkt->avpkt, 0, sizeof(AVPacket));
+  pkt->avpts      = 0;
+  pkt->avdts      = 0;
+  pkt->avduration = 0;
+  pkt->isvalid    = 0;
+  pkt->newflag    = 0;
+  pkt->lastpts    = 0;
+  pkt->data       = NULL;
+  pkt->buf        = NULL;
+  pkt->data_size  = 0;
+  pkt->buf_size   = 0;
+  pkt->hdr        = NULL;
+  pkt->codec      = NULL;
+}
+
+void am_packet_release(am_packet_t *pkt)
+{
+  if (pkt->buf != NULL)
+  {
+    free(pkt->buf);
+    pkt->buf= NULL;
+  }
+  if (pkt->hdr != NULL)
+  {
+    free(pkt->hdr->data);
+    pkt->hdr->data = NULL;
+    free(pkt->hdr);
+    pkt->hdr = NULL;
+  }
+  pkt->codec = NULL;
+}
+
+int check_in_pts(am_private_t *para, am_packet_t *pkt)
+{
+    int last_duration = 0;
+    static int last_v_duration = 0;
+    int64_t pts = 0;
+
+    last_duration = last_v_duration;
+
+    if (para->stream_type == AM_STREAM_ES) {
+        if ((int64_t)INT64_0 != pkt->avpts) {
+            pts = pkt->avpts;
+
+            if (para->m_dll->codec_checkin_pts(pkt->codec, pts) != 0) {
+                CLog::Log(LOGDEBUG, "ERROR check in pts error!");
+                return PLAYER_PTS_ERROR;
+            }
+
+        } else if ((int64_t)INT64_0 != pkt->avdts) {
+            pts = pkt->avdts * last_duration;
+
+            if (para->m_dll->codec_checkin_pts(pkt->codec, pts) != 0) {
+                CLog::Log(LOGDEBUG, "ERROR check in dts error!");
+                return PLAYER_PTS_ERROR;
+            }
+
+            last_v_duration = pkt->avduration ? pkt->avduration : 1;
+        } else {
+            if (!para->check_first_pts) {
+                if (para->m_dll->codec_checkin_pts(pkt->codec, 0) != 0) {
+                    CLog::Log(LOGDEBUG, "ERROR check in 0 to video pts error!");
+                    return PLAYER_PTS_ERROR;
+                }
+            }
+        }
+        if (!para->check_first_pts) {
+            para->check_first_pts = 1;
+        }
+    }
+    if (pts > 0)
+      pkt->lastpts = pts;
+
+    return PLAYER_SUCCESS;
+}
+
+static int check_write_finish(am_private_t *para, am_packet_t *pkt)
+{
+    if (para->playctrl_info.read_end_flag) {
+        if ((para->write_size.vpkt_num == para->read_size.vpkt_num)) {
+            return PLAYER_WR_FINISH;
+        }
+    }
+    return PLAYER_WR_FAILED;
+}
+
+static int write_header(am_private_t *para, am_packet_t *pkt)
+{
+    int write_bytes = 0, len = 0;
+
+    if (pkt->hdr && pkt->hdr->size > 0) {
+        if ((NULL == pkt->codec) || (NULL == pkt->hdr->data)) {
+            CLog::Log(LOGDEBUG, "[write_header]codec null!");
+            return PLAYER_EMPTY_P;
+        }
+        //some wvc1 es data not need to add header
+        if (para->video_format == VFORMAT_VC1 && para->video_codec_type == VIDEO_DEC_FORMAT_WVC1) {
+            if ((pkt->data) && (pkt->data_size >= 4)
+              && (pkt->data[0] == 0) && (pkt->data[1] == 0)
+              && (pkt->data[2] == 1) && (pkt->data[3] == 0xd || pkt->data[3] == 0xf)) {
+                return PLAYER_SUCCESS;
+            }
+        }
+        while (1) {
+            write_bytes = para->m_dll->codec_write(pkt->codec, pkt->hdr->data + len, pkt->hdr->size - len);
+            if (write_bytes < 0 || write_bytes > (pkt->hdr->size - len)) {
+                if (-errno != AVERROR(EAGAIN)) {
+                    CLog::Log(LOGDEBUG, "ERROR:write header failed!");
+                    return PLAYER_WR_FAILED;
+                } else {
+                    continue;
+                }
+            } else {
+                len += write_bytes;
+                if (len == pkt->hdr->size) {
+                    break;
+                }
+            }
+        }
+    }
+    return PLAYER_SUCCESS;
+}
+
+int check_avbuffer_enough(am_private_t *para, am_packet_t *pkt)
+{
+    return 1;
+}
+
+int write_av_packet(am_private_t *para, am_packet_t *pkt)
+{
+  //CLog::Log(LOGDEBUG, "write_av_packet, pkt->isvalid(%d), pkt->data(%p), pkt->data_size(%d)",
+  //  pkt->isvalid, pkt->data, pkt->data_size);
+
+    int write_bytes = 0, len = 0, ret;
+    unsigned char *buf;
+    int size;
+
+    if (pkt->newflag) {
+        if (pkt->isvalid) {
+            ret = check_in_pts(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                CLog::Log(LOGDEBUG, "check in pts failed");
+                return PLAYER_WR_FAILED;
+            }
+        }
+        if (write_header(para, pkt) == PLAYER_WR_FAILED) {
+            CLog::Log(LOGDEBUG, "[%s]write header failed!", __FUNCTION__);
+            return PLAYER_WR_FAILED;
+        }
+        pkt->newflag = 0;
+    }
+       
+    buf = pkt->data;
+    size = pkt->data_size ;
+    if (size == 0 && pkt->isvalid) {
+        para->write_size.vpkt_num++;
+        pkt->isvalid = 0;
+    }
+    while (size > 0 && pkt->isvalid) {
+        write_bytes = para->m_dll->codec_write(pkt->codec, (char *)buf, size);
+        if (write_bytes < 0 || write_bytes > size) {
+            if (-errno != AVERROR(EAGAIN)) {
+                para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+                CLog::Log(LOGDEBUG, "write codec data failed!");
+                return PLAYER_WR_FAILED;
+            } else {
+                // EAGAIN to see if buffer full or write time out too much
+                if (check_avbuffer_enough(para, pkt)) {
+                  para->playctrl_info.check_lowlevel_eagain_cnt++;
+                } else {
+                  para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+                }
+
+                if (para->playctrl_info.check_lowlevel_eagain_cnt > 50) {
+                    // reset decoder
+                    para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+                    para->playctrl_info.reset_flag = 1;
+                    para->playctrl_info.end_flag = 1;
+                    CLog::Log(LOGDEBUG, "$$$$$$ write blocked, need reset decoder!$$$$$$");
+                }
+                //pkt->data += len;
+                //pkt->data_size -= len;
+                usleep(RW_WAIT_TIME);
+                CLog::Log(LOGDEBUG, "usleep(RW_WAIT_TIME), len(%d)", len);
+                return PLAYER_SUCCESS;
+            }
+        } else {
+            para->playctrl_info.check_lowlevel_eagain_cnt = 0;
+            len += write_bytes;
+            if (len == pkt->data_size) {
+                para->write_size.vpkt_num++;
+                pkt->isvalid = 0;
+                pkt->data_size = 0;
+                break;
+            } else if (len < pkt->data_size) {
+                buf += write_bytes;
+                size -= write_bytes;
+            } else {
+                return PLAYER_WR_FAILED;
+            }
+        }
+    }
+    if (check_write_finish(para, pkt) == PLAYER_WR_FINISH) {
+        return PLAYER_WR_FINISH;
+    }
+    return PLAYER_SUCCESS;
+}
+
+static int check_size_in_buffer(unsigned char *p, int len)
+{
+    unsigned int size;
+    unsigned char *q = p;
+    while ((q + 4) < (p + len)) {
+        size = (*q << 24) | (*(q + 1) << 16) | (*(q + 2) << 8) | (*(q + 3));
+        if (size & 0xff000000) {
+            return 0;
+        }
+
+        if (q + size + 4 == p + len) {
+            return 1;
+        }
+
+        q += size + 4;
+    }
+    return 0;
+}
+
+static int check_size_in_buffer3(unsigned char *p, int len)
+{
+    unsigned int size;
+    unsigned char *q = p;
+    while ((q + 3) < (p + len)) {
+        size = (*q << 16) | (*(q + 1) << 8) | (*(q + 2));
+
+        if (q + size + 3 == p + len) {
+            return 1;
+        }
+
+        q += size + 3;
+    }
+    return 0;
+}
+
+static int check_size_in_buffer2(unsigned char *p, int len)
+{
+    unsigned int size;
+    unsigned char *q = p;
+    while ((q + 2) < (p + len)) {
+        size = (*q << 8) | (*(q + 1));
+
+        if (q + size + 2 == p + len) {
+            return 1;
+        }
+
+        q += size + 2;
+    }
+    return 0;
+}
+
+/*************************************************************************/
+static int m4s2_dx50_mp4v_add_header(unsigned char *buf, int size,  am_packet_t *pkt)
+{
+    if (size > pkt->hdr->size) {
+        free(pkt->hdr->data), pkt->hdr->data = NULL;
+        pkt->hdr->size = 0;
+
+        pkt->hdr->data = (char*)malloc(size);
+        if (!pkt->hdr->data) {
+            CLog::Log(LOGDEBUG, "[m4s2_dx50_add_header] NOMEM!");
+            return PLAYER_FAILED;
+        }
+    }
+
+    pkt->hdr->size = size;
+    memcpy(pkt->hdr->data, buf, size);
+
+    return PLAYER_SUCCESS;
+}
+
+static int m4s2_dx50_mp4v_write_header(am_private_t *para, am_packet_t *pkt)
+{
+    CLog::Log(LOGDEBUG, "m4s2_dx50_mp4v_write_header");
+    int ret = m4s2_dx50_mp4v_add_header(para->extradata, para->extrasize, pkt);
+    if (ret == PLAYER_SUCCESS) {
+        if (1) {
+            pkt->codec = &para->vcodec;
+        } else {
+            CLog::Log(LOGDEBUG, "[m4s2_dx50_mp4v_add_header]invalid video codec!");
+            return PLAYER_EMPTY_P;
+        }
+        pkt->newflag = 1;
+        ret = write_av_packet(para, pkt);
+    }
+    return ret;
+}
+
+static int mjpeg_data_prefeeding(am_packet_t *pkt)
+{
+    const unsigned char mjpeg_addon_data[] = {
+        0xff, 0xd8, 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01,
+        0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
+        0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01,
+        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x10,
+        0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00,
+        0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
+        0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1,
+        0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72,
+        0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29,
+        0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47,
+        0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64,
+        0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+        0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95,
+        0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+        0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4,
+        0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+        0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1,
+        0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0x11, 0x00, 0x02, 0x01,
+        0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+        0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51,
+        0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1,
+        0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24,
+        0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
+        0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+        0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
+        0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82,
+        0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+        0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
+        0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+        0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+        0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4,
+        0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
+    };
+
+    if (pkt->hdr->data) {
+        memcpy(pkt->hdr->data, &mjpeg_addon_data, sizeof(mjpeg_addon_data));
+        pkt->hdr->size = sizeof(mjpeg_addon_data);
+    } else {
+        CLog::Log(LOGDEBUG, "[mjpeg_data_prefeeding]No enough memory!");
+        return PLAYER_FAILED;
+    }
+    return PLAYER_SUCCESS;
+}
+
+static int mjpeg_write_header(am_private_t *para, am_packet_t *pkt)
+{
+    mjpeg_data_prefeeding(pkt);
+    if (1) {
+        pkt->codec = &para->vcodec;
+    } else {
+        CLog::Log(LOGDEBUG, "[mjpeg_write_header]invalid codec!");
+        return PLAYER_EMPTY_P;
+    }
+    pkt->newflag = 1;
+    write_av_packet(para, pkt);
+    return PLAYER_SUCCESS;
+}
+
+static int divx3_data_prefeeding(am_packet_t *pkt, unsigned w, unsigned h)
+{
+    unsigned i = (w << 12) | (h & 0xfff);
+    unsigned char divx311_add[10] = {
+        0x00, 0x00, 0x00, 0x01,
+        0x20, 0x00, 0x00, 0x00,
+        0x00, 0x00
+    };
+    divx311_add[5] = (i >> 16) & 0xff;
+    divx311_add[6] = (i >> 8) & 0xff;
+    divx311_add[7] = i & 0xff;
+
+    if (pkt->hdr->data) {
+        memcpy(pkt->hdr->data, divx311_add, sizeof(divx311_add));
+        pkt->hdr->size = sizeof(divx311_add);
+    } else {
+        CLog::Log(LOGDEBUG, "[divx3_data_prefeeding]No enough memory!");
+        return PLAYER_FAILED;
+    }
+    return PLAYER_SUCCESS;
+}
+
+static int divx3_write_header(am_private_t *para, am_packet_t *pkt)
+{
+    CLog::Log(LOGDEBUG, "divx3_write_header");
+    divx3_data_prefeeding(pkt, para->video_width, para->video_height);
+    if (1) {
+        pkt->codec = &para->vcodec;
+    } else {
+        CLog::Log(LOGDEBUG, "[divx3_write_header]invalid codec!");
+        return PLAYER_EMPTY_P;
+    }
+    pkt->newflag = 1;
+    write_av_packet(para, pkt);
+    return PLAYER_SUCCESS;
+}
+
+static int h264_add_header(unsigned char *buf, int size, am_packet_t *pkt)
+{
+    char nal_start_code[] = {0x0, 0x0, 0x0, 0x1};
+    int nalsize;
+    unsigned char* p;
+    int tmpi;
+    unsigned char* extradata = buf;
+    int header_len = 0;
+    char* buffer = pkt->hdr->data;
+
+    p = extradata;
+
+    // h264 annex-b
+         if ((p[0]==0 && p[1]==0 && p[2]==0 && p[3]==1) && size < HDR_BUF_SIZE) {
+        CLog::Log(LOGDEBUG, "add four byte NAL 264 header in stream before header len=%d",size);
+        memcpy(buffer, buf, size);
+        pkt->hdr->size = size;
+        return PLAYER_SUCCESS;
+    }
+
+    if ((p[0]==0 && p[1]==0 && p[2]==1) && size < HDR_BUF_SIZE) {
+        CLog::Log(LOGDEBUG, "add three byte NAL 264 header in stream before header len=%d",size);
+        memcpy(buffer, buf, size);
+        pkt->hdr->size = size;
+        return PLAYER_SUCCESS;
+    }
+
+    if (size < 4) {
+        return PLAYER_FAILED;
+    }
+
+    if (size < 10) {
+        CLog::Log(LOGDEBUG, "avcC too short");
+        return PLAYER_FAILED;
+    }
+
+    // h264 avcC
+    if (*p != 1) {
+        CLog::Log(LOGDEBUG, "Unknown avcC version %d", *p);
+        return PLAYER_FAILED;
+    }
+
+    int cnt = *(p + 5) & 0x1f; //number of sps
+    // CLog::Log(LOGDEBUG, "number of sps :%d", cnt);
+    p += 6;
+    for (tmpi = 0; tmpi < cnt; tmpi++) {
+        nalsize = (*p << 8) | (*(p + 1));
+        memcpy(&(buffer[header_len]), nal_start_code, 4);
+        header_len += 4;
+        memcpy(&(buffer[header_len]), p + 2, nalsize);
+        header_len += nalsize;
+        p += (nalsize + 2);
+    }
+
+    cnt = *(p++); //Number of pps
+    // CLog::Log(LOGDEBUG, "number of pps :%d", cnt);
+    for (tmpi = 0; tmpi < cnt; tmpi++) {
+        nalsize = (*p << 8) | (*(p + 1));
+        memcpy(&(buffer[header_len]), nal_start_code, 4);
+        header_len += 4;
+        memcpy(&(buffer[header_len]), p + 2, nalsize);
+        header_len += nalsize;
+        p += (nalsize + 2);
+    }
+    if (header_len >= HDR_BUF_SIZE) {
+        CLog::Log(LOGDEBUG, "header_len %d is larger than max length", header_len);
+        return 0;
+    }
+    pkt->hdr->size = header_len;
+
+    return PLAYER_SUCCESS;
+}
+static int h264_write_header(am_private_t *para, am_packet_t *pkt)
+{
+    // CLog::Log(LOGDEBUG, "h264_write_header");
+    int ret = -1;
+
+    ret = h264_add_header(para->extradata, para->extrasize, pkt);
+    if (ret == PLAYER_SUCCESS) {
+        //if (ctx->vcodec) {
+        if (1) {
+            pkt->codec = &para->vcodec;
+        } else {
+            //CLog::Log(LOGDEBUG, "[pre_header_feeding]invalid video codec!");
+            return PLAYER_EMPTY_P;
+        }
+
+        pkt->newflag = 1;
+        ret = write_av_packet(para, pkt);
+    }
+    return ret;
+}
+
+static int wmv3_write_header(am_private_t *para, am_packet_t *pkt)
+{
+    CLog::Log(LOGDEBUG, "wmv3_write_header");
+    unsigned i, check_sum = 0;
+    unsigned data_len = para->extrasize + 4;
+
+    pkt->hdr->data[0] = 0;
+    pkt->hdr->data[1] = 0;
+    pkt->hdr->data[2] = 1;
+    pkt->hdr->data[3] = 0x10;
+
+    pkt->hdr->data[4] = 0;
+    pkt->hdr->data[5] = (data_len >> 16) & 0xff;
+    pkt->hdr->data[6] = 0x88;
+    pkt->hdr->data[7] = (data_len >> 8) & 0xff;
+    pkt->hdr->data[8] = data_len & 0xff;
+    pkt->hdr->data[9] = 0x88;
+
+    pkt->hdr->data[10] = 0xff;
+    pkt->hdr->data[11] = 0xff;
+    pkt->hdr->data[12] = 0x88;
+    pkt->hdr->data[13] = 0xff;
+    pkt->hdr->data[14] = 0xff;
+    pkt->hdr->data[15] = 0x88;
+
+    for (i = 4 ; i < 16 ; i++) {
+        check_sum += pkt->hdr->data[i];
+    }
+
+    pkt->hdr->data[16] = (check_sum >> 8) & 0xff;
+    pkt->hdr->data[17] =  check_sum & 0xff;
+    pkt->hdr->data[18] = 0x88;
+    pkt->hdr->data[19] = (check_sum >> 8) & 0xff;
+    pkt->hdr->data[20] =  check_sum & 0xff;
+    pkt->hdr->data[21] = 0x88;
+
+    pkt->hdr->data[22] = (para->video_width >> 8) & 0xff;
+    pkt->hdr->data[23] =  para->video_width & 0xff;
+    pkt->hdr->data[24] = (para->video_height >> 8) & 0xff;
+    pkt->hdr->data[25] =  para->video_height & 0xff;
+
+    memcpy(pkt->hdr->data + 26, para->extradata, para->extrasize);
+    pkt->hdr->size = para->extrasize + 26;
+    if (1) {
+        pkt->codec = &para->vcodec;
+    } else {
+        CLog::Log(LOGDEBUG, "[wmv3_write_header]invalid codec!");
+        return PLAYER_EMPTY_P;
+    }
+    pkt->newflag = 1;
+    return write_av_packet(para, pkt);
+}
+
+static int wvc1_write_header(am_private_t *para, am_packet_t *pkt)
+{
+    CLog::Log(LOGDEBUG, "wvc1_write_header");
+    memcpy(pkt->hdr->data, para->extradata + 1, para->extrasize - 1);
+    pkt->hdr->size = para->extrasize - 1;
+    if (1) {
+        pkt->codec = &para->vcodec;
+    } else {
+        CLog::Log(LOGDEBUG, "[wvc1_write_header]invalid codec!");
+        return PLAYER_EMPTY_P;
+    }
+    pkt->newflag = 1;
+    return write_av_packet(para, pkt);
+}
+
+static int mpeg_add_header(am_private_t *para, am_packet_t *pkt)
+{
+    CLog::Log(LOGDEBUG, "mpeg_add_header");
+#define STUFF_BYTES_LENGTH     (256)
+    int size;
+    unsigned char packet_wrapper[] = {
+        0x00, 0x00, 0x01, 0xe0,
+        0x00, 0x00,                                /* pes packet length */
+        0x81, 0xc0, 0x0d,
+        0x20, 0x00, 0x00, 0x00, 0x00, /* PTS */
+        0x1f, 0xff, 0xff, 0xff, 0xff, /* DTS */
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+    };
+
+    size = para->extrasize + sizeof(packet_wrapper);
+    packet_wrapper[4] = size >> 8 ;
+    packet_wrapper[5] = size & 0xff ;
+    memcpy(pkt->hdr->data, packet_wrapper, sizeof(packet_wrapper));
+    size = sizeof(packet_wrapper);
+    //CLog::Log(LOGDEBUG, "[mpeg_add_header:%d]wrapper size=%d\n",__LINE__,size);
+    memcpy(pkt->hdr->data + size, para->extradata, para->extrasize);
+    size += para->extrasize;
+    //CLog::Log(LOGDEBUG, "[mpeg_add_header:%d]wrapper+seq size=%d\n",__LINE__,size);
+    memset(pkt->hdr->data + size, 0xff, STUFF_BYTES_LENGTH);
+    size += STUFF_BYTES_LENGTH;
+    pkt->hdr->size = size;
+    //CLog::Log(LOGDEBUG, "[mpeg_add_header:%d]hdr_size=%d\n",__LINE__,size);
+    if (1) {
+        pkt->codec = &para->vcodec;
+    } else {
+        CLog::Log(LOGDEBUG, "[mpeg_add_header]invalid codec!");
+        return PLAYER_EMPTY_P;
+    }
+
+    pkt->newflag = 1;
+    return write_av_packet(para, pkt);
+}
+
+int pre_header_feeding(am_private_t *para, am_packet_t *pkt)
+{
+    int ret;
+    if (para->stream_type == AM_STREAM_ES) {
+        if (pkt->hdr == NULL) {
+            pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+            pkt->hdr->data = (char *)malloc(HDR_BUF_SIZE);
+            if (!pkt->hdr->data) {
+                //CLog::Log(LOGDEBUG, "[pre_header_feeding] NOMEM!");
+                return PLAYER_NOMEM;
+            }
+        }
+
+        if (VFORMAT_H264 == para->video_format /*|| VFORMAT_H264MVC == para->video_format*/) {
+            ret = h264_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        } else if ((VFORMAT_MPEG4 == para->video_format) && (VIDEO_DEC_FORMAT_MPEG4_3 == para->video_codec_type)) {
+            ret = divx3_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        } else if ((CODEC_TAG_M4S2 == para->video_codec_tag)
+                || (CODEC_TAG_DX50 == para->video_codec_tag)
+                || (CODEC_TAG_mp4v == para->video_codec_tag)) {
+            ret = m4s2_dx50_mp4v_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        /*
+        } else if ((AVI_FILE == para->file_type)
+                && (VIDEO_DEC_FORMAT_MPEG4_3 != para->vstream_info.video_codec_type)
+                && (VFORMAT_H264 != para->vstream_info.video_format)
+                && (VFORMAT_VC1 != para->vstream_info.video_format)) {
+            ret = avi_write_header(para);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        */
+        } else if (CODEC_TAG_WMV3 == para->video_codec_tag) {
+            CLog::Log(LOGDEBUG, "CODEC_TAG_WMV3 == para->video_codec_tag");
+            ret = wmv3_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        } else if ((CODEC_TAG_WVC1 == para->video_codec_tag)
+                || (CODEC_TAG_VC_1 == para->video_codec_tag)
+                || (CODEC_TAG_WMVA == para->video_codec_tag)) {
+            CLog::Log(LOGDEBUG, "CODEC_TAG_WVC1 == para->video_codec_tag");
+            ret = wvc1_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        /*
+        } else if ((MKV_FILE == para->file_type) &&
+                  ((VFORMAT_MPEG4 == para->vstream_info.video_format)
+                || (VFORMAT_MPEG12 == para->vstream_info.video_format))) {
+            ret = mkv_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        */
+        } else if (VFORMAT_MJPEG == para->video_format) {
+            ret = mjpeg_write_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        }
+
+        if (pkt->hdr) {
+            if (pkt->hdr->data) {
+                free(pkt->hdr->data);
+                pkt->hdr->data = NULL;
+            }
+            free(pkt->hdr);
+            pkt->hdr = NULL;
+        }
+    }
+    else if (para->stream_type == AM_STREAM_PS) {
+        if (pkt->hdr == NULL) {
+            pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+            pkt->hdr->data = (char*)malloc(HDR_BUF_SIZE);
+            if (!pkt->hdr->data) {
+                CLog::Log(LOGDEBUG, "[pre_header_feeding] NOMEM!");
+                return PLAYER_NOMEM;
+            }
+        }
+        if (( CODEC_ID_MPEG1VIDEO == para->video_codec_id)
+          || (CODEC_ID_MPEG2VIDEO == para->video_codec_id)
+          || (CODEC_ID_MPEG2VIDEO_XVMC == para->video_codec_id)) {
+            ret = mpeg_add_header(para, pkt);
+            if (ret != PLAYER_SUCCESS) {
+                return ret;
+            }
+        }
+        if (pkt->hdr) {
+            if (pkt->hdr->data) {
+                free(pkt->hdr->data);
+                pkt->hdr->data = NULL;
+            }
+            free(pkt->hdr);
+            pkt->hdr = NULL;
+        }
+    }
+    return PLAYER_SUCCESS;
+}
+
+/*************************************************************************/
+int h264_update_frame_header(am_packet_t *pkt)
+{
+    int nalsize, size = pkt->data_size;
+    unsigned char *data = pkt->data;
+    unsigned char *p = data;
+    if (p != NULL) {
+        if (check_size_in_buffer(p, size)) {
+            while ((p + 4) < (data + size)) {
+                nalsize = (*p << 24) | (*(p + 1) << 16) | (*(p + 2) << 8) | (*(p + 3));
+                *p = 0;
+                *(p + 1) = 0;
+                *(p + 2) = 0;
+                *(p + 3) = 1;
+                p += (nalsize + 4);
+            }
+            return PLAYER_SUCCESS;
+        } else if (check_size_in_buffer3(p, size)) {
+            while ((p + 3) < (data + size)) {
+                nalsize = (*p << 16) | (*(p + 1) << 8) | (*(p + 2));
+                *p = 0;
+                *(p + 1) = 0;
+                *(p + 2) = 1;
+                p += (nalsize + 3);
+            }
+            return PLAYER_SUCCESS;
+        } else if (check_size_in_buffer2(p, size)) {
+            unsigned char *new_data;
+            int new_len = 0;
+
+            new_data = (unsigned char *)malloc(size + 2 * 1024);
+            if (!new_data) {
+                return PLAYER_NOMEM;
+            }
+
+            while ((p + 2) < (data + size)) {
+                nalsize = (*p << 8) | (*(p + 1));
+                *(new_data + new_len) = 0;
+                *(new_data + new_len + 1) = 0;
+                *(new_data + new_len + 2) = 0;
+                *(new_data + new_len + 3) = 1;
+                memcpy(new_data + new_len + 4, p + 2, nalsize);
+                p += (nalsize + 2);
+                new_len += nalsize + 4;
+            }
+
+            free(pkt->buf);
+
+            pkt->buf = new_data;
+            pkt->buf_size = size + 2 * 1024;
+            pkt->data = pkt->buf;
+            pkt->data_size = new_len;
+        }
+    } else {
+        CLog::Log(LOGDEBUG, "[%s]invalid pointer!", __FUNCTION__);
+        return PLAYER_FAILED;
+    }
+    return PLAYER_SUCCESS;
+}
+
+int divx3_prefix(am_packet_t *pkt)
+{
+#define DIVX311_CHUNK_HEAD_SIZE 13
+    const unsigned char divx311_chunk_prefix[DIVX311_CHUNK_HEAD_SIZE] = {
+        0x00, 0x00, 0x00, 0x01, 0xb6, 'D', 'I', 'V', 'X', '3', '.', '1', '1'
+    };
+    if ((pkt->hdr != NULL) && (pkt->hdr->data != NULL)) {
+        free(pkt->hdr->data);
+        pkt->hdr->data = NULL;
+    }
+
+    if (pkt->hdr == NULL) {
+        pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+        if (!pkt->hdr) {
+            CLog::Log(LOGDEBUG, "[divx3_prefix] NOMEM!");
+            return PLAYER_FAILED;
+        }
+
+        pkt->hdr->data = NULL;
+        pkt->hdr->size = 0;
+    }
+
+    pkt->hdr->data = (char*)malloc(DIVX311_CHUNK_HEAD_SIZE + 4);
+    if (pkt->hdr->data == NULL) {
+        CLog::Log(LOGDEBUG, "[divx3_prefix] NOMEM!");
+        return PLAYER_FAILED;
+    }
+
+    memcpy(pkt->hdr->data, divx311_chunk_prefix, DIVX311_CHUNK_HEAD_SIZE);
+
+    pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 0] = (pkt->data_size >> 24) & 0xff;
+    pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 1] = (pkt->data_size >> 16) & 0xff;
+    pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 2] = (pkt->data_size >>  8) & 0xff;
+    pkt->hdr->data[DIVX311_CHUNK_HEAD_SIZE + 3] = pkt->data_size & 0xff;
+
+    pkt->hdr->size = DIVX311_CHUNK_HEAD_SIZE + 4;
+    pkt->newflag = 1;
+
+    return PLAYER_SUCCESS;
+}
+
+int set_header_info(am_private_t *para)
+{
+  am_packet_t *pkt = &para->am_pkt;
+
+  //if (pkt->newflag)
+  {
+    //if (pkt->hdr)
+    //  pkt->hdr->size = 0;
+
+    if ((para->video_format == VFORMAT_H264) /*|| (am_private->video_format == VFORMAT_H264MVC)*/)
+    {
+      return h264_update_frame_header(pkt);
+    }
+    else if (para->video_format == VFORMAT_MPEG4)
+    {
+      if (para->video_codec_type == VIDEO_DEC_FORMAT_MPEG4_3)
+      {
+        return divx3_prefix(pkt);
+      }
+      else if (para->video_codec_type == VIDEO_DEC_FORMAT_H263)
+      {
+        return PLAYER_UNSUPPORT;
+        unsigned char *vld_buf;
+        int vld_len, vld_buf_size = para->video_width * para->video_height * 2;
+
+        if (!pkt->data_size) {
+            return PLAYER_SUCCESS;
+        }
+
+        if ((pkt->data[0] == 0) && (pkt->data[1] == 0) && (pkt->data[2] == 1) && (pkt->data[3] == 0xb6)) {
+            return PLAYER_SUCCESS;
+        }
+
+        vld_buf = (unsigned char*)malloc(vld_buf_size);
+        if (!vld_buf) {
+            return PLAYER_NOMEM;
+        }
+
+        if (para->flv_flag) {
+            vld_len = para->m_dll->h263vld(pkt->data, vld_buf, pkt->data_size, 1);
+        } else {
+            if (0 == para->h263_decodable) {
+                para->h263_decodable = para->m_dll->decodeble_h263(pkt->data);
+                if (0 == para->h263_decodable) {
+                    CLog::Log(LOGDEBUG, "[%s]h263 unsupport video and audio, exit", __FUNCTION__);
+                    return PLAYER_UNSUPPORT;
+                }
+            }
+            vld_len = para->m_dll->h263vld(pkt->data, vld_buf, pkt->data_size, 0);
+        }
+
+        if (vld_len > 0) {
+            if (pkt->buf) {
+                free(pkt->buf);
+            }
+            pkt->buf = vld_buf;
+            pkt->buf_size = vld_buf_size;
+            pkt->data = pkt->buf;
+            pkt->data_size = vld_len;
+        } else {
+            free(vld_buf);
+            pkt->data_size = 0;
+        }
+      }
+    } else if (para->video_format == VFORMAT_VC1) {
+        if (para->video_codec_type == VIDEO_DEC_FORMAT_WMV3) {
+            unsigned i, check_sum = 0, data_len = 0;
+
+            if ((pkt->hdr != NULL) && (pkt->hdr->data != NULL)) {
+                free(pkt->hdr->data);
+                pkt->hdr->data = NULL;
+            }
+
+            if (pkt->hdr == NULL) {
+                pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+                if (!pkt->hdr) {
+                    return PLAYER_FAILED;
+                }
+
+                pkt->hdr->data = NULL;
+                pkt->hdr->size = 0;
+            }
+
+            if (pkt->avpkt.flags) {
+                pkt->hdr->data = (char*)malloc(para->extrasize + 26 + 22);
+                if (pkt->hdr->data == NULL) {
+                    return PLAYER_FAILED;
+                }
+
+                pkt->hdr->data[0] = 0;
+                pkt->hdr->data[1] = 0;
+                pkt->hdr->data[2] = 1;
+                pkt->hdr->data[3] = 0x10;
+
+                data_len = para->extrasize + 4;
+                pkt->hdr->data[4] = 0;
+                pkt->hdr->data[5] = (data_len >> 16) & 0xff;
+                pkt->hdr->data[6] = 0x88;
+                pkt->hdr->data[7] = (data_len >> 8) & 0xff;
+                pkt->hdr->data[8] =  data_len & 0xff;
+                pkt->hdr->data[9] = 0x88;
+
+                pkt->hdr->data[10] = 0xff;
+                pkt->hdr->data[11] = 0xff;
+                pkt->hdr->data[12] = 0x88;
+                pkt->hdr->data[13] = 0xff;
+                pkt->hdr->data[14] = 0xff;
+                pkt->hdr->data[15] = 0x88;
+
+                for (i = 4 ; i < 16 ; i++) {
+                    check_sum += pkt->hdr->data[i];
+                }
+
+                pkt->hdr->data[16] = (check_sum >> 8) & 0xff;
+                pkt->hdr->data[17] =  check_sum & 0xff;
+                pkt->hdr->data[18] = 0x88;
+                pkt->hdr->data[19] = (check_sum >> 8) & 0xff;
+                pkt->hdr->data[20] =  check_sum & 0xff;
+                pkt->hdr->data[21] = 0x88;
+
+                pkt->hdr->data[22] = (para->video_width  >> 8) & 0xff;
+                pkt->hdr->data[23] =  para->video_width  & 0xff;
+                pkt->hdr->data[24] = (para->video_height >> 8) & 0xff;
+                pkt->hdr->data[25] =  para->video_height & 0xff;
+
+                memcpy(pkt->hdr->data + 26, para->extradata, para->extrasize);
+
+                check_sum = 0;
+                data_len = para->extrasize + 26;
+            } else {
+                pkt->hdr->data = (char*)malloc(22);
+                if (pkt->hdr->data == NULL) {
+                    return PLAYER_FAILED;
+                }
+            }
+
+            pkt->hdr->data[data_len + 0]  = 0;
+            pkt->hdr->data[data_len + 1]  = 0;
+            pkt->hdr->data[data_len + 2]  = 1;
+            pkt->hdr->data[data_len + 3]  = 0xd;
+
+            pkt->hdr->data[data_len + 4]  = 0;
+            pkt->hdr->data[data_len + 5]  = (pkt->data_size >> 16) & 0xff;
+            pkt->hdr->data[data_len + 6]  = 0x88;
+            pkt->hdr->data[data_len + 7]  = (pkt->data_size >> 8) & 0xff;
+            pkt->hdr->data[data_len + 8]  =  pkt->data_size & 0xff;
+            pkt->hdr->data[data_len + 9]  = 0x88;
+
+            pkt->hdr->data[data_len + 10] = 0xff;
+            pkt->hdr->data[data_len + 11] = 0xff;
+            pkt->hdr->data[data_len + 12] = 0x88;
+            pkt->hdr->data[data_len + 13] = 0xff;
+            pkt->hdr->data[data_len + 14] = 0xff;
+            pkt->hdr->data[data_len + 15] = 0x88;
+
+            for (i = data_len + 4 ; i < data_len + 16 ; i++) {
+                check_sum += pkt->hdr->data[i];
+            }
+
+            pkt->hdr->data[data_len + 16] = (check_sum >> 8) & 0xff;
+            pkt->hdr->data[data_len + 17] =  check_sum & 0xff;
+            pkt->hdr->data[data_len + 18] = 0x88;
+            pkt->hdr->data[data_len + 19] = (check_sum >> 8) & 0xff;
+            pkt->hdr->data[data_len + 20] =  check_sum & 0xff;
+            pkt->hdr->data[data_len + 21] = 0x88;
+
+            pkt->hdr->size = data_len + 22;
+            pkt->newflag = 1;
+        } else if (para->video_codec_type == VIDEO_DEC_FORMAT_WVC1) {
+            if ((pkt->hdr != NULL) && (pkt->hdr->data != NULL)) {
+                free(pkt->hdr->data);
+                pkt->hdr->data = NULL;
+            }
+
+            if (pkt->hdr == NULL) {
+                pkt->hdr = (hdr_buf_t*)malloc(sizeof(hdr_buf_t));
+                if (!pkt->hdr) {
+                    CLog::Log(LOGDEBUG, "[wvc1_prefix] NOMEM!");
+                    return PLAYER_FAILED;
+                }
+
+                pkt->hdr->data = NULL;
+                pkt->hdr->size = 0;
+            }
+
+            pkt->hdr->data = (char*)malloc(4);
+            if (pkt->hdr->data == NULL) {
+                CLog::Log(LOGDEBUG, "[wvc1_prefix] NOMEM!");
+                return PLAYER_FAILED;
+            }
+
+            pkt->hdr->data[0] = 0;
+            pkt->hdr->data[1] = 0;
+            pkt->hdr->data[2] = 1;
+            pkt->hdr->data[3] = 0xd;
+            pkt->hdr->size = 4;
+            pkt->newflag = 1;
+        }
+    }
+  }
+  return PLAYER_SUCCESS;
+}
+
+/*************************************************************************/
+CAMLCodec::CAMLCodec() : CThread("CAMLCodec")
+{
+  m_opened = false;
+  am_private = new am_private_t;
+  memset(am_private, 0, sizeof(am_private_t));
+  m_dll = new DllLibAmCodec;
+  m_dll->Load();
+  am_private->m_dll = m_dll;
+}
+
+
+CAMLCodec::~CAMLCodec()
+{
+  StopThread();
+  delete am_private;
+  am_private = NULL;
+  delete m_dll, m_dll = NULL;
+}
+
+bool CAMLCodec::OpenDecoder(CDVDStreamInfo &hints)
+{
+  CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder");
+  m_speed = DVD_PLAYSPEED_NORMAL;
+  m_1st_pts = 0;
+  m_cur_pts = 0;
+  m_cur_pictcnt = 0;
+  m_old_pictcnt = 0;
+  m_dst_rect.SetRect(0, 0, 0, 0);
+  m_zoom = -1;
+  m_contrast = -1;
+  m_brightness = -1;
+  m_vbufsize = 500000 * 2;
+  m_start_dts = 0;
+  m_start_pts = 0;
+  m_hints = hints;
+
+  ShowMainVideo(false);
+
+  am_packet_init(&am_private->am_pkt);
+  // default stream type
+  am_private->stream_type      = AM_STREAM_ES;
+  // handle hints.
+  am_private->video_width      = hints.width;
+  am_private->video_height     = hints.height;
+  am_private->video_codec_id   = hints.codec;
+  am_private->video_codec_tag  = hints.codec_tag;
+  am_private->video_pid        = hints.pid;
+
+  // handle video ratio
+  AVRational video_ratio       = m_dll->av_d2q(1, SHRT_MAX);
+  //if (!hints.forced_aspect)
+  //  video_ratio = m_dll->av_d2q(hints.aspect, SHRT_MAX);
+  am_private->video_ratio      = ((int32_t)video_ratio.num << 16) | video_ratio.den;
+  am_private->video_ratio64    = ((int64_t)video_ratio.num << 32) | video_ratio.den;
+
+  // handle video rate
+  if (hints.rfpsrate > 0 && hints.rfpsscale != 0)
+  {
+    // check ffmpeg r_frame_rate 1st
+    am_private->video_rate = 0.5 + (float)UNIT_FREQ * hints.rfpsscale / hints.rfpsrate;
+  }
+  else if (hints.fpsrate > 0 && hints.fpsscale != 0)
+  {
+    // then ffmpeg avg_frame_rate next
+    am_private->video_rate = 0.5 + (float)UNIT_FREQ * hints.fpsscale / hints.fpsrate;
+  }
+
+  // check for 1920x1080, interlaced, 25 fps
+  // incorrectly reported as 50 fps (yes, video_rate == 1920)
+  if (hints.width == 1920 && am_private->video_rate == 1920)
+  {
+    CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder video_rate exception");
+    am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 25000;
+  }
+
+  // check for SD h264 content incorrectly reported as 60 fsp
+  // mp4/avi containers :(
+  if (hints.codec == CODEC_ID_H264 && hints.width <= 720 && am_private->video_rate == 1602)
+  {
+    CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder video_rate exception");
+    am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 24000;
+  }
+
+  // check for SD h264 content incorrectly reported as some form of 30 fsp
+  // mp4/avi containers :(
+  if (hints.codec == CODEC_ID_H264 && hints.width <= 720)
+  {
+    if (am_private->video_rate >= 3200 && am_private->video_rate <= 3210)
+    {
+      CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder video_rate exception");
+      am_private->video_rate = 0.5 + (float)UNIT_FREQ * 1001 / 24000;
+    }
+  }
+
+  // handle orientation
+  am_private->video_rotation_degree = 0;
+  if (hints.orientation == 90)
+    am_private->video_rotation_degree = 1;
+  else if (hints.orientation == 180)
+    am_private->video_rotation_degree = 2;
+  else if (hints.orientation == 270)
+    am_private->video_rotation_degree = 3;
+  // handle extradata
+  am_private->video_format      = codecid_to_vformat(hints.codec);
+  switch (am_private->video_format)
+  {
+    default:
+      am_private->extrasize       = hints.extrasize;
+      am_private->extradata       = (uint8_t*)malloc(hints.extrasize);
+      memcpy(am_private->extradata, hints.extradata, hints.extrasize);
+      break;
+    case VFORMAT_REAL:
+    case VFORMAT_MPEG12:
+      break;
+  }
+
+  if (am_private->stream_type == AM_STREAM_ES && am_private->video_codec_tag != 0)
+    am_private->video_codec_type = codec_tag_to_vdec_type(am_private->video_codec_tag);
+  else
+    am_private->video_codec_type = codec_tag_to_vdec_type(am_private->video_codec_id);
+
+  am_private->flv_flag = 0;
+  if (am_private->video_codec_id == CODEC_ID_FLV1)
+  {
+    am_private->video_codec_tag = CODEC_TAG_F263;
+    am_private->flv_flag = 1;
+  }
+
+  CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder hints.fpsrate(%d), hints.fpsscale(%d), hints.rfpsrate(%d), hints.rfpsscale(%d), video_rate(%d)",
+    hints.fpsrate, hints.fpsscale, hints.rfpsrate, hints.rfpsscale, am_private->video_rate);
+  CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder hints.aspect(%f), video_ratio.num(%d), video_ratio.den(%d)",
+    hints.aspect, video_ratio.num, video_ratio.den);
+  CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder hints.orientation(%d), hints.forced_aspect(%d), hints.extrasize(%d)",
+    hints.orientation, hints.forced_aspect, hints.extrasize);
+
+  // default video codec params
+  am_private->vcodec.has_video   = 1;
+  am_private->vcodec.noblock     = 0;
+  am_private->vcodec.video_pid   = am_private->video_pid;
+  am_private->vcodec.video_type  = am_private->video_format;
+  am_private->vcodec.stream_type = STREAM_TYPE_ES_VIDEO;
+  am_private->vcodec.am_sysinfo.format  = am_private->video_codec_type;
+  am_private->vcodec.am_sysinfo.width   = am_private->video_width;
+  am_private->vcodec.am_sysinfo.height  = am_private->video_height;
+  am_private->vcodec.am_sysinfo.rate    = am_private->video_rate;
+  am_private->vcodec.am_sysinfo.ratio   = am_private->video_ratio;
+  am_private->vcodec.am_sysinfo.ratio64 = am_private->video_ratio64;
+  am_private->vcodec.am_sysinfo.param   = NULL;
+
+  switch(am_private->video_format)
+  {
+    default:
+      break;
+    case VFORMAT_MPEG4:
+      am_private->vcodec.am_sysinfo.param = (void*)EXTERNAL_PTS;
+      break;
+    case VFORMAT_H264:
+    case VFORMAT_H264MVC:
+      am_private->vcodec.am_sysinfo.format = VIDEO_DEC_FORMAT_H264;
+      am_private->vcodec.am_sysinfo.param  = (void*)EXTERNAL_PTS;
+      // h264 in an avi file
+      if (m_hints.ptsinvalid)
+        am_private->vcodec.am_sysinfo.param = (void*)(EXTERNAL_PTS | SYNC_OUTSIDE);
+      break;
+    case VFORMAT_REAL:
+      am_private->stream_type = AM_STREAM_RM;
+      am_private->vcodec.stream_type = STREAM_TYPE_RM;
+      am_private->vcodec.am_sysinfo.ratio = 0x100;
+      am_private->vcodec.am_sysinfo.ratio64 = 0;
+      {
+        static unsigned short tbl[9] = {0};
+        if (VIDEO_DEC_FORMAT_REAL_8 == am_private->video_codec_type)
+        {
+          am_private->vcodec.am_sysinfo.extra = am_private->extradata[1] & 7;
+          tbl[0] = (((am_private->vcodec.am_sysinfo.width  >> 2) - 1) << 8)
+                 | (((am_private->vcodec.am_sysinfo.height >> 2) - 1) & 0xff);
+          unsigned int j;
+          for (unsigned int i = 1; i <= am_private->vcodec.am_sysinfo.extra; i++)
+          {
+            j = 2 * (i - 1);
+            tbl[i] = ((am_private->extradata[8 + j] - 1) << 8) | ((am_private->extradata[8 + j + 1] - 1) & 0xff);
+          }
+        }
+        am_private->vcodec.am_sysinfo.param = &tbl;
+      }
+      break;
+    case VFORMAT_VC1:
+      // vc1 in an avi file
+      if (m_hints.ptsinvalid)
+        am_private->vcodec.am_sysinfo.param = (void*)EXTERNAL_PTS;
+      break;
+  }
+  am_private->vcodec.am_sysinfo.param = (void *)((unsigned int)am_private->vcodec.am_sysinfo.param | (am_private->video_rotation_degree << 16));
+
+  int ret = m_dll->codec_init(&am_private->vcodec);
+  if (ret != CODEC_ERROR_NONE)
+  {
+    CLog::Log(LOGDEBUG, "CAMLCodec::OpenDecoder codec init failed, ret=0x%x", -ret);
+    return false;
+  }
+  // make sure we are not stuck in pause (amcodec bug)
+  m_dll->codec_resume(&am_private->vcodec);
+  m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+
+  m_dll->codec_set_cntl_avthresh(&am_private->vcodec, AV_SYNC_THRESH);
+  m_dll->codec_set_cntl_syncthresh(&am_private->vcodec, 0);
+  // disable tsync, we are playing video disconnected from audio.
+  aml_set_sysfs_int("/sys/class/tsync/enable", 0);
+
+  am_private->am_pkt.codec = &am_private->vcodec;
+  pre_header_feeding(am_private, &am_private->am_pkt);
+
+  Create();
+
+  g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
+  g_renderManager.RegisterRenderFeaturesCallBack((const void*)this, RenderFeaturesCallBack);
+
+/*
+  // if display is set to 1080xxx, then disable deinterlacer for HD content
+  // else bandwidth usage is too heavy and it will slow down video decoder.
+  char display_mode[256] = {0};
+  aml_get_sysfs_str("/sys/class/display/mode", display_mode, 255);
+  if (strstr(display_mode,"1080"))
+    aml_set_sysfs_int("/sys/module/di/parameters/bypass_all", 1);
+  else
+    aml_set_sysfs_int("/sys/module/di/parameters/bypass_all", 0);
+*/
+
+  m_opened = true;
+  // vcodec is open, update speed if it was
+  // changed before dvdplayer called OpenDecoder.
+  SetSpeed(m_speed);
+
+  return true;
+}
+
+void CAMLCodec::CloseDecoder()
+{
+  CLog::Log(LOGDEBUG, "CAMLCodec::CloseDecoder");
+  StopThread();
+
+  g_renderManager.RegisterRenderUpdateCallBack((const void*)NULL, NULL);
+  g_renderManager.RegisterRenderFeaturesCallBack((const void*)NULL, NULL);
+
+  // never leave vcodec paused and closed.
+  SetSpeed(DVD_PLAYSPEED_NORMAL);
+  m_dll->codec_close(&am_private->vcodec);
+  m_opened = false;
+
+  am_packet_release(&am_private->am_pkt);
+  free(am_private->extradata);
+  am_private->extradata = NULL;
+  // return tsync to default so external apps work
+  aml_set_sysfs_int("/sys/class/tsync/enable", 1);
+
+  ShowMainVideo(false);
+
+}
+
+void CAMLCodec::Reset()
+{
+  CLog::Log(LOGDEBUG, "CAMLCodec::Reset");
+
+  if (!m_opened)
+    return;
+
+  // set the system blackout_policy to leave the last frame showing
+  int blackout_policy = aml_get_sysfs_int("/sys/class/video/blackout_policy");
+  aml_set_sysfs_int("/sys/class/video/blackout_policy", 0);
+
+  // restore the speed (some amcodec versions require this)
+  if (m_speed != DVD_PLAYSPEED_NORMAL)
+  {
+    m_dll->codec_resume(&am_private->vcodec);
+    m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+  }
+  // reset the decoder
+  m_dll->codec_reset(&am_private->vcodec);
+
+  // re-init our am_pkt
+  am_packet_release(&am_private->am_pkt);
+  am_packet_init(&am_private->am_pkt);
+  am_private->am_pkt.codec = &am_private->vcodec;
+  pre_header_feeding(am_private, &am_private->am_pkt);
+
+  // restore the saved system blackout_policy value
+  aml_set_sysfs_int("/sys/class/video/blackout_policy", blackout_policy);
+
+  // reset some interal vars
+  m_1st_pts = 0;
+  m_cur_pts = 0;
+  m_cur_pictcnt = 0;
+  m_old_pictcnt = 0;
+  SetSpeed(m_speed);
+}
+
+int CAMLCodec::Decode(unsigned char *pData, size_t size, double dts, double pts)
+{
+  if (!m_opened)
+    return VC_BUFFER;
+
+  // grr, m_RenderUpdateCallBackFn in g_renderManager is NULL'ed during
+  // g_renderManager.Configure call by player, which happens after the codec
+  // OpenDecoder call. So we need to restore it but it does not seem to stick :)
+  g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
+
+  if (pData)
+  {
+    am_private->am_pkt.data = pData;
+    am_private->am_pkt.data_size = size;
+
+    am_private->am_pkt.newflag    = 1;
+    am_private->am_pkt.isvalid    = 1;
+    am_private->am_pkt.avduration = 0;
+
+    // handle pts, including 31bit wrap, aml can only handle 31
+    // bit pts as it uses an int in kernel.
+    if (m_hints.ptsinvalid || pts == DVD_NOPTS_VALUE)
+      am_private->am_pkt.avpts = AV_NOPTS_VALUE;
+    else
+    {
+      am_private->am_pkt.avpts = 0.5 + (pts * PTS_FREQ) / DVD_TIME_BASE;\
+      if (!m_start_pts && am_private->am_pkt.avpts >= 0x7fffffff)
+        m_start_pts = am_private->am_pkt.avpts & ~0x0000ffff;
+    }
+    if (am_private->am_pkt.avpts != (int64_t)AV_NOPTS_VALUE)
+      am_private->am_pkt.avpts -= m_start_pts;
+
+
+    // handle dts, including 31bit wrap, aml can only handle 31
+    // bit dts as it uses an int in kernel.
+    if (dts == DVD_NOPTS_VALUE)
+      am_private->am_pkt.avdts = AV_NOPTS_VALUE;
+    else
+    {
+      am_private->am_pkt.avdts = 0.5 + (dts * PTS_FREQ) / DVD_TIME_BASE;
+      if (!m_start_dts && am_private->am_pkt.avdts >= 0x7fffffff)
+        m_start_dts = am_private->am_pkt.avdts & ~0x0000ffff;
+    }
+    if (am_private->am_pkt.avdts != (int64_t)AV_NOPTS_VALUE)
+      am_private->am_pkt.avdts -= m_start_dts;
+
+    //CLog::Log(LOGDEBUG, "CAMLCodec::Decode: siz(%d), dts(%f), pts(%f), avdts(%llx), avpts(%llx)",
+    //  size, dts, pts, am_private->am_pkt.avdts, am_private->am_pkt.avpts);
+
+    set_header_info(am_private);
+    write_av_packet(am_private, &am_private->am_pkt);
+
+    // if we seek, then GetTimeSize is wrong as
+    // reports lastpts - cur_pts and hw decoder has
+    // not started outputing new pts values yet.
+    // so we grab the 1st pts sent into driver and
+    // use that to calc GetTimeSize.
+    if (m_1st_pts == 0)
+      m_1st_pts = am_private->am_pkt.lastpts;
+  }
+
+  // if we have still frames, demux size will be small
+  // and we need to pre-buffer more.
+  double target_timesize = 1.0;
+  if (size < 20)
+    target_timesize = 2.0;
+
+  // keep hw buffered demux above 1 second
+  if (GetTimeSize() < target_timesize && m_speed == DVD_PLAYSPEED_NORMAL)
+    return VC_BUFFER;
+
+  // wait until we get a new frame or 100ms,
+  if (m_old_pictcnt == m_cur_pictcnt)
+    m_ready_event.WaitMSec(100);
+
+  // we must return VC_BUFFER or VC_PICTURE,
+  // default to VC_BUFFER.
+  int rtn = VC_BUFFER;
+  if (m_old_pictcnt != m_cur_pictcnt)
+  {
+    m_old_pictcnt = m_cur_pictcnt;
+    rtn = VC_PICTURE;
+    // we got a new pict, try and keep hw buffered demux above 2 seconds.
+    // this, combined with the above 1 second check, keeps hw buffered demux between 1 and 2 seconds.
+    // we also check to make sure we keep from filling hw buffer.
+    if (GetTimeSize() < 2.0 && GetDataSize() < m_vbufsize/3)
+      rtn |= VC_BUFFER;
+  }
+/*
+  CLog::Log(LOGDEBUG, "CAMLCodec::Decode: "
+    "rtn(%d), m_cur_pictcnt(%lld), m_cur_pts(%f), lastpts(%f), GetTimeSize(%f), GetDataSize(%d)",
+    rtn, m_cur_pictcnt, (float)m_cur_pts/PTS_FREQ, (float)am_private->am_pkt.lastpts/PTS_FREQ, GetTimeSize(), GetDataSize());
+*/
+  return rtn;
+}
+
+bool CAMLCodec::GetPicture(DVDVideoPicture *pDvdVideoPicture)
+{
+  if (!m_opened)
+    return false;
+
+  pDvdVideoPicture->iFlags = DVP_FLAG_ALLOCATED;
+  pDvdVideoPicture->format = RENDER_FMT_BYPASS;
+  pDvdVideoPicture->iDuration = (double)(am_private->video_rate * DVD_TIME_BASE) / UNIT_FREQ;
+
+  pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
+  pDvdVideoPicture->pts = GetPlayerPtsSeconds() * (double)DVD_TIME_BASE;
+  // video pts cannot be late or dvdplayer goes nuts,
+  // so run it one frame ahead
+  pDvdVideoPicture->pts += 1 * pDvdVideoPicture->iDuration;
+
+  return true;
+}
+
+void CAMLCodec::SetSpeed(int speed)
+{
+  CLog::Log(LOGDEBUG, "CAMLCodec::SetSpeed, speed(%d)", speed);
+
+  // update internal vars regardless
+  // of if we are open or not.
+  m_speed = speed;
+
+  if (!m_opened)
+    return;
+
+  switch(speed)
+  {
+    case DVD_PLAYSPEED_PAUSE:
+      m_dll->codec_pause(&am_private->vcodec);
+      m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+      break;
+    case DVD_PLAYSPEED_NORMAL:
+      m_dll->codec_resume(&am_private->vcodec);
+      m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_NONE);
+      break;
+    default:
+      m_dll->codec_resume(&am_private->vcodec);
+      if (am_private->video_format == VFORMAT_H264)
+        m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_FFFB);
+      else
+        m_dll->codec_set_cntl_mode(&am_private->vcodec, TRICKMODE_I);
+      break;
+  }
+}
+
+int CAMLCodec::GetDataSize()
+{
+  if (!m_opened)
+    return 0;
+
+  struct buf_status vbuf ={0};
+  if (m_dll->codec_get_vbuf_state(&am_private->vcodec, &vbuf) >= 0)
+    m_vbufsize = vbuf.size;
+
+  return vbuf.data_len;
+}
+
+double CAMLCodec::GetTimeSize()
+{
+  if (!m_opened)
+    return 0;
+
+  // if m_cur_pts is zero, hw decoder was not started yet
+  // so we use the pts of the 1st demux packet that was send
+  // to hw decoder to calc timesize.
+  if (m_cur_pts == 0)
+    m_timesize = (double)(am_private->am_pkt.lastpts - m_1st_pts) / PTS_FREQ;
+  else
+    m_timesize = (double)(am_private->am_pkt.lastpts - m_cur_pts) / PTS_FREQ;
+
+  // lie to DVDPlayer, it is hardcoded to a max of 8 seconds,
+  // if you buffer more than 8 seconds, it goes nuts.
+  double timesize = m_timesize;
+  if (timesize < 0.0)
+    timesize = 0.0;
+  else if (timesize > 7.0)
+    timesize = 7.0;
+
+  return timesize;
+}
+
+void CAMLCodec::Process()
+{
+  CLog::Log(LOGDEBUG, "CAMLCodec::Process Started");
+
+  // bump our priority to be level with SoftAE
+  SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
+  while (!m_bStop)
+  {
+    int64_t pts_video = 0;
+    if (am_private->am_pkt.lastpts > 0)
+    {
+      // this is a blocking poll that returns every vsync.
+      // since we are running at a higher priority, make sure
+      // we sleep if the call fails or does a timeout.
+      if (m_dll->codec_poll_cntl(&am_private->vcodec) < 0)
+      {
+        CLog::Log(LOGDEBUG, "CAMLCodec::Process: codec_poll_cntl failed");
+        Sleep(10);
+      }
+
+      pts_video = get_pts_video();
+      if (m_cur_pts != pts_video)
+      {
+        //CLog::Log(LOGDEBUG, "CAMLCodec::Process: pts_video(%lld), pts_video/PTS_FREQ(%f), duration(%f)",
+        //  pts_video, (double)pts_video/PTS_FREQ, 1.0/((double)(pts_video - m_cur_pts)/PTS_FREQ));
+        // other threads look at these, do them first
+        m_cur_pts = pts_video;
+        m_cur_pictcnt++;
+        m_ready_event.Set();
+
+        // correct video pts by starting pts.
+        if (m_start_pts != 0)
+          pts_video += m_start_pts;
+        else if (m_start_dts != 0)
+          pts_video += m_start_dts;
+
+        double app_pts = GetPlayerPtsSeconds();
+        // add in audio delay/display latency contribution
+        double offset  = g_renderManager.GetDisplayLatency() - CMediaSettings::Get().GetCurrentVideoSettings().m_AudioDelay;
+        // correct video pts by user set delay and rendering delay
+        app_pts += offset;
+
+        //CLog::Log(LOGDEBUG, "CAMLCodec::Process: app_pts(%f), pts_video/PTS_FREQ(%f)",
+        //  app_pts, (double)pts_video/PTS_FREQ);
+
+        double error = app_pts - (double)pts_video/PTS_FREQ;
+        double abs_error = fabs(error);
+        if (abs_error > 0.150)
+        {
+          //CLog::Log(LOGDEBUG, "CAMLCodec::Process pts diff = %f", error);
+          if (abs_error > 0.125)
+          {
+            // big error so try to reset pts_pcrscr
+            SetVideoPtsSeconds(app_pts);
+          }
+          else
+          {
+            // small error so try to avoid a frame jump
+            SetVideoPtsSeconds((double)pts_video/PTS_FREQ + error/4);
+          }
+        }
+      }
+    }
+    else
+    {
+      Sleep(10);
+    }
+  }
+  SetPriority(THREAD_PRIORITY_NORMAL);
+  CLog::Log(LOGDEBUG, "CAMLCodec::Process Stopped");
+}
+
+double CAMLCodec::GetPlayerPtsSeconds()
+{
+  double clock_pts = 0.0;
+  CDVDClock *playerclock = CDVDClock::GetMasterClock();
+  if (playerclock)
+    clock_pts = playerclock->GetClock() / DVD_TIME_BASE;
+
+  return clock_pts;
+}
+
+void CAMLCodec::SetVideoPtsSeconds(const double pts)
+{
+  //CLog::Log(LOGDEBUG, "CAMLCodec::SetVideoPtsSeconds: pts(%f)", pts);
+  if (pts >= 0.0)
+  {
+    int64_t pts_video = (int64_t)(pts * PTS_FREQ);
+    if (m_start_pts != 0)
+      pts_video -= m_start_pts;
+    else if (m_start_dts != 0)
+      pts_video -= m_start_dts;
+
+    set_pts_pcrscr(pts_video);
+  }
+}
+
+void CAMLCodec::ShowMainVideo(const bool show)
+{
+  static int saved_disable_video = -1;
+
+  int disable_video = show ? 0:1;
+  if (saved_disable_video == disable_video)
+    return;
+
+  aml_set_sysfs_int("/sys/class/video/disable_video", disable_video);
+  saved_disable_video = disable_video;
+}
+
+void CAMLCodec::SetVideoZoom(const float zoom)
+{
+  // input zoom range is 0.5 to 2.0 with a default of 1.0.
+  // output zoom range is 2 to 300 with default of 100.
+  // we limit that to a range of 50 to 200 with default of 100.
+  aml_set_sysfs_int("/sys/class/video/zoom", (int)(100 * zoom));
+}
+
+void CAMLCodec::SetVideoContrast(const int contrast)
+{
+  // input contrast range is 0 to 100 with default of 50.
+  // output contrast range is -255 to 255 with default of 0.
+  int aml_contrast = (255 * (contrast - 50)) / 50;
+  aml_set_sysfs_int("/sys/class/video/contrast", aml_contrast);
+}
+void CAMLCodec::SetVideoBrightness(const int brightness)
+{
+  // input brightness range is 0 to 100 with default of 50.
+  // output brightness range is -127 to 127 with default of 0.
+  int aml_brightness = (127 * (brightness - 50)) / 50;
+  aml_set_sysfs_int("/sys/class/video/brightness", aml_brightness);
+}
+void CAMLCodec::SetVideoSaturation(const int saturation)
+{
+  // output saturation range is -127 to 127 with default of 127.
+  aml_set_sysfs_int("/sys/class/video/saturation", saturation);
+}
+
+void CAMLCodec::GetRenderFeatures(Features &renderFeatures)
+{
+  renderFeatures.push_back(RENDERFEATURE_ZOOM);
+  renderFeatures.push_back(RENDERFEATURE_CONTRAST);
+  renderFeatures.push_back(RENDERFEATURE_BRIGHTNESS);
+  renderFeatures.push_back(RENDERFEATURE_STRETCH);
+  renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO);
+  return;
+}
+
+void CAMLCodec::RenderFeaturesCallBack(const void *ctx, Features &renderFeatures)
+{
+  CAMLCodec *codec = (CAMLCodec*)ctx;
+  if (codec)
+    codec->GetRenderFeatures(renderFeatures);
+}
+
+void CAMLCodec::SetVideoRect(const CRect &SrcRect, const CRect &DestRect)
+{
+  // this routine gets called every video frame
+  // and is in the context of the renderer thread so
+  // do not do anything stupid here.
+
+  // video zoom adjustment.
+  float zoom = CMediaSettings::Get().GetCurrentVideoSettings().m_CustomZoomAmount;
+  if ((int)(zoom * 1000) != (int)(m_zoom * 1000))
+  {
+    m_zoom = zoom;
+  }
+  // video contrast adjustment.
+  int contrast = CMediaSettings::Get().GetCurrentVideoSettings().m_Contrast;
+  if (contrast != m_contrast)
+  {
+    SetVideoContrast(contrast);
+    m_contrast = contrast;
+  }
+  // video brightness adjustment.
+  int brightness = CMediaSettings::Get().GetCurrentVideoSettings().m_Brightness;
+  if (brightness != m_brightness)
+  {
+    SetVideoBrightness(brightness);
+    m_brightness = brightness;
+  }
+
+  // check if destination rect or video view mode has changed
+  if ((m_dst_rect != DestRect) || (m_view_mode != CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode))
+  {
+    m_dst_rect  = DestRect;
+    m_view_mode = CMediaSettings::Get().GetCurrentVideoSettings().m_ViewMode;
+  }
+  else
+  {
+    // mainvideo 'should' be showing already if we get here, make sure.
+    ShowMainVideo(true);
+    return;
+  }
+
+  CRect gui, display, dst_rect;
+  gui = g_graphicsContext.GetViewWindow();
+  // when display is at 1080p, we have freescale enabled
+  // and that scales all layers into 1080p display including video,
+  // so we have to setup video axis for 720p instead of 1080p... Boooo.
+  display = g_graphicsContext.GetViewWindow();
+  dst_rect = m_dst_rect;
+  if (gui != display)
+  {
+    float xscale = display.Width()  / gui.Width();
+    float yscale = display.Height() / gui.Height();
+    dst_rect.x1 *= xscale;
+    dst_rect.x2 *= xscale;
+    dst_rect.y1 *= yscale;
+    dst_rect.y2 *= yscale;
+  }
+
+  ShowMainVideo(false);
+
+  // goofy 0/1 based difference in aml axis coordinates.
+  // fix them.
+  dst_rect.x2--;
+  dst_rect.y2--;
+
+  char video_axis[256] = {0};
+  sprintf(video_axis, "%d %d %d %d", (int)dst_rect.x1, (int)dst_rect.y1, (int)dst_rect.x2, (int)dst_rect.y2);
+  aml_set_sysfs_str("/sys/class/video/axis", video_axis);
+  // make sure we are in 'full stretch' so we can stretch
+  aml_set_sysfs_int("/sys/class/video/screen_mode", 1);
+
+/*
+  CStdString rectangle;
+  rectangle.Format("%i,%i,%i,%i",
+    (int)dst_rect.x1, (int)dst_rect.y1,
+    (int)dst_rect.Width(), (int)dst_rect.Height());
+  CLog::Log(LOGDEBUG, "CAMLCodec::SetVideoRect:dst_rect(%s)", rectangle.c_str());
+*/
+
+  // we only get called once gui has changed to something
+  // that would show video playback, so show it.
+  ShowMainVideo(true);
+}
+
+void CAMLCodec::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
+{
+  CAMLCodec *codec = (CAMLCodec*)ctx;
+  codec->SetVideoRect(SrcRect, DestRect);
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/AMLCodec.h
new file mode 100644 (file)
index 0000000..346f92b
--- /dev/null
@@ -0,0 +1,86 @@
+#pragma once
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "DVDVideoCodec.h"
+#include "cores/dvdplayer/DVDStreamInfo.h"
+#include "cores/VideoRenderers/RenderFeatures.h"
+#include "guilib/Geometry.h"
+#include "threads/Thread.h"
+
+typedef struct am_private_t am_private_t;
+
+class DllLibAmCodec;
+
+class CAMLCodec : public CThread
+{
+public:
+  CAMLCodec();
+  virtual ~CAMLCodec();
+
+  bool          OpenDecoder(CDVDStreamInfo &hints);
+  void          CloseDecoder();
+  void          Reset();
+
+  int           Decode(unsigned char *pData, size_t size, double dts, double pts);
+
+  bool          GetPicture(DVDVideoPicture* pDvdVideoPicture);
+  void          SetSpeed(int speed);
+  int           GetDataSize();
+  double        GetTimeSize();
+
+protected:
+  virtual void  Process();
+
+private:
+  double        GetPlayerPtsSeconds();
+  void          SetVideoPtsSeconds(double pts);
+  void          ShowMainVideo(const bool show);
+  void          SetVideoZoom(const float zoom);
+  void          SetVideoContrast(const int contrast);
+  void          SetVideoBrightness(const int brightness);
+  void          SetVideoSaturation(const int saturation);
+  void          GetRenderFeatures(Features &renderFeatures);
+  static void   RenderFeaturesCallBack(const void *ctx, Features &renderFeatures);
+  void          SetVideoRect(const CRect &SrcRect, const CRect &DestRect);
+  static void   RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect);
+
+  DllLibAmCodec   *m_dll;
+  bool             m_opened;
+  am_private_t    *am_private;
+  CDVDStreamInfo   m_hints;
+  volatile int     m_speed;
+  volatile int64_t m_1st_pts;
+  volatile int64_t m_cur_pts;
+  volatile int64_t m_cur_pictcnt;
+  volatile int64_t m_old_pictcnt;
+  volatile double  m_timesize;
+  volatile int64_t m_vbufsize;
+  int64_t          m_start_dts;
+  int64_t          m_start_pts;
+  CEvent           m_ready_event;
+
+  CRect            m_dst_rect;
+  int              m_view_mode;
+  float            m_zoom;
+  int              m_contrast;
+  int              m_brightness;
+};
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.cpp
new file mode 100644 (file)
index 0000000..252ab6c
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <math.h>
+
+#include "DVDVideoCodecAmlogic.h"
+#include "DVDClock.h"
+#include "DVDStreamInfo.h"
+#include "AMLCodec.h"
+#include "video/VideoThumbLoader.h"
+#include "utils/BitstreamConverter.h"
+#include "utils/log.h"
+
+#define __MODULE_NAME__ "DVDVideoCodecAmlogic"
+
+typedef struct frame_queue {
+  double dts;
+  double pts;
+  double sort_time;
+  struct frame_queue *nextframe;
+} frame_queue;
+
+CDVDVideoCodecAmlogic::CDVDVideoCodecAmlogic() :
+  m_Codec(NULL),
+  m_pFormatName("amcodec"),
+  m_last_pts(0.0),
+  m_frame_queue(NULL),
+  m_queue_depth(0),
+  m_framerate(0.0),
+  m_video_rate(0),
+  m_mpeg2_sequence(NULL)
+{
+  pthread_mutex_init(&m_queue_mutex, NULL);
+}
+
+CDVDVideoCodecAmlogic::~CDVDVideoCodecAmlogic()
+{
+  Dispose();
+  pthread_mutex_destroy(&m_queue_mutex);
+}
+
+bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
+{
+  switch(hints.codec)
+  {
+    case CODEC_ID_MJPEG:
+      m_pFormatName = "am-mjpeg";
+      break;
+    case CODEC_ID_MPEG1VIDEO:
+    case CODEC_ID_MPEG2VIDEO:
+    case CODEC_ID_MPEG2VIDEO_XVMC:
+      m_mpeg2_sequence_pts = 0;
+      m_mpeg2_sequence = new mpeg2_sequence;
+      m_mpeg2_sequence->width  = hints.width;
+      m_mpeg2_sequence->height = hints.height;
+      m_mpeg2_sequence->ratio  = hints.aspect;
+      if (hints.rfpsrate > 0 && hints.rfpsscale != 0)
+        m_mpeg2_sequence->rate = (float)hints.rfpsrate / hints.rfpsscale;
+      else if (hints.fpsrate > 0 && hints.fpsscale != 0)
+        m_mpeg2_sequence->rate = (float)hints.fpsrate / hints.fpsscale;
+      else
+        m_mpeg2_sequence->rate = 1.0;
+      m_pFormatName = "am-mpeg2";
+      break;
+    case CODEC_ID_H264:
+      m_pFormatName = "am-h264";
+      break;
+    case CODEC_ID_MPEG4:
+    case CODEC_ID_MSMPEG4V2:
+    case CODEC_ID_MSMPEG4V3:
+      m_pFormatName = "am-mpeg4";
+      break;
+    case CODEC_ID_H263:
+    case CODEC_ID_H263P:
+    case CODEC_ID_H263I:
+      m_pFormatName = "am-h263";
+      break;
+    case CODEC_ID_FLV1:
+      m_pFormatName = "am-flv1";
+      break;
+    case CODEC_ID_RV10:
+    case CODEC_ID_RV20:
+    case CODEC_ID_RV30:
+    case CODEC_ID_RV40:
+      m_pFormatName = "am-rv";
+      break;
+    case CODEC_ID_VC1:
+      m_pFormatName = "am-vc1";
+      break;
+    case CODEC_ID_WMV3:
+      m_pFormatName = "am-wmv3";
+      break;
+    case CODEC_ID_AVS:
+    case CODEC_ID_CAVS:
+      m_pFormatName = "am-avs";
+      break;
+    default:
+      CLog::Log(LOGDEBUG, "%s: Unknown hints.codec(%d", __MODULE_NAME__, hints.codec);
+      return false;
+      break;
+  }
+
+  m_hints = hints;
+  m_aspect_ratio = hints.aspect;
+  m_Codec = new CAMLCodec();
+  if (!m_Codec)
+  {
+    CLog::Log(LOGERROR, "%s: Failed to create Amlogic Codec", __MODULE_NAME__);
+    return false;
+  }
+  m_opened = false;
+
+  // allocate a dummy DVDVideoPicture buffer.
+  // first make sure all properties are reset.
+  memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
+
+  m_videobuffer.dts = DVD_NOPTS_VALUE;
+  m_videobuffer.pts = DVD_NOPTS_VALUE;
+  m_videobuffer.format = RENDER_FMT_BYPASS;
+  m_videobuffer.color_range  = 0;
+  m_videobuffer.color_matrix = 4;
+  m_videobuffer.iFlags  = DVP_FLAG_ALLOCATED;
+  m_videobuffer.iWidth  = hints.width;
+  m_videobuffer.iHeight = hints.height;
+
+  m_videobuffer.iDisplayWidth  = m_videobuffer.iWidth;
+  m_videobuffer.iDisplayHeight = m_videobuffer.iHeight;
+  if (hints.aspect > 0.0 && !hints.forced_aspect)
+  {
+    m_videobuffer.iDisplayWidth  = ((int)lrint(m_videobuffer.iHeight * hints.aspect)) & -3;
+    if (m_videobuffer.iDisplayWidth > m_videobuffer.iWidth)
+    {
+      m_videobuffer.iDisplayWidth  = m_videobuffer.iWidth;
+      m_videobuffer.iDisplayHeight = ((int)lrint(m_videobuffer.iWidth / hints.aspect)) & -3;
+    }
+  }
+
+  CLog::Log(LOGINFO, "%s: Opened Amlogic Codec", __MODULE_NAME__);
+  return true;
+}
+
+void CDVDVideoCodecAmlogic::Dispose(void)
+{
+  if (m_Codec)
+    m_Codec->CloseDecoder(), m_Codec = NULL;
+  if (m_videobuffer.iFlags)
+    m_videobuffer.iFlags = 0;
+  if (m_mpeg2_sequence)
+    delete m_mpeg2_sequence, m_mpeg2_sequence = NULL;
+
+  while (m_queue_depth)
+    FrameQueuePop();
+}
+
+int CDVDVideoCodecAmlogic::Decode(BYTE *pData, int iSize, double dts, double pts)
+{
+  // Handle Input, add demuxer packet to input queue, we must accept it or
+  // it will be discarded as DVDPlayerVideo has no concept of "try again".
+
+  if (pData)
+    FrameRateTracking( pData, iSize, dts, pts);
+
+  if (!m_opened)
+  {
+    if (m_Codec && !m_Codec->OpenDecoder(m_hints))
+      CLog::Log(LOGERROR, "%s: Failed to open Amlogic Codec", __MODULE_NAME__);
+    m_opened = true;
+  }
+
+  if (m_hints.ptsinvalid)
+    pts = DVD_NOPTS_VALUE;
+
+  return m_Codec->Decode(pData, iSize, dts, pts);
+}
+
+void CDVDVideoCodecAmlogic::Reset(void)
+{
+  while (m_queue_depth)
+    FrameQueuePop();
+
+  m_Codec->Reset();
+  m_mpeg2_sequence_pts = 0;
+}
+
+bool CDVDVideoCodecAmlogic::GetPicture(DVDVideoPicture* pDvdVideoPicture)
+{
+  if (m_Codec)
+    m_Codec->GetPicture(&m_videobuffer);
+  *pDvdVideoPicture = m_videobuffer;
+
+  // check for mpeg2 aspect ratio changes
+  if (m_mpeg2_sequence && pDvdVideoPicture->pts >= m_mpeg2_sequence_pts)
+    m_aspect_ratio = m_mpeg2_sequence->ratio;
+
+  pDvdVideoPicture->iDisplayWidth  = pDvdVideoPicture->iWidth;
+  pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight;
+  if (m_aspect_ratio > 1.0 && !m_hints.forced_aspect)
+  {
+    pDvdVideoPicture->iDisplayWidth  = ((int)lrint(pDvdVideoPicture->iHeight * m_aspect_ratio)) & -3;
+    if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth)
+    {
+      pDvdVideoPicture->iDisplayWidth  = pDvdVideoPicture->iWidth;
+      pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / m_aspect_ratio)) & -3;
+    }
+  }
+
+  return true;
+}
+
+void CDVDVideoCodecAmlogic::SetDropState(bool bDrop)
+{
+}
+
+void CDVDVideoCodecAmlogic::SetSpeed(int iSpeed)
+{
+  if (m_Codec)
+    m_Codec->SetSpeed(iSpeed);
+}
+
+int CDVDVideoCodecAmlogic::GetDataSize(void)
+{
+  if (m_Codec)
+    return m_Codec->GetDataSize();
+
+  return 0;
+}
+
+double CDVDVideoCodecAmlogic::GetTimeSize(void)
+{
+  if (m_Codec)
+    return m_Codec->GetTimeSize();
+
+  return 0.0;
+}
+
+void CDVDVideoCodecAmlogic::FrameQueuePop(void)
+{
+  if (!m_frame_queue || m_queue_depth == 0)
+    return;
+
+  pthread_mutex_lock(&m_queue_mutex);
+  // pop the top frame off the queue
+  frame_queue *top = m_frame_queue;
+  m_frame_queue = top->nextframe;
+  m_queue_depth--;
+  pthread_mutex_unlock(&m_queue_mutex);
+
+  // and release it
+  free(top);
+}
+
+void CDVDVideoCodecAmlogic::FrameQueuePush(double dts, double pts)
+{
+  frame_queue *newframe = (frame_queue*)calloc(sizeof(frame_queue), 1);
+  newframe->dts = dts;
+  newframe->pts = pts;
+  // if both dts or pts are good we use those, else use decoder insert time for frame sort
+  if ((newframe->pts != DVD_NOPTS_VALUE) || (newframe->dts != DVD_NOPTS_VALUE))
+  {
+    // if pts is borked (stupid avi's), use dts for frame sort
+    if (newframe->pts == DVD_NOPTS_VALUE)
+      newframe->sort_time = newframe->dts;
+    else
+      newframe->sort_time = newframe->pts;
+  }
+
+  pthread_mutex_lock(&m_queue_mutex);
+  frame_queue *queueWalker = m_frame_queue;
+  if (!queueWalker || (newframe->sort_time < queueWalker->sort_time))
+  {
+    // we have an empty queue, or this frame earlier than the current queue head.
+    newframe->nextframe = queueWalker;
+    m_frame_queue = newframe;
+  }
+  else
+  {
+    // walk the queue and insert this frame where it belongs in display order.
+    bool ptrInserted = false;
+    frame_queue *nextframe = NULL;
+    //
+    while (!ptrInserted)
+    {
+      nextframe = queueWalker->nextframe;
+      if (!nextframe || (newframe->sort_time < nextframe->sort_time))
+      {
+        // if the next frame is the tail of the queue, or our new frame is earlier.
+        newframe->nextframe = nextframe;
+        queueWalker->nextframe = newframe;
+        ptrInserted = true;
+      }
+      queueWalker = nextframe;
+    }
+  }
+  m_queue_depth++;
+  pthread_mutex_unlock(&m_queue_mutex);        
+}
+
+void CDVDVideoCodecAmlogic::FrameRateTracking(BYTE *pData, int iSize, double dts, double pts)
+{
+  // mpeg2 handling
+  if (m_mpeg2_sequence)
+  {
+    // probe demux for sequence_header_code NAL and
+    // decode aspect ratio and frame rate.
+    if (CBitstreamConverter::mpeg2_sequence_header(pData, iSize, m_mpeg2_sequence))
+    {
+      m_mpeg2_sequence_pts = pts;
+      if (m_mpeg2_sequence_pts == DVD_NOPTS_VALUE)
+        m_mpeg2_sequence_pts = dts;
+
+      m_framerate = m_mpeg2_sequence->rate;
+      m_video_rate = (int)(0.5 + (96000.0 / m_framerate));
+
+      CLog::Log(LOGDEBUG, "%s: detected mpeg2 aspect ratio(%f), framerate(%f), video_rate(%d)",
+        __MODULE_NAME__, m_mpeg2_sequence->ratio, m_framerate, m_video_rate);
+
+      // update hints for 1st frame fixup.
+      switch(m_mpeg2_sequence->rate_info)
+      {
+        default:
+        case 0x01:
+          m_hints.rfpsrate = 24000.0;
+          m_hints.rfpsscale = 1001.0;
+          break;
+        case 0x02:
+          m_hints.rfpsrate = 24000.0;
+          m_hints.rfpsscale = 1000.0;
+          break;
+        case 0x03:
+          m_hints.rfpsrate = 25000.0;
+          m_hints.rfpsscale = 1000.0;
+          break;
+        case 0x04:
+          m_hints.rfpsrate = 30000.0;
+          m_hints.rfpsscale = 1001.0;
+          break;
+        case 0x05:
+          m_hints.rfpsrate = 30000.0;
+          m_hints.rfpsscale = 1000.0;
+          break;
+        case 0x06:
+          m_hints.rfpsrate = 50000.0;
+          m_hints.rfpsscale = 1000.0;
+          break;
+        case 0x07:
+          m_hints.rfpsrate = 60000.0;
+          m_hints.rfpsscale = 1001.0;
+          break;
+        case 0x08:
+          m_hints.rfpsrate = 60000.0;
+          m_hints.rfpsscale = 1000.0;
+          break;
+      }
+      m_hints.width    = m_mpeg2_sequence->width;
+      m_hints.height   = m_mpeg2_sequence->height;
+      m_hints.aspect   = m_mpeg2_sequence->ratio;
+      m_hints.fpsrate  = m_hints.rfpsrate;
+      m_hints.fpsscale = m_hints.rfpsscale;
+    }
+    return;
+  }
+
+  // everything else
+  FrameQueuePush(dts, pts);
+
+  // we might have out-of-order pts,
+  // so make sure we wait for at least 8 values in sorted queue.
+  if (m_queue_depth > 16)
+  {
+    pthread_mutex_lock(&m_queue_mutex);
+
+    float cur_pts = m_frame_queue->pts;
+    if (cur_pts == DVD_NOPTS_VALUE)
+      cur_pts = m_frame_queue->dts;
+
+    pthread_mutex_unlock(&m_queue_mutex);      
+
+    float duration = cur_pts - m_last_pts;
+    m_last_pts = cur_pts;
+
+    // clamp duration to sensible range,
+    // 66 fsp to 20 fsp
+    if (duration >= 15000.0 && duration <= 50000.0)
+    {
+      double framerate;
+      switch((int)(0.5 + duration))
+      {
+        // 59.940 (16683.333333)
+        case 16000 ... 17000:
+          framerate = 60000.0 / 1001.0;
+          break;
+
+        // 50.000 (20000.000000)
+        case 20000:
+          framerate = 50000.0 / 1000.0;
+          break;
+
+        // 49.950 (20020.000000)
+        case 20020:
+          framerate = 50000.0 / 1001.0;
+          break;
+
+        // 29.970 (33366.666656)
+        case 32000 ... 35000:
+          framerate = 30000.0 / 1001.0;
+          break;
+
+        // 25.000 (40000.000000)
+        case 40000:
+          framerate = 25000.0 / 1000.0;
+          break;
+
+        // 24.975 (40040.000000)
+        case 40040:
+          framerate = 25000.0 / 1001.0;
+          break;
+
+        /*
+        // 24.000 (41666.666666)
+        case 41667:
+          framerate = 24000.0 / 1000.0;
+          break;
+        */
+
+        // 23.976 (41708.33333)
+        case 40200 ... 43200:
+          // 23.976 seems to have the crappiest encodings :)
+          framerate = 24000.0 / 1001.0;
+          break;
+
+        default:
+          framerate = 0.0;
+          //CLog::Log(LOGDEBUG, "%s: unknown duration(%f), cur_pts(%f)",
+          //  __MODULE_NAME__, duration, cur_pts);
+          break;
+      }
+
+      if (framerate > 0.0 && (int)m_framerate != (int)framerate)
+      {
+        m_framerate = framerate;
+        m_video_rate = (int)(0.5 + (96000.0 / framerate));
+        CLog::Log(LOGDEBUG, "%s: detected new framerate(%f), video_rate(%d)",
+          __MODULE_NAME__, m_framerate, m_video_rate);
+      }
+    }
+
+    FrameQueuePop();
+  }
+}
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecAmlogic.h
new file mode 100644 (file)
index 0000000..a78a953
--- /dev/null
@@ -0,0 +1,67 @@
+#pragma once
+/*
+ *      Copyright (C) 2005-2012 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "DVDVideoCodec.h"
+#include "DVDStreamInfo.h"
+
+class CAMLCodec;
+struct frame_queue;
+struct mpeg2_sequence;
+
+class CDVDVideoCodecAmlogic : public CDVDVideoCodec
+{
+public:
+  CDVDVideoCodecAmlogic();
+  virtual ~CDVDVideoCodecAmlogic();
+
+  // Required overrides
+  virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
+  virtual void Dispose(void);
+  virtual int  Decode(BYTE *pData, int iSize, double dts, double pts);
+  virtual void Reset(void);
+  virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
+  virtual void SetSpeed(int iSpeed);
+  virtual void SetDropState(bool bDrop);
+  virtual int  GetDataSize(void);
+  virtual double GetTimeSize(void);
+  virtual const char* GetName(void) { return (const char*)m_pFormatName; }
+
+protected:
+  void            FrameQueuePop(void);
+  void            FrameQueuePush(double dts, double pts);
+  void            FrameRateTracking(BYTE *pData, int iSize, double dts, double pts);
+
+  CAMLCodec      *m_Codec;
+  const char     *m_pFormatName;
+  DVDVideoPicture m_videobuffer;
+  bool            m_opened;
+  CDVDStreamInfo  m_hints;
+  double          m_last_pts;
+  frame_queue    *m_frame_queue;
+  int32_t         m_queue_depth;
+  pthread_mutex_t m_queue_mutex;
+  double          m_framerate;
+  int             m_video_rate;
+  float           m_aspect_ratio;
+  mpeg2_sequence *m_mpeg2_sequence;
+  double          m_mpeg2_sequence_pts;
+};
index 176ceff..157b6b3 100644 (file)
@@ -23,6 +23,12 @@ SRCS += OpenMaxVideo.cpp
 SRCS += DVDVideoCodecOpenMax.cpp
 endif
 
+ifeq (@USE_LIBAMCODEC@,1)
+SRCS += AMLCodec.cpp
+SRCS += DVDVideoCodecAmlogic.cpp
+INCLUDES += -I$(prefix)/include/amlplayer
+endif
+
 LIB=Video.a
 
 include @abs_top_srcdir@/Makefile.include
index e45c5d0..99e26ae 100644 (file)
@@ -160,6 +160,8 @@ public:
   {
     iFpsScale = 0;
     iFpsRate = 0;
+    irFpsScale = 0;
+    irFpsRate = 0;
     iHeight = 0;
     iWidth = 0;
     fAspect = 0.0;
@@ -174,6 +176,8 @@ public:
   virtual ~CDemuxStreamVideo() {}
   int iFpsScale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
   int iFpsRate;
+  int irFpsScale;
+  int irFpsRate;
   int iHeight; // height of the stream reported by the demuxer
   int iWidth; // width of the stream reported by the demuxer
   float fAspect; // display aspect of stream
index 8a6fa22..23c0a01 100644 (file)
@@ -1049,6 +1049,18 @@ void CDVDDemuxFFmpeg::AddStream(int iId)
           st->iFpsScale = 0;
         }
 
+        // added for aml hw decoder, mkv frame-rate can be wrong.
+        if (pStream->r_frame_rate.den && pStream->r_frame_rate.num)
+        {
+          st->irFpsRate = pStream->r_frame_rate.num;
+          st->irFpsScale = pStream->r_frame_rate.den;
+        }
+        else
+        {
+          st->irFpsRate = 0;
+          st->irFpsScale = 0;
+        }
+
         if (pStream->codec_info_nb_frames >  0
         &&  pStream->codec_info_nb_frames <= 2
         &&  m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
index 26cdbc4..fddfffd 100644 (file)
@@ -1188,8 +1188,11 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
     limited = true;
 
   //correct any pattern in the timestamps
-  m_pullupCorrection.Add(pts);
-  pts += m_pullupCorrection.GetCorrection();
+  if (m_output.color_format != RENDER_FMT_BYPASS)
+  {
+    m_pullupCorrection.Add(pts);
+    pts += m_pullupCorrection.GetCorrection();
+  }
 
   //try to calculate the framerate
   CalcFrameRate();
@@ -1203,8 +1206,11 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
     pts -= DVD_TIME_BASE * interval;
   }
 
-  // Correct pts by user set delay and rendering delay
-  pts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency());
+  if (m_output.color_format != RENDER_FMT_BYPASS)
+  {
+    // Correct pts by user set delay and rendering delay
+    pts += m_iVideoDelay - DVD_SEC_TO_TIME(g_renderManager.GetDisplayLatency());
+  }
 
   // calculate the time we need to delay this picture before displaying
   double iSleepTime, iClockSleep, iFrameSleep, iPlayingClock, iCurrentClock, iFrameDuration;
index 2619ab5..8947481 100644 (file)
@@ -50,6 +50,8 @@ void CDVDStreamInfo::Clear()
 
   fpsscale = 0;
   fpsrate  = 0;
+  rfpsscale= 0;
+  rfpsrate = 0;
   height   = 0;
   width    = 0;
   aspect   = 0.0;
@@ -60,6 +62,7 @@ void CDVDStreamInfo::Clear()
   ptsinvalid = false;
   forced_aspect = false;
   bitsperpixel = 0;
+  pid = 0;
 
   channels   = 0;
   samplerate = 0;
@@ -89,6 +92,8 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata)
   // VIDEO
   if( fpsscale != right.fpsscale
   ||  fpsrate  != right.fpsrate
+  ||  rfpsscale!= right.rfpsscale
+  ||  rfpsrate != right.rfpsrate
   ||  height   != right.height
   ||  width    != right.width
   ||  stills   != right.stills
@@ -97,6 +102,7 @@ bool CDVDStreamInfo::Equal(const CDVDStreamInfo& right, bool withextradata)
   ||  ptsinvalid != right.ptsinvalid
   ||  forced_aspect != right.forced_aspect
   ||  bitsperpixel != right.bitsperpixel
+  ||  pid != right.pid
   ||  vfr      != right.vfr) return false;
 
   // AUDIO
@@ -143,6 +149,8 @@ void CDVDStreamInfo::Assign(const CDVDStreamInfo& right, bool withextradata)
   // VIDEO
   fpsscale = right.fpsscale;
   fpsrate  = right.fpsrate;
+  rfpsscale= right.rfpsscale;
+  rfpsrate = right.rfpsrate;
   height   = right.height;
   width    = right.width;
   aspect   = right.aspect;
@@ -153,6 +161,7 @@ void CDVDStreamInfo::Assign(const CDVDStreamInfo& right, bool withextradata)
   forced_aspect = right.forced_aspect;
   orientation = right.orientation;
   bitsperpixel = right.bitsperpixel;
+  pid = right.pid;
   vfr = right.vfr;
   software = right.software;
 
@@ -197,6 +206,8 @@ void CDVDStreamInfo::Assign(const CDemuxStream& right, bool withextradata)
     const CDemuxStreamVideo *stream = static_cast<const CDemuxStreamVideo*>(&right);
     fpsscale  = stream->iFpsScale;
     fpsrate   = stream->iFpsRate;
+    rfpsscale = stream->irFpsScale;
+    rfpsrate  = stream->irFpsRate;
     height    = stream->iHeight;
     width     = stream->iWidth;
     aspect    = stream->fAspect;
@@ -205,6 +216,7 @@ void CDVDStreamInfo::Assign(const CDemuxStream& right, bool withextradata)
     forced_aspect = stream->bForcedAspect;
     orientation = stream->iOrientation;
     bitsperpixel = stream->iBitsPerPixel;
+    pid = stream->iPhysicalId;
   }
   else if(  right.type == STREAM_SUBTITLE )
   {
index 80669b1..f27d6cb 100644 (file)
@@ -63,6 +63,8 @@ public:
   // VIDEO
   int fpsscale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
   int fpsrate;
+  int rfpsscale;
+  int rfpsrate;
   int height; // height of the stream reported by the demuxer
   int width; // width of the stream reported by the demuxer
   float aspect; // display aspect as reported by demuxer
@@ -74,6 +76,7 @@ public:
   bool forced_aspect; // aspect is forced from container
   int orientation; // orientation of the video in degress counter clockwise
   int bitsperpixel;
+  int pid;
 
   // AUDIO
   int channels;