Merge "CCodec: ignore input buffer done callbacks before flush" into sc-qpr1-dev
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 200e92d..bd6db55 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -53,6 +53,83 @@
//EL_FIXME 20 seconds may not be enough and must be reconciled with new obtainBuffer implementation
#define MAX_RUN_OFFLOADED_TIMEOUT_MS 20000 // assuming up to a maximum of 20 seconds of offloaded
+// for audio_track_cblk_t::mState, to match TrackBase.h
+static inline constexpr int CBLK_STATE_IDLE = 0;
+static inline constexpr int CBLK_STATE_PAUSING = 7;
+
+/**
+ * MirroredVariable is a local variable which simultaneously updates
+ * a mirrored storage location. This is useful for server side variables
+ * where a local copy is kept, but a client visible copy is offered through shared memory.
+ *
+ * We use std::atomic as the default container class to access this memory.
+ */
+template <typename T, template <typename> class Container = std::atomic>
+class MirroredVariable {
+ template <typename C>
+ struct Constraints {
+ // If setMirror is used with a different type U != T passed in,
+ // as a general rule, the Container must issue a memcpy to read or write
+ // (or its equivalent) to avoid possible strict aliasing issues.
+ // The memcpy also avoids gaps in structs and alignment issues with different types.
+ static constexpr bool ok_ = false; // Containers must specify constraints.
+ };
+ template <typename X>
+ struct Constraints<std::atomic<X>> {
+ // Atomics force read and write to memory.
+ static constexpr bool ok = std::is_same_v<X, T> ||
+ (std::atomic<X>::is_always_lock_free // no additional locking
+ && sizeof(std::atomic<X>) == sizeof(X) // layout identical to X.
+ && (std::is_arithmetic_v<X> || std::is_enum_v<X>)); // No gaps in the layout.
+ };
+
+static_assert(Constraints<Container<T>>::ok);
+public:
+ explicit MirroredVariable(const T& t) : t_{t} {}
+
+ // implicit conversion operator
+ operator T() const {
+ return t_;
+ }
+
+ MirroredVariable& operator=(const T& t) {
+ t_ = t;
+ if (mirror_ != nullptr) {
+ *mirror_ = t;
+ }
+ return *this;
+ }
+
+ template <typename U>
+ void setMirror(Container<U> *other_mirror) {
+ // Much of the concern is with T != U, however there are additional concerns
+ // when storage uses shared memory between processes. For atomics, it must be
+ // lock free.
+ static_assert(sizeof(U) == sizeof(T));
+ static_assert(alignof(U) == alignof(T));
+ static_assert(Constraints<Container<U>>::ok);
+ static_assert(sizeof(Container<U>) == sizeof(Container<T>));
+ static_assert(alignof(Container<U>) == alignof(Container<T>));
+ auto mirror = reinterpret_cast<Container<T>*>(other_mirror);
+ if (mirror_ != mirror) {
+ mirror_ = mirror;
+ if (mirror != nullptr) {
+ *mirror = t_;
+ }
+ }
+ }
+
+ void clear() {
+ mirror_ = nullptr;
+ }
+
+ MirroredVariable& operator&() const = delete;
+
+protected:
+ T t_{};
+ Container<T>* mirror_ = nullptr;
+};
+
struct AudioTrackSharedStreaming {
// similar to NBAIO MonoPipe
// in continuously incrementing frame units, take modulo buffer size, which must be a power of 2
@@ -188,6 +265,8 @@
volatile int32_t mFlags; // combinations of CBLK_*
+ std::atomic<int32_t> mState; // current TrackBase state.
+
public:
union {
AudioTrackSharedStreaming mStreaming;
@@ -198,6 +277,9 @@
// Cache line boundary (32 bytes)
};
+// TODO: ensure standard layout.
+// static_assert(std::is_standard_layout_v<audio_track_cblk_t>);
+
// ----------------------------------------------------------------------------
// Proxy for shared memory control block, to isolate callers from needing to know the details.
@@ -323,6 +405,7 @@
return mEpoch;
}
+ int32_t getState() const { return mCblk->mState; }
uint32_t getBufferSizeInFrames() const { return mBufferSizeInFrames; }
// See documentation for AudioTrack::setBufferSizeInFrames()
uint32_t setBufferSizeInFrames(uint32_t requestedSize);
diff --git a/media/codec2/components/aac/C2SoftAacDec.cpp b/media/codec2/components/aac/C2SoftAacDec.cpp
index 342d771..57cdcd0 100644
--- a/media/codec2/components/aac/C2SoftAacDec.cpp
+++ b/media/codec2/components/aac/C2SoftAacDec.cpp
@@ -287,6 +287,7 @@
mOutputDelayRingBufferWritePos = 0;
mOutputDelayRingBufferReadPos = 0;
mOutputDelayRingBufferFilled = 0;
+ mOutputDelayRingBuffer.reset();
mBuffersInfo.clear();
status_t status = UNKNOWN_ERROR;
@@ -308,10 +309,7 @@
aacDecoder_Close(mAACDecoder);
mAACDecoder = nullptr;
}
- if (mOutputDelayRingBuffer) {
- delete[] mOutputDelayRingBuffer;
- mOutputDelayRingBuffer = nullptr;
- }
+ mOutputDelayRingBuffer.reset();
}
status_t C2SoftAacDec::initDecoder() {
@@ -327,7 +325,7 @@
mOutputDelayCompensated = 0;
mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax;
- mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize];
+ mOutputDelayRingBuffer.reset(new short[mOutputDelayRingBufferSize]);
mOutputDelayRingBufferWritePos = 0;
mOutputDelayRingBufferReadPos = 0;
mOutputDelayRingBufferFilled = 0;
diff --git a/media/codec2/components/aac/C2SoftAacDec.h b/media/codec2/components/aac/C2SoftAacDec.h
index 986187c..a03fc70 100644
--- a/media/codec2/components/aac/C2SoftAacDec.h
+++ b/media/codec2/components/aac/C2SoftAacDec.h
@@ -93,7 +93,7 @@
bool mEndOfOutput;
int32_t mOutputDelayCompensated;
int32_t mOutputDelayRingBufferSize;
- short *mOutputDelayRingBuffer;
+ std::unique_ptr<short[]> mOutputDelayRingBuffer;
int32_t mOutputDelayRingBufferWritePos;
int32_t mOutputDelayRingBufferReadPos;
int32_t mOutputDelayRingBufferFilled;
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 30d7394..e394670 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -406,7 +406,7 @@
mConfig->inputBufferCurrentLength = (inSize - inPos);
mConfig->inputBufferMaxLength = 0;
mConfig->inputBufferUsedLength = 0;
- mConfig->outputFrameSize = (calOutSize - outSize);
+ mConfig->outputFrameSize = (calOutSize - outSize) / sizeof(int16_t);
mConfig->pOutputBuffer = reinterpret_cast<int16_t *> (wView.data() + outSize);
ERROR_CODE decoderErr;
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index 74b099c..9e3a823 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -100,8 +100,10 @@
ASSERT_NE(mLinearPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
- mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
- ASSERT_GT(queried.size(), 0);
+ c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+ C2_DONT_BLOCK, &queried);
+ ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+ ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
mMime = ((C2PortMediaTypeSetting::input*)queried[0].get())->m.value;
@@ -277,24 +279,20 @@
};
std::vector<std::unique_ptr<C2Param>> inParams;
c2_status_t status = component->query({}, indices, C2_DONT_BLOCK, &inParams);
- if (status != C2_OK && inParams.size() == 0) {
- ALOGE("Query media type failed => %d", status);
- ASSERT_TRUE(false);
- } else {
- size_t offset = sizeof(C2Param);
- for (size_t i = 0; i < inParams.size(); ++i) {
- C2Param* param = inParams[i].get();
- bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
- }
- if (mime.find("3gpp") != std::string::npos) {
- ASSERT_EQ(bitStreamInfo[0], 8000);
- ASSERT_EQ(bitStreamInfo[1], 1);
- } else if (mime.find("amr-wb") != std::string::npos) {
- ASSERT_EQ(bitStreamInfo[0], 16000);
- ASSERT_EQ(bitStreamInfo[1], 1);
- } else if (mime.find("gsm") != std::string::npos) {
- ASSERT_EQ(bitStreamInfo[0], 8000);
- }
+ ASSERT_EQ(status, C2_OK) << "Query sample rate and channel count info failed";
+ ASSERT_EQ(inParams.size(), indices.size()) << "Size of the vector returned is invalid";
+
+ bitStreamInfo[0] = C2StreamSampleRateInfo::output::From(inParams[0].get())->value;
+ bitStreamInfo[1] = C2StreamChannelCountInfo::output::From(inParams[1].get())->value;
+ if (mime.find("3gpp") != std::string::npos) {
+ ASSERT_EQ(bitStreamInfo[0], 8000);
+ ASSERT_EQ(bitStreamInfo[1], 1);
+ } else if (mime.find("amr-wb") != std::string::npos) {
+ ASSERT_EQ(bitStreamInfo[0], 16000);
+ ASSERT_EQ(bitStreamInfo[1], 1);
+ } else if (mime.find("gsm") != std::string::npos) {
+ ASSERT_EQ(bitStreamInfo[0], 8000);
+ ASSERT_EQ(bitStreamInfo[1], 1);
}
}
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
index d77b943..bd7ec0d 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioEncTest.cpp
@@ -73,26 +73,22 @@
ASSERT_NE(mLinearPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
- mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE}, C2_DONT_BLOCK,
- &queried);
- ASSERT_GT(queried.size(), 0);
+ c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE},
+ C2_DONT_BLOCK, &queried);
+ ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+ ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
mMime = ((C2PortMediaTypeSetting::output*)queried[0].get())->m.value;
mEos = false;
mCsd = false;
mFramesReceived = 0;
+ mEncoderFrameSize = 0;
mWorkResult = C2_OK;
mOutputSize = 0u;
- getInputMaxBufSize();
-
- c2_status_t status = getChannelCount(&mNumChannels);
- ASSERT_EQ(status, C2_OK) << "Unable to get supported channel count";
-
- status = getSampleRate(&mSampleRate);
- ASSERT_EQ(status, C2_OK) << "Unable to get supported sample rate";
-
- status = getSamplesPerFrame(mNumChannels, &mSamplesPerFrame);
- ASSERT_EQ(status, C2_OK) << "Unable to get supported number of samples per frame";
+ ASSERT_NO_FATAL_FAILURE(getInputMaxBufSize());
+ ASSERT_NO_FATAL_FAILURE(getChannelCount(&mNumChannels));
+ ASSERT_NO_FATAL_FAILURE(getSampleRate(&mSampleRate));
+ ASSERT_NO_FATAL_FAILURE(getSamplesPerFrame(mNumChannels, &mSamplesPerFrame));
getFile(mNumChannels, mSampleRate);
}
@@ -108,9 +104,9 @@
// Get the test parameters from GetParam call.
virtual void getParams() {}
- c2_status_t getChannelCount(int32_t* nChannels);
- c2_status_t getSampleRate(int32_t* nSampleRate);
- c2_status_t getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame);
+ void getChannelCount(int32_t* nChannels);
+ void getSampleRate(int32_t* nSampleRate);
+ void getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame);
void getFile(int32_t channelCount, int32_t sampleRate);
@@ -146,6 +142,7 @@
uint32_t mFramesReceived;
int32_t mInputMaxBufSize;
uint64_t mOutputSize;
+ uint32_t mEncoderFrameSize;
std::list<uint64_t> mFlushedIndices;
C2BlockPool::local_id_t mBlockPoolId;
@@ -173,21 +170,13 @@
// In encoder components, fetch the size of input buffer allocated
void getInputMaxBufSize() {
- int32_t bitStreamInfo[1] = {0};
std::vector<std::unique_ptr<C2Param>> inParams;
c2_status_t status = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
C2_DONT_BLOCK, &inParams);
- if (status != C2_OK && inParams.size() == 0) {
- ALOGE("Query MaxBufferSizeInfo failed => %d", status);
- ASSERT_TRUE(false);
- } else {
- size_t offset = sizeof(C2Param);
- for (size_t i = 0; i < inParams.size(); ++i) {
- C2Param* param = inParams[i].get();
- bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
- }
- }
- mInputMaxBufSize = bitStreamInfo[0];
+ ASSERT_EQ(status, C2_OK) << "Query max buffer size info failed";
+ ASSERT_EQ(inParams.size(), 1) << "Size of the vector returned is invalid";
+
+ mInputMaxBufSize = C2StreamMaxBufferSizeInfo::input::From(inParams[0].get())->value;
}
};
@@ -243,17 +232,15 @@
return false;
}
-c2_status_t Codec2AudioEncHidlTestBase::getChannelCount(int32_t* nChannels) {
+void Codec2AudioEncHidlTestBase::getChannelCount(int32_t* nChannels) {
std::unique_ptr<C2StreamChannelCountInfo::input> channelCount =
std::make_unique<C2StreamChannelCountInfo::input>();
std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
C2FieldSupportedValuesQuery::Current(
C2ParamField(channelCount.get(), &C2StreamChannelCountInfo::value))};
c2_status_t c2err = mComponent->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
- if (c2err != C2_OK || validValueInfos.size() != 1u) {
- ALOGE("querySupportedValues_vb failed for channelCount");
- return c2err;
- }
+ ASSERT_EQ(c2err, C2_OK) << "Query channel count info failed";
+ ASSERT_EQ(validValueInfos.size(), 1) << "Size of the vector returned is invalid";
// setting default value of channelCount
*nChannels = 1;
@@ -280,37 +267,45 @@
break;
}
default:
+ ASSERT_TRUE(false) << "Unsupported type: " << c2FSV.type;
break;
}
- return C2_OK;
+ return;
}
-c2_status_t Codec2AudioEncHidlTestBase::getSampleRate(int32_t* nSampleRate) {
+void Codec2AudioEncHidlTestBase::getSampleRate(int32_t* nSampleRate) {
// Use the default sample rate for mComponents
std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = mComponent->query({}, {C2StreamSampleRateInfo::input::PARAM_TYPE},
C2_DONT_BLOCK, &queried);
- if (c2err != C2_OK || queried.size() == 0) return c2err;
+ ASSERT_EQ(c2err, C2_OK) << "Query sample rate info failed";
+ ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
- size_t offset = sizeof(C2Param);
- C2Param* param = queried[0].get();
- *nSampleRate = *(int32_t*)((uint8_t*)param + offset);
-
- return C2_OK;
+ *nSampleRate = C2StreamSampleRateInfo::input::From(queried[0].get())->value;
+ return;
}
-c2_status_t Codec2AudioEncHidlTestBase::getSamplesPerFrame(int32_t nChannels,
- int32_t* samplesPerFrame) {
+void Codec2AudioEncHidlTestBase::getSamplesPerFrame(int32_t nChannels, int32_t* samplesPerFrame) {
std::vector<std::unique_ptr<C2Param>> queried;
- c2_status_t c2err = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE},
+ c2_status_t c2err = mComponent->query({}, {C2StreamAudioFrameSizeInfo::input::PARAM_TYPE},
C2_DONT_BLOCK, &queried);
- if (c2err != C2_OK || queried.size() == 0) return c2err;
- size_t offset = sizeof(C2Param);
- C2Param* param = queried[0].get();
- uint32_t maxInputSize = *(uint32_t*)((uint8_t*)param + offset);
+ if (c2err == C2_OK && queried.size() == 1) {
+ mEncoderFrameSize = C2StreamAudioFrameSizeInfo::input::From(queried[0].get())->value;
+ if (mEncoderFrameSize) {
+ *samplesPerFrame = mEncoderFrameSize;
+ return;
+ }
+ }
+
+ c2err = mComponent->query({}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
+ &queried);
+ ASSERT_EQ(c2err, C2_OK) << "Query max buffer size info failed";
+ ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
+
+ uint32_t maxInputSize = C2StreamMaxBufferSizeInfo::input::From(queried[0].get())->value;
*samplesPerFrame = std::min((maxInputSize / (nChannels * 2)), kMaxSamplesPerFrame);
- return C2_OK;
+ return;
}
// LookUpTable of clips and metadata for component testing
@@ -440,10 +435,13 @@
ALOGV("EncodeTest");
if (mDisableTest) GTEST_SKIP() << "Test is disabled";
bool signalEOS = std::get<2>(GetParam());
- // Ratio w.r.t to mInputMaxBufSize
- int32_t inputMaxBufRatio = std::get<3>(GetParam());
- mSamplesPerFrame = ((mInputMaxBufSize / inputMaxBufRatio) / (mNumChannels * 2));
-
+ // Set samples per frame based on inputMaxBufRatio if component does not
+ // advertise supported frame size
+ if (!mEncoderFrameSize) {
+ // Ratio w.r.t to mInputMaxBufSize
+ int32_t inputMaxBufRatio = std::get<3>(GetParam());
+ mSamplesPerFrame = ((mInputMaxBufSize / inputMaxBufRatio) / (mNumChannels * 2));
+ }
ALOGV("signalEOS %d mInputMaxBufSize %d mSamplesPerFrame %d", signalEOS, mInputMaxBufSize,
mSamplesPerFrame);
@@ -603,12 +601,11 @@
std::vector<std::unique_ptr<C2Param>> inParams;
c2_status_t c2_status = mComponent->query({}, {C2StreamChannelCountInfo::input::PARAM_TYPE},
C2_DONT_BLOCK, &inParams);
- ASSERT_TRUE(!c2_status && inParams.size())
- << "Query configured channelCount failed => %d" << c2_status;
+ ASSERT_EQ(c2_status, C2_OK) << "Query channel count info failed";
+ ASSERT_EQ(inParams.size(), 1) << "Size of the vector returned is invalid";
- size_t offset = sizeof(C2Param);
- C2Param* param = inParams[0].get();
- int32_t channelCount = *(int32_t*)((uint8_t*)param + offset);
+ int32_t channelCount = C2StreamChannelCountInfo::input::From(inParams[0].get())->value;
+
if (channelCount != nChannels) {
std::cout << "[ WARN ] Test Skipped for ChannelCount " << nChannels << "\n";
continue;
@@ -692,13 +689,11 @@
std::vector<std::unique_ptr<C2Param>> inParams;
c2_status_t c2_status = mComponent->query({}, {C2StreamSampleRateInfo::input::PARAM_TYPE},
C2_DONT_BLOCK, &inParams);
+ ASSERT_EQ(c2_status, C2_OK) << "Query sample rate info failed";
+ ASSERT_EQ(inParams.size(), 1) << "Size of the vector returned is invalid";
- ASSERT_TRUE(!c2_status && inParams.size())
- << "Query configured SampleRate failed => %d" << c2_status;
- size_t offset = sizeof(C2Param);
- C2Param* param = inParams[0].get();
- int32_t configuredSampleRate = *(int32_t*)((uint8_t*)param + offset);
-
+ int32_t configuredSampleRate =
+ C2StreamSampleRateInfo::input::From(inParams[0].get())->value;
if (configuredSampleRate != nSampleRate) {
std::cout << "[ WARN ] Test Skipped for SampleRate " << nSampleRate << "\n";
continue;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 95a4674..67873fa 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -123,8 +123,10 @@
ASSERT_NE(mLinearPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
- mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE}, C2_DONT_BLOCK, &queried);
- ASSERT_GT(queried.size(), 0);
+ c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
+ C2_DONT_BLOCK, &queried);
+ ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+ ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
mMime = ((C2PortMediaTypeSetting::input*)queried[0].get())->m.value;
mEos = false;
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index a6507e7..8305feb 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -74,9 +74,10 @@
ASSERT_NE(mGraphicPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
- mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE}, C2_DONT_BLOCK,
- &queried);
- ASSERT_GT(queried.size(), 0);
+ c2_status_t c2err = mComponent->query({}, {C2PortMediaTypeSetting::output::PARAM_TYPE},
+ C2_DONT_BLOCK, &queried);
+ ASSERT_EQ(c2err, C2_OK) << "Query media type failed";
+ ASSERT_EQ(queried.size(), 1) << "Size of the vector returned is invalid";
mMime = ((C2PortMediaTypeSetting::output*)queried[0].get())->m.value;
std::cout << "mime : " << mMime << "\n";
@@ -531,9 +532,17 @@
<< " resetting num BFrames to 0\n";
mConfigBPictures = false;
} else {
- size_t offset = sizeof(C2Param);
- C2Param* param = inParams[0].get();
- int32_t numBFrames = *(int32_t*)((uint8_t*)param + offset);
+ int32_t numBFrames = 0;
+ C2StreamGopTuning::output* gop = C2StreamGopTuning::output::From(inParams[0].get());
+ if (gop && gop->flexCount() >= 1) {
+ for (size_t i = 0; i < gop->flexCount(); ++i) {
+ const C2GopLayerStruct& layer = gop->m.values[i];
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)) {
+ numBFrames = layer.count;
+ break;
+ }
+ }
+ }
if (!numBFrames) {
std::cout << "[ WARN ] Bframe not supported for " << mComponentName
@@ -817,6 +826,10 @@
TEST_P(Codec2VideoEncHidlTest, AdaptiveBitrateTest) {
description("Encodes input file for different bitrates");
if (mDisableTest) GTEST_SKIP() << "Test is disabled";
+ if (mMime != "video/avc" && mMime != "video/hevc" && mMime != "video/x-vnd.on2.vp8" &&
+ mMime != "video/x-vnd.on2.vp9") {
+ GTEST_SKIP() << "AdaptiveBitrateTest is enabled only for avc, hevc, vp8 and vp9 encoders";
+ }
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 29cc564..333a2ca 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -96,7 +96,10 @@
if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
int32_t stride = img->mPlane[0].mRowInc;
mFormatWithImageData->setInt32(KEY_STRIDE, stride);
- ALOGD("[%s] updating stride = %d", mName, stride);
+ mFormatWithImageData->setInt32(KEY_WIDTH, img->mWidth);
+ mFormatWithImageData->setInt32(KEY_HEIGHT, img->mHeight);
+ ALOGD("[%s] updating stride = %d, width: %d, height: %d",
+ mName, stride, img->mWidth, img->mHeight);
if (img->mNumPlanes > 1 && stride > 0) {
int64_t offsetDelta =
(int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 62c8fcd..4070478 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -248,10 +248,7 @@
// align width and height to support subsampling cleanly
uint32_t stride = align(view.crop().width, 2) * divUp(layout.planes[0].allocatedDepth, 8u);
-
- int32_t fmtHeight = mHeight;
- format->findInt32(KEY_HEIGHT, &fmtHeight);
- uint32_t vStride = align(fmtHeight, 2);
+ uint32_t vStride = align(view.crop().height, 2);
bool tryWrapping = !copy;
diff --git a/media/codec2/vndk/C2PlatformStorePluginLoader.cpp b/media/codec2/vndk/C2PlatformStorePluginLoader.cpp
index bee028a..2a888a8 100644
--- a/media/codec2/vndk/C2PlatformStorePluginLoader.cpp
+++ b/media/codec2/vndk/C2PlatformStorePluginLoader.cpp
@@ -59,13 +59,14 @@
c2_status_t C2PlatformStorePluginLoader::createBlockPool(
::C2Allocator::id_t allocatorId, ::C2BlockPool::local_id_t blockPoolId,
- std::shared_ptr<C2BlockPool>* pool) {
+ std::shared_ptr<C2BlockPool>* pool,
+ std::function<void(C2BlockPool *)> deleter) {
if (mCreateBlockPool == nullptr) {
ALOGD("Handle or CreateBlockPool symbol is null");
return C2_NOT_FOUND;
}
- std::shared_ptr<::C2BlockPool> ptr(mCreateBlockPool(allocatorId, blockPoolId));
+ std::shared_ptr<::C2BlockPool> ptr(mCreateBlockPool(allocatorId, blockPoolId), deleter);
if (ptr) {
*pool = ptr;
return C2_OK;
@@ -75,14 +76,16 @@
}
c2_status_t C2PlatformStorePluginLoader::createAllocator(
- ::C2Allocator::id_t allocatorId, std::shared_ptr<C2Allocator>* const allocator) {
+ ::C2Allocator::id_t allocatorId,
+ std::shared_ptr<C2Allocator>* const allocator,
+ std::function<void(C2Allocator *)> deleter) {
if (mCreateAllocator == nullptr) {
ALOGD("Handle or CreateAllocator symbol is null");
return C2_NOT_FOUND;
}
c2_status_t res = C2_CORRUPTED;
- allocator->reset(mCreateAllocator(allocatorId, &res));
+ allocator->reset(mCreateAllocator(allocatorId, &res), deleter);
if (res != C2_OK) {
ALOGD("Failed to CreateAllocator by id: %u, res: %d", allocatorId, res);
allocator->reset();
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index c07c09e..1660c38 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -443,6 +443,7 @@
public:
_C2BlockPoolCache() : mBlockPoolSeqId(C2BlockPool::PLATFORM_START + 1) {}
+private:
c2_status_t _createBlockPool(
C2PlatformAllocatorStore::id_t allocatorId,
std::vector<std::shared_ptr<const C2Component>> components,
@@ -456,14 +457,19 @@
if (allocatorId == C2AllocatorStore::DEFAULT_LINEAR) {
allocatorId = GetPreferredLinearAllocatorId(GetCodec2PoolMask());
}
+ auto deleter = [this, poolId](C2BlockPool *pool) {
+ std::unique_lock lock(mMutex);
+ mBlockPools.erase(poolId);
+ mComponents.erase(poolId);
+ delete pool;
+ };
switch(allocatorId) {
case C2PlatformAllocatorStore::ION: /* also ::DMABUFHEAP */
res = allocatorStore->fetchAllocator(
C2PlatformAllocatorStore::ION, &allocator);
if (res == C2_OK) {
- std::shared_ptr<C2BlockPool> ptr =
- std::make_shared<C2PooledBlockPool>(
- allocator, poolId);
+ std::shared_ptr<C2BlockPool> ptr(
+ new C2PooledBlockPool(allocator, poolId), deleter);
*pool = ptr;
mBlockPools[poolId] = ptr;
mComponents[poolId].insert(
@@ -475,9 +481,8 @@
res = allocatorStore->fetchAllocator(
C2PlatformAllocatorStore::BLOB, &allocator);
if (res == C2_OK) {
- std::shared_ptr<C2BlockPool> ptr =
- std::make_shared<C2PooledBlockPool>(
- allocator, poolId);
+ std::shared_ptr<C2BlockPool> ptr(
+ new C2PooledBlockPool(allocator, poolId), deleter);
*pool = ptr;
mBlockPools[poolId] = ptr;
mComponents[poolId].insert(
@@ -490,8 +495,8 @@
res = allocatorStore->fetchAllocator(
C2AllocatorStore::DEFAULT_GRAPHIC, &allocator);
if (res == C2_OK) {
- std::shared_ptr<C2BlockPool> ptr =
- std::make_shared<C2PooledBlockPool>(allocator, poolId);
+ std::shared_ptr<C2BlockPool> ptr(
+ new C2PooledBlockPool(allocator, poolId), deleter);
*pool = ptr;
mBlockPools[poolId] = ptr;
mComponents[poolId].insert(
@@ -503,9 +508,8 @@
res = allocatorStore->fetchAllocator(
C2PlatformAllocatorStore::BUFFERQUEUE, &allocator);
if (res == C2_OK) {
- std::shared_ptr<C2BlockPool> ptr =
- std::make_shared<C2BufferQueueBlockPool>(
- allocator, poolId);
+ std::shared_ptr<C2BlockPool> ptr(
+ new C2BufferQueueBlockPool(allocator, poolId), deleter);
*pool = ptr;
mBlockPools[poolId] = ptr;
mComponents[poolId].insert(
@@ -517,7 +521,7 @@
// Try to create block pool from platform store plugins.
std::shared_ptr<C2BlockPool> ptr;
res = C2PlatformStorePluginLoader::GetInstance()->createBlockPool(
- allocatorId, poolId, &ptr);
+ allocatorId, poolId, &ptr, deleter);
if (res == C2_OK) {
*pool = ptr;
mBlockPools[poolId] = ptr;
@@ -530,17 +534,20 @@
return res;
}
+public:
c2_status_t createBlockPool(
C2PlatformAllocatorStore::id_t allocatorId,
std::vector<std::shared_ptr<const C2Component>> components,
std::shared_ptr<C2BlockPool> *pool) {
+ std::unique_lock lock(mMutex);
return _createBlockPool(allocatorId, components, mBlockPoolSeqId++, pool);
}
- bool getBlockPool(
+ c2_status_t getBlockPool(
C2BlockPool::local_id_t blockPoolId,
std::shared_ptr<const C2Component> component,
std::shared_ptr<C2BlockPool> *pool) {
+ std::unique_lock lock(mMutex);
// TODO: use one iterator for multiple blockpool type scalability.
std::shared_ptr<C2BlockPool> ptr;
auto it = mBlockPools.find(blockPoolId);
@@ -558,14 +565,22 @@
});
if (found != mComponents[blockPoolId].end()) {
*pool = ptr;
- return true;
+ return C2_OK;
}
}
}
- return false;
+ // TODO: remove this. this is temporary
+ if (blockPoolId == C2BlockPool::PLATFORM_START) {
+ return _createBlockPool(
+ C2PlatformAllocatorStore::BUFFERQUEUE, {component}, blockPoolId, pool);
+ }
+ return C2_NOT_FOUND;
}
private:
+ // Deleter needs to hold this mutex, and there is a small chance that deleter
+ // is invoked while the mutex is held.
+ std::recursive_mutex mMutex;
C2BlockPool::local_id_t mBlockPoolSeqId;
std::map<C2BlockPool::local_id_t, std::weak_ptr<C2BlockPool>> mBlockPools;
@@ -574,7 +589,6 @@
static std::unique_ptr<_C2BlockPoolCache> sBlockPoolCache =
std::make_unique<_C2BlockPoolCache>();
-static std::mutex sBlockPoolCacheMutex;
} // anynymous namespace
@@ -582,15 +596,12 @@
C2BlockPool::local_id_t id, std::shared_ptr<const C2Component> component,
std::shared_ptr<C2BlockPool> *pool) {
pool->reset();
- std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
std::shared_ptr<C2Allocator> allocator;
c2_status_t res = C2_NOT_FOUND;
if (id >= C2BlockPool::PLATFORM_START) {
- if (sBlockPoolCache->getBlockPool(id, component, pool)) {
- return C2_OK;
- }
+ return sBlockPoolCache->getBlockPool(id, component, pool);
}
switch (id) {
@@ -606,11 +617,6 @@
*pool = std::make_shared<C2BasicGraphicBlockPool>(allocator);
}
break;
- // TODO: remove this. this is temporary
- case C2BlockPool::PLATFORM_START:
- res = sBlockPoolCache->_createBlockPool(
- C2PlatformAllocatorStore::BUFFERQUEUE, {component}, id, pool);
- break;
default:
break;
}
@@ -623,7 +629,6 @@
std::shared_ptr<C2BlockPool> *pool) {
pool->reset();
- std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
return sBlockPoolCache->createBlockPool(allocatorId, components, pool);
}
@@ -633,7 +638,6 @@
std::shared_ptr<C2BlockPool> *pool) {
pool->reset();
- std::lock_guard<std::mutex> lock(sBlockPoolCacheMutex);
return sBlockPoolCache->createBlockPool(allocatorId, {component}, pool);
}
diff --git a/media/codec2/vndk/include/C2PlatformStorePluginLoader.h b/media/codec2/vndk/include/C2PlatformStorePluginLoader.h
index 4c10643..73d1b5e 100644
--- a/media/codec2/vndk/include/C2PlatformStorePluginLoader.h
+++ b/media/codec2/vndk/include/C2PlatformStorePluginLoader.h
@@ -61,9 +61,11 @@
* \retval C2_NOT_FOUND the extension symbol was not found.
* \retval C2_BAD_INDEX the input allocatorId is not defined in platform store extension.
*/
- c2_status_t createBlockPool(::C2Allocator::id_t allocatorId,
- ::C2BlockPool::local_id_t blockPoolId,
- std::shared_ptr<C2BlockPool>* pool);
+ c2_status_t createBlockPool(
+ ::C2Allocator::id_t allocatorId,
+ ::C2BlockPool::local_id_t blockPoolId,
+ std::shared_ptr<C2BlockPool>* pool,
+ std::function<void(C2BlockPool *)> deleter = std::default_delete<C2BlockPool>());
/**
* Creates allocator from platform store extension.
@@ -81,8 +83,10 @@
* \retval C2_BAD_INDEX the input allocatorId is not defined in platform store extension.
* \retval C2_NO_MEMORY not enough memory to create the allocator
*/
- c2_status_t createAllocator(::C2Allocator::id_t allocatorId,
- std::shared_ptr<C2Allocator>* const allocator);
+ c2_status_t createAllocator(
+ ::C2Allocator::id_t allocatorId,
+ std::shared_ptr<C2Allocator>* const allocator,
+ std::function<void(C2Allocator *)> deleter = std::default_delete<C2Allocator>());
private:
explicit C2PlatformStorePluginLoader(const char *libPath);
diff --git a/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp b/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp
index 234faef..00b2ab6 100644
--- a/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp
+++ b/media/codecs/m4v_h263/enc/src/mp4enc_api.cpp
@@ -610,18 +610,19 @@
/* Find the maximum width*height for memory allocation of the VOPs */
for (idx = 0; idx < nLayers; idx++)
{
- temp_w = video->encParams->LayerWidth[idx];
- temp_h = video->encParams->LayerHeight[idx];
+ temp_w = ((video->encParams->LayerWidth[idx] + 15) >> 4) << 4;
+ temp_h = ((video->encParams->LayerHeight[idx] + 15) >> 4) << 4;
+
+ if (temp_w > 2048 || temp_h > 2048) {
+ goto CLEAN_UP;
+ }
if ((temp_w*temp_h) > max)
{
max = temp_w * temp_h;
- max_width = ((temp_w + 15) >> 4) << 4;
- max_height = ((temp_h + 15) >> 4) << 4;
- if (((uint64_t)max_width * max_height) > (uint64_t)INT32_MAX
- || temp_w > INT32_MAX - 15 || temp_h > INT32_MAX - 15) {
- goto CLEAN_UP;
- }
+ max_width = temp_w;
+ max_height = temp_h;
+
nTotalMB = ((max_width * max_height) >> 8);
}
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index fbcd554..8836c47 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -157,6 +157,7 @@
MediaBufferHelper *mBuffer;
+ size_t mSrcBufferSize;
uint8_t *mSrcBuffer;
bool mIsHeif;
@@ -5083,6 +5084,7 @@
mNALLengthSize(0),
mStarted(false),
mBuffer(NULL),
+ mSrcBufferSize(0),
mSrcBuffer(NULL),
mItemTable(itemTable),
mElstShiftStartTicks(elstShiftStartTicks),
@@ -5264,6 +5266,7 @@
// file probably specified a bad max size
return AMEDIA_ERROR_MALFORMED;
}
+ mSrcBufferSize = max_size;
mStarted = true;
@@ -5280,6 +5283,7 @@
mBuffer = NULL;
}
+ mSrcBufferSize = 0;
delete[] mSrcBuffer;
mSrcBuffer = NULL;
@@ -6467,13 +6471,19 @@
// Whole NAL units are returned but each fragment is prefixed by
// the start code (0x00 00 00 01).
ssize_t num_bytes_read = 0;
- num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
+ bool mSrcBufferFitsDataToRead = size <= mSrcBufferSize;
+ if (mSrcBufferFitsDataToRead) {
+ num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
+ } else {
+ // We are trying to read a sample larger than the expected max sample size.
+ // Fall through and let the failure be handled by the following if.
+ android_errorWriteLog(0x534e4554, "188893559");
+ }
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
mBuffer = NULL;
-
- return AMEDIA_ERROR_IO;
+ return mSrcBufferFitsDataToRead ? AMEDIA_ERROR_IO : AMEDIA_ERROR_MALFORMED;
}
uint8_t *dstData = (uint8_t *)mBuffer->data();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 5f802de..3bc666b 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -21,6 +21,7 @@
#include <inttypes.h>
#include <math.h>
#include <sys/resource.h>
+#include <thread>
#include <android/media/IAudioPolicyService.h>
#include <android-base/macros.h>
@@ -947,6 +948,44 @@
mAudioTrack->flush();
}
+bool AudioTrack::pauseAndWait(const std::chrono::milliseconds& timeout)
+{
+ using namespace std::chrono_literals;
+
+ pause();
+
+ AutoMutex lock(mLock);
+ // offload and direct tracks do not wait because pause volume ramp is handled by hardware.
+ if (isOffloadedOrDirect_l()) return true;
+
+ // Wait for the track state to be anything besides pausing.
+ // This ensures that the volume has ramped down.
+ constexpr auto SLEEP_INTERVAL_MS = 10ms;
+ auto begin = std::chrono::steady_clock::now();
+ while (true) {
+ // wait for state to change
+ const int state = mProxy->getState();
+
+ mLock.unlock(); // only local variables accessed until lock.
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - begin);
+ if (state != CBLK_STATE_PAUSING) {
+ ALOGV("%s: success state:%d after %lld ms", __func__, state, elapsed.count());
+ return true;
+ }
+ std::chrono::milliseconds remaining = timeout - elapsed;
+ if (remaining.count() <= 0) {
+ ALOGW("%s: timeout expired state:%d still pausing:%d after %lld ms",
+ __func__, state, CBLK_STATE_PAUSING, elapsed.count());
+ return false;
+ }
+ // It is conceivable that the track is restored while sleeping;
+ // as this logic is advisory, we allow that.
+ std::this_thread::sleep_for(std::min(remaining, SLEEP_INTERVAL_MS));
+ mLock.lock();
+ }
+}
+
void AudioTrack::pause()
{
const int64_t beginNs = systemTime();
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index cb00990..6b592cb 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -28,6 +28,7 @@
#include <utils/threads.h>
#include <android/content/AttributionSourceState.h>
+#include <chrono>
#include <string>
#include "android/media/BnAudioTrackCallback.h"
@@ -510,6 +511,14 @@
*/
void pause();
+ /* Pause and wait (with timeout) for the audio track to ramp to silence.
+ *
+ * \param timeout is the time limit to wait before returning.
+ * A negative number is treated as 0.
+ * \return true if the track is ramped to silence, false if the timeout occurred.
+ */
+ bool pauseAndWait(const std::chrono::milliseconds& timeout);
+
/* Set volume for this track, mostly used for games' sound effects
* left and right volumes. Levels must be >= 0.0 and <= 1.0.
* This is the older API. New applications should use setVolume(float) when possible.
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d278a01..f85887e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -21,6 +21,7 @@
#define LOG_TAG "MediaPlayerService"
#include <utils/Log.h>
+#include <chrono>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -2467,8 +2468,13 @@
void MediaPlayerService::AudioOutput::pause()
{
ALOGV("pause");
+ // We use pauseAndWait() instead of pause() to ensure tracks ramp to silence before
+ // any flush. We choose 40 ms timeout to allow 1 deep buffer mixer period
+ // to occur. Often waiting is 0 - 20 ms.
+ using namespace std::chrono_literals;
+ constexpr auto TIMEOUT_MS = 40ms;
Mutex::Autolock lock(mLock);
- if (mTrack != 0) mTrack->pause();
+ if (mTrack != 0) mTrack->pauseAndWait(TIMEOUT_MS);
}
void MediaPlayerService::AudioOutput::close()
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index efd4070..b513e45 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -883,9 +883,18 @@
}
int32_t width, height, stride;
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
- CHECK(outputFormat->findInt32("stride", &stride));
+ if (outputFormat->findInt32("width", &width) == false) {
+ ALOGE("MediaImageDecoder::onOutputReceived:width is missing in outputFormat");
+ return ERROR_MALFORMED;
+ }
+ if (outputFormat->findInt32("height", &height) == false) {
+ ALOGE("MediaImageDecoder::onOutputReceived:height is missing in outputFormat");
+ return ERROR_MALFORMED;
+ }
+ if (outputFormat->findInt32("stride", &stride) == false) {
+ ALOGE("MediaImageDecoder::onOutputReceived:stride is missing in outputFormat");
+ return ERROR_MALFORMED;
+ }
if (mFrame == NULL) {
sp<IMemory> frameMem = allocVideoFrame(
diff --git a/media/libstagefright/rtsp/JitterCalculator.cpp b/media/libstagefright/rtsp/JitterCalculator.cpp
index 93b5a83..7e60be2 100644
--- a/media/libstagefright/rtsp/JitterCalculator.cpp
+++ b/media/libstagefright/rtsp/JitterCalculator.cpp
@@ -38,14 +38,13 @@
mInterArrivalJitterUs = inter;
}
-void JitterCalc::putBaseData(int64_t rtpTime, int64_t arrivalTimeUs) {
- // A RTP time wraps around after UINT32_MAX. We must consider this case.
- const int64_t UINT32_MSB = 0x80000000;
- int64_t overflowMask = (mFirstTimeStamp & UINT32_MSB & ~rtpTime) << 1;
- int64_t tempRtpTime = overflowMask | rtpTime;
+void JitterCalc::putBaseData(uint32_t rtpTime, int64_t arrivalTimeUs) {
+ // A RTP time wraps around after UINT32_MAX. Overflow can present.
+ uint32_t diff = 0;
+ __builtin_usub_overflow(rtpTime, mFirstTimeStamp, &diff);
// Base jitter implementation can be various
- int64_t scheduledTimeUs = (tempRtpTime - (int64_t)mFirstTimeStamp) * 1000000ll / mClockRate;
+ int64_t scheduledTimeUs = ((int32_t)diff) * 1000000ll / mClockRate;
int64_t elapsedTimeUs = arrivalTimeUs - mFirstArrivalTimeUs;
int64_t correctionTimeUs = elapsedTimeUs - scheduledTimeUs; // additional propagation delay;
mBaseJitterUs = (mBaseJitterUs * 15 + correctionTimeUs) / 16;
@@ -53,18 +52,13 @@
(long long)mBaseJitterUs, (long long)correctionTimeUs);
}
-void JitterCalc::putInterArrivalData(int64_t rtpTime, int64_t arrivalTimeUs) {
- const int64_t UINT32_MSB = 0x80000000;
- int64_t tempRtpTime = rtpTime;
- int64_t tempLastTimeStamp = mLastTimeStamp;
-
- // A RTP time wraps around after UINT32_MAX. We must consider this case.
- int64_t overflowMask = (mLastTimeStamp ^ rtpTime) & UINT32_MSB;
- tempRtpTime |= ((overflowMask & ~rtpTime) << 1);
- tempLastTimeStamp |= ((overflowMask & ~mLastTimeStamp) << 1);
+void JitterCalc::putInterArrivalData(uint32_t rtpTime, int64_t arrivalTimeUs) {
+ // A RTP time wraps around after UINT32_MAX. Overflow can present.
+ uint32_t diff = 0;
+ __builtin_usub_overflow(rtpTime, mLastTimeStamp, &diff);
// 6.4.1 of RFC3550 defines this interarrival jitter value.
- int64_t diffTimeStampUs = abs(tempRtpTime - tempLastTimeStamp) * 1000000ll / mClockRate;
+ int64_t diffTimeStampUs = abs((int32_t)diff) * 1000000ll / mClockRate;
int64_t diffArrivalUs = arrivalTimeUs - mLastArrivalTimeUs; // Can't be minus
ALOGV("diffTimeStampUs %lld \t\t diffArrivalUs %lld",
(long long)diffTimeStampUs, (long long)diffArrivalUs);
@@ -72,7 +66,7 @@
int64_t varianceUs = diffArrivalUs - diffTimeStampUs;
mInterArrivalJitterUs = (mInterArrivalJitterUs * 15 + abs(varianceUs)) / 16;
- mLastTimeStamp = (uint32_t)rtpTime;
+ mLastTimeStamp = rtpTime;
mLastArrivalTimeUs = arrivalTimeUs;
}
diff --git a/media/libstagefright/rtsp/JitterCalculator.h b/media/libstagefright/rtsp/JitterCalculator.h
index ff36f1f..4f3b761 100644
--- a/media/libstagefright/rtsp/JitterCalculator.h
+++ b/media/libstagefright/rtsp/JitterCalculator.h
@@ -40,8 +40,8 @@
JitterCalc(int32_t clockRate);
void init(uint32_t rtpTime, int64_t arrivalTimeUs, int32_t base, int32_t inter);
- void putInterArrivalData(int64_t rtpTime, int64_t arrivalTime);
- void putBaseData(int64_t rtpTime, int64_t arrivalTimeUs);
+ void putInterArrivalData(uint32_t rtpTime, int64_t arrivalTime);
+ void putBaseData(uint32_t rtpTime, int64_t arrivalTimeUs);
int32_t getBaseJitterMs();
int32_t getInterArrivalJitterMs();
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b9cdab8..746d875 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -5089,7 +5089,7 @@
break;
case TrackBase::IDLE:
default:
- LOG_ALWAYS_FATAL("unexpected track state %d", track->mState);
+ LOG_ALWAYS_FATAL("unexpected track state %d", (int)track->mState);
}
if (isActive) {
@@ -5148,7 +5148,7 @@
// TODO Remove the ALOGW when this theory is confirmed.
ALOGW("fast track %d should have been active; "
"mState=%d, mTrackMask=%#x, recentUnderruns=%u, isShared=%d",
- j, track->mState, state->mTrackMask, recentUnderruns,
+ j, (int)track->mState, state->mTrackMask, recentUnderruns,
track->sharedBuffer() != 0);
// Since the FastMixer state already has the track inactive, do nothing here.
}
@@ -8041,7 +8041,7 @@
ALOGV("active record track PAUSING -> ACTIVE");
recordTrack->mState = TrackBase::ACTIVE;
} else {
- ALOGV("active record track state %d", recordTrack->mState);
+ ALOGV("active record track state %d", (int)recordTrack->mState);
}
return status;
}
@@ -8067,7 +8067,7 @@
}
if (recordTrack->mState != TrackBase::STARTING_1) {
ALOGW("%s(%d): unsynchronized mState:%d change",
- __func__, recordTrack->id(), recordTrack->mState);
+ __func__, recordTrack->id(), (int)recordTrack->mState);
// Someone else has changed state, let them take over,
// leave mState in the new state.
recordTrack->clearSyncStartEvent();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 92f129c..5311fe2 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -23,7 +23,7 @@
class TrackBase : public ExtendedAudioBufferProvider, public RefBase {
public:
- enum track_state {
+ enum track_state : int32_t {
IDLE,
FLUSHED, // for PlaybackTracks only
STOPPED,
@@ -271,6 +271,7 @@
void releaseCblk() {
if (mCblk != nullptr) {
+ mState.clear();
mCblk->~audio_track_cblk_t(); // destroy our shared-structure.
if (mClient == 0) {
free(mCblk);
@@ -355,7 +356,7 @@
// except for OutputTrack when it is in local memory
size_t mBufferSize; // size of mBuffer in bytes
// we don't really need a lock for these
- track_state mState;
+ MirroredVariable<track_state> mState;
const audio_attributes_t mAttr;
const uint32_t mSampleRate; // initial sample rate only; for tracks which
// support dynamic rates, the current value is in control block
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d2a30b1..e0c5fa5 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -234,7 +234,11 @@
#ifdef TEE_SINK
mTee.set(sampleRate, mChannelCount, format, NBAIO_Tee::TEE_FLAG_TRACK);
#endif
-
+ // mState is mirrored for the client to read.
+ mState.setMirror(&mCblk->mState);
+ // ensure our state matches up until we consolidate the enumeration.
+ static_assert(CBLK_STATE_IDLE == IDLE);
+ static_assert(CBLK_STATE_PAUSING == PAUSING);
}
}
@@ -933,7 +937,7 @@
buffer->raw = buf.mRaw;
if (buf.mFrameCount == 0 && !isStopping() && !isStopped() && !isPaused() && !isOffloaded()) {
ALOGV("%s(%d): underrun, framesReady(%zu) < framesDesired(%zd), state: %d",
- __func__, mId, buf.mFrameCount, desiredFrames, mState);
+ __func__, mId, buf.mFrameCount, desiredFrames, (int)mState);
mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
} else {
mAudioTrackServerProxy->tallyUnderrunFrames(0);
@@ -1590,7 +1594,7 @@
(mState == STOPPED)))) {
ALOGW("%s(%d): in invalid state %d on session %d %s mode, framesReady %zu",
__func__, mId,
- mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady());
+ (int)mState, mSessionId, (mSharedBuffer != 0) ? "static" : "stream", framesReady());
event->cancel();
return INVALID_OPERATION;
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index d0d3a9d..04b5604 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2054,6 +2054,11 @@
id.string());
errorCode = ERROR_ILLEGAL_ARGUMENT;
break;
+ case -EBUSY:
+ msg = String8::format("Camera \"%s\" is in use",
+ id.string());
+ errorCode = ERROR_CAMERA_IN_USE;
+ break;
default:
msg = String8::format(
"Setting torch mode of camera \"%s\" to %d failed: %s (%d)",
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a195fb1..87c1c75 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -4783,6 +4783,26 @@
return submitRequestSuccess;
}
+status_t Camera3Device::removeFwkOnlyRegionKeys(CameraMetadata *request) {
+ static const std::array<uint32_t, 4> kFwkOnlyRegionKeys = {ANDROID_CONTROL_AF_REGIONS_SET,
+ ANDROID_CONTROL_AE_REGIONS_SET, ANDROID_CONTROL_AWB_REGIONS_SET,
+ ANDROID_SCALER_CROP_REGION_SET};
+ if (request == nullptr) {
+ ALOGE("%s request metadata nullptr", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ status_t res = OK;
+ for (const auto &key : kFwkOnlyRegionKeys) {
+ if (request->exists(key)) {
+ res = request->erase(key);
+ if (res != OK) {
+ return res;
+ }
+ }
+ }
+ return OK;
+}
+
status_t Camera3Device::RequestThread::prepareHalRequests() {
ATRACE_CALL();
@@ -4842,6 +4862,12 @@
it != captureRequest->mSettingsList.end(); it++) {
if (parent->mUHRCropAndMeteringRegionMappers.find(it->cameraId) ==
parent->mUHRCropAndMeteringRegionMappers.end()) {
+ if (removeFwkOnlyRegionKeys(&(it->metadata)) != OK) {
+ SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
+ "%d: %s (%d)", halRequest->frame_number, strerror(-res),
+ res);
+ return INVALID_OPERATION;
+ }
continue;
}
@@ -4856,6 +4882,12 @@
return INVALID_OPERATION;
}
captureRequest->mUHRCropAndMeteringRegionsUpdated = true;
+ if (removeFwkOnlyRegionKeys(&(it->metadata)) != OK) {
+ SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
+ "%d: %s (%d)", halRequest->frame_number, strerror(-res),
+ res);
+ return INVALID_OPERATION;
+ }
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 543de64..df941b2 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -297,6 +297,7 @@
private:
status_t disconnectImpl();
+ static status_t removeFwkOnlyRegionKeys(CameraMetadata *request);
// internal typedefs
using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
diff --git a/services/camera/libcameraservice/tests/ExifUtilsTest.cpp b/services/camera/libcameraservice/tests/ExifUtilsTest.cpp
new file mode 100644
index 0000000..3de4bf2
--- /dev/null
+++ b/services/camera/libcameraservice/tests/ExifUtilsTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExifUtilsTest"
+
+#include <camera/CameraMetadata.h>
+#include "../utils/ExifUtils.h"
+#include <gtest/gtest.h>
+
+using android::camera3::ExifUtils;
+using android::camera3::ExifOrientation;
+using android::CameraMetadata;
+
+uint32_t kImageWidth = 1920;
+uint32_t kImageHeight = 1440;
+ExifOrientation kExifOrientation = ExifOrientation::ORIENTATION_0_DEGREES;
+
+// Test that setFromMetadata works correctly, without errors.
+TEST(ExifUtilsTest, SetFromMetadataTest) {
+ std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+ uint8_t invalidSensorPixelMode = 2;
+ uint8_t validSensorPixelMode = ANDROID_SENSOR_PIXEL_MODE_DEFAULT;
+ CameraMetadata metadata;
+ // Empty staticInfo
+ CameraMetadata staticInfo;
+ ASSERT_TRUE(utils->initializeEmpty());
+ ASSERT_TRUE(
+ metadata.update(ANDROID_SENSOR_PIXEL_MODE, &invalidSensorPixelMode, 1) == android::OK);
+ ASSERT_FALSE(utils->setFromMetadata(metadata, staticInfo, kImageWidth, kImageHeight));
+ ASSERT_TRUE(
+ metadata.update(ANDROID_SENSOR_PIXEL_MODE, &validSensorPixelMode, 1) == android::OK);
+ ASSERT_TRUE(utils->setFromMetadata(metadata, staticInfo, kImageWidth, kImageHeight));
+ ASSERT_TRUE(utils->setImageWidth(kImageWidth));
+ ASSERT_TRUE(utils->setImageHeight(kImageHeight));
+ ASSERT_TRUE(utils->setOrientationValue(kExifOrientation));
+ ASSERT_TRUE(utils->generateApp1());
+ const uint8_t* exifBuffer = utils->getApp1Buffer();
+ ASSERT_NE(exifBuffer, nullptr);
+ size_t exifBufferSize = utils->getApp1Length();
+ ASSERT_TRUE(exifBufferSize != 0);
+}
diff --git a/services/camera/libcameraservice/utils/ExifUtils.cpp b/services/camera/libcameraservice/utils/ExifUtils.cpp
index 485705c..21f02db 100644
--- a/services/camera/libcameraservice/utils/ExifUtils.cpp
+++ b/services/camera/libcameraservice/utils/ExifUtils.cpp
@@ -920,7 +920,7 @@
camera_metadata_ro_entry sensorPixelModeEntry = metadata.find(ANDROID_SENSOR_PIXEL_MODE);
if (sensorPixelModeEntry.count != 0) {
sensorPixelMode = sensorPixelModeEntry.data.u8[0];
- if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_DEFAULT ||
+ if (sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_DEFAULT &&
sensorPixelMode != ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
ALOGE("%s: Request sensor pixel mode is not one of the valid values %d",
__FUNCTION__, sensorPixelMode);