backport 569648f2a3b8e094c33d102edd41397ca04b07be into dharma 10.1 (because git maste...
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / DVDCodecUtils.cpp
1 /*
2  *      Copyright (C) 2005-2008 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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "DVDCodecUtils.h"
23 #include "cores/VideoRenderers/RenderManager.h"
24 #include "utils/log.h"
25 #include "utils/fastmemcpy.h"
26 #include "../Codecs/DllSwScale.h"
27 #include "../Codecs/DllAvCodec.h"
28
29 // allocate a new picture (PIX_FMT_YUV420P)
30 DVDVideoPicture* CDVDCodecUtils::AllocatePicture(int iWidth, int iHeight)
31 {
32   DVDVideoPicture* pPicture = new DVDVideoPicture;
33   if (pPicture)
34   {
35     pPicture->iWidth = iWidth;
36     pPicture->iHeight = iHeight;
37
38     int w = iWidth / 2;
39     int h = iHeight / 2;
40     int size = w * h;
41     int totalsize = (iWidth * iHeight) + size * 2;
42     BYTE* data = new BYTE[totalsize];
43     if (data)
44     {
45       pPicture->data[0] = data;
46       pPicture->data[1] = pPicture->data[0] + (iWidth * iHeight);
47       pPicture->data[2] = pPicture->data[1] + size;
48       pPicture->data[3] = NULL;
49       pPicture->iLineSize[0] = iWidth;
50       pPicture->iLineSize[1] = w;
51       pPicture->iLineSize[2] = w;
52       pPicture->iLineSize[3] = 0;
53     }
54     else
55     {
56       CLog::Log(LOGFATAL, "CDVDCodecUtils::AllocatePicture, unable to allocate new video picture, out of memory.");
57       delete pPicture;
58       pPicture = NULL;
59     }
60   }
61   return pPicture;
62 }
63
64 void CDVDCodecUtils::FreePicture(DVDVideoPicture* pPicture)
65 {
66   delete[] pPicture->data[0];
67   delete pPicture;
68 }
69
70 bool CDVDCodecUtils::CopyPicture(DVDVideoPicture* pDst, DVDVideoPicture* pSrc)
71 {
72   BYTE *s, *d;
73   int w = pSrc->iWidth;
74   int h = pSrc->iHeight;
75
76   s = pSrc->data[0];
77   d = pDst->data[0];
78
79   for (int y = 0; y < h; y++)
80   {
81     fast_memcpy(d, s, w);
82     s += pSrc->iLineSize[0];
83     d += pDst->iLineSize[0];
84   }
85
86   w >>= 1;
87   h >>= 1;
88
89   s = pSrc->data[1];
90   d = pDst->data[1];
91   for (int y = 0; y < h; y++)
92   {
93     fast_memcpy(d, s, w);
94     s += pSrc->iLineSize[1];
95     d += pDst->iLineSize[1];
96   }
97
98   s = pSrc->data[2];
99   d = pDst->data[2];
100   for (int y = 0; y < h; y++)
101   {
102     fast_memcpy(d, s, w);
103     s += pSrc->iLineSize[2];
104     d += pDst->iLineSize[2];
105   }
106   return true;
107 }
108
109 bool CDVDCodecUtils::CopyPicture(YV12Image* pImage, DVDVideoPicture *pSrc)
110 {
111   BYTE *s = pSrc->data[0];
112   BYTE *d = pImage->plane[0];
113   int w = pSrc->iWidth;
114   int h = pSrc->iHeight;
115   if ((w == pSrc->iLineSize[0]) && ((unsigned int) pSrc->iLineSize[0] == pImage->stride[0]))
116   {
117     fast_memcpy(d, s, w*h);
118   }
119   else
120   {
121     for (int y = 0; y < h; y++)
122     {
123       fast_memcpy(d, s, w);
124       s += pSrc->iLineSize[0];
125       d += pImage->stride[0];
126     }
127   }
128   s = pSrc->data[1];
129   d = pImage->plane[1];
130   w = pSrc->iWidth >> 1;
131   h = pSrc->iHeight >> 1;
132   if ((w==pSrc->iLineSize[1]) && ((unsigned int) pSrc->iLineSize[1]==pImage->stride[1]))
133   {
134     fast_memcpy(d, s, w*h);
135   }
136   else
137   {
138     for (int y = 0; y < h; y++)
139     {
140       fast_memcpy(d, s, w);
141       s += pSrc->iLineSize[1];
142       d += pImage->stride[1];
143     }
144   }
145   s = pSrc->data[2];
146   d = pImage->plane[2];
147   if ((w==pSrc->iLineSize[2]) && ((unsigned int) pSrc->iLineSize[2]==pImage->stride[2]))
148   {
149     fast_memcpy(d, s, w*h);
150   }
151   else
152   {
153     for (int y = 0; y < h; y++)
154     {
155       fast_memcpy(d, s, w);
156       s += pSrc->iLineSize[2];
157       d += pImage->stride[2];
158     }
159   }
160   return true;
161 }
162
163 DVDVideoPicture* CDVDCodecUtils::ConvertToNV12Picture(DVDVideoPicture *pSrc)
164 {
165   // Clone a YV12 picture to new NV12 picture.
166   DVDVideoPicture* pPicture = new DVDVideoPicture;
167   if (pPicture)
168   {
169     *pPicture = *pSrc;
170
171     int w = pPicture->iWidth / 2;
172     int h = pPicture->iHeight / 2;
173     int size = w * h;
174     int totalsize = (pPicture->iWidth * pPicture->iHeight) + size * 2;
175     BYTE* data = new BYTE[totalsize];
176     if (data)
177     {
178       pPicture->data[0] = data;
179       pPicture->data[1] = pPicture->data[0] + (pPicture->iWidth * pPicture->iHeight);
180       pPicture->data[2] = NULL;
181       pPicture->data[3] = NULL;
182       pPicture->iLineSize[0] = pPicture->iWidth;
183       pPicture->iLineSize[1] = pPicture->iWidth;
184       pPicture->iLineSize[2] = 0;
185       pPicture->iLineSize[3] = 0;
186       pPicture->format = DVDVideoPicture::FMT_NV12;
187       
188       // copy luma
189       uint8_t *s = pSrc->data[0];
190       uint8_t *d = pPicture->data[0];
191       for (int y = 0; y < (int)pSrc->iHeight; y++)
192       {
193         fast_memcpy(d, s, pSrc->iWidth);
194         s += pSrc->iLineSize[0];
195         d += pPicture->iLineSize[0];
196       }
197
198       //copy chroma
199       uint8_t *s_u, *s_v, *d_uv;
200       for (int y = 0; y < (int)pSrc->iHeight/2; y++) {
201         s_u = pSrc->data[1] + (y * pSrc->iLineSize[1]);
202         s_v = pSrc->data[2] + (y * pSrc->iLineSize[2]);
203         d_uv = pPicture->data[1] + (y * pPicture->iLineSize[1]);
204         for (int x = 0; x < (int)pSrc->iWidth/2; x++) {
205           *d_uv++ = *s_u++;
206           *d_uv++ = *s_v++;
207         }
208       }
209       
210     }
211     else
212     {
213       CLog::Log(LOGFATAL, "CDVDCodecUtils::AllocateNV12Picture, unable to allocate new video picture, out of memory.");
214       delete pPicture;
215       pPicture = NULL;
216     }
217   }
218   return pPicture;
219 }
220
221 DVDVideoPicture* CDVDCodecUtils::ConvertToYUV422PackedPicture(DVDVideoPicture *pSrc, DVDVideoPicture::EFormat format)
222 {
223   // Clone a YV12 picture to new YUY2 or UYVY picture.
224   DVDVideoPicture* pPicture = new DVDVideoPicture;
225   if (pPicture)
226   {
227     *pPicture = *pSrc;
228
229     int totalsize = pPicture->iWidth * pPicture->iHeight * 2;
230     BYTE* data = new BYTE[totalsize];
231
232     if (data)
233     {
234       pPicture->data[0] = data;
235       pPicture->data[1] = NULL;
236       pPicture->data[2] = NULL;
237       pPicture->data[3] = NULL;
238       pPicture->iLineSize[0] = pPicture->iWidth * 2;
239       pPicture->iLineSize[1] = 0;
240       pPicture->iLineSize[2] = 0;
241       pPicture->iLineSize[3] = 0;
242       pPicture->format = format;
243
244       //if this is going to be used for anything else than testing the renderer
245       //the libraries should not be loaded on every function call
246       DllAvUtil   dllAvUtil;
247       DllAvCodec  dllAvCodec;
248       DllSwScale  dllSwScale;
249       if (!dllAvUtil.Load() || !dllAvCodec.Load() || !dllSwScale.Load())
250       {
251         CLog::Log(LOGERROR,"CDVDCodecUtils::ConvertToYUY2Picture - failed to load rescale libraries!");
252       }
253       else
254       {
255         // Perform the scaling.
256         uint8_t* src[] =       { pSrc->data[0],          pSrc->data[1],      pSrc->data[2],      NULL };
257         int      srcStride[] = { pSrc->iLineSize[0],     pSrc->iLineSize[1], pSrc->iLineSize[2], NULL };
258         uint8_t* dst[] =       { pPicture->data[0],      NULL,               NULL,               NULL };
259         int      dstStride[] = { pPicture->iLineSize[0], NULL,               NULL,               NULL };
260
261         int dstformat;
262         if (format == DVDVideoPicture::FMT_UYVY)
263           dstformat = PIX_FMT_UYVY422;
264         else
265           dstformat = PIX_FMT_YUYV422;
266
267         struct SwsContext *ctx = dllSwScale.sws_getContext(pSrc->iWidth, pSrc->iHeight, PIX_FMT_YUV420P,
268                                                            pPicture->iWidth, pPicture->iHeight, dstformat,
269                                                            SWS_FAST_BILINEAR | SwScaleCPUFlags(),
270                                                            NULL, NULL, NULL);
271         dllSwScale.sws_scale(ctx, src, srcStride, 0, pSrc->iHeight, dst, dstStride);
272         dllSwScale.sws_freeContext(ctx);
273       }
274     }
275     else
276     {
277       CLog::Log(LOGFATAL, "CDVDCodecUtils::ConvertToYUY2Picture, unable to allocate new video picture, out of memory.");
278       delete pPicture;
279       pPicture = NULL;
280     }
281   }
282   return pPicture;
283 }
284
285 bool CDVDCodecUtils::CopyNV12Picture(YV12Image* pImage, DVDVideoPicture *pSrc)
286 {
287   BYTE *s = pSrc->data[0];
288   BYTE *d = pImage->plane[0];
289   int w = pSrc->iWidth;
290   int h = pSrc->iHeight;
291   // Copy Y
292   if ((w == pSrc->iLineSize[0]) && ((unsigned int) pSrc->iLineSize[0] == pImage->stride[0]))
293   {
294     fast_memcpy(d, s, w*h);
295   }
296   else
297   {
298     for (int y = 0; y < h; y++)
299     {
300       fast_memcpy(d, s, w);
301       s += pSrc->iLineSize[0];
302       d += pImage->stride[0];
303     }
304   }
305   
306   s = pSrc->data[1];
307   d = pImage->plane[1];
308   w = pSrc->iWidth;
309   h = pSrc->iHeight >> 1;
310   // Copy packed UV (width is same as for Y as it's both U and V components)
311   if ((w==pSrc->iLineSize[1]) && ((unsigned int) pSrc->iLineSize[1]==pImage->stride[1]))
312   {
313     fast_memcpy(d, s, w*h);
314   }
315   else
316   {
317     for (int y = 0; y < h; y++)
318     {
319       fast_memcpy(d, s, w);
320       s += pSrc->iLineSize[1];
321       d += pImage->stride[1];
322     }
323   }
324
325   return true;
326 }
327
328 bool CDVDCodecUtils::CopyYUV422PackedPicture(YV12Image* pImage, DVDVideoPicture *pSrc)
329 {
330   BYTE *s = pSrc->data[0];
331   BYTE *d = pImage->plane[0];
332   int w = pSrc->iWidth;
333   int h = pSrc->iHeight;
334
335   // Copy YUYV
336   if ((w * 2 == pSrc->iLineSize[0]) && ((unsigned int) pSrc->iLineSize[0] == pImage->stride[0]))
337   {
338     fast_memcpy(d, s, w*h*2);
339   }
340   else
341   {
342     for (int y = 0; y < h; y++)
343     {
344       fast_memcpy(d, s, w*2);
345       s += pSrc->iLineSize[0];
346       d += pImage->stride[0];
347     }
348   }
349   
350   return true;
351 }
352