summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2013-12-05 12:38:14 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2013-12-05 12:38:14 -0800
commite2d617f5ba7fb90f27b03e2593666b2c927e4dc9 (patch)
tree187992f0c2d4bc565ca24b34aa0ee78e359a3f68 /media
parent92630351d265a61faae2dfe006a8bb330283aa7b (diff)
parent2381f06f374ee0cb8bca0edf5388394432b00e6d (diff)
downloadframeworks_av-e2d617f5ba7fb90f27b03e2593666b2c927e4dc9.zip
frameworks_av-e2d617f5ba7fb90f27b03e2593666b2c927e4dc9.tar.gz
frameworks_av-e2d617f5ba7fb90f27b03e2593666b2c927e4dc9.tar.bz2
Merge commit '2381f06f374ee0cb8bca0edf5388394432b00e6d' into HEAD
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/AudioTrack.cpp20
-rw-r--r--media/libmedia/AudioTrackShared.cpp10
-rw-r--r--media/libmedia/IAudioFlinger.cpp5
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp19
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h11
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp31
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h3
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp11
-rw-r--r--media/libstagefright/ACodec.cpp27
-rw-r--r--media/libstagefright/AudioSource.cpp4
-rw-r--r--media/libstagefright/AwesomePlayer.cpp55
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp12
-rw-r--r--media/libstagefright/DataSource.cpp43
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp26
-rw-r--r--media/libstagefright/MediaCodec.cpp3
-rw-r--r--media/libstagefright/MetaData.cpp3
-rw-r--r--media/libstagefright/OMXCodec.cpp8
-rw-r--r--media/libstagefright/TimedEventQueue.cpp94
-rw-r--r--media/libstagefright/Utils.cpp5
-rw-r--r--media/libstagefright/include/TimedEventQueue.h4
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp5
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.cpp40
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.h5
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp19
24 files changed, 338 insertions, 125 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index fe5cd9e..b8a89a0 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -101,7 +101,8 @@ AudioTrack::AudioTrack(
int notificationFrames,
int sessionId,
transfer_type transferType,
- const audio_offload_info_t *offloadInfo)
+ const audio_offload_info_t *offloadInfo,
+ int uid)
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -109,7 +110,8 @@ AudioTrack::AudioTrack(
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
- 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo);
+ 0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
+ offloadInfo, uid);
}
AudioTrack::AudioTrack(
@@ -124,7 +126,8 @@ AudioTrack::AudioTrack(
int notificationFrames,
int sessionId,
transfer_type transferType,
- const audio_offload_info_t *offloadInfo)
+ const audio_offload_info_t *offloadInfo,
+ int uid)
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -132,7 +135,7 @@ AudioTrack::AudioTrack(
{
mStatus = set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
- sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo);
+ sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid);
}
AudioTrack::~AudioTrack()
@@ -169,7 +172,8 @@ status_t AudioTrack::set(
bool threadCanCallJava,
int sessionId,
transfer_type transferType,
- const audio_offload_info_t *offloadInfo)
+ const audio_offload_info_t *offloadInfo,
+ int uid)
{
switch (transferType) {
case TRANSFER_DEFAULT:
@@ -313,6 +317,11 @@ status_t AudioTrack::set(
mNotificationFramesReq = notificationFrames;
mNotificationFramesAct = 0;
mSessionId = sessionId;
+ if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) {
+ mClientUid = IPCThreadState::self()->getCallingUid();
+ } else {
+ mClientUid = uid;
+ }
mAuxEffectId = 0;
mFlags = flags;
mCbf = cbf;
@@ -962,6 +971,7 @@ status_t AudioTrack::createTrack_l(
tid,
&mSessionId,
mName,
+ mClientUid,
&status);
if (track == 0) {
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index da73d65..caa7900 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -506,7 +506,7 @@ ServerProxy::ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCo
{
}
-status_t ServerProxy::obtainBuffer(Buffer* buffer)
+status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
{
LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
if (mIsShutdown) {
@@ -579,7 +579,11 @@ status_t ServerProxy::obtainBuffer(Buffer* buffer)
buffer->mRaw = part1 > 0 ?
&((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
buffer->mNonContig = availToServer - part1;
- mUnreleased = part1;
+ // After flush(), allow releaseBuffer() on a previously obtained buffer;
+ // see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
+ if (!ackFlush) {
+ mUnreleased = part1;
+ }
return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
}
no_init:
@@ -761,7 +765,7 @@ ssize_t StaticAudioTrackServerProxy::pollPosition()
return (ssize_t) position;
}
-status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer)
+status_t StaticAudioTrackServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
{
if (mIsShutdown) {
buffer->mFrameCount = 0;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 448a82e..acfaea0 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -96,6 +96,7 @@ public:
pid_t tid,
int *sessionId,
String8& name,
+ int clientUid,
status_t *status)
{
Parcel data, reply;
@@ -121,6 +122,7 @@ public:
lSessionId = *sessionId;
}
data.writeInt32(lSessionId);
+ data.writeInt32(clientUid);
status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
if (lStatus != NO_ERROR) {
ALOGE("createTrack error: %s", strerror(-lStatus));
@@ -762,6 +764,7 @@ status_t BnAudioFlinger::onTransact(
audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
pid_t tid = (pid_t) data.readInt32();
int sessionId = data.readInt32();
+ int clientUid = data.readInt32();
String8 name;
status_t status;
sp<IAudioTrack> track;
@@ -773,7 +776,7 @@ status_t BnAudioFlinger::onTransact(
track = createTrack(
(audio_stream_type_t) streamType, sampleRate, format,
channelMask, frameCount, &flags, buffer, output, tid,
- &sessionId, name, &status);
+ &sessionId, name, clientUid, &status);
}
reply->writeInt32(flags);
reply->writeInt32(sessionId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9553458..cd052e6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -590,7 +590,7 @@ sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
}
if (!p->hardwareOutput()) {
- mAudioOutput = new AudioOutput(mAudioSessionId);
+ mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid());
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}
@@ -1296,12 +1296,13 @@ Exit:
#undef LOG_TAG
#define LOG_TAG "AudioSink"
-MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
+MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid)
: mCallback(NULL),
mCallbackCookie(NULL),
mCallbackData(NULL),
mBytesWritten(0),
mSessionId(sessionId),
+ mUid(uid),
mFlags(AUDIO_OUTPUT_FLAG_NONE) {
ALOGV("AudioOutput(%d)", sessionId);
mStreamType = AUDIO_STREAM_MUSIC;
@@ -1549,7 +1550,8 @@ status_t MediaPlayerService::AudioOutput::open(
0, // notification frames
mSessionId,
AudioTrack::TRANSFER_CALLBACK,
- offloadInfo);
+ offloadInfo,
+ mUid);
} else {
t = new AudioTrack(
mStreamType,
@@ -1558,10 +1560,13 @@ status_t MediaPlayerService::AudioOutput::open(
channelMask,
frameCount,
flags,
- NULL,
- NULL,
- 0,
- mSessionId);
+ NULL, // callback
+ NULL, // user data
+ 0, // notification frames
+ mSessionId,
+ AudioTrack::TRANSFER_DEFAULT,
+ NULL, // offload info
+ mUid);
}
if ((t == 0) || (t->initCheck() != NO_ERROR)) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 21f4117..a486cb5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -72,7 +72,7 @@ class MediaPlayerService : public BnMediaPlayerService
class CallbackData;
public:
- AudioOutput(int sessionId);
+ AudioOutput(int sessionId, int uid);
virtual ~AudioOutput();
virtual bool ready() const { return mTrack != 0; }
@@ -100,7 +100,10 @@ class MediaPlayerService : public BnMediaPlayerService
virtual void flush();
virtual void pause();
virtual void close();
- void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; }
+ void setAudioStreamType(audio_stream_type_t streamType) {
+ mStreamType = streamType; }
+ virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; }
+
void setVolume(float left, float right);
virtual status_t setPlaybackRatePermille(int32_t ratePermille);
status_t setAuxEffectSendLevel(float level);
@@ -135,6 +138,7 @@ class MediaPlayerService : public BnMediaPlayerService
uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
int mSessionId;
+ int mUid;
float mSendLevel;
int mAuxEffectId;
static bool mIsOnEmulator;
@@ -206,6 +210,9 @@ class MediaPlayerService : public BnMediaPlayerService
virtual void pause() {}
virtual void close() {}
void setAudioStreamType(audio_stream_type_t streamType) {}
+ // stream type is not used for AudioCache
+ virtual audio_stream_type_t getAudioStreamType() const { return AUDIO_STREAM_DEFAULT; }
+
void setVolume(float left, float right) {}
virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
uint32_t sampleRate() const { return mSampleRate; }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 095d5ca..f9d9020 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -70,8 +70,9 @@ StagefrightRecorder::StagefrightRecorder()
mOutputFd(-1),
mAudioSource(AUDIO_SOURCE_CNT),
mVideoSource(VIDEO_SOURCE_LIST_END),
- mStarted(false), mSurfaceMediaSource(NULL),
- mCaptureTimeLapse(false) {
+ mCaptureTimeLapse(false),
+ mStarted(false),
+ mSurfaceMediaSource(NULL) {
ALOGV("Constructor");
reset();
@@ -1089,7 +1090,22 @@ void StagefrightRecorder::clipVideoFrameWidth() {
}
}
-status_t StagefrightRecorder::checkVideoEncoderCapabilities() {
+status_t StagefrightRecorder::checkVideoEncoderCapabilities(
+ bool *supportsCameraSourceMetaDataMode) {
+ /* hardware codecs must support camera source meta data mode */
+ Vector<CodecCapabilities> codecs;
+ OMXClient client;
+ CHECK_EQ(client.connect(), (status_t)OK);
+ QueryCodecs(
+ client.interface(),
+ (mVideoEncoder == VIDEO_ENCODER_H263 ? MEDIA_MIMETYPE_VIDEO_H263 :
+ mVideoEncoder == VIDEO_ENCODER_MPEG_4_SP ? MEDIA_MIMETYPE_VIDEO_MPEG4 :
+ mVideoEncoder == VIDEO_ENCODER_H264 ? MEDIA_MIMETYPE_VIDEO_AVC : ""),
+ false /* decoder */, true /* hwCodec */, &codecs);
+ *supportsCameraSourceMetaDataMode = codecs.size() > 0;
+ ALOGV("encoder %s camera source meta-data mode",
+ *supportsCameraSourceMetaDataMode ? "supports" : "DOES NOT SUPPORT");
+
if (!mCaptureTimeLapse) {
// Dont clip for time lapse capture as encoder will have enough
// time to encode because of slow capture rate of time lapse.
@@ -1307,7 +1323,9 @@ status_t StagefrightRecorder::setupSurfaceMediaSource() {
status_t StagefrightRecorder::setupCameraSource(
sp<CameraSource> *cameraSource) {
status_t err = OK;
- if ((err = checkVideoEncoderCapabilities()) != OK) {
+ bool encoderSupportsCameraSourceMetaDataMode;
+ if ((err = checkVideoEncoderCapabilities(
+ &encoderSupportsCameraSourceMetaDataMode)) != OK) {
return err;
}
Size videoSize;
@@ -1323,13 +1341,14 @@ status_t StagefrightRecorder::setupCameraSource(
mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
videoSize, mFrameRate, mPreviewSurface,
- mTimeBetweenTimeLapseFrameCaptureUs);
+ mTimeBetweenTimeLapseFrameCaptureUs,
+ encoderSupportsCameraSourceMetaDataMode);
*cameraSource = mCameraSourceTimeLapse;
} else {
*cameraSource = CameraSource::CreateFromCamera(
mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
videoSize, mFrameRate,
- mPreviewSurface, true /*storeMetaDataInVideoBuffers*/);
+ mPreviewSurface, encoderSupportsCameraSourceMetaDataMode);
}
mCamera.clear();
mCameraProxy.clear();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index c864207..31f09e0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -139,7 +139,8 @@ private:
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
- status_t checkVideoEncoderCapabilities();
+ status_t checkVideoEncoderCapabilities(
+ bool *supportsCameraSourceMetaDataMode);
status_t checkAudioEncoderCapabilities();
// Generic MediaSource set-up. Returns the appropriate
// source (CameraSource or SurfaceMediaSource)
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index d8b35d7..f1782cc 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -201,7 +201,16 @@ void NuPlayer::HTTPLiveSource::onSessionNotify(const sp<AMessage> &msg) {
switch (what) {
case LiveSession::kWhatPrepared:
{
- notifyVideoSizeChanged(0, 0);
+ // notify the current size here if we have it, otherwise report an initial size of (0,0)
+ sp<AMessage> format = getFormat(false /* audio */);
+ int32_t width;
+ int32_t height;
+ if (format != NULL &&
+ format->findInt32("width", &width) && format->findInt32("height", &height)) {
+ notifyVideoSizeChanged(width, height);
+ } else {
+ notifyVideoSizeChanged(0, 0);
+ }
uint32_t flags = FLAG_CAN_PAUSE;
if (mLiveSession->isSeekable()) {
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 1adab38..528fdb9 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1909,6 +1909,11 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp<AMessage> &msg) {
err = setupAVCEncoderParameters(msg);
break;
+ case OMX_VIDEO_CodingVP8:
+ case OMX_VIDEO_CodingVP9:
+ err = setupVPXEncoderParameters(msg);
+ break;
+
default:
break;
}
@@ -2240,6 +2245,17 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
return configureBitrate(bitrate, bitrateMode);
}
+status_t ACodec::setupVPXEncoderParameters(const sp<AMessage> &msg) {
+ int32_t bitrate;
+ if (!msg->findInt32("bitrate", &bitrate)) {
+ return INVALID_OPERATION;
+ }
+
+ OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg);
+
+ return configureBitrate(bitrate, bitrateMode);
+}
+
status_t ACodec::verifySupportForProfileAndLevel(
int32_t profile, int32_t level) {
OMX_VIDEO_PARAM_PROFILELEVELTYPE params;
@@ -3072,11 +3088,16 @@ void ACodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) {
/* these are unfilled buffers returned by client */
CHECK(msg->findInt32("err", &err));
- ALOGV("[%s] saw error %d instead of an input buffer",
- mCodec->mComponentName.c_str(), err);
+ if (err == OK) {
+ /* buffers with no errors are returned on MediaCodec.flush */
+ mode = KEEP_BUFFERS;
+ } else {
+ ALOGV("[%s] saw error %d instead of an input buffer",
+ mCodec->mComponentName.c_str(), err);
+ eos = true;
+ }
buffer.clear();
- mode = KEEP_BUFFERS;
}
int32_t tmp;
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index bdd842f..d7223d9 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -236,10 +236,10 @@ status_t AudioSource::read(
memset((uint8_t *) buffer->data(), 0, buffer->range_length());
} else if (elapsedTimeUs < kAutoRampStartUs + kAutoRampDurationUs) {
int32_t autoRampDurationFrames =
- (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL;
+ ((int64_t)kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; //Need type casting
int32_t autoRampStartFrames =
- (kAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL;
+ ((int64_t)kAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; //Need type casting
int32_t nFrames = mNumFramesReceived - autoRampStartFrames;
rampVolume(nFrames, autoRampDurationFrames,
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index c912f75..130207d 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -606,6 +606,9 @@ void AwesomePlayer::reset_l() {
mWatchForAudioSeekComplete = false;
mWatchForAudioEOS = false;
+
+ mMediaRenderingStartGeneration = 0;
+ mStartGeneration = 0;
}
void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -798,7 +801,7 @@ void AwesomePlayer::onBufferingUpdate() {
}
}
- if (mFlags & (PLAYING | PREPARING)) {
+ if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) {
postBufferingEvent_l();
}
}
@@ -895,6 +898,8 @@ status_t AwesomePlayer::play_l() {
return OK;
}
+ mMediaRenderingStartGeneration = ++mStartGeneration;
+
if (!(mFlags & PREPARED)) {
status_t err = prepare_l();
@@ -1197,8 +1202,7 @@ void AwesomePlayer::initRenderer_l() {
setVideoScalingMode_l(mVideoScalingMode);
if (USE_SURFACE_ALLOC
&& !strncmp(component, "OMX.", 4)
- && strncmp(component, "OMX.google.", 11)
- && strcmp(component, "OMX.Nvidia.mpeg2v.decode")) {
+ && strncmp(component, "OMX.google.", 11)) {
// Hardware decoders avoid the CPU color conversion by decoding
// directly to ANativeBuffers, so we must use a renderer that
// just pushes those buffers to the ANativeWindow.
@@ -1495,7 +1499,13 @@ status_t AwesomePlayer::initAudioDecoder() {
// This doesn't guarantee that the hardware has a free stream
// but it avoids us attempting to open (and re-open) an offload
// stream to hardware that doesn't have the necessary codec
- mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), isStreamingHTTP());
+ audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
+ if (mAudioSink != NULL) {
+ streamType = mAudioSink->getAudioStreamType();
+ }
+
+ mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL),
+ isStreamingHTTP(), streamType);
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
ALOGV("createAudioPlayer: bypass OMX (raw)");
@@ -1927,7 +1937,7 @@ void AwesomePlayer::onVideoEvent() {
++mStats.mNumVideoFramesDropped;
}
- postVideoEvent_l();
+ postVideoEvent_l(0);
return;
}
}
@@ -1967,6 +1977,41 @@ void AwesomePlayer::onVideoEvent() {
return;
}
+ /* get next frame time */
+ if (wasSeeking == NO_SEEK) {
+ MediaSource::ReadOptions options;
+ for (;;) {
+ status_t err = mVideoSource->read(&mVideoBuffer, &options);
+ if (err != OK) {
+ // deal with any errors next time
+ CHECK(mVideoBuffer == NULL);
+ postVideoEvent_l(0);
+ return;
+ }
+
+ if (mVideoBuffer->range_length() != 0) {
+ break;
+ }
+
+ // Some decoders, notably the PV AVC software decoder
+ // return spurious empty buffers that we just want to ignore.
+
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+ }
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ ++mStats.mNumVideoFramesDecoded;
+ }
+
+ int64_t nextTimeUs;
+ CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs));
+ int64_t delayUs = nextTimeUs - ts->getRealTimeUs() + mTimeSourceDeltaUs;
+ postVideoEvent_l(delayUs > 10000 ? 10000 : delayUs < 0 ? 0 : delayUs);
+ return;
+ }
+
postVideoEvent_l();
}
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 20214e8..5772316 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -41,13 +41,15 @@ CameraSourceTimeLapse *CameraSourceTimeLapse::CreateFromCamera(
Size videoSize,
int32_t videoFrameRate,
const sp<IGraphicBufferProducer>& surface,
- int64_t timeBetweenFrameCaptureUs) {
+ int64_t timeBetweenFrameCaptureUs,
+ bool storeMetaDataInVideoBuffers) {
CameraSourceTimeLapse *source = new
CameraSourceTimeLapse(camera, proxy, cameraId,
clientName, clientUid,
videoSize, videoFrameRate, surface,
- timeBetweenFrameCaptureUs);
+ timeBetweenFrameCaptureUs,
+ storeMetaDataInVideoBuffers);
if (source != NULL) {
if (source->initCheck() != OK) {
@@ -67,9 +69,11 @@ CameraSourceTimeLapse::CameraSourceTimeLapse(
Size videoSize,
int32_t videoFrameRate,
const sp<IGraphicBufferProducer>& surface,
- int64_t timeBetweenFrameCaptureUs)
+ int64_t timeBetweenFrameCaptureUs,
+ bool storeMetaDataInVideoBuffers)
: CameraSource(camera, proxy, cameraId, clientName, clientUid,
- videoSize, videoFrameRate, surface, true),
+ videoSize, videoFrameRate, surface,
+ storeMetaDataInVideoBuffers),
mTimeBetweenTimeLapseVideoFramesUs(1E6/videoFrameRate),
mLastTimeLapseFrameRealTimestampUs(0),
mSkipCurrentFrame(false) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index fc6fd9c..97987e2 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -107,6 +107,7 @@ status_t DataSource::getSize(off64_t *size) {
Mutex DataSource::gSnifferMutex;
List<DataSource::SnifferFunc> DataSource::gSniffers;
+bool DataSource::gSniffersRegistered = false;
bool DataSource::sniff(
String8 *mimeType, float *confidence, sp<AMessage> *meta) {
@@ -114,7 +115,13 @@ bool DataSource::sniff(
*confidence = 0.0f;
meta->clear();
- Mutex::Autolock autoLock(gSnifferMutex);
+ {
+ Mutex::Autolock autoLock(gSnifferMutex);
+ if (!gSniffersRegistered) {
+ return false;
+ }
+ }
+
for (List<SnifferFunc>::iterator it = gSniffers.begin();
it != gSniffers.end(); ++it) {
String8 newMimeType;
@@ -133,9 +140,7 @@ bool DataSource::sniff(
}
// static
-void DataSource::RegisterSniffer(SnifferFunc func) {
- Mutex::Autolock autoLock(gSnifferMutex);
-
+void DataSource::RegisterSniffer_l(SnifferFunc func) {
for (List<SnifferFunc>::iterator it = gSniffers.begin();
it != gSniffers.end(); ++it) {
if (*it == func) {
@@ -148,23 +153,29 @@ void DataSource::RegisterSniffer(SnifferFunc func) {
// static
void DataSource::RegisterDefaultSniffers() {
- RegisterSniffer(SniffMPEG4);
- RegisterSniffer(SniffMatroska);
- RegisterSniffer(SniffOgg);
- RegisterSniffer(SniffWAV);
- RegisterSniffer(SniffFLAC);
- RegisterSniffer(SniffAMR);
- RegisterSniffer(SniffMPEG2TS);
- RegisterSniffer(SniffMP3);
- RegisterSniffer(SniffAAC);
- RegisterSniffer(SniffMPEG2PS);
- RegisterSniffer(SniffWVM);
+ Mutex::Autolock autoLock(gSnifferMutex);
+ if (gSniffersRegistered) {
+ return;
+ }
+
+ RegisterSniffer_l(SniffMPEG4);
+ RegisterSniffer_l(SniffMatroska);
+ RegisterSniffer_l(SniffOgg);
+ RegisterSniffer_l(SniffWAV);
+ RegisterSniffer_l(SniffFLAC);
+ RegisterSniffer_l(SniffAMR);
+ RegisterSniffer_l(SniffMPEG2TS);
+ RegisterSniffer_l(SniffMP3);
+ RegisterSniffer_l(SniffAAC);
+ RegisterSniffer_l(SniffMPEG2PS);
+ RegisterSniffer_l(SniffWVM);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
- RegisterSniffer(SniffDRM);
+ RegisterSniffer_l(SniffDRM);
}
+ gSniffersRegistered = true;
}
// static
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 13e22d6..9b36b6a 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1386,19 +1386,33 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
} else {
// No size was specified. Pick a conservatively large size.
int32_t width, height;
- if (mLastTrack->meta->findInt32(kKeyWidth, &width) &&
- mLastTrack->meta->findInt32(kKeyHeight, &height)) {
- mLastTrack->meta->setInt32(kKeyMaxInputSize, width * height * 3 / 2);
- } else {
+ if (!mLastTrack->meta->findInt32(kKeyWidth, &width) ||
+ !mLastTrack->meta->findInt32(kKeyHeight, &height)) {
ALOGE("No width or height, assuming worst case 1080p");
- mLastTrack->meta->setInt32(kKeyMaxInputSize, 3110400);
+ width = 1920;
+ height = 1080;
+ }
+
+ const char *mime;
+ CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+ if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ // AVC requires compression ratio of at least 2, and uses
+ // macroblocks
+ max_size = ((width + 15) / 16) * ((height + 15) / 16) * 192;
+ } else {
+ // For all other formats there is no minimum compression
+ // ratio. Use compression ratio of 1.
+ max_size = width * height * 3 / 2;
}
+ mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size);
}
*offset += chunk_size;
- // Calculate average frame rate.
+ // NOTE: setting another piece of metadata invalidates any pointers (such as the
+ // mimetype) previously obtained, so don't cache them.
const char *mime;
CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+ // Calculate average frame rate.
if (!strncasecmp("video/", mime, 6)) {
size_t nSamples = mLastTrack->sampleTable->countSamples();
int64_t durationUs;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index e299caf..8af1aaf 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1506,7 +1506,8 @@ void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) {
info->mOwnedByClient = false;
if (portIndex == kPortIndexInput) {
- msg->setInt32("err", ERROR_END_OF_STREAM);
+ /* no error, just returning buffers */
+ msg->setInt32("err", OK);
}
msg->post();
}
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index ae6ae2d..7b60afc 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -89,6 +89,9 @@ bool MetaData::setRect(
return setData(key, TYPE_RECT, &r, sizeof(r));
}
+/**
+ * Note that the returned pointer becomes invalid when additional metadata is set.
+ */
bool MetaData::findCString(uint32_t key, const char **value) {
uint32_t type;
const void *data;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 7f56af8..43736ad 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -359,12 +359,7 @@ sp<MediaSource> OMXCodec::Create(
observer->setCodec(codec);
err = codec->configureCodec(meta);
-
if (err == OK) {
- if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
- codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
- }
-
return codec;
}
@@ -1346,8 +1341,7 @@ OMXCodec::OMXCodec(
mLeftOverBuffer(NULL),
mPaused(false),
mNativeWindow(
- (!strncmp(componentName, "OMX.google.", 11)
- || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode"))
+ (!strncmp(componentName, "OMX.google.", 11))
? NULL : nativeWindow) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 6a16bb4..1a9a26b 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -38,11 +38,14 @@
namespace android {
+static int64_t kWakelockMinDelay = 100000ll; // 100ms
+
TimedEventQueue::TimedEventQueue()
: mNextEventID(1),
mRunning(false),
mStopped(false),
- mDeathRecipient(new PMDeathRecipient(this)) {
+ mDeathRecipient(new PMDeathRecipient(this)),
+ mWakeLockCount(0) {
}
TimedEventQueue::~TimedEventQueue() {
@@ -87,9 +90,7 @@ void TimedEventQueue::stop(bool flush) {
// some events may be left in the queue if we did not flush and the wake lock
// must be released.
- if (!mQueue.empty()) {
- releaseWakeLock_l();
- }
+ releaseWakeLock_l(true /*force*/);
mQueue.clear();
mRunning = false;
@@ -126,13 +127,15 @@ TimedEventQueue::event_id TimedEventQueue::postTimedEvent(
QueueItem item;
item.event = event;
item.realtime_us = realtime_us;
+ item.has_wakelock = false;
if (it == mQueue.begin()) {
mQueueHeadChangedCondition.signal();
}
- if (mQueue.empty()) {
+ if (realtime_us > ALooper::GetNowUs() + kWakelockMinDelay) {
acquireWakeLock_l();
+ item.has_wakelock = true;
}
mQueue.insert(it, item);
@@ -188,10 +191,10 @@ void TimedEventQueue::cancelEvents(
ALOGV("cancelling event %d", (*it).event->eventID());
(*it).event->setEventID(0);
- it = mQueue.erase(it);
- if (mQueue.empty()) {
+ if ((*it).has_wakelock) {
releaseWakeLock_l();
}
+ it = mQueue.erase(it);
if (stopAfterFirstMatch) {
return;
}
@@ -297,11 +300,10 @@ sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
if ((*it).event->eventID() == id) {
sp<Event> event = (*it).event;
event->setEventID(0);
-
- mQueue.erase(it);
- if (mQueue.empty()) {
+ if ((*it).has_wakelock) {
releaseWakeLock_l();
}
+ mQueue.erase(it);
return event;
}
}
@@ -313,51 +315,59 @@ sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
void TimedEventQueue::acquireWakeLock_l()
{
- if (mWakeLockToken != 0) {
- return;
- }
- if (mPowerManager == 0) {
- // use checkService() to avoid blocking if power service is not up yet
- sp<IBinder> binder =
- defaultServiceManager()->checkService(String16("power"));
- if (binder == 0) {
- ALOGW("cannot connect to the power manager service");
- } else {
- mPowerManager = interface_cast<IPowerManager>(binder);
- binder->linkToDeath(mDeathRecipient);
+ if (mWakeLockCount++ == 0) {
+ CHECK(mWakeLockToken == 0);
+ if (mPowerManager == 0) {
+ // use checkService() to avoid blocking if power service is not up yet
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("power"));
+ if (binder == 0) {
+ ALOGW("cannot connect to the power manager service");
+ } else {
+ mPowerManager = interface_cast<IPowerManager>(binder);
+ binder->linkToDeath(mDeathRecipient);
+ }
}
- }
- if (mPowerManager != 0) {
- sp<IBinder> binder = new BBinder();
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
- binder,
- String16("TimedEventQueue"),
- String16("media"));
- IPCThreadState::self()->restoreCallingIdentity(token);
- if (status == NO_ERROR) {
- mWakeLockToken = binder;
+ if (mPowerManager != 0) {
+ sp<IBinder> binder = new BBinder();
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
+ binder,
+ String16("TimedEventQueue"),
+ String16("media"));
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ if (status == NO_ERROR) {
+ mWakeLockToken = binder;
+ }
}
}
}
-void TimedEventQueue::releaseWakeLock_l()
+void TimedEventQueue::releaseWakeLock_l(bool force)
{
- if (mWakeLockToken == 0) {
- return;
+ if (force) {
+ if (mWakeLockCount == 0) {
+ return;
+ }
+ // Force wakelock release below by setting reference count to 1.
+ mWakeLockCount = 1;
}
- if (mPowerManager != 0) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- mPowerManager->releaseWakeLock(mWakeLockToken, 0);
- IPCThreadState::self()->restoreCallingIdentity(token);
+ CHECK(mWakeLockCount != 0);
+ if (--mWakeLockCount == 0) {
+ CHECK(mWakeLockToken != 0);
+ if (mPowerManager != 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ mPowerManager->releaseWakeLock(mWakeLockToken, 0);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
+ mWakeLockToken.clear();
}
- mWakeLockToken.clear();
}
void TimedEventQueue::clearPowerManager()
{
Mutex::Autolock _l(mLock);
- releaseWakeLock_l();
+ releaseWakeLock_l(true /*force*/);
mPowerManager.clear();
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 4db8e80..9041c21 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -540,7 +540,8 @@ const struct mime_conv_t* p = &mimeLookup[0];
return BAD_VALUE;
}
-bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo, bool isStreaming)
+bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
+ bool isStreaming, audio_stream_type_t streamType)
{
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -594,7 +595,7 @@ bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo, bool isStreaming)
info.bit_rate = brate;
- info.stream_type = AUDIO_STREAM_MUSIC;
+ info.stream_type = streamType;
info.has_video = hasVideo;
info.is_streaming = isStreaming;
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
index 4e49c83..38a08b1 100644
--- a/media/libstagefright/include/TimedEventQueue.h
+++ b/media/libstagefright/include/TimedEventQueue.h
@@ -118,6 +118,7 @@ private:
struct QueueItem {
sp<Event> event;
int64_t realtime_us;
+ bool has_wakelock;
};
struct StopEvent : public TimedEventQueue::Event {
@@ -139,6 +140,7 @@ private:
sp<IPowerManager> mPowerManager;
sp<IBinder> mWakeLockToken;
const sp<PMDeathRecipient> mDeathRecipient;
+ uint32_t mWakeLockCount;
static void *ThreadWrapper(void *me);
void threadEntry();
@@ -146,7 +148,7 @@ private:
sp<Event> removeEventFromQueue_l(event_id id);
void acquireWakeLock_l();
- void releaseWakeLock_l();
+ void releaseWakeLock_l(bool force = false);
TimedEventQueue(const TimedEventQueue &);
TimedEventQueue &operator=(const TimedEventQueue &);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 9850a46..175a263 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -1193,7 +1193,10 @@ status_t ATSParser::parseTS(ABitReader *br) {
unsigned sync_byte = br->getBits(8);
CHECK_EQ(sync_byte, 0x47u);
- MY_LOGV("transport_error_indicator = %u", br->getBits(1));
+ if (br->getBits(1)) { // transport_error_indicator
+ // silently ignore.
+ return OK;
+ }
unsigned payload_unit_start_indicator = br->getBits(1);
ALOGV("payload_unit_start_indicator = %u", payload_unit_start_indicator);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index cf43e94..b8970ad 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -148,6 +148,18 @@ void GraphicBufferSource::omxExecuting() {
}
}
+void GraphicBufferSource::omxIdle() {
+ ALOGV("omxIdle");
+
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting) {
+ // We are only interested in the transition from executing->idle,
+ // not loaded->idle.
+ mExecuting = false;
+ }
+}
+
void GraphicBufferSource::omxLoaded(){
Mutex::Autolock autoLock(mMutex);
if (!mExecuting) {
@@ -194,7 +206,9 @@ void GraphicBufferSource::addCodecBuffer(OMX_BUFFERHEADERTYPE* header) {
void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {
Mutex::Autolock autoLock(mMutex);
- CHECK(mExecuting); // could this happen if app stop()s early?
+ if (!mExecuting) {
+ return;
+ }
int cbi = findMatchingCodecBuffer_l(header);
if (cbi < 0) {
@@ -213,7 +227,12 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {
// see if the GraphicBuffer reference was null, which should only ever
// happen for EOS.
if (codecBuffer.mGraphicBuffer == NULL) {
- CHECK(mEndOfStream && mEndOfStreamSent);
+ if (!(mEndOfStream && mEndOfStreamSent)) {
+ // This can happen when broken code sends us the same buffer
+ // twice in a row.
+ ALOGE("ERROR: codecBufferEmptied on non-EOS null buffer "
+ "(buffer emptied twice?)");
+ }
// No GraphicBuffer to deal with, no additional input or output is
// expected, so just return.
return;
@@ -384,6 +403,23 @@ bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() {
if (mLatestSubmittedBufferId < 0 || mSuspended) {
return false;
}
+ if (mBufferSlot[mLatestSubmittedBufferId] == NULL) {
+ // This can happen if the remote side disconnects, causing
+ // onBuffersReleased() to NULL out our copy of the slots. The
+ // buffer is gone, so we have nothing to show.
+ //
+ // To be on the safe side we try to release the buffer.
+ ALOGD("repeatLatestSubmittedBuffer_l: slot was NULL");
+ mBufferQueue->releaseBuffer(
+ mLatestSubmittedBufferId,
+ mLatestSubmittedBufferFrameNum,
+ EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE);
+ mLatestSubmittedBufferId = -1;
+ mLatestSubmittedBufferFrameNum = 0;
+ return false;
+ }
int cbi = findAvailableCodecBuffer_l();
if (cbi < 0) {
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 244a843..9e5eee6 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -69,6 +69,11 @@ public:
// sitting in the BufferQueue, this will send them to the codec.
void omxExecuting();
+ // This is called when OMX transitions to OMX_StateIdle, indicating that
+ // the codec is meant to return all buffers back to the client for them
+ // to be freed. Do NOT submit any more buffers to the component.
+ void omxIdle();
+
// This is called when OMX transitions to OMX_StateLoaded, indicating that
// we are shutting down.
void omxLoaded();
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 46e5d71..5f104fc 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -243,13 +243,18 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
status_t OMXNodeInstance::sendCommand(
OMX_COMMANDTYPE cmd, OMX_S32 param) {
const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
- if (bufferSource != NULL
- && cmd == OMX_CommandStateSet
- && param == OMX_StateLoaded) {
- // Initiating transition from Executing -> Loaded
- // Buffers are about to be freed.
- bufferSource->omxLoaded();
- setGraphicBufferSource(NULL);
+ if (bufferSource != NULL && cmd == OMX_CommandStateSet) {
+ if (param == OMX_StateIdle) {
+ // Initiating transition from Executing -> Idle
+ // ACodec is waiting for all buffers to be returned, do NOT
+ // submit any more buffers to the codec.
+ bufferSource->omxIdle();
+ } else if (param == OMX_StateLoaded) {
+ // Initiating transition from Idle/Executing -> Loaded
+ // Buffers are about to be freed.
+ bufferSource->omxLoaded();
+ setGraphicBufferSource(NULL);
+ }
// fall through
}