2 * Copyright (C) 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, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 // http://developer.android.com/reference/android/media/MediaCodec.html
24 // Android MediaCodec class can be used to access low-level media codec,
25 // i.e. encoder/decoder components. (android.media.MediaCodec). Requires
26 // SDK16+ which is 4.1 Jellybean and above.
29 #include "DVDVideoCodecAndroidMediaCodec.h"
31 #include "Application.h"
32 #include "ApplicationMessenger.h"
34 #include "threads/Atomics.h"
35 #include "utils/BitstreamConverter.h"
36 #include "utils/CPUInfo.h"
37 #include "utils/log.h"
39 #include "android/jni/ByteBuffer.h"
40 #include "android/jni/MediaCodec.h"
41 #include "android/jni/MediaCrypto.h"
42 #include "android/jni/MediaFormat.h"
43 #include "android/jni/MediaCodecList.h"
44 #include "android/jni/MediaCodecInfo.h"
45 #include "android/jni/Surface.h"
46 #include "android/jni/SurfaceTexture.h"
47 #include "android/activity/AndroidFeatures.h"
49 #include <GLES2/gl2.h>
50 #include <GLES2/gl2ext.h>
52 static bool CanSurfaceRenderWhiteList(const std::string &name)
54 // All devices 'should' be capiable of surface rendering
55 // but that seems to be hit or miss as most odd name devices
56 // cannot surface render.
57 static const char *cansurfacerender_decoders[] = {
65 for (const char **ptr = cansurfacerender_decoders; *ptr; ptr++)
67 if (!strnicmp(*ptr, name.c_str(), strlen(*ptr)))
73 static bool IsBlacklisted(const std::string &name)
75 static const char *blacklisted_decoders[] = {
76 // No software decoders
78 // For Rockchip non-standard components
90 for (const char **ptr = blacklisted_decoders; *ptr; ptr++)
92 if (!strnicmp(*ptr, name.c_str(), strlen(*ptr)))
98 static bool IsSupportedColorFormat(int color_format)
100 static const int supported_colorformats[] = {
101 CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar,
102 CJNIMediaCodecInfoCodecCapabilities::COLOR_TI_FormatYUV420PackedSemiPlanar,
103 CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420SemiPlanar,
104 CJNIMediaCodecInfoCodecCapabilities::COLOR_QCOM_FormatYUV420SemiPlanar,
105 CJNIMediaCodecInfoCodecCapabilities::OMX_QCOM_COLOR_FormatYVU420SemiPlanarInterlace,
108 for (const int *ptr = supported_colorformats; *ptr != -1; ptr++)
110 if (color_format == *ptr)
116 /*****************************************************************************/
117 /*****************************************************************************/
118 class CNULL_Listener : public CJNISurfaceTextureOnFrameAvailableListener
121 CNULL_Listener() : CJNISurfaceTextureOnFrameAvailableListener(jni::jhobject(NULL)) {};
124 virtual void OnFrameAvailable(CJNISurfaceTexture &surface) {};
127 class CDVDMediaCodecOnFrameAvailable : public CEvent, CJNISurfaceTextureOnFrameAvailableListener
130 CDVDMediaCodecOnFrameAvailable(boost::shared_ptr<CJNISurfaceTexture> &surfaceTexture)
131 : m_surfaceTexture(surfaceTexture)
133 m_surfaceTexture->setOnFrameAvailableListener(*this);
136 virtual ~CDVDMediaCodecOnFrameAvailable()
138 // unhook the callback
139 CNULL_Listener null_listener;
140 m_surfaceTexture->setOnFrameAvailableListener(null_listener);
144 virtual void OnFrameAvailable(CJNISurfaceTexture &surface)
150 boost::shared_ptr<CJNISurfaceTexture> m_surfaceTexture;
154 /*****************************************************************************/
155 /*****************************************************************************/
156 CDVDMediaCodecInfo::CDVDMediaCodecInfo(
158 , unsigned int texture
159 , boost::shared_ptr<CJNIMediaCodec> &codec
160 , boost::shared_ptr<CJNISurfaceTexture> &surfacetexture
161 , boost::shared_ptr<CDVDMediaCodecOnFrameAvailable> &frameready
170 , m_surfacetexture(surfacetexture)
171 , m_frameready(frameready)
174 assert(m_index >= 0);
175 assert(m_texture > 0);
176 assert(m_codec != NULL);
177 assert(m_surfacetexture != NULL);
178 assert(m_frameready != NULL);
181 CDVDMediaCodecInfo::~CDVDMediaCodecInfo()
186 CDVDMediaCodecInfo* CDVDMediaCodecInfo::Retain()
188 AtomicIncrement(&m_refs);
189 m_isReleased = false;
194 long CDVDMediaCodecInfo::Release()
196 long count = AtomicDecrement(&m_refs);
198 ReleaseOutputBuffer(false);
205 void CDVDMediaCodecInfo::Validate(bool state)
207 CSingleLock lock(m_section);
212 void CDVDMediaCodecInfo::ReleaseOutputBuffer(bool render)
214 CSingleLock lock(m_section);
216 if (!m_valid || m_isReleased)
219 // release OutputBuffer and render if indicated
220 // then wait for rendered frame to become avaliable.
223 m_frameready->Reset();
225 m_codec->releaseOutputBuffer(m_index, render);
228 if (xbmc_jnienv()->ExceptionOccurred())
230 CLog::Log(LOGERROR, "CDVDMediaCodecInfo::ReleaseOutputBuffer "
231 "ExceptionOccurred render(%d)", render);
232 xbmc_jnienv()->ExceptionDescribe();
233 xbmc_jnienv()->ExceptionClear();
237 int CDVDMediaCodecInfo::GetIndex() const
239 CSingleLock lock(m_section);
244 int CDVDMediaCodecInfo::GetTextureID() const
246 // since m_texture never changes,
247 // we do not need a m_section lock here.
251 void CDVDMediaCodecInfo::GetTransformMatrix(float *textureMatrix)
253 CSingleLock lock(m_section);
258 m_surfacetexture->getTransformMatrix(textureMatrix);
261 void CDVDMediaCodecInfo::UpdateTexImage()
263 CSingleLock lock(m_section);
268 // updateTexImage will check and spew any prior gl errors,
269 // clear them before we call updateTexImage.
272 // this is key, after calling releaseOutputBuffer, we must
273 // wait a little for MediaCodec to render to the surface.
274 // Then we can updateTexImage without delay. If we do not
275 // wait, then video playback gets jerky. To optomize this,
276 // we hook the SurfaceTexture OnFrameAvailable callback
277 // using CJNISurfaceTextureOnFrameAvailableListener and wait
278 // on a CEvent to fire. 50ms seems to be a good max fallback.
279 m_frameready->WaitMSec(50);
281 m_surfacetexture->updateTexImage();
282 if (xbmc_jnienv()->ExceptionOccurred())
284 CLog::Log(LOGERROR, "CDVDMediaCodecInfo::UpdateTexImage updateTexImage:ExceptionOccurred");
285 xbmc_jnienv()->ExceptionDescribe();
286 xbmc_jnienv()->ExceptionClear();
289 m_timestamp = m_surfacetexture->getTimestamp();
290 if (xbmc_jnienv()->ExceptionOccurred())
292 CLog::Log(LOGERROR, "CDVDMediaCodecInfo::UpdateTexImage getTimestamp:ExceptionOccurred");
293 xbmc_jnienv()->ExceptionDescribe();
294 xbmc_jnienv()->ExceptionClear();
298 /*****************************************************************************/
299 /*****************************************************************************/
300 CDVDVideoCodecAndroidMediaCodec::CDVDVideoCodecAndroidMediaCodec()
301 : m_formatname("mediacodec")
308 memset(&m_videobuffer, 0x00, sizeof(DVDVideoPicture));
311 CDVDVideoCodecAndroidMediaCodec::~CDVDVideoCodecAndroidMediaCodec()
316 bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
318 // check for 4.1 Jellybean and above.
319 if (CAndroidFeatures::GetVersion() < 16)
325 switch(m_hints.codec)
327 case AV_CODEC_ID_MPEG2VIDEO:
328 m_mime = "video/mpeg2";
329 m_formatname = "amc-mpeg2";
331 case AV_CODEC_ID_MPEG4:
332 m_mime = "video/mp4v-es";
333 m_formatname = "amc-mpeg4";
335 case AV_CODEC_ID_H263:
336 m_mime = "video/3gpp";
337 m_formatname = "amc-h263";
339 case AV_CODEC_ID_VP3:
340 case AV_CODEC_ID_VP6:
341 case AV_CODEC_ID_VP6F:
342 case AV_CODEC_ID_VP8:
343 //m_mime = "video/x-vp6";
344 //m_mime = "video/x-vp7";
345 m_mime = "video/x-vnd.on2.vp8";
346 m_formatname = "amc-vpX";
348 case AV_CODEC_ID_AVS:
349 case AV_CODEC_ID_CAVS:
350 case AV_CODEC_ID_H264:
351 m_mime = "video/avc";
352 m_formatname = "amc-h264";
353 // check for h264-avcC and convert to h264-annex-b
354 if (m_hints.extradata && *(uint8_t*)m_hints.extradata == 1)
356 m_bitstream = new CBitstreamConverter;
357 if (!m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true))
359 SAFE_DELETE(m_bitstream);
364 case AV_CODEC_ID_VC1:
365 case AV_CODEC_ID_WMV3:
366 m_mime = "video/wvc1";
367 //m_mime = "video/wmv9";
368 m_formatname = "amc-vc1";
371 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Unknown hints.codec(%d)", hints.codec);
376 // CJNIMediaCodec::createDecoderByXXX doesn't handle errors nicely,
377 // it crashes if the codec isn't found. This is fixed in latest AOSP,
378 // but not in current 4.1 devices. So 1st search for a matching codec, then create it.
380 int num_codecs = CJNIMediaCodecList::getCodecCount();
381 for (int i = 0; i < num_codecs; i++)
383 CJNIMediaCodecInfo codec_info = CJNIMediaCodecList::getCodecInfoAt(i);
384 if (codec_info.isEncoder())
386 m_codecname = codec_info.getName();
387 if (IsBlacklisted(m_codecname))
390 std::vector<std::string> types = codec_info.getSupportedTypes();
391 // return the 1st one we find, that one is typically 'the best'
392 for (size_t j = 0; j < types.size(); ++j)
394 if (types[j] == m_mime)
396 m_codec = boost::shared_ptr<CJNIMediaCodec>(new CJNIMediaCodec(CJNIMediaCodec::createByCodecName(m_codecname)));
398 CJNIMediaCodecInfoCodecCapabilities codec_caps = codec_info.getCapabilitiesForType(m_mime);
399 std::vector<int> color_formats = codec_caps.colorFormats();
401 // clear any jni exceptions, jni gets upset if we do not.
402 if (xbmc_jnienv()->ExceptionOccurred())
404 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Open ExceptionOccurred");
405 xbmc_jnienv()->ExceptionClear();
410 for (size_t k = 0; k < color_formats.size(); ++k)
412 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::Open "
413 "m_codecname(%s), colorFormat(%d)", m_codecname.c_str(), color_formats[k]);
414 if (IsSupportedColorFormat(color_formats[k]))
415 m_colorFormat = color_formats[k]; // Save color format for initial output configuration
425 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:: Failed to create Android MediaCodec");
426 SAFE_DELETE(m_bitstream);
430 // whitelist of devices that can surface render.
431 m_render_sw = !CanSurfaceRenderWhiteList(m_codecname);
434 if (m_colorFormat == -1)
436 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:: No supported color format");
438 SAFE_DELETE(m_bitstream);
443 // setup a YUV420P DVDVideoPicture buffer.
444 // first make sure all properties are reset.
445 memset(&m_videobuffer, 0x00, sizeof(DVDVideoPicture));
447 m_videobuffer.dts = DVD_NOPTS_VALUE;
448 m_videobuffer.pts = DVD_NOPTS_VALUE;
449 m_videobuffer.color_range = 0;
450 m_videobuffer.color_matrix = 4;
451 m_videobuffer.iFlags = DVP_FLAG_ALLOCATED;
452 m_videobuffer.iWidth = m_hints.width;
453 m_videobuffer.iHeight = m_hints.height;
454 // these will get reset to crop values later
455 m_videobuffer.iDisplayWidth = m_hints.width;
456 m_videobuffer.iDisplayHeight = m_hints.height;
458 if (!ConfigureMediaCodec())
461 SAFE_DELETE(m_bitstream);
465 CLog::Log(LOGINFO, "CDVDVideoCodecAndroidMediaCodec:: "
466 "Open Android MediaCodec %s", m_codecname.c_str());
473 void CDVDVideoCodecAndroidMediaCodec::Dispose()
477 // release any retained demux packets
478 while (!m_demux.empty())
480 amc_demux &demux_pkt = m_demux.front();
481 free(demux_pkt.pData);
485 // invalidate any inflight outputbuffers, make sure
486 // m_output is empty so we do not create new ones
491 // clear m_videobuffer bits
494 free(m_videobuffer.data[0]), m_videobuffer.data[0] = NULL;
495 free(m_videobuffer.data[1]), m_videobuffer.data[1] = NULL;
496 free(m_videobuffer.data[2]), m_videobuffer.data[2] = NULL;
498 m_videobuffer.iFlags = 0;
499 // m_videobuffer.mediacodec is unioned with m_videobuffer.data[0]
500 // so be very careful when and how you touch it.
501 m_videobuffer.mediacodec = NULL;
509 ReleaseSurfaceTexture();
511 SAFE_DELETE(m_bitstream);
514 int CDVDVideoCodecAndroidMediaCodec::Decode(uint8_t *pData, int iSize, double dts, double pts)
516 // Handle input, add demuxer packet to input queue, we must accept it or
517 // it will be discarded as DVDPlayerVideo has no concept of "try again".
518 // we must return VC_BUFFER or VC_PICTURE, default to VC_BUFFER.
524 if (m_hints.ptsinvalid)
525 pts = DVD_NOPTS_VALUE;
527 // must check for an output picture 1st,
528 // otherwise, mediacodec can stall on some devices.
529 if (GetOutputPicture() > 0)
536 m_bitstream->Convert(pData, iSize);
537 iSize = m_bitstream->GetConvertSize();
538 pData = m_bitstream->GetConvertBuffer();
541 // queue demux pkt in case we cannot get an input buffer
545 demux_pkt.iSize = iSize;
546 demux_pkt.pData = (uint8_t*)malloc(iSize);
547 memcpy(demux_pkt.pData, pData, iSize);
548 m_demux.push(demux_pkt);
550 // try to fetch an input buffer
551 int64_t timeout_us = 5000;
552 int index = m_codec->dequeueInputBuffer(timeout_us);
555 // docs lie, getInputBuffers should be good after
556 // m_codec->start() but the internal refs are not
557 // setup until much later on some devices.
559 m_input = m_codec->getInputBuffers();
561 // we have an input buffer, fill it.
562 int size = m_input[index].capacity();
563 // fetch the front demux packet
564 amc_demux &demux_pkt = m_demux.front();
565 if (demux_pkt.iSize > size)
567 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Decode, iSize(%d) > size(%d)", iSize, size);
568 demux_pkt.iSize = size;
570 // fetch a pointer to the ByteBuffer backing store
571 void *dst_ptr = xbmc_jnienv()->GetDirectBufferAddress(m_input[index].get_raw());
573 memcpy(dst_ptr, demux_pkt.pData, demux_pkt.iSize);
575 free(demux_pkt.pData);
578 // Translate from dvdplayer dts/pts to MediaCodec pts,
579 // pts WILL get re-ordered by MediaCodec if needed.
580 // Do not try to pass pts as a unioned double/int64_t,
581 // some android devices will diddle with presentationTimeUs
582 // and you will get NaN back and DVDPlayerVideo will barf.
583 int64_t presentationTimeUs = AV_NOPTS_VALUE;
584 if (demux_pkt.pts != DVD_NOPTS_VALUE)
585 presentationTimeUs = demux_pkt.pts;
586 else if (demux_pkt.dts != DVD_NOPTS_VALUE)
587 presentationTimeUs = demux_pkt.dts;
589 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: "
590 "pts(%f), ipts(%lld), iSize(%d), GetDataSize(%d), loop_cnt(%d)",
591 presentationTimeUs, pts_dtoi(presentationTimeUs), iSize, GetDataSize(), loop_cnt);
595 m_codec->queueInputBuffer(index, offset, demux_pkt.iSize, presentationTimeUs, flags);
596 // clear any jni exceptions, jni gets upset if we do not.
597 if (xbmc_jnienv()->ExceptionOccurred())
599 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Decode ExceptionOccurred");
600 xbmc_jnienv()->ExceptionClear();
608 void CDVDVideoCodecAndroidMediaCodec::Reset()
613 // dump any pending demux packets
614 while (!m_demux.empty())
616 amc_demux &demux_pkt = m_demux.front();
617 free(demux_pkt.pData);
623 // flush all outputbuffers inflight, they will
624 // become invalid on m_codec->flush and generate
625 // a spew of java exceptions if used
628 // now we can flush the actual MediaCodec object
630 if (xbmc_jnienv()->ExceptionOccurred())
632 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Reset ExceptionOccurred");
633 xbmc_jnienv()->ExceptionClear();
636 // Invalidate our local DVDVideoPicture bits
637 m_videobuffer.pts = DVD_NOPTS_VALUE;
639 m_videobuffer.mediacodec = NULL;
643 bool CDVDVideoCodecAndroidMediaCodec::GetPicture(DVDVideoPicture* pDvdVideoPicture)
648 *pDvdVideoPicture = m_videobuffer;
650 // Invalidate our local DVDVideoPicture bits
651 m_videobuffer.pts = DVD_NOPTS_VALUE;
653 m_videobuffer.mediacodec = NULL;
658 bool CDVDVideoCodecAndroidMediaCodec::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
660 if (pDvdVideoPicture->format == RENDER_FMT_MEDIACODEC)
661 SAFE_RELEASE(pDvdVideoPicture->mediacodec);
662 memset(pDvdVideoPicture, 0x00, sizeof(DVDVideoPicture));
667 void CDVDVideoCodecAndroidMediaCodec::SetDropState(bool bDrop)
671 m_videobuffer.iFlags |= DVP_FLAG_DROPPED;
673 m_videobuffer.iFlags &= ~DVP_FLAG_DROPPED;
676 int CDVDVideoCodecAndroidMediaCodec::GetDataSize(void)
678 // just ignore internal buffering contribution.
682 double CDVDVideoCodecAndroidMediaCodec::GetTimeSize(void)
684 // just ignore internal buffering contribution.
688 unsigned CDVDVideoCodecAndroidMediaCodec::GetAllowedReferences()
693 void CDVDVideoCodecAndroidMediaCodec::FlushInternal()
695 // invalidate any existing inflight buffers and create
696 // new ones to match the number of output buffers
701 for (size_t i = 0; i < m_inflight.size(); i++)
702 m_inflight[i]->Validate(false);
705 for (size_t i = 0; i < m_output.size(); i++)
707 m_inflight.push_back(
708 new CDVDMediaCodecInfo(i, m_textureId, m_codec, m_surfaceTexture, m_frameAvailable)
713 bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void)
715 // setup a MediaFormat to match the video content,
716 // used by codec during configure
717 CJNIMediaFormat mediaformat = CJNIMediaFormat::createVideoFormat(
718 m_mime.c_str(), m_hints.width, m_hints.height);
719 // some android devices forget to default the demux input max size
720 mediaformat.setInteger(CJNIMediaFormat::KEY_MAX_INPUT_SIZE, 0);
722 // handle codec extradata
723 if (m_hints.extrasize)
725 size_t size = m_hints.extrasize;
726 void *src_ptr = m_hints.extradata;
729 size = m_bitstream->GetExtraSize();
730 src_ptr = m_bitstream->GetExtraData();
732 // Allocate a byte buffer via allocateDirect in java instead of NewDirectByteBuffer,
733 // since the latter doesn't allocate storage of its own, and we don't know how long
734 // the codec uses the buffer.
735 CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(size);
736 void *dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw());
737 memcpy(dts_ptr, src_ptr, size);
738 // codec will automatically handle buffers as extradata
739 // using entries with keys "csd-0", "csd-1", etc.
740 mediaformat.setByteBuffer("csd-0", bytebuffer);
743 InitSurfaceTexture();
745 // configure and start the codec.
746 // use the MediaFormat that we have setup.
747 // use a null MediaCrypto, our content is not encrypted.
748 // use a null Surface, we will extract the video picture data manually.
750 CJNIMediaCrypto crypto(jni::jhobject(NULL));
751 // our jni gets upset if we do this a different
752 // way, do not mess with it.
755 CJNISurface surface(jni::jhobject(NULL));
756 m_codec->configure(mediaformat, surface, crypto, flags);
760 m_codec->configure(mediaformat, *m_surface, crypto, flags);
762 // always, check/clear jni exceptions.
763 if (xbmc_jnienv()->ExceptionOccurred())
765 xbmc_jnienv()->ExceptionClear();
771 // always, check/clear jni exceptions.
772 if (xbmc_jnienv()->ExceptionOccurred())
774 xbmc_jnienv()->ExceptionClear();
778 // There is no guarantee we'll get an INFO_OUTPUT_FORMAT_CHANGED (up to Android 4.3)
779 // Configure the output with defaults
780 ConfigureOutputFormat(&mediaformat);
785 int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
789 int64_t timeout_us = 5000;
790 CJNIMediaCodecBufferInfo bufferInfo;
791 int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us);
796 m_codec->releaseOutputBuffer(index, false);
797 if (xbmc_jnienv()->ExceptionOccurred())
798 xbmc_jnienv()->ExceptionClear();
802 // some devices will return a valid index
803 // before signaling INFO_OUTPUT_BUFFERS_CHANGED which
804 // is used to setup m_output, D'uh. setup m_output here.
805 if (m_output.empty())
807 m_output = m_codec->getOutputBuffers();
811 int flags = bufferInfo.flags();
812 if (flags & CJNIMediaCodec::BUFFER_FLAG_SYNC_FRAME)
813 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_SYNC_FRAME");
815 if (flags & CJNIMediaCodec::BUFFER_FLAG_CODEC_CONFIG)
816 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_CODEC_CONFIG");
818 if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM)
820 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM");
821 m_codec->releaseOutputBuffer(index, false);
822 if (xbmc_jnienv()->ExceptionOccurred())
823 xbmc_jnienv()->ExceptionClear();
829 m_videobuffer.mediacodec = m_inflight[index]->Retain();
830 m_videobuffer.mediacodec->Validate(true);
834 int size = bufferInfo.size();
835 int offset = bufferInfo.offset();
837 if (!m_output[index].isDirect())
838 CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec:: m_output[index].isDirect == false");
840 if (size && m_output[index].capacity())
842 uint8_t *src_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(m_output[index].get_raw());
846 if (m_videobuffer.format == RENDER_FMT_NV12)
848 else if (m_videobuffer.format == RENDER_FMT_YUV420P)
851 for (int i = 0; i < loop_end; i++)
853 uint8_t *src = src_ptr + m_src_offset[i];
854 int src_stride = m_src_stride[i];
855 uint8_t *dst = m_videobuffer.data[i];
856 int dst_stride = m_videobuffer.iLineSize[i];
858 int height = m_videobuffer.iHeight;
860 height = (m_videobuffer.iHeight + 1) / 2;
862 if (src_stride == dst_stride)
863 memcpy(dst, src, dst_stride * height);
865 for (int j = 0; j < height; j++, src += src_stride, dst += dst_stride)
866 memcpy(dst, src, dst_stride);
869 m_codec->releaseOutputBuffer(index, false);
872 int64_t pts= bufferInfo.presentationTimeUs();
873 m_videobuffer.dts = DVD_NOPTS_VALUE;
874 m_videobuffer.pts = DVD_NOPTS_VALUE;
875 if (pts != AV_NOPTS_VALUE)
876 m_videobuffer.pts = pts;
879 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture "
880 "index(%d), pts(%f)", index, m_videobuffer.pts);
882 // always, check/clear jni exceptions.
883 if (xbmc_jnienv()->ExceptionOccurred())
884 xbmc_jnienv()->ExceptionClear();
888 else if (index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED)
890 m_output = m_codec->getOutputBuffers();
893 else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED)
895 CJNIMediaFormat mediaformat = m_codec->getOutputFormat();
896 ConfigureOutputFormat(&mediaformat);
898 else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER)
900 // normal dequeueOutputBuffer timeout, ignore it.
905 // we should never get here
906 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture unknown index(%d)", index);
912 void CDVDVideoCodecAndroidMediaCodec::ConfigureOutputFormat(CJNIMediaFormat* mediaformat)
924 if (mediaformat->containsKey("width"))
925 width = mediaformat->getInteger("width");
926 if (mediaformat->containsKey("height"))
927 height = mediaformat->getInteger("height");
928 if (mediaformat->containsKey("stride"))
929 stride = mediaformat->getInteger("stride");
930 if (mediaformat->containsKey("slice-height"))
931 slice_height= mediaformat->getInteger("slice-height");
932 if (mediaformat->containsKey("color-format"))
933 color_format= mediaformat->getInteger("color-format");
934 if (mediaformat->containsKey("crop-left"))
935 crop_left = mediaformat->getInteger("crop-left");
936 if (mediaformat->containsKey("crop-top"))
937 crop_top = mediaformat->getInteger("crop-top");
938 if (mediaformat->containsKey("crop-right"))
939 crop_right = mediaformat->getInteger("crop-right");
940 if (mediaformat->containsKey("crop-bottom"))
941 crop_bottom = mediaformat->getInteger("crop-bottom");
943 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: "
944 "width(%d), height(%d), stride(%d), slice-height(%d), color-format(%d)",
945 width, height, stride, slice_height, color_format);
946 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: "
947 "crop-left(%d), crop-top(%d), crop-right(%d), crop-bottom(%d)",
948 crop_left, crop_top, crop_right, crop_bottom);
952 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Direct Surface Rendering");
953 m_videobuffer.format = RENDER_FMT_MEDIACODEC;
957 // Android device quirks and fixes
959 // Samsung Quirk: ignore width/height/stride/slice: http://code.google.com/p/android/issues/detail?id=37768#c3
960 if (strstr(m_codecname.c_str(), "OMX.SEC.avc.dec") != NULL || strstr(m_codecname.c_str(), "OMX.SEC.avcdec") != NULL)
962 width = stride = m_hints.width;
963 height = slice_height = m_hints.height;
965 // No color-format? Initialize with the one we detected as valid earlier
966 if (color_format == 0)
967 color_format = m_colorFormat;
971 crop_right = width-1;
973 crop_bottom = height-1;
974 if (slice_height <= height)
976 slice_height = height;
977 if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar)
979 // NVidia Tegra 3 on Nexus 7 does not set slice_heights
980 if (strstr(m_codecname.c_str(), "OMX.Nvidia.") != NULL)
982 slice_height = (((height) + 15) & ~15);
983 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: NVidia Tegra 3 quirk, slice_height(%d)", slice_height);
987 if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_TI_FormatYUV420PackedSemiPlanar)
989 slice_height -= crop_top / 2;
990 // set crop top/left here, since the offset parameter already includes this.
991 // if we would ignore the offset parameter in the BufferInfo, we could just keep
992 // the original slice height and apply the top/left cropping instead.
997 // default picture format to none
998 for (int i = 0; i < 4; i++)
999 m_src_offset[i] = m_src_stride[i] = 0;
1000 // delete any existing buffers
1001 for (int i = 0; i < 4; i++)
1002 free(m_videobuffer.data[i]);
1004 // setup picture format and data offset vectors
1005 if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar)
1007 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: COLOR_FormatYUV420Planar");
1010 m_src_stride[0] = stride;
1011 m_src_offset[0] = crop_top * stride;
1012 m_src_offset[0]+= crop_left;
1015 m_src_stride[1] = (stride + 1) / 2;
1016 // skip over the Y plane
1017 m_src_offset[1] = slice_height * stride;
1018 // crop_top/crop_left divided by two
1019 // because one byte of the U/V planes
1020 // corresponds to two pixels horizontally/vertically
1021 m_src_offset[1]+= crop_top / 2 * m_src_stride[1];
1022 m_src_offset[1]+= crop_left / 2;
1025 m_src_stride[2] = (stride + 1) / 2;
1026 // skip over the Y plane
1027 m_src_offset[2] = slice_height * stride;
1028 // skip over the U plane
1029 m_src_offset[2]+= ((slice_height + 1) / 2) * ((stride + 1) / 2);
1030 // crop_top/crop_left divided by two
1031 // because one byte of the U/V planes
1032 // corresponds to two pixels horizontally/vertically
1033 m_src_offset[2]+= crop_top / 2 * m_src_stride[2];
1034 m_src_offset[2]+= crop_left / 2;
1036 m_videobuffer.iLineSize[0] = width; // Y
1037 m_videobuffer.iLineSize[1] = (width + 1) /2; // U
1038 m_videobuffer.iLineSize[2] = (width + 1) /2; // V
1039 m_videobuffer.iLineSize[3] = 0;
1041 unsigned int iPixels = width * height;
1042 unsigned int iChromaPixels = iPixels/4;
1043 m_videobuffer.data[0] = (uint8_t*)malloc(16 + iPixels);
1044 m_videobuffer.data[1] = (uint8_t*)malloc(16 + iChromaPixels);
1045 m_videobuffer.data[2] = (uint8_t*)malloc(16 + iChromaPixels);
1046 m_videobuffer.data[3] = NULL;
1047 m_videobuffer.format = RENDER_FMT_YUV420P;
1049 else if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420SemiPlanar
1050 || color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_QCOM_FormatYUV420SemiPlanar
1051 || color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_TI_FormatYUV420PackedSemiPlanar
1052 || color_format == CJNIMediaCodecInfoCodecCapabilities::OMX_QCOM_COLOR_FormatYVU420SemiPlanarInterlace)
1055 CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: COLOR_FormatYUV420SemiPlanar");
1058 m_src_stride[0] = stride;
1059 m_src_offset[0] = crop_top * stride;
1060 m_src_offset[0]+= crop_left;
1063 m_src_stride[1] = stride;
1064 // skip over the Y plane
1065 m_src_offset[1] = slice_height * stride;
1066 m_src_offset[1]+= crop_top * stride;
1067 m_src_offset[1]+= crop_left;
1069 m_videobuffer.iLineSize[0] = width; // Y
1070 m_videobuffer.iLineSize[1] = width; // UV
1071 m_videobuffer.iLineSize[2] = 0;
1072 m_videobuffer.iLineSize[3] = 0;
1074 unsigned int iPixels = width * height;
1075 unsigned int iChromaPixels = iPixels;
1076 m_videobuffer.data[0] = (uint8_t*)malloc(16 + iPixels);
1077 m_videobuffer.data[1] = (uint8_t*)malloc(16 + iChromaPixels);
1078 m_videobuffer.data[2] = NULL;
1079 m_videobuffer.data[3] = NULL;
1080 m_videobuffer.format = RENDER_FMT_NV12;
1084 CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:: Fixme unknown color_format(%d)", color_format);
1089 // picture display width/height include the cropping.
1090 m_videobuffer.iDisplayWidth = crop_right + 1 - crop_left;
1091 m_videobuffer.iDisplayHeight = crop_bottom + 1 - crop_top;
1093 // clear any jni exceptions
1094 if (xbmc_jnienv()->ExceptionOccurred())
1095 xbmc_jnienv()->ExceptionClear();
1098 void CDVDVideoCodecAndroidMediaCodec::CallbackInitSurfaceTexture(void *userdata)
1100 CDVDVideoCodecAndroidMediaCodec *ctx = static_cast<CDVDVideoCodecAndroidMediaCodec*>(userdata);
1101 ctx->InitSurfaceTexture();
1104 void CDVDVideoCodecAndroidMediaCodec::InitSurfaceTexture(void)
1109 // We MUST create the GLES texture on the main thread
1110 // to match where the valid GLES context is located.
1111 // It would be nice to move this out of here, we would need
1112 // to create/fetch/create from g_RenderMananger. But g_RenderMananger
1113 // does not know we are using MediaCodec until Configure and we
1114 // we need m_surfaceTexture valid before then. Chicken, meet Egg.
1115 if (g_application.IsCurrentThread())
1117 // localize GLuint so we do not spew gles includes in our header
1120 glGenTextures(1, &texture_id);
1121 glBindTexture( GL_TEXTURE_EXTERNAL_OES, texture_id);
1122 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1123 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1124 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1125 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1126 glBindTexture( GL_TEXTURE_EXTERNAL_OES, 0);
1127 m_textureId = texture_id;
1129 m_surfaceTexture = boost::shared_ptr<CJNISurfaceTexture>(new CJNISurfaceTexture(m_textureId));
1130 // hook the surfaceTexture OnFrameAvailable callback
1131 m_frameAvailable = boost::shared_ptr<CDVDMediaCodecOnFrameAvailable>(new CDVDMediaCodecOnFrameAvailable(m_surfaceTexture));
1132 m_surface = new CJNISurface(*m_surfaceTexture);
1136 ThreadMessageCallback callbackData;
1137 callbackData.callback = &CallbackInitSurfaceTexture;
1138 callbackData.userptr = (void*)this;
1141 msg.dwMessage = TMSG_CALLBACK;
1142 msg.lpVoid = (void*)&callbackData;
1145 CApplicationMessenger::Get().SendMessage(msg, true);
1151 void CDVDVideoCodecAndroidMediaCodec::ReleaseSurfaceTexture(void)
1156 // it is safe to delete here even though these items
1157 // were created in the main thread instance
1158 SAFE_DELETE(m_surface);
1159 m_frameAvailable.reset();
1160 m_surfaceTexture.reset();
1162 if (m_textureId > 0)
1164 GLuint texture_id = m_textureId;
1165 glDeleteTextures(1, &texture_id);