[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / cores / omxplayer / OMXImage.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 #include "OMXImage.h"
28
29 #include "utils/log.h"
30 #include "linux/XMemUtils.h"
31
32 #include "utils/BitstreamConverter.h"
33
34 #include <sys/time.h>
35 #include <inttypes.h>
36 #include "settings/GUISettings.h"
37 #include "settings/Settings.h"
38 #include "settings/AdvancedSettings.h"
39
40 #ifdef CLASSNAME
41 #undef CLASSNAME
42 #endif
43 #define CLASSNAME "COMXImage"
44
45 #define CONTENTURI_MAXLEN 256
46
47 #define EXIF_TAG_ORIENTATION    0x0112
48
49 static CCriticalSection g_OMXSection;
50
51 COMXImage::COMXImage()
52 {
53   m_is_open       = false;
54   m_image_size    = 0;
55   m_image_buffer  = NULL;
56   m_progressive   = false;
57   m_alpha         = false;
58   m_orientation   = 0;
59   m_width         = 0;
60   m_height        = 0;
61
62   m_is_open       = false;
63   m_decoded_buffer = NULL;
64   m_encoded_buffer = NULL;
65
66   m_decoder_open  = false;
67   m_encoder_open  = false;
68
69   OMX_INIT_STRUCTURE(m_decoded_format);
70   OMX_INIT_STRUCTURE(m_encoded_format);
71   memset(&m_omx_image, 0x0, sizeof(OMX_IMAGE_PORTDEFINITIONTYPE));
72 }
73
74 COMXImage::~COMXImage()
75 {
76   Close();
77 }
78
79 void COMXImage::Close()
80 {
81   CSingleLock lock(g_OMXSection);
82
83   OMX_INIT_STRUCTURE(m_decoded_format);
84   OMX_INIT_STRUCTURE(m_encoded_format);
85   memset(&m_omx_image, 0x0, sizeof(OMX_IMAGE_PORTDEFINITIONTYPE));
86
87   if(m_image_buffer)
88     free(m_image_buffer);
89
90   m_image_buffer  = NULL;
91   m_image_size    = 0;
92   m_width         = 0;
93   m_height        = 0;
94   m_is_open       = false;
95   m_progressive   = false;
96   m_orientation   = 0;
97   m_decoded_buffer = NULL;
98   m_encoded_buffer = NULL;
99
100   if(m_decoder_open)
101   {
102     m_omx_decoder.FlushInput();
103     m_omx_decoder.FreeInputBuffers();
104     m_omx_resize.FlushOutput();
105     m_omx_resize.FreeOutputBuffers();
106
107     m_omx_tunnel_decode.Flush();
108     m_omx_tunnel_decode.Flush();
109     m_omx_tunnel_decode.Deestablish();
110     m_omx_decoder.Deinitialize();
111     m_omx_resize.Deinitialize();
112     m_decoder_open = false;
113   }
114
115   if(m_encoder_open)
116   {
117     m_omx_encoder.Deinitialize();
118     m_encoder_open = false;
119   }
120
121   m_pFile.Close();
122 }
123
124 typedef enum {      /* JPEG marker codes */
125   M_SOF0  = 0xc0,
126   M_SOF1  = 0xc1,
127   M_SOF2  = 0xc2,
128   M_SOF3  = 0xc3,
129   M_SOF5  = 0xc5,
130   M_SOF6  = 0xc6,
131   M_SOF7  = 0xc7,
132   M_JPG   = 0xc8,
133   M_SOF9  = 0xc9,
134   M_SOF10 = 0xca,
135   M_SOF11 = 0xcb,
136   M_SOF13 = 0xcd,
137   M_SOF14 = 0xce,
138   M_SOF15 = 0xcf,
139
140   M_DHT   = 0xc4,
141   M_DAC   = 0xcc,
142
143   M_RST0  = 0xd0,
144   M_RST1  = 0xd1,
145   M_RST2  = 0xd2,
146   M_RST3  = 0xd3,
147   M_RST4  = 0xd4,
148   M_RST5  = 0xd5,
149   M_RST6  = 0xd6,
150   M_RST7  = 0xd7,
151
152   M_SOI   = 0xd8,
153   M_EOI   = 0xd9,
154   M_SOS   = 0xda,
155   M_DQT   = 0xdb,
156   M_DNL   = 0xdc,
157   M_DRI   = 0xdd,
158   M_DHP   = 0xde,
159   M_EXP   = 0xdf,
160
161   M_APP0  = 0xe0,
162   M_APP1  = 0xe1,
163   M_APP2  = 0xe2,
164   M_APP3  = 0xe3,
165   M_APP4  = 0xe4,
166   M_APP5  = 0xe5,
167   M_APP6  = 0xe6,
168   M_APP7  = 0xe7,
169   M_APP8  = 0xe8,
170   M_APP9  = 0xe9,
171   M_APP10 = 0xea,
172   M_APP11 = 0xeb,
173   M_APP12 = 0xec,
174   M_APP13 = 0xed,
175   M_APP14 = 0xee,
176   M_APP15 = 0xef,
177   // extensions
178   M_JPG0  = 0xf0,
179   M_JPG1  = 0xf1,
180   M_JPG2  = 0xf2,
181   M_JPG3  = 0xf3,
182   M_JPG4  = 0xf4,
183   M_JPG5  = 0xf5,
184   M_JPG6  = 0xf6,
185   M_JPG7  = 0xf7,
186   M_JPG8  = 0xf8,
187   M_JPG9  = 0xf9,
188   M_JPG10 = 0xfa,
189   M_JPG11 = 0xfb,
190   M_JPG12 = 0xfc,
191   M_JPG13 = 0xfd,
192   M_JPG14 = 0xfe,
193   M_COM   = 0xff,
194
195   M_TEM   = 0x01,
196 } JPEG_MARKER;
197
198 OMX_IMAGE_CODINGTYPE COMXImage::GetCodingType()
199 {
200   memset(&m_omx_image, 0x0, sizeof(OMX_IMAGE_PORTDEFINITIONTYPE));
201   m_width         = 0;
202   m_height        = 0;
203   m_progressive   = false;
204   m_orientation   = 0;
205
206   m_omx_image.eCompressionFormat = OMX_IMAGE_CodingMax;
207
208   if(!m_image_size)
209     return OMX_IMAGE_CodingMax;
210
211   bits_reader_t br;
212   CBitstreamConverter::bits_reader_set( &br, m_image_buffer, m_image_size );
213
214   /* JPEG Header */
215   if(CBitstreamConverter::read_bits(&br, 16) == 0xFFD8)
216   {
217     m_omx_image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
218
219     CBitstreamConverter::read_bits(&br, 8);
220     unsigned char marker = CBitstreamConverter::read_bits(&br, 8);
221     unsigned short block_size = 0;
222     bool nMarker = false;
223
224     while(!br.oflow) {
225
226       switch(marker)
227       {
228         case M_TEM:
229         case M_DRI:
230           CBitstreamConverter::skip_bits(&br, 16);
231           continue;
232         case M_SOI:
233         case M_EOI:
234           continue;
235         
236         case M_SOS:
237         case M_DQT:
238         case M_DNL:
239         case M_DHP:
240         case M_EXP:
241
242         case M_DHT:
243
244         case M_SOF0:
245         case M_SOF1:
246         case M_SOF2:
247         case M_SOF3:
248
249         case M_SOF5:
250         case M_SOF6:
251         case M_SOF7:
252
253         case M_JPG:
254         case M_SOF9:
255         case M_SOF10:
256         case M_SOF11:
257
258         case M_SOF13:
259         case M_SOF14:
260         case M_SOF15:
261
262         case M_APP0:
263         case M_APP1:
264         case M_APP2:
265         case M_APP3:
266         case M_APP4:
267         case M_APP5:
268         case M_APP6:
269         case M_APP7:
270         case M_APP8:
271         case M_APP9:
272         case M_APP10:
273         case M_APP11:
274         case M_APP12:
275         case M_APP13:
276         case M_APP14:
277         case M_APP15:
278
279         case M_JPG0:
280         case M_JPG1:
281         case M_JPG2:
282         case M_JPG3:
283         case M_JPG4:
284         case M_JPG5:
285         case M_JPG6:
286         case M_JPG7:
287         case M_JPG8:
288         case M_JPG9:
289         case M_JPG10:
290         case M_JPG11:
291         case M_JPG12:
292         case M_JPG13:
293         case M_JPG14:
294         case M_COM:
295           block_size = CBitstreamConverter::read_bits(&br, 16);
296           nMarker = true;
297           break;
298
299         default:
300           nMarker = false;
301           break;
302       }
303
304       if(!nMarker)
305       {
306         break;
307       }
308
309       if(marker >= M_SOF0 && marker <= M_SOF15 && marker != M_DHT && marker != M_DAC)
310       {
311         if(marker == M_SOF2 || marker == M_SOF6 || marker == M_SOF10 || marker == M_SOF14)
312         {
313           m_progressive = true;
314         }
315         CBitstreamConverter::skip_bits(&br, 8);
316         m_omx_image.nFrameHeight = CBitstreamConverter::read_bits(&br, 16);
317         m_omx_image.nFrameWidth = CBitstreamConverter::read_bits(&br, 16);
318         CBitstreamConverter::skip_bits(&br, 8 * (block_size - 9));
319       }
320       else if(marker == M_APP1)
321       {
322         int readBits = 2;
323         bool bMotorolla = false;
324         bool bError = false;
325
326         // Exif header
327         if(CBitstreamConverter::read_bits(&br, 32) == 0x45786966)
328         {
329           CBitstreamConverter::skip_bits(&br, 8 * 2);
330           readBits += 2;
331         
332           char o1 = CBitstreamConverter::read_bits(&br, 8);
333           char o2 = CBitstreamConverter::read_bits(&br, 8);
334           readBits += 2;
335
336           /* Discover byte order */
337           if(o1 == 'M' && o2 == 'M')
338             bMotorolla = true;
339           else if(o1 == 'I' && o2 == 'I')
340             bMotorolla = false;
341           else
342             bError = true;
343         
344           CBitstreamConverter::skip_bits(&br, 8 * 2);
345           readBits += 2;
346
347           if(!bError)
348           {
349             unsigned int offset, a, b, numberOfTags, tagNumber;
350   
351             // Get first IFD offset (offset to IFD0)
352             if(bMotorolla)
353             {
354               CBitstreamConverter::skip_bits(&br, 8 * 2);
355               readBits += 2;
356
357               a = CBitstreamConverter::read_bits(&br, 8);
358               b = CBitstreamConverter::read_bits(&br, 8);
359               readBits += 2;
360               offset = (a << 8) + b;
361             }
362             else
363             {
364               a = CBitstreamConverter::read_bits(&br, 8);
365               b = CBitstreamConverter::read_bits(&br, 8);
366               readBits += 2;
367               offset = (b << 8) + a;
368
369               CBitstreamConverter::skip_bits(&br, 8 * 2);
370               readBits += 2;
371             }
372
373             offset -= 8;
374             if(offset > 0)
375             {
376               CBitstreamConverter::skip_bits(&br, 8 * offset);
377               readBits += offset;
378             } 
379
380             // Get the number of directory entries contained in this IFD
381             if(bMotorolla)
382             {
383               a = CBitstreamConverter::read_bits(&br, 8);
384               b = CBitstreamConverter::read_bits(&br, 8);
385               numberOfTags = (a << 8) + b;
386             }
387             else
388             {
389               a = CBitstreamConverter::read_bits(&br, 8);
390               b = CBitstreamConverter::read_bits(&br, 8);
391               numberOfTags = (b << 8) + a;
392             }
393             readBits += 2;
394
395             while(numberOfTags && !br.oflow)
396             {
397               // Get Tag number
398               if(bMotorolla)
399               {
400                 a = CBitstreamConverter::read_bits(&br, 8);
401                 b = CBitstreamConverter::read_bits(&br, 8);
402                 tagNumber = (a << 8) + b;
403                 readBits += 2;
404               }
405               else
406               {
407                 a = CBitstreamConverter::read_bits(&br, 8);
408                 b = CBitstreamConverter::read_bits(&br, 8);
409                 tagNumber = (b << 8) + a;
410                 readBits += 2;
411               }
412
413               //found orientation tag
414               if(tagNumber == EXIF_TAG_ORIENTATION)
415               {
416                 if(bMotorolla)
417                 {
418                   CBitstreamConverter::skip_bits(&br, 8 * 7);
419                   readBits += 7;
420                   m_orientation = CBitstreamConverter::read_bits(&br, 8);
421                   readBits += 1;
422                   CBitstreamConverter::skip_bits(&br, 8 * 2);
423                   readBits += 2;
424                 }
425                 else
426                 {
427                   CBitstreamConverter::skip_bits(&br, 8 * 6);
428                   readBits += 6;
429                   m_orientation = CBitstreamConverter::read_bits(&br, 8);
430                   readBits += 1;
431                   CBitstreamConverter::skip_bits(&br, 8 * 3);
432                   readBits += 3;
433                 }
434                 break;
435               }
436               else
437               {
438                 CBitstreamConverter::skip_bits(&br, 8 * 10);
439                 readBits += 10;
440               }
441               numberOfTags--;
442             }
443           }
444         }
445         readBits += 4;
446         CBitstreamConverter::skip_bits(&br, 8 * (block_size - readBits));
447       }
448       else
449       {
450         CBitstreamConverter::skip_bits(&br, 8 * (block_size - 2));
451       }
452
453       CBitstreamConverter::read_bits(&br, 8);
454       marker = CBitstreamConverter::read_bits(&br, 8);
455
456     }
457
458   }
459
460   CBitstreamConverter::bits_reader_set( &br, m_image_buffer, m_image_size );
461
462   /* PNG Header */
463   if(CBitstreamConverter::read_bits(&br, 32) == 0x89504E47)
464   {
465     m_omx_image.eCompressionFormat = OMX_IMAGE_CodingPNG;
466     CBitstreamConverter::skip_bits(&br, 32 * 2);
467     if(CBitstreamConverter::read_bits(&br, 32) == 0x49484452)
468     {
469       m_omx_image.nFrameWidth = CBitstreamConverter::read_bits(&br, 32);
470       m_omx_image.nFrameHeight = CBitstreamConverter::read_bits(&br, 32);
471       (void)CBitstreamConverter::read_bits(&br, 8); // bit depth
472       unsigned int coding_type = CBitstreamConverter::read_bits(&br, 8);
473       m_alpha = coding_type==4 || coding_type==6;
474     }
475   }
476
477   if(m_orientation > 8)
478     m_orientation = 0;
479
480   m_width  = m_omx_image.nFrameWidth;
481   m_height = m_omx_image.nFrameHeight;
482
483   return m_omx_image.eCompressionFormat;
484 }
485
486 bool COMXImage::ClampLimits(unsigned int &width, unsigned int &height)
487 {
488   RESOLUTION_INFO& res_info =  g_settings.m_ResInfo[g_graphicsContext.GetVideoResolution()];
489   const bool transposed = m_orientation & 4;
490   const int gui_width  = transposed ? res_info.iHeight:res_info.iWidth;
491   const int gui_height = transposed ? res_info.iWidth:res_info.iHeight;
492   const unsigned int max_width  = min(gui_width, 2048);
493   const unsigned int max_height = min(gui_height, 2048);
494
495   if(!max_width || !max_height)
496     return false;
497
498   const float ar = (float)width/(float)height;
499   // bigger than maximum, so need to clamp
500   if (width > max_width || height > max_height) {
501     // wider than max, so clamp width first
502     if (ar > (float)max_width/(float)max_height)
503     {
504       width = max_width;
505       height = (float)max_width / ar + 0.5f;
506     // taller than max, so clamp height first
507     } else {
508       height = max_height;
509       width = (float)max_height * ar + 0.5f;
510     }
511     return true;
512   }
513
514   return false;
515 }
516
517 bool COMXImage::ReadFile(const CStdString& inputFile)
518 {
519   if(!m_pFile.Open(inputFile, 0))
520   {
521     CLog::Log(LOGERROR, "%s::%s %s not found\n", CLASSNAME, __func__, inputFile.c_str());
522     return false;
523   }
524
525   if(m_image_buffer)
526     free(m_image_buffer);
527   m_image_buffer = NULL;
528
529   m_image_size = m_pFile.GetLength();
530
531   if(!m_image_size) {
532     CLog::Log(LOGERROR, "%s::%s %s m_image_size zero\n", CLASSNAME, __func__, inputFile.c_str());
533     return false;
534   }
535   m_image_buffer = (uint8_t *)malloc(m_image_size);
536   if(!m_image_buffer) {
537     CLog::Log(LOGERROR, "%s::%s %s m_image_buffer null (%lu)\n", CLASSNAME, __func__, inputFile.c_str(), m_image_size);
538     return false;
539   }
540   
541   m_pFile.Read(m_image_buffer, m_image_size);
542
543   if(GetCodingType() != OMX_IMAGE_CodingJPEG) {
544     CLog::Log(LOGERROR, "%s::%s %s GetCodingType=0x%x\n", CLASSNAME, __func__, inputFile.c_str(), GetCodingType());
545     return false;
546   }
547
548   if(m_width < 1 || m_height < 1) {
549     CLog::Log(LOGERROR, "%s::%s %s m_width=%d m_height=%d\n", CLASSNAME, __func__, inputFile.c_str(), m_width, m_height);
550     return false;
551   }
552   ClampLimits(m_width, m_height);
553
554   m_is_open = true;
555
556   return true;
557 }
558
559 bool COMXImage::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height)
560 {
561   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
562   // on the first port settings changed event, we create the tunnel and alloc the buffer
563   if (!m_decoded_buffer)
564   {
565     OMX_PARAM_PORTDEFINITIONTYPE port_def;
566     OMX_INIT_STRUCTURE(port_def);
567
568     port_def.nPortIndex = m_omx_decoder.GetOutputPort();
569     m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
570     port_def.nPortIndex = m_omx_resize.GetInputPort();
571     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
572
573     m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
574
575     omx_err = m_omx_tunnel_decode.Establish(false);
576     if(omx_err != OMX_ErrorNone)
577     {
578       CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
579       return false;
580     }
581     omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
582     if(omx_err != OMX_ErrorNone)
583     {
584       CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
585       return false;
586     }
587
588     port_def.nPortIndex = m_omx_resize.GetOutputPort();
589     m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
590
591     port_def.nPortIndex = m_omx_resize.GetOutputPort();
592     port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
593     port_def.format.image.eColorFormat = OMX_COLOR_Format32bitARGB8888;
594     port_def.format.image.nFrameWidth = resize_width;
595     port_def.format.image.nFrameHeight = resize_height;
596     port_def.format.image.nStride = resize_width*4;
597     port_def.format.image.nSliceHeight = 0;
598     port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
599
600     omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
601     if(omx_err != OMX_ErrorNone)
602     {
603       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
604       return false;
605     }
606
607     OMX_INIT_STRUCTURE(m_decoded_format);
608     m_decoded_format.nPortIndex = m_omx_resize.GetOutputPort();
609     omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &m_decoded_format);
610     if(omx_err != OMX_ErrorNone)
611     {
612       CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
613       return false;
614     }
615     assert(m_decoded_format.nBufferCountActual == 1);
616
617     omx_err = m_omx_resize.AllocOutputBuffers();//false, true);
618     if(omx_err != OMX_ErrorNone)
619     {
620       CLog::Log(LOGERROR, "%s::%s m_omx_resize.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
621       return false;
622     }
623     omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
624     if(omx_err != OMX_ErrorNone)
625     {
626       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
627       return false;
628     }
629
630     m_decoded_buffer = m_omx_resize.GetOutputBuffer();
631
632     if(!m_decoded_buffer)
633     {
634       CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
635       return false;
636     }
637
638     omx_err = m_omx_resize.FillThisBuffer(m_decoded_buffer);
639     if(omx_err != OMX_ErrorNone)
640      {
641       CLog::Log(LOGERROR, "%s::%s m_omx_resize FillThisBuffer result(0x%x)\n", CLASSNAME, __func__, omx_err);
642       return false;
643     }
644   }
645   // on subsequent port settings changed event, we just copy the port settings
646   else
647   {
648     // a little surprising, make a note
649     CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
650     m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
651     m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
652
653     OMX_PARAM_PORTDEFINITIONTYPE port_def;
654     OMX_INIT_STRUCTURE(port_def);
655
656     port_def.nPortIndex = m_omx_decoder.GetOutputPort();
657     m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
658     port_def.nPortIndex = m_omx_resize.GetInputPort();
659     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
660
661     omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
662     if(omx_err != OMX_ErrorNone)
663     {
664       CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
665       return false;
666     }
667     m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
668     m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
669   }
670   return true;
671 }
672
673 bool COMXImage::Decode(unsigned width, unsigned height)
674 {
675   CSingleLock lock(g_OMXSection);
676   std::string componentName = "";
677   unsigned int demuxer_bytes = 0;
678   const uint8_t *demuxer_content = NULL;
679   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
680   OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
681
682   if(!m_image_buffer)
683   {
684     CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
685     return false;
686   }
687
688   if(GetCompressionFormat() == OMX_IMAGE_CodingMax)
689   {
690     CLog::Log(LOGERROR, "%s::%s error unsupported image format\n", CLASSNAME, __func__);
691     return false;
692   }
693
694   if(IsProgressive())
695   {
696     CLog::Log(LOGWARNING, "%s::%s progressive images not supported by decoder\n", CLASSNAME, __func__);
697     return false;
698   }
699
700   if(!m_is_open)
701   {
702     CLog::Log(LOGERROR, "%s::%s error not opened\n", CLASSNAME, __func__);
703     return false;
704   }
705
706   componentName = "OMX.broadcom.image_decode";
707   if(!m_omx_decoder.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
708   {
709     CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize\n", CLASSNAME, __func__);
710     return false;
711   }
712
713   componentName = "OMX.broadcom.resize";
714   if(!m_omx_resize.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
715   {
716     CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
717     return false;
718   }
719
720   m_decoder_open = true;
721
722   if(width == 0 || height == 0)
723   {
724     height = g_advancedSettings.m_imageRes;
725     if (g_advancedSettings.m_fanartRes > g_advancedSettings.m_imageRes)
726     { // a separate fanart resolution is specified - check if the image is exactly equal to this res
727       if (m_width == (unsigned int)g_advancedSettings.m_fanartRes * 16/9 &&
728           m_height == (unsigned int)g_advancedSettings.m_fanartRes)
729       { // special case for fanart res
730         height = g_advancedSettings.m_fanartRes;
731       }
732     }
733     width = height * 16/9;
734     if(!width || !height)
735     {
736       width = g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution].iWidth;
737       height = g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution].iHeight;
738     }
739   }
740
741   ClampLimits(width, height);
742
743   // set input format
744   OMX_IMAGE_PARAM_PORTFORMATTYPE imagePortFormat;
745   OMX_INIT_STRUCTURE(imagePortFormat);
746   imagePortFormat.nPortIndex = m_omx_decoder.GetInputPort();
747   imagePortFormat.eCompressionFormat = OMX_IMAGE_CodingJPEG;
748
749   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamImagePortFormat, &imagePortFormat);
750   if(omx_err != OMX_ErrorNone)
751   {
752     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter OMX_IndexParamImagePortFormat result(0x%x)\n", CLASSNAME, __func__, omx_err);
753     return false;
754   }
755
756   omx_err = m_omx_decoder.AllocInputBuffers();
757   if(omx_err != OMX_ErrorNone)
758   {
759     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
760     return false;
761   }
762
763   omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
764   if (omx_err != OMX_ErrorNone)
765   {
766     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
767     return false;
768   }
769
770   demuxer_bytes   = GetImageSize();
771   demuxer_content = GetImageBuffer();
772   if(!demuxer_bytes || !demuxer_content)
773     return false;
774
775   while(demuxer_bytes > 0 || !m_decoded_buffer)
776   {
777     long timeout = 0;
778     if (demuxer_bytes)
779     {
780        omx_buffer = m_omx_decoder.GetInputBuffer(1000);
781        if(omx_buffer == NULL)
782          return false;
783
784        omx_buffer->nOffset = omx_buffer->nFlags  = 0;
785
786        omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
787        memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
788
789        demuxer_content += omx_buffer->nFilledLen;
790        demuxer_bytes -= omx_buffer->nFilledLen;
791
792        if(demuxer_bytes == 0)
793          omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
794
795        omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
796        if (omx_err != OMX_ErrorNone)
797        {
798          CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
799          return false;
800        }
801     }
802     else
803     {
804        // we've submitted all buffers so can wait now
805        timeout = 1000;
806     }
807     omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
808     if(omx_err == OMX_ErrorNone)
809     {
810       if (!HandlePortSettingChange(width, height))
811       {
812         CLog::Log(LOGERROR, "%s::%s HandlePortSettingChange() failed\n", CLASSNAME, __func__);
813         return false;
814       }
815     }
816     // we treat it as an error if a real timeout occurred
817     else  if (timeout)
818     {
819       CLog::Log(LOGERROR, "%s::%s HandlePortSettingChange() failed\n", CLASSNAME, __func__);
820       return false;
821     }
822   }
823
824   omx_err = m_omx_decoder.WaitForEvent(OMX_EventBufferFlag, 1000);
825   if(omx_err != OMX_ErrorNone)
826   {
827     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.WaitForEvent result(0x%x)\n", CLASSNAME, __func__, omx_err);
828     return false;
829   }
830
831   m_omx_tunnel_decode.Deestablish();
832
833   if(m_omx_decoder.BadState())
834     return false;
835
836   return true;
837 }
838
839
840 bool COMXImage::Encode(unsigned char *buffer, int size, unsigned width, unsigned height, unsigned int pitch)
841 {
842   CSingleLock lock(g_OMXSection);
843
844   std::string componentName = "";
845   unsigned int demuxer_bytes = 0;
846   const uint8_t *demuxer_content = NULL;
847   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
848   OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
849   OMX_INIT_STRUCTURE(m_encoded_format);
850
851   if (pitch == 0)
852      pitch = 4 * width;
853
854   if (!buffer || !size) 
855   {
856     CLog::Log(LOGERROR, "%s::%s error no buffer\n", CLASSNAME, __func__);
857     return false;
858   }
859
860   componentName = "OMX.broadcom.image_encode";
861   if(!m_omx_encoder.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
862   {
863     CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
864     return false;
865   }
866
867   m_encoder_open = true;
868
869   OMX_PARAM_PORTDEFINITIONTYPE port_def;
870   OMX_INIT_STRUCTURE(port_def);
871   port_def.nPortIndex = m_omx_encoder.GetInputPort();
872
873   omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
874   if(omx_err != OMX_ErrorNone)
875   {
876     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
877     return false;
878   }
879
880   port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
881   port_def.format.image.eColorFormat = OMX_COLOR_Format32bitARGB8888;
882   port_def.format.image.nFrameWidth = width;
883   port_def.format.image.nFrameHeight = height;
884   port_def.format.image.nStride = pitch;
885   port_def.format.image.nSliceHeight = (height+15) & ~15;
886   port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
887
888   omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
889   if(omx_err != OMX_ErrorNone)
890   {
891     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
892     return false;
893   }
894
895   OMX_INIT_STRUCTURE(port_def);
896   port_def.nPortIndex = m_omx_encoder.GetOutputPort();
897
898   omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
899   if(omx_err != OMX_ErrorNone)
900   {
901     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
902     return false;
903   }
904
905   port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
906   port_def.format.image.eColorFormat = OMX_COLOR_FormatUnused;
907   port_def.format.image.nFrameWidth = width;
908   port_def.format.image.nFrameHeight = height;
909   port_def.format.image.nStride = 0;
910   port_def.format.image.nSliceHeight = 0;
911   port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
912
913   omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
914   if(omx_err != OMX_ErrorNone)
915   {
916     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
917     return false;
918   }
919
920   OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
921   OMX_INIT_STRUCTURE(qfactor);
922   qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
923   qfactor.nQFactor = 16;
924
925   omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
926   if(omx_err != OMX_ErrorNone)
927   {
928     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
929     return false;
930   }
931
932   omx_err = m_omx_encoder.AllocInputBuffers();
933   if(omx_err != OMX_ErrorNone)
934   {
935     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
936     return false;
937   }
938
939   omx_err = m_omx_encoder.AllocOutputBuffers();
940   if(omx_err != OMX_ErrorNone)
941   {
942     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
943     return false;
944   }
945
946   omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
947   if (omx_err != OMX_ErrorNone)
948   {
949     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
950     return false;
951   }
952
953   demuxer_content = buffer;
954   demuxer_bytes   = height * pitch;
955
956   if(!demuxer_bytes || !demuxer_content)
957     return false;
958
959   while(demuxer_bytes > 0)
960   {
961     omx_buffer = m_omx_encoder.GetInputBuffer(1000);
962     if(omx_buffer == NULL)
963     {
964       return false;
965     }
966
967     omx_buffer->nOffset = omx_buffer->nFlags  = 0;
968
969     omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
970     memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
971
972     demuxer_content += omx_buffer->nFilledLen;
973     demuxer_bytes -= omx_buffer->nFilledLen;
974
975     if(demuxer_bytes == 0)
976       omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
977
978     omx_err = m_omx_encoder.EmptyThisBuffer(omx_buffer);
979     if (omx_err != OMX_ErrorNone)
980     {
981       CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
982       break;
983     }
984   }
985
986   m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
987
988   if(!m_encoded_buffer)
989   {
990     CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
991     return false;
992   }
993
994   omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
995   if(omx_err != OMX_ErrorNone)
996     return false;
997
998   omx_err = m_omx_encoder.WaitForEvent(OMX_EventBufferFlag, 1000);
999   if(omx_err != OMX_ErrorNone)
1000   {
1001     CLog::Log(LOGERROR, "%s::%s m_omx_encoder WaitForEvent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1002     return false;
1003   }
1004
1005   m_encoded_format.nPortIndex = m_omx_encoder.GetOutputPort();
1006   omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &m_encoded_format);
1007   if(omx_err != OMX_ErrorNone)
1008   {
1009     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1010     return false;
1011   }
1012
1013   if(m_omx_encoder.BadState())
1014     return false;
1015
1016   return true;
1017 }
1018
1019 unsigned char *COMXImage::GetDecodedData()
1020 {
1021   if(!m_decoded_buffer)
1022     return NULL;
1023
1024   return (unsigned char *)m_decoded_buffer->pBuffer;
1025 }
1026
1027 unsigned int COMXImage::GetDecodedSize()
1028 {
1029   if(!m_decoded_buffer)
1030     return 0;
1031   return (unsigned int)m_decoded_buffer->nFilledLen;
1032 }
1033
1034 unsigned char *COMXImage::GetEncodedData()
1035 {
1036   if(!m_encoded_buffer)
1037     return NULL;
1038
1039   return (unsigned char *)m_encoded_buffer->pBuffer;
1040 }
1041
1042 unsigned int COMXImage::GetEncodedSize()
1043 {
1044   if(!m_encoded_buffer)
1045     return 0;
1046   return (unsigned int)m_encoded_buffer->nFilledLen;
1047 }
1048
1049 bool COMXImage::SwapBlueRed(unsigned char *pixels, unsigned int height, unsigned int pitch, 
1050   unsigned int elements, unsigned int offset)
1051 {
1052   if (!pixels) return false;
1053   unsigned char *dst = pixels;
1054   for (unsigned int y = 0; y < height; y++)
1055   {
1056     dst = pixels + (y * pitch);
1057     for (unsigned int x = 0; x < pitch; x+=elements)
1058       std::swap(dst[x+offset], dst[x+2+offset]);
1059   }
1060   return true;
1061 }
1062
1063 bool COMXImage::CreateThumbnail(const CStdString& sourceFile, const CStdString& destFile, 
1064     int minx, int miny, bool rotateExif)
1065 {
1066   if (!ReadFile(sourceFile))
1067     return false;
1068
1069   return CreateThumbnailFromMemory(m_image_buffer, m_image_size, destFile, minx, miny);
1070 }
1071
1072 bool COMXImage::CreateThumbnailFromMemory(unsigned char* buffer, unsigned int bufSize, const CStdString& destFile, 
1073     unsigned int minx, unsigned int miny)
1074 {
1075   if(!bufSize || !buffer)
1076     return false;
1077
1078   if(!m_is_open)
1079   {
1080     m_image_size = bufSize;
1081     m_image_buffer = (uint8_t *)malloc(m_image_size);
1082     if(!m_image_buffer)
1083       return false;
1084
1085     memcpy(m_image_buffer, buffer, m_image_size);
1086
1087     if(GetCodingType() != OMX_IMAGE_CodingJPEG) {
1088       CLog::Log(LOGERROR, "%s::%s : %s GetCodingType()=0x%x\n", CLASSNAME, __func__, destFile.c_str(), GetCodingType());
1089       return false;
1090     }
1091     m_is_open = true;
1092   }
1093
1094   if(!Decode(minx, miny))
1095     return false;
1096
1097   return CreateThumbnailFromSurface(GetDecodedData(), GetDecodedWidth(), GetDecodedHeight(), 
1098     XB_FMT_A8R8G8B8, GetDecodedStride(), destFile);
1099 }
1100
1101 bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height, 
1102     unsigned int format, unsigned int pitch, const CStdString& destFile)
1103 {
1104   if(format != XB_FMT_A8R8G8B8 || !buffer) {
1105     CLog::Log(LOGDEBUG, "%s::%s : %s failed format=0x%x\n", CLASSNAME, __func__, destFile.c_str(), format);
1106     return false;
1107   }
1108
1109   if(!Encode(buffer, height * pitch, width, height, pitch)) {
1110     CLog::Log(LOGDEBUG, "%s::%s : %s encode failed\n", CLASSNAME, __func__, destFile.c_str());
1111     return false;
1112   }
1113
1114   XFILE::CFile file;
1115   if (file.OpenForWrite(destFile, true))
1116   {
1117     CLog::Log(LOGDEBUG, "%s::%s : %s width %d height %d\n", CLASSNAME, __func__, destFile.c_str(), width, height);
1118
1119     file.Write(GetEncodedData(), GetEncodedSize());
1120     file.Close();
1121     return true;
1122   }
1123
1124   return false;
1125 }