2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
23 #include "DVDVideoCodecAmlogic.h"
25 #include "DVDStreamInfo.h"
27 #include "utils/BitstreamConverter.h"
28 #include "utils/log.h"
30 #define __MODULE_NAME__ "DVDVideoCodecAmlogic"
32 typedef struct frame_queue {
36 struct frame_queue *nextframe;
39 CDVDVideoCodecAmlogic::CDVDVideoCodecAmlogic() :
41 m_pFormatName("amcodec"),
47 m_mpeg2_sequence(NULL),
51 pthread_mutex_init(&m_queue_mutex, NULL);
54 CDVDVideoCodecAmlogic::~CDVDVideoCodecAmlogic()
57 pthread_mutex_destroy(&m_queue_mutex);
60 bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
66 case AV_CODEC_ID_MJPEG:
67 m_pFormatName = "am-mjpeg";
69 case AV_CODEC_ID_MPEG1VIDEO:
70 case AV_CODEC_ID_MPEG2VIDEO:
71 case AV_CODEC_ID_MPEG2VIDEO_XVMC:
72 if (m_hints.width <= 1280)
74 // amcodec struggles with VOB playback
75 // which can be handled via software
79 m_mpeg2_sequence_pts = 0;
80 m_mpeg2_sequence = new mpeg2_sequence;
81 m_mpeg2_sequence->width = m_hints.width;
82 m_mpeg2_sequence->height = m_hints.height;
83 m_mpeg2_sequence->ratio = m_hints.aspect;
84 if (m_hints.rfpsrate > 0 && m_hints.rfpsscale != 0)
85 m_mpeg2_sequence->rate = (float)m_hints.rfpsrate / m_hints.rfpsscale;
86 else if (m_hints.fpsrate > 0 && m_hints.fpsscale != 0)
87 m_mpeg2_sequence->rate = (float)m_hints.fpsrate / m_hints.fpsscale;
89 m_mpeg2_sequence->rate = 1.0;
90 m_pFormatName = "am-mpeg2";
92 case AV_CODEC_ID_H264:
93 m_pFormatName = "am-h264";
94 // convert h264-avcC to h264-annex-b as h264-avcC
95 // under streamers can have issues when seeking.
96 if (m_hints.extradata && *(uint8_t*)m_hints.extradata == 1)
98 m_bitstream = new CBitstreamConverter;
99 m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true);
100 // make sure we do not leak the existing m_hints.extradata
101 free(m_hints.extradata);
102 m_hints.extrasize = m_bitstream->GetExtraSize();
103 m_hints.extradata = malloc(m_hints.extrasize);
104 memcpy(m_hints.extradata, m_bitstream->GetExtraData(), m_hints.extrasize);
106 //m_bitparser = new CBitstreamParser();
107 //m_bitparser->Open();
109 case AV_CODEC_ID_MPEG4:
110 case AV_CODEC_ID_MSMPEG4V2:
111 case AV_CODEC_ID_MSMPEG4V3:
112 m_pFormatName = "am-mpeg4";
114 case AV_CODEC_ID_H263:
115 case AV_CODEC_ID_H263P:
116 case AV_CODEC_ID_H263I:
117 m_pFormatName = "am-h263";
119 case AV_CODEC_ID_FLV1:
120 m_pFormatName = "am-flv1";
122 case AV_CODEC_ID_RV10:
123 case AV_CODEC_ID_RV20:
124 case AV_CODEC_ID_RV30:
125 case AV_CODEC_ID_RV40:
126 // m_pFormatName = "am-rv";
127 // rmvb is not handled well by amcodec
130 case AV_CODEC_ID_VC1:
131 m_pFormatName = "am-vc1";
133 case AV_CODEC_ID_WMV3:
134 m_pFormatName = "am-wmv3";
136 case AV_CODEC_ID_AVS:
137 case AV_CODEC_ID_CAVS:
138 m_pFormatName = "am-avs";
141 CLog::Log(LOGDEBUG, "%s: Unknown hints.codec(%d", __MODULE_NAME__, m_hints.codec);
146 m_aspect_ratio = m_hints.aspect;
147 m_Codec = new CAMLCodec();
150 CLog::Log(LOGERROR, "%s: Failed to create Amlogic Codec", __MODULE_NAME__);
155 // allocate a dummy DVDVideoPicture buffer.
156 // first make sure all properties are reset.
157 memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
159 m_videobuffer.dts = DVD_NOPTS_VALUE;
160 m_videobuffer.pts = DVD_NOPTS_VALUE;
161 m_videobuffer.format = RENDER_FMT_BYPASS;
162 m_videobuffer.color_range = 0;
163 m_videobuffer.color_matrix = 4;
164 m_videobuffer.iFlags = DVP_FLAG_ALLOCATED;
165 m_videobuffer.iWidth = m_hints.width;
166 m_videobuffer.iHeight = m_hints.height;
168 m_videobuffer.iDisplayWidth = m_videobuffer.iWidth;
169 m_videobuffer.iDisplayHeight = m_videobuffer.iHeight;
170 if (m_hints.aspect > 0.0 && !m_hints.forced_aspect)
172 m_videobuffer.iDisplayWidth = ((int)lrint(m_videobuffer.iHeight * m_hints.aspect)) & -3;
173 if (m_videobuffer.iDisplayWidth > m_videobuffer.iWidth)
175 m_videobuffer.iDisplayWidth = m_videobuffer.iWidth;
176 m_videobuffer.iDisplayHeight = ((int)lrint(m_videobuffer.iWidth / m_hints.aspect)) & -3;
180 CLog::Log(LOGINFO, "%s: Opened Amlogic Codec", __MODULE_NAME__);
184 void CDVDVideoCodecAmlogic::Dispose(void)
187 m_Codec->CloseDecoder(), m_Codec = NULL;
188 if (m_videobuffer.iFlags)
189 m_videobuffer.iFlags = 0;
190 if (m_mpeg2_sequence)
191 delete m_mpeg2_sequence, m_mpeg2_sequence = NULL;
194 delete m_bitstream, m_bitstream = NULL;
197 delete m_bitparser, m_bitparser = NULL;
199 while (m_queue_depth)
203 int CDVDVideoCodecAmlogic::Decode(uint8_t *pData, int iSize, double dts, double pts)
205 // Handle Input, add demuxer packet to input queue, we must accept it or
206 // it will be discarded as DVDPlayerVideo has no concept of "try again".
211 if (!m_bitstream->Convert(pData, iSize))
214 pData = m_bitstream->GetConvertBuffer();
215 iSize = m_bitstream->GetConvertSize();
219 m_bitparser->FindIdrSlice(pData, iSize);
221 FrameRateTracking( pData, iSize, dts, pts);
226 if (m_Codec && !m_Codec->OpenDecoder(m_hints))
227 CLog::Log(LOGERROR, "%s: Failed to open Amlogic Codec", __MODULE_NAME__);
231 if (m_hints.ptsinvalid)
232 pts = DVD_NOPTS_VALUE;
234 return m_Codec->Decode(pData, iSize, dts, pts);
237 void CDVDVideoCodecAmlogic::Reset(void)
239 while (m_queue_depth)
243 m_mpeg2_sequence_pts = 0;
246 bool CDVDVideoCodecAmlogic::GetPicture(DVDVideoPicture* pDvdVideoPicture)
249 m_Codec->GetPicture(&m_videobuffer);
250 *pDvdVideoPicture = m_videobuffer;
252 // check for mpeg2 aspect ratio changes
253 if (m_mpeg2_sequence && pDvdVideoPicture->pts >= m_mpeg2_sequence_pts)
254 m_aspect_ratio = m_mpeg2_sequence->ratio;
256 pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth;
257 pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight;
258 if (m_aspect_ratio > 1.0 && !m_hints.forced_aspect)
260 pDvdVideoPicture->iDisplayWidth = ((int)lrint(pDvdVideoPicture->iHeight * m_aspect_ratio)) & -3;
261 if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth)
263 pDvdVideoPicture->iDisplayWidth = pDvdVideoPicture->iWidth;
264 pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / m_aspect_ratio)) & -3;
271 void CDVDVideoCodecAmlogic::SetDropState(bool bDrop)
275 void CDVDVideoCodecAmlogic::SetSpeed(int iSpeed)
278 m_Codec->SetSpeed(iSpeed);
281 int CDVDVideoCodecAmlogic::GetDataSize(void)
284 return m_Codec->GetDataSize();
289 double CDVDVideoCodecAmlogic::GetTimeSize(void)
292 return m_Codec->GetTimeSize();
297 void CDVDVideoCodecAmlogic::FrameQueuePop(void)
299 if (!m_frame_queue || m_queue_depth == 0)
302 pthread_mutex_lock(&m_queue_mutex);
303 // pop the top frame off the queue
304 frame_queue *top = m_frame_queue;
305 m_frame_queue = top->nextframe;
307 pthread_mutex_unlock(&m_queue_mutex);
313 void CDVDVideoCodecAmlogic::FrameQueuePush(double dts, double pts)
315 frame_queue *newframe = (frame_queue*)calloc(sizeof(frame_queue), 1);
318 // if both dts or pts are good we use those, else use decoder insert time for frame sort
319 if ((newframe->pts != DVD_NOPTS_VALUE) || (newframe->dts != DVD_NOPTS_VALUE))
321 // if pts is borked (stupid avi's), use dts for frame sort
322 if (newframe->pts == DVD_NOPTS_VALUE)
323 newframe->sort_time = newframe->dts;
325 newframe->sort_time = newframe->pts;
328 pthread_mutex_lock(&m_queue_mutex);
329 frame_queue *queueWalker = m_frame_queue;
330 if (!queueWalker || (newframe->sort_time < queueWalker->sort_time))
332 // we have an empty queue, or this frame earlier than the current queue head.
333 newframe->nextframe = queueWalker;
334 m_frame_queue = newframe;
338 // walk the queue and insert this frame where it belongs in display order.
339 bool ptrInserted = false;
340 frame_queue *nextframe = NULL;
344 nextframe = queueWalker->nextframe;
345 if (!nextframe || (newframe->sort_time < nextframe->sort_time))
347 // if the next frame is the tail of the queue, or our new frame is earlier.
348 newframe->nextframe = nextframe;
349 queueWalker->nextframe = newframe;
352 queueWalker = nextframe;
356 pthread_mutex_unlock(&m_queue_mutex);
359 void CDVDVideoCodecAmlogic::FrameRateTracking(uint8_t *pData, int iSize, double dts, double pts)
362 if (m_mpeg2_sequence)
364 // probe demux for sequence_header_code NAL and
365 // decode aspect ratio and frame rate.
366 if (CBitstreamConverter::mpeg2_sequence_header(pData, iSize, m_mpeg2_sequence))
368 m_mpeg2_sequence_pts = pts;
369 if (m_mpeg2_sequence_pts == DVD_NOPTS_VALUE)
370 m_mpeg2_sequence_pts = dts;
372 m_framerate = m_mpeg2_sequence->rate;
373 m_video_rate = (int)(0.5 + (96000.0 / m_framerate));
375 CLog::Log(LOGDEBUG, "%s: detected mpeg2 aspect ratio(%f), framerate(%f), video_rate(%d)",
376 __MODULE_NAME__, m_mpeg2_sequence->ratio, m_framerate, m_video_rate);
378 // update m_hints for 1st frame fixup.
379 switch(m_mpeg2_sequence->rate_info)
383 m_hints.rfpsrate = 24000.0;
384 m_hints.rfpsscale = 1001.0;
387 m_hints.rfpsrate = 24000.0;
388 m_hints.rfpsscale = 1000.0;
391 m_hints.rfpsrate = 25000.0;
392 m_hints.rfpsscale = 1000.0;
395 m_hints.rfpsrate = 30000.0;
396 m_hints.rfpsscale = 1001.0;
399 m_hints.rfpsrate = 30000.0;
400 m_hints.rfpsscale = 1000.0;
403 m_hints.rfpsrate = 50000.0;
404 m_hints.rfpsscale = 1000.0;
407 m_hints.rfpsrate = 60000.0;
408 m_hints.rfpsscale = 1001.0;
411 m_hints.rfpsrate = 60000.0;
412 m_hints.rfpsscale = 1000.0;
415 m_hints.width = m_mpeg2_sequence->width;
416 m_hints.height = m_mpeg2_sequence->height;
417 m_hints.aspect = m_mpeg2_sequence->ratio;
418 m_hints.fpsrate = m_hints.rfpsrate;
419 m_hints.fpsscale = m_hints.rfpsscale;
425 FrameQueuePush(dts, pts);
427 // we might have out-of-order pts,
428 // so make sure we wait for at least 8 values in sorted queue.
429 if (m_queue_depth > 16)
431 pthread_mutex_lock(&m_queue_mutex);
433 float cur_pts = m_frame_queue->pts;
434 if (cur_pts == DVD_NOPTS_VALUE)
435 cur_pts = m_frame_queue->dts;
437 pthread_mutex_unlock(&m_queue_mutex);
439 float duration = cur_pts - m_last_pts;
440 m_last_pts = cur_pts;
442 // clamp duration to sensible range,
444 if (duration >= 15000.0 && duration <= 50000.0)
447 switch((int)(0.5 + duration))
449 // 59.940 (16683.333333)
450 case 16000 ... 17000:
451 framerate = 60000.0 / 1001.0;
454 // 50.000 (20000.000000)
456 framerate = 50000.0 / 1000.0;
459 // 49.950 (20020.000000)
461 framerate = 50000.0 / 1001.0;
464 // 29.970 (33366.666656)
465 case 32000 ... 35000:
466 framerate = 30000.0 / 1001.0;
469 // 25.000 (40000.000000)
471 framerate = 25000.0 / 1000.0;
474 // 24.975 (40040.000000)
476 framerate = 25000.0 / 1001.0;
480 // 24.000 (41666.666666)
482 framerate = 24000.0 / 1000.0;
486 // 23.976 (41708.33333)
487 case 40200 ... 43200:
488 // 23.976 seems to have the crappiest encodings :)
489 framerate = 24000.0 / 1001.0;
494 //CLog::Log(LOGDEBUG, "%s: unknown duration(%f), cur_pts(%f)",
495 // __MODULE_NAME__, duration, cur_pts);
499 if (framerate > 0.0 && (int)m_framerate != (int)framerate)
501 m_framerate = framerate;
502 m_video_rate = (int)(0.5 + (96000.0 / framerate));
503 CLog::Log(LOGDEBUG, "%s: detected new framerate(%f), video_rate(%d)",
504 __MODULE_NAME__, m_framerate, m_video_rate);