summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/AudioTrack.cpp133
-rw-r--r--media/libmedia/AudioTrackShared.cpp10
-rw-r--r--media/libmedia/ICrypto.cpp24
-rw-r--r--media/libmediaplayerservice/Crypto.cpp5
-rw-r--r--media/libmediaplayerservice/Crypto.h2
-rw-r--r--media/libmediaplayerservice/Drm.cpp66
-rw-r--r--media/libmediaplayerservice/Drm.h9
-rw-r--r--media/libstagefright/ESDS.cpp6
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp92
-rw-r--r--media/libstagefright/MediaClock.cpp5
-rw-r--r--media/libstagefright/MediaCodec.cpp20
-rw-r--r--media/libstagefright/SampleTable.cpp30
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp25
-rw-r--r--media/libstagefright/httplive/LiveSession.h2
-rw-r--r--media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp17
-rw-r--r--media/libstagefright/omx/SoftOMXPlugin.cpp2
16 files changed, 372 insertions, 76 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 9e9ec5b..89138e2 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -56,6 +56,24 @@ static int64_t getNowUs()
return convertTimespecToUs(tv);
}
+// Must match similar computation in createTrack_l in Threads.cpp.
+// TODO: Move to a common library
+static size_t calculateMinFrameCount(
+ uint32_t afLatencyMs, uint32_t afFrameCount, uint32_t afSampleRate,
+ uint32_t sampleRate, float speed)
+{
+ // Ensure that buffer depth covers at least audio hardware latency
+ uint32_t minBufCount = afLatencyMs / ((1000 * afFrameCount) / afSampleRate);
+ if (minBufCount < 2) {
+ minBufCount = 2;
+ }
+ ALOGV("calculateMinFrameCount afLatency %u afFrameCount %u afSampleRate %u "
+ "sampleRate %u speed %f minBufCount: %u",
+ afLatencyMs, afFrameCount, afSampleRate, sampleRate, speed, minBufCount);
+ return minBufCount * sourceFramesNeededWithTimestretch(
+ sampleRate, afFrameCount, afSampleRate, speed);
+}
+
// static
status_t AudioTrack::getMinFrameCount(
size_t* frameCount,
@@ -94,13 +112,10 @@ status_t AudioTrack::getMinFrameCount(
return status;
}
- // Ensure that buffer depth covers at least audio hardware latency
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
- if (minBufCount < 2) {
- minBufCount = 2;
- }
+ // When called from createTrack, speed is 1.0f (normal speed).
+ // This is rechecked again on setting playback rate (TODO: on setting sample rate, too).
+ *frameCount = calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, 1.0f);
- *frameCount = minBufCount * sourceFramesNeeded(sampleRate, afFrameCount, afSampleRate);
// The formula above should always produce a non-zero value under normal circumstances:
// AudioTrack.SAMPLE_RATE_HZ_MIN <= sampleRate <= AudioTrack.SAMPLE_RATE_HZ_MAX.
// Return error in the unlikely event that it does not, as that's part of the API contract.
@@ -109,8 +124,8 @@ status_t AudioTrack::getMinFrameCount(
streamType, sampleRate);
return BAD_VALUE;
}
- ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, minBufCount=%u, afSampleRate=%u, afLatency=%u",
- *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency);
+ ALOGV("getMinFrameCount=%zu: afFrameCount=%zu, afSampleRate=%u, afLatency=%u",
+ *frameCount, afFrameCount, afSampleRate, afLatency);
return NO_ERROR;
}
@@ -360,6 +375,8 @@ status_t AudioTrack::set(
return BAD_VALUE;
}
mSampleRate = sampleRate;
+ mSpeed = AUDIO_TIMESTRETCH_SPEED_NORMAL;
+ mPitch = AUDIO_TIMESTRETCH_PITCH_NORMAL;
// Make copy of input parameter offloadInfo so that in the future:
// (a) createTrack_l doesn't need it as an input parameter
@@ -689,6 +706,7 @@ status_t AudioTrack::setSampleRate(uint32_t rate)
if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
return BAD_VALUE;
}
+ // TODO: Should we also check if the buffer size is compatible?
mSampleRate = rate;
mProxy->setSampleRate(rate);
@@ -719,6 +737,42 @@ uint32_t AudioTrack::getSampleRate() const
return mSampleRate;
}
+status_t AudioTrack::setPlaybackRate(float speed, float pitch)
+{
+ if (speed < AUDIO_TIMESTRETCH_SPEED_MIN
+ || speed > AUDIO_TIMESTRETCH_SPEED_MAX
+ || pitch < AUDIO_TIMESTRETCH_PITCH_MIN
+ || pitch > AUDIO_TIMESTRETCH_PITCH_MAX) {
+ return BAD_VALUE;
+ }
+ AutoMutex lock(mLock);
+ if (speed == mSpeed && pitch == mPitch) {
+ return NO_ERROR;
+ }
+ if (mIsTimed || isOffloadedOrDirect_l()) {
+ return INVALID_OPERATION;
+ }
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
+ return INVALID_OPERATION;
+ }
+ // Check if the buffer size is compatible.
+ if (!isSampleRateSpeedAllowed_l(mSampleRate, speed)) {
+ ALOGV("setPlaybackRate(%f, %f) failed", speed, pitch);
+ return BAD_VALUE;
+ }
+ mSpeed = speed;
+ mPitch = pitch;
+ mProxy->setPlaybackRate(speed, pitch);
+ return NO_ERROR;
+}
+
+void AudioTrack::getPlaybackRate(float *speed, float *pitch) const
+{
+ AutoMutex lock(mLock);
+ *speed = mSpeed;
+ *pitch = mPitch;
+}
+
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) {
@@ -1086,8 +1140,16 @@ status_t AudioTrack::createTrack_l()
// there _is_ a frameCount parameter. We silently ignore it.
frameCount = mSharedBuffer->size() / mFrameSize;
} else {
- // For fast and normal streaming tracks,
- // the frame count calculations and checks are done by server
+ // For fast tracks the frame count calculations and checks are done by server
+
+ if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) == 0) {
+ // for normal tracks precompute the frame count based on speed.
+ const size_t minFrameCount = calculateMinFrameCount(
+ afLatency, afFrameCount, afSampleRate, mSampleRate, mSpeed);
+ if (frameCount < minFrameCount) {
+ frameCount = minFrameCount;
+ }
+ }
}
IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
@@ -1230,6 +1292,7 @@ status_t AudioTrack::createTrack_l()
}
mAudioTrack->attachAuxEffect(mAuxEffectId);
+ // FIXME doesn't take into account speed or future sample rate changes (until restoreTrack)
// FIXME don't believe this lie
mLatency = afLatency + (1000*frameCount) / mSampleRate;
@@ -1255,6 +1318,7 @@ status_t AudioTrack::createTrack_l()
mProxy->setSendLevel(mSendLevel);
mProxy->setSampleRate(mSampleRate);
+ mProxy->setPlaybackRate(mSpeed, mPitch);
mProxy->setMinimum(mNotificationFramesAct);
mDeathNotifier = new DeathNotifier(this);
@@ -1617,6 +1681,7 @@ nsecs_t AudioTrack::processAudioBuffer()
// Cache other fields that will be needed soon
uint32_t sampleRate = mSampleRate;
+ float speed = mSpeed;
uint32_t notificationFrames = mNotificationFramesAct;
if (mRefreshRemaining) {
mRefreshRemaining = false;
@@ -1745,7 +1810,7 @@ nsecs_t AudioTrack::processAudioBuffer()
if (minFrames != (uint32_t) ~0) {
// This "fudge factor" avoids soaking CPU, and compensates for late progress by server
static const nsecs_t kFudgeNs = 10000000LL; // 10 ms
- ns = ((minFrames * 1000000000LL) / sampleRate) + kFudgeNs;
+ ns = ((double)minFrames * 1000000000) / ((double)sampleRate * speed) + kFudgeNs;
}
// If not supplying data by EVENT_MORE_DATA, then we're done
@@ -1786,7 +1851,8 @@ nsecs_t AudioTrack::processAudioBuffer()
if (mRetryOnPartialBuffer && !isOffloaded()) {
mRetryOnPartialBuffer = false;
if (avail < mRemainingFrames) {
- int64_t myns = ((mRemainingFrames - avail) * 1100000000LL) / sampleRate;
+ int64_t myns = ((double)(mRemainingFrames - avail) * 1100000000)
+ / ((double)sampleRate * speed);
if (ns < 0 || myns < ns) {
ns = myns;
}
@@ -1841,7 +1907,7 @@ nsecs_t AudioTrack::processAudioBuffer()
// that total to a sum == notificationFrames.
if (0 < misalignment && misalignment <= mRemainingFrames) {
mRemainingFrames = misalignment;
- return (mRemainingFrames * 1100000000LL) / sampleRate;
+ return ((double)mRemainingFrames * 1100000000) / ((double)sampleRate * speed);
}
#endif
@@ -1936,6 +2002,41 @@ uint32_t AudioTrack::updateAndGetPosition_l()
return mPosition += (uint32_t) delta;
}
+bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
+{
+ // applicable for mixing tracks only (not offloaded or direct)
+ if (mStaticProxy != 0) {
+ return true; // static tracks do not have issues with buffer sizing.
+ }
+ status_t status;
+ uint32_t afLatency;
+ status = AudioSystem::getLatency(mOutput, &afLatency);
+ if (status != NO_ERROR) {
+ ALOGE("getLatency(%d) failed status %d", mOutput, status);
+ return false;
+ }
+
+ size_t afFrameCount;
+ status = AudioSystem::getFrameCount(mOutput, &afFrameCount);
+ if (status != NO_ERROR) {
+ ALOGE("getFrameCount(output=%d) status %d", mOutput, status);
+ return false;
+ }
+
+ uint32_t afSampleRate;
+ status = AudioSystem::getSamplingRate(mOutput, &afSampleRate);
+ if (status != NO_ERROR) {
+ ALOGE("getSamplingRate(output=%d) status %d", mOutput, status);
+ return false;
+ }
+
+ const size_t minFrameCount =
+ calculateMinFrameCount(afLatency, afFrameCount, afSampleRate, sampleRate, speed);
+ ALOGV("isSampleRateSpeedAllowed_l mFrameCount %zu minFrameCount %zu",
+ mFrameCount, minFrameCount);
+ return mFrameCount >= minFrameCount;
+}
+
status_t AudioTrack::setParameters(const String8& keyValuePairs)
{
AutoMutex lock(mLock);
@@ -2001,7 +2102,8 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
return WOULD_BLOCK; // stale timestamp time, occurs before start.
}
const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
- const int64_t deltaPositionByUs = timestamp.mPosition * 1000000LL / mSampleRate;
+ const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
+ / ((double)mSampleRate * mSpeed);
if (deltaPositionByUs > deltaTimeUs + kTimeJitterUs) {
// Verify that the counter can't count faster than the sample rate
@@ -2088,7 +2190,8 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args __unused) const
snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%zu)\n", mFormat,
mChannelCount, mFrameCount);
result.append(buffer);
- snprintf(buffer, 255, " sample rate(%u), status(%d)\n", mSampleRate, mStatus);
+ snprintf(buffer, 255, " sample rate(%u), speed(%f), status(%d)\n",
+ mSampleRate, mSpeed, mStatus);
result.append(buffer);
snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, mLatency);
result.append(buffer);
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 6d5f1af..ba67b40 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -793,6 +793,16 @@ void AudioTrackServerProxy::tallyUnderrunFrames(uint32_t frameCount)
(void) android_atomic_or(CBLK_UNDERRUN, &cblk->mFlags);
}
+void AudioTrackServerProxy::getPlaybackRate(float *speed, float *pitch)
+{ // do not call from multiple threads without holding lock
+ AudioTrackPlaybackRate playbackRate;
+ if (mPlaybackRateObserver.poll(playbackRate)) {
+ mPlaybackRate = playbackRate;
+ }
+ *speed = mPlaybackRate.mSpeed;
+ *pitch = mPlaybackRate.mPitch;
+}
+
// ---------------------------------------------------------------------------
StaticAudioTrackServerProxy::StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers,
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index c26c5bf..23308c1 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <binder/Parcel.h>
+#include <binder/IMemory.h>
#include <media/ICrypto.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -97,7 +98,7 @@ struct BpCrypto : public BpInterface<ICrypto> {
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
- const void *srcPtr,
+ const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
AString *errorDetailMsg) {
@@ -126,7 +127,8 @@ struct BpCrypto : public BpInterface<ICrypto> {
}
data.writeInt32(totalSize);
- data.write(srcPtr, totalSize);
+ data.writeStrongBinder(IInterface::asBinder(sharedBuffer));
+ data.writeInt32(offset);
data.writeInt32(numSubSamples);
data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples);
@@ -245,8 +247,9 @@ status_t BnCrypto::onTransact(
data.read(iv, sizeof(iv));
size_t totalSize = data.readInt32();
- void *srcData = malloc(totalSize);
- data.read(srcData, totalSize);
+ sp<IMemory> sharedBuffer =
+ interface_cast<IMemory>(data.readStrongBinder());
+ int32_t offset = data.readInt32();
int32_t numSubSamples = data.readInt32();
@@ -265,15 +268,21 @@ status_t BnCrypto::onTransact(
}
AString errorDetailMsg;
- ssize_t result = decrypt(
+ ssize_t result;
+
+ if (offset + totalSize > sharedBuffer->size()) {
+ result = -EINVAL;
+ } else {
+ result = decrypt(
secure,
key,
iv,
mode,
- srcData,
+ sharedBuffer, offset,
subSamples, numSubSamples,
dstPtr,
&errorDetailMsg);
+ }
reply->writeInt32(result);
@@ -294,9 +303,6 @@ status_t BnCrypto::onTransact(
delete[] subSamples;
subSamples = NULL;
- free(srcData);
- srcData = NULL;
-
return OK;
}
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 8ee7c0b..e768772 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -22,6 +22,7 @@
#include "Crypto.h"
+#include <binder/IMemory.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
@@ -238,7 +239,7 @@ ssize_t Crypto::decrypt(
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
- const void *srcPtr,
+ const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
AString *errorDetailMsg) {
@@ -252,6 +253,8 @@ ssize_t Crypto::decrypt(
return -EINVAL;
}
+ const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset;
+
return mPlugin->decrypt(
secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
errorDetailMsg);
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 0037c2e..d5f3c50 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -52,7 +52,7 @@ struct Crypto : public BnCrypto {
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
- const void *srcPtr,
+ const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
AString *errorDetailMsg);
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 49e01d1..62cf3e5 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -136,22 +136,54 @@ void Drm::sendEvent(DrmPlugin::EventType eventType, int extra,
if (listener != NULL) {
Parcel obj;
- if (sessionId && sessionId->size()) {
- obj.writeInt32(sessionId->size());
- obj.write(sessionId->array(), sessionId->size());
- } else {
- obj.writeInt32(0);
- }
+ writeByteArray(obj, sessionId);
+ writeByteArray(obj, data);
- if (data && data->size()) {
- obj.writeInt32(data->size());
- obj.write(data->array(), data->size());
- } else {
- obj.writeInt32(0);
+ Mutex::Autolock lock(mNotifyLock);
+ listener->notify(eventType, extra, &obj);
+ }
+}
+
+void Drm::sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS)
+{
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Parcel obj;
+ writeByteArray(obj, sessionId);
+ obj.writeInt64(expiryTimeInMS);
+
+ Mutex::Autolock lock(mNotifyLock);
+ listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+ }
+}
+
+void Drm::sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+ bool hasNewUsableKey)
+{
+ mEventLock.lock();
+ sp<IDrmClient> listener = mListener;
+ mEventLock.unlock();
+
+ if (listener != NULL) {
+ Parcel obj;
+ writeByteArray(obj, sessionId);
+
+ size_t nkeys = keyStatusList->size();
+ obj.writeInt32(keyStatusList->size());
+ for (size_t i = 0; i < nkeys; ++i) {
+ const DrmPlugin::KeyStatus *keyStatus = &keyStatusList->itemAt(i);
+ writeByteArray(obj, &keyStatus->mKeyId);
+ obj.writeInt32(keyStatus->mType);
}
+ obj.writeInt32(hasNewUsableKey);
Mutex::Autolock lock(mNotifyLock);
- listener->notify(eventType, extra, &obj);
+ listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
}
}
@@ -756,4 +788,14 @@ void Drm::binderDied(const wp<IBinder> &the_late_who)
closeFactory();
}
+void Drm::writeByteArray(Parcel &obj, Vector<uint8_t> const *array)
+{
+ if (array && array->size()) {
+ obj.writeInt32(array->size());
+ obj.write(array->array(), array->size());
+ } else {
+ obj.writeInt32(0);
+ }
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 7e8f246..1591738 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -133,6 +133,13 @@ struct Drm : public BnDrm,
Vector<uint8_t> const *sessionId,
Vector<uint8_t> const *data);
+ virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId,
+ int64_t expiryTimeInMS);
+
+ virtual void sendKeysChange(Vector<uint8_t> const *sessionId,
+ Vector<DrmPlugin::KeyStatus> const *keyStatusList,
+ bool hasNewUsableKey);
+
virtual void binderDied(const wp<IBinder> &the_late_who);
private:
@@ -157,7 +164,7 @@ private:
void findFactoryForScheme(const uint8_t uuid[16]);
bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
void closeFactory();
-
+ void writeByteArray(Parcel &obj, Vector<uint8_t> const *array);
DISALLOW_EVIL_CONSTRUCTORS(Drm);
};
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index 427bf7b..8fbb57c 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -136,6 +136,8 @@ status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
--size;
if (streamDependenceFlag) {
+ if (size < 2)
+ return ERROR_MALFORMED;
offset += 2;
size -= 2;
}
@@ -145,11 +147,15 @@ status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
return ERROR_MALFORMED;
}
unsigned URLlength = mData[offset];
+ if (URLlength >= size)
+ return ERROR_MALFORMED;
offset += URLlength + 1;
size -= URLlength + 1;
}
if (OCRstreamFlag) {
+ if (size < 2)
+ return ERROR_MALFORMED;
offset += 2;
size -= 2;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index d0f42cc..f7fa2b6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -874,6 +874,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->sampleTable = new SampleTable(mDataSource);
}
@@ -1028,6 +1031,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
original_fourcc = ntohl(original_fourcc);
ALOGV("read original format: %d", original_fourcc);
+
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(original_fourcc));
uint32_t num_channels = 0;
uint32_t sample_rate = 0;
@@ -1083,6 +1090,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyCryptoMode, defaultAlgorithmId);
mLastTrack->meta->setInt32(kKeyCryptoDefaultIVSize, defaultIVSize);
mLastTrack->meta->setData(kKeyCryptoKey, 'tenc', defaultKeyId, 16);
@@ -1168,6 +1178,11 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (!timescale) {
+ ALOGE("timescale should not be ZERO.");
+ return ERROR_MALFORMED;
+ }
+
mLastTrack->timescale = ntohl(timescale);
// 14496-12 says all ones means indeterminate, but some files seem to use
@@ -1193,7 +1208,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
duration = ntohl(duration32);
}
}
- if (duration != 0) {
+ if (duration != 0 && mLastTrack->timescale != 0) {
mLastTrack->meta->setInt64(
kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
}
@@ -1257,6 +1272,10 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// display the timed text.
// For encrypted files, there may also be more than one entry.
const char *mime;
+
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) &&
strcasecmp(mime, "application/octet-stream")) {
@@ -1303,6 +1322,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
uint16_t sample_size = U16_AT(&buffer[18]);
uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
if (chunk_type != FOURCC('e', 'n', 'c', 'a')) {
// if the chunk type is enca, we'll get the type from the sinf/frma box later
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
@@ -1364,6 +1386,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
// printf("*** coding='%s' width=%d height=%d\n",
// chunk, width, height);
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
if (chunk_type != FOURCC('e', 'n', 'c', 'v')) {
// if the chunk type is encv, we'll get the type from the sinf/frma box later
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
@@ -1389,6 +1414,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 'c', 'o'):
case FOURCC('c', 'o', '6', '4'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setChunkOffsetParams(
chunk_type, data_offset, chunk_data_size);
@@ -1404,6 +1432,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 'c'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setSampleToChunkParams(
data_offset, chunk_data_size);
@@ -1420,6 +1451,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 'z'):
case FOURCC('s', 't', 'z', '2'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
status_t err =
mLastTrack->sampleTable->setSampleSizeParams(
chunk_type, data_offset, chunk_data_size);
@@ -1489,6 +1523,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 't', 's'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
*offset += chunk_size;
status_t err =
@@ -1504,6 +1541,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('c', 't', 't', 's'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
*offset += chunk_size;
status_t err =
@@ -1519,6 +1559,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('s', 't', 's', 's'):
{
+ if ((mLastTrack == NULL) || (mLastTrack->sampleTable == NULL))
+ return ERROR_MALFORMED;
+
*offset += chunk_size;
status_t err =
@@ -1591,6 +1634,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
@@ -1623,6 +1669,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyAVCC, kTypeAVCC, buffer->data(), chunk_data_size);
@@ -1637,6 +1686,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(
kKeyHVCC, kTypeHVCC, buffer->data(), chunk_data_size);
@@ -1670,6 +1722,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size);
break;
@@ -1767,7 +1822,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
duration = d32;
}
- if (duration != 0) {
+ if (duration != 0 && mHeaderTimescale != 0) {
mFileMetaData->setInt64(kKeyDuration, duration * 1000000 / mHeaderTimescale);
}
@@ -1816,7 +1871,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
}
- if (duration != 0) {
+ if (duration != 0 && mHeaderTimescale != 0) {
mFileMetaData->setInt64(kKeyDuration, duration * 1000000 / mHeaderTimescale);
}
@@ -1851,6 +1906,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_IO;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
uint32_t type = ntohl(buffer);
// For the 3GPP file format, the handler-type within the 'hdlr' box
// shall be 'text'. We also want to support 'sbtl' handler type
@@ -1883,6 +1941,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
case FOURCC('t', 'x', '3', 'g'):
{
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
uint32_t type;
const void *data;
size_t size = 0;
@@ -2024,6 +2085,8 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
return ERROR_MALFORMED;
}
ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale);
+ if (timeScale == 0)
+ return ERROR_MALFORMED;
uint64_t earliestPresentationTime;
uint64_t firstOffset;
@@ -2107,6 +2170,9 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) {
uint64_t sidxDuration = total_duration * 1000000 / timeScale;
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
int64_t metaDuration;
if (!mLastTrack->meta->findInt64(kKeyDuration, &metaDuration) || metaDuration == 0) {
mLastTrack->meta->setInt64(kKeyDuration, sidxDuration);
@@ -2157,6 +2223,9 @@ status_t MPEG4Extractor::parseTrackHeader(
return ERROR_UNSUPPORTED;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyTrackID, id);
size_t matrixOffset = dynSize + 16;
@@ -2339,6 +2408,9 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) {
int32_t delay, padding;
if (sscanf(mLastCommentData,
" %*x %x %x %*x", &delay, &padding) == 2) {
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setInt32(kKeyEncoderDelay, delay);
mLastTrack->meta->setInt32(kKeyEncoderPadding, padding);
}
@@ -2635,6 +2707,11 @@ status_t MPEG4Extractor::verifyTrack(Track *track) {
return ERROR_MALFORMED;
}
+ if (track->timescale == 0) {
+ ALOGE("timescale invalid.");
+ return ERROR_MALFORMED;
+ }
+
return OK;
}
@@ -2701,6 +2778,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
if (objectTypeIndication == 0xe1) {
// This isn't MPEG4 audio at all, it's QCELP 14k...
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
return OK;
}
@@ -2749,6 +2829,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
objectType = 32 + br.getBits(6);
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
//keep AOT type
mLastTrack->meta->setInt32(kKeyAACAOT, objectType);
@@ -2919,6 +3002,9 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
return ERROR_UNSUPPORTED;
}
+ if (mLastTrack == NULL)
+ return ERROR_MALFORMED;
+
int32_t prevSampleRate;
CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 433f555..2641e4e 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -92,6 +92,11 @@ void MediaClock::setPlaybackRate(float rate) {
mPlaybackRate = rate;
}
+float MediaClock::getPlaybackRate() const {
+ Mutex::Autolock autoLock(mLock);
+ return mPlaybackRate;
+}
+
status_t MediaClock::getMediaTime(
int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) const {
if (outMediaUs == NULL) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 0597f1d..8186f63 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,7 +22,9 @@
#include "include/SoftwareRenderer.h"
#include <binder/IBatteryStats.h>
+#include <binder/IMemory.h>
#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
#include <gui/Surface.h>
#include <media/ICrypto.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -969,6 +971,17 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
size_t numBuffers = portDesc->countBuffers();
+ size_t totalSize = 0;
+ for (size_t i = 0; i < numBuffers; ++i) {
+ if (portIndex == kPortIndexInput && mCrypto != NULL) {
+ totalSize += portDesc->bufferAt(i)->capacity();
+ }
+ }
+
+ if (totalSize) {
+ mDealer = new MemoryDealer(totalSize, "MediaCodec");
+ }
+
for (size_t i = 0; i < numBuffers; ++i) {
BufferInfo info;
info.mBufferID = portDesc->bufferIDAt(i);
@@ -976,8 +989,10 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
info.mData = portDesc->bufferAt(i);
if (portIndex == kPortIndexInput && mCrypto != NULL) {
+ sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
info.mEncryptedData =
- new ABuffer(info.mData->capacity());
+ new ABuffer(mem->pointer(), info.mData->capacity());
+ info.mSharedEncryptedBuffer = mem;
}
buffers->push_back(info);
@@ -1953,7 +1968,8 @@ status_t MediaCodec::onQueueInputBuffer(const sp<AMessage> &msg) {
key,
iv,
mode,
- info->mEncryptedData->base() + offset,
+ info->mSharedEncryptedBuffer,
+ offset,
subSamples,
numSubSamples,
info->mData->base(),
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index bdd6d56..aba64d5 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -230,8 +230,13 @@ status_t SampleTable::setSampleToChunkParams(
return ERROR_MALFORMED;
}
+ if (SIZE_MAX / sizeof(SampleToChunkEntry) <= mNumSampleToChunkOffsets)
+ return ERROR_OUT_OF_RANGE;
+
mSampleToChunkEntries =
- new SampleToChunkEntry[mNumSampleToChunkOffsets];
+ new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets];
+ if (!mSampleToChunkEntries)
+ return ERROR_OUT_OF_RANGE;
for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
uint8_t buffer[12];
@@ -330,11 +335,13 @@ status_t SampleTable::setTimeToSampleParams(
}
mTimeToSampleCount = U32_AT(&header[4]);
- uint64_t allocSize = mTimeToSampleCount * 2 * sizeof(uint32_t);
+ uint64_t allocSize = mTimeToSampleCount * 2 * (uint64_t)sizeof(uint32_t);
if (allocSize > SIZE_MAX) {
return ERROR_OUT_OF_RANGE;
}
- mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
+ mTimeToSample = new (std::nothrow) uint32_t[mTimeToSampleCount * 2];
+ if (!mTimeToSample)
+ return ERROR_OUT_OF_RANGE;
size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
if (mDataSource->readAt(
@@ -376,12 +383,14 @@ status_t SampleTable::setCompositionTimeToSampleParams(
}
mNumCompositionTimeDeltaEntries = numEntries;
- uint64_t allocSize = numEntries * 2 * sizeof(uint32_t);
+ uint64_t allocSize = numEntries * 2 * (uint64_t)sizeof(uint32_t);
if (allocSize > SIZE_MAX) {
return ERROR_OUT_OF_RANGE;
}
- mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
+ mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries];
+ if (!mCompositionTimeDeltaEntries)
+ return ERROR_OUT_OF_RANGE;
if (mDataSource->readAt(
data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
@@ -426,12 +435,15 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size)
ALOGV("Table of sync samples is empty or has only a single entry!");
}
- uint64_t allocSize = mNumSyncSamples * sizeof(uint32_t);
+ uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t);
if (allocSize > SIZE_MAX) {
return ERROR_OUT_OF_RANGE;
}
- mSyncSamples = new uint32_t[mNumSyncSamples];
+ mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples];
+ if (!mSyncSamples)
+ return ERROR_OUT_OF_RANGE;
+
size_t size = mNumSyncSamples * sizeof(uint32_t);
if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size)
!= (ssize_t)size) {
@@ -499,7 +511,9 @@ void SampleTable::buildSampleEntriesTable() {
return;
}
- mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
+ mSampleTimeEntries = new (std::nothrow) SampleTimeEntry[mNumSampleSizes];
+ if (!mSampleTimeEntries)
+ return;
uint32_t sampleIndex = 0;
uint32_t sampleTime = 0;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 9586d92..74f58e9 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -498,16 +498,15 @@ void LiveSession::onMessageReceived(const sp<AMessage> &msg) {
case kWhatSeek:
{
- sp<AReplyToken> seekReplyID;
- CHECK(msg->senderAwaitsResponse(&seekReplyID));
- mSeekReplyID = seekReplyID;
- mSeekReply = new AMessage;
-
- status_t err = onSeek(msg);
-
- if (err != OK) {
+ if (mReconfigurationInProgress) {
msg->post(50000);
+ break;
}
+
+ CHECK(msg->senderAwaitsResponse(&mSeekReplyID));
+ mSeekReply = new AMessage;
+
+ onSeek(msg);
break;
}
@@ -1372,16 +1371,10 @@ HLSTime LiveSession::latestMediaSegmentStartTime() const {
return audioTime < videoTime ? videoTime : audioTime;
}
-status_t LiveSession::onSeek(const sp<AMessage> &msg) {
+void LiveSession::onSeek(const sp<AMessage> &msg) {
int64_t timeUs;
CHECK(msg->findInt64("timeUs", &timeUs));
-
- if (!mReconfigurationInProgress) {
- changeConfiguration(timeUs);
- return OK;
- } else {
- return -EWOULDBLOCK;
- }
+ changeConfiguration(timeUs);
}
status_t LiveSession::getDuration(int64_t *durationUs) const {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 6345a50..9117bb1 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -237,7 +237,7 @@ private:
sp<PlaylistFetcher> addFetcher(const char *uri);
void onConnect(const sp<AMessage> &msg);
- status_t onSeek(const sp<AMessage> &msg);
+ void onSeek(const sp<AMessage> &msg);
void onFinishDisconnect2();
// If given a non-zero block_size (default 0), it is used to cap the number of
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 1f43d6d..33cfd1d 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -85,12 +85,6 @@ status_t MPEG2TSSource::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- return ERROR_UNSUPPORTED;
- }
-
status_t finalResult;
while (!mImpl->hasBufferAvailable(&finalResult)) {
if (finalResult != OK) {
@@ -103,6 +97,17 @@ status_t MPEG2TSSource::read(
}
}
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode seekMode;
+ if (mSeekable && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
+ // A seek was requested, but we don't actually support seeking and so can only "seek" to
+ // the current position
+ int64_t nextBufTimeUs;
+ if (mImpl->nextBufferTime(&nextBufTimeUs) != OK || seekTimeUs != nextBufTimeUs) {
+ return ERROR_UNSUPPORTED;
+ }
+ }
+
return mImpl->read(out, options);
}
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index 9b6958a..3ab241a 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -85,7 +85,7 @@ OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
void *libHandle = dlopen(libName.c_str(), RTLD_NOW);
if (libHandle == NULL) {
- ALOGE("unable to dlopen %s", libName.c_str());
+ ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror());
return OMX_ErrorComponentNotFound;
}