Merge "Thread: Add ThreadBase_ThreadLoop capability" into main
diff --git a/camera/Android.bp b/camera/Android.bp
index e5ae954..7de8a62 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -101,6 +101,7 @@
],
shared_libs: [
+ "camera_platform_flags_c_lib",
"libbase",
"libcutils",
"libutils",
diff --git a/camera/CameraSessionStats.cpp b/camera/CameraSessionStats.cpp
index 36bf24c..f0630dd 100644
--- a/camera/CameraSessionStats.cpp
+++ b/camera/CameraSessionStats.cpp
@@ -16,6 +16,7 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "CameraSessionStats"
+
#include <utils/Log.h>
#include <utils/String16.h>
@@ -414,6 +415,12 @@
return err;
}
+ bool usedUltraWide = false;
+ if ((err = parcel->readBool(&usedUltraWide)) != OK) {
+ ALOGE("%s: Failed to read ultrawide usage from parcel", __FUNCTION__);
+ return err;
+ }
+
int32_t sessionIdx;
if ((err = parcel->readInt32(&sessionIdx)) != OK) {
ALOGE("%s: Failed to read session index from parcel", __FUNCTION__);
@@ -443,6 +450,7 @@
mStreamStats = std::move(streamStats);
mUserTag = toStdString(userTag);
mVideoStabilizationMode = videoStabilizationMode;
+ mUsedUltraWide = usedUltraWide;
mSessionIndex = sessionIdx;
mCameraExtensionSessionStats = extStats;
@@ -541,6 +549,10 @@
ALOGE("%s: Failed to write video stabilization mode!", __FUNCTION__);
return err;
}
+ if ((err = parcel->writeBool(mUsedUltraWide)) != OK) {
+ ALOGE("%s: Failed to write ultrawide usage!", __FUNCTION__);
+ return err;
+ }
if ((err = parcel->writeInt32(mSessionIndex)) != OK) {
ALOGE("%s: Failed to write session index!", __FUNCTION__);
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index 6200489..3d12983 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -2,15 +2,15 @@
flag {
namespace: "camera_platform"
- name: "initial_test_flag"
- description: "Flag infrastructure test flag"
- bug: "292631208"
+ name: "camera_hsum_permission"
+ description: "Camera access by headless system user"
+ bug: "273539631"
}
flag {
namespace: "camera_platform"
- name: "camera_hsum_permission"
- description: "Camera access by headless system user"
- bug: "273539631"
+ name: "log_ultrawide_usage"
+ description: "Enable measuring how much usage there is for ultrawide-angle cameras"
+ bug: "300515796"
}
diff --git a/camera/include/camera/CameraSessionStats.h b/camera/include/camera/CameraSessionStats.h
index 70ca0b3..158ac2a 100644
--- a/camera/include/camera/CameraSessionStats.h
+++ b/camera/include/camera/CameraSessionStats.h
@@ -161,6 +161,7 @@
std::vector<CameraStreamStats> mStreamStats;
std::string mUserTag;
int mVideoStabilizationMode;
+ bool mUsedUltraWide;
int mSessionIndex;
CameraExtensionSessionStats mCameraExtensionSessionStats;
diff --git a/camera/tests/fuzzer/Android.bp b/camera/tests/fuzzer/Android.bp
index bae8706..9aecba4 100644
--- a/camera/tests/fuzzer/Android.bp
+++ b/camera/tests/fuzzer/Android.bp
@@ -28,6 +28,7 @@
"libcamera_client",
],
shared_libs: [
+ "camera_platform_flags_c_lib",
"libbase",
"libcutils",
"libutils",
diff --git a/media/codec2/components/base/Android.bp b/media/codec2/components/base/Android.bp
index 664647a..4b189b4 100644
--- a/media/codec2/components/base/Android.bp
+++ b/media/codec2/components/base/Android.bp
@@ -42,6 +42,10 @@
"libnativewindow_headers",
],
+ static_libs: [
+ "libyuv_static", // for conversion routines
+ ],
+
shared_libs: [
"libcutils", // for properties
"liblog", // for ALOG
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index 55a1164..06a21f6 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -21,8 +21,10 @@
#include <android/hardware_buffer.h>
#include <cutils/properties.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
#include <inttypes.h>
+#include <libyuv.h>
#include <C2Config.h>
#include <C2Debug.h>
@@ -32,6 +34,15 @@
#include <SimpleC2Component.h>
namespace android {
+
+// libyuv version required for I410ToAB30Matrix and I210ToAB30Matrix.
+#if LIBYUV_VERSION >= 1780
+#include <algorithm>
+#define HAVE_LIBYUV_I410_I210_TO_AB30 1
+#else
+#define HAVE_LIBYUV_I410_I210_TO_AB30 0
+#endif
+
constexpr uint8_t kNeutralUVBitDepth8 = 128;
constexpr uint16_t kNeutralUVBitDepth10 = 512;
@@ -506,6 +517,120 @@
}
}
+void convertPlanar16ToY410OrRGBA1010102(uint8_t* dst, const uint16_t* srcY, const uint16_t* srcU,
+ const uint16_t* srcV, size_t srcYStride, size_t srcUStride,
+ size_t srcVStride, size_t dstStride, size_t width,
+ size_t height,
+ std::shared_ptr<const C2ColorAspectsStruct> aspects,
+ CONV_FORMAT_T format) {
+ bool processed = false;
+#if HAVE_LIBYUV_I410_I210_TO_AB30
+ if (format == CONV_FORMAT_I444) {
+ libyuv::I410ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dst,
+ dstStride, &libyuv::kYuvV2020Constants, width, height);
+ processed = true;
+ } else if (format == CONV_FORMAT_I422) {
+ libyuv::I210ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dst,
+ dstStride, &libyuv::kYuvV2020Constants, width, height);
+ processed = true;
+ }
+#endif // HAVE_LIBYUV_I410_I210_TO_AB30
+ if (!processed) {
+ convertYUV420Planar16ToY410OrRGBA1010102(
+ (uint32_t*)dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ dstStride / sizeof(uint32_t), width, height,
+ std::static_pointer_cast<const C2ColorAspectsStruct>(aspects));
+ }
+}
+
+void convertPlanar16ToP010(uint16_t* dstY, uint16_t* dstUV, const uint16_t* srcY,
+ const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUStride, size_t dstVStride, size_t width, size_t height,
+ bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
+ size_t tmpFrameBufferSize) {
+#if LIBYUV_VERSION >= 1779
+ if ((format == CONV_FORMAT_I444) || (format == CONV_FORMAT_I422)) {
+ // TODO(https://crbug.com/libyuv/952): replace this block with libyuv::I410ToP010
+ // and libyuv::I210ToP010 when they are available. Note it may be safe to alias dstY
+ // in I010ToP010, but the libyuv API doesn't make any guarantees.
+ const size_t tmpSize = dstYStride * height + dstUStride * align(height, 2);
+ CHECK(tmpSize <= tmpFrameBufferSize);
+
+ uint16_t* const tmpY = tmpFrameBuffer;
+ uint16_t* const tmpU = tmpY + dstYStride * height;
+ uint16_t* const tmpV = tmpU + dstUStride * align(height, 2) / 2;
+ if (format == CONV_FORMAT_I444) {
+ libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
+ dstYStride, tmpU, dstUStride, tmpV, dstUStride, width, height);
+ } else {
+ libyuv::I210ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
+ dstYStride, tmpU, dstUStride, tmpV, dstUStride, width, height);
+ }
+ libyuv::I010ToP010(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride, dstY, dstYStride,
+ dstUV, dstUStride, width, height);
+ } else {
+ convertYUV420Planar16ToP010(dstY, dstUV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUStride, width, height,
+ isMonochrome);
+ }
+#else // LIBYUV_VERSION < 1779
+ convertYUV420Planar16ToP010(dstY, dstUV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ dstYStride, dstUStride, width, height, isMonochrome);
+#endif // LIBYUV_VERSION >= 1779
+}
+
+void convertPlanar16ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint16_t* srcY,
+ const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUStride, size_t dstVStride, size_t width, size_t height,
+ bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
+ size_t tmpFrameBufferSize) {
+#if LIBYUV_VERSION >= 1779
+ if (format == CONV_FORMAT_I444) {
+ // TODO(https://crbug.com/libyuv/950): replace this block with libyuv::I410ToI420
+ // when it's available.
+ const size_t tmpSize = dstYStride * height + dstUStride * align(height, 2);
+ CHECK(tmpSize <= tmpFrameBufferSize);
+
+ uint16_t* const tmpY = tmpFrameBuffer;
+ uint16_t* const tmpU = tmpY + dstYStride * height;
+ uint16_t* const tmpV = tmpU + dstUStride * align(height, 2) / 2;
+ libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY, dstYStride,
+ tmpU, dstUStride, tmpV, dstVStride, width, height);
+ libyuv::I010ToI420(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride, dstY, dstYStride,
+ dstU, dstUStride, dstV, dstVStride, width, height);
+ } else if (format == CONV_FORMAT_I422) {
+ libyuv::I210ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
+ dstU, dstUStride, dstV, dstVStride, width, height);
+ } else {
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUStride, width, height,
+ isMonochrome);
+ }
+#else // LIBYUV_VERSION < 1779
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUStride, width, height, isMonochrome);
+#endif // LIBYUV_VERSION >= 1779
+}
+
+void convertPlanar8ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint8_t* srcY,
+ const uint8_t* srcU, const uint8_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUStride, size_t dstVStride, uint32_t width, uint32_t height,
+ bool isMonochrome, CONV_FORMAT_T format) {
+ if (format == CONV_FORMAT_I444) {
+ libyuv::I444ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
+ dstU, dstUStride, dstV, dstVStride, width, height);
+ } else if (format == CONV_FORMAT_I422) {
+ libyuv::I422ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY, dstYStride,
+ dstU, dstUStride, dstV, dstVStride, width, height);
+ } else {
+ convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUStride, dstVStride, width, height,
+ isMonochrome);
+ }
+}
std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
mQueue.pop_front();
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index bc27474..b28c47e 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -31,6 +31,12 @@
namespace android {
+typedef enum {
+ CONV_FORMAT_I420,
+ CONV_FORMAT_I422,
+ CONV_FORMAT_I444,
+} CONV_FORMAT_T;
+
void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
size_t srcUStride, size_t srcVStride, size_t dstYStride,
@@ -66,6 +72,30 @@
const uint32_t* srcRGBA, size_t srcRGBStride, size_t width,
size_t height, C2Color::matrix_t colorMatrix,
C2Color::range_t colorRange);
+void convertPlanar16ToY410OrRGBA1010102(uint8_t* dst, const uint16_t* srcY, const uint16_t* srcU,
+ const uint16_t* srcV, size_t srcYStride, size_t srcUStride,
+ size_t srcVStride, size_t dstStride, size_t width,
+ size_t height,
+ std::shared_ptr<const C2ColorAspectsStruct> aspects,
+ CONV_FORMAT_T format);
+
+void convertPlanar16ToP010(uint16_t* dstY, uint16_t* dstUV, const uint16_t* srcY,
+ const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUStride, size_t dstVStride, size_t width, size_t height,
+ bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
+ size_t tmpFrameBufferSize);
+void convertPlanar16ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint16_t* srcY,
+ const uint16_t* srcU, const uint16_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUStride, size_t dstVStride, size_t width, size_t height,
+ bool isMonochrome, CONV_FORMAT_T format, uint16_t* tmpFrameBuffer,
+ size_t tmpFrameBufferSize);
+void convertPlanar8ToYV12(uint8_t* dstY, uint8_t* dstU, uint8_t* dstV, const uint8_t* srcY,
+ const uint8_t* srcU, const uint8_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, size_t dstYStride,
+ size_t dstUStride, size_t dstVStride, uint32_t width, uint32_t height,
+ bool isMonochrome, CONV_FORMAT_T format);
class SimpleC2Component
: public C2Component, public std::enable_shared_from_this<SimpleC2Component> {
diff --git a/media/codec2/components/dav1d/Android.bp b/media/codec2/components/dav1d/Android.bp
index f7850ad..c9387dd 100644
--- a/media/codec2/components/dav1d/Android.bp
+++ b/media/codec2/components/dav1d/Android.bp
@@ -15,6 +15,7 @@
defaults: [
"libcodec2_soft-defaults",
"libcodec2_soft_sanitize_all-defaults",
+ "libcodec2_soft_sanitize_cfi-defaults",
],
cflags: [
@@ -22,9 +23,8 @@
"-Wno-unused-variable",
],
- srcs: ["C2SoftDav1dDec.cpp"],
+ srcs: ["C2SoftDav1dDec.cpp", "C2SoftDav1dDump.cpp"],
static_libs: [
- "libyuv_static",
"libdav1d_8bit",
"libdav1d_16bit",
],
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
index b0cef41..3f96cb3 100644
--- a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
+++ b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
@@ -26,30 +26,13 @@
#include <Codec2CommonUtils.h>
#include <Codec2Mapper.h>
#include <SimpleC2Interface.h>
-#include <libyuv.h>
#include <log/log.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include "C2SoftDav1dDec.h"
-// libyuv version required for I410ToAB30Matrix and I210ToAB30Matrix.
-#if LIBYUV_VERSION >= 1780
-#include <algorithm>
-#define HAVE_LIBYUV_I410_I210_TO_AB30 1
-#else
-#define HAVE_LIBYUV_I410_I210_TO_AB30 0
-#endif
-
namespace android {
-// Flag to enable dumping the bitsteram and the decoded pictures to files.
-static const bool ENABLE_DUMPING_FILES_DEFAULT = false;
-static const char ENABLE_DUMPING_FILES_PROPERTY[] = "debug.dav1d.enabledumping";
-
-// The number of frames to dump to a file
-static const int NUM_FRAMES_TO_DUMP_DEFAULT = INT_MAX;
-static const char NUM_FRAMES_TO_DUMP_PROPERTY[] = "debug.dav1d.numframestodump";
-
// The number of threads used for the dav1d decoder.
static const int NUM_THREADS_DAV1D_DEFAULT = 0;
static const char NUM_THREADS_DAV1D_PROPERTY[] = "debug.dav1d.numthreads";
@@ -522,37 +505,8 @@
}
bool C2SoftDav1dDec::initDecoder() {
- nsecs_t now = systemTime();
#ifdef FILE_DUMP_ENABLE
- snprintf(mInDataFileName, 256, "%s_%" PRId64 "d.%s", DUMP_FILE_PATH, now, INPUT_DATA_DUMP_EXT);
- snprintf(mInSizeFileName, 256, "%s_%" PRId64 "d.%s", DUMP_FILE_PATH, now, INPUT_SIZE_DUMP_EXT);
- snprintf(mDav1dOutYuvFileName, 256, "%s_%" PRId64 "dx.%s", DUMP_FILE_PATH, now,
- OUTPUT_YUV_DUMP_EXT);
-
- bool enableDumping = android::base::GetBoolProperty(ENABLE_DUMPING_FILES_PROPERTY,
- ENABLE_DUMPING_FILES_DEFAULT);
-
- num_frames_to_dump =
- android::base::GetIntProperty(NUM_FRAMES_TO_DUMP_PROPERTY, NUM_FRAMES_TO_DUMP_DEFAULT);
-
- if (enableDumping) {
- ALOGD("enableDumping = %d, num_frames_to_dump = %d", enableDumping, num_frames_to_dump);
-
- mInDataFile = fopen(mInDataFileName, "wb");
- if (mInDataFile == nullptr) {
- ALOGD("Could not open file %s", mInDataFileName);
- }
-
- mInSizeFile = fopen(mInSizeFileName, "wb");
- if (mInSizeFile == nullptr) {
- ALOGD("Could not open file %s", mInSizeFileName);
- }
-
- mDav1dOutYuvFile = fopen(mDav1dOutYuvFileName, "wb");
- if (mDav1dOutYuvFile == nullptr) {
- ALOGD("Could not open file %s", mDav1dOutYuvFileName);
- }
- }
+ mC2SoftDav1dDump.initDumping();
#endif
mSignalledError = false;
mSignalledOutputEos = false;
@@ -601,20 +555,7 @@
mInputBufferIndex = 0;
}
#ifdef FILE_DUMP_ENABLE
- if (mInDataFile != nullptr) {
- fclose(mInDataFile);
- mInDataFile = nullptr;
- }
-
- if (mInSizeFile != nullptr) {
- fclose(mInSizeFile);
- mInSizeFile = nullptr;
- }
-
- if (mDav1dOutYuvFile != nullptr) {
- fclose(mDav1dOutYuvFile);
- mDav1dOutYuvFile = nullptr;
- }
+ mC2SoftDav1dDump.destroyDumping();
#endif
}
@@ -657,6 +598,10 @@
}
}
+static void freeCallback(const uint8_t */*data*/, void */*cookie*/) {
+ return;
+}
+
void C2SoftDav1dDec::process(const std::unique_ptr<C2Work>& work,
const std::shared_ptr<C2BlockPool>& pool) {
work->result = C2_OK;
@@ -709,65 +654,24 @@
seq.max_height, (long)in_frameIndex);
}
- // insert OBU TD if it is not present.
- // TODO: b/286852962
- uint8_t obu_type = (bitstream[0] >> 3) & 0xf;
Dav1dData data;
- uint8_t* ptr = (obu_type == DAV1D_OBU_TD) ? dav1d_data_create(&data, inSize)
- : dav1d_data_create(&data, inSize + 2);
- if (ptr == nullptr) {
- ALOGE("dav1d_data_create failed!");
+ res = dav1d_data_wrap(&data, bitstream, inSize, freeCallback, nullptr);
+ if (res != 0) {
+ ALOGE("Decoder wrap error %s!", strerror(DAV1D_ERR(res)));
i_ret = -1;
-
} else {
data.m.timestamp = in_frameIndex;
+ // ALOGV("inSize=%ld, in_frameIndex=%ld, timestamp=%ld",
+ // inSize, frameIndex, data.m.timestamp);
- int new_Size;
- if (obu_type != DAV1D_OBU_TD) {
- new_Size = (int)(inSize + 2);
-
- // OBU TD
- ptr[0] = 0x12;
- ptr[1] = 0;
-
- memcpy(ptr + 2, bitstream, inSize);
- } else {
- new_Size = (int)(inSize);
- // TODO: b/277797541 - investigate how to wrap this pointer in Dav1dData to
- // avoid memcopy operations.
- memcpy(ptr, bitstream, new_Size);
- }
-
- // ALOGV("memcpy(ptr,bitstream,inSize=%ld,new_Size=%d,in_frameIndex=%ld,timestamp=%ld,"
- // "ptr[0,1,2,3,4]=%x,%x,%x,%x,%x)",
- // inSize, new_Size, frameIndex, data.m.timestamp, ptr[0], ptr[1], ptr[2],
- // ptr[3], ptr[4]);
// Dump the bitstream data (inputBuffer) if dumping is enabled.
#ifdef FILE_DUMP_ENABLE
- if (mInDataFile) {
- int ret = fwrite(ptr, 1, new_Size, mInDataFile);
-
- if (ret != new_Size) {
- ALOGE("Error in fwrite %s, requested %d, returned %d", mInDataFileName,
- new_Size, ret);
- }
- }
-
- // Dump the size per inputBuffer if dumping is enabled.
- if (mInSizeFile) {
- int ret = fwrite(&new_Size, 1, 4, mInSizeFile);
-
- if (ret != 4) {
- ALOGE("Error in fwrite %s, requested %d, returned %d", mInSizeFileName, 4,
- ret);
- }
- }
+ mC2SoftDav1dDump.dumpInput(ptr, new_Size);
#endif
bool b_draining = false;
- int res;
do {
res = dav1d_send_data(mDav1dCtx, &data);
@@ -1010,49 +914,6 @@
return true;
}
-#ifdef FILE_DUMP_ENABLE
-void C2SoftDav1dDec::writeDav1dOutYuvFile(const Dav1dPicture& p) {
- if (mDav1dOutYuvFile != NULL) {
- uint8_t* ptr;
- const int hbd = p.p.bpc > 8;
-
- ptr = (uint8_t*)p.data[0];
- for (int y = 0; y < p.p.h; y++) {
- int iSize = p.p.w << hbd;
- int ret = fwrite(ptr, 1, iSize, mDav1dOutYuvFile);
- if (ret != iSize) {
- ALOGE("Error in fwrite %s, requested %d, returned %d", mDav1dOutYuvFileName, iSize,
- ret);
- break;
- }
-
- ptr += p.stride[0];
- }
-
- if (p.p.layout != DAV1D_PIXEL_LAYOUT_I400) {
- // u/v
- const int ss_ver = p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
- const int ss_hor = p.p.layout != DAV1D_PIXEL_LAYOUT_I444;
- const int cw = (p.p.w + ss_hor) >> ss_hor;
- const int ch = (p.p.h + ss_ver) >> ss_ver;
- for (int pl = 1; pl <= 2; pl++) {
- ptr = (uint8_t*)p.data[pl];
- for (int y = 0; y < ch; y++) {
- int iSize = cw << hbd;
- int ret = fwrite(ptr, 1, cw << hbd, mDav1dOutYuvFile);
- if (ret != iSize) {
- ALOGE("Error in fwrite %s, requested %d, returned %d", mDav1dOutYuvFileName,
- iSize, ret);
- break;
- }
- ptr += p.stride[1];
- }
- }
- }
- }
-}
-#endif
-
bool C2SoftDav1dDec::outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
const std::unique_ptr<C2Work>& work) {
if (!(work && pool)) return false;
@@ -1114,16 +975,6 @@
// out_frameIndex that the decoded picture returns from dav1d.
int64_t out_frameIndex = img.m.timestamp;
-#if LIBYUV_VERSION < 1779
- if (!(img.p.layout != DAV1D_PIXEL_LAYOUT_I400 || img.p.layout != DAV1D_PIXEL_LAYOUT_I420)) {
- ALOGE("image_format %d not supported", img.p.layout);
- mSignalledError = true;
- work->workletsProcessed = 1u;
- work->result = C2_CORRUPTED;
- return false;
- }
-#endif
-
const bool isMonochrome = img.p.layout == DAV1D_PIXEL_LAYOUT_I400;
int bitdepth = img.p.bpc;
@@ -1141,17 +992,6 @@
allowRGBA1010102 = true;
}
format = getHalPixelFormatForBitDepth10(allowRGBA1010102);
-#if !HAVE_LIBYUV_I410_I210_TO_AB30
- if ((format == HAL_PIXEL_FORMAT_RGBA_1010102) &&
- (is_img_ready ? img.p.layout == DAV1D_PIXEL_LAYOUT_I420
- : buffer->image_format != libgav1::kImageFormatYuv420)) {
- ALOGE("Only YUV420 output is supported when targeting RGBA_1010102");
- mSignalledError = true;
- work->result = C2_OMITTED;
- work->workletsProcessed = 1u;
- return false;
- }
-#endif
}
if (mHalPixelFormat != format) {
@@ -1206,6 +1046,19 @@
size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
+ CONV_FORMAT_T convFormat;
+ switch (img.p.layout) {
+ case DAV1D_PIXEL_LAYOUT_I444:
+ convFormat = CONV_FORMAT_I444;
+ break;
+ case DAV1D_PIXEL_LAYOUT_I422:
+ convFormat = CONV_FORMAT_I422;
+ break;
+ default:
+ convFormat = CONV_FORMAT_I420;
+ break;
+ }
+
if (bitdepth == 10) {
// TODO: b/277797541 - Investigate if we can ask DAV1D to output the required format during
// decompression to avoid color conversion.
@@ -1217,146 +1070,67 @@
size_t srcVStride = img.stride[1] / 2;
if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
- bool processed = false;
-#if HAVE_LIBYUV_I410_I210_TO_AB30
- if (img.p.layout == DAV1D_PIXEL_LAYOUT_I444) {
- libyuv::I410ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY,
- dstYStride, &libyuv::kYuvV2020Constants, mWidth, mHeight);
- processed = true;
- } else if (img.p.layout == DAV1D_PIXEL_LAYOUT_I422) {
- libyuv::I210ToAB30Matrix(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY,
- dstYStride, &libyuv::kYuvV2020Constants, mWidth, mHeight);
- processed = true;
- }
-#endif // HAVE_LIBYUV_I410_I210_TO_AB30
- if (!processed) {
- if (isMonochrome) {
- const size_t tmpSize = mWidth;
- const bool needFill = tmpSize > mTmpFrameBufferSize;
- if (!allocTmpFrameBuffer(tmpSize)) {
- ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
- setError(work, C2_NO_MEMORY);
- return false;
- }
- srcU = srcV = mTmpFrameBuffer.get();
- srcUStride = srcVStride = 0;
- if (needFill) {
- std::fill_n(mTmpFrameBuffer.get(), tmpSize, 512);
- }
+ if (isMonochrome) {
+ const size_t tmpSize = mWidth;
+ const bool needFill = tmpSize > mTmpFrameBufferSize;
+ if (!allocTmpFrameBuffer(tmpSize)) {
+ ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
+ setError(work, C2_NO_MEMORY);
+ return false;
}
- convertYUV420Planar16ToY410OrRGBA1010102(
- (uint32_t*)dstY, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
- dstYStride / sizeof(uint32_t), mWidth, mHeight,
- std::static_pointer_cast<const C2ColorAspectsStruct>(codedColorAspects));
+ srcU = srcV = mTmpFrameBuffer.get();
+ srcUStride = srcVStride = 0;
+ if (needFill) {
+ std::fill_n(mTmpFrameBuffer.get(), tmpSize, 512);
+ }
}
+ convertPlanar16ToY410OrRGBA1010102(
+ dstY, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ dstYStride, mWidth, mHeight,
+ std::static_pointer_cast<const C2ColorAspectsStruct>(codedColorAspects),
+ convFormat);
} else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
dstYStride /= 2;
dstUStride /= 2;
dstVStride /= 2;
-#if LIBYUV_VERSION >= 1779
+ size_t tmpSize = 0;
if ((img.p.layout == DAV1D_PIXEL_LAYOUT_I444) ||
(img.p.layout == DAV1D_PIXEL_LAYOUT_I422)) {
- // TODO(https://crbug.com/libyuv/952): replace this block with libyuv::I410ToP010
- // and libyuv::I210ToP010 when they are available. Note it may be safe to alias dstY
- // in I010ToP010, but the libyuv API doesn't make any guarantees.
- const size_t tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
+ tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
if (!allocTmpFrameBuffer(tmpSize)) {
ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
setError(work, C2_NO_MEMORY);
return false;
}
- uint16_t* const tmpY = mTmpFrameBuffer.get();
- uint16_t* const tmpU = tmpY + dstYStride * mHeight;
- uint16_t* const tmpV = tmpU + dstUStride * align(mHeight, 2) / 2;
- if (img.p.layout == DAV1D_PIXEL_LAYOUT_I444) {
- libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
- dstYStride, tmpU, dstUStride, tmpV, dstUStride, mWidth,
- mHeight);
- } else {
- libyuv::I210ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
- dstYStride, tmpU, dstUStride, tmpV, dstUStride, mWidth,
- mHeight);
- }
- libyuv::I010ToP010(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride,
- (uint16_t*)dstY, dstYStride, (uint16_t*)dstU, dstUStride, mWidth,
- mHeight);
- } else {
- convertYUV420Planar16ToP010((uint16_t*)dstY, (uint16_t*)dstU, srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride, dstYStride,
- dstUStride, mWidth, mHeight, isMonochrome);
}
-#else // LIBYUV_VERSION < 1779
- convertYUV420Planar16ToP010((uint16_t*)dstY, (uint16_t*)dstU, srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride, dstYStride, dstUStride,
- mWidth, mHeight, isMonochrome);
-#endif // LIBYUV_VERSION >= 1779
+ convertPlanar16ToP010((uint16_t*)dstY, (uint16_t*)dstU, srcY, srcU, srcV, srcYStride,
+ srcUStride, srcVStride, dstYStride, dstUStride, dstVStride,
+ mWidth, mHeight, isMonochrome, convFormat, mTmpFrameBuffer.get(),
+ tmpSize);
} else {
-#if LIBYUV_VERSION >= 1779
+ size_t tmpSize = 0;
if (img.p.layout == DAV1D_PIXEL_LAYOUT_I444) {
- // TODO(https://crbug.com/libyuv/950): replace this block with libyuv::I410ToI420
- // when it's available.
- const size_t tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
+ tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
if (!allocTmpFrameBuffer(tmpSize)) {
ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
setError(work, C2_NO_MEMORY);
return false;
}
- uint16_t* const tmpY = mTmpFrameBuffer.get();
- uint16_t* const tmpU = tmpY + dstYStride * mHeight;
- uint16_t* const tmpV = tmpU + dstUStride * align(mHeight, 2) / 2;
- libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, tmpY,
- dstYStride, tmpU, dstUStride, tmpV, dstVStride, mWidth, mHeight);
- libyuv::I010ToI420(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride, dstY,
- dstYStride, dstU, dstUStride, dstV, dstVStride, mWidth, mHeight);
- } else if (img.p.layout == DAV1D_PIXEL_LAYOUT_I422) {
- libyuv::I210ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY,
- dstYStride, dstU, dstUStride, dstV, dstVStride, mWidth, mHeight);
- } else {
- convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride,
- srcUStride, srcVStride, dstYStride, dstUStride, mWidth,
- mHeight, isMonochrome);
}
-#else // LIBYUV_VERSION < 1779
- convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUStride, mWidth, mHeight,
- isMonochrome);
-#endif // LIBYUV_VERSION >= 1779
+ convertPlanar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUStride, dstVStride, mWidth, mHeight,
+ isMonochrome, convFormat, mTmpFrameBuffer.get(), tmpSize);
}
- // Dump the output buffer if dumping is enabled (debug only).
-#ifdef FILE_DUMP_ENABLE
- FILE* fp_out = mDav1dOutYuvFile;
-
// if(mOutputBufferIndex % 100 == 0)
ALOGV("output a 10bit picture %dx%d from dav1d "
"(mInputBufferIndex=%d,mOutputBufferIndex=%d,format=%d).",
mWidth, mHeight, mInputBufferIndex, mOutputBufferIndex, format);
- if (fp_out && mOutputBufferIndex <= num_frames_to_dump) {
- for (int i = 0; i < mHeight; i++) {
- int ret = fwrite((uint8_t*)srcY + i * srcYStride * 2, 1, mWidth * 2, fp_out);
- if (ret != mWidth * 2) {
- ALOGE("Error in fwrite, requested %d, returned %d", mWidth * 2, ret);
- break;
- }
- }
-
- for (int i = 0; i < mHeight / 2; i++) {
- int ret = fwrite((uint8_t*)srcU + i * srcUStride * 2, 1, mWidth, fp_out);
- if (ret != mWidth) {
- ALOGE("Error in fwrite, requested %d, returned %d", mWidth, ret);
- break;
- }
- }
-
- for (int i = 0; i < mHeight / 2; i++) {
- int ret = fwrite((uint8_t*)srcV + i * srcVStride * 2, 1, mWidth, fp_out);
- if (ret != mWidth) {
- ALOGE("Error in fwrite, requested %d, returned %d", mWidth, ret);
- break;
- }
- }
- }
+ // Dump the output buffer if dumping is enabled (debug only).
+#ifdef FILE_DUMP_ENABLE
+ mC2SoftDav1dDump.dumpOutput<uint16_t>(srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ mWidth, mHeight);
#endif
} else {
const uint8_t* srcY = (const uint8_t*)img.data[0];
@@ -1367,51 +1141,19 @@
size_t srcUStride = img.stride[1];
size_t srcVStride = img.stride[1];
- // Dump the output buffer is dumping is enabled (debug only)
-#ifdef FILE_DUMP_ENABLE
- FILE* fp_out = mDav1dOutYuvFile;
// if(mOutputBufferIndex % 100 == 0)
ALOGV("output a 8bit picture %dx%d from dav1d "
"(mInputBufferIndex=%d,mOutputBufferIndex=%d,format=%d).",
mWidth, mHeight, mInputBufferIndex, mOutputBufferIndex, format);
- if (fp_out && mOutputBufferIndex <= num_frames_to_dump) {
- for (int i = 0; i < mHeight; i++) {
- int ret = fwrite((uint8_t*)srcY + i * srcYStride, 1, mWidth, fp_out);
- if (ret != mWidth) {
- ALOGE("Error in fwrite, requested %d, returned %d", mWidth, ret);
- break;
- }
- }
-
- for (int i = 0; i < mHeight / 2; i++) {
- int ret = fwrite((uint8_t*)srcU + i * srcUStride, 1, mWidth / 2, fp_out);
- if (ret != mWidth / 2) {
- ALOGE("Error in fwrite, requested %d, returned %d", mWidth / 2, ret);
- break;
- }
- }
-
- for (int i = 0; i < mHeight / 2; i++) {
- int ret = fwrite((uint8_t*)srcV + i * srcVStride, 1, mWidth / 2, fp_out);
- if (ret != mWidth / 2) {
- ALOGE("Error in fwrite, requested %d, returned %d", mWidth / 2, ret);
- break;
- }
- }
- }
+ // Dump the output buffer is dumping is enabled (debug only)
+#ifdef FILE_DUMP_ENABLE
+ mC2SoftDav1dDump.dumpOutput<uint8_t>(srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ mWidth, mHeight);
#endif
- if (img.p.layout == DAV1D_PIXEL_LAYOUT_I444) {
- libyuv::I444ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY,
- dstYStride, dstU, dstUStride, dstV, dstVStride, mWidth, mHeight);
- } else if (img.p.layout == DAV1D_PIXEL_LAYOUT_I422) {
- libyuv::I422ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride, dstY,
- dstYStride, dstU, dstUStride, dstV, dstVStride, mWidth, mHeight);
- } else {
- convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUStride, dstVStride, mWidth,
- mHeight, isMonochrome);
- }
+ convertPlanar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ dstYStride, dstUStride, dstVStride, mWidth, mHeight, isMonochrome,
+ convFormat);
}
dav1d_picture_unref(&img);
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.h b/media/codec2/components/dav1d/C2SoftDav1dDec.h
index 5201456..e3d2a93 100644
--- a/media/codec2/components/dav1d/C2SoftDav1dDec.h
+++ b/media/codec2/components/dav1d/C2SoftDav1dDec.h
@@ -28,12 +28,9 @@
#include <dav1d/dav1d.h>
#include <deque>
+#include <C2SoftDav1dDump.h>
//#define FILE_DUMP_ENABLE 1
-#define DUMP_FILE_PATH "/data/local/tmp/dump"
-#define INPUT_DATA_DUMP_EXT "av1"
-#define INPUT_SIZE_DUMP_EXT "size"
-#define OUTPUT_YUV_DUMP_EXT "yuv"
namespace android {
@@ -122,17 +119,7 @@
void flushDav1d();
#ifdef FILE_DUMP_ENABLE
- char mInDataFileName[256];
- char mInSizeFileName[256];
- char mDav1dOutYuvFileName[256];
-
- FILE* mInDataFile = nullptr;
- FILE* mInSizeFile = nullptr;
- FILE* mDav1dOutYuvFile = nullptr;
-
- void writeDav1dOutYuvFile(const Dav1dPicture& p);
-
- int num_frames_to_dump = 0;
+ C2SoftDav1dDump mC2SoftDav1dDump;
#endif
C2_DO_NOT_COPY(C2SoftDav1dDec);
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDump.cpp b/media/codec2/components/dav1d/C2SoftDav1dDump.cpp
new file mode 100644
index 0000000..ec8d6cd
--- /dev/null
+++ b/media/codec2/components/dav1d/C2SoftDav1dDump.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2023 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 "C2SoftDav1dDump"
+#include "C2SoftDav1dDump.h"
+
+namespace android {
+
+// Flag to enable dumping the bitsteram and the decoded pictures to files.
+static const bool ENABLE_DUMPING_FILES_DEFAULT = true;
+static const char ENABLE_DUMPING_FILES_PROPERTY[] = "debug.dav1d.enabledumping";
+
+// The number of frames to dump to a file
+static const int NUM_FRAMES_TO_DUMP_DEFAULT = INT_MAX;
+static const char NUM_FRAMES_TO_DUMP_PROPERTY[] = "debug.dav1d.numframestodump";
+
+// start dumping from this frame
+static const int STARTING_FRAME_TO_DUMP_DEFAULT = 0;
+static const char STARTING_FRAME_TO_DUMP_PROPERTY[] = "debug.dav1d.startingframetodump";
+
+void C2SoftDav1dDump::initDumping() {
+ nsecs_t now = systemTime();
+ snprintf(mInDataFileName, kFileNameLength, "%s_%" PRId64 "d.%s", DUMP_FILE_PATH, now,
+ INPUT_DATA_DUMP_EXT);
+ snprintf(mInSizeFileName, kFileNameLength, "%s_%" PRId64 "d.%s", DUMP_FILE_PATH, now,
+ INPUT_SIZE_DUMP_EXT);
+ snprintf(mDav1dOutYuvFileName, kFileNameLength, "%s_%" PRId64 "dx.%s", DUMP_FILE_PATH, now,
+ OUTPUT_YUV_DUMP_EXT);
+
+ mFramesToDump =
+ android::base::GetIntProperty(NUM_FRAMES_TO_DUMP_PROPERTY, NUM_FRAMES_TO_DUMP_DEFAULT);
+ mFirstFrameToDump = android::base::GetIntProperty(STARTING_FRAME_TO_DUMP_PROPERTY,
+ STARTING_FRAME_TO_DUMP_DEFAULT);
+ bool enableDumping = android::base::GetBoolProperty(ENABLE_DUMPING_FILES_PROPERTY,
+ ENABLE_DUMPING_FILES_DEFAULT);
+ ALOGD("enableDumping = %d, mFramesToDump = %d", enableDumping, mFramesToDump);
+
+ if (enableDumping) {
+ mInDataFile = fopen(mInDataFileName, "wb");
+ if (mInDataFile == nullptr) {
+ ALOGD("Could not open file %s", mInDataFileName);
+ }
+
+ mInSizeFile = fopen(mInSizeFileName, "wb");
+ if (mInSizeFile == nullptr) {
+ ALOGD("Could not open file %s", mInSizeFileName);
+ }
+
+ mDav1dOutYuvFile = fopen(mDav1dOutYuvFileName, "wb");
+ if (mDav1dOutYuvFile == nullptr) {
+ ALOGD("Could not open file %s", mDav1dOutYuvFileName);
+ }
+ }
+}
+
+void C2SoftDav1dDump::destroyDumping() {
+ if (mInDataFile != nullptr) {
+ fclose(mInDataFile);
+ mInDataFile = nullptr;
+ }
+
+ if (mInSizeFile != nullptr) {
+ fclose(mInSizeFile);
+ mInSizeFile = nullptr;
+ }
+
+ if (mDav1dOutYuvFile != nullptr) {
+ fclose(mDav1dOutYuvFile);
+ mDav1dOutYuvFile = nullptr;
+ }
+}
+
+void C2SoftDav1dDump::dumpInput(uint8_t* ptr, int size) {
+ if (mInDataFile) {
+ int ret = fwrite(ptr, 1, size, mInDataFile);
+
+ if (ret != size) {
+ ALOGE("Error in fwrite %s, requested %d, returned %d", mInDataFileName, size, ret);
+ }
+ }
+
+ // Dump the size per inputBuffer if dumping is enabled.
+ if (mInSizeFile) {
+ int ret = fwrite(&size, 1, 4, mInSizeFile);
+
+ if (ret != 4) {
+ ALOGE("Error in fwrite %s, requested %d, returned %d", mInSizeFileName, 4, ret);
+ }
+ }
+}
+
+template <typename T>
+void C2SoftDav1dDump::dumpOutput(const T* srcY, const T* srcU, const T* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, int width, int height) {
+ mOutputCount++;
+ FILE* fp_out = mDav1dOutYuvFile;
+ int typeSize = sizeof(T);
+ if (fp_out && mOutputCount >= mFirstFrameToDump &&
+ mOutputCount <= (mFirstFrameToDump + mFramesToDump - 1)) {
+ for (int i = 0; i < height; i++) {
+ int ret =
+ fwrite((uint8_t*)srcY + i * srcYStride * typeSize, 1, width * typeSize, fp_out);
+ if (ret != width * typeSize) {
+ ALOGE("Error in fwrite, requested %d, returned %d", width * typeSize, ret);
+ break;
+ }
+ }
+
+ for (int i = 0; i < height / 2; i++) {
+ int ret = fwrite((uint8_t*)srcU + i * srcUStride * typeSize, 1, width * typeSize / 2,
+ fp_out);
+ if (ret != width * typeSize / 2) {
+ ALOGE("Error in fwrite, requested %d, returned %d", width * typeSize / 2, ret);
+ break;
+ }
+ }
+
+ for (int i = 0; i < height / 2; i++) {
+ int ret = fwrite((uint8_t*)srcV + i * srcVStride * typeSize, 1, width * typeSize / 2,
+ fp_out);
+ if (ret != width * typeSize / 2) {
+ ALOGE("Error in fwrite, requested %d, returned %d", width * typeSize / 2, ret);
+ break;
+ }
+ }
+ }
+}
+
+void C2SoftDav1dDump::writeDav1dOutYuvFile(const Dav1dPicture& p) {
+ if (mDav1dOutYuvFile != NULL) {
+ uint8_t* ptr;
+ const int hbd = p.p.bpc > 8;
+
+ ptr = (uint8_t*)p.data[0];
+ for (int y = 0; y < p.p.h; y++) {
+ int iSize = p.p.w << hbd;
+ int ret = fwrite(ptr, 1, iSize, mDav1dOutYuvFile);
+ if (ret != iSize) {
+ ALOGE("Error in fwrite %s, requested %d, returned %d", mDav1dOutYuvFileName, iSize,
+ ret);
+ break;
+ }
+
+ ptr += p.stride[0];
+ }
+
+ if (p.p.layout != DAV1D_PIXEL_LAYOUT_I400) {
+ // u/v
+ const int ss_ver = p.p.layout == DAV1D_PIXEL_LAYOUT_I420;
+ const int ss_hor = p.p.layout != DAV1D_PIXEL_LAYOUT_I444;
+ const int cw = (p.p.w + ss_hor) >> ss_hor;
+ const int ch = (p.p.h + ss_ver) >> ss_ver;
+ for (int pl = 1; pl <= 2; pl++) {
+ ptr = (uint8_t*)p.data[pl];
+ for (int y = 0; y < ch; y++) {
+ int iSize = cw << hbd;
+ int ret = fwrite(ptr, 1, cw << hbd, mDav1dOutYuvFile);
+ if (ret != iSize) {
+ ALOGE("Error in fwrite %s, requested %d, returned %d", mDav1dOutYuvFileName,
+ iSize, ret);
+ break;
+ }
+ ptr += p.stride[1];
+ }
+ }
+ }
+ }
+}
+
+template void C2SoftDav1dDump::dumpOutput<uint8_t>(const uint8_t* srcY, const uint8_t* srcU,
+ const uint8_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, int width,
+ int height);
+template void C2SoftDav1dDump::dumpOutput<uint16_t>(const uint16_t* srcY, const uint16_t* srcU,
+ const uint16_t* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, int width,
+ int height);
+} // namespace android
\ No newline at end of file
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDump.h b/media/codec2/components/dav1d/C2SoftDav1dDump.h
new file mode 100644
index 0000000..ea7a48a
--- /dev/null
+++ b/media/codec2/components/dav1d/C2SoftDav1dDump.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 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 <android-base/properties.h>
+#include <Codec2CommonUtils.h>
+#include <Codec2Mapper.h>
+#include <dav1d/dav1d.h>
+
+#define DUMP_FILE_PATH "/data/local/tmp/dump"
+#define INPUT_DATA_DUMP_EXT "av1"
+#define INPUT_SIZE_DUMP_EXT "size"
+#define OUTPUT_YUV_DUMP_EXT "yuv"
+
+namespace android {
+constexpr size_t kFileNameLength = 256;
+
+class C2SoftDav1dDump {
+ public:
+ void initDumping();
+ void destroyDumping();
+ void dumpInput(uint8_t* ptr, int new_size);
+ template <typename T>
+ void dumpOutput(const T* srcY, const T* srcU, const T* srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride, int width, int height);
+ void writeDav1dOutYuvFile(const Dav1dPicture& p);
+
+ private:
+ int mFramesToDump = 0;
+ int mFirstFrameToDump = 0;
+ int mOutputCount = 0;
+
+ char mInDataFileName[kFileNameLength];
+ char mInSizeFileName[kFileNameLength];
+ char mDav1dOutYuvFileName[kFileNameLength];
+
+ FILE* mInDataFile = nullptr;
+ FILE* mInSizeFile = nullptr;
+ FILE* mDav1dOutYuvFile = nullptr;
+};
+} // namespace android
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index b680931..e7dd7c2 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -1954,7 +1954,8 @@
std::shared_ptr<Codec2Client::Configurable>* configurable) {
if (mAidlBase) {
c2_aidl::IComponent::BlockPool aidlBlockPool;
- ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(id, &aidlBlockPool);
+ ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(static_cast<int32_t>(id),
+ &aidlBlockPool);
c2_status_t status = GetC2Status(transStatus, "createBlockPool");
if (status != C2_OK) {
return status;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 2bf11ba..490f957 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -2175,8 +2175,15 @@
if (notifyClient && !buffer && !flags) {
if (mTunneled && drop && outputFormat) {
- ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
- mName, work->input.ordinal.frameIndex.peekull());
+ if (mOutputFormat != outputFormat) {
+ ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
+ mName, work->input.ordinal.frameIndex.peekull());
+ mOutputFormat = outputFormat;
+ } else {
+ ALOGV("[%s] onWorkDone: Not reporting output buffer without format change (%lld)",
+ mName, work->input.ordinal.frameIndex.peekull());
+ notifyClient = false;
+ }
} else {
ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
mName, work->input.ordinal.frameIndex.peekull());
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 2bdb7bc..6800107 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -303,6 +303,7 @@
std::shared_ptr<C2BlockPool> mInputAllocator;
QueueSync mQueueSync;
std::vector<std::unique_ptr<C2Param>> mParamsToBeSet;
+ sp<AMessage> mOutputFormat;
struct Input {
Input();
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index aecbba7..196b432 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -255,37 +255,37 @@
status_t EffectConversionHelperAidl::handleReset(uint32_t cmdSize __unused,
const void* pCmdData __unused, uint32_t* replySize,
void* pReplyData) {
- if (!replySize || !pReplyData) {
+ if (!replySize || *replySize != sizeof(int) || !pReplyData) {
ALOGE("%s parameter invalid, replySize %s pReplyData %p", __func__,
numericPointerToString(replySize).c_str(), pReplyData);
return BAD_VALUE;
}
- return statusTFromBinderStatus(mEffect->command(CommandId::RESET));
+ return *(int *)pReplyData = statusTFromBinderStatus(mEffect->command(CommandId::RESET));
}
status_t EffectConversionHelperAidl::handleEnable(uint32_t cmdSize __unused,
const void* pCmdData __unused,
uint32_t* replySize, void* pReplyData) {
- if (!replySize || !pReplyData) {
+ if (!replySize || *replySize != sizeof(int) || !pReplyData) {
ALOGE("%s parameter invalid, replySize %s pReplyData %p", __func__,
numericPointerToString(replySize).c_str(), pReplyData);
return BAD_VALUE;
}
- return statusTFromBinderStatus(mEffect->command(CommandId::START));
+ return *(int *)pReplyData = statusTFromBinderStatus(mEffect->command(CommandId::START));
}
status_t EffectConversionHelperAidl::handleDisable(uint32_t cmdSize __unused,
const void* pCmdData __unused,
uint32_t* replySize, void* pReplyData) {
- if (!replySize || !pReplyData) {
+ if (!replySize || *replySize != sizeof(int) || !pReplyData) {
ALOGE("%s parameter invalid, replySize %s pReplyData %p", __func__,
numericPointerToString(replySize).c_str(), pReplyData);
return BAD_VALUE;
}
- return statusTFromBinderStatus(mEffect->command(CommandId::STOP));
+ return *(int *)pReplyData = statusTFromBinderStatus(mEffect->command(CommandId::STOP));
}
status_t EffectConversionHelperAidl::handleSetAudioSource(uint32_t cmdSize, const void* pCmdData,
@@ -477,7 +477,7 @@
efGroup);
status = (status == OK) ? BAD_VALUE : status;
}
- } else if (isBypassingOrOffload()) {
+ } else if (isBypassingOrTunnel()) {
// for effect with bypass (no processing) or offloadIndication flag, it's okay to not have
// statusQ
return OK;
@@ -487,8 +487,8 @@
return status;
}
-bool EffectConversionHelperAidl::isBypassingOrOffload() const {
- return isBypassing() || isOffload();
+bool EffectConversionHelperAidl::isBypassingOrTunnel() const {
+ return isBypassing() || isTunnel();
}
bool EffectConversionHelperAidl::isBypassing() const {
@@ -497,10 +497,10 @@
(mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isBypassing()));
}
-bool EffectConversionHelperAidl::isOffload() const {
+bool EffectConversionHelperAidl::isTunnel() const {
return mEffect &&
- (mDesc.common.flags.offloadIndication ||
- (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isOffload()));
+ (mDesc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL ||
+ (mIsProxyEffect && std::static_pointer_cast<EffectProxy>(mEffect)->isTunnel()));
}
Descriptor EffectConversionHelperAidl::getDescriptor() const {
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index b2ef155..5db334c 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -43,8 +43,8 @@
std::shared_ptr<android::hardware::EventFlag> getEventFlagGroup() { return mEfGroup; }
bool isBypassing() const;
- bool isOffload() const;
- bool isBypassingOrOffload() const;
+ bool isTunnel() const;
+ bool isBypassingOrTunnel() const;
::aidl::android::hardware::audio::effect::Descriptor getDescriptor() const;
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index 4d7db4c..1099b6d 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -278,8 +278,9 @@
return mSubEffects[mActiveSubIdx].descriptor.common.flags.bypass;
}
-bool EffectProxy::isOffload() const {
- return mSubEffects[mActiveSubIdx].descriptor.common.flags.offloadIndication;
+bool EffectProxy::isTunnel() const {
+ return mSubEffects[mActiveSubIdx].descriptor.common.flags.hwAcceleratorMode ==
+ Flags::HardwareAccelerator::TUNNEL;
}
binder_status_t EffectProxy::dump(int fd, const char** args, uint32_t numArgs) {
diff --git a/media/libaudiohal/impl/EffectProxy.h b/media/libaudiohal/impl/EffectProxy.h
index e14eb8a..0d62642 100644
--- a/media/libaudiohal/impl/EffectProxy.h
+++ b/media/libaudiohal/impl/EffectProxy.h
@@ -98,7 +98,7 @@
}
bool isBypassing() const;
- bool isOffload() const;
+ bool isTunnel() const;
// call dump for all sub-effects
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
diff --git a/media/libstagefright/VideoRenderQualityTracker.cpp b/media/libstagefright/VideoRenderQualityTracker.cpp
index e920bd1..90d5405 100644
--- a/media/libstagefright/VideoRenderQualityTracker.cpp
+++ b/media/libstagefright/VideoRenderQualityTracker.cpp
@@ -15,7 +15,11 @@
*/
#define LOG_TAG "VideoRenderQualityTracker"
+#define ATRACE_TAG ATRACE_TAG_VIDEO
+
#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/Mutex.h>
#include <media/stagefright/VideoRenderQualityTracker.h>
@@ -25,8 +29,10 @@
#include <stdio.h>
#include <sys/time.h>
+#include <android-base/macros.h>
#include <android-base/parsebool.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
namespace android {
@@ -38,6 +44,7 @@
typedef VideoRenderQualityTracker::Configuration::GetServerConfigurableFlagFn
GetServerConfigurableFlagFn;
+typedef VideoRenderQualityTracker::TraceTriggerFn TraceTriggerFn;
static void getServerConfigurableFlag(GetServerConfigurableFlagFn getServerConfigurableFlagFn,
char const *flagNameSuffix, bool *value) {
@@ -149,6 +156,10 @@
getFlag(judderEventMax, "judder_event_max");
getFlag(judderEventDetailsMax, "judder_event_details_max");
getFlag(judderEventDistanceToleranceMs, "judder_event_distance_tolerance_ms");
+ getFlag(traceTriggerEnabled, "trace_trigger_enabled");
+ getFlag(traceTriggerThrottleMs, "trace_trigger_throttle_ms");
+ getFlag(traceMinFreezeDurationMs, "trace_minimum_freeze_duration_ms");
+ getFlag(traceMaxFreezeDurationMs, "trace_maximum_freeze_duration_ms");
#undef getFlag
return c;
}
@@ -186,15 +197,25 @@
judderEventMax = 0; // enabled only when debugging
judderEventDetailsMax = 20;
judderEventDistanceToleranceMs = 5000; // lump judder occurrences together when 5s or less
+
+ // Perfetto trigger configuration.
+ traceTriggerEnabled = android::base::GetProperty(
+ "ro.build.type", "user") != "user"; // Enabled for non-user builds for debugging.
+ traceTriggerThrottleMs = 5 * 60 * 1000; // 5 mins.
+ traceMinFreezeDurationMs = 400;
+ traceMaxFreezeDurationMs = 1500;
}
-VideoRenderQualityTracker::VideoRenderQualityTracker() : mConfiguration(Configuration()) {
+VideoRenderQualityTracker::VideoRenderQualityTracker()
+ : mConfiguration(Configuration()), mTraceTriggerFn(triggerTrace) {
configureHistograms(mMetrics, mConfiguration);
clear();
}
-VideoRenderQualityTracker::VideoRenderQualityTracker(const Configuration &configuration) :
- mConfiguration(configuration) {
+VideoRenderQualityTracker::VideoRenderQualityTracker(const Configuration &configuration,
+ const TraceTriggerFn traceTriggerFn)
+ : mConfiguration(configuration),
+ mTraceTriggerFn(traceTriggerFn == nullptr ? triggerTrace : traceTriggerFn) {
configureHistograms(mMetrics, mConfiguration);
clear();
}
@@ -231,6 +252,11 @@
resetIfDiscontinuity(contentTimeUs, -1);
+ if (mTraceFrameSkippedToken == -1) {
+ mTraceFrameSkippedToken = contentTimeUs;
+ ATRACE_ASYNC_BEGIN("Video frame(s) skipped", mTraceFrameSkippedToken);
+ }
+
// Frames skipped at the end of playback shouldn't be counted as skipped frames, since the
// app could be terminating the playback. The pending count will be added to the metrics if and
// when the next frame is rendered.
@@ -261,11 +287,25 @@
return;
}
+ if (mTraceFrameSkippedToken != -1) {
+ ATRACE_ASYNC_END("Video frame(s) skipped", mTraceFrameSkippedToken);
+ mTraceFrameSkippedToken = -1;
+ }
+
int64_t actualRenderTimeUs = actualRenderTimeNs / 1000;
if (mLastRenderTimeUs != -1) {
- mRenderDurationMs += (actualRenderTimeUs - mLastRenderTimeUs) / 1000;
+ int64_t frameRenderDurationMs = (actualRenderTimeUs - mLastRenderTimeUs) / 1000;
+ mRenderDurationMs += frameRenderDurationMs;
+ if (mConfiguration.traceTriggerEnabled
+ // Threshold for visible video freeze.
+ && frameRenderDurationMs >= mConfiguration.traceMinFreezeDurationMs
+ // Threshold for removing long render durations which could be video pause.
+ && frameRenderDurationMs < mConfiguration.traceMaxFreezeDurationMs) {
+ triggerTraceWithThrottle(mTraceTriggerFn, mConfiguration, actualRenderTimeUs);
+ }
}
+
// Now that a frame has been rendered, the previously skipped frames can be processed as skipped
// frames since the app is not skipping them to terminate playback.
for (int64_t contentTimeUs : mPendingSkippedFrameContentTimeUsList) {
@@ -738,4 +778,42 @@
return false;
}
+void VideoRenderQualityTracker::triggerTraceWithThrottle(const TraceTriggerFn traceTriggerFn,
+ const Configuration &c,
+ const int64_t triggerTimeUs) {
+ static int64_t lastTriggerUs = -1;
+ static Mutex updateLastTriggerLock;
+
+ Mutex::Autolock autoLock(updateLastTriggerLock);
+ if (lastTriggerUs != -1) {
+ int32_t sinceLastTriggerMs = int32_t((triggerTimeUs - lastTriggerUs) / 1000);
+ // Throttle the trace trigger calls to reduce continuous PID fork calls in a short time
+ // to impact device performance, and reduce spamming trace reports.
+ if (sinceLastTriggerMs < c.traceTriggerThrottleMs) {
+ ALOGI("Not triggering trace - not enough time since last trigger");
+ return;
+ }
+ }
+ lastTriggerUs = triggerTimeUs;
+ (*traceTriggerFn)();
+}
+
+void VideoRenderQualityTracker::triggerTrace() {
+ // Trigger perfetto to stop always-on-tracing (AOT) to collect trace into a file for video
+ // freeze event, the collected trace categories are configured by AOT.
+ const char* args[] = {"/system/bin/trigger_perfetto", "com.android.codec-video-freeze", NULL};
+ pid_t pid = fork();
+ if (pid < 0) {
+ ALOGI("Failed to fork for triggering trace");
+ return;
+ }
+ if (pid == 0) {
+ // child process.
+ execvp(args[0], const_cast<char**>(args));
+ ALOGW("Failed to trigger trace %s", args[1]);
+ _exit(1);
+ }
+ ALOGI("Triggered trace %s", args[1]);
+}
+
} // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index a4b3e2f..e091cb8 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -286,9 +286,11 @@
return;
}
- // decoder deals in ms, OMX in us.
- outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
- mPvToOmxTimeMap.removeItem(timestamp);
+ if (mPvToOmxTimeMap.indexOfKey(timestamp) >= 0) {
+ // decoder deals in ms, OMX in us.
+ outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
+ mPvToOmxTimeMap.removeItem(timestamp);
+ }
inHeader->nOffset += bufferSize;
inHeader->nFilledLen = 0;
diff --git a/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp
index 04737a9..9198b7c 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVP8Encoder.cpp
@@ -120,6 +120,11 @@
OMX_ERRORTYPE SoftVP8Encoder::internalGetVp8Params(
OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
+ if (!isValidOMXParam(vp8Params)) {
+ android_errorWriteLog(0x534e4554, "273936274");
+ return OMX_ErrorBadParameter;
+ }
+
if (vp8Params->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUnsupportedIndex;
}
@@ -133,6 +138,11 @@
OMX_ERRORTYPE SoftVP8Encoder::internalSetVp8Params(
const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
+ if (!isValidOMXParam(vp8Params)) {
+ android_errorWriteLog(0x534e4554, "273937171");
+ return OMX_ErrorBadParameter;
+ }
+
if (vp8Params->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUnsupportedIndex;
}
diff --git a/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp
index 1ea1c85..f8495c2 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVP9Encoder.cpp
@@ -119,6 +119,11 @@
OMX_ERRORTYPE SoftVP9Encoder::internalGetVp9Params(
OMX_VIDEO_PARAM_VP9TYPE *vp9Params) {
+ if (!isValidOMXParam(vp9Params)) {
+ android_errorWriteLog(0x534e4554, "273936553");
+ return OMX_ErrorBadParameter;
+ }
+
if (vp9Params->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUnsupportedIndex;
}
@@ -133,6 +138,11 @@
OMX_ERRORTYPE SoftVP9Encoder::internalSetVp9Params(
const OMX_VIDEO_PARAM_VP9TYPE *vp9Params) {
+ if (!isValidOMXParam(vp9Params)) {
+ android_errorWriteLog(0x534e4554, "273937136");
+ return OMX_ErrorBadParameter;
+ }
+
if (vp9Params->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUnsupportedIndex;
}
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index e9b4341..cbedb72 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -485,6 +485,11 @@
OMX_ERRORTYPE SoftVPXEncoder::internalGetAndroidVpxParams(
OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vpxAndroidParams) {
+ if (!isValidOMXParam(vpxAndroidParams)) {
+ android_errorWriteLog(0x534e4554, "273936601");
+ return OMX_ErrorBadParameter;
+ }
+
if (vpxAndroidParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUnsupportedIndex;
}
@@ -501,6 +506,10 @@
OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVpxParams(
const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vpxAndroidParams) {
+ if (!isValidOMXParam(vpxAndroidParams)) {
+ android_errorWriteLog(0x534e4554, "273937551");
+ return OMX_ErrorBadParameter;
+ }
if (vpxAndroidParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorUnsupportedIndex;
}
diff --git a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
index a656e6e..cf53f27 100644
--- a/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
+++ b/media/libstagefright/include/media/stagefright/VideoRenderQualityTracker.h
@@ -200,6 +200,21 @@
// The maximum distance in time between two judder occurrences such that both will be
// lumped into the same judder event.
int32_t judderEventDistanceToleranceMs;
+ //
+ // Whether or not Perfetto trace trigger is enabled.
+ bool traceTriggerEnabled;
+ //
+ // The throttle time for Perfetto trace trigger to avoid triggering multiple traces for
+ // the same event in a short time.
+ int32_t traceTriggerThrottleMs;
+ //
+ // The minimum frame render duration to recognize video freeze event to collect trace.
+ int32_t traceMinFreezeDurationMs;
+ //
+ // The maximum frame render duration to recognize video freeze event. A frame render
+ // duration that is larger than the max duration would not trigger trace collection for
+ // video freeze because it's highly possible a video pause.
+ int32_t traceMaxFreezeDurationMs;
};
struct FreezeEvent {
@@ -256,8 +271,11 @@
Details details;
};
+ typedef void (*TraceTriggerFn)();
+
VideoRenderQualityTracker();
- VideoRenderQualityTracker(const Configuration &configuration);
+ VideoRenderQualityTracker(const Configuration &configuration,
+ const TraceTriggerFn traceTriggerFn = nullptr);
// Called when a tunnel mode frame has been queued.
void onTunnelFrameQueued(int64_t contentTimeUs);
@@ -376,6 +394,14 @@
JudderEvent &e, const VideoRenderQualityMetrics & m,
const Configuration &c, JudderEvent *judderEventOut);
+ // Trigger trace collection for video freeze.
+ static void triggerTrace();
+
+ // Trigger collection of a Perfetto Always-On-Tracing (AOT) trace file for video freeze,
+ // triggerTimeUs is used as a throttle to avoid triggering multiple traces in a short time.
+ static void triggerTraceWithThrottle(TraceTriggerFn traceTriggerFn,
+ const Configuration &c, const int64_t triggerTimeUs);
+
// Check to see if a discontinuity has occurred by examining the content time and the
// app-desired render time. If so, reset some internal state.
bool resetIfDiscontinuity(int64_t contentTimeUs, int64_t desiredRenderTimeUs);
@@ -394,6 +420,9 @@
// Configurable elements of the metrics algorithms.
const Configuration mConfiguration;
+ // The function for triggering trace collection for video freeze.
+ const TraceTriggerFn mTraceTriggerFn;
+
// Metrics are updated every time a frame event occurs - skipped, dropped, rendered.
VideoRenderQualityMetrics mMetrics;
@@ -445,6 +474,9 @@
// Frame durations derived from timestamps captured by the display subsystem, indicating the
// wall clock atime at which the frame is actually rendered.
FrameDurationUs mActualFrameDurationUs;
+
+ // Token of async atrace for video frame dropped/skipped by the app.
+ int64_t mTraceFrameSkippedToken= -1;
};
} // namespace android
diff --git a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
index 7823922..3b70636 100644
--- a/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
+++ b/media/libstagefright/tests/VideoRenderQualityTracker_test.cpp
@@ -36,10 +36,11 @@
class Helper {
public:
Helper(double contentFrameDurationMs, const Configuration &configuration) :
- mVideoRenderQualityTracker(configuration) {
+ mVideoRenderQualityTracker(configuration, testTraceTrigger) {
mContentFrameDurationUs = int64_t(contentFrameDurationMs * 1000);
mMediaTimeUs = 0;
mClockTimeNs = 0;
+ sTraceTriggeredCount = 0;
}
void changeContentFrameDuration(double contentFrameDurationMs) {
@@ -100,6 +101,10 @@
return e;
}
+ int getTraceTriggeredCount() {
+ return sTraceTriggeredCount;
+ }
+
private:
VideoRenderQualityTracker mVideoRenderQualityTracker;
int64_t mContentFrameDurationUs;
@@ -107,8 +112,16 @@
int64_t mClockTimeNs;
VideoRenderQualityTracker::FreezeEvent mFreezeEvent;
VideoRenderQualityTracker::JudderEvent mJudderEvent;
+
+ static int sTraceTriggeredCount;
+
+ static void testTraceTrigger() {
+ sTraceTriggeredCount++;
+ };
};
+int Helper::sTraceTriggeredCount = 0;
+
class VideoRenderQualityTrackerTest : public ::testing::Test {
public:
VideoRenderQualityTrackerTest() {}
@@ -139,6 +152,10 @@
EXPECT_EQ(c.judderEventMax, d.judderEventMax);
EXPECT_EQ(c.judderEventDetailsMax, d.judderEventDetailsMax);
EXPECT_EQ(c.judderEventDistanceToleranceMs, d.judderEventDistanceToleranceMs);
+ EXPECT_EQ(c.traceTriggerEnabled, d.traceTriggerEnabled);
+ EXPECT_EQ(c.traceTriggerThrottleMs, d.traceTriggerThrottleMs);
+ EXPECT_EQ(c.traceMinFreezeDurationMs, d.traceMinFreezeDurationMs);
+ EXPECT_EQ(c.traceMaxFreezeDurationMs, d.traceMaxFreezeDurationMs);
}
TEST_F(VideoRenderQualityTrackerTest, getFromServerConfigurableFlags_withEmpty) {
@@ -166,6 +183,10 @@
EXPECT_EQ(c.judderEventMax, d.judderEventMax);
EXPECT_EQ(c.judderEventDetailsMax, d.judderEventDetailsMax);
EXPECT_EQ(c.judderEventDistanceToleranceMs, d.judderEventDistanceToleranceMs);
+ EXPECT_EQ(c.traceTriggerEnabled, d.traceTriggerEnabled);
+ EXPECT_EQ(c.traceTriggerThrottleMs, d.traceTriggerThrottleMs);
+ EXPECT_EQ(c.traceMinFreezeDurationMs, d.traceMinFreezeDurationMs);
+ EXPECT_EQ(c.traceMaxFreezeDurationMs, d.traceMaxFreezeDurationMs);
}
TEST_F(VideoRenderQualityTrackerTest, getFromServerConfigurableFlags_withInvalid) {
@@ -193,6 +214,10 @@
EXPECT_EQ(c.judderEventMax, d.judderEventMax);
EXPECT_EQ(c.judderEventDetailsMax, d.judderEventDetailsMax);
EXPECT_EQ(c.judderEventDistanceToleranceMs, d.judderEventDistanceToleranceMs);
+ EXPECT_EQ(c.traceTriggerEnabled, d.traceTriggerEnabled);
+ EXPECT_EQ(c.traceTriggerThrottleMs, d.traceTriggerThrottleMs);
+ EXPECT_EQ(c.traceMinFreezeDurationMs, d.traceMinFreezeDurationMs);
+ EXPECT_EQ(c.traceMaxFreezeDurationMs, d.traceMaxFreezeDurationMs);
}
TEST_F(VideoRenderQualityTrackerTest, getFromServerConfigurableFlags_withAlmostValid) {
@@ -232,6 +257,14 @@
return "10*10";
} else if (flag == "render_metrics_judder_event_distance_tolerance_ms") {
return "140-a";
+ } else if (flag == "render_metrics_trace_trigger_enabled") {
+ return "fals";
+ } else if (flag == "render_metrics_trace_trigger_throttle_ms") {
+ return "12345678901234";
+ } else if (flag == "render_metrics_trace_minimum_freeze_duration_ms") {
+ return "10b0";
+ } else if (flag == "render_metrics_trace_maximum_freeze_duration_ms") {
+ return "100a";
}
return "";
}
@@ -255,6 +288,10 @@
EXPECT_EQ(c.judderEventMax, d.judderEventMax);
EXPECT_EQ(c.judderEventDetailsMax, d.judderEventDetailsMax);
EXPECT_EQ(c.judderEventDistanceToleranceMs, d.judderEventDistanceToleranceMs);
+ EXPECT_EQ(c.traceTriggerEnabled, d.traceTriggerEnabled);
+ EXPECT_EQ(c.traceTriggerThrottleMs, d.traceTriggerThrottleMs);
+ EXPECT_EQ(c.traceMinFreezeDurationMs, d.traceMinFreezeDurationMs);
+ EXPECT_EQ(c.traceMaxFreezeDurationMs, d.traceMaxFreezeDurationMs);
}
TEST_F(VideoRenderQualityTrackerTest, getFromServerConfigurableFlags_withValid) {
@@ -294,6 +331,14 @@
return "10000";
} else if (flag == "render_metrics_judder_event_distance_tolerance_ms") {
return "11000";
+ } else if (flag == "render_metrics_trace_trigger_enabled") {
+ return "true";
+ } else if (flag == "render_metrics_trace_trigger_throttle_ms") {
+ return "50000";
+ } else if (flag == "render_metrics_trace_minimum_freeze_duration_ms") {
+ return "1000";
+ } else if (flag == "render_metrics_trace_maximum_freeze_duration_ms") {
+ return "5000";
}
return "";
}
@@ -353,6 +398,11 @@
EXPECT_NE(c.judderEventDetailsMax, d.judderEventDetailsMax);
EXPECT_EQ(c.judderEventDistanceToleranceMs, 11000);
EXPECT_NE(c.judderEventDistanceToleranceMs, d.judderEventDistanceToleranceMs);
+
+ EXPECT_EQ(c.traceTriggerEnabled, true);
+ EXPECT_EQ(c.traceTriggerThrottleMs, 50000);
+ EXPECT_EQ(c.traceMinFreezeDurationMs, 1000);
+ EXPECT_EQ(c.traceMaxFreezeDurationMs, 5000);
}
TEST_F(VideoRenderQualityTrackerTest, countsReleasedFrames) {
@@ -1024,4 +1074,75 @@
EXPECT_EQ(h.getMetrics().judderScore, 10 + 300 + 2000);
}
+TEST_F(VideoRenderQualityTrackerTest,
+ freezesForTraceDuration_withThrottle_throttlesTraceTrigger) {
+ Configuration c;
+ c.enabled = true;
+ c.traceTriggerEnabled = true; // The trigger is enabled, so traces should be triggered.
+ // The value of traceTriggerThrottleMs must be larger than traceMinFreezeDurationMs. Otherwise,
+ // the throttle does work.
+ c.traceTriggerThrottleMs = 200;
+ c.traceMinFreezeDurationMs = 40;
+ int32_t freeze = c.traceMinFreezeDurationMs;
+
+ Helper h(20, c);
+ // Freeze triggers separated by 80ms which is less than the threshold.
+ h.render({
+ freeze, // Freeze duration does not check trace trigger.
+ 20, // Trace triggered.
+ 20, // Throttle time: 20/200ms
+ 20, // Throttle time: 40/200ms
+ freeze, // Throttle time: 80/200ms
+ 20, // Throttle time: 100/200ms (Trace not triggered)
+ });
+ EXPECT_EQ(h.getTraceTriggeredCount(), 1);
+ // Next freeze trigger is separated by 200ms which breaks the throttle threshold.
+ h.render({
+ 20, // Throttle time: 120/200ms
+ 20, // Throttle time: 140/200ms
+ 20, // Throttle time: 160/200ms
+ freeze, // Throttle time: 200/200ms
+ 20, // Trace triggered.
+ });
+ EXPECT_EQ(h.getTraceTriggeredCount(), 2);
+ // Next freeze trigger is separated by 80ms which is less than the threshold.
+ h.render({
+ 20, // Throttle time: 20/200ms
+ 20, // Throttle time: 40/200ms
+ freeze, // Throttle time: 80/200ms
+ 20, // Throttle time: 100/200ms (Trace not triggered)
+ });
+ EXPECT_EQ(h.getTraceTriggeredCount(), 2);
+}
+
+TEST_F(VideoRenderQualityTrackerTest, freezeForTraceDuration_triggersTrace) {
+ Configuration c;
+ c.enabled = true;
+ c.traceTriggerEnabled = true; // The trigger is enabled, so traces should be triggered.
+ c.traceTriggerThrottleMs = 0; // Disable throttle in the test case.
+ int32_t freeze1 = c.traceMinFreezeDurationMs;
+ int32_t freeze2 = c.traceMaxFreezeDurationMs - 1;
+ int32_t couldBeAPause = c.traceMaxFreezeDurationMs + 1;
+
+ Helper h(20, c);
+ h.render({freeze1, 20, freeze2, 20, couldBeAPause, 20});
+
+ EXPECT_EQ(h.getTraceTriggeredCount(), 2);
+}
+
+TEST_F(VideoRenderQualityTrackerTest,
+ freezeForTraceDuration_withTraceDisabled_doesNotTriggerTrace) {
+ Configuration c;
+ c.enabled = true;
+ c.traceTriggerEnabled = false; // The trigger is disabled, so no traces should be triggered.
+ c.traceTriggerThrottleMs = 0; // Disable throttle in the test case.
+ int32_t freeze1 = c.traceMinFreezeDurationMs;
+ int32_t freeze2 = c.traceMaxFreezeDurationMs - 1;
+ int32_t couldBeAPause = c.traceMaxFreezeDurationMs + 1;
+
+ Helper h(20, c);
+ h.render({freeze1, 20, freeze2, 20, couldBeAPause, 20});
+
+ EXPECT_EQ(h.getTraceTriggeredCount(), 0);
+}
} // android
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index 48a0a82..b722b74 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -534,6 +534,11 @@
* Get the native_handle_t corresponding to the ANativeWindow owned by the
* AImageReader provided.
*
+ * This is deprecated in API level 35 and will return AMEDIA_ERROR_UNKNOWN.
+ * The native_handle_t is no longer used with AIDL interfaces and
+ * ANativeWindow is used directly instead.
+ * Use AImageRead_getWindow to get the ANativeWindow and use that object.
+ *
* @param reader The image reader of interest.
* @param handle The output native_handle_t. This native handle is owned by
* this image reader.
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 93db608..589050c 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -830,7 +830,10 @@
if (mStatus != NO_ERROR || mEffectInterface == 0) {
return;
}
- mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, 0, NULL);
+
+ int reply = 0;
+ uint32_t replySize = sizeof(reply);
+ mEffectInterface->command(EFFECT_CMD_RESET, 0, NULL, &replySize, &reply);
}
status_t EffectModule::configure()
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 89f0a6e..5f238fb 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -412,7 +412,23 @@
mAfPatchPanelCallback->updateOutDevicesForRecordThreads_l(devices);
}
+ // For endpoint patches, we do not need to re-evaluate the device effect state
+ // if the same HAL patch is reused (see calls to mAfPatchPanelCallback below)
+ if (endpointPatch) {
+ for (auto& p : mPatches) {
+ // end point patches are skipped so we do not compare against this patch
+ if (!p.second.mIsEndpointPatch && patchesHaveSameRoute(
+ newPatch.mAudioPatch, p.second.mAudioPatch)) {
+ ALOGV("%s() Sw Bridge endpoint reusing halHandle=%d", __func__,
+ p.second.mHalHandle);
+ halHandle = p.second.mHalHandle;
+ reuseExistingHalPatch = true;
+ break;
+ }
+ }
+ }
mAfPatchPanelCallback->mutex().unlock();
+
status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
mAfPatchPanelCallback->mutex().lock();
if (status == NO_ERROR) {
@@ -442,11 +458,18 @@
*handle = static_cast<audio_patch_handle_t>(
mAfPatchPanelCallback->nextUniqueId(AUDIO_UNIQUE_ID_USE_PATCH));
newPatch.mHalHandle = halHandle;
- if (reuseExistingHalPatch) {
- mAfPatchPanelCallback->getPatchCommandThread()->updateAudioPatch(
- oldhandle, *handle, newPatch);
- } else {
- mAfPatchPanelCallback->getPatchCommandThread()->createAudioPatch(*handle, newPatch);
+ // Skip device effect:
+ // -for sw bridge as effect are likely held by endpoint patches
+ // -for endpoint reusing a HalPatch handle
+ if (!(newPatch.isSoftware()
+ || (endpointPatch && reuseExistingHalPatch))) {
+ if (reuseExistingHalPatch) {
+ mAfPatchPanelCallback->getPatchCommandThread()->updateAudioPatch(
+ oldhandle, *handle, newPatch);
+ } else {
+ mAfPatchPanelCallback->getPatchCommandThread()->createAudioPatch(
+ *handle, newPatch);
+ }
}
if (insertedModule != AUDIO_MODULE_HANDLE_NONE) {
addSoftwarePatchToInsertedModules_l(insertedModule, *handle, &newPatch.mAudioPatch);
@@ -734,12 +757,14 @@
{
ALOGV("%s handle %d", __func__, handle);
status_t status = NO_ERROR;
+ bool doReleasePatch = true;
auto iter = mPatches.find(handle);
if (iter == mPatches.end()) {
return BAD_VALUE;
}
Patch &removedPatch = iter->second;
+ const bool isSwBridge = removedPatch.isSoftware();
const struct audio_patch &patch = removedPatch.mAudioPatch;
const struct audio_port_config &src = patch.sources[0];
@@ -791,15 +816,31 @@
break;
}
}
- mAfPatchPanelCallback->mutex().unlock();
- status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
- mAfPatchPanelCallback->mutex().lock();
+ // Check whether the removed patch Hal Handle is used in another non-Endpoint patch.
+ // Since this is a non-Endpoint patch, the removed patch is not considered (it is
+ // removed later from mPatches).
+ if (removedPatch.mIsEndpointPatch) {
+ for (auto& p: mPatches) {
+ if (!p.second.mIsEndpointPatch
+ && p.second.mHalHandle == removedPatch.mHalHandle) {
+ ALOGV("%s() Sw Bridge endpoint used existing halHandle=%d, do not release",
+ __func__, p.second.mHalHandle);
+ doReleasePatch = false;
+ break;
+ }
+ }
+ }
+ if (doReleasePatch) {
+ mAfPatchPanelCallback->mutex().unlock();
+ status = thread->sendReleaseAudioPatchConfigEvent(removedPatch.mHalHandle);
+ mAfPatchPanelCallback->mutex().lock();
+ }
} break;
default:
status = BAD_VALUE;
}
- erasePatch(handle);
+ erasePatch(handle, /* reuseExistingHalPatch= */ !doReleasePatch || isSwBridge);
return status;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a72598e..99042af 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -658,7 +658,7 @@
status_t AudioPolicyManager::updateCallRouting(bool fromCache, uint32_t delayMs, uint32_t *waitMs)
{
- if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
+ if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) {
DeviceVector rxDevices = selectBestRxSinkDevicesForCall(fromCache);
return updateCallRoutingInternal(rxDevices, delayMs, waitMs);
}
@@ -671,14 +671,21 @@
bool createTxPatch = false;
bool createRxPatch = false;
uint32_t muteWaitMs = 0;
- if(!hasPrimaryOutput() ||
+ if (hasPrimaryOutput() &&
mPrimaryOutput->devices().onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_STUB)) {
return INVALID_OPERATION;
}
- ALOG_ASSERT(!rxDevices.isEmpty(), "%s() no selected output device", __func__);
audio_attributes_t attr = { .source = AUDIO_SOURCE_VOICE_COMMUNICATION };
auto txSourceDevice = mEngine->getInputDeviceForAttributes(attr);
+
+ disconnectTelephonyAudioSource(mCallRxSourceClient);
+ disconnectTelephonyAudioSource(mCallTxSourceClient);
+
+ if (rxDevices.isEmpty()) {
+ ALOGW("%s() no selected output device", __func__);
+ return INVALID_OPERATION;
+ }
if (txSourceDevice == nullptr) {
ALOGE("%s() selected input device not available", __func__);
return INVALID_OPERATION;
@@ -687,9 +694,6 @@
ALOGV("%s device rxDevice %s txDevice %s", __func__,
rxDevices.itemAt(0)->toString().c_str(), txSourceDevice->toString().c_str());
- disconnectTelephonyAudioSource(mCallRxSourceClient);
- disconnectTelephonyAudioSource(mCallTxSourceClient);
-
auto telephonyRxModule =
mHwModules.getModuleForDeviceType(AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_FORMAT_DEFAULT);
auto telephonyTxModule =
@@ -729,6 +733,10 @@
// Use legacy routing method for voice calls via setOutputDevice() on primary output.
// Otherwise, create two audio patches for TX and RX path.
if (!createRxPatch) {
+ if (!hasPrimaryOutput()) {
+ ALOGW("%s() no primary output available", __func__);
+ return INVALID_OPERATION;
+ }
muteWaitMs = setOutputDevices(__func__, mPrimaryOutput, rxDevices, true, delayMs);
} else { // create RX path audio patch
connectTelephonyRxAudioSource();
@@ -875,20 +883,20 @@
}
}
- if (hasPrimaryOutput()) {
- if (state == AUDIO_MODE_IN_CALL) {
- (void)updateCallRouting(false /*fromCache*/, delayMs);
- } else {
+ if (state == AUDIO_MODE_IN_CALL) {
+ (void)updateCallRouting(false /*fromCache*/, delayMs);
+ } else {
+ if (oldState == AUDIO_MODE_IN_CALL) {
+ disconnectTelephonyAudioSource(mCallRxSourceClient);
+ disconnectTelephonyAudioSource(mCallTxSourceClient);
+ }
+ if (hasPrimaryOutput()) {
DeviceVector rxDevices = getNewOutputDevices(mPrimaryOutput, false /*fromCache*/);
// force routing command to audio hardware when ending call
// even if no device change is needed
if (isStateInCall(oldState) && rxDevices.isEmpty()) {
rxDevices = mPrimaryOutput->devices();
}
- if (oldState == AUDIO_MODE_IN_CALL) {
- disconnectTelephonyAudioSource(mCallRxSourceClient);
- disconnectTelephonyAudioSource(mCallTxSourceClient);
- }
setOutputDevices(__func__, mPrimaryOutput, rxDevices, force, 0);
}
}
@@ -5250,14 +5258,9 @@
return NO_ERROR;
}
patchHandle = outputDesc->getPatchHandle();
- // When a Sw bridge is released, the mixer used by this bridge will release its
- // patch at AudioFlinger side. Hence, the mixer audio patch must be recreated
- // Reuse patch handle to force audio flinger removing initial mixer patch removal
- // updating hal patch handle (prevent leaks).
// While using a HwBridge, force reconsidering device only if not reusing an existing
// output and no more activity on output (will force to close).
- bool force = sourceDesc->useSwBridge() ||
- (sourceDesc->canCloseOutput() && !outputDesc->isActive());
+ const bool force = sourceDesc->canCloseOutput() && !outputDesc->isActive();
// APM pattern is to have always outputs opened / patch realized for reachable devices.
// Update device may result to NONE (empty), coupled with force, it releases the patch.
// Reconsider device only for cases:
@@ -6280,6 +6283,7 @@
if (mPrimaryOutput == nullptr &&
outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
mPrimaryOutput = outputDesc;
+ mPrimaryModuleHandle = mPrimaryOutput->getModuleHandle();
}
if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
outputDesc->close();
@@ -7114,7 +7118,9 @@
DeviceVector AudioPolicyManager::getNewOutputDevices(const sp<SwAudioOutputDescriptor>& outputDesc,
bool fromCache)
{
- DeviceVector devices;
+ if (outputDesc == nullptr) {
+ return DeviceVector{};
+ }
ssize_t index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
if (index >= 0) {
@@ -7148,6 +7154,7 @@
return DeviceVector(device);
}
+ DeviceVector devices;
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
StreamTypeVector streams = mEngine->getStreamTypesForProductStrategy(productStrategy);
auto attr = mEngine->getAllAttributesForProductStrategy(productStrategy).front();
@@ -8442,6 +8449,7 @@
if (mPrimaryOutput == nullptr && profile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
ALOGV("%s(): re-assigning mPrimaryOutput", __func__);
mPrimaryOutput = desc;
+ mPrimaryModuleHandle = mPrimaryOutput->getModuleHandle();
}
return desc;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 91fe1cc..6365962 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -820,10 +820,10 @@
bool isPrimaryModule(const sp<HwModule> &module) const
{
- if (module == 0 || !hasPrimaryOutput()) {
+ if (module == nullptr || mPrimaryModuleHandle == AUDIO_MODULE_HANDLE_NONE) {
return false;
}
- return module->getHandle() == mPrimaryOutput->getModuleHandle();
+ return module->getHandle() == mPrimaryModuleHandle;
}
DeviceVector availablePrimaryOutputDevices() const
{
@@ -935,6 +935,8 @@
EngineInstance mEngine; // Audio Policy Engine instance
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
+ // mPrimaryModuleHandle is cached mPrimaryOutput->getModuleHandle();
+ audio_module_handle_t mPrimaryModuleHandle = AUDIO_MODULE_HANDLE_NONE;
// list of descriptors for outputs currently opened
sp<SwAudioOutputDescriptor> mSpatializerOutput;
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index ea467e7..abc3ecf 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -84,8 +84,8 @@
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"android.hardware.graphics.common-V4-ndk",
+ "camera_platform_flags_c_lib",
"media_permission-aidl-cpp",
- "server_configurable_flags",
],
static_libs: [
@@ -106,7 +106,6 @@
"android.hardware.camera.provider@2.6",
"android.hardware.camera.provider@2.7",
"android.hardware.camera.provider-V2-ndk",
- "camera_platform_flags_c_lib",
"libaidlcommonsupport",
"libbinderthreadstateutils",
"libcameraservice_device_independent",
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 45ce4c8..6819136 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -367,7 +367,7 @@
static bool isValidAudioRestriction(int32_t mode);
// Override rotate-and-crop AUTO behavior
- virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop) = 0;
+ virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop, bool fromHal = false) = 0;
// Override autoframing AUTO behaviour
virtual status_t setAutoframingOverride(uint8_t autoframingValue) = 0;
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index b217476..caa6424 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -2342,7 +2342,7 @@
return mDevice->setCameraServiceWatchdog(enabled);
}
-status_t Camera2Client::setRotateAndCropOverride(uint8_t rotateAndCrop) {
+status_t Camera2Client::setRotateAndCropOverride(uint8_t rotateAndCrop, bool fromHal) {
if (rotateAndCrop > ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return BAD_VALUE;
{
@@ -2356,7 +2356,7 @@
}
return mDevice->setRotateAndCropAutoBehavior(
- static_cast<camera_metadata_enum_android_scaler_rotate_and_crop_t>(rotateAndCrop));
+ static_cast<camera_metadata_enum_android_scaler_rotate_and_crop_t>(rotateAndCrop), fromHal);
}
status_t Camera2Client::setAutoframingOverride(uint8_t autoframingValue) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 9ec1eb5..2cb7af0 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -81,7 +81,7 @@
virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
virtual status_t setAudioRestriction(int mode);
virtual int32_t getGlobalAudioRestriction();
- virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop);
+ virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop, bool fromHal = false);
virtual status_t setAutoframingOverride(uint8_t autoframingMode);
virtual bool supportsCameraMute();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 939f969..2e6eb06 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -18,6 +18,7 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
#include <utils/CameraThreadState.h>
#include <utils/Log.h>
@@ -55,6 +56,8 @@
using namespace camera3;
using camera3::camera_stream_rotation_t::CAMERA_STREAM_ROTATION_0;
+namespace flags = com::android::internal::camera::flags;
+
CameraDeviceClientBase::CameraDeviceClientBase(
const sp<CameraService>& cameraService,
const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
@@ -539,6 +542,13 @@
if (entry.count == 1) {
mVideoStabilizationMode = entry.data.u8[0];
}
+ if (flags::log_ultrawide_usage()) {
+ entry = physicalSettingsList.begin()->metadata.find(
+ ANDROID_CONTROL_ZOOM_RATIO);
+ if (entry.count == 1 && entry.data.f[0] < 1.0f ) {
+ mUsedUltraWide = true;
+ }
+ }
}
mRequestIdCounter++;
@@ -1762,11 +1772,11 @@
return mDevice->setCameraServiceWatchdog(enabled);
}
-status_t CameraDeviceClient::setRotateAndCropOverride(uint8_t rotateAndCrop) {
+status_t CameraDeviceClient::setRotateAndCropOverride(uint8_t rotateAndCrop, bool fromHal) {
if (rotateAndCrop > ANDROID_SCALER_ROTATE_AND_CROP_AUTO) return BAD_VALUE;
return mDevice->setRotateAndCropAutoBehavior(
- static_cast<camera_metadata_enum_android_scaler_rotate_and_crop_t>(rotateAndCrop));
+ static_cast<camera_metadata_enum_android_scaler_rotate_and_crop_t>(rotateAndCrop), fromHal);
}
status_t CameraDeviceClient::setAutoframingOverride(uint8_t autoframingValue) {
@@ -2051,7 +2061,7 @@
}
}
Camera2ClientBase::notifyIdleWithUserTag(requestCount, resultErrorCount, deviceError,
- fullStreamStats, mUserTag, mVideoStabilizationMode);
+ fullStreamStats, mUserTag, mVideoStabilizationMode, mUsedUltraWide);
}
void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 86a94e2..c2870aa 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -198,7 +198,8 @@
virtual status_t initialize(sp<CameraProviderManager> manager,
const std::string& monitorTags) override;
- virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop) override;
+ virtual status_t setRotateAndCropOverride(uint8_t rotateAndCrop,
+ bool fromHal = false) override;
virtual status_t setAutoframingOverride(uint8_t autoframingValue) override;
@@ -369,6 +370,8 @@
std::string mUserTag;
// The last set video stabilization mode
int mVideoStabilizationMode = -1;
+ // Whether a zoom_ratio < 1.0 has been used during this session
+ bool mUsedUltraWide = false;
// This only exists in case of camera ID Remapping.
const std::string mOriginalCameraId;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 99bdb0e..4ed352d 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -80,7 +80,8 @@
return OK;
}
-status_t CameraOfflineSessionClient::setRotateAndCropOverride(uint8_t /*rotateAndCrop*/) {
+status_t CameraOfflineSessionClient::setRotateAndCropOverride(uint8_t /*rotateAndCrop*/,
+ bool /*fromHal*/) {
// Since we're not submitting more capture requests, changes to rotateAndCrop override
// make no difference.
return OK;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 70bad03..8aad4e9 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -80,7 +80,7 @@
status_t initialize(sp<CameraProviderManager> /*manager*/,
const std::string& /*monitorTags*/) override;
- status_t setRotateAndCropOverride(uint8_t rotateAndCrop) override;
+ status_t setRotateAndCropOverride(uint8_t rotateAndCrop, bool fromHal = false) override;
status_t setAutoframingOverride(uint8_t autoframingValue) override;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index a611cc6..5c88cfa 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -370,7 +370,8 @@
rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90;
}
- static_cast<TClientBase *>(this)->setRotateAndCropOverride(rotateAndCropMode);
+ static_cast<TClientBase *>(this)->setRotateAndCropOverride(rotateAndCropMode,
+ /*fromHal*/ true);
}
}
@@ -395,7 +396,7 @@
void Camera2ClientBase<TClientBase>::notifyIdleWithUserTag(
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
const std::vector<hardware::CameraStreamStats>& streamStats,
- const std::string& userTag, int videoStabilizationMode) {
+ const std::string& userTag, int videoStabilizationMode, bool usedUltraWide) {
if (mDeviceActive) {
status_t res = TClientBase::finishCameraStreamingOps();
if (res != OK) {
@@ -404,7 +405,7 @@
}
mCameraServiceProxyWrapper->logIdle(TClientBase::mCameraIdStr,
requestCount, resultErrorCount, deviceError, userTag, videoStabilizationMode,
- streamStats);
+ usedUltraWide, streamStats);
}
mDeviceActive = false;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 88d65dc..226881a 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -97,7 +97,8 @@
void notifyIdleWithUserTag(int64_t requestCount, int64_t resultErrorCount,
bool deviceError,
const std::vector<hardware::CameraStreamStats>& streamStats,
- const std::string& userTag, int videoStabilizationMode);
+ const std::string& userTag, int videoStabilizationMode,
+ bool usedUltraWide);
int getCameraId() const;
const sp<CameraDeviceBase>&
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 017da0f..01199af 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -444,7 +444,8 @@
* and defaults to NONE.
*/
virtual status_t setRotateAndCropAutoBehavior(
- camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) = 0;
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue,
+ bool fromHal = false) = 0;
/**
* Set the current behavior for the AUTOFRAMING control when in AUTO.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index e2181ec..6765c1d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -70,6 +70,7 @@
#include "utils/TraceHFR.h"
#include <algorithm>
+#include <optional>
#include <tuple>
using namespace android::camera3;
@@ -5394,9 +5395,13 @@
}
status_t Camera3Device::setRotateAndCropAutoBehavior(
- camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue, bool fromHal) {
ATRACE_CALL();
- Mutex::Autolock il(mInterfaceLock);
+ // We shouldn't hold mInterfaceLock when called as an effect of a HAL
+ // callback since this can lead to a deadlock : b/299348355.
+ // mLock still protects state.
+ std::optional<Mutex::Autolock> maybeMutex =
+ fromHal ? std::nullopt : std::optional<Mutex::Autolock>(mInterfaceLock);
Mutex::Autolock l(mLock);
if (mRequestThread == nullptr) {
return INVALID_OPERATION;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index a890c2b..d812c01 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -275,7 +275,7 @@
* and defaults to NONE.
*/
status_t setRotateAndCropAutoBehavior(
- camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue);
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue, bool fromHal);
/**
* Set the current behavior for the AUTOFRAMING control when in AUTO.
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index d07bf6d..d227606 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -94,7 +94,7 @@
void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onIdle(
sp<hardware::ICameraServiceProxy>& proxyBinder,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
- const std::string& userTag, int32_t videoStabilizationMode,
+ const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
const std::vector<hardware::CameraStreamStats>& streamStats) {
Mutex::Autolock l(mLock);
@@ -104,6 +104,7 @@
mSessionStats.mDeviceError = deviceError;
mSessionStats.mUserTag = userTag;
mSessionStats.mVideoStabilizationMode = videoStabilizationMode;
+ mSessionStats.mUsedUltraWide = usedUltraWide;
mSessionStats.mStreamStats = streamStats;
updateProxyDeviceState(proxyBinder);
@@ -278,7 +279,7 @@
void CameraServiceProxyWrapper::logIdle(const std::string& id,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
- const std::string& userTag, int32_t videoStabilizationMode,
+ const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
const std::vector<hardware::CameraStreamStats>& streamStats) {
std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
{
@@ -304,7 +305,7 @@
sp<hardware::ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
sessionStats->onIdle(proxyBinder, requestCount, resultErrorCount, deviceError, userTag,
- videoStabilizationMode, streamStats);
+ videoStabilizationMode, usedUltraWide, streamStats);
}
void CameraServiceProxyWrapper::logOpen(const std::string& id, int facing,
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index 1afe5b3..4e21e58 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -61,7 +61,7 @@
void onActive(sp<hardware::ICameraServiceProxy>& proxyBinder, float maxPreviewFps);
void onIdle(sp<hardware::ICameraServiceProxy>& proxyBinder,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
- const std::string& userTag, int32_t videoStabilizationMode,
+ const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
const std::vector<hardware::CameraStreamStats>& streamStats);
std::string updateExtensionSessionStats(
@@ -110,7 +110,7 @@
// Session state becomes idle
void logIdle(const std::string& id,
int64_t requestCount, int64_t resultErrorCount, bool deviceError,
- const std::string& userTag, int32_t videoStabilizationMode,
+ const std::string& userTag, int32_t videoStabilizationMode, bool usedUltraWide,
const std::vector<hardware::CameraStreamStats>& streamStats);
// Ping camera service proxy for user update