[release] version bump to 13.0 beta1
[vuplus_xbmc] / xbmc / cores / omxplayer / OMXImage.cpp
1 /*
2  *      Copyright (C) 2010-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 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
22   #include "config.h"
23 #elif defined(TARGET_WINDOWS)
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 <sys/time.h>
33 #include <inttypes.h>
34 #include "guilib/GraphicContext.h"
35 #include "settings/AdvancedSettings.h"
36 #include "settings/DisplaySettings.h"
37 #include "settings/Settings.h"
38 #include "linux/RBP.h"
39 #include "utils/URIUtils.h"
40 #include "windowing/WindowingFactory.h"
41 #include "Application.h"
42
43 #ifdef _DEBUG
44 #define CheckError() m_result = eglGetError(); if (m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
45 #else
46 #define CheckError()
47 #endif
48
49 #define EXIF_TAG_ORIENTATION    0x0112
50
51
52 #ifdef CLASSNAME
53 #undef CLASSNAME
54 #endif
55 #define CLASSNAME "COMXImage"
56
57 COMXImage::COMXImage()
58 : CThread("CRBPWorker")
59 {
60 }
61
62 COMXImage::~COMXImage()
63 {
64   Deinitialize();
65 }
66
67 void COMXImage::Initialize()
68 {
69   Create();
70 }
71
72 void COMXImage::Deinitialize()
73 {
74   // wake up thread so it can quit
75   {
76     CSingleLock lock(m_texqueue_lock);
77     m_bStop = true;
78     m_texqueue_cond.notifyAll();
79   }
80   if (IsRunning())
81     StopThread();
82 }
83
84 bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
85       unsigned int format, unsigned int pitch, const CStdString& destFile)
86 {
87   COMXImageEnc omxImageEnc;
88   bool ret = omxImageEnc.CreateThumbnailFromSurface(buffer, width, height, format, pitch, destFile);
89   if (!ret)
90     CLog::Log(LOGNOTICE, "%s: unable to create thumbnail %s %dx%d", __func__, destFile.c_str(), width, height);
91   return ret;
92 }
93
94 COMXImageFile *COMXImage::LoadJpeg(const CStdString& texturePath)
95 {
96   COMXImageFile *file = new COMXImageFile();
97   if (!file->ReadFile(texturePath))
98   {
99     CLog::Log(LOGNOTICE, "%s: unable to load %s", __func__, texturePath.c_str());
100     delete file;
101     file = NULL;
102   }
103   return file;
104 }
105
106 void COMXImage::CloseJpeg(COMXImageFile *file)
107 {
108   delete file;
109 }
110
111 bool COMXImage::DecodeJpeg(COMXImageFile *file, unsigned int width, unsigned int height, unsigned int stride, void *pixels)
112 {
113   bool ret = false;
114   COMXImageDec omx_image;
115   if (omx_image.Decode(file->GetImageBuffer(), file->GetImageSize(), width, height, stride, pixels))
116   {
117     assert(width  == omx_image.GetDecodedWidth());
118     assert(height == omx_image.GetDecodedHeight());
119     assert(stride == omx_image.GetDecodedStride());
120     ret = true;
121   }
122   else
123     CLog::Log(LOGNOTICE, "%s: unable to decode %s %dx%d", __func__, file->GetFilename(), width, height);
124   omx_image.Close();
125   return ret;
126 }
127
128 bool COMXImage::ClampLimits(unsigned int &width, unsigned int &height, unsigned int m_width, unsigned int m_height, bool transposed)
129 {
130   RESOLUTION_INFO& res_info = CDisplaySettings::Get().GetResolutionInfo(g_graphicsContext.GetVideoResolution());
131   unsigned int max_width = width;
132   unsigned int max_height = height;
133   const unsigned int gui_width = transposed ? res_info.iHeight:res_info.iWidth;
134   const unsigned int gui_height = transposed ? res_info.iWidth:res_info.iHeight;
135   const float aspect = (float)m_width / m_height;
136   bool clamped = false;
137
138   if (max_width == 0 || max_height == 0)
139   {
140     max_height = g_advancedSettings.m_imageRes;
141
142     if (g_advancedSettings.m_fanartRes > g_advancedSettings.m_imageRes)
143     { // 16x9 images larger than the fanart res use that rather than the image res
144       if (fabsf(aspect / (16.0f/9.0f) - 1.0f) <= 0.01f && m_height >= g_advancedSettings.m_fanartRes)
145       {
146         max_height = g_advancedSettings.m_fanartRes;
147       }
148     }
149     max_width = max_height * 16/9;
150   }
151
152   if (gui_width)
153     max_width = min(max_width, gui_width);
154   if (gui_height)
155     max_height = min(max_height, gui_height);
156
157   max_width  = min(max_width, 2048U);
158   max_height = min(max_height, 2048U);
159
160   width = m_width;
161   height = m_height;
162   if (width > max_width || height > max_height)
163   {
164     if ((unsigned int)(max_width / aspect + 0.5f) > max_height)
165       max_width = (unsigned int)(max_height * aspect + 0.5f);
166     else
167       max_height = (unsigned int)(max_width / aspect + 0.5f);
168     width = max_width;
169     height = max_height;
170     clamped = true;
171   }
172   // Texture.cpp wants even width/height
173   width  = (width  + 15) & ~15;
174   height = (height + 15) & ~15;
175
176   return clamped;
177 }
178
179 bool COMXImage::CreateThumb(const CStdString& srcFile, unsigned int maxHeight, unsigned int maxWidth, std::string &additional_info, const CStdString& destFile)
180 {
181   bool okay = false;
182   COMXImageFile file;
183   COMXImageReEnc reenc;
184   void *pDestBuffer;
185   unsigned int nDestSize;
186   if (URIUtils::HasExtension(srcFile, ".jpg|.tbn") && file.ReadFile(srcFile) && reenc.ReEncode(file, maxWidth, maxHeight, pDestBuffer, nDestSize))
187   {
188     XFILE::CFile outfile;
189     if (outfile.OpenForWrite(destFile, true))
190     {
191       outfile.Write(pDestBuffer, nDestSize);
192       outfile.Close();
193       okay = true;
194     }
195     else
196       CLog::Log(LOGERROR, "%s: can't open output file: %s\n", __func__, destFile.c_str());
197   }
198   return okay;
199 }
200
201 void COMXImage::AllocTextureInternal(struct textureinfo *tex)
202 {
203   glGenTextures(1, (GLuint*) &tex->texture);
204   glBindTexture(GL_TEXTURE_2D, tex->texture);
205   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
206   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
207   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
208   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
209   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
210   tex->egl_image = eglCreateImageKHR(m_egl_display, m_egl_context, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)tex->texture, NULL);
211   tex->sync.Set();
212   GLint m_result;
213   CheckError();
214 }
215
216 void COMXImage::GetTexture(void *userdata, GLuint *texture)
217 {
218   struct textureinfo *tex = static_cast<struct textureinfo *>(userdata);
219   *texture = tex->texture;
220 }
221
222 void COMXImage::DestroyTextureInternal(struct textureinfo *tex)
223 {
224   bool s = true;
225   if (!tex->egl_image || !tex->texture)
226   {
227     CLog::Log(LOGNOTICE, "%s: Invalid image/texture %p:%d", __func__, tex->egl_image, tex->texture);
228     return;
229   }
230   s = eglDestroyImageKHR(m_egl_display, tex->egl_image);
231   if (!s)
232     CLog::Log(LOGNOTICE, "%s: failed to destroy texture", __func__);
233   glDeleteTextures(1, (GLuint*) &tex->texture);
234   tex->sync.Set();
235 }
236
237 void COMXImage::DestroyTexture(void *userdata)
238 {
239   struct textureinfo *tex = static_cast<struct textureinfo *>(userdata);
240   // we can only call gl functions from the application thread
241
242   tex->action = TEXTURE_DELETE;
243   tex->sync.Reset();
244   if ( g_application.IsCurrentThread() )
245   {
246      DestroyTextureInternal(tex);
247   }
248   else
249   {
250     CSingleLock lock(m_texqueue_lock);
251     m_texqueue.push(tex);
252     m_texqueue_cond.notifyAll();
253   }
254   // wait for function to have finished (in texture thread)
255   tex->sync.Wait();
256   delete tex;
257 }
258
259 bool COMXImage::DecodeJpegToTexture(COMXImageFile *file, unsigned int width, unsigned int height, void **userdata)
260 {
261   bool ret = false;
262   COMXTexture omx_image;
263
264   struct textureinfo *tex = new struct textureinfo;
265   if (!tex)
266     return NULL;
267
268   tex->parent = (void *)this;
269   tex->width = width;
270   tex->height = height;
271   tex->texture = 0;
272   tex->egl_image = NULL;
273   tex->filename = file->GetFilename();
274   tex->action = TEXTURE_ALLOC;
275   tex->sync.Reset();
276
277   {
278     CSingleLock lock(m_texqueue_lock);
279     m_texqueue.push(tex);
280     m_texqueue_cond.notifyAll();
281   }
282
283   // wait for function to have finished (in texture thread)
284   tex->sync.Wait();
285
286   if (tex->egl_image && tex->texture && omx_image.Decode(file->GetImageBuffer(), file->GetImageSize(), width, height, tex->egl_image, m_egl_display))
287   {
288     ret = true;
289     *userdata = tex;
290   }
291   else
292   {
293     CLog::Log(LOGNOTICE, "%s: unable to decode to texture %s %dx%d", __func__, file->GetFilename(), width, height);
294     DestroyTexture(tex);
295   }
296   return ret;
297 }
298
299 static bool ChooseConfig(EGLDisplay display, const EGLint *configAttrs, EGLConfig *config)
300 {
301   EGLBoolean eglStatus = true;
302   EGLint     configCount = 0;
303   EGLConfig* configList = NULL;
304   GLint m_result;
305   // Find out how many configurations suit our needs
306   eglStatus = eglChooseConfig(display, configAttrs, NULL, 0, &configCount);
307   CheckError();
308
309   if (!eglStatus || !configCount)
310   {
311     CLog::Log(LOGERROR, "EGL failed to return any matching configurations: %i", configCount);
312     return false;
313   }
314
315   // Allocate room for the list of matching configurations
316   configList = (EGLConfig*)malloc(configCount * sizeof(EGLConfig));
317   if (!configList)
318   {
319     CLog::Log(LOGERROR, "EGL failure obtaining configuration list");
320     return false;
321   }
322
323   // Obtain the configuration list from EGL
324   eglStatus = eglChooseConfig(display, configAttrs, configList, configCount, &configCount);
325   CheckError();
326   if (!eglStatus || !configCount)
327   {
328     CLog::Log(LOGERROR, "EGL failed to populate configuration list: %d", eglStatus);
329     return false;
330   }
331
332   // Select an EGL configuration that matches the native window
333   *config = configList[0];
334
335   free(configList);
336   return true;
337 }
338
339 void COMXImage::CreateContext()
340 {
341   EGLConfig egl_config;
342   GLint m_result;
343
344   m_egl_display = g_Windowing.GetEGLDisplay();
345   eglInitialize(m_egl_display, NULL, NULL);
346   CheckError();
347   eglBindAPI(EGL_OPENGL_ES_API);
348   CheckError();
349   static const EGLint contextAttrs [] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
350   static const EGLint configAttrs [] = {
351         EGL_RED_SIZE,        8,
352         EGL_GREEN_SIZE,      8,
353         EGL_BLUE_SIZE,       8,
354         EGL_ALPHA_SIZE,      8,
355         EGL_DEPTH_SIZE,     16,
356         EGL_STENCIL_SIZE,    0,
357         EGL_SAMPLE_BUFFERS,  0,
358         EGL_SAMPLES,         0,
359         EGL_SURFACE_TYPE,    EGL_WINDOW_BIT,
360         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
361         EGL_NONE
362   };
363   bool s = ChooseConfig(m_egl_display, configAttrs, &egl_config);
364   CheckError();
365   if (!s)
366   {
367     CLog::Log(LOGERROR, "%s: Could not find a compatible configuration",__FUNCTION__);
368     return;
369   }
370   m_egl_context = eglCreateContext(m_egl_display, egl_config, g_Windowing.GetEGLContext(), contextAttrs);
371   CheckError();
372   if (m_egl_context == EGL_NO_CONTEXT)
373   {
374     CLog::Log(LOGERROR, "%s: Could not create a context",__FUNCTION__);
375     return;
376   }
377   EGLSurface egl_surface = eglCreatePbufferSurface(m_egl_display, egl_config, NULL);
378   CheckError();
379   if (egl_surface == EGL_NO_SURFACE)
380   {
381     CLog::Log(LOGERROR, "%s: Could not create a surface",__FUNCTION__);
382     return;
383   }
384   s = eglMakeCurrent(m_egl_display, egl_surface, egl_surface, m_egl_context);
385   CheckError();
386   if (!s)
387   {
388     CLog::Log(LOGERROR, "%s: Could not make current",__FUNCTION__);
389     return;
390   }
391 }
392
393 void COMXImage::Process()
394 {
395   bool firsttime = true;
396
397   while(!m_bStop)
398   {
399     struct textureinfo *tex = NULL;
400     while (!m_bStop)
401     {
402       CSingleLock lock(m_texqueue_lock);
403       if (!m_texqueue.empty())
404       {
405         tex = m_texqueue.front();
406         m_texqueue.pop();
407         break;
408       }
409       m_texqueue_cond.wait(lock);
410     }
411
412     if (m_bStop)
413       return;
414
415     if (firsttime)
416       CreateContext();
417     firsttime = false;
418
419     if (tex && tex->action == TEXTURE_ALLOC)
420       AllocTextureInternal(tex);
421     else if (tex && tex->action == TEXTURE_DELETE)
422       DestroyTextureInternal(tex);
423     else
424       CLog::Log(LOGERROR, "%s: Unexpected texture job: %p:%d", __func__, tex, tex ? tex->action : 0);
425   }
426 }
427
428 void COMXImage::OnStartup()
429 {
430 }
431
432 void COMXImage::OnExit()
433 {
434 }
435
436 #ifdef CLASSNAME
437 #undef CLASSNAME
438 #endif
439 #define CLASSNAME "COMXImageFile"
440
441 COMXImageFile::COMXImageFile()
442 {
443   m_image_size    = 0;
444   m_image_buffer  = NULL;
445   m_orientation   = 0;
446   m_width         = 0;
447   m_height        = 0;
448   m_filename      = "";
449 }
450
451 COMXImageFile::~COMXImageFile()
452 {
453   if(m_image_buffer)
454     free(m_image_buffer);
455 }
456
457 typedef enum {      /* JPEG marker codes */
458   M_SOF0  = 0xc0,
459   M_SOF1  = 0xc1,
460   M_SOF2  = 0xc2,
461   M_SOF3  = 0xc3,
462   M_SOF5  = 0xc5,
463   M_SOF6  = 0xc6,
464   M_SOF7  = 0xc7,
465   M_JPG   = 0xc8,
466   M_SOF9  = 0xc9,
467   M_SOF10 = 0xca,
468   M_SOF11 = 0xcb,
469   M_SOF13 = 0xcd,
470   M_SOF14 = 0xce,
471   M_SOF15 = 0xcf,
472
473   M_DHT   = 0xc4,
474   M_DAC   = 0xcc,
475
476   M_RST0  = 0xd0,
477   M_RST1  = 0xd1,
478   M_RST2  = 0xd2,
479   M_RST3  = 0xd3,
480   M_RST4  = 0xd4,
481   M_RST5  = 0xd5,
482   M_RST6  = 0xd6,
483   M_RST7  = 0xd7,
484
485   M_SOI   = 0xd8,
486   M_EOI   = 0xd9,
487   M_SOS   = 0xda,
488   M_DQT   = 0xdb,
489   M_DNL   = 0xdc,
490   M_DRI   = 0xdd,
491   M_DHP   = 0xde,
492   M_EXP   = 0xdf,
493
494   M_APP0  = 0xe0,
495   M_APP1  = 0xe1,
496   M_APP2  = 0xe2,
497   M_APP3  = 0xe3,
498   M_APP4  = 0xe4,
499   M_APP5  = 0xe5,
500   M_APP6  = 0xe6,
501   M_APP7  = 0xe7,
502   M_APP8  = 0xe8,
503   M_APP9  = 0xe9,
504   M_APP10 = 0xea,
505   M_APP11 = 0xeb,
506   M_APP12 = 0xec,
507   M_APP13 = 0xed,
508   M_APP14 = 0xee,
509   M_APP15 = 0xef,
510   // extensions
511   M_JPG0  = 0xf0,
512   M_JPG1  = 0xf1,
513   M_JPG2  = 0xf2,
514   M_JPG3  = 0xf3,
515   M_JPG4  = 0xf4,
516   M_JPG5  = 0xf5,
517   M_JPG6  = 0xf6,
518   M_JPG7  = 0xf7,
519   M_JPG8  = 0xf8,
520   M_JPG9  = 0xf9,
521   M_JPG10 = 0xfa,
522   M_JPG11 = 0xfb,
523   M_JPG12 = 0xfc,
524   M_JPG13 = 0xfd,
525   M_JPG14 = 0xfe,
526   M_COM   = 0xff,
527
528   M_TEM   = 0x01,
529 } JPEG_MARKER;
530
531 static uint8_t inline READ8(uint8_t * &p)
532 {
533   uint8_t r = p[0];
534   p += 1;
535   return r;
536 }
537
538 static uint16_t inline READ16(uint8_t * &p)
539 {
540   uint16_t r = (p[0] << 8) | p[1];
541   p += 2;
542   return r;
543 }
544
545 static uint32_t inline READ32(uint8_t * &p)
546 {
547   uint32_t r = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
548   p += 4;
549   return r;
550 }
551
552 static void inline SKIPN(uint8_t * &p, unsigned int n)
553 {
554   p += n;
555 }
556
557 OMX_IMAGE_CODINGTYPE COMXImageFile::GetCodingType(unsigned int &width, unsigned int &height)
558 {
559   OMX_IMAGE_CODINGTYPE eCompressionFormat = OMX_IMAGE_CodingMax;
560   bool progressive = false;
561   int components = 0;
562   m_orientation   = 0;
563
564   if(!m_image_size)
565     return OMX_IMAGE_CodingMax;
566
567   uint8_t *p = m_image_buffer;
568   uint8_t *q = m_image_buffer + m_image_size;
569
570   /* JPEG Header */
571   if(READ16(p) == 0xFFD8)
572   {
573     eCompressionFormat = OMX_IMAGE_CodingJPEG;
574
575     READ8(p);
576     unsigned char marker = READ8(p);
577     unsigned short block_size = 0;
578     bool nMarker = false;
579
580     while(p < q)
581     {
582       switch(marker)
583       {
584         case M_DQT:
585         case M_DNL:
586         case M_DHP:
587         case M_EXP:
588
589         case M_DHT:
590
591         case M_SOF0:
592         case M_SOF1:
593         case M_SOF2:
594         case M_SOF3:
595
596         case M_SOF5:
597         case M_SOF6:
598         case M_SOF7:
599
600         case M_JPG:
601         case M_SOF9:
602         case M_SOF10:
603         case M_SOF11:
604
605         case M_SOF13:
606         case M_SOF14:
607         case M_SOF15:
608
609         case M_APP0:
610         case M_APP1:
611         case M_APP2:
612         case M_APP3:
613         case M_APP4:
614         case M_APP5:
615         case M_APP6:
616         case M_APP7:
617         case M_APP8:
618         case M_APP9:
619         case M_APP10:
620         case M_APP11:
621         case M_APP12:
622         case M_APP13:
623         case M_APP14:
624         case M_APP15:
625
626         case M_JPG0:
627         case M_JPG1:
628         case M_JPG2:
629         case M_JPG3:
630         case M_JPG4:
631         case M_JPG5:
632         case M_JPG6:
633         case M_JPG7:
634         case M_JPG8:
635         case M_JPG9:
636         case M_JPG10:
637         case M_JPG11:
638         case M_JPG12:
639         case M_JPG13:
640         case M_JPG14:
641         case M_COM:
642           block_size = READ16(p);
643           nMarker = true;
644           break;
645
646         case M_SOS:
647         default:
648           nMarker = false;
649           break;
650       }
651
652       if(!nMarker)
653       {
654         break;
655       }
656
657       if(marker >= M_SOF0 && marker <= M_SOF15 && marker != M_DHT && marker != M_DAC)
658       {
659         if(marker == M_SOF2 || marker == M_SOF6 || marker == M_SOF10 || marker == M_SOF14)
660         {
661           progressive = true;
662         }
663         int readBits = 2;
664         SKIPN(p, 1);
665         readBits ++;
666         height = READ16(p);
667         readBits += 2;
668         width = READ16(p);
669         readBits += 2;
670         components = READ8(p);
671         readBits += 1;
672         SKIPN(p, 1 * (block_size - readBits));
673       }
674       else if(marker == M_APP1)
675       {
676         int readBits = 2;
677
678         // Exif header
679         if(READ32(p) == 0x45786966)
680         {
681           bool bMotorolla = false;
682           bool bError = false;
683           SKIPN(p, 1 * 2);
684           readBits += 2;
685         
686           char o1 = READ8(p);
687           char o2 = READ8(p);
688           readBits += 2;
689
690           /* Discover byte order */
691           if(o1 == 'M' && o2 == 'M')
692             bMotorolla = true;
693           else if(o1 == 'I' && o2 == 'I')
694             bMotorolla = false;
695           else
696             bError = true;
697         
698           SKIPN(p, 1 * 2);
699           readBits += 2;
700
701           if(!bError)
702           {
703             unsigned int offset, a, b, numberOfTags, tagNumber;
704   
705             // Get first IFD offset (offset to IFD0)
706             if(bMotorolla)
707             {
708               SKIPN(p, 1 * 2);
709               readBits += 2;
710
711               a = READ8(p);
712               b = READ8(p);
713               readBits += 2;
714               offset = (a << 8) + b;
715             }
716             else
717             {
718               a = READ8(p);
719               b = READ8(p);
720               readBits += 2;
721               offset = (b << 8) + a;
722
723               SKIPN(p, 1 * 2);
724               readBits += 2;
725             }
726
727             offset -= 8;
728             if(offset > 0)
729             {
730               SKIPN(p, 1 * offset);
731               readBits += offset;
732             } 
733
734             // Get the number of directory entries contained in this IFD
735             if(bMotorolla)
736             {
737               a = READ8(p);
738               b = READ8(p);
739               numberOfTags = (a << 8) + b;
740             }
741             else
742             {
743               a = READ8(p);
744               b = READ8(p);
745               numberOfTags = (b << 8) + a;
746             }
747             readBits += 2;
748
749             while(numberOfTags && p < q)
750             {
751               // Get Tag number
752               if(bMotorolla)
753               {
754                 a = READ8(p);
755                 b = READ8(p);
756                 tagNumber = (a << 8) + b;
757                 readBits += 2;
758               }
759               else
760               {
761                 a = READ8(p);
762                 b = READ8(p);
763                 tagNumber = (b << 8) + a;
764                 readBits += 2;
765               }
766
767               //found orientation tag
768               if(tagNumber == EXIF_TAG_ORIENTATION)
769               {
770                 if(bMotorolla)
771                 {
772                   SKIPN(p, 1 * 7);
773                   readBits += 7;
774                   m_orientation = READ8(p);
775                   readBits += 1;
776                   SKIPN(p, 1 * 2);
777                   readBits += 2;
778                 }
779                 else
780                 {
781                   SKIPN(p, 1 * 6);
782                   readBits += 6;
783                   m_orientation = READ8(p);
784                   readBits += 1;
785                   SKIPN(p, 1 * 3);
786                   readBits += 3;
787                 }
788                 break;
789               }
790               else
791               {
792                 SKIPN(p, 1 * 10);
793                 readBits += 10;
794               }
795               numberOfTags--;
796             }
797           }
798         }
799         readBits += 4;
800         SKIPN(p, 1 * (block_size - readBits));
801       }
802       else
803       {
804         SKIPN(p, 1 * (block_size - 2));
805       }
806
807       READ8(p);
808       marker = READ8(p);
809
810     }
811   }
812
813   if(m_orientation > 8)
814     m_orientation = 0;
815
816   if(eCompressionFormat == OMX_IMAGE_CodingMax)
817   {
818     CLog::Log(LOGERROR, "%s::%s error unsupported image format\n", CLASSNAME, __func__);
819   }
820
821   if(progressive)
822   {
823     CLog::Log(LOGWARNING, "%s::%s progressive images not supported by decoder\n", CLASSNAME, __func__);
824     eCompressionFormat = OMX_IMAGE_CodingMax;
825   }
826
827   if(components > 3)
828   {
829     CLog::Log(LOGWARNING, "%s::%s Only YUV images are supported by decoder\n", CLASSNAME, __func__);
830     eCompressionFormat = OMX_IMAGE_CodingMax;
831   }
832
833   return eCompressionFormat;
834 }
835
836
837 bool COMXImageFile::ReadFile(const CStdString& inputFile)
838 {
839   XFILE::CFile      m_pFile;
840   m_filename = inputFile.c_str();
841   if(!m_pFile.Open(inputFile, 0))
842   {
843     CLog::Log(LOGERROR, "%s::%s %s not found\n", CLASSNAME, __func__, inputFile.c_str());
844     return false;
845   }
846
847   if(m_image_buffer)
848     free(m_image_buffer);
849   m_image_buffer = NULL;
850
851   m_image_size = m_pFile.GetLength();
852
853   if(!m_image_size)
854   {
855     CLog::Log(LOGERROR, "%s::%s %s m_image_size zero\n", CLASSNAME, __func__, inputFile.c_str());
856     return false;
857   }
858   m_image_buffer = (uint8_t *)malloc(m_image_size);
859   if(!m_image_buffer)
860   {
861     CLog::Log(LOGERROR, "%s::%s %s m_image_buffer null (%lu)\n", CLASSNAME, __func__, inputFile.c_str(), m_image_size);
862     return false;
863   }
864   
865   m_pFile.Read(m_image_buffer, m_image_size);
866   m_pFile.Close();
867
868   OMX_IMAGE_CODINGTYPE eCompressionFormat = GetCodingType(m_width, m_height);
869   if(eCompressionFormat != OMX_IMAGE_CodingJPEG)
870   {
871     CLog::Log(LOGERROR, "%s::%s %s GetCodingType=0x%x\n", CLASSNAME, __func__, inputFile.c_str(), eCompressionFormat);
872     return false;
873   }
874
875   if(m_width < 1 || m_height < 1)
876   {
877     CLog::Log(LOGERROR, "%s::%s %s m_width=%d m_height=%d\n", CLASSNAME, __func__, inputFile.c_str(), m_width, m_height);
878     return false;
879   }
880
881   return true;
882 }
883
884 #ifdef CLASSNAME
885 #undef CLASSNAME
886 #endif
887 #define CLASSNAME "COMXImageDec"
888
889 COMXImageDec::COMXImageDec()
890 {
891   m_decoded_buffer = NULL;
892   OMX_INIT_STRUCTURE(m_decoded_format);
893 }
894
895 COMXImageDec::~COMXImageDec()
896 {
897   Close();
898
899   OMX_INIT_STRUCTURE(m_decoded_format);
900   m_decoded_buffer = NULL;
901 }
902
903 void COMXImageDec::Close()
904 {
905   CSingleLock lock(m_OMXSection);
906
907   if(m_omx_decoder.IsInitialized())
908   {
909     m_omx_decoder.FlushInput();
910     m_omx_decoder.FreeInputBuffers();
911   }
912   if(m_omx_resize.IsInitialized())
913   {
914     m_omx_resize.FlushOutput();
915     m_omx_resize.FreeOutputBuffers();
916   }
917   if(m_omx_tunnel_decode.IsInitialized())
918     m_omx_tunnel_decode.Deestablish();
919   if(m_omx_decoder.IsInitialized())
920     m_omx_decoder.Deinitialize();
921   if(m_omx_resize.IsInitialized())
922     m_omx_resize.Deinitialize();
923 }
924
925 bool COMXImageDec::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height)
926 {
927   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
928   // on the first port settings changed event, we create the tunnel and alloc the buffer
929   if (!m_decoded_buffer)
930   {
931     OMX_PARAM_PORTDEFINITIONTYPE port_def;
932     OMX_INIT_STRUCTURE(port_def);
933
934     port_def.nPortIndex = m_omx_decoder.GetOutputPort();
935     m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
936     port_def.format.image.nSliceHeight = 16;
937     m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
938
939     port_def.nPortIndex = m_omx_resize.GetInputPort();
940     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
941
942     m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
943
944     omx_err = m_omx_tunnel_decode.Establish();
945     if(omx_err != OMX_ErrorNone)
946     {
947       CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
948       return false;
949     }
950     omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
951     if(omx_err != OMX_ErrorNone)
952     {
953       CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
954       return false;
955     }
956
957     port_def.nPortIndex = m_omx_resize.GetOutputPort();
958     m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
959
960     port_def.nPortIndex = m_omx_resize.GetOutputPort();
961     port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
962     port_def.format.image.eColorFormat = OMX_COLOR_Format32bitARGB8888;
963     port_def.format.image.nFrameWidth = resize_width;
964     port_def.format.image.nFrameHeight = resize_height;
965     port_def.format.image.nStride = resize_width*4;
966     port_def.format.image.nSliceHeight = 0;
967     port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
968
969     omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
970     if(omx_err != OMX_ErrorNone)
971     {
972       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
973       return false;
974     }
975
976     OMX_INIT_STRUCTURE(m_decoded_format);
977     m_decoded_format.nPortIndex = m_omx_resize.GetOutputPort();
978     omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &m_decoded_format);
979     if(omx_err != OMX_ErrorNone)
980     {
981       CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
982       return false;
983     }
984     assert(m_decoded_format.nBufferCountActual == 1);
985
986     omx_err = m_omx_resize.AllocOutputBuffers();
987     if(omx_err != OMX_ErrorNone)
988     {
989       CLog::Log(LOGERROR, "%s::%s m_omx_resize.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
990       return false;
991     }
992     omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
993     if(omx_err != OMX_ErrorNone)
994     {
995       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
996       return false;
997     }
998
999     m_decoded_buffer = m_omx_resize.GetOutputBuffer();
1000
1001     if(!m_decoded_buffer)
1002     {
1003       CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
1004       return false;
1005     }
1006
1007     omx_err = m_omx_resize.FillThisBuffer(m_decoded_buffer);
1008     if(omx_err != OMX_ErrorNone)
1009      {
1010       CLog::Log(LOGERROR, "%s::%s m_omx_resize FillThisBuffer result(0x%x)\n", CLASSNAME, __func__, omx_err);
1011       return false;
1012     }
1013   }
1014   // on subsequent port settings changed event, we just copy the port settings
1015   else
1016   {
1017     // a little surprising, make a note
1018     CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
1019     m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
1020     m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
1021
1022     OMX_PARAM_PORTDEFINITIONTYPE port_def;
1023     OMX_INIT_STRUCTURE(port_def);
1024
1025     port_def.nPortIndex = m_omx_decoder.GetOutputPort();
1026     m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1027     port_def.nPortIndex = m_omx_resize.GetInputPort();
1028     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1029
1030     omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
1031     if(omx_err != OMX_ErrorNone)
1032     {
1033       CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
1034       return false;
1035     }
1036     m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
1037     m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
1038   }
1039   return true;
1040 }
1041
1042 bool COMXImageDec::Decode(const uint8_t *demuxer_content, unsigned demuxer_bytes, unsigned width, unsigned height, unsigned stride, void *pixels)
1043 {
1044   CSingleLock lock(m_OMXSection);
1045   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1046   OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
1047
1048   if(!demuxer_content || !demuxer_bytes)
1049   {
1050     CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
1051     return false;
1052   }
1053
1054   if(!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
1055   {
1056     CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize\n", CLASSNAME, __func__);
1057     return false;
1058   }
1059
1060   if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
1061   {
1062     CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
1063     return false;
1064   }
1065
1066   // set input format
1067   OMX_PARAM_PORTDEFINITIONTYPE portParam;
1068   OMX_INIT_STRUCTURE(portParam);
1069   portParam.nPortIndex = m_omx_decoder.GetInputPort();
1070
1071   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
1072   if(omx_err != OMX_ErrorNone)
1073   {
1074     CLog::Log(LOGERROR, "%s::%s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
1075     return false;
1076   }
1077
1078   portParam.nBufferCountActual = portParam.nBufferCountMin;
1079   portParam.nBufferSize = std::max(portParam.nBufferSize, ALIGN_UP(demuxer_bytes, portParam.nBufferAlignment));
1080   portParam.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
1081
1082   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
1083   if(omx_err != OMX_ErrorNone)
1084   {
1085     CLog::Log(LOGERROR, "%s::%s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
1086     return false;
1087   }
1088
1089   omx_err = m_omx_decoder.AllocInputBuffers();
1090   if(omx_err != OMX_ErrorNone)
1091   {
1092     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
1093     return false;
1094   }
1095
1096   omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
1097   if (omx_err != OMX_ErrorNone)
1098   {
1099     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1100     return false;
1101   }
1102
1103   while(demuxer_bytes > 0 || !m_decoded_buffer)
1104   {
1105     long timeout = 0;
1106     if (demuxer_bytes)
1107     {
1108        omx_buffer = m_omx_decoder.GetInputBuffer(1000);
1109        if(omx_buffer == NULL)
1110          return false;
1111
1112        omx_buffer->nOffset = omx_buffer->nFlags  = 0;
1113
1114        omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
1115        memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
1116
1117        demuxer_content += omx_buffer->nFilledLen;
1118        demuxer_bytes -= omx_buffer->nFilledLen;
1119
1120        if(demuxer_bytes == 0)
1121          omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1122
1123        omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1124        if (omx_err != OMX_ErrorNone)
1125        {
1126          CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1127          return false;
1128        }
1129     }
1130     if (!demuxer_bytes)
1131     {
1132        // we've submitted all buffers so can wait now
1133        timeout = 1000;
1134     }
1135     omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
1136     if(omx_err == OMX_ErrorNone)
1137     {
1138       if (!HandlePortSettingChange(width, height))
1139       {
1140         CLog::Log(LOGERROR, "%s::%s HandlePortSettingChange() failed\n", CLASSNAME, __func__);
1141         return false;
1142       }
1143     }
1144     else if(omx_err == OMX_ErrorStreamCorrupt)
1145     {
1146       CLog::Log(LOGERROR, "%s::%s - image not supported", CLASSNAME, __func__);
1147       return false;
1148     }
1149     else if(timeout || omx_err != OMX_ErrorTimeout)
1150     {
1151       CLog::Log(LOGERROR, "%s::%s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, omx_err);
1152       return false;
1153     }
1154   }
1155
1156   omx_err = m_omx_resize.WaitForOutputDone(1000);
1157   if(omx_err != OMX_ErrorNone)
1158   {
1159     CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
1160     return false;
1161   }
1162
1163   if(m_omx_decoder.BadState())
1164     return false;
1165
1166   assert(m_decoded_buffer->nFilledLen <= stride * height);
1167   memcpy( (char*)pixels, m_decoded_buffer->pBuffer, m_decoded_buffer->nFilledLen);
1168
1169   Close();
1170   return true;
1171 }
1172
1173 #ifdef CLASSNAME
1174 #undef CLASSNAME
1175 #endif
1176 #define CLASSNAME "COMXImageEnc"
1177
1178 COMXImageEnc::COMXImageEnc()
1179 {
1180   CSingleLock lock(m_OMXSection);
1181   OMX_INIT_STRUCTURE(m_encoded_format);
1182   m_encoded_buffer = NULL;
1183 }
1184
1185 COMXImageEnc::~COMXImageEnc()
1186 {
1187   CSingleLock lock(m_OMXSection);
1188
1189   OMX_INIT_STRUCTURE(m_encoded_format);
1190   m_encoded_buffer = NULL;
1191   if(m_omx_encoder.IsInitialized())
1192     m_omx_encoder.Deinitialize();
1193 }
1194
1195 bool COMXImageEnc::Encode(unsigned char *buffer, int size, unsigned width, unsigned height, unsigned int pitch)
1196 {
1197   CSingleLock lock(m_OMXSection);
1198
1199   unsigned int demuxer_bytes = 0;
1200   const uint8_t *demuxer_content = NULL;
1201   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1202   OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
1203   OMX_INIT_STRUCTURE(m_encoded_format);
1204
1205   if (pitch == 0)
1206      pitch = 4 * width;
1207
1208   if (!buffer || !size) 
1209   {
1210     CLog::Log(LOGERROR, "%s::%s error no buffer\n", CLASSNAME, __func__);
1211     return false;
1212   }
1213
1214   if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
1215   {
1216     CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
1217     return false;
1218   }
1219
1220   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1221   OMX_INIT_STRUCTURE(port_def);
1222   port_def.nPortIndex = m_omx_encoder.GetInputPort();
1223
1224   omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1225   if(omx_err != OMX_ErrorNone)
1226   {
1227     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1228     return false;
1229   }
1230
1231   port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
1232   port_def.format.image.eColorFormat = OMX_COLOR_Format32bitARGB8888;
1233   port_def.format.image.nFrameWidth = width;
1234   port_def.format.image.nFrameHeight = height;
1235   port_def.format.image.nStride = pitch;
1236   port_def.format.image.nSliceHeight = (height+15) & ~15;
1237   port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
1238
1239   omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1240   if(omx_err != OMX_ErrorNone)
1241   {
1242     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1243     return false;
1244   }
1245
1246   OMX_INIT_STRUCTURE(port_def);
1247   port_def.nPortIndex = m_omx_encoder.GetOutputPort();
1248
1249   omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1250   if(omx_err != OMX_ErrorNone)
1251   {
1252     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1253     return false;
1254   }
1255
1256   port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
1257   port_def.format.image.eColorFormat = OMX_COLOR_FormatUnused;
1258   port_def.format.image.nFrameWidth = width;
1259   port_def.format.image.nFrameHeight = height;
1260   port_def.format.image.nStride = 0;
1261   port_def.format.image.nSliceHeight = 0;
1262   port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
1263
1264   omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1265   if(omx_err != OMX_ErrorNone)
1266   {
1267     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1268     return false;
1269   }
1270
1271   OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
1272   OMX_INIT_STRUCTURE(qfactor);
1273   qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
1274   qfactor.nQFactor = 16;
1275
1276   omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
1277   if(omx_err != OMX_ErrorNone)
1278   {
1279     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
1280     return false;
1281   }
1282
1283   omx_err = m_omx_encoder.AllocInputBuffers();
1284   if(omx_err != OMX_ErrorNone)
1285   {
1286     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
1287     return false;
1288   }
1289
1290   omx_err = m_omx_encoder.AllocOutputBuffers();
1291   if(omx_err != OMX_ErrorNone)
1292   {
1293     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
1294     return false;
1295   }
1296
1297   omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
1298   if (omx_err != OMX_ErrorNone)
1299   {
1300     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1301     return false;
1302   }
1303
1304   demuxer_content = buffer;
1305   demuxer_bytes   = height * pitch;
1306
1307   if(!demuxer_bytes || !demuxer_content)
1308     return false;
1309
1310   while(demuxer_bytes > 0)
1311   {
1312     omx_buffer = m_omx_encoder.GetInputBuffer(1000);
1313     if(omx_buffer == NULL)
1314     {
1315       return false;
1316     }
1317
1318     omx_buffer->nOffset = omx_buffer->nFlags  = 0;
1319
1320     omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
1321     memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
1322
1323     demuxer_content += omx_buffer->nFilledLen;
1324     demuxer_bytes -= omx_buffer->nFilledLen;
1325
1326     if(demuxer_bytes == 0)
1327       omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1328
1329     omx_err = m_omx_encoder.EmptyThisBuffer(omx_buffer);
1330     if (omx_err != OMX_ErrorNone)
1331     {
1332       CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1333       break;
1334     }
1335   }
1336
1337   m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
1338
1339   if(!m_encoded_buffer)
1340   {
1341     CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
1342     return false;
1343   }
1344
1345   omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
1346   if(omx_err != OMX_ErrorNone)
1347     return false;
1348
1349   omx_err = m_omx_encoder.WaitForOutputDone(1000);
1350   if(omx_err != OMX_ErrorNone)
1351   {
1352     CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
1353     return false;
1354   }
1355
1356   m_encoded_format.nPortIndex = m_omx_encoder.GetOutputPort();
1357   omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &m_encoded_format);
1358   if(omx_err != OMX_ErrorNone)
1359   {
1360     CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1361     return false;
1362   }
1363
1364   if(m_omx_encoder.BadState())
1365     return false;
1366
1367   return true;
1368 }
1369
1370 bool COMXImageEnc::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
1371     unsigned int format, unsigned int pitch, const CStdString& destFile)
1372 {
1373   if(format != XB_FMT_A8R8G8B8 || !buffer)
1374   {
1375     CLog::Log(LOGDEBUG, "%s::%s : %s failed format=0x%x\n", CLASSNAME, __func__, destFile.c_str(), format);
1376     return false;
1377   }
1378
1379   if(!Encode(buffer, height * pitch, width, height, pitch))
1380   {
1381     CLog::Log(LOGDEBUG, "%s::%s : %s encode failed\n", CLASSNAME, __func__, destFile.c_str());
1382     return false;
1383   }
1384
1385   XFILE::CFile file;
1386   if (file.OpenForWrite(destFile, true))
1387   {
1388     CLog::Log(LOGDEBUG, "%s::%s : %s width %d height %d\n", CLASSNAME, __func__, destFile.c_str(), width, height);
1389
1390     file.Write(m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen);
1391     file.Close();
1392     return true;
1393   }
1394
1395   return false;
1396 }
1397
1398 #ifdef CLASSNAME
1399 #undef CLASSNAME
1400 #endif
1401 #define CLASSNAME "COMXReEnc"
1402
1403 COMXImageReEnc::COMXImageReEnc()
1404 {
1405   m_encoded_buffer = NULL;
1406   m_pDestBuffer = NULL;
1407   m_nDestAllocSize = 0;
1408 }
1409
1410 COMXImageReEnc::~COMXImageReEnc()
1411 {
1412   Close();
1413   if (m_pDestBuffer)
1414     free (m_pDestBuffer);
1415   m_pDestBuffer = NULL;
1416   m_nDestAllocSize = 0;
1417 }
1418
1419 void COMXImageReEnc::Close()
1420 {
1421   CSingleLock lock(m_OMXSection);
1422
1423   if(m_omx_decoder.IsInitialized())
1424   {
1425     m_omx_decoder.FlushInput();
1426     m_omx_decoder.FreeInputBuffers();
1427   }
1428   if(m_omx_encoder.IsInitialized())
1429   {
1430     m_omx_encoder.FlushOutput();
1431     m_omx_encoder.FreeOutputBuffers();
1432   }
1433   if(m_omx_tunnel_decode.IsInitialized())
1434     m_omx_tunnel_decode.Deestablish();
1435   if(m_omx_tunnel_resize.IsInitialized())
1436     m_omx_tunnel_resize.Deestablish();
1437   if(m_omx_decoder.IsInitialized())
1438     m_omx_decoder.Deinitialize();
1439   if(m_omx_resize.IsInitialized())
1440     m_omx_resize.Deinitialize();
1441   if(m_omx_encoder.IsInitialized())
1442     m_omx_encoder.Deinitialize();
1443 }
1444
1445
1446
1447 bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, bool port_settings_changed)
1448 {
1449   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1450   // on the first port settings changed event, we create the tunnel and alloc the buffer
1451   if (!port_settings_changed)
1452   {
1453     OMX_PARAM_PORTDEFINITIONTYPE port_def;
1454     OMX_INIT_STRUCTURE(port_def);
1455
1456     port_def.nPortIndex = m_omx_decoder.GetOutputPort();
1457     m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1458     if(omx_err != OMX_ErrorNone)
1459     {
1460       CLog::Log(LOGERROR, "%s::%s m_omx_decoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1461       return false;
1462     }
1463
1464     // TODO: jpeg decoder can decimate by factors of 2
1465     port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1466     port_def.format.image.nSliceHeight = 16;//(port_def.format.image.nFrameHeight+15) & ~15;
1467     port_def.format.image.nStride = 0;
1468
1469     m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1470     if(omx_err != OMX_ErrorNone)
1471     {
1472       CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1473       return false;
1474     }
1475
1476     if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
1477     {
1478       CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
1479       return false;
1480     }
1481
1482     port_def.nPortIndex = m_omx_resize.GetInputPort();
1483
1484     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1485     if(omx_err != OMX_ErrorNone)
1486     {
1487       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1488       return false;
1489     }
1490
1491     port_def.nPortIndex = m_omx_resize.GetOutputPort();
1492     m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1493     if(omx_err != OMX_ErrorNone)
1494     {
1495       CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1496       return false;
1497     }
1498     port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1499     port_def.format.image.nFrameWidth = resize_width;
1500     port_def.format.image.nFrameHeight = resize_height;
1501     port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
1502     port_def.format.image.nStride = 0;
1503     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1504     if(omx_err != OMX_ErrorNone)
1505     {
1506       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1507       return false;
1508     }
1509
1510     if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
1511     {
1512       CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
1513       return false;
1514     }
1515
1516     port_def.nPortIndex = m_omx_encoder.GetInputPort();
1517     m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1518     if(omx_err != OMX_ErrorNone)
1519     {
1520       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1521       return false;
1522     }
1523     port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1524     port_def.format.image.nFrameWidth = resize_width;
1525     port_def.format.image.nFrameHeight = resize_height;
1526     port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
1527     port_def.format.image.nStride = 0;
1528     m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1529     if(omx_err != OMX_ErrorNone)
1530     {
1531       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1532       return false;
1533     }
1534
1535     port_def.nPortIndex = m_omx_encoder.GetOutputPort();
1536     omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1537     if(omx_err != OMX_ErrorNone)
1538     {
1539       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1540       return false;
1541     }
1542
1543     port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
1544     port_def.format.image.eColorFormat = OMX_COLOR_FormatUnused;
1545     port_def.format.image.nFrameWidth = resize_width;
1546     port_def.format.image.nFrameHeight = resize_height;
1547     port_def.format.image.nStride = 0;
1548     port_def.format.image.nSliceHeight = 0;
1549     port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
1550
1551     omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1552     if(omx_err != OMX_ErrorNone)
1553     {
1554       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1555       return false;
1556     }
1557
1558     OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
1559     OMX_INIT_STRUCTURE(qfactor);
1560     qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
1561     qfactor.nQFactor = 16;
1562
1563     omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
1564     if(omx_err != OMX_ErrorNone)
1565     {
1566       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
1567       return false;
1568     }
1569
1570     omx_err = m_omx_encoder.AllocOutputBuffers();
1571     if(omx_err != OMX_ErrorNone)
1572     {
1573       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
1574       return false;
1575     }
1576
1577     m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
1578
1579     omx_err = m_omx_tunnel_decode.Establish();
1580     if(omx_err != OMX_ErrorNone)
1581     {
1582       CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
1583       return false;
1584     }
1585
1586     m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
1587
1588     omx_err = m_omx_tunnel_resize.Establish();
1589     if(omx_err != OMX_ErrorNone)
1590     {
1591       CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
1592       return false;
1593     }
1594
1595     omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
1596     if(omx_err != OMX_ErrorNone)
1597     {
1598       CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1599       return false;
1600     }
1601
1602     omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
1603     if (omx_err != OMX_ErrorNone)
1604     {
1605       CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1606       return false;
1607     }
1608
1609     if(m_omx_encoder.BadState())
1610       return false;
1611   }
1612   // on subsequent port settings changed event, we just copy the port settings
1613   else
1614   {
1615     // a little surprising, make a note
1616     CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
1617     m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
1618     m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
1619
1620     OMX_PARAM_PORTDEFINITIONTYPE port_def;
1621     OMX_INIT_STRUCTURE(port_def);
1622
1623     port_def.nPortIndex = m_omx_decoder.GetOutputPort();
1624     m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1625     port_def.nPortIndex = m_omx_resize.GetInputPort();
1626     m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1627
1628     omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
1629     if(omx_err != OMX_ErrorNone)
1630     {
1631       CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
1632       return false;
1633     }
1634     m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
1635     m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
1636   }
1637   return true;
1638 }
1639
1640 bool COMXImageReEnc::ReEncode(COMXImageFile &srcFile, unsigned int maxWidth, unsigned int maxHeight, void * &pDestBuffer, unsigned int &nDestSize)
1641 {
1642   CSingleLock lock(m_OMXSection);
1643   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1644
1645   COMXImage::ClampLimits(maxWidth, maxHeight, srcFile.GetWidth(), srcFile.GetHeight(), srcFile.GetOrientation() & 4);
1646   unsigned int demuxer_bytes = srcFile.GetImageSize();
1647   unsigned char *demuxer_content = (unsigned char *)srcFile.GetImageBuffer();
1648   // initial dest buffer size
1649   nDestSize = 0;
1650
1651   if(!demuxer_content || !demuxer_bytes)
1652   {
1653     CLog::Log(LOGERROR, "%s::%s %s no input buffer\n", CLASSNAME, __func__, srcFile.GetFilename());
1654     return false;
1655   }
1656
1657   if(!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
1658   {
1659     CLog::Log(LOGERROR, "%s::%s %s error m_omx_decoder.Initialize\n", CLASSNAME, __func__, srcFile.GetFilename());
1660     return false;
1661   }
1662
1663   // set input format
1664   OMX_PARAM_PORTDEFINITIONTYPE portParam;
1665   OMX_INIT_STRUCTURE(portParam);
1666   portParam.nPortIndex = m_omx_decoder.GetInputPort();
1667
1668   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
1669   if(omx_err != OMX_ErrorNone)
1670   {
1671     CLog::Log(LOGERROR, "%s::%s %s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1672     return false;
1673   }
1674
1675   portParam.nBufferCountActual = portParam.nBufferCountMin;
1676   portParam.nBufferSize = std::max(portParam.nBufferSize, ALIGN_UP(demuxer_bytes, portParam.nBufferAlignment));
1677   portParam.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
1678
1679   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
1680   if(omx_err != OMX_ErrorNone)
1681   {
1682     CLog::Log(LOGERROR, "%s::%s %s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1683     return false;
1684   }
1685
1686   omx_err = m_omx_decoder.AllocInputBuffers();
1687   if(omx_err != OMX_ErrorNone)
1688   {
1689     CLog::Log(LOGERROR, "%s::%s %s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1690     return false;
1691   }
1692
1693   omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
1694   if (omx_err != OMX_ErrorNone)
1695   {
1696     CLog::Log(LOGERROR, "%s::%s %s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1697     return false;
1698   }
1699
1700   bool port_settings_changed = false, eos = false;
1701   while(demuxer_bytes > 0 || !port_settings_changed || !eos)
1702   {
1703     long timeout = 0;
1704     if (demuxer_bytes)
1705     {
1706        OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
1707        if(omx_buffer)
1708        {
1709          omx_buffer->nOffset = omx_buffer->nFlags  = 0;
1710
1711          omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
1712          memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
1713
1714          demuxer_content += omx_buffer->nFilledLen;
1715          demuxer_bytes -= omx_buffer->nFilledLen;
1716          if(demuxer_bytes == 0)
1717            omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1718
1719          omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1720          if (omx_err != OMX_ErrorNone)
1721          {
1722            CLog::Log(LOGERROR, "%s::%s %s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1723            return false;
1724          }
1725       }
1726     }
1727     if (!demuxer_bytes)
1728     {
1729        // we've submitted all buffers so can wait now
1730        timeout = 1000;
1731     }
1732
1733     omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
1734     if(omx_err == OMX_ErrorNone)
1735     {
1736       if (!HandlePortSettingChange(maxWidth, maxHeight, port_settings_changed))
1737       {
1738         CLog::Log(LOGERROR, "%s::%s %s HandlePortSettingChange() failed\n", srcFile.GetFilename(), CLASSNAME, __func__);
1739         return false;
1740       }
1741       port_settings_changed = true;
1742     }
1743     else if(omx_err == OMX_ErrorStreamCorrupt)
1744     {
1745       CLog::Log(LOGERROR, "%s::%s %s - image not supported", CLASSNAME, __func__, srcFile.GetFilename());
1746       return false;
1747     }
1748     else if(timeout || omx_err != OMX_ErrorTimeout)
1749     {
1750       CLog::Log(LOGERROR, "%s::%s %s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1751       return false;
1752     }
1753
1754     if (!m_encoded_buffer && port_settings_changed && demuxer_bytes == 0)
1755     {
1756       m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
1757       omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
1758       if(omx_err != OMX_ErrorNone)
1759       {
1760         CLog::Log(LOGERROR, "%s::%s %s FillThisBuffer() failed (%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1761         return false;
1762       }
1763     }
1764     if (m_encoded_buffer)
1765     {
1766       omx_err = m_omx_encoder.WaitForOutputDone(1000);
1767       if (omx_err != OMX_ErrorNone)
1768       {
1769         CLog::Log(LOGERROR, "%s::%s %s m_omx_encoder.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1770         return false;
1771       }
1772       if (!m_encoded_buffer->nFilledLen)
1773       {
1774         CLog::Log(LOGERROR, "%s::%s %s m_omx_encoder.WaitForOutputDone no data\n", CLASSNAME, __func__, srcFile.GetFilename());
1775         return false;
1776       }
1777       if (m_encoded_buffer->nFlags & OMX_BUFFERFLAG_EOS)
1778          eos = true;
1779
1780       if (nDestSize + m_encoded_buffer->nFilledLen > m_nDestAllocSize)
1781       {
1782          m_nDestAllocSize = std::max(1024U*1024U, m_nDestAllocSize*2);
1783          m_pDestBuffer = realloc(m_pDestBuffer, m_nDestAllocSize);
1784       }
1785       memcpy((char *)m_pDestBuffer + nDestSize, m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen);
1786       nDestSize += m_encoded_buffer->nFilledLen;
1787       m_encoded_buffer = NULL;
1788     }
1789   }
1790
1791   Close();
1792
1793   if(m_omx_decoder.BadState())
1794     return false;
1795
1796   pDestBuffer = m_pDestBuffer;
1797   CLog::Log(LOGDEBUG, "%s::%s : %s %dx%d -> %dx%d\n", CLASSNAME, __func__, srcFile.GetFilename(), srcFile.GetWidth(), srcFile.GetHeight(), maxWidth, maxHeight);
1798
1799   return true;
1800 }
1801
1802
1803 #ifdef CLASSNAME
1804 #undef CLASSNAME
1805 #endif
1806 #define CLASSNAME "COMXTexture"
1807
1808 COMXTexture::COMXTexture()
1809 {
1810 }
1811
1812 COMXTexture::~COMXTexture()
1813 {
1814   Close();
1815 }
1816
1817 void COMXTexture::Close()
1818 {
1819   CSingleLock lock(m_OMXSection);
1820
1821   if (m_omx_tunnel_decode.IsInitialized())
1822     m_omx_tunnel_decode.Deestablish();
1823   if (m_omx_tunnel_egl.IsInitialized())
1824     m_omx_tunnel_egl.Deestablish();
1825   // delete components
1826   if (m_omx_decoder.IsInitialized())
1827     m_omx_decoder.Deinitialize();
1828   if (m_omx_resize.IsInitialized())
1829     m_omx_resize.Deinitialize();
1830   if (m_omx_egl_render.IsInitialized())
1831     m_omx_egl_render.Deinitialize();
1832 }
1833
1834 bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, void *egl_image, void *egl_display, bool port_settings_changed)
1835 {
1836   OMX_ERRORTYPE omx_err;
1837
1838   if (port_settings_changed)
1839     CLog::Log(LOGERROR, "%s::%s Unexpected second port_settings_changed call\n", CLASSNAME, __func__);
1840
1841   OMX_PARAM_PORTDEFINITIONTYPE port_def;
1842   OMX_INIT_STRUCTURE(port_def);
1843
1844   port_def.nPortIndex = m_omx_decoder.GetOutputPort();
1845   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1846   if (omx_err != OMX_ErrorNone)
1847   {
1848     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1849     return false;
1850   }
1851
1852   // TODO: jpeg decoder can decimate by factors of 2
1853   port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1854   port_def.format.image.nSliceHeight = 16;
1855   port_def.format.image.nStride = 0;
1856
1857   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1858   if (omx_err != OMX_ErrorNone)
1859   {
1860     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1861     return false;
1862   }
1863
1864   if (!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
1865   {
1866     CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize", CLASSNAME, __func__);
1867     return false;
1868   }
1869
1870   port_def.nPortIndex = m_omx_resize.GetInputPort();
1871
1872   omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1873   if (omx_err != OMX_ErrorNone)
1874   {
1875     CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1876     return false;
1877   }
1878
1879   port_def.nPortIndex = m_omx_resize.GetOutputPort();
1880   omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1881   if (omx_err != OMX_ErrorNone)
1882   {
1883     CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1884     return false;
1885   }
1886
1887   port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1888   port_def.format.image.nFrameWidth = resize_width;
1889   port_def.format.image.nFrameHeight = resize_height;
1890   port_def.format.image.nSliceHeight = 16;
1891   port_def.format.image.nStride = 0;
1892   omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1893   if (omx_err != OMX_ErrorNone)
1894   {
1895     CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1896     return false;
1897   }
1898
1899   if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit))
1900   {
1901     CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
1902     return false;
1903   }
1904
1905   port_def.nPortIndex = m_omx_egl_render.GetOutputPort();
1906   omx_err = m_omx_egl_render.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1907   if (omx_err != OMX_ErrorNone)
1908   {
1909     CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1910     return false;
1911   }
1912   port_def.nBufferCountActual = 1;
1913   port_def.format.video.pNativeWindow = egl_display;
1914
1915   omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1916   if (omx_err != OMX_ErrorNone)
1917   {
1918     CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1919     return false;
1920   }
1921
1922   omx_err = m_omx_egl_render.UseEGLImage(&m_egl_buffer, m_omx_egl_render.GetOutputPort(), NULL, egl_image);
1923   if (omx_err != OMX_ErrorNone)
1924   {
1925     CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.UseEGLImage (%x)", CLASSNAME, __func__, omx_err);
1926     return false;
1927   }
1928
1929   m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
1930
1931   omx_err = m_omx_tunnel_decode.Establish();
1932   if (omx_err != OMX_ErrorNone)
1933   {
1934     CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
1935     return false;
1936   }
1937
1938   m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
1939
1940   omx_err = m_omx_tunnel_egl.Establish();
1941   if (omx_err != OMX_ErrorNone)
1942   {
1943     CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
1944     return false;
1945   }
1946
1947   omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
1948   if (omx_err != OMX_ErrorNone)
1949   {
1950     CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
1951     return false;
1952   }
1953
1954   omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
1955   if (omx_err != OMX_ErrorNone)
1956   {
1957     CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.SetStateForComponent (%x)", CLASSNAME, __func__, omx_err);
1958     return false;
1959   }
1960
1961   return true;
1962 }
1963
1964 bool COMXTexture::Decode(const uint8_t *demuxer_content, unsigned demuxer_bytes, unsigned int width, unsigned int height, void *egl_image, void *egl_display)
1965 {
1966   CSingleLock lock(m_OMXSection);
1967   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1968
1969   if (!demuxer_content || !demuxer_bytes)
1970   {
1971     CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
1972     return false;
1973   }
1974
1975   if (!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
1976   {
1977     CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize", CLASSNAME, __func__);
1978     return false;
1979   }
1980
1981   // set input format
1982   OMX_PARAM_PORTDEFINITIONTYPE portParam;
1983   OMX_INIT_STRUCTURE(portParam);
1984   portParam.nPortIndex = m_omx_decoder.GetInputPort();
1985
1986   omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
1987   if (omx_err != OMX_ErrorNone)
1988   {
1989     CLog::Log(LOGERROR, "%s::%s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
1990     return false;
1991   }
1992
1993   portParam.nBufferCountActual = portParam.nBufferCountMin;
1994   portParam.nBufferSize = std::max(portParam.nBufferSize, ALIGN_UP(demuxer_bytes, portParam.nBufferAlignment));
1995   portParam.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
1996
1997   omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
1998   if (omx_err != OMX_ErrorNone)
1999   {
2000     CLog::Log(LOGERROR, "%s::%s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
2001     return false;
2002   }
2003
2004   omx_err = m_omx_decoder.AllocInputBuffers();
2005   if (omx_err != OMX_ErrorNone)
2006   {
2007     CLog::Log(LOGERROR, "%s::%s - Error alloc buffers  (%x)", CLASSNAME, __func__, omx_err);
2008     return false;
2009   }
2010
2011   omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
2012   if (omx_err != OMX_ErrorNone)
2013   {
2014     CLog::Log(LOGERROR, "%s::%s error m_omx_sched.SetStateForComponent (%x)", CLASSNAME, __func__, omx_err);
2015     return false;
2016   }
2017
2018   bool port_settings_changed = false;
2019   bool eos = false;
2020   while(demuxer_bytes > 0 || !port_settings_changed || !eos)
2021   {
2022     long timeout = 0;
2023     if (demuxer_bytes)
2024     {
2025       OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
2026       if (omx_buffer)
2027       {
2028         omx_buffer->nOffset = omx_buffer->nFlags  = 0;
2029
2030         omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
2031         memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
2032
2033         demuxer_content += omx_buffer->nFilledLen;
2034         demuxer_bytes -= omx_buffer->nFilledLen;
2035
2036         if (demuxer_bytes == 0)
2037           omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
2038
2039         omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
2040         if (omx_err != OMX_ErrorNone)
2041         {
2042           CLog::Log(LOGERROR, "%s::%s - m_omx_decoder.OMX_EmptyThisBuffer (%x)", CLASSNAME, __func__, omx_err);
2043           return false;
2044          }
2045       }
2046     }
2047     if (!demuxer_bytes)
2048     {
2049        // we've submitted all buffers so can wait now
2050        timeout = 1000;
2051     }
2052
2053     omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
2054     if (omx_err == OMX_ErrorNone)
2055     {
2056       if (!HandlePortSettingChange(width, height, egl_image, egl_display, port_settings_changed))
2057       {
2058         CLog::Log(LOGERROR, "%s::%s - HandlePortSettingChange failed (%x)", CLASSNAME, __func__, omx_err);
2059         return false;
2060       }
2061       port_settings_changed = true;
2062     }
2063     else if (omx_err == OMX_ErrorStreamCorrupt)
2064     {
2065       CLog::Log(LOGERROR, "%s::%s - image not supported", CLASSNAME, __func__);
2066       return false;
2067     }
2068     else if (timeout || omx_err != OMX_ErrorTimeout)
2069     {
2070       CLog::Log(LOGERROR, "%s::%s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, omx_err);
2071       return false;
2072     }
2073
2074     if (port_settings_changed && m_egl_buffer && demuxer_bytes == 0 && !eos)
2075     {
2076       OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_egl_render.GetOutputBuffer();
2077       if (!omx_buffer)
2078       {
2079         CLog::Log(LOGERROR, "%s::%s GetOutputBuffer failed\n", CLASSNAME, __func__);
2080         return false;
2081       }
2082       if (omx_buffer != m_egl_buffer)
2083       {
2084         CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetOutputBuffer (%p,%p)", CLASSNAME, __func__, omx_buffer, m_egl_buffer);
2085         return false;
2086       }
2087
2088       omx_err = m_omx_egl_render.FillThisBuffer(m_egl_buffer);
2089       if (omx_err != OMX_ErrorNone)
2090       {
2091         CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.FillThisBuffer (%x)", CLASSNAME, __func__, omx_err);
2092         return false;
2093       }
2094
2095       omx_err = m_omx_egl_render.WaitForOutputDone(1000);
2096       if (omx_err != OMX_ErrorNone)
2097       {
2098         CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
2099         return false;
2100       }
2101       eos = true;
2102     }
2103   }
2104   Close();
2105   return true;
2106 }
2107
2108 COMXImage g_OMXImage;