Upstream changes from hardware/google/av
This includes changes up to commit
c3f6c282c22de48e89fe1f364c37b13be7498404
Test: make cts -j123 && cts-tradefed run cts-dev -m \
CtsMediaTestCases --compatibility:module-arg \
CtsMediaTestCases:include-annotation:\
android.platform.test.annotations.RequiresDevice
Bug: 112362730
Change-Id: Idf91ba6d3b71a724292cc3ae533307194678ea83
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 2527b00..10263de 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1024,7 +1024,7 @@
ALOGD("ISConfig: no configuration");
}
- return surface->start();
+ return OK;
}
void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
@@ -1111,12 +1111,20 @@
}
sp<AMessage> inputFormat;
sp<AMessage> outputFormat;
+ status_t err2 = OK;
{
Mutexed<Config>::Locked config(mConfig);
inputFormat = config->mInputFormat;
outputFormat = config->mOutputFormat;
+ if (config->mInputSurface) {
+ err2 = config->mInputSurface->start();
+ }
}
- status_t err2 = mChannel->start(inputFormat, outputFormat);
+ if (err2 != OK) {
+ mCallback->onError(err2, ACTION_CODE_FATAL);
+ return;
+ }
+ err2 = mChannel->start(inputFormat, outputFormat);
if (err2 != OK) {
mCallback->onError(err2, ACTION_CODE_FATAL);
return;
@@ -1191,6 +1199,13 @@
}
{
+ Mutexed<Config>::Locked config(mConfig);
+ if (config->mInputSurface) {
+ config->mInputSurface->disconnect();
+ config->mInputSurface = nullptr;
+ }
+ }
+ {
Mutexed<State>::Locked state(mState);
if (state->get() == STOPPING) {
state->set(ALLOCATED);
@@ -1200,6 +1215,7 @@
}
void CCodec::initiateRelease(bool sendCallback /* = true */) {
+ bool clearInputSurfaceIfNeeded = false;
{
Mutexed<State>::Locked state(mState);
if (state->get() == RELEASED || state->get() == RELEASING) {
@@ -1221,9 +1237,23 @@
}
return;
}
+ if (state->get() == STARTING
+ || state->get() == RUNNING
+ || state->get() == STOPPING) {
+ // Input surface may have been started, so clean up is needed.
+ clearInputSurfaceIfNeeded = true;
+ }
state->set(RELEASING);
}
+ if (clearInputSurfaceIfNeeded) {
+ Mutexed<Config>::Locked config(mConfig);
+ if (config->mInputSurface) {
+ config->mInputSurface->disconnect();
+ config->mInputSurface = nullptr;
+ }
+ }
+
mChannel->stop();
// thiz holds strong ref to this while the thread is running.
sp<CCodec> thiz(this);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 577aff3..1ae7bd7 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -128,7 +128,9 @@
* and released successfully.
*/
virtual bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) = 0;
/**
* Release the buffer that is no longer used by the codec process. Return
@@ -455,13 +457,18 @@
* \return true if the buffer is successfully released from a slot
* false otherwise
*/
- bool releaseSlot(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+ bool releaseSlot(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
sp<Codec2Buffer> clientBuffer;
size_t index = mBuffers.size();
for (size_t i = 0; i < mBuffers.size(); ++i) {
if (mBuffers[i].clientBuffer == buffer) {
clientBuffer = mBuffers[i].clientBuffer;
- mBuffers[i].clientBuffer.clear();
+ if (release) {
+ mBuffers[i].clientBuffer.clear();
+ }
index = i;
break;
}
@@ -470,8 +477,11 @@
ALOGV("[%s] %s: No matching buffer found", mName, __func__);
return false;
}
- std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
+ std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+ if (!result) {
+ result = clientBuffer->asC2Buffer();
+ mBuffers[index].compBuffer = result;
+ }
if (c2buffer) {
*c2buffer = result;
}
@@ -485,8 +495,8 @@
if (!compBuffer || compBuffer != c2buffer) {
continue;
}
- mBuffers[i].clientBuffer = nullptr;
mBuffers[i].compBuffer.reset();
+ ALOGV("[%s] codec released buffer #%zu", mName, i);
return true;
}
ALOGV("[%s] codec released an unknown buffer", mName);
@@ -597,7 +607,10 @@
* \return true if the buffer is successfully returned
* false otherwise
*/
- bool returnBuffer(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+ bool returnBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
sp<Codec2Buffer> clientBuffer;
size_t index = mBuffers.size();
for (size_t i = 0; i < mBuffers.size(); ++i) {
@@ -606,7 +619,9 @@
ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
}
clientBuffer = mBuffers[i].clientBuffer;
- mBuffers[i].ownedByClient = false;
+ if (release) {
+ mBuffers[i].ownedByClient = false;
+ }
index = i;
break;
}
@@ -616,8 +631,11 @@
return false;
}
ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
- std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
+ std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+ if (!result) {
+ result = clientBuffer->asC2Buffer();
+ mBuffers[index].compBuffer = result;
+ }
if (c2buffer) {
*c2buffer = result;
}
@@ -636,9 +654,9 @@
// This should not happen.
ALOGD("[%s] codec released a buffer owned by client "
"(index %zu)", mName, i);
- mBuffers[i].ownedByClient = false;
}
mBuffers[i].compBuffer.reset();
+ ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
return true;
}
}
@@ -723,8 +741,10 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.returnBuffer(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.returnBuffer(buffer, c2buffer, release);
}
bool expireComponentBuffer(
@@ -765,8 +785,10 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
}
bool expireComponentBuffer(
@@ -801,7 +823,7 @@
return std::move(array);
}
- virtual sp<Codec2Buffer> alloc(size_t size) const {
+ virtual sp<Codec2Buffer> alloc(size_t size) {
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
std::shared_ptr<C2LinearBlock> block;
@@ -850,11 +872,12 @@
~EncryptedLinearInputBuffers() override {
}
- sp<Codec2Buffer> alloc(size_t size) const override {
+ sp<Codec2Buffer> alloc(size_t size) override {
sp<IMemory> memory;
- for (const Entry &entry : mMemoryVector) {
- if (entry.block.expired()) {
- memory = entry.memory;
+ size_t slot = 0;
+ for (; slot < mMemoryVector.size(); ++slot) {
+ if (mMemoryVector[slot].block.expired()) {
+ memory = mMemoryVector[slot].memory;
break;
}
}
@@ -864,10 +887,11 @@
std::shared_ptr<C2LinearBlock> block;
c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
- if (err != C2_OK) {
+ if (err != C2_OK || block == nullptr) {
return nullptr;
}
+ mMemoryVector[slot].block = block;
return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
}
@@ -907,8 +931,10 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
}
bool expireComponentBuffer(
@@ -971,14 +997,17 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
}
bool expireComponentBuffer(
const std::shared_ptr<C2Buffer> &c2buffer) override {
return mImpl.expireComponentBuffer(c2buffer);
}
+
void flush() override {
// This is no-op by default unless we're in array mode where we need to keep
// track of the flushed work.
@@ -1016,7 +1045,7 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *) override {
+ const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
return false;
}
@@ -1111,7 +1140,7 @@
bool releaseBuffer(
const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.returnBuffer(buffer, c2buffer);
+ return mImpl.returnBuffer(buffer, c2buffer, true);
}
void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
@@ -1190,8 +1219,9 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer) override {
+ return mImpl.releaseSlot(buffer, c2buffer, true);
}
void flush(
@@ -1615,7 +1645,7 @@
if (buffer->size() > 0u) {
Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
std::shared_ptr<C2Buffer> c2buffer;
- if (!(*buffers)->releaseBuffer(buffer, &c2buffer)) {
+ if (!(*buffers)->releaseBuffer(buffer, &c2buffer, false)) {
return -ENOENT;
}
work->input.buffers.push_back(c2buffer);
@@ -1653,6 +1683,10 @@
}
if (err == C2_OK) {
mCCodecCallback->onWorkQueued(eos);
+
+ Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
+ bool released = (*buffers)->releaseBuffer(buffer, nullptr, true);
+ ALOGV("[%s] queueInputBuffer: buffer %sreleased", mName, released ? "" : "not ");
}
feedInputBufferIfAvailableInternal();
@@ -1981,7 +2015,7 @@
bool released = false;
{
Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) {
+ if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr, true)) {
buffers.unlock();
released = true;
mAvailablePipelineCapacity.freeInputSlots(1, "discardBuffer");
@@ -2446,7 +2480,6 @@
mSync.stop();
mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
if (mInputSurface != nullptr) {
- mInputSurface->disconnect();
mInputSurface.reset();
}
}
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index a8cc62d..5f0dd0b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -44,6 +44,7 @@
#include <cutils/native_handle.h>
#include <media/omx/1.0/WOmxNode.h>
#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
@@ -299,7 +300,6 @@
// OMX components don't have aliases
for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
const std::string &mediaType = type.first;
-
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(mediaType.c_str());
const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
@@ -376,7 +376,7 @@
}
bool surfaceTest(Codec2Client::CreateInputSurface());
- if (option == 0 || !surfaceTest) {
+ if (option == 0 || (option != 4 && !surfaceTest)) {
buildOmxInfo(parser, writer);
}
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index eb6c3e9..8c8f025 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -26,6 +26,10 @@
"libutils",
],
+ static_libs: [
+ "libyuv_static",
+ ],
+
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 84d22a3..6b8663f 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "Codec2BufferUtils"
#include <utils/Log.h>
+#include <libyuv.h>
+
#include <list>
#include <mutex>
@@ -62,14 +64,10 @@
*/
template<bool ToMediaImage, typename View, typename ImagePixel>
static status_t _ImageCopy(View &view, const MediaImage2 *img, ImagePixel *imgBase) {
- // TODO: more efficient copying --- e.g. one row at a time, copying
- // interleaved planes together, etc.
+ // TODO: more efficient copying --- e.g. copy interleaved planes together, etc.
const C2PlanarLayout &layout = view.layout();
const size_t bpp = divUp(img->mBitDepthAllocated, 8u);
- if (view.width() != img->mWidth
- || view.height() != img->mHeight) {
- return BAD_VALUE;
- }
+
for (uint32_t i = 0; i < layout.numPlanes; ++i) {
typename std::conditional<ToMediaImage, uint8_t, const uint8_t>::type *imgRow =
imgBase + img->mPlane[i].mOffset;
@@ -120,10 +118,72 @@
} // namespace
status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
+ if (view.width() != img->mWidth || view.height() != img->mHeight) {
+ return BAD_VALUE;
+ }
+ if ((IsNV12(view) && IsI420(img)) || (IsI420(view) && IsNV12(img))) {
+ // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+ const uint8_t* src_y = view.data()[0];
+ const uint8_t* src_u = view.data()[1];
+ const uint8_t* src_v = view.data()[2];
+ int32_t src_stride_y = view.layout().planes[0].rowInc;
+ int32_t src_stride_u = view.layout().planes[1].rowInc;
+ int32_t src_stride_v = view.layout().planes[2].rowInc;
+ uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
+ uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
+ uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
+ int32_t dst_stride_y = img->mPlane[0].mRowInc;
+ int32_t dst_stride_u = img->mPlane[1].mRowInc;
+ int32_t dst_stride_v = img->mPlane[2].mRowInc;
+ if (IsNV12(view) && IsI420(img)) {
+ if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+ dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+ view.height())) {
+ return OK;
+ }
+ } else {
+ if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+ dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+ view.height())) {
+ return OK;
+ }
+ }
+ }
return _ImageCopy<true>(view, img, imgBase);
}
status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img) {
+ if (view.width() != img->mWidth || view.height() != img->mHeight) {
+ return BAD_VALUE;
+ }
+ if ((IsNV12(img) && IsI420(view)) || (IsI420(img) && IsNV12(view))) {
+ // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+ const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
+ const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
+ const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
+ int32_t src_stride_y = img->mPlane[0].mRowInc;
+ int32_t src_stride_u = img->mPlane[1].mRowInc;
+ int32_t src_stride_v = img->mPlane[2].mRowInc;
+ uint8_t* dst_y = view.data()[0];
+ uint8_t* dst_u = view.data()[1];
+ uint8_t* dst_v = view.data()[2];
+ int32_t dst_stride_y = view.layout().planes[0].rowInc;
+ int32_t dst_stride_u = view.layout().planes[1].rowInc;
+ int32_t dst_stride_v = view.layout().planes[2].rowInc;
+ if (IsNV12(img) && IsI420(view)) {
+ if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+ dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+ view.height())) {
+ return OK;
+ }
+ } else {
+ if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+ dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+ view.height())) {
+ return OK;
+ }
+ }
+ }
return _ImageCopy<false>(view, img, imgBase);
}
@@ -151,6 +211,65 @@
&& layout.planes[layout.PLANE_V].rowSampling == 2);
}
+bool IsNV12(const C2GraphicView &view) {
+ if (!IsYUV420(view)) {
+ return false;
+ }
+ const C2PlanarLayout &layout = view.layout();
+ return (layout.rootPlanes == 2
+ && layout.planes[layout.PLANE_U].colInc == 2
+ && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_U].offset == 0
+ && layout.planes[layout.PLANE_V].colInc == 2
+ && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_V].offset == 1);
+}
+
+bool IsI420(const C2GraphicView &view) {
+ if (!IsYUV420(view)) {
+ return false;
+ }
+ const C2PlanarLayout &layout = view.layout();
+ return (layout.rootPlanes == 3
+ && layout.planes[layout.PLANE_U].colInc == 1
+ && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_U].offset == 0
+ && layout.planes[layout.PLANE_V].colInc == 1
+ && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
+ && layout.planes[layout.PLANE_V].offset == 0);
+}
+
+bool IsYUV420(const MediaImage2 *img) {
+ return (img->mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV
+ && img->mNumPlanes == 3
+ && img->mBitDepth == 8
+ && img->mBitDepthAllocated == 8
+ && img->mPlane[0].mHorizSubsampling == 1
+ && img->mPlane[0].mVertSubsampling == 1
+ && img->mPlane[1].mHorizSubsampling == 2
+ && img->mPlane[1].mVertSubsampling == 2
+ && img->mPlane[2].mHorizSubsampling == 2
+ && img->mPlane[2].mVertSubsampling == 2);
+}
+
+bool IsNV12(const MediaImage2 *img) {
+ if (!IsYUV420(img)) {
+ return false;
+ }
+ return (img->mPlane[1].mColInc == 2
+ && img->mPlane[2].mColInc == 2
+ && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+}
+
+bool IsI420(const MediaImage2 *img) {
+ if (!IsYUV420(img)) {
+ return false;
+ }
+ return (img->mPlane[1].mColInc == 1
+ && img->mPlane[2].mColInc == 1
+ && img->mPlane[2].mOffset > img->mPlane[1].mOffset);
+}
+
MediaImage2 CreateYUV420PlanarMediaImage2(
uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
return MediaImage2 {
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index eaf6776..afadf00 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -91,6 +91,31 @@
bool IsYUV420(const C2GraphicView &view);
/**
+ * Returns true iff a view has a NV12 layout.
+ */
+bool IsNV12(const C2GraphicView &view);
+
+/**
+ * Returns true iff a view has a I420 layout.
+ */
+bool IsI420(const C2GraphicView &view);
+
+/**
+ * Returns true iff a MediaImage2 has a YUV 420 888 layout.
+ */
+bool IsYUV420(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a NV12 layout.
+ */
+bool IsNV12(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a I420 layout.
+ */
+bool IsI420(const MediaImage2 *img);
+
+/**
* A raw memory block to use for internal buffers.
*
* TODO: replace this with C2LinearBlocks from a private C2BlockPool