Merge "audio: add command to purge permission cache" 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/camera/Android.bp b/camera/Android.bp
index 2c01496..6878c20 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -119,6 +119,8 @@
"aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl",
"aidl/android/hardware/camera2/ICameraDeviceUser.aidl",
"aidl/android/hardware/camera2/ICameraOfflineSession.aidl",
+ "aidl/android/hardware/camera2/ICameraInjectionCallback.aidl",
+ "aidl/android/hardware/camera2/ICameraInjectionSession.aidl",
],
path: "aidl",
}
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 459ad15..873d738 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -20,6 +20,8 @@
import android.hardware.ICameraClient;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.ICameraDeviceCallbacks;
+import android.hardware.camera2.ICameraInjectionCallback;
+import android.hardware.camera2.ICameraInjectionSession;
import android.hardware.camera2.params.VendorTagDescriptor;
import android.hardware.camera2.params.VendorTagDescriptorCache;
import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
@@ -161,6 +163,9 @@
boolean supportsCameraApi(String cameraId, int apiVersion);
// Determines if a cameraId is a hidden physical camera of a logical multi-camera.
boolean isHiddenPhysicalCamera(String cameraId);
+ // Inject the external camera to replace the internal camera session.
+ ICameraInjectionSession injectCamera(String packageName, String internalCamId,
+ String externalCamId, in ICameraInjectionCallback CameraInjectionCallback);
void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
diff --git a/camera/aidl/android/hardware/camera2/ICameraInjectionCallback.aidl b/camera/aidl/android/hardware/camera2/ICameraInjectionCallback.aidl
new file mode 100644
index 0000000..9791352
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/ICameraInjectionCallback.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.hardware.camera2;
+
+import android.hardware.camera2.ICameraInjectionSession;
+
+/**
+ * Binder interface used to call back the error state injected by the external camera,
+ * and camera service can be switched back to internal camera when binder signals process death.
+ *
+ * @hide
+ */
+interface ICameraInjectionCallback
+{
+ // Error codes for onInjectionError
+ // To indicate all invalid error codes
+ const int ERROR_INJECTION_INVALID_ERROR = -1;
+ // To indicate the camera injection session has encountered a fatal error, such as injection
+ // init failure, configure failure or injecting failure etc.
+ const int ERROR_INJECTION_SESSION = 0;
+ // To indicate the camera service has encountered a fatal error.
+ const int ERROR_INJECTION_SERVICE = 1;
+ // To indicate the injection camera does not support certain camera functions, such as
+ // unsupport stream format, no capture/record function or no multi-camera function etc.
+ // When this error occurs, the default processing is still in the inject state, and the app is
+ // notified to display an error message and a black screen.
+ const int ERROR_INJECTION_UNSUPPORTED = 2;
+
+ oneway void onInjectionError(int errorCode);
+}
diff --git a/camera/aidl/android/hardware/camera2/ICameraInjectionSession.aidl b/camera/aidl/android/hardware/camera2/ICameraInjectionSession.aidl
new file mode 100644
index 0000000..c31c30b
--- /dev/null
+++ b/camera/aidl/android/hardware/camera2/ICameraInjectionSession.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.hardware.camera2;
+
+/** @hide */
+interface ICameraInjectionSession
+{
+ oneway void stopInjection();
+}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 20ffd48..d1b4ede 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -3578,7 +3578,7 @@
* android.scaler.availableInputOutputFormatsMap.</p>
* <p>The following table describes the minimum required output stream
* configurations based on the hardware level
- * (ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL):</p>
+ * (ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL), prior to Android 12:</p>
* <p>Format | Size | Hardware Level | Notes
* :-------------:|:--------------------------------------------:|:--------------:|:--------------:
* JPEG | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE | Any |
@@ -3589,6 +3589,21 @@
* YUV_420_888 | all output sizes available for JPEG | FULL |
* YUV_420_888 | all output sizes available for JPEG, up to the maximum video size | LIMITED |
* IMPLEMENTATION_DEFINED | same as YUV_420_888 | Any |</p>
+ * <p>Starting from Android 12, the camera device may not support JPEG sizes smaller than the
+ * minimum of 1080p and the camera sensor active array size. The requirements for
+ * IMPLEMENTATION_DEFINED and YUV_420_888 stay the same. This new minimum required output
+ * stream configurations are illustrated by the table below:</p>
+ * <p>Format | Size | Hardware Level | Notes
+ * :-------------:|:--------------------------------------------:|:--------------:|:--------------:
+ * JPEG | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE | Any |
+ * JPEG | 1920x1080 (1080p) | Any | if 1080p <= activeArraySize
+ * YUV_420_888 | ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE | FULL |
+ * YUV_420_888 | 1920x1080 (1080p) | FULL | if 1080p <= activeArraySize
+ * YUV_420_888 | 1280x720 (720) | FULL | if 720p <= activeArraySize
+ * YUV_420_888 | 640x480 (480p) | FULL | if 480p <= activeArraySize
+ * YUV_420_888 | 320x240 (240p) | FULL | if 240p <= activeArraySize
+ * YUV_420_888 | all output sizes available for FULL hardware level, up to the maximum video size | LIMITED |
+ * IMPLEMENTATION_DEFINED | same as YUV_420_888 | Any |</p>
* <p>Refer to ACAMERA_REQUEST_AVAILABLE_CAPABILITIES for additional
* mandatory stream configurations on a per-capability basis.</p>
* <p>Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 9308b81..cda23ff 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -29,7 +29,7 @@
namespace V2_0 {
namespace implementation {
-static constexpr int64_t kReceiveTimeoutUs = 1000000; // 100ms
+static constexpr int64_t kReceiveTimeoutUs = 2000000; // 2s
static constexpr int kPostMaxRetry = 3;
static constexpr int kCacheTtlUs = 1000000; // TODO: tune
static constexpr size_t kMaxCachedBufferCount = 64;
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index f8aa672..b312802 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -394,6 +394,7 @@
_C2_PL_VP9_BASE = 0x7000,
_C2_PL_DV_BASE = 0x8000,
_C2_PL_AV1_BASE = 0x9000,
+ _C2_PL_VP8_BASE = 0xA000,
C2_PROFILE_LEVEL_VENDOR_START = 0x70000000,
};
@@ -547,6 +548,12 @@
PROFILE_AV1_0 = _C2_PL_AV1_BASE, ///< AV1 Profile 0 (4:2:0, 8 to 10 bit)
PROFILE_AV1_1, ///< AV1 Profile 1 (8 to 10 bit)
PROFILE_AV1_2, ///< AV1 Profile 2 (8 to 12 bit)
+
+ // VP8 profiles
+ PROFILE_VP8_0 = _C2_PL_VP8_BASE, ///< VP8 Profile 0
+ PROFILE_VP8_1, ///< VP8 Profile 1
+ PROFILE_VP8_2, ///< VP8 Profile 2
+ PROFILE_VP8_3, ///< VP8 Profile 3
};
enum C2Config::level_t : uint32_t {
diff --git a/media/codec2/hidl/plugin/FilterWrapperStub.cpp b/media/codec2/hidl/plugin/FilterWrapperStub.cpp
index 1b94a1a..01ca596 100644
--- a/media/codec2/hidl/plugin/FilterWrapperStub.cpp
+++ b/media/codec2/hidl/plugin/FilterWrapperStub.cpp
@@ -42,10 +42,10 @@
}
c2_status_t FilterWrapper::createBlockPool(
- C2PlatformAllocatorStore::id_t,
- std::shared_ptr<const C2Component>,
- std::shared_ptr<C2BlockPool> *) {
- return C2_OMITTED;
+ C2PlatformAllocatorStore::id_t allocatorId,
+ std::shared_ptr<const C2Component> component,
+ std::shared_ptr<C2BlockPool> *pool) {
+ return CreateCodec2BlockPool(allocatorId, component, pool);
}
} // namespace android
diff --git a/media/codec2/sfplugin/C2OMXNode.cpp b/media/codec2/sfplugin/C2OMXNode.cpp
index f66dc11..c049187 100644
--- a/media/codec2/sfplugin/C2OMXNode.cpp
+++ b/media/codec2/sfplugin/C2OMXNode.cpp
@@ -90,6 +90,10 @@
}
}
+ void setPriority(int priority) {
+ androidSetThreadPriority(getTid(), priority);
+ }
+
protected:
bool threadLoop() override {
constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000; // 10ms
@@ -529,4 +533,8 @@
return *mDataspace.lock();
}
+void C2OMXNode::setPriority(int priority) {
+ mQueueThread->setPriority(priority);
+}
+
} // namespace android
diff --git a/media/codec2/sfplugin/C2OMXNode.h b/media/codec2/sfplugin/C2OMXNode.h
index 9c04969..6669318 100644
--- a/media/codec2/sfplugin/C2OMXNode.h
+++ b/media/codec2/sfplugin/C2OMXNode.h
@@ -98,6 +98,11 @@
*/
android_dataspace getDataspace();
+ /**
+ * Sets priority of the queue thread.
+ */
+ void setPriority(int priority);
+
private:
std::weak_ptr<Codec2Client::Component> mComp;
sp<IOMXBufferSource> mBufferSource;
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 15d2989..0a895b0 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -397,6 +397,14 @@
// consumer usage is queried earlier.
+ // priority
+ if (mConfig.mPriority != config.mPriority) {
+ if (config.mPriority != INT_MAX) {
+ mNode->setPriority(config.mPriority);
+ }
+ mConfig.mPriority = config.mPriority;
+ }
+
if (status.str().empty()) {
ALOGD("ISConfig not changed");
} else {
@@ -944,6 +952,7 @@
}
}
config->mISConfig->mUsage = 0;
+ config->mISConfig->mPriority = INT_MAX;
}
/*
@@ -1135,6 +1144,16 @@
configUpdate.push_back(std::move(qp));
}
+ int32_t background = 0;
+ if ((config->mDomain & Config::IS_VIDEO)
+ && msg->findInt32("android._background-mode", &background)
+ && background) {
+ androidSetThreadPriority(gettid(), ANDROID_PRIORITY_BACKGROUND);
+ if (config->mISConfig) {
+ config->mISConfig->mPriority = ANDROID_PRIORITY_BACKGROUND;
+ }
+ }
+
err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
if (err != OK) {
ALOGW("failed to configure c2 params");
diff --git a/media/codec2/sfplugin/InputSurfaceWrapper.h b/media/codec2/sfplugin/InputSurfaceWrapper.h
index 50d600c..44ba78a 100644
--- a/media/codec2/sfplugin/InputSurfaceWrapper.h
+++ b/media/codec2/sfplugin/InputSurfaceWrapper.h
@@ -79,6 +79,7 @@
float mFixedAdjustedFps = 0.0; // fixed fps via PTS manipulation
float mMinAdjustedFps = 0.0; // minimum fps via PTS manipulation
uint64_t mUsage = 0; // consumer usage
+ int mPriority = INT_MAX; // priority of queue thread (if any); INT_MAX for no-op
};
/**
diff --git a/media/codecs/m4v_h263/dec/test/Android.bp b/media/codecs/m4v_h263/dec/test/Android.bp
index 9459ed1..6eed66f 100644
--- a/media/codecs/m4v_h263/dec/test/Android.bp
+++ b/media/codecs/m4v_h263/dec/test/Android.bp
@@ -28,7 +28,24 @@
cc_test {
name: "Mpeg4H263DecoderTest",
gtest: true,
- test_suites: ["device-tests"],
+
+ test_suites: [
+ "device-tests",
+ "mts",
+ ],
+
+ // Support multilib variants (using different suffix per sub-architecture), which is needed on
+ // build targets with secondary architectures, as the MTS test suite packaging logic flattens
+ // all test artifacts into a single `testcases` directory.
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
srcs: [
"Mpeg4H263DecoderTest.cpp",
diff --git a/media/codecs/m4v_h263/dec/test/AndroidTest.xml b/media/codecs/m4v_h263/dec/test/AndroidTest.xml
index f572b0c..8bb4d1c 100755
--- a/media/codecs/m4v_h263/dec/test/AndroidTest.xml
+++ b/media/codecs/m4v_h263/dec/test/AndroidTest.xml
@@ -15,9 +15,10 @@
-->
<configuration description="Test module config for Mpeg4H263 Decoder unit tests">
<option name="test-suite-tag" value="Mpeg4H263DecoderTest" />
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="Mpeg4H263DecoderTest->/data/local/tmp/Mpeg4H263DecoderTest" />
+ <option name="append-bitness" value="true" />
<option name="push-file"
key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip?unzip=true"
value="/data/local/tmp/Mpeg4H263DecoderTestRes/" />
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index b1d72e8..416884e 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -62,6 +62,16 @@
#define ALAC_SPECIFIC_INFO_SIZE (36)
+// TODO : Remove the defines once mainline media is built against NDK >= 31.
+// The mp4 extractor is part of mainline and builds against NDK 29 as of
+// writing. These keys are available only from NDK 31:
+#define AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION \
+ "mpegh-profile-level-indication"
+#define AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT \
+ "mpegh-reference-channel-layout"
+#define AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS \
+ "mpegh-compatible-sets"
+
namespace android {
enum {
@@ -139,6 +149,7 @@
bool mIsHEVC;
bool mIsDolbyVision;
bool mIsAC4;
+ bool mIsMpegH = false;
bool mIsPcm;
size_t mNALLengthSize;
@@ -378,6 +389,10 @@
case FOURCC(".mp3"):
case 0x6D730055: // "ms U" mp3 audio
return MEDIA_MIMETYPE_AUDIO_MPEG;
+ case FOURCC("mha1"):
+ return MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1;
+ case FOURCC("mhm1"):
+ return MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1;
default:
ALOGW("Unknown fourcc: %c%c%c%c",
(fourcc >> 24) & 0xff,
@@ -1778,6 +1793,8 @@
case FOURCC("fLaC"):
case FOURCC(".mp3"):
case 0x6D730055: // "ms U" mp3 audio
+ case FOURCC("mha1"):
+ case FOURCC("mhm1"):
{
if (mIsQT && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
@@ -1977,7 +1994,94 @@
}
break;
}
+ case FOURCC("mhaC"):
+ {
+ // See ISO_IEC_23008-3;2019 MHADecoderConfigurationRecord
+ constexpr uint32_t mhac_header_size = 4 /* size */ + 4 /* boxtype 'mhaC' */
+ + 1 /* configurationVersion */ + 1 /* mpegh3daProfileLevelIndication */
+ + 1 /* referenceChannelLayout */ + 2 /* mpegh3daConfigLength */;
+ uint8_t mhac_header[mhac_header_size];
+ off64_t data_offset = *offset;
+ if (chunk_size < sizeof(mhac_header)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(data_offset, mhac_header, sizeof(mhac_header))
+ < (ssize_t)sizeof(mhac_header)) {
+ return ERROR_IO;
+ }
+
+ //get mpegh3daProfileLevelIndication
+ const uint32_t mpegh3daProfileLevelIndication = mhac_header[9];
+ AMediaFormat_setInt32(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION,
+ mpegh3daProfileLevelIndication);
+
+ //get referenceChannelLayout
+ const uint32_t referenceChannelLayout = mhac_header[10];
+ AMediaFormat_setInt32(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT,
+ referenceChannelLayout);
+
+ // get mpegh3daConfigLength
+ const uint32_t mhac_config_size = U16_AT(&mhac_header[11]);
+ if (chunk_size != sizeof(mhac_header) + mhac_config_size) {
+ return ERROR_MALFORMED;
+ }
+
+ data_offset += sizeof(mhac_header);
+ uint8_t mhac_config[mhac_config_size];
+ if (mDataSource->readAt(data_offset, mhac_config, sizeof(mhac_config))
+ < (ssize_t)sizeof(mhac_config)) {
+ return ERROR_IO;
+ }
+
+ AMediaFormat_setBuffer(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_CSD_0, mhac_config, sizeof(mhac_config));
+ data_offset += sizeof(mhac_config);
+ *offset = data_offset;
+ break;
+ }
+ case FOURCC("mhaP"):
+ {
+ // FDAmd_2 of ISO_IEC_23008-3;2019 MHAProfileAndLevelCompatibilitySetBox
+ constexpr uint32_t mhap_header_size = 4 /* size */ + 4 /* boxtype 'mhaP' */
+ + 1 /* numCompatibleSets */;
+
+ uint8_t mhap_header[mhap_header_size];
+ off64_t data_offset = *offset;
+
+ if (chunk_size < (ssize_t)mhap_header_size) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(data_offset, mhap_header, sizeof(mhap_header))
+ < (ssize_t)sizeof(mhap_header)) {
+ return ERROR_IO;
+ }
+
+ // mhap_compatible_sets_size = numCompatibleSets * sizeof(uint8_t)
+ const uint32_t mhap_compatible_sets_size = mhap_header[8];
+ if (chunk_size != sizeof(mhap_header) + mhap_compatible_sets_size) {
+ return ERROR_MALFORMED;
+ }
+
+ data_offset += sizeof(mhap_header);
+ uint8_t mhap_compatible_sets[mhap_compatible_sets_size];
+ if (mDataSource->readAt(
+ data_offset, mhap_compatible_sets, sizeof(mhap_compatible_sets))
+ < (ssize_t)sizeof(mhap_compatible_sets)) {
+ return ERROR_IO;
+ }
+
+ AMediaFormat_setBuffer(mLastTrack->meta,
+ AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS,
+ mhap_compatible_sets, sizeof(mhap_compatible_sets));
+ data_offset += sizeof(mhap_compatible_sets);
+ *offset = data_offset;
+ break;
+ }
case FOURCC("mp4v"):
case FOURCC("encv"):
case FOURCC("s263"):
@@ -5001,6 +5105,8 @@
bool success = AMediaFormat_getString(mFormat, AMEDIAFORMAT_KEY_MIME, &mime);
CHECK(success);
+ mIsMpegH = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1) ||
+ !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1);
mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
mIsHEVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
@@ -6072,10 +6178,11 @@
}
uint32_t syncSampleIndex = sampleIndex;
- // assume every non-USAC audio sample is a sync sample. This works around
+ // assume every non-USAC/non-MPEGH audio sample is a sync sample.
+ // This works around
// seek issues with files that were incorrectly written with an
// empty or single-sample stss block for the audio track
- if (err == OK && (!mIsAudio || mIsUsac)) {
+ if (err == OK && (!mIsAudio || mIsUsac || mIsMpegH)) {
err = mSampleTable->findSyncSampleNear(
sampleIndex, &syncSampleIndex, findFlags);
}
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index 901b29d..9e94587 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -440,19 +440,22 @@
int64_t seekTimeUs;
ReadOptions::SeekMode mode;
if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
- int64_t pos = 0;
-
+ int64_t pos;
+ int64_t sampleNumber;
+ bool overflowed = __builtin_mul_overflow(seekTimeUs, mSampleRate, &sampleNumber);
+ sampleNumber /= 1000000;
if (mWaveFormat == WAVE_FORMAT_MSGSM) {
// 65 bytes decode to 320 8kHz samples
- int64_t samplenumber = (seekTimeUs * mSampleRate) / 1000000;
- int64_t framenumber = samplenumber / 320;
- pos = framenumber * 65;
+ pos = sampleNumber / 320 * 65;
} else {
- pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * (mBitsPerSample >> 3);
+ int64_t bytesPerFrame;
+ overflowed |= __builtin_mul_overflow(mNumChannels, mBitsPerSample >> 3, &bytesPerFrame);
+ overflowed |= __builtin_mul_overflow(bytesPerFrame, sampleNumber, &pos);
}
- if (pos > (off64_t)mSize) {
- pos = mSize;
+ if (overflowed) {
+ return AMEDIA_ERROR_MALFORMED;
}
+ pos = std::clamp(pos, (int64_t) 0, (int64_t) mSize);
mCurrentPos = pos + mOffset;
}
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index b2056ad..e471c7b 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -45,6 +45,12 @@
enabled: false,
},
},
+ header_libs: [
+ "libbinder_headers",
+ ],
+ export_header_lib_headers: [
+ "libbinder_headers",
+ ],
apex_available: [
"//apex_available:platform",
"com.android.media",
diff --git a/media/libmediatranscoding/TranscoderWrapper.cpp b/media/libmediatranscoding/TranscoderWrapper.cpp
index b19e711..5e4c671 100644
--- a/media/libmediatranscoding/TranscoderWrapper.cpp
+++ b/media/libmediatranscoding/TranscoderWrapper.cpp
@@ -23,6 +23,7 @@
#include <media/NdkCommon.h>
#include <media/TranscoderWrapper.h>
#include <media/TranscodingRequest.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <thread>
@@ -599,6 +600,7 @@
}
void TranscoderWrapper::threadLoop() {
+ androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
std::unique_lock<std::mutex> lock{mLock};
// TranscoderWrapper currently lives in the transcoding service, as long as
// MediaTranscodingService itself.
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index 9705f3c..ea3e518 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <media/TranscodingSessionController.h>
#include <media/TranscodingUidPolicy.h>
+#include <utils/AndroidThreads.h>
#include <utils/Log.h>
#include <thread>
@@ -162,6 +163,7 @@
// Unfortunately std::unique_lock is incompatible with -Wthread-safety.
void TranscodingSessionController::Watchdog::threadLoop() NO_THREAD_SAFETY_ANALYSIS {
+ androidSetThreadPriority(0 /*tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
std::unique_lock<std::mutex> lock{mLock};
while (!mAbort) {
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index d6ae0f3..e931cc1 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -19,8 +19,10 @@
#include <android-base/logging.h>
#include <media/MediaSampleWriter.h>
+#include <media/NdkCommon.h>
#include <media/NdkMediaMuxer.h>
#include <sys/prctl.h>
+#include <utils/AndroidThreads.h>
namespace android {
@@ -125,7 +127,15 @@
LOG(ERROR) << "Muxer needs to be initialized when adding tracks.";
return nullptr;
}
- ssize_t trackIndexOrError = mMuxer->addTrack(trackFormat.get());
+
+ AMediaFormat* trackFormatCopy = AMediaFormat_new();
+ AMediaFormat_copy(trackFormatCopy, trackFormat.get());
+ // Request muxer to use background priorities by default.
+ AMediaFormatUtils::SetDefaultFormatValueInt32(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE,
+ trackFormatCopy, 1 /* true */);
+
+ ssize_t trackIndexOrError = mMuxer->addTrack(trackFormatCopy);
+ AMediaFormat_delete(trackFormatCopy);
if (trackIndexOrError < 0) {
LOG(ERROR) << "Failed to add media track to muxer: " << trackIndexOrError;
return nullptr;
@@ -174,6 +184,7 @@
mState = STARTED;
std::thread([this] {
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
prctl(PR_SET_NAME, (unsigned long)"SampleWriterTrd", 0, 0, 0);
bool wasStopped = false;
diff --git a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
index 15f7427..f01a948 100644
--- a/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTrackTranscoder.cpp
@@ -20,6 +20,7 @@
#include <android-base/logging.h>
#include <media/MediaTrackTranscoder.h>
#include <media/MediaTrackTranscoderCallback.h>
+#include <utils/AndroidThreads.h>
namespace android {
@@ -72,6 +73,7 @@
mState = STARTED;
std::thread([this] {
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
bool stopped = false;
media_status_t status = runTranscodeLoop(&stopped);
diff --git a/media/libmediatranscoding/transcoder/NdkCommon.cpp b/media/libmediatranscoding/transcoder/NdkCommon.cpp
index 2d85df7..e133cd6 100644
--- a/media/libmediatranscoding/transcoder/NdkCommon.cpp
+++ b/media/libmediatranscoding/transcoder/NdkCommon.cpp
@@ -42,6 +42,7 @@
/* TODO(lnilsson): Finalize value or adopt AMediaFormat key once available. */
const char* TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST = "color-transfer-request";
+const char* TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE = "android._background-mode";
namespace AMediaFormatUtils {
diff --git a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
index af4ef69..b43efcb 100644
--- a/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp
@@ -253,6 +253,10 @@
// MediaSampleWriter track format, and MediaSampleWriter will call AMediaMuxer_setOrientationHint.
AMediaFormat_setInt32(encoderFormat, AMEDIAFORMAT_KEY_ROTATION, 0);
+ // Request encoder to use background priorities by default.
+ SetDefaultFormatValueInt32(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, encoderFormat,
+ 1 /* true */);
+
mDestinationFormat = std::shared_ptr<AMediaFormat>(encoderFormat, &AMediaFormat_delete);
// Create and configure the encoder.
@@ -334,6 +338,7 @@
static const std::vector<EntryCopier> kEncoderEntriesToCopy{
ENTRY_COPIER2(AMEDIAFORMAT_KEY_OPERATING_RATE, Float, Int32),
ENTRY_COPIER(AMEDIAFORMAT_KEY_PRIORITY, Int32),
+ ENTRY_COPIER(TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE, Int32),
};
CopyFormatEntries(mDestinationFormat.get(), decoderFormat.get(), kEncoderEntriesToCopy);
diff --git a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
index ac3b2c0..8f8ad4e 100644
--- a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
+++ b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
@@ -113,6 +113,16 @@
// Asset directory
static const std::string kAssetDirectory = "/data/local/tmp/TranscodingBenchmark/";
+ // Transcoding configuration params to be logged
+ int64_t trackDurationUs = 0;
+ int32_t width = 0;
+ int32_t height = 0;
+ std::string sourceMime = "NA";
+ std::string targetMime = "NA";
+ bool includeAudio = false;
+ bool transcodeVideo = false;
+ int32_t targetBitrate = 0;
+
int srcFd = 0;
int dstFd = 0;
@@ -163,10 +173,30 @@
state.counters[PARAM_VIDEO_FRAME_RATE] = benchmark::Counter(
frameCount, benchmark::Counter::kIsIterationInvariantRate);
}
+ if (!AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_WIDTH, &width)) {
+ state.SkipWithError("Video source track format does not have width");
+ goto exit;
+ }
+ if (!AMediaFormat_getInt32(srcFormat, AMEDIAFORMAT_KEY_HEIGHT, &height)) {
+ state.SkipWithError("Video source track format does not have height");
+ goto exit;
+ }
+ AMediaFormat_getInt64(srcFormat, AMEDIAFORMAT_KEY_DURATION, &trackDurationUs);
+ sourceMime = mime;
}
if (trackSelectionCallback(mime, &dstFormat)) {
status = transcoder->configureTrackFormat(i, dstFormat);
+ if (strncmp(mime, "video/", 6) == 0 && dstFormat != nullptr) {
+ const char* mime = nullptr;
+ if (AMediaFormat_getString(dstFormat, AMEDIAFORMAT_KEY_MIME, &mime)) {
+ targetMime = mime;
+ }
+ AMediaFormat_getInt32(dstFormat, AMEDIAFORMAT_KEY_BIT_RATE, &targetBitrate);
+ transcodeVideo = true;
+ } else if (strncmp(mime, "audio/", 6) == 0) {
+ includeAudio = true;
+ }
}
if (dstFormat != nullptr) {
@@ -195,6 +225,17 @@
}
}
+ // Set transcoding configuration params in benchmark label
+ state.SetLabel(srcFileName + "," +
+ std::to_string(width) + "x" + std::to_string(height) + "," +
+ sourceMime + "," +
+ std::to_string(trackDurationUs/1000) + "," +
+ (includeAudio ? "Yes" : "No") + "," +
+ (transcodeVideo ? "Yes" : "No") + "," +
+ targetMime + "," +
+ std::to_string(targetBitrate)
+ );
+
exit:
if (srcFd > 0) close(srcFd);
if (dstFd > 0) close(dstFd);
@@ -543,7 +584,11 @@
void PrintRunData(const Run& report);
bool mPrintedHeader;
- std::vector<std::string> mHeaders = {"name", "real_time", "cpu_time", PARAM_VIDEO_FRAME_RATE};
+ std::vector<std::string> mHeaders = {
+ "File", "Resolution", "SourceMime", "VideoTrackDuration(ms)",
+ "IncludeAudio", "TranscodeVideo", "TargetMime", "TargetBirate(bps)",
+ "real_time(ms)", "cpu_time(ms)", PARAM_VIDEO_FRAME_RATE
+ };
};
bool CustomCsvReporter::ReportContext(const Context& context __unused) {
@@ -574,7 +619,8 @@
return;
}
std::ostream& Out = GetOutputStream();
- Out << run.benchmark_name() << ",";
+ // Log the transcoding params reported through label
+ Out << run.report_label << ",";
Out << run.GetAdjustedRealTime() << ",";
Out << run.GetAdjustedCPUTime() << ",";
auto frameRate = run.counters.find(PARAM_VIDEO_FRAME_RATE);
diff --git a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
index c5547c6..2441922 100644
--- a/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
+++ b/media/libmediatranscoding/transcoder/include/media/NdkCommon.h
@@ -59,6 +59,7 @@
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_VIDEO_BITRATE;
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES;
extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_COLOR_TRANSFER_REQUEST;
+extern const char* TBD_AMEDIACODEC_PARAMETER_KEY_BACKGROUND_MODE;
static constexpr int TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME = 0x1;
static constexpr int kBitrateModeConstant = 2;
diff --git a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
index 8b3905c..0a8a06e 100644
--- a/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
+++ b/media/libmediatranscoding/transcoder/tests/MediaSampleWriterTests.cpp
@@ -117,8 +117,9 @@
}
bool operator==(const TestMuxer::Event& lhs, const TestMuxer::Event& rhs) {
- return lhs.type == rhs.type && lhs.format == rhs.format && lhs.trackIndex == rhs.trackIndex &&
- lhs.data == rhs.data && lhs.info == rhs.info;
+ // Don't test format pointer equality since the writer can make a copy.
+ return lhs.type == rhs.type /*&& lhs.format == rhs.format*/ &&
+ lhs.trackIndex == rhs.trackIndex && lhs.data == rhs.data && lhs.info == rhs.info;
}
/** Represents a media source file. */
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 5c39239..7c7fcac 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -522,6 +522,7 @@
// Reset following variables for all the sessions and they will be
// initialized in start(MetaData *param).
mIsRealTimeRecording = true;
+ mIsBackgroundMode = false;
mUse4ByteNalLength = true;
mOffset = 0;
mMaxOffsetAppend = 0;
@@ -662,6 +663,14 @@
sp<MetaData> meta = source->getFormat();
meta->findCString(kKeyMIMEType, &mime);
+
+ // Background mode for media transcoding. If either audio or video track signal this is in
+ // background mode, we will set all the threads to run in background priority.
+ int32_t isBackgroundMode;
+ if (meta && meta->findInt32(kKeyBackgroundMode, &isBackgroundMode)) {
+ mIsBackgroundMode |= isBackgroundMode;
+ }
+
if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
@@ -2309,7 +2318,11 @@
if (mLooper == nullptr) {
mLooper = new ALooper;
mLooper->setName("MP4WtrCtrlHlpLooper");
- err = mLooper->start();
+ if (mIsBackgroundMode) {
+ err = mLooper->start(false, false, ANDROID_PRIORITY_BACKGROUND);
+ } else {
+ err = mLooper->start();
+ }
mReflector = new AHandlerReflector<MPEG4Writer>(this);
mLooper->registerHandler(mReflector);
}
@@ -2778,6 +2791,11 @@
prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
+ if (mIsBackgroundMode) {
+ // Background priority for media transcoding.
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
+ }
+
Mutex::Autolock autoLock(mLock);
while (!mDone) {
Chunk chunk;
@@ -3379,6 +3397,9 @@
if (mOwner->isRealTimeRecording()) {
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+ } else if (mOwner->isBackgroundMode()) {
+ // Background priority for media transcoding.
+ androidSetThreadPriority(0 /* tid (0 = current) */, ANDROID_PRIORITY_BACKGROUND);
}
sp<MetaData> meta_data;
@@ -4076,6 +4097,10 @@
return mIsRealTimeRecording;
}
+bool MPEG4Writer::isBackgroundMode() const {
+ return mIsBackgroundMode;
+}
+
bool MPEG4Writer::useNalLengthFour() {
return mUse4ByteNalLength;
}
@@ -5393,4 +5418,4 @@
endBox();
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 50ebeef..6b2e7be 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -102,6 +102,17 @@
static const char *kCodecWidth = "android.media.mediacodec.width"; /* 0..n */
static const char *kCodecHeight = "android.media.mediacodec.height"; /* 0..n */
static const char *kCodecRotation = "android.media.mediacodec.rotation-degrees"; /* 0/90/180/270 */
+static const char *kCodecColorFormat = "android.media.mediacodec.color-format";
+static const char *kCodecFrameRate = "android.media.mediacodec.frame-rate";
+static const char *kCodecCaptureRate = "android.media.mediacodec.capture-rate";
+static const char *kCodecOperatingRate = "android.media.mediacodec.operating-rate";
+static const char *kCodecPriority = "android.media.mediacodec.priority";
+static const char *kCodecRequestedVideoQPIMin = "android.media.mediacodec.video-qp-i-min";
+static const char *kCodecRequestedVideoQPIMax = "android.media.mediacodec.video-qp-i-max";
+static const char *kCodecRequestedVideoQPPMin = "android.media.mediacodec.video-qp-p-min";
+static const char *kCodecRequestedVideoQPPMax = "android.media.mediacodec.video-qp-p-max";
+static const char *kCodecRequestedVideoQPBMin = "android.media.mediacodec.video-qp-b-min";
+static const char *kCodecRequestedVideoQPBMax = "android.media.mediacodec.video-qp-b-max";
// NB: These are not yet exposed as public Java API constants.
static const char *kCodecCrypto = "android.media.mediacodec.crypto"; /* 0,1 */
@@ -131,6 +142,8 @@
static const char *kCodecSampleRate = "android.media.mediacodec.sampleRate";
static const char *kCodecVideoEncodedBytes = "android.media.mediacodec.vencode.bytes";
static const char *kCodecVideoEncodedFrames = "android.media.mediacodec.vencode.frames";
+static const char *kCodecVideoInputBytes = "android.media.mediacodec.video.input.bytes";
+static const char *kCodecVideoInputFrames = "android.media.mediacodec.video.input.frames";
static const char *kCodecVideoEncodedDurationUs = "android.media.mediacodec.vencode.durationUs";
// the kCodecRecent* fields appear only in getMetrics() results
@@ -841,6 +854,8 @@
}
mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedDurationUs, duration);
mediametrics_setInt64(mMetricsHandle, kCodecVideoEncodedFrames, mFramesEncoded);
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoInputFrames, mFramesInput);
+ mediametrics_setInt64(mMetricsHandle, kCodecVideoInputBytes, mBytesInput);
}
{
@@ -1053,7 +1068,7 @@
}
// when we send a buffer to the codec;
-void MediaCodec::statsBufferSent(int64_t presentationUs) {
+void MediaCodec::statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer) {
// only enqueue if we have a legitimate time
if (presentationUs <= 0) {
@@ -1067,6 +1082,11 @@
});
}
+ if (mIsVideo && (mFlags & kFlagIsEncoder)) {
+ mBytesInput += buffer->size();
+ mFramesInput++;
+ }
+
const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
BufferFlightTiming_t startdata = { presentationUs, nowNs };
@@ -1450,6 +1470,50 @@
if (format->findInt32("max-height", &maxHeight)) {
mediametrics_setInt32(mMetricsHandle, kCodecMaxHeight, maxHeight);
}
+ int32_t colorFormat = -1;
+ if (format->findInt32("color-format", &colorFormat)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecColorFormat, colorFormat);
+ }
+ float frameRate = -1.0;
+ if (format->findFloat("frame-rate", &frameRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecFrameRate, frameRate);
+ }
+ float captureRate = -1.0;
+ if (format->findFloat("capture-rate", &captureRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecCaptureRate, captureRate);
+ }
+ float operatingRate = -1.0;
+ if (format->findFloat("operating-rate", &operatingRate)) {
+ mediametrics_setDouble(mMetricsHandle, kCodecOperatingRate, operatingRate);
+ }
+ int32_t priority = -1;
+ if (format->findInt32("priority", &priority)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecPriority, priority);
+ }
+ int32_t qpIMin = -1;
+ if (format->findInt32("video-qp-i-min", &qpIMin)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMin, qpIMin);
+ }
+ int32_t qpIMax = -1;
+ if (format->findInt32("video-qp-i-max", &qpIMax)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPIMax, qpIMax);
+ }
+ int32_t qpPMin = -1;
+ if (format->findInt32("video-qp-p-min", &qpPMin)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMin, qpPMin);
+ }
+ int32_t qpPMax = -1;
+ if (format->findInt32("video-qp-p-max", &qpPMax)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPPMax, qpPMax);
+ }
+ int32_t qpBMin = -1;
+ if (format->findInt32("video-qp-b-min", &qpBMin)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMin, qpBMin);
+ }
+ int32_t qpBMax = -1;
+ if (format->findInt32("video-qp-b-max", &qpBMax)) {
+ mediametrics_setInt32(mMetricsHandle, kCodecRequestedVideoQPBMax, qpBMax);
+ }
}
// Prevent possible integer overflow in downstream code.
@@ -3518,6 +3582,11 @@
mTunneled = false;
}
+ int32_t background = 0;
+ if (format->findInt32("android._background-mode", &background) && background) {
+ androidSetThreadPriority(gettid(), ANDROID_PRIORITY_BACKGROUND);
+ }
+
mCodec->initiateConfigureComponent(format);
break;
}
@@ -4659,7 +4728,7 @@
info->mOwnedByClient = false;
info->mData.clear();
- statsBufferSent(timeUs);
+ statsBufferSent(timeUs, buffer);
}
return err;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index b381033..4c18f87 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -47,6 +47,16 @@
#include <media/AudioParameter.h>
#include <system/audio.h>
+// TODO : Remove the defines once mainline media is built against NDK >= 31.
+// The mp4 extractor is part of mainline and builds against NDK 29 as of
+// writing. These keys are available only from NDK 31:
+#define AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION \
+ "mpegh-profile-level-indication"
+#define AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT \
+ "mpegh-reference-channel-layout"
+#define AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS \
+ "mpegh-compatible-sets"
+
namespace android {
static status_t copyNALUToABuffer(sp<ABuffer> *buffer, const uint8_t *ptr, size_t length) {
@@ -1085,6 +1095,25 @@
msg->setInt32("is-adts", isADTS);
}
+ int32_t mpeghProfileLevelIndication;
+ if (meta->findInt32(kKeyMpeghProfileLevelIndication, &mpeghProfileLevelIndication)) {
+ msg->setInt32(AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION,
+ mpeghProfileLevelIndication);
+ }
+ int32_t mpeghReferenceChannelLayout;
+ if (meta->findInt32(kKeyMpeghReferenceChannelLayout, &mpeghReferenceChannelLayout)) {
+ msg->setInt32(AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT,
+ mpeghReferenceChannelLayout);
+ }
+ if (meta->findData(kKeyMpeghCompatibleSets, &type, &data, &size)) {
+ sp<ABuffer> buffer = new (std::nothrow) ABuffer(size);
+ if (buffer.get() == NULL || buffer->base() == NULL) {
+ return NO_MEMORY;
+ }
+ msg->setBuffer(AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS, buffer);
+ memcpy(buffer->data(), data, size);
+ }
+
int32_t aacProfile = -1;
if (meta->findInt32(kKeyAACAOT, &aacProfile)) {
msg->setInt32("aac-profile", aacProfile);
@@ -1707,6 +1736,12 @@
meta->setInt32(kKeyIsSyncFrame, 1);
}
+ // Mode for media transcoding.
+ int32_t isBackgroundMode;
+ if (msg->findInt32("android._background-mode", &isBackgroundMode) && isBackgroundMode != 0) {
+ meta->setInt32(isBackgroundMode, 1);
+ }
+
int32_t avgBitrate = 0;
int32_t maxBitrate;
if (msg->findInt32("bitrate", &avgBitrate) && avgBitrate > 0) {
@@ -1844,6 +1879,23 @@
meta->setInt32(kKeyIsADTS, isADTS);
}
+ int32_t mpeghProfileLevelIndication = -1;
+ if (msg->findInt32(AMEDIAFORMAT_KEY_MPEGH_PROFILE_LEVEL_INDICATION,
+ &mpeghProfileLevelIndication)) {
+ meta->setInt32(kKeyMpeghProfileLevelIndication, mpeghProfileLevelIndication);
+ }
+ int32_t mpeghReferenceChannelLayout = -1;
+ if (msg->findInt32(AMEDIAFORMAT_KEY_MPEGH_REFERENCE_CHANNEL_LAYOUT,
+ &mpeghReferenceChannelLayout)) {
+ meta->setInt32(kKeyMpeghReferenceChannelLayout, mpeghReferenceChannelLayout);
+ }
+ sp<ABuffer> mpeghCompatibleSets;
+ if (msg->findBuffer(AMEDIAFORMAT_KEY_MPEGH_COMPATIBLE_SETS,
+ &mpeghCompatibleSets)) {
+ meta->setData(kKeyMpeghCompatibleSets, kTypeHCOS,
+ mpeghCompatibleSets->data(), mpeghCompatibleSets->size());
+ }
+
int32_t aacProfile = -1;
if (msg->findInt32("aac-profile", &aacProfile)) {
meta->setInt32(kKeyAACAOT, aacProfile);
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index c216bc5..ada5d81 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -58,6 +58,8 @@
const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC = "audio/eac3-joc";
const char *MEDIA_MIMETYPE_AUDIO_AC4 = "audio/ac4";
+const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1 = "audio/mha1";
+const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1 = "audio/mhm1";
const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index e96243e..7644a9a 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -60,6 +60,8 @@
extern const char *MEDIA_MIMETYPE_AUDIO_EAC3;
extern const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC;
extern const char *MEDIA_MIMETYPE_AUDIO_AC4;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1;
extern const char *MEDIA_MIMETYPE_AUDIO_SCRAMBLED;
extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index e97f6eb..b7c9062 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -234,9 +234,11 @@
}
// first handle global unsynchronization
+ bool hasGlobalUnsync = false;
if (header.flags & 0x80) {
ALOGV("removing unsynchronization");
+ hasGlobalUnsync = true;
removeUnsynchronization();
}
@@ -341,12 +343,12 @@
memcpy(copy, mData, size);
- bool success = removeUnsynchronizationV2_4(false /* iTunesHack */);
+ bool success = removeUnsynchronizationV2_4(false /* iTunesHack */, hasGlobalUnsync);
if (!success) {
memcpy(mData, copy, size);
mSize = size;
- success = removeUnsynchronizationV2_4(true /* iTunesHack */);
+ success = removeUnsynchronizationV2_4(true /* iTunesHack */, hasGlobalUnsync);
if (success) {
ALOGV("Had to apply the iTunes hack to parse this ID3 tag");
@@ -407,7 +409,7 @@
}
}
-bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) {
+bool ID3::removeUnsynchronizationV2_4(bool iTunesHack, bool hasGlobalUnsync) {
size_t oldSize = mSize;
size_t offset = mFirstFrameOffset;
@@ -443,7 +445,7 @@
flags &= ~1;
}
- if ((flags & 2) && (dataSize >= 2)) {
+ if (!hasGlobalUnsync && (flags & 2) && (dataSize >= 2)) {
// This frame has "unsynchronization", so we have to replace occurrences
// of 0xff 0x00 with just 0xff in order to get the real data.
diff --git a/media/libstagefright/id3/test/AndroidTest.xml b/media/libstagefright/id3/test/AndroidTest.xml
index d6ea470..50f9253 100644
--- a/media/libstagefright/id3/test/AndroidTest.xml
+++ b/media/libstagefright/id3/test/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="ID3Test->/data/local/tmp/ID3Test" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test-1.1.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test-1.2.zip?unzip=true"
value="/data/local/tmp/ID3TestRes/" />
</target_preparer>
diff --git a/media/libstagefright/id3/test/ID3Test.cpp b/media/libstagefright/id3/test/ID3Test.cpp
index 8db83cb..1ceeb6a 100644
--- a/media/libstagefright/id3/test/ID3Test.cpp
+++ b/media/libstagefright/id3/test/ID3Test.cpp
@@ -135,6 +135,7 @@
} else {
ASSERT_EQ(data, nullptr) << "Found album art when expected none!";
}
+
#if (LOG_NDEBUG == 0)
hexdump(data, dataSize > 128 ? 128 : dataSize);
#endif
@@ -186,7 +187,8 @@
"bbb_1sec_v23_3tags.mp3",
"bbb_1sec_v1_5tags.mp3",
"bbb_2sec_v24_unsynchronizedOneFrame.mp3",
- "bbb_2sec_v24_unsynchronizedAllFrames.mp3"));
+ "bbb_2sec_v24_unsynchronizedAllFrames.mp3",
+ "idv24_unsynchronized.mp3"));
INSTANTIATE_TEST_SUITE_P(
id3TestAll, ID3versionTest,
@@ -201,7 +203,8 @@
make_pair("bbb_1sec_v1_5tags.mp3", ID3::ID3_V1_1),
make_pair("bbb_1sec_v1_3tags.mp3", ID3::ID3_V1_1),
make_pair("bbb_2sec_v24_unsynchronizedOneFrame.mp3", ID3::ID3_V2_4),
- make_pair("bbb_2sec_v24_unsynchronizedAllFrames.mp3", ID3::ID3_V2_4)));
+ make_pair("bbb_2sec_v24_unsynchronizedAllFrames.mp3", ID3::ID3_V2_4),
+ make_pair("idv24_unsynchronized.mp3", ID3::ID3_V2_4)));
INSTANTIATE_TEST_SUITE_P(
id3TestAll, ID3textTagTest,
@@ -227,7 +230,9 @@
make_pair("bbb_2sec_1_image.mp3", true),
make_pair("bbb_2sec_2_image.mp3", true),
make_pair("bbb_2sec_largeSize.mp3", true),
- make_pair("bbb_1sec_v1_5tags.mp3", false)));
+ make_pair("bbb_1sec_v1_5tags.mp3", false),
+ make_pair("idv24_unsynchronized.mp3", true)
+ ));
INSTANTIATE_TEST_SUITE_P(id3TestAll, ID3multiAlbumArtTest,
::testing::Values(make_pair("bbb_1sec_v23.mp3", 0),
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 0be5896..bd0d27c 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -91,7 +91,7 @@
bool parseV1(DataSourceBase *source);
bool parseV2(DataSourceBase *source, off64_t offset);
void removeUnsynchronization();
- bool removeUnsynchronizationV2_4(bool iTunesHack);
+ bool removeUnsynchronizationV2_4(bool iTunesHack, bool hasGlobalUnsync);
static bool ParseSyncsafeInteger(const uint8_t encoded[4], size_t *x);
diff --git a/media/libstagefright/include/media/stagefright/MPEG4Writer.h b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
index 7f2728e..7c3eca6 100644
--- a/media/libstagefright/include/media/stagefright/MPEG4Writer.h
+++ b/media/libstagefright/include/media/stagefright/MPEG4Writer.h
@@ -97,6 +97,7 @@
sp<MetaData> mStartMeta;
status_t mInitCheck;
bool mIsRealTimeRecording;
+ bool mIsBackgroundMode;
bool mUse4ByteNalLength;
bool mIsFileSizeLimitExplicitlyRequested;
bool mPaused;
@@ -275,6 +276,10 @@
// By default, real time recording is on.
bool isRealTimeRecording() const;
+ // Return whether the writer is used in background mode for media
+ // transcoding.
+ bool isBackgroundMode() const;
+
void lock();
void unlock();
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 3f93e6d..0584054 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -572,8 +572,9 @@
int64_t mBytesEncoded = 0;
int64_t mEarliestEncodedPtsUs = INT64_MAX;
int64_t mLatestEncodedPtsUs = INT64_MIN;
- int32_t mFramesEncoded = 0;
-
+ int64_t mFramesEncoded = 0;
+ int64_t mBytesInput = 0;
+ int64_t mFramesInput = 0;
int64_t mNumLowLatencyEnables; // how many times low latency mode is enabled
int64_t mNumLowLatencyDisables; // how many times low latency mode is disabled
@@ -590,7 +591,7 @@
sp<BatteryChecker> mBatteryChecker;
- void statsBufferSent(int64_t presentationUs);
+ void statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
void statsBufferReceived(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
enum {
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 408872f..c80012e 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -127,6 +127,8 @@
kKeyTrackTimeStatus = 'tktm', // int64_t
kKeyRealTimeRecording = 'rtrc', // bool (int32_t)
+ kKeyBackgroundMode = 'bkmd', // bool (int32_t)
+
kKeyNumBuffers = 'nbbf', // int32_t
// Ogg files can be tagged to be automatically looping...
@@ -153,6 +155,10 @@
kKeyIsADTS = 'adts', // bool (int32_t)
kKeyAACAOT = 'aaot', // int32_t
+ kKeyMpeghProfileLevelIndication = 'hpli', // int32_t
+ kKeyMpeghReferenceChannelLayout = 'hrcl', // int32_t
+ kKeyMpeghCompatibleSets = 'hcos', // raw data
+
// If a MediaBuffer's data represents (at least partially) encrypted
// data, the following fields aid in decryption.
// The data can be thought of as pairs of plain and encrypted data
@@ -278,6 +284,7 @@
kTypeAV1C = 'av1c',
kTypeDVCC = 'dvcc',
kTypeD263 = 'd263',
+ kTypeHCOS = 'hcos',
};
enum {
diff --git a/media/mediaserver/mediaserver.rc b/media/mediaserver/mediaserver.rc
index c82e532..05373c9 100644
--- a/media/mediaserver/mediaserver.rc
+++ b/media/mediaserver/mediaserver.rc
@@ -7,9 +7,3 @@
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
-
-# media.transcoding service is defined on com.android.media apex which goes back
-# to API29, but we only want it started on API31+ devices. So we declare it as
-# "disabled" and start it explicitly on boot.
-on boot
- start media.transcoding
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 3007574..8d527e9 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -85,7 +85,9 @@
cc_library_shared {
name: "libmediandk",
- llndk_stubs: "libmediandk.llndk",
+ llndk: {
+ symbol_file: "libmediandk.map.txt",
+ },
srcs: [
"NdkJavaVMHelper.cpp",
@@ -168,14 +170,6 @@
},
}
-llndk_library {
- name: "libmediandk.llndk",
- symbol_file: "libmediandk.map.txt",
- export_include_dirs: [
- "include",
- ],
-}
-
cc_library {
name: "libmediandk_utils",
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 40a1041..c19fe38 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -114,15 +114,14 @@
if (int32_t mode = appOps.startOpNoThrow(op, identity.uid,
resolvedOpPackageName, /*startIfModeDefault*/ false,
VALUE_OR_FATAL(aidl2legacy_optional_string_view_optional_String16(
- identity.attributionTag)), msg) != AppOpsManager::MODE_ALLOWED) {
+ identity.attributionTag)), msg) == AppOpsManager::MODE_ERRORED) {
ALOGE("Request start for \"%s\" (uid %d) denied by app op: %d, mode: %d",
String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
return false;
}
} else {
- // Always use OP_RECORD_AUDIO for checks at creation time.
if (int32_t mode = appOps.checkOp(op, uid,
- resolvedOpPackageName) != AppOpsManager::MODE_ALLOWED) {
+ resolvedOpPackageName) == AppOpsManager::MODE_ERRORED) {
ALOGE("Request check for \"%s\" (uid %d) denied by app op: %d, mode: %d",
String8(resolvedOpPackageName).c_str(), identity.uid, op, mode);
return false;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index b0f386d..3e6a7c7 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -29,7 +29,6 @@
#include <inttypes.h>
#include <pthread.h>
-#include <android/content/pm/IPackageManagerNative.h>
#include <android/hardware/ICamera.h>
#include <android/hardware/ICameraClient.h>
@@ -92,6 +91,8 @@
using hardware::ICameraServiceListener;
using hardware::camera::common::V1_0::CameraDeviceStatus;
using hardware::camera::common::V1_0::TorchModeStatus;
+using hardware::camera2::ICameraInjectionCallback;
+using hardware::camera2::ICameraInjectionSession;
using hardware::camera2::utils::CameraIdAndSessionConfiguration;
using hardware::camera2::utils::ConcurrentCameraIdCombination;
@@ -128,6 +129,8 @@
sCameraSendSystemEventsPermission("android.permission.CAMERA_SEND_SYSTEM_EVENTS");
static const String16 sCameraOpenCloseListenerPermission(
"android.permission.CAMERA_OPEN_CLOSE_LISTENER");
+static const String16
+ sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
static constexpr int32_t kVendorClientScore = resource_policy::PERCEPTIBLE_APP_ADJ;
static constexpr int32_t kVendorClientState = ActivityManager::PROCESS_STATE_PERSISTENT_UI;
@@ -167,6 +170,7 @@
mUidPolicy->registerSelf();
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
mSensorPrivacyPolicy->registerSelf();
+ mInjectionStatusListener = new InjectionStatusListener(this);
mAppOps.setCameraAudioRestriction(mAudioRestriction);
sp<HidlCameraService> hcs = HidlCameraService::getInstance(this);
if (hcs->registerAsService() != android::OK) {
@@ -244,6 +248,7 @@
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
mUidPolicy->unregisterSelf();
mSensorPrivacyPolicy->unregisterSelf();
+ mInjectionStatusListener->removeListener();
}
void CameraService::onNewProviderRegistered() {
@@ -2387,6 +2392,42 @@
return Status::ok();
}
+Status CameraService::injectCamera(
+ const String16& packageName, const String16& internalCamId,
+ const String16& externalCamId,
+ const sp<ICameraInjectionCallback>& callback,
+ /*out*/
+ sp<hardware::camera2::ICameraInjectionSession>* cameraInjectionSession) {
+ ATRACE_CALL();
+
+ if (!checkCallingPermission(sCameraInjectExternalCameraPermission)) {
+ const int pid = CameraThreadState::getCallingPid();
+ const int uid = CameraThreadState::getCallingUid();
+ ALOGE("Permission Denial: can't inject camera pid=%d, uid=%d", pid, uid);
+ return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+ "Permission Denial: no permission to inject camera");
+ }
+
+ ALOGV(
+ "%s: Package name = %s, Internal camera ID = %s, External camera ID = "
+ "%s",
+ __FUNCTION__, String8(packageName).string(),
+ String8(internalCamId).string(), String8(externalCamId).string());
+
+ binder::Status ret = binder::Status::ok();
+ // TODO: Implement the injection camera function.
+ // ret = internalInjectCamera(...);
+ // if(!ret.isOk()) {
+ // mInjectionStatusListener->notifyInjectionError(...);
+ // return ret;
+ // }
+
+ mInjectionStatusListener->addListener(callback);
+ *cameraInjectionSession = new CameraInjectionSession(this);
+
+ return ret;
+}
+
void CameraService::removeByClient(const BasicClient* client) {
Mutex::Autolock lock(mServiceLock);
for (auto& i : mActiveClientManager.getAll()) {
@@ -2725,6 +2766,11 @@
ATRACE_CALL();
LOG1("playSound(%d)", kind);
+ if (kind < 0 || kind >= NUM_SOUNDS) {
+ ALOGE("%s: Invalid sound id requested: %d", __FUNCTION__, kind);
+ return;
+ }
+
Mutex::Autolock lock(mSoundLock);
loadSoundLocked(kind);
sp<MediaPlayer> player = mSoundPlayer[kind];
@@ -3441,28 +3487,7 @@
}
bool CameraService::SensorPrivacyPolicy::hasCameraPrivacyFeature() {
- if (!mNeedToCheckCameraPrivacyFeature) {
- return mHasCameraPrivacyFeature;
- }
- bool hasCameraPrivacyFeature = false;
- sp<IBinder> binder = defaultServiceManager()->getService(String16("package_native"));
- if (binder != nullptr) {
- sp<content::pm::IPackageManagerNative> packageManager =
- interface_cast<content::pm::IPackageManagerNative>(binder);
- if (packageManager != nullptr) {
- binder::Status status = packageManager->hasSystemFeature(
- String16("android.hardware.camera.toggle"), 0, &hasCameraPrivacyFeature);
-
- if (status.isOk()) {
- mNeedToCheckCameraPrivacyFeature = false;
- mHasCameraPrivacyFeature = hasCameraPrivacyFeature;
- } else {
- ALOGE("Unable to check if camera privacy feature is supported");
- }
- }
- }
-
- return hasCameraPrivacyFeature;
+ return mSpm.supportsSensorToggle(SensorPrivacyManager::INDIVIDUAL_SENSOR_CAMERA);
}
// ----------------------------------------------------------------------------
@@ -3631,6 +3656,66 @@
}
// ----------------------------------------------------------------------------
+// InjectionStatusListener
+// ----------------------------------------------------------------------------
+
+void CameraService::InjectionStatusListener::addListener(
+ const sp<ICameraInjectionCallback>& callback) {
+ Mutex::Autolock lock(mListenerLock);
+ if (mCameraInjectionCallback) return;
+ status_t res = IInterface::asBinder(callback)->linkToDeath(this);
+ if (res == OK) {
+ mCameraInjectionCallback = callback;
+ }
+}
+
+void CameraService::InjectionStatusListener::removeListener() {
+ Mutex::Autolock lock(mListenerLock);
+ if (mCameraInjectionCallback == nullptr) {
+ ALOGW("InjectionStatusListener: mCameraInjectionCallback == nullptr");
+ return;
+ }
+ IInterface::asBinder(mCameraInjectionCallback)->unlinkToDeath(this);
+ mCameraInjectionCallback = nullptr;
+}
+
+void CameraService::InjectionStatusListener::notifyInjectionError(
+ int errorCode) {
+ Mutex::Autolock lock(mListenerLock);
+ if (mCameraInjectionCallback == nullptr) {
+ ALOGW("InjectionStatusListener: mCameraInjectionCallback == nullptr");
+ return;
+ }
+ mCameraInjectionCallback->onInjectionError(errorCode);
+}
+
+void CameraService::InjectionStatusListener::binderDied(
+ const wp<IBinder>& /*who*/) {
+ Mutex::Autolock lock(mListenerLock);
+ ALOGV("InjectionStatusListener: ICameraInjectionCallback has died");
+ auto parent = mParent.promote();
+ if (parent != nullptr) {
+ parent->stopInjectionImpl();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// CameraInjectionSession
+// ----------------------------------------------------------------------------
+
+binder::Status CameraService::CameraInjectionSession::stopInjection() {
+ Mutex::Autolock lock(mInjectionSessionLock);
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("CameraInjectionSession: Parent is gone");
+ return STATUS_ERROR(ICameraInjectionCallback::ERROR_INJECTION_SERVICE,
+ "Camera service encountered error");
+ }
+ parent->stopInjectionImpl();
+ return binder::Status::ok();
+}
+
+// ----------------------------------------------------------------------------
static const int kDumpLockRetries = 50;
static const int kDumpLockSleep = 60000;
@@ -4290,4 +4375,10 @@
return mode;
}
+void CameraService::stopInjectionImpl() {
+ mInjectionStatusListener->removeListener();
+
+ // TODO: Implement the stop injection function.
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 2b4f9a2..10e1748 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -20,6 +20,8 @@
#include <android/hardware/BnCameraService.h>
#include <android/hardware/BnSensorPrivacyListener.h>
#include <android/hardware/ICameraServiceListener.h>
+#include <android/hardware/camera2/BnCameraInjectionSession.h>
+#include <android/hardware/camera2/ICameraInjectionCallback.h>
#include <cutils/multiuser.h>
#include <utils/Vector.h>
@@ -180,6 +182,13 @@
/*out*/
bool *isSupported);
+ virtual binder::Status injectCamera(
+ const String16& packageName, const String16& internalCamId,
+ const String16& externalCamId,
+ const sp<hardware::camera2::ICameraInjectionCallback>& callback,
+ /*out*/
+ sp<hardware::camera2::ICameraInjectionSession>* cameraInjectionSession);
+
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -676,8 +685,7 @@
public virtual IBinder::DeathRecipient {
public:
explicit SensorPrivacyPolicy(wp<CameraService> service)
- : mService(service), mSensorPrivacyEnabled(false), mRegistered(false),
- mHasCameraPrivacyFeature(false), mNeedToCheckCameraPrivacyFeature(true) {}
+ : mService(service), mSensorPrivacyEnabled(false), mRegistered(false) {}
void registerSelf();
void unregisterSelf();
@@ -696,8 +704,6 @@
Mutex mSensorPrivacyLock;
bool mSensorPrivacyEnabled;
bool mRegistered;
- bool mHasCameraPrivacyFeature;
- bool mNeedToCheckCameraPrivacyFeature;
bool hasCameraPrivacyFeature();
};
@@ -1150,6 +1156,46 @@
// Current camera mute mode
bool mOverrideCameraMuteMode = false;
+
+ /**
+ * A listener class that implements the IBinder::DeathRecipient interface
+ * for use to call back the error state injected by the external camera, and
+ * camera service can kill the injection when binder signals process death.
+ */
+ class InjectionStatusListener : public virtual IBinder::DeathRecipient {
+ public:
+ InjectionStatusListener(sp<CameraService> parent) : mParent(parent) {}
+
+ void addListener(const sp<hardware::camera2::ICameraInjectionCallback>& callback);
+ void removeListener();
+ void notifyInjectionError(int errorCode);
+
+ // IBinder::DeathRecipient implementation
+ virtual void binderDied(const wp<IBinder>& who);
+
+ private:
+ Mutex mListenerLock;
+ wp<CameraService> mParent;
+ sp<hardware::camera2::ICameraInjectionCallback> mCameraInjectionCallback;
+ };
+
+ sp<InjectionStatusListener> mInjectionStatusListener;
+
+ /**
+ * A class that implements the hardware::camera2::BnCameraInjectionSession interface
+ */
+ class CameraInjectionSession : public hardware::camera2::BnCameraInjectionSession {
+ public:
+ CameraInjectionSession(sp<CameraService> parent) : mParent(parent) {}
+ virtual ~CameraInjectionSession() {}
+ binder::Status stopInjection() override;
+
+ private:
+ Mutex mInjectionSessionLock;
+ wp<CameraService> mParent;
+ };
+
+ void stopInjectionImpl();
};
} // namespace android
diff --git a/services/mediametrics/statsd_codec.cpp b/services/mediametrics/statsd_codec.cpp
index 381f441..4539ad5 100644
--- a/services/mediametrics/statsd_codec.cpp
+++ b/services/mediametrics/statsd_codec.cpp
@@ -95,7 +95,7 @@
if ( item->getInt32("android.media.mediacodec.rotation-degrees", &rotation)) {
metrics_proto.set_rotation(rotation);
}
- // android.media.mediacodec.crypto int32 (although missing if not needed
+ // android.media.mediacodec.crypto int32 (although missing if not needed)
int32_t crypto = -1;
if ( item->getInt32("android.media.mediacodec.crypto", &crypto)) {
metrics_proto.set_crypto(crypto);
@@ -185,15 +185,114 @@
metrics_proto.set_lifetime_millis(lifetime_millis);
}
- // new for S; need to plumb through to westworld
- // android.media.mediacodec.channelCount int32
- // android.media.mediacodec.sampleRate int32
+ // android.media.mediacodec.channelCount
+ int32_t channelCount = -1;
+ if ( item->getInt32("android.media.mediacodec.channelCount", &channelCount)) {
+ metrics_proto.set_channel_count(channelCount);
+ }
- // new for S; need to plumb through to westworld
+ // android.media.mediacodec.sampleRate
+ int32_t sampleRate = -1;
+ if ( item->getInt32("android.media.mediacodec.sampleRate", &sampleRate)) {
+ metrics_proto.set_sample_rate(sampleRate);
+ }
+
// TODO PWG may want these fuzzed up a bit to obscure some precision
- // android.media.mediacodec.vencode.bytes int64
- // android.media.mediacodec.vencode.frames int64
- // android.media.mediacodec.vencode.durationUs int64
+ // android.media.mediacodec.vencode.bytes
+ int64_t bytes = -1;
+ if ( item->getInt64("android.media.mediacodec.vencode.bytes", &bytes)) {
+ metrics_proto.set_video_encode_bytes(bytes);
+ }
+
+ // android.media.mediacodec.vencode.frames
+ int64_t frames = -1;
+ if ( item->getInt64("android.media.mediacodec.vencode.frames", &frames)) {
+ metrics_proto.set_video_encode_frames(frames);
+ }
+
+ // android.media.mediacodec.vencode.durationUs
+ int64_t durationUs = -1;
+ if ( item->getInt64("android.media.mediacodec.vencode.durationUs", &durationUs)) {
+ metrics_proto.set_video_encode_duration_us(durationUs);
+ }
+
+ // android.media.mediacodec.color-format
+ int32_t colorFormat = -1;
+ if ( item->getInt32("android.media.mediacodec.color-format", &colorFormat)) {
+ metrics_proto.set_color_format(colorFormat);
+ }
+
+ // android.media.mediacodec.frame-rate
+ double frameRate = -1.0;
+ if ( item->getDouble("android.media.mediacodec.frame-rate", &frameRate)) {
+ metrics_proto.set_frame_rate(frameRate);
+ }
+
+ // android.media.mediacodec.capture-rate
+ double captureRate = -1.0;
+ if ( item->getDouble("android.media.mediacodec.capture-rate", &captureRate)) {
+ metrics_proto.set_capture_rate(captureRate);
+ }
+
+ // android.media.mediacodec.operating-rate
+ double operatingRate = -1.0;
+ if ( item->getDouble("android.media.mediacodec.operating-rate", &operatingRate)) {
+ metrics_proto.set_operating_rate(operatingRate);
+ }
+
+ // android.media.mediacodec.priority
+ int32_t priority = -1;
+ if ( item->getInt32("android.media.mediacodec.priority", &priority)) {
+ metrics_proto.set_priority(priority);
+ }
+
+ // android.media.mediacodec.video-qp-i-min
+ int32_t qpIMin = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-i-min", &qpIMin)) {
+ metrics_proto.set_video_qp_i_min(qpIMin);
+ }
+
+ // android.media.mediacodec.video-qp-i-max
+ int32_t qpIMax = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-i-max", &qpIMax)) {
+ metrics_proto.set_video_qp_i_max(qpIMax);
+ }
+
+ // android.media.mediacodec.video-qp-p-min
+ int32_t qpPMin = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-p-min", &qpPMin)) {
+ metrics_proto.set_video_qp_p_min(qpPMin);
+ }
+
+ // android.media.mediacodec.video-qp-p-max
+ int32_t qpPMax = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-p-max", &qpPMax)) {
+ metrics_proto.set_video_qp_p_max(qpPMax);
+ }
+
+ // android.media.mediacodec.video-qp-b-min
+ int32_t qpBMin = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-b-min", &qpBMin)) {
+ metrics_proto.set_video_qp_b_min(qpIMin);
+ }
+
+ // android.media.mediacodec.video-qp-b-max
+ int32_t qpBMax = -1;
+ if ( item->getInt32("android.media.mediacodec.video-qp-b-max", &qpBMax)) {
+ metrics_proto.set_video_qp_b_max(qpBMax);
+ }
+
+ // android.media.mediacodec.video.input.bytes
+ int64_t inputBytes = -1;
+ if ( item->getInt64("android.media.mediacodec.video.input.bytes", &inputBytes)) {
+ metrics_proto.set_video_input_bytes(inputBytes);
+ }
+
+ // android.media.mediacodec.video.input.frames
+ int64_t inputFrames = -1;
+ if ( item->getInt64("android.media.mediacodec.video.input.frames", &inputFrames)) {
+ metrics_proto.set_video_input_frames(inputFrames);
+ }
std::string serialized;
if (!metrics_proto.SerializeToString(&serialized)) {
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
index 73b8872..287fb8d 100644
--- a/services/mediametrics/statsd_drm.cpp
+++ b/services/mediametrics/statsd_drm.cpp
@@ -59,9 +59,16 @@
std::string description;
(void) item->getString("description", &description);
+ std::string serialized_metrics;
+ (void) item->getString("serialized_metrics", &serialized_metrics);
+ if (serialized_metrics.empty()) {
+ ALOGD("statsd_mediadrm skipping empty entry");
+ return false;
+ }
+
// This field is left here for backward compatibility.
// This field is not used anymore.
- const std::string kUnusedField("unused");
+ const std::string kUnusedField("");
android::util::BytesField bf_serialized(kUnusedField.c_str(), kUnusedField.size());
int result = android::util::stats_write(android::util::MEDIAMETRICS_MEDIADRM_REPORTED,
timestamp_nanos, package_name.c_str(), package_version_code,
diff --git a/services/mediatranscoding/MediaTranscodingService.cpp b/services/mediatranscoding/MediaTranscodingService.cpp
index 8b64134..b80fe57 100644
--- a/services/mediatranscoding/MediaTranscodingService.cpp
+++ b/services/mediatranscoding/MediaTranscodingService.cpp
@@ -131,10 +131,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.");