Merge "Remove dependencies on hardware/audio_effects.h and EffectsFactoryApi.h"
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 88c4e61..4e2b740 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -1056,6 +1056,10 @@
// after flush.
int64_t mFramesWrittenServerOffset; // An offset to server frames due to
// restoring AudioTrack, or stop/start.
+ // This offset is also used for static tracks.
+ int64_t mFramesWrittenAtRestore; // Frames written at restore point (or frames
+ // delivered for static tracks).
+ // -1 indicates no previous restore point.
audio_output_flags_t mFlags; // same as mOrigFlags, except for bits that may
// be denied by client or server, such as
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index c02742c..cdfe2c9 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -76,21 +76,15 @@
size_t countBuffers();
IOMX::buffer_id bufferIDAt(size_t index) const;
sp<MediaCodecBuffer> bufferAt(size_t index) const;
- sp<NativeHandle> handleAt(size_t index) const;
- sp<RefBase> memRefAt(size_t index) const;
private:
friend struct ACodec;
Vector<IOMX::buffer_id> mBufferIDs;
Vector<sp<MediaCodecBuffer>> mBuffers;
- Vector<sp<NativeHandle> > mHandles;
- Vector<sp<RefBase> > mMemRefs;
PortDescription();
- void addBuffer(
- IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer,
- const sp<NativeHandle> &handle, const sp<RefBase> &memRef);
+ void addBuffer(IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
};
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index 13f82f0..1295b59 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -90,8 +90,6 @@
virtual size_t countBuffers() = 0;
virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
virtual sp<MediaCodecBuffer> bufferAt(size_t index) const = 0;
- virtual sp<NativeHandle> handleAt(size_t index) const { return NULL; };
- virtual sp<RefBase> memRefAt(size_t index) const { return NULL; }
protected:
PortDescription();
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index e3e5c2d..19d7047 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -255,9 +255,7 @@
struct BufferInfo {
uint32_t mBufferID;
sp<MediaCodecBuffer> mData;
- sp<NativeHandle> mNativeHandle;
- sp<RefBase> mMemRef;
- sp<MediaCodecBuffer> mEncryptedData;
+ sp<MediaCodecBuffer> mSecureData;
sp<IMemory> mSharedEncryptedBuffer;
sp<AMessage> mNotify;
sp<AMessage> mFormat;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c96f16a..516a558 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -50,6 +50,8 @@
return x > y ? x : y;
}
+static const int32_t NANOS_PER_SECOND = 1000000000;
+
static inline nsecs_t framesToNanoseconds(ssize_t frames, uint32_t sampleRate, float speed)
{
return ((double)frames * 1000000000) / ((double)sampleRate * speed);
@@ -60,6 +62,11 @@
return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
}
+static inline nsecs_t convertTimespecToNs(const struct timespec &tv)
+{
+ return tv.tv_sec * (long long)NANOS_PER_SECOND + tv.tv_nsec;
+}
+
// current monotonic time in microseconds.
static int64_t getNowUs()
{
@@ -539,6 +546,7 @@
mUnderrunCountOffset = 0;
mFramesWritten = 0;
mFramesWrittenServerOffset = 0;
+ mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
return NO_ERROR;
}
@@ -2181,10 +2189,12 @@
mUnderrunCountOffset = getUnderrunCount_l();
// save the old static buffer position
+ uint32_t staticPosition = 0;
size_t bufferPosition = 0;
int loopCount = 0;
if (mStaticProxy != 0) {
mStaticProxy->getBufferPositionAndLoopCount(&bufferPosition, &loopCount);
+ staticPosition = mStaticProxy->getPosition().unsignedValue();
}
mFlags = mOrigFlags;
@@ -2216,8 +2226,11 @@
}
if (mState == STATE_ACTIVE) {
result = mAudioTrack->start();
- mFramesWrittenServerOffset = mFramesWritten; // server resets to zero so we offset
}
+ // server resets to zero so we offset
+ mFramesWrittenServerOffset =
+ mStaticProxy.get() != nullptr ? staticPosition : mFramesWritten;
+ mFramesWrittenAtRestore = mFramesWrittenServerOffset;
}
if (result != NO_ERROR) {
ALOGW("restoreTrack_l() failed status %d", result);
@@ -2393,6 +2406,26 @@
ALOGV_IF(mPreviousLocation == ExtendedTimestamp::LOCATION_SERVER,
"getTimestamp() location moved from server to kernel");
}
+
+ // We update the timestamp time even when paused.
+ if (mState == STATE_PAUSED /* not needed: STATE_PAUSED_STOPPING */) {
+ const int64_t now = systemTime();
+ const int64_t at = convertTimespecToNs(timestamp.mTime);
+ const int64_t lag =
+ (ets.mTimeNs[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK] < 0 ||
+ ets.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK] < 0)
+ ? int64_t(mAfLatency * 1000000LL)
+ : (ets.mPosition[ExtendedTimestamp::LOCATION_SERVER_LASTKERNELOK]
+ - ets.mPosition[ExtendedTimestamp::LOCATION_KERNEL_LASTKERNELOK])
+ * NANOS_PER_SECOND / mSampleRate;
+ const int64_t limit = now - lag; // no earlier than this limit
+ if (at < limit) {
+ ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
+ (long long)lag, (long long)at, (long long)limit);
+ timestamp.mTime.tv_sec = limit / NANOS_PER_SECOND;
+ timestamp.mTime.tv_nsec = limit % NANOS_PER_SECOND; // compiler opt.
+ }
+ }
mPreviousLocation = location;
} else {
// right after AudioTrack is started, one may not find a timestamp
@@ -2400,7 +2433,17 @@
}
}
if (status == INVALID_OPERATION) {
- status = WOULD_BLOCK;
+ // INVALID_OPERATION occurs when no timestamp has been issued by the server;
+ // other failures are signaled by a negative time.
+ // If we come out of FLUSHED or STOPPED where the position is known
+ // to be zero we convert this to WOULD_BLOCK (with the implicit meaning of
+ // "zero" for NuPlayer). We don't convert for track restoration as position
+ // does not reset.
+ ALOGV("timestamp server offset:%lld restore frames:%lld",
+ (long long)mFramesWrittenServerOffset, (long long)mFramesWrittenAtRestore);
+ if (mFramesWrittenServerOffset != mFramesWrittenAtRestore) {
+ status = WOULD_BLOCK;
+ }
}
}
if (status != NO_ERROR) {
@@ -2412,6 +2455,7 @@
// use cached paused position in case another offloaded track is running.
timestamp.mPosition = mPausedPosition;
clock_gettime(CLOCK_MONOTONIC, ×tamp.mTime);
+ // TODO: adjust for delay
return NO_ERROR;
}
@@ -2498,21 +2542,18 @@
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
if (previousTimestampValid) {
-#define TIME_TO_NANOS(time) ((int64_t)(time).tv_sec * 1000000000 + (time).tv_nsec)
- const int64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
- const int64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
-#undef TIME_TO_NANOS
+ const int64_t previousTimeNanos = convertTimespecToNs(mPreviousTimestamp.mTime);
+ const int64_t currentTimeNanos = convertTimespecToNs(timestamp.mTime);
if (currentTimeNanos < previousTimeNanos) {
- ALOGW("retrograde timestamp time");
- // FIXME Consider blocking this from propagating upwards.
+ ALOGW("retrograde timestamp time corrected, %lld < %lld",
+ (long long)currentTimeNanos, (long long)previousTimeNanos);
+ timestamp.mTime = mPreviousTimestamp.mTime;
}
// Looking at signed delta will work even when the timestamps
// are wrapping around.
int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
- mPreviousTimestamp.mPosition).signedValue();
- // position can bobble slightly as an artifact; this hides the bobble
- static const int32_t MINIMUM_POSITION_DELTA = 8;
if (deltaPosition < 0) {
// Only report once per position instead of spamming the log.
if (!mRetrogradeMotionReported) {
@@ -2525,9 +2566,21 @@
} else {
mRetrogradeMotionReported = false;
}
- if (deltaPosition < MINIMUM_POSITION_DELTA) {
- timestamp = mPreviousTimestamp; // Use last valid timestamp.
+ if (deltaPosition < 0) {
+ timestamp.mPosition = mPreviousTimestamp.mPosition;
+ deltaPosition = 0;
}
+#if 0
+ // Uncomment this to verify audio timestamp rate.
+ const int64_t deltaTime =
+ convertTimespecToNs(timestamp.mTime) - previousTimeNanos;
+ if (deltaTime != 0) {
+ const int64_t computedSampleRate =
+ deltaPosition * (long long)NANOS_PER_SECOND / deltaTime;
+ ALOGD("computedSampleRate:%u sampleRate:%u",
+ (unsigned)computedSampleRate, mSampleRate);
+ }
+#endif
}
mPreviousTimestamp = timestamp;
mPreviousTimestampValid = true;
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index eb88efd..94c96f6 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -160,6 +160,9 @@
if (data.readUint32(&idx) == NO_ERROR &&
data.readUint32(&flags) == NO_ERROR) {
sp<MetaData> meta = getTrackMetaData(idx, flags);
+ if (meta == NULL) {
+ return UNKNOWN_ERROR;
+ }
meta->writeToParcel(*reply);
return NO_ERROR;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index d45dbcd..f619e1d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1521,57 +1521,45 @@
}
uint32_t numFramesPlayed;
- int64_t numFramesPlayedAt;
+ int64_t numFramesPlayedAtUs;
AudioTimestamp ts;
- static const int64_t kStaleTimestamp100ms = 100000;
status_t res = mTrack->getTimestamp(ts);
if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
numFramesPlayed = ts.mPosition;
- numFramesPlayedAt = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- const int64_t timestampAge = nowUs - numFramesPlayedAt;
- if (timestampAge > kStaleTimestamp100ms) {
- // This is an audio FIXME.
- // getTimestamp returns a timestamp which may come from audio mixing threads.
- // After pausing, the MixerThread may go idle, thus the mTime estimate may
- // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
- // the max latency should be about 25ms with an average around 12ms (to be verified).
- // For safety we use 100ms.
- ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
- (long long)nowUs, (long long)numFramesPlayedAt);
- numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
- }
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+ //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
} else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
numFramesPlayed = 0;
- numFramesPlayedAt = nowUs;
+ numFramesPlayedAtUs = nowUs;
//ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAt);
+ // numFramesPlayed, (long long)numFramesPlayedAtUs);
} else { // case 3: transitory at new track or audio fast tracks.
res = mTrack->getPosition(&numFramesPlayed);
CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAt = nowUs;
- numFramesPlayedAt += 1000LL * mTrack->latency() / 2; /* XXX */
- //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ numFramesPlayedAtUs = nowUs;
+ numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
+ //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
}
// CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
// TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
- + nowUs - numFramesPlayedAt;
+ + nowUs - numFramesPlayedAtUs;
if (durationUs < 0) {
// Occurs when numFramesPlayed position is very small and the following:
// (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
+ // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
// (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
+ // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
//
// Both of these are transitory conditions.
ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
durationUs = 0;
}
ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
+ (long long)durationUs, (long long)nowUs,
+ numFramesPlayed, (long long)numFramesPlayedAtUs);
return durationUs;
}
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index db24b33..ebba93c 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -30,6 +30,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/Utils.h>
namespace android {
@@ -100,26 +101,38 @@
void NuPlayer::HTTPLiveSource::start() {
}
-sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
- sp<AMessage> format;
- status_t err = -EWOULDBLOCK;
+sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
+ sp<MetaData> meta;
if (mLiveSession != NULL) {
- err = mLiveSession->getStreamFormat(
+ mLiveSession->getStreamFormatMeta(
audio ? LiveSession::STREAMTYPE_AUDIO
: LiveSession::STREAMTYPE_VIDEO,
- &format);
+ &meta);
}
+ return meta;
+}
+
+sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
+ sp<MetaData> meta;
+ status_t err = -EWOULDBLOCK;
+ if (mLiveSession != NULL) {
+ err = mLiveSession->getStreamFormatMeta(
+ audio ? LiveSession::STREAMTYPE_AUDIO
+ : LiveSession::STREAMTYPE_VIDEO,
+ &meta);
+ }
+
+ sp<AMessage> format;
if (err == -EWOULDBLOCK) {
format = new AMessage();
format->setInt32("err", err);
return format;
}
- if (err != OK) {
+ if (err != OK || convertMetaDataToMessage(meta, &format) != OK) {
return NULL;
}
-
return format;
}
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 9e0ec2f..574937d 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -38,6 +38,7 @@
virtual void start();
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
+ virtual sp<MetaData> getFormatMeta(bool audio);
virtual sp<AMessage> getFormat(bool audio);
virtual status_t feedMoreTSData();
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index c4e5df7..7ce909d 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -258,7 +258,7 @@
}
status_t NuPlayer::RTSPSource::getDuration(int64_t *durationUs) {
- *durationUs = 0ll;
+ *durationUs = -1ll;
int64_t audioDurationUs;
if (mAudioTrack != NULL
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index a7c5cf4..7f9f913 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -228,6 +228,10 @@
}
sp<MetaData> meta = source->getFormat();
+ if (meta == NULL) {
+ format->setInt32("err", -EWOULDBLOCK);
+ return format;
+ }
status_t err = convertMetaDataToMessage(meta, &format);
if (err != OK) { // format may have been cleared on error
format = new AMessage;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 478de35..dbb5f0d 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -53,6 +53,7 @@
#include "include/avc_utils.h"
#include "include/DataConverter.h"
+#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
#include "omx/OMXUtils.h"
@@ -876,7 +877,6 @@
info.mStatus = BufferInfo::OWNED_BY_US;
info.mFenceFd = -1;
info.mRenderInfo = NULL;
- info.mNativeHandle = NULL;
if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
mem.clear();
@@ -887,19 +887,9 @@
portIndex, bufSize, &info.mBufferID,
&ptr, &native_handle);
- // TRICKY: this representation is unorthodox, but ACodec requires
- // an ABuffer with a proper size to validate range offsets and lengths.
- // Since mData is never referenced for secure input, it is used to store
- // either the pointer to the secure buffer, or the opaque handle as on
- // some devices ptr is actually an opaque handle, not a pointer.
-
- // TRICKY2: use native handle as the base of the ABuffer if received one,
- // because Widevine source only receives these base addresses.
- const native_handle_t *native_handle_ptr =
- native_handle == NULL ? NULL : native_handle->handle();
- info.mData = new MediaCodecBuffer(format,
- new ABuffer(ptr != NULL ? ptr : (void *)native_handle_ptr, bufSize));
- info.mNativeHandle = native_handle;
+ info.mData = (native_handle == NULL)
+ ? new SecureBuffer(format, ptr, bufSize)
+ : new SecureBuffer(format, native_handle, bufSize);
info.mCodecData = info.mData;
} else {
err = mOMXNode->useBuffer(
@@ -948,7 +938,7 @@
for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
const BufferInfo &info = mBuffers[portIndex][i];
- desc->addBuffer(info.mBufferID, info.mData, info.mNativeHandle, info.mMemRef);
+ desc->addBuffer(info.mBufferID, info.mData);
}
notify->setObject("portDesc", desc);
@@ -1215,7 +1205,6 @@
info.mCodecData = info.mData;
info.mCodecRef = mem;
- // we use useBuffer for metadata regardless of quirks
err = mOMXNode->useBuffer(
kPortIndexOutput, mem, &info.mBufferID, mem->size());
mBuffers[kPortIndexOutput].push(info);
@@ -5248,12 +5237,9 @@
}
void ACodec::PortDescription::addBuffer(
- IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer,
- const sp<NativeHandle> &handle, const sp<RefBase> &memRef) {
+ IOMX::buffer_id id, const sp<MediaCodecBuffer> &buffer) {
mBufferIDs.push_back(id);
mBuffers.push_back(buffer);
- mHandles.push_back(handle);
- mMemRefs.push_back(memRef);
}
size_t ACodec::PortDescription::countBuffers() {
@@ -5268,14 +5254,6 @@
return mBuffers.itemAt(index);
}
-sp<NativeHandle> ACodec::PortDescription::handleAt(size_t index) const {
- return mHandles.itemAt(index);
-}
-
-sp<RefBase> ACodec::PortDescription::memRefAt(size_t index) const {
- return mMemRefs.itemAt(index);
-}
-
////////////////////////////////////////////////////////////////////////////////
ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
diff --git a/media/libstagefright/BufferImpl.cpp b/media/libstagefright/BufferImpl.cpp
index 7d195d3..4ed7911 100644
--- a/media/libstagefright/BufferImpl.cpp
+++ b/media/libstagefright/BufferImpl.cpp
@@ -21,7 +21,10 @@
#include <binder/IMemory.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/ICrypto.h>
+#include <utils/NativeHandle.h>
+#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
namespace android {
@@ -31,4 +34,25 @@
mMemory(mem) {
}
+SecureBuffer::SecureBuffer(const sp<AMessage> &format, void *ptr, size_t size)
+ : MediaCodecBuffer(format, new ABuffer(nullptr, size)),
+ mPointer(ptr) {
+}
+
+SecureBuffer::SecureBuffer(
+ const sp<AMessage> &format, const sp<NativeHandle> &handle, size_t size)
+ : MediaCodecBuffer(format, new ABuffer(nullptr, size)),
+ mPointer(nullptr),
+ mHandle(handle) {
+}
+
+void *SecureBuffer::getDestinationPointer() {
+ return (void *)(mHandle == nullptr ? mPointer : mHandle->handle());
+}
+
+ICrypto::DestinationType SecureBuffer::getDestinationType() {
+ return mHandle == nullptr ? ICrypto::kDestinationTypeOpaqueHandle
+ : ICrypto::kDestinationTypeNativeHandle;
+}
+
} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index d37e973..ee603a4 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -478,7 +478,8 @@
} else {
uint32_t sampleIndex;
uint32_t sampleTime;
- if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
+ if (track->timescale != 0 &&
+ track->sampleTable->findThumbnailSample(&sampleIndex) == OK
&& track->sampleTable->getMetaDataForSample(
sampleIndex, NULL /* offset */, NULL /* size */,
&sampleTime) == OK) {
@@ -934,6 +935,10 @@
case FOURCC('e', 'd', 't', 's'):
case FOURCC('w', 'a', 'v', 'e'):
{
+ if (chunk_type == FOURCC('m', 'o', 'o', 'v') && depth != 0) {
+ ALOGE("moov: depth %d", depth);
+ return ERROR_MALFORMED;
+ }
if (chunk_type == FOURCC('m', 'o', 'o', 'f') && !mMoofFound) {
// store the offset of the first segment
mMoofFound = true;
@@ -962,6 +967,10 @@
bool isTrack = false;
if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
+ if (depth != 1) {
+ ALOGE("trak: depth %d", depth);
+ return ERROR_MALFORMED;
+ }
isTrack = true;
Track *track = new Track;
@@ -985,6 +994,10 @@
while (*offset < stop_offset) {
status_t err = parseChunk(offset, depth + 1);
if (err != OK) {
+ if (isTrack) {
+ mLastTrack->skipTrack = true;
+ break;
+ }
return err;
}
}
@@ -1330,10 +1343,6 @@
case FOURCC('s', 't', 's', 'd'):
{
- if (chunk_data_size < 8) {
- return ERROR_MALFORMED;
- }
-
uint8_t buffer[8];
if (chunk_data_size < (off64_t)sizeof(buffer)) {
return ERROR_MALFORMED;
@@ -2000,6 +2009,10 @@
{
*offset += chunk_size;
+ if (depth != 1) {
+ ALOGE("mvhd: depth %d", depth);
+ return ERROR_MALFORMED;
+ }
if (chunk_data_size < 32) {
return ERROR_MALFORMED;
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 465ebc8..436a960 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include "include/avc_utils.h"
+#include "include/SecureBuffer.h"
#include "include/SharedMemoryBuffer.h"
#include "include/SoftwareRenderer.h"
@@ -929,9 +930,7 @@
}
// by the time buffers array is initialized, crypto is set
- *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
- info.mEncryptedData :
- info.mData;
+ *buffer = info.mData;
*format = info.mFormat;
return OK;
@@ -1348,13 +1347,11 @@
info.mBufferID = portDesc->bufferIDAt(i);
info.mOwnedByClient = false;
info.mData = portDesc->bufferAt(i);
- info.mNativeHandle = portDesc->handleAt(i);
- info.mMemRef = portDesc->memRefAt(i);
if (portIndex == kPortIndexInput && mCrypto != NULL) {
sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
- info.mEncryptedData =
- new SharedMemoryBuffer(mInputFormat, mem);
+ info.mSecureData = info.mData;
+ info.mData = new SharedMemoryBuffer(mInputFormat, mem);
info.mSharedEncryptedBuffer = mem;
}
@@ -2151,9 +2148,7 @@
for (size_t i = 0; i < srcBuffers.size(); ++i) {
const BufferInfo &info = srcBuffers.itemAt(i);
- dstBuffers->push_back(
- (portIndex == kPortIndexInput && mCrypto != NULL)
- ? info.mEncryptedData : info.mData);
+ dstBuffers->push_back(info.mData);
}
}
@@ -2288,8 +2283,7 @@
sp<ABuffer> csd = *mCSD.begin();
mCSD.erase(mCSD.begin());
- const sp<MediaCodecBuffer> &codecInputData =
- (mCrypto != NULL) ? info->mEncryptedData : info->mData;
+ const sp<MediaCodecBuffer> &codecInputData = info->mData;
if (csd->size() > codecInputData->capacity()) {
return -EINVAL;
@@ -2370,7 +2364,7 @@
ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
portIndex, i);
} else {
- info->mMemRef = NULL;
+ // TODO: clear memory reference.
info->mOwnedByClient = false;
}
@@ -2488,32 +2482,22 @@
sp<AMessage> reply = info->mNotify;
info->mData->setRange(offset, size);
- info->mData->meta()->setInt64("timeUs", timeUs);
- if (flags & BUFFER_FLAG_EOS) {
- info->mData->meta()->setInt32("eos", true);
- }
-
- if (flags & BUFFER_FLAG_CODECCONFIG) {
- info->mData->meta()->setInt32("csd", true);
- }
-
+ sp<MediaCodecBuffer> buffer = info->mData;
if (mCrypto != NULL) {
- if (size > info->mEncryptedData->capacity()) {
- return -ERANGE;
- }
-
AString *errorDetailMsg;
CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
- void *dst_pointer = info->mData->base();
+ void *dst_pointer = nullptr;
ICrypto::DestinationType dst_type = ICrypto::kDestinationTypeOpaqueHandle;
- if (info->mNativeHandle != NULL) {
- dst_pointer = (void *)info->mNativeHandle->handle();
- dst_type = ICrypto::kDestinationTypeNativeHandle;
- } else if ((mFlags & kFlagIsSecure) == 0) {
+ if ((mFlags & kFlagIsSecure) == 0) {
+ dst_pointer = info->mSecureData->base();
dst_type = ICrypto::kDestinationTypeVmPointer;
+ } else {
+ sp<SecureBuffer> secureData = static_cast<SecureBuffer *>(info->mSecureData.get());
+ dst_pointer = secureData->getDestinationPointer();
+ dst_type = secureData->getDestinationType();
}
ssize_t result = mCrypto->decrypt(
@@ -2533,7 +2517,17 @@
return result;
}
- info->mData->setRange(0, result);
+ info->mSecureData->setRange(0, result);
+ buffer = info->mSecureData;
+ }
+ buffer->meta()->setInt64("timeUs", timeUs);
+
+ if (flags & BUFFER_FLAG_EOS) {
+ buffer->meta()->setInt32("eos", true);
+ }
+
+ if (flags & BUFFER_FLAG_CODECCONFIG) {
+ buffer->meta()->setInt32("csd", true);
}
// TODO: release buffer reference.
@@ -2542,7 +2536,7 @@
Mutex::Autolock al(mBufferLock);
info->mOwnedByClient = false;
}
- reply->setObject("buffer", info->mData);
+ reply->setObject("buffer", buffer);
reply->post();
info->mNotify = NULL;
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 6f2d868..0cf6fbf 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -478,59 +478,43 @@
CHECK(mAudioTrack != NULL);
uint32_t numFramesPlayed;
- int64_t numFramesPlayedAt;
+ int64_t numFramesPlayedAtUs;
AudioTimestamp ts;
- static const int64_t kStaleTimestamp100ms = 100000;
status_t res = mAudioTrack->getTimestamp(ts);
if (res == OK) {
// case 1: mixing audio tracks.
numFramesPlayed = ts.mPosition;
- numFramesPlayedAt =
- ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- const int64_t timestampAge = nowUs - numFramesPlayedAt;
- if (timestampAge > kStaleTimestamp100ms) {
- // This is an audio FIXME.
- // getTimestamp returns a timestamp which may come from audio
- // mixing threads. After pausing, the MixerThread may go idle,
- // thus the mTime estimate may become stale. Assuming that the
- // MixerThread runs 20ms, with FastMixer at 5ms, the max latency
- // should be about 25ms with an average around 12ms (to be
- // verified). For safety we use 100ms.
- ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) "
- "numFramesPlayedAt(%lld)",
- (long long)nowUs, (long long)numFramesPlayedAt);
- numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
- }
+ numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
//ALOGD("getTimestamp: OK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAt);
+ // numFramesPlayed, (long long)numFramesPlayedAtUs);
} else if (res == WOULD_BLOCK) {
// case 2: transitory state on start of a new track
numFramesPlayed = 0;
- numFramesPlayedAt = nowUs;
+ numFramesPlayedAtUs = nowUs;
//ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAt);
+ // numFramesPlayed, (long long)numFramesPlayedAtUs);
} else {
// case 3: transitory at new track or audio fast tracks.
res = mAudioTrack->getPosition(&numFramesPlayed);
CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAt = nowUs;
- numFramesPlayedAt += 1000LL * mAudioTrack->latency() / 2; /* XXX */
- //ALOGD("getPosition: %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ numFramesPlayedAtUs = nowUs;
+ numFramesPlayedAtUs += 1000LL * mAudioTrack->latency() / 2; /* XXX */
+ //ALOGD("getPosition: %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
}
//can't be negative until 12.4 hrs, test.
//CHECK_EQ(numFramesPlayed & (1 << 31), 0);
int64_t durationUs =
getDurationIfPlayedAtNativeSampleRate_l(numFramesPlayed)
- + nowUs - numFramesPlayedAt;
+ + nowUs - numFramesPlayedAtUs;
if (durationUs < 0) {
// Occurs when numFramesPlayed position is very small and the following:
// (1) In case 1, the time nowUs is computed before getTimestamp() is
- // called and numFramesPlayedAt is greater than nowUs by time more
+ // called and numFramesPlayedAtUs is greater than nowUs by time more
// than numFramesPlayed.
// (2) In case 3, using getPosition and adding mAudioTrack->latency()
- // to numFramesPlayedAt, by a time amount greater than
+ // to numFramesPlayedAtUs, by a time amount greater than
// numFramesPlayed.
//
// Both of these are transitory conditions.
@@ -541,7 +525,7 @@
ALOGV("getPlayedOutAudioDurationMedia_l(%lld) nowUs(%lld) frames(%u) "
"framesAt(%lld)",
(long long)durationUs, (long long)nowUs, numFramesPlayed,
- (long long)numFramesPlayedAt);
+ (long long)numFramesPlayedAtUs);
return durationUs;
}
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index e24d08d..8b9472e 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -467,28 +467,28 @@
return err;
}
-status_t LiveSession::getStreamFormat(StreamType stream, sp<AMessage> *format) {
+status_t LiveSession::getStreamFormatMeta(StreamType stream, sp<MetaData> *meta) {
if (!(mStreamMask & stream)) {
return UNKNOWN_ERROR;
}
sp<AnotherPacketSource> packetSource = mPacketSources.valueFor(stream);
- sp<MetaData> meta = packetSource->getFormat();
+ *meta = packetSource->getFormat();
- if (meta == NULL) {
+ if (*meta == NULL) {
return -EWOULDBLOCK;
}
if (stream == STREAMTYPE_AUDIO) {
// set AAC input buffer size to 32K bytes (256kbps x 1sec)
- meta->setInt32(kKeyMaxInputSize, 32 * 1024);
+ (*meta)->setInt32(kKeyMaxInputSize, 32 * 1024);
} else if (stream == STREAMTYPE_VIDEO) {
- meta->setInt32(kKeyMaxWidth, mMaxWidth);
- meta->setInt32(kKeyMaxHeight, mMaxHeight);
+ (*meta)->setInt32(kKeyMaxWidth, mMaxWidth);
+ (*meta)->setInt32(kKeyMaxHeight, mMaxHeight);
}
- return convertMetaDataToMessage(meta, format);
+ return OK;
}
sp<HTTPDownloader> LiveSession::getHTTPDownloader() {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index de7cefd..65a824e 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -75,7 +75,7 @@
int64_t calculateMediaTimeUs(int64_t firstTimeUs, int64_t timeUs, int32_t discontinuitySeq);
status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
- status_t getStreamFormat(StreamType stream, sp<AMessage> *format);
+ status_t getStreamFormatMeta(StreamType stream, sp<MetaData> *meta);
sp<HTTPDownloader> getHTTPDownloader();
diff --git a/media/libstagefright/include/SecureBuffer.h b/media/libstagefright/include/SecureBuffer.h
new file mode 100644
index 0000000..4bb1418
--- /dev/null
+++ b/media/libstagefright/include/SecureBuffer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016, 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 SECURE_BUFFER_H_
+
+#define SECURE_BUFFER_H_
+
+#include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
+
+namespace android {
+
+class NativeHandle;
+
+/**
+ * Secure MediaCodecBuffer implementation.
+ *
+ * For classes outside of MediaCodec, this buffer is an opaque buffer only with
+ * the size information. For decryption, it exposes underlying handle/pointer
+ * and its type, which can be fed to ICrypto::decrypt().
+ */
+class SecureBuffer : public MediaCodecBuffer {
+public:
+ SecureBuffer(const sp<AMessage> &format, void *ptr, size_t size);
+ SecureBuffer(const sp<AMessage> &format, const sp<NativeHandle> &handle, size_t size);
+
+ virtual ~SecureBuffer() = default;
+
+ void *getDestinationPointer();
+ ICrypto::DestinationType getDestinationType();
+
+private:
+ SecureBuffer() = delete;
+
+ const void *mPointer;
+ const sp<NativeHandle> mHandle;
+};
+
+} // namespace android
+
+#endif // SECURE_BUFFER_H_
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index ef18958..2a4bd15 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -912,13 +912,17 @@
OMX_BUFFERHEADERTYPE *header;
OMX_ERRORTYPE err = OMX_ErrorNone;
bool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;
+ bool isOutputGraphicMetadata = (portIndex == kPortIndexOutput) &&
+ (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource ||
+ mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer);
uint32_t requiresAllocateBufferBit =
(portIndex == kPortIndexInput)
? kRequiresAllocateBufferOnInputPorts
: kRequiresAllocateBufferOnOutputPorts;
- if (mQuirks & requiresAllocateBufferBit) {
+ // we use useBuffer for output metadata regardless of quirks
+ if (!isOutputGraphicMetadata && (mQuirks & requiresAllocateBufferBit)) {
// metadata buffers are not connected cross process; only copy if not meta.
buffer_meta = new BufferMeta(
params, portIndex, !isMetadata /* copy */, NULL /* data */);
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index cfafaa7..8ba9e02 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -418,7 +418,7 @@
if (sessionDesc->getDurationUs(&durationUs)) {
mFormat->setInt64(kKeyDuration, durationUs);
} else {
- mFormat->setInt64(kKeyDuration, 60 * 60 * 1000000ll);
+ mFormat->setInt64(kKeyDuration, -1ll);
}
mInitCheck = OK;