Merge "Include calling uid proc state in CameraService reject log." into qt-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index 6673543..2cc6fcb 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -15,7 +15,6 @@
apex_defaults {
name: "com.android.media-defaults",
java_libs: ["updatable-media"],
- compile_multilib: "both",
multilib: {
first: {
// Extractor process runs only with the primary ABI.
@@ -33,12 +32,6 @@
"libwavextractor",
],
},
- both: {
- native_shared_libs: [
- // MediaPlayer2
- "libmedia2_jni",
- ],
- },
},
key: "com.android.media.key",
certificate: ":com.android.media.certificate",
@@ -99,7 +92,6 @@
name: "com.android.media.swcodec",
manifest: "manifest_codec.json",
defaults: ["com.android.media.swcodec-defaults"],
- vintf_fragments: ["manifest_media_c2_software.xml"],
}
apex_key {
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index b6896f5..715113d 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -27,7 +27,7 @@
# TODO: replace the following when apex has a way to auto-generate this list
# namespace.default.link.platform.shared_libs = %LLNDK_LIBRARIES%
# namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so
###############################################################################
# "platform" namespace
diff --git a/apex/manifest.json b/apex/manifest.json
index c6c63f6..cee94e2 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media",
- "version": 200000000
+ "version": 210000000
}
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index 4f31b15..b83e65a 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
{
"name": "com.android.media.swcodec",
- "version": 200000000
+ "version": 210000000
}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 320e7b3..4563b41 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7670,6 +7670,24 @@
* <li>ACAMERA_LENS_POSE_REFERENCE</li>
* <li>ACAMERA_LENS_DISTORTION</li>
* </ul>
+ * <p>The field of view of all non-RAW physical streams must be the same or as close as
+ * possible to that of non-RAW logical streams. If the requested FOV is outside of the
+ * range supported by the physical camera, the physical stream for that physical camera
+ * will use either the maximum or minimum scaler crop region, depending on which one is
+ * closer to the requested FOV. For example, for a logical camera with wide-tele lens
+ * configuration where the wide lens is the default, if the logical camera's crop region
+ * is set to maximum, the physical stream for the tele lens will be configured to its
+ * maximum crop region. On the other hand, if the logical camera has a normal-wide lens
+ * configuration where the normal lens is the default, when the logical camera's crop
+ * region is set to maximum, the FOV of the logical streams will be that of the normal
+ * lens. The FOV of the physical streams for the wide lens will be the same as the
+ * logical stream, by making the crop region smaller than its active array size to
+ * compensate for the smaller focal length.</p>
+ * <p>Even if the underlying physical cameras have different RAW characteristics (such as
+ * size or CFA pattern), a logical camera can still advertise RAW capability. In this
+ * case, when the application configures a RAW stream, the camera device will make sure
+ * the active physical camera will remain active to ensure consistent RAW output
+ * behavior, and not switch to other physical cameras.</p>
* <p>To maintain backward compatibility, the capture request and result metadata tags
* required for basic camera functionalities will be solely based on the
* logical camera capabiltity. Other request and result metadata tags, on the other
@@ -8311,6 +8329,7 @@
* fire the flash for flash power metering during precapture, and then fire the flash
* for the final capture, if a flash is available on the device and the AE mode is set to
* enable the flash.</p>
+ * <p>Devices that initially shipped with Android version <a href="https://developer.android.com/reference/android/os/Build.VERSION_CODES.html#Q">Q</a> or newer will not include any LEGACY-level devices.</p>
*
* @see ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
* @see ACAMERA_REQUEST_AVAILABLE_CAPABILITIES
diff --git a/media/OWNERS b/media/OWNERS
index 1e2d123..1afc253 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -1,3 +1,4 @@
+andrewlewis@google.com
chz@google.com
dwkang@google.com
elaurent@google.com
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index 97dde71..b2a5fee 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -1,4 +1,49 @@
// DO NOT DEPEND ON THIS DIRECTLY
+// use libcodec2-hidl-client-defaults instead
+cc_library {
+ name: "libcodec2_hidl_client@1.0",
+
+ defaults: ["hidl_defaults"],
+
+ srcs: [
+ "ClientBlockHelper.cpp",
+ "types.cpp",
+ ],
+
+ header_libs: [
+ "libcodec2_internal", // private
+ ],
+
+ shared_libs: [
+ "android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.c2@1.0",
+ "libbase",
+ "libcodec2",
+ "libcodec2_vndk",
+ "libcutils",
+ "libgui",
+ "libhidlbase",
+ "liblog",
+ "libstagefright_bufferpool@2.0",
+ "libui",
+ "libutils",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "android.hardware.media.c2@1.0",
+ "libcodec2",
+ "libgui",
+ "libstagefright_bufferpool@2.0",
+ "libui",
+ ],
+}
+
+
+// DO NOT DEPEND ON THIS DIRECTLY
// use libcodec2-hidl-defaults instead
cc_library {
name: "libcodec2_hidl@1.0",
@@ -33,12 +78,10 @@
"android.hardware.media.bufferpool@2.0",
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
- "android.hidl.safe_union@1.0",
"libbase",
"libcodec2",
"libcodec2_vndk",
"libcutils",
- "libgui",
"libhidlbase",
"libhidltransport",
"libhwbinder",
@@ -58,7 +101,6 @@
"libcodec2",
"libhidlbase",
"libstagefright_bufferpool@2.0",
- "libstagefright_bufferqueue_helper",
"libui",
],
}
@@ -73,3 +115,14 @@
"libcodec2_hidl@1.0",
],
}
+
+// public dependency for Codec 2.0 HAL client
+cc_defaults {
+ name: "libcodec2-hidl-client-defaults",
+ defaults: ["libcodec2-impl-defaults"],
+
+ shared_libs: [
+ "android.hardware.media.c2@1.0",
+ "libcodec2_hidl_client@1.0",
+ ],
+}
diff --git a/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp b/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
new file mode 100644
index 0000000..1786c69
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/ClientBlockHelper.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-block_helper"
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/ClientBlockHelper.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2PlatformSupport.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+ V2_0::IGraphicBufferProducer;
+using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
+ V2_0::utils::B2HGraphicBufferProducer;
+
+namespace /* unnamed */ {
+
+// Create a GraphicBuffer object from a graphic block.
+sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint64_t usage;
+ uint32_t stride;
+ uint32_t generation;
+ uint64_t bqId;
+ int32_t bqSlot;
+ _UnwrapNativeCodec2GrallocMetadata(
+ block.handle(), &width, &height, &format, &usage,
+ &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
+ native_handle_t *grallocHandle =
+ UnwrapNativeCodec2GrallocHandle(block.handle());
+ sp<GraphicBuffer> graphicBuffer =
+ new GraphicBuffer(grallocHandle,
+ GraphicBuffer::CLONE_HANDLE,
+ width, height, format,
+ 1, usage, stride);
+ native_handle_delete(grallocHandle);
+ return graphicBuffer;
+}
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+ BlockProcessor process) {
+ for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block :
+ buffer->data().graphicBlocks()) {
+ process(block);
+ }
+ }
+ }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+ BlockProcessor process,
+ bool processInput, bool processOutput) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ if (processInput) {
+ forEachBlock(work->input, process);
+ }
+ if (processOutput) {
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ forEachBlock(worklet->output,
+ process);
+ }
+ }
+ }
+ }
+}
+
+sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
+ sp<HGraphicBufferProducer> hgbp =
+ igbp->getHalInterface<HGraphicBufferProducer>();
+ return hgbp ? hgbp :
+ new B2HGraphicBufferProducer(igbp);
+}
+
+} // unnamed namespace
+
+status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ int32_t* bqSlot) {
+ if (!igbp) {
+ LOG(WARNING) << "attachToBufferQueue -- null producer.";
+ return NO_INIT;
+ }
+
+ sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
+ graphicBuffer->setGenerationNumber(generation);
+
+ LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
+ << " block dimension " << block.width() << "x"
+ << block.height()
+ << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
+ << graphicBuffer->getHeight()
+ << std::hex << std::setfill('0')
+ << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
+ << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
+ << std::dec << std::setfill(' ')
+ << ", stride " << graphicBuffer->getStride()
+ << ", generation " << graphicBuffer->getGenerationNumber();
+
+ status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
+ if (result != OK) {
+ LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+ "status = " << result << ".";
+ return result;
+ }
+ LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+ << *bqSlot << ".";
+ return OK;
+}
+
+bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
+ uint32_t* generation,
+ uint64_t* bqId,
+ int32_t* bqSlot) {
+ return _C2BlockFactory::GetBufferQueueData(
+ _C2BlockFactory::GetGraphicBlockPoolData(block),
+ generation, bqId, bqSlot);
+}
+
+bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint64_t bqId,
+ uint32_t generation) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (!data) {
+ return false;
+ }
+
+ uint32_t oldGeneration;
+ uint64_t oldId;
+ int32_t oldSlot;
+ // If the block is not bufferqueue-based, do nothing.
+ if (!_C2BlockFactory::GetBufferQueueData(
+ data, &oldGeneration, &oldId, &oldSlot) ||
+ (oldId == 0)) {
+ return false;
+ }
+
+ // If the block's bqId is the same as the desired bqId, just hold.
+ if ((oldId == bqId) && (oldGeneration == generation)) {
+ LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+ << " bqId " << oldId
+ << ", bqSlot " << oldSlot
+ << ", generation " << generation
+ << ".";
+ _C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
+ return true;
+ }
+
+ // Otherwise, attach to the given igbp, which must not be null.
+ if (!igbp) {
+ return false;
+ }
+
+ int32_t bqSlot;
+ status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
+
+ if (result != OK) {
+ LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
+ << " target bqId " << bqId
+ << ", generation " << generation
+ << ".";
+ return false;
+ }
+
+ LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
+ << " bqId " << bqId
+ << ", bqSlot " << bqSlot
+ << ", generation " << generation
+ << ".";
+ _C2BlockFactory::AssignBlockToBufferQueue(
+ data, getHgbp(igbp), generation, bqId, bqSlot, true);
+ return true;
+}
+
+void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint64_t bqId,
+ uint32_t generation,
+ bool forInput) {
+ forEachBlock(workList,
+ std::bind(holdBufferQueueBlock,
+ std::placeholders::_1, igbp, bqId, generation),
+ forInput, !forInput);
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 53bb6d2..d6f84b4 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -222,8 +222,7 @@
sp<InputSurface> inputSurface = new InputSurface(
this,
std::make_shared<C2ReflectorHelper>(),
- new ::android::hardware::graphics::bufferqueue::V2_0::utils::
- B2HGraphicBufferProducer(source->getIGraphicBufferProducer()),
+ source->getHGraphicBufferProducer(),
source);
_hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
inputSurface);
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
new file mode 100644
index 0000000..be429ac
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ClientBlockHelper.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CLIENT_BLOCK_HELPER_H
+#define CLIENT_BLOCK_HELPER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <codec2/hidl/1.0/types.h>
+#include <C2Work.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+
+// BufferQueue-Based Block Operations
+// ==================================
+
+// Create a GraphicBuffer object from a graphic block and attach it to an
+// IGraphicBufferProducer.
+status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint32_t generation,
+ int32_t* bqSlot);
+
+// Return false if block does not come from a bufferqueue-based blockpool.
+// Otherwise, extract generation, bqId and bqSlot and return true.
+bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
+ uint32_t* generation,
+ uint64_t* bqId,
+ int32_t* bqSlot);
+
+// Assign the given block to a bufferqueue so that when the block is destroyed,
+// cancelBuffer() will be called.
+//
+// If the block does not come from a bufferqueue-based blockpool, this function
+// returns false.
+//
+// If the block already has a bufferqueue assignment that matches the given one,
+// the function returns true.
+//
+// If the block already has a bufferqueue assignment that does not match the
+// given one, the block will be reassigned to the given bufferqueue. This
+// will call attachBuffer() on the given igbp. The function then returns true on
+// success or false on any failure during the operation.
+//
+// Note: This function should be called after detachBuffer() or dequeueBuffer()
+// is called manually.
+bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint64_t bqId,
+ uint32_t generation);
+
+// Call holdBufferQueueBlock() on input or output blocks in the given workList.
+// Since the bufferqueue assignment for input and output buffers can be
+// different, this function takes forInput to determine whether the given
+// bufferqueue is for input buffers or output buffers. (The default value of
+// forInput is false.)
+//
+// In the (rare) case that both input and output buffers are bufferqueue-based,
+// this function must be called twice, once for the input buffers and once for
+// the output buffers.
+//
+// Note: This function should be called after WorkBundle has been received from
+// another process.
+void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
+ const sp<IGraphicBufferProducer>& igbp,
+ uint64_t bqId,
+ uint32_t generation,
+ bool forInput = false);
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CLIENT_BLOCK_HELPER_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index 817d148..0ddfec5 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -23,7 +23,6 @@
#include <android/hardware/media/c2/1.0/IComponentStore.h>
#include <android/hardware/media/c2/1.0/types.h>
#include <android/hidl/safe_union/1.0/types.h>
-#include <gui/IGraphicBufferProducer.h>
#include <C2Component.h>
#include <C2Param.h>
@@ -50,7 +49,6 @@
using ::android::sp;
using ::android::hardware::media::bufferpool::V2_0::implementation::
ConnectionId;
-using ::android::IGraphicBufferProducer;
// Types of metadata for Blocks.
struct C2Hidl_Range {
@@ -301,20 +299,6 @@
// BufferQueue-Based Block Operations
// ==================================
-// Create a GraphicBuffer object from a graphic block and attach it to an
-// IGraphicBufferProducer.
-status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
- const sp<IGraphicBufferProducer>& igbp,
- uint32_t generation,
- int32_t* bqSlot);
-
-// Return false if block does not come from a bufferqueue-based blockpool.
-// Otherwise, extract generation, bqId and bqSlot and return true.
-bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
- uint32_t* generation,
- uint64_t* bqId,
- int32_t* bqSlot);
-
// Disassociate the given block with its designated bufferqueue so that
// cancelBuffer() will not be called when the block is destroyed. If the block
// does not have a designated bufferqueue, the function returns false.
@@ -336,45 +320,6 @@
bool processInput = false,
bool processOutput = true);
-// Assign the given block to a bufferqueue so that when the block is destroyed,
-// cancelBuffer() will be called.
-//
-// If the block does not come from a bufferqueue-based blockpool, this function
-// returns false.
-//
-// If the block already has a bufferqueue assignment that matches the given one,
-// the function returns true.
-//
-// If the block already has a bufferqueue assignment that does not match the
-// given one, the block will be reassigned to the given bufferqueue. This
-// will call attachBuffer() on the given igbp. The function then returns true on
-// success or false on any failure during the operation.
-//
-// Note: This function should be called after detachBuffer() or dequeueBuffer()
-// is called manually.
-bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
- const sp<IGraphicBufferProducer>& igbp,
- uint64_t bqId,
- uint32_t generation);
-
-// Call holdBufferQueueBlock() on input or output blocks in the given workList.
-// Since the bufferqueue assignment for input and output buffers can be
-// different, this function takes forInput to determine whether the given
-// bufferqueue is for input buffers or output buffers. (The default value of
-// forInput is false.)
-//
-// In the (rare) case that both input and output buffers are bufferqueue-based,
-// this function must be called twice, once for the input buffers and once for
-// the output buffers.
-//
-// Note: This function should be called after WorkBundle has been received from
-// another process.
-void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
- const sp<IGraphicBufferProducer>& igbp,
- uint64_t bqId,
- uint32_t generation,
- bool forInput = false);
-
} // namespace utils
} // namespace V1_0
} // namespace c2
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 74320e7..3fd2f92 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -18,9 +18,7 @@
#define LOG_TAG "Codec2-types"
#include <android-base/logging.h>
-#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
#include <codec2/hidl/1.0/types.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
#include <media/stagefright/foundation/AUtils.h>
#include <C2AllocatorIon.h>
@@ -54,10 +52,6 @@
ClientManager;
using ::android::hardware::media::bufferpool::V2_0::implementation::
TransactionId;
-using HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
- V2_0::IGraphicBufferProducer;
-using B2HGraphicBufferProducer = ::android::hardware::graphics::bufferqueue::
- V2_0::utils::B2HGraphicBufferProducer;
const char* asString(Status status, const char* def) {
return asString(static_cast<c2_status_t>(status), def);
@@ -1741,30 +1735,6 @@
namespace /* unnamed */ {
-// Create a GraphicBuffer object from a graphic block.
-sp<GraphicBuffer> createGraphicBuffer(const C2ConstGraphicBlock& block) {
- uint32_t width;
- uint32_t height;
- uint32_t format;
- uint64_t usage;
- uint32_t stride;
- uint32_t generation;
- uint64_t bqId;
- int32_t bqSlot;
- _UnwrapNativeCodec2GrallocMetadata(
- block.handle(), &width, &height, &format, &usage,
- &stride, &generation, &bqId, reinterpret_cast<uint32_t*>(&bqSlot));
- native_handle_t *grallocHandle =
- UnwrapNativeCodec2GrallocHandle(block.handle());
- sp<GraphicBuffer> graphicBuffer =
- new GraphicBuffer(grallocHandle,
- GraphicBuffer::CLONE_HANDLE,
- width, height, format,
- 1, usage, stride);
- native_handle_delete(grallocHandle);
- return graphicBuffer;
-}
-
template <typename BlockProcessor>
void forEachBlock(C2FrameData& frameData,
BlockProcessor process) {
@@ -1800,59 +1770,8 @@
}
}
-sp<HGraphicBufferProducer> getHgbp(const sp<IGraphicBufferProducer>& igbp) {
- sp<HGraphicBufferProducer> hgbp =
- igbp->getHalInterface<HGraphicBufferProducer>();
- return hgbp ? hgbp :
- new B2HGraphicBufferProducer(igbp);
-}
-
} // unnamed namespace
-status_t attachToBufferQueue(const C2ConstGraphicBlock& block,
- const sp<IGraphicBufferProducer>& igbp,
- uint32_t generation,
- int32_t* bqSlot) {
- if (!igbp) {
- LOG(WARNING) << "attachToBufferQueue -- null producer.";
- return NO_INIT;
- }
-
- sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
- graphicBuffer->setGenerationNumber(generation);
-
- LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
- << " block dimension " << block.width() << "x"
- << block.height()
- << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
- << graphicBuffer->getHeight()
- << std::hex << std::setfill('0')
- << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
- << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
- << std::dec << std::setfill(' ')
- << ", stride " << graphicBuffer->getStride()
- << ", generation " << graphicBuffer->getGenerationNumber();
-
- status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
- if (result != OK) {
- LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
- "status = " << result << ".";
- return result;
- }
- LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
- << *bqSlot << ".";
- return OK;
-}
-
-bool getBufferQueueAssignment(const C2ConstGraphicBlock& block,
- uint32_t* generation,
- uint64_t* bqId,
- int32_t* bqSlot) {
- return _C2BlockFactory::GetBufferQueueData(
- _C2BlockFactory::GetGraphicBlockPoolData(block),
- generation, bqId, bqSlot);
-}
-
bool yieldBufferQueueBlock(const C2ConstGraphicBlock& block) {
std::shared_ptr<_C2BlockPoolData> data =
_C2BlockFactory::GetGraphicBlockPoolData(block);
@@ -1869,74 +1788,6 @@
forEachBlock(workList, yieldBufferQueueBlock, processInput, processOutput);
}
-bool holdBufferQueueBlock(const C2ConstGraphicBlock& block,
- const sp<IGraphicBufferProducer>& igbp,
- uint64_t bqId,
- uint32_t generation) {
- std::shared_ptr<_C2BlockPoolData> data =
- _C2BlockFactory::GetGraphicBlockPoolData(block);
- if (!data) {
- return false;
- }
-
- uint32_t oldGeneration;
- uint64_t oldId;
- int32_t oldSlot;
- // If the block is not bufferqueue-based, do nothing.
- if (!_C2BlockFactory::GetBufferQueueData(
- data, &oldGeneration, &oldId, &oldSlot) ||
- (oldId == 0)) {
- return false;
- }
-
- // If the block's bqId is the same as the desired bqId, just hold.
- if ((oldId == bqId) && (oldGeneration == generation)) {
- LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
- << " bqId " << oldId
- << ", bqSlot " << oldSlot
- << ", generation " << generation
- << ".";
- _C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
- return true;
- }
-
- // Otherwise, attach to the given igbp, which must not be null.
- if (!igbp) {
- return false;
- }
-
- int32_t bqSlot;
- status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
-
- if (result != OK) {
- LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
- << " target bqId " << bqId
- << ", generation " << generation
- << ".";
- return false;
- }
-
- LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
- << " bqId " << bqId
- << ", bqSlot " << bqSlot
- << ", generation " << generation
- << ".";
- _C2BlockFactory::AssignBlockToBufferQueue(
- data, getHgbp(igbp), generation, bqId, bqSlot, true);
- return true;
-}
-
-void holdBufferQueueBlocks(const std::list<std::unique_ptr<C2Work>>& workList,
- const sp<IGraphicBufferProducer>& igbp,
- uint64_t bqId,
- uint32_t generation,
- bool forInput) {
- forEachBlock(workList,
- std::bind(holdBufferQueueBlock,
- std::placeholders::_1, igbp, bqId, generation),
- forInput, !forInput);
-}
-
} // namespace utils
} // namespace V1_0
} // namespace c2
diff --git a/media/codec2/hidl/1.0/vts/functional/common/Android.bp b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
index 94f46ed..da0061a 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
@@ -2,7 +2,7 @@
name: "VtsMediaC2V1_0CommonUtil",
defaults: [
"VtsHalTargetTestDefaults",
- "libcodec2-hidl-defaults",
+ "libcodec2-hidl-client-defaults",
],
include_dirs: [
@@ -20,7 +20,7 @@
name: "VtsMediaC2V1_0Defaults",
defaults: [
"VtsHalTargetTestDefaults",
- "libcodec2-hidl-defaults",
+ "libcodec2-hidl-client-defaults",
],
static_libs: [
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index f92d1af..a174008 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -12,7 +12,7 @@
"libbase",
"libbinder",
"libcodec2",
- "libcodec2_hidl@1.0",
+ "libcodec2_hidl_client@1.0",
"libcodec2_vndk",
"libcutils",
"libgui",
@@ -20,7 +20,6 @@
"libhidltransport",
"liblog",
"libstagefright_bufferpool@2.0",
- "libstagefright_bufferqueue_helper",
"libui",
"libutils",
],
@@ -31,7 +30,7 @@
export_shared_lib_headers: [
"libcodec2",
- "libcodec2_hidl@1.0",
+ "libcodec2_hidl_client@1.0",
],
}
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index 8265380..1851752 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -18,8 +18,7 @@
#define CODEC2_HIDL_CLIENT_H
#include <gui/IGraphicBufferProducer.h>
-#include <codec2/hidl/1.0/types.h>
-
+#include <codec2/hidl/1.0/ClientBlockHelper.h>
#include <C2PlatformSupport.h>
#include <C2Component.h>
#include <C2Buffer.h>
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index a212651..8ae80ee 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -5,6 +5,7 @@
"C2OMXNode.cpp",
"CCodec.cpp",
"CCodecBufferChannel.cpp",
+ "CCodecBuffers.cpp",
"CCodecConfig.cpp",
"Codec2Buffer.cpp",
"Codec2InfoBuilder.cpp",
@@ -40,7 +41,6 @@
"libmedia",
"libmedia_omx",
"libsfplugin_ccodec_utils",
- "libstagefright_bufferqueue_helper",
"libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx_utils",
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index 962df0f..6ae1c13 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -287,7 +287,7 @@
return UNKNOWN_ERROR;
}
- (void)mBufferIdsInUse.emplace(index, buffer);
+ mBufferIdsInUse.lock()->emplace(index, buffer);
return OK;
}
@@ -327,13 +327,19 @@
ALOGD("Buffer source not set (index=%llu)", index.peekull());
return;
}
- auto it = mBufferIdsInUse.find(index.peeku());
- if (it == mBufferIdsInUse.end()) {
- ALOGV("Untracked input index %llu (maybe already removed)", index.peekull());
- return;
+
+ int32_t bufferId = 0;
+ {
+ decltype(mBufferIdsInUse)::Locked bufferIds(mBufferIdsInUse);
+ auto it = bufferIds->find(index.peeku());
+ if (it == bufferIds->end()) {
+ ALOGV("Untracked input index %llu (maybe already removed)", index.peekull());
+ return;
+ }
+ bufferId = it->second;
+ (void)bufferIds->erase(it);
}
- (void)mBufferSource->onInputBufferEmptied(it->second, -1);
- (void)mBufferIdsInUse.erase(it);
+ (void)mBufferSource->onInputBufferEmptied(bufferId, -1);
}
} // namespace android
diff --git a/media/codec2/sfplugin/C2OMXNode.h b/media/codec2/sfplugin/C2OMXNode.h
index b7bd696..3ca6c0a 100644
--- a/media/codec2/sfplugin/C2OMXNode.h
+++ b/media/codec2/sfplugin/C2OMXNode.h
@@ -20,9 +20,10 @@
#include <atomic>
#include <android/IOMXBufferSource.h>
+#include <codec2/hidl/client.h>
+#include <media/stagefright/foundation/Mutexed.h>
#include <media/IOMX.h>
#include <media/OMXBuffer.h>
-#include <codec2/hidl/client.h>
namespace android {
@@ -111,7 +112,7 @@
c2_cntr64_t mPrevInputTimestamp; // input timestamp for previous frame
c2_cntr64_t mPrevCodecTimestamp; // adjusted (codec) timestamp for previous frame
- std::map<uint64_t, buffer_id> mBufferIdsInUse;
+ Mutexed<std::map<uint64_t, buffer_id>> mBufferIdsInUse;
};
} // namespace android
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 751c8c5..85c783b 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -40,7 +40,6 @@
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/PersistentSurface.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
#include "C2OMXNode.h"
#include "CCodec.h"
@@ -1034,7 +1033,8 @@
OmxStatus s;
android::sp<HGraphicBufferProducer> gbp;
android::sp<HGraphicBufferSource> gbs;
- android::Return<void> transStatus = omx->createInputSurface(
+ using ::android::hardware::Return;
+ Return<void> transStatus = omx->createInputSurface(
[&s, &gbp, &gbs](
OmxStatus status,
const android::sp<HGraphicBufferProducer>& producer,
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index d1fa920..90265de 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -56,1398 +56,14 @@
using CasStatus = hardware::cas::V1_0::Status;
-/**
- * Base class for representation of buffers at one port.
- */
-class CCodecBufferChannel::Buffers {
-public:
- Buffers(const char *componentName, const char *name = "Buffers")
- : mComponentName(componentName),
- mChannelName(std::string(componentName) + ":" + name),
- mName(mChannelName.c_str()) {
- }
- virtual ~Buffers() = default;
-
- /**
- * Set format for MediaCodec-facing buffers.
- */
- void setFormat(const sp<AMessage> &format) {
- CHECK(format != nullptr);
- mFormat = format;
- }
-
- /**
- * Return a copy of current format.
- */
- sp<AMessage> dupFormat() {
- return mFormat != nullptr ? mFormat->dup() : nullptr;
- }
-
- /**
- * Returns true if the buffers are operating under array mode.
- */
- virtual bool isArrayMode() const { return false; }
-
- /**
- * Fills the vector with MediaCodecBuffer's if in array mode; otherwise,
- * no-op.
- */
- virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {}
-
- /**
- * Return number of buffers the client owns.
- */
- virtual size_t numClientBuffers() const = 0;
-
- void handleImageData(const sp<Codec2Buffer> &buffer) {
- sp<ABuffer> imageDataCandidate = buffer->getImageData();
- if (imageDataCandidate == nullptr) {
- return;
- }
- sp<ABuffer> imageData;
- if (!mFormat->findBuffer("image-data", &imageData)
- || imageDataCandidate->size() != imageData->size()
- || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
- ALOGD("[%s] updating image-data", mName);
- sp<AMessage> newFormat = dupFormat();
- newFormat->setBuffer("image-data", imageDataCandidate);
- MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
- if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
- int32_t stride = img->mPlane[0].mRowInc;
- newFormat->setInt32(KEY_STRIDE, stride);
- ALOGD("[%s] updating stride = %d", mName, stride);
- if (img->mNumPlanes > 1 && stride > 0) {
- int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
- newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
- ALOGD("[%s] updating vstride = %d", mName, vstride);
- }
- }
- setFormat(newFormat);
- buffer->setFormat(newFormat);
- }
- }
-
-protected:
- std::string mComponentName; ///< name of component for debugging
- std::string mChannelName; ///< name of channel for debugging
- const char *mName; ///< C-string version of channel name
- // Format to be used for creating MediaCodec-facing buffers.
- sp<AMessage> mFormat;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(Buffers);
-};
-
-class CCodecBufferChannel::InputBuffers : public CCodecBufferChannel::Buffers {
-public:
- InputBuffers(const char *componentName, const char *name = "Input[]")
- : Buffers(componentName, name) { }
- virtual ~InputBuffers() = default;
-
- /**
- * Set a block pool to obtain input memory blocks.
- */
- void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; }
-
- /**
- * Get a new MediaCodecBuffer for input and its corresponding index.
- * Returns false if no new buffer can be obtained at the moment.
- */
- virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0;
-
- /**
- * Release the buffer obtained from requestNewBuffer() and get the
- * associated C2Buffer object back. Returns true if the buffer was on file
- * and released successfully.
- */
- virtual bool releaseBuffer(
- 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
- * true if and only if the buffer was on file and released successfully.
- */
- virtual bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) = 0;
-
- /**
- * Flush internal state. After this call, no index or buffer previously
- * returned from requestNewBuffer() is valid.
- */
- virtual void flush() = 0;
-
- /**
- * Return array-backed version of input buffers. The returned object
- * shall retain the internal state so that it will honor index and
- * buffer from previous calls of requestNewBuffer().
- */
- virtual std::unique_ptr<InputBuffers> toArrayMode(size_t size) = 0;
-
-protected:
- // Pool to obtain blocks for input buffers.
- std::shared_ptr<C2BlockPool> mPool;
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
-};
-
-class CCodecBufferChannel::OutputBuffers : public CCodecBufferChannel::Buffers {
-public:
- OutputBuffers(const char *componentName, const char *name = "Output")
- : Buffers(componentName, name) { }
- virtual ~OutputBuffers() = default;
-
- /**
- * Register output C2Buffer from the component and obtain corresponding
- * index and MediaCodecBuffer object. Returns false if registration
- * fails.
- */
- virtual status_t registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) = 0;
-
- /**
- * Register codec specific data as a buffer to be consistent with
- * MediaCodec behavior.
- */
- virtual status_t registerCsd(
- const C2StreamInitDataInfo::output * /* csd */,
- size_t * /* index */,
- sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
-
- /**
- * Release the buffer obtained from registerBuffer() and get the
- * associated C2Buffer object back. Returns true if the buffer was on file
- * and released successfully.
- */
- virtual bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
-
- /**
- * Flush internal state. After this call, no index or buffer previously
- * returned from registerBuffer() is valid.
- */
- virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0;
-
- /**
- * Return array-backed version of output buffers. The returned object
- * shall retain the internal state so that it will honor index and
- * buffer from previous calls of registerBuffer().
- */
- virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
-
- /**
- * Initialize SkipCutBuffer object.
- */
- void initSkipCutBuffer(
- int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
- CHECK(mSkipCutBuffer == nullptr);
- mDelay = delay;
- mPadding = padding;
- mSampleRate = sampleRate;
- setSkipCutBuffer(delay, padding, channelCount);
- }
-
- /**
- * Update the SkipCutBuffer object. No-op if it's never initialized.
- */
- void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
- if (mSkipCutBuffer == nullptr) {
- return;
- }
- int32_t delay = mDelay;
- int32_t padding = mPadding;
- if (sampleRate != mSampleRate) {
- delay = ((int64_t)delay * sampleRate) / mSampleRate;
- padding = ((int64_t)padding * sampleRate) / mSampleRate;
- }
- setSkipCutBuffer(delay, padding, channelCount);
- }
-
- /**
- * Submit buffer to SkipCutBuffer object, if initialized.
- */
- void submit(const sp<MediaCodecBuffer> &buffer) {
- if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->submit(buffer);
- }
- }
-
- /**
- * Transfer SkipCutBuffer object to the other Buffers object.
- */
- void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
- mSkipCutBuffer = scb;
- }
-
-protected:
- sp<SkipCutBuffer> mSkipCutBuffer;
-
-private:
- int32_t mDelay;
- int32_t mPadding;
- int32_t mSampleRate;
-
- void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
- if (mSkipCutBuffer != nullptr) {
- size_t prevSize = mSkipCutBuffer->size();
- if (prevSize != 0u) {
- ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
- }
- }
- mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
-};
-
namespace {
-const static size_t kSmoothnessFactor = 4;
-const static size_t kRenderingDepth = 3;
-const static size_t kLinearBufferSize = 1048576;
-// This can fit 4K RGBA frame, and most likely client won't need more than this.
-const static size_t kMaxLinearBufferSize = 3840 * 2160 * 4;
+constexpr size_t kSmoothnessFactor = 4;
+constexpr size_t kRenderingDepth = 3;
-/**
- * Simple local buffer pool backed by std::vector.
- */
-class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> {
-public:
- /**
- * Create a new LocalBufferPool object.
- *
- * \param poolCapacity max total size of buffers managed by this pool.
- *
- * \return a newly created pool object.
- */
- static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity) {
- return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
- }
-
- /**
- * Return an ABuffer object whose size is at least |capacity|.
- *
- * \param capacity requested capacity
- * \return nullptr if the pool capacity is reached
- * an ABuffer object otherwise.
- */
- sp<ABuffer> newBuffer(size_t capacity) {
- Mutex::Autolock lock(mMutex);
- auto it = std::find_if(
- mPool.begin(), mPool.end(),
- [capacity](const std::vector<uint8_t> &vec) {
- return vec.capacity() >= capacity;
- });
- if (it != mPool.end()) {
- sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
- mPool.erase(it);
- return buffer;
- }
- if (mUsedSize + capacity > mPoolCapacity) {
- while (!mPool.empty()) {
- mUsedSize -= mPool.back().capacity();
- mPool.pop_back();
- }
- if (mUsedSize + capacity > mPoolCapacity) {
- ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
- mUsedSize, capacity, mPoolCapacity);
- return nullptr;
- }
- }
- std::vector<uint8_t> vec(capacity);
- mUsedSize += vec.capacity();
- return new VectorBuffer(std::move(vec), shared_from_this());
- }
-
-private:
- /**
- * ABuffer backed by std::vector.
- */
- class VectorBuffer : public ::android::ABuffer {
- public:
- /**
- * Construct a VectorBuffer by taking the ownership of supplied vector.
- *
- * \param vec backing vector of the buffer. this object takes
- * ownership at construction.
- * \param pool a LocalBufferPool object to return the vector at
- * destruction.
- */
- VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
- : ABuffer(vec.data(), vec.capacity()),
- mVec(std::move(vec)),
- mPool(pool) {
- }
-
- ~VectorBuffer() override {
- std::shared_ptr<LocalBufferPool> pool = mPool.lock();
- if (pool) {
- // If pool is alive, return the vector back to the pool so that
- // it can be recycled.
- pool->returnVector(std::move(mVec));
- }
- }
-
- private:
- std::vector<uint8_t> mVec;
- std::weak_ptr<LocalBufferPool> mPool;
- };
-
- Mutex mMutex;
- size_t mPoolCapacity;
- size_t mUsedSize;
- std::list<std::vector<uint8_t>> mPool;
-
- /**
- * Private constructor to prevent constructing non-managed LocalBufferPool.
- */
- explicit LocalBufferPool(size_t poolCapacity)
- : mPoolCapacity(poolCapacity), mUsedSize(0) {
- }
-
- /**
- * Take back the ownership of vec from the destructed VectorBuffer and put
- * it in front of the pool.
- */
- void returnVector(std::vector<uint8_t> &&vec) {
- Mutex::Autolock lock(mMutex);
- mPool.push_front(std::move(vec));
- }
-
- DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool);
-};
-
-sp<GraphicBlockBuffer> AllocateGraphicBuffer(
- const std::shared_ptr<C2BlockPool> &pool,
- const sp<AMessage> &format,
- uint32_t pixelFormat,
- const C2MemoryUsage &usage,
- const std::shared_ptr<LocalBufferPool> &localBufferPool) {
- int32_t width, height;
- if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
- ALOGD("format lacks width or height");
- return nullptr;
- }
-
- std::shared_ptr<C2GraphicBlock> block;
- c2_status_t err = pool->fetchGraphicBlock(
- width, height, pixelFormat, usage, &block);
- if (err != C2_OK) {
- ALOGD("fetch graphic block failed: %d", err);
- return nullptr;
- }
-
- return GraphicBlockBuffer::Allocate(
- format,
- block,
- [localBufferPool](size_t capacity) {
- return localBufferPool->newBuffer(capacity);
- });
-}
-
-class BuffersArrayImpl;
-
-/**
- * Flexible buffer slots implementation.
- */
-class FlexBuffersImpl {
-public:
- FlexBuffersImpl(const char *name)
- : mImplName(std::string(name) + ".Impl"),
- mName(mImplName.c_str()) { }
-
- /**
- * Assign an empty slot for a buffer and return the index. If there's no
- * empty slot, just add one at the end and return it.
- *
- * \param buffer[in] a new buffer to assign a slot.
- * \return index of the assigned slot.
- */
- size_t assignSlot(const sp<Codec2Buffer> &buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (mBuffers[i].clientBuffer == nullptr
- && mBuffers[i].compBuffer.expired()) {
- mBuffers[i].clientBuffer = buffer;
- return i;
- }
- }
- mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
- return mBuffers.size() - 1;
- }
-
- /**
- * Release the slot from the client, and get the C2Buffer object back from
- * the previously assigned buffer. Note that the slot is not completely free
- * until the returned C2Buffer object is freed.
- *
- * \param buffer[in] the buffer previously assigned a slot.
- * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored
- * if null.
- * \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 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;
- if (release) {
- mBuffers[i].clientBuffer.clear();
- }
- index = i;
- break;
- }
- }
- if (clientBuffer == nullptr) {
- ALOGV("[%s] %s: No matching buffer found", mName, __func__);
- return false;
- }
- std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
- if (!result) {
- result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
- }
- if (c2buffer) {
- *c2buffer = result;
- }
- return true;
- }
-
- bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- std::shared_ptr<C2Buffer> compBuffer =
- mBuffers[i].compBuffer.lock();
- if (!compBuffer || compBuffer != c2buffer) {
- continue;
- }
- mBuffers[i].compBuffer.reset();
- ALOGV("[%s] codec released buffer #%zu", mName, i);
- return true;
- }
- ALOGV("[%s] codec released an unknown buffer", mName);
- return false;
- }
-
- void flush() {
- ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
- mBuffers.clear();
- }
-
- size_t numClientBuffers() const {
- return std::count_if(
- mBuffers.begin(), mBuffers.end(),
- [](const Entry &entry) {
- return (entry.clientBuffer != nullptr);
- });
- }
-
-private:
- friend class BuffersArrayImpl;
-
- std::string mImplName; ///< name for debugging
- const char *mName; ///< C-string version of name
-
- struct Entry {
- sp<Codec2Buffer> clientBuffer;
- std::weak_ptr<C2Buffer> compBuffer;
- };
- std::vector<Entry> mBuffers;
-};
-
-/**
- * Static buffer slots implementation based on a fixed-size array.
- */
-class BuffersArrayImpl {
-public:
- BuffersArrayImpl()
- : mImplName("BuffersArrayImpl"),
- mName(mImplName.c_str()) { }
-
- /**
- * Initialize buffer array from the original |impl|. The buffers known by
- * the client is preserved, and the empty slots are populated so that the
- * array size is at least |minSize|.
- *
- * \param impl[in] FlexBuffersImpl object used so far.
- * \param minSize[in] minimum size of the buffer array.
- * \param allocate[in] function to allocate a client buffer for an empty slot.
- */
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImplName = impl.mImplName + "[N]";
- mName = mImplName.c_str();
- for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
- sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
- bool ownedByClient = (clientBuffer != nullptr);
- if (!ownedByClient) {
- clientBuffer = allocate();
- }
- mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
- }
- ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
- for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
- mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
- }
- }
-
- /**
- * Grab a buffer from the underlying array which matches the criteria.
- *
- * \param index[out] index of the slot.
- * \param buffer[out] the matching buffer.
- * \param match[in] a function to test whether the buffer matches the
- * criteria or not.
- * \return OK if successful,
- * WOULD_BLOCK if slots are being used,
- * NO_MEMORY if no slot matches the criteria, even though it's
- * available
- */
- status_t grabBuffer(
- size_t *index,
- sp<Codec2Buffer> *buffer,
- std::function<bool(const sp<Codec2Buffer> &)> match =
- [](const sp<Codec2Buffer> &) { return true; }) {
- // allBuffersDontMatch remains true if all buffers are available but
- // match() returns false for every buffer.
- bool allBuffersDontMatch = true;
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
- if (match(mBuffers[i].clientBuffer)) {
- mBuffers[i].ownedByClient = true;
- *buffer = mBuffers[i].clientBuffer;
- (*buffer)->meta()->clear();
- (*buffer)->setRange(0, (*buffer)->capacity());
- *index = i;
- return OK;
- }
- } else {
- allBuffersDontMatch = false;
- }
- }
- return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
- }
-
- /**
- * Return the buffer from the client, and get the C2Buffer object back from
- * the buffer. Note that the slot is not completely free until the returned
- * C2Buffer object is freed.
- *
- * \param buffer[in] the buffer previously grabbed.
- * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored
- * if null.
- * \return true if the buffer is successfully returned
- * false otherwise
- */
- 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) {
- if (mBuffers[i].clientBuffer == buffer) {
- if (!mBuffers[i].ownedByClient) {
- ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
- }
- clientBuffer = mBuffers[i].clientBuffer;
- if (release) {
- mBuffers[i].ownedByClient = false;
- }
- index = i;
- break;
- }
- }
- if (clientBuffer == nullptr) {
- ALOGV("[%s] %s: No matching buffer found", mName, __func__);
- return false;
- }
- ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
- std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
- if (!result) {
- result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
- }
- if (c2buffer) {
- *c2buffer = result;
- }
- return true;
- }
-
- bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
- for (size_t i = 0; i < mBuffers.size(); ++i) {
- std::shared_ptr<C2Buffer> compBuffer =
- mBuffers[i].compBuffer.lock();
- if (!compBuffer) {
- continue;
- }
- if (c2buffer == compBuffer) {
- if (mBuffers[i].ownedByClient) {
- // This should not happen.
- ALOGD("[%s] codec released a buffer owned by client "
- "(index %zu)", mName, i);
- }
- mBuffers[i].compBuffer.reset();
- ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
- return true;
- }
- }
- ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
- return false;
- }
-
- /**
- * Populate |array| with the underlying buffer array.
- *
- * \param array[out] an array to be filled with the underlying buffer array.
- */
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const {
- array->clear();
- for (const Entry &entry : mBuffers) {
- array->push(entry.clientBuffer);
- }
- }
-
- /**
- * The client abandoned all known buffers, so reclaim the ownership.
- */
- void flush() {
- for (Entry &entry : mBuffers) {
- entry.ownedByClient = false;
- }
- }
-
- void realloc(std::function<sp<Codec2Buffer>()> alloc) {
- size_t size = mBuffers.size();
- mBuffers.clear();
- for (size_t i = 0; i < size; ++i) {
- mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
- }
- }
-
- size_t numClientBuffers() const {
- return std::count_if(
- mBuffers.begin(), mBuffers.end(),
- [](const Entry &entry) {
- return entry.ownedByClient;
- });
- }
-
-private:
- std::string mImplName; ///< name for debugging
- const char *mName; ///< C-string version of name
-
- struct Entry {
- const sp<Codec2Buffer> clientBuffer;
- std::weak_ptr<C2Buffer> compBuffer;
- bool ownedByClient;
- };
- std::vector<Entry> mBuffers;
-};
-
-class InputBuffersArray : public CCodecBufferChannel::InputBuffers {
-public:
- InputBuffersArray(const char *componentName, const char *name = "Input[N]")
- : InputBuffers(componentName, name) { }
- ~InputBuffersArray() override = default;
-
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImpl.initialize(impl, minSize, allocate);
- }
-
- bool isArrayMode() const final { return true; }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t) final {
- return nullptr;
- }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- mImpl.getArray(array);
- }
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(index, &c2Buffer);
- if (err == OK) {
- c2Buffer->setFormat(mFormat);
- handleImageData(c2Buffer);
- *buffer = c2Buffer;
- return true;
- }
- return false;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer,
- bool release) override {
- return mImpl.returnBuffer(buffer, c2buffer, release);
- }
-
- bool expireComponentBuffer(
- const std::shared_ptr<C2Buffer> &c2buffer) override {
- return mImpl.expireComponentBuffer(c2buffer);
- }
-
- void flush() override {
- mImpl.flush();
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- BuffersArrayImpl mImpl;
-};
-
-class LinearInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- LinearInputBuffers(const char *componentName, const char *name = "1D-Input")
- : InputBuffers(componentName, name),
- mImpl(mName) { }
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- int32_t capacity = kLinearBufferSize;
- (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
- if ((size_t)capacity > kMaxLinearBufferSize) {
- ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
- capacity = kMaxLinearBufferSize;
- }
- // TODO: proper max input size
- // TODO: read usage from intf
- sp<Codec2Buffer> newBuffer = alloc((size_t)capacity);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- bool releaseBuffer(
- 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.
- mImpl.flush();
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t size) final {
- int32_t capacity = kLinearBufferSize;
- (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
- if ((size_t)capacity > kMaxLinearBufferSize) {
- ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
- capacity = kMaxLinearBufferSize;
- }
- // TODO: proper max input size
- // TODO: read usage from intf
- std::unique_ptr<InputBuffersArray> array(
- new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
- array->setPool(mPool);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- size,
- [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
- virtual sp<Codec2Buffer> alloc(size_t size) {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- std::shared_ptr<C2LinearBlock> block;
-
- c2_status_t err = mPool->fetchLinearBlock(size, usage, &block);
- if (err != C2_OK) {
- return nullptr;
- }
-
- return LinearBlockBuffer::Allocate(mFormat, block);
- }
-
-private:
- FlexBuffersImpl mImpl;
-};
-
-class EncryptedLinearInputBuffers : public LinearInputBuffers {
-public:
- EncryptedLinearInputBuffers(
- bool secure,
- const sp<MemoryDealer> &dealer,
- const sp<ICrypto> &crypto,
- int32_t heapSeqNum,
- size_t capacity,
- size_t numInputSlots,
- const char *componentName, const char *name = "EncryptedInput")
- : LinearInputBuffers(componentName, name),
- mUsage({0, 0}),
- mDealer(dealer),
- mCrypto(crypto),
- mHeapSeqNum(heapSeqNum) {
- if (secure) {
- mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
- } else {
- mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- }
- for (size_t i = 0; i < numInputSlots; ++i) {
- sp<IMemory> memory = mDealer->allocate(capacity);
- if (memory == nullptr) {
- ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated", mName, i);
- break;
- }
- mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory});
- }
- }
-
- ~EncryptedLinearInputBuffers() override {
- }
-
- sp<Codec2Buffer> alloc(size_t size) override {
- sp<IMemory> memory;
- size_t slot = 0;
- for (; slot < mMemoryVector.size(); ++slot) {
- if (mMemoryVector[slot].block.expired()) {
- memory = mMemoryVector[slot].memory;
- break;
- }
- }
- if (memory == nullptr) {
- return nullptr;
- }
-
- std::shared_ptr<C2LinearBlock> block;
- c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
- if (err != C2_OK || block == nullptr) {
- return nullptr;
- }
-
- mMemoryVector[slot].block = block;
- return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
- }
-
-private:
- C2MemoryUsage mUsage;
- sp<MemoryDealer> mDealer;
- sp<ICrypto> mCrypto;
- int32_t mHeapSeqNum;
- struct Entry {
- std::weak_ptr<C2LinearBlock> block;
- sp<IMemory> memory;
- };
- std::vector<Entry> mMemoryVector;
-};
-
-class GraphicMetadataInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- GraphicMetadataInputBuffers(const char *componentName, const char *name = "2D-MetaInput")
- : InputBuffers(componentName, name),
- mImpl(mName),
- mStore(GetCodec2PlatformAllocatorStore()) { }
- ~GraphicMetadataInputBuffers() override = default;
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- std::shared_ptr<C2Allocator> alloc;
- c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
- if (err != C2_OK) {
- return false;
- }
- sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- bool releaseBuffer(
- 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.
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t size) final {
- std::shared_ptr<C2Allocator> alloc;
- c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
- if (err != C2_OK) {
- return nullptr;
- }
- std::unique_ptr<InputBuffersArray> array(
- new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
- array->setPool(mPool);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- size,
- [format = mFormat, alloc]() -> sp<Codec2Buffer> {
- return new GraphicMetadataBuffer(format, alloc);
- });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- FlexBuffersImpl mImpl;
- std::shared_ptr<C2AllocatorStore> mStore;
-};
-
-class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- GraphicInputBuffers(
- size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input")
- : InputBuffers(componentName, name),
- mImpl(mName),
- mLocalBufferPool(LocalBufferPool::Create(
- kMaxLinearBufferSize * numInputSlots)) { }
- ~GraphicInputBuffers() override = default;
-
- bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
- // TODO: proper max input size
- // TODO: read usage from intf
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
- mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
- if (newBuffer == nullptr) {
- return false;
- }
- *index = mImpl.assignSlot(newBuffer);
- handleImageData(newBuffer);
- *buffer = newBuffer;
- return true;
- }
-
- bool releaseBuffer(
- 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.
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t size) final {
- std::unique_ptr<InputBuffersArray> array(
- new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
- array->setPool(mPool);
- array->setFormat(mFormat);
- array->initialize(
- mImpl,
- size,
- [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
- C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- return AllocateGraphicBuffer(
- pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
- });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- FlexBuffersImpl mImpl;
- std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
-
-class DummyInputBuffers : public CCodecBufferChannel::InputBuffers {
-public:
- DummyInputBuffers(const char *componentName, const char *name = "2D-Input")
- : InputBuffers(componentName, name) { }
-
- bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
- return false;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
- return false;
- }
-
- bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &) override {
- return false;
- }
- void flush() override {
- }
-
- std::unique_ptr<CCodecBufferChannel::InputBuffers> toArrayMode(
- size_t) final {
- return nullptr;
- }
-
- bool isArrayMode() const final { return true; }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- array->clear();
- }
-
- size_t numClientBuffers() const final {
- return 0u;
- }
-};
-
-class OutputBuffersArray : public CCodecBufferChannel::OutputBuffers {
-public:
- OutputBuffersArray(const char *componentName, const char *name = "Output[N]")
- : OutputBuffers(componentName, name) { }
- ~OutputBuffersArray() override = default;
-
- void initialize(
- const FlexBuffersImpl &impl,
- size_t minSize,
- std::function<sp<Codec2Buffer>()> allocate) {
- mImpl.initialize(impl, minSize, allocate);
- }
-
- bool isArrayMode() const final { return true; }
-
- std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode(
- size_t) final {
- return nullptr;
- }
-
- status_t registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(
- index,
- &c2Buffer,
- [buffer](const sp<Codec2Buffer> &clientBuffer) {
- return clientBuffer->canCopy(buffer);
- });
- if (err == WOULD_BLOCK) {
- ALOGV("[%s] buffers temporarily not available", mName);
- return err;
- } else if (err != OK) {
- ALOGD("[%s] grabBuffer failed: %d", mName, err);
- return err;
- }
- c2Buffer->setFormat(mFormat);
- if (!c2Buffer->copy(buffer)) {
- ALOGD("[%s] copy buffer failed", mName);
- return WOULD_BLOCK;
- }
- submit(c2Buffer);
- handleImageData(c2Buffer);
- *clientBuffer = c2Buffer;
- ALOGV("[%s] grabbed buffer %zu", mName, *index);
- return OK;
- }
-
- status_t registerCsd(
- const C2StreamInitDataInfo::output *csd,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> c2Buffer;
- status_t err = mImpl.grabBuffer(
- index,
- &c2Buffer,
- [csd](const sp<Codec2Buffer> &clientBuffer) {
- return clientBuffer->base() != nullptr
- && clientBuffer->capacity() >= csd->flexCount();
- });
- if (err != OK) {
- return err;
- }
- memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
- c2Buffer->setRange(0, csd->flexCount());
- c2Buffer->setFormat(mFormat);
- *clientBuffer = c2Buffer;
- return OK;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.returnBuffer(buffer, c2buffer, true);
- }
-
- void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- (void)flushedWork;
- mImpl.flush();
- if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->clear();
- }
- }
-
- void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
- mImpl.getArray(array);
- }
-
- void realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
- std::function<sp<Codec2Buffer>()> alloc;
- switch (c2buffer->data().type()) {
- case C2BufferData::LINEAR: {
- uint32_t size = kLinearBufferSize;
- const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
- if (block.size() < kMaxLinearBufferSize / 2) {
- size = block.size() * 2;
- } else {
- size = kMaxLinearBufferSize;
- }
- alloc = [format = mFormat, size] {
- return new LocalLinearBuffer(format, new ABuffer(size));
- };
- break;
- }
-
- // TODO: add support
- case C2BufferData::GRAPHIC: FALLTHROUGH_INTENDED;
-
- case C2BufferData::INVALID: FALLTHROUGH_INTENDED;
- case C2BufferData::LINEAR_CHUNKS: FALLTHROUGH_INTENDED;
- case C2BufferData::GRAPHIC_CHUNKS: FALLTHROUGH_INTENDED;
- default:
- ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
- return;
- }
- mImpl.realloc(alloc);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
-private:
- BuffersArrayImpl mImpl;
-};
-
-class FlexOutputBuffers : public CCodecBufferChannel::OutputBuffers {
-public:
- FlexOutputBuffers(const char *componentName, const char *name = "Output[]")
- : OutputBuffers(componentName, name),
- mImpl(mName) { }
-
- status_t registerBuffer(
- const std::shared_ptr<C2Buffer> &buffer,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) override {
- sp<Codec2Buffer> newBuffer = wrap(buffer);
- if (newBuffer == nullptr) {
- return NO_MEMORY;
- }
- newBuffer->setFormat(mFormat);
- *index = mImpl.assignSlot(newBuffer);
- handleImageData(newBuffer);
- *clientBuffer = newBuffer;
- ALOGV("[%s] registered buffer %zu", mName, *index);
- return OK;
- }
-
- status_t registerCsd(
- const C2StreamInitDataInfo::output *csd,
- size_t *index,
- sp<MediaCodecBuffer> *clientBuffer) final {
- sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
- mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
- *index = mImpl.assignSlot(newBuffer);
- *clientBuffer = newBuffer;
- return OK;
- }
-
- bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer,
- std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer, true);
- }
-
- void flush(
- const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- (void) flushedWork;
- // This is no-op by default unless we're in array mode where we need to keep
- // track of the flushed work.
- }
-
- std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode(
- size_t size) override {
- std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
- array->setFormat(mFormat);
- array->transferSkipCutBuffer(mSkipCutBuffer);
- array->initialize(
- mImpl,
- size,
- [this]() { return allocateArrayBuffer(); });
- return std::move(array);
- }
-
- size_t numClientBuffers() const final {
- return mImpl.numClientBuffers();
- }
-
- /**
- * Return an appropriate Codec2Buffer object for the type of buffers.
- *
- * \param buffer C2Buffer object to wrap.
- *
- * \return appropriate Codec2Buffer object to wrap |buffer|.
- */
- virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
-
- /**
- * Return an appropriate Codec2Buffer object for the type of buffers, to be
- * used as an empty array buffer.
- *
- * \return appropriate Codec2Buffer object which can copy() from C2Buffers.
- */
- virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
-
-private:
- FlexBuffersImpl mImpl;
-};
-
-class LinearOutputBuffers : public FlexOutputBuffers {
-public:
- LinearOutputBuffers(const char *componentName, const char *name = "1D-Output")
- : FlexOutputBuffers(componentName, name) { }
-
- void flush(
- const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
- if (mSkipCutBuffer != nullptr) {
- mSkipCutBuffer->clear();
- }
- FlexOutputBuffers::flush(flushedWork);
- }
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- if (buffer == nullptr) {
- ALOGV("[%s] using a dummy buffer", mName);
- return new LocalLinearBuffer(mFormat, new ABuffer(0));
- }
- if (buffer->data().type() != C2BufferData::LINEAR) {
- ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
- // We expect linear output buffers from the component.
- return nullptr;
- }
- if (buffer->data().linearBlocks().size() != 1u) {
- ALOGV("[%s] no linear buffers", mName);
- // We expect one and only one linear block from the component.
- return nullptr;
- }
- sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
- if (clientBuffer == nullptr) {
- ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
- return nullptr;
- }
- submit(clientBuffer);
- return clientBuffer;
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- // TODO: proper max output size
- return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
- }
-};
-
-class GraphicOutputBuffers : public FlexOutputBuffers {
-public:
- GraphicOutputBuffers(const char *componentName, const char *name = "2D-Output")
- : FlexOutputBuffers(componentName, name) { }
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- return new DummyContainerBuffer(mFormat, buffer);
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- return new DummyContainerBuffer(mFormat);
- }
-};
-
-class RawGraphicOutputBuffers : public FlexOutputBuffers {
-public:
- RawGraphicOutputBuffers(
- size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output")
- : FlexOutputBuffers(componentName, name),
- mLocalBufferPool(LocalBufferPool::Create(
- kMaxLinearBufferSize * numOutputSlots)) { }
- ~RawGraphicOutputBuffers() override = default;
-
- sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override {
- if (buffer == nullptr) {
- sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
- mFormat,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- if (c2buffer == nullptr) {
- ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
- return nullptr;
- }
- c2buffer->setRange(0, 0);
- return c2buffer;
- } else {
- return ConstGraphicBlockBuffer::Allocate(
- mFormat,
- buffer,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- }
- }
-
- sp<Codec2Buffer> allocateArrayBuffer() override {
- return ConstGraphicBlockBuffer::AllocateEmpty(
- mFormat,
- [lbp = mLocalBufferPool](size_t capacity) {
- return lbp->newBuffer(capacity);
- });
- }
-
-private:
- std::shared_ptr<LocalBufferPool> mLocalBufferPool;
-};
+// This is for keeping IGBP's buffer dropping logic in legacy mode other
+// than making it non-blocking. Do not change this value.
+const static size_t kDequeueTimeoutNs = 0;
} // namespace
@@ -2844,6 +1460,7 @@
sp<IGraphicBufferProducer> producer;
if (newSurface) {
newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ newSurface->setDequeueTimeout(kDequeueTimeoutNs);
producer = newSurface->getIGraphicBufferProducer();
producer->setGenerationNumber(generation);
} else {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 1ea29b4..bc997e6 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -27,12 +27,11 @@
#include <Codec2Mapper.h>
#include <codec2/hidl/client.h>
-#include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <media/stagefright/codec2/1.0/InputSurface.h>
#include <media/stagefright/foundation/Mutexed.h>
#include <media/stagefright/CodecBase.h>
#include <media/ICrypto.h>
+#include "CCodecBuffers.h"
#include "InputSurfaceWrapper.h"
#include "PipelineWatcher.h"
@@ -151,11 +150,6 @@
void setMetaMode(MetaMode mode);
- // Internal classes
- class Buffers;
- class InputBuffers;
- class OutputBuffers;
-
private:
class QueueGuard;
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
new file mode 100644
index 0000000..fb0efce
--- /dev/null
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -0,0 +1,963 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CCodecBuffers"
+#include <utils/Log.h>
+
+#include <C2PlatformSupport.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaCodecConstants.h>
+
+#include "CCodecBuffers.h"
+
+namespace android {
+
+namespace {
+
+sp<GraphicBlockBuffer> AllocateGraphicBuffer(
+ const std::shared_ptr<C2BlockPool> &pool,
+ const sp<AMessage> &format,
+ uint32_t pixelFormat,
+ const C2MemoryUsage &usage,
+ const std::shared_ptr<LocalBufferPool> &localBufferPool) {
+ int32_t width, height;
+ if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
+ ALOGD("format lacks width or height");
+ return nullptr;
+ }
+
+ std::shared_ptr<C2GraphicBlock> block;
+ c2_status_t err = pool->fetchGraphicBlock(
+ width, height, pixelFormat, usage, &block);
+ if (err != C2_OK) {
+ ALOGD("fetch graphic block failed: %d", err);
+ return nullptr;
+ }
+
+ return GraphicBlockBuffer::Allocate(
+ format,
+ block,
+ [localBufferPool](size_t capacity) {
+ return localBufferPool->newBuffer(capacity);
+ });
+}
+
+} // namespace
+
+// CCodecBuffers
+
+void CCodecBuffers::setFormat(const sp<AMessage> &format) {
+ CHECK(format != nullptr);
+ mFormat = format;
+}
+
+sp<AMessage> CCodecBuffers::dupFormat() {
+ return mFormat != nullptr ? mFormat->dup() : nullptr;
+}
+
+void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
+ sp<ABuffer> imageDataCandidate = buffer->getImageData();
+ if (imageDataCandidate == nullptr) {
+ return;
+ }
+ sp<ABuffer> imageData;
+ if (!mFormat->findBuffer("image-data", &imageData)
+ || imageDataCandidate->size() != imageData->size()
+ || memcmp(imageDataCandidate->data(), imageData->data(), imageData->size()) != 0) {
+ ALOGD("[%s] updating image-data", mName);
+ sp<AMessage> newFormat = dupFormat();
+ newFormat->setBuffer("image-data", imageDataCandidate);
+ MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
+ if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
+ int32_t stride = img->mPlane[0].mRowInc;
+ newFormat->setInt32(KEY_STRIDE, stride);
+ ALOGD("[%s] updating stride = %d", mName, stride);
+ if (img->mNumPlanes > 1 && stride > 0) {
+ int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
+ newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
+ ALOGD("[%s] updating vstride = %d", mName, vstride);
+ }
+ }
+ setFormat(newFormat);
+ buffer->setFormat(newFormat);
+ }
+}
+
+// OutputBuffers
+
+void OutputBuffers::initSkipCutBuffer(
+ int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
+ CHECK(mSkipCutBuffer == nullptr);
+ mDelay = delay;
+ mPadding = padding;
+ mSampleRate = sampleRate;
+ setSkipCutBuffer(delay, padding, channelCount);
+}
+
+void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
+ if (mSkipCutBuffer == nullptr) {
+ return;
+ }
+ int32_t delay = mDelay;
+ int32_t padding = mPadding;
+ if (sampleRate != mSampleRate) {
+ delay = ((int64_t)delay * sampleRate) / mSampleRate;
+ padding = ((int64_t)padding * sampleRate) / mSampleRate;
+ }
+ setSkipCutBuffer(delay, padding, channelCount);
+}
+
+void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
+ if (mSkipCutBuffer != nullptr) {
+ mSkipCutBuffer->submit(buffer);
+ }
+}
+
+void OutputBuffers::transferSkipCutBuffer(const sp<SkipCutBuffer> &scb) {
+ mSkipCutBuffer = scb;
+}
+
+void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount) {
+ if (mSkipCutBuffer != nullptr) {
+ size_t prevSize = mSkipCutBuffer->size();
+ if (prevSize != 0u) {
+ ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
+ }
+ }
+ mSkipCutBuffer = new SkipCutBuffer(skip, cut, channelCount);
+}
+
+// LocalBufferPool
+
+std::shared_ptr<LocalBufferPool> LocalBufferPool::Create(size_t poolCapacity) {
+ return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(poolCapacity));
+}
+
+sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
+ Mutex::Autolock lock(mMutex);
+ auto it = std::find_if(
+ mPool.begin(), mPool.end(),
+ [capacity](const std::vector<uint8_t> &vec) {
+ return vec.capacity() >= capacity;
+ });
+ if (it != mPool.end()) {
+ sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
+ mPool.erase(it);
+ return buffer;
+ }
+ if (mUsedSize + capacity > mPoolCapacity) {
+ while (!mPool.empty()) {
+ mUsedSize -= mPool.back().capacity();
+ mPool.pop_back();
+ }
+ if (mUsedSize + capacity > mPoolCapacity) {
+ ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
+ mUsedSize, capacity, mPoolCapacity);
+ return nullptr;
+ }
+ }
+ std::vector<uint8_t> vec(capacity);
+ mUsedSize += vec.capacity();
+ return new VectorBuffer(std::move(vec), shared_from_this());
+}
+
+LocalBufferPool::VectorBuffer::VectorBuffer(
+ std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
+ : ABuffer(vec.data(), vec.capacity()),
+ mVec(std::move(vec)),
+ mPool(pool) {
+}
+
+LocalBufferPool::VectorBuffer::~VectorBuffer() {
+ std::shared_ptr<LocalBufferPool> pool = mPool.lock();
+ if (pool) {
+ // If pool is alive, return the vector back to the pool so that
+ // it can be recycled.
+ pool->returnVector(std::move(mVec));
+ }
+}
+
+void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
+ Mutex::Autolock lock(mMutex);
+ mPool.push_front(std::move(vec));
+}
+
+size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
+ for (size_t i = 0; i < mBuffers.size(); ++i) {
+ if (mBuffers[i].clientBuffer == nullptr
+ && mBuffers[i].compBuffer.expired()) {
+ mBuffers[i].clientBuffer = buffer;
+ return i;
+ }
+ }
+ mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
+ return mBuffers.size() - 1;
+}
+
+// FlexBuffersImpl
+
+bool FlexBuffersImpl::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;
+ if (release) {
+ mBuffers[i].clientBuffer.clear();
+ }
+ index = i;
+ break;
+ }
+ }
+ if (clientBuffer == nullptr) {
+ ALOGV("[%s] %s: No matching buffer found", mName, __func__);
+ return false;
+ }
+ std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+ if (!result) {
+ result = clientBuffer->asC2Buffer();
+ mBuffers[index].compBuffer = result;
+ }
+ if (c2buffer) {
+ *c2buffer = result;
+ }
+ return true;
+}
+
+bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
+ for (size_t i = 0; i < mBuffers.size(); ++i) {
+ std::shared_ptr<C2Buffer> compBuffer =
+ mBuffers[i].compBuffer.lock();
+ if (!compBuffer || compBuffer != c2buffer) {
+ continue;
+ }
+ mBuffers[i].compBuffer.reset();
+ ALOGV("[%s] codec released buffer #%zu", mName, i);
+ return true;
+ }
+ ALOGV("[%s] codec released an unknown buffer", mName);
+ return false;
+}
+
+void FlexBuffersImpl::flush() {
+ ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
+ mBuffers.clear();
+}
+
+size_t FlexBuffersImpl::numClientBuffers() const {
+ return std::count_if(
+ mBuffers.begin(), mBuffers.end(),
+ [](const Entry &entry) {
+ return (entry.clientBuffer != nullptr);
+ });
+}
+
+// BuffersArrayImpl
+
+void BuffersArrayImpl::initialize(
+ const FlexBuffersImpl &impl,
+ size_t minSize,
+ std::function<sp<Codec2Buffer>()> allocate) {
+ mImplName = impl.mImplName + "[N]";
+ mName = mImplName.c_str();
+ for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
+ sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
+ bool ownedByClient = (clientBuffer != nullptr);
+ if (!ownedByClient) {
+ clientBuffer = allocate();
+ }
+ mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
+ }
+ ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
+ for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
+ mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
+ }
+}
+
+status_t BuffersArrayImpl::grabBuffer(
+ size_t *index,
+ sp<Codec2Buffer> *buffer,
+ std::function<bool(const sp<Codec2Buffer> &)> match) {
+ // allBuffersDontMatch remains true if all buffers are available but
+ // match() returns false for every buffer.
+ bool allBuffersDontMatch = true;
+ for (size_t i = 0; i < mBuffers.size(); ++i) {
+ if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
+ if (match(mBuffers[i].clientBuffer)) {
+ mBuffers[i].ownedByClient = true;
+ *buffer = mBuffers[i].clientBuffer;
+ (*buffer)->meta()->clear();
+ (*buffer)->setRange(0, (*buffer)->capacity());
+ *index = i;
+ return OK;
+ }
+ } else {
+ allBuffersDontMatch = false;
+ }
+ }
+ return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
+}
+
+bool BuffersArrayImpl::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) {
+ if (mBuffers[i].clientBuffer == buffer) {
+ if (!mBuffers[i].ownedByClient) {
+ ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
+ mName, i);
+ }
+ clientBuffer = mBuffers[i].clientBuffer;
+ if (release) {
+ mBuffers[i].ownedByClient = false;
+ }
+ index = i;
+ break;
+ }
+ }
+ if (clientBuffer == nullptr) {
+ ALOGV("[%s] %s: No matching buffer found", mName, __func__);
+ return false;
+ }
+ ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
+ std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+ if (!result) {
+ result = clientBuffer->asC2Buffer();
+ mBuffers[index].compBuffer = result;
+ }
+ if (c2buffer) {
+ *c2buffer = result;
+ }
+ return true;
+}
+
+bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
+ for (size_t i = 0; i < mBuffers.size(); ++i) {
+ std::shared_ptr<C2Buffer> compBuffer =
+ mBuffers[i].compBuffer.lock();
+ if (!compBuffer) {
+ continue;
+ }
+ if (c2buffer == compBuffer) {
+ if (mBuffers[i].ownedByClient) {
+ // This should not happen.
+ ALOGD("[%s] codec released a buffer owned by client "
+ "(index %zu)", mName, i);
+ }
+ mBuffers[i].compBuffer.reset();
+ ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
+ return true;
+ }
+ }
+ ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
+ return false;
+}
+
+void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+ array->clear();
+ for (const Entry &entry : mBuffers) {
+ array->push(entry.clientBuffer);
+ }
+}
+
+void BuffersArrayImpl::flush() {
+ for (Entry &entry : mBuffers) {
+ entry.ownedByClient = false;
+ }
+}
+
+void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
+ size_t size = mBuffers.size();
+ mBuffers.clear();
+ for (size_t i = 0; i < size; ++i) {
+ mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
+ }
+}
+
+size_t BuffersArrayImpl::numClientBuffers() const {
+ return std::count_if(
+ mBuffers.begin(), mBuffers.end(),
+ [](const Entry &entry) {
+ return entry.ownedByClient;
+ });
+}
+
+// InputBuffersArray
+
+void InputBuffersArray::initialize(
+ const FlexBuffersImpl &impl,
+ size_t minSize,
+ std::function<sp<Codec2Buffer>()> allocate) {
+ mImpl.initialize(impl, minSize, allocate);
+}
+
+void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+ mImpl.getArray(array);
+}
+
+bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+ sp<Codec2Buffer> c2Buffer;
+ status_t err = mImpl.grabBuffer(index, &c2Buffer);
+ if (err == OK) {
+ c2Buffer->setFormat(mFormat);
+ handleImageData(c2Buffer);
+ *buffer = c2Buffer;
+ return true;
+ }
+ return false;
+}
+
+bool InputBuffersArray::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
+ return mImpl.returnBuffer(buffer, c2buffer, release);
+}
+
+bool InputBuffersArray::expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) {
+ return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void InputBuffersArray::flush() {
+ mImpl.flush();
+}
+
+size_t InputBuffersArray::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+// LinearInputBuffers
+
+bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+ int32_t capacity = kLinearBufferSize;
+ (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
+ if ((size_t)capacity > kMaxLinearBufferSize) {
+ ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
+ capacity = kMaxLinearBufferSize;
+ }
+ // TODO: proper max input size
+ // TODO: read usage from intf
+ sp<Codec2Buffer> newBuffer = alloc((size_t)capacity);
+ if (newBuffer == nullptr) {
+ return false;
+ }
+ *index = mImpl.assignSlot(newBuffer);
+ *buffer = newBuffer;
+ return true;
+}
+
+bool LinearInputBuffers::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool LinearInputBuffers::expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) {
+ return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void LinearInputBuffers::flush() {
+ // This is no-op by default unless we're in array mode where we need to keep
+ // track of the flushed work.
+ mImpl.flush();
+}
+
+std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(
+ size_t size) {
+ int32_t capacity = kLinearBufferSize;
+ (void)mFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
+ if ((size_t)capacity > kMaxLinearBufferSize) {
+ ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
+ capacity = kMaxLinearBufferSize;
+ }
+ // TODO: proper max input size
+ // TODO: read usage from intf
+ std::unique_ptr<InputBuffersArray> array(
+ new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
+ array->setPool(mPool);
+ array->setFormat(mFormat);
+ array->initialize(
+ mImpl,
+ size,
+ [this, capacity] () -> sp<Codec2Buffer> { return alloc(capacity); });
+ return std::move(array);
+}
+
+size_t LinearInputBuffers::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+sp<Codec2Buffer> LinearInputBuffers::alloc(size_t size) {
+ C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ std::shared_ptr<C2LinearBlock> block;
+
+ c2_status_t err = mPool->fetchLinearBlock(size, usage, &block);
+ if (err != C2_OK) {
+ return nullptr;
+ }
+
+ return LinearBlockBuffer::Allocate(mFormat, block);
+}
+
+// EncryptedLinearInputBuffers
+
+EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
+ bool secure,
+ const sp<MemoryDealer> &dealer,
+ const sp<ICrypto> &crypto,
+ int32_t heapSeqNum,
+ size_t capacity,
+ size_t numInputSlots,
+ const char *componentName, const char *name)
+ : LinearInputBuffers(componentName, name),
+ mUsage({0, 0}),
+ mDealer(dealer),
+ mCrypto(crypto),
+ mHeapSeqNum(heapSeqNum) {
+ if (secure) {
+ mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
+ } else {
+ mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ }
+ for (size_t i = 0; i < numInputSlots; ++i) {
+ sp<IMemory> memory = mDealer->allocate(capacity);
+ if (memory == nullptr) {
+ ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
+ mName, i);
+ break;
+ }
+ mMemoryVector.push_back({std::weak_ptr<C2LinearBlock>(), memory});
+ }
+}
+
+sp<Codec2Buffer> EncryptedLinearInputBuffers::alloc(size_t size) {
+ sp<IMemory> memory;
+ size_t slot = 0;
+ for (; slot < mMemoryVector.size(); ++slot) {
+ if (mMemoryVector[slot].block.expired()) {
+ memory = mMemoryVector[slot].memory;
+ break;
+ }
+ }
+ if (memory == nullptr) {
+ return nullptr;
+ }
+
+ std::shared_ptr<C2LinearBlock> block;
+ c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
+ if (err != C2_OK || block == nullptr) {
+ return nullptr;
+ }
+
+ mMemoryVector[slot].block = block;
+ return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
+}
+
+// GraphicMetadataInputBuffers
+
+GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
+ const char *componentName, const char *name)
+ : InputBuffers(componentName, name),
+ mImpl(mName),
+ mStore(GetCodec2PlatformAllocatorStore()) { }
+
+bool GraphicMetadataInputBuffers::requestNewBuffer(
+ size_t *index, sp<MediaCodecBuffer> *buffer) {
+ std::shared_ptr<C2Allocator> alloc;
+ c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
+ if (err != C2_OK) {
+ return false;
+ }
+ sp<GraphicMetadataBuffer> newBuffer = new GraphicMetadataBuffer(mFormat, alloc);
+ if (newBuffer == nullptr) {
+ return false;
+ }
+ *index = mImpl.assignSlot(newBuffer);
+ *buffer = newBuffer;
+ return true;
+}
+
+bool GraphicMetadataInputBuffers::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool GraphicMetadataInputBuffers::expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) {
+ return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void GraphicMetadataInputBuffers::flush() {
+ // This is no-op by default unless we're in array mode where we need to keep
+ // track of the flushed work.
+}
+
+std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
+ size_t size) {
+ std::shared_ptr<C2Allocator> alloc;
+ c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
+ if (err != C2_OK) {
+ return nullptr;
+ }
+ std::unique_ptr<InputBuffersArray> array(
+ new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
+ array->setPool(mPool);
+ array->setFormat(mFormat);
+ array->initialize(
+ mImpl,
+ size,
+ [format = mFormat, alloc]() -> sp<Codec2Buffer> {
+ return new GraphicMetadataBuffer(format, alloc);
+ });
+ return std::move(array);
+}
+
+size_t GraphicMetadataInputBuffers::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+// GraphicInputBuffers
+
+GraphicInputBuffers::GraphicInputBuffers(
+ size_t numInputSlots, const char *componentName, const char *name)
+ : InputBuffers(componentName, name),
+ mImpl(mName),
+ mLocalBufferPool(LocalBufferPool::Create(
+ kMaxLinearBufferSize * numInputSlots)) { }
+
+bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
+ // TODO: proper max input size
+ // TODO: read usage from intf
+ C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ sp<GraphicBlockBuffer> newBuffer = AllocateGraphicBuffer(
+ mPool, mFormat, HAL_PIXEL_FORMAT_YV12, usage, mLocalBufferPool);
+ if (newBuffer == nullptr) {
+ return false;
+ }
+ *index = mImpl.assignSlot(newBuffer);
+ handleImageData(newBuffer);
+ *buffer = newBuffer;
+ return true;
+}
+
+bool GraphicInputBuffers::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
+}
+
+bool GraphicInputBuffers::expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) {
+ return mImpl.expireComponentBuffer(c2buffer);
+}
+
+void GraphicInputBuffers::flush() {
+ // This is no-op by default unless we're in array mode where we need to keep
+ // track of the flushed work.
+}
+
+std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
+ std::unique_ptr<InputBuffersArray> array(
+ new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
+ array->setPool(mPool);
+ array->setFormat(mFormat);
+ array->initialize(
+ mImpl,
+ size,
+ [pool = mPool, format = mFormat, lbp = mLocalBufferPool]() -> sp<Codec2Buffer> {
+ C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ return AllocateGraphicBuffer(
+ pool, format, HAL_PIXEL_FORMAT_YV12, usage, lbp);
+ });
+ return std::move(array);
+}
+
+size_t GraphicInputBuffers::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+// OutputBuffersArray
+
+void OutputBuffersArray::initialize(
+ const FlexBuffersImpl &impl,
+ size_t minSize,
+ std::function<sp<Codec2Buffer>()> allocate) {
+ mImpl.initialize(impl, minSize, allocate);
+}
+
+status_t OutputBuffersArray::registerBuffer(
+ const std::shared_ptr<C2Buffer> &buffer,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) {
+ sp<Codec2Buffer> c2Buffer;
+ status_t err = mImpl.grabBuffer(
+ index,
+ &c2Buffer,
+ [buffer](const sp<Codec2Buffer> &clientBuffer) {
+ return clientBuffer->canCopy(buffer);
+ });
+ if (err == WOULD_BLOCK) {
+ ALOGV("[%s] buffers temporarily not available", mName);
+ return err;
+ } else if (err != OK) {
+ ALOGD("[%s] grabBuffer failed: %d", mName, err);
+ return err;
+ }
+ c2Buffer->setFormat(mFormat);
+ if (!c2Buffer->copy(buffer)) {
+ ALOGD("[%s] copy buffer failed", mName);
+ return WOULD_BLOCK;
+ }
+ submit(c2Buffer);
+ handleImageData(c2Buffer);
+ *clientBuffer = c2Buffer;
+ ALOGV("[%s] grabbed buffer %zu", mName, *index);
+ return OK;
+}
+
+status_t OutputBuffersArray::registerCsd(
+ const C2StreamInitDataInfo::output *csd,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) {
+ sp<Codec2Buffer> c2Buffer;
+ status_t err = mImpl.grabBuffer(
+ index,
+ &c2Buffer,
+ [csd](const sp<Codec2Buffer> &clientBuffer) {
+ return clientBuffer->base() != nullptr
+ && clientBuffer->capacity() >= csd->flexCount();
+ });
+ if (err != OK) {
+ return err;
+ }
+ memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
+ c2Buffer->setRange(0, csd->flexCount());
+ c2Buffer->setFormat(mFormat);
+ *clientBuffer = c2Buffer;
+ return OK;
+}
+
+bool OutputBuffersArray::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+ return mImpl.returnBuffer(buffer, c2buffer, true);
+}
+
+void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
+ (void)flushedWork;
+ mImpl.flush();
+ if (mSkipCutBuffer != nullptr) {
+ mSkipCutBuffer->clear();
+ }
+}
+
+void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
+ mImpl.getArray(array);
+}
+
+void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
+ std::function<sp<Codec2Buffer>()> alloc;
+ switch (c2buffer->data().type()) {
+ case C2BufferData::LINEAR: {
+ uint32_t size = kLinearBufferSize;
+ const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
+ if (block.size() < kMaxLinearBufferSize / 2) {
+ size = block.size() * 2;
+ } else {
+ size = kMaxLinearBufferSize;
+ }
+ alloc = [format = mFormat, size] {
+ return new LocalLinearBuffer(format, new ABuffer(size));
+ };
+ break;
+ }
+
+ // TODO: add support
+ case C2BufferData::GRAPHIC: [[fallthrough]];
+
+ case C2BufferData::INVALID: [[fallthrough]];
+ case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
+ case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
+ default:
+ ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
+ return;
+ }
+ mImpl.realloc(alloc);
+}
+
+size_t OutputBuffersArray::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+// FlexOutputBuffers
+
+status_t FlexOutputBuffers::registerBuffer(
+ const std::shared_ptr<C2Buffer> &buffer,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) {
+ sp<Codec2Buffer> newBuffer = wrap(buffer);
+ if (newBuffer == nullptr) {
+ return NO_MEMORY;
+ }
+ newBuffer->setFormat(mFormat);
+ *index = mImpl.assignSlot(newBuffer);
+ handleImageData(newBuffer);
+ *clientBuffer = newBuffer;
+ ALOGV("[%s] registered buffer %zu", mName, *index);
+ return OK;
+}
+
+status_t FlexOutputBuffers::registerCsd(
+ const C2StreamInitDataInfo::output *csd,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) {
+ sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
+ mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
+ *index = mImpl.assignSlot(newBuffer);
+ *clientBuffer = newBuffer;
+ return OK;
+}
+
+bool FlexOutputBuffers::releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer) {
+ return mImpl.releaseSlot(buffer, c2buffer, true);
+}
+
+void FlexOutputBuffers::flush(
+ const std::list<std::unique_ptr<C2Work>> &flushedWork) {
+ (void) flushedWork;
+ // This is no-op by default unless we're in array mode where we need to keep
+ // track of the flushed work.
+}
+
+std::unique_ptr<OutputBuffers> FlexOutputBuffers::toArrayMode(size_t size) {
+ std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
+ array->setFormat(mFormat);
+ array->transferSkipCutBuffer(mSkipCutBuffer);
+ array->initialize(
+ mImpl,
+ size,
+ [this]() { return allocateArrayBuffer(); });
+ return std::move(array);
+}
+
+size_t FlexOutputBuffers::numClientBuffers() const {
+ return mImpl.numClientBuffers();
+}
+
+// LinearOutputBuffers
+
+void LinearOutputBuffers::flush(
+ const std::list<std::unique_ptr<C2Work>> &flushedWork) {
+ if (mSkipCutBuffer != nullptr) {
+ mSkipCutBuffer->clear();
+ }
+ FlexOutputBuffers::flush(flushedWork);
+}
+
+sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
+ if (buffer == nullptr) {
+ ALOGV("[%s] using a dummy buffer", mName);
+ return new LocalLinearBuffer(mFormat, new ABuffer(0));
+ }
+ if (buffer->data().type() != C2BufferData::LINEAR) {
+ ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
+ // We expect linear output buffers from the component.
+ return nullptr;
+ }
+ if (buffer->data().linearBlocks().size() != 1u) {
+ ALOGV("[%s] no linear buffers", mName);
+ // We expect one and only one linear block from the component.
+ return nullptr;
+ }
+ sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
+ if (clientBuffer == nullptr) {
+ ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
+ return nullptr;
+ }
+ submit(clientBuffer);
+ return clientBuffer;
+}
+
+sp<Codec2Buffer> LinearOutputBuffers::allocateArrayBuffer() {
+ // TODO: proper max output size
+ return new LocalLinearBuffer(mFormat, new ABuffer(kLinearBufferSize));
+}
+
+// GraphicOutputBuffers
+
+sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
+ return new DummyContainerBuffer(mFormat, buffer);
+}
+
+sp<Codec2Buffer> GraphicOutputBuffers::allocateArrayBuffer() {
+ return new DummyContainerBuffer(mFormat);
+}
+
+// RawGraphicOutputBuffers
+
+RawGraphicOutputBuffers::RawGraphicOutputBuffers(
+ size_t numOutputSlots, const char *componentName, const char *name)
+ : FlexOutputBuffers(componentName, name),
+ mLocalBufferPool(LocalBufferPool::Create(
+ kMaxLinearBufferSize * numOutputSlots)) { }
+
+sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
+ if (buffer == nullptr) {
+ sp<Codec2Buffer> c2buffer = ConstGraphicBlockBuffer::AllocateEmpty(
+ mFormat,
+ [lbp = mLocalBufferPool](size_t capacity) {
+ return lbp->newBuffer(capacity);
+ });
+ if (c2buffer == nullptr) {
+ ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
+ return nullptr;
+ }
+ c2buffer->setRange(0, 0);
+ return c2buffer;
+ } else {
+ return ConstGraphicBlockBuffer::Allocate(
+ mFormat,
+ buffer,
+ [lbp = mLocalBufferPool](size_t capacity) {
+ return lbp->newBuffer(capacity);
+ });
+ }
+}
+
+sp<Codec2Buffer> RawGraphicOutputBuffers::allocateArrayBuffer() {
+ return ConstGraphicBlockBuffer::AllocateEmpty(
+ mFormat,
+ [lbp = mLocalBufferPool](size_t capacity) {
+ return lbp->newBuffer(capacity);
+ });
+}
+
+} // namespace android
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
new file mode 100644
index 0000000..f5d9fee
--- /dev/null
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -0,0 +1,808 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CCODEC_BUFFERS_H_
+
+#define CCODEC_BUFFERS_H_
+
+#include <string>
+
+#include <C2Config.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/MediaCodecBuffer.h>
+
+#include "Codec2Buffer.h"
+#include "SkipCutBuffer.h"
+
+namespace android {
+
+constexpr size_t kLinearBufferSize = 1048576;
+// This can fit 4K RGBA frame, and most likely client won't need more than this.
+constexpr size_t kMaxLinearBufferSize = 3840 * 2160 * 4;
+
+/**
+ * Base class for representation of buffers at one port.
+ */
+class CCodecBuffers {
+public:
+ CCodecBuffers(const char *componentName, const char *name = "Buffers")
+ : mComponentName(componentName),
+ mChannelName(std::string(componentName) + ":" + name),
+ mName(mChannelName.c_str()) {
+ }
+ virtual ~CCodecBuffers() = default;
+
+ /**
+ * Set format for MediaCodec-facing buffers.
+ */
+ void setFormat(const sp<AMessage> &format);
+
+ /**
+ * Return a copy of current format.
+ */
+ sp<AMessage> dupFormat();
+
+ /**
+ * Returns true if the buffers are operating under array mode.
+ */
+ virtual bool isArrayMode() const { return false; }
+
+ /**
+ * Fills the vector with MediaCodecBuffer's if in array mode; otherwise,
+ * no-op.
+ */
+ virtual void getArray(Vector<sp<MediaCodecBuffer>> *) const {}
+
+ /**
+ * Return number of buffers the client owns.
+ */
+ virtual size_t numClientBuffers() const = 0;
+
+ /**
+ * Examine image data from the buffer and update the format if necessary.
+ */
+ void handleImageData(const sp<Codec2Buffer> &buffer);
+
+protected:
+ std::string mComponentName; ///< name of component for debugging
+ std::string mChannelName; ///< name of channel for debugging
+ const char *mName; ///< C-string version of channel name
+ // Format to be used for creating MediaCodec-facing buffers.
+ sp<AMessage> mFormat;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(CCodecBuffers);
+};
+
+class InputBuffers : public CCodecBuffers {
+public:
+ InputBuffers(const char *componentName, const char *name = "Input[]")
+ : CCodecBuffers(componentName, name) { }
+ virtual ~InputBuffers() = default;
+
+ /**
+ * Set a block pool to obtain input memory blocks.
+ */
+ void setPool(const std::shared_ptr<C2BlockPool> &pool) { mPool = pool; }
+
+ /**
+ * Get a new MediaCodecBuffer for input and its corresponding index.
+ * Returns false if no new buffer can be obtained at the moment.
+ */
+ virtual bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) = 0;
+
+ /**
+ * Release the buffer obtained from requestNewBuffer() and get the
+ * associated C2Buffer object back. Returns true if the buffer was on file
+ * and released successfully.
+ */
+ virtual bool releaseBuffer(
+ 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
+ * true if and only if the buffer was on file and released successfully.
+ */
+ virtual bool expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) = 0;
+
+ /**
+ * Flush internal state. After this call, no index or buffer previously
+ * returned from requestNewBuffer() is valid.
+ */
+ virtual void flush() = 0;
+
+ /**
+ * Return array-backed version of input buffers. The returned object
+ * shall retain the internal state so that it will honor index and
+ * buffer from previous calls of requestNewBuffer().
+ */
+ virtual std::unique_ptr<InputBuffers> toArrayMode(size_t size) = 0;
+
+protected:
+ // Pool to obtain blocks for input buffers.
+ std::shared_ptr<C2BlockPool> mPool;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(InputBuffers);
+};
+
+class OutputBuffers : public CCodecBuffers {
+public:
+ OutputBuffers(const char *componentName, const char *name = "Output")
+ : CCodecBuffers(componentName, name) { }
+ virtual ~OutputBuffers() = default;
+
+ /**
+ * Register output C2Buffer from the component and obtain corresponding
+ * index and MediaCodecBuffer object. Returns false if registration
+ * fails.
+ */
+ virtual status_t registerBuffer(
+ const std::shared_ptr<C2Buffer> &buffer,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) = 0;
+
+ /**
+ * Register codec specific data as a buffer to be consistent with
+ * MediaCodec behavior.
+ */
+ virtual status_t registerCsd(
+ const C2StreamInitDataInfo::output * /* csd */,
+ size_t * /* index */,
+ sp<MediaCodecBuffer> * /* clientBuffer */) = 0;
+
+ /**
+ * Release the buffer obtained from registerBuffer() and get the
+ * associated C2Buffer object back. Returns true if the buffer was on file
+ * and released successfully.
+ */
+ virtual bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
+
+ /**
+ * Flush internal state. After this call, no index or buffer previously
+ * returned from registerBuffer() is valid.
+ */
+ virtual void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) = 0;
+
+ /**
+ * Return array-backed version of output buffers. The returned object
+ * shall retain the internal state so that it will honor index and
+ * buffer from previous calls of registerBuffer().
+ */
+ virtual std::unique_ptr<OutputBuffers> toArrayMode(size_t size) = 0;
+
+ /**
+ * Initialize SkipCutBuffer object.
+ */
+ void initSkipCutBuffer(
+ int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount);
+
+ /**
+ * Update the SkipCutBuffer object. No-op if it's never initialized.
+ */
+ void updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount);
+
+ /**
+ * Submit buffer to SkipCutBuffer object, if initialized.
+ */
+ void submit(const sp<MediaCodecBuffer> &buffer);
+
+ /**
+ * Transfer SkipCutBuffer object to the other Buffers object.
+ */
+ void transferSkipCutBuffer(const sp<SkipCutBuffer> &scb);
+
+protected:
+ sp<SkipCutBuffer> mSkipCutBuffer;
+
+private:
+ int32_t mDelay;
+ int32_t mPadding;
+ int32_t mSampleRate;
+
+ void setSkipCutBuffer(int32_t skip, int32_t cut, int32_t channelCount);
+
+ DISALLOW_EVIL_CONSTRUCTORS(OutputBuffers);
+};
+
+/**
+ * Simple local buffer pool backed by std::vector.
+ */
+class LocalBufferPool : public std::enable_shared_from_this<LocalBufferPool> {
+public:
+ /**
+ * Create a new LocalBufferPool object.
+ *
+ * \param poolCapacity max total size of buffers managed by this pool.
+ *
+ * \return a newly created pool object.
+ */
+ static std::shared_ptr<LocalBufferPool> Create(size_t poolCapacity);
+
+ /**
+ * Return an ABuffer object whose size is at least |capacity|.
+ *
+ * \param capacity requested capacity
+ * \return nullptr if the pool capacity is reached
+ * an ABuffer object otherwise.
+ */
+ sp<ABuffer> newBuffer(size_t capacity);
+
+private:
+ /**
+ * ABuffer backed by std::vector.
+ */
+ class VectorBuffer : public ::android::ABuffer {
+ public:
+ /**
+ * Construct a VectorBuffer by taking the ownership of supplied vector.
+ *
+ * \param vec backing vector of the buffer. this object takes
+ * ownership at construction.
+ * \param pool a LocalBufferPool object to return the vector at
+ * destruction.
+ */
+ VectorBuffer(std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool);
+
+ ~VectorBuffer() override;
+
+ private:
+ std::vector<uint8_t> mVec;
+ std::weak_ptr<LocalBufferPool> mPool;
+ };
+
+ Mutex mMutex;
+ size_t mPoolCapacity;
+ size_t mUsedSize;
+ std::list<std::vector<uint8_t>> mPool;
+
+ /**
+ * Private constructor to prevent constructing non-managed LocalBufferPool.
+ */
+ explicit LocalBufferPool(size_t poolCapacity)
+ : mPoolCapacity(poolCapacity), mUsedSize(0) {
+ }
+
+ /**
+ * Take back the ownership of vec from the destructed VectorBuffer and put
+ * it in front of the pool.
+ */
+ void returnVector(std::vector<uint8_t> &&vec);
+
+ DISALLOW_EVIL_CONSTRUCTORS(LocalBufferPool);
+};
+
+class BuffersArrayImpl;
+
+/**
+ * Flexible buffer slots implementation.
+ */
+class FlexBuffersImpl {
+public:
+ FlexBuffersImpl(const char *name)
+ : mImplName(std::string(name) + ".Impl"),
+ mName(mImplName.c_str()) { }
+
+ /**
+ * Assign an empty slot for a buffer and return the index. If there's no
+ * empty slot, just add one at the end and return it.
+ *
+ * \param buffer[in] a new buffer to assign a slot.
+ * \return index of the assigned slot.
+ */
+ size_t assignSlot(const sp<Codec2Buffer> &buffer);
+
+ /**
+ * Release the slot from the client, and get the C2Buffer object back from
+ * the previously assigned buffer. Note that the slot is not completely free
+ * until the returned C2Buffer object is freed.
+ *
+ * \param buffer[in] the buffer previously assigned a slot.
+ * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored
+ * if null.
+ * \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 release);
+
+ /**
+ * Expire the C2Buffer object in the slot.
+ *
+ * \param c2buffer[in] C2Buffer object which the component released.
+ * \return true if the buffer is found in one of the slots and
+ * successfully released
+ * false otherwise
+ */
+ bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer);
+
+ /**
+ * The client abandoned all known buffers, so reclaim the ownership.
+ */
+ void flush();
+
+ /**
+ * Return the number of buffers that are sent to the client but not released
+ * yet.
+ */
+ size_t numClientBuffers() const;
+
+private:
+ friend class BuffersArrayImpl;
+
+ std::string mImplName; ///< name for debugging
+ const char *mName; ///< C-string version of name
+
+ struct Entry {
+ sp<Codec2Buffer> clientBuffer;
+ std::weak_ptr<C2Buffer> compBuffer;
+ };
+ std::vector<Entry> mBuffers;
+};
+
+/**
+ * Static buffer slots implementation based on a fixed-size array.
+ */
+class BuffersArrayImpl {
+public:
+ BuffersArrayImpl()
+ : mImplName("BuffersArrayImpl"),
+ mName(mImplName.c_str()) { }
+
+ /**
+ * Initialize buffer array from the original |impl|. The buffers known by
+ * the client is preserved, and the empty slots are populated so that the
+ * array size is at least |minSize|.
+ *
+ * \param impl[in] FlexBuffersImpl object used so far.
+ * \param minSize[in] minimum size of the buffer array.
+ * \param allocate[in] function to allocate a client buffer for an empty slot.
+ */
+ void initialize(
+ const FlexBuffersImpl &impl,
+ size_t minSize,
+ std::function<sp<Codec2Buffer>()> allocate);
+
+ /**
+ * Grab a buffer from the underlying array which matches the criteria.
+ *
+ * \param index[out] index of the slot.
+ * \param buffer[out] the matching buffer.
+ * \param match[in] a function to test whether the buffer matches the
+ * criteria or not.
+ * \return OK if successful,
+ * WOULD_BLOCK if slots are being used,
+ * NO_MEMORY if no slot matches the criteria, even though it's
+ * available
+ */
+ status_t grabBuffer(
+ size_t *index,
+ sp<Codec2Buffer> *buffer,
+ std::function<bool(const sp<Codec2Buffer> &)> match =
+ [](const sp<Codec2Buffer> &) { return true; });
+
+ /**
+ * Return the buffer from the client, and get the C2Buffer object back from
+ * the buffer. Note that the slot is not completely free until the returned
+ * C2Buffer object is freed.
+ *
+ * \param buffer[in] the buffer previously grabbed.
+ * \param c2buffer[in,out] pointer to C2Buffer to be populated. Ignored
+ * if null.
+ * \return true if the buffer is successfully returned
+ * false otherwise
+ */
+ bool returnBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release);
+
+ /**
+ * Expire the C2Buffer object in the slot.
+ *
+ * \param c2buffer[in] C2Buffer object which the component released.
+ * \return true if the buffer is found in one of the slots and
+ * successfully released
+ * false otherwise
+ */
+ bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer);
+
+ /**
+ * Populate |array| with the underlying buffer array.
+ *
+ * \param array[out] an array to be filled with the underlying buffer array.
+ */
+ void getArray(Vector<sp<MediaCodecBuffer>> *array) const;
+
+ /**
+ * The client abandoned all known buffers, so reclaim the ownership.
+ */
+ void flush();
+
+ /**
+ * Reallocate the array with the given allocation function.
+ *
+ * \param alloc[in] the allocation function for client buffers.
+ */
+ void realloc(std::function<sp<Codec2Buffer>()> alloc);
+
+ /**
+ * Return the number of buffers that are sent to the client but not released
+ * yet.
+ */
+ size_t numClientBuffers() const;
+
+private:
+ std::string mImplName; ///< name for debugging
+ const char *mName; ///< C-string version of name
+
+ struct Entry {
+ const sp<Codec2Buffer> clientBuffer;
+ std::weak_ptr<C2Buffer> compBuffer;
+ bool ownedByClient;
+ };
+ std::vector<Entry> mBuffers;
+};
+
+class InputBuffersArray : public InputBuffers {
+public:
+ InputBuffersArray(const char *componentName, const char *name = "Input[N]")
+ : InputBuffers(componentName, name) { }
+ ~InputBuffersArray() override = default;
+
+ /**
+ * Initialize this object from the non-array state. We keep existing slots
+ * at the same index, and for empty slots we allocate client buffers with
+ * the given allocate function. If the number of slots is less than minSize,
+ * we fill the array to the minimum size.
+ *
+ * \param impl[in] existing non-array state
+ * \param minSize[in] minimum size of the array
+ * \param allocate[in] allocate function to fill empty slots
+ */
+ void initialize(
+ const FlexBuffersImpl &impl,
+ size_t minSize,
+ std::function<sp<Codec2Buffer>()> allocate);
+
+ bool isArrayMode() const final { return true; }
+
+ std::unique_ptr<InputBuffers> toArrayMode(size_t) final {
+ return nullptr;
+ }
+
+ void getArray(Vector<sp<MediaCodecBuffer>> *array) const final;
+
+ bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override;
+
+ bool expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+ void flush() override;
+
+ size_t numClientBuffers() const final;
+
+private:
+ BuffersArrayImpl mImpl;
+};
+
+class LinearInputBuffers : public InputBuffers {
+public:
+ LinearInputBuffers(const char *componentName, const char *name = "1D-Input")
+ : InputBuffers(componentName, name),
+ mImpl(mName) { }
+ ~LinearInputBuffers() override = default;
+
+ bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override;
+
+ bool expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+ void flush() override;
+
+ std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
+
+ size_t numClientBuffers() const final;
+
+ /**
+ * Allocate a client buffer with the given size. This method may be
+ * overridden to support different kind of linear buffers (e.g. encrypted).
+ */
+ virtual sp<Codec2Buffer> alloc(size_t size);
+
+private:
+ FlexBuffersImpl mImpl;
+};
+
+class EncryptedLinearInputBuffers : public LinearInputBuffers {
+public:
+ EncryptedLinearInputBuffers(
+ bool secure,
+ const sp<MemoryDealer> &dealer,
+ const sp<ICrypto> &crypto,
+ int32_t heapSeqNum,
+ size_t capacity,
+ size_t numInputSlots,
+ const char *componentName, const char *name = "EncryptedInput");
+
+ ~EncryptedLinearInputBuffers() override = default;
+
+ sp<Codec2Buffer> alloc(size_t size) override;
+
+private:
+ C2MemoryUsage mUsage;
+ sp<MemoryDealer> mDealer;
+ sp<ICrypto> mCrypto;
+ int32_t mHeapSeqNum;
+ struct Entry {
+ std::weak_ptr<C2LinearBlock> block;
+ sp<IMemory> memory;
+ };
+ std::vector<Entry> mMemoryVector;
+};
+
+class GraphicMetadataInputBuffers : public InputBuffers {
+public:
+ GraphicMetadataInputBuffers(const char *componentName, const char *name = "2D-MetaInput");
+ ~GraphicMetadataInputBuffers() override = default;
+
+ bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override;
+
+ bool expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+ void flush() override;
+
+ std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
+
+ size_t numClientBuffers() const final;
+
+private:
+ FlexBuffersImpl mImpl;
+ std::shared_ptr<C2AllocatorStore> mStore;
+};
+
+class GraphicInputBuffers : public InputBuffers {
+public:
+ GraphicInputBuffers(
+ size_t numInputSlots, const char *componentName, const char *name = "2D-BB-Input");
+ ~GraphicInputBuffers() override = default;
+
+ bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override;
+
+ bool expireComponentBuffer(
+ const std::shared_ptr<C2Buffer> &c2buffer) override;
+
+ void flush() override;
+
+ std::unique_ptr<InputBuffers> toArrayMode(
+ size_t size) final;
+
+ size_t numClientBuffers() const final;
+
+private:
+ FlexBuffersImpl mImpl;
+ std::shared_ptr<LocalBufferPool> mLocalBufferPool;
+};
+
+class DummyInputBuffers : public InputBuffers {
+public:
+ DummyInputBuffers(const char *componentName, const char *name = "2D-Input")
+ : InputBuffers(componentName, name) { }
+ ~DummyInputBuffers() override = default;
+
+ bool requestNewBuffer(size_t *, sp<MediaCodecBuffer> *) override {
+ return false;
+ }
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
+ return false;
+ }
+
+ bool expireComponentBuffer(const std::shared_ptr<C2Buffer> &) override {
+ return false;
+ }
+ void flush() override {
+ }
+
+ std::unique_ptr<InputBuffers> toArrayMode(size_t) final {
+ return nullptr;
+ }
+
+ bool isArrayMode() const final { return true; }
+
+ void getArray(Vector<sp<MediaCodecBuffer>> *array) const final {
+ array->clear();
+ }
+
+ size_t numClientBuffers() const final {
+ return 0u;
+ }
+};
+
+class OutputBuffersArray : public OutputBuffers {
+public:
+ OutputBuffersArray(const char *componentName, const char *name = "Output[N]")
+ : OutputBuffers(componentName, name) { }
+ ~OutputBuffersArray() override = default;
+
+ /**
+ * Initialize this object from the non-array state. We keep existing slots
+ * at the same index, and for empty slots we allocate client buffers with
+ * the given allocate function. If the number of slots is less than minSize,
+ * we fill the array to the minimum size.
+ *
+ * \param impl[in] existing non-array state
+ * \param minSize[in] minimum size of the array
+ * \param allocate[in] allocate function to fill empty slots
+ */
+ void initialize(
+ const FlexBuffersImpl &impl,
+ size_t minSize,
+ std::function<sp<Codec2Buffer>()> allocate);
+
+ bool isArrayMode() const final { return true; }
+
+ std::unique_ptr<OutputBuffers> toArrayMode(size_t) final {
+ return nullptr;
+ }
+
+ status_t registerBuffer(
+ const std::shared_ptr<C2Buffer> &buffer,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) final;
+
+ status_t registerCsd(
+ const C2StreamInitDataInfo::output *csd,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) final;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override;
+
+ void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
+
+ void getArray(Vector<sp<MediaCodecBuffer>> *array) const final;
+
+ /**
+ * Reallocate the array, filled with buffers with the same size as given
+ * buffer.
+ *
+ * \param c2buffer[in] the reference buffer
+ */
+ void realloc(const std::shared_ptr<C2Buffer> &c2buffer);
+
+ size_t numClientBuffers() const final;
+
+private:
+ BuffersArrayImpl mImpl;
+};
+
+class FlexOutputBuffers : public OutputBuffers {
+public:
+ FlexOutputBuffers(const char *componentName, const char *name = "Output[]")
+ : OutputBuffers(componentName, name),
+ mImpl(mName) { }
+
+ status_t registerBuffer(
+ const std::shared_ptr<C2Buffer> &buffer,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) override;
+
+ status_t registerCsd(
+ const C2StreamInitDataInfo::output *csd,
+ size_t *index,
+ sp<MediaCodecBuffer> *clientBuffer) final;
+
+ bool releaseBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer) override;
+
+ void flush(
+ const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
+
+ std::unique_ptr<OutputBuffers> toArrayMode(size_t size) override;
+
+ size_t numClientBuffers() const final;
+
+ /**
+ * Return an appropriate Codec2Buffer object for the type of buffers.
+ *
+ * \param buffer C2Buffer object to wrap.
+ *
+ * \return appropriate Codec2Buffer object to wrap |buffer|.
+ */
+ virtual sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) = 0;
+
+ /**
+ * Return an appropriate Codec2Buffer object for the type of buffers, to be
+ * used as an empty array buffer.
+ *
+ * \return appropriate Codec2Buffer object which can copy() from C2Buffers.
+ */
+ virtual sp<Codec2Buffer> allocateArrayBuffer() = 0;
+
+private:
+ FlexBuffersImpl mImpl;
+};
+
+class LinearOutputBuffers : public FlexOutputBuffers {
+public:
+ LinearOutputBuffers(const char *componentName, const char *name = "1D-Output")
+ : FlexOutputBuffers(componentName, name) { }
+
+ void flush(
+ const std::list<std::unique_ptr<C2Work>> &flushedWork) override;
+
+ sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
+
+ sp<Codec2Buffer> allocateArrayBuffer() override;
+};
+
+class GraphicOutputBuffers : public FlexOutputBuffers {
+public:
+ GraphicOutputBuffers(const char *componentName, const char *name = "2D-Output")
+ : FlexOutputBuffers(componentName, name) { }
+
+ sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
+
+ sp<Codec2Buffer> allocateArrayBuffer() override;
+};
+
+class RawGraphicOutputBuffers : public FlexOutputBuffers {
+public:
+ RawGraphicOutputBuffers(
+ size_t numOutputSlots, const char *componentName, const char *name = "2D-BB-Output");
+ ~RawGraphicOutputBuffers() override = default;
+
+ sp<Codec2Buffer> wrap(const std::shared_ptr<C2Buffer> &buffer) override;
+
+ sp<Codec2Buffer> allocateArrayBuffer() override;
+
+private:
+ std::shared_ptr<LocalBufferPool> mLocalBufferPool;
+};
+
+} // namespace android
+
+#endif // CCODEC_BUFFERS_H_
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index c6ca670..198bd72 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -26,6 +26,7 @@
"C2PlatformStorePluginLoader.cpp",
"C2Store.cpp",
"platform/C2BqBuffer.cpp",
+ "types.cpp",
"util/C2Debug.cpp",
"util/C2InterfaceHelper.cpp",
"util/C2InterfaceUtils.cpp",
@@ -38,7 +39,6 @@
export_shared_lib_headers: [
"libbase",
- "libgui",
"android.hardware.media.bufferpool@2.0",
],
@@ -60,13 +60,12 @@
"libbinder",
"libcutils",
"libdl",
- "libgui",
"libhardware",
"libhidlbase",
"libion",
"libfmq",
"liblog",
- "libstagefright_bufferqueue_helper",
+ "libnativewindow",
"libstagefright_foundation",
"libstagefright_bufferpool@2.0",
"libui",
diff --git a/media/codec2/vndk/include/types.h b/media/codec2/vndk/include/types.h
new file mode 100644
index 0000000..b41d3f8
--- /dev/null
+++ b/media/codec2/vndk/include/types.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CODEC2_VNDK_TYPES_H
+#define CODEC2_VNDK_TYPES_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <hidl/HidlSupport.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::
+ Status;
+
+// A status_t value may have flags encoded. These flags are decoded into boolean
+// values if their corresponding output pointers are not null.
+bool b2h(status_t from, HStatus* to,
+ bool* bufferNeedsReallocation = nullptr,
+ bool* releaseAllBuffers = nullptr);
+// Simple 1-to-1 mapping. If BUFFER_NEEDS_REALLOCATION or RELEASE_ALL_BUFFERS
+// needs to be added, it must be done manually afterwards.
+bool h2b(HStatus from, status_t* to);
+
+// Fence
+// =====
+
+using BFence = ::android::Fence;
+// This class manages the lifetime of a copied handle. Its destructor calls
+// native_handle_delete() but not native_handle_close().
+struct HFenceWrapper {
+ HFenceWrapper() = default;
+ // Sets mHandle to a new value.
+ HFenceWrapper(native_handle_t* h);
+ // Deletes mHandle without closing.
+ ~HFenceWrapper();
+ // Deletes mHandle without closing, then sets mHandle to a new value.
+ HFenceWrapper& set(native_handle_t* h);
+ HFenceWrapper& operator=(native_handle_t* h);
+ // Returns a non-owning hidl_handle pointing to mHandle.
+ hidl_handle getHandle() const;
+ operator hidl_handle() const;
+protected:
+ native_handle_t* mHandle{nullptr};
+};
+
+// Does not clone the fd---only copy the fd. The returned HFenceWrapper should
+// not outlive the input Fence object.
+bool b2h(sp<BFence> const& from, HFenceWrapper* to);
+// Clones the fd and puts it in a new Fence object.
+bool h2b(native_handle_t const* from, sp<BFence>* to);
+
+// ConnectionType
+// ==============
+
+using HConnectionType = ::android::hardware::graphics::bufferqueue::V2_0::
+ ConnectionType;
+
+bool b2h(int from, HConnectionType* to);
+bool h2b(HConnectionType from, int* to);
+
+// Rect
+// ====
+
+using BRect = ::android::Rect;
+using HRect = ::android::hardware::graphics::common::V1_2::Rect;
+
+bool b2h(BRect const& from, HRect* to);
+bool h2b(HRect const& from, BRect* to);
+
+// Region
+// ======
+
+using BRegion = ::android::Region;
+using HRegion = ::android::hardware::hidl_vec<HRect>;
+
+bool b2h(BRegion const& from, HRegion* to);
+bool h2b(HRegion const& from, BRegion* to);
+
+// GraphicBuffer
+// =============
+
+using HardwareBuffer = ::android::hardware::graphics::common::V1_2::
+ HardwareBuffer;
+using HardwareBufferDescription = ::android::hardware::graphics::common::V1_2::
+ HardwareBufferDescription;
+
+// Does not clone the handle. The returned HardwareBuffer should not outlive the
+// input GraphicBuffer. Note that HardwareBuffer does not carry the generation
+// number, so this function needs another output argument.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+ uint32_t* toGenerationNumber = nullptr);
+// Clones the handle and creates a new GraphicBuffer from the cloned handle.
+// Note that the generation number of the GraphicBuffer has to be set manually
+// afterwards because HardwareBuffer does not have such information.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to);
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_VNDK_TYPES_H
+
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 9cc5677..3f40e56 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -18,8 +18,12 @@
#define LOG_TAG "C2BqBuffer"
#include <utils/Log.h>
-#include <gui/BufferQueueDefs.h>
-#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <ui/BufferQueueDefs.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Fence.h>
+
+#include <types.h>
+
#include <hidl/HidlSupport.h>
#include <C2AllocatorGralloc.h>
@@ -35,7 +39,6 @@
using ::android::C2AndroidMemoryUsage;
using ::android::Fence;
using ::android::GraphicBuffer;
-using ::android::IGraphicBufferProducer;
using ::android::sp;
using ::android::status_t;
using ::android::wp;
@@ -223,7 +226,6 @@
}
});
if (!transResult.isOk() || status != android::OK) {
- ALOGD("cannot dequeue buffer %d", status);
if (transResult.isOk()) {
if (status == android::INVALID_OPERATION ||
status == android::TIMED_OUT ||
@@ -233,6 +235,7 @@
return C2_BLOCKING;
}
}
+ ALOGD("cannot dequeue buffer %d", status);
return C2_BAD_VALUE;
}
}
@@ -355,39 +358,31 @@
return mInit;
}
- static int kMaxIgbpRetry = 20; // TODO: small number can cause crash in releasing.
static int kMaxIgbpRetryDelayUs = 10000;
- int curTry = 0;
-
- while (curTry++ < kMaxIgbpRetry) {
- std::unique_lock<std::mutex> lock(mMutex);
- // TODO: return C2_NO_INIT
- if (mProducerId == 0) {
- std::shared_ptr<C2GraphicAllocation> alloc;
- c2_status_t err = mAllocator->newGraphicAllocation(
- width, height, format, usage, &alloc);
- if (err != C2_OK) {
- return err;
- }
- std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
- std::make_shared<C2BufferQueueBlockPoolData>(
- 0, (uint64_t)0, ~0, shared_from_this());
- // TODO: config?
- *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
- ALOGV("allocated a buffer successfully");
-
- return C2_OK;
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mProducerId == 0) {
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ c2_status_t err = mAllocator->newGraphicAllocation(
+ width, height, format, usage, &alloc);
+ if (err != C2_OK) {
+ return err;
}
- c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
- if (status == C2_BLOCKING) {
- lock.unlock();
- ::usleep(kMaxIgbpRetryDelayUs);
- continue;
- }
- return status;
+ std::shared_ptr<C2BufferQueueBlockPoolData> poolData =
+ std::make_shared<C2BufferQueueBlockPoolData>(
+ 0, (uint64_t)0, ~0, shared_from_this());
+ *block = _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ ALOGV("allocated a buffer successfully");
+
+ return C2_OK;
}
- return C2_BLOCKING;
+ c2_status_t status = fetchFromIgbp_l(width, height, format, usage, block);
+ if (status == C2_BLOCKING) {
+ lock.unlock();
+ // in order not to drain cpu from component's spinning
+ ::usleep(kMaxIgbpRetryDelayUs);
+ }
+ return status;
}
void setRenderCallback(const OnRenderCallback &renderCallback) {
diff --git a/media/codec2/vndk/types.cpp b/media/codec2/vndk/types.cpp
new file mode 100644
index 0000000..99b1e9b
--- /dev/null
+++ b/media/codec2/vndk/types.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/native_handle.h>
+#include <ui/BufferQueueDefs.h>
+#include <types.h>
+#include <system/window.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// TODO: move this into ui/BufferQueueDefs.h so that we don't need
+// to include headers from libgui.
+enum {
+ // The API number used to indicate the currently connected producer
+ CURRENTLY_CONNECTED_API = -1,
+ // The API number used to indicate that no producer is connected
+ NO_CONNECTED_API = 0,
+};
+
+// Status
+// ======
+
+bool b2h(status_t from, HStatus* to,
+ bool* bufferNeedsReallocation, bool* releaseAllBuffers) {
+ switch (from) {
+ case OK:
+ *to = HStatus::OK; break;
+ case NO_MEMORY:
+ *to = HStatus::NO_MEMORY; break;
+ case NO_INIT:
+ *to = HStatus::NO_INIT; break;
+ case BAD_VALUE:
+ *to = HStatus::BAD_VALUE; break;
+ case DEAD_OBJECT:
+ *to = HStatus::DEAD_OBJECT; break;
+ case INVALID_OPERATION:
+ *to = HStatus::INVALID_OPERATION; break;
+ case TIMED_OUT:
+ *to = HStatus::TIMED_OUT; break;
+ case WOULD_BLOCK:
+ *to = HStatus::WOULD_BLOCK; break;
+ case UNKNOWN_ERROR:
+ *to = HStatus::UNKNOWN_ERROR; break;
+ default:
+ status_t mask =
+ (bufferNeedsReallocation ? BufferQueueDefs::BUFFER_NEEDS_REALLOCATION : 0)
+ | (releaseAllBuffers ? BufferQueueDefs::RELEASE_ALL_BUFFERS : 0);
+ if (from & ~mask) {
+ *to = static_cast<HStatus>(from);
+ } else {
+ *to = HStatus::OK;
+ if (bufferNeedsReallocation) {
+ *bufferNeedsReallocation = from & BufferQueueDefs::BUFFER_NEEDS_REALLOCATION;
+ }
+ if (releaseAllBuffers) {
+ *releaseAllBuffers = from & BufferQueueDefs::RELEASE_ALL_BUFFERS;
+ }
+ }
+ }
+ return true;
+}
+
+bool h2b(HStatus from, status_t* to) {
+ switch (from) {
+ case HStatus::OK:
+ *to = OK; break;
+ case HStatus::NO_MEMORY:
+ *to = NO_MEMORY; break;
+ case HStatus::NO_INIT:
+ *to = NO_INIT; break;
+ case HStatus::BAD_VALUE:
+ *to = BAD_VALUE; break;
+ case HStatus::DEAD_OBJECT:
+ *to = DEAD_OBJECT; break;
+ case HStatus::INVALID_OPERATION:
+ *to = INVALID_OPERATION; break;
+ case HStatus::TIMED_OUT:
+ *to = TIMED_OUT; break;
+ case HStatus::WOULD_BLOCK:
+ *to = WOULD_BLOCK; break;
+ case HStatus::UNKNOWN_ERROR:
+ *to = UNKNOWN_ERROR; break;
+ default:
+ *to = static_cast<status_t>(from);
+ }
+ return true;
+}
+
+// Fence
+// =====
+
+HFenceWrapper::HFenceWrapper(native_handle_t* h) : mHandle{h} {
+}
+
+HFenceWrapper::~HFenceWrapper() {
+ native_handle_delete(mHandle);
+}
+
+HFenceWrapper& HFenceWrapper::set(native_handle_t* h) {
+ native_handle_delete(mHandle);
+ mHandle = h;
+ return *this;
+}
+
+HFenceWrapper& HFenceWrapper::operator=(native_handle_t* h) {
+ return set(h);
+}
+
+hidl_handle HFenceWrapper::getHandle() const {
+ return hidl_handle{mHandle};
+}
+
+HFenceWrapper::operator hidl_handle() const {
+ return getHandle();
+}
+
+bool b2h(sp<BFence> const& from, HFenceWrapper* to) {
+ if (!from) {
+ to->set(nullptr);
+ return true;
+ }
+ int fenceFd = from->get();
+ if (fenceFd == -1) {
+ to->set(nullptr);
+ return true;
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (!nh) {
+ return false;
+ }
+ nh->data[0] = fenceFd;
+ to->set(nh);
+ return true;
+}
+
+bool h2b(native_handle_t const* from, sp<BFence>* to) {
+ if (!from || from->numFds == 0) {
+ *to = new ::android::Fence();
+ return true;
+ }
+ if (from->numFds != 1 || from->numInts != 0) {
+ return false;
+ }
+ *to = new BFence(dup(from->data[0]));
+ return true;
+}
+
+// ConnectionType
+// ==============
+
+bool b2h(int from, HConnectionType* to) {
+ *to = static_cast<HConnectionType>(from);
+ switch (from) {
+ case CURRENTLY_CONNECTED_API:
+ *to = HConnectionType::CURRENTLY_CONNECTED; break;
+ case NATIVE_WINDOW_API_EGL:
+ *to = HConnectionType::EGL; break;
+ case NATIVE_WINDOW_API_CPU:
+ *to = HConnectionType::CPU; break;
+ case NATIVE_WINDOW_API_MEDIA:
+ *to = HConnectionType::MEDIA; break;
+ case NATIVE_WINDOW_API_CAMERA:
+ *to = HConnectionType::CAMERA; break;
+ }
+ return true;
+}
+
+bool h2b(HConnectionType from, int* to) {
+ *to = static_cast<int>(from);
+ switch (from) {
+ case HConnectionType::CURRENTLY_CONNECTED:
+ *to = CURRENTLY_CONNECTED_API; break;
+ case HConnectionType::EGL:
+ *to = NATIVE_WINDOW_API_EGL; break;
+ case HConnectionType::CPU:
+ *to = NATIVE_WINDOW_API_CPU; break;
+ case HConnectionType::MEDIA:
+ *to = NATIVE_WINDOW_API_MEDIA; break;
+ case HConnectionType::CAMERA:
+ *to = NATIVE_WINDOW_API_CAMERA; break;
+ }
+ return true;
+}
+
+// Rect
+// ====
+
+bool b2h(BRect const& from, HRect* to) {
+ BRect* dst = reinterpret_cast<BRect*>(to->data());
+ dst->left = from.left;
+ dst->top = from.top;
+ dst->right = from.right;
+ dst->bottom = from.bottom;
+ return true;
+}
+
+bool h2b(HRect const& from, BRect* to) {
+ BRect const* src = reinterpret_cast<BRect const*>(from.data());
+ to->left = src->left;
+ to->top = src->top;
+ to->right = src->right;
+ to->bottom = src->bottom;
+ return true;
+}
+
+// Region
+// ======
+
+bool b2h(BRegion const& from, HRegion* to) {
+ size_t numRects;
+ BRect const* rectArray = from.getArray(&numRects);
+ to->resize(numRects);
+ for (size_t i = 0; i < numRects; ++i) {
+ if (!b2h(rectArray[i], &(*to)[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool h2b(HRegion const& from, BRegion* to) {
+ if (from.size() > 0) {
+ BRect bRect;
+ if (!h2b(from[0], &bRect)) {
+ return false;
+ }
+ to->set(bRect);
+ for (size_t i = 1; i < from.size(); ++i) {
+ if (!h2b(from[i], &bRect)) {
+ return false;
+ }
+ to->addRectUnchecked(
+ static_cast<int>(bRect.left),
+ static_cast<int>(bRect.top),
+ static_cast<int>(bRect.right),
+ static_cast<int>(bRect.bottom));
+ }
+ } else {
+ to->clear();
+ }
+ return true;
+}
+
+// GraphicBuffer
+// =============
+
+// The handle is not cloned. Its lifetime is tied to the original GraphicBuffer.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+ uint32_t* toGenerationNumber) {
+ if (!from) {
+ return false;
+ }
+ AHardwareBuffer* hwBuffer = from->toAHardwareBuffer();
+ to->nativeHandle.setTo(
+ const_cast<native_handle_t*>(
+ AHardwareBuffer_getNativeHandle(hwBuffer)),
+ false);
+ AHardwareBuffer_describe(
+ hwBuffer,
+ reinterpret_cast<AHardwareBuffer_Desc*>(to->description.data()));
+ if (toGenerationNumber) {
+ *toGenerationNumber = from->getGenerationNumber();
+ }
+ return true;
+}
+
+// The handle is cloned.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to) {
+ AHardwareBuffer_Desc const* desc =
+ reinterpret_cast<AHardwareBuffer_Desc const*>(
+ from.description.data());
+ native_handle_t const* handle = from.nativeHandle;
+ AHardwareBuffer* hwBuffer;
+ if (AHardwareBuffer_createFromHandle(
+ desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+ &hwBuffer) != OK) {
+ return false;
+ }
+ *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer);
+ AHardwareBuffer_release(hwBuffer);
+ return true;
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index e284cda..a1c81f3 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -150,6 +150,7 @@
AAC,
HEVC,
MP3,
+ PCM,
OTHER
};
@@ -270,6 +271,8 @@
mType = AAC;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
mType = MP3;
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+ mType = PCM;
}
}
@@ -1054,6 +1057,27 @@
AMEDIAFORMAT_KEY_TARGET_TIME, targetSampleTimeUs);
}
+ if (mType == PCM) {
+ int32_t bitPerFrame = 16;
+ int32_t bigEndian = 0;
+ AMediaFormat *meta = AMediaFormat_new();
+ if (getFormat(meta) == AMEDIA_OK && meta != NULL) {
+ AMediaFormat_getInt32(meta,
+ AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &bitPerFrame);
+ AMediaFormat_getInt32(meta,
+ AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, &bigEndian);
+ }
+ AMediaFormat_delete(meta);
+ if (bigEndian == 1 && bitPerFrame == 16) {
+ // Big-endian -> little-endian
+ uint16_t *dstData = (uint16_t *)frame->data() + frame->range_offset();
+ uint16_t *srcData = (uint16_t *)frame->data() + frame->range_offset();
+ for (size_t i = 0; i < frame->range_length() / 2; i++) {
+ dstData[i] = ntohs(srcData[i]);
+ }
+ }
+ }
+
*out = frame;
return AMEDIA_OK;
@@ -1170,6 +1194,51 @@
////////////////////////////////////////////////////////////////////////////////
+enum WaveID {
+ MKV_RIFF_WAVE_FORMAT_PCM = 0x0001,
+ MKV_RIFF_WAVE_FORMAT_ADPCM_ms = 0x0002,
+ MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav = 0x0011,
+ MKV_RIFF_WAVE_FORMAT_MPEGL12 = 0x0050,
+ MKV_RIFF_WAVE_FORMAT_MPEGL3 = 0x0055,
+ MKV_RIFF_WAVE_FORMAT_WMAV1 = 0x0160,
+ MKV_RIFF_WAVE_FORMAT_WMAV2 = 0x0161,
+};
+
+static const char *MKVWave2MIME(uint16_t id) {
+ switch (id) {
+ case MKV_RIFF_WAVE_FORMAT_MPEGL12:
+ return MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
+
+ case MKV_RIFF_WAVE_FORMAT_MPEGL3:
+ return MEDIA_MIMETYPE_AUDIO_MPEG;
+
+ case MKV_RIFF_WAVE_FORMAT_PCM:
+ return MEDIA_MIMETYPE_AUDIO_RAW;
+
+ case MKV_RIFF_WAVE_FORMAT_ADPCM_ms:
+ return MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
+ case MKV_RIFF_WAVE_FORMAT_ADPCM_ima_wav:
+ return MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;
+
+ case MKV_RIFF_WAVE_FORMAT_WMAV1:
+ case MKV_RIFF_WAVE_FORMAT_WMAV2:
+ return MEDIA_MIMETYPE_AUDIO_WMA;
+ default:
+ ALOGW("unknown wave %x", id);
+ return "";
+ };
+}
+
+static bool isMkvAudioCsdSizeOK(const char* mime, size_t csdSize) {
+ if ((!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) && csdSize < 50) ||
+ (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) && csdSize < 20) ||
+ (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA) && csdSize < 28) ||
+ (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) && csdSize < 30)) {
+ return false;
+ }
+ return true;
+}
+
// trans all FOURCC to lower char
static uint32_t FourCCtoLower(uint32_t fourcc) {
uint8_t ch_1 = tolower((fourcc >> 24) & 0xff);
@@ -2036,20 +2105,40 @@
} else if (!strcmp("A_FLAC", codecID)) {
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_FLAC);
err = addFlacMetadata(meta, codecPrivate, codecPrivateSize);
+ } else if (!strcmp("A_MPEG/L2", codecID)) {
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
+ } else if (!strcmp("A_PCM/INT/LIT", codecID) ||
+ !strcmp("A_PCM/INT/BIG", codecID)) {
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+ int32_t bigEndian = !strcmp("A_PCM/INT/BIG", codecID) ? 1: 0;
+ AMediaFormat_setInt32(meta,
+ AMEDIAFORMAT_KEY_PCM_BIG_ENDIAN, bigEndian);
} else if ((!strcmp("A_MS/ACM", codecID))) {
- if ((NULL == codecPrivate) || (codecPrivateSize < 30)) {
+ if ((NULL == codecPrivate) || (codecPrivateSize < 18)) {
ALOGW("unsupported audio: A_MS/ACM has no valid private data: %s, size: %zu",
codecPrivate == NULL ? "null" : "non-null", codecPrivateSize);
continue;
} else {
uint16_t ID = *(uint16_t *)codecPrivate;
- if (ID == 0x0055) {
- AMediaFormat_setString(meta,
- AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MPEG);
+ const char* mime = MKVWave2MIME(ID);
+ ALOGV("A_MS/ACM type is %s", mime);
+ if (!strncasecmp("audio/", mime, 6) &&
+ isMkvAudioCsdSizeOK(mime, codecPrivateSize)) {
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, mime);
} else {
- ALOGW("A_MS/ACM unsupported type , continue");
+ ALOGE("A_MS/ACM continue, unsupported audio type=%s, csdSize:%zu",
+ mime, codecPrivateSize);
continue;
}
+ if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_WMA)) {
+ addESDSFromCodecPrivate(meta, true, codecPrivate, codecPrivateSize);
+ } else if (!strcmp(mime, MEDIA_MIMETYPE_AUDIO_MS_ADPCM) ||
+ !strcmp(mime, MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM)) {
+ uint32_t blockAlign = *(uint16_t*)(codecPrivate + 12);
+ addESDSFromCodecPrivate(meta, true, &blockAlign, sizeof(blockAlign));
+ }
}
} else {
ALOGW("%s is not supported.", codecID);
@@ -2058,6 +2147,7 @@
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, atrack->GetSamplingRate());
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, atrack->GetChannels());
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, atrack->GetBitDepth());
break;
}
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.cpp b/media/libaaudio/src/binding/AAudioBinderClient.cpp
index dd620e3..7b0d31f 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.cpp
+++ b/media/libaaudio/src/binding/AAudioBinderClient.cpp
@@ -97,8 +97,7 @@
status_t status = binder->linkToDeath(mAAudioClient);
// TODO review what we should do if this fails
if (status != NO_ERROR) {
- ALOGE("getAAudioService: linkToDeath(mAAudioClient = %p) returned %d",
- mAAudioClient.get(), status);
+ ALOGE("%s() - linkToDeath() returned %d", __func__, status);
}
mAAudioService = interface_cast<IAAudioService>(binder);
needToRegister = true;
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
index 67955e8..b6e8472 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.cpp
@@ -157,5 +157,4 @@
void SharedMemoryParcelable::dump() {
ALOGD("mFd = %d", mFd.get());
ALOGD("mSizeInBytes = %d", mSizeInBytes);
- ALOGD("mResolvedAddress = %p", mResolvedAddress);
}
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index 3e43c6b..8f2c488 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -38,7 +38,7 @@
int32_t sinkChannelCount) {
AudioFloatOutputPort *lastOutput = nullptr;
- ALOGD("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
+ ALOGV("%s() source format = 0x%08x, channels = %d, sink format = 0x%08x, channels = %d",
__func__, sourceFormat, sourceChannelCount, sinkFormat, sinkChannelCount);
switch (sourceFormat) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index ec270f3..db98d58 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -195,13 +195,13 @@
if (isDataCallbackSet()) {
mCallbackFrames = builder.getFramesPerDataCallback();
if (mCallbackFrames > getBufferCapacity() / 2) {
- ALOGE("%s - framesPerCallback too big = %d, capacity = %d",
+ ALOGW("%s - framesPerCallback too big = %d, capacity = %d",
__func__, mCallbackFrames, getBufferCapacity());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
} else if (mCallbackFrames < 0) {
- ALOGE("%s - framesPerCallback negative", __func__);
+ ALOGW("%s - framesPerCallback negative", __func__);
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
@@ -225,7 +225,7 @@
aaudio_result_t AudioStreamInternal::close() {
aaudio_result_t result = AAUDIO_OK;
- ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
+ ALOGV("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
// Don't close a stream while it is running.
aaudio_stream_state_t currentState = getState();
@@ -236,7 +236,7 @@
result = waitForStateChange(currentState, &nextState,
timeoutNanoseconds);
if (result != AAUDIO_OK) {
- ALOGE("%s() waitForStateChange() returned %d %s",
+ ALOGW("%s() waitForStateChange() returned %d %s",
__func__, result, AAudio_convertResultToText(result));
}
}
@@ -283,17 +283,17 @@
{
int64_t startTime;
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("requestStart() mServiceStreamHandle invalid");
+ ALOGD("requestStart() mServiceStreamHandle invalid");
return AAUDIO_ERROR_INVALID_STATE;
}
if (isActive()) {
- ALOGE("requestStart() already active");
+ ALOGD("requestStart() already active");
return AAUDIO_ERROR_INVALID_STATE;
}
aaudio_stream_state_t originalState = getState();
if (originalState == AAUDIO_STREAM_STATE_DISCONNECTED) {
- ALOGE("requestStart() but DISCONNECTED");
+ ALOGD("requestStart() but DISCONNECTED");
return AAUDIO_ERROR_DISCONNECTED;
}
setState(AAUDIO_STREAM_STATE_STARTING);
@@ -356,8 +356,8 @@
}
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
+ ALOGW("%s() mServiceStreamHandle invalid = 0x%08X",
+ __func__, mServiceStreamHandle);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -370,7 +370,7 @@
aaudio_result_t AudioStreamInternal::registerThread() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("registerThread() mServiceStreamHandle invalid");
+ ALOGW("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
return mServiceInterface.registerAudioThread(mServiceStreamHandle,
@@ -380,7 +380,7 @@
aaudio_result_t AudioStreamInternal::unregisterThread() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("unregisterThread() mServiceStreamHandle invalid");
+ ALOGW("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, gettid());
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index e1443d9..164ad2b 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -65,7 +65,7 @@
return result;
}
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("%s() mServiceStreamHandle invalid", __func__);
+ ALOGW("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -77,7 +77,7 @@
aaudio_result_t AudioStreamInternalPlay::requestFlush() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("%s() mServiceStreamHandle invalid", __func__);
+ ALOGW("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 8ae2644..44d5122 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -246,18 +246,20 @@
AAudioStream** streamPtr)
{
AudioStream *audioStream = nullptr;
+ aaudio_stream_id_t id = 0;
// Please leave these logs because they are very helpful when debugging.
- ALOGD("%s() called ----------------------------------------", __func__);
+ ALOGI("%s() called ----------------------------------------", __func__);
AudioStreamBuilder *streamBuilder = COMMON_GET_FROM_BUILDER_OR_RETURN(streamPtr);
aaudio_result_t result = streamBuilder->build(&audioStream);
- ALOGD("AAudioStreamBuilder_openStream() returns %d = %s for (%p) ----------------",
- result, AAudio_convertResultToText(result), audioStream);
if (result == AAUDIO_OK) {
audioStream->registerPlayerBase();
*streamPtr = (AAudioStream*) audioStream;
+ id = audioStream->getId();
} else {
*streamPtr = nullptr;
}
+ ALOGI("%s() returns %d = %s for s#%u ----------------",
+ __func__, result, AAudio_convertResultToText(result), id);
return result;
}
@@ -275,8 +277,9 @@
{
aaudio_result_t result = AAUDIO_ERROR_NULL;
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- ALOGD("%s(%p) called ---------------", __func__, stream);
if (audioStream != nullptr) {
+ aaudio_stream_id_t id = audioStream->getId();
+ ALOGD("%s(s#%u) called ---------------", __func__, id);
result = audioStream->safeClose();
// Close will only fail if called illegally, for example, from a callback.
// That would result in deleting an active stream, which would cause a crash.
@@ -286,42 +289,39 @@
} else {
ALOGW("%s attempt to close failed. Close it from another thread.", __func__);
}
+ ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
}
- // We're potentially freeing `stream` above, so its use here makes some
- // static analysis tools unhappy. Casting to uintptr_t helps assure
- // said tools that we're not doing anything bad here.
- ALOGD("%s(%#" PRIxPTR ") returned %d ---------", __func__,
- reinterpret_cast<uintptr_t>(stream), result);
return result;
}
AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- ALOGD("%s(%p) called --------------", __func__, stream);
+ aaudio_stream_id_t id = audioStream->getId();
+ ALOGD("%s(s#%u) called --------------", __func__, id);
aaudio_result_t result = audioStream->systemStart();
- ALOGD("%s(%p) returned %d ---------", __func__, stream, result);
+ ALOGD("%s(s#%u) returned %d ---------", __func__, id, result);
return result;
}
AAUDIO_API aaudio_result_t AAudioStream_requestPause(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- ALOGD("%s(%p) called", __func__, stream);
+ ALOGD("%s(s#%u) called", __func__, audioStream->getId());
return audioStream->systemPause();
}
AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- ALOGD("%s(%p) called", __func__, stream);
+ ALOGD("%s(s#%u) called", __func__, audioStream->getId());
return audioStream->safeFlush();
}
AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream)
{
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- ALOGD("%s(%p) called", __func__, stream);
+ ALOGD("%s(s#%u) called", __func__, audioStream->getId());
return audioStream->systemStopFromApp();
}
@@ -371,7 +371,7 @@
// Don't allow writes when playing with a callback.
if (audioStream->isDataCallbackActive()) {
- ALOGE("Cannot write to a callback stream when running.");
+ ALOGD("Cannot write to a callback stream when running.");
return AAUDIO_ERROR_INVALID_STATE;
}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index e5bda30..c9711da 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -56,7 +56,7 @@
case AUDIO_FORMAT_PCM_FLOAT:
break; // valid
default:
- ALOGE("audioFormat not valid, audio_format_t = 0x%08x", format);
+ ALOGD("audioFormat not valid, audio_format_t = 0x%08x", format);
return AAUDIO_ERROR_INVALID_FORMAT;
// break;
}
@@ -66,12 +66,12 @@
aaudio_result_t AAudioStreamParameters::validate() const {
if (mSamplesPerFrame != AAUDIO_UNSPECIFIED
&& (mSamplesPerFrame < SAMPLES_PER_FRAME_MIN || mSamplesPerFrame > SAMPLES_PER_FRAME_MAX)) {
- ALOGE("channelCount out of range = %d", mSamplesPerFrame);
+ ALOGD("channelCount out of range = %d", mSamplesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
if (mDeviceId < 0) {
- ALOGE("deviceId out of range = %d", mDeviceId);
+ ALOGD("deviceId out of range = %d", mDeviceId);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -89,7 +89,7 @@
case AAUDIO_SHARING_MODE_SHARED:
break;
default:
- ALOGE("illegal sharingMode = %d", mSharingMode);
+ ALOGD("illegal sharingMode = %d", mSharingMode);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -99,12 +99,12 @@
if (mSampleRate != AAUDIO_UNSPECIFIED
&& (mSampleRate < SAMPLE_RATE_HZ_MIN || mSampleRate > SAMPLE_RATE_HZ_MAX)) {
- ALOGE("sampleRate out of range = %d", mSampleRate);
+ ALOGD("sampleRate out of range = %d", mSampleRate);
return AAUDIO_ERROR_INVALID_RATE;
}
if (mBufferCapacity < 0) {
- ALOGE("bufferCapacity out of range = %d", mBufferCapacity);
+ ALOGD("bufferCapacity out of range = %d", mBufferCapacity);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
@@ -113,7 +113,7 @@
case AAUDIO_DIRECTION_OUTPUT:
break; // valid
default:
- ALOGE("direction not valid = %d", mDirection);
+ ALOGD("direction not valid = %d", mDirection);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -134,7 +134,7 @@
case AAUDIO_USAGE_ASSISTANT:
break; // valid
default:
- ALOGE("usage not valid = %d", mUsage);
+ ALOGD("usage not valid = %d", mUsage);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -147,7 +147,7 @@
case AAUDIO_CONTENT_TYPE_SPEECH:
break; // valid
default:
- ALOGE("content type not valid = %d", mContentType);
+ ALOGD("content type not valid = %d", mContentType);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -162,7 +162,7 @@
case AAUDIO_INPUT_PRESET_VOICE_PERFORMANCE:
break; // valid
default:
- ALOGE("input preset not valid = %d", mInputPreset);
+ ALOGD("input preset not valid = %d", mInputPreset);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
@@ -174,7 +174,7 @@
case AAUDIO_ALLOW_CAPTURE_BY_NONE:
break; // valid
default:
- ALOGE("allowed capture policy not valid = %d", mAllowedCapturePolicy);
+ ALOGD("allowed capture policy not valid = %d", mAllowedCapturePolicy);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
// break;
}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 732d45c..25669be 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -28,9 +28,17 @@
using namespace aaudio;
+
+// Sequential number assigned to streams solely for debugging purposes.
+static aaudio_stream_id_t AAudio_getNextStreamId() {
+ static std::atomic <aaudio_stream_id_t> nextStreamId{1};
+ return nextStreamId++;
+}
+
AudioStream::AudioStream()
: mPlayerBase(new MyPlayerBase(this))
-{
+ , mStreamId(AAudio_getNextStreamId())
+ {
// mThread is a pthread_t of unknown size so we need memset.
memset(&mThread, 0, sizeof(mThread));
setPeriodNanoseconds(0);
@@ -48,22 +56,6 @@
mPlayerBase->clearParentReference(); // remove reference to this AudioStream
}
-static const char *AudioStream_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
- const char *result;
- switch (sharingMode) {
- case AAUDIO_SHARING_MODE_EXCLUSIVE:
- result = "EX";
- break;
- case AAUDIO_SHARING_MODE_SHARED:
- result = "SH";
- break;
- default:
- result = "?!";
- break;
- }
- return result;
-}
-
aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
{
// Call here as well because the AAudioService will call this without calling build().
@@ -106,20 +98,6 @@
mDataCallbackUserData = builder.getDataCallbackUserData();
mErrorCallbackUserData = builder.getErrorCallbackUserData();
- // This is very helpful for debugging in the future. Please leave it in.
- ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
- mSampleRate, mSamplesPerFrame, mFormat,
- AudioStream_convertSharingModeToShortText(mSharingMode),
- (getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
- ALOGI("open() device = %d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
- mDeviceId,
- mSessionId,
- mPerformanceMode,
- (isDataCallbackSet() ? "ON" : "OFF"),
- mFramesPerDataCallback);
- ALOGI("open() usage = %d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
- mUsage, mContentType, mInputPreset, mAllowedCapturePolicy);
-
return AAUDIO_OK;
}
@@ -278,15 +256,15 @@
}
void AudioStream::setState(aaudio_stream_state_t state) {
- ALOGV("%s(%p) from %d to %d", __func__, this, mState, state);
+ ALOGV("%s(%d) from %d to %d", __func__, getId(), mState, state);
// CLOSED is a final state
if (mState == AAUDIO_STREAM_STATE_CLOSED) {
- ALOGE("%s(%p) tried to set to %d but already CLOSED", __func__, this, state);
+ ALOGE("%s(%d) tried to set to %d but already CLOSED", __func__, getId(), state);
// Once DISCONNECTED, we can only move to CLOSED state.
} else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
&& state != AAUDIO_STREAM_STATE_CLOSED) {
- ALOGE("%s(%p) tried to set to %d but already DISCONNECTED", __func__, this, state);
+ ALOGE("%s(%d) tried to set to %d but already DISCONNECTED", __func__, getId(), state);
} else {
mState = state;
@@ -485,7 +463,6 @@
}
AudioStream::MyPlayerBase::~MyPlayerBase() {
- ALOGV("MyPlayerBase::~MyPlayerBase(%p) deleted", this);
}
void AudioStream::MyPlayerBase::registerWithAudioManager() {
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 32713b1..044c979 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -36,6 +36,7 @@
namespace aaudio {
typedef void *(*aaudio_audio_thread_proc_t)(void *);
+typedef uint32_t aaudio_stream_id_t;
class AudioStreamBuilder;
@@ -121,6 +122,12 @@
return AAUDIO_OK;
}
+ // This is only used to identify a stream in the logs without
+ // revealing any pointers.
+ aaudio_stream_id_t getId() {
+ return mStreamId;
+ }
+
virtual aaudio_result_t setBufferSize(int32_t requestedFrames) = 0;
virtual aaudio_result_t createThread(int64_t periodNanoseconds,
@@ -587,6 +594,8 @@
void *mThreadArg = nullptr;
aaudio_result_t mThreadRegistrationResult = AAUDIO_OK;
+ const aaudio_stream_id_t mStreamId;
+
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 4ef765d..08f4958 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -104,6 +104,8 @@
}
*streamPtr = nullptr;
+ logParameters();
+
aaudio_result_t result = validate();
if (result != AAUDIO_OK) {
return result;
@@ -217,3 +219,41 @@
return AAUDIO_OK;
}
+
+static const char *AAudio_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
+ switch (sharingMode) {
+ case AAUDIO_SHARING_MODE_EXCLUSIVE:
+ return "EX";
+ case AAUDIO_SHARING_MODE_SHARED:
+ return "SH";
+ default:
+ return "?!";
+ }
+}
+
+static const char *AAudio_convertDirectionToText(aaudio_direction_t direction) {
+ switch (direction) {
+ case AAUDIO_DIRECTION_OUTPUT:
+ return "OUTPUT";
+ case AAUDIO_DIRECTION_INPUT:
+ return "INPUT";
+ default:
+ return "?!";
+ }
+}
+
+void AudioStreamBuilder::logParameters() const {
+ // This is very helpful for debugging in the future. Please leave it in.
+ ALOGI("rate = %6d, channels = %d, format = %d, sharing = %s, dir = %s",
+ getSampleRate(), getSamplesPerFrame(), getFormat(),
+ AAudio_convertSharingModeToShortText(getSharingMode()),
+ AAudio_convertDirectionToText(getDirection()));
+ ALOGI("device = %6d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
+ getDeviceId(),
+ getSessionId(),
+ getPerformanceMode(),
+ ((getDataCallbackProc() != nullptr) ? "ON" : "OFF"),
+ mFramesPerDataCallback);
+ ALOGI("usage = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
+ getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
+}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index a43cfa8..8149af2 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -102,6 +102,8 @@
virtual aaudio_result_t validate() const override;
+ void logParameters() const;
+
private:
bool mSharingModeMatchRequired = false; // must match sharing mode requested
aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 2edab58..91d2eff 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -206,7 +206,9 @@
void AudioStreamLegacy::onAudioDeviceUpdate(audio_port_handle_t deviceId)
{
- ALOGD("onAudioDeviceUpdate() deviceId %d", (int)deviceId);
+ // Device routing is a common source of errors and DISCONNECTS.
+ // Please leave this log in place.
+ ALOGD("%s() devId %d => %d", __func__, (int) getDeviceId(), (int)deviceId);
if (getDeviceId() != AAUDIO_UNSPECIFIED && getDeviceId() != deviceId &&
getState() != AAUDIO_STREAM_STATE_DISCONNECTED) {
// Note that isDataCallbackActive() is affected by state so call it before DISCONNECTING.
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index f324669..de82d2b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1067,6 +1067,13 @@
return aps->setEffectEnabled(id, enabled);
}
+status_t AudioSystem::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->moveEffectsToIo(ids, io);
+}
+
status_t AudioSystem::isStreamActive(audio_stream_type_t stream, bool* state, uint32_t inPastMs)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e59f7e0..8d1f511 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -250,10 +250,7 @@
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0)
{
- mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
- mAttributes.usage = AUDIO_USAGE_UNKNOWN;
- mAttributes.flags = 0x0;
- strcpy(mAttributes.tags, "");
+ mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
(void)set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
@@ -286,10 +283,7 @@
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
{
- mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
- mAttributes.usage = AUDIO_USAGE_UNKNOWN;
- mAttributes.flags = 0x0;
- strcpy(mAttributes.tags, "");
+ mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
(void)set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -2603,6 +2597,20 @@
ALOGV_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_SERVER,
"%s(%d): location moved from server to kernel",
__func__, mPortId);
+
+ if (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER] ==
+ ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL]) {
+ // In Q, we don't return errors as an invalid time
+ // but instead we leave the last kernel good timestamp alone.
+ //
+ // If server is identical to kernel, the device data pipeline is idle.
+ // A better start time is now. The retrograde check ensures
+ // timestamp monotonicity.
+ const int64_t nowNs = systemTime();
+ ALOGD("%s(%d) device stall, using current time %lld",
+ __func__, mPortId, (long long)nowNs);
+ timestamp.mTime = convertNsToTimespec(nowNs);
+ }
}
// We update the timestamp time even when paused.
@@ -2740,27 +2748,32 @@
// Prevent retrograde motion in timestamp.
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
+ // Fix stale time when checking timestamp right after start().
+ // The position is at the last reported location but the time can be stale
+ // due to pause or standby or cold start latency.
+ //
+ // We keep advancing the time (but not the position) to ensure that the
+ // stale value does not confuse the application.
+ //
+ // For offload compatibility, use a default lag value here.
+ // Any time discrepancy between this update and the pause timestamp is handled
+ // by the retrograde check afterwards.
+ int64_t currentTimeNanos = audio_utils_ns_from_timespec(×tamp.mTime);
+ const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
+ const int64_t limitNs = mStartNs - lagNs;
+ if (currentTimeNanos < limitNs) {
+ ALOGD("%s(%d): correcting timestamp time for pause, "
+ "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
+ __func__, mPortId,
+ (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
+ timestamp.mTime = convertNsToTimespec(limitNs);
+ currentTimeNanos = limitNs;
+ }
+
// previousTimestampValid is set to false when starting after a stop or flush.
if (previousTimestampValid) {
const int64_t previousTimeNanos =
audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
- int64_t currentTimeNanos = audio_utils_ns_from_timespec(×tamp.mTime);
-
- // Fix stale time when checking timestamp right after start().
- //
- // For offload compatibility, use a default lag value here.
- // Any time discrepancy between this update and the pause timestamp is handled
- // by the retrograde check afterwards.
- const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
- const int64_t limitNs = mStartNs - lagNs;
- if (currentTimeNanos < limitNs) {
- ALOGD("%s(%d): correcting timestamp time for pause, "
- "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
- __func__, mPortId,
- (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
- timestamp.mTime = convertNsToTimespec(limitNs);
- currentTimeNanos = limitNs;
- }
// retrograde check
if (currentTimeNanos < previousTimeNanos) {
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index c997cfa..ee6c335 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -20,30 +20,13 @@
#include <android-base/macros.h>
#include <private/media/AudioTrackShared.h>
#include <utils/Log.h>
+#include <audio_utils/safe_math.h>
#include <linux/futex.h>
#include <sys/syscall.h>
namespace android {
-// TODO: consider pulling this into a shared header.
-// safe_sub_overflow is used ensure that subtraction occurs in the same native type
-// with proper 2's complement overflow. Without calling this function, it is possible,
-// for example, that optimizing compilers may elect to treat 32 bit subtraction
-// as 64 bit subtraction when storing into a 64 bit destination as integer overflow is
-// technically undefined.
-template<typename T,
- typename U,
- typename = std::enable_if_t<std::is_same<std::decay_t<T>,
- std::decay_t<U>>{}>>
- // ensure arguments are same type (ignoring volatile, which is used in cblk variables).
-auto safe_sub_overflow(const T& a, const U& b) {
- std::decay_t<T> result;
- (void)__builtin_sub_overflow(a, b, &result);
- // note if __builtin_sub_overflow returns true, an overflow occurred.
- return result;
-}
-
// used to clamp a value to size_t. TODO: move to another file.
template <typename T>
size_t clampToSize(T x) {
@@ -204,7 +187,7 @@
front = cblk->u.mStreaming.mFront;
}
// write to rear, read from front
- ssize_t filled = safe_sub_overflow(rear, front);
+ ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
// pipe should not be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
if (mIsOut) {
@@ -702,7 +685,7 @@
const size_t overflowBit = mFrameCountP2 << 1;
const size_t mask = overflowBit - 1;
int32_t newFront = (front & ~mask) | (flush & mask);
- ssize_t filled = safe_sub_overflow(rear, newFront);
+ ssize_t filled = audio_utils::safe_sub_overflow(rear, newFront);
if (filled >= (ssize_t)overflowBit) {
// front and rear offsets span the overflow bit of the p2 mask
// so rebasing newFront on the front offset is off by the overflow bit.
@@ -744,7 +727,7 @@
const size_t overflowBit = mFrameCountP2 << 1;
const size_t mask = overflowBit - 1;
int32_t newRear = (rear & ~mask) | (stop & mask);
- ssize_t filled = safe_sub_overflow(newRear, front);
+ ssize_t filled = audio_utils::safe_sub_overflow(newRear, front);
// overflowBit is unsigned, so cast to signed for comparison.
if (filled >= (ssize_t)overflowBit) {
// front and rear offsets span the overflow bit of the p2 mask
@@ -796,7 +779,7 @@
front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
rear = cblk->u.mStreaming.mRear;
}
- ssize_t filled = safe_sub_overflow(rear, front);
+ ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
// pipe should not already be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -923,7 +906,7 @@
return mFrameCount;
}
const int32_t rear = getRear();
- ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
+ ssize_t filled = audio_utils::safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
// pipe should not already be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -949,7 +932,7 @@
return mFrameCount;
}
const int32_t rear = getRear();
- const ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
+ const ssize_t filled = audio_utils::safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
return 0; // error condition, silently return 0.
}
@@ -1259,7 +1242,7 @@
}
const int32_t front = android_atomic_acquire_load(&mCblk->u.mStreaming.mFront);
const int32_t rear = mCblk->u.mStreaming.mRear;
- const ssize_t filled = safe_sub_overflow(rear, front);
+ const ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
return 0; // error condition, silently return 0.
}
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index bf98c60..4a8bb52 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -103,6 +103,7 @@
LIST_AUDIO_VOLUME_GROUPS,
GET_VOLUME_GROUP_FOR_ATTRIBUTES,
SET_ALLOWED_CAPTURE_POLICY,
+ MOVE_EFFECTS_TO_IO,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -550,6 +551,22 @@
return static_cast <status_t> (reply.readInt32());
}
+ status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(ids.size());
+ for (auto id : ids) {
+ data.writeInt32(id);
+ }
+ data.writeInt32(io);
+ status_t status = remote()->transact(MOVE_EFFECTS_TO_IO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast <status_t> (reply.readInt32());
+ }
+
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
Parcel data, reply;
@@ -1284,6 +1301,7 @@
case GET_OUTPUT_FOR_ATTR:
case ACQUIRE_SOUNDTRIGGER_SESSION:
case RELEASE_SOUNDTRIGGER_SESSION:
+ case MOVE_EFFECTS_TO_IO:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
// return status only for non void methods
@@ -1700,6 +1718,31 @@
return NO_ERROR;
} break;
+ case MOVE_EFFECTS_TO_IO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ std::vector<int> ids;
+ int32_t size;
+ status_t status = data.readInt32(&size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ if (size > MAX_ITEMS_PER_LIST) {
+ return BAD_VALUE;
+ }
+ for (int32_t i = 0; i < size; i++) {
+ int id;
+ status = data.readInt32(&id);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ ids.push_back(id);
+ }
+
+ audio_io_handle_t io = data.readInt32();
+ reply->writeInt32(static_cast <int32_t>(moveEffectsToIo(ids, io)));
+ return NO_ERROR;
+ } break;
+
case IS_STREAM_ACTIVE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
audio_stream_type_t stream = (audio_stream_type_t) data.readInt32();
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 05a1d56..d180bbc 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -286,6 +286,7 @@
int id);
static status_t unregisterEffect(int id);
static status_t setEffectEnabled(int id, bool enabled);
+ static status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io);
// clear stream to output mapping cache (gStreamOutputMap)
// and output configuration cache (gOutputs)
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 95530ac..11983d5 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -114,6 +114,7 @@
int id) = 0;
virtual status_t unregisterEffect(int id) = 0;
virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+ virtual status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) = 0;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0)
const = 0;
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 3a97905..3fbbc09 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -650,6 +650,9 @@
params.SpeakerType = LVM_HEADPHONES;
pContext->pBundledContext->SampleRate = LVM_FS_44100;
+#ifdef SUPPORT_MC
+ pContext->pBundledContext->ChMask = AUDIO_CHANNEL_OUT_STEREO;
+#endif
/* Concert Sound parameters */
params.VirtualizerOperatingMode = LVM_MODE_OFF;
@@ -695,6 +698,11 @@
params.TE_OperatingMode = LVM_TE_OFF;
params.TE_EffectLevel = 0;
+#ifdef SUPPORT_MC
+ params.NrChannels =
+ audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
+ params.ChMask = AUDIO_CHANNEL_OUT_STEREO;
+#endif
/* Activate the initial settings */
LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance,
¶ms);
@@ -1297,7 +1305,12 @@
return -EINVAL;
}
+#ifdef SUPPORT_MC
+ if (pContext->pBundledContext->SampleRate != SampleRate ||
+ pContext->pBundledContext->ChMask != pConfig->inputCfg.channels) {
+#else
if(pContext->pBundledContext->SampleRate != SampleRate){
+#endif
LVM_ControlParams_t ActiveParams;
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS;
@@ -1323,6 +1336,9 @@
LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "Effect_setConfig")
ALOGV("\tEffect_setConfig Succesfully called LVM_SetControlParameters\n");
pContext->pBundledContext->SampleRate = SampleRate;
+#ifdef SUPPORT_MC
+ pContext->pBundledContext->ChMask = pConfig->inputCfg.channels;
+#endif
LvmEffect_limitLevel(pContext);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 6bf045d..6af4554 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -107,6 +107,9 @@
LVM_FLOAT *pInputBuffer;
LVM_FLOAT *pOutputBuffer;
#endif
+#ifdef SUPPORT_MC
+ LVM_INT32 ChMask;
+#endif
};
/* SessionContext : One session */
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index a529628..1d33590 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -65,7 +65,6 @@
"MediaCodecInfo.cpp",
"OMXBuffer.cpp",
"omx/1.0/WGraphicBufferSource.cpp",
- "omx/1.0/WOmx.cpp",
"omx/1.0/WOmxBufferSource.cpp",
"omx/1.0/WOmxNode.cpp",
"omx/1.0/WOmxObserver.cpp",
@@ -75,13 +74,16 @@
local_include_dirs: ["aidl"],
export_aidl_headers: true,
},
+
+ local_include_dirs: [
+ "include",
+ ],
shared_libs: [
"android.hidl.token@1.0-utils",
"android.hardware.media.omx@1.0",
"libbinder",
"libcutils",
- "libgui",
"libhidlbase",
"libhidltransport",
"liblog",
@@ -93,21 +95,84 @@
export_shared_lib_headers: [
"android.hidl.token@1.0-utils",
"android.hardware.media.omx@1.0",
- "libgui",
"libstagefright_foundation",
"libui",
],
header_libs: [
- "libmedia_headers",
+ "libstagefright_headers",
+ "media_plugin_headers",
],
export_header_lib_headers: [
- "libmedia_headers",
+ "libstagefright_headers",
+ "media_plugin_headers",
],
export_include_dirs: [
"aidl",
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
+
+cc_library_shared {
+ name: "libmedia_omx_client",
+
+ srcs: [
+ "omx/1.0/WOmx.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libgui",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libmedia_omx",
+ "libstagefright_foundation",
+ "libui",
+ "libutils",
+ ],
+
+ export_shared_lib_headers: [
+ "libgui",
+ "libmedia_omx",
+ "libstagefright_foundation",
+ "libui",
+ ],
+
+ header_libs: [
+ "libstagefright_headers",
+ "media_plugin_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libstagefright_headers",
+ "media_plugin_headers",
+ ],
+
+ export_include_dirs: [
+ "include",
],
cflags: [
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 747b88f..bc0c2cd 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -27,7 +27,6 @@
#include <media/openmax/OMX_IndexExt.h>
#include <media/OMXBuffer.h>
#include <utils/NativeHandle.h>
-#include <gui/IGraphicBufferProducer.h>
#include <media/omx/1.0/WOmxNode.h>
#include <android/IGraphicBufferSource.h>
@@ -62,79 +61,6 @@
SET_QUIRKS,
};
-class BpOMX : public BpInterface<IOMX> {
-public:
- explicit BpOMX(const sp<IBinder> &impl)
- : BpInterface<IOMX>(impl) {
- }
-
- virtual status_t listNodes(List<ComponentInfo> *list) {
- list->clear();
-
- Parcel data, reply;
- data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- remote()->transact(LIST_NODES, data, &reply);
-
- int32_t n = reply.readInt32();
- for (int32_t i = 0; i < n; ++i) {
- list->push_back(ComponentInfo());
- ComponentInfo &info = *--list->end();
-
- info.mName = reply.readString8();
- int32_t numRoles = reply.readInt32();
- for (int32_t j = 0; j < numRoles; ++j) {
- info.mRoles.push_back(reply.readString8());
- }
- }
-
- return OK;
- }
-
- virtual status_t allocateNode(
- const char *name, const sp<IOMXObserver> &observer,
- sp<IOMXNode> *omxNode) {
- Parcel data, reply;
- data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- data.writeCString(name);
- data.writeStrongBinder(IInterface::asBinder(observer));
- remote()->transact(ALLOCATE_NODE, data, &reply);
-
- status_t err = reply.readInt32();
- if (err == OK) {
- *omxNode = IOMXNode::asInterface(reply.readStrongBinder());
- } else {
- omxNode->clear();
- }
-
- return err;
- }
-
- virtual status_t createInputSurface(
- sp<IGraphicBufferProducer> *bufferProducer,
- sp<IGraphicBufferSource> *bufferSource) {
- Parcel data, reply;
- status_t err;
- data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- err = remote()->transact(CREATE_INPUT_SURFACE, data, &reply);
- if (err != OK) {
- ALOGW("binder transaction failed: %d", err);
- return err;
- }
-
- err = reply.readInt32();
- if (err != OK) {
- return err;
- }
-
- *bufferProducer = IGraphicBufferProducer::asInterface(
- reply.readStrongBinder());
- *bufferSource = IGraphicBufferSource::asInterface(
- reply.readStrongBinder());
-
- return err;
- }
-};
-
class BpOMXNode : public BpInterface<IOMXNode> {
public:
explicit BpOMXNode(const sp<IBinder> &impl)
@@ -551,7 +477,6 @@
}
};
-IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
IMPLEMENT_HYBRID_META_INTERFACE(OMXNode, "android.hardware.IOMXNode");
////////////////////////////////////////////////////////////////////////////////
@@ -562,82 +487,6 @@
return PERMISSION_DENIED; \
} } while (0)
-status_t BnOMX::onTransact(
- uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
- switch (code) {
- case LIST_NODES:
- {
- CHECK_OMX_INTERFACE(IOMX, data, reply);
-
- List<ComponentInfo> list;
- listNodes(&list);
-
- reply->writeInt32(list.size());
- for (List<ComponentInfo>::iterator it = list.begin();
- it != list.end(); ++it) {
- ComponentInfo &cur = *it;
-
- reply->writeString8(cur.mName);
- reply->writeInt32(cur.mRoles.size());
- for (List<String8>::iterator role_it = cur.mRoles.begin();
- role_it != cur.mRoles.end(); ++role_it) {
- reply->writeString8(*role_it);
- }
- }
-
- return NO_ERROR;
- }
-
- case ALLOCATE_NODE:
- {
- CHECK_OMX_INTERFACE(IOMX, data, reply);
-
- const char *name = data.readCString();
-
- sp<IOMXObserver> observer =
- interface_cast<IOMXObserver>(data.readStrongBinder());
-
- if (name == NULL || observer == NULL) {
- ALOGE("b/26392700");
- reply->writeInt32(INVALID_OPERATION);
- return NO_ERROR;
- }
-
- sp<IOMXNode> omxNode;
-
- status_t err = allocateNode(name, observer, &omxNode);
-
- reply->writeInt32(err);
- if (err == OK) {
- reply->writeStrongBinder(IInterface::asBinder(omxNode));
- }
-
- return NO_ERROR;
- }
-
- case CREATE_INPUT_SURFACE:
- {
- CHECK_OMX_INTERFACE(IOMX, data, reply);
-
- sp<IGraphicBufferProducer> bufferProducer;
- sp<IGraphicBufferSource> bufferSource;
- status_t err = createInputSurface(&bufferProducer, &bufferSource);
-
- reply->writeInt32(err);
-
- if (err == OK) {
- reply->writeStrongBinder(IInterface::asBinder(bufferProducer));
- reply->writeStrongBinder(IInterface::asBinder(bufferSource));
- }
-
- return NO_ERROR;
- }
-
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
status_t BnOMXNode::onTransact(
uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
switch (code) {
diff --git a/media/libmedia/include/media/IOMX.h b/media/libmedia/include/media/IOMX.h
index e69c02d..7e7c2d2 100644
--- a/media/libmedia/include/media/IOMX.h
+++ b/media/libmedia/include/media/IOMX.h
@@ -47,9 +47,8 @@
using hardware::media::omx::V1_0::IOmxNode;
-class IOMX : public IInterface {
+class IOMX : public RefBase {
public:
- DECLARE_META_INTERFACE(OMX);
typedef uint32_t buffer_id;
@@ -224,14 +223,6 @@
};
////////////////////////////////////////////////////////////////////////////////
-
-class BnOMX : public BnInterface<IOMX> {
-public:
- virtual status_t onTransact(
- uint32_t code, const Parcel &data, Parcel *reply,
- uint32_t flags = 0);
-};
-
class BnOMXNode : public BnInterface<IOMXNode> {
public:
virtual status_t onTransact(
diff --git a/media/libmedia/include/media/TypeConverter.h b/media/libmedia/include/media/TypeConverter.h
index 3acfe98..2f8c209 100644
--- a/media/libmedia/include/media/TypeConverter.h
+++ b/media/libmedia/include/media/TypeConverter.h
@@ -305,8 +305,8 @@
result << "{ Content type: " << toString(attributes.content_type)
<< " Usage: " << toString(attributes.usage)
<< " Source: " << toString(attributes.source)
- << " Flags: " << attributes.flags
- << " Tags: " << attributes.tags
+ << std::hex << " Flags: 0x" << attributes.flags
+ << std::dec << " Tags: " << attributes.tags
<< " }";
return result.str();
diff --git a/media/libmedia/include/media/omx/1.0/Conversion.h b/media/libmedia/include/media/omx/1.0/Conversion.h
index 3700a23..babda22 100644
--- a/media/libmedia/include/media/omx/1.0/Conversion.h
+++ b/media/libmedia/include/media/omx/1.0/Conversion.h
@@ -31,12 +31,12 @@
#include <ui/FenceTime.h>
#include <cutils/native_handle.h>
+#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
#include <media/OMXFenceParcelable.h>
#include <media/OMXBuffer.h>
#include <media/hardware/VideoAPI.h>
#include <media/stagefright/MediaErrors.h>
-#include <gui/IGraphicBufferProducer.h>
#include <android/hardware/media/omx/1.0/types.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
@@ -282,8 +282,8 @@
case TIMED_OUT:
case ERROR_UNSUPPORTED:
case UNKNOWN_ERROR:
- case IGraphicBufferProducer::RELEASE_ALL_BUFFERS:
- case IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION:
+ case BufferQueueDefs::RELEASE_ALL_BUFFERS:
+ case BufferQueueDefs::BUFFER_NEEDS_REALLOCATION:
return static_cast<Status>(l);
case NOT_ENOUGH_DATA:
return Status::BUFFER_NEEDS_REALLOCATION;
diff --git a/media/libmedia/include/media/omx/1.0/WOmx.h b/media/libmedia/include/media/omx/1.0/WOmx.h
index f13546e..0680eec 100644
--- a/media/libmedia/include/media/omx/1.0/WOmx.h
+++ b/media/libmedia/include/media/omx/1.0/WOmx.h
@@ -47,7 +47,6 @@
using ::android::List;
using ::android::IOMX;
-using ::android::BnOMX;
/**
* Wrapper classes for conversion
@@ -58,7 +57,7 @@
* - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
*/
-struct LWOmx : public BnOMX {
+struct LWOmx : public IOMX {
sp<IOmx> mBase;
LWOmx(sp<IOmx> const& base);
status_t listNodes(List<IOMX::ComponentInfo>* list) override;
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 08519cd..dca6bb6 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -38,6 +38,7 @@
export_shared_lib_headers: [
"libaudioclient",
"libbinder",
+ "libgui",
"libmedia_omx",
],
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 2993ab1..1e8a1d5 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -143,6 +143,7 @@
Mutex mNotifyLock;
sp<MediaPlayer2Listener> mListener;
media_player2_internal_states mCurrentState;
+ bool mTransitionToNext;
int64_t mCurrentPosition;
MediaPlayer2SeekMode mCurrentSeekMode;
int64_t mSeekPosition;
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index ae7ac59..de65f8d 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -241,6 +241,7 @@
mSeekPosition = -1;
mSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
mCurrentState = MEDIA_PLAYER2_IDLE;
+ mTransitionToNext = false;
mLoop = false;
mVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
@@ -389,6 +390,7 @@
return INVALID_OPERATION;
}
mSrcId = srcId;
+ mTransitionToNext = true;
return mPlayer->playNextDataSource(srcId);
}
@@ -568,6 +570,7 @@
mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
} else {
mCurrentState = MEDIA_PLAYER2_PAUSED;
+ mTransitionToNext = false;
}
return ret;
}
@@ -815,6 +818,7 @@
} else {
mPlayer->setListener(NULL);
mCurrentState = MEDIA_PLAYER2_IDLE;
+ mTransitionToNext = false;
}
// setDataSource has to be called again to create a
// new mediaplayer.
@@ -1026,8 +1030,10 @@
case MEDIA2_NOP: // interface test message
break;
case MEDIA2_PREPARED:
- ALOGV("MediaPlayer2::notify() prepared");
- mCurrentState = MEDIA_PLAYER2_PREPARED;
+ ALOGV("MediaPlayer2::notify() prepared, srcId=%lld", (long long)srcId);
+ if (srcId == mSrcId) {
+ mCurrentState = MEDIA_PLAYER2_PREPARED;
+ }
break;
case MEDIA2_DRM_INFO:
ALOGV("MediaPlayer2::notify() MEDIA2_DRM_INFO(%lld, %d, %d, %d, %p)",
@@ -1038,7 +1044,7 @@
if (mCurrentState == MEDIA_PLAYER2_IDLE) {
ALOGE("playback complete in idle state");
}
- if (!mLoop) {
+ if (!mLoop && srcId == mSrcId) {
mCurrentState = MEDIA_PLAYER2_PLAYBACK_COMPLETE;
}
break;
@@ -1054,6 +1060,11 @@
// ext2: Implementation dependant error code.
if (ext1 != MEDIA2_INFO_VIDEO_TRACK_LAGGING) {
ALOGW("info/warning (%d, %d)", ext1, ext2);
+
+ if (ext1 == MEDIA2_INFO_DATA_SOURCE_START && srcId == mSrcId && mTransitionToNext) {
+ mCurrentState = MEDIA_PLAYER2_STARTED;
+ mTransitionToNext = false;
+ }
}
break;
case MEDIA2_SEEK_COMPLETE:
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d8de103..3b87462 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -780,6 +780,9 @@
// need to enable allocation when attaching
surface->getIGraphicBufferProducer()->allowAllocation(true);
+ // dequeueBuffer cannot time out
+ surface->setDequeueTimeout(-1);
+
// for meta data mode, we move dequeud buffers to the new surface.
// for non-meta mode, we must move all registered buffers
for (size_t i = 0; i < buffers.size(); ++i) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index b05718c..5932518 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -187,6 +187,7 @@
"liblog",
"libmedia",
"libmedia_omx",
+ "libmedia_omx_client",
"libaudioclient",
"libmediametrics",
"libmediautils",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b6b7784..2ca5eee 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1659,10 +1659,12 @@
return;
}
int32_t colorFormat;
- if (mSoftRenderer != NULL
- && mOutputFormat->contains("hdr-static-info")
+ if (mOutputFormat->contains("hdr-static-info")
&& mOutputFormat->findInt32("color-format", &colorFormat)
- && (colorFormat == OMX_COLOR_FormatYUV420Planar16)) {
+ // check format for OMX only, for C2 the format is always opaque since the
+ // software rendering doesn't go through client
+ && ((mSoftRenderer != NULL && colorFormat == OMX_COLOR_FormatYUV420Planar16)
+ || mOwnerName.equalsIgnoreCase("codec2::software"))) {
int32_t left, top, right, bottom, width, height;
int64_t totalPixel = 0;
if (mOutputFormat->findRect("crop", &left, &top, &right, &bottom)) {
@@ -1934,6 +1936,13 @@
case kWhatComponentAllocated:
{
+ if (mState == RELEASING || mState == UNINITIALIZED) {
+ // In case a kWhatError or kWhatRelease message came in and replied,
+ // we log a warning and ignore.
+ ALOGW("allocate interrupted by error or release, current state %d",
+ mState);
+ break;
+ }
CHECK_EQ(mState, INITIALIZING);
setState(INITIALIZED);
mFlags |= kFlagIsComponentAllocated;
@@ -1951,6 +1960,7 @@
} else {
mFlags &= ~kFlagUsesSoftwareRenderer;
}
+ mOwnerName = owner;
MediaResource::Type resourceType;
if (mComponentName.endsWith(".secure")) {
@@ -2214,6 +2224,7 @@
}
if (mime.startsWithIgnoreCase("video/")) {
+ mSurface->setDequeueTimeout(-1);
mSoftRenderer = new SoftwareRenderer(mSurface, mRotationDegrees);
}
}
@@ -2501,6 +2512,7 @@
&& (mFlags & kFlagPushBlankBuffersOnShutdown)) {
pushBlankBuffersToNativeWindow(mSurface.get());
}
+ surface->setDequeueTimeout(-1);
mSoftRenderer = new SoftwareRenderer(surface);
// TODO: check if this was successful
} else {
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 83b87d9..680d426 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -430,18 +430,6 @@
return OK;
}
-void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
- if (info == NULL || info->mSamples.empty()) {
- return;
- }
-
- auto it = info->mSamples.begin();
- if (it->mBuffer != NULL) {
- it->mBuffer->release();
- }
- info->mSamples.erase(it);
-}
-
void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
if (info == NULL) {
return;
@@ -472,7 +460,7 @@
fetchTrackSamples(info, seekTimeUs, mode);
status_t err = info->mFinalResult;
- if (err != OK && err != ERROR_END_OF_STREAM) {
+ if (err != OK && err != ERROR_END_OF_STREAM && info->mSamples.empty()) {
return err;
}
@@ -527,14 +515,6 @@
info->mFinalResult = err;
if (err != OK && err != ERROR_END_OF_STREAM) {
ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
- size_t count = mediaBuffers.size();
- for (size_t id = 0; id < count; ++id) {
- MediaBufferBase *mbuf = mediaBuffers[id];
- if (mbuf != NULL) {
- mbuf->release();
- }
- }
- return;
}
size_t count = mediaBuffers.size();
@@ -584,8 +564,26 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- releaseOneSample(info);
+ if (info == NULL || info->mSamples.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
+ auto it = info->mSamples.begin();
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
+ }
+ info->mSamples.erase(it);
+
+ if (info->mSamples.empty()) {
+ minIndex = fetchAllTrackSamples();
+ if (minIndex < 0) {
+ return ERROR_END_OF_STREAM;
+ }
+ info = &mSelectedTracks.editItemAt(minIndex);
+ if (info == NULL || info->mSamples.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
+ }
return OK;
}
@@ -756,6 +754,9 @@
}
status_t NuMediaExtractor::getMetrics(Parcel *reply) {
+ if (mImpl == NULL) {
+ return -EINVAL;
+ }
status_t status = mImpl->getMetrics(reply);
return status;
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index c7b2719..537e4c0 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1756,7 +1756,11 @@
size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
}
- } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) {
+ } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC ||
+ mime == MEDIA_MIMETYPE_VIDEO_MPEG4 ||
+ mime == MEDIA_MIMETYPE_AUDIO_WMA ||
+ mime == MEDIA_MIMETYPE_AUDIO_MS_ADPCM ||
+ mime == MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM) {
std::vector<char> esds(csd0size + 31);
// The written ESDS is actually for an audio stream, but it's enough
// for transporting the CSD to muxers.
diff --git a/media/libstagefright/bqhelper/GraphicBufferSource.cpp b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
index a4374c9..68abcb5 100644
--- a/media/libstagefright/bqhelper/GraphicBufferSource.cpp
+++ b/media/libstagefright/bqhelper/GraphicBufferSource.cpp
@@ -32,6 +32,7 @@
#include <media/hardware/MetadataBufferType.h>
#include <ui/GraphicBuffer.h>
#include <gui/BufferItem.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
#include <media/hardware/HardwareAPI.h>
#include <inttypes.h>
@@ -281,6 +282,39 @@
}
};
+struct GraphicBufferSource::ConsumerProxy : public BufferQueue::ConsumerListener {
+ ConsumerProxy(const wp<GraphicBufferSource> &gbs) : mGbs(gbs) {}
+
+ ~ConsumerProxy() = default;
+
+ void onFrameAvailable(const BufferItem& item) override {
+ sp<GraphicBufferSource> gbs = mGbs.promote();
+ if (gbs != nullptr) {
+ gbs->onFrameAvailable(item);
+ }
+ }
+
+ void onBuffersReleased() override {
+ sp<GraphicBufferSource> gbs = mGbs.promote();
+ if (gbs != nullptr) {
+ gbs->onBuffersReleased();
+ }
+ }
+
+ void onSidebandStreamChanged() override {
+ sp<GraphicBufferSource> gbs = mGbs.promote();
+ if (gbs != nullptr) {
+ gbs->onSidebandStreamChanged();
+ }
+ }
+
+private:
+ // Note that GraphicBufferSource is holding an sp to us, we can't hold
+ // an sp back to GraphicBufferSource as the circular dependency will
+ // make both immortal.
+ wp<GraphicBufferSource> mGbs;
+};
+
GraphicBufferSource::GraphicBufferSource() :
mInitCheck(UNKNOWN_ERROR),
mNumAvailableUnacquiredBuffers(0),
@@ -313,14 +347,12 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mConsumer->setConsumerName(name);
- // Note that we can't create an sp<...>(this) in a ctor that will not keep a
- // reference once the ctor ends, as that would cause the refcount of 'this'
- // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
- // that's what we create.
- wp<BufferQueue::ConsumerListener> listener =
- static_cast<BufferQueue::ConsumerListener*>(this);
+ // create the consumer listener interface, and hold sp so that this
+ // interface lives as long as the GraphicBufferSource.
+ mConsumerProxy = new ConsumerProxy(this);
+
sp<IConsumerListener> proxy =
- new BufferQueue::ProxyConsumerListener(listener);
+ new BufferQueue::ProxyConsumerListener(mConsumerProxy);
mInitCheck = mConsumer->consumerConnect(proxy, false);
if (mInitCheck != NO_ERROR) {
@@ -357,6 +389,12 @@
}
}
+sp<::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer>
+GraphicBufferSource::getHGraphicBufferProducer() const {
+ return new ::android::hardware::graphics::bufferqueue::V2_0::utils::
+ B2HGraphicBufferProducer(getIGraphicBufferProducer());
+}
+
Status GraphicBufferSource::start() {
Mutex::Autolock autoLock(mMutex);
ALOGV("--> start; available=%zu, submittable=%zd",
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
index abc8910..bf329b9 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/GraphicBufferSource.h
@@ -68,7 +68,7 @@
* (even if it was dropped) to reencode it after an interval if no further
* frames are sent by the producer.
*/
-class GraphicBufferSource : public BufferQueue::ConsumerListener {
+class GraphicBufferSource : public RefBase {
public:
GraphicBufferSource();
@@ -86,6 +86,11 @@
return mProducer;
}
+ // Returns the handle to the bufferqueue HAL producer side of the BufferQueue.
+ // Buffers queued on this will be received by GraphicBufferSource.
+ sp<::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer>
+ getHGraphicBufferProducer() const;
+
// This is called when component transitions to running state, which means
// we can start handing it buffers. If we already have buffers of data
// sitting in the BufferQueue, this will send them to the codec.
@@ -190,8 +195,6 @@
status_t setColorAspects(int32_t aspectsPacked);
protected:
- // BQ::ConsumerListener interface
- // ------------------------------
// BufferQueue::ConsumerListener interface, called when a new frame of
// data is available. If we're executing and a codec buffer is
@@ -199,19 +202,24 @@
// into the codec buffer, and call Empty[This]Buffer. If we're not yet
// executing or there's no codec buffer available, we just increment
// mNumFramesAvailable and return.
- void onFrameAvailable(const BufferItem& item) override;
+ void onFrameAvailable(const BufferItem& item) ;
// BufferQueue::ConsumerListener interface, called when the client has
// released one or more GraphicBuffers. We clear out the appropriate
// set of mBufferSlot entries.
- void onBuffersReleased() override;
+ void onBuffersReleased() ;
// BufferQueue::ConsumerListener interface, called when the client has
// changed the sideband stream. GraphicBufferSource doesn't handle sideband
// streams so this is a no-op (and should never be called).
- void onSidebandStreamChanged() override;
+ void onSidebandStreamChanged() ;
private:
+ // BQ::ConsumerListener interface
+ // ------------------------------
+ struct ConsumerProxy;
+ sp<ConsumerProxy> mConsumerProxy;
+
// Lock, covers all member variables.
mutable Mutex mMutex;
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index 52b2765..a08fed1 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -59,6 +59,10 @@
const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
+const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM = "audio/x-adpcm-ms";
+const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM = "audio/x-adpcm-dvi-ima";
+
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mp4";
const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/x-wav";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 007a09b..1f9e636 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -61,6 +61,10 @@
extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
+extern const char *MEDIA_MIMETYPE_AUDIO_MS_ADPCM;
+extern const char *MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM;
+
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 7f6aae6..6cd4265 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -313,6 +313,7 @@
sp<ALooper> mCodecLooper;
sp<CodecBase> mCodec;
AString mComponentName;
+ AString mOwnerName;
sp<MediaCodecInfo> mCodecInfo;
sp<AReplyToken> mReplyID;
uint32_t mFlags;
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index f34f9b6..4307110 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -149,7 +149,6 @@
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
- void releaseOneSample(TrackInfo *info);
void releaseTrackSamples(TrackInfo *info);
void releaseAllTrackSamples();
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 15952e3..0c50752 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -6,7 +6,6 @@
},
srcs: [
- "BWGraphicBufferSource.cpp",
"OMXMaster.cpp",
"OMXNodeInstance.cpp",
"OMXUtils.cpp",
@@ -39,7 +38,6 @@
"libutils",
"liblog",
"libui",
- "libgui",
"libcutils",
"libstagefright_foundation",
"libstagefright_bufferqueue_helper",
@@ -55,7 +53,6 @@
],
export_shared_lib_headers: [
- "libmedia_omx",
"libstagefright_foundation",
"libstagefright_xmlparser",
"libutils",
diff --git a/media/libstagefright/omx/BWGraphicBufferSource.cpp b/media/libstagefright/omx/BWGraphicBufferSource.cpp
deleted file mode 100644
index fa30a46..0000000
--- a/media/libstagefright/omx/BWGraphicBufferSource.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "BWGraphicBufferSource"
-
-#include <media/stagefright/omx/BWGraphicBufferSource.h>
-#include <media/stagefright/omx/OMXUtils.h>
-#include <media/openmax/OMX_Component.h>
-#include <media/openmax/OMX_IndexExt.h>
-#include <media/OMXBuffer.h>
-#include <media/IOMX.h>
-
-namespace android {
-
-static const OMX_U32 kPortIndexInput = 0;
-
-struct BWGraphicBufferSource::BWOmxNodeWrapper : public IOmxNodeWrapper {
- sp<IOMXNode> mOMXNode;
-
- BWOmxNodeWrapper(const sp<IOMXNode> &omxNode): mOMXNode(omxNode) {
- }
-
- virtual status_t emptyBuffer(
- int32_t bufferId, uint32_t flags,
- const sp<GraphicBuffer> &buffer,
- int64_t timestamp, int fenceFd) override {
- return mOMXNode->emptyBuffer(bufferId, buffer, flags, timestamp, fenceFd);
- }
-
- virtual void dispatchDataSpaceChanged(
- int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
- omx_message msg;
- msg.type = omx_message::EVENT;
- msg.fenceFd = -1;
- msg.u.event_data.event = OMX_EventDataSpaceChanged;
- msg.u.event_data.data1 = dataSpace;
- msg.u.event_data.data2 = aspects;
- msg.u.event_data.data3 = pixelFormat;
- mOMXNode->dispatchMessage(msg);
- }
-};
-
-struct BWGraphicBufferSource::BWOMXBufferSource : public BnOMXBufferSource {
- sp<OmxGraphicBufferSource> mSource;
-
- BWOMXBufferSource(const sp<OmxGraphicBufferSource> &source): mSource(source) {
- }
-
- Status onOmxExecuting() override {
- return mSource->onOmxExecuting();
- }
-
- Status onOmxIdle() override {
- return mSource->onOmxIdle();
- }
-
- Status onOmxLoaded() override {
- return mSource->onOmxLoaded();
- }
-
- Status onInputBufferAdded(int bufferId) override {
- return mSource->onInputBufferAdded(bufferId);
- }
-
- Status onInputBufferEmptied(
- int bufferId, const OMXFenceParcelable& fenceParcel) override {
- return mSource->onInputBufferEmptied(bufferId, fenceParcel.get());
- }
-};
-
-BWGraphicBufferSource::BWGraphicBufferSource(
- sp<OmxGraphicBufferSource> const& base) :
- mBase(base),
- mOMXBufferSource(new BWOMXBufferSource(base)) {
-}
-
-::android::binder::Status BWGraphicBufferSource::configure(
- const sp<IOMXNode>& omxNode, int32_t dataSpace) {
- // Do setInputSurface() first, the node will try to enable metadata
- // mode on input, and does necessary error checking. If this fails,
- // we can't use this input surface on the node.
- status_t err = omxNode->setInputSurface(mOMXBufferSource);
- if (err != NO_ERROR) {
- ALOGE("Unable to set input surface: %d", err);
- return Status::fromStatusT(err);
- }
-
- // use consumer usage bits queried from encoder, but always add
- // HW_VIDEO_ENCODER for backward compatibility.
- uint32_t consumerUsage;
- if (omxNode->getParameter(
- (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits,
- &consumerUsage, sizeof(consumerUsage)) != OK) {
- consumerUsage = 0;
- }
-
- OMX_PARAM_PORTDEFINITIONTYPE def;
- InitOMXParams(&def);
- def.nPortIndex = kPortIndexInput;
-
- err = omxNode->getParameter(
- OMX_IndexParamPortDefinition, &def, sizeof(def));
- if (err != NO_ERROR) {
- ALOGE("Failed to get port definition: %d", err);
- return Status::fromStatusT(UNKNOWN_ERROR);
- }
-
- return Status::fromStatusT(mBase->configure(
- new BWOmxNodeWrapper(omxNode),
- dataSpace,
- def.nBufferCountActual,
- def.format.video.nFrameWidth,
- def.format.video.nFrameHeight,
- consumerUsage));
-}
-
-::android::binder::Status BWGraphicBufferSource::setSuspend(
- bool suspend, int64_t timeUs) {
- return Status::fromStatusT(mBase->setSuspend(suspend, timeUs));
-}
-
-::android::binder::Status BWGraphicBufferSource::setRepeatPreviousFrameDelayUs(
- int64_t repeatAfterUs) {
- return Status::fromStatusT(mBase->setRepeatPreviousFrameDelayUs(repeatAfterUs));
-}
-
-::android::binder::Status BWGraphicBufferSource::setMaxFps(float maxFps) {
- return Status::fromStatusT(mBase->setMaxFps(maxFps));
-}
-
-::android::binder::Status BWGraphicBufferSource::setTimeLapseConfig(
- double fps, double captureFps) {
- return Status::fromStatusT(mBase->setTimeLapseConfig(
- fps, captureFps));
-}
-
-::android::binder::Status BWGraphicBufferSource::setStartTimeUs(
- int64_t startTimeUs) {
- return Status::fromStatusT(mBase->setStartTimeUs(startTimeUs));
-}
-
-::android::binder::Status BWGraphicBufferSource::setStopTimeUs(
- int64_t stopTimeUs) {
- return Status::fromStatusT(mBase->setStopTimeUs(stopTimeUs));
-}
-
-::android::binder::Status BWGraphicBufferSource::getStopTimeOffsetUs(
- int64_t *stopTimeOffsetUs) {
- return Status::fromStatusT(mBase->getStopTimeOffsetUs(stopTimeOffsetUs));
-}
-
-::android::binder::Status BWGraphicBufferSource::setColorAspects(
- int32_t aspects) {
- return Status::fromStatusT(mBase->setColorAspects(aspects));
-}
-
-::android::binder::Status BWGraphicBufferSource::setTimeOffsetUs(
- int64_t timeOffsetsUs) {
- return Status::fromStatusT(mBase->setTimeOffsetUs(timeOffsetsUs));
-}
-
-::android::binder::Status BWGraphicBufferSource::signalEndOfInputStream() {
- return Status::fromStatusT(mBase->signalEndOfInputStream());
-}
-
-} // namespace android
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/BWGraphicBufferSource.h b/media/libstagefright/omx/include/media/stagefright/omx/BWGraphicBufferSource.h
deleted file mode 100644
index 0efff22..0000000
--- a/media/libstagefright/omx/include/media/stagefright/omx/BWGraphicBufferSource.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef BWGRAPHIC_BUFFER_SOURCE_H_
-#define BWGRAPHIC_BUFFER_SOURCE_H_
-
-#include <binder/Binder.h>
-#include <binder/Status.h>
-#include <android/BnGraphicBufferSource.h>
-#include <android/BnOMXBufferSource.h>
-#include <media/IOMX.h>
-
-#include "OmxGraphicBufferSource.h"
-#include "IOmxNodeWrapper.h"
-
-namespace android {
-
-using ::android::binder::Status;
-using ::android::BnGraphicBufferSource;
-using ::android::OmxGraphicBufferSource;
-using ::android::IOMXNode;
-using ::android::sp;
-
-struct BWGraphicBufferSource : public BnGraphicBufferSource {
- struct BWOMXBufferSource;
- struct BWOmxNodeWrapper;
-
- sp<OmxGraphicBufferSource> mBase;
- sp<IOMXBufferSource> mOMXBufferSource;
-
- BWGraphicBufferSource(sp<OmxGraphicBufferSource> const &base);
-
- Status configure(
- const sp<IOMXNode>& omxNode, int32_t dataSpace) override;
- Status setSuspend(bool suspend, int64_t timeUs) override;
- Status setRepeatPreviousFrameDelayUs(
- int64_t repeatAfterUs) override;
- Status setMaxFps(float maxFps) override;
- Status setTimeLapseConfig(
- double fps, double captureFps) override;
- Status setStartTimeUs(int64_t startTimeUs) override;
- Status setStopTimeUs(int64_t stopTimeUs) override;
- Status getStopTimeOffsetUs(int64_t* stopTimeOffsetUs) override;
- Status setColorAspects(int32_t aspects) override;
- Status setTimeOffsetUs(int64_t timeOffsetsUs) override;
- Status signalEndOfInputStream() override;
-};
-
-} // namespace android
-
-#endif // ANDROID_HARDWARE_MEDIA_OMX_V1_0_WGRAPHICBUFFERSOURCE_H
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index fb03229..569fa88 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -18,12 +18,6 @@
"libnativewindow",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
- "android.hardware.media.omx@1.0",
- ],
-
- include_dirs: [
- "frameworks/av/media/libstagefright",
- "frameworks/native/include/media/openmax",
],
header_libs: [
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index c2f1072..cc8c234 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -40,9 +40,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
#include <media/stagefright/SimpleDecodingSource.h>
-#include <android/hardware/media/omx/1.0/IOmx.h>
-#include <media/omx/1.0/WOmx.h>
#include <system/window.h>
#define DEFAULT_TIMEOUT 500000
@@ -81,12 +80,13 @@
}
status_t Harness::initOMX() {
- using namespace ::android::hardware::media::omx::V1_0;
- sp<IOmx> tOmx = IOmx::getService();
- if (tOmx == nullptr) {
+ OMXClient client;
+ if (client.connect() != OK) {
+ ALOGE("Failed to connect to OMX to create persistent input surface.");
return NO_INIT;
}
- mOMX = new utils::LWOmx(tOmx);
+
+ mOMX = client.interface();
return mOMX != 0 ? OK : NO_INIT;
}
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index 5443f2c..f7f4c36 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -37,13 +37,10 @@
public class Included {
ctor public Included();
- method public media.codecs.Decoders getDecoders_optional();
- method public media.codecs.Encoders getEncoders_optional();
+ method public java.util.List<media.codecs.Decoders> getDecoders_optional();
+ method public java.util.List<media.codecs.Encoders> getEncoders_optional();
method public java.util.List<media.codecs.Include> getInclude_optional();
- method public media.codecs.Settings getSettings_optional();
- method public void setDecoders_optional(media.codecs.Decoders);
- method public void setEncoders_optional(media.codecs.Encoders);
- method public void setSettings_optional(media.codecs.Settings);
+ method public java.util.List<media.codecs.Settings> getSettings_optional();
}
public class Limit {
@@ -85,13 +82,10 @@
public class MediaCodecs {
ctor public MediaCodecs();
- method public media.codecs.Decoders getDecoders_optional();
- method public media.codecs.Encoders getEncoders_optional();
+ method public java.util.List<media.codecs.Decoders> getDecoders_optional();
+ method public java.util.List<media.codecs.Encoders> getEncoders_optional();
method public java.util.List<media.codecs.Include> getInclude_optional();
- method public media.codecs.Settings getSettings_optional();
- method public void setDecoders_optional(media.codecs.Decoders);
- method public void setEncoders_optional(media.codecs.Encoders);
- method public void setSettings_optional(media.codecs.Settings);
+ method public java.util.List<media.codecs.Settings> getSettings_optional();
}
public class Quirk {
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 6a1cc71..a968890 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -43,4 +43,5 @@
"-Wall",
],
+ vintf_fragments: ["manifest_media_c2_software.xml"],
}
diff --git a/apex/manifest_media_c2_software.xml b/media/mediaserver/manifest_media_c2_software.xml
similarity index 100%
rename from apex/manifest_media_c2_software.xml
rename to media/mediaserver/manifest_media_c2_software.xml
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index a4f5730..7d1c88b 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -81,7 +81,6 @@
"libmediadrm",
"libstagefright",
"libstagefright_foundation",
- "libstagefright_bufferqueue_helper",
"liblog",
"libutils",
"libcutils",
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index 22e15d3..baa4fc7 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -29,7 +29,7 @@
#include <ui/PublicFormat.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <grallocusage/GrallocUsageConversion.h>
-#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <gui/bufferqueue/1.0/WGraphicBufferProducer.h>
using namespace android;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0825cb4..9527195 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -687,6 +687,10 @@
bool updatePid = (input.clientInfo.clientPid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t clientUid = input.clientInfo.clientUid;
+ audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
+ std::vector<int> effectIds;
+
+
if (!isAudioServerOrMediaServerUid(callingUid)) {
ALOGW_IF(clientUid != callingUid,
"%s uid %d tried to pass itself off as %d",
@@ -851,7 +855,10 @@
// no risk of deadlock because AudioFlinger::mLock is held
Mutex::Autolock _dl(thread->mLock);
Mutex::Autolock _sl(effectThread->mLock);
- moveEffectChain_l(sessionId, effectThread, thread, true);
+ if (moveEffectChain_l(sessionId, effectThread, thread) == NO_ERROR) {
+ effectThreadId = thread->id();
+ effectIds = thread->getEffectIds_l(sessionId);
+ }
}
// Look for sync events awaiting for a session to be used.
@@ -885,6 +892,12 @@
goto Exit;
}
+ // effectThreadId is not NONE if an effect chain corresponding to the track session
+ // was found on another thread and must be moved on this thread
+ if (effectThreadId != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::moveEffectsToIo(effectIds, effectThreadId);
+ }
+
// return handle to client
trackHandle = new TrackHandle(track);
@@ -1225,7 +1238,8 @@
if (output == AUDIO_IO_HANDLE_NONE) {
return BAD_VALUE;
}
- ALOG_ASSERT(stream != AUDIO_STREAM_PATCH, "attempt to change AUDIO_STREAM_PATCH volume");
+ LOG_ALWAYS_FATAL_IF(stream == AUDIO_STREAM_PATCH && value != 1.0f,
+ "AUDIO_STREAM_PATCH must have full scale volume");
AutoMutex lock(mLock);
VolumeInterface *volumeInterface = getVolumeInterface_l(output);
@@ -1630,30 +1644,36 @@
void AudioFlinger::removeNotificationClient(pid_t pid)
{
- Mutex::Autolock _l(mLock);
+ std::vector< sp<AudioFlinger::EffectModule> > removedEffects;
{
- Mutex::Autolock _cl(mClientLock);
- mNotificationClients.removeItem(pid);
- }
+ Mutex::Autolock _l(mLock);
+ {
+ Mutex::Autolock _cl(mClientLock);
+ mNotificationClients.removeItem(pid);
+ }
- ALOGV("%d died, releasing its sessions", pid);
- size_t num = mAudioSessionRefs.size();
- bool removed = false;
- for (size_t i = 0; i < num; ) {
- AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
- ALOGV(" pid %d @ %zu", ref->mPid, i);
- if (ref->mPid == pid) {
- ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
- mAudioSessionRefs.removeAt(i);
- delete ref;
- removed = true;
- num--;
- } else {
- i++;
+ ALOGV("%d died, releasing its sessions", pid);
+ size_t num = mAudioSessionRefs.size();
+ bool removed = false;
+ for (size_t i = 0; i < num; ) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+ ALOGV(" pid %d @ %zu", ref->mPid, i);
+ if (ref->mPid == pid) {
+ ALOGV(" removing entry for pid %d session %d", pid, ref->mSessionid);
+ mAudioSessionRefs.removeAt(i);
+ delete ref;
+ removed = true;
+ num--;
+ } else {
+ i++;
+ }
+ }
+ if (removed) {
+ removedEffects = purgeStaleEffects_l();
}
}
- if (removed) {
- purgeStaleEffects_l();
+ for (auto& effect : removedEffects) {
+ effect->updatePolicyState();
}
}
@@ -2425,7 +2445,7 @@
Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
for (size_t i = 0; i < effectChains.size(); i ++) {
moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(),
- dstThread, true);
+ dstThread);
}
}
}
@@ -2792,31 +2812,40 @@
void AudioFlinger::releaseAudioSessionId(audio_session_t audioSession, pid_t pid)
{
- Mutex::Autolock _l(mLock);
- pid_t caller = IPCThreadState::self()->getCallingPid();
- ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
- const uid_t callerUid = IPCThreadState::self()->getCallingUid();
- if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
- caller = pid;
- }
- size_t num = mAudioSessionRefs.size();
- for (size_t i = 0; i < num; i++) {
- AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
- if (ref->mSessionid == audioSession && ref->mPid == caller) {
- ref->mCnt--;
- ALOGV(" decremented refcount to %d", ref->mCnt);
- if (ref->mCnt == 0) {
- mAudioSessionRefs.removeAt(i);
- delete ref;
- purgeStaleEffects_l();
- }
- return;
+ std::vector< sp<EffectModule> > removedEffects;
+ {
+ Mutex::Autolock _l(mLock);
+ pid_t caller = IPCThreadState::self()->getCallingPid();
+ ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
+ const uid_t callerUid = IPCThreadState::self()->getCallingUid();
+ if (pid != -1 && isAudioServerUid(callerUid)) { // check must match acquireAudioSessionId()
+ caller = pid;
}
+ size_t num = mAudioSessionRefs.size();
+ for (size_t i = 0; i < num; i++) {
+ AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
+ if (ref->mSessionid == audioSession && ref->mPid == caller) {
+ ref->mCnt--;
+ ALOGV(" decremented refcount to %d", ref->mCnt);
+ if (ref->mCnt == 0) {
+ mAudioSessionRefs.removeAt(i);
+ delete ref;
+ std::vector< sp<EffectModule> > effects = purgeStaleEffects_l();
+ removedEffects.insert(removedEffects.end(), effects.begin(), effects.end());
+ }
+ goto Exit;
+ }
+ }
+ // If the caller is audioserver it is likely that the session being released was acquired
+ // on behalf of a process not in notification clients and we ignore the warning.
+ ALOGW_IF(!isAudioServerUid(callerUid),
+ "session id %d not found for pid %d", audioSession, caller);
}
- // If the caller is audioserver it is likely that the session being released was acquired
- // on behalf of a process not in notification clients and we ignore the warning.
- ALOGW_IF(!isAudioServerUid(callerUid),
- "session id %d not found for pid %d", audioSession, caller);
+
+Exit:
+ for (auto& effect : removedEffects) {
+ effect->updatePolicyState();
+ }
}
bool AudioFlinger::isSessionAcquired_l(audio_session_t audioSession)
@@ -2831,11 +2860,12 @@
return false;
}
-void AudioFlinger::purgeStaleEffects_l() {
+std::vector<sp<AudioFlinger::EffectModule>> AudioFlinger::purgeStaleEffects_l() {
ALOGV("purging stale effects");
Vector< sp<EffectChain> > chains;
+ std::vector< sp<EffectModule> > removedEffects;
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
@@ -2847,6 +2877,7 @@
}
}
}
+
for (size_t i = 0; i < mRecordThreads.size(); i++) {
sp<RecordThread> t = mRecordThreads.valueAt(i);
Mutex::Autolock _l(t->mLock);
@@ -2856,6 +2887,15 @@
}
}
+ for (size_t i = 0; i < mMmapThreads.size(); i++) {
+ sp<MmapThread> t = mMmapThreads.valueAt(i);
+ Mutex::Autolock _l(t->mLock);
+ for (size_t j = 0; j < t->mEffectChains.size(); j++) {
+ sp<EffectChain> ec = t->mEffectChains[j];
+ chains.push(ec);
+ }
+ }
+
for (size_t i = 0; i < chains.size(); i++) {
sp<EffectChain> ec = chains[i];
int sessionid = ec->sessionId();
@@ -2884,11 +2924,11 @@
if (effect->purgeHandles()) {
t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
}
- AudioSystem::unregisterEffect(effect->id());
+ removedEffects.push_back(effect);
}
}
}
- return;
+ return removedEffects;
}
// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
@@ -3380,8 +3420,16 @@
}
}
- if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) {
- // handle must be cleared outside lock.
+ if (lStatus == NO_ERROR || lStatus == ALREADY_EXISTS) {
+ // Check CPU and memory usage
+ sp<EffectModule> effect = handle->effect().promote();
+ if (effect != nullptr) {
+ status_t rStatus = effect->updatePolicyState();
+ if (rStatus != NO_ERROR) {
+ lStatus = rStatus;
+ }
+ }
+ } else {
handle.clear();
}
@@ -3413,14 +3461,13 @@
Mutex::Autolock _dl(dstThread->mLock);
Mutex::Autolock _sl(srcThread->mLock);
- return moveEffectChain_l(sessionId, srcThread, dstThread, false);
+ return moveEffectChain_l(sessionId, srcThread, dstThread);
}
// moveEffectChain_l must be called with both srcThread and dstThread mLocks held
status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
AudioFlinger::PlaybackThread *srcThread,
- AudioFlinger::PlaybackThread *dstThread,
- bool reRegister)
+ AudioFlinger::PlaybackThread *dstThread)
{
ALOGV("moveEffectChain_l() session %d from thread %p to thread %p",
sessionId, srcThread, dstThread);
@@ -3476,36 +3523,67 @@
}
strategy = dstChain->strategy();
}
- if (reRegister) {
- AudioSystem::unregisterEffect(effect->id());
- AudioSystem::registerEffect(&effect->desc(),
- dstThread->id(),
- strategy,
- sessionId,
- effect->id());
- AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
- }
effect = chain->getEffectFromId_l(0);
}
if (status != NO_ERROR) {
for (size_t i = 0; i < removed.size(); i++) {
srcThread->addEffect_l(removed[i]);
- if (dstChain != 0 && reRegister) {
- AudioSystem::unregisterEffect(removed[i]->id());
- AudioSystem::registerEffect(&removed[i]->desc(),
- srcThread->id(),
- strategy,
- sessionId,
- removed[i]->id());
- AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
- }
}
}
return status;
}
+status_t AudioFlinger::moveAuxEffectToIo(int EffectId,
+ const sp<PlaybackThread>& dstThread,
+ sp<PlaybackThread> *srcThread)
+{
+ status_t status = NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ sp<PlaybackThread> thread = getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId);
+
+ if (EffectId != 0 && thread != 0 && dstThread != thread.get()) {
+ Mutex::Autolock _dl(dstThread->mLock);
+ Mutex::Autolock _sl(thread->mLock);
+ sp<EffectChain> srcChain = thread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
+ sp<EffectChain> dstChain;
+ if (srcChain == 0) {
+ return INVALID_OPERATION;
+ }
+
+ sp<EffectModule> effect = srcChain->getEffectFromId_l(EffectId);
+ if (effect == 0) {
+ return INVALID_OPERATION;
+ }
+ thread->removeEffect_l(effect);
+ status = dstThread->addEffect_l(effect);
+ if (status != NO_ERROR) {
+ thread->addEffect_l(effect);
+ status = INVALID_OPERATION;
+ goto Exit;
+ }
+
+ dstChain = effect->chain().promote();
+ if (dstChain == 0) {
+ thread->addEffect_l(effect);
+ status = INVALID_OPERATION;
+ }
+
+Exit:
+ // removeEffect_l() has stopped the effect if it was active so it must be restarted
+ if (effect->state() == EffectModule::ACTIVE ||
+ effect->state() == EffectModule::STOPPING) {
+ effect->start();
+ }
+ }
+
+ if (status == NO_ERROR && srcThread != nullptr) {
+ *srcThread = thread;
+ }
+ return status;
+}
+
bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l()
{
if (mGlobalEffectEnableTime != 0 &&
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 9960f0e..8bf89c8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -369,7 +369,6 @@
AudioHwDevice* findSuitableHwDev_l(audio_module_handle_t module,
audio_devices_t devices);
- void purgeStaleEffects_l();
// Set kEnableExtendedChannels to true to enable greater than stereo output
// for the MixerThread and device sink. Number of channels allowed is
@@ -696,8 +695,11 @@
status_t moveEffectChain_l(audio_session_t sessionId,
PlaybackThread *srcThread,
- PlaybackThread *dstThread,
- bool reRegister);
+ PlaybackThread *dstThread);
+
+ status_t moveAuxEffectToIo(int EffectId,
+ const sp<PlaybackThread>& dstThread,
+ sp<PlaybackThread> *srcThread);
// return thread associated with primary hardware device, or NULL
PlaybackThread *primaryPlaybackThread_l() const;
@@ -732,6 +734,8 @@
// Return true if the effect was found in mOrphanEffectChains, false otherwise.
bool updateOrphanEffectChains(const sp<EffectModule>& effect);
+ std::vector< sp<EffectModule> > purgeStaleEffects_l();
+
void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
void forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 2b34267..50ab634 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -168,6 +168,68 @@
return status;
}
+status_t AudioFlinger::EffectModule::updatePolicyState()
+{
+ status_t status = NO_ERROR;
+ bool doRegister = false;
+ bool registered = false;
+ bool doEnable = false;
+ bool enabled = false;
+ audio_io_handle_t io;
+ uint32_t strategy;
+
+ {
+ Mutex::Autolock _l(mLock);
+ // register effect when first handle is attached and unregister when last handle is removed
+ if (mPolicyRegistered != mHandles.size() > 0) {
+ doRegister = true;
+ mPolicyRegistered = mHandles.size() > 0;
+ if (mPolicyRegistered) {
+ sp <EffectChain> chain = mChain.promote();
+ sp <ThreadBase> thread = mThread.promote();
+
+ if (thread == nullptr || chain == nullptr) {
+ return INVALID_OPERATION;
+ }
+ io = thread->id();
+ strategy = chain->strategy();
+ }
+ }
+ // enable effect when registered according to enable state requested by controlling handle
+ if (mHandles.size() > 0) {
+ EffectHandle *handle = controlHandle_l();
+ if (handle != nullptr && mPolicyEnabled != handle->enabled()) {
+ doEnable = true;
+ mPolicyEnabled = handle->enabled();
+ }
+ }
+ registered = mPolicyRegistered;
+ enabled = mPolicyEnabled;
+ mPolicyLock.lock();
+ }
+ ALOGV("%s name %s id %d session %d doRegister %d registered %d doEnable %d enabled %d",
+ __func__, mDescriptor.name, mId, mSessionId, doRegister, registered, doEnable, enabled);
+ if (doRegister) {
+ if (registered) {
+ status = AudioSystem::registerEffect(
+ &mDescriptor,
+ io,
+ strategy,
+ mSessionId,
+ mId);
+ } else {
+ status = AudioSystem::unregisterEffect(mId);
+ }
+ }
+ if (registered && doEnable) {
+ status = AudioSystem::setEffectEnabled(mId, enabled);
+ }
+ mPolicyLock.unlock();
+
+ return status;
+}
+
+
ssize_t AudioFlinger::EffectModule::removeHandle(EffectHandle *handle)
{
Mutex::Autolock _l(mLock);
@@ -230,7 +292,6 @@
Mutex::Autolock _l(mLock);
ssize_t numHandles = removeHandle_l(handle);
if ((numHandles == 0) && (!mPinned || unpinIfLast)) {
- AudioSystem::unregisterEffect(mId);
sp<AudioFlinger> af = mAudioFlinger.promote();
if (af != 0) {
mLock.unlock();
@@ -943,11 +1004,6 @@
ALOGV("setEnabled %p enabled %d", this, enabled);
if (enabled != isEnabled()) {
- status_t status = AudioSystem::setEffectEnabled(mId, enabled);
- if (enabled && status != NO_ERROR) {
- return status;
- }
-
switch (mState) {
// going from disabled to enabled
case IDLE:
@@ -1253,14 +1309,11 @@
{
bool enabled = false;
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i < mHandles.size(); i++) {
- EffectHandle *handle = mHandles[i];
- if (handle != NULL && !handle->disconnected()) {
- if (handle->hasControl()) {
- enabled = handle->enabled();
- }
- }
+ EffectHandle *handle = controlHandle_l();
+ if (handle != NULL) {
+ enabled = handle->enabled();
}
+ mHandles.clear();
return enabled;
}
@@ -1572,6 +1625,12 @@
mEnabled = true;
+ status_t status = effect->updatePolicyState();
+ if (status != NO_ERROR) {
+ mEnabled = false;
+ return status;
+ }
+
sp<ThreadBase> thread = effect->thread().promote();
if (thread != 0) {
thread->checkSuspendOnEffectEnabled(effect, true, effect->sessionId());
@@ -1582,7 +1641,7 @@
return NO_ERROR;
}
- status_t status = effect->setEnabled(true);
+ status = effect->setEnabled(true);
if (status != NO_ERROR) {
if (thread != 0) {
thread->checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
@@ -1625,6 +1684,8 @@
}
mEnabled = false;
+ effect->updatePolicyState();
+
if (effect->suspended()) {
return NO_ERROR;
}
@@ -1660,20 +1721,17 @@
return;
}
mDisconnected = true;
- sp<ThreadBase> thread;
{
sp<EffectModule> effect = mEffect.promote();
if (effect != 0) {
- thread = effect->thread().promote();
- }
- }
- if (thread != 0) {
- thread->disconnectEffectHandle(this, unpinIfLast);
- } else {
- // try to cleanup as much as we can
- sp<EffectModule> effect = mEffect.promote();
- if (effect != 0 && effect->disconnectHandle(this, unpinIfLast) > 0) {
- ALOGW("%s Effect handle %p disconnected after thread destruction", __FUNCTION__, this);
+ sp<ThreadBase> thread = effect->thread().promote();
+ if (thread != 0) {
+ thread->disconnectEffectHandle(this, unpinIfLast);
+ } else if (effect->disconnectHandle(this, unpinIfLast) > 0) {
+ ALOGW("%s Effect handle %p disconnected after thread destruction",
+ __func__, this);
+ }
+ effect->updatePolicyState();
}
}
@@ -1947,6 +2005,16 @@
return 0;
}
+std::vector<int> AudioFlinger::EffectChain::getEffectIds()
+{
+ std::vector<int> ids;
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0; i < mEffects.size(); i++) {
+ ids.push_back(mEffects[i]->id());
+ }
+ return ids;
+}
+
void AudioFlinger::EffectChain::clearInputBuffer()
{
Mutex::Autolock _l(mLock);
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 58ce351..220874d 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -142,6 +142,8 @@
void addEffectToHal_l();
void release_l();
+ status_t updatePolicyState();
+
void dump(int fd, const Vector<String16>& args);
private:
@@ -204,6 +206,16 @@
static constexpr pid_t INVALID_PID = (pid_t)-1;
// this tid is allowed to call setVolume() without acquiring the mutex.
pid_t mSetVolumeReentrantTid = INVALID_PID;
+
+ // Audio policy effect state management
+ // Mutex protecting transactions with audio policy manager as mLock cannot
+ // be held to avoid cross deadlocks with audio policy mutex
+ Mutex mPolicyLock;
+ // Effect is registered in APM or not
+ bool mPolicyRegistered = false;
+ // Effect enabled state communicated to APM. Enabled state corresponds to
+ // state requested by the EffectHandle with control
+ bool mPolicyEnabled = false;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -334,6 +346,7 @@
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId_l(int id);
sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
+ std::vector<int> getEffectIds();
// FIXME use float to improve the dynamic range
bool setVolume_l(uint32_t *left, uint32_t *right, bool force = false);
void resetVolume_l();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0b203c4..e71f0c6 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -44,6 +44,7 @@
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
+#include <audio_utils/safe_math.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio.h>
@@ -1305,7 +1306,6 @@
sp<EffectChain> chain;
bool chainCreated = false;
bool effectCreated = false;
- bool effectRegistered = false;
audio_unique_id_t effectId = AUDIO_UNIQUE_ID_USE_UNSPECIFIED;
lStatus = initCheck();
@@ -1341,13 +1341,6 @@
if (effect == 0) {
effectId = mAudioFlinger->nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
- // Check CPU and memory usage
- lStatus = AudioSystem::registerEffect(
- desc, mId, chain->strategy(), sessionId, effectId);
- if (lStatus != NO_ERROR) {
- goto Exit;
- }
- effectRegistered = true;
// create a new effect module if none present in the chain
lStatus = chain->createEffect_l(effect, this, desc, effectId, sessionId, pinned);
if (lStatus != NO_ERROR) {
@@ -1377,9 +1370,6 @@
if (effectCreated) {
chain->removeEffect_l(effect);
}
- if (effectRegistered) {
- AudioSystem::unregisterEffect(effectId);
- }
if (chainCreated) {
removeEffectChain_l(chain);
}
@@ -1410,7 +1400,6 @@
}
if (remove) {
mAudioFlinger->updateOrphanEffectChains(effect);
- AudioSystem::unregisterEffect(effect->id());
if (handle->enabled()) {
checkSuspendOnEffectEnabled(effect, false, effect->sessionId());
}
@@ -1431,6 +1420,12 @@
return chain != 0 ? chain->getEffectFromId_l(effectId) : 0;
}
+std::vector<int> AudioFlinger::ThreadBase::getEffectIds_l(audio_session_t sessionId)
+{
+ sp<EffectChain> chain = getEffectChain_l(sessionId);
+ return chain != nullptr ? chain->getEffectIds() : std::vector<int>{};
+}
+
// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
// PlaybackThread::mLock held
status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
@@ -2136,9 +2131,15 @@
// notify every HAL buffer, regardless of the size of the track buffer
maxNotificationFrames = mFrameCount;
} else {
- // For normal tracks, use at least double-buffering if no sample rate conversion,
- // or at least triple-buffering if there is sample rate conversion
- const int nBuffering = sampleRate == mSampleRate ? 2 : 3;
+ // Triple buffer the notification period for a triple buffered mixer period;
+ // otherwise, double buffering for the notification period is fine.
+ //
+ // TODO: This should be moved to AudioTrack to modify the notification period
+ // on AudioTrack::setBufferSizeInFrames() changes.
+ const int nBuffering =
+ (uint64_t{frameCount} * mSampleRate)
+ / (uint64_t{mNormalFrameCount} * sampleRate) == 3 ? 3 : 2;
+
maxNotificationFrames = frameCount / nBuffering;
// If client requested a fast track but this was denied, then use the smaller maximum.
if (requestedFlags & AUDIO_OUTPUT_FLAG_FAST) {
@@ -2725,7 +2726,8 @@
// create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
Vector< sp<EffectChain> > effectChains = mEffectChains;
for (size_t i = 0; i < effectChains.size(); i ++) {
- mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this, false);
+ mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(),
+ this/* srcThread */, this/* dstThread */);
}
}
@@ -3610,8 +3612,30 @@
// only process effects if we're going to write
if (mSleepTimeUs == 0 && mType != OFFLOAD) {
+ audio_session_t activeHapticId = AUDIO_SESSION_NONE;
+ if (mHapticChannelCount > 0 && effectChains.size() > 0) {
+ for (auto track : mActiveTracks) {
+ if (track->getHapticPlaybackEnabled()) {
+ activeHapticId = track->sessionId();
+ break;
+ }
+ }
+ }
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
+ // TODO: Write haptic data directly to sink buffer when mixing.
+ if (activeHapticId != AUDIO_SESSION_NONE
+ && activeHapticId == effectChains[i]->sessionId()) {
+ // Haptic data is active in this case, copy it directly from
+ // in buffer to out buffer.
+ const size_t audioBufferSize = mNormalFrameCount
+ * audio_bytes_per_frame(mChannelCount, EFFECT_BUFFER_FORMAT);
+ memcpy_by_audio_format(
+ (uint8_t*)effectChains[i]->outBuffer() + audioBufferSize,
+ EFFECT_BUFFER_FORMAT,
+ (const uint8_t*)effectChains[i]->inBuffer() + audioBufferSize,
+ EFFECT_BUFFER_FORMAT, mNormalFrameCount * mHapticChannelCount);
+ }
}
}
}
@@ -4169,6 +4193,7 @@
// audio to FastMixer
fastTrack->mFormat = mFormat; // mPipeSink format for audio to FastMixer
fastTrack->mHapticPlaybackEnabled = mHapticChannelMask != AUDIO_CHANNEL_NONE;
+ fastTrack->mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
fastTrack->mGeneration++;
state->mFastTracksGen++;
state->mTrackMask = 1;
@@ -7875,7 +7900,7 @@
RecordThread *recordThread = (RecordThread *) threadBase.get();
const int32_t rear = recordThread->mRsmpInRear;
const int32_t front = mRsmpInFront;
- const ssize_t filled = rear - front;
+ const ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
size_t framesIn;
bool overrun = false;
@@ -7889,7 +7914,8 @@
} else {
// client is not keeping up with server, but give it latest data
framesIn = recordThread->mRsmpInFrames;
- mRsmpInFront = /* front = */ rear - framesIn;
+ mRsmpInFront = /* front = */ audio_utils::safe_sub_overflow(
+ rear, static_cast<int32_t>(framesIn));
overrun = true;
}
if (framesAvailable != NULL) {
@@ -7913,7 +7939,7 @@
RecordThread *recordThread = (RecordThread *) threadBase.get();
int32_t rear = recordThread->mRsmpInRear;
int32_t front = mRsmpInFront;
- ssize_t filled = rear - front;
+ ssize_t filled = audio_utils::safe_sub_overflow(rear, front);
// FIXME should not be P2 (don't want to increase latency)
// FIXME if client not keeping up, discard
LOG_ALWAYS_FATAL_IF(!(0 <= filled && (size_t) filled <= recordThread->mRsmpInFrames));
@@ -7946,13 +7972,13 @@
void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer(
AudioBufferProvider::Buffer* buffer)
{
- size_t stepCount = buffer->frameCount;
+ int32_t stepCount = static_cast<int32_t>(buffer->frameCount);
if (stepCount == 0) {
return;
}
ALOG_ASSERT(stepCount <= mRsmpInUnrel);
mRsmpInUnrel -= stepCount;
- mRsmpInFront += stepCount;
+ mRsmpInFront = audio_utils::safe_add_overflow(mRsmpInFront, stepCount);
buffer->raw = NULL;
buffer->frameCount = 0;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 18cb361..37b2d08 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -315,6 +315,7 @@
sp<EffectChain> getEffectChain(audio_session_t sessionId);
// same as getEffectChain() but must be called with ThreadBase mutex locked
sp<EffectChain> getEffectChain_l(audio_session_t sessionId) const;
+ std::vector<int> getEffectIds_l(audio_session_t sessionId);
// add an effect chain to the chain list (mEffectChains)
virtual status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
// remove an effect chain from the chain list (mEffectChains)
@@ -334,7 +335,8 @@
sp<AudioFlinger::EffectModule> getEffect(audio_session_t sessionId, int effectId);
sp<AudioFlinger::EffectModule> getEffect_l(audio_session_t sessionId, int effectId);
// add and effect module. Also creates the effect chain is none exists for
- // the effects audio session
+ // the effects audio session. Only called in a context of moving an effect
+ // from one thread to another
status_t addEffect_l(const sp< EffectModule>& effect);
// remove and effect module. Also removes the effect chain is this was the last
// effect
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index bbda17f..2ff80c6 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1244,54 +1244,25 @@
status_t AudioFlinger::PlaybackThread::Track::attachAuxEffect(int EffectId)
{
- status_t status = DEAD_OBJECT;
sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
- sp<AudioFlinger> af = mClient->audioFlinger();
+ if (thread == nullptr) {
+ return DEAD_OBJECT;
+ }
- Mutex::Autolock _l(af->mLock);
+ sp<PlaybackThread> dstThread = (PlaybackThread *)thread.get();
+ sp<PlaybackThread> srcThread; // srcThread is initialized by call to moveAuxEffectToIo()
+ sp<AudioFlinger> af = mClient->audioFlinger();
+ status_t status = af->moveAuxEffectToIo(EffectId, dstThread, &srcThread);
- sp<PlaybackThread> srcThread = af->getEffectThread_l(AUDIO_SESSION_OUTPUT_MIX, EffectId);
-
- if (EffectId != 0 && srcThread != 0 && playbackThread != srcThread.get()) {
- Mutex::Autolock _dl(playbackThread->mLock);
- Mutex::Autolock _sl(srcThread->mLock);
- sp<EffectChain> chain = srcThread->getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX);
- if (chain == 0) {
- return INVALID_OPERATION;
- }
-
- sp<EffectModule> effect = chain->getEffectFromId_l(EffectId);
- if (effect == 0) {
- return INVALID_OPERATION;
- }
- srcThread->removeEffect_l(effect);
- status = playbackThread->addEffect_l(effect);
- if (status != NO_ERROR) {
- srcThread->addEffect_l(effect);
- return INVALID_OPERATION;
- }
- // removeEffect_l() has stopped the effect if it was active so it must be restarted
- if (effect->state() == EffectModule::ACTIVE ||
- effect->state() == EffectModule::STOPPING) {
- effect->start();
- }
-
- sp<EffectChain> dstChain = effect->chain().promote();
- if (dstChain == 0) {
- srcThread->addEffect_l(effect);
- return INVALID_OPERATION;
- }
- AudioSystem::unregisterEffect(effect->id());
- AudioSystem::registerEffect(&effect->desc(),
- srcThread->id(),
- dstChain->strategy(),
- AUDIO_SESSION_OUTPUT_MIX,
- effect->id());
- AudioSystem::setEffectEnabled(effect->id(), effect->isEnabled());
+ if (EffectId != 0 && status == NO_ERROR) {
+ status = dstThread->attachAuxEffect(this, EffectId);
+ if (status == NO_ERROR) {
+ AudioSystem::moveEffectsToIo(std::vector<int>(EffectId), dstThread->id());
}
- status = playbackThread->attachAuxEffect(this, EffectId);
+ }
+
+ if (status != NO_ERROR && srcThread != nullptr) {
+ af->moveAuxEffectToIo(EffectId, srcThread, &dstThread);
}
return status;
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index a2cf7aa..caf0d7e 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -189,6 +189,7 @@
int id) = 0;
virtual status_t unregisterEffect(int id) = 0;
virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+ virtual status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) = 0;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const = 0;
virtual bool isStreamActiveRemotely(audio_stream_type_t stream,
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 54c5c76..1dbd1eb 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -23,7 +23,6 @@
namespace android {
-
/**
* VolumeSource is the discriminent for volume management on an output.
* It used to be the stream type by legacy, it may be host volume group or a volume curves if
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 7a9c26e..f2b51d9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -65,10 +65,13 @@
* @param[in] attributes to consider fowr the research of output descriptor.
* @param[out] desc to return if an primary output could be found.
* @param[out] secondaryDesc other desc that the audio should be routed to.
+ * @return OK if the request is valid
+ * otherwise if the request is not supported
*/
status_t getOutputForAttr(const audio_attributes_t& attributes, uid_t uid,
- sp<SwAudioOutputDescriptor> &primaryDesc,
- std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
+ audio_output_flags_t flags,
+ sp<SwAudioOutputDescriptor> &primaryDesc,
+ std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs);
sp<DeviceDescriptor> getDeviceAndMixForInputSource(audio_source_t inputSource,
const DeviceVector &availableDeviceTypes,
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 7f01dc5..c729ef9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -65,6 +65,11 @@
uint32_t getMaxEffectsMemory() const;
bool isNonOffloadableEffectEnabled() const;
+ void moveEffects(audio_session_t session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput);
+ void moveEffects(const std::vector<int>& ids, audio_io_handle_t dstOutput);
+
void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
private:
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 1b812c0..26bb354 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -126,21 +126,33 @@
}
status_t AudioPolicyMixCollection::getOutputForAttr(
- const audio_attributes_t& attributes, uid_t uid, sp<SwAudioOutputDescriptor> &primaryDesc,
+ const audio_attributes_t& attributes, uid_t uid,
+ audio_output_flags_t flags,
+ sp<SwAudioOutputDescriptor> &primaryDesc,
std::vector<sp<SwAudioOutputDescriptor>> *secondaryDescs)
{
ALOGV("getOutputForAttr() querying %zu mixes:", size());
primaryDesc = 0;
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = valueAt(i);
+ const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
+ if (!primaryOutputMix && (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) {
+ // AAudio does not support MMAP_NO_IRQ loopback render, and there is no way with
+ // the current MmapStreamInterface::start to reject a specific client added to a shared
+ // mmap stream.
+ // As a result all MMAP_NOIRQ requests have to be rejected when an loopback render
+ // policy is present. That ensures no shared mmap stream is used when an loopback
+ // render policy is registered.
+ ALOGD("%s: Rejecting MMAP_NOIRQ request due to LOOPBACK|RENDER mix present.", __func__);
+ return INVALID_OPERATION;
+ }
+
sp<SwAudioOutputDescriptor> policyDesc = policyMix->getOutput();
if (!policyDesc) {
ALOGV("%s: Skiping %zu: Mix has no output", __func__, i);
continue;
}
- const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
-
if (primaryOutputMix && primaryDesc != 0) {
ALOGV("%s: Skiping %zu: Primary output already found", __func__, i);
continue; // Primary output already found
@@ -170,7 +182,7 @@
}
}
}
- return (primaryDesc == nullptr && secondaryDescs->empty()) ? BAD_VALUE : NO_ERROR;
+ return NO_ERROR;
}
AudioPolicyMixCollection::MixMatchStatus AudioPolicyMixCollection::mixMatch(
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 89f9899..627fa8d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -174,6 +174,32 @@
return MAX_EFFECTS_MEMORY;
}
+void EffectDescriptorCollection::moveEffects(audio_session_t session,
+ audio_io_handle_t srcOutput,
+ audio_io_handle_t dstOutput)
+{
+ ALOGV("%s session %d srcOutput %d dstOutput %d", __func__, session, srcOutput, dstOutput);
+ for (size_t i = 0; i < size(); i++) {
+ sp<EffectDescriptor> effect = valueAt(i);
+ if (effect->mSession == session && effect->mIo == srcOutput) {
+ effect->mIo = dstOutput;
+ }
+ }
+}
+
+void EffectDescriptorCollection::moveEffects(const std::vector<int>& ids,
+ audio_io_handle_t dstOutput)
+{
+ ALOGV("%s num effects %zu, first ID %d, dstOutput %d",
+ __func__, ids.size(), ids.size() ? ids[0] : 0, dstOutput);
+ for (size_t i = 0; i < size(); i++) {
+ sp<EffectDescriptor> effect = valueAt(i);
+ if (std::find(begin(ids), end(ids), effect->mId) != end(ids)) {
+ effect->mIo = dstOutput;
+ }
+ }
+}
+
void EffectDescriptorCollection::dump(String8 *dst, int spaces, bool verbose) const
{
if (verbose) {
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
index c487da9..0ee83a2 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_product_strategies.xml
@@ -166,5 +166,20 @@
<Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
+
+ <!-- Routing Strategy rerouting may be removed as following media??? -->
+ <ProductStrategy name="rerouting">
+ <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
+ <ProductStrategy name="patch">
+ <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
index 9ec3d77..6e72dc5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/audio_policy_engine_volumes.xml
@@ -188,5 +188,26 @@
<point>100,0</point>
</volume>
</volumeGroup>
+
+ <volumeGroup>
+ <name>rerouting</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>patch</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
</volumeGroups>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
index c487da9..adcbd83 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_product_strategies.xml
@@ -166,5 +166,19 @@
<Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
</AttributesGroup>
</ProductStrategy>
+
+ <!-- Routing Strategy rerouting may be removed as following media??? -->
+ <ProductStrategy name="rerouting">
+ <AttributesGroup streamType="AUDIO_STREAM_REROUTING" volumeGroup="rerouting">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Patch stream needs full scale volume, define it otherwise switch to default... -->
+ <ProductStrategy name="patch">
+ <AttributesGroup streamType="AUDIO_STREAM_PATCH" volumeGroup="patch">
+ <Attributes></Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
</ProductStrategies>
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
index 9ec3d77..6e72dc5 100644
--- a/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/audio_policy_engine_volumes.xml
@@ -188,5 +188,26 @@
<point>100,0</point>
</volume>
</volumeGroup>
+
+ <volumeGroup>
+ <name>rerouting</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>patch</name>
+ <indexMin>0</indexMin>
+ <indexMax>1</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,0</point>
+ <point>100,0</point>
+ </volume>
+ </volumeGroup>
+
</volumeGroups>
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bd53f0f..4992fd4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -142,18 +142,7 @@
__func__, device->toString().c_str(), encodedFormat);
// register new device as available
- index = mAvailableOutputDevices.add(device);
- if (index >= 0) {
- sp<HwModule> module = mHwModules.getModuleForDevice(device, encodedFormat);
- if (module == 0) {
- ALOGD("setDeviceConnectionState() could not find HW module for device %s",
- device->toString().c_str());
- mAvailableOutputDevices.remove(device);
- return INVALID_OPERATION;
- }
- ALOGV("setDeviceConnectionState() module name=%s", module->getName());
- mAvailableOutputDevices[index]->attach(module);
- } else {
+ if (mAvailableOutputDevices.add(device) < 0) {
return NO_MEMORY;
}
@@ -295,13 +284,6 @@
ALOGW("%s() device already connected: %s", __func__, device->toString().c_str());
return INVALID_OPERATION;
}
- sp<HwModule> module = mHwModules.getModuleForDevice(device, AUDIO_FORMAT_DEFAULT);
- if (module == NULL) {
- ALOGW("setDeviceConnectionState(): could not find HW module for device %s",
- device->toString().c_str());
- return INVALID_OPERATION;
- }
-
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
broadcastDeviceConnectionState(device, state);
@@ -963,10 +945,11 @@
// otherwise, fallback to the dynamic policies, if none match, query the engine.
// Secondary outputs are always found by dynamic policies as the engine do not support them
sp<SwAudioOutputDescriptor> policyDesc;
- if (mPolicyMixes.getOutputForAttr(*resultAttr, uid, policyDesc, secondaryDescs) != NO_ERROR) {
- policyDesc = nullptr; // reset getOutputForAttr in case of failure
- secondaryDescs->clear();
+ status = mPolicyMixes.getOutputForAttr(*resultAttr, uid, *flags, policyDesc, secondaryDescs);
+ if (status != OK) {
+ return status;
}
+
// Explicit routing is higher priority then any dynamic policy primary output
bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && policyDesc != nullptr;
@@ -1640,7 +1623,14 @@
outputDesc->setClientActive(client, true);
if (client->hasPreferredDevice(true)) {
- devices = getNewOutputDevices(outputDesc, false /*fromCache*/);
+ if (outputDesc->clientsList(true /*activeOnly*/).size() == 1 &&
+ client->isPreferredDeviceForExclusiveUse()) {
+ // Preferred device may be exclusive, use only if no other active clients on this output
+ devices = DeviceVector(
+ mAvailableOutputDevices.getDeviceFromId(client->preferredDeviceId()));
+ } else {
+ devices = getNewOutputDevices(outputDesc, false /*fromCache*/);
+ }
if (devices != outputDesc->devices()) {
checkStrategyRoute(clientStrategy, outputDesc->mIoHandle);
}
@@ -2463,12 +2453,17 @@
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
audio_devices_t curDevice = desc->devices().types();
+ if (curDevice & AUDIO_DEVICE_OUT_SPEAKER_SAFE) {
+ curDevice |= AUDIO_DEVICE_OUT_SPEAKER;
+ curDevice &= ~AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ }
+
// Inter / intra volume group priority management: Loop on strategies arranged by priority
// If a higher priority strategy is active, and the output is routed to a device with a
// HW Gain management, do not change the volume
bool applyVolume = false;
if (desc->useHwGain()) {
- if (!(desc->isActive(group) || isInCall())) {
+ if (!(desc->isActive(toVolumeSource(group)) || isInCall())) {
continue;
}
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
@@ -2662,6 +2657,7 @@
}
if (output != mMusicEffectOutput) {
+ mEffects.moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
mpClientInterface->moveEffects(AUDIO_SESSION_OUTPUT_MIX, mMusicEffectOutput, output);
mMusicEffectOutput = output;
}
@@ -2721,6 +2717,13 @@
return status;
}
+
+status_t AudioPolicyManager::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+ mEffects.moveEffects(ids, io);
+ return NO_ERROR;
+}
+
bool AudioPolicyManager::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
return mOutputs.isActive(toVolumeSource(stream), inPastMs);
@@ -5064,12 +5067,12 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
- // FIXME code duplicated from getOutputForAttrInt
sp<SwAudioOutputDescriptor> desc;
std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
- mPolicyMixes.getOutputForAttr(client->attributes(), client->uid(), desc,
- &secondaryDescs);
- if (!std::equal(client->getSecondaryOutputs().begin(),
+ status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->uid(),
+ client->flags(), desc, &secondaryDescs);
+ if (status != OK ||
+ !std::equal(client->getSecondaryOutputs().begin(),
client->getSecondaryOutputs().end(),
secondaryDescs.begin(), secondaryDescs.end())) {
streamsToInvalidate.insert(client->stream());
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a700868..43637f6 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -200,6 +200,7 @@
int id);
virtual status_t unregisterEffect(int id);
virtual status_t setEffectEnabled(int id, bool enabled);
+ status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
// return whether a stream is playing remotely, override to change the definition of
@@ -344,11 +345,12 @@
}
virtual const DeviceVector getAvailableOutputDevices() const
{
- return mAvailableOutputDevices.filterForEngine();
+ return mAvailableOutputDevices;
}
virtual const DeviceVector getAvailableInputDevices() const
{
- return mAvailableInputDevices.filterForEngine();
+ // legacy and non-legacy remote-submix are managed by the engine, do not filter
+ return mAvailableInputDevices;
}
virtual const sp<DeviceDescriptor> &getDefaultOutputDevice() const
{
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 6ad01f7..dcf093b 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -225,6 +225,8 @@
size_t *totSize);
// protects access to mInputSources, mInputSessions, mOutputStreams, mOutputSessions
+ // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+ // those can call back into AudioPolicyService methods and try to acquire the mutex
Mutex mLock;
// Automatic input effects are configured per audio_source_t
KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index b8036bb..2e47eb6 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -225,6 +225,21 @@
return result;
}
+void AudioPolicyService::getPlaybackClientAndEffects(audio_port_handle_t portId,
+ sp<AudioPlaybackClient>& client,
+ sp<AudioPolicyEffects>& effects,
+ const char *context)
+{
+ Mutex::Autolock _l(mLock);
+ const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
+ if (index < 0) {
+ ALOGE("%s AudioTrack client not found for portId %d", context, portId);
+ return;
+ }
+ client = mAudioPlaybackClients.valueAt(index);
+ effects = mAudioPolicyEffects;
+}
+
status_t AudioPolicyService::startOutput(audio_port_handle_t portId)
{
if (mAudioPolicyManager == NULL) {
@@ -233,16 +248,9 @@
ALOGV("startOutput()");
sp<AudioPlaybackClient> client;
sp<AudioPolicyEffects>audioPolicyEffects;
- {
- Mutex::Autolock _l(mLock);
- const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
- if (index < 0) {
- ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
- return INVALID_OPERATION;
- }
- client = mAudioPlaybackClients.valueAt(index);
- audioPolicyEffects = mAudioPolicyEffects;
- }
+
+ getPlaybackClientAndEffects(portId, client, audioPolicyEffects, __func__);
+
if (audioPolicyEffects != 0) {
// create audio processors according to stream
status_t status = audioPolicyEffects->addOutputSessionEffects(
@@ -275,17 +283,9 @@
ALOGV("doStopOutput");
sp<AudioPlaybackClient> client;
sp<AudioPolicyEffects>audioPolicyEffects;
- {
- Mutex::Autolock _l(mLock);
- const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
- if (index < 0) {
- ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
- return INVALID_OPERATION;
- }
- client = mAudioPlaybackClients.valueAt(index);
- audioPolicyEffects = mAudioPolicyEffects;
- }
+ getPlaybackClientAndEffects(portId, client, audioPolicyEffects, __func__);
+
if (audioPolicyEffects != 0) {
// release audio processors from the stream
status_t status = audioPolicyEffects->releaseOutputSessionEffects(
@@ -315,13 +315,17 @@
void AudioPolicyService::doReleaseOutput(audio_port_handle_t portId)
{
ALOGV("doReleaseOutput from tid %d", gettid());
- Mutex::Autolock _l(mLock);
- const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
- if (index < 0) {
- ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
- return;
+ sp<AudioPlaybackClient> client;
+ sp<AudioPolicyEffects> audioPolicyEffects;
+
+ getPlaybackClientAndEffects(portId, client, audioPolicyEffects, __func__);
+
+ if (audioPolicyEffects != 0 && client->active) {
+ // clean up effects if output was not stopped before being released
+ audioPolicyEffects->releaseOutputSessionEffects(
+ client->io, client->stream, client->session);
}
- sp<AudioPlaybackClient> client = mAudioPlaybackClients.valueAt(index);
+ Mutex::Autolock _l(mLock);
mAudioPlaybackClients.removeItem(portId);
// called from internal thread: no need to clear caller identity
@@ -793,7 +797,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- Mutex::Autolock _l(mEffectsLock);
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->registerEffect(desc, io, strategy, session, id);
}
@@ -803,7 +807,7 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- Mutex::Autolock _l(mEffectsLock);
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->unregisterEffect(id);
}
@@ -813,11 +817,21 @@
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
- Mutex::Autolock _l(mEffectsLock);
+ Mutex::Autolock _l(mLock);
AutoCallerClear acc;
return mAudioPolicyManager->setEffectEnabled(id, enabled);
}
+status_t AudioPolicyService::moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->moveEffectsToIo(ids, io);
+}
+
bool AudioPolicyService::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
@@ -969,8 +983,6 @@
return false;
}
Mutex::Autolock _l(mLock);
- Mutex::Autolock _le(mEffectsLock); // isOffloadSupported queries for
- // non-offloadable effects
AutoCallerClear acc;
return mAudioPolicyManager->isOffloadSupported(info);
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index efdba56..0842649 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -134,6 +134,7 @@
int id);
virtual status_t unregisterEffect(int id);
virtual status_t setEffectEnabled(int id, bool enabled);
+ status_t moveEffectsToIo(const std::vector<int>& ids, audio_io_handle_t io) override;
virtual bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
virtual bool isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
virtual bool isSourceActive(audio_source_t source) const;
@@ -782,6 +783,12 @@
const audio_stream_type_t stream;
};
+ void getPlaybackClientAndEffects(audio_port_handle_t portId,
+ sp<AudioPlaybackClient>& client,
+ sp<AudioPolicyEffects>& effects,
+ const char *context);
+
+
// A class automatically clearing and restoring binder caller identity inside
// a code block (scoped variable)
// Declare one systematically before calling AudioPolicyManager methods so that they are
@@ -804,7 +811,6 @@
mutable Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing
// device connection state or routing
- mutable Mutex mEffectsLock; // serialize access to Effect state within APM.
// Note: lock acquisition order is always mLock > mEffectsLock:
// mLock protects AudioPolicyManager methods that can call into audio flinger
// and possibly back in to audio policy service and acquire mEffectsLock.
@@ -818,6 +824,8 @@
DefaultKeyedVector< int64_t, sp<NotificationClient> > mNotificationClients;
Mutex mNotificationClientsLock; // protects mNotificationClients
// Manage all effects configured in audio_effects.conf
+ // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+ // those can call back into AudioPolicyService methods and try to acquire the mutex
sp<AudioPolicyEffects> mAudioPolicyEffects;
audio_mode_t mPhoneState;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 3b93a4d..a1cb8ee 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -117,6 +117,9 @@
static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");
+Mutex CameraService::sProxyMutex;
+sp<hardware::ICameraServiceProxy> CameraService::sCameraServiceProxy;
+
CameraService::CameraService() :
mEventLog(DEFAULT_EVENT_LOG_LENGTH),
mNumberOfCameras(0),
@@ -203,18 +206,20 @@
}
sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() {
- sp<ICameraServiceProxy> proxyBinder = nullptr;
#ifndef __BRILLO__
- sp<IServiceManager> sm = defaultServiceManager();
- // Use checkService because cameraserver normally starts before the
- // system server and the proxy service. So the long timeout that getService
- // has before giving up is inappropriate.
- sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
- if (binder != nullptr) {
- proxyBinder = interface_cast<ICameraServiceProxy>(binder);
+ Mutex::Autolock al(sProxyMutex);
+ if (sCameraServiceProxy == nullptr) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ // Use checkService because cameraserver normally starts before the
+ // system server and the proxy service. So the long timeout that getService
+ // has before giving up is inappropriate.
+ sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
+ if (binder != nullptr) {
+ sCameraServiceProxy = interface_cast<ICameraServiceProxy>(binder);
+ }
}
#endif
- return proxyBinder;
+ return sCameraServiceProxy;
}
void CameraService::pingCameraServiceProxy() {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 643b8cb..a8c2606 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -932,6 +932,11 @@
static StatusInternal mapToInternal(hardware::camera::common::V1_0::CameraDeviceStatus status);
static int32_t mapToInterface(StatusInternal status);
+ // Guard mCameraServiceProxy
+ static Mutex sProxyMutex;
+ // Cached interface to the camera service proxy in system service
+ static sp<hardware::ICameraServiceProxy> sCameraServiceProxy;
+
static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
static void pingCameraServiceProxy();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index bc0dafe..415b2d8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -132,13 +132,24 @@
bool isLogical = manager->isLogicalCamera(mId.string(), &physicalCameraIds);
if (isLogical) {
for (auto& physicalId : physicalCameraIds) {
- res = manager->getCameraCharacteristics(physicalId, &mPhysicalDeviceInfoMap[physicalId]);
+ res = manager->getCameraCharacteristics(
+ physicalId, &mPhysicalDeviceInfoMap[physicalId]);
if (res != OK) {
SET_ERR_L("Could not retrieve camera %s characteristics: %s (%d)",
physicalId.c_str(), strerror(-res), res);
session->close();
return res;
}
+
+ if (DistortionMapper::isDistortionSupported(mPhysicalDeviceInfoMap[physicalId])) {
+ mDistortionMappers[physicalId].setupStaticInfo(mPhysicalDeviceInfoMap[physicalId]);
+ if (res != OK) {
+ SET_ERR_L("Unable to read camera %s's calibration fields for distortion "
+ "correction", physicalId.c_str());
+ session->close();
+ return res;
+ }
+ }
}
}
@@ -308,7 +319,7 @@
}
if (DistortionMapper::isDistortionSupported(mDeviceInfo)) {
- res = mDistortionMapper.setupStaticInfo(mDeviceInfo);
+ res = mDistortionMappers[mId.c_str()].setupStaticInfo(mDeviceInfo);
if (res != OK) {
SET_ERR_L("Unable to read necessary calibration fields for distortion correction");
return res;
@@ -3503,12 +3514,27 @@
}
// Fix up some result metadata to account for HAL-level distortion correction
- status_t res = mDistortionMapper.correctCaptureResult(&captureResult.mMetadata);
+ status_t res =
+ mDistortionMappers[mId.c_str()].correctCaptureResult(&captureResult.mMetadata);
if (res != OK) {
SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
frameNumber, strerror(res), res);
return;
}
+ for (auto& physicalMetadata : captureResult.mPhysicalMetadatas) {
+ String8 cameraId8(physicalMetadata.mPhysicalCameraId);
+ if (mDistortionMappers.find(cameraId8.c_str()) == mDistortionMappers.end()) {
+ continue;
+ }
+ res = mDistortionMappers[cameraId8.c_str()].correctCaptureResult(
+ &physicalMetadata.mPhysicalCameraMetadata);
+ if (res != OK) {
+ SET_ERR("Unable to correct physical capture result metadata for frame %d: %s (%d)",
+ frameNumber, strerror(res), res);
+ return;
+ }
+ }
+
// Fix up result metadata for monochrome camera.
res = fixupMonochromeTags(mDeviceInfo, captureResult.mMetadata);
if (res != OK) {
@@ -4278,12 +4304,13 @@
// Start scan at i, with the assumption that the stream order matches
size_t realIdx = i;
bool found = false;
- for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
+ size_t halStreamCount = finalConfiguration.streams.size();
+ for (size_t idx = 0; idx < halStreamCount; idx++) {
if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
found = true;
break;
}
- realIdx = (realIdx >= finalConfiguration.streams.size()) ? 0 : realIdx + 1;
+ realIdx = (realIdx >= halStreamCount - 1) ? 0 : realIdx + 1;
}
if (!found) {
ALOGE("%s: Stream %d not found in stream configuration response from HAL",
@@ -5481,13 +5508,21 @@
// Correct metadata regions for distortion correction if enabled
sp<Camera3Device> parent = mParent.promote();
if (parent != nullptr) {
- res = parent->mDistortionMapper.correctCaptureRequest(
- &(captureRequest->mSettingsList.begin()->metadata));
- if (res != OK) {
- SET_ERR("RequestThread: Unable to correct capture requests "
- "for lens distortion for request %d: %s (%d)",
- halRequest->frame_number, strerror(-res), res);
- return INVALID_OPERATION;
+ List<PhysicalCameraSettings>::iterator it;
+ for (it = captureRequest->mSettingsList.begin();
+ it != captureRequest->mSettingsList.end(); it++) {
+ if (parent->mDistortionMappers.find(it->cameraId) ==
+ parent->mDistortionMappers.end()) {
+ continue;
+ }
+ res = parent->mDistortionMappers[it->cameraId].correctCaptureRequest(
+ &(it->metadata));
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to correct capture requests "
+ "for lens distortion for request %d: %s (%d)",
+ halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
}
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index d3bb212..f8245df 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -1250,8 +1250,10 @@
/**
* Distortion correction support
*/
-
- camera3::DistortionMapper mDistortionMapper;
+ // Map from camera IDs to its corresponding distortion mapper. Only contains
+ // 1 ID if the device isn't a logical multi-camera. Otherwise contains both
+ // logical camera and its physical subcameras.
+ std::unordered_map<std::string, camera3::DistortionMapper> mDistortionMappers;
// Debug tracker for metadata tag value changes
// - Enabled with the -m <taglist> option to dumpsys, such as
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index 9cc19a3..473e21c 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -32,7 +32,6 @@
endif
LOCAL_SRC_FILES := main_codecservice.cpp
LOCAL_SHARED_LIBRARIES := \
- libmedia_omx \
libbinder \
libutils \
liblog \
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index 6d47be6..6ffbd26 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -25,7 +25,6 @@
#include <media/stagefright/omx/1.0/Omx.h>
#include <media/stagefright/omx/1.0/OmxStore.h>
-#include <media/CodecServiceRegistrant.h>
#include <dlfcn.h>
using namespace android;
diff --git a/services/mediacodec/main_swcodecservice.cpp b/services/mediacodec/main_swcodecservice.cpp
index a5db031..d91b788 100644
--- a/services/mediacodec/main_swcodecservice.cpp
+++ b/services/mediacodec/main_swcodecservice.cpp
@@ -33,11 +33,12 @@
extern "C" void RegisterCodecServices();
-int main(int argc __unused, char** /*argv*/)
+int main(int argc __unused, char** argv)
{
LOG(INFO) << "media swcodec service starting";
signal(SIGPIPE, SIG_IGN);
SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);
+ strcpy(argv[0], "media.swcodec");
::android::hardware::configureRpcThreadpool(64, false);
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 845f84b..d9c4045 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -45,6 +45,7 @@
exit_group: 1
rt_sigreturn: 1
ugetrlimit: 1
+readlink: 1
readlinkat: 1
_llseek: 1
fstatfs64: 1
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 7264a9b..83704ba 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -101,7 +101,7 @@
aaudio_result_t
AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
aaudio_result_t result = AAUDIO_OK;
- ALOGV("registerClientStream(%d, %p)\n", pid, serviceStream.get());
+ ALOGV("registerClientStream(%d,)\n", pid);
std::lock_guard<std::mutex> lock(mLock);
sp<NotificationClient> notificationClient = mNotificationClients[pid];
if (notificationClient == 0) {
@@ -118,27 +118,23 @@
aaudio_result_t
AAudioClientTracker::unregisterClientStream(pid_t pid,
sp<AAudioServiceStreamBase> serviceStream) {
- ALOGV("unregisterClientStream(%d, %p)\n", pid, serviceStream.get());
+ ALOGV("unregisterClientStream(%d,)\n", pid);
std::lock_guard<std::mutex> lock(mLock);
auto it = mNotificationClients.find(pid);
if (it != mNotificationClients.end()) {
- ALOGV("unregisterClientStream(%d, %p) found NotificationClient\n",
- pid, serviceStream.get());
+ ALOGV("unregisterClientStream(%d,) found NotificationClient\n", pid);
it->second->unregisterClientStream(serviceStream);
} else {
- ALOGE("unregisterClientStream(%d, %p) missing NotificationClient\n",
- pid, serviceStream.get());
+ ALOGE("unregisterClientStream(%d,) missing NotificationClient\n", pid);
}
return AAUDIO_OK;
}
AAudioClientTracker::NotificationClient::NotificationClient(pid_t pid)
: mProcessId(pid) {
- //ALOGD("NotificationClient(%d) created %p\n", pid, this);
}
AAudioClientTracker::NotificationClient::~NotificationClient() {
- //ALOGD("~NotificationClient() destroyed %p\n", this);
}
int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 2fbaeb4..e6a8375 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -132,11 +132,10 @@
if (result != AAUDIO_OK) {
serviceStream.clear();
- ALOGW("openStream(): failed, return %d = %s", result, AAudio_convertResultToText(result));
return result;
} else {
aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
- ALOGD("openStream(): handle = 0x%08X", handle);
+ ALOGV("openStream(): handle = 0x%08X", handle);
serviceStream->setHandle(handle);
pid_t pid = request.getProcessId();
AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 4dfb62a..553754e 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -90,7 +90,8 @@
std::lock_guard<std::mutex> lock(mLockStreams);
mConnected.store(false);
for (const auto& stream : mRegisteredStreams) {
- ALOGD("disconnectRegisteredStreams() stop and disconnect %p", stream.get());
+ ALOGD("disconnectRegisteredStreams() stop and disconnect port %d",
+ stream->getPortHandle());
stream->stop();
stream->disconnect();
}
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 3616fa2..a2f66a5 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -61,7 +61,7 @@
virtual aaudio_result_t startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
- ALOGD("AAudioServiceEndpoint::startClient(%p, ...) AAUDIO_ERROR_UNAVAILABLE", &client);
+ ALOGD("AAudioServiceEndpoint::startClient(...) AAUDIO_ERROR_UNAVAILABLE");
return AAUDIO_ERROR_UNAVAILABLE;
}
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index fbf7d10..447f32c 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -163,7 +163,9 @@
ALOGD("%s() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
__func__, mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
if (status != OK) {
- ALOGE("%s() - openMmapStream() returned status %d", __func__, status);
+ // This can happen if the resource is busy or the config does
+ // not match the hardware.
+ ALOGD("%s() - openMmapStream() returned status %d", __func__, status);
return AAUDIO_ERROR_UNAVAILABLE;
}
@@ -196,9 +198,9 @@
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
} else {
- ALOGD("%s() createMmapBuffer() returned = %d, buffer_size = %d, burst_size %d"
+ ALOGD("%s() createMmapBuffer() buffer_size = %d fr, burst_size %d fr"
", Sharable FD: %s",
- __func__, status,
+ __func__,
mMmapBufferinfo.buffer_size_frames,
mMmapBufferinfo.burst_size_frames,
isBufferShareable ? "Yes" : "No");
@@ -243,14 +245,13 @@
burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
} while (burstMicros < burstMinMicros);
- ALOGD("%s() original burst = %d, minMicros = %d, to burst = %d\n",
+ ALOGD("%s() original burst = %d, minMicros = %d => burst = %d\n",
__func__, mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
- ALOGD("%s() actual rate = %d, channels = %d"
- ", deviceId = %d, capacity = %d\n",
- __func__, getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
+ ALOGD("%s() actual rate = %d, channels = %d, deviceId = %d\n",
+ __func__, getSampleRate(), getSamplesPerFrame(), deviceId);
- ALOGD("%s() format = =x%08x, frame size = %d",
+ ALOGD("%s() format = 0x%08x, frame size = %d",
__func__, getFormat(), calculateBytesPerFrame());
return result;
@@ -262,7 +263,6 @@
aaudio_result_t AAudioServiceEndpointMMAP::close() {
if (mMmapStream != 0) {
- ALOGD("%s() clear() endpoint", __func__);
// Needs to be explicitly cleared or CTS will fail but it is not clear why.
mMmapStream.clear();
// Apparently the above close is asynchronous. An attempt to open a new device
@@ -284,7 +284,7 @@
LOG_ALWAYS_FATAL_IF(tempHandle != mPortHandle,
"%s() port handle not expected to change from %d to %d",
__func__, mPortHandle, tempHandle);
- ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
+ ALOGV("%s() mPortHandle = %d", __func__, mPortHandle);
return result;
}
@@ -299,26 +299,20 @@
mFramesTransferred.roundUp64(getBufferCapacity());
// Use the port handle that was provided by openMmapStream().
- ALOGV("%s(%p) mPortHandle = %d", __func__, stream.get(), mPortHandle);
+ ALOGV("%s() mPortHandle = %d", __func__, mPortHandle);
return stopClient(mPortHandle);
}
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- ALOGD("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
- audio_port_handle_t originalHandle = *clientHandle;
status_t status = mMmapStream->start(client, clientHandle);
- aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
- ALOGD("%s() , portHandle %d => %d, returns %d", __func__, originalHandle, *clientHandle, result);
- return result;
+ return AAudioConvert_androidToAAudioResult(status);
}
aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
- ALOGD("%s(portHandle = %d), called", __func__, clientHandle);
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
- ALOGD("%s(portHandle = %d), returns %d", __func__, clientHandle, result);
return result;
}
@@ -371,7 +365,7 @@
// TODO Do we really need a different volume for each channel?
// We get called with an array filled with a single value!
float volume = values[0];
- ALOGD("%s(%p) volume[0] = %f", __func__, this, volume);
+ ALOGD("%s() volume[0] = %f", __func__, volume);
std::lock_guard<std::mutex> lock(mLockStreams);
for(const auto& stream : mRegisteredStreams) {
stream->onVolumeChanged(volume);
@@ -379,7 +373,7 @@
};
void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
- ALOGD("%s(%p) called with dev %d, old = %d", __func__, this, deviceId, getDeviceId());
+ ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE && getDeviceId() != deviceId) {
disconnectRegisteredStreams();
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 1e1c552..bda4b90 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -43,7 +43,6 @@
AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService)
: mStreamInternalPlay(audioService, true) {
- ALOGD("%s(%p) created", __func__, this);
mStreamInternal = &mStreamInternalPlay;
}
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 14742dd..2ca847a 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -111,7 +111,7 @@
capacityInFrames, MAX_FRAMES_PER_BUFFER);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
- ALOGD("calculateBufferCapacity() requested %d frames, actual = %d",
+ ALOGV("calculateBufferCapacity() requested %d frames, actual = %d",
requestedCapacityFrames, capacityInFrames);
return capacityInFrames;
}
@@ -144,7 +144,7 @@
if (getFormat() == AUDIO_FORMAT_DEFAULT) {
setFormat(AUDIO_FORMAT_PCM_FLOAT);
} else if (getFormat() != AUDIO_FORMAT_PCM_FLOAT) {
- ALOGE("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat());
+ ALOGD("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat());
result = AAUDIO_ERROR_INVALID_FORMAT;
goto error;
}
@@ -153,7 +153,7 @@
if (getSampleRate() == AAUDIO_UNSPECIFIED) {
setSampleRate(endpoint->getSampleRate());
} else if (getSampleRate() != endpoint->getSampleRate()) {
- ALOGE("%s() mSampleRate = %d, need %d",
+ ALOGD("%s() mSampleRate = %d, need %d",
__func__, getSampleRate(), endpoint->getSampleRate());
result = AAUDIO_ERROR_INVALID_RATE;
goto error;
@@ -163,7 +163,7 @@
if (getSamplesPerFrame() == AAUDIO_UNSPECIFIED) {
setSamplesPerFrame(endpoint->getSamplesPerFrame());
} else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) {
- ALOGE("%s() mSamplesPerFrame = %d, need %d",
+ ALOGD("%s() mSamplesPerFrame = %d, need %d",
__func__, getSamplesPerFrame(), endpoint->getSamplesPerFrame());
result = AAUDIO_ERROR_OUT_OF_RANGE;
goto error;
@@ -190,9 +190,6 @@
}
}
- ALOGD("%s() actual rate = %d, channels = %d, deviceId = %d",
- __func__, getSampleRate(), getSamplesPerFrame(), endpoint->getDeviceId());
-
result = endpoint->registerStream(keep);
if (result != AAUDIO_OK) {
goto error;
@@ -227,7 +224,7 @@
{
std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
if (mAudioDataQueue == nullptr) {
- ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
+ ALOGW("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
}
// Gather information on the data queue.
@@ -262,7 +259,7 @@
int64_t position = 0;
sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
if (endpoint == nullptr) {
- ALOGE("%s() has no endpoint", __func__);
+ ALOGW("%s() has no endpoint", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}