Merge "Fix "invalid device combination" in system audio mode." into lmp-dev
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 2442219..9cc208e 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -278,6 +278,7 @@
bool mPrepareSync;
status_t mPrepareStatus;
audio_stream_type_t mStreamType;
+ Parcel* mAudioAttributesParcel;
bool mLoop;
float mLeftVolume;
float mRightVolume;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 6cd377a..9611ac7 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -50,6 +50,7 @@
mListener = NULL;
mCookie = NULL;
mStreamType = AUDIO_STREAM_MUSIC;
+ mAudioAttributesParcel = NULL;
mCurrentPosition = -1;
mSeekPosition = -1;
mCurrentState = MEDIA_PLAYER_IDLE;
@@ -68,6 +69,10 @@
MediaPlayer::~MediaPlayer()
{
ALOGV("destructor");
+ if (mAudioAttributesParcel != NULL) {
+ delete mAudioAttributesParcel;
+ mAudioAttributesParcel = NULL;
+ }
AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
disconnect();
IPCThreadState::self()->flushCommands();
@@ -237,6 +242,9 @@
{
if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
mPlayer->setAudioStreamType(mStreamType);
+ if (mAudioAttributesParcel != NULL) {
+ mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
+ }
mCurrentState = MEDIA_PLAYER_PREPARING;
return mPlayer->prepareAsync();
}
@@ -662,8 +670,17 @@
if (mPlayer != NULL) {
return mPlayer->setParameter(key, request);
}
- ALOGV("setParameter: no active player");
- return INVALID_OPERATION;
+ switch (key) {
+ case KEY_PARAMETER_AUDIO_ATTRIBUTES:
+ // no player, save the marshalled audio attributes
+ if (mAudioAttributesParcel != NULL) { delete mAudioAttributesParcel; };
+ mAudioAttributesParcel = new Parcel();
+ mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize());
+ return OK;
+ default:
+ ALOGV("setParameter: no active player");
+ return INVALID_OPERATION;
+ }
}
status_t MediaPlayer::getParameter(int key, Parcel *reply)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b5bd988..c8cb7ed 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -204,6 +204,8 @@
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | content_type |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | flags |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found
@@ -219,6 +221,7 @@
{
attributes->usage = (audio_usage_t) parcel.readInt32();
attributes->content_type = (audio_content_type_t) parcel.readInt32();
+ attributes->source = (audio_source_t) parcel.readInt32();
attributes->flags = (audio_flags_mask_t) parcel.readInt32();
const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
if (hasFlattenedTag) {
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index f257ef3..8e1987a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -32,6 +32,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
#include "../../libstagefright/include/DRMExtractor.h"
#include "../../libstagefright/include/NuCachedSource2.h"
#include "../../libstagefright/include/WVMExtractor.h"
@@ -318,7 +319,14 @@
}
if (mVideoTrack.mSource != NULL) {
- notifyVideoSizeChanged(getFormat(false /* audio */));
+ sp<MetaData> meta = doGetFormatMeta(false /* audio */);
+ sp<AMessage> msg = new AMessage;
+ err = convertMetaDataToMessage(meta, &msg);
+ if(err != OK) {
+ notifyPreparedAndCleanup(err);
+ return;
+ }
+ notifyVideoSizeChanged(msg);
}
notifyFlagsChanged(
@@ -422,7 +430,7 @@
mAudioTrack.mPackets =
new AnotherPacketSource(mAudioTrack.mSource->getFormat());
- readBuffer(MEDIA_TRACK_TYPE_AUDIO);
+ postReadBuffer(MEDIA_TRACK_TYPE_AUDIO);
}
if (mVideoTrack.mSource != NULL) {
@@ -430,7 +438,7 @@
mVideoTrack.mPackets =
new AnotherPacketSource(mVideoTrack.mSource->getFormat());
- readBuffer(MEDIA_TRACK_TYPE_VIDEO);
+ postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
}
setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000);
@@ -459,6 +467,8 @@
if (mDecryptHandle != NULL) {
mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position);
}
+ mSubtitleTrack.mPackets = new AnotherPacketSource(NULL);
+ mTimedTextTrack.mPackets = new AnotherPacketSource(NULL);
}
status_t NuPlayer::GenericSource::feedMoreTSData() {
@@ -615,6 +625,37 @@
}
break;
}
+
+ case kWhatGetFormat:
+ {
+ onGetFormatMeta(msg);
+ break;
+ }
+
+ case kWhatGetSelectedTrack:
+ {
+ onGetSelectedTrack(msg);
+ break;
+ }
+
+ case kWhatSelectTrack:
+ {
+ onSelectTrack(msg);
+ break;
+ }
+
+ case kWhatSeek:
+ {
+ onSeek(msg);
+ break;
+ }
+
+ case kWhatReadBuffer:
+ {
+ onReadBuffer(msg);
+ break;
+ }
+
default:
Source::onMessageReceived(msg);
break;
@@ -690,6 +731,34 @@
}
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
+ sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
+ msg->setInt32("audio", audio);
+
+ sp<AMessage> response;
+ void *format;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findPointer("format", &format));
+ return (MetaData *)format;
+ } else {
+ return NULL;
+ }
+}
+
+void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const {
+ int32_t audio;
+ CHECK(msg->findInt32("audio", &audio));
+
+ sp<AMessage> response = new AMessage;
+ sp<MetaData> format = doGetFormatMeta(audio);
+ response->setPointer("format", format.get());
+
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ response->postReply(replyID);
+}
+
+sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
if (source == NULL) {
@@ -709,7 +778,7 @@
if (mIsWidevine && !audio) {
// try to read a buffer as we may not have been able to the last time
- readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll);
+ postReadBuffer(MEDIA_TRACK_TYPE_VIDEO);
}
status_t finalResult;
@@ -720,18 +789,7 @@
status_t result = track->mPackets->dequeueAccessUnit(accessUnit);
if (!track->mPackets->hasBufferAvailable(&finalResult)) {
- readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll);
- }
-
- if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) {
- return result;
- }
-
- if (mSubtitleTrack.mSource != NULL) {
- CHECK(mSubtitleTrack.mPackets != NULL);
- }
- if (mTimedTextTrack.mSource != NULL) {
- CHECK(mTimedTextTrack.mPackets != NULL);
+ postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO);
}
if (result != OK) {
@@ -825,6 +883,35 @@
}
ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const {
+ sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id());
+ msg->setInt32("type", type);
+
+ sp<AMessage> response;
+ int32_t index;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("index", &index));
+ return index;
+ } else {
+ return -1;
+ }
+}
+
+void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const {
+ int32_t tmpType;
+ CHECK(msg->findInt32("type", &tmpType));
+ media_track_type type = (media_track_type)tmpType;
+
+ sp<AMessage> response = new AMessage;
+ ssize_t index = doGetSelectedTrack(type);
+ response->setInt32("index", index);
+
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ response->postReply(replyID);
+}
+
+ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const {
const Track *track = NULL;
switch (type) {
case MEDIA_TRACK_TYPE_VIDEO:
@@ -852,6 +939,34 @@
status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) {
ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex);
+ sp<AMessage> msg = new AMessage(kWhatSelectTrack, id());
+ msg->setInt32("trackIndex", trackIndex);
+ msg->setInt32("select", trackIndex);
+
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+
+ return err;
+}
+
+void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) {
+ int32_t trackIndex, select;
+ CHECK(msg->findInt32("trackIndex", &trackIndex));
+ CHECK(msg->findInt32("select", &select));
+
+ sp<AMessage> response = new AMessage;
+ status_t err = doSelectTrack(trackIndex, select);
+ response->setInt32("err", err);
+
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ response->postReply(replyID);
+}
+
+status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) {
if (trackIndex >= mSources.size()) {
return BAD_INDEX;
}
@@ -922,6 +1037,32 @@
}
status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) {
+ sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ msg->setInt64("seekTimeUs", seekTimeUs);
+
+ sp<AMessage> response;
+ status_t err = msg->postAndAwaitResponse(&response);
+ if (err == OK && response != NULL) {
+ CHECK(response->findInt32("err", &err));
+ }
+
+ return err;
+}
+
+void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) {
+ int64_t seekTimeUs;
+ CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
+
+ sp<AMessage> response = new AMessage;
+ status_t err = doSeek(seekTimeUs);
+ response->setInt32("err", err);
+
+ uint32_t replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+ response->postReply(replyID);
+}
+
+status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) {
if (mVideoTrack.mSource != NULL) {
int64_t actualTimeUs;
readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
@@ -1006,6 +1147,19 @@
return ab;
}
+void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) {
+ sp<AMessage> msg = new AMessage(kWhatReadBuffer, id());
+ msg->setInt32("trackType", trackType);
+ msg->post();
+}
+
+void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) {
+ int32_t tmpType;
+ CHECK(msg->findInt32("trackType", &tmpType));
+ media_track_type trackType = (media_track_type)tmpType;
+ readBuffer(trackType);
+}
+
void NuPlayer::GenericSource::readBuffer(
media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) {
Track *track;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 1f13120..50ff98a 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -84,6 +84,11 @@
kWhatSendTimedTextData,
kWhatChangeAVSource,
kWhatPollBuffering,
+ kWhatGetFormat,
+ kWhatGetSelectedTrack,
+ kWhatSelectTrack,
+ kWhatSeek,
+ kWhatReadBuffer,
};
Vector<sp<MediaSource> > mSources;
@@ -140,6 +145,18 @@
void notifyPreparedAndCleanup(status_t err);
+ void onGetFormatMeta(sp<AMessage> msg) const;
+ sp<MetaData> doGetFormatMeta(bool audio) const;
+
+ void onGetSelectedTrack(sp<AMessage> msg) const;
+ ssize_t doGetSelectedTrack(media_track_type type) const;
+
+ void onSelectTrack(sp<AMessage> msg);
+ status_t doSelectTrack(size_t trackIndex, bool select);
+
+ void onSeek(sp<AMessage> msg);
+ status_t doSeek(int64_t seekTimeUs);
+
void onPrepareAsync();
void fetchTextData(
@@ -155,6 +172,8 @@
media_track_type trackType,
int64_t *actualTimeUs = NULL);
+ void postReadBuffer(media_track_type trackType);
+ void onReadBuffer(sp<AMessage> msg);
void readBuffer(
media_track_type trackType,
int64_t seekTimeUs = -1ll, int64_t *actualTimeUs = NULL, bool formatChange = false);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ae22123..4a5d18a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -541,7 +541,13 @@
static_cast<NativeWindowWrapper *>(obj.get())));
if (obj != NULL) {
- mDeferredActions.push_back(new SeekAction(mCurrentPositionUs));
+ if (mStarted && mVideoDecoder != NULL) {
+ // Issue a seek to refresh the video screen only if started otherwise
+ // the extractor may not yet be started and will assert.
+ // If the video decoder is not set (perhaps audio only in this case)
+ // do not perform a seek as it is not needed.
+ mDeferredActions.push_back(new SeekAction(mCurrentPositionUs));
+ }
// If there is a new surface texture, instantiate decoders
// again if possible.
@@ -1540,6 +1546,10 @@
ALOGE_IF(mFlushingVideo != NONE,
"video flushDecoder() is called in state %d", mFlushingVideo);
mFlushingVideo = newStatus;
+
+ if (mCCDecoder != NULL) {
+ mCCDecoder->flush();
+ }
}
}
@@ -1665,6 +1675,14 @@
seekTimeUs,
seekTimeUs / 1E6);
+ if (mSource == NULL) {
+ // This happens when reset occurs right before the loop mode
+ // asynchronously seeks to the start of the stream.
+ LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL,
+ "mSource is NULL and decoders not NULL audio(%p) video(%p)",
+ mAudioDecoder.get(), mVideoDecoder.get());
+ return;
+ }
mSource->seekTo(seekTimeUs);
++mTimedTextGeneration;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 5aaf48c..8ce7baf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -716,72 +716,28 @@
return seamless;
}
-struct NuPlayer::CCDecoder::CCData {
+struct CCData {
CCData(uint8_t type, uint8_t data1, uint8_t data2)
: mType(type), mData1(data1), mData2(data2) {
}
+ bool getChannel(size_t *channel) const {
+ if (mData1 >= 0x10 && mData1 <= 0x1f) {
+ *channel = (mData1 >= 0x18 ? 1 : 0) + (mType ? 2 : 0);
+ return true;
+ }
+ return false;
+ }
uint8_t mType;
uint8_t mData1;
uint8_t mData2;
};
-NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
- : mNotify(notify),
- mTrackCount(0),
- mSelectedTrack(-1) {
-}
-
-size_t NuPlayer::CCDecoder::getTrackCount() const {
- return mTrackCount;
-}
-
-sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
- CHECK(index == 0);
-
- sp<AMessage> format = new AMessage();
-
- format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
- format->setString("language", "und");
- format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
- format->setInt32("auto", 1);
- format->setInt32("default", 1);
- format->setInt32("forced", 0);
-
- return format;
-}
-
-status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
- CHECK(index < mTrackCount);
-
- if (select) {
- if (mSelectedTrack == (ssize_t)index) {
- ALOGE("track %zu already selected", index);
- return BAD_VALUE;
- }
- ALOGV("selected track %zu", index);
- mSelectedTrack = index;
- } else {
- if (mSelectedTrack != (ssize_t)index) {
- ALOGE("track %zu is not selected", index);
- return BAD_VALUE;
- }
- ALOGV("unselected track %zu", index);
- mSelectedTrack = -1;
- }
-
- return OK;
-}
-
-bool NuPlayer::CCDecoder::isSelected() const {
- return mSelectedTrack >= 0 && mSelectedTrack < (int32_t)mTrackCount;
-}
-
-bool NuPlayer::CCDecoder::isNullPad(CCData *cc) const {
+static bool isNullPad(CCData *cc) {
return cc->mData1 < 0x10 && cc->mData2 < 0x10;
}
-void NuPlayer::CCDecoder::dumpBytePair(const sp<ABuffer> &ccBuf) const {
+static void dumpBytePair(const sp<ABuffer> &ccBuf) {
size_t offset = 0;
AString out;
@@ -843,6 +799,78 @@
ALOGI("%s", out.c_str());
}
+NuPlayer::CCDecoder::CCDecoder(const sp<AMessage> ¬ify)
+ : mNotify(notify),
+ mCurrentChannel(0),
+ mSelectedTrack(-1) {
+ for (size_t i = 0; i < sizeof(mTrackIndices)/sizeof(mTrackIndices[0]); ++i) {
+ mTrackIndices[i] = -1;
+ }
+}
+
+size_t NuPlayer::CCDecoder::getTrackCount() const {
+ return mFoundChannels.size();
+}
+
+sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
+ if (!isTrackValid(index)) {
+ return NULL;
+ }
+
+ sp<AMessage> format = new AMessage();
+
+ format->setInt32("type", MEDIA_TRACK_TYPE_SUBTITLE);
+ format->setString("language", "und");
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
+ //CC1, field 0 channel 0
+ bool isDefaultAuto = (mFoundChannels[index] == 0);
+ format->setInt32("auto", isDefaultAuto);
+ format->setInt32("default", isDefaultAuto);
+ format->setInt32("forced", 0);
+
+ return format;
+}
+
+status_t NuPlayer::CCDecoder::selectTrack(size_t index, bool select) {
+ if (!isTrackValid(index)) {
+ return BAD_VALUE;
+ }
+
+ if (select) {
+ if (mSelectedTrack == (ssize_t)index) {
+ ALOGE("track %zu already selected", index);
+ return BAD_VALUE;
+ }
+ ALOGV("selected track %zu", index);
+ mSelectedTrack = index;
+ } else {
+ if (mSelectedTrack != (ssize_t)index) {
+ ALOGE("track %zu is not selected", index);
+ return BAD_VALUE;
+ }
+ ALOGV("unselected track %zu", index);
+ mSelectedTrack = -1;
+ }
+
+ return OK;
+}
+
+bool NuPlayer::CCDecoder::isSelected() const {
+ return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount();
+}
+
+bool NuPlayer::CCDecoder::isTrackValid(size_t index) const {
+ return index < getTrackCount();
+}
+
+int32_t NuPlayer::CCDecoder::getTrackIndex(size_t channel) const {
+ if (channel < sizeof(mTrackIndices)/sizeof(mTrackIndices[0])) {
+ return mTrackIndices[channel];
+ }
+ return -1;
+}
+
+// returns true if a new CC track is found
bool NuPlayer::CCDecoder::extractFromSEI(const sp<ABuffer> &accessUnit) {
int64_t timeUs;
CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
@@ -852,7 +880,7 @@
return false;
}
- bool hasCC = false;
+ bool trackAdded = false;
NALBitReader br(sei->data() + 1, sei->size() - 1);
// sei_message()
@@ -887,8 +915,6 @@
&& itu_t_t35_provider_code == 0x0031
&& user_identifier == 'GA94'
&& user_data_type_code == 0x3) {
- hasCC = true;
-
// MPEG_cc_data()
// ATSC A/53 Part 4: 6.2.3.1
br.skipBits(1); //process_em_data_flag
@@ -918,6 +944,12 @@
&& (cc_type == 0 || cc_type == 1)) {
CCData cc(cc_type, cc_data_1, cc_data_2);
if (!isNullPad(&cc)) {
+ size_t channel;
+ if (cc.getChannel(&channel) && getTrackIndex(channel) < 0) {
+ mTrackIndices[channel] = mFoundChannels.size();
+ mFoundChannels.push_back(channel);
+ trackAdded = true;
+ }
memcpy(ccBuf->data() + ccBuf->size(),
(void *)&cc, sizeof(cc));
ccBuf->setRange(0, ccBuf->size() + sizeof(CCData));
@@ -940,13 +972,33 @@
br.skipBits(payload_size * 8);
}
- return hasCC;
+ return trackAdded;
+}
+
+sp<ABuffer> NuPlayer::CCDecoder::filterCCBuf(
+ const sp<ABuffer> &ccBuf, size_t index) {
+ sp<ABuffer> filteredCCBuf = new ABuffer(ccBuf->size());
+ filteredCCBuf->setRange(0, 0);
+
+ size_t cc_count = ccBuf->size() / sizeof(CCData);
+ const CCData* cc_data = (const CCData*)ccBuf->data();
+ for (size_t i = 0; i < cc_count; ++i) {
+ size_t channel;
+ if (cc_data[i].getChannel(&channel)) {
+ mCurrentChannel = channel;
+ }
+ if (mCurrentChannel == mFoundChannels[index]) {
+ memcpy(filteredCCBuf->data() + filteredCCBuf->size(),
+ (void *)&cc_data[i], sizeof(CCData));
+ filteredCCBuf->setRange(0, filteredCCBuf->size() + sizeof(CCData));
+ }
+ }
+
+ return filteredCCBuf;
}
void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
- if (extractFromSEI(accessUnit) && mTrackCount == 0) {
- mTrackCount++;
-
+ if (extractFromSEI(accessUnit)) {
ALOGI("Found CEA-608 track");
sp<AMessage> msg = mNotify->dup();
msg->setInt32("what", kWhatTrackAdded);
@@ -956,13 +1008,18 @@
}
void NuPlayer::CCDecoder::display(int64_t timeUs) {
+ if (!isTrackValid(mSelectedTrack)) {
+ ALOGE("Could not find current track(index=%d)", mSelectedTrack);
+ return;
+ }
+
ssize_t index = mCCMap.indexOfKey(timeUs);
if (index < 0) {
ALOGV("cc for timestamp %" PRId64 " not found", timeUs);
return;
}
- sp<ABuffer> &ccBuf = mCCMap.editValueAt(index);
+ sp<ABuffer> ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack);
if (ccBuf->size() > 0) {
#if 0
@@ -983,5 +1040,9 @@
mCCMap.removeItemsAt(0, index + 1);
}
+void NuPlayer::CCDecoder::flush() {
+ mCCMap.clear();
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 67bddb8..cc1bdff 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -126,18 +126,20 @@
bool isSelected() const;
void decode(const sp<ABuffer> &accessUnit);
void display(int64_t timeUs);
+ void flush();
private:
- struct CCData;
-
sp<AMessage> mNotify;
KeyedVector<int64_t, sp<ABuffer> > mCCMap;
- size_t mTrackCount;
+ size_t mCurrentChannel;
int32_t mSelectedTrack;
+ int32_t mTrackIndices[4];
+ Vector<size_t> mFoundChannels;
- bool isNullPad(CCData *cc) const;
- void dumpBytePair(const sp<ABuffer> &ccBuf) const;
+ bool isTrackValid(size_t index) const;
+ int32_t getTrackIndex(size_t channel) const;
bool extractFromSEI(const sp<ABuffer> &accessUnit);
+ sp<ABuffer> filterCCBuf(const sp<ABuffer> &ccBuf, size_t index);
DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 2423f5f..09324ae 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -626,7 +626,7 @@
switch (msg) {
case MEDIA_PLAYBACK_COMPLETE:
{
- if (mLooping) {
+ if (mLooping && mState != STATE_RESET_IN_PROGRESS) {
mLock.unlock();
mPlayer->seekToAsync(0);
mLock.lock();
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 19a5908..9b03b71 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2313,7 +2313,6 @@
return 0;
}
OMX_U32 ret = frameRate * iFramesInterval;
- CHECK(ret > 1);
return ret;
}
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 0064293..1729f93 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2810,7 +2810,6 @@
{
if (objectType == AOT_SBR || objectType == AOT_PS) {
- const int32_t extensionSamplingFrequency = br.getBits(4);
objectType = br.getBits(5);
if (objectType == AOT_ESCAPE) {
@@ -2828,9 +2827,30 @@
const int32_t coreCoderDelay = br.getBits(14);
}
- const int32_t extensionFlag = br.getBits(1);
+ int32_t extensionFlag = -1;
+ if (br.numBitsLeft() > 0) {
+ extensionFlag = br.getBits(1);
+ } else {
+ switch (objectType) {
+ // 14496-3 4.5.1.1 extensionFlag
+ case AOT_AAC_LC:
+ extensionFlag = 0;
+ break;
+ case AOT_ER_AAC_LC:
+ case AOT_ER_AAC_SCAL:
+ case AOT_ER_BSAC:
+ case AOT_ER_AAC_LD:
+ extensionFlag = 1;
+ break;
+ default:
+ TRESPASS();
+ break;
+ }
+ ALOGW("csd missing extension flag; assuming %d for object type %u.",
+ extensionFlag, objectType);
+ }
- if (numChannels == 0 ) {
+ if (numChannels == 0) {
int32_t channelsEffectiveNum = 0;
int32_t channelsNum = 0;
const int32_t ElementInstanceTag = br.getBits(4);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 78758da..a8806c8 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -994,7 +994,6 @@
return 0;
}
OMX_U32 ret = frameRate * iFramesInterval - 1;
- CHECK(ret > 1);
return ret;
}
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 7f14960..50bb8c7 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -765,7 +765,16 @@
sp<AudioCommand> command2 = mAudioCommands[i];
// commands are sorted by increasing time stamp: no need to scan the rest of mAudioCommands
if (command2->mTime <= command->mTime) break;
- if (command2->mCommand != command->mCommand) continue;
+
+ // create audio patch or release audio patch commands are equivalent
+ // with regard to filtering
+ if ((command->mCommand == CREATE_AUDIO_PATCH) ||
+ (command->mCommand == RELEASE_AUDIO_PATCH)) {
+ if ((command2->mCommand != CREATE_AUDIO_PATCH) &&
+ (command2->mCommand != RELEASE_AUDIO_PATCH)) {
+ continue;
+ }
+ } else if (command2->mCommand != command->mCommand) continue;
switch (command->mCommand) {
case SET_PARAMETERS: {
@@ -817,6 +826,31 @@
// command status as the command is now delayed
delayMs = 1;
} break;
+
+ case CREATE_AUDIO_PATCH:
+ case RELEASE_AUDIO_PATCH: {
+ audio_patch_handle_t handle;
+ if (command->mCommand == CREATE_AUDIO_PATCH) {
+ handle = ((CreateAudioPatchData *)command->mParam.get())->mHandle;
+ } else {
+ handle = ((ReleaseAudioPatchData *)command->mParam.get())->mHandle;
+ }
+ audio_patch_handle_t handle2;
+ if (command2->mCommand == CREATE_AUDIO_PATCH) {
+ handle2 = ((CreateAudioPatchData *)command2->mParam.get())->mHandle;
+ } else {
+ handle2 = ((ReleaseAudioPatchData *)command2->mParam.get())->mHandle;
+ }
+ if (handle != handle2) break;
+ ALOGV("Filtering out %s audio patch command for handle %d",
+ (command->mCommand == CREATE_AUDIO_PATCH) ? "create" : "release", handle);
+ removedCommands.add(command2);
+ command->mTime = command2->mTime;
+ // force delayMs to non 0 so that code below does not request to wait for
+ // command status as the command is now delayed
+ delayMs = 1;
+ } break;
+
case START_TONE:
case STOP_TONE:
default:
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index cb9aca6..9849f4d 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -445,11 +445,18 @@
if (mNewAEState) {
if (!mAeInPrecapture) {
// Waiting to see PRECAPTURE state
- if (mAETriggerId == mTriggerId &&
- mAEState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
- ALOGV("%s: Got precapture start", __FUNCTION__);
- mAeInPrecapture = true;
- mTimeoutCount = kMaxTimeoutsForPrecaptureEnd;
+ if (mAETriggerId == mTriggerId) {
+ if (mAEState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
+ ALOGV("%s: Got precapture start", __FUNCTION__);
+ mAeInPrecapture = true;
+ mTimeoutCount = kMaxTimeoutsForPrecaptureEnd;
+ } else if (mAEState == ANDROID_CONTROL_AE_STATE_CONVERGED ||
+ mAEState == ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED) {
+ // It is legal to transit to CONVERGED or FLASH_REQUIRED
+ // directly after a trigger.
+ ALOGV("%s: AE is already in good state, start capture", __FUNCTION__);
+ return STANDARD_CAPTURE;
+ }
}
} else {
// Waiting to see PRECAPTURE state end