[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / DVDVideoCodecOpenMax.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://www.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 #if (defined HAVE_CONFIG_H) && (!defined WIN32)
22   #include "config.h"
23 #elif defined(_WIN32)
24 #include "system.h"
25 #endif
26
27 #if defined(HAVE_LIBOPENMAX)
28 #include "DVDClock.h"
29 #include "settings/GUISettings.h"
30 #include "DVDStreamInfo.h"
31 #include "DVDVideoCodecOpenMax.h"
32 #include "OpenMaxVideo.h"
33 #include "utils/log.h"
34
35 #define CLASSNAME "COpenMax"
36 ////////////////////////////////////////////////////////////////////////////////////////////
37 ////////////////////////////////////////////////////////////////////////////////////////////
38 CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() : CDVDVideoCodec()
39 {
40   m_omx_decoder = NULL;
41   m_pFormatName = "omx-xxxx";
42
43   m_convert_bitstream = false;
44   memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
45 }
46
47 CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax()
48 {
49   Dispose();
50 }
51
52 bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
53 {
54   // we always qualify even if DVDFactoryCodec does this too.
55   if (g_guiSettings.GetBool("videoplayer.useomx") && !hints.software)
56   {
57     m_convert_bitstream = false;
58
59     switch (hints.codec)
60     {
61       case CODEC_ID_H264:
62       {
63         m_pFormatName = "omx-h264";
64         if (hints.extrasize < 7 || hints.extradata == NULL)
65         {
66           CLog::Log(LOGNOTICE,
67             "%s::%s - avcC data too small or missing", CLASSNAME, __func__);
68           return false;
69         }
70         // valid avcC data (bitstream) always starts with the value 1 (version)
71         if ( *(char*)hints.extradata == 1 )
72           m_convert_bitstream = bitstream_convert_init(hints.extradata, hints.extrasize);
73       }
74       break;
75       case CODEC_ID_MPEG4:
76         m_pFormatName = "omx-mpeg4";
77       break;
78       case CODEC_ID_MPEG2VIDEO:
79         m_pFormatName = "omx-mpeg2";
80       break;
81       case CODEC_ID_VC1:
82         m_pFormatName = "omx-vc1";
83       break;
84       default:
85         return false;
86       break;
87     }
88
89     m_omx_decoder = new COpenMaxVideo;
90     if (!m_omx_decoder->Open(hints))
91     {
92       CLog::Log(LOGERROR,
93         "%s::%s - failed to open, codec(%d), profile(%d), level(%d)", 
94         CLASSNAME, __func__, hints.codec, hints.profile, hints.level);
95       return false;
96     }
97
98     // allocate a YV12 DVDVideoPicture buffer.
99     // first make sure all properties are reset.
100     memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
101     unsigned int luma_pixels = hints.width * hints.height;
102     unsigned int chroma_pixels = luma_pixels/4;
103
104     m_videobuffer.dts = DVD_NOPTS_VALUE;
105     m_videobuffer.pts = DVD_NOPTS_VALUE;
106     //m_videobuffer.format = RENDER_FMT_YUV420P;
107     m_videobuffer.format = RENDER_FMT_OMXEGL;
108     m_videobuffer.color_range  = 0;
109     m_videobuffer.color_matrix = 4;
110     m_videobuffer.iFlags  = DVP_FLAG_ALLOCATED;
111     m_videobuffer.iWidth  = hints.width;
112     m_videobuffer.iHeight = hints.height;
113     m_videobuffer.iDisplayWidth  = hints.width;
114     m_videobuffer.iDisplayHeight = hints.height;
115
116     return true;
117   }
118
119   return false;
120 }
121
122 void CDVDVideoCodecOpenMax::Dispose()
123 {
124   if (m_omx_decoder)
125   {
126     m_omx_decoder->Close();
127     delete m_omx_decoder;
128     m_omx_decoder = NULL;
129   }
130   if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED)
131   {
132     m_videobuffer.iFlags = 0;
133   }
134   if (m_convert_bitstream)
135   {
136     if (m_sps_pps_context.sps_pps_data)
137     {
138       free(m_sps_pps_context.sps_pps_data);
139       m_sps_pps_context.sps_pps_data = NULL;
140     }
141   }
142 }
143
144 void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
145 {
146   m_omx_decoder->SetDropState(bDrop);
147 }
148
149 int CDVDVideoCodecOpenMax::Decode(BYTE* pData, int iSize, double dts, double pts)
150 {
151   if (pData)
152   {
153     int rtn;
154     int demuxer_bytes = iSize;
155     uint8_t *demuxer_content = pData;
156     bool bitstream_convered  = false;
157
158     if (m_convert_bitstream)
159     {
160       // convert demuxer packet from bitstream to bytestream (AnnexB)
161       int bytestream_size = 0;
162       uint8_t *bytestream_buff = NULL;
163
164       bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size);
165       if (bytestream_buff && (bytestream_size > 0))
166       {
167         bitstream_convered = true;
168         demuxer_bytes = bytestream_size;
169         demuxer_content = bytestream_buff;
170       }
171     }
172
173     rtn = m_omx_decoder->Decode(demuxer_content, demuxer_bytes, dts, pts);
174
175     if (bitstream_convered)
176       free(demuxer_content);
177
178     return rtn;
179   }
180   
181   return VC_BUFFER;
182 }
183
184 void CDVDVideoCodecOpenMax::Reset(void)
185 {
186   m_omx_decoder->Reset();
187 }
188
189 bool CDVDVideoCodecOpenMax::GetPicture(DVDVideoPicture* pDvdVideoPicture)
190 {
191   m_omx_decoder->GetPicture(&m_videobuffer);
192   *pDvdVideoPicture = m_videobuffer;
193
194   return VC_PICTURE | VC_BUFFER;
195 }
196
197 ////////////////////////////////////////////////////////////////////////////////////////////
198 bool CDVDVideoCodecOpenMax::bitstream_convert_init(void *in_extradata, int in_extrasize)
199 {
200   // based on h264_mp4toannexb_bsf.c (ffmpeg)
201   // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
202   // and Licensed GPL 2.1 or greater
203
204   m_sps_pps_size = 0;
205   m_sps_pps_context.sps_pps_data = NULL;
206   
207   // nothing to filter
208   if (!in_extradata || in_extrasize < 6)
209     return false;
210
211   uint16_t unit_size;
212   uint32_t total_size = 0;
213   uint8_t *out = NULL, unit_nb, sps_done = 0;
214   const uint8_t *extradata = (uint8_t*)in_extradata + 4;
215   static const uint8_t nalu_header[4] = {0, 0, 0, 1};
216
217   // retrieve length coded size
218   m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1;
219   if (m_sps_pps_context.length_size == 3)
220     return false;
221
222   // retrieve sps and pps unit(s)
223   unit_nb = *extradata++ & 0x1f;  // number of sps unit(s)
224   if (!unit_nb)
225   {
226     unit_nb = *extradata++;       // number of pps unit(s)
227     sps_done++;
228   }
229   while (unit_nb--)
230   {
231     unit_size = extradata[0] << 8 | extradata[1];
232     total_size += unit_size + 4;
233     if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) )
234     {
235       free(out);
236       return false;
237     }
238     out = (uint8_t*)realloc(out, total_size);
239     if (!out)
240       return false;
241
242     memcpy(out + total_size - unit_size - 4, nalu_header, 4);
243     memcpy(out + total_size - unit_size, extradata + 2, unit_size);
244     extradata += 2 + unit_size;
245
246     if (!unit_nb && !sps_done++)
247       unit_nb = *extradata++;     // number of pps unit(s)
248   }
249
250   m_sps_pps_context.sps_pps_data = out;
251   m_sps_pps_context.size = total_size;
252   m_sps_pps_context.first_idr = 1;
253
254   return true;
255 }
256
257 bool CDVDVideoCodecOpenMax::bitstream_convert(BYTE* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size)
258 {
259   // based on h264_mp4toannexb_bsf.c (ffmpeg)
260   // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
261   // and Licensed GPL 2.1 or greater
262
263   uint8_t *buf = pData;
264   uint32_t buf_size = iSize;
265   uint8_t  unit_type;
266   int32_t  nal_size;
267   uint32_t cumul_size = 0;
268   const uint8_t *buf_end = buf + buf_size;
269
270   do
271   {
272     if (buf + m_sps_pps_context.length_size > buf_end)
273       goto fail;
274
275     if (m_sps_pps_context.length_size == 1)
276       nal_size = buf[0];
277     else if (m_sps_pps_context.length_size == 2)
278       nal_size = buf[0] << 8 | buf[1];
279     else
280       nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
281
282     buf += m_sps_pps_context.length_size;
283     unit_type = *buf & 0x1f;
284
285     if (buf + nal_size > buf_end || nal_size < 0)
286       goto fail;
287
288     // prepend only to the first type 5 NAL unit of an IDR picture
289     if (m_sps_pps_context.first_idr && unit_type == 5)
290     {
291       bitstream_alloc_and_copy(poutbuf, poutbuf_size,
292         m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size);
293       m_sps_pps_context.first_idr = 0;
294     }
295     else
296     {
297       bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size);
298       if (!m_sps_pps_context.first_idr && unit_type == 1)
299           m_sps_pps_context.first_idr = 1;
300     }
301
302     buf += nal_size;
303     cumul_size += nal_size + m_sps_pps_context.length_size;
304   } while (cumul_size < buf_size);
305
306   return true;
307
308 fail:
309   free(*poutbuf);
310   *poutbuf = NULL;
311   *poutbuf_size = 0;
312   return false;
313 }
314
315 void CDVDVideoCodecOpenMax::bitstream_alloc_and_copy(
316   uint8_t **poutbuf,      int *poutbuf_size,
317   const uint8_t *sps_pps, uint32_t sps_pps_size,
318   const uint8_t *in,      uint32_t in_size)
319 {
320   // based on h264_mp4toannexb_bsf.c (ffmpeg)
321   // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
322   // and Licensed GPL 2.1 or greater
323
324   #define CHD_WB32(p, d) { \
325     ((uint8_t*)(p))[3] = (d); \
326     ((uint8_t*)(p))[2] = (d) >> 8; \
327     ((uint8_t*)(p))[1] = (d) >> 16; \
328     ((uint8_t*)(p))[0] = (d) >> 24; }
329
330   uint32_t offset = *poutbuf_size;
331   uint8_t nal_header_size = offset ? 3 : 4;
332
333   *poutbuf_size += sps_pps_size + in_size + nal_header_size;
334   *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size);
335   if (sps_pps)
336     memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
337
338   memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
339   if (!offset)
340   {
341     CHD_WB32(*poutbuf + sps_pps_size, 1);
342   }
343   else
344   {
345     (*poutbuf + offset + sps_pps_size)[0] = 0;
346     (*poutbuf + offset + sps_pps_size)[1] = 0;
347     (*poutbuf + offset + sps_pps_size)[2] = 1;
348   }
349 }
350
351 #endif