Merge "NBLog: Restore log dump and add new logging types"
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 1dfa4f7..c1f5ddc 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -7217,11 +7217,11 @@
* camera in the list of supported camera devices.</p>
* <p>This capability requires the camera device to support the following:</p>
* <ul>
- * <li>This camera device must list the following static metadata entries in <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a>:<ul>
- * <li>android.logicalMultiCamera.physicalIds</li>
- * <li>ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE</li>
- * </ul>
- * </li>
+ * <li>The IDs of underlying physical cameras are returned via
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getPhysicalCameraIds">CameraCharacteristics#getPhysicalCameraIds</a>.</li>
+ * <li>This camera device must list static metadata
+ * ACAMERA_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE in
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a>.</li>
* <li>The underlying physical cameras' static metadata must list the following entries,
* so that the application can correlate pixels from the physical streams:<ul>
* <li>ACAMERA_LENS_POSE_REFERENCE</li>
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 73ecda1..a2594aa 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -225,8 +225,13 @@
void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
uint32_t size = data.readInt32();
- vector.insertAt((size_t)0, size);
- data.read(vector.editArray(), size);
+ if (vector.insertAt((size_t)0, size) < 0) {
+ vector.clear();
+ }
+ if (data.read(vector.editArray(), size) != NO_ERROR) {
+ vector.clear();
+ android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+ }
}
void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index e3da259..a721b65 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "FLACExtractor"
#include <utils/Log.h>
+#include <stdint.h>
+
#include "FLACExtractor.h"
// libFLAC parser
#include "FLAC/stream_decoder.h"
@@ -124,7 +126,7 @@
// media buffers
size_t mMaxBufferSize;
MediaBufferGroup *mGroup;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
// handle to underlying libFLAC parser
FLAC__StreamDecoder *mDecoder;
@@ -383,7 +385,7 @@
// These are candidates for optimization if needed.
static void copyMono8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -393,7 +395,7 @@
}
static void copyStereo8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -403,7 +405,7 @@
}
}
-static void copyMultiCh8(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh8(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -413,7 +415,7 @@
}
static void copyMono16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -423,7 +425,7 @@
}
static void copyStereo16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -433,7 +435,7 @@
}
}
-static void copyMultiCh16(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh16(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -445,7 +447,7 @@
// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -455,7 +457,7 @@
}
static void copyStereo24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -465,7 +467,7 @@
}
}
-static void copyMultiCh24(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh24(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -475,7 +477,7 @@
}
static void copyTrespass(
- short * /* dst */,
+ int16_t * /* dst */,
const int *[FLACParser::kMaxChannels] /* src */,
unsigned /* nSamples */,
unsigned /* nChannels */) {
@@ -592,7 +594,7 @@
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
{ 2, 8, copyStereo8 },
@@ -635,7 +637,7 @@
{
CHECK(mGroup == NULL);
mGroup = new MediaBufferGroup;
- mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
+ mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(int16_t);
mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
@@ -688,9 +690,9 @@
if (err != OK) {
return NULL;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(short);
+ size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
CHECK(bufferSize <= mMaxBufferSize);
- short *data = (short *) buffer->data();
+ int16_t *data = (int16_t *) buffer->data();
buffer->set_range(0, bufferSize);
// copy PCM from FLAC write buffer to our media buffer, with interleaving
(*mCopy)(data, mWriteBuffer, blocksize, getChannels());
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index fe9f99c..251a4cd 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -68,6 +68,7 @@
};
class MPEG4Source : public MediaTrack {
+static const size_t kMaxPcmFrameSize = 8192;
public:
// Caller retains ownership of both "dataSource" and "sampleTable".
MPEG4Source(MetaDataBase &format,
@@ -127,7 +128,7 @@
bool mIsAVC;
bool mIsHEVC;
bool mIsAC4;
-
+ bool mIsPcm;
size_t mNALLengthSize;
bool mStarted;
@@ -332,6 +333,11 @@
return MEDIA_MIMETYPE_VIDEO_HEVC;
case FOURCC('a', 'c', '-', '4'):
return MEDIA_MIMETYPE_AUDIO_AC4;
+
+ case FOURCC('t', 'w', 'o', 's'):
+ case FOURCC('s', 'o', 'w', 't'):
+ return MEDIA_MIMETYPE_AUDIO_RAW;
+
default:
ALOGW("Unknown fourcc: %c%c%c%c",
(fourcc >> 24) & 0xff,
@@ -475,8 +481,15 @@
if (__builtin_mul_overflow(media_time, samplerate, &delay) ||
__builtin_add_overflow(delay, halfscale, &delay) ||
(delay /= mHeaderTimescale, false) ||
- delay > INT32_MAX ||
- delay < INT32_MIN) {
+ /* the calculated delay should be small, but some apps
+ * appear to write a bogus edit list that causes a really
+ * large delay, resulting in playback problems.
+ * Ignore such edit lists.
+ * (4096 is enough to drop 4 full samples)
+ */
+ delay > 4096 ||
+ delay < 0) {
+ ALOGW("ignoring edit list with bogus values");
return;
}
ALOGV("delay = %" PRId64, delay);
@@ -1481,6 +1494,8 @@
case FOURCC('e', 'n', 'c', 'a'):
case FOURCC('s', 'a', 'm', 'r'):
case FOURCC('s', 'a', 'w', 'b'):
+ case FOURCC('t', 'w', 'o', 's'):
+ case FOURCC('s', 'o', 'w', 't'):
{
if (mIsQT && chunk_type == FOURCC('m', 'p', '4', 'a')
&& depth >= 1 && mPath[depth - 1] == FOURCC('w', 'a', 'v', 'e')) {
@@ -1550,6 +1565,13 @@
// if the chunk type is enca, we'll get the type from the frma box later
mLastTrack->meta.setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
+
+ if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, FourCC2MIME(chunk_type))) {
+ mLastTrack->meta.setInt32(kKeyBitsPerSample, sample_size);
+ if (chunk_type == FOURCC('t', 'w', 'o', 's')) {
+ mLastTrack->meta.setInt32(kKeyPcmBigEndian, 1);
+ }
+ }
}
ALOGV("*** coding='%s' %d channels, size %d, rate %d\n",
chunk, num_channels, sample_size, sample_rate);
@@ -4099,6 +4121,7 @@
mIsAVC(false),
mIsHEVC(false),
mIsAC4(false),
+ mIsPcm(false),
mNALLengthSize(0),
mStarted(false),
mGroup(NULL),
@@ -4161,6 +4184,27 @@
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
}
+ mIsPcm = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW);
+
+ if (mIsPcm) {
+ int32_t numChannels = 0;
+ int32_t bitsPerSample = 0;
+ CHECK(mFormat.findInt32(kKeyBitsPerSample, &bitsPerSample));
+ CHECK(mFormat.findInt32(kKeyChannelCount, &numChannels));
+
+ int32_t bytesPerSample = bitsPerSample >> 3;
+ int32_t pcmSampleSize = bytesPerSample * numChannels;
+
+ size_t maxSampleSize;
+ status_t err = mSampleTable->getMaxSampleSize(&maxSampleSize);
+ if (err != OK || maxSampleSize != static_cast<size_t>(pcmSampleSize) || bitsPerSample != 16) {
+ // Not supported
+ mIsPcm = false;
+ } else {
+ mFormat.setInt32(kKeyMaxInputSize, pcmSampleSize * kMaxPcmFrameSize);
+ }
+ }
+
CHECK(format.findInt32(kKeyTrackID, &mTrackId));
}
@@ -5075,34 +5119,78 @@
if ((!mIsAVC && !mIsHEVC && !mIsAC4) || mWantsNALFragments) {
if (newBuffer) {
- ssize_t num_bytes_read =
- mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
+ if (mIsPcm) {
+ // The twos' PCM block reader assumes that all samples has the same size.
- if (num_bytes_read < (ssize_t)size) {
- mBuffer->release();
- mBuffer = NULL;
+ uint32_t samplesToRead = mSampleTable->getLastSampleIndexInChunk()
+ - mCurrentSampleIndex + 1;
+ if (samplesToRead > kMaxPcmFrameSize) {
+ samplesToRead = kMaxPcmFrameSize;
+ }
- return ERROR_IO;
- }
+ ALOGV("Reading %d PCM frames of size %zu at index %d to stop of chunk at %d",
+ samplesToRead, size, mCurrentSampleIndex,
+ mSampleTable->getLastSampleIndexInChunk());
- CHECK(mBuffer != NULL);
- mBuffer->set_range(0, size);
- mBuffer->meta_data().clear();
- mBuffer->meta_data().setInt64(
- kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
- mBuffer->meta_data().setInt64(
- kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+ size_t totalSize = samplesToRead * size;
+ uint8_t* buf = (uint8_t *)mBuffer->data();
+ ssize_t bytesRead = mDataSource->readAt(offset, buf, totalSize);
+ if (bytesRead < (ssize_t)totalSize) {
+ mBuffer->release();
+ mBuffer = NULL;
- if (targetSampleTimeUs >= 0) {
- mBuffer->meta_data().setInt64(
- kKeyTargetTime, targetSampleTimeUs);
- }
+ return ERROR_IO;
+ }
- if (isSyncSample) {
+ mBuffer->meta_data().clear();
+ mBuffer->meta_data().setInt64(kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
- }
- ++mCurrentSampleIndex;
+ int32_t byteOrder;
+ mFormat.findInt32(kKeyPcmBigEndian, &byteOrder);
+
+ if (byteOrder == 1) {
+ // Big-endian -> little-endian
+ uint16_t *dstData = (uint16_t *)buf;
+ uint16_t *srcData = (uint16_t *)buf;
+
+ for (size_t j = 0; j < bytesRead / sizeof(uint16_t); j++) {
+ dstData[j] = ntohs(srcData[j]);
+ }
+ }
+
+ mCurrentSampleIndex += samplesToRead;
+ mBuffer->set_range(0, totalSize);
+ } else {
+ ssize_t num_bytes_read =
+ mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
+
+ if (num_bytes_read < (ssize_t)size) {
+ mBuffer->release();
+ mBuffer = NULL;
+
+ return ERROR_IO;
+ }
+
+ CHECK(mBuffer != NULL);
+ mBuffer->set_range(0, size);
+ mBuffer->meta_data().clear();
+ mBuffer->meta_data().setInt64(
+ kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+ mBuffer->meta_data().setInt64(
+ kKeyDuration, ((int64_t)stts * 1000000) / mTimescale);
+
+ if (targetSampleTimeUs >= 0) {
+ mBuffer->meta_data().setInt64(
+ kKeyTargetTime, targetSampleTimeUs);
+ }
+
+ if (isSyncSample) {
+ mBuffer->meta_data().setInt32(kKeyIsSyncFrame, 1);
+ }
+
+ ++mCurrentSampleIndex;
+ }
}
if (!mIsAVC && !mIsHEVC && !mIsAC4) {
diff --git a/media/extractors/mp4/SampleIterator.h b/media/extractors/mp4/SampleIterator.h
index 6a3fd3b..6e4f60e 100644
--- a/media/extractors/mp4/SampleIterator.h
+++ b/media/extractors/mp4/SampleIterator.h
@@ -36,6 +36,11 @@
uint32_t getSampleTime() const { return mCurrentSampleTime; }
uint32_t getSampleDuration() const { return mCurrentSampleDuration; }
+ uint32_t getLastSampleIndexInChunk() const {
+ return mCurrentSampleIndex + mSamplesPerChunk -
+ ((mCurrentSampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk) - 1;
+ }
+
status_t getSampleSizeDirect(
uint32_t sampleIndex, size_t *size);
diff --git a/media/extractors/mp4/SampleTable.cpp b/media/extractors/mp4/SampleTable.cpp
index 81c353e..28fe717 100644
--- a/media/extractors/mp4/SampleTable.cpp
+++ b/media/extractors/mp4/SampleTable.cpp
@@ -946,6 +946,11 @@
sampleIndex, sampleSize);
}
+uint32_t SampleTable::getLastSampleIndexInChunk() {
+ Mutex::Autolock autoLock(mLock);
+ return mSampleIterator->getLastSampleIndexInChunk();
+}
+
status_t SampleTable::getMetaDataForSample(
uint32_t sampleIndex,
off64_t *offset,
diff --git a/media/extractors/mp4/SampleTable.h b/media/extractors/mp4/SampleTable.h
index e4e974b..dd68860 100644
--- a/media/extractors/mp4/SampleTable.h
+++ b/media/extractors/mp4/SampleTable.h
@@ -69,6 +69,9 @@
bool *isSyncSample = NULL,
uint32_t *sampleDuration = NULL);
+ // call only after getMetaDataForSample has been called successfully.
+ uint32_t getLastSampleIndexInChunk();
+
enum {
kFlagBefore,
kFlagAfter,
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index 0641b6e..da7d85e 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -52,6 +52,7 @@
)
: mStatus(NO_INIT), mOpPackageName(opPackageName)
{
+ AutoMutex lock(mConstructLock);
mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
}
@@ -85,6 +86,7 @@
}
}
+ AutoMutex lock(mConstructLock);
mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
}
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index c97f783..58a9baa 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -494,6 +494,7 @@
effect_descriptor_t mDescriptor; // effect descriptor
int32_t mId; // system wide unique effect engine instance ID
Mutex mLock; // Mutex for mEnabled access
+ Mutex mConstructLock; // Mutex for integrality construction
String16 mOpPackageName; // The package name used for app op checks.
@@ -520,12 +521,22 @@
virtual void controlStatusChanged(bool controlGranted) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->controlStatusChanged(controlGranted);
}
}
virtual void enableStatusChanged(bool enabled) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->enableStatusChanged(enabled);
}
}
@@ -536,6 +547,11 @@
void *pReplyData) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->commandExecuted(
cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
@@ -545,6 +561,11 @@
virtual void binderDied(const wp<IBinder>& /*who*/) {
sp<AudioEffect> effect = mEffect.promote();
if (effect != 0) {
+ {
+ // Got the mConstructLock means the construction of AudioEffect
+ // has finished, we should release the mConstructLock immediately.
+ AutoMutex lock(effect->mConstructLock);
+ }
effect->binderDied();
}
}
diff --git a/media/libaudioprocessing/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
index 055f724..50ca33d 100644
--- a/media/libaudioprocessing/include/media/AudioResamplerPublic.h
+++ b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
@@ -104,8 +104,8 @@
const AudioPlaybackRate &pr2) {
return fabs(pr1.mSpeed - pr2.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
fabs(pr1.mPitch - pr2.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA &&
- pr2.mStretchMode == pr2.mStretchMode &&
- pr2.mFallbackMode == pr2.mFallbackMode;
+ pr1.mStretchMode == pr2.mStretchMode &&
+ pr1.mFallbackMode == pr2.mFallbackMode;
}
static inline bool isAudioPlaybackRateValid(const AudioPlaybackRate &playbackRate) {
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index dfe34e8..2e9aede 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -53,6 +53,7 @@
kKeyFrameRate = 'frmR', // int32_t (video frame rate fps)
kKeyBitRate = 'brte', // int32_t (bps)
kKeyMaxBitRate = 'mxBr', // int32_t (bps)
+ kKeyBitsPerSample = 'bits', // int32_t (bits per sample)
kKeyStreamHeader = 'stHd', // raw data
kKeyESDS = 'esds', // raw data
kKeyAACProfile = 'aacp', // int32_t
@@ -225,6 +226,7 @@
kKeyExifOffset = 'exof', // int64_t, Exif data offset
kKeyExifSize = 'exsz', // int64_t, Exif data size
kKeyIsExif = 'exif', // bool (int32_t) buffer contains exif data block
+ kKeyPcmBigEndian = 'pcmb', // bool (int32_t)
};
enum {
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index bc84729..211a5c0 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -107,6 +107,9 @@
// The player just completed the playback of all data sources.
// But this is not visible in native code. Just keep this entry for completeness.
MEDIA2_INFO_DATA_SOURCE_LIST_END = 6,
+ // The player just completed an iteration of playback loop. This event is sent only when
+ // looping is enabled.
+ MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
//1xx
// The player just prepared a data source.
diff --git a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
index 196b103..a6d88a2 100644
--- a/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
+++ b/media/libmediaplayer2/nuplayer2/GenericSource2.cpp
@@ -34,7 +34,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
+#include <media/stagefright/ClearDataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
@@ -368,7 +368,7 @@
String8 contentType;
if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
- mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService);
+ mHttpSource = ClearDataSourceFactory::CreateMediaHTTP(mHTTPService);
if (mHttpSource == NULL) {
ALOGE("Failed to create http source!");
notifyPreparedAndCleanup(UNKNOWN_ERROR);
@@ -378,7 +378,7 @@
mLock.unlock();
// This might take long time if connection has some issue.
- sp<DataSource> dataSource = DataSourceFactory::CreateFromURI(
+ sp<DataSource> dataSource = ClearDataSourceFactory::CreateFromURI(
mHTTPService, uri, &mUriHeaders, &contentType,
static_cast<HTTPBase *>(mHttpSource.get()));
mLock.lock();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 03d17a5..3069f54 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -930,7 +930,12 @@
// the last little bit of audio. In looping mode, we need to restart it.
mAudioSink->start();
}
- // don't send completion event when looping
+
+ sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
+ notify->setInt64("srcId", srcId);
+ notify->setInt32("messageId", MEDIA2_INFO);
+ notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
+ notify->post();
return;
}
if (property_get_bool("persist.debug.sf.stats", false)) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index bde0862..8d876da 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -239,8 +239,14 @@
size_t *encryptedbytes)
{
// size needed to store all the crypto data
- size_t cryptosize = sizeof(CryptoInfo) +
- sizeof(CryptoPlugin::SubSample) * numSubSamples;
+ size_t cryptosize;
+ // sizeof(CryptoInfo) + sizeof(CryptoPlugin::SubSample) * numSubSamples;
+ if (__builtin_mul_overflow(sizeof(CryptoPlugin::SubSample), numSubSamples, &cryptosize) ||
+ __builtin_add_overflow(cryptosize, sizeof(CryptoInfo), &cryptosize)) {
+ ALOGE("crypto size overflow");
+ return NULL;
+ }
+
CryptoInfo *ret = (CryptoInfo*) malloc(cryptosize);
if (ret == NULL) {
ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 48e351b..27383cb 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -105,6 +105,7 @@
"DataConverter.cpp",
"DataSourceFactory.cpp",
"DataURISource.cpp",
+ "ClearFileSource.cpp",
"FileSource.cpp",
"FrameDecoder.cpp",
"HTTPBase.cpp",
@@ -121,6 +122,7 @@
"MediaCodecSource.cpp",
"MediaExtractorFactory.cpp",
"MediaSync.cpp",
+ "http/ClearMediaHTTP.cpp",
"http/MediaHTTP.cpp",
"MediaMuxer.cpp",
"NuCachedSource2.cpp",
@@ -232,9 +234,9 @@
srcs: [
"CallbackDataSource.cpp",
"CallbackMediaSource.cpp",
- "DataSourceFactory.cpp",
+ "ClearDataSourceFactory.cpp",
+ "ClearFileSource.cpp",
"DataURISource.cpp",
- "FileSource.cpp",
"HTTPBase.cpp",
"HevcUtils.cpp",
"InterfaceUtils.cpp",
@@ -246,13 +248,12 @@
"RemoteMediaSource.cpp",
"Utils.cpp",
"VideoFrameScheduler.cpp",
- "http/MediaHTTP.cpp",
+ "http/ClearMediaHTTP.cpp",
],
shared_libs: [
"libbinder",
"libcutils",
- "libdrmframework",
"libgui",
"liblog",
"libmedia_player2_util",
diff --git a/media/libstagefright/ClearDataSourceFactory.cpp b/media/libstagefright/ClearDataSourceFactory.cpp
new file mode 100644
index 0000000..5d23fda
--- /dev/null
+++ b/media/libstagefright/ClearDataSourceFactory.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "ClearDataSourceFactory"
+
+#include "include/HTTPBase.h"
+#include "include/NuCachedSource2.h"
+
+#include <media/MediaHTTPConnection.h>
+#include <media/MediaHTTPService.h>
+#include <media/stagefright/ClearFileSource.h>
+#include <media/stagefright/ClearMediaHTTP.h>
+#include <media/stagefright/ClearDataSourceFactory.h>
+#include <media/stagefright/DataURISource.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// static
+sp<DataSource> ClearDataSourceFactory::CreateFromURI(
+ const sp<MediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ String8 *contentType,
+ HTTPBase *httpSource) {
+ if (contentType != NULL) {
+ *contentType = "";
+ }
+
+ sp<DataSource> source;
+ if (!strncasecmp("file://", uri, 7)) {
+ source = new ClearFileSource(uri + 7);
+ } else if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) {
+ if (httpService == NULL) {
+ ALOGE("Invalid http service!");
+ return NULL;
+ }
+
+ if (httpSource == NULL) {
+ sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ ALOGE("Failed to make http connection from http service!");
+ return NULL;
+ }
+ httpSource = new ClearMediaHTTP(conn);
+ }
+
+ String8 cacheConfig;
+ bool disconnectAtHighwatermark = false;
+ KeyedVector<String8, String8> nonCacheSpecificHeaders;
+ if (headers != NULL) {
+ nonCacheSpecificHeaders = *headers;
+ NuCachedSource2::RemoveCacheSpecificHeaders(
+ &nonCacheSpecificHeaders,
+ &cacheConfig,
+ &disconnectAtHighwatermark);
+ }
+
+ if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
+ ALOGE("Failed to connect http source!");
+ return NULL;
+ }
+
+ if (contentType != NULL) {
+ *contentType = httpSource->getMIMEType();
+ }
+
+ source = NuCachedSource2::Create(
+ httpSource,
+ cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+ disconnectAtHighwatermark);
+ } else if (!strncasecmp("data:", uri, 5)) {
+ source = DataURISource::Create(uri);
+ } else {
+ // Assume it's a filename.
+ source = new ClearFileSource(uri);
+ }
+
+ if (source == NULL || source->initCheck() != OK) {
+ return NULL;
+ }
+
+ return source;
+}
+
+sp<DataSource> ClearDataSourceFactory::CreateFromFd(int fd, int64_t offset, int64_t length) {
+ sp<ClearFileSource> source = new ClearFileSource(fd, offset, length);
+ return source->initCheck() != OK ? nullptr : source;
+}
+
+sp<DataSource> ClearDataSourceFactory::CreateMediaHTTP(const sp<MediaHTTPService> &httpService) {
+ if (httpService == NULL) {
+ return NULL;
+ }
+
+ sp<MediaHTTPConnection> conn = httpService->makeHTTPConnection();
+ if (conn == NULL) {
+ return NULL;
+ } else {
+ return new ClearMediaHTTP(conn);
+ }
+}
+
+} // namespace android
diff --git a/media/libstagefright/ClearFileSource.cpp b/media/libstagefright/ClearFileSource.cpp
new file mode 100644
index 0000000..e3a2cb7
--- /dev/null
+++ b/media/libstagefright/ClearFileSource.cpp
@@ -0,0 +1,143 @@
+/*
+ * 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 "ClearFileSource"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ClearFileSource.h>
+#include <media/stagefright/Utils.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+ClearFileSource::ClearFileSource(const char *filename)
+ : mFd(-1),
+ mOffset(0),
+ mLength(-1),
+ mName("<null>") {
+
+ if (filename) {
+ mName = String8::format("FileSource(%s)", filename);
+ }
+ ALOGV("%s", filename);
+ mFd = open(filename, O_LARGEFILE | O_RDONLY);
+
+ if (mFd >= 0) {
+ mLength = lseek64(mFd, 0, SEEK_END);
+ } else {
+ ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
+ }
+}
+
+ClearFileSource::ClearFileSource(int fd, int64_t offset, int64_t length)
+ : mFd(fd),
+ mOffset(offset),
+ mLength(length),
+ mName("<null>") {
+ ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
+ if (mOffset < 0) {
+ mOffset = 0;
+ }
+ if (mLength < 0) {
+ mLength = 0;
+ }
+ if (mLength > INT64_MAX - mOffset) {
+ mLength = INT64_MAX - mOffset;
+ }
+ struct stat s;
+ if (fstat(fd, &s) == 0) {
+ if (mOffset > s.st_size) {
+ mOffset = s.st_size;
+ mLength = 0;
+ }
+ if (mOffset + mLength > s.st_size) {
+ mLength = s.st_size - mOffset;
+ }
+ }
+ if (mOffset != offset || mLength != length) {
+ ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
+ (long long) offset, (long long) length,
+ (long long) mOffset, (long long) mLength);
+ }
+
+ mName = String8::format(
+ "FileSource(fd(%s), %lld, %lld)",
+ nameForFd(fd).c_str(),
+ (long long) mOffset,
+ (long long) mLength);
+
+}
+
+ClearFileSource::~ClearFileSource() {
+ if (mFd >= 0) {
+ ::close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t ClearFileSource::initCheck() const {
+ return mFd >= 0 ? OK : NO_INIT;
+}
+
+ssize_t ClearFileSource::readAt(off64_t offset, void *data, size_t size) {
+ if (mFd < 0) {
+ return NO_INIT;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+ if (mLength >= 0) {
+ if (offset >= mLength) {
+ return 0; // read beyond EOF.
+ }
+ uint64_t numAvailable = mLength - offset;
+ if ((uint64_t)size > numAvailable) {
+ size = numAvailable;
+ }
+ }
+ return readAt_l(offset, data, size);
+}
+
+ssize_t ClearFileSource::readAt_l(off64_t offset, void *data, size_t size) {
+ off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
+ if (result == -1) {
+ ALOGE("seek to %lld failed", (long long)(offset + mOffset));
+ return UNKNOWN_ERROR;
+ }
+
+ return ::read(mFd, data, size);
+}
+
+status_t ClearFileSource::getSize(off64_t *size) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mFd < 0) {
+ return NO_INIT;
+ }
+
+ *size = mLength;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index eef5314..aee7fd8 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -22,90 +22,28 @@
#include <media/stagefright/FileSource.h>
#include <media/stagefright/Utils.h>
#include <private/android_filesystem_config.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
namespace android {
FileSource::FileSource(const char *filename)
- : mFd(-1),
- mOffset(0),
- mLength(-1),
- mName("<null>"),
+ : ClearFileSource(filename),
mDecryptHandle(NULL),
mDrmManagerClient(NULL),
mDrmBufOffset(0),
mDrmBufSize(0),
mDrmBuf(NULL){
-
- if (filename) {
- mName = String8::format("FileSource(%s)", filename);
- }
- ALOGV("%s", filename);
- mFd = open(filename, O_LARGEFILE | O_RDONLY);
-
- if (mFd >= 0) {
- mLength = lseek64(mFd, 0, SEEK_END);
- } else {
- ALOGE("Failed to open file '%s'. (%s)", filename, strerror(errno));
- }
}
FileSource::FileSource(int fd, int64_t offset, int64_t length)
- : mFd(fd),
- mOffset(offset),
- mLength(length),
- mName("<null>"),
+ : ClearFileSource(fd, offset, length),
mDecryptHandle(NULL),
mDrmManagerClient(NULL),
mDrmBufOffset(0),
mDrmBufSize(0),
mDrmBuf(NULL) {
- ALOGV("fd=%d (%s), offset=%lld, length=%lld",
- fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
-
- if (mOffset < 0) {
- mOffset = 0;
- }
- if (mLength < 0) {
- mLength = 0;
- }
- if (mLength > INT64_MAX - mOffset) {
- mLength = INT64_MAX - mOffset;
- }
- struct stat s;
- if (fstat(fd, &s) == 0) {
- if (mOffset > s.st_size) {
- mOffset = s.st_size;
- mLength = 0;
- }
- if (mOffset + mLength > s.st_size) {
- mLength = s.st_size - mOffset;
- }
- }
- if (mOffset != offset || mLength != length) {
- ALOGW("offset/length adjusted from %lld/%lld to %lld/%lld",
- (long long) offset, (long long) length,
- (long long) mOffset, (long long) mLength);
- }
-
- mName = String8::format(
- "FileSource(fd(%s), %lld, %lld)",
- nameForFd(fd).c_str(),
- (long long) mOffset,
- (long long) mLength);
-
}
FileSource::~FileSource() {
- if (mFd >= 0) {
- ::close(mFd);
- mFd = -1;
- }
-
if (mDrmBuf != NULL) {
delete[] mDrmBuf;
mDrmBuf = NULL;
@@ -124,10 +62,6 @@
}
}
-status_t FileSource::initCheck() const {
- return mFd >= 0 ? OK : NO_INIT;
-}
-
ssize_t FileSource::readAt(off64_t offset, void *data, size_t size) {
if (mFd < 0) {
return NO_INIT;
@@ -147,30 +81,12 @@
if (mDecryptHandle != NULL && DecryptApiType::CONTAINER_BASED
== mDecryptHandle->decryptApiType) {
- return readAtDRM(offset, data, size);
+ return readAtDRM_l(offset, data, size);
} else {
- off64_t result = lseek64(mFd, offset + mOffset, SEEK_SET);
- if (result == -1) {
- ALOGE("seek to %lld failed", (long long)(offset + mOffset));
- return UNKNOWN_ERROR;
- }
-
- return ::read(mFd, data, size);
+ return readAt_l(offset, data, size);
}
}
-status_t FileSource::getSize(off64_t *size) {
- Mutex::Autolock autoLock(mLock);
-
- if (mFd < 0) {
- return NO_INIT;
- }
-
- *size = mLength;
-
- return OK;
-}
-
sp<DecryptHandle> FileSource::DrmInitialization(const char *mime) {
if (getuid() == AID_MEDIA_EX) return nullptr; // no DRM in media extractor
if (mDrmManagerClient == NULL) {
@@ -194,7 +110,7 @@
return mDecryptHandle;
}
-ssize_t FileSource::readAtDRM(off64_t offset, void *data, size_t size) {
+ssize_t FileSource::readAtDRM_l(off64_t offset, void *data, size_t size) {
size_t DRM_CACHE_SIZE = 1024;
if (mDrmBuf == NULL) {
mDrmBuf = new unsigned char[DRM_CACHE_SIZE];
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
index 75ca846..9c0fcfa 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
@@ -186,8 +186,8 @@
#ifdef DEC_INTERNAL_MEMORY_OPT
video->vol[idx] = IMEM_vol[idx];
video->memoryUsage += sizeof(Vol);
- oscl_memset(video->vol[idx], 0, sizeof(Vol));
if (video->vol[idx] == NULL) status = PV_FALSE;
+ else oscl_memset(video->vol[idx], 0, sizeof(Vol));
stream = IMEM_BitstreamDecVideo;
#else
video->vol[idx] = (Vol *) oscl_malloc(sizeof(Vol));
@@ -213,6 +213,7 @@
else
{
int32 buffer_size;
+ oscl_memset(stream, 0, sizeof(BitstreamDecVideo));
if ((buffer_size = BitstreamOpen(stream, idx)) < 0)
{
mp4dec_log("InitVideoDecoder(): Can't allocate bitstream buffer.\n");
@@ -339,27 +340,33 @@
#ifdef DEC_INTERNAL_MEMORY_OPT
video->currVop->yChan = IMEM_currVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
- video->currVop->uChan = video->currVop->yChan + size;
- video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ else {
+ video->currVop->uChan = video->currVop->yChan + size;
+ video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ }
video->prevVop->yChan = IMEM_prevVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
- video->prevVop->uChan = video->prevVop->yChan + size;
- video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ else {
+ video->prevVop->uChan = video->prevVop->yChan + size;
+ video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ }
#else
if (size > INT32_MAX / 3) {
return PV_FALSE;
}
video->currVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
-
- video->currVop->uChan = video->currVop->yChan + size;
- video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ else {
+ video->currVop->uChan = video->currVop->yChan + size;
+ video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ }
video->prevVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
-
- video->prevVop->uChan = video->prevVop->yChan + size;
- video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ else {
+ video->prevVop->uChan = video->prevVop->yChan + size;
+ video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ }
#endif
video->memoryUsage += (size * 3);
#endif // MEMORY_POOL
@@ -383,8 +390,10 @@
video->prevEnhcVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevEnhcVop->yChan == NULL) status = PV_FALSE;
- video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
- video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+ else {
+ video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
+ video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+ }
video->memoryUsage += (3 * size / 2);
#endif
}
@@ -431,10 +440,12 @@
#else
video->sliceNo = (uint8 *) oscl_malloc(nTotalMB);
if (video->sliceNo == NULL) status = PV_FALSE;
+ else oscl_memset(video->sliceNo, 0, nTotalMB);
video->memoryUsage += nTotalMB;
video->acPredFlag = (uint8 *) oscl_malloc(nTotalMB * sizeof(uint8));
if (video->acPredFlag == NULL) status = PV_FALSE;
+ else oscl_memset(video->acPredFlag, 0, nTotalMB * sizeof(uint8));
video->memoryUsage += (nTotalMB);
if ((size_t)nTotalMB > SIZE_MAX / sizeof(typeDCStore)) {
@@ -442,6 +453,7 @@
}
video->predDC = (typeDCStore *) oscl_malloc(nTotalMB * sizeof(typeDCStore));
if (video->predDC == NULL) status = PV_FALSE;
+ else oscl_memset(video->predDC, 0, nTotalMB * sizeof(typeDCStore));
video->memoryUsage += (nTotalMB * sizeof(typeDCStore));
if (nMBPerRow > INT32_MAX - 1
@@ -450,6 +462,7 @@
}
video->predDCAC_col = (typeDCACStore *) oscl_malloc((nMBPerRow + 1) * sizeof(typeDCACStore));
if (video->predDCAC_col == NULL) status = PV_FALSE;
+ else oscl_memset(video->predDCAC_col, 0, (nMBPerRow + 1) * sizeof(typeDCACStore));
video->memoryUsage += ((nMBPerRow + 1) * sizeof(typeDCACStore));
/* element zero will be used for storing vertical (col) AC coefficients */
@@ -459,9 +472,11 @@
/* Allocating HeaderInfo structure & Quantizer array */
video->headerInfo.Mode = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.Mode == NULL) status = PV_FALSE;
+ else oscl_memset(video->headerInfo.Mode, 0, nTotalMB);
video->memoryUsage += nTotalMB;
video->headerInfo.CBP = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.CBP == NULL) status = PV_FALSE;
+ else oscl_memset (video->headerInfo.CBP, 0, nTotalMB);
video->memoryUsage += nTotalMB;
if ((size_t)nTotalMB > SIZE_MAX / sizeof(int16)) {
@@ -469,6 +484,7 @@
}
video->QPMB = (int16 *) oscl_malloc(nTotalMB * sizeof(int16));
if (video->QPMB == NULL) status = PV_FALSE;
+ else memset(video->QPMB, 0x0, nTotalMB * sizeof(int16));
video->memoryUsage += (nTotalMB * sizeof(int));
/* Allocating macroblock space */
@@ -489,8 +505,10 @@
}
video->motX = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motX == NULL) status = PV_FALSE;
+ else memset(video->motX, 0, sizeof(MOT) * 4 * nTotalMB);
video->motY = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motY == NULL) status = PV_FALSE;
+ else memset(video->motY, 0, sizeof(MOT) * 4 * nTotalMB);
video->memoryUsage += (sizeof(MOT) * 8 * nTotalMB);
#endif
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 2364684..cd984f0 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -114,7 +114,7 @@
mConfig->crcEnabled = false;
uint32_t memRequirements = pvmp3_decoderMemRequirements();
- mDecoderBuf = malloc(memRequirements);
+ mDecoderBuf = calloc(1, memRequirements);
pvmp3_InitDecoder(mConfig, mDecoderBuf);
mIsFirst = true;
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libstagefright/http/ClearMediaHTTP.cpp
new file mode 100644
index 0000000..bfbad1e
--- /dev/null
+++ b/media/libstagefright/http/ClearMediaHTTP.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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 "ClearMediaHTTP"
+#include <utils/Log.h>
+
+#include <media/stagefright/ClearMediaHTTP.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/MediaHTTPConnection.h>
+
+namespace android {
+
+ClearMediaHTTP::ClearMediaHTTP(const sp<MediaHTTPConnection> &conn)
+ : mInitCheck((conn != NULL) ? OK : NO_INIT),
+ mHTTPConnection(conn),
+ mCachedSizeValid(false),
+ mCachedSize(0ll) {
+}
+
+ClearMediaHTTP::~ClearMediaHTTP() {
+}
+
+status_t ClearMediaHTTP::connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t /* offset */) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ KeyedVector<String8, String8> extHeaders;
+ if (headers != NULL) {
+ extHeaders = *headers;
+ }
+
+ if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
+ extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
+ }
+
+ mLastURI = uri;
+ // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
+ // as part of the above assignment. Ensure no accidental later use.
+ uri = NULL;
+
+ bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
+
+ mLastHeaders = extHeaders;
+
+ mCachedSizeValid = false;
+
+ if (success) {
+ AString sanitized = uriDebugString(mLastURI);
+ mName = String8::format("ClearMediaHTTP(%s)", sanitized.c_str());
+ }
+
+ return success ? OK : UNKNOWN_ERROR;
+}
+
+void ClearMediaHTTP::disconnect() {
+ mName = String8("ClearMediaHTTP(<disconnected>)");
+ if (mInitCheck != OK) {
+ return;
+ }
+
+ mHTTPConnection->disconnect();
+}
+
+status_t ClearMediaHTTP::initCheck() const {
+ return mInitCheck;
+}
+
+ssize_t ClearMediaHTTP::readAt(off64_t offset, void *data, size_t size) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ int64_t startTimeUs = ALooper::GetNowUs();
+
+ size_t numBytesRead = 0;
+ while (numBytesRead < size) {
+ size_t copy = size - numBytesRead;
+
+ if (copy > 64 * 1024) {
+ // limit the buffer sizes transferred across binder boundaries
+ // to avoid spurious transaction failures.
+ copy = 64 * 1024;
+ }
+
+ ssize_t n = mHTTPConnection->readAt(
+ offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
+
+ if (n < 0) {
+ return n;
+ } else if (n == 0) {
+ break;
+ }
+
+ numBytesRead += n;
+ }
+
+ int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
+
+ addBandwidthMeasurement(numBytesRead, delayUs);
+
+ return numBytesRead;
+}
+
+status_t ClearMediaHTTP::getSize(off64_t *size) {
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ // Caching the returned size so that it stays valid even after a
+ // disconnect. NuCachedSource2 relies on this.
+
+ if (!mCachedSizeValid) {
+ mCachedSize = mHTTPConnection->getSize();
+ mCachedSizeValid = true;
+ }
+
+ *size = mCachedSize;
+
+ return *size < 0 ? *size : static_cast<status_t>(OK);
+}
+
+uint32_t ClearMediaHTTP::flags() {
+ return kWantsPrefetching | kIsHTTPBasedSource;
+}
+
+status_t ClearMediaHTTP::reconnectAtOffset(off64_t offset) {
+ return connect(mLastURI.c_str(), &mLastHeaders, offset);
+}
+
+
+String8 ClearMediaHTTP::getUri() {
+ if (mInitCheck != OK) {
+ return String8::empty();
+ }
+
+ String8 uri;
+ if (OK == mHTTPConnection->getUri(&uri)) {
+ return uri;
+ }
+ return String8(mLastURI.c_str());
+}
+
+String8 ClearMediaHTTP::getMIMEType() const {
+ if (mInitCheck != OK) {
+ return String8("application/octet-stream");
+ }
+
+ String8 mimeType;
+ status_t err = mHTTPConnection->getMIMEType(&mimeType);
+
+ if (err != OK) {
+ return String8("application/octet-stream");
+ }
+
+ return mimeType;
+}
+
+} // namespace android
diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp
index 77845e2..b895f03 100644
--- a/media/libstagefright/http/HTTPHelper.cpp
+++ b/media/libstagefright/http/HTTPHelper.cpp
@@ -42,11 +42,11 @@
env, env->FindClass("android/media/MediaHTTPService"));
CHECK(clazz.get() != NULL);
- jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "()V");
+ jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "(Ljava/util/List;)V");
CHECK(constructID != NULL);
ScopedLocalRef<jobject> httpServiceObj(
- env, env->NewObject(clazz.get(), constructID));
+ env, env->NewObject(clazz.get(), constructID, NULL));
sp<IMediaHTTPService> httpService;
if (httpServiceObj.get() != NULL) {
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index 7c9247e..0fba3dc 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -30,10 +30,7 @@
namespace android {
MediaHTTP::MediaHTTP(const sp<MediaHTTPConnection> &conn)
- : mInitCheck((conn != NULL) ? OK : NO_INIT),
- mHTTPConnection(conn),
- mCachedSizeValid(false),
- mCachedSize(0ll),
+ : ClearMediaHTTP(conn),
mDrmManagerClient(NULL) {
}
@@ -41,117 +38,6 @@
clearDRMState_l();
}
-status_t MediaHTTP::connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- off64_t /* offset */) {
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- KeyedVector<String8, String8> extHeaders;
- if (headers != NULL) {
- extHeaders = *headers;
- }
-
- if (extHeaders.indexOfKey(String8("User-Agent")) < 0) {
- extHeaders.add(String8("User-Agent"), String8(MakeUserAgent().c_str()));
- }
-
- mLastURI = uri;
- // reconnect() calls with uri == old mLastURI.c_str(), which gets zapped
- // as part of the above assignment. Ensure no accidental later use.
- uri = NULL;
-
- bool success = mHTTPConnection->connect(mLastURI.c_str(), &extHeaders);
-
- mLastHeaders = extHeaders;
-
- mCachedSizeValid = false;
-
- if (success) {
- AString sanitized = uriDebugString(mLastURI);
- mName = String8::format("MediaHTTP(%s)", sanitized.c_str());
- }
-
- return success ? OK : UNKNOWN_ERROR;
-}
-
-void MediaHTTP::disconnect() {
- mName = String8("MediaHTTP(<disconnected>)");
- if (mInitCheck != OK) {
- return;
- }
-
- mHTTPConnection->disconnect();
-}
-
-status_t MediaHTTP::initCheck() const {
- return mInitCheck;
-}
-
-ssize_t MediaHTTP::readAt(off64_t offset, void *data, size_t size) {
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- int64_t startTimeUs = ALooper::GetNowUs();
-
- size_t numBytesRead = 0;
- while (numBytesRead < size) {
- size_t copy = size - numBytesRead;
-
- if (copy > 64 * 1024) {
- // limit the buffer sizes transferred across binder boundaries
- // to avoid spurious transaction failures.
- copy = 64 * 1024;
- }
-
- ssize_t n = mHTTPConnection->readAt(
- offset + numBytesRead, (uint8_t *)data + numBytesRead, copy);
-
- if (n < 0) {
- return n;
- } else if (n == 0) {
- break;
- }
-
- numBytesRead += n;
- }
-
- int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
-
- addBandwidthMeasurement(numBytesRead, delayUs);
-
- return numBytesRead;
-}
-
-status_t MediaHTTP::getSize(off64_t *size) {
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- // Caching the returned size so that it stays valid even after a
- // disconnect. NuCachedSource2 relies on this.
-
- if (!mCachedSizeValid) {
- mCachedSize = mHTTPConnection->getSize();
- mCachedSizeValid = true;
- }
-
- *size = mCachedSize;
-
- return *size < 0 ? *size : static_cast<status_t>(OK);
-}
-
-uint32_t MediaHTTP::flags() {
- return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-status_t MediaHTTP::reconnectAtOffset(off64_t offset) {
- return connect(mLastURI.c_str(), &mLastHeaders, offset);
-}
-
// DRM...
sp<DecryptHandle> MediaHTTP::DrmInitialization(const char* mime) {
@@ -176,33 +62,6 @@
return mDecryptHandle;
}
-String8 MediaHTTP::getUri() {
- if (mInitCheck != OK) {
- return String8::empty();
- }
-
- String8 uri;
- if (OK == mHTTPConnection->getUri(&uri)) {
- return uri;
- }
- return String8(mLastURI.c_str());
-}
-
-String8 MediaHTTP::getMIMEType() const {
- if (mInitCheck != OK) {
- return String8("application/octet-stream");
- }
-
- String8 mimeType;
- status_t err = mHTTPConnection->getMIMEType(&mimeType);
-
- if (err != OK) {
- return String8("application/octet-stream");
- }
-
- return mimeType;
-}
-
void MediaHTTP::clearDRMState_l() {
if (mDecryptHandle != NULL) {
// To release mDecryptHandle
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index 72604e3..59265fe 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -26,8 +26,8 @@
#include <media/MediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaHTTP.h>
-#include <media/stagefright/FileSource.h>
+#include <media/stagefright/ClearMediaHTTP.h>
+#include <media/stagefright/ClearFileSource.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
@@ -38,7 +38,7 @@
HTTPDownloader::HTTPDownloader(
const sp<MediaHTTPService> &httpService,
const KeyedVector<String8, String8> &headers) :
- mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())),
+ mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())),
mExtraHeaders(headers),
mDisconnecting(false) {
}
@@ -91,7 +91,7 @@
if (reconnect) {
if (!strncasecmp(url, "file://", 7)) {
- mDataSource = new FileSource(url + 7);
+ mDataSource = new ClearFileSource(url + 7);
} else if (strncasecmp(url, "http://", 7)
&& strncasecmp(url, "https://", 8)) {
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h b/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
new file mode 100644
index 0000000..12bcdd3
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/ClearDataSourceFactory.h
@@ -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.
+ */
+
+#ifndef DATA_SOURCE_FACTORY2_H_
+
+#define DATA_SOURCE_FACTORY2_H_
+
+#include <sys/types.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct MediaHTTPService;
+class String8;
+struct HTTPBase;
+
+class ClearDataSourceFactory {
+public:
+ static sp<DataSource> CreateFromURI(
+ const sp<MediaHTTPService> &httpService,
+ const char *uri,
+ const KeyedVector<String8, String8> *headers = NULL,
+ String8 *contentType = NULL,
+ HTTPBase *httpSource = NULL);
+
+ static sp<DataSource> CreateMediaHTTP(const sp<MediaHTTPService> &httpService);
+ static sp<DataSource> CreateFromFd(int fd, int64_t offset, int64_t length);
+};
+
+} // namespace android
+
+#endif // DATA_SOURCE_FACTORY2_H_
diff --git a/media/libstagefright/include/media/stagefright/ClearFileSource.h b/media/libstagefright/include/media/stagefright/ClearFileSource.h
new file mode 100644
index 0000000..be83748
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/ClearFileSource.h
@@ -0,0 +1,68 @@
+/*
+ * 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 CLEAR_FILE_SOURCE_H_
+
+#define CLEAR_FILE_SOURCE_H_
+
+#include <stdio.h>
+
+#include <media/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ClearFileSource : public DataSource {
+public:
+ ClearFileSource(const char *filename);
+ // ClearFileSource takes ownership and will close the fd
+ ClearFileSource(int fd, int64_t offset, int64_t length);
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual status_t getSize(off64_t *size);
+
+ virtual uint32_t flags() {
+ return kIsLocalFileSource;
+ }
+
+ virtual String8 toString() {
+ return mName;
+ }
+
+protected:
+ virtual ~ClearFileSource();
+ virtual ssize_t readAt_l(off64_t offset, void *data, size_t size);
+
+ int mFd;
+ int64_t mOffset;
+ int64_t mLength;
+ Mutex mLock;
+
+private:
+ String8 mName;
+
+ ClearFileSource(const ClearFileSource &);
+ ClearFileSource &operator=(const ClearFileSource &);
+};
+
+} // namespace android
+
+#endif // CLEAR_FILE_SOURCE_H_
+
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
new file mode 100644
index 0000000..7fe9c74
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
@@ -0,0 +1,71 @@
+/*
+ * 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 CLEAR_MEDIA_HTTP_H_
+
+#define CLEAR_MEDIA_HTTP_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+#include "include/HTTPBase.h"
+
+namespace android {
+
+struct MediaHTTPConnection;
+
+struct ClearMediaHTTP : public HTTPBase {
+ ClearMediaHTTP(const sp<MediaHTTPConnection> &conn);
+
+ virtual status_t connect(
+ const char *uri,
+ const KeyedVector<String8, String8> *headers,
+ off64_t offset);
+
+ virtual void disconnect();
+
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+
+ virtual status_t getSize(off64_t *size);
+
+ virtual uint32_t flags();
+
+ virtual status_t reconnectAtOffset(off64_t offset);
+
+protected:
+ virtual ~ClearMediaHTTP();
+
+ virtual String8 getUri();
+ virtual String8 getMIMEType() const;
+
+ AString mLastURI;
+
+private:
+ status_t mInitCheck;
+ sp<MediaHTTPConnection> mHTTPConnection;
+
+ KeyedVector<String8, String8> mLastHeaders;
+
+ bool mCachedSizeValid;
+ off64_t mCachedSize;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ClearMediaHTTP);
+};
+
+} // namespace android
+
+#endif // CLEAR_MEDIA_HTTP_H_
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libstagefright/include/media/stagefright/FileSource.h
index 8604890..b610eef 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libstagefright/include/media/stagefright/FileSource.h
@@ -20,47 +20,29 @@
#include <stdio.h>
-#include <media/DataSource.h>
+#include <media/stagefright/ClearFileSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/threads.h>
#include <drm/DrmManagerClient.h>
namespace android {
-class FileSource : public DataSource {
+class FileSource : public ClearFileSource {
public:
FileSource(const char *filename);
// FileSource takes ownership and will close the fd
FileSource(int fd, int64_t offset, int64_t length);
- virtual status_t initCheck() const;
-
virtual ssize_t readAt(off64_t offset, void *data, size_t size);
- virtual status_t getSize(off64_t *size);
-
- virtual uint32_t flags() {
- return kIsLocalFileSource;
- }
-
virtual sp<DecryptHandle> DrmInitialization(const char *mime);
- virtual String8 toString() {
- return mName;
- }
-
static bool requiresDrm(int fd, int64_t offset, int64_t length, const char *mime);
protected:
virtual ~FileSource();
private:
- int mFd;
- int64_t mOffset;
- int64_t mLength;
- Mutex mLock;
- String8 mName;
-
/*for DRM*/
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
@@ -68,7 +50,7 @@
ssize_t mDrmBufSize;
unsigned char *mDrmBuf;
- ssize_t readAtDRM(off64_t offset, void *data, size_t size);
+ ssize_t readAtDRM_l(off64_t offset, void *data, size_t size);
FileSource(const FileSource &);
FileSource &operator=(const FileSource &);
diff --git a/media/libstagefright/include/media/stagefright/MediaHTTP.h b/media/libstagefright/include/media/stagefright/MediaHTTP.h
index fe0e613..acaa6c4 100644
--- a/media/libstagefright/include/media/stagefright/MediaHTTP.h
+++ b/media/libstagefright/include/media/stagefright/MediaHTTP.h
@@ -19,50 +19,21 @@
#define MEDIA_HTTP_H_
#include <media/stagefright/foundation/AString.h>
-
-#include "include/HTTPBase.h"
+#include <media/stagefright/ClearMediaHTTP.h>
namespace android {
struct MediaHTTPConnection;
-struct MediaHTTP : public HTTPBase {
+struct MediaHTTP : public ClearMediaHTTP {
MediaHTTP(const sp<MediaHTTPConnection> &conn);
- virtual status_t connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers,
- off64_t offset);
-
- virtual void disconnect();
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
-
- virtual status_t getSize(off64_t *size);
-
- virtual uint32_t flags();
-
- virtual status_t reconnectAtOffset(off64_t offset);
-
protected:
virtual ~MediaHTTP();
virtual sp<DecryptHandle> DrmInitialization(const char* mime);
- virtual String8 getUri();
- virtual String8 getMIMEType() const;
private:
- status_t mInitCheck;
- sp<MediaHTTPConnection> mHTTPConnection;
-
- KeyedVector<String8, String8> mLastHeaders;
- AString mLastURI;
-
- bool mCachedSizeValid;
- off64_t mCachedSize;
-
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient *mDrmManagerClient;
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index d459cbd..665d51a 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -24,7 +24,7 @@
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
-#include <media/stagefright/MediaHTTP.h>
+#include <media/stagefright/ClearMediaHTTP.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
@@ -41,7 +41,7 @@
mFlags(flags),
mNetLooper(new ALooper),
mCancelled(false),
- mHTTPDataSource(new MediaHTTP(httpService->makeHTTPConnection())) {
+ mHTTPDataSource(new ClearMediaHTTP(httpService->makeHTTPConnection())) {
mNetLooper->setName("sdp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 6b20bca..42285f8 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -811,7 +811,13 @@
size_t *encryptedbytes) {
// size needed to store all the crypto data
- size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ size_t cryptosize;
+ // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
+ __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
+ ALOGE("crypto size overflow");
+ return NULL;
+ }
AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
if (!ret) {
ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 786c4af..c4c742e 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -50,6 +50,8 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#define DEFAULT_OUTPUT_SAMPLE_RATE 48000
+
namespace android {
// ----------------------------------------------------------------------------
@@ -263,7 +265,9 @@
}
break;
case STOPPING:
- if (stop_l() == NO_ERROR) {
+ // volume control for offload and direct threads must take effect immediately.
+ if (stop_l() == NO_ERROR
+ && !(isVolumeControl() && isOffloadedOrDirect())) {
mDisableWaitCnt = mMaxDisableWaitCnt;
} else {
mDisableWaitCnt = 1; // will cause immediate transition to IDLE
@@ -547,7 +551,14 @@
mConfig.inputCfg.format = EFFECT_BUFFER_FORMAT;
mConfig.outputCfg.format = EFFECT_BUFFER_FORMAT;
- mConfig.inputCfg.samplingRate = thread->sampleRate();
+
+ // Don't use sample rate for thread if effect isn't offloadable.
+ if ((thread->type() == ThreadBase::OFFLOAD) && !isOffloaded()) {
+ mConfig.inputCfg.samplingRate = DEFAULT_OUTPUT_SAMPLE_RATE;
+ ALOGV("Overriding effect input as 48kHz");
+ } else {
+ mConfig.inputCfg.samplingRate = thread->sampleRate();
+ }
mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
mConfig.inputCfg.bufferProvider.cookie = NULL;
mConfig.inputCfg.bufferProvider.getBuffer = NULL;
@@ -778,6 +789,16 @@
}
status_t cmdStatus = NO_ERROR;
uint32_t size = sizeof(status_t);
+
+ if (isVolumeControl() && isOffloadedOrDirect()) {
+ sp<EffectChain>chain = mChain.promote();
+ // We have the EffectChain and EffectModule lock, permit a reentrant call to setVolume:
+ // resetVolume_l --> setVolume_l --> EffectModule::setVolume
+ mSetVolumeReentrantTid = gettid();
+ chain->resetVolume_l();
+ mSetVolumeReentrantTid = INVALID_PID;
+ }
+
status_t status = mEffectInterface->command(EFFECT_CMD_DISABLE,
0,
NULL,
@@ -993,6 +1014,16 @@
}
}
+bool AudioFlinger::EffectModule::isOffloadedOrDirect() const
+{
+ return (mThreadType == ThreadBase::OFFLOAD || mThreadType == ThreadBase::DIRECT);
+}
+
+bool AudioFlinger::EffectModule::isVolumeControlEnabled() const
+{
+ return (isVolumeControl() && (isOffloadedOrDirect() ? isEnabled() : isProcessEnabled()));
+}
+
void AudioFlinger::EffectModule::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
ALOGVV("setInBuffer %p",(&buffer));
@@ -1091,7 +1122,7 @@
status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
{
- Mutex::Autolock _l(mLock);
+ AutoLockReentrant _l(mLock, mSetVolumeReentrantTid);
if (mStatus != NO_ERROR) {
return mStatus;
}
@@ -1122,6 +1153,18 @@
return status;
}
+void AudioFlinger::EffectChain::setVolumeForOutput_l(uint32_t left, uint32_t right)
+{
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0 &&
+ (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT)) {
+ PlaybackThread *t = (PlaybackThread *)thread.get();
+ float vol_l = (float)left / (1 << 24);
+ float vol_r = (float)right / (1 << 24);
+ t->setVolumeForOutput_l(vol_l, vol_r);
+ }
+}
+
status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
{
if (device == AUDIO_DEVICE_NONE) {
@@ -2200,8 +2243,7 @@
// first update volume controller
for (size_t i = size; i > 0; i--) {
- if (mEffects[i - 1]->isProcessEnabled() &&
- (mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL) {
+ if (mEffects[i - 1]->isVolumeControlEnabled()) {
ctrlIdx = i - 1;
hasControl = true;
break;
@@ -2247,6 +2289,8 @@
*left = newLeft;
*right = newRight;
+ setVolumeForOutput_l(*left, *right);
+
return hasControl;
}
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 2327bb9..e04ee8e 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -85,6 +85,8 @@
status_t setEnabled_l(bool enabled);
bool isEnabled() const;
bool isProcessEnabled() const;
+ bool isOffloadedOrDirect() const;
+ bool isVolumeControlEnabled() const;
void setInBuffer(const sp<EffectBufferHalInterface>& buffer);
int16_t *inBuffer() const {
@@ -95,7 +97,8 @@
return mOutBuffer != 0 ? reinterpret_cast<int16_t*>(mOutBuffer->ptr()) : NULL;
}
void setChain(const wp<EffectChain>& chain) { mChain = chain; }
- void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
+ void setThread(const wp<ThreadBase>& thread)
+ { mThread = thread; mThreadType = thread.promote()->type(); }
const wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(EffectHandle *handle);
@@ -128,6 +131,9 @@
{ return (mDescriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0; }
bool isProcessImplemented() const
{ return (mDescriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0; }
+ bool isVolumeControl() const
+ { return (mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK)
+ == EFFECT_FLAG_VOLUME_CTRL; }
status_t setOffloaded(bool offloaded, audio_io_handle_t io);
bool isOffloaded() const;
void addEffectToHal_l();
@@ -150,6 +156,7 @@
mutable Mutex mLock; // mutex for process, commands and handles list protection
wp<ThreadBase> mThread; // parent thread
+ ThreadBase::type_t mThreadType; // parent thread type
wp<EffectChain> mChain; // parent effect chain
const int mId; // this instance unique ID
const audio_session_t mSessionId; // audio session ID
@@ -176,6 +183,24 @@
uint32_t mInChannelCountRequested;
uint32_t mOutChannelCountRequested;
#endif
+
+ class AutoLockReentrant {
+ public:
+ AutoLockReentrant(Mutex& mutex, pid_t allowedTid)
+ : mMutex(gettid() == allowedTid ? nullptr : &mutex)
+ {
+ if (mMutex != nullptr) mMutex->lock();
+ }
+ ~AutoLockReentrant() {
+ if (mMutex != nullptr) mMutex->unlock();
+ }
+ private:
+ Mutex * const mMutex;
+ };
+
+ static constexpr pid_t INVALID_PID = (pid_t)-1;
+ // this tid is allowed to call setVolume() without acquiring the mutex.
+ pid_t mSetVolumeReentrantTid = INVALID_PID;
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -403,6 +428,8 @@
void setThread(const sp<ThreadBase>& thread);
+ void setVolumeForOutput_l(uint32_t left, uint32_t right);
+
wp<ThreadBase> mThread; // parent mixer thread
mutable Mutex mLock; // mutex protecting effect list
Vector< sp<EffectModule> > mEffects; // list of effect modules
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index ada8572..7b165a1 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -547,14 +547,46 @@
// reverse due to internal biases).
//
// TODO: is this stable enough? Consider a PatchTrack synchronized version of this.
- double recordServerLatencyMs;
- if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) != OK) return INVALID_OPERATION;
- double playbackTrackLatencyMs;
- if (playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) != OK) return INVALID_OPERATION;
+ // For PCM tracks get server latency.
+ if (audio_is_linear_pcm(recordTrack->format())) {
+ double recordServerLatencyMs, playbackTrackLatencyMs;
+ if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) == OK
+ && playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) == OK) {
+ *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
+ return OK;
+ }
+ }
- *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
- return OK;
+ // See if kernel latencies are available.
+ // If so, do a frame diff and time difference computation to estimate
+ // the total patch latency. This requires that frame counts are reported by the
+ // HAL are matched properly in the case of record overruns and playback underruns.
+ ThreadBase::TrackBase::FrameTime recordFT{}, playFT{};
+ recordTrack->getKernelFrameTime(&recordFT);
+ playbackTrack->getKernelFrameTime(&playFT);
+ if (recordFT.timeNs > 0 && playFT.timeNs > 0) {
+ const int64_t frameDiff = recordFT.frames - playFT.frames;
+ const int64_t timeDiffNs = recordFT.timeNs - playFT.timeNs;
+
+ // It is possible that the patch track and patch record have a large time disparity because
+ // one thread runs but another is stopped. We arbitrarily choose the maximum timestamp
+ // time difference based on how often we expect the timestamps to update in normal operation
+ // (typical should be no more than 50 ms).
+ //
+ // If the timestamps aren't sampled close enough, the patch latency is not
+ // considered valid.
+ //
+ // TODO: change this based on more experiments.
+ constexpr int64_t maxValidTimeDiffNs = 200 * NANOS_PER_MILLISECOND;
+ if (std::abs(timeDiffNs) < maxValidTimeDiffNs) {
+ *latencyMs = frameDiff * 1e3 / recordTrack->sampleRate()
+ - timeDiffNs * 1e-6;
+ return OK;
+ }
+ }
+
+ return INVALID_OPERATION;
}
String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 269a398..2d9bd8e 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -35,6 +35,7 @@
// Must be called under AudioFlinger::mLock
status_t getLatencyMs_l(double *latencyMs) const;
+ audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
private:
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index cd585f5..b5f61e7 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -863,6 +863,7 @@
|| mType == DIRECT
|| mType == OFFLOAD) {
dprintf(fd, " Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
+ dprintf(fd, " Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
}
if (locked) {
@@ -1732,10 +1733,21 @@
if (mOutput->audioHwDev->canSetMasterMute()) {
mMasterMute = false;
}
+ mIsMsdDevice = strcmp(
+ mOutput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
}
readOutputParameters_l();
+ // TODO: We may also match on address as well as device type for
+ // AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+ if (type == MIXER || type == DIRECT) {
+ mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_output_devices",
+ (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
+ : AUDIO_DEVICE_NONE));
+ }
+
// ++ operator does not compile
for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_FOR_POLICY_CNT;
stream = (audio_stream_type_t) (stream + 1)) {
@@ -2320,6 +2332,11 @@
return mStreamTypes[stream].volume;
}
+void AudioFlinger::PlaybackThread::setVolumeForOutput_l(float left, float right) const
+{
+ mOutput->stream->setVolume(left, right);
+}
+
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
@@ -3208,6 +3225,8 @@
if (mType == OFFLOAD || mType == DIRECT) {
mTimestampVerifier.setDiscontinuityMode(mTimestampVerifier.DISCONTINUITY_MODE_ZERO);
}
+ audio_utils::Statistics<double> downstreamLatencyStatMs(0.999 /* alpha */);
+ audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
while (!exitPending())
{
@@ -3219,6 +3238,46 @@
Vector< sp<EffectChain> > effectChains;
+ // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
+ //
+ // Note: we access outDevice() outside of mLock.
+ if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+ // Here, we try for the AF lock, but do not block on it as the latency
+ // is more informational.
+ if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
+ std::vector<PatchPanel::SoftwarePatch> swPatches;
+ double latencyMs;
+ status_t status = INVALID_OPERATION;
+ audio_patch_handle_t downstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ if (mAudioFlinger->mPatchPanel.getDownstreamSoftwarePatches(id(), &swPatches) == OK
+ && swPatches.size() > 0) {
+ status = swPatches[0].getLatencyMs_l(&latencyMs);
+ downstreamPatchHandle = swPatches[0].getPatchHandle();
+ }
+ if (downstreamPatchHandle != lastDownstreamPatchHandle) {
+ downstreamLatencyStatMs.reset();
+ lastDownstreamPatchHandle = downstreamPatchHandle;
+ }
+ if (status == OK) {
+ // verify downstream latency (we assume a max reasonable
+ // latency of 1 second).
+ if (latencyMs >= 0. && latencyMs <= 1000.) {
+ ALOGV("new downstream latency %lf ms", latencyMs);
+ downstreamLatencyStatMs.add(latencyMs);
+ } else {
+ ALOGD("out of range downstream latency %lf ms", latencyMs);
+ }
+ }
+ mAudioFlinger->mLock.unlock();
+ }
+ } else {
+ if (lastDownstreamPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
+ // our device is no longer AUDIO_DEVICE_OUT_BUS, reset patch handle and stats.
+ downstreamLatencyStatMs.reset();
+ lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ }
+ }
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -3248,6 +3307,33 @@
mTimestampVerifier.add(timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
mSampleRate);
+
+ if (isTimestampCorrectionEnabled()) {
+ ALOGV("TS_BEFORE: %d %lld %lld", id(),
+ (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+ (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+ auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ = correctedTimestamp.mFrames;
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]
+ = correctedTimestamp.mTimeNs;
+ ALOGV("TS_AFTER: %d %lld %lld", id(),
+ (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+ (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+
+ // Note: Downstream latency only added if timestamp correction enabled.
+ if (downstreamLatencyStatMs.getN() > 0) { // we have latency info.
+ const int64_t newPosition =
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ - int64_t(downstreamLatencyStatMs.getMean() * mSampleRate * 1e-3);
+ // prevent retrograde
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = max(
+ newPosition,
+ (mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ - mSuspendedFrames));
+ }
+ }
+
// We always fetch the timestamp here because often the downstream
// sink will block while writing.
@@ -5236,20 +5322,20 @@
mLeftVolFloat = left;
mRightVolFloat = right;
- // Convert volumes from float to 8.24
- uint32_t vl = (uint32_t)(left * (1 << 24));
- uint32_t vr = (uint32_t)(right * (1 << 24));
-
// Delegate volume control to effect in track effect chain if needed
// only one effect chain can be present on DirectOutputThread, so if
// there is one, the track is connected to it
if (!mEffectChains.isEmpty()) {
- mEffectChains[0]->setVolume_l(&vl, &vr);
- left = (float)vl / (1 << 24);
- right = (float)vr / (1 << 24);
+ // if effect chain exists, volume is handled by it.
+ // Convert volumes from float to 8.24
+ uint32_t vl = (uint32_t)(left * (1 << 24));
+ uint32_t vr = (uint32_t)(right * (1 << 24));
+ // Direct/Offload effect chains set output volume in setVolume_l().
+ (void)mEffectChains[0]->setVolume_l(&vl, &vr);
+ } else {
+ // otherwise we directly set the volume.
+ setVolumeForOutput_l(left, right);
}
- status_t result = mOutput->stream->setVolume(left, right);
- ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
}
}
}
@@ -6368,8 +6454,20 @@
snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
+ if (mInput != nullptr && mInput->audioHwDev != nullptr) {
+ mIsMsdDevice = strcmp(
+ mInput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
+ }
+
readInputParameters_l();
+ // TODO: We may also match on address as well as device type for
+ // AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
+ mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_input_devices",
+ (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
+ : AUDIO_DEVICE_NONE));
+
// create an NBAIO source for the HAL input stream, and negotiate
mInputSource = new AudioStreamInSource(input->stream);
size_t numCounterOffers = 0;
@@ -6804,7 +6902,22 @@
int64_t position, time;
if (mStandby) {
mTimestampVerifier.discontinuity();
- } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR) {
+ } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR
+ && time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
+
+ mTimestampVerifier.add(position, time, mSampleRate);
+
+ // Correct timestamps
+ if (isTimestampCorrectionEnabled()) {
+ ALOGV("TS_BEFORE: %d %lld %lld",
+ id(), (long long)time, (long long)position);
+ auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+ position = correctedTimestamp.mFrames;
+ time = correctedTimestamp.mTimeNs;
+ ALOGV("TS_AFTER: %d %lld %lld",
+ id(), (long long)time, (long long)position);
+ }
+
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
// Note: In general record buffers should tend to be empty in
@@ -6812,10 +6925,6 @@
//
// Also, it is not advantageous to call get_presentation_position during the read
// as the read obtains a lock, preventing the timestamp call from executing.
-
- mTimestampVerifier.add(mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
- mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
- mSampleRate);
} else {
mTimestampVerifier.error();
}
@@ -6833,6 +6942,7 @@
goto unlock;
}
ALOG_ASSERT(framesRead > 0);
+ mFramesRead += framesRead;
#ifdef TEE_SINK
(void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
@@ -7457,6 +7567,7 @@
audio_input_flags_t flags = input != NULL ? input->flags : AUDIO_INPUT_FLAG_NONE;
dprintf(fd, " AudioStreamIn: %p flags %#x (%s)\n",
input, flags, inputFlagsToString(flags).c_str());
+ dprintf(fd, " Frames read: %lld\n", (long long)mFramesRead);
if (mActiveTracks.isEmpty()) {
dprintf(fd, " No active record clients\n");
}
@@ -7466,7 +7577,8 @@
(void)input->stream->dump(fd);
}
- const double latencyMs = - mTimestamp.getOutputServerLatencyMs(mSampleRate);
+ const double latencyMs = audio_is_linear_pcm(mFormat)
+ ? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
if (latencyMs != 0.) {
dprintf(fd, " NormalRecord latency ms: %.2lf\n", latencyMs);
} else {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 2ab0bee..dce3d2e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -393,6 +393,10 @@
void broadcast_l();
+ virtual bool isTimestampCorrectionEnabled() const { return false; }
+
+ bool isMsdDevice() const { return mIsMsdDevice; }
+
mutable Mutex mLock;
protected:
@@ -501,7 +505,8 @@
ExtendedTimestamp mTimestamp;
TimestampVerifier< // For timestamp statistics.
int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
-
+ audio_devices_t mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+ bool mIsMsdDevice = false;
// A condition that must be evaluated by the thread loop has changed and
// we must not wait for async write callback in the thread loop before evaluating it
bool mSignalPending;
@@ -729,6 +734,8 @@
virtual void setStreamMute(audio_stream_type_t stream, bool muted);
virtual float streamVolume(audio_stream_type_t stream) const;
+ void setVolumeForOutput_l(float left, float right) const;
+
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
audio_stream_type_t streamType,
@@ -816,6 +823,11 @@
&& mTracks.size() < PlaybackThread::kMaxTracks;
}
+ bool isTimestampCorrectionEnabled() const override {
+ const audio_devices_t device =
+ mOutDevice & mTimestampCorrectedDevices;
+ return audio_is_output_devices(device) && popcount(device) > 0;
+ }
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
@@ -1532,6 +1544,11 @@
bool fastTrackAvailable() const { return mFastTrackAvail; }
+ bool isTimestampCorrectionEnabled() const override {
+ // checks popcount for exactly one device.
+ return audio_is_input_device(
+ mInDevice & mTimestampCorrectedDevices);
+ }
private:
// Enter standby if not already in standby, and set mStandby flag
void standbyIfNotAlreadyInStandby();
@@ -1601,6 +1618,8 @@
bool mFastTrackAvail; // true if fast track available
// common state to all record threads
std::atomic_bool mBtNrecSuspended;
+
+ int64_t mFramesRead = 0; // continuous running counter.
};
class MmapThread : public ThreadBase
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 95da9d7..a43cb75 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -187,6 +187,19 @@
return status;
}
+ // TODO: Consider making this external.
+ struct FrameTime {
+ int64_t frames;
+ int64_t timeNs;
+ };
+
+ // KernelFrameTime is updated per "mix" period even for non-pcm tracks.
+ void getKernelFrameTime(FrameTime *ft) const {
+ *ft = mKernelFrameTime.load();
+ }
+
+ audio_format_t format() const { return mFormat; }
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -198,8 +211,6 @@
// but putting it in TrackBase avoids the complexity of virtual inheritance
virtual size_t framesReady() const { return SIZE_MAX; }
- audio_format_t format() const { return mFormat; }
-
uint32_t channelCount() const { return mChannelCount; }
audio_channel_mask_t channelMask() const { return mChannelMask; }
@@ -307,6 +318,7 @@
bool mServerLatencySupported = false;
std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
std::atomic<double> mServerLatencyMs{}; // last latency pushed from server thread.
+ std::atomic<FrameTime> mKernelFrameTime{}; // last frame time on kernel side.
};
// PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8b9485f..78e6c6c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1258,6 +1258,16 @@
void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
int64_t trackFramesReleased, int64_t sinkFramesWritten,
uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
+ // Make the kernel frametime available.
+ const FrameTime ft{
+ timeStamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+ timeStamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+ // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+ mKernelFrameTime.store(ft);
+ if (!audio_is_linear_pcm(mFormat)) {
+ return;
+ }
+
//update frame map
mFrameMap.push(trackFramesReleased, sinkFramesWritten);
@@ -1720,7 +1730,7 @@
thread->mFastTrackAvail = false;
} else {
// TODO: only Normal Record has timestamps (Fast Record does not).
- mServerLatencySupported = true;
+ mServerLatencySupported = audio_is_linear_pcm(mFormat);
}
#ifdef TEE_SINK
mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
@@ -1886,6 +1896,16 @@
int64_t trackFramesReleased, int64_t sourceFramesRead,
uint32_t halSampleRate, const ExtendedTimestamp ×tamp)
{
+ // Make the kernel frametime available.
+ const FrameTime ft{
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+ // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+ mKernelFrameTime.store(ft);
+ if (!audio_is_linear_pcm(mFormat)) {
+ return;
+ }
+
ExtendedTimestamp local = timestamp;
// Convert HAL frames to server-side track frames at track sample rate.
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 96079cc..b0e6b0f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1514,11 +1514,6 @@
setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
}
- if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
- setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
- }
-
return NO_ERROR;
}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
new file mode 100644
index 0000000..eccbe54
--- /dev/null
+++ b/services/camera/libcameraservice/Android.bp
@@ -0,0 +1,106 @@
+// 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.
+
+//
+// libcameraservice
+//
+
+cc_library_shared {
+ name: "libcameraservice",
+
+ // Camera service source
+
+ srcs: [
+ "CameraService.cpp",
+ "CameraFlashlight.cpp",
+ "common/Camera2ClientBase.cpp",
+ "common/CameraDeviceBase.cpp",
+ "common/CameraProviderManager.cpp",
+ "common/FrameProcessorBase.cpp",
+ "api1/CameraClient.cpp",
+ "api1/Camera2Client.cpp",
+ "api1/client2/Parameters.cpp",
+ "api1/client2/FrameProcessor.cpp",
+ "api1/client2/StreamingProcessor.cpp",
+ "api1/client2/JpegProcessor.cpp",
+ "api1/client2/CallbackProcessor.cpp",
+ "api1/client2/JpegCompressor.cpp",
+ "api1/client2/CaptureSequencer.cpp",
+ "api1/client2/ZslProcessor.cpp",
+ "api2/CameraDeviceClient.cpp",
+ "device1/CameraHardwareInterface.cpp",
+ "device3/Camera3Device.cpp",
+ "device3/Camera3Stream.cpp",
+ "device3/Camera3IOStreamBase.cpp",
+ "device3/Camera3InputStream.cpp",
+ "device3/Camera3OutputStream.cpp",
+ "device3/Camera3DummyStream.cpp",
+ "device3/Camera3SharedOutputStream.cpp",
+ "device3/StatusTracker.cpp",
+ "device3/Camera3BufferManager.cpp",
+ "device3/Camera3StreamSplitter.cpp",
+ "device3/DistortionMapper.cpp",
+ "gui/RingBufferConsumer.cpp",
+ "utils/CameraTraces.cpp",
+ "utils/AutoConditionLock.cpp",
+ "utils/TagMonitor.cpp",
+ "utils/LatencyHistogram.cpp",
+ ],
+
+ shared_libs: [
+ "libui",
+ "liblog",
+ "libutilscallstack",
+ "libutils",
+ "libbinder",
+ "libcutils",
+ "libmedia",
+ "libmediautils",
+ "libcamera_client",
+ "libcamera_metadata",
+ "libfmq",
+ "libgui",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libjpeg",
+ "libmemunreachable",
+ "android.hardware.camera.common@1.0",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.3",
+ "android.hardware.camera.device@3.4",
+ ],
+
+ export_shared_lib_headers: [
+ "libbinder",
+ "libcamera_client",
+ "libfmq",
+ ],
+
+ include_dirs: [
+ "system/media/private/camera/include",
+ "frameworks/native/include/media/openmax",
+ ],
+
+ export_include_dirs: ["."],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+
+}
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 96261ab..4cfecfd 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -14,91 +14,9 @@
LOCAL_PATH:= $(call my-dir)
-#
-# libcameraservice
-#
-
include $(CLEAR_VARS)
-# Camera service source
-
-LOCAL_SRC_FILES := \
- CameraService.cpp \
- CameraFlashlight.cpp \
- common/Camera2ClientBase.cpp \
- common/CameraDeviceBase.cpp \
- common/CameraProviderManager.cpp \
- common/FrameProcessorBase.cpp \
- api1/CameraClient.cpp \
- api1/Camera2Client.cpp \
- api1/client2/Parameters.cpp \
- api1/client2/FrameProcessor.cpp \
- api1/client2/StreamingProcessor.cpp \
- api1/client2/JpegProcessor.cpp \
- api1/client2/CallbackProcessor.cpp \
- api1/client2/JpegCompressor.cpp \
- api1/client2/CaptureSequencer.cpp \
- api1/client2/ZslProcessor.cpp \
- api2/CameraDeviceClient.cpp \
- device1/CameraHardwareInterface.cpp \
- device3/Camera3Device.cpp \
- device3/Camera3Stream.cpp \
- device3/Camera3IOStreamBase.cpp \
- device3/Camera3InputStream.cpp \
- device3/Camera3OutputStream.cpp \
- device3/Camera3DummyStream.cpp \
- device3/Camera3SharedOutputStream.cpp \
- device3/StatusTracker.cpp \
- device3/Camera3BufferManager.cpp \
- device3/Camera3StreamSplitter.cpp \
- device3/DistortionMapper.cpp \
- gui/RingBufferConsumer.cpp \
- utils/CameraTraces.cpp \
- utils/AutoConditionLock.cpp \
- utils/TagMonitor.cpp \
- utils/LatencyHistogram.cpp
-
-LOCAL_SHARED_LIBRARIES:= \
- libui \
- liblog \
- libutilscallstack \
- libutils \
- libbinder \
- libcutils \
- libmedia \
- libmediautils \
- libcamera_client \
- libcamera_metadata \
- libfmq \
- libgui \
- libhardware \
- libhidlbase \
- libhidltransport \
- libjpeg \
- libmemunreachable \
- android.hardware.camera.common@1.0 \
- android.hardware.camera.provider@2.4 \
- android.hardware.camera.device@1.0 \
- android.hardware.camera.device@3.2 \
- android.hardware.camera.device@3.3 \
- android.hardware.camera.device@3.4
-
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
-
-LOCAL_C_INCLUDES += \
- system/media/private/camera/include \
- frameworks/native/include/media/openmax
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
- frameworks/av/services/camera/libcameraservice
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= libcameraservice
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Build tests too
+# Build tests
include $(LOCAL_PATH)/tests/Android.mk
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 261cdbf..bf18c48 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -453,8 +453,6 @@
mDevice->disconnect();
- mDevice.clear();
-
CameraService::Client::disconnect();
return res;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index ce006a7..aeea473 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -57,13 +57,13 @@
cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
+ mDevice(new Camera3Device(cameraId)),
mDeviceActive(false), mApi1CameraId(api1CameraId)
{
ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
- mDevice = new Camera3Device(cameraId);
LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
@@ -206,8 +206,6 @@
if (mDevice == 0) return;
mDevice->disconnect();
- mDevice.clear();
-
ALOGV("Camera %s: Detach complete", TClientBase::mCameraIdStr.string());
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index e74fbdf..6693847 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -130,7 +130,10 @@
/** CameraDeviceBase instance wrapping HAL3+ entry */
const int mDeviceVersion;
- sp<CameraDeviceBase> mDevice;
+
+ // Set to const to avoid mDevice being updated (update of sp<> is racy) during
+ // dumpDevice (which is important to be lock free for debugging purpose)
+ const sp<CameraDeviceBase> mDevice;
/** Utility members */
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 4c6718c..7656407 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -90,7 +90,7 @@
{
ATRACE_CALL();
ALOGV("%s: Tearing down for camera id %s", __FUNCTION__, mId.string());
- disconnect();
+ disconnectImpl();
}
const String8& Camera3Device::getId() const {
@@ -275,6 +275,10 @@
}
status_t Camera3Device::disconnect() {
+ return disconnectImpl();
+}
+
+status_t Camera3Device::disconnectImpl() {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock stLock(mTrackerLock);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 51e1fb0..85f9614 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -210,6 +210,8 @@
private:
+ status_t disconnectImpl();
+
// internal typedefs
using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;