Merge "media: Rename ImageDecoder class" into sc-dev
diff --git a/apex/mediatranscoding.rc b/apex/mediatranscoding.rc
index 24306a2..ae9f8ba 100644
--- a/apex/mediatranscoding.rc
+++ b/apex/mediatranscoding.rc
@@ -8,4 +8,5 @@
ioprio rt 4
# Restrict to little cores only with system-background cpuset.
writepid /dev/cpuset/system-background/tasks
+ interface aidl media.transcoding
disabled
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index 2fa4f25..f857e87 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -26,6 +26,11 @@
#include <media/stagefright/foundation/MediaDefs.h>
namespace android {
+namespace {
+
+constexpr uint8_t NEUTRAL_UV_VALUE = 128;
+
+} // namespace
// codecname set and passed in as a compile flag from Android.bp
constexpr char COMPONENT_NAME[] = CODECNAME;
@@ -51,8 +56,8 @@
DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
.withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
.withFields({
- C2F(mSize, width).inRange(2, 2048, 2),
- C2F(mSize, height).inRange(2, 2048, 2),
+ C2F(mSize, width).inRange(2, 4096, 2),
+ C2F(mSize, height).inRange(2, 4096, 2),
})
.withSetter(SizeSetter)
.build());
@@ -464,7 +469,8 @@
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 dstUVStride,
- uint32_t width, uint32_t height) {
+ uint32_t width, uint32_t height,
+ bool isMonochrome) {
for (size_t i = 0; i < height; ++i) {
memcpy(dstY, srcY, width);
@@ -472,6 +478,17 @@
dstY += dstYStride;
}
+ if (isMonochrome) {
+ // Fill with neutral U/V values.
+ for (size_t i = 0; i < height / 2; ++i) {
+ memset(dstV, NEUTRAL_UV_VALUE, width / 2);
+ memset(dstU, NEUTRAL_UV_VALUE, width / 2);
+ dstV += dstUVStride;
+ dstU += dstUVStride;
+ }
+ return;
+ }
+
for (size_t i = 0; i < height / 2; ++i) {
memcpy(dstV, srcV, width / 2);
srcV += srcVStride;
@@ -557,7 +574,7 @@
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 dstUVStride,
- size_t width, size_t height) {
+ size_t width, size_t height, bool isMonochrome) {
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
@@ -568,6 +585,17 @@
dstY += dstYStride;
}
+ if (isMonochrome) {
+ // Fill with neutral U/V values.
+ for (size_t y = 0; y < (height + 1) / 2; ++y) {
+ memset(dstV, NEUTRAL_UV_VALUE, (width + 1) / 2);
+ memset(dstU, NEUTRAL_UV_VALUE, (width + 1) / 2);
+ dstV += dstUVStride;
+ dstU += dstUVStride;
+ }
+ return;
+ }
+
for (size_t y = 0; y < (height + 1) / 2; ++y) {
for (size_t x = 0; x < (width + 1) / 2; ++x) {
dstU[x] = (uint8_t)(srcU[x] >> 2);
@@ -623,8 +651,16 @@
}
}
- // TODO(vigneshv): Add support for monochrome videos since AV1 supports it.
- CHECK(buffer->image_format == libgav1::kImageFormatYuv420);
+ if (!(buffer->image_format == libgav1::kImageFormatYuv420 ||
+ buffer->image_format == libgav1::kImageFormatMonochrome400)) {
+ ALOGE("image_format %d not supported", buffer->image_format);
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return false;
+ }
+ const bool isMonochrome =
+ buffer->image_format == libgav1::kImageFormatMonochrome400;
std::shared_ptr<C2GraphicBlock> block;
uint32_t format = HAL_PIXEL_FORMAT_YV12;
@@ -636,6 +672,13 @@
if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
+ if (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;
+ }
format = HAL_PIXEL_FORMAT_RGBA_1010102;
}
}
@@ -682,21 +725,18 @@
(uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
srcVStride / 2, dstYStride / sizeof(uint32_t), mWidth, mHeight);
} else {
- convertYUV420Planar16ToYUV420Planar(dstY, dstU, dstV,
- srcY, srcU, srcV,
- srcYStride / 2, srcUStride / 2, srcVStride / 2,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ convertYUV420Planar16ToYUV420Planar(
+ dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
+ srcVStride / 2, dstYStride, dstUVStride, mWidth, mHeight,
+ isMonochrome);
}
} else {
const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
- copyOutputBufferToYV12Frame(dstY, dstU, dstV,
- srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride,
- dstYStride, dstUVStride,
- mWidth, mHeight);
+ copyOutputBufferToYV12Frame(
+ dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride,
+ dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
}
finishWork(buffer->user_private_data, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/core/include/C2Work.h b/media/codec2/core/include/C2Work.h
index 67084cc..794402f 100644
--- a/media/codec2/core/include/C2Work.h
+++ b/media/codec2/core/include/C2Work.h
@@ -145,10 +145,35 @@
*/
FLAG_INCOMPLETE = (1 << 3),
/**
+ * This frame has been corrected due to a bitstream error. This is a hint, and in most cases
+ * can be ignored. This flag can be set by components on their output to signal the clients
+ * that errors may be present but the frame should be used nonetheless. It can also be set
+ * by clients to signal that the input frame has been corrected, but nonetheless should be
+ * processed.
+ */
+ FLAG_CORRECTED = (1 << 4),
+ /**
+ * This frame is corrupt due to a bitstream error. This is similar to FLAG_CORRECTED,
+ * with the exception that this is a hint that downstream components should not process this
+ * frame.
+ * <p>
+ * If set on the input by the client, the input is likely non-processable and should be
+ * handled similarly to uncorrectable bitstream error detected. For components that operat
+ * on whole access units, this flag can be propagated to the output. Other components should
+ * aim to detect access unit boundaries to determine if any part of the input frame can be
+ * processed.
+ * <p>
+ * If set by the component, this signals to the client that the output is non-usable -
+ * including possibly the metadata that may also be non-usable; -- however, the component
+ * will try to recover on successive input frames.
+ */
+ FLAG_CORRUPT = (1 << 5),
+
+ /**
* This frame contains only codec-specific configuration data, and no actual access unit.
*
- * \deprecated pass codec configuration with using the \todo codec-specific configuration
- * info together with the access unit.
+ * \deprecated pass codec configuration with using the C2InitData info parameter together
+ * with the access unit.
*/
FLAG_CODEC_CONFIG = (1u << 31),
};
diff --git a/media/codec2/sfplugin/utils/Codec2Mapper.cpp b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
index 00bf84f..4d939fa 100644
--- a/media/codec2/sfplugin/utils/Codec2Mapper.cpp
+++ b/media/codec2/sfplugin/utils/Codec2Mapper.cpp
@@ -92,6 +92,7 @@
ALookup<C2Config::bitrate_mode_t, int32_t> sBitrateModes = {
{ C2Config::BITRATE_CONST, BITRATE_MODE_CBR },
+ { C2Config::BITRATE_CONST_SKIP_ALLOWED, BITRATE_MODE_CBR_FD },
{ C2Config::BITRATE_VARIABLE, BITRATE_MODE_VBR },
{ C2Config::BITRATE_IGNORE, BITRATE_MODE_CQ },
};
diff --git a/media/libmediaformatshaper/VQApply.cpp b/media/libmediaformatshaper/VQApply.cpp
index 585ec6c..694182d 100644
--- a/media/libmediaformatshaper/VQApply.cpp
+++ b/media/libmediaformatshaper/VQApply.cpp
@@ -63,13 +63,36 @@
return 0;
}
+ // only proceed if we're in the handheld category.
+ // We embed this information within the codec record when we build up features
+ // and pass them in from MediaCodec; it's the easiest place to store it
+ //
+ // TODO: make a #define for ' _vq_eligible.device' here and in MediaCodec.cpp
+ //
+ int32_t isVQEligible = 0;
+ (void) codec->getFeatureValue("_vq_eligible.device", &isVQEligible);
+ ALOGD("minquality: are we eligible: %d", isVQEligible);
+ if (!isVQEligible) {
+ ALOGD("minquality: not an eligible device class");
+ return 0;
+ }
+
if (codec->supportedMinimumQuality() > 0) {
// allow the codec provided minimum quality behavior to work at it
ALOGD("minquality: codec claims to implement minquality=%d",
codec->supportedMinimumQuality());
+
+ // tell the underlying codec to do its thing; we won't try to second guess.
+ // default to 1, aka S_HANDHELD;
+ int32_t qualityTarget = 1;
+ (void) codec->getFeatureValue("_quality.target", &qualityTarget);
+ AMediaFormat_setInt32(inFormat, "android._encoding-quality-level", qualityTarget);
return 0;
}
+ // let the codec know that we'll be enforcing the minimum quality standards
+ AMediaFormat_setInt32(inFormat, "android._encoding-quality-level", 0);
+
//
// consider any and all tools available
// -- qp
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f2bcebb..c03236a 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -31,6 +31,8 @@
#include "include/SoftwareRenderer.h"
#include "PlaybackDurationAccumulator.h"
+#include <android/binder_manager.h>
+#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/media/omx/1.0/IGraphicBufferSource.h>
@@ -40,6 +42,7 @@
#include <android/binder_manager.h>
#include <android/dlext.h>
#include <binder/IMemory.h>
+#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <cutils/properties.h>
#include <gui/BufferQueue.h>
@@ -1697,6 +1700,7 @@
//
static android::mediaformatshaper::FormatShaperOps_t *sShaperOps = NULL;
+static bool sIsHandheld = true;
static bool connectFormatShaper() {
static std::once_flag sCheckOnce;
@@ -1770,6 +1774,64 @@
ALOGV("connectFormatShaper: loaded libraries: %" PRId64 " us",
(loading_finished - loading_started)/1000);
+
+ // we also want to know whether this is a handheld device
+ // start with assumption that the device is handheld.
+ sIsHandheld = true;
+ sp<IServiceManager> serviceMgr = defaultServiceManager();
+ sp<content::pm::IPackageManagerNative> packageMgr;
+ if (serviceMgr.get() != nullptr) {
+ sp<IBinder> binder = serviceMgr->waitForService(String16("package_native"));
+ packageMgr = interface_cast<content::pm::IPackageManagerNative>(binder);
+ }
+ // if we didn't get serviceMgr, we'll leave packageMgr as default null
+ if (packageMgr != nullptr) {
+
+ // MUST have these
+ static const String16 featuresNeeded[] = {
+ String16("android.hardware.touchscreen")
+ };
+ // these must be present to be a handheld
+ for (::android::String16 required : featuresNeeded) {
+ bool hasFeature = false;
+ binder::Status status = packageMgr->hasSystemFeature(required, 0, &hasFeature);
+ if (!status.isOk()) {
+ ALOGE("%s: hasSystemFeature failed: %s",
+ __func__, status.exceptionMessage().c_str());
+ continue;
+ }
+ ALOGV("feature %s says %d", String8(required).c_str(), hasFeature);
+ if (!hasFeature) {
+ ALOGV("... which means we are not handheld");
+ sIsHandheld = false;
+ break;
+ }
+ }
+
+ // MUST NOT have these
+ static const String16 featuresDisallowed[] = {
+ String16("android.hardware.type.automotive"),
+ String16("android.hardware.type.television"),
+ String16("android.hardware.type.watch")
+ };
+ // any of these present -- we aren't a handheld
+ for (::android::String16 forbidden : featuresDisallowed) {
+ bool hasFeature = false;
+ binder::Status status = packageMgr->hasSystemFeature(forbidden, 0, &hasFeature);
+ if (!status.isOk()) {
+ ALOGE("%s: hasSystemFeature failed: %s",
+ __func__, status.exceptionMessage().c_str());
+ continue;
+ }
+ ALOGV("feature %s says %d", String8(forbidden).c_str(), hasFeature);
+ if (hasFeature) {
+ ALOGV("... which means we are not handheld");
+ sIsHandheld = false;
+ break;
+ }
+ }
+ }
+
});
return true;
@@ -1848,6 +1910,18 @@
}
}
}
+
+ // we also carry in the codec description whether we are on a handheld device.
+ // this info is eventually used by both the Codec and the C2 machinery to inform
+ // the underlying codec whether to do any shaping.
+ //
+ if (sIsHandheld) {
+ // set if we are indeed a handheld device (or in future 'any eligible device'
+ // missing on devices that aren't eligible for minimum quality enforcement.
+ (void)(sShaperOps->setFeature)(shaperHandle, "_vq_eligible.device", 1);
+ // strictly speaking, it's a tuning, but those are strings and feature stores int
+ (void)(sShaperOps->setFeature)(shaperHandle, "_quality.target", 1 /* S_HANDHELD */);
+ }
}
status_t MediaCodec::setupFormatShaper(AString mediaType) {
@@ -1888,6 +1962,16 @@
// Format Shaping
// Mapping and Manipulation of encoding parameters
//
+// All of these decisions are pushed into the shaper instead of here within MediaCodec.
+// this includes decisions based on whether the codec implements minimum quality bars
+// itself or needs to be shaped outside of the codec.
+// This keeps all those decisions in one place.
+// It also means that we push some extra decision information (is this a handheld device
+// or one that is otherwise eligible for minimum quality manipulation, which generational
+// quality target is in force, etc). This allows those values to be cached in the
+// per-codec structures that are done 1 time within a process instead of for each
+// codec instantiation.
+//
status_t MediaCodec::shapeMediaFormat(
const sp<AMessage> &format,
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 6371769..4237e8c 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -557,12 +557,14 @@
}
constexpr int32_t BITRATE_MODE_CBR = 2;
+constexpr int32_t BITRATE_MODE_CBR_FD = 3;
constexpr int32_t BITRATE_MODE_CQ = 0;
constexpr int32_t BITRATE_MODE_VBR = 1;
inline static const char *asString_BitrateMode(int32_t i, const char *def = "??") {
switch (i) {
case BITRATE_MODE_CBR: return "CBR";
+ case BITRATE_MODE_CBR_FD: return "CBR_FD";
case BITRATE_MODE_CQ: return "CQ";
case BITRATE_MODE_VBR: return "VBR";
default: return def;
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 79b192e..e25658f 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -35,7 +35,6 @@
"android.hardware.media.omx@1.0",
"libandroidicu",
"libfmq",
- "libbase",
"libbinder",
"libhidlbase",
"liblog",
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index dc1b9b8..58e2d2a 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
-#include <android-base/properties.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
@@ -43,12 +42,6 @@
ResourceManagerService::instantiate();
registerExtensions();
::android::hardware::configureRpcThreadpool(16, false);
-
- if (!android::base::GetBoolProperty("ro.config.low_ram", false)) {
- // Start the media.transcoding service if the device is not low ram
- // device.
- android::base::SetProperty("ctl.start", "media.transcoding");
- }
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
::android::hardware::joinRpcThreadpool();
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index e387800..2a20981 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -132,10 +132,10 @@
void MediaTranscodingService::instantiate() {
std::shared_ptr<MediaTranscodingService> service =
::ndk::SharedRefBase::make<MediaTranscodingService>();
- binder_status_t status =
- AServiceManager_addService(service->asBinder().get(), getServiceName());
- if (status != STATUS_OK) {
- return;
+ if (__builtin_available(android __TRANSCODING_MIN_API__, *)) {
+ // Once service is started, we want it to stay even is client side perished.
+ AServiceManager_forceLazyServicesPersist(true /*persist*/);
+ (void)AServiceManager_registerLazyService(service->asBinder().get(), getServiceName());
}
}
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 20e4bfb..0cb2fad 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -481,7 +481,7 @@
// Need thread pool to receive callbacks, otherwise oneway callbacks are
// silently ignored.
ABinderProcess_startThreadPool();
- ::ndk::SpAIBinder binder(AServiceManager_getService("media.transcoding"));
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("media.transcoding"));
mService = IMediaTranscodingService::fromBinder(binder);
if (mService == nullptr) {
ALOGE("Failed to connect to the media.trascoding service.");