Merge "MediaPlayer2: add native DataSourceDesc."
diff --git a/include/media/AudioPresentationInfo.h b/include/media/AudioPresentationInfo.h
new file mode 100644
index 0000000..e91a992
--- /dev/null
+++ b/include/media/AudioPresentationInfo.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_PRESENTATION_INFO_H_
+#define AUDIO_PRESENTATION_INFO_H_
+
+#include <sstream>
+#include <stdint.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+enum mastering_indication {
+ MASTERING_NOT_INDICATED,
+ MASTERED_FOR_STEREO,
+ MASTERED_FOR_SURROUND,
+ MASTERED_FOR_3D,
+ MASTERED_FOR_HEADPHONE,
+};
+
+struct AudioPresentation : public RefBase {
+ int32_t mPresentationId;
+ int32_t mProgramId;
+ KeyedVector<String8, String8> mLabels;
+ String8 mLanguage;
+ int32_t mMasteringIndication;
+ bool mAudioDescriptionAvailable;
+ bool mSpokenSubtitlesAvailable;
+ bool mDialogueEnhancementAvailable;
+
+ AudioPresentation() {
+ mPresentationId = -1;
+ mProgramId = -1;
+ mLanguage = "";
+ mMasteringIndication = MASTERING_NOT_INDICATED;
+ mAudioDescriptionAvailable = false;
+ mSpokenSubtitlesAvailable = false;
+ mDialogueEnhancementAvailable = false;
+ }
+};
+
+typedef Vector<sp<AudioPresentation>> AudioPresentations;
+
+class AudioPresentationInfo : public RefBase {
+ public:
+ AudioPresentationInfo();
+
+ ~AudioPresentationInfo();
+
+ void addPresentation(sp<AudioPresentation> presentation);
+
+ size_t countPresentations() const;
+
+ const sp<AudioPresentation> getPresentation(size_t index) const;
+
+ private:
+ AudioPresentations mPresentations;
+};
+
+} // namespace android
+
+#endif // AUDIO_PRESENTATION_INFO_H_
diff --git a/include/media/MicrophoneInfo.h b/include/media/MicrophoneInfo.h
index b0199d4..2287aca 100644
--- a/include/media/MicrophoneInfo.h
+++ b/include/media/MicrophoneInfo.h
@@ -42,7 +42,7 @@
MicrophoneInfo(audio_microphone_characteristic_t& characteristic) {
mDeviceId = String16(&characteristic.device_id[0]);
mPortId = characteristic.id;
- mType = characteristic.type;
+ mType = characteristic.device;
mAddress = String16(&characteristic.address[0]);
mDeviceLocation = characteristic.location;
mDeviceGroup = characteristic.group;
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index adc4904..854c691 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -251,8 +251,8 @@
}
audio_session_t AAudioConvert_aaudioToAndroidSessionId(aaudio_session_id_t sessionId) {
- // If not a valid sessionId then convert to a safe value of AUDIO_SESSION_ALLOCATE.
- return (sessionId < AAUDIO_SESSION_ID_MIN)
+ // If not a regular sessionId then convert to a safe value of AUDIO_SESSION_ALLOCATE.
+ return (sessionId == AAUDIO_SESSION_ID_ALLOCATE || sessionId == AAUDIO_SESSION_ID_NONE)
? AUDIO_SESSION_ALLOCATE
: (audio_session_t) sessionId;
}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 3673c34..dc6a671 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -27,9 +27,6 @@
#include "aaudio/AAudio.h"
-
-constexpr aaudio_session_id_t AAUDIO_SESSION_ID_MIN = 1; // must be positive
-
/**
* Convert an AAudio result into the closest matching Android status.
*/
diff --git a/media/libaaudio/tests/test_session_id.cpp b/media/libaaudio/tests/test_session_id.cpp
index d9072af..3f7d4fc 100644
--- a/media/libaaudio/tests/test_session_id.cpp
+++ b/media/libaaudio/tests/test_session_id.cpp
@@ -97,7 +97,10 @@
// Get the allocated ID from the stream.
sessionId1 = AAudioStream_getSessionId(aaudioStream1);
- ASSERT_LT(0, sessionId1); // Must be positive.
+
+ // Check for invalid session IDs.
+ ASSERT_NE(AAUDIO_SESSION_ID_NONE, sessionId1);
+ ASSERT_NE(AAUDIO_SESSION_ID_ALLOCATE, sessionId1);
ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream1));
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 7dd3f29..55954f2 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -29,6 +29,7 @@
#include <utils/Log.h>
#include <private/media/AudioTrackShared.h>
#include <media/IAudioFlinger.h>
+#include <media/AudioParameter.h>
#include <media/AudioPolicyHelper.h>
#include <media/AudioResamplerPublic.h>
#include <media/MediaAnalyticsItem.h>
@@ -2354,6 +2355,17 @@
return mAudioTrack->setParameters(keyValuePairs);
}
+status_t AudioTrack::selectPresentation(int presentationId, int programId)
+{
+ AutoMutex lock(mLock);
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyPresentationId), presentationId);
+ param.addInt(String8(AudioParameter::keyProgramId), programId);
+ ALOGV("PresentationId/ProgramId[%s]",param.toString().string());
+
+ return mAudioTrack->setParameters(param.toString());
+}
+
VolumeShaper::Status AudioTrack::applyVolumeShaper(
const sp<VolumeShaper::Configuration>& configuration,
const sp<VolumeShaper::Operation>& operation)
diff --git a/media/libaudioclient/include/media/AudioParameter.h b/media/libaudioclient/include/media/AudioParameter.h
index 1ace607..59ac1db 100644
--- a/media/libaudioclient/include/media/AudioParameter.h
+++ b/media/libaudioclient/include/media/AudioParameter.h
@@ -58,6 +58,12 @@
static const char * const keyMonoOutput;
static const char * const keyStreamHwAvSync;
+ // keys for presentation selection
+ // keyPresentationId: Audio presentation identifier
+ // keyProgramId: Audio presentation program identifier
+ static const char * const keyPresentationId;
+ static const char * const keyProgramId;
+
// keyStreamConnect / Disconnect: value is an int in audio_devices_t
static const char * const keyStreamConnect;
static const char * const keyStreamDisconnect;
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index e5bb854..3eb627d 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -765,6 +765,9 @@
/* Gets the volume shaper state */
sp<media::VolumeShaper::State> getVolumeShaperState(int id);
+ /* Selects the presentation (if available) */
+ status_t selectPresentation(int presentationId, int programId);
+
/* Get parameters */
String8 getParameters(const String8& keys);
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 65fc70b..cb0e927 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -34,6 +34,8 @@
const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
const char * const AudioParameter::keyBtNrec = AUDIO_PARAMETER_KEY_BT_NREC;
const char * const AudioParameter::keyHwAvSync = AUDIO_PARAMETER_HW_AV_SYNC;
+const char * const AudioParameter::keyPresentationId = AUDIO_PARAMETER_STREAM_PRESENTATION_ID;
+const char * const AudioParameter::keyProgramId = AUDIO_PARAMETER_STREAM_PROGRAM_ID;
const char * const AudioParameter::keyMonoOutput = AUDIO_PARAMETER_MONO_OUTPUT;
const char * const AudioParameter::keyStreamHwAvSync = AUDIO_PARAMETER_STREAM_HW_AV_SYNC;
const char * const AudioParameter::keyStreamConnect = AUDIO_PARAMETER_DEVICE_CONNECT;
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
deleted file mode 100644
index 406074b..0000000
--- a/media/libstagefright/AVIExtractor.cpp
+++ /dev/null
@@ -1,1307 +0,0 @@
-/*
- * Copyright (C) 2011 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 "AVIExtractor"
-#include <utils/Log.h>
-
-#include "include/AVIExtractor.h"
-
-#include <binder/ProcessState.h>
-#include <media/DataSource.h>
-#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-struct AVIExtractor::AVISource : public MediaSource {
- AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex);
-
- virtual status_t start(MetaData *params);
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
-
-protected:
- virtual ~AVISource();
-
-private:
- sp<AVIExtractor> mExtractor;
- size_t mTrackIndex;
- const AVIExtractor::Track &mTrack;
- MediaBufferGroup *mBufferGroup;
- size_t mSampleIndex;
-
- sp<MP3Splitter> mSplitter;
-
- DISALLOW_EVIL_CONSTRUCTORS(AVISource);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct AVIExtractor::MP3Splitter : public RefBase {
- MP3Splitter();
-
- void clear();
- void append(MediaBuffer *buffer);
- status_t read(MediaBuffer **buffer);
-
-protected:
- virtual ~MP3Splitter();
-
-private:
- bool mFindSync;
- int64_t mBaseTimeUs;
- int64_t mNumSamplesRead;
- sp<ABuffer> mBuffer;
-
- bool resync();
-
- DISALLOW_EVIL_CONSTRUCTORS(MP3Splitter);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-AVIExtractor::AVISource::AVISource(
- const sp<AVIExtractor> &extractor, size_t trackIndex)
- : mExtractor(extractor),
- mTrackIndex(trackIndex),
- mTrack(mExtractor->mTracks.itemAt(trackIndex)),
- mBufferGroup(NULL) {
-}
-
-AVIExtractor::AVISource::~AVISource() {
- if (mBufferGroup) {
- stop();
- }
-}
-
-status_t AVIExtractor::AVISource::start(MetaData *params) {
- CHECK(!mBufferGroup);
-
- mBufferGroup = new MediaBufferGroup;
-
- mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
- mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
- mSampleIndex = 0;
-
- const char *mime;
- CHECK(mTrack.mMeta->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
- mSplitter = new MP3Splitter;
- } else {
- mSplitter.clear();
- }
-
- return OK;
-}
-
-status_t AVIExtractor::AVISource::stop() {
- CHECK(mBufferGroup);
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSplitter.clear();
-
- return OK;
-}
-
-sp<MetaData> AVIExtractor::AVISource::getFormat() {
- return mTrack.mMeta;
-}
-
-status_t AVIExtractor::AVISource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
- CHECK(mBufferGroup);
-
- *buffer = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- status_t err =
- mExtractor->getSampleIndexAtTime(
- mTrackIndex, seekTimeUs, seekMode, &mSampleIndex);
-
- if (err != OK) {
- return ERROR_END_OF_STREAM;
- }
-
- if (mSplitter != NULL) {
- mSplitter->clear();
- }
- }
-
- for (;;) {
- if (mSplitter != NULL) {
- status_t err = mSplitter->read(buffer);
-
- if (err == OK) {
- break;
- } else if (err != -EAGAIN) {
- return err;
- }
- }
-
- off64_t offset;
- size_t size;
- bool isKey;
- int64_t timeUs;
- status_t err = mExtractor->getSampleInfo(
- mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
-
- ++mSampleIndex;
-
- if (err != OK) {
- return ERROR_END_OF_STREAM;
- }
-
- MediaBuffer *out;
- CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK);
-
- ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size);
-
- if (n < (ssize_t)size) {
- return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
- }
-
- out->set_range(0, size);
-
- out->meta_data()->setInt64(kKeyTime, timeUs);
-
- if (isKey) {
- out->meta_data()->setInt32(kKeyIsSyncFrame, 1);
- }
-
- if (mSplitter == NULL) {
- *buffer = out;
- break;
- }
-
- mSplitter->append(out);
- out->release();
- out = NULL;
- }
-
- return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-AVIExtractor::MP3Splitter::MP3Splitter()
- : mFindSync(true),
- mBaseTimeUs(-1ll),
- mNumSamplesRead(0) {
-}
-
-AVIExtractor::MP3Splitter::~MP3Splitter() {
-}
-
-void AVIExtractor::MP3Splitter::clear() {
- mFindSync = true;
- mBaseTimeUs = -1ll;
- mNumSamplesRead = 0;
-
- if (mBuffer != NULL) {
- mBuffer->setRange(0, 0);
- }
-}
-
-void AVIExtractor::MP3Splitter::append(MediaBuffer *buffer) {
- size_t prevCapacity = (mBuffer != NULL) ? mBuffer->capacity() : 0;
-
- if (mBaseTimeUs < 0) {
- CHECK(mBuffer == NULL || mBuffer->size() == 0);
- CHECK(buffer->meta_data()->findInt64(kKeyTime, &mBaseTimeUs));
- mNumSamplesRead = 0;
- }
-
- if (mBuffer != NULL && mBuffer->offset() > 0) {
- memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
- mBuffer->setRange(0, mBuffer->size());
- }
-
- if (mBuffer == NULL
- || mBuffer->size() + buffer->range_length() > prevCapacity) {
- size_t newCapacity =
- (prevCapacity + buffer->range_length() + 1023) & ~1023;
-
- sp<ABuffer> newBuffer = new ABuffer(newCapacity);
- if (mBuffer != NULL) {
- memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
- newBuffer->setRange(0, mBuffer->size());
- } else {
- newBuffer->setRange(0, 0);
- }
- mBuffer = newBuffer;
- }
-
- memcpy(mBuffer->data() + mBuffer->size(),
- (const uint8_t *)buffer->data() + buffer->range_offset(),
- buffer->range_length());
-
- mBuffer->setRange(0, mBuffer->size() + buffer->range_length());
-}
-
-bool AVIExtractor::MP3Splitter::resync() {
- if (mBuffer == NULL) {
- return false;
- }
-
- bool foundSync = false;
- for (size_t offset = 0; offset + 3 < mBuffer->size(); ++offset) {
- uint32_t firstHeader = U32_AT(mBuffer->data() + offset);
-
- size_t frameSize;
- if (!GetMPEGAudioFrameSize(firstHeader, &frameSize)) {
- continue;
- }
-
- size_t subsequentOffset = offset + frameSize;
- size_t i = 3;
- while (i > 0) {
- if (subsequentOffset + 3 >= mBuffer->size()) {
- break;
- }
-
- static const uint32_t kMask = 0xfffe0c00;
-
- uint32_t header = U32_AT(mBuffer->data() + subsequentOffset);
- if ((header & kMask) != (firstHeader & kMask)) {
- break;
- }
-
- if (!GetMPEGAudioFrameSize(header, &frameSize)) {
- break;
- }
-
- subsequentOffset += frameSize;
- --i;
- }
-
- if (i == 0) {
- foundSync = true;
- memmove(mBuffer->data(),
- mBuffer->data() + offset,
- mBuffer->size() - offset);
-
- mBuffer->setRange(0, mBuffer->size() - offset);
- break;
- }
- }
-
- return foundSync;
-}
-
-status_t AVIExtractor::MP3Splitter::read(MediaBuffer **out) {
- *out = NULL;
-
- if (mFindSync) {
- if (!resync()) {
- return -EAGAIN;
- }
-
- mFindSync = false;
- }
-
- if (mBuffer->size() < 4) {
- return -EAGAIN;
- }
-
- uint32_t header = U32_AT(mBuffer->data());
- size_t frameSize;
- int sampleRate;
- int numSamples;
- if (!GetMPEGAudioFrameSize(
- header, &frameSize, &sampleRate, NULL, NULL, &numSamples)) {
- return ERROR_MALFORMED;
- }
-
- if (mBuffer->size() < frameSize) {
- return -EAGAIN;
- }
-
- MediaBuffer *mbuf = new MediaBuffer(frameSize);
- memcpy(mbuf->data(), mBuffer->data(), frameSize);
-
- int64_t timeUs = mBaseTimeUs + (mNumSamplesRead * 1000000ll) / sampleRate;
- mNumSamplesRead += numSamples;
-
- mbuf->meta_data()->setInt64(kKeyTime, timeUs);
-
- mBuffer->setRange(
- mBuffer->offset() + frameSize, mBuffer->size() - frameSize);
-
- *out = mbuf;
-
- return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource)
- : mDataSource(dataSource) {
- mInitCheck = parseHeaders();
-
- if (mInitCheck != OK) {
- mTracks.clear();
- }
-}
-
-AVIExtractor::~AVIExtractor() {
-}
-
-size_t AVIExtractor::countTracks() {
- return mTracks.size();
-}
-
-sp<MediaSource> AVIExtractor::getTrack(size_t index) {
- return index < mTracks.size() ? new AVISource(this, index) : NULL;
-}
-
-sp<MetaData> AVIExtractor::getTrackMetaData(
- size_t index, uint32_t flags) {
- return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL;
-}
-
-sp<MetaData> AVIExtractor::getMetaData() {
- sp<MetaData> meta = new MetaData;
-
- if (mInitCheck == OK) {
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI);
- }
-
- return meta;
-}
-
-status_t AVIExtractor::parseHeaders() {
- mTracks.clear();
- mMovieOffset = 0;
- mFoundIndex = false;
- mOffsetsAreAbsolute = false;
-
- ssize_t res = parseChunk(0ll, -1ll);
-
- if (res < 0) {
- return (status_t)res;
- }
-
- if (mMovieOffset == 0ll || !mFoundIndex) {
- return ERROR_MALFORMED;
- }
-
- return OK;
-}
-
-ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) {
- if (size >= 0 && size < 8) {
- return ERROR_MALFORMED;
- }
-
- uint8_t tmp[12];
- ssize_t n = mDataSource->readAt(offset, tmp, 8);
-
- if (n < 8) {
- return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
- }
-
- uint32_t fourcc = U32_AT(tmp);
- uint32_t chunkSize = U32LE_AT(&tmp[4]);
-
- if (size >= 0 && chunkSize + 8 > size) {
- return ERROR_MALFORMED;
- }
-
- static const char kPrefix[] = " ";
- const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth];
-
- if (fourcc == FOURCC('L', 'I', 'S', 'T')
- || fourcc == FOURCC('R', 'I', 'F', 'F')) {
- // It's a list of chunks
-
- if (size >= 0 && size < 12) {
- return ERROR_MALFORMED;
- }
-
- n = mDataSource->readAt(offset + 8, &tmp[8], 4);
-
- if (n < 4) {
- return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
- }
-
- uint32_t subFourcc = U32_AT(&tmp[8]);
-
- ALOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d",
- prefix,
- offset,
- (char)(subFourcc >> 24),
- (char)((subFourcc >> 16) & 0xff),
- (char)((subFourcc >> 8) & 0xff),
- (char)(subFourcc & 0xff),
- chunkSize - 4);
-
- if (subFourcc == FOURCC('m', 'o', 'v', 'i')) {
- // We're not going to parse this, but will take note of the
- // offset.
-
- mMovieOffset = offset;
- } else {
- off64_t subOffset = offset + 12;
- off64_t subOffsetLimit = subOffset + chunkSize - 4;
- while (subOffset < subOffsetLimit) {
- ssize_t res =
- parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1);
-
- if (res < 0) {
- return res;
- }
-
- subOffset += res;
- }
- }
- } else {
- ALOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'",
- prefix,
- offset,
- (char)(fourcc >> 24),
- (char)((fourcc >> 16) & 0xff),
- (char)((fourcc >> 8) & 0xff),
- (char)(fourcc & 0xff));
-
- status_t err = OK;
-
- switch (fourcc) {
- case FOURCC('s', 't', 'r', 'h'):
- {
- err = parseStreamHeader(offset + 8, chunkSize);
- break;
- }
-
- case FOURCC('s', 't', 'r', 'f'):
- {
- err = parseStreamFormat(offset + 8, chunkSize);
- break;
- }
-
- case FOURCC('i', 'd', 'x', '1'):
- {
- err = parseIndex(offset + 8, chunkSize);
- break;
- }
-
- default:
- break;
- }
-
- if (err != OK) {
- return err;
- }
- }
-
- if (chunkSize & 1) {
- ++chunkSize;
- }
-
- return chunkSize + 8;
-}
-
-static const char *GetMIMETypeForHandler(uint32_t handler) {
- switch (handler) {
- // Wow... shamelessly copied from
- // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4
-
- case FOURCC('3', 'I', 'V', '2'):
- case FOURCC('3', 'i', 'v', '2'):
- case FOURCC('B', 'L', 'Z', '0'):
- case FOURCC('D', 'I', 'G', 'I'):
- case FOURCC('D', 'I', 'V', '1'):
- case FOURCC('d', 'i', 'v', '1'):
- case FOURCC('D', 'I', 'V', 'X'):
- case FOURCC('d', 'i', 'v', 'x'):
- case FOURCC('D', 'X', '5', '0'):
- case FOURCC('d', 'x', '5', '0'):
- case FOURCC('D', 'X', 'G', 'M'):
- case FOURCC('E', 'M', '4', 'A'):
- case FOURCC('E', 'P', 'H', 'V'):
- case FOURCC('F', 'M', 'P', '4'):
- case FOURCC('f', 'm', 'p', '4'):
- case FOURCC('F', 'V', 'F', 'W'):
- case FOURCC('H', 'D', 'X', '4'):
- case FOURCC('h', 'd', 'x', '4'):
- case FOURCC('M', '4', 'C', 'C'):
- case FOURCC('M', '4', 'S', '2'):
- case FOURCC('m', '4', 's', '2'):
- case FOURCC('M', 'P', '4', 'S'):
- case FOURCC('m', 'p', '4', 's'):
- case FOURCC('M', 'P', '4', 'V'):
- case FOURCC('m', 'p', '4', 'v'):
- case FOURCC('M', 'V', 'X', 'M'):
- case FOURCC('R', 'M', 'P', '4'):
- case FOURCC('S', 'E', 'D', 'G'):
- case FOURCC('S', 'M', 'P', '4'):
- case FOURCC('U', 'M', 'P', '4'):
- case FOURCC('W', 'V', '1', 'F'):
- case FOURCC('X', 'V', 'I', 'D'):
- case FOURCC('X', 'v', 'i', 'D'):
- case FOURCC('x', 'v', 'i', 'd'):
- case FOURCC('X', 'V', 'I', 'X'):
- return MEDIA_MIMETYPE_VIDEO_MPEG4;
-
- // from http://wiki.multimedia.cx/index.php?title=H264
- case FOURCC('a', 'v', 'c', '1'):
- case FOURCC('d', 'a', 'v', 'c'):
- case FOURCC('x', '2', '6', '4'):
- case FOURCC('H', '2', '6', '4'):
- case FOURCC('v', 's', 's', 'h'):
- return MEDIA_MIMETYPE_VIDEO_AVC;
-
- default:
- return NULL;
- }
-}
-
-status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
- if (size != 56) {
- return ERROR_MALFORMED;
- }
-
- if (mTracks.size() > 99) {
- return -ERANGE;
- }
-
- sp<ABuffer> buffer = new ABuffer(size);
- ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
- if (n < (ssize_t)size) {
- return n < 0 ? (status_t)n : ERROR_MALFORMED;
- }
-
- const uint8_t *data = buffer->data();
-
- uint32_t type = U32_AT(data);
- uint32_t handler = U32_AT(&data[4]);
- uint32_t flags = U32LE_AT(&data[8]);
-
- sp<MetaData> meta = new MetaData;
-
- uint32_t rate = U32LE_AT(&data[20]);
- uint32_t scale = U32LE_AT(&data[24]);
-
- uint32_t sampleSize = U32LE_AT(&data[44]);
-
- const char *mime = NULL;
- Track::Kind kind = Track::OTHER;
-
- if (type == FOURCC('v', 'i', 'd', 's')) {
- mime = GetMIMETypeForHandler(handler);
-
- if (mime && strncasecmp(mime, "video/", 6)) {
- return ERROR_MALFORMED;
- }
-
- if (mime == NULL) {
- ALOGW("Unsupported video format '%c%c%c%c'",
- (char)(handler >> 24),
- (char)((handler >> 16) & 0xff),
- (char)((handler >> 8) & 0xff),
- (char)(handler & 0xff));
- }
-
- kind = Track::VIDEO;
- } else if (type == FOURCC('a', 'u', 'd', 's')) {
- if (mime && strncasecmp(mime, "audio/", 6)) {
- return ERROR_MALFORMED;
- }
-
- kind = Track::AUDIO;
- }
-
- if (!mime) {
- mime = "application/octet-stream";
- }
-
- meta->setCString(kKeyMIMEType, mime);
-
- mTracks.push();
- Track *track = &mTracks.editItemAt(mTracks.size() - 1);
-
- track->mMeta = meta;
- track->mRate = rate;
- track->mScale = scale;
- track->mBytesPerSample = sampleSize;
- track->mKind = kind;
- track->mNumSyncSamples = 0;
- track->mThumbnailSampleSize = 0;
- track->mThumbnailSampleIndex = -1;
- track->mMaxSampleSize = 0;
- track->mAvgChunkSize = 1.0;
- track->mFirstChunkSize = 0;
-
- return OK;
-}
-
-status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
- if (mTracks.isEmpty()) {
- return ERROR_MALFORMED;
- }
-
- Track *track = &mTracks.editItemAt(mTracks.size() - 1);
-
- if (track->mKind == Track::OTHER) {
- // We don't support this content, but that's not a parsing error.
- return OK;
- }
-
- bool isVideo = (track->mKind == Track::VIDEO);
-
- if ((isVideo && size < 40) || (!isVideo && size < 16)) {
- // Expected a BITMAPINFO or WAVEFORMAT(EX) structure, respectively.
- return ERROR_MALFORMED;
- }
-
- sp<ABuffer> buffer = new ABuffer(size);
- ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
- if (n < (ssize_t)size) {
- return n < 0 ? (status_t)n : ERROR_MALFORMED;
- }
-
- const uint8_t *data = buffer->data();
-
- if (isVideo) {
- uint32_t width = U32LE_AT(&data[4]);
- uint32_t height = U32LE_AT(&data[8]);
-
- track->mMeta->setInt32(kKeyWidth, width);
- track->mMeta->setInt32(kKeyHeight, height);
- } else {
- uint32_t format = U16LE_AT(data);
-
- if (format == 0x55) {
- track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- } else {
- ALOGW("Unsupported audio format = 0x%04x", format);
- }
-
- uint32_t numChannels = U16LE_AT(&data[2]);
- uint32_t sampleRate = U32LE_AT(&data[4]);
-
- track->mMeta->setInt32(kKeyChannelCount, numChannels);
- track->mMeta->setInt32(kKeySampleRate, sampleRate);
- }
-
- return OK;
-}
-
-// static
-bool AVIExtractor::IsCorrectChunkType(
- ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) {
- uint32_t chunkBase = chunkType & 0xffff;
-
- switch (kind) {
- case Track::VIDEO:
- {
- if (chunkBase != FOURCC(0, 0, 'd', 'c')
- && chunkBase != FOURCC(0, 0, 'd', 'b')) {
- return false;
- }
- break;
- }
-
- case Track::AUDIO:
- {
- if (chunkBase != FOURCC(0, 0, 'w', 'b')) {
- return false;
- }
- break;
- }
-
- default:
- break;
- }
-
- if (trackIndex < 0) {
- return true;
- }
-
- uint8_t hi = chunkType >> 24;
- uint8_t lo = (chunkType >> 16) & 0xff;
-
- if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
- return false;
- }
-
- if (trackIndex != (10 * (hi - '0') + (lo - '0'))) {
- return false;
- }
-
- return true;
-}
-
-status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
- if ((size % 16) != 0) {
- return ERROR_MALFORMED;
- }
-
- sp<ABuffer> buffer = new ABuffer(size);
- ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
- if (n < (ssize_t)size) {
- return n < 0 ? (status_t)n : ERROR_MALFORMED;
- }
-
- const uint8_t *data = buffer->data();
-
- while (size > 0) {
- uint32_t chunkType = U32_AT(data);
-
- uint8_t hi = chunkType >> 24;
- uint8_t lo = (chunkType >> 16) & 0xff;
-
- if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
- return ERROR_MALFORMED;
- }
-
- size_t trackIndex = 10 * (hi - '0') + (lo - '0');
-
- if (trackIndex >= mTracks.size()) {
- return ERROR_MALFORMED;
- }
-
- Track *track = &mTracks.editItemAt(trackIndex);
-
- if (!IsCorrectChunkType(-1, track->mKind, chunkType)) {
- return ERROR_MALFORMED;
- }
-
- if (track->mKind == Track::OTHER) {
- data += 16;
- size -= 16;
- continue;
- }
-
- uint32_t flags = U32LE_AT(&data[4]);
- uint32_t offset = U32LE_AT(&data[8]);
- uint32_t chunkSize = U32LE_AT(&data[12]);
-
- if (chunkSize > track->mMaxSampleSize) {
- track->mMaxSampleSize = chunkSize;
- }
-
- track->mSamples.push();
-
- SampleInfo *info =
- &track->mSamples.editItemAt(track->mSamples.size() - 1);
-
- info->mOffset = offset;
- info->mIsKey = (flags & 0x10) != 0;
-
- if (info->mIsKey) {
- static const size_t kMaxNumSyncSamplesToScan = 20;
-
- if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) {
- if (chunkSize > track->mThumbnailSampleSize) {
- track->mThumbnailSampleSize = chunkSize;
-
- track->mThumbnailSampleIndex =
- track->mSamples.size() - 1;
- }
- }
-
- ++track->mNumSyncSamples;
- }
-
- data += 16;
- size -= 16;
- }
-
- if (!mTracks.isEmpty()) {
- off64_t offset;
- size_t size;
- bool isKey;
- int64_t timeUs;
- status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
-
- if (err != OK) {
- mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
- err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
-
- if (err != OK) {
- return err;
- }
- }
-
- ALOGV("Chunk offsets are %s",
- mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative");
- }
-
- for (size_t i = 0; i < mTracks.size(); ++i) {
- Track *track = &mTracks.editItemAt(i);
-
- if (track->mBytesPerSample > 0) {
- // Assume all chunks are roughly the same size for now.
-
- // Compute the avg. size of the first 128 chunks (if there are
- // that many), but exclude the size of the first one, since
- // it may be an outlier.
- size_t numSamplesToAverage = track->mSamples.size();
- if (numSamplesToAverage > 256) {
- numSamplesToAverage = 256;
- }
-
- double avgChunkSize = 0;
- size_t j;
- for (j = 0; j <= numSamplesToAverage; ++j) {
- off64_t offset;
- size_t size;
- bool isKey;
- int64_t dummy;
-
- status_t err =
- getSampleInfo(
- i, j,
- &offset, &size, &isKey, &dummy);
-
- if (err != OK) {
- return err;
- }
-
- if (j == 0) {
- track->mFirstChunkSize = size;
- continue;
- }
-
- avgChunkSize += size;
- }
-
- avgChunkSize /= numSamplesToAverage;
-
- track->mAvgChunkSize = avgChunkSize;
- }
-
- int64_t durationUs;
- CHECK_EQ((status_t)OK,
- getSampleTime(i, track->mSamples.size() - 1, &durationUs));
-
- ALOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
-
- track->mMeta->setInt64(kKeyDuration, durationUs);
- track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize);
-
- const char *tmp;
- CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp));
-
- AString mime = tmp;
-
- if (!strncasecmp("video/", mime.c_str(), 6)) {
- if (track->mThumbnailSampleIndex >= 0) {
- int64_t thumbnailTimeUs;
- CHECK_EQ((status_t)OK,
- getSampleTime(i, track->mThumbnailSampleIndex,
- &thumbnailTimeUs));
-
- track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
- }
-
- status_t err = OK;
-
- if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
- err = addMPEG4CodecSpecificData(i);
- } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
- err = addH264CodecSpecificData(i);
- }
-
- if (err != OK) {
- return err;
- }
- }
- }
-
- mFoundIndex = true;
-
- return OK;
-}
-
-static size_t GetSizeWidth(size_t x) {
- size_t n = 1;
- while (x > 127) {
- ++n;
- x >>= 7;
- }
- return n;
-}
-
-static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
- while (x > 127) {
- *dst++ = (x & 0x7f) | 0x80;
- x >>= 7;
- }
- *dst++ = x;
- return dst;
-}
-
-sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) {
- size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
- size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
- size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
-
- sp<ABuffer> csd = new ABuffer(len3);
- uint8_t *dst = csd->data();
- *dst++ = 0x03;
- dst = EncodeSize(dst, len2 + 3);
- *dst++ = 0x00; // ES_ID
- *dst++ = 0x00;
- *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
- *dst++ = 0x04;
- dst = EncodeSize(dst, len1 + 13);
- *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile
- for (size_t i = 0; i < 12; ++i) {
- *dst++ = 0x00;
- }
-
- *dst++ = 0x05;
- dst = EncodeSize(dst, config->size());
- memcpy(dst, config->data(), config->size());
- dst += config->size();
-
- // hexdump(csd->data(), csd->size());
-
- return csd;
-}
-
-status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
- Track *track = &mTracks.editItemAt(trackIndex);
-
- off64_t offset;
- size_t size;
- bool isKey;
- int64_t timeUs;
- status_t err =
- getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
-
- if (err != OK) {
- return err;
- }
-
- sp<ABuffer> buffer = new ABuffer(size);
- ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
- if (n < (ssize_t)size) {
- return n < 0 ? (status_t)n : ERROR_MALFORMED;
- }
-
- // Extract everything up to the first VOP start code from the first
- // frame's encoded data and use it to construct an ESDS with the
- // codec specific data.
-
- size_t i = 0;
- bool found = false;
- while (i + 3 < buffer->size()) {
- if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) {
- found = true;
- break;
- }
-
- ++i;
- }
-
- if (!found) {
- return ERROR_MALFORMED;
- }
-
- buffer->setRange(0, i);
-
- sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer);
- track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size());
-
- return OK;
-}
-
-status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) {
- Track *track = &mTracks.editItemAt(trackIndex);
-
- off64_t offset;
- size_t size;
- bool isKey;
- int64_t timeUs;
-
- // Extract codec specific data from the first non-empty sample.
-
- size_t sampleIndex = 0;
- for (;;) {
- status_t err =
- getSampleInfo(
- trackIndex, sampleIndex, &offset, &size, &isKey, &timeUs);
-
- if (err != OK) {
- return err;
- }
-
- if (size > 0) {
- break;
- }
-
- ++sampleIndex;
- }
-
- sp<ABuffer> buffer = new ABuffer(size);
- ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
-
- if (n < (ssize_t)size) {
- return n < 0 ? (status_t)n : ERROR_MALFORMED;
- }
-
- sp<MetaData> meta = MakeAVCCodecSpecificData(buffer);
-
- if (meta == NULL) {
- ALOGE("Unable to extract AVC codec specific data");
- return ERROR_MALFORMED;
- }
-
- int32_t width, height;
- CHECK(meta->findInt32(kKeyWidth, &width));
- CHECK(meta->findInt32(kKeyHeight, &height));
-
- uint32_t type;
- const void *csd;
- size_t csdSize;
- CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
-
- track->mMeta->setInt32(kKeyWidth, width);
- track->mMeta->setInt32(kKeyHeight, height);
- track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
-
- return OK;
-}
-
-status_t AVIExtractor::getSampleInfo(
- size_t trackIndex, size_t sampleIndex,
- off64_t *offset, size_t *size, bool *isKey,
- int64_t *sampleTimeUs) {
- if (trackIndex >= mTracks.size()) {
- return -ERANGE;
- }
-
- const Track &track = mTracks.itemAt(trackIndex);
-
- if (sampleIndex >= track.mSamples.size()) {
- return -ERANGE;
- }
-
- const SampleInfo &info = track.mSamples.itemAt(sampleIndex);
-
- if (!mOffsetsAreAbsolute) {
- *offset = info.mOffset + mMovieOffset + 8;
- } else {
- *offset = info.mOffset;
- }
-
- *size = 0;
-
- uint8_t tmp[8];
- ssize_t n = mDataSource->readAt(*offset, tmp, 8);
-
- if (n < 8) {
- return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
- }
-
- uint32_t chunkType = U32_AT(tmp);
-
- if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) {
- return ERROR_MALFORMED;
- }
-
- *offset += 8;
- *size = U32LE_AT(&tmp[4]);
-
- *isKey = info.mIsKey;
-
- if (track.mBytesPerSample > 0) {
- size_t sampleStartInBytes;
- if (sampleIndex == 0) {
- sampleStartInBytes = 0;
- } else {
- sampleStartInBytes =
- track.mFirstChunkSize + track.mAvgChunkSize * (sampleIndex - 1);
- }
-
- sampleIndex = sampleStartInBytes / track.mBytesPerSample;
- }
-
- *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
-
- return OK;
-}
-
-status_t AVIExtractor::getSampleTime(
- size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
- off64_t offset;
- size_t size;
- bool isKey;
- return getSampleInfo(
- trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
-}
-
-status_t AVIExtractor::getSampleIndexAtTime(
- size_t trackIndex,
- int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
- size_t *sampleIndex) const {
- if (trackIndex >= mTracks.size()) {
- return -ERANGE;
- }
-
- const Track &track = mTracks.itemAt(trackIndex);
-
- ssize_t closestSampleIndex;
-
- if (track.mBytesPerSample > 0) {
- size_t closestByteOffset =
- (timeUs * track.mBytesPerSample)
- / track.mRate * track.mScale / 1000000ll;
-
- if (closestByteOffset <= track.mFirstChunkSize) {
- closestSampleIndex = 0;
- } else {
- closestSampleIndex =
- (closestByteOffset - track.mFirstChunkSize)
- / track.mAvgChunkSize;
- }
- } else {
- // Each chunk contains a single sample.
- closestSampleIndex = timeUs / track.mRate * track.mScale / 1000000ll;
- }
-
- ssize_t numSamples = track.mSamples.size();
-
- if (closestSampleIndex < 0) {
- closestSampleIndex = 0;
- } else if (closestSampleIndex >= numSamples) {
- closestSampleIndex = numSamples - 1;
- }
-
- if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) {
- *sampleIndex = closestSampleIndex;
-
- return OK;
- }
-
- ssize_t prevSyncSampleIndex = closestSampleIndex;
- while (prevSyncSampleIndex >= 0) {
- const SampleInfo &info =
- track.mSamples.itemAt(prevSyncSampleIndex);
-
- if (info.mIsKey) {
- break;
- }
-
- --prevSyncSampleIndex;
- }
-
- ssize_t nextSyncSampleIndex = closestSampleIndex;
- while (nextSyncSampleIndex < numSamples) {
- const SampleInfo &info =
- track.mSamples.itemAt(nextSyncSampleIndex);
-
- if (info.mIsKey) {
- break;
- }
-
- ++nextSyncSampleIndex;
- }
-
- switch (mode) {
- case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
- {
- *sampleIndex = prevSyncSampleIndex;
-
- return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR;
- }
-
- case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
- {
- *sampleIndex = nextSyncSampleIndex;
-
- return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR;
- }
-
- case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
- {
- if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) {
- return UNKNOWN_ERROR;
- }
-
- if (prevSyncSampleIndex < 0) {
- *sampleIndex = nextSyncSampleIndex;
- return OK;
- }
-
- if (nextSyncSampleIndex >= numSamples) {
- *sampleIndex = prevSyncSampleIndex;
- return OK;
- }
-
- size_t dist1 = closestSampleIndex - prevSyncSampleIndex;
- size_t dist2 = nextSyncSampleIndex - closestSampleIndex;
-
- *sampleIndex =
- (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex;
-
- return OK;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-bool SniffAVI(
- const sp<DataSource> &source, String8 *mimeType, float *confidence,
- sp<AMessage> *) {
- char tmp[12];
- if (source->readAt(0, tmp, 12) < 12) {
- return false;
- }
-
- if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
- mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
-
- // Just a tad over the mp3 extractor's confidence, since
- // these .avi files may contain .mp3 content that otherwise would
- // mistakenly lead to us identifying the entire file as a .mp3 file.
- *confidence = 0.21;
-
- return true;
- }
-
- return false;
-}
-
-} // namespace android
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 106688a..5240f7b 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -57,6 +57,7 @@
"AACWriter.cpp",
"AMRWriter.cpp",
"AudioPlayer.cpp",
+ "AudioPresentationInfo.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
"CCodec.cpp",
@@ -136,6 +137,8 @@
"libRScpp",
"libhidlbase",
"libhidlmemory",
+ // TODO: Remove libv4l2_c2_componentstore.
+ "libv4l2_c2componentstore",
"libziparchive",
"android.hidl.allocator@1.0",
"android.hardware.cas.native@1.0",
diff --git a/media/libstagefright/AudioPresentationInfo.cpp b/media/libstagefright/AudioPresentationInfo.cpp
new file mode 100644
index 0000000..86e1859
--- /dev/null
+++ b/media/libstagefright/AudioPresentationInfo.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "AudioPresentationInfo"
+
+#include <media/AudioPresentationInfo.h>
+
+namespace android {
+
+AudioPresentationInfo::AudioPresentationInfo() {
+}
+
+AudioPresentationInfo::~AudioPresentationInfo() {
+ mPresentations.clear();
+}
+
+void AudioPresentationInfo::addPresentation(sp<AudioPresentation> presentation) {
+ mPresentations.push(presentation);
+}
+
+size_t AudioPresentationInfo::countPresentations() const {
+ return mPresentations.size();
+}
+
+// Returns an AudioPresentation for the given valid index
+// index must be >=0 and < countPresentations()
+const sp<AudioPresentation> AudioPresentationInfo::getPresentation(size_t index) const {
+ return mPresentations[index];
+}
+
+} // namespace android
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 9fb6d34..bd2443d 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -64,28 +64,51 @@
return ICrypto::kDestinationTypeNativeHandle;
}
-// Codec2Buffer
+// LinearBlockBuffer
// static
-sp<Codec2Buffer> Codec2Buffer::allocate(
+sp<LinearBlockBuffer> LinearBlockBuffer::allocate(
const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block) {
C2WriteView writeView(block->map().get());
if (writeView.error() != C2_OK) {
return nullptr;
}
- return new Codec2Buffer(format, new ABuffer(writeView.base(), writeView.capacity()), block);
+ return new LinearBlockBuffer(format, std::move(writeView), block);
}
-C2ConstLinearBlock Codec2Buffer::share() {
+C2ConstLinearBlock LinearBlockBuffer::share() {
return mBlock->share(offset(), size(), C2Fence());
}
-Codec2Buffer::Codec2Buffer(
+LinearBlockBuffer::LinearBlockBuffer(
const sp<AMessage> &format,
- const sp<ABuffer> &buffer,
+ C2WriteView&& writeView,
const std::shared_ptr<C2LinearBlock> &block)
- : MediaCodecBuffer(format, buffer),
+ : MediaCodecBuffer(format, new ABuffer(writeView.data(), writeView.size())),
+ mWriteView(writeView),
mBlock(block) {
}
+// ConstLinearBlockBuffer
+
+// static
+sp<ConstLinearBlockBuffer> ConstLinearBlockBuffer::allocate(
+ const sp<AMessage> &format, const C2ConstLinearBlock &block) {
+ C2ReadView readView(block.map().get());
+ if (readView.error() != C2_OK) {
+ return nullptr;
+ }
+ return new ConstLinearBlockBuffer(format, std::move(readView));
+}
+
+ConstLinearBlockBuffer::ConstLinearBlockBuffer(
+ const sp<AMessage> &format,
+ C2ReadView&& readView)
+ : MediaCodecBuffer(format, new ABuffer(
+ // NOTE: ABuffer only takes non-const pointer but this data is
+ // supposed to be read-only.
+ const_cast<uint8_t *>(readView.data()), readView.capacity())),
+ mReadView(readView) {
+}
+
} // namespace android
diff --git a/media/libstagefright/CCodec.cpp b/media/libstagefright/CCodec.cpp
index 1e0a53f..84e98f8 100644
--- a/media/libstagefright/CCodec.cpp
+++ b/media/libstagefright/CCodec.cpp
@@ -16,11 +16,13 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "CCodec"
+#include <cutils/properties.h>
#include <utils/Log.h>
#include <thread>
#include <C2PlatformSupport.h>
+#include <C2V4l2Support.h>
#include <gui/Surface.h>
#include <media/stagefright/BufferProducerWrapper.h>
@@ -187,7 +189,14 @@
std::shared_ptr<C2Component> comp;
c2_status_t err = GetCodec2PlatformComponentStore()->createComponent(
componentName.c_str(), &comp);
+ static bool v4l2Enabled =
+ property_get_bool("debug.stagefright.ccodec_v4l2", false);
+ if (err != C2_OK && v4l2Enabled) {
+ err = GetCodec2VDAComponentStore()->createComponent(
+ componentName.c_str(), &comp);
+ }
if (err != C2_OK) {
+ ALOGE("Failed Create component: %s", componentName.c_str());
Mutexed<State>::Locked state(mState);
state->set(RELEASED);
state.unlock();
@@ -195,6 +204,7 @@
state.lock();
return;
}
+ ALOGV("Success Create component: %s", componentName.c_str());
comp->setListener_vb(mListener, C2_MAY_BLOCK);
{
Mutexed<State>::Locked state(mState);
diff --git a/media/libstagefright/CCodecBufferChannel.cpp b/media/libstagefright/CCodecBufferChannel.cpp
index 04f7593..ca4ddc8 100644
--- a/media/libstagefright/CCodecBufferChannel.cpp
+++ b/media/libstagefright/CCodecBufferChannel.cpp
@@ -249,7 +249,7 @@
return std::distance(buffers->begin(), it);
}
-sp<Codec2Buffer> allocateLinearBuffer(
+sp<LinearBlockBuffer> allocateLinearBuffer(
const std::shared_ptr<C2BlockPool> &pool,
const sp<AMessage> &format,
size_t size,
@@ -264,7 +264,7 @@
return nullptr;
}
- return Codec2Buffer::allocate(format, block);
+ return LinearBlockBuffer::allocate(format, block);
}
class Buffer1D : public C2Buffer {
@@ -283,7 +283,7 @@
void add(
size_t index,
- const sp<Codec2Buffer> &clientBuffer,
+ const sp<LinearBlockBuffer> &clientBuffer,
bool available) {
if (mBufferArray.size() <= index) {
// TODO: make this more efficient
@@ -340,7 +340,7 @@
private:
struct Entry {
- sp<Codec2Buffer> clientBuffer;
+ sp<LinearBlockBuffer> clientBuffer;
std::weak_ptr<C2Buffer> compBuffer;
bool available;
};
@@ -354,7 +354,7 @@
bool requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) override {
*buffer = nullptr;
- ssize_t ret = findBufferSlot<wp<Codec2Buffer>>(
+ ssize_t ret = findBufferSlot<wp<LinearBlockBuffer>>(
&mBuffers, kMinBufferArraySize,
[] (const auto &elem) { return elem.promote() == nullptr; });
if (ret < 0) {
@@ -363,7 +363,7 @@
// TODO: proper max input size and usage
// TODO: read usage from intf
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
- sp<Codec2Buffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
+ sp<LinearBlockBuffer> newBuffer = allocateLinearBuffer(mPool, mFormat, kLinearBufferSize, usage);
if (newBuffer == nullptr) {
return false;
}
@@ -378,7 +378,7 @@
if (it == mBuffers.end()) {
return nullptr;
}
- sp<Codec2Buffer> codecBuffer = it->promote();
+ sp<LinearBlockBuffer> codecBuffer = it->promote();
// We got sp<> reference from the caller so this should never happen..
CHECK(codecBuffer != nullptr);
return std::make_shared<Buffer1D>(codecBuffer->share());
@@ -394,7 +394,7 @@
const size_t size = std::max(kMinBufferArraySize, mBuffers.size());
mBuffers.resize(size);
for (size_t i = 0; i < size; ++i) {
- sp<Codec2Buffer> clientBuffer = mBuffers[i].promote();
+ sp<LinearBlockBuffer> clientBuffer = mBuffers[i].promote();
bool available = false;
if (clientBuffer == nullptr) {
// TODO: proper max input size
@@ -414,7 +414,7 @@
private:
// Buffers we passed to the client. The index of a buffer matches what
// was passed in BufferCallback::onInputBufferAvailable().
- std::vector<wp<Codec2Buffer>> mBuffers;
+ std::vector<wp<LinearBlockBuffer>> mBuffers;
};
class GraphicInputBuffers : public CCodecBufferChannel::InputBuffers {
@@ -617,9 +617,7 @@
if (ret < 0) {
return false;
}
- sp<MediaCodecBuffer> newBuffer = new MediaCodecBuffer(
- mFormat,
- convert(buffer));
+ sp<MediaCodecBuffer> newBuffer = convert(buffer);
mBuffers[ret] = { newBuffer, buffer };
*index = ret;
*codecBuffer = newBuffer;
@@ -669,7 +667,7 @@
// track of the flushed work.
}
- virtual sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
+ virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) = 0;
protected:
struct BufferInfo {
@@ -687,9 +685,9 @@
public:
using FlexOutputBuffers::FlexOutputBuffers;
- virtual sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+ virtual sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
if (buffer == nullptr) {
- return new ABuffer(nullptr, 0);
+ return new MediaCodecBuffer(mFormat, new ABuffer(nullptr, 0));
}
if (buffer->data().type() != C2BufferData::LINEAR) {
// We expect linear output buffers from the component.
@@ -699,16 +697,7 @@
// We expect one and only one linear block from the component.
return nullptr;
}
- C2ReadView view = buffer->data().linearBlocks().front().map().get();
- if (view.error() != C2_OK) {
- // Mapping the linear block failed
- return nullptr;
- }
- return new ABuffer(
- // XXX: the data is supposed to be read-only. We don't have
- // const equivalent of ABuffer however...
- const_cast<uint8_t *>(view.data()),
- view.capacity());
+ return ConstLinearBlockBuffer::allocate(mFormat, buffer->data().linearBlocks().front());
}
std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
@@ -737,8 +726,9 @@
public:
using FlexOutputBuffers::FlexOutputBuffers;
- sp<ABuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
- return buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0);
+ sp<MediaCodecBuffer> convert(const std::shared_ptr<C2Buffer> &buffer) override {
+ return new MediaCodecBuffer(
+ mFormat, buffer ? new ABuffer(nullptr, 1) : new ABuffer(nullptr, 0));
}
std::unique_ptr<CCodecBufferChannel::OutputBuffers> toArrayMode() override {
diff --git a/media/libstagefright/codec2/include/C2.h b/media/libstagefright/codec2/include/C2.h
index 442c89e..ab81cdc 100644
--- a/media/libstagefright/codec2/include/C2.h
+++ b/media/libstagefright/codec2/include/C2.h
@@ -189,6 +189,7 @@
#define C2_CONST __attribute__((const))
#define C2_HIDE __attribute__((visibility("hidden")))
#define C2_INTERNAL __attribute__((internal_linkage))
+#define C2_ALLOW_OVERFLOW __attribute__((no_sanitize("integer")))
#define DEFINE_OTHER_COMPARISON_OPERATORS(type) \
inline bool operator!=(const type &other) const { return !(*this == other); } \
@@ -221,13 +222,13 @@
template<typename T>
struct C2_HIDE _c2_cntr_compat_helper {
template<typename U, typename E=typename std::enable_if<std::is_integral<U>::value>::type>
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline static constexpr T get(const U &value) {
return T(value);
}
template<typename U, typename E=typename std::enable_if<(sizeof(U) >= sizeof(T))>::type>
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline static constexpr T get(const c2_cntr_t<U, void> &value) {
return T(value.mValue);
}
@@ -281,7 +282,7 @@
/**
* Peek as underlying signed type.
*/
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline constexpr typename std::make_signed<T>::type peek() const {
return static_cast<typename std::make_signed<T>::type>(mValue);
}
@@ -296,7 +297,7 @@
/**
* Peek as long long - e.g. for printing.
*/
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline constexpr long long peekll() const {
return (long long)mValue;
}
@@ -304,7 +305,7 @@
/**
* Peek as unsigned long long - e.g. for printing.
*/
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline constexpr unsigned long long peekull() const {
return (unsigned long long)mValue;
}
@@ -352,24 +353,24 @@
return c2_cntr_t<T, void>(mValue op); \
}
- DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), +, +=)
- DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), -, -=)
- DEFINE_C2_CNTR_BINARY_OP(__attribute__((no_sanitize("integer"))), *, *=)
+ DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, +, +=)
+ DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, -, -=)
+ DEFINE_C2_CNTR_BINARY_OP(C2_ALLOW_OVERFLOW, *, *=)
- DEFINE_C2_CNTR_UNARY_OP(__attribute__((no_sanitize("integer"))), -)
- DEFINE_C2_CNTR_UNARY_OP(__attribute__((no_sanitize("integer"))), +)
+ DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, -)
+ DEFINE_C2_CNTR_UNARY_OP(C2_ALLOW_OVERFLOW, +)
- DEFINE_C2_CNTR_CREMENT_OP(__attribute__((no_sanitize("integer"))), ++)
- DEFINE_C2_CNTR_CREMENT_OP(__attribute__((no_sanitize("integer"))), --)
+ DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, ++)
+ DEFINE_C2_CNTR_CREMENT_OP(C2_ALLOW_OVERFLOW, --)
template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline constexpr c2_cntr_t<T> operator<<(const U &value) const {
return c2_cntr_t<T>(mValue << value);
}
template<typename U, typename E=typename std::enable_if<std::is_unsigned<U>::value>::type>
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline c2_cntr_t<T> &operator<<=(const U &value) {
mValue <<= value;
return *this;
@@ -378,12 +379,12 @@
/**
* Comparison operators
*/
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline constexpr bool operator<=(const c2_cntr_t<T> &other) const {
return T(other.mValue - mValue) < HALF_RANGE;
}
- __attribute__((no_sanitize("integer")))
+ C2_ALLOW_OVERFLOW
inline constexpr bool operator>=(const c2_cntr_t<T> &other) const {
return T(mValue - other.mValue) < HALF_RANGE;
}
diff --git a/media/libstagefright/codec2/include/C2Buffer.h b/media/libstagefright/codec2/include/C2Buffer.h
index 2ca8222..45ad17f 100644
--- a/media/libstagefright/codec2/include/C2Buffer.h
+++ b/media/libstagefright/codec2/include/C2Buffer.h
@@ -126,9 +126,16 @@
*/
bool isHW() const;
+ /**
+ * Null-fence. A fence that has fired.
+ */
+ constexpr C2Fence() : mImpl(nullptr) { }
+
private:
class Impl;
std::shared_ptr<Impl> mImpl;
+ C2Fence(const std::shared_ptr<Impl> &impl);
+ friend struct _C2FenceFactory;
};
/**
@@ -245,13 +252,101 @@
**************************************************************************************************/
/**
+ * Basic segment math support.
+ */
+struct C2Segment {
+ uint32_t offset;
+ uint32_t size;
+
+ inline constexpr C2Segment(uint32_t offset_, uint32_t size_)
+ : offset(offset_),
+ size(size_) {
+ }
+
+ inline constexpr bool isEmpty() const {
+ return size == 0;
+ }
+
+ inline constexpr bool isValid() const {
+ return offset <= ~size;
+ }
+
+ inline constexpr operator bool() const {
+ return isValid() && !isEmpty();
+ }
+
+ inline constexpr bool operator!() const {
+ return !bool(*this);
+ }
+
+ C2_ALLOW_OVERFLOW
+ inline constexpr bool contains(const C2Segment &other) const {
+ if (!isValid() || !other.isValid()) {
+ return false;
+ } else {
+ return offset <= other.offset
+ && offset + size >= other.offset + other.size;
+ }
+ }
+
+ inline constexpr bool operator==(const C2Segment &other) const {
+ if (!isValid()) {
+ return !other.isValid();
+ } else {
+ return offset == other.offset && size == other.size;
+ }
+ }
+
+ inline constexpr bool operator!=(const C2Segment &other) const {
+ return !operator==(other);
+ }
+
+ inline constexpr bool operator>=(const C2Segment &other) const {
+ return contains(other);
+ }
+
+ inline constexpr bool operator>(const C2Segment &other) const {
+ return contains(other) && !operator==(other);
+ }
+
+ inline constexpr bool operator<=(const C2Segment &other) const {
+ return other.contains(*this);
+ }
+
+ inline constexpr bool operator<(const C2Segment &other) const {
+ return other.contains(*this) && !operator==(other);
+ }
+
+ C2_ALLOW_OVERFLOW
+ inline constexpr uint32_t end() const {
+ return offset + size;
+ }
+
+ C2_ALLOW_OVERFLOW
+ inline constexpr C2Segment intersect(const C2Segment &other) const {
+ if (!isValid()) {
+ return *this;
+ } else if (!other.isValid()) {
+ return other;
+ } else {
+ return C2Segment(c2_max(offset, other.offset),
+ c2_min(end(), other.end()) - c2_max(offset, other.offset));
+ }
+ }
+};
+
+/**
* Common aspect for all objects that have a linear capacity.
*/
class _C2LinearCapacityAspect {
/// \name Linear capacity interface
/// @{
public:
- inline uint32_t capacity() const { return mCapacity; }
+ inline constexpr uint32_t capacity() const { return mCapacity; }
+
+ inline constexpr operator C2Segment() const {
+ return C2Segment(0, mCapacity);
+ }
protected:
@@ -263,10 +358,10 @@
inline explicit _C2LinearCapacityAspect(size_t capacity) = delete;
#endif
- inline explicit _C2LinearCapacityAspect(uint32_t capacity)
+ inline explicit constexpr _C2LinearCapacityAspect(uint32_t capacity)
: mCapacity(capacity) { }
- inline explicit _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
+ inline explicit constexpr _C2LinearCapacityAspect(const _C2LinearCapacityAspect *parent)
: mCapacity(parent == nullptr ? 0 : parent->capacity()) { }
private:
@@ -283,23 +378,35 @@
/// \name Linear range interface
/// @{
public:
- inline uint32_t offset() const { return mOffset; }
- inline uint32_t endOffset() const { return mOffset + mSize; }
- inline uint32_t size() const { return mSize; }
+ inline constexpr uint32_t offset() const { return mOffset; }
+ inline constexpr uint32_t endOffset() const { return mOffset + mSize; }
+ inline constexpr uint32_t size() const { return mSize; }
+
+ inline constexpr operator C2Segment() const {
+ return C2Segment(mOffset, mSize);
+ }
protected:
- inline explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
+ // capacity range [0, capacity]
+ inline constexpr explicit _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent)
: _C2LinearCapacityAspect(parent),
mOffset(0),
mSize(capacity()) { }
- inline _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
+ // copy constructor (no error check)
+ inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect &other)
+ : _C2LinearCapacityAspect(other.capacity()),
+ mOffset(other.offset()),
+ mSize(other.size()) { }
+
+ // subrange of capacity [0, capacity] & [size, size + offset]
+ inline constexpr _C2LinearRangeAspect(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
: _C2LinearCapacityAspect(parent),
mOffset(c2_min(offset, capacity())),
mSize(c2_min(size, capacity() - mOffset)) { }
// subsection of the two [offset, offset + size] ranges
- inline _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
+ inline constexpr _C2LinearRangeAspect(const _C2LinearRangeAspect *parent, size_t offset, size_t size)
: _C2LinearCapacityAspect(parent == nullptr ? 0 : parent->capacity()),
mOffset(c2_min(c2_max(offset, parent == nullptr ? 0 : parent->offset()), capacity())),
mSize(c2_min(c2_min(size, parent == nullptr ? 0 : parent->size()), capacity() - mOffset)) { }
@@ -312,28 +419,31 @@
/// @}
};
-class C2_HIDE _C2LinearCapacityBase : public _C2LinearCapacityAspect {
-public:
- inline explicit _C2LinearCapacityBase(size_t capacity)
- : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) {}
-};
-
/**
* Utility class for safe range calculations.
*/
class C2LinearRange : public _C2LinearRangeAspect {
public:
- inline C2LinearRange(const _C2LinearCapacityBase &parent, size_t offset, size_t size)
- : _C2LinearRangeAspect(&parent, offset, size) {}
+ inline constexpr C2LinearRange(const _C2LinearCapacityAspect &parent, size_t offset, size_t size)
+ : _C2LinearRangeAspect(&parent, offset, size) { }
+
+ inline constexpr C2LinearRange(const _C2LinearRangeAspect &parent, size_t offset, size_t size)
+ : _C2LinearRangeAspect(&parent, offset, size) { }
+
+ inline constexpr C2LinearRange intersect(size_t offset, size_t size) const {
+ return C2LinearRange(*this, offset, size);
+ }
};
/**
* Utility class for simple capacity and range construction.
*/
-class C2LinearCapacity : public _C2LinearCapacityBase {
+class C2LinearCapacity : public _C2LinearCapacityAspect {
public:
- using _C2LinearCapacityBase::_C2LinearCapacityBase;
- inline C2LinearRange range(size_t offset, size_t size) {
+ inline constexpr explicit C2LinearCapacity(size_t capacity)
+ : _C2LinearCapacityAspect(c2_min(capacity, std::numeric_limits<uint32_t>::max())) { }
+
+ inline constexpr C2LinearRange range(size_t offset, size_t size) const {
return C2LinearRange(*this, offset, size);
}
};
@@ -348,6 +458,9 @@
inline explicit _C2EditableLinearRange(const _C2LinearCapacityAspect *parent)
: _C2LinearRangeAspect(parent) { }
+ inline _C2EditableLinearRange(const _C2LinearRangeAspect &other)
+ : _C2LinearRangeAspect(other) { }
+
inline _C2EditableLinearRange(const _C2LinearCapacityAspect *parent, size_t offset, size_t size)
: _C2LinearRangeAspect(parent, offset, size) { }
@@ -379,6 +492,7 @@
mOffset = offset;
return true;
}
+
/**
* Sets the size to |size|. Returns true if successful, which is equivalent to
* if 0 <= |size| <= capacity() - offset().
@@ -394,6 +508,7 @@
return true;
}
}
+
/**
* Sets the offset to |offset| with best effort. Same as setOffset() except that offset will
* be clamped to the buffer capacity.
@@ -402,16 +517,9 @@
* on the order of the operations. Always set offset first to ensure proper size.
*/
inline void setOffset_be(uint32_t offset) {
- if (offset > capacity()) {
- offset = capacity();
- }
- if (offset > mOffset + mSize) {
- mSize = 0;
- } else {
- mSize = mOffset + mSize - offset;
- }
- mOffset = offset;
+ (void)setOffset(c2_min(offset, capacity()));
}
+
/**
* Sets the size to |size| with best effort. Same as setSize() except that the selected region
* will be clamped to the buffer capacity (e.g. size is clamped to [0, capacity() - offset()]).
@@ -420,11 +528,471 @@
* on the order of the operations. Always set offset first to ensure proper size.
*/
inline void setSize_be(uint32_t size) {
- mSize = std::min(size, capacity() - mOffset);
+ mSize = c2_min(size, capacity() - mOffset);
}
/// @}
};
+/**************************************************************************************************
+ ALLOCATIONS
+**************************************************************************************************/
+
+/// \defgroup allocator Allocation and memory placement
+/// @{
+
+/**
+ * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
+ * buffer layout.
+ *
+ * \note This struct has public fields without getters/setters. All methods are inline.
+ */
+struct C2MemoryUsage {
+// public:
+ // TODO: match these to gralloc1.h
+ enum Consumer : uint64_t {
+ // \todo do we need to distinguish often from rarely?
+ CPU_READ = GRALLOC_USAGE_SW_READ_OFTEN,
+ RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
+ HW_TEXTURE_READ = GRALLOC_USAGE_HW_TEXTURE,
+ HW_COMPOSER_READ = GRALLOC_USAGE_HW_COMPOSER,
+ HW_CODEC_READ = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ READ_PROTECTED = GRALLOC_USAGE_PROTECTED,
+ };
+
+ enum Producer : uint64_t {
+ CPU_WRITE = GRALLOC_USAGE_SW_WRITE_OFTEN,
+ RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
+ HW_TEXTURE_WRITE = GRALLOC_USAGE_HW_RENDER,
+ HW_COMPOSER_WRITE = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
+ HW_CODEC_WRITE = GRALLOC_USAGE_HW_VIDEO_ENCODER,
+ WRITE_PROTECTED = GRALLOC_USAGE_PROTECTED,
+ };
+
+ uint64_t consumer; // e.g. input
+ uint64_t producer; // e.g. output
+};
+
+class C2LinearAllocation;
+class C2GraphicAllocation;
+
+/**
+ * Allocators are used by the framework to allocate memory (allocations) for buffers. They can
+ * support either 1D or 2D allocations.
+ *
+ * \note In theory they could support both, but in practice, we will use only one or the other.
+ *
+ * Never constructed on stack.
+ *
+ * Allocators are provided by vendors.
+ */
+class C2Allocator {
+public:
+ /**
+ * Allocator ID type.
+ */
+ typedef uint32_t id_t;
+ enum : id_t {
+ BAD_ID = 0xBADD, // invalid allocator ID
+ };
+
+ /**
+ * Allocation types. This is a bitmask and is used in C2Allocator::Info
+ * to list the supported allocation types of an allocator.
+ */
+ enum type_t : uint32_t {
+ LINEAR = 1 << 0, //
+ GRAPHIC = 1 << 1,
+ };
+
+ /**
+ * Information about an allocator.
+ *
+ * Allocators don't have a query API so all queriable information is stored here.
+ */
+ struct Traits {
+ C2String name; ///< allocator name
+ id_t id; ///< allocator ID
+ type_t supportedTypes; ///< supported allocation types
+ C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
+ C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
+ };
+
+ /**
+ * Returns the unique name of this allocator.
+ *
+ * This method MUST be "non-blocking" and return within 1ms.
+ *
+ * \return the name of this allocator.
+ * \retval an empty string if there was not enough memory to allocate the actual name.
+ */
+ virtual C2String getName() const = 0;
+
+ /**
+ * Returns a unique ID for this allocator. This ID is used to get this allocator from the
+ * allocator store, and to identify this allocator across all processes.
+ *
+ * This method MUST be "non-blocking" and return within 1ms.
+ *
+ * \return a unique ID for this allocator.
+ */
+ virtual id_t getId() const = 0;
+
+ /**
+ * Returns the allocator traits.
+ *
+ * This method MUST be "non-blocking" and return within 1ms.
+ *
+ * Allocators don't have a full-fledged query API, only this method.
+ *
+ * \return allocator information
+ */
+ virtual std::shared_ptr<const Traits> getTraits() const = 0;
+
+ /**
+ * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
+ * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+ *
+ * \param capacity the size of requested allocation (the allocation could be slightly
+ * larger, e.g. to account for any system-required alignment)
+ * \param usage the memory usage info for the requested allocation. \note that the
+ * returned allocation may be later used/mapped with different usage.
+ * The allocator should layout the buffer to be optimized for this usage,
+ * but must support any usage. One exception: protected buffers can
+ * only be used in a protected scenario.
+ * \param allocation pointer to where the allocation shall be stored on success. nullptr
+ * will be stored here on failure
+ *
+ * \retval C2_OK the allocation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete the allocation
+ * \retval C2_TIMED_OUT the allocation timed out
+ * \retval C2_REFUSED no permission to complete the allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_OMITTED this allocator does not support 1D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual c2_status_t newLinearAllocation(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_OMITTED;
+ }
+
+ /**
+ * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
+ * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+ *
+ * \param handle the handle for the existing allocation
+ * \param allocation pointer to where the allocation shall be stored on success. nullptr
+ * will be stored here on failure
+ *
+ * \retval C2_OK the allocation was recreated successfully
+ * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+ * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+ * \retval C2_REFUSED no permission to recreate the allocation
+ * \retval C2_BAD_VALUE invalid handle (caller error)
+ * \retval C2_OMITTED this allocator does not support 1D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual c2_status_t priorLinearAllocation(
+ const C2Handle *handle __unused,
+ std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_OMITTED;
+ }
+
+ /**
+ * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
+ * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+ *
+ * \param width the width of requested allocation (the allocation could be slightly
+ * larger, e.g. to account for any system-required alignment)
+ * \param height the height of requested allocation (the allocation could be slightly
+ * larger, e.g. to account for any system-required alignment)
+ * \param format the pixel format of requested allocation. This could be a vendor
+ * specific format.
+ * \param usage the memory usage info for the requested allocation. \note that the
+ * returned allocation may be later used/mapped with different usage.
+ * The allocator should layout the buffer to be optimized for this usage,
+ * but must support any usage. One exception: protected buffers can
+ * only be used in a protected scenario.
+ * \param allocation pointer to where the allocation shall be stored on success. nullptr
+ * will be stored here on failure
+ *
+ * \retval C2_OK the allocation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete the allocation
+ * \retval C2_TIMED_OUT the allocation timed out
+ * \retval C2_REFUSED no permission to complete the allocation
+ * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
+ * \retval C2_OMITTED this allocator does not support 2D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
+ */
+ virtual c2_status_t newGraphicAllocation(
+ uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+ C2MemoryUsage usage __unused,
+ std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_OMITTED;
+ }
+
+ /**
+ * (Re)creates a 2D allocation from a native handle. If successful, the allocation is stored
+ * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
+ *
+ * \param handle the handle for the existing allocation
+ * \param allocation pointer to where the allocation shall be stored on success. nullptr
+ * will be stored here on failure
+ *
+ * \retval C2_OK the allocation was recreated successfully
+ * \retval C2_NO_MEMORY not enough memory to recreate the allocation
+ * \retval C2_TIMED_OUT the recreation timed out (unexpected)
+ * \retval C2_REFUSED no permission to recreate the allocation
+ * \retval C2_BAD_VALUE invalid handle (caller error)
+ * \retval C2_OMITTED this allocator does not support 2D allocations
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
+ */
+ virtual c2_status_t priorGraphicAllocation(
+ const C2Handle *handle __unused,
+ std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
+ *allocation = nullptr;
+ return C2_OMITTED;
+ }
+
+protected:
+ C2Allocator() = default;
+
+ virtual ~C2Allocator() = default;
+};
+
+/**
+ * \ingroup linear allocator
+ * 1D allocation interface.
+ */
+class C2LinearAllocation : public _C2LinearCapacityAspect {
+public:
+ /**
+ * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
+ * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
+ * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
+ * safe to access the buffer contents, then -1.
+ *
+ * \param offset starting position of the portion to be mapped (this does not have to
+ * be page aligned)
+ * \param size size of the portion to be mapped (this does not have to be page
+ * aligned)
+ * \param usage the desired usage. \todo this must be kSoftwareRead and/or
+ * kSoftwareWrite.
+ * \param fenceFd a pointer to a file descriptor if an async mapping is requested. If
+ * not-null, and acquire fence FD will be stored here on success, or -1
+ * on failure. If null, the mapping will be synchronous.
+ * \param addr a pointer to where the starting address of the mapped portion will be
+ * stored. On failure, nullptr will be stored here.
+ *
+ * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
+ * is no need for this for 1D buffers.
+ * \todo Do we need to support sync operation as we could just wait for the fence?
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_REFUSED no permission to map the portion
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_DUPLICATE if the allocation is already mapped.
+ * \retval C2_NO_MEMORY not enough memory to complete the operation
+ * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
+ * the usage flags are invalid (caller error)
+ * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+ */
+ virtual c2_status_t map(
+ size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
+ void **addr /* nonnull */) = 0;
+
+ /**
+ * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
+ * passed to |map|; otherwise, this operation is a no-op.
+ *
+ * \param addr starting address of the mapped region
+ * \param size size of the mapped region
+ * \param fenceFd a pointer to a file descriptor if an async unmapping is requested. If
+ * not-null, a release fence FD will be stored here on success, or -1
+ * on failure. This fence signals when the original allocation contains
+ * any changes that happened to the mapped region. If null, the unmapping
+ * will be synchronous.
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_NOT_FOUND if the allocation was not mapped previously.
+ * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
+ * regions (caller error)
+ * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+ * \retval C2_REFUSED no permission to unmap the portion (unexpected - system)
+ */
+ virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
+
+ /**
+ * Returns the allocator ID for this allocation. This is useful to put the handle into context.
+ */
+ virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+ /**
+ * Returns a pointer to the allocation handle.
+ */
+ virtual const C2Handle *handle() const = 0;
+
+ /**
+ * Returns true if this is the same allocation as |other|.
+ */
+ virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
+
+protected:
+ // \todo should we limit allocation directly?
+ C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
+ virtual ~C2LinearAllocation() = default;
+};
+
+class C2CircularBlock;
+class C2LinearBlock;
+class C2GraphicBlock;
+
+/**
+ * Block pools are used by components to obtain output buffers in an efficient way. They can
+ * support either linear (1D), circular (1D) or graphic (2D) blocks.
+ *
+ * Block pools decouple the recycling of memory/allocations from the components. They are meant to
+ * be an opaque service (there are no public APIs other than obtaining blocks) provided by the
+ * platform. Block pools are also meant to decouple allocations from memory used by buffers. This
+ * is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
+ * their name suggest, block pools maintain a pool of memory blocks. When a component asks for
+ * a memory block, pools will try to return a free memory block already in the pool. If no such
+ * block exists, they will allocate memory using the backing allocator and allot a block on that
+ * allocation. When blocks are no longer used in the system, they are recycled back to the block
+ * pool and are available as free blocks.
+ *
+ * Never constructed on stack.
+ */
+class C2BlockPool {
+public:
+ /**
+ * Block pool ID type.
+ */
+ typedef uint64_t local_id_t;
+
+ enum : local_id_t {
+ BASIC_LINEAR = 0, ///< ID of basic (unoptimized) block pool for fetching 1D blocks
+ BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
+ PLATFORM_START = 0x10,
+ };
+
+ /**
+ * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
+ * It is only valid in the current process.
+ *
+ * This method MUST be "non-blocking" and return within 1ms.
+ *
+ * \return a local ID for this block pool.
+ */
+ virtual local_id_t getLocalId() const = 0;
+
+ /**
+ * Returns the ID of the backing allocator of this block pool.
+ *
+ * This method MUST be "non-blocking" and return within 1ms.
+ *
+ * \return the ID of the backing allocator of this block pool.
+ */
+ virtual C2Allocator::id_t getAllocatorId() const = 0;
+
+ /**
+ * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
+ * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+ *
+ * \param capacity the size of requested block.
+ * \param usage the memory usage info for the requested block. Returned blocks will be
+ * optimized for this usage, but may be used with any usage. One exception:
+ * protected blocks/buffers can only be used in a protected scenario.
+ * \param block pointer to where the obtained block shall be stored on success. nullptr will
+ * be stored here on failure
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_REFUSED no permission to complete any required allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_OMITTED this pool does not support linear blocks
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+ */
+ virtual c2_status_t fetchLinearBlock(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+ *block = nullptr;
+ return C2_OMITTED;
+ }
+
+ /**
+ * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
+ * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+ *
+ * \param capacity the size of requested circular block. (note: the size of the obtained
+ * block could be slightly larger, e.g. to accommodate any system-required
+ * alignment)
+ * \param usage the memory usage info for the requested block. Returned blocks will be
+ * optimized for this usage, but may be used with any usage. One exception:
+ * protected blocks/buffers can only be used in a protected scenario.
+ * \param block pointer to where the obtained block shall be stored on success. nullptr
+ * will be stored here on failure
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_REFUSED no permission to complete any required allocation
+ * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
+ * \retval C2_OMITTED this pool does not support circular blocks
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+ */
+ virtual c2_status_t fetchCircularBlock(
+ uint32_t capacity __unused, C2MemoryUsage usage __unused,
+ std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
+ *block = nullptr;
+ return C2_OMITTED;
+ }
+
+ /**
+ * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
+ * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
+ *
+ * \param width the width of requested block (the obtained block could be slightly larger, e.g.
+ * to accommodate any system-required alignment)
+ * \param height the height of requested block (the obtained block could be slightly larger,
+ * e.g. to accommodate any system-required alignment)
+ * \param format the pixel format of requested block. This could be a vendor specific format.
+ * \param usage the memory usage info for the requested block. Returned blocks will be
+ * optimized for this usage, but may be used with any usage. One exception:
+ * protected blocks/buffers can only be used in a protected scenario.
+ * \param block pointer to where the obtained block shall be stored on success. nullptr
+ * will be stored here on failure
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_NO_MEMORY not enough memory to complete any required allocation
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_REFUSED no permission to complete any required allocation
+ * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
+ * error)
+ * \retval C2_OMITTED this pool does not support 2D blocks
+ * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
+ */
+ virtual c2_status_t fetchGraphicBlock(
+ uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
+ C2MemoryUsage usage __unused,
+ std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
+ *block = nullptr;
+ return C2_OMITTED;
+ }
+
+protected:
+ C2BlockPool() = default;
+
+ virtual ~C2BlockPool() = default;
+};
+
+/// @}
+
// ================================================================================================
// BLOCKS
// ================================================================================================
@@ -435,16 +1003,36 @@
class C2LinearAllocation;
+/**
+ * A 1D block.
+ *
+ * \note capacity() is not meaningful for users of blocks; instead size() is the capacity of the
+ * usable portion. Use and offset() and size() if accessing the block directly through its handle
+ * to represent the allotted range of the underlying allocation to this block.
+ */
class C2Block1D : public _C2LinearRangeAspect {
public:
+ /**
+ * Returns the underlying handle for this allocation.
+ *
+ * \note that the block and its block pool has shared ownership of the handle
+ * and if all references to the block are released, the underlying block
+ * allocation may get reused even if a client keeps a clone of this handle.
+ */
const C2Handle *handle() const;
-protected:
- C2Block1D(std::shared_ptr<C2LinearAllocation> alloc);
- C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+ /**
+ * Returns the allocator's ID that created the underlying allocation for this block. This
+ * provides the context for understanding the handle.
+ */
+ C2Allocator::id_t getAllocatorId() const;
-private:
+protected:
class Impl;
+ /** construct a block. */
+ C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
+
+ friend struct _C2BlockFactory;
std::shared_ptr<Impl> mImpl;
};
@@ -457,6 +1045,7 @@
public:
/**
* \return pointer to the start of the block or nullptr on error.
+ * This pointer is only valid during the lifetime of this view or until it is released.
*/
const uint8_t *data() const;
@@ -476,13 +1065,20 @@
*/
c2_status_t error() const;
+ /**
+ * Releases this view. This sets error to C2_NO_INIT.
+ */
+ //void release();
+
protected:
- C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data);
+ class Impl;
+ C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size);
explicit C2ReadView(c2_status_t error);
private:
- class Impl;
+ friend struct _C2BlockFactory;
std::shared_ptr<Impl> mImpl;
+ uint32_t mOffset; /**< offset into the linear block backing this read view */
};
/**
@@ -496,11 +1092,13 @@
* Start of the block.
*
* \return pointer to the start of the block or nullptr on error.
+ * This pointer is only valid during the lifetime of this view or until it is released.
*/
uint8_t *base();
/**
* \return pointer to the block at the current offset or nullptr on error.
+ * This pointer is only valid during the lifetime of this view or until it is released.
*/
uint8_t *data();
@@ -509,14 +1107,18 @@
*/
c2_status_t error() const;
+ /**
+ * Releases this view. This sets error to C2_NO_INIT.
+ */
+ //void release();
+
protected:
- C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base);
+ class Impl;
+ C2WriteView(std::shared_ptr<Impl> impl);
explicit C2WriteView(c2_status_t error);
private:
- class Impl;
- /// \todo should this be unique_ptr to make this movable only - to avoid inconsistent regions
- /// between copies.
+ friend struct _C2BlockFactory;
std::shared_ptr<Impl> mImpl;
};
@@ -554,12 +1156,10 @@
C2Fence fence() const { return mFence; }
protected:
- C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
- C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+ C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence mFence);
private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
+ friend struct _C2BlockFactory;
C2Fence mFence;
};
@@ -589,12 +1189,9 @@
C2ConstLinearBlock share(size_t offset, size_t size, C2Fence fence);
protected:
- C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc);
- C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size);
+ C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range);
-private:
- class Impl;
- std::shared_ptr<Impl> mImpl;
+ friend struct _C2BlockFactory;
};
/// @}
@@ -800,27 +1397,26 @@
// utility methods
- inline bool isEmpty() const {
+ inline constexpr bool isEmpty() const {
return width == 0 || height == 0;
}
- inline bool isValid() const {
+ inline constexpr bool isValid() const {
return left <= ~width && top <= ~height;
}
- inline operator bool() const {
+ inline constexpr operator bool() const {
return isValid() && !isEmpty();
}
- inline bool operator!() const {
+ inline constexpr bool operator!() const {
return !bool(*this);
}
- inline bool contains(const C2Rect &other) const {
+ C2_ALLOW_OVERFLOW
+ inline constexpr bool contains(const C2Rect &other) const {
if (!isValid() || !other.isValid()) {
return false;
- } else if (other.isEmpty()) {
- return true;
} else {
return left <= other.left && top <= other.top
&& left + width >= other.left + other.width
@@ -828,36 +1424,58 @@
}
}
- inline bool operator==(const C2Rect &other) const {
+ inline constexpr bool operator==(const C2Rect &other) const {
if (!isValid()) {
return !other.isValid();
- } else if (isEmpty()) {
- return other.isEmpty();
} else {
return left == other.left && top == other.top
&& width == other.width && height == other.height;
}
}
- inline bool operator!=(const C2Rect &other) const {
+ inline constexpr bool operator!=(const C2Rect &other) const {
return !operator==(other);
}
- inline bool operator>=(const C2Rect &other) const {
+ inline constexpr bool operator>=(const C2Rect &other) const {
return contains(other);
}
- inline bool operator>(const C2Rect &other) const {
+ inline constexpr bool operator>(const C2Rect &other) const {
return contains(other) && !operator==(other);
}
- inline bool operator<=(const C2Rect &other) const {
+ inline constexpr bool operator<=(const C2Rect &other) const {
return other.contains(*this);
}
- inline bool operator<(const C2Rect &other) const {
+ inline constexpr bool operator<(const C2Rect &other) const {
return other.contains(*this) && !operator==(other);
}
+
+ C2_ALLOW_OVERFLOW
+ inline constexpr uint32_t right() const {
+ return left + width;
+ }
+
+ C2_ALLOW_OVERFLOW
+ inline constexpr uint32_t bottom() const {
+ return top + height;
+ }
+
+ C2_ALLOW_OVERFLOW
+ inline constexpr C2Rect intersect(const C2Rect &other) const {
+ if (!isValid()) {
+ return *this;
+ } else if (!other.isValid()) {
+ return other;
+ } else {
+ return C2Rect(c2_min(right(), other.right()) - c2_max(left, other.left),
+ c2_min(bottom(), other.bottom()) - c2_max(top, other.top),
+ c2_max(left, other.left),
+ c2_max(top, other.top));
+ }
+ }
};
/**
@@ -1008,6 +1626,88 @@
/// @}
};
+/**
+ * \ingroup graphic allocator
+ * 2D allocation interface.
+ */
+class C2GraphicAllocation : public _C2PlanarCapacityAspect {
+public:
+ /**
+ * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
+ * memory for flexible access. On success, it fills out |layout| with the plane specifications
+ * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
+ * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
+ * descriptor referring to an acquire sync fence object. If it is already safe to access the
+ * buffer contents, then -1.
+ *
+ * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
+ * from gralloc1 limitation.)
+ *
+ * \param rect section to be mapped (this does not have to be aligned)
+ * \param usage the desired usage. \todo this must be kSoftwareRead and/or
+ * kSoftwareWrite.
+ * \param fenceFd a pointer to a file descriptor if an async mapping is requested. If
+ * not-null, and acquire fence FD will be stored here on success, or -1
+ * on failure. If null, the mapping will be synchronous.
+ * \param layout a pointer to where the mapped planes' descriptors will be
+ * stored. On failure, nullptr will be stored here.
+ *
+ * \todo Do we need to support sync operation as we could just wait for the fence?
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_REFUSED no permission to map the section
+ * \retval C2_DUPLICATE there is already a mapped region (caller error)
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_NO_MEMORY not enough memory to complete the operation
+ * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
+ * usage flags are invalid (caller error)
+ * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+
+ */
+ virtual c2_status_t map(
+ C2Rect rect, C2MemoryUsage usage, int *fenceFd,
+ // TODO: return <addr, size> buffers with plane sizes
+ C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
+
+ /**
+ * Unmaps the last mapped rectangular section.
+ *
+ * \param fenceFd a pointer to a file descriptor if an async unmapping is requested. If
+ * not-null, a release fence FD will be stored here on success, or -1
+ * on failure. This fence signals when the original allocation contains
+ * any changes that happened to the mapped section. If null, the unmapping
+ * will be synchronous.
+ *
+ * \retval C2_OK the operation was successful
+ * \retval C2_TIMED_OUT the operation timed out
+ * \retval C2_NOT_FOUND there is no mapped region (caller error)
+ * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
+ * \retval C2_REFUSED no permission to unmap the section (unexpected - system)
+ */
+ virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
+
+ /**
+ * Returns true if this is a valid allocation.
+ *
+ * \todo remove?
+ */
+ virtual bool isValid() const = 0;
+
+ /**
+ * Returns a pointer to the allocation handle.
+ */
+ virtual const C2Handle *handle() const = 0;
+
+ /**
+ * Returns true if this is the same allocation as |other|.
+ */
+ virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
+
+protected:
+ using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
+ virtual ~C2GraphicAllocation() = default;
+};
+
class C2GraphicAllocation;
class C2Block2D : public _C2PlanarSection {
@@ -1323,9 +2023,33 @@
* \return true iff there is a metadata with the parameter type attached to this buffer.
*/
bool hasInfo(C2Param::Type index) const;
+
+ /**
+ * Removes a metadata from the buffer.
+ */
std::shared_ptr<C2Info> removeInfo(C2Param::Type index);
///@}
+ /**
+ * Creates a buffer containing a single linear block.
+ *
+ * \param block the content of the buffer.
+ *
+ * \return shared pointer to the created buffer.
+ */
+ static std::shared_ptr<C2Buffer> CreateLinearBuffer(const C2ConstLinearBlock &block);
+
+ /**
+ * Creates a buffer containing a single graphic block.
+ *
+ * \param block the content of the buffer.
+ *
+ * \return shared pointer to the created buffer.
+ */
+ static std::shared_ptr<C2Buffer> CreateGraphicBuffer(const C2ConstGraphicBlock &block);
+
+
+
protected:
// no public constructor
explicit C2Buffer(const std::vector<C2ConstLinearBlock> &blocks);
@@ -1361,540 +2085,6 @@
/// @}
-/**************************************************************************************************
- ALLOCATIONS
-**************************************************************************************************/
-
-/// \defgroup allocator Allocation and memory placement
-/// @{
-
-/**
- * Buffer/memory usage bits. These are used by the allocators to select optimal memory type/pool and
- * buffer layout.
- *
- * \note This struct has public fields without getters/setters. All methods are inline.
- */
-struct C2MemoryUsage {
-// public:
- // TODO: match these to gralloc1.h
- enum Consumer : uint64_t {
- // \todo do we need to distinguish often from rarely?
- CPU_READ = GRALLOC_USAGE_SW_READ_OFTEN,
- RENDERSCRIPT_READ = GRALLOC_USAGE_RENDERSCRIPT,
- HW_TEXTURE_READ = GRALLOC_USAGE_HW_TEXTURE,
- HW_COMPOSER_READ = GRALLOC_USAGE_HW_COMPOSER,
- HW_CODEC_READ = GRALLOC_USAGE_HW_VIDEO_ENCODER,
- READ_PROTECTED = GRALLOC_USAGE_PROTECTED,
- };
-
- enum Producer : uint64_t {
- CPU_WRITE = GRALLOC_USAGE_SW_WRITE_OFTEN,
- RENDERSCRIPT_WRITE = GRALLOC_USAGE_RENDERSCRIPT,
- HW_TEXTURE_WRITE = GRALLOC_USAGE_HW_RENDER,
- HW_COMPOSER_WRITE = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER,
- HW_CODEC_WRITE = GRALLOC_USAGE_HW_VIDEO_ENCODER,
- WRITE_PROTECTED = GRALLOC_USAGE_PROTECTED,
- };
-
- uint64_t consumer; // e.g. input
- uint64_t producer; // e.g. output
-};
-
-/**
- * \ingroup linear allocator
- * 1D allocation interface.
- */
-class C2LinearAllocation : public _C2LinearCapacityAspect {
-public:
- /**
- * Maps a portion of an allocation starting from |offset| with |size| into local process memory.
- * Stores the starting address into |addr|, or NULL if the operation was unsuccessful.
- * |fenceFd| is a file descriptor referring to an acquire sync fence object. If it is already
- * safe to access the buffer contents, then -1.
- *
- * \param offset starting position of the portion to be mapped (this does not have to
- * be page aligned)
- * \param size size of the portion to be mapped (this does not have to be page
- * aligned)
- * \param usage the desired usage. \todo this must be kSoftwareRead and/or
- * kSoftwareWrite.
- * \param fenceFd a pointer to a file descriptor if an async mapping is requested. If
- * not-null, and acquire fence FD will be stored here on success, or -1
- * on failure. If null, the mapping will be synchronous.
- * \param addr a pointer to where the starting address of the mapped portion will be
- * stored. On failure, nullptr will be stored here.
- *
- * \todo Only one portion can be mapped at the same time - this is true for gralloc, but there
- * is no need for this for 1D buffers.
- * \todo Do we need to support sync operation as we could just wait for the fence?
- *
- * \retval C2_OK the operation was successful
- * \retval C2_REFUSED no permission to map the portion
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_DUPLICATE if the allocation is already mapped.
- * \retval C2_NO_MEMORY not enough memory to complete the operation
- * \retval C2_BAD_VALUE the parameters (offset/size) are invalid or outside the allocation, or
- * the usage flags are invalid (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- */
- virtual c2_status_t map(
- size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd /* nullable */,
- void **addr /* nonnull */) = 0;
-
- /**
- * Unmaps a portion of an allocation at |addr| with |size|. These must be parameters previously
- * passed to |map|; otherwise, this operation is a no-op.
- *
- * \param addr starting address of the mapped region
- * \param size size of the mapped region
- * \param fenceFd a pointer to a file descriptor if an async unmapping is requested. If
- * not-null, a release fence FD will be stored here on success, or -1
- * on failure. This fence signals when the original allocation contains
- * any changes that happened to the mapped region. If null, the unmapping
- * will be synchronous.
- *
- * \retval C2_OK the operation was successful
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_NOT_FOUND if the allocation was not mapped previously.
- * \retval C2_BAD_VALUE the parameters (addr/size) do not correspond to previously mapped
- * regions (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- * \retval C2_REFUSED no permission to unmap the portion (unexpected - system)
- */
- virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd /* nullable */) = 0;
-
- /**
- * Returns true if this is a valid allocation.
- *
- * \todo remove?
- */
- virtual bool isValid() const = 0;
-
- /**
- * Returns a pointer to the allocation handle.
- */
- virtual const C2Handle *handle() const = 0;
-
- /**
- * Returns true if this is the same allocation as |other|.
- */
- virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const = 0;
-
-protected:
- // \todo should we limit allocation directly?
- C2LinearAllocation(size_t capacity) : _C2LinearCapacityAspect(c2_min(capacity, UINT32_MAX)) {}
- virtual ~C2LinearAllocation() = default;
-};
-
-/**
- * \ingroup graphic allocator
- * 2D allocation interface.
- */
-class C2GraphicAllocation : public _C2PlanarCapacityAspect {
-public:
- /**
- * Maps a rectangular section (as defined by |rect|) of a 2D allocation into local process
- * memory for flexible access. On success, it fills out |layout| with the plane specifications
- * and fills the |addr| array with pointers to the first byte of the top-left pixel of each
- * plane used. Otherwise, it leaves |layout| and |addr| untouched. |fenceFd| is a file
- * descriptor referring to an acquire sync fence object. If it is already safe to access the
- * buffer contents, then -1.
- *
- * \note Only one portion of the graphic allocation can be mapped at the same time. (This is
- * from gralloc1 limitation.)
- *
- * \param rect section to be mapped (this does not have to be aligned)
- * \param usage the desired usage. \todo this must be kSoftwareRead and/or
- * kSoftwareWrite.
- * \param fenceFd a pointer to a file descriptor if an async mapping is requested. If
- * not-null, and acquire fence FD will be stored here on success, or -1
- * on failure. If null, the mapping will be synchronous.
- * \param layout a pointer to where the mapped planes' descriptors will be
- * stored. On failure, nullptr will be stored here.
- *
- * \todo Do we need to support sync operation as we could just wait for the fence?
- *
- * \retval C2_OK the operation was successful
- * \retval C2_REFUSED no permission to map the section
- * \retval C2_DUPLICATE there is already a mapped region (caller error)
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_NO_MEMORY not enough memory to complete the operation
- * \retval C2_BAD_VALUE the parameters (rect) are invalid or outside the allocation, or the
- * usage flags are invalid (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
-
- */
- virtual c2_status_t map(
- C2Rect rect, C2MemoryUsage usage, int *fenceFd,
- // TODO: return <addr, size> buffers with plane sizes
- C2PlanarLayout *layout /* nonnull */, uint8_t **addr /* nonnull */) = 0;
-
- /**
- * Unmaps the last mapped rectangular section.
- *
- * \param fenceFd a pointer to a file descriptor if an async unmapping is requested. If
- * not-null, a release fence FD will be stored here on success, or -1
- * on failure. This fence signals when the original allocation contains
- * any changes that happened to the mapped section. If null, the unmapping
- * will be synchronous.
- *
- * \retval C2_OK the operation was successful
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_NOT_FOUND there is no mapped region (caller error)
- * \retval C2_CORRUPTED some unknown error prevented the operation from completing (unexpected)
- * \retval C2_REFUSED no permission to unmap the section (unexpected - system)
- */
- virtual c2_status_t unmap(C2Fence *fenceFd /* nullable */) = 0;
-
- /**
- * Returns true if this is a valid allocation.
- *
- * \todo remove?
- */
- virtual bool isValid() const = 0;
-
- /**
- * Returns a pointer to the allocation handle.
- */
- virtual const C2Handle *handle() const = 0;
-
- /**
- * Returns true if this is the same allocation as |other|.
- */
- virtual bool equals(const std::shared_ptr<const C2GraphicAllocation> &other) const = 0;
-
-protected:
- using _C2PlanarCapacityAspect::_C2PlanarCapacityAspect;
- virtual ~C2GraphicAllocation() = default;
-};
-
-/**
- * Allocators are used by the framework to allocate memory (allocations) for buffers. They can
- * support either 1D or 2D allocations.
- *
- * \note In theory they could support both, but in practice, we will use only one or the other.
- *
- * Never constructed on stack.
- *
- * Allocators are provided by vendors.
- */
-class C2Allocator {
-public:
- /**
- * Allocator ID type.
- */
- typedef uint32_t id_t;
-
- /**
- * Allocation types. This is a bitmask and is used in C2Allocator::Info
- * to list the supported allocation types of an allocator.
- */
- enum type_t : uint32_t {
- LINEAR = 1 << 0, //
- GRAPHIC = 1 << 1,
- };
-
- /**
- * Information about an allocator.
- *
- * Allocators don't have a query API so all queriable information is stored here.
- */
- struct Traits {
- C2String name; ///< allocator name
- id_t id; ///< allocator ID
- type_t supportedTypes; ///< supported allocation types
- C2MemoryUsage minimumUsage; ///< usage that is minimally required for allocations
- C2MemoryUsage maximumUsage; ///< usage that is maximally allowed for allocations
- };
-
- /**
- * Returns the unique name of this allocator.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the name of this allocator.
- * \retval an empty string if there was not enough memory to allocate the actual name.
- */
- virtual C2String getName() const = 0;
-
- /**
- * Returns a unique ID for this allocator. This ID is used to get this allocator from the
- * allocator store, and to identify this allocator across all processes.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return a unique ID for this allocator.
- */
- virtual id_t getId() const = 0;
-
- /**
- * Returns the allocator traits.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * Allocators don't have a full-fledged query API, only this method.
- *
- * \return allocator information
- */
- virtual std::shared_ptr<const Traits> getTraits() const = 0;
-
- /**
- * Allocates a 1D allocation of given |capacity| and |usage|. If successful, the allocation is
- * stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param capacity the size of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param usage the memory usage info for the requested allocation. \note that the
- * returned allocation may be later used/mapped with different usage.
- * The allocator should layout the buffer to be optimized for this usage,
- * but must support any usage. One exception: protected buffers can
- * only be used in a protected scenario.
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_REFUSED no permission to complete the allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
- virtual c2_status_t newLinearAllocation(
- uint32_t capacity __unused, C2MemoryUsage usage __unused,
- std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * (Re)creates a 1D allocation from a native |handle|. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle the handle for the existing allocation
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_REFUSED no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_OMITTED this allocator does not support 1D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
- virtual c2_status_t priorLinearAllocation(
- const C2Handle *handle __unused,
- std::shared_ptr<C2LinearAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * Allocates a 2D allocation of given |width|, |height|, |format| and |usage|. If successful,
- * the allocation is stored in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param width the width of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param height the height of requested allocation (the allocation could be slightly
- * larger, e.g. to account for any system-required alignment)
- * \param format the pixel format of requested allocation. This could be a vendor
- * specific format.
- * \param usage the memory usage info for the requested allocation. \note that the
- * returned allocation may be later used/mapped with different usage.
- * The allocator should layout the buffer to be optimized for this usage,
- * but must support any usage. One exception: protected buffers can
- * only be used in a protected scenario.
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was successful
- * \retval C2_NO_MEMORY not enough memory to complete the allocation
- * \retval C2_TIMED_OUT the allocation timed out
- * \retval C2_REFUSED no permission to complete the allocation
- * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this allocator does not support 2D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during allocation (unexpected)
- */
- virtual c2_status_t newGraphicAllocation(
- uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
- C2MemoryUsage usage __unused,
- std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * (Re)creates a 2D allocation from a native handle. If successful, the allocation is stored
- * in |allocation|. Otherwise, |allocation| is set to 'nullptr'.
- *
- * \param handle the handle for the existing allocation
- * \param allocation pointer to where the allocation shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the allocation was recreated successfully
- * \retval C2_NO_MEMORY not enough memory to recreate the allocation
- * \retval C2_TIMED_OUT the recreation timed out (unexpected)
- * \retval C2_REFUSED no permission to recreate the allocation
- * \retval C2_BAD_VALUE invalid handle (caller error)
- * \retval C2_OMITTED this allocator does not support 2D allocations
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during recreation (unexpected)
- */
- virtual c2_status_t priorGraphicAllocation(
- const C2Handle *handle __unused,
- std::shared_ptr<C2GraphicAllocation> *allocation /* nonnull */) {
- *allocation = nullptr;
- return C2_OMITTED;
- }
-
-protected:
- C2Allocator() = default;
-
- virtual ~C2Allocator() = default;
-};
-
-/**
- * Block pools are used by components to obtain output buffers in an efficient way. They can
- * support either linear (1D), circular (1D) or graphic (2D) blocks.
- *
- * Block pools decouple the recycling of memory/allocations from the components. They are meant to
- * be an opaque service (there are no public APIs other than obtaining blocks) provided by the
- * platform. Block pools are also meant to decouple allocations from memory used by buffers. This
- * is accomplished by allowing pools to allot multiple memory 'blocks' on a single allocation. As
- * their name suggest, block pools maintain a pool of memory blocks. When a component asks for
- * a memory block, pools will try to return a free memory block already in the pool. If no such
- * block exists, they will allocate memory using the backing allocator and allot a block on that
- * allocation. When blocks are no longer used in the system, they are recycled back to the block
- * pool and are available as free blocks.
- *
- * Never constructed on stack.
- */
-class C2BlockPool {
-public:
- /**
- * Block pool ID type.
- */
- typedef uint64_t local_id_t;
-
- enum : local_id_t {
- BASIC_LINEAR = 0, ///< ID of basic (unoptimized) block pool for fetching 1D blocks
- BASIC_GRAPHIC = 1, ///< ID of basic (unoptimized) block pool for fetching 2D blocks
- PLATFORM_START = 0x10,
- };
-
- /**
- * Returns the ID for this block pool. This ID is used to get this block pool from the platform.
- * It is only valid in the current process.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return a local ID for this block pool.
- */
- virtual local_id_t getLocalId() const = 0;
-
- /**
- * Returns the ID of the backing allocator of this block pool.
- *
- * This method MUST be "non-blocking" and return within 1ms.
- *
- * \return the ID of the backing allocator of this block pool.
- */
- virtual C2Allocator::id_t getAllocatorId() const = 0;
-
- /**
- * Obtains a linear writeable block of given |capacity| and |usage|. If successful, the
- * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
- *
- * \param capacity the size of requested block.
- * \param usage the memory usage info for the requested block. Returned blocks will be
- * optimized for this usage, but may be used with any usage. One exception:
- * protected blocks/buffers can only be used in a protected scenario.
- * \param block pointer to where the obtained block shall be stored on success. nullptr will
- * be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_NO_MEMORY not enough memory to complete any required allocation
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_REFUSED no permission to complete any required allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this pool does not support linear blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
- */
- virtual c2_status_t fetchLinearBlock(
- uint32_t capacity __unused, C2MemoryUsage usage __unused,
- std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
- *block = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * Obtains a circular writeable block of given |capacity| and |usage|. If successful, the
- * block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
- *
- * \param capacity the size of requested circular block. (note: the size of the obtained
- * block could be slightly larger, e.g. to accommodate any system-required
- * alignment)
- * \param usage the memory usage info for the requested block. Returned blocks will be
- * optimized for this usage, but may be used with any usage. One exception:
- * protected blocks/buffers can only be used in a protected scenario.
- * \param block pointer to where the obtained block shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_NO_MEMORY not enough memory to complete any required allocation
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_REFUSED no permission to complete any required allocation
- * \retval C2_BAD_VALUE capacity or usage are not supported (invalid) (caller error)
- * \retval C2_OMITTED this pool does not support circular blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
- */
- virtual c2_status_t fetchCircularBlock(
- uint32_t capacity __unused, C2MemoryUsage usage __unused,
- std::shared_ptr<C2CircularBlock> *block /* nonnull */) {
- *block = nullptr;
- return C2_OMITTED;
- }
-
- /**
- * Obtains a 2D graphic block of given |width|, |height|, |format| and |usage|. If successful,
- * the block is stored in |block|. Otherwise, |block| is set to 'nullptr'.
- *
- * \param width the width of requested block (the obtained block could be slightly larger, e.g.
- * to accommodate any system-required alignment)
- * \param height the height of requested block (the obtained block could be slightly larger,
- * e.g. to accommodate any system-required alignment)
- * \param format the pixel format of requested block. This could be a vendor specific format.
- * \param usage the memory usage info for the requested block. Returned blocks will be
- * optimized for this usage, but may be used with any usage. One exception:
- * protected blocks/buffers can only be used in a protected scenario.
- * \param block pointer to where the obtained block shall be stored on success. nullptr
- * will be stored here on failure
- *
- * \retval C2_OK the operation was successful
- * \retval C2_NO_MEMORY not enough memory to complete any required allocation
- * \retval C2_TIMED_OUT the operation timed out
- * \retval C2_REFUSED no permission to complete any required allocation
- * \retval C2_BAD_VALUE width, height, format or usage are not supported (invalid) (caller
- * error)
- * \retval C2_OMITTED this pool does not support 2D blocks
- * \retval C2_CORRUPTED some unknown, unrecoverable error occured during operation (unexpected)
- */
- virtual c2_status_t fetchGraphicBlock(
- uint32_t width __unused, uint32_t height __unused, uint32_t format __unused,
- C2MemoryUsage usage __unused,
- std::shared_ptr<C2GraphicBlock> *block /* nonnull */) {
- *block = nullptr;
- return C2_OMITTED;
- }
-
-protected:
- C2BlockPool() = default;
-
- virtual ~C2BlockPool() = default;
-};
-
-/// @}
-
/// \cond INTERNAL
/// \todo These are no longer used
diff --git a/media/libstagefright/codec2/include/C2Component.h b/media/libstagefright/codec2/include/C2Component.h
index aa0974a..721966b 100644
--- a/media/libstagefright/codec2/include/C2Component.h
+++ b/media/libstagefright/codec2/include/C2Component.h
@@ -696,6 +696,7 @@
DEFAULT_GRAPHIC, ///< basic graphic allocator type
PLATFORM_START = 0x10,
VENDOR_START = 0x100,
+ BAD_ID = C2Allocator::BAD_ID, ///< DO NOT USE
};
/**
diff --git a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
index a310717..2de43c8 100644
--- a/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
+++ b/media/libstagefright/codec2/tests/vndk/C2BufferTest.cpp
@@ -29,10 +29,10 @@
class C2BufferTest : public ::testing::Test {
public:
C2BufferTest()
- : mLinearAllocator(std::make_shared<C2AllocatorIon>()),
+ : mLinearAllocator(std::make_shared<C2AllocatorIon>('i')),
mSize(0u),
mAddr(nullptr),
- mGraphicAllocator(std::make_shared<C2AllocatorGralloc>()) {
+ mGraphicAllocator(std::make_shared<C2AllocatorGralloc>('g')) {
}
~C2BufferTest() = default;
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
index a5ea511..155583d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorGralloc.cpp
@@ -540,7 +540,7 @@
return C2_OK;
}
-C2AllocatorGralloc::C2AllocatorGralloc() : mImpl(new Impl) {}
+C2AllocatorGralloc::C2AllocatorGralloc(id_t) : mImpl(new Impl) {}
C2AllocatorGralloc::~C2AllocatorGralloc() { delete mImpl; }
diff --git a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
index 34c68bb..4328a8d 100644
--- a/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
+++ b/media/libstagefright/codec2/vndk/C2AllocatorIon.cpp
@@ -119,14 +119,14 @@
size_t offset, size_t size, C2MemoryUsage usage, int *fence,
void **addr /* nonnull */) override;
virtual c2_status_t unmap(void *addr, size_t size, int *fenceFd) override;
- virtual bool isValid() const override;
virtual ~C2AllocationIon() override;
virtual const C2Handle *handle() const override;
+ virtual id_t getAllocatorId() const override;
virtual bool equals(const std::shared_ptr<C2LinearAllocation> &other) const override;
// internal methods
- C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags);
- C2AllocationIon(int ionFd, size_t size, int shareFd);
+ C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id);
+ C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id);
c2_status_t status() const;
@@ -154,10 +154,11 @@
* invalid if err is not 0.
* \param err errno during buffer allocation or import
*/
- Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, int err)
+ Impl(int ionFd, size_t capacity, int bufferFd, ion_user_handle_t buffer, C2Allocator::id_t id, int err)
: mIonFd(ionFd),
mHandle(bufferFd, capacity),
mBuffer(buffer),
+ mId(id),
mInit(c2_map_errno<ENOMEM, EACCES, EINVAL>(err)),
mMapFd(-1),
mMapSize(0) {
@@ -183,10 +184,10 @@
* \return created ion allocation (implementation) which may be invalid if the
* import failed.
*/
- static Impl *Import(int ionFd, size_t capacity, int bufferFd) {
+ static Impl *Import(int ionFd, size_t capacity, int bufferFd, C2Allocator::id_t id) {
ion_user_handle_t buffer = -1;
int ret = ion_import(ionFd, bufferFd, &buffer);
- return new Impl(ionFd, capacity, bufferFd, buffer, ret);
+ return new Impl(ionFd, capacity, bufferFd, buffer, id, ret);
}
/**
@@ -201,7 +202,7 @@
* \return created ion allocation (implementation) which may be invalid if the
* allocation failed.
*/
- static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags) {
+ static Impl *Alloc(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags, C2Allocator::id_t id) {
int bufferFd = -1;
ion_user_handle_t buffer = -1;
int ret = ion_alloc(ionFd, size, align, heapMask, flags, &buffer);
@@ -213,7 +214,7 @@
buffer = -1;
}
}
- return new Impl(ionFd, size, bufferFd, buffer, ret);
+ return new Impl(ionFd, size, bufferFd, buffer, id, ret);
}
c2_status_t map(size_t offset, size_t size, C2MemoryUsage usage, int *fenceFd, void **addr) {
@@ -311,10 +312,19 @@
return &mHandle;
}
+ C2Allocator::id_t getAllocatorId() const {
+ return mId;
+ }
+
+ ion_user_handle_t ionHandle() const {
+ return mBuffer;
+ }
+
private:
int mIonFd;
C2HandleIon mHandle;
ion_user_handle_t mBuffer;
+ C2Allocator::id_t mId;
c2_status_t mInit;
int mMapFd; // only one for now
void *mMapAddr;
@@ -331,17 +341,21 @@
return mImpl->unmap(addr, size, fenceFd);
}
-bool C2AllocationIon::isValid() const {
- return mImpl->status() == C2_OK;
-}
-
c2_status_t C2AllocationIon::status() const {
return mImpl->status();
}
+C2Allocator::id_t C2AllocationIon::getAllocatorId() const {
+ return mImpl->getAllocatorId();
+}
+
bool C2AllocationIon::equals(const std::shared_ptr<C2LinearAllocation> &other) const {
- return other != nullptr &&
- other->handle(); // TODO
+ if (!other || other->getAllocatorId() != getAllocatorId()) {
+ return false;
+ }
+ // get user handle to compare objects
+ std::shared_ptr<C2AllocationIon> otherAsIon = std::static_pointer_cast<C2AllocationIon>(other);
+ return mImpl->ionHandle() == otherAsIon->mImpl->ionHandle();
}
const C2Handle *C2AllocationIon::handle() const {
@@ -352,21 +366,28 @@
delete mImpl;
}
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align, unsigned heapMask, unsigned flags)
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, size_t align,
+ unsigned heapMask, unsigned flags, C2Allocator::id_t id)
: C2LinearAllocation(size),
- mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags)) { }
+ mImpl(Impl::Alloc(ionFd, size, align, heapMask, flags, id)) { }
-C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd)
+C2AllocationIon::C2AllocationIon(int ionFd, size_t size, int shareFd, C2Allocator::id_t id)
: C2LinearAllocation(size),
- mImpl(Impl::Import(ionFd, size, shareFd)) { }
+ mImpl(Impl::Import(ionFd, size, shareFd, id)) { }
/* ======================================= ION ALLOCATOR ====================================== */
-C2AllocatorIon::C2AllocatorIon() : mInit(C2_OK), mIonFd(ion_open()) {
+C2AllocatorIon::C2AllocatorIon(id_t id)
+ : mInit(C2_OK),
+ mIonFd(ion_open()) {
if (mIonFd < 0) {
switch (errno) {
case ENOENT: mInit = C2_OMITTED; break;
default: mInit = c2_map_errno<EACCES>(errno); break;
}
+ } else {
+ C2MemoryUsage minUsage = { 0, 0 }, maxUsage = { ~(uint64_t)0, ~(uint64_t)0 };
+ Traits traits = { "android.allocator.ion", id, LINEAR, minUsage, maxUsage };
+ mTraits = std::make_shared<Traits>(traits);
}
}
@@ -377,11 +398,15 @@
}
C2Allocator::id_t C2AllocatorIon::getId() const {
- return 0; /// \todo implement ID
+ return mTraits->id;
}
C2String C2AllocatorIon::getName() const {
- return "android.allocator.ion";
+ return mTraits->name;
+}
+
+std::shared_ptr<const C2Allocator::Traits> C2AllocatorIon::getTraits() const {
+ return mTraits;
}
c2_status_t C2AllocatorIon::newLinearAllocation(
@@ -410,7 +435,7 @@
#endif
std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags);
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), capacity, align, heapMask, flags, mTraits->id);
c2_status_t ret = alloc->status();
if (ret == C2_OK) {
*allocation = alloc;
@@ -432,7 +457,7 @@
// TODO: get capacity and validate it
const C2HandleIon *h = static_cast<const C2HandleIon*>(handle);
std::shared_ptr<C2AllocationIon> alloc
- = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd());
+ = std::make_shared<C2AllocationIon>(dup(mIonFd), h->size(), h->bufferFd(), mTraits->id);
c2_status_t ret = alloc->status();
if (ret == C2_OK) {
*allocation = alloc;
diff --git a/media/libstagefright/codec2/vndk/C2Buffer.cpp b/media/libstagefright/codec2/vndk/C2Buffer.cpp
index 4ab3e05..ff92679 100644
--- a/media/libstagefright/codec2/vndk/C2Buffer.cpp
+++ b/media/libstagefright/codec2/vndk/C2Buffer.cpp
@@ -21,49 +21,46 @@
#include <map>
#include <C2BufferPriv.h>
+#include <C2BlockInternal.h>
namespace android {
namespace {
+// This anonymous namespace contains the helper classes that allow our implementation to create
+// block/buffer objects.
+//
// Inherit from the parent, share with the friend.
-
-class DummyCapacityAspect : public _C2LinearCapacityAspect {
- using _C2LinearCapacityAspect::_C2LinearCapacityAspect;
- friend class ::android::C2ReadView;
- friend class ::android::C2ConstLinearBlock;
-};
-
-class C2DefaultReadView : public C2ReadView {
+class ReadViewBuddy : public C2ReadView {
using C2ReadView::C2ReadView;
friend class ::android::C2ConstLinearBlock;
};
-class C2DefaultWriteView : public C2WriteView {
+class WriteViewBuddy : public C2WriteView {
using C2WriteView::C2WriteView;
friend class ::android::C2LinearBlock;
};
-class C2AcquirableReadView : public C2Acquirable<C2ReadView> {
- using C2Acquirable::C2Acquirable;
- friend class ::android::C2ConstLinearBlock;
-};
-
-class C2AcquirableWriteView : public C2Acquirable<C2WriteView> {
- using C2Acquirable::C2Acquirable;
- friend class ::android::C2LinearBlock;
-};
-
-class C2DefaultConstLinearBlock : public C2ConstLinearBlock {
+class ConstLinearBlockBuddy : public C2ConstLinearBlock {
using C2ConstLinearBlock::C2ConstLinearBlock;
friend class ::android::C2LinearBlock;
};
-class C2DefaultLinearBlock : public C2LinearBlock {
+class LinearBlockBuddy : public C2LinearBlock {
using C2LinearBlock::C2LinearBlock;
friend class ::android::C2BasicLinearBlockPool;
};
+class AcquirableReadViewBuddy : public C2Acquirable<C2ReadView> {
+ using C2Acquirable::C2Acquirable;
+ friend class ::android::C2ConstLinearBlock;
+};
+
+class AcquirableWriteViewBuddy : public C2Acquirable<C2WriteView> {
+ using C2Acquirable::C2Acquirable;
+ friend class ::android::C2LinearBlock;
+};
+
class C2DefaultGraphicView : public C2GraphicView {
using C2GraphicView::C2GraphicView;
friend class ::android::C2ConstGraphicBlock;
@@ -99,255 +96,230 @@
/* ========================================== 1D BLOCK ========================================= */
-class C2Block1D::Impl {
+struct C2_HIDE _C2BlockPoolData;
+
+/**
+ * This class is the base class for all 1D block and view implementations.
+ *
+ * This is basically just a placeholder for the underlying 1D allocation and the range of the
+ * alloted portion to this block. There is also a placeholder for a blockpool data.
+ */
+class C2_HIDE _C2Block1DImpl : public _C2LinearRangeAspect {
public:
- const C2Handle *handle() const {
- return mAllocation->handle();
+ _C2Block1DImpl(const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &poolData = nullptr,
+ size_t offset = 0, size_t size = ~(size_t)0)
+ : _C2LinearRangeAspect(alloc.get(), offset, size),
+ mAllocation(alloc),
+ mPoolData(poolData) { }
+
+ _C2Block1DImpl(const _C2Block1DImpl &other, size_t offset = 0, size_t size = ~(size_t)0)
+ : _C2LinearRangeAspect(&other, offset, size),
+ mAllocation(other.mAllocation),
+ mPoolData(other.mPoolData) { }
+
+ /** returns const pool data */
+ std::shared_ptr<const _C2BlockPoolData> poolData() const {
+ return mPoolData;
}
- Impl(std::shared_ptr<C2LinearAllocation> alloc)
- : mAllocation(alloc) {}
+ /** returns native handle */
+ const C2Handle *handle() const {
+ return mAllocation ? mAllocation->handle() : nullptr;
+ }
+
+ /** returns the allocator's ID */
+ C2Allocator::id_t getAllocatorId() const {
+ // BAD_ID can only happen if this Impl class is initialized for a view - never for a block.
+ return mAllocation ? mAllocation->getAllocatorId() : C2Allocator::BAD_ID;
+ }
+
+ std::shared_ptr<C2LinearAllocation> getAllocation() const {
+ return mAllocation;
+ }
private:
std::shared_ptr<C2LinearAllocation> mAllocation;
+ std::shared_ptr<_C2BlockPoolData> mPoolData;
};
-const C2Handle *C2Block1D::handle() const {
- return mImpl->handle();
-};
-
-C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc)
- : _C2LinearRangeAspect(alloc.get()), mImpl(new Impl(alloc)) {
-}
-
-C2Block1D::C2Block1D(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
- : _C2LinearRangeAspect(alloc.get(), offset, size), mImpl(new Impl(alloc)) {
-}
-
-class C2ReadView::Impl {
+/**
+ * This class contains the mapped data pointer, and the potential error.
+ *
+ * range is the mapped range of the underlying allocation (which is part of the allotted
+ * range).
+ */
+class C2_HIDE _C2MappedBlock1DImpl : public _C2Block1DImpl {
public:
- explicit Impl(const uint8_t *data)
- : mData(data), mError(C2_OK) {}
+ _C2MappedBlock1DImpl(const _C2Block1DImpl &block, uint8_t *data,
+ size_t offset = 0, size_t size = ~(size_t)0)
+ : _C2Block1DImpl(block, offset, size), mData(data), mError(C2_OK) { }
- explicit Impl(c2_status_t error)
- : mData(nullptr), mError(error) {}
+ _C2MappedBlock1DImpl(c2_status_t error)
+ : _C2Block1DImpl(nullptr), mData(nullptr), mError(error) {
+ // CHECK(error != C2_OK);
+ }
const uint8_t *data() const {
return mData;
}
+ uint8_t *data() {
+ return mData;
+ }
+
c2_status_t error() const {
return mError;
}
private:
- const uint8_t *mData;
+ uint8_t *mData;
c2_status_t mError;
};
-C2ReadView::C2ReadView(const _C2LinearCapacityAspect *parent, const uint8_t *data)
- : _C2LinearCapacityAspect(parent), mImpl(std::make_shared<Impl>(data)) {}
+/**
+ * Block implementation.
+ */
+class C2Block1D::Impl : public _C2Block1DImpl {
+ using _C2Block1DImpl::_C2Block1DImpl;
+};
-C2ReadView::C2ReadView(c2_status_t error)
- : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)) {}
+const C2Handle *C2Block1D::handle() const {
+ return mImpl->handle();
+};
-const uint8_t *C2ReadView::data() const {
- return mImpl->data();
+C2Allocator::id_t C2Block1D::getAllocatorId() const {
+ return mImpl->getAllocatorId();
+};
+
+C2Block1D::C2Block1D(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+ // always clamp subrange to parent (impl) range for safety
+ : _C2LinearRangeAspect(impl.get(), range.offset(), range.size()), mImpl(impl) {
}
-C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
- if (offset > capacity()) {
- offset = capacity();
- }
- if (size > capacity() - offset) {
- size = capacity() - offset;
- }
- // TRICKY: newCapacity will just be used to grab the size.
- DummyCapacityAspect newCapacity((uint32_t)size);
- return C2ReadView(&newCapacity, data() + offset);
+/**
+ * Read view implementation.
+ *
+ * range of Impl is the mapped range of the underlying allocation (which is part of the allotted
+ * range). range of View is 0 to capacity() (not represented as an actual range). This maps to a
+ * subrange of Impl range starting at mImpl->offset() + _mOffset.
+ */
+class C2ReadView::Impl : public _C2MappedBlock1DImpl {
+ using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
+};
+
+C2ReadView::C2ReadView(std::shared_ptr<Impl> impl, uint32_t offset, uint32_t size)
+ : _C2LinearCapacityAspect(C2LinearCapacity(impl->size()).range(offset, size).size()),
+ mImpl(impl),
+ mOffset(C2LinearCapacity(impl->size()).range(offset, size).offset()) { }
+
+C2ReadView::C2ReadView(c2_status_t error)
+ : _C2LinearCapacityAspect(0u), mImpl(std::make_shared<Impl>(error)), mOffset(0u) {
+ // CHECK(error != C2_OK);
+}
+
+const uint8_t *C2ReadView::data() const {
+ return mImpl->error() ? nullptr : mImpl->data() + mOffset;
}
c2_status_t C2ReadView::error() const {
return mImpl->error();
}
-class C2WriteView::Impl {
-public:
- explicit Impl(uint8_t *base)
- : mBase(base), mError(C2_OK) {}
+C2ReadView C2ReadView::subView(size_t offset, size_t size) const {
+ C2LinearRange subRange(*this, offset, size);
+ return C2ReadView(mImpl, mOffset + subRange.offset(), subRange.size());
+}
- explicit Impl(c2_status_t error)
- : mBase(nullptr), mError(error) {}
-
- uint8_t *base() const {
- return mBase;
- }
-
- c2_status_t error() const {
- return mError;
- }
-
-private:
- uint8_t *mBase;
- c2_status_t mError;
+/**
+ * Write view implementation.
+ */
+class C2WriteView::Impl : public _C2MappedBlock1DImpl {
+ using _C2MappedBlock1DImpl::_C2MappedBlock1DImpl;
};
-C2WriteView::C2WriteView(const _C2LinearRangeAspect *parent, uint8_t *base)
- : _C2EditableLinearRange(parent), mImpl(std::make_shared<Impl>(base)) {}
+C2WriteView::C2WriteView(std::shared_ptr<Impl> impl)
+// UGLY: _C2LinearRangeAspect requires a bona-fide object for capacity to prevent spoofing, so
+// this is what we have to do.
+ : _C2EditableLinearRange(std::make_unique<C2LinearCapacity>(impl->size()).get()), mImpl(impl) { }
C2WriteView::C2WriteView(c2_status_t error)
: _C2EditableLinearRange(nullptr), mImpl(std::make_shared<Impl>(error)) {}
-uint8_t *C2WriteView::base() { return mImpl->base(); }
+uint8_t *C2WriteView::base() { return mImpl->data(); }
-uint8_t *C2WriteView::data() { return mImpl->base() + offset(); }
+uint8_t *C2WriteView::data() { return mImpl->data() + offset(); }
c2_status_t C2WriteView::error() const { return mImpl->error(); }
-class C2ConstLinearBlock::Impl {
-public:
- explicit Impl(std::shared_ptr<C2LinearAllocation> alloc)
- : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
-
- ~Impl() {
- if (mBase != nullptr) {
- // TODO: fence
- c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
- if (err != C2_OK) {
- // TODO: Log?
- }
- }
- }
-
- C2ConstLinearBlock subBlock(size_t offset, size_t size) const {
- return C2ConstLinearBlock(mAllocation, offset, size);
- }
-
- void map(size_t offset, size_t size) {
- if (mBase == nullptr) {
- void *base = nullptr;
- mError = mAllocation->map(
- offset, size, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
- // TODO: fence
- if (mError == C2_OK) {
- mBase = (uint8_t *)base;
- mSize = size;
- }
- }
- }
-
- const uint8_t *base() const { return mBase; }
-
- c2_status_t error() const { return mError; }
-
-private:
- std::shared_ptr<C2LinearAllocation> mAllocation;
- uint8_t *mBase;
- size_t mSize;
- c2_status_t mError;
-};
-
-C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
- : C2Block1D(alloc), mImpl(std::make_shared<Impl>(alloc)) {}
-
-C2ConstLinearBlock::C2ConstLinearBlock(
- std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
- : C2Block1D(alloc, offset, size), mImpl(std::make_shared<Impl>(alloc)) {}
+/**
+ * Const linear block implementation.
+ */
+C2ConstLinearBlock::C2ConstLinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range, C2Fence fence)
+ : C2Block1D(impl, range), mFence(fence) { }
C2Acquirable<C2ReadView> C2ConstLinearBlock::map() const {
- mImpl->map(offset(), size());
- if (mImpl->base() == nullptr) {
- C2DefaultReadView view(mImpl->error());
- return C2AcquirableReadView(mImpl->error(), mFence, view);
+ void *base = nullptr;
+ uint32_t len = size();
+ c2_status_t error = mImpl->getAllocation()->map(
+ offset(), len, { C2MemoryUsage::CPU_READ, 0 }, nullptr, &base);
+ // TODO: wait on fence
+ if (error == C2_OK) {
+ std::shared_ptr<ReadViewBuddy::Impl> rvi = std::shared_ptr<ReadViewBuddy::Impl>(
+ new ReadViewBuddy::Impl(*mImpl, (uint8_t *)base, offset(), len),
+ [base, len](ReadViewBuddy::Impl *i) {
+ (void)i->getAllocation()->unmap(base, len, nullptr);
+ });
+ return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(rvi, 0, len));
+ } else {
+ return AcquirableReadViewBuddy(error, C2Fence(), ReadViewBuddy(error));
}
- DummyCapacityAspect newCapacity(size());
- C2DefaultReadView view(&newCapacity, mImpl->base());
- return C2AcquirableReadView(mImpl->error(), mFence, view);
}
-C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset, size_t size) const {
- return mImpl->subBlock(offset, size);
+C2ConstLinearBlock C2ConstLinearBlock::subBlock(size_t offset_, size_t size_) const {
+ C2LinearRange subRange(*mImpl, offset_, size_);
+ return C2ConstLinearBlock(mImpl, subRange, mFence);
}
-class C2LinearBlock::Impl {
-public:
- Impl(std::shared_ptr<C2LinearAllocation> alloc)
- : mAllocation(alloc), mBase(nullptr), mSize(0u), mError(C2_CORRUPTED) {}
-
- ~Impl() {
- if (mBase != nullptr) {
- // TODO: fence
- c2_status_t err = mAllocation->unmap(mBase, mSize, nullptr);
- if (err != C2_OK) {
- // TODO: Log?
- }
- }
- }
-
- void map(size_t capacity) {
- if (mBase == nullptr) {
- void *base = nullptr;
- // TODO: fence
- mError = mAllocation->map(
- 0u,
- capacity,
- { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE },
- nullptr,
- &base);
- if (mError == C2_OK) {
- mBase = (uint8_t *)base;
- mSize = capacity;
- }
- }
- }
-
- C2ConstLinearBlock share(size_t offset, size_t size, C2Fence &fence) {
- // TODO
- (void) fence;
- return C2DefaultConstLinearBlock(mAllocation, offset, size);
- }
-
- uint8_t *base() const { return mBase; }
-
- c2_status_t error() const { return mError; }
-
- C2Fence fence() const { return mFence; }
-
-private:
- std::shared_ptr<C2LinearAllocation> mAllocation;
- uint8_t *mBase;
- size_t mSize;
- c2_status_t mError;
- C2Fence mFence;
-};
-
-C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc)
- : C2Block1D(alloc),
- mImpl(new Impl(alloc)) {}
-
-C2LinearBlock::C2LinearBlock(std::shared_ptr<C2LinearAllocation> alloc, size_t offset, size_t size)
- : C2Block1D(alloc, offset, size),
- mImpl(new Impl(alloc)) {}
+/**
+ * Linear block implementation.
+ */
+C2LinearBlock::C2LinearBlock(std::shared_ptr<Impl> impl, const _C2LinearRangeAspect &range)
+ : C2Block1D(impl, range) { }
C2Acquirable<C2WriteView> C2LinearBlock::map() {
- mImpl->map(capacity());
- if (mImpl->base() == nullptr) {
- C2DefaultWriteView view(mImpl->error());
- return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
+ void *base = nullptr;
+ uint32_t len = size();
+ c2_status_t error = mImpl->getAllocation()->map(
+ offset(), len, { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE }, nullptr, &base);
+ // TODO: wait on fence
+ if (error == C2_OK) {
+ std::shared_ptr<WriteViewBuddy::Impl> rvi = std::shared_ptr<WriteViewBuddy::Impl>(
+ new WriteViewBuddy::Impl(*mImpl, (uint8_t *)base, 0, len),
+ [base, len](WriteViewBuddy::Impl *i) {
+ (void)i->getAllocation()->unmap(base, len, nullptr);
+ });
+ return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(rvi));
+ } else {
+ return AcquirableWriteViewBuddy(error, C2Fence(), WriteViewBuddy(error));
}
- C2DefaultWriteView view(this, mImpl->base());
- view.setOffset_be(offset());
- view.setSize_be(size());
- return C2AcquirableWriteView(mImpl->error(), mImpl->fence(), view);
}
-C2ConstLinearBlock C2LinearBlock::share(size_t offset, size_t size, C2Fence fence) {
- return mImpl->share(offset, size, fence);
+C2ConstLinearBlock C2LinearBlock::share(size_t offset_, size_t size_, C2Fence fence) {
+ return ConstLinearBlockBuddy(mImpl, C2LinearRange(*this, offset_, size_), fence);
+}
+
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+ const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
+ std::shared_ptr<C2Block1D::Impl> impl =
+ std::make_shared<C2Block1D::Impl>(alloc, data, offset, size);
+ return std::shared_ptr<C2LinearBlock>(new C2LinearBlock(impl, *impl));
}
C2BasicLinearBlockPool::C2BasicLinearBlockPool(
const std::shared_ptr<C2Allocator> &allocator)
- : mAllocator(allocator) {}
+ : mAllocator(allocator) { }
c2_status_t C2BasicLinearBlockPool::fetchLinearBlock(
uint32_t capacity,
@@ -361,7 +333,7 @@
return err;
}
- block->reset(new C2DefaultLinearBlock(alloc));
+ *block = _C2BlockFactory::CreateLinearBlock(alloc);
return C2_OK;
}
diff --git a/media/libstagefright/codec2/vndk/C2Store.cpp b/media/libstagefright/codec2/vndk/C2Store.cpp
index a49fd24..05b46c3 100644
--- a/media/libstagefright/codec2/vndk/C2Store.cpp
+++ b/media/libstagefright/codec2/vndk/C2Store.cpp
@@ -40,14 +40,9 @@
* \todo Move ion allocation into its HIDL or provide some mapping from memory usage to ion flags
* \todo Make this allocator store extendable
*/
-class C2PlatformAllocatorStore : public C2AllocatorStore {
+class C2PlatformAllocatorStoreImpl : public C2PlatformAllocatorStore {
public:
- enum : id_t {
- ION = PLATFORM_START,
- GRALLOC,
- };
-
- C2PlatformAllocatorStore(
+ C2PlatformAllocatorStoreImpl(
/* ionmapper */
);
@@ -71,10 +66,10 @@
std::shared_ptr<C2Allocator> fetchGrallocAllocator();
};
-C2PlatformAllocatorStore::C2PlatformAllocatorStore() {
+C2PlatformAllocatorStoreImpl::C2PlatformAllocatorStoreImpl() {
}
-c2_status_t C2PlatformAllocatorStore::fetchAllocator(
+c2_status_t C2PlatformAllocatorStoreImpl::fetchAllocator(
id_t id, std::shared_ptr<C2Allocator> *const allocator) {
allocator->reset();
switch (id) {
@@ -98,32 +93,32 @@
return C2_OK;
}
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchIonAllocator() {
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchIonAllocator() {
static std::mutex mutex;
static std::weak_ptr<C2Allocator> ionAllocator;
std::lock_guard<std::mutex> lock(mutex);
std::shared_ptr<C2Allocator> allocator = ionAllocator.lock();
if (allocator == nullptr) {
- allocator = std::make_shared<C2AllocatorIon>();
+ allocator = std::make_shared<C2AllocatorIon>(C2PlatformAllocatorStore::ION);
ionAllocator = allocator;
}
return allocator;
}
-std::shared_ptr<C2Allocator> C2PlatformAllocatorStore::fetchGrallocAllocator() {
+std::shared_ptr<C2Allocator> C2PlatformAllocatorStoreImpl::fetchGrallocAllocator() {
static std::mutex mutex;
static std::weak_ptr<C2Allocator> grallocAllocator;
std::lock_guard<std::mutex> lock(mutex);
std::shared_ptr<C2Allocator> allocator = grallocAllocator.lock();
if (allocator == nullptr) {
- allocator = std::make_shared<C2AllocatorGralloc>();
+ allocator = std::make_shared<C2AllocatorGralloc>(C2PlatformAllocatorStore::GRALLOC);
grallocAllocator = allocator;
}
return allocator;
}
std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore() {
- return std::make_shared<C2PlatformAllocatorStore>();
+ return std::make_shared<C2PlatformAllocatorStoreImpl>();
}
c2_status_t GetCodec2BlockPool(
@@ -408,6 +403,8 @@
mComponents.emplace("c2.google.aac.decoder", "libstagefright_soft_c2aacdec.so");
mComponents.emplace("c2.google.aac.encoder", "libstagefright_soft_c2aacenc.so");
mComponents.emplace("c2.google.mp3.decoder", "libstagefright_soft_c2mp3dec.so");
+ mComponents.emplace("c2.google.g711.alaw.decoder", "libstagefright_soft_c2g711alawdec.so");
+ mComponents.emplace("c2.google.g711.mlaw.decoder", "libstagefright_soft_c2g711mlawdec.so");
}
c2_status_t C2PlatformComponentStore::copyBuffer(
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
index 56fa317..0e1a3ac 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorGralloc.h
@@ -61,7 +61,7 @@
const C2Handle *handle,
std::shared_ptr<C2GraphicAllocation> *allocation) override;
- C2AllocatorGralloc();
+ C2AllocatorGralloc(id_t id = 0);
c2_status_t status() const;
diff --git a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
index bb815f9..716eae0 100644
--- a/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
+++ b/media/libstagefright/codec2/vndk/include/C2AllocatorIon.h
@@ -33,9 +33,7 @@
virtual C2String getName() const override;
- virtual std::shared_ptr<const Traits> getTraits() const override {
- return nullptr; // \todo
- }
+ virtual std::shared_ptr<const Traits> getTraits() const override;
virtual c2_status_t newLinearAllocation(
uint32_t capacity, C2MemoryUsage usage,
@@ -45,13 +43,14 @@
const C2Handle *handle,
std::shared_ptr<C2LinearAllocation> *allocation) override;
- C2AllocatorIon();
+ C2AllocatorIon(id_t id);
virtual c2_status_t status() const { return mInit; }
virtual ~C2AllocatorIon() override;
private:
+ std::shared_ptr<const Traits> mTraits;
c2_status_t mInit;
int mIonFd;
usage_mapper_fn mUsageMapper;
diff --git a/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
new file mode 100644
index 0000000..cfea104
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/include/C2ComponentFactory.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+#define STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
+
+#include <C2Component.h>
+
+#include <functional>
+#include <memory>
+
+namespace android {
+
+/**
+ * Component factory object that enables to create a component and/or interface from a dynamically
+ * linked library. This is needed because the component/interfaces are managed objects, but we
+ * cannot safely create a managed object and pass it in C.
+ *
+ * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
+ * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
+ * derives from enable_shared_from_this.
+ *
+ */
+class C2ComponentFactory {
+public:
+ typedef std::function<void(::android::C2Component*)> ComponentDeleter;
+ typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
+
+ /**
+ * Creates a component.
+ *
+ * This method SHALL return within 100ms.
+ *
+ * \param id component ID for the created component
+ * \param component shared pointer where the created component is stored. Cleared on
+ * failure and updated on success.
+ *
+ * \retval C2_OK the component was created successfully
+ * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
+ * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
+ *
+ * \retval C2_NO_MEMORY not enough memory to create the component
+ */
+ virtual c2_status_t createComponent(
+ c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+ ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
+
+ /**
+ * Creates a component interface.
+ *
+ * This method SHALL return within 100ms.
+ *
+ * \param id component interface ID for the created interface
+ * \param interface shared pointer where the created interface is stored. Cleared on
+ * failure and updated on success.
+ *
+ * \retval C2_OK the component interface was created successfully
+ * \retval C2_TIMED_OUT could not create the component interface within the time limit
+ * (unexpected)
+ * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
+ * (unexpected)
+ *
+ * \retval C2_NO_MEMORY not enough memory to create the component interface
+ */
+ virtual c2_status_t createInterface(
+ c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+ InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
+
+ virtual ~C2ComponentFactory() = default;
+
+ typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
+ typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
+};
+} // namespace android
+
+#endif // STAGEFRIGHT_CODEC2_COMPONENT_FACTORY_H_
diff --git a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
index 2281dab..76b02ed 100644
--- a/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/libstagefright/codec2/vndk/include/C2PlatformSupport.h
@@ -18,8 +18,8 @@
#define STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
#include <C2Component.h>
+#include <C2ComponentFactory.h>
-#include <functional>
#include <memory>
namespace android {
@@ -31,6 +31,34 @@
std::shared_ptr<C2AllocatorStore> GetCodec2PlatformAllocatorStore();
/**
+ * Platform allocator store IDs
+ */
+class C2PlatformAllocatorStore : public C2AllocatorStore {
+public:
+ enum : id_t {
+ /**
+ * ID of the ion backed platform allocator.
+ *
+ * C2Handle consists of:
+ * fd shared ion buffer handle
+ * int size (lo 32 bits)
+ * int size (hi 32 bits)
+ * int magic '\xc2io\x00'
+ */
+ ION = PLATFORM_START,
+
+ /**
+ * ID of the gralloc backed platform allocator.
+ *
+ * C2Handle layout is not public. Use C2AllocatorGralloc::UnwrapNativeCodec2GrallocHandle
+ * to get the underlying gralloc handle from a C2Handle, and WrapNativeCodec2GrallocHandle
+ * to create a C2Handle from a gralloc handle - for C2Allocator::priorAllocation.
+ */
+ GRALLOC,
+ };
+};
+
+/**
* Retrieves a block pool for a component.
*
* \param id the local ID of the block pool
@@ -54,73 +82,10 @@
std::shared_ptr<C2BlockPool> *pool);
/**
- * Component factory object that enables to create a component and/or interface from a dynamically
- * linked library. This is needed because the component/interfaces are managed objects, but we
- * cannot safely create a managed object and pass it in C.
- *
- * Components/interfaces typically inherit from std::enable_shared_from_this, but C requires
- * passing simple pointer, and shared_ptr constructor needs to know the class to be constructed
- * derives from enable_shared_from_this.
- *
- */
-class C2ComponentFactory {
-public:
- typedef std::function<void(::android::C2Component*)> ComponentDeleter;
- typedef std::function<void(::android::C2ComponentInterface*)> InterfaceDeleter;
-
- /**
- * Creates a component.
- *
- * This method SHALL return within 100ms.
- *
- * \param id component ID for the created component
- * \param component shared pointer where the created component is stored. Cleared on
- * failure and updated on success.
- *
- * \retval C2_OK the component was created successfully
- * \retval C2_TIMED_OUT could not create the component within the time limit (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the component (unexpected)
- *
- * \retval C2_NO_MEMORY not enough memory to create the component
- */
- virtual c2_status_t createComponent(
- c2_node_id_t id, std::shared_ptr<C2Component>* const component,
- ComponentDeleter deleter = std::default_delete<C2Component>()) = 0;
-
- /**
- * Creates a component interface.
- *
- * This method SHALL return within 100ms.
- *
- * \param id component interface ID for the created interface
- * \param interface shared pointer where the created interface is stored. Cleared on
- * failure and updated on success.
- *
- * \retval C2_OK the component interface was created successfully
- * \retval C2_TIMED_OUT could not create the component interface within the time limit
- * (unexpected)
- * \retval C2_CORRUPTED some unknown error prevented the creation of the component interface
- * (unexpected)
- *
- * \retval C2_NO_MEMORY not enough memory to create the component interface
- */
- virtual c2_status_t createInterface(
- c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
- InterfaceDeleter deleter = std::default_delete<C2ComponentInterface>()) = 0;
-
- virtual ~C2ComponentFactory() = default;
-
- typedef ::android::C2ComponentFactory* (*CreateCodec2FactoryFunc)(void);
- typedef void (*DestroyCodec2FactoryFunc)(::android::C2ComponentFactory*);
-};
-
-/**
* Returns the platform component store.
* \retval nullptr if the platform component store could not be obtained
*/
std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
-
-
} // namespace android
#endif // STAGEFRIGHT_CODEC2_PLATFORM_SUPPORT_H_
diff --git a/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
new file mode 100644
index 0000000..c84d1fb
--- /dev/null
+++ b/media/libstagefright/codec2/vndk/internal/C2BlockInternal.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+#define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
+#include <C2Buffer.h>
+
+namespace android {
+
+struct _C2BlockPoolData;
+
+/**
+ * Interface for creating blocks by block pool/buffer passing implementations.
+ */
+struct C2_HIDE _C2BlockFactory {
+ static
+ std::shared_ptr<C2LinearBlock> C2_HIDE CreateLinearBlock(
+ const std::shared_ptr<C2LinearAllocation> &alloc,
+ const std::shared_ptr<_C2BlockPoolData> &data = nullptr,
+ size_t offset = 0,
+ size_t size = ~(size_t)0);
+};
+
+}
+
+#endif // ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
+
diff --git a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
index 7c281e3..911f0f8 100644
--- a/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/C2SoftAvcEnc.cpp
@@ -654,7 +654,6 @@
ALOGE("Unable to allocate memory for hold memory records: Size %zu",
mNumMemRecords * sizeof(iv_mem_rec_t));
mSignalledError = true;
- // TODO: notify(error, C2_CORRUPTED, 0, 0);
return C2_CORRUPTED;
}
@@ -697,8 +696,6 @@
if (status != IV_SUCCESS) {
ALOGE("Fill memory records failed = 0x%x\n",
s_fill_mem_rec_op.u4_error_code);
- mSignalledError = true;
- // TODO: notify(error, C2_CORRUPTED, 0, 0);
return C2_CORRUPTED;
}
}
@@ -716,8 +713,6 @@
if (ps_mem_rec->pv_base == NULL) {
ALOGE("Allocation failure for mem record id %zu size %u\n", i,
ps_mem_rec->u4_mem_size);
- mSignalledError = true;
- // TODO: notify(error, C2_CORRUPTED, 0, 0);
return C2_CORRUPTED;
}
@@ -771,8 +766,6 @@
if (status != IV_SUCCESS) {
ALOGE("Init encoder failed = 0x%x\n", s_init_op.u4_error_code);
- mSignalledError = true;
- // TODO: notify(error, C2_CORRUPTED, 0 /* arg2 */, NULL /* data */);
return C2_CORRUPTED;
}
}
@@ -1001,6 +994,7 @@
void C2SoftAvcEnc::process(
const std::unique_ptr<C2Work> &work,
const std::shared_ptr<C2BlockPool> &pool) {
+ work->result = C2_OK;
work->workletsProcessed = 0u;
IV_STATUS_T status;
@@ -1011,7 +1005,8 @@
if (mCodecCtx == NULL) {
if (C2_OK != initEncoder()) {
ALOGE("Failed to initialize encoder");
- // TODO: notify(error, C2_CORRUPTED, 0 /* arg2 */, NULL /* data */);
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
return;
}
}
@@ -1031,7 +1026,8 @@
&s_encode_ip, &s_encode_op, NULL, header, kHeaderLength, timestamp);
if (error != C2_OK) {
mSignalledError = true;
- // TODO: notify(error, C2_CORRUPTED, 0, 0);
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
return;
}
status = ive_api_function(mCodecCtx, &s_encode_ip, &s_encode_op);
@@ -1100,11 +1096,15 @@
c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
if (err != C2_OK) {
ALOGE("fetch linear block err = %d", err);
+ work->workletsProcessed = 1u;
+ work->result = err;
return;
}
C2WriteView wView = block->map().get();
if (wView.error() != C2_OK) {
ALOGE("write view map err = %d", wView.error());
+ work->workletsProcessed = 1u;
+ work->result = wView.error();
return;
}
@@ -1113,7 +1113,8 @@
if (error != C2_OK) {
mSignalledError = true;
ALOGE("setEncodeArgs failed : %d", error);
- // TODO: notify(error, C2_CORRUPTED, 0, 0);
+ work->workletsProcessed = 1u;
+ work->result = error;
return;
}
@@ -1136,7 +1137,8 @@
ALOGE("Encode Frame failed = 0x%x\n",
s_encode_op.u4_error_code);
mSignalledError = true;
- // TODO: notify(error, C2_CORRUPTED, 0, 0);
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
return;
}
} while (IV_SUCCESS != status);
@@ -1155,7 +1157,8 @@
/* If encoder frees up an input buffer, mark it as free */
if (freed != NULL) {
if (mBuffers.count(freed) == 0u) {
- // TODO: error
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
return;
}
// Release input buffer reference
diff --git a/media/libstagefright/codecs/g711/dec/Android.bp b/media/libstagefright/codecs/g711/dec/Android.bp
index 3d97d8c..58a0a4d 100644
--- a/media/libstagefright/codecs/g711/dec/Android.bp
+++ b/media/libstagefright/codecs/g711/dec/Android.bp
@@ -1,4 +1,79 @@
cc_library_shared {
+ name: "libstagefright_soft_c2g711alawdec",
+// vendor_available: true,
+// vndk: {
+// enabled: true,
+// },
+
+ srcs: [
+ "C2SoftG711.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-DALAW",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ "libstagefright_codec2",
+ "libstagefright_codec2_vndk",
+ "libstagefright_foundation",
+ "libstagefright_simple_c2component",
+ ],
+}
+
+cc_library_shared {
+ name: "libstagefright_soft_c2g711mlawdec",
+// vendor_available: true,
+// vndk: {
+// enabled: true,
+// },
+
+ srcs: [
+ "C2SoftG711.cpp",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ "libstagefright_codec2",
+ "libstagefright_codec2_vndk",
+ "libstagefright_foundation",
+ "libstagefright_simple_c2component",
+ ],
+}
+
+cc_library_shared {
name: "libstagefright_soft_g711dec",
vendor_available: true,
vndk: {
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
new file mode 100644
index 0000000..a26dbb9
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "C2SoftG711"
+#include <utils/Log.h>
+
+#include "C2SoftG711.h"
+
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#ifdef ALAW
+#define COMPONENT_NAME "g711a"
+#else
+#define COMPONENT_NAME "g711m"
+#endif
+
+namespace android {
+
+C2SoftG711::C2SoftG711(const char *name, c2_node_id_t id)
+ : SimpleC2Component(
+ SimpleC2Interface::Builder(name, id)
+ .inputFormat(C2FormatCompressed)
+ .outputFormat(C2FormatAudio)
+ .build()) {
+}
+
+C2SoftG711::~C2SoftG711() {
+ onRelease();
+}
+
+c2_status_t C2SoftG711::onInit() {
+ mSignalledOutputEos = false;
+ return C2_OK;
+}
+
+c2_status_t C2SoftG711::onStop() {
+ mSignalledOutputEos = false;
+ return C2_OK;
+}
+
+void C2SoftG711::onReset() {
+ (void)onStop();
+}
+
+void C2SoftG711::onRelease() {
+}
+
+c2_status_t C2SoftG711::onFlush_sm() {
+ return onStop();
+}
+
+void C2SoftG711::process(
+ const std::unique_ptr<C2Work> &work,
+ const std::shared_ptr<C2BlockPool> &pool) {
+ work->result = C2_OK;
+ work->workletsProcessed = 0u;
+ if (mSignalledOutputEos) {
+ work->result = C2_BAD_VALUE;
+ return;
+ }
+
+ const C2ConstLinearBlock &inBuffer =
+ work->input.buffers[0]->data().linearBlocks().front();
+ C2ReadView rView = inBuffer.map().get();
+ size_t inOffset = inBuffer.offset();
+ size_t inSize = inBuffer.size();
+ int outSize = inSize * sizeof(int16_t);
+ if (inSize && rView.error()) {
+ ALOGE("read view map failed %d", rView.error());
+ work->result = C2_CORRUPTED;
+ return;
+ }
+ bool eos = (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+
+ ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
+ (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
+
+ if (inSize == 0) {
+ work->worklets.front()->output.flags = work->input.flags;
+ work->worklets.front()->output.buffers.clear();
+ work->worklets.front()->output.ordinal = work->input.ordinal;
+ work->workletsProcessed = 1u;
+ if (eos) {
+ mSignalledOutputEos = true;
+ ALOGV("signalled EOS");
+ }
+ return;
+ }
+
+ uint8_t *inputptr = const_cast<uint8_t *>(rView.data() + inOffset);
+
+ std::shared_ptr<C2LinearBlock> block;
+ C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
+ c2_status_t err = pool->fetchLinearBlock(outSize, usage, &block);
+ if (err != C2_OK) {
+ ALOGE("fetchLinearBlock for Output failed with status %d", err);
+ work->result = C2_NO_MEMORY;
+ return;
+ }
+ C2WriteView wView = block->map().get();
+ if (wView.error()) {
+ ALOGE("write view map failed %d", wView.error());
+ work->result = C2_CORRUPTED;
+ return;
+ }
+ int16_t *outputptr = reinterpret_cast<int16_t *>(wView.data());
+
+#ifdef ALAW
+ DecodeALaw(outputptr, inputptr, inSize);
+#else
+ DecodeMLaw(outputptr, inputptr, inSize);
+#endif
+
+ work->worklets.front()->output.flags = work->input.flags;
+ work->worklets.front()->output.buffers.clear();
+ work->worklets.front()->output.buffers.push_back(createLinearBuffer(block));
+ work->worklets.front()->output.ordinal = work->input.ordinal;
+ work->workletsProcessed = 1u;
+
+ if (eos) {
+ mSignalledOutputEos = true;
+ ALOGV("signalled EOS");
+ }
+}
+
+c2_status_t C2SoftG711::drain(
+ uint32_t drainMode,
+ const std::shared_ptr<C2BlockPool> &pool) {
+ (void) pool;
+ if (drainMode == NO_DRAIN) {
+ ALOGW("drain with NO_DRAIN: no-op");
+ return C2_OK;
+ }
+ if (drainMode == DRAIN_CHAIN) {
+ ALOGW("DRAIN_CHAIN not supported");
+ return C2_OMITTED;
+ }
+
+ return C2_OK;
+}
+
+#ifdef ALAW
+void C2SoftG711::DecodeALaw(
+ int16_t *out, const uint8_t *in, size_t inSize) {
+ while (inSize > 0) {
+ inSize--;
+ int32_t x = *in++;
+
+ int32_t ix = x ^ 0x55;
+ ix &= 0x7f;
+
+ int32_t iexp = ix >> 4;
+ int32_t mant = ix & 0x0f;
+
+ if (iexp > 0) {
+ mant += 16;
+ }
+
+ mant = (mant << 4) + 8;
+
+ if (iexp > 1) {
+ mant = mant << (iexp - 1);
+ }
+
+ *out++ = (x > 127) ? mant : -mant;
+ }
+}
+#else
+void C2SoftG711::DecodeMLaw(
+ int16_t *out, const uint8_t *in, size_t inSize) {
+ while (inSize > 0) {
+ inSize--;
+ int32_t x = *in++;
+
+ int32_t mantissa = ~x;
+ int32_t exponent = (mantissa >> 4) & 7;
+ int32_t segment = exponent + 1;
+ mantissa &= 0x0f;
+
+ int32_t step = 4 << segment;
+
+ int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+
+ *out++ = (x < 0x80) ? -abs : abs;
+ }
+}
+#endif
+
+class C2SoftG711DecFactory : public C2ComponentFactory {
+public:
+ virtual c2_status_t createComponent(
+ c2_node_id_t id, std::shared_ptr<C2Component>* const component,
+ std::function<void(::android::C2Component*)> deleter) override {
+ *component = std::shared_ptr<C2Component>(new C2SoftG711(COMPONENT_NAME, id), deleter);
+ return C2_OK;
+ }
+
+ virtual c2_status_t createInterface(
+ c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
+ std::function<void(::android::C2ComponentInterface*)> deleter) override {
+ *interface =
+ SimpleC2Interface::Builder(COMPONENT_NAME, id, deleter)
+ .inputFormat(C2FormatCompressed)
+ .outputFormat(C2FormatAudio)
+ .build();
+ return C2_OK;
+ }
+
+ virtual ~C2SoftG711DecFactory() override = default;
+};
+
+} // namespace android
+
+extern "C" ::android::C2ComponentFactory* CreateCodec2Factory() {
+ ALOGV("in %s", __func__);
+ return new ::android::C2SoftG711DecFactory();
+}
+
+extern "C" void DestroyCodec2Factory(::android::C2ComponentFactory* factory) {
+ ALOGV("in %s", __func__);
+ delete factory;
+}
diff --git a/media/libstagefright/codecs/g711/dec/C2SoftG711.h b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
new file mode 100644
index 0000000..eed38c9
--- /dev/null
+++ b/media/libstagefright/codecs/g711/dec/C2SoftG711.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef C2_SOFT_G711_H_
+#define C2_SOFT_G711_H_
+
+#include <SimpleC2Component.h>
+
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct C2SoftG711 : public SimpleC2Component {
+ C2SoftG711(const char *name, c2_node_id_t id);
+ virtual ~C2SoftG711();
+
+ // From SimpleC2Component
+ c2_status_t onInit() override;
+ c2_status_t onStop() override;
+ void onReset() override;
+ void onRelease() override;
+ c2_status_t onFlush_sm() override;
+ void process(
+ const std::unique_ptr<C2Work> &work,
+ const std::shared_ptr<C2BlockPool> &pool) override;
+ c2_status_t drain(
+ uint32_t drainMode,
+ const std::shared_ptr<C2BlockPool> &pool) override;
+private:
+ bool mSignalledOutputEos;
+
+#ifdef ALAW
+ void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
+#else
+ void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
+#endif
+
+ DISALLOW_EVIL_CONSTRUCTORS(C2SoftG711);
+};
+
+} // namespace android
+
+#endif // C2_SOFT_G711_H_
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
deleted file mode 100644
index 1223c80..0000000
--- a/media/libstagefright/include/AVIExtractor.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AVI_EXTRACTOR_H_
-
-#define AVI_EXTRACTOR_H_
-
-#include <media/MediaExtractor.h>
-#include <media/MediaSource.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct AVIExtractor : public MediaExtractor {
- AVIExtractor(const sp<DataSource> &dataSource);
-
- virtual size_t countTracks();
-
- virtual sp<MediaSource> getTrack(size_t index);
-
- virtual sp<MetaData> getTrackMetaData(
- size_t index, uint32_t flags);
-
- virtual sp<MetaData> getMetaData();
- virtual const char * name() { return "AVIExtractor"; }
-
-protected:
- virtual ~AVIExtractor();
-
-private:
- struct AVISource;
- struct MP3Splitter;
-
- struct SampleInfo {
- uint32_t mOffset;
- bool mIsKey;
- };
-
- struct Track {
- sp<MetaData> mMeta;
- Vector<SampleInfo> mSamples;
- uint32_t mRate;
- uint32_t mScale;
-
- // If bytes per sample == 0, each chunk represents a single sample,
- // otherwise each chunk should me a multiple of bytes-per-sample in
- // size.
- uint32_t mBytesPerSample;
-
- enum Kind {
- AUDIO,
- VIDEO,
- OTHER
-
- } mKind;
-
- size_t mNumSyncSamples;
- size_t mThumbnailSampleSize;
- ssize_t mThumbnailSampleIndex;
- size_t mMaxSampleSize;
-
- // If mBytesPerSample > 0:
- double mAvgChunkSize;
- size_t mFirstChunkSize;
- };
-
- sp<DataSource> mDataSource;
- status_t mInitCheck;
- Vector<Track> mTracks;
-
- off64_t mMovieOffset;
- bool mFoundIndex;
- bool mOffsetsAreAbsolute;
-
- ssize_t parseChunk(off64_t offset, off64_t size, int depth = 0);
- status_t parseStreamHeader(off64_t offset, size_t size);
- status_t parseStreamFormat(off64_t offset, size_t size);
- status_t parseIndex(off64_t offset, size_t size);
-
- status_t parseHeaders();
-
- status_t getSampleInfo(
- size_t trackIndex, size_t sampleIndex,
- off64_t *offset, size_t *size, bool *isKey,
- int64_t *sampleTimeUs);
-
- status_t getSampleTime(
- size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
-
- status_t getSampleIndexAtTime(
- size_t trackIndex,
- int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
- size_t *sampleIndex) const;
-
- status_t addMPEG4CodecSpecificData(size_t trackIndex);
- status_t addH264CodecSpecificData(size_t trackIndex);
-
- static bool IsCorrectChunkType(
- ssize_t trackIndex, Track::Kind kind, uint32_t chunkType);
-
- DISALLOW_EVIL_CONSTRUCTORS(AVIExtractor);
-};
-
-class String8;
-struct AMessage;
-
-bool SniffAVI(
- const sp<DataSource> &source, String8 *mimeType, float *confidence,
- sp<AMessage> *);
-
-} // namespace android
-
-#endif // AVI_EXTRACTOR_H_
diff --git a/media/libstagefright/include/Codec2Buffer.h b/media/libstagefright/include/Codec2Buffer.h
index 0272cea..6d85e83 100644
--- a/media/libstagefright/include/Codec2Buffer.h
+++ b/media/libstagefright/include/Codec2Buffer.h
@@ -24,30 +24,48 @@
namespace android {
-class C2Buffer;
-
/**
* MediaCodecBuffer implementation wraps around C2LinearBlock.
*/
-class Codec2Buffer : public MediaCodecBuffer {
+class LinearBlockBuffer : public MediaCodecBuffer {
public:
- static sp<Codec2Buffer> allocate(
+ static sp<LinearBlockBuffer> allocate(
const sp<AMessage> &format, const std::shared_ptr<C2LinearBlock> &block);
- virtual ~Codec2Buffer() = default;
+ virtual ~LinearBlockBuffer() = default;
C2ConstLinearBlock share();
private:
- Codec2Buffer(
+ LinearBlockBuffer(
const sp<AMessage> &format,
- const sp<ABuffer> &buffer,
+ C2WriteView &&writeView,
const std::shared_ptr<C2LinearBlock> &block);
- Codec2Buffer() = delete;
+ LinearBlockBuffer() = delete;
+ C2WriteView mWriteView;
std::shared_ptr<C2LinearBlock> mBlock;
};
+/**
+ * MediaCodecBuffer implementation wraps around C2ConstLinearBlock.
+ */
+class ConstLinearBlockBuffer : public MediaCodecBuffer {
+public:
+ static sp<ConstLinearBlockBuffer> allocate(
+ const sp<AMessage> &format, const C2ConstLinearBlock &block);
+
+ virtual ~ConstLinearBlockBuffer() = default;
+
+private:
+ ConstLinearBlockBuffer(
+ const sp<AMessage> &format,
+ C2ReadView &&readView);
+ ConstLinearBlockBuffer() = delete;
+
+ C2ReadView mReadView;
+};
+
} // namespace android
#endif // CODEC2_BUFFER_H_
diff --git a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
index aabbc69..eaf404c 100644
--- a/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
+++ b/packages/MediaComponents/src/com/android/media/IMediaSession2Callback.aidl
@@ -31,6 +31,7 @@
void onPlaybackStateChanged(in Bundle state);
void onPlaylistChanged(in List<Bundle> playlist);
void onPlaylistParamsChanged(in Bundle params);
+ void onPlaybackInfoChanged(in Bundle playbackInfo);
/**
* Called only when the controller is created with service's token.
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 41dfd00..6ee79a0 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -74,6 +74,8 @@
private List<MediaItem2> mPlaylist;
@GuardedBy("mLock")
private PlaylistParams mPlaylistParams;
+ @GuardedBy("mLock")
+ private PlaybackInfo mPlaybackInfo;
// Assignment should be used with the lock hold, but should be used without a lock to prevent
// potential deadlock.
@@ -293,12 +295,6 @@
}
@Override
- public PlaybackInfo getPlaybackInfo_impl() {
- // TODO(jaewan): Implement
- return null;
- }
-
- @Override
public void prepareFromUri_impl(Uri uri, Bundle extras) {
// TODO(jaewan): Implement
}
@@ -413,6 +409,13 @@
}
@Override
+ public PlaybackInfo getPlaybackInfo_impl() {
+ synchronized (mLock) {
+ return mPlaybackInfo;
+ }
+ }
+
+ @Override
public void setPlaylistParams_impl(PlaylistParams params) {
if (params == null) {
throw new IllegalArgumentException("PlaylistParams should not be null!");
@@ -449,6 +452,18 @@
});
}
+ private void pushPlaybackInfoChanges(final PlaybackInfo info) {
+ synchronized (mLock) {
+ mPlaybackInfo = info;
+ }
+ mCallbackExecutor.execute(() -> {
+ if (!mInstance.isConnected()) {
+ return;
+ }
+ mCallback.onPlaybackInfoChanged(info);
+ });
+ }
+
private void pushPlaylistChanges(final List<Bundle> list) {
final List<MediaItem2> playlist = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
@@ -603,6 +618,19 @@
}
@Override
+ public void onPlaybackInfoChanged(Bundle playbackInfo) throws RuntimeException {
+ final MediaController2Impl controller;
+ try {
+ controller = getController();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Don't fail silently here. Highly likely a bug");
+ return;
+ }
+ controller.pushPlaybackInfoChanges(
+ PlaybackInfoImpl.fromBundle(controller.getContext(), playbackInfo));
+ }
+
+ @Override
public void onConnectionChanged(IMediaSession2 sessionBinder, Bundle commandGroup)
throws RuntimeException {
final MediaController2Impl controller;
diff --git a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
index 54c8d41..77bd334 100644
--- a/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaLibraryService2Impl.java
@@ -28,7 +28,7 @@
import android.media.MediaSession2.ControllerInfo;
import android.media.MediaSessionService2;
import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
import android.media.update.MediaLibraryService2Provider;
import android.os.Bundle;
@@ -68,7 +68,7 @@
private final MediaLibrarySessionCallback mCallback;
public MediaLibrarySessionImpl(Context context,
- MediaPlayerInterface player, String id, VolumeProvider volumeProvider,
+ MediaPlayerInterface player, String id, VolumeProvider2 volumeProvider,
int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
MediaLibrarySessionCallback callback) {
super(context, player, id, volumeProvider, ratingType, sessionActivity,
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index f820cdc..cde98d2 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -21,15 +21,19 @@
import static android.media.SessionToken2.TYPE_SESSION;
import static android.media.SessionToken2.TYPE_SESSION_SERVICE;
+import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.Manifest.permission;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaController2;
+import android.media.MediaController2.PlaybackInfo;
import android.media.MediaItem2;
import android.media.MediaLibraryService2;
import android.media.MediaMetadata2;
@@ -48,14 +52,13 @@
import android.media.MediaSessionService2;
import android.media.PlaybackState2;
import android.media.SessionToken2;
-import android.media.VolumeProvider;
+import android.media.VolumeProvider2;
import android.media.session.MediaSessionManager;
import android.media.update.MediaSession2Provider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcelable;
import android.os.Process;
-import android.os.IBinder;
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
import android.text.TextUtils;
@@ -80,11 +83,16 @@
private final SessionCallback mCallback;
private final MediaSession2Stub mSessionStub;
private final SessionToken2 mSessionToken;
+ private final AudioManager mAudioManager;
private final List<PlaybackListenerHolder> mListeners = new ArrayList<>();
@GuardedBy("mLock")
private MediaPlayerInterface mPlayer;
@GuardedBy("mLock")
+ private VolumeProvider2 mVolumeProvider;
+ @GuardedBy("mLock")
+ private PlaybackInfo mPlaybackInfo;
+ @GuardedBy("mLock")
private MyPlaybackListener mListener;
@GuardedBy("mLock")
private PlaylistParams mPlaylistParams;
@@ -103,8 +111,8 @@
* @param ratingType
* @param sessionActivity
*/
- public MediaSession2Impl(Context context, MediaPlayerInterface player,
- String id, VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+ public MediaSession2Impl(Context context, MediaPlayerInterface player, String id,
+ VolumeProvider2 volumeProvider, int ratingType, PendingIntent sessionActivity,
Executor callbackExecutor, SessionCallback callback) {
// TODO(jaewan): Keep other params.
mInstance = createInstance();
@@ -116,6 +124,7 @@
mCallback = callback;
mCallbackExecutor = callbackExecutor;
mSessionStub = new MediaSession2Stub(this);
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
// Infer type from the id and package name.
String libraryService = getServiceName(context, MediaLibraryService2.SERVICE_INTERFACE, id);
@@ -135,6 +144,8 @@
}
setPlayerLocked(player);
+ mVolumeProvider = volumeProvider;
+ mPlaybackInfo = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
// Ask server for the sanity check, and starts
// Sanity check for making session ID unique 'per package' cannot be done in here.
@@ -178,12 +189,8 @@
return serviceName;
}
- // TODO(jaewan): Add explicit release() and do not remove session object with the
- // setPlayer(null). Token can be available when player is null, and
- // controller can also attach to session.
@Override
- public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider)
- throws IllegalArgumentException {
+ public void setPlayer_impl(MediaPlayerInterface player) {
ensureCallingThread();
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
@@ -191,9 +198,37 @@
if (player == mPlayer) {
return;
}
+ PlaybackInfo info =
+ createPlaybackInfo(null /* VolumeProvider */, player.getAudioAttributes());
synchronized (mLock) {
setPlayerLocked(player);
+ mVolumeProvider = null;
+ mPlaybackInfo = info;
}
+ mSessionStub.notifyPlaybackInfoChanged(info);
+ }
+
+ @Override
+ public void setPlayer_impl(MediaPlayerInterface player, VolumeProvider2 volumeProvider)
+ throws IllegalArgumentException {
+ ensureCallingThread();
+ if (player == null) {
+ throw new IllegalArgumentException("player shouldn't be null");
+ }
+ if (volumeProvider == null) {
+ throw new IllegalArgumentException("volumeProvider shouldn't be null");
+ }
+ if (player == mPlayer) {
+ return;
+ }
+
+ PlaybackInfo info = createPlaybackInfo(volumeProvider, player.getAudioAttributes());
+ synchronized (mLock) {
+ setPlayerLocked(player);
+ mVolumeProvider = volumeProvider;
+ mPlaybackInfo = info;
+ }
+ mSessionStub.notifyPlaybackInfoChanged(info);
}
private void setPlayerLocked(MediaPlayerInterface player) {
@@ -206,6 +241,29 @@
player.addPlaybackListener(mCallbackExecutor, mListener);
}
+ private PlaybackInfo createPlaybackInfo(VolumeProvider2 volumeProvider, AudioAttributes attrs) {
+ PlaybackInfo info;
+ if (volumeProvider == null) {
+ int stream = attrs == null ? AudioManager.STREAM_MUSIC : attrs.getVolumeControlStream();
+ info = PlaybackInfoImpl.createPlaybackInfo(
+ mContext,
+ PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+ attrs,
+ VolumeProvider2.VOLUME_CONTROL_ABSOLUTE,
+ mAudioManager.getStreamMaxVolume(stream),
+ mAudioManager.getStreamVolume(stream));
+ } else {
+ info = PlaybackInfoImpl.createPlaybackInfo(
+ mContext,
+ PlaybackInfo.PLAYBACK_TYPE_REMOTE /* ControlType */,
+ attrs,
+ volumeProvider.getControlType(),
+ volumeProvider.getMaxVolume(),
+ volumeProvider.getCurrentVolume());
+ }
+ return info;
+ }
+
@Override
public void close_impl() {
// Stop system service from listening this session first.
@@ -320,10 +378,6 @@
//////////////////////////////////////////////////////////////////////////////////////
// TODO(jaewan): Implement follows
//////////////////////////////////////////////////////////////////////////////////////
- @Override
- public void setPlayer_impl(MediaPlayerInterface player) {
- // TODO(jaewan): Implement
- }
@Override
public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
@@ -1032,7 +1086,7 @@
String mId;
Executor mCallbackExecutor;
C mCallback;
- VolumeProvider mVolumeProvider;
+ VolumeProvider2 mVolumeProvider;
int mRatingType;
PendingIntent mSessionActivity;
@@ -1058,7 +1112,7 @@
mId = "";
}
- public void setVolumeProvider_impl(VolumeProvider volumeProvider) {
+ public void setVolumeProvider_impl(VolumeProvider2 volumeProvider) {
mVolumeProvider = volumeProvider;
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index 1f71187..5d3a06e 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -17,6 +17,7 @@
package com.android.media;
import android.content.Context;
+import android.media.MediaController2;
import android.media.MediaItem2;
import android.media.MediaLibraryService2.LibraryRoot;
import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
@@ -130,6 +131,7 @@
// Controller may be died prematurely.
}
if (accept) {
+ // TODO(jaewan): We need to send current PlaybackInfo.
// If connection is accepted, notify the current state to the controller.
// It's needed because we cannot call synchronous calls between session/controller.
// Note: We're doing this after the onConnectionChanged(), but there's no guarantee
@@ -390,6 +392,21 @@
}
}
+ public void notifyPlaybackInfoChanged(MediaController2.PlaybackInfo playbackInfo) {
+ final List<ControllerInfo> list = getControllers();
+ for (int i = 0; i < list.size(); i++) {
+ IMediaSession2Callback callbackBinder =
+ ControllerInfoImpl.from(list.get(i)).getControllerBinder();
+ try {
+ callbackBinder.onPlaybackInfoChanged(
+ ((PlaybackInfoImpl) playbackInfo.getProvider()).toBundle());
+ } catch (RemoteException e) {
+ Log.w(TAG, "Controller is gone", e);
+ // TODO(jaewan): What to do when the controller is gone?
+ }
+ }
+ }
+
public void sendCustomCommand(ControllerInfo controller, Command command, Bundle args,
ResultReceiver receiver) {
if (receiver != null && controller == null) {
diff --git a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
index 661e252..46812e7 100644
--- a/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
+++ b/packages/MediaComponents/src/com/android/media/update/ApiFactory.java
@@ -64,7 +64,7 @@
import android.media.update.SessionToken2Provider;
import android.media.update.StaticProvider;
import android.media.update.VideoView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
import android.media.update.VolumeProvider2Provider;
import android.os.Bundle;
import android.os.IInterface;
@@ -205,16 +205,17 @@
}
@Override
- public MediaControlView2Provider createMediaControlView2(
- MediaControlView2 instance, ViewProvider superProvider) {
- return new MediaControlView2Impl(instance, superProvider);
+ public MediaControlView2Provider createMediaControlView2(MediaControlView2 instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
+ @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ return new MediaControlView2Impl(instance, superProvider, privateProvider);
}
@Override
public VideoView2Provider createVideoView2(
- VideoView2 instance, ViewProvider superProvider,
+ VideoView2 instance, ViewGroupProvider superProvider, ViewGroupProvider privateProvider,
@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- return new VideoView2Impl(instance, superProvider, attrs, defStyleAttr, defStyleRes);
+ return new VideoView2Impl(instance, superProvider, privateProvider);
}
@Override
diff --git a/packages/MediaComponents/src/com/android/widget/BaseLayout.java b/packages/MediaComponents/src/com/android/widget/BaseLayout.java
new file mode 100644
index 0000000..fb6471d
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/BaseLayout.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.graphics.drawable.Drawable;
+import android.media.update.ViewGroupProvider;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
+
+import java.util.ArrayList;
+
+public class BaseLayout extends ViewGroupImpl {
+ private final ViewGroup mInstance;
+ private final ViewGroupProvider mSuperProvider;
+ private final ViewGroupProvider mPrivateProvider;
+
+ private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+ public BaseLayout(ViewGroup instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+ super(instance, superProvider, privateProvider);
+ mInstance = instance;
+ mSuperProvider = superProvider;
+ mPrivateProvider = privateProvider;
+ }
+
+ @Override
+ public boolean checkLayoutParams_impl(LayoutParams p) {
+ return p instanceof MarginLayoutParams;
+ }
+
+ @Override
+ public LayoutParams generateDefaultLayoutParams_impl() {
+ return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+ return new MarginLayoutParams(mInstance.getContext(), attrs);
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams_impl(LayoutParams lp) {
+ if (lp instanceof MarginLayoutParams) {
+ return lp;
+ }
+ return new MarginLayoutParams(lp);
+ }
+
+ @Override
+ public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+ int count = mInstance.getChildCount();
+
+ final boolean measureMatchParentChildren =
+ View.MeasureSpec.getMode(widthMeasureSpec) != View.MeasureSpec.EXACTLY ||
+ View.MeasureSpec.getMode(heightMeasureSpec) != View.MeasureSpec.EXACTLY;
+ mMatchParentChildren.clear();
+
+ int maxHeight = 0;
+ int maxWidth = 0;
+ int childState = 0;
+
+ for (int i = 0; i < count; i++) {
+ final View child = mInstance.getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ mPrivateProvider.measureChildWithMargins_impl(
+ child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+ maxWidth = Math.max(maxWidth,
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
+ maxHeight = Math.max(maxHeight,
+ child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+ childState = childState | child.getMeasuredState();
+ if (measureMatchParentChildren) {
+ if (lp.width == LayoutParams.MATCH_PARENT ||
+ lp.height == LayoutParams.MATCH_PARENT) {
+ mMatchParentChildren.add(child);
+ }
+ }
+ }
+ }
+
+ // Account for padding too
+ maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
+ maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
+
+ // Check against our minimum height and width
+ maxHeight = Math.max(maxHeight, mPrivateProvider.getSuggestedMinimumHeight_impl());
+ maxWidth = Math.max(maxWidth, mPrivateProvider.getSuggestedMinimumWidth_impl());
+
+ // Check against our foreground's minimum height and width
+ final Drawable drawable = mInstance.getForeground();
+ if (drawable != null) {
+ maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+ maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+ }
+
+ mPrivateProvider.setMeasuredDimension_impl(
+ mInstance.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+ mInstance.resolveSizeAndState(maxHeight, heightMeasureSpec,
+ childState << View.MEASURED_HEIGHT_STATE_SHIFT));
+
+ count = mMatchParentChildren.size();
+ if (count > 1) {
+ for (int i = 0; i < count; i++) {
+ final View child = mMatchParentChildren.get(i);
+ final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+ final int childWidthMeasureSpec;
+ if (lp.width == LayoutParams.MATCH_PARENT) {
+ final int width = Math.max(0, mInstance.getMeasuredWidth()
+ - getPaddingLeftWithForeground() - getPaddingRightWithForeground()
+ - lp.leftMargin - lp.rightMargin);
+ childWidthMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+ width, View.MeasureSpec.EXACTLY);
+ } else {
+ childWidthMeasureSpec = mInstance.getChildMeasureSpec(widthMeasureSpec,
+ getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
+ lp.leftMargin + lp.rightMargin,
+ lp.width);
+ }
+
+ final int childHeightMeasureSpec;
+ if (lp.height == LayoutParams.MATCH_PARENT) {
+ final int height = Math.max(0, mInstance.getMeasuredHeight()
+ - getPaddingTopWithForeground() - getPaddingBottomWithForeground()
+ - lp.topMargin - lp.bottomMargin);
+ childHeightMeasureSpec = View.MeasureSpec.makeMeasureSpec(
+ height, View.MeasureSpec.EXACTLY);
+ } else {
+ childHeightMeasureSpec = mInstance.getChildMeasureSpec(heightMeasureSpec,
+ getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
+ lp.topMargin + lp.bottomMargin,
+ lp.height);
+ }
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+ }
+ }
+
+ @Override
+ public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+ final int count = mInstance.getChildCount();
+
+ final int parentLeft = getPaddingLeftWithForeground();
+ final int parentRight = right - left - getPaddingRightWithForeground();
+
+ final int parentTop = getPaddingTopWithForeground();
+ final int parentBottom = bottom - top - getPaddingBottomWithForeground();
+
+ for (int i = 0; i < count; i++) {
+ final View child = mInstance.getChildAt(i);
+ if (child.getVisibility() != View.GONE) {
+ final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+ final int width = child.getMeasuredWidth();
+ final int height = child.getMeasuredHeight();
+
+ int childLeft;
+ int childTop;
+
+ childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
+ lp.leftMargin - lp.rightMargin;
+
+ childTop = parentTop + (parentBottom - parentTop - height) / 2 +
+ lp.topMargin - lp.bottomMargin;
+
+ child.layout(childLeft, childTop, childLeft + width, childTop + height);
+ }
+ }
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState_impl() {
+ return false;
+ }
+
+ private int getPaddingLeftWithForeground() {
+ return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingLeft(), 0) :
+ mInstance.getPaddingLeft() + 0;
+ }
+
+ private int getPaddingRightWithForeground() {
+ return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingRight(), 0) :
+ mInstance.getPaddingRight() + 0;
+ }
+
+ private int getPaddingTopWithForeground() {
+ return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingTop(), 0) :
+ mInstance.getPaddingTop() + 0;
+ }
+
+ private int getPaddingBottomWithForeground() {
+ return mInstance.isForegroundInsidePadding() ? Math.max(mInstance.getPaddingBottom(), 0) :
+ mInstance.getPaddingBottom() + 0;
+ }
+}
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 138232e..1cdaaee 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -21,8 +21,10 @@
import android.media.session.MediaController;
import android.media.session.PlaybackState;
import android.media.update.MediaControlView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
@@ -46,11 +48,10 @@
import java.util.List;
import java.util.Locale;
-public class MediaControlView2Impl implements MediaControlView2Provider {
+public class MediaControlView2Impl extends BaseLayout implements MediaControlView2Provider {
private static final String TAG = "MediaControlView2";
private final MediaControlView2 mInstance;
- private final ViewProvider mSuperProvider;
static final String ARGUMENT_KEY_FULLSCREEN = "fullScreen";
@@ -63,7 +64,7 @@
private static final int REWIND_TIME_MS = 10000;
private static final int FORWARD_TIME_MS = 30000;
- private final AccessibilityManager mAccessibilityManager;
+ private AccessibilityManager mAccessibilityManager;
private MediaController mController;
private MediaController.TransportControls mControls;
@@ -113,10 +114,14 @@
private MediaRouteButton mRouteButton;
private MediaRouteSelector mRouteSelector;
- public MediaControlView2Impl(
- MediaControlView2 instance, ViewProvider superProvider) {
+ public MediaControlView2Impl(MediaControlView2 instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+ super(instance, superProvider, privateProvider);
mInstance = instance;
- mSuperProvider = superProvider;
+ }
+
+ @Override
+ public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mAccessibilityManager = AccessibilityManager.getInstance(mInstance.getContext());
// Inflate MediaControlView2 from XML
@@ -144,11 +149,6 @@
}
@Override
- public boolean isShowing_impl() {
- return (mInstance.getVisibility() == View.VISIBLE) ? true : false;
- }
-
- @Override
public void setButtonVisibility_impl(int button, int visibility) {
switch (button) {
case MediaControlView2.BUTTON_PLAY_PAUSE:
@@ -233,39 +233,6 @@
}
@Override
- public void onVisibilityAggregated_impl(boolean invisible) {
- int visibility = mInstance.getVisibility();
- if (mCurrentVisibility != visibility) {
- mInstance.setVisibility(visibility);
- mCurrentVisibility = visibility;
-
- if (visibility == View.VISIBLE) {
- setProgress();
- disableUnsupportedButtons();
- // cause the progress bar to be updated even if mShowing
- // was already true. This happens, for example, if we're
- // paused with the progress bar showing the user hits play.
- mInstance.post(mShowProgress);
- resetFadeOutRunnable();
- } else if (visibility == View.GONE) {
- mInstance.removeCallbacks(mShowProgress);
- // Remove existing call to mFadeOut to avoid from being called later.
- mInstance.removeCallbacks(mFadeOut);
- }
- }
- }
-
- @Override
- public void onAttachedToWindow_impl() {
- mSuperProvider.onAttachedToWindow_impl();
- }
-
- @Override
- public void onDetachedFromWindow_impl() {
- mSuperProvider.onDetachedFromWindow_impl();
- }
-
- @Override
public CharSequence getAccessibilityClassName_impl() {
return MediaControlView2.class.getName();
}
@@ -283,12 +250,9 @@
}
@Override
- public void onFinishInflate_impl() {
- mSuperProvider.onFinishInflate_impl();
- }
-
- @Override
public void setEnabled_impl(boolean enabled) {
+ super.setEnabled_impl(enabled);
+
if (mPlayPauseButton != null) {
mPlayPauseButton.setEnabled(enabled);
}
@@ -308,7 +272,31 @@
mProgress.setEnabled(enabled);
}
disableUnsupportedButtons();
- mSuperProvider.setEnabled_impl(enabled);
+ }
+
+ @Override
+ public void onVisibilityAggregated_impl(boolean invisible) {
+ super.onVisibilityAggregated_impl(invisible);
+
+ int visibility = mInstance.getVisibility();
+ if (mCurrentVisibility != visibility) {
+ mInstance.setVisibility(visibility);
+ mCurrentVisibility = visibility;
+
+ if (visibility == View.VISIBLE) {
+ setProgress();
+ disableUnsupportedButtons();
+ // cause the progress bar to be updated even if mShowing
+ // was already true. This happens, for example, if we're
+ // paused with the progress bar showing the user hits play.
+ mInstance.post(mShowProgress);
+ resetFadeOutRunnable();
+ } else if (visibility == View.GONE) {
+ mInstance.removeCallbacks(mShowProgress);
+ // Remove existing call to mFadeOut to avoid from being called later.
+ mInstance.removeCallbacks(mFadeOut);
+ }
+ }
}
public void setRouteSelector(MediaRouteSelector selector) {
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index 7218150..9f207b1 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -39,17 +39,16 @@
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.media.update.VideoView2Provider;
-import android.media.update.ViewProvider;
+import android.media.update.ViewGroupProvider;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.widget.FrameLayout.LayoutParams;
+import android.view.ViewGroup.LayoutParams;
import android.widget.MediaControlView2;
import android.widget.VideoView2;
@@ -67,12 +66,12 @@
import java.util.Map;
import java.util.concurrent.Executor;
-public class VideoView2Impl implements VideoView2Provider, VideoViewInterface.SurfaceListener {
+public class VideoView2Impl extends BaseLayout
+ implements VideoView2Provider, VideoViewInterface.SurfaceListener {
private static final String TAG = "VideoView2";
private static final boolean DEBUG = true; // STOPSHIP: Log.isLoggable(TAG, Log.DEBUG);
private final VideoView2 mInstance;
- private final ViewProvider mSuperProvider;
private static final int STATE_ERROR = -1;
private static final int STATE_IDLE = 0;
@@ -82,7 +81,7 @@
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
- private final AudioManager mAudioManager;
+ private AudioManager mAudioManager;
private AudioAttributes mAudioAttributes;
private int mAudioFocusType = AudioManager.AUDIOFOCUS_GAIN; // legacy focus gain
@@ -127,11 +126,14 @@
// Refer: https://docs.google.com/document/d/1nzAfns6i2hJ3RkaUre3QMT6wsDedJ5ONLiA_OOBFFX8/edit
private float mFallbackSpeed; // keep the original speed before 'pause' is called.
- public VideoView2Impl(VideoView2 instance, ViewProvider superProvider,
- @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public VideoView2Impl(VideoView2 instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+ super(instance, superProvider, privateProvider);
mInstance = instance;
- mSuperProvider = superProvider;
+ }
+ @Override
+ public void initialize(@Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
mVideoWidth = 0;
mVideoHeight = 0;
mSpeed = 1.0f;
@@ -150,7 +152,6 @@
mSurfaceView = new VideoSurfaceView(mInstance.getContext());
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
- params.gravity = Gravity.CENTER;
mTextureView.setLayoutParams(params);
mSurfaceView.setLayoutParams(params);
mTextureView.setSurfaceListener(this);
@@ -397,7 +398,7 @@
@Override
public void onAttachedToWindow_impl() {
- mSuperProvider.onAttachedToWindow_impl();
+ super.onAttachedToWindow_impl();
// Create MediaSession
mMediaSession = new MediaSession(mInstance.getContext(), "VideoView2MediaSession");
@@ -412,8 +413,8 @@
@Override
public void onDetachedFromWindow_impl() {
- Log.e(TAG, ".... Debugging. onDetachedFromWindow_impl()");
- mSuperProvider.onDetachedFromWindow_impl();
+ super.onDetachedFromWindow_impl();
+
mMediaSession.release();
mMediaSession = null;
mMediaController = null;
@@ -434,7 +435,8 @@
&& isInPlaybackState() && mMediaControlView != null) {
toggleMediaControlViewVisibility();
}
- return mSuperProvider.onTouchEvent_impl(ev);
+
+ return super.onTouchEvent_impl(ev);
}
@Override
@@ -443,17 +445,8 @@
&& isInPlaybackState() && mMediaControlView != null) {
toggleMediaControlViewVisibility();
}
- return mSuperProvider.onTrackballEvent_impl(ev);
- }
- @Override
- public void onFinishInflate_impl() {
- mSuperProvider.onFinishInflate_impl();
- }
-
- @Override
- public void setEnabled_impl(boolean enabled) {
- mSuperProvider.setEnabled_impl(enabled);
+ return super.onTrackballEvent_impl(ev);
}
///////////////////////////////////////////////////
@@ -700,7 +693,7 @@
}
private void toggleMediaControlViewVisibility() {
- if (mMediaControlView.isShowing()) {
+ if (mMediaControlView.getVisibility() == View.VISIBLE) {
mMediaControlView.setVisibility(View.GONE);
} else {
mMediaControlView.setVisibility(View.VISIBLE);
diff --git a/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java b/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java
new file mode 100644
index 0000000..8598bb2
--- /dev/null
+++ b/packages/MediaComponents/src/com/android/widget/ViewGroupImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.widget;
+
+import android.media.update.ViewGroupProvider;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class ViewGroupImpl implements ViewGroupProvider {
+ private final ViewGroupProvider mSuperProvider;
+
+ public ViewGroupImpl(ViewGroup instance,
+ ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
+ mSuperProvider = superProvider;
+ }
+
+ @Override
+ public void onAttachedToWindow_impl() {
+ mSuperProvider.onAttachedToWindow_impl();
+ }
+
+ @Override
+ public void onDetachedFromWindow_impl() {
+ mSuperProvider.onDetachedFromWindow_impl();
+ }
+
+ @Override
+ public CharSequence getAccessibilityClassName_impl() {
+ return mSuperProvider.getAccessibilityClassName_impl();
+ }
+
+ @Override
+ public boolean onTouchEvent_impl(MotionEvent ev) {
+ return mSuperProvider.onTouchEvent_impl(ev);
+ }
+
+ @Override
+ public boolean onTrackballEvent_impl(MotionEvent ev) {
+ return mSuperProvider.onTrackballEvent_impl(ev);
+ }
+
+ @Override
+ public void onFinishInflate_impl() {
+ mSuperProvider.onFinishInflate_impl();
+ }
+
+ @Override
+ public void setEnabled_impl(boolean enabled) {
+ mSuperProvider.setEnabled_impl(enabled);
+ }
+
+ @Override
+ public void onVisibilityAggregated_impl(boolean isVisible) {
+ mSuperProvider.onVisibilityAggregated_impl(isVisible);
+ }
+
+ @Override
+ public void onLayout_impl(boolean changed, int left, int top, int right, int bottom) {
+ mSuperProvider.onLayout_impl(changed, left, top, right, bottom);
+ }
+
+ @Override
+ public void onMeasure_impl(int widthMeasureSpec, int heightMeasureSpec) {
+ mSuperProvider.onMeasure_impl(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public int getSuggestedMinimumWidth_impl() {
+ return mSuperProvider.getSuggestedMinimumWidth_impl();
+ }
+
+ @Override
+ public int getSuggestedMinimumHeight_impl() {
+ return mSuperProvider.getSuggestedMinimumHeight_impl();
+ }
+
+ @Override
+ public void setMeasuredDimension_impl(int measuredWidth, int measuredHeight) {
+ mSuperProvider.setMeasuredDimension_impl(measuredWidth, measuredHeight);
+ }
+
+ @Override
+ public boolean checkLayoutParams_impl(ViewGroup.LayoutParams p) {
+ return mSuperProvider.checkLayoutParams_impl(p);
+ }
+
+ @Override
+ public ViewGroup.LayoutParams generateDefaultLayoutParams_impl() {
+ return mSuperProvider.generateDefaultLayoutParams_impl();
+ }
+
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams_impl(AttributeSet attrs) {
+ return mSuperProvider.generateLayoutParams_impl(attrs);
+ }
+
+ @Override
+ public ViewGroup.LayoutParams generateLayoutParams_impl(ViewGroup.LayoutParams lp) {
+ return mSuperProvider.generateLayoutParams_impl(lp);
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState_impl() {
+ return mSuperProvider.shouldDelayChildPressedState_impl();
+ }
+
+ @Override
+ public void measureChildWithMargins_impl(View child,
+ int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
+ mSuperProvider.measureChildWithMargins_impl(child,
+ parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+ }
+}
diff --git a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
index 38475a8..4cd8177 100644
--- a/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaBrowser2Test.java
@@ -128,6 +128,13 @@
}
@Override
+ public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+ if (mCallbackProxy != null) {
+ mCallbackProxy.onPlaybackInfoChanged(info);
+ }
+ }
+
+ @Override
public void onCustomCommand(Command command, Bundle args, ResultReceiver receiver) {
super.onCustomCommand(command, args, receiver);
mCallbackProxy.onCustomCommand(command, args, receiver);
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
index ff8c2b7..43a6c2c 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2Test.java
@@ -16,10 +16,16 @@
package android.media;
+import static android.media.AudioAttributes.CONTENT_TYPE_MUSIC;
+import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
-import static android.media.TestUtils.ensurePlaylistParamsModeEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import android.media.MediaPlayerInterface.PlaybackListener;
import android.media.MediaSession2.Builder;
@@ -36,19 +42,17 @@
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
-import java.util.ArrayList;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.*;
-
/**
* Tests {@link MediaSession2}.
*/
@@ -105,6 +109,48 @@
}
@Test
+ public void testSetPlayerWithVolumeProvider() throws Exception {
+ MockPlayer player = new MockPlayer(0);
+ AudioAttributes attrs = new AudioAttributes.Builder()
+ .setContentType(CONTENT_TYPE_MUSIC)
+ .build();
+ player.setAudioAttributes(attrs);
+
+ final int maxVolume = 100;
+ final int currentVolume = 23;
+ final int volumeControlType = VolumeProvider2.VOLUME_CONTROL_ABSOLUTE;
+ VolumeProvider2 volumeProvider =
+ new VolumeProvider2(mContext, volumeControlType, maxVolume, currentVolume) { };
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final TestControllerCallbackInterface callback = new TestControllerCallbackInterface() {
+ @Override
+ public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+ assertEquals(MediaController2.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+ info.getPlaybackType());
+ assertEquals(attrs, info.getAudioAttributes());
+ assertEquals(volumeControlType, info.getPlaybackType());
+ assertEquals(maxVolume, info.getMaxVolume());
+ assertEquals(currentVolume, info.getCurrentVolume());
+ latch.countDown();
+ }
+ };
+
+ final MediaController2 controller = createController(mSession.getToken(), true, callback);
+ assertNull(controller.getPlaybackInfo());
+
+ mSession.setPlayer(player, volumeProvider);
+ assertTrue(latch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+
+ MediaController2.PlaybackInfo infoOut = controller.getPlaybackInfo();
+ assertEquals(MediaController2.PlaybackInfo.PLAYBACK_TYPE_REMOTE, infoOut.getPlaybackType());
+ assertEquals(attrs, infoOut.getAudioAttributes());
+ assertEquals(volumeControlType, infoOut.getPlaybackType());
+ assertEquals(maxVolume, infoOut.getMaxVolume());
+ assertEquals(currentVolume, infoOut.getCurrentVolume());
+ }
+
+ @Test
public void testPlay() throws Exception {
sHandler.postAndSync(() -> {
mSession.play();
diff --git a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
index 5d94b17..513fa29 100644
--- a/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
+++ b/packages/MediaComponents/test/src/android/media/MediaSession2TestBase.java
@@ -63,6 +63,7 @@
// Add methods in ControllerCallback/BrowserCallback that you want to test.
default void onPlaylistChanged(List<MediaItem2> playlist) {}
default void onPlaylistParamsChanged(MediaSession2.PlaylistParams params) {}
+ default void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {}
// Currently empty. Add methods in ControllerCallback/BrowserCallback that you want to test.
default void onPlaybackStateChanged(PlaybackState2 state) { }
@@ -241,6 +242,13 @@
mCallbackProxy.onPlaylistParamsChanged(params);
}
}
+
+ @Override
+ public void onPlaybackInfoChanged(MediaController2.PlaybackInfo info) {
+ if (mCallbackProxy != null) {
+ mCallbackProxy.onPlaybackInfoChanged(info);
+ }
+ }
}
public class TestMediaController extends MediaController2 implements TestControllerInterface {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 592273e..e7140c2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1984,7 +1984,7 @@
for (size_t i = 0; i < fakeNum; i++) {
struct audio_microphone_characteristic_t characteristics;
sprintf(characteristics.device_id, "microphone:%zu", i);
- characteristics.type = fakeTypes[i];
+ characteristics.device = fakeTypes[i];
sprintf(characteristics.address, "");
characteristics.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
characteristics.group = 0;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 14d7e2e..24d862f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7051,7 +7051,7 @@
// Fake data
struct audio_microphone_characteristic_t characteristic;
sprintf(characteristic.device_id, "builtin_mic");
- characteristic.type = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ characteristic.device = AUDIO_DEVICE_IN_BUILTIN_MIC;
sprintf(characteristic.address, "");
characteristic.location = AUDIO_MICROPHONE_LOCATION_MAINBODY;
characteristic.group = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 9ba8bb7..324201b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2400,7 +2400,7 @@
Vector<camera3_stream_t*> streams;
streams.setCapacity(config.num_streams);
- std::vector<uint32_t> outBufSizes(mOutputStreams.size(), 0);
+ std::vector<uint32_t> bufferSizes(config.num_streams, 0);
if (mInputStream != NULL) {
@@ -2435,7 +2435,9 @@
if (outputStream->format == HAL_PIXEL_FORMAT_BLOB &&
outputStream->data_space == HAL_DATASPACE_V0_JFIF) {
- outBufSizes[i] = static_cast<uint32_t>(
+ size_t k = i + ((mInputStream != nullptr) ? 1 : 0); // Input stream if present should
+ // always occupy the initial entry.
+ bufferSizes[k] = static_cast<uint32_t>(
getJpegBufferSize(outputStream->width, outputStream->height));
}
}
@@ -2446,7 +2448,7 @@
// max_buffers, usage, priv fields.
const camera_metadata_t *sessionBuffer = sessionParams.getAndLock();
- res = mInterface->configureStreams(sessionBuffer, &config, outBufSizes);
+ res = mInterface->configureStreams(sessionBuffer, &config, bufferSizes);
sessionParams.unlock(sessionBuffer);
if (res == BAD_VALUE) {
@@ -3504,7 +3506,7 @@
}
status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *sessionParams,
- camera3_stream_configuration *config, const std::vector<uint32_t>& outputBufferSizes) {
+ camera3_stream_configuration *config, const std::vector<uint32_t>& bufferSizes) {
ATRACE_NAME("CameraHal::configureStreams");
if (!valid()) return INVALID_OPERATION;
status_t res = OK;
@@ -3545,7 +3547,7 @@
dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
dst3_2.rotation = mapToStreamRotation((camera3_stream_rotation_t) src->rotation);
dst3_4.v3_2 = dst3_2;
- dst3_4.bufferSize = outputBufferSizes[i];
+ dst3_4.bufferSize = bufferSizes[i];
if (src->physical_camera_id != nullptr) {
dst3_4.physicalCameraId = src->physical_camera_id;
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index ccd9d7a..12cb6b4 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -283,7 +283,7 @@
/*out*/ camera_metadata_t **requestTemplate);
status_t configureStreams(const camera_metadata_t *sessionParams,
/*inout*/ camera3_stream_configuration *config,
- const std::vector<uint32_t>& outputBufferSizes);
+ const std::vector<uint32_t>& bufferSizes);
status_t processCaptureRequest(camera3_capture_request_t *request);
status_t processBatchCaptureRequests(
std::vector<camera3_capture_request_t*>& requests,