void CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) { // setup a MediaFormat to match the video content, // used by codec during configure CJNIMediaFormat mediaformat = CJNIMediaFormat::createVideoFormat( m_mime.c_str(), m_hints.width, m_hints.height); // some android devices forget to default the demux input max size mediaformat.setInteger(CJNIMediaFormat::KEY_MAX_INPUT_SIZE, 0); // handle codec extradata if (m_hints.extrasize) { size_t size = m_hints.extrasize; void *src_ptr = m_hints.extradata; if (m_bitstream) { size = m_bitstream->GetExtraSize(); src_ptr = m_bitstream->GetExtraData(); } // Allocate a byte buffer via allocateDirect in java instead of NewDirectByteBuffer, // since the latter doesn't allocate storage of its own, and we don't know how long // the codec uses the buffer. CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(size); void *dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw()); memcpy(dts_ptr, src_ptr, size); // codec will automatically handle buffers as extradata // using entries with keys "csd-0", "csd-1", etc. mediaformat.setByteBuffer("csd-0", bytebuffer); } InitSurfaceTexture(); // configure and start the codec. // use the MediaFormat that we have setup. // use a null MediaCrypto, our content is not encrypted. // use a null Surface, we will extract the video picture data manually. int flags = 0; CJNIMediaCrypto crypto(jni::jhobject(NULL)); // our jni gets upset if we do this a different // way, do not mess with it. if (m_render_sw) { CJNISurface surface(jni::jhobject(NULL)); m_codec->configure(mediaformat, surface, crypto, flags); } else { m_codec->configure(mediaformat, *m_surface, crypto, flags); } m_codec->start(); // always, check/clear jni exceptions. if (xbmc_jnienv()->ExceptionOccurred()) xbmc_jnienv()->ExceptionClear(); }
bool CDVDVideoCodecHybris::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options) { int ret = 0; if (hints.software) return false; // stagefright crashes with null size. Trap this... if (!hints.width || !hints.height) { CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"null size, cannot handle"); return false; } if(m_bitstream) { SAFE_DELETE(m_bitstream); m_bitstream = NULL; } CLog::Log(LOGDEBUG, "%s::%s - trying to open, codec(%d), profile(%d), level(%d)", CLASSNAME, __func__, hints.codec, hints.profile, hints.level); m_drop = false; m_hints = hints; switch(hints.codec) { // OMX_ON2_VIDEO_CodingMPEG2, /**< AKA: H.262 */^M case AV_CODEC_ID_MPEG2VIDEO: m_mimeType = "video/mpeg2"; m_name = "hyb-mpeg2"; break; // OMX_ON2_VIDEO_CodingH263, /**< H.263 */^M case AV_CODEC_ID_H263: m_name = "hyb-h263"; m_mimeType = "video/3gpp"; break; // OMX_ON2_VIDEO_CodingMPEG4, /**< MPEG-4 */^M case AV_CODEC_ID_MPEG4: m_name = "hyb-mpeg4"; m_mimeType = "video/mp4v-es"; break; // OMX_ON2_VIDEO_CodingAVC, /**< H.264/AVC */^M case AV_CODEC_ID_AVS: case AV_CODEC_ID_CAVS: case AV_CODEC_ID_H264: switch(hints.profile) { case FF_PROFILE_H264_HIGH_10: case FF_PROFILE_H264_HIGH_10_INTRA: case FF_PROFILE_H264_HIGH_422: case FF_PROFILE_H264_HIGH_422_INTRA: case FF_PROFILE_H264_HIGH_444_PREDICTIVE: case FF_PROFILE_H264_HIGH_444_INTRA: case FF_PROFILE_H264_CAVLC_444: // Hi10P not supported return false; } m_name = "hyb-h264"; m_mimeType = "video/avc"; if (m_hints.extradata) { m_bitstream = new CBitstreamConverter; if (!m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true)) { SAFE_DELETE(m_bitstream); } } break; // OMX_ON2_VIDEO_CodingVP6,^M // OMX_ON2_VIDEO_CodingVP8, /**< VP8 */^M case AV_CODEC_ID_VP3: case AV_CODEC_ID_VP6: case AV_CODEC_ID_VP6F: case AV_CODEC_ID_VP8: //m_mimeType = "video/x-vp6"; //m_mimeType = "video/x-vp7"; m_mimeType = "video/x-vnd.on2.vp8"; m_name = "hyb-vpX"; break; // OMX_ON2_VIDEO_CodingWMV, /**< Windows Media Video (WMV1,WMV2,WMV3)*/^M case AV_CODEC_ID_WMV3: m_mimeType = "video/wmv3"; m_name = "hyb-wmv3"; if (m_hints.extradata) { m_bitstream = new CBitstreamConverter; if (!m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true)) { SAFE_DELETE(m_bitstream); } } break; // OMX_ON2_VIDEO_CodingVC1 = 0x01000000, /**< Windows Media Video (WMV1,WMV2,WMV3)*/^M case AV_CODEC_ID_VC1: m_mimeType = "video/vc1"; m_name = "hyb-vc1"; if (m_hints.extradata) { m_bitstream = new CBitstreamConverter; if (!m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true)) { SAFE_DELETE(m_bitstream); } } break; // mac_l1: 4K HEVC crashes after 10-20 secs... so exclude for now // OMX_RK_VIDEO_CodingHEVC, /**< H.265/HEVC */^M case AV_CODEC_ID_HEVC: m_mimeType = "video/hevc"; m_name = "hyb-h265"; // check for hevc-hvcC and convert to h265-annex-b if (m_hints.extradata) { m_bitstream = new CBitstreamConverter; if (!m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true)) { SAFE_DELETE(m_bitstream); } } break; // mac_l1: better safe than sorry (although they might be supported by HW): // following are not supported in Androids XBMC/SPMC // OMX_ON2_VIDEO_CodingRV, /**< all versions of Real Video */^M // OMX_ON2_VIDEO_CodingMJPEG, /**< Motion JPEG */^M // OMX_ON2_VIDEO_CodingFLV1, /**< Sorenson H.263 */^M // following are not implemented in // frameworks/av/media/libstagefright/codecs/rkon2dec/RkOn2Decoder.cpp // however, could work though... // OMX_ON2_VIDEO_CodingDIVX3, /**< DIVX3 */^M // OMX_ON2_VIDEO_CodingVP9, /**< VP9 */^M default: CLog::Log(LOGDEBUG, "%s::%s - Unsupported hints.codec(%d)", CLASSNAME, __func__, hints.codec); return false; break; } m_format = media_format_create_video_format(m_mimeType.c_str(), hints.width, hints.height, 0, 0); if (m_format == NULL) { CLog::Log(LOGERROR, "%s::%s - Failed to create format object for %s", CLASSNAME, __func__, m_mimeType.c_str()); return false; } m_codec = media_codec_create_by_codec_type(m_mimeType.c_str()); if (m_codec == NULL) { CLog::Log(LOGERROR, "%s::%s - Failed to create codec for %s", CLASSNAME, __func__, m_mimeType.c_str()); media_codec_release(m_codec); media_codec_delegate_destroy(m_codec); media_format_destroy(m_codec); return false; } if (hints.extrasize > 0) { size_t size = m_hints.extrasize; void *src_ptr = m_hints.extradata; if (m_bitstream) { size = m_bitstream->GetExtraSize(); src_ptr = m_bitstream->GetExtraData(); } media_format_set_byte_buffer(m_format, "csd-0", (uint8_t*)src_ptr, size); } // setup a YUV420P DVDVideoPicture buffer. // first make sure all properties are reset. memset(&m_videoBuffer, 0x00, sizeof(DVDVideoPicture)); m_videoBuffer.dts = DVD_NOPTS_VALUE; m_videoBuffer.pts = DVD_NOPTS_VALUE; m_videoBuffer.color_range = 0; m_videoBuffer.color_matrix = 4; m_videoBuffer.iFlags = DVP_FLAG_ALLOCATED; m_videoBuffer.iWidth = m_hints.width; m_videoBuffer.iHeight = m_hints.height; // these will get reset to crop values later m_videoBuffer.iDisplayWidth = m_hints.width; m_videoBuffer.iDisplayHeight = m_hints.height; m_render_sw = false; InitSurfaceTexture(); if( m_render_sw ) { if (media_codec_configure(m_codec, m_format, NULL, 0) != OK) { CLog::Log(LOGERROR, "%s::%s - Failed to configure codec for %s", CLASSNAME, __func__, m_mimeType.c_str()); return false; } } else { if (media_codec_configure(m_codec, m_format, m_surface, 0) != OK) { CLog::Log(LOGERROR, "%s::%s - Failed to configure codec w surface for %s", CLASSNAME, __func__, m_mimeType.c_str()); return false; } } media_codec_start(m_codec); return true; }