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 WIN32)
29 #include "utils/log.h"
30 #include "linux/XMemUtils.h"
32 #include "utils/BitstreamConverter.h"
36 #include "settings/GUISettings.h"
37 #include "settings/Settings.h"
38 #include "settings/AdvancedSettings.h"
43 #define CLASSNAME "COMXImage"
45 #define CONTENTURI_MAXLEN 256
47 #define EXIF_TAG_ORIENTATION 0x0112
49 static CCriticalSection g_OMXSection;
51 COMXImage::COMXImage()
55 m_image_buffer = NULL;
56 m_progressive = false;
63 m_decoded_buffer = NULL;
64 m_encoded_buffer = NULL;
66 m_decoder_open = false;
67 m_encoder_open = false;
69 OMX_INIT_STRUCTURE(m_decoded_format);
70 OMX_INIT_STRUCTURE(m_encoded_format);
71 memset(&m_omx_image, 0x0, sizeof(OMX_IMAGE_PORTDEFINITIONTYPE));
74 COMXImage::~COMXImage()
79 void COMXImage::Close()
81 CSingleLock lock(g_OMXSection);
83 OMX_INIT_STRUCTURE(m_decoded_format);
84 OMX_INIT_STRUCTURE(m_encoded_format);
85 memset(&m_omx_image, 0x0, sizeof(OMX_IMAGE_PORTDEFINITIONTYPE));
90 m_image_buffer = NULL;
95 m_progressive = false;
97 m_decoded_buffer = NULL;
98 m_encoded_buffer = NULL;
102 m_omx_decoder.FlushInput();
103 m_omx_decoder.FreeInputBuffers();
104 m_omx_resize.FlushOutput();
105 m_omx_resize.FreeOutputBuffers();
107 m_omx_tunnel_decode.Flush();
108 m_omx_tunnel_decode.Flush();
109 m_omx_tunnel_decode.Deestablish();
110 m_omx_decoder.Deinitialize();
111 m_omx_resize.Deinitialize();
112 m_decoder_open = false;
117 m_omx_encoder.Deinitialize();
118 m_encoder_open = false;
124 typedef enum { /* JPEG marker codes */
198 OMX_IMAGE_CODINGTYPE COMXImage::GetCodingType()
200 memset(&m_omx_image, 0x0, sizeof(OMX_IMAGE_PORTDEFINITIONTYPE));
203 m_progressive = false;
206 m_omx_image.eCompressionFormat = OMX_IMAGE_CodingMax;
209 return OMX_IMAGE_CodingMax;
212 CBitstreamConverter::bits_reader_set( &br, m_image_buffer, m_image_size );
215 if(CBitstreamConverter::read_bits(&br, 16) == 0xFFD8)
217 m_omx_image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
219 CBitstreamConverter::read_bits(&br, 8);
220 unsigned char marker = CBitstreamConverter::read_bits(&br, 8);
221 unsigned short block_size = 0;
222 bool nMarker = false;
230 CBitstreamConverter::skip_bits(&br, 16);
295 block_size = CBitstreamConverter::read_bits(&br, 16);
309 if(marker >= M_SOF0 && marker <= M_SOF15 && marker != M_DHT && marker != M_DAC)
311 if(marker == M_SOF2 || marker == M_SOF6 || marker == M_SOF10 || marker == M_SOF14)
313 m_progressive = true;
315 CBitstreamConverter::skip_bits(&br, 8);
316 m_omx_image.nFrameHeight = CBitstreamConverter::read_bits(&br, 16);
317 m_omx_image.nFrameWidth = CBitstreamConverter::read_bits(&br, 16);
318 CBitstreamConverter::skip_bits(&br, 8 * (block_size - 9));
320 else if(marker == M_APP1)
323 bool bMotorolla = false;
327 if(CBitstreamConverter::read_bits(&br, 32) == 0x45786966)
329 CBitstreamConverter::skip_bits(&br, 8 * 2);
332 char o1 = CBitstreamConverter::read_bits(&br, 8);
333 char o2 = CBitstreamConverter::read_bits(&br, 8);
336 /* Discover byte order */
337 if(o1 == 'M' && o2 == 'M')
339 else if(o1 == 'I' && o2 == 'I')
344 CBitstreamConverter::skip_bits(&br, 8 * 2);
349 unsigned int offset, a, b, numberOfTags, tagNumber;
351 // Get first IFD offset (offset to IFD0)
354 CBitstreamConverter::skip_bits(&br, 8 * 2);
357 a = CBitstreamConverter::read_bits(&br, 8);
358 b = CBitstreamConverter::read_bits(&br, 8);
360 offset = (a << 8) + b;
364 a = CBitstreamConverter::read_bits(&br, 8);
365 b = CBitstreamConverter::read_bits(&br, 8);
367 offset = (b << 8) + a;
369 CBitstreamConverter::skip_bits(&br, 8 * 2);
376 CBitstreamConverter::skip_bits(&br, 8 * offset);
380 // Get the number of directory entries contained in this IFD
383 a = CBitstreamConverter::read_bits(&br, 8);
384 b = CBitstreamConverter::read_bits(&br, 8);
385 numberOfTags = (a << 8) + b;
389 a = CBitstreamConverter::read_bits(&br, 8);
390 b = CBitstreamConverter::read_bits(&br, 8);
391 numberOfTags = (b << 8) + a;
395 while(numberOfTags && !br.oflow)
400 a = CBitstreamConverter::read_bits(&br, 8);
401 b = CBitstreamConverter::read_bits(&br, 8);
402 tagNumber = (a << 8) + b;
407 a = CBitstreamConverter::read_bits(&br, 8);
408 b = CBitstreamConverter::read_bits(&br, 8);
409 tagNumber = (b << 8) + a;
413 //found orientation tag
414 if(tagNumber == EXIF_TAG_ORIENTATION)
418 CBitstreamConverter::skip_bits(&br, 8 * 7);
420 m_orientation = CBitstreamConverter::read_bits(&br, 8);
422 CBitstreamConverter::skip_bits(&br, 8 * 2);
427 CBitstreamConverter::skip_bits(&br, 8 * 6);
429 m_orientation = CBitstreamConverter::read_bits(&br, 8);
431 CBitstreamConverter::skip_bits(&br, 8 * 3);
438 CBitstreamConverter::skip_bits(&br, 8 * 10);
446 CBitstreamConverter::skip_bits(&br, 8 * (block_size - readBits));
450 CBitstreamConverter::skip_bits(&br, 8 * (block_size - 2));
453 CBitstreamConverter::read_bits(&br, 8);
454 marker = CBitstreamConverter::read_bits(&br, 8);
460 CBitstreamConverter::bits_reader_set( &br, m_image_buffer, m_image_size );
463 if(CBitstreamConverter::read_bits(&br, 32) == 0x89504E47)
465 m_omx_image.eCompressionFormat = OMX_IMAGE_CodingPNG;
466 CBitstreamConverter::skip_bits(&br, 32 * 2);
467 if(CBitstreamConverter::read_bits(&br, 32) == 0x49484452)
469 m_omx_image.nFrameWidth = CBitstreamConverter::read_bits(&br, 32);
470 m_omx_image.nFrameHeight = CBitstreamConverter::read_bits(&br, 32);
471 (void)CBitstreamConverter::read_bits(&br, 8); // bit depth
472 unsigned int coding_type = CBitstreamConverter::read_bits(&br, 8);
473 m_alpha = coding_type==4 || coding_type==6;
477 if(m_orientation > 8)
480 m_width = m_omx_image.nFrameWidth;
481 m_height = m_omx_image.nFrameHeight;
483 return m_omx_image.eCompressionFormat;
486 bool COMXImage::ClampLimits(unsigned int &width, unsigned int &height)
488 RESOLUTION_INFO& res_info = g_settings.m_ResInfo[g_graphicsContext.GetVideoResolution()];
489 const bool transposed = m_orientation & 4;
490 const int gui_width = transposed ? res_info.iHeight:res_info.iWidth;
491 const int gui_height = transposed ? res_info.iWidth:res_info.iHeight;
492 const unsigned int max_width = min(gui_width, 2048);
493 const unsigned int max_height = min(gui_height, 2048);
495 if(!max_width || !max_height)
498 const float ar = (float)width/(float)height;
499 // bigger than maximum, so need to clamp
500 if (width > max_width || height > max_height) {
501 // wider than max, so clamp width first
502 if (ar > (float)max_width/(float)max_height)
505 height = (float)max_width / ar + 0.5f;
506 // taller than max, so clamp height first
509 width = (float)max_height * ar + 0.5f;
517 bool COMXImage::ReadFile(const CStdString& inputFile)
519 if(!m_pFile.Open(inputFile, 0))
521 CLog::Log(LOGERROR, "%s::%s %s not found\n", CLASSNAME, __func__, inputFile.c_str());
526 free(m_image_buffer);
527 m_image_buffer = NULL;
529 m_image_size = m_pFile.GetLength();
532 CLog::Log(LOGERROR, "%s::%s %s m_image_size zero\n", CLASSNAME, __func__, inputFile.c_str());
535 m_image_buffer = (uint8_t *)malloc(m_image_size);
536 if(!m_image_buffer) {
537 CLog::Log(LOGERROR, "%s::%s %s m_image_buffer null (%lu)\n", CLASSNAME, __func__, inputFile.c_str(), m_image_size);
541 m_pFile.Read(m_image_buffer, m_image_size);
543 if(GetCodingType() != OMX_IMAGE_CodingJPEG) {
544 CLog::Log(LOGERROR, "%s::%s %s GetCodingType=0x%x\n", CLASSNAME, __func__, inputFile.c_str(), GetCodingType());
548 if(m_width < 1 || m_height < 1) {
549 CLog::Log(LOGERROR, "%s::%s %s m_width=%d m_height=%d\n", CLASSNAME, __func__, inputFile.c_str(), m_width, m_height);
552 ClampLimits(m_width, m_height);
559 bool COMXImage::HandlePortSettingChange(unsigned int resize_width, unsigned int resize_height)
561 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
562 // on the first port settings changed event, we create the tunnel and alloc the buffer
563 if (!m_decoded_buffer)
565 OMX_PARAM_PORTDEFINITIONTYPE port_def;
566 OMX_INIT_STRUCTURE(port_def);
568 port_def.nPortIndex = m_omx_decoder.GetOutputPort();
569 m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
570 port_def.nPortIndex = m_omx_resize.GetInputPort();
571 m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
573 m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
575 omx_err = m_omx_tunnel_decode.Establish(false);
576 if(omx_err != OMX_ErrorNone)
578 CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
581 omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
582 if(omx_err != OMX_ErrorNone)
584 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
588 port_def.nPortIndex = m_omx_resize.GetOutputPort();
589 m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
591 port_def.nPortIndex = m_omx_resize.GetOutputPort();
592 port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
593 port_def.format.image.eColorFormat = OMX_COLOR_Format32bitARGB8888;
594 port_def.format.image.nFrameWidth = resize_width;
595 port_def.format.image.nFrameHeight = resize_height;
596 port_def.format.image.nStride = resize_width*4;
597 port_def.format.image.nSliceHeight = 0;
598 port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
600 omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
601 if(omx_err != OMX_ErrorNone)
603 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
607 OMX_INIT_STRUCTURE(m_decoded_format);
608 m_decoded_format.nPortIndex = m_omx_resize.GetOutputPort();
609 omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &m_decoded_format);
610 if(omx_err != OMX_ErrorNone)
612 CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
615 assert(m_decoded_format.nBufferCountActual == 1);
617 omx_err = m_omx_resize.AllocOutputBuffers();//false, true);
618 if(omx_err != OMX_ErrorNone)
620 CLog::Log(LOGERROR, "%s::%s m_omx_resize.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
623 omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
624 if(omx_err != OMX_ErrorNone)
626 CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
630 m_decoded_buffer = m_omx_resize.GetOutputBuffer();
632 if(!m_decoded_buffer)
634 CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
638 omx_err = m_omx_resize.FillThisBuffer(m_decoded_buffer);
639 if(omx_err != OMX_ErrorNone)
641 CLog::Log(LOGERROR, "%s::%s m_omx_resize FillThisBuffer result(0x%x)\n", CLASSNAME, __func__, omx_err);
645 // on subsequent port settings changed event, we just copy the port settings
648 // a little surprising, make a note
649 CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
650 m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
651 m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
653 OMX_PARAM_PORTDEFINITIONTYPE port_def;
654 OMX_INIT_STRUCTURE(port_def);
656 port_def.nPortIndex = m_omx_decoder.GetOutputPort();
657 m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
658 port_def.nPortIndex = m_omx_resize.GetInputPort();
659 m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
661 omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
662 if(omx_err != OMX_ErrorNone)
664 CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
667 m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
668 m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
673 bool COMXImage::Decode(unsigned width, unsigned height)
675 CSingleLock lock(g_OMXSection);
676 std::string componentName = "";
677 unsigned int demuxer_bytes = 0;
678 const uint8_t *demuxer_content = NULL;
679 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
680 OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
684 CLog::Log(LOGERROR, "%s::%s no input buffer\n", CLASSNAME, __func__);
688 if(GetCompressionFormat() == OMX_IMAGE_CodingMax)
690 CLog::Log(LOGERROR, "%s::%s error unsupported image format\n", CLASSNAME, __func__);
696 CLog::Log(LOGWARNING, "%s::%s progressive images not supported by decoder\n", CLASSNAME, __func__);
702 CLog::Log(LOGERROR, "%s::%s error not opened\n", CLASSNAME, __func__);
706 componentName = "OMX.broadcom.image_decode";
707 if(!m_omx_decoder.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
709 CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize\n", CLASSNAME, __func__);
713 componentName = "OMX.broadcom.resize";
714 if(!m_omx_resize.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
716 CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
720 m_decoder_open = true;
722 if(width == 0 || height == 0)
724 height = g_advancedSettings.m_imageRes;
725 if (g_advancedSettings.m_fanartRes > g_advancedSettings.m_imageRes)
726 { // a separate fanart resolution is specified - check if the image is exactly equal to this res
727 if (m_width == (unsigned int)g_advancedSettings.m_fanartRes * 16/9 &&
728 m_height == (unsigned int)g_advancedSettings.m_fanartRes)
729 { // special case for fanart res
730 height = g_advancedSettings.m_fanartRes;
733 width = height * 16/9;
734 if(!width || !height)
736 width = g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution].iWidth;
737 height = g_settings.m_ResInfo[g_guiSettings.m_LookAndFeelResolution].iHeight;
741 ClampLimits(width, height);
744 OMX_IMAGE_PARAM_PORTFORMATTYPE imagePortFormat;
745 OMX_INIT_STRUCTURE(imagePortFormat);
746 imagePortFormat.nPortIndex = m_omx_decoder.GetInputPort();
747 imagePortFormat.eCompressionFormat = OMX_IMAGE_CodingJPEG;
749 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamImagePortFormat, &imagePortFormat);
750 if(omx_err != OMX_ErrorNone)
752 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter OMX_IndexParamImagePortFormat result(0x%x)\n", CLASSNAME, __func__, omx_err);
756 omx_err = m_omx_decoder.AllocInputBuffers();
757 if(omx_err != OMX_ErrorNone)
759 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
763 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
764 if (omx_err != OMX_ErrorNone)
766 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
770 demuxer_bytes = GetImageSize();
771 demuxer_content = GetImageBuffer();
772 if(!demuxer_bytes || !demuxer_content)
775 while(demuxer_bytes > 0 || !m_decoded_buffer)
780 omx_buffer = m_omx_decoder.GetInputBuffer(1000);
781 if(omx_buffer == NULL)
784 omx_buffer->nOffset = omx_buffer->nFlags = 0;
786 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
787 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
789 demuxer_content += omx_buffer->nFilledLen;
790 demuxer_bytes -= omx_buffer->nFilledLen;
792 if(demuxer_bytes == 0)
793 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
795 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
796 if (omx_err != OMX_ErrorNone)
798 CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
804 // we've submitted all buffers so can wait now
807 omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, timeout);
808 if(omx_err == OMX_ErrorNone)
810 if (!HandlePortSettingChange(width, height))
812 CLog::Log(LOGERROR, "%s::%s HandlePortSettingChange() failed\n", CLASSNAME, __func__);
816 // we treat it as an error if a real timeout occurred
819 CLog::Log(LOGERROR, "%s::%s HandlePortSettingChange() failed\n", CLASSNAME, __func__);
824 omx_err = m_omx_decoder.WaitForEvent(OMX_EventBufferFlag, 1000);
825 if(omx_err != OMX_ErrorNone)
827 CLog::Log(LOGERROR, "%s::%s m_omx_decoder.WaitForEvent result(0x%x)\n", CLASSNAME, __func__, omx_err);
831 m_omx_tunnel_decode.Deestablish();
833 if(m_omx_decoder.BadState())
840 bool COMXImage::Encode(unsigned char *buffer, int size, unsigned width, unsigned height, unsigned int pitch)
842 CSingleLock lock(g_OMXSection);
844 std::string componentName = "";
845 unsigned int demuxer_bytes = 0;
846 const uint8_t *demuxer_content = NULL;
847 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
848 OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
849 OMX_INIT_STRUCTURE(m_encoded_format);
854 if (!buffer || !size)
856 CLog::Log(LOGERROR, "%s::%s error no buffer\n", CLASSNAME, __func__);
860 componentName = "OMX.broadcom.image_encode";
861 if(!m_omx_encoder.Initialize((const std::string)componentName, OMX_IndexParamImageInit))
863 CLog::Log(LOGERROR, "%s::%s error m_omx_encoder.Initialize\n", CLASSNAME, __func__);
867 m_encoder_open = true;
869 OMX_PARAM_PORTDEFINITIONTYPE port_def;
870 OMX_INIT_STRUCTURE(port_def);
871 port_def.nPortIndex = m_omx_encoder.GetInputPort();
873 omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
874 if(omx_err != OMX_ErrorNone)
876 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
880 port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
881 port_def.format.image.eColorFormat = OMX_COLOR_Format32bitARGB8888;
882 port_def.format.image.nFrameWidth = width;
883 port_def.format.image.nFrameHeight = height;
884 port_def.format.image.nStride = pitch;
885 port_def.format.image.nSliceHeight = (height+15) & ~15;
886 port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
888 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
889 if(omx_err != OMX_ErrorNone)
891 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
895 OMX_INIT_STRUCTURE(port_def);
896 port_def.nPortIndex = m_omx_encoder.GetOutputPort();
898 omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
899 if(omx_err != OMX_ErrorNone)
901 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
905 port_def.format.image.eCompressionFormat = OMX_IMAGE_CodingJPEG;
906 port_def.format.image.eColorFormat = OMX_COLOR_FormatUnused;
907 port_def.format.image.nFrameWidth = width;
908 port_def.format.image.nFrameHeight = height;
909 port_def.format.image.nStride = 0;
910 port_def.format.image.nSliceHeight = 0;
911 port_def.format.image.bFlagErrorConcealment = OMX_FALSE;
913 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
914 if(omx_err != OMX_ErrorNone)
916 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
920 OMX_IMAGE_PARAM_QFACTORTYPE qfactor;
921 OMX_INIT_STRUCTURE(qfactor);
922 qfactor.nPortIndex = m_omx_encoder.GetOutputPort();
923 qfactor.nQFactor = 16;
925 omx_err = m_omx_encoder.SetParameter(OMX_IndexParamQFactor, &qfactor);
926 if(omx_err != OMX_ErrorNone)
928 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetParameter OMX_IndexParamQFactor result(0x%x)\n", CLASSNAME, __func__, omx_err);
932 omx_err = m_omx_encoder.AllocInputBuffers();
933 if(omx_err != OMX_ErrorNone)
935 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocInputBuffers result(0x%x)", CLASSNAME, __func__, omx_err);
939 omx_err = m_omx_encoder.AllocOutputBuffers();
940 if(omx_err != OMX_ErrorNone)
942 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.AllocOutputBuffers result(0x%x)\n", CLASSNAME, __func__, omx_err);
946 omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
947 if (omx_err != OMX_ErrorNone)
949 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
953 demuxer_content = buffer;
954 demuxer_bytes = height * pitch;
956 if(!demuxer_bytes || !demuxer_content)
959 while(demuxer_bytes > 0)
961 omx_buffer = m_omx_encoder.GetInputBuffer(1000);
962 if(omx_buffer == NULL)
967 omx_buffer->nOffset = omx_buffer->nFlags = 0;
969 omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
970 memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
972 demuxer_content += omx_buffer->nFilledLen;
973 demuxer_bytes -= omx_buffer->nFilledLen;
975 if(demuxer_bytes == 0)
976 omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
978 omx_err = m_omx_encoder.EmptyThisBuffer(omx_buffer);
979 if (omx_err != OMX_ErrorNone)
981 CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
986 m_encoded_buffer = m_omx_encoder.GetOutputBuffer();
988 if(!m_encoded_buffer)
990 CLog::Log(LOGERROR, "%s::%s no output buffer\n", CLASSNAME, __func__);
994 omx_err = m_omx_encoder.FillThisBuffer(m_encoded_buffer);
995 if(omx_err != OMX_ErrorNone)
998 omx_err = m_omx_encoder.WaitForEvent(OMX_EventBufferFlag, 1000);
999 if(omx_err != OMX_ErrorNone)
1001 CLog::Log(LOGERROR, "%s::%s m_omx_encoder WaitForEvent result(0x%x)\n", CLASSNAME, __func__, omx_err);
1005 m_encoded_format.nPortIndex = m_omx_encoder.GetOutputPort();
1006 omx_err = m_omx_encoder.GetParameter(OMX_IndexParamPortDefinition, &m_encoded_format);
1007 if(omx_err != OMX_ErrorNone)
1009 CLog::Log(LOGERROR, "%s::%s m_omx_encoder.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
1013 if(m_omx_encoder.BadState())
1019 unsigned char *COMXImage::GetDecodedData()
1021 if(!m_decoded_buffer)
1024 return (unsigned char *)m_decoded_buffer->pBuffer;
1027 unsigned int COMXImage::GetDecodedSize()
1029 if(!m_decoded_buffer)
1031 return (unsigned int)m_decoded_buffer->nFilledLen;
1034 unsigned char *COMXImage::GetEncodedData()
1036 if(!m_encoded_buffer)
1039 return (unsigned char *)m_encoded_buffer->pBuffer;
1042 unsigned int COMXImage::GetEncodedSize()
1044 if(!m_encoded_buffer)
1046 return (unsigned int)m_encoded_buffer->nFilledLen;
1049 bool COMXImage::SwapBlueRed(unsigned char *pixels, unsigned int height, unsigned int pitch,
1050 unsigned int elements, unsigned int offset)
1052 if (!pixels) return false;
1053 unsigned char *dst = pixels;
1054 for (unsigned int y = 0; y < height; y++)
1056 dst = pixels + (y * pitch);
1057 for (unsigned int x = 0; x < pitch; x+=elements)
1058 std::swap(dst[x+offset], dst[x+2+offset]);
1063 bool COMXImage::CreateThumbnail(const CStdString& sourceFile, const CStdString& destFile,
1064 int minx, int miny, bool rotateExif)
1066 if (!ReadFile(sourceFile))
1069 return CreateThumbnailFromMemory(m_image_buffer, m_image_size, destFile, minx, miny);
1072 bool COMXImage::CreateThumbnailFromMemory(unsigned char* buffer, unsigned int bufSize, const CStdString& destFile,
1073 unsigned int minx, unsigned int miny)
1075 if(!bufSize || !buffer)
1080 m_image_size = bufSize;
1081 m_image_buffer = (uint8_t *)malloc(m_image_size);
1085 memcpy(m_image_buffer, buffer, m_image_size);
1087 if(GetCodingType() != OMX_IMAGE_CodingJPEG) {
1088 CLog::Log(LOGERROR, "%s::%s : %s GetCodingType()=0x%x\n", CLASSNAME, __func__, destFile.c_str(), GetCodingType());
1094 if(!Decode(minx, miny))
1097 return CreateThumbnailFromSurface(GetDecodedData(), GetDecodedWidth(), GetDecodedHeight(),
1098 XB_FMT_A8R8G8B8, GetDecodedStride(), destFile);
1101 bool COMXImage::CreateThumbnailFromSurface(unsigned char* buffer, unsigned int width, unsigned int height,
1102 unsigned int format, unsigned int pitch, const CStdString& destFile)
1104 if(format != XB_FMT_A8R8G8B8 || !buffer) {
1105 CLog::Log(LOGDEBUG, "%s::%s : %s failed format=0x%x\n", CLASSNAME, __func__, destFile.c_str(), format);
1109 if(!Encode(buffer, height * pitch, width, height, pitch)) {
1110 CLog::Log(LOGDEBUG, "%s::%s : %s encode failed\n", CLASSNAME, __func__, destFile.c_str());
1115 if (file.OpenForWrite(destFile, true))
1117 CLog::Log(LOGDEBUG, "%s::%s : %s width %d height %d\n", CLASSNAME, __func__, destFile.c_str(), width, height);
1119 file.Write(GetEncodedData(), GetEncodedSize());