2 * Copyright (C) 2010-2013 Team XBMC
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)
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.
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/>.
21 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
23 #elif defined(TARGET_WINDOWS)
29 #include "utils/log.h"
30 #include "linux/XMemUtils.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"
44 #define CheckError() m_result = eglGetError(); if (m_result != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",__FUNCTION__, m_result);
49 #define EXIF_TAG_ORIENTATION 0x0112
55 #define CLASSNAME "COMXImage"
57 COMXImage::COMXImage()
58 : CThread("CRBPWorker")
62 COMXImage::~COMXImage()
67 void COMXImage::Initialize()
72 void COMXImage::Deinitialize()
74 // wake up thread so it can quit
76 CSingleLock lock(m_texqueue_lock);
78 m_texqueue_cond.notifyAll();
84 bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
85 unsigned int format, unsigned int pitch, const CStdString& destFile)
87 COMXImageEnc omxImageEnc;
88 bool ret = omxImageEnc.CreateThumbnailFromSurface(buffer, width, height, format, pitch, destFile);
90 CLog::Log(LOGNOTICE, "%s: unable to create thumbnail %s %dx%d", __func__, destFile.c_str(), width, height);
94 COMXImageFile *COMXImage::LoadJpeg(const CStdString& texturePath)
96 COMXImageFile *file = new COMXImageFile();
97 if (!file->ReadFile(texturePath))
99 CLog::Log(LOGNOTICE, "%s: unable to load %s", __func__, texturePath.c_str());
106 void COMXImage::CloseJpeg(COMXImageFile *file)
111 bool COMXImage::DecodeJpeg(COMXImageFile *file, unsigned int width, unsigned int height, unsigned int stride, void *pixels)
114 COMXImageDec omx_image;
115 if (omx_image.Decode(file->GetImageBuffer(), file->GetImageSize(), width, height, stride, pixels))
117 assert(width == omx_image.GetDecodedWidth());
118 assert(height == omx_image.GetDecodedHeight());
119 assert(stride == omx_image.GetDecodedStride());
123 CLog::Log(LOGNOTICE, "%s: unable to decode %s %dx%d", __func__, file->GetFilename(), width, height);
128 bool COMXImage::ClampLimits(unsigned int &width, unsigned int &height, unsigned int m_width, unsigned int m_height, bool transposed)
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;
138 if (max_width == 0 || max_height == 0)
140 max_height = g_advancedSettings.m_imageRes;
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)
146 max_height = g_advancedSettings.m_fanartRes;
149 max_width = max_height * 16/9;
153 max_width = min(max_width, gui_width);
155 max_height = min(max_height, gui_height);
157 max_width = min(max_width, 2048U);
158 max_height = min(max_height, 2048U);
162 if (width > max_width || height > max_height)
164 if ((unsigned int)(max_width / aspect + 0.5f) > max_height)
165 max_width = (unsigned int)(max_height * aspect + 0.5f);
167 max_height = (unsigned int)(max_width / aspect + 0.5f);
172 // Texture.cpp wants even width/height
173 width = (width + 15) & ~15;
174 height = (height + 15) & ~15;
179 bool COMXImage::CreateThumb(const CStdString& srcFile, unsigned int maxHeight, unsigned int maxWidth, std::string &additional_info, const CStdString& destFile)
183 COMXImageReEnc reenc;
185 unsigned int nDestSize;
186 if (URIUtils::HasExtension(srcFile, ".jpg|.tbn") && file.ReadFile(srcFile) && reenc.ReEncode(file, maxWidth, maxHeight, pDestBuffer, nDestSize))
188 XFILE::CFile outfile;
189 if (outfile.OpenForWrite(destFile, true))
191 outfile.Write(pDestBuffer, nDestSize);
196 CLog::Log(LOGERROR, "%s: can't open output file: %s\n", __func__, destFile.c_str());
201 void COMXImage::AllocTextureInternal(struct textureinfo *tex)
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);
216 void COMXImage::GetTexture(void *userdata, GLuint *texture)
218 struct textureinfo *tex = static_cast<struct textureinfo *>(userdata);
219 *texture = tex->texture;
222 void COMXImage::DestroyTextureInternal(struct textureinfo *tex)
225 if (!tex->egl_image || !tex->texture)
227 CLog::Log(LOGNOTICE, "%s: Invalid image/texture %p:%d", __func__, tex->egl_image, tex->texture);
230 s = eglDestroyImageKHR(m_egl_display, tex->egl_image);
232 CLog::Log(LOGNOTICE, "%s: failed to destroy texture", __func__);
233 glDeleteTextures(1, (GLuint*) &tex->texture);
237 void COMXImage::DestroyTexture(void *userdata)
239 struct textureinfo *tex = static_cast<struct textureinfo *>(userdata);
240 // we can only call gl functions from the application thread
242 tex->action = TEXTURE_DELETE;
244 if ( g_application.IsCurrentThread() )
246 DestroyTextureInternal(tex);
250 CSingleLock lock(m_texqueue_lock);
251 m_texqueue.push(tex);
252 m_texqueue_cond.notifyAll();
254 // wait for function to have finished (in texture thread)
259 bool COMXImage::DecodeJpegToTexture(COMXImageFile *file, unsigned int width, unsigned int height, void **userdata)
262 COMXTexture omx_image;
264 struct textureinfo *tex = new struct textureinfo;
268 tex->parent = (void *)this;
270 tex->height = height;
272 tex->egl_image = NULL;
273 tex->filename = file->GetFilename();
274 tex->action = TEXTURE_ALLOC;
278 CSingleLock lock(m_texqueue_lock);
279 m_texqueue.push(tex);
280 m_texqueue_cond.notifyAll();
283 // wait for function to have finished (in texture thread)
286 if (tex->egl_image && tex->texture && omx_image.Decode(file->GetImageBuffer(), file->GetImageSize(), width, height, tex->egl_image, m_egl_display))
293 CLog::Log(LOGNOTICE, "%s: unable to decode to texture %s %dx%d", __func__, file->GetFilename(), width, height);
299 static bool ChooseConfig(EGLDisplay display, const EGLint *configAttrs, EGLConfig *config)
301 EGLBoolean eglStatus = true;
302 EGLint configCount = 0;
303 EGLConfig* configList = NULL;
305 // Find out how many configurations suit our needs
306 eglStatus = eglChooseConfig(display, configAttrs, NULL, 0, &configCount);
309 if (!eglStatus || !configCount)
311 CLog::Log(LOGERROR, "EGL failed to return any matching configurations: %i", configCount);
315 // Allocate room for the list of matching configurations
316 configList = (EGLConfig*)malloc(configCount * sizeof(EGLConfig));
319 CLog::Log(LOGERROR, "EGL failure obtaining configuration list");
323 // Obtain the configuration list from EGL
324 eglStatus = eglChooseConfig(display, configAttrs, configList, configCount, &configCount);
326 if (!eglStatus || !configCount)
328 CLog::Log(LOGERROR, "EGL failed to populate configuration list: %d", eglStatus);
332 // Select an EGL configuration that matches the native window
333 *config = configList[0];
339 void COMXImage::CreateContext()
341 EGLConfig egl_config;
344 m_egl_display = g_Windowing.GetEGLDisplay();
345 eglInitialize(m_egl_display, NULL, NULL);
347 eglBindAPI(EGL_OPENGL_ES_API);
349 static const EGLint contextAttrs [] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
350 static const EGLint configAttrs [] = {
357 EGL_SAMPLE_BUFFERS, 0,
359 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
360 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
363 bool s = ChooseConfig(m_egl_display, configAttrs, &egl_config);
367 CLog::Log(LOGERROR, "%s: Could not find a compatible configuration",__FUNCTION__);
370 m_egl_context = eglCreateContext(m_egl_display, egl_config, g_Windowing.GetEGLContext(), contextAttrs);
372 if (m_egl_context == EGL_NO_CONTEXT)
374 CLog::Log(LOGERROR, "%s: Could not create a context",__FUNCTION__);
377 EGLSurface egl_surface = eglCreatePbufferSurface(m_egl_display, egl_config, NULL);
379 if (egl_surface == EGL_NO_SURFACE)
381 CLog::Log(LOGERROR, "%s: Could not create a surface",__FUNCTION__);
384 s = eglMakeCurrent(m_egl_display, egl_surface, egl_surface, m_egl_context);
388 CLog::Log(LOGERROR, "%s: Could not make current",__FUNCTION__);
393 void COMXImage::Process()
395 bool firsttime = true;
399 struct textureinfo *tex = NULL;
402 CSingleLock lock(m_texqueue_lock);
403 if (!m_texqueue.empty())
405 tex = m_texqueue.front();
409 m_texqueue_cond.wait(lock);
419 if (tex && tex->action == TEXTURE_ALLOC)
420 AllocTextureInternal(tex);
421 else if (tex && tex->action == TEXTURE_DELETE)
422 DestroyTextureInternal(tex);
424 CLog::Log(LOGERROR, "%s: Unexpected texture job: %p:%d", __func__, tex, tex ? tex->action : 0);
428 void COMXImage::OnStartup()
432 void COMXImage::OnExit()
439 #define CLASSNAME "COMXImageFile"
441 COMXImageFile::COMXImageFile()
444 m_image_buffer = NULL;
451 COMXImageFile::~COMXImageFile()
454 free(m_image_buffer);
457 typedef enum { /* JPEG marker codes */
531 static uint8_t inline READ8(uint8_t * &p)
538 static uint16_t inline READ16(uint8_t * &p)
540 uint16_t r = (p[0] << 8) | p[1];
545 static uint32_t inline READ32(uint8_t * &p)
547 uint32_t r = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
552 static void inline SKIPN(uint8_t * &p, unsigned int n)
557 OMX_IMAGE_CODINGTYPE COMXImageFile::GetCodingType(unsigned int &width, unsigned int &height)
559 OMX_IMAGE_CODINGTYPE eCompressionFormat = OMX_IMAGE_CodingMax;
560 bool progressive = false;
565 return OMX_IMAGE_CodingMax;
567 uint8_t *p = m_image_buffer;
568 uint8_t *q = m_image_buffer + m_image_size;
571 if(READ16(p) == 0xFFD8)
573 eCompressionFormat = OMX_IMAGE_CodingJPEG;
576 unsigned char marker = READ8(p);
577 unsigned short block_size = 0;
578 bool nMarker = false;
642 block_size = READ16(p);
657 if(marker >= M_SOF0 && marker <= M_SOF15 && marker != M_DHT && marker != M_DAC)
659 if(marker == M_SOF2 || marker == M_SOF6 || marker == M_SOF10 || marker == M_SOF14)
670 components = READ8(p);
672 SKIPN(p, 1 * (block_size - readBits));
674 else if(marker == M_APP1)
679 if(READ32(p) == 0x45786966)
681 bool bMotorolla = false;
690 /* Discover byte order */
691 if(o1 == 'M' && o2 == 'M')
693 else if(o1 == 'I' && o2 == 'I')
703 unsigned int offset, a, b, numberOfTags, tagNumber;
705 // Get first IFD offset (offset to IFD0)
714 offset = (a << 8) + b;
721 offset = (b << 8) + a;
730 SKIPN(p, 1 * offset);
734 // Get the number of directory entries contained in this IFD
739 numberOfTags = (a << 8) + b;
745 numberOfTags = (b << 8) + a;
749 while(numberOfTags && p < q)
756 tagNumber = (a << 8) + b;
763 tagNumber = (b << 8) + a;
767 //found orientation tag
768 if(tagNumber == EXIF_TAG_ORIENTATION)
774 m_orientation = READ8(p);
783 m_orientation = READ8(p);
800 SKIPN(p, 1 * (block_size - readBits));
804 SKIPN(p, 1 * (block_size - 2));
813 if(m_orientation > 8)
816 if(eCompressionFormat == OMX_IMAGE_CodingMax)
818 CLog::Log(LOGERROR, "%s::%s error unsupported image format\n", CLASSNAME, __func__);
823 CLog::Log(LOGWARNING, "%s::%s progressive images not supported by decoder\n", CLASSNAME, __func__);
824 eCompressionFormat = OMX_IMAGE_CodingMax;
829 CLog::Log(LOGWARNING, "%s::%s Only YUV images are supported by decoder\n", CLASSNAME, __func__);
830 eCompressionFormat = OMX_IMAGE_CodingMax;
833 return eCompressionFormat;
837 bool COMXImageFile::ReadFile(const CStdString& inputFile)
839 XFILE::CFile m_pFile;
840 m_filename = inputFile.c_str();
841 if(!m_pFile.Open(inputFile, 0))
843 CLog::Log(LOGERROR, "%s::%s %s not found\n", CLASSNAME, __func__, inputFile.c_str());
848 free(m_image_buffer);
849 m_image_buffer = NULL;
851 m_image_size = m_pFile.GetLength();
855 CLog::Log(LOGERROR, "%s::%s %s m_image_size zero\n", CLASSNAME, __func__, inputFile.c_str());
858 m_image_buffer = (uint8_t *)malloc(m_image_size);
861 CLog::Log(LOGERROR, "%s::%s %s m_image_buffer null (%lu)\n", CLASSNAME, __func__, inputFile.c_str(), m_image_size);
865 m_pFile.Read(m_image_buffer, m_image_size);
868 OMX_IMAGE_CODINGTYPE eCompressionFormat = GetCodingType(m_width, m_height);
869 if(eCompressionFormat != OMX_IMAGE_CodingJPEG)
871 CLog::Log(LOGERROR, "%s::%s %s GetCodingType=0x%x\n", CLASSNAME, __func__, inputFile.c_str(), eCompressionFormat);
875 if(m_width < 1 || m_height < 1)
877 CLog::Log(LOGERROR, "%s::%s %s m_width=%d m_height=%d\n", CLASSNAME, __func__, inputFile.c_str(), m_width, m_height);
887 #define CLASSNAME "COMXImageDec"
889 COMXImageDec::COMXImageDec()
891 m_decoded_buffer = NULL;
892 OMX_INIT_STRUCTURE(m_decoded_format);
895 COMXImageDec::~COMXImageDec()
899 OMX_INIT_STRUCTURE(m_decoded_format);
900 m_decoded_buffer = NULL;
903 void COMXImageDec::Close()
905 CSingleLock lock(m_OMXSection);
907 if(m_omx_decoder.IsInitialized())
909 m_omx_decoder.FlushInput();
910 m_omx_decoder.FreeInputBuffers();
912 if(m_omx_resize.IsInitialized())
914 m_omx_resize.FlushOutput();
915 m_omx_resize.FreeOutputBuffers();
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();
925 bool COMXImageDec::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height)
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)
931 OMX_PARAM_PORTDEFINITIONTYPE port_def;
932 OMX_INIT_STRUCTURE(port_def);
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);
939 port_def.nPortIndex = m_omx_resize.GetInputPort();
940 m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
942 m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
944 omx_err = m_omx_tunnel_decode.Establish();
945 if(omx_err != OMX_ErrorNone)
947 CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
950 omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
951 if(omx_err != OMX_ErrorNone)
953 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
957 port_def.nPortIndex = m_omx_resize.GetOutputPort();
958 m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
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;
969 omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
970 if(omx_err != OMX_ErrorNone)
972 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
981 CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
984 assert(m_decoded_format.nBufferCountActual == 1);
986 omx_err = m_omx_resize.AllocOutputBuffers();
987 if(omx_err != OMX_ErrorNone)
989 CLog::Log(LOGERROR, "%s::%s m_omx_resize.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
992 omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
993 if(omx_err != OMX_ErrorNone)
995 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
999 m_decoded_buffer = m_omx_resize.GetOutputBuffer();
1001 if(!m_decoded_buffer)
1003 CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
1007 omx_err = m_omx_resize.FillThisBuffer(m_decoded_buffer);
1008 if(omx_err != OMX_ErrorNone)
1010 CLog::Log(LOGERROR, "%s::%s m_omx_resize FillThisBuffer result(0x%x)\n", CLASSNAME, __func__, omx_err);
1014 // on subsequent port settings changed event, we just copy the port settings
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);
1022 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1023 OMX_INIT_STRUCTURE(port_def);
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);
1030 omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
1031 if(omx_err != OMX_ErrorNone)
1033 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
1036 m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
1037 m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
1042 bool COMXImageDec::Decode(const uint8_t *demuxer_content, unsigned demuxer_bytes, unsigned width, unsigned height, unsigned stride, void *pixels)
1044 CSingleLock lock(m_OMXSection);
1045 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1046 OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
1048 if(!demuxer_content || !demuxer_bytes)
1050 CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
1054 if(!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
1056 CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize\n", CLASSNAME, __func__);
1060 if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
1062 CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
1067 OMX_PARAM_PORTDEFINITIONTYPE portParam;
1068 OMX_INIT_STRUCTURE(portParam);
1069 portParam.nPortIndex = m_omx_decoder.GetInputPort();
1071 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
1072 if(omx_err != OMX_ErrorNone)
1074 CLog::Log(LOGERROR, "%s::%s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
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;
1082 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
1083 if(omx_err != OMX_ErrorNone)
1085 CLog::Log(LOGERROR, "%s::%s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
1089 omx_err = m_omx_decoder.AllocInputBuffers();
1090 if(omx_err != OMX_ErrorNone)
1092 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
1096 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
1097 if (omx_err != OMX_ErrorNone)
1099 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1103 while(demuxer_bytes > 0 || !m_decoded_buffer)
1108 omx_buffer = m_omx_decoder.GetInputBuffer(1000);
1109 if(omx_buffer == NULL)
1112 omx_buffer->nOffset = omx_buffer->nFlags = 0;
1114 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
1115 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
1117 demuxer_content += omx_buffer->nFilledLen;
1118 demuxer_bytes -= omx_buffer->nFilledLen;
1120 if(demuxer_bytes == 0)
1121 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1123 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1124 if (omx_err != OMX_ErrorNone)
1126 CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1132 // we've submitted all buffers so can wait now
1135 omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
1136 if(omx_err == OMX_ErrorNone)
1138 if (!HandlePortSettingChange(width, height))
1140 CLog::Log(LOGERROR, "%s::%s HandlePortSettingChange() failed\n", CLASSNAME, __func__);
1144 else if(omx_err == OMX_ErrorStreamCorrupt)
1146 CLog::Log(LOGERROR, "%s::%s - image not supported", CLASSNAME, __func__);
1149 else if(timeout || omx_err != OMX_ErrorTimeout)
1151 CLog::Log(LOGERROR, "%s::%s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, omx_err);
1156 omx_err = m_omx_resize.WaitForOutputDone(1000);
1157 if(omx_err != OMX_ErrorNone)
1159 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
1163 if(m_omx_decoder.BadState())
1166 assert(m_decoded_buffer->nFilledLen <= stride * height);
1167 memcpy( (char*)pixels, m_decoded_buffer->pBuffer, m_decoded_buffer->nFilledLen);
1176 #define CLASSNAME "COMXImageEnc"
1178 COMXImageEnc::COMXImageEnc()
1180 CSingleLock lock(m_OMXSection);
1181 OMX_INIT_STRUCTURE(m_encoded_format);
1182 m_encoded_buffer = NULL;
1185 COMXImageEnc::~COMXImageEnc()
1187 CSingleLock lock(m_OMXSection);
1189 OMX_INIT_STRUCTURE(m_encoded_format);
1190 m_encoded_buffer = NULL;
1191 if(m_omx_encoder.IsInitialized())
1192 m_omx_encoder.Deinitialize();
1195 bool COMXImageEnc::Encode(unsigned char *buffer, int size, unsigned width, unsigned height, unsigned int pitch)
1197 CSingleLock lock(m_OMXSection);
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);
1208 if (!buffer || !size)
1210 CLog::Log(LOGERROR, "%s::%s error no buffer\n", CLASSNAME, __func__);
1214 if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
1216 CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
1220 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1221 OMX_INIT_STRUCTURE(port_def);
1222 port_def.nPortIndex = m_omx_encoder.GetInputPort();
1224 omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1225 if(omx_err != OMX_ErrorNone)
1227 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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;
1239 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1240 if(omx_err != OMX_ErrorNone)
1242 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1246 OMX_INIT_STRUCTURE(port_def);
1247 port_def.nPortIndex = m_omx_encoder.GetOutputPort();
1249 omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1250 if(omx_err != OMX_ErrorNone)
1252 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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;
1264 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1265 if(omx_err != OMX_ErrorNone)
1267 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1271 OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
1272 OMX_INIT_STRUCTURE(qfactor);
1273 qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
1274 qfactor.nQFactor = 16;
1276 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
1277 if(omx_err != OMX_ErrorNone)
1279 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
1283 omx_err = m_omx_encoder.AllocInputBuffers();
1284 if(omx_err != OMX_ErrorNone)
1286 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
1290 omx_err = m_omx_encoder.AllocOutputBuffers();
1291 if(omx_err != OMX_ErrorNone)
1293 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
1297 omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
1298 if (omx_err != OMX_ErrorNone)
1300 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1304 demuxer_content = buffer;
1305 demuxer_bytes = height * pitch;
1307 if(!demuxer_bytes || !demuxer_content)
1310 while(demuxer_bytes > 0)
1312 omx_buffer = m_omx_encoder.GetInputBuffer(1000);
1313 if(omx_buffer == NULL)
1318 omx_buffer->nOffset = omx_buffer->nFlags = 0;
1320 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
1321 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
1323 demuxer_content += omx_buffer->nFilledLen;
1324 demuxer_bytes -= omx_buffer->nFilledLen;
1326 if(demuxer_bytes == 0)
1327 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1329 omx_err = m_omx_encoder.EmptyThisBuffer(omx_buffer);
1330 if (omx_err != OMX_ErrorNone)
1332 CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1337 m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
1339 if(!m_encoded_buffer)
1341 CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
1345 omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
1346 if(omx_err != OMX_ErrorNone)
1349 omx_err = m_omx_encoder.WaitForOutputDone(1000);
1350 if(omx_err != OMX_ErrorNone)
1352 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1360 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1364 if(m_omx_encoder.BadState())
1370 bool COMXImageEnc::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
1371 unsigned int format, unsigned int pitch, const CStdString& destFile)
1373 if(format != XB_FMT_A8R8G8B8 || !buffer)
1375 CLog::Log(LOGDEBUG, "%s::%s : %s failed format=0x%x\n", CLASSNAME, __func__, destFile.c_str(), format);
1379 if(!Encode(buffer, height * pitch, width, height, pitch))
1381 CLog::Log(LOGDEBUG, "%s::%s : %s encode failed\n", CLASSNAME, __func__, destFile.c_str());
1386 if (file.OpenForWrite(destFile, true))
1388 CLog::Log(LOGDEBUG, "%s::%s : %s width %d height %d\n", CLASSNAME, __func__, destFile.c_str(), width, height);
1390 file.Write(m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen);
1401 #define CLASSNAME "COMXReEnc"
1403 COMXImageReEnc::COMXImageReEnc()
1405 m_encoded_buffer = NULL;
1406 m_pDestBuffer = NULL;
1407 m_nDestAllocSize = 0;
1410 COMXImageReEnc::~COMXImageReEnc()
1414 free (m_pDestBuffer);
1415 m_pDestBuffer = NULL;
1416 m_nDestAllocSize = 0;
1419 void COMXImageReEnc::Close()
1421 CSingleLock lock(m_OMXSection);
1423 if(m_omx_decoder.IsInitialized())
1425 m_omx_decoder.FlushInput();
1426 m_omx_decoder.FreeInputBuffers();
1428 if(m_omx_encoder.IsInitialized())
1430 m_omx_encoder.FlushOutput();
1431 m_omx_encoder.FreeOutputBuffers();
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();
1447 bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, bool port_settings_changed)
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)
1453 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1454 OMX_INIT_STRUCTURE(port_def);
1456 port_def.nPortIndex = m_omx_decoder.GetOutputPort();
1457 m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1458 if(omx_err != OMX_ErrorNone)
1460 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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;
1469 m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1470 if(omx_err != OMX_ErrorNone)
1472 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1476 if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
1478 CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
1482 port_def.nPortIndex = m_omx_resize.GetInputPort();
1484 m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1485 if(omx_err != OMX_ErrorNone)
1487 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1491 port_def.nPortIndex = m_omx_resize.GetOutputPort();
1492 m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1493 if(omx_err != OMX_ErrorNone)
1495 CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1506 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1510 if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
1512 CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
1516 port_def.nPortIndex = m_omx_encoder.GetInputPort();
1517 m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
1518 if(omx_err != OMX_ErrorNone)
1520 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1531 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1539 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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;
1551 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1552 if(omx_err != OMX_ErrorNone)
1554 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1558 OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
1559 OMX_INIT_STRUCTURE(qfactor);
1560 qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
1561 qfactor.nQFactor = 16;
1563 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
1564 if(omx_err != OMX_ErrorNone)
1566 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
1570 omx_err = m_omx_encoder.AllocOutputBuffers();
1571 if(omx_err != OMX_ErrorNone)
1573 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
1577 m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
1579 omx_err = m_omx_tunnel_decode.Establish();
1580 if(omx_err != OMX_ErrorNone)
1582 CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
1586 m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
1588 omx_err = m_omx_tunnel_resize.Establish();
1589 if(omx_err != OMX_ErrorNone)
1591 CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
1595 omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
1596 if(omx_err != OMX_ErrorNone)
1598 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1602 omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
1603 if (omx_err != OMX_ErrorNone)
1605 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1609 if(m_omx_encoder.BadState())
1612 // on subsequent port settings changed event, we just copy the port settings
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);
1620 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1621 OMX_INIT_STRUCTURE(port_def);
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);
1628 omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
1629 if(omx_err != OMX_ErrorNone)
1631 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
1634 m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
1635 m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
1640 bool COMXImageReEnc::ReEncode(COMXImageFile &srcFile, unsigned int maxWidth, unsigned int maxHeight, void * &pDestBuffer, unsigned int &nDestSize)
1642 CSingleLock lock(m_OMXSection);
1643 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
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
1651 if(!demuxer_content || !demuxer_bytes)
1653 CLog::Log(LOGERROR, "%s::%s %s no input buffer\n", CLASSNAME, __func__, srcFile.GetFilename());
1657 if(!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
1659 CLog::Log(LOGERROR, "%s::%s %s error m_omx_decoder.Initialize\n", CLASSNAME, __func__, srcFile.GetFilename());
1664 OMX_PARAM_PORTDEFINITIONTYPE portParam;
1665 OMX_INIT_STRUCTURE(portParam);
1666 portParam.nPortIndex = m_omx_decoder.GetInputPort();
1668 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
1669 if(omx_err != OMX_ErrorNone)
1671 CLog::Log(LOGERROR, "%s::%s %s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
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;
1679 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
1680 if(omx_err != OMX_ErrorNone)
1682 CLog::Log(LOGERROR, "%s::%s %s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1686 omx_err = m_omx_decoder.AllocInputBuffers();
1687 if(omx_err != OMX_ErrorNone)
1689 CLog::Log(LOGERROR, "%s::%s %s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1693 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
1694 if (omx_err != OMX_ErrorNone)
1696 CLog::Log(LOGERROR, "%s::%s %s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1700 bool port_settings_changed = false, eos = false;
1701 while(demuxer_bytes > 0 || !port_settings_changed || !eos)
1706 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
1709 omx_buffer->nOffset = omx_buffer->nFlags = 0;
1711 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
1712 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
1714 demuxer_content += omx_buffer->nFilledLen;
1715 demuxer_bytes -= omx_buffer->nFilledLen;
1716 if(demuxer_bytes == 0)
1717 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
1719 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1720 if (omx_err != OMX_ErrorNone)
1722 CLog::Log(LOGERROR, "%s::%s %s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1729 // we've submitted all buffers so can wait now
1733 omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
1734 if(omx_err == OMX_ErrorNone)
1736 if (!HandlePortSettingChange(maxWidth, maxHeight, port_settings_changed))
1738 CLog::Log(LOGERROR, "%s::%s %s HandlePortSettingChange() failed\n", srcFile.GetFilename(), CLASSNAME, __func__);
1741 port_settings_changed = true;
1743 else if(omx_err == OMX_ErrorStreamCorrupt)
1745 CLog::Log(LOGERROR, "%s::%s %s - image not supported", CLASSNAME, __func__, srcFile.GetFilename());
1748 else if(timeout || omx_err != OMX_ErrorTimeout)
1750 CLog::Log(LOGERROR, "%s::%s %s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1754 if (!m_encoded_buffer && port_settings_changed && demuxer_bytes == 0)
1756 m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
1757 omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
1758 if(omx_err != OMX_ErrorNone)
1760 CLog::Log(LOGERROR, "%s::%s %s FillThisBuffer() failed (%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1764 if (m_encoded_buffer)
1766 omx_err = m_omx_encoder.WaitForOutputDone(1000);
1767 if (omx_err != OMX_ErrorNone)
1769 CLog::Log(LOGERROR, "%s::%s %s m_omx_encoder.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, srcFile.GetFilename(), omx_err);
1772 if (!m_encoded_buffer->nFilledLen)
1774 CLog::Log(LOGERROR, "%s::%s %s m_omx_encoder.WaitForOutputDone no data\n", CLASSNAME, __func__, srcFile.GetFilename());
1777 if (m_encoded_buffer->nFlags & OMX_BUFFERFLAG_EOS)
1780 if (nDestSize + m_encoded_buffer->nFilledLen > m_nDestAllocSize)
1782 m_nDestAllocSize = std::max(1024U*1024U, m_nDestAllocSize*2);
1783 m_pDestBuffer = realloc(m_pDestBuffer, m_nDestAllocSize);
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;
1793 if(m_omx_decoder.BadState())
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);
1806 #define CLASSNAME "COMXTexture"
1808 COMXTexture::COMXTexture()
1812 COMXTexture::~COMXTexture()
1817 void COMXTexture::Close()
1819 CSingleLock lock(m_OMXSection);
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();
1834 bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height, void *egl_image, void *egl_display, bool port_settings_changed)
1836 OMX_ERRORTYPE omx_err;
1838 if (port_settings_changed)
1839 CLog::Log(LOGERROR, "%s::%s Unexpected second port_settings_changed call\n", CLASSNAME, __func__);
1841 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1842 OMX_INIT_STRUCTURE(port_def);
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)
1848 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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;
1857 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1858 if (omx_err != OMX_ErrorNone)
1860 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1864 if (!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
1866 CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize", CLASSNAME, __func__);
1870 port_def.nPortIndex = m_omx_resize.GetInputPort();
1872 omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1873 if (omx_err != OMX_ErrorNone)
1875 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1883 CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1895 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1899 if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit))
1901 CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
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)
1909 CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1912 port_def.nBufferCountActual = 1;
1913 port_def.format.video.pNativeWindow = egl_display;
1915 omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamPortDefinition, &port_def);
1916 if (omx_err != OMX_ErrorNone)
1918 CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
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)
1925 CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.UseEGLImage (%x)", CLASSNAME, __func__, omx_err);
1929 m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
1931 omx_err = m_omx_tunnel_decode.Establish();
1932 if (omx_err != OMX_ErrorNone)
1934 CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
1938 m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
1940 omx_err = m_omx_tunnel_egl.Establish();
1941 if (omx_err != OMX_ErrorNone)
1943 CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
1947 omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
1948 if (omx_err != OMX_ErrorNone)
1950 CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
1954 omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
1955 if (omx_err != OMX_ErrorNone)
1957 CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.SetStateForComponent (%x)", CLASSNAME, __func__, omx_err);
1964 bool COMXTexture::Decode(const uint8_t *demuxer_content, unsigned demuxer_bytes, unsigned int width, unsigned int height, void *egl_image, void *egl_display)
1966 CSingleLock lock(m_OMXSection);
1967 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1969 if (!demuxer_content || !demuxer_bytes)
1971 CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
1975 if (!m_omx_decoder.Initialize("OMX.broadcom.image_decode", OMX_IndexParamImageInit))
1977 CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize", CLASSNAME, __func__);
1982 OMX_PARAM_PORTDEFINITIONTYPE portParam;
1983 OMX_INIT_STRUCTURE(portParam);
1984 portParam.nPortIndex = m_omx_decoder.GetInputPort();
1986 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
1987 if (omx_err != OMX_ErrorNone)
1989 CLog::Log(LOGERROR, "%s::%s error GetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
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;
1997 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
1998 if (omx_err != OMX_ErrorNone)
2000 CLog::Log(LOGERROR, "%s::%s error SetParameter:OMX_IndexParamPortDefinition omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
2004 omx_err = m_omx_decoder.AllocInputBuffers();
2005 if (omx_err != OMX_ErrorNone)
2007 CLog::Log(LOGERROR, "%s::%s - Error alloc buffers (%x)", CLASSNAME, __func__, omx_err);
2011 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
2012 if (omx_err != OMX_ErrorNone)
2014 CLog::Log(LOGERROR, "%s::%s error m_omx_sched.SetStateForComponent (%x)", CLASSNAME, __func__, omx_err);
2018 bool port_settings_changed = false;
2020 while(demuxer_bytes > 0 || !port_settings_changed || !eos)
2025 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
2028 omx_buffer->nOffset = omx_buffer->nFlags = 0;
2030 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
2031 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
2033 demuxer_content += omx_buffer->nFilledLen;
2034 demuxer_bytes -= omx_buffer->nFilledLen;
2036 if (demuxer_bytes == 0)
2037 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
2039 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
2040 if (omx_err != OMX_ErrorNone)
2042 CLog::Log(LOGERROR, "%s::%s - m_omx_decoder.OMX_EmptyThisBuffer (%x)", CLASSNAME, __func__, omx_err);
2049 // we've submitted all buffers so can wait now
2053 omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
2054 if (omx_err == OMX_ErrorNone)
2056 if (!HandlePortSettingChange(width, height, egl_image, egl_display, port_settings_changed))
2058 CLog::Log(LOGERROR, "%s::%s - HandlePortSettingChange failed (%x)", CLASSNAME, __func__, omx_err);
2061 port_settings_changed = true;
2063 else if (omx_err == OMX_ErrorStreamCorrupt)
2065 CLog::Log(LOGERROR, "%s::%s - image not supported", CLASSNAME, __func__);
2068 else if (timeout || omx_err != OMX_ErrorTimeout)
2070 CLog::Log(LOGERROR, "%s::%s WaitForEvent:OMX_EventPortSettingsChanged failed (%x)\n", CLASSNAME, __func__, omx_err);
2074 if (port_settings_changed && m_egl_buffer && demuxer_bytes == 0 && !eos)
2076 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_egl_render.GetOutputBuffer();
2079 CLog::Log(LOGERROR, "%s::%s GetOutputBuffer failed\n", CLASSNAME, __func__);
2082 if (omx_buffer != m_egl_buffer)
2084 CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetOutputBuffer (%p,%p)", CLASSNAME, __func__, omx_buffer, m_egl_buffer);
2088 omx_err = m_omx_egl_render.FillThisBuffer(m_egl_buffer);
2089 if (omx_err != OMX_ErrorNone)
2091 CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.FillThisBuffer (%x)", CLASSNAME, __func__, omx_err);
2095 omx_err = m_omx_egl_render.WaitForOutputDone(1000);
2096 if (omx_err != OMX_ErrorNone)
2098 CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.WaitForOutputDone result(0x%x)\n", CLASSNAME, __func__, omx_err);
2108 COMXImage g_OMXImage;