int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) { int rtn = 0; int64_t timeout_us = 10000; CJNIMediaCodecBufferInfo bufferInfo; int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture ExceptionCheck; dequeueOutputBuffer"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return -2; } if (index >= 0) { int64_t pts= bufferInfo.presentationTimeUs(); m_videobuffer.dts = DVD_NOPTS_VALUE; m_videobuffer.pts = DVD_NOPTS_VALUE; if (pts != AV_NOPTS_VALUE) m_videobuffer.pts = pts; int flags = bufferInfo.flags(); if (flags & CJNIMediaCodec::BUFFER_FLAG_SYNC_FRAME) CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_SYNC_FRAME"); if (flags & CJNIMediaCodec::BUFFER_FLAG_CODEC_CONFIG) CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_CODEC_CONFIG"); if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM) { CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM"); m_codec->releaseOutputBuffer(index, false); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture ExceptionCheck: releaseOutputBuffer"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return -2; } return -1; } if (m_drop) { m_codec->releaseOutputBuffer(index, false); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture ExceptionCheck: releaseOutputBuffer"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return -2; } m_videobuffer.mediacodec = nullptr; return 1; } if (!m_render_sw) { size_t i = 0; for (; i < m_inflight.size(); ++i) { if (m_inflight[i]->GetIndex() == index) break; } if (i == m_inflight.size()) m_inflight.push_back( new CDVDMediaCodecInfo(index, m_textureId, m_codec, m_surfaceTexture, m_frameAvailable) ); m_videobuffer.mediacodec = m_inflight[i]->Retain(); m_videobuffer.mediacodec->Validate(true); } else { int size = bufferInfo.size(); int offset = bufferInfo.offset(); CJNIByteBuffer buffer = m_codec->getOutputBuffer(index);; if (!buffer.isDirect()) CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec:: buffer.isDirect == false"); if (!buffer.isDirect()) CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec:: m_output[index].isDirect == false"); if (size && buffer.capacity()) { uint8_t *src_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(buffer.get_raw()); src_ptr += offset; int loop_end = 0; if (m_videobuffer.format == RENDER_FMT_NV12) loop_end = 2; else if (m_videobuffer.format == RENDER_FMT_YUV420P) loop_end = 3; for (int i = 0; i < loop_end; i++) { uint8_t *src = src_ptr + m_src_offset[i]; int src_stride = m_src_stride[i]; uint8_t *dst = m_videobuffer.data[i]; int dst_stride = m_videobuffer.iLineSize[i]; int height = m_videobuffer.iHeight; if (i > 0) height = (m_videobuffer.iHeight + 1) / 2; if (src_stride == dst_stride) memcpy(dst, src, dst_stride * height); else for (int j = 0; j < height; j++, src += src_stride, dst += dst_stride) memcpy(dst, src, dst_stride); } } m_codec->releaseOutputBuffer(index, false); } /* CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture " "index(%d), pts(%f)", index, m_videobuffer.pts); */ // always, check/clear jni exceptions. if (xbmc_jnienv()->ExceptionCheck()) xbmc_jnienv()->ExceptionClear(); rtn = 1; } else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED) { CJNIMediaFormat mediaformat = m_codec->getOutputFormat(); if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); } ConfigureOutputFormat(&mediaformat); } else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER || index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) { // ignore rtn = 0; } else { // we should never get here CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture unknown index(%d)", index); rtn = -2; } return rtn; }
int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) { int rtn = 0; int64_t timeout_us = 50000; CJNIMediaCodecBufferInfo bufferInfo; int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us); if (xbmc_jnienv()->ExceptionOccurred()) { CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture ExceptionOccurred"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return 0; } if (index >= 0) { if (m_drop) { m_codec->releaseOutputBuffer(index, false); if (xbmc_jnienv()->ExceptionOccurred()) xbmc_jnienv()->ExceptionClear(); return 0; } // some devices will return a valid index // before signaling INFO_OUTPUT_BUFFERS_CHANGED which // is used to setup m_output, D'uh. setup m_output here. if (m_output.empty()) { m_output = m_codec->getOutputBuffers(); FlushInternal(); } int flags = bufferInfo.flags(); if (flags & CJNIMediaCodec::BUFFER_FLAG_SYNC_FRAME) CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_SYNC_FRAME"); if (flags & CJNIMediaCodec::BUFFER_FLAG_CODEC_CONFIG) CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_CODEC_CONFIG"); if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM) { CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM"); m_codec->releaseOutputBuffer(index, false); if (xbmc_jnienv()->ExceptionOccurred()) xbmc_jnienv()->ExceptionClear(); return 0; } if (!m_render_sw) { m_videobuffer.mediacodec = m_inflight[index]->Retain(); m_videobuffer.mediacodec->Validate(true); } else { int size = bufferInfo.size(); int offset = bufferInfo.offset(); if (!m_output[index].isDirect()) CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec:: m_output[index].isDirect == false"); if (size && m_output[index].capacity()) { uint8_t *src_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(m_output[index].get_raw()); src_ptr += offset; int loop_end = 0; if (m_videobuffer.format == RENDER_FMT_NV12) loop_end = 2; else if (m_videobuffer.format == RENDER_FMT_YUV420P) loop_end = 3; for (int i = 0; i < loop_end; i++) { uint8_t *src = src_ptr + m_src_offset[i]; int src_stride = m_src_stride[i]; uint8_t *dst = m_videobuffer.data[i]; int dst_stride = m_videobuffer.iLineSize[i]; int height = m_videobuffer.iHeight; if (i > 0) height = (m_videobuffer.iHeight + 1) / 2; if (src_stride == dst_stride) memcpy(dst, src, dst_stride * height); else for (int j = 0; j < height; j++, src += src_stride, dst += dst_stride) memcpy(dst, src, dst_stride); } } m_codec->releaseOutputBuffer(index, false); } int64_t pts= bufferInfo.presentationTimeUs(); m_videobuffer.dts = DVD_NOPTS_VALUE; m_videobuffer.pts = DVD_NOPTS_VALUE; if (pts != AV_NOPTS_VALUE) m_videobuffer.pts = pts; /* CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture " "index(%d), pts(%f)", index, m_videobuffer.pts); */ // always, check/clear jni exceptions. if (xbmc_jnienv()->ExceptionOccurred()) xbmc_jnienv()->ExceptionClear(); rtn = 1; } else if (index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) { m_output = m_codec->getOutputBuffers(); FlushInternal(); } else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED) { CJNIMediaFormat mediaformat = m_codec->getOutputFormat(); ConfigureOutputFormat(&mediaformat); } else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER) { // normal dequeueOutputBuffer timeout, ignore it. rtn = -1; } else { // we should never get here CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture unknown index(%d)", index); } return rtn; }
int CDVDAudioCodecAndroidMediaCodec::GetData(uint8_t** dst) { m_bufferUsed = 0; int64_t timeout_us = 10000; CJNIMediaCodecBufferInfo bufferInfo; int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us); if (xbmc_jnienv()->ExceptionCheck()) { std::string err = CJNIBase::ExceptionToString(); CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck; dequeueOutputBuffer \n %s", err.c_str()); return 0; } if (index >= 0) { // some devices will return a valid index // before signaling INFO_OUTPUT_BUFFERS_CHANGED which // is used to setup m_output, D'uh. setup m_output here. if (m_output.empty()) { m_output = m_codec->getOutputBuffers(); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck: getOutputBuffers"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return 0; } } int flags = bufferInfo.flags(); if (flags & CJNIMediaCodec::BUFFER_FLAG_SYNC_FRAME) CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: BUFFER_FLAG_SYNC_FRAME"); if (flags & CJNIMediaCodec::BUFFER_FLAG_CODEC_CONFIG) CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: BUFFER_FLAG_CODEC_CONFIG"); if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM) { CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM"); m_codec->releaseOutputBuffer(index, false); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck: releaseOutputBuffer"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); return 0; } return 0; } int size = bufferInfo.size(); int offset = bufferInfo.offset(); if (!m_output[index].isDirect()) CLog::Log(LOGWARNING, "CDVDAudioCodecAndroidMediaCodec:: m_output[index].isDirect == false"); if (size && m_output[index].capacity()) { uint8_t *src_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(m_output[index].get_raw()); src_ptr += offset; if (size > m_bufferSize) { m_bufferSize = size; m_buffer = (uint8_t*)realloc(m_buffer, m_bufferSize); } memcpy(m_buffer, src_ptr, size); m_bufferUsed = size; } else return 0; m_codec->releaseOutputBuffer(index, false); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck: releaseOutputBuffer"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); } #ifdef DEBUG_VERBOSE CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec::GetData " "index(%d), size(%d)", index, m_bufferUsed); #endif // always, check/clear jni exceptions. if (xbmc_jnienv()->ExceptionCheck()) xbmc_jnienv()->ExceptionClear(); } else if (index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) { m_output = m_codec->getOutputBuffers(); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData(INFO_OUTPUT_BUFFERS_CHANGED) ExceptionCheck: getOutputBuffers"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); } } else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED) { CJNIMediaFormat mediaformat = m_codec->getOutputFormat(); if (xbmc_jnienv()->ExceptionCheck()) { CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData(INFO_OUTPUT_FORMAT_CHANGED) ExceptionCheck: getOutputBuffers"); xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); } ConfigureOutputFormat(&mediaformat); } else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER) { // normal dequeueOutputBuffer timeout, ignore it. m_bufferUsed = 0; } else { // we should never get here CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData unknown index(%d)", index); } *dst = m_buffer; return m_bufferUsed; }
int CJNIMediaCodec::dequeueOutputBuffer(const CJNIMediaCodecBufferInfo &info, int64_t timeoutUs) { return call_method<int>(m_object, "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I", info.get_raw(), timeoutUs); }