FIX: [droid] set "remote as keyboard" default to true
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / DVDVideoCodecAmlogic.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <math.h>
22
23 #include "DVDVideoCodecAmlogic.h"
24 #include "DVDClock.h"
25 #include "DVDStreamInfo.h"
26 #include "AMLCodec.h"
27 #include "utils/BitstreamConverter.h"
28 #include "utils/log.h"
29
30 #define __MODULE_NAME__ "DVDVideoCodecAmlogic"
31
32 typedef struct frame_queue {
33   double dts;
34   double pts;
35   double sort_time;
36   struct frame_queue *nextframe;
37 } frame_queue;
38
39 CDVDVideoCodecAmlogic::CDVDVideoCodecAmlogic() :
40   m_Codec(NULL),
41   m_pFormatName("amcodec"),
42   m_last_pts(0.0),
43   m_frame_queue(NULL),
44   m_queue_depth(0),
45   m_framerate(0.0),
46   m_video_rate(0),
47   m_mpeg2_sequence(NULL),
48   m_bitparser(NULL),
49   m_bitstream(NULL)
50 {
51   pthread_mutex_init(&m_queue_mutex, NULL);
52 }
53
54 CDVDVideoCodecAmlogic::~CDVDVideoCodecAmlogic()
55 {
56   Dispose();
57   pthread_mutex_destroy(&m_queue_mutex);
58 }
59
60 bool CDVDVideoCodecAmlogic::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
61 {
62   m_hints = hints;
63
64   switch(m_hints.codec)
65   {
66     case AV_CODEC_ID_MJPEG:
67       m_pFormatName = "am-mjpeg";
68       break;
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)
73       {
74         // amcodec struggles with VOB playback
75         // which can be handled via software
76         return false;
77         break;
78       }
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;
88       else
89         m_mpeg2_sequence->rate = 1.0;
90       m_pFormatName = "am-mpeg2";
91       break;
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)
97       {
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);
105       }
106       //m_bitparser = new CBitstreamParser();
107       //m_bitparser->Open();
108       break;
109     case AV_CODEC_ID_MPEG4:
110     case AV_CODEC_ID_MSMPEG4V2:
111     case AV_CODEC_ID_MSMPEG4V3:
112       m_pFormatName = "am-mpeg4";
113       break;
114     case AV_CODEC_ID_H263:
115     case AV_CODEC_ID_H263P:
116     case AV_CODEC_ID_H263I:
117       m_pFormatName = "am-h263";
118       break;
119     case AV_CODEC_ID_FLV1:
120       m_pFormatName = "am-flv1";
121       break;
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
128       return false;
129       break;
130     case AV_CODEC_ID_VC1:
131       m_pFormatName = "am-vc1";
132       break;
133     case AV_CODEC_ID_WMV3:
134       m_pFormatName = "am-wmv3";
135       break;
136     case AV_CODEC_ID_AVS:
137     case AV_CODEC_ID_CAVS:
138       m_pFormatName = "am-avs";
139       break;
140     default:
141       CLog::Log(LOGDEBUG, "%s: Unknown hints.codec(%d", __MODULE_NAME__, m_hints.codec);
142       return false;
143       break;
144   }
145
146   m_aspect_ratio = m_hints.aspect;
147   m_Codec = new CAMLCodec();
148   if (!m_Codec)
149   {
150     CLog::Log(LOGERROR, "%s: Failed to create Amlogic Codec", __MODULE_NAME__);
151     return false;
152   }
153   m_opened = false;
154
155   // allocate a dummy DVDVideoPicture buffer.
156   // first make sure all properties are reset.
157   memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
158
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;
167
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)
171   {
172     m_videobuffer.iDisplayWidth  = ((int)lrint(m_videobuffer.iHeight * m_hints.aspect)) & -3;
173     if (m_videobuffer.iDisplayWidth > m_videobuffer.iWidth)
174     {
175       m_videobuffer.iDisplayWidth  = m_videobuffer.iWidth;
176       m_videobuffer.iDisplayHeight = ((int)lrint(m_videobuffer.iWidth / m_hints.aspect)) & -3;
177     }
178   }
179
180   CLog::Log(LOGINFO, "%s: Opened Amlogic Codec", __MODULE_NAME__);
181   return true;
182 }
183
184 void CDVDVideoCodecAmlogic::Dispose(void)
185 {
186   if (m_Codec)
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;
192
193   if (m_bitstream)
194     delete m_bitstream, m_bitstream = NULL;
195
196   if (m_bitparser)
197     delete m_bitparser, m_bitparser = NULL;
198
199   while (m_queue_depth)
200     FrameQueuePop();
201 }
202
203 int CDVDVideoCodecAmlogic::Decode(uint8_t *pData, int iSize, double dts, double pts)
204 {
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".
207   if (pData)
208   {
209     if (m_bitstream)
210     {
211       if (!m_bitstream->Convert(pData, iSize))
212         return VC_ERROR;
213
214       pData = m_bitstream->GetConvertBuffer();
215       iSize = m_bitstream->GetConvertSize();
216     }
217
218     if (m_bitparser)
219       m_bitparser->FindIdrSlice(pData, iSize);
220
221     FrameRateTracking( pData, iSize, dts, pts);
222   }
223
224   if (!m_opened)
225   {
226     if (m_Codec && !m_Codec->OpenDecoder(m_hints))
227       CLog::Log(LOGERROR, "%s: Failed to open Amlogic Codec", __MODULE_NAME__);
228     m_opened = true;
229   }
230
231   if (m_hints.ptsinvalid)
232     pts = DVD_NOPTS_VALUE;
233
234   return m_Codec->Decode(pData, iSize, dts, pts);
235 }
236
237 void CDVDVideoCodecAmlogic::Reset(void)
238 {
239   while (m_queue_depth)
240     FrameQueuePop();
241
242   m_Codec->Reset();
243   m_mpeg2_sequence_pts = 0;
244 }
245
246 bool CDVDVideoCodecAmlogic::GetPicture(DVDVideoPicture* pDvdVideoPicture)
247 {
248   if (m_Codec)
249     m_Codec->GetPicture(&m_videobuffer);
250   *pDvdVideoPicture = m_videobuffer;
251
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;
255
256   pDvdVideoPicture->iDisplayWidth  = pDvdVideoPicture->iWidth;
257   pDvdVideoPicture->iDisplayHeight = pDvdVideoPicture->iHeight;
258   if (m_aspect_ratio > 1.0 && !m_hints.forced_aspect)
259   {
260     pDvdVideoPicture->iDisplayWidth  = ((int)lrint(pDvdVideoPicture->iHeight * m_aspect_ratio)) & -3;
261     if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth)
262     {
263       pDvdVideoPicture->iDisplayWidth  = pDvdVideoPicture->iWidth;
264       pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / m_aspect_ratio)) & -3;
265     }
266   }
267
268   return true;
269 }
270
271 void CDVDVideoCodecAmlogic::SetDropState(bool bDrop)
272 {
273 }
274
275 void CDVDVideoCodecAmlogic::SetSpeed(int iSpeed)
276 {
277   if (m_Codec)
278     m_Codec->SetSpeed(iSpeed);
279 }
280
281 int CDVDVideoCodecAmlogic::GetDataSize(void)
282 {
283   if (m_Codec)
284     return m_Codec->GetDataSize();
285
286   return 0;
287 }
288
289 double CDVDVideoCodecAmlogic::GetTimeSize(void)
290 {
291   if (m_Codec)
292     return m_Codec->GetTimeSize();
293
294   return 0.0;
295 }
296
297 void CDVDVideoCodecAmlogic::FrameQueuePop(void)
298 {
299   if (!m_frame_queue || m_queue_depth == 0)
300     return;
301
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;
306   m_queue_depth--;
307   pthread_mutex_unlock(&m_queue_mutex);
308
309   // and release it
310   free(top);
311 }
312
313 void CDVDVideoCodecAmlogic::FrameQueuePush(double dts, double pts)
314 {
315   frame_queue *newframe = (frame_queue*)calloc(sizeof(frame_queue), 1);
316   newframe->dts = dts;
317   newframe->pts = pts;
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))
320   {
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;
324     else
325       newframe->sort_time = newframe->pts;
326   }
327
328   pthread_mutex_lock(&m_queue_mutex);
329   frame_queue *queueWalker = m_frame_queue;
330   if (!queueWalker || (newframe->sort_time < queueWalker->sort_time))
331   {
332     // we have an empty queue, or this frame earlier than the current queue head.
333     newframe->nextframe = queueWalker;
334     m_frame_queue = newframe;
335   }
336   else
337   {
338     // walk the queue and insert this frame where it belongs in display order.
339     bool ptrInserted = false;
340     frame_queue *nextframe = NULL;
341     //
342     while (!ptrInserted)
343     {
344       nextframe = queueWalker->nextframe;
345       if (!nextframe || (newframe->sort_time < nextframe->sort_time))
346       {
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;
350         ptrInserted = true;
351       }
352       queueWalker = nextframe;
353     }
354   }
355   m_queue_depth++;
356   pthread_mutex_unlock(&m_queue_mutex); 
357 }
358
359 void CDVDVideoCodecAmlogic::FrameRateTracking(uint8_t *pData, int iSize, double dts, double pts)
360 {
361   // mpeg2 handling
362   if (m_mpeg2_sequence)
363   {
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))
367     {
368       m_mpeg2_sequence_pts = pts;
369       if (m_mpeg2_sequence_pts == DVD_NOPTS_VALUE)
370         m_mpeg2_sequence_pts = dts;
371
372       m_framerate = m_mpeg2_sequence->rate;
373       m_video_rate = (int)(0.5 + (96000.0 / m_framerate));
374
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);
377
378       // update m_hints for 1st frame fixup.
379       switch(m_mpeg2_sequence->rate_info)
380       {
381         default:
382         case 0x01:
383           m_hints.rfpsrate = 24000.0;
384           m_hints.rfpsscale = 1001.0;
385           break;
386         case 0x02:
387           m_hints.rfpsrate = 24000.0;
388           m_hints.rfpsscale = 1000.0;
389           break;
390         case 0x03:
391           m_hints.rfpsrate = 25000.0;
392           m_hints.rfpsscale = 1000.0;
393           break;
394         case 0x04:
395           m_hints.rfpsrate = 30000.0;
396           m_hints.rfpsscale = 1001.0;
397           break;
398         case 0x05:
399           m_hints.rfpsrate = 30000.0;
400           m_hints.rfpsscale = 1000.0;
401           break;
402         case 0x06:
403           m_hints.rfpsrate = 50000.0;
404           m_hints.rfpsscale = 1000.0;
405           break;
406         case 0x07:
407           m_hints.rfpsrate = 60000.0;
408           m_hints.rfpsscale = 1001.0;
409           break;
410         case 0x08:
411           m_hints.rfpsrate = 60000.0;
412           m_hints.rfpsscale = 1000.0;
413           break;
414       }
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;
420     }
421     return;
422   }
423
424   // everything else
425   FrameQueuePush(dts, pts);
426
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)
430   {
431     pthread_mutex_lock(&m_queue_mutex);
432
433     float cur_pts = m_frame_queue->pts;
434     if (cur_pts == DVD_NOPTS_VALUE)
435       cur_pts = m_frame_queue->dts;
436
437     pthread_mutex_unlock(&m_queue_mutex);       
438
439     float duration = cur_pts - m_last_pts;
440     m_last_pts = cur_pts;
441
442     // clamp duration to sensible range,
443     // 66 fsp to 20 fsp
444     if (duration >= 15000.0 && duration <= 50000.0)
445     {
446       double framerate;
447       switch((int)(0.5 + duration))
448       {
449         // 59.940 (16683.333333)
450         case 16000 ... 17000:
451           framerate = 60000.0 / 1001.0;
452           break;
453
454         // 50.000 (20000.000000)
455         case 20000:
456           framerate = 50000.0 / 1000.0;
457           break;
458
459         // 49.950 (20020.000000)
460         case 20020:
461           framerate = 50000.0 / 1001.0;
462           break;
463
464         // 29.970 (33366.666656)
465         case 32000 ... 35000:
466           framerate = 30000.0 / 1001.0;
467           break;
468
469         // 25.000 (40000.000000)
470         case 40000:
471           framerate = 25000.0 / 1000.0;
472           break;
473
474         // 24.975 (40040.000000)
475         case 40040:
476           framerate = 25000.0 / 1001.0;
477           break;
478
479         /*
480         // 24.000 (41666.666666)
481         case 41667:
482           framerate = 24000.0 / 1000.0;
483           break;
484         */
485
486         // 23.976 (41708.33333)
487         case 40200 ... 43200:
488           // 23.976 seems to have the crappiest encodings :)
489           framerate = 24000.0 / 1001.0;
490           break;
491
492         default:
493           framerate = 0.0;
494           //CLog::Log(LOGDEBUG, "%s: unknown duration(%f), cur_pts(%f)",
495           //  __MODULE_NAME__, duration, cur_pts);
496           break;
497       }
498
499       if (framerate > 0.0 && (int)m_framerate != (int)framerate)
500       {
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);
505       }
506     }
507
508     FrameQueuePop();
509   }
510 }