Merge "NuPlayer: use kWhatPauseOnBufferingStart instead of kWhatBufferingStart in RTSPSource."
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 3e4df0f..83cf192 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -629,7 +629,8 @@
MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
- MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9
+ MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
+ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION
};
const char *codecType = queryDecoders? "decoder" : "encoder";
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 8b5b862..2a69685 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -68,15 +68,17 @@
size_t countBuffers();
IOMX::buffer_id bufferIDAt(size_t index) const;
sp<ABuffer> bufferAt(size_t index) const;
+ sp<RefBase> memRefAt(size_t index) const;
private:
friend struct ACodec;
Vector<IOMX::buffer_id> mBufferIDs;
Vector<sp<ABuffer> > mBuffers;
+ Vector<sp<RefBase> > mMemRefs;
PortDescription();
- void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer);
+ void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer, const sp<RefBase> &memRef);
DISALLOW_EVIL_CONSTRUCTORS(PortDescription);
};
@@ -170,6 +172,7 @@
unsigned mDequeuedAt;
sp<ABuffer> mData;
+ sp<RefBase> mMemRef;
sp<GraphicBuffer> mGraphicBuffer;
int mFenceFd;
FrameRenderTracker::Info *mRenderInfo;
diff --git a/include/media/stagefright/CodecBase.h b/include/media/stagefright/CodecBase.h
index bb36052..542db71 100644
--- a/include/media/stagefright/CodecBase.h
+++ b/include/media/stagefright/CodecBase.h
@@ -72,6 +72,7 @@
virtual size_t countBuffers() = 0;
virtual IOMX::buffer_id bufferIDAt(size_t index) const = 0;
virtual sp<ABuffer> bufferAt(size_t index) const = 0;
+ 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 93ffa93..fd9c3cd 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -248,6 +248,7 @@
struct BufferInfo {
uint32_t mBufferID;
sp<ABuffer> mData;
+ sp<RefBase> mMemRef;
sp<ABuffer> mEncryptedData;
sp<IMemory> mSharedEncryptedBuffer;
sp<AMessage> mNotify;
@@ -348,8 +349,8 @@
status_t init(const AString &name, bool nameIsType, bool encoder);
void setState(State newState);
- void returnBuffersToCodec();
- void returnBuffersToCodecOnPort(int32_t portIndex);
+ void returnBuffersToCodec(bool isReclaim = false);
+ void returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim = false);
size_t updateBuffers(int32_t portIndex, const sp<AMessage> &msg);
status_t onQueueInputBuffer(const sp<AMessage> &msg);
status_t onReleaseOutputBuffer(const sp<AMessage> &msg);
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 21eb04a..e5bcec6 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -30,6 +30,7 @@
extern const char *MEDIA_MIMETYPE_VIDEO_H263;
extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2;
extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
+extern const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
@@ -64,6 +65,7 @@
extern const char *MEDIA_MIMETYPE_TEXT_SUBRIP;
extern const char *MEDIA_MIMETYPE_TEXT_VTT;
extern const char *MEDIA_MIMETYPE_TEXT_CEA_608;
+extern const char *MEDIA_MIMETYPE_TEXT_CEA_708;
extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3;
} // namespace android
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 59686ed..6c14a94 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -182,6 +182,9 @@
// H264 supplemental enhancement information offsets/sizes
kKeySEI = 'sei ', // raw data
+
+ // MPEG user data offsets
+ kKeyMpegUserData = 'mpud', // size_t[]
};
enum {
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 82415d5..4e4b094 100644
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -12,7 +12,7 @@
LOCAL_C_INCLUDES += \
external/webrtc \
- external/webrtc/webrtc/modules/interface \
+ external/webrtc/webrtc/modules/include \
external/webrtc/webrtc/modules/audio_processing/include \
$(call include-path-for, audio-effects)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index fe41946..42f1f40 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -884,8 +884,8 @@
int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
{
uint32_t sr;
- uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
- uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
+ uint32_t inCnl = audio_channel_count_from_in_mask(config->inputCfg.channels);
+ uint32_t outCnl = audio_channel_count_from_in_mask(config->outputCfg.channels);
if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
config->inputCfg.format != config->outputCfg.format ||
@@ -919,10 +919,10 @@
}
const webrtc::ProcessingConfig processing_config = {
- {{static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)},
- {static_cast<int>(session->apmSamplingRate), static_cast<int>(outCnl)},
- {static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)},
- {static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)}}};
+ {{static_cast<int>(session->apmSamplingRate), inCnl},
+ {static_cast<int>(session->apmSamplingRate), outCnl},
+ {static_cast<int>(session->apmSamplingRate), inCnl},
+ {static_cast<int>(session->apmSamplingRate), inCnl}}};
status = session->apm->Initialize(processing_config);
if (status < 0) {
return -EINVAL;
@@ -1040,14 +1040,10 @@
}
uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
const webrtc::ProcessingConfig processing_config = {
- {{static_cast<int>(session->apmSamplingRate),
- static_cast<int>(session->inChannelCount)},
- {static_cast<int>(session->apmSamplingRate),
- static_cast<int>(session->outChannelCount)},
- {static_cast<int>(session->apmSamplingRate),
- static_cast<int>(inCnl)},
- {static_cast<int>(session->apmSamplingRate),
- static_cast<int>(inCnl)}}};
+ {{static_cast<int>(session->apmSamplingRate), session->inChannelCount},
+ {static_cast<int>(session->apmSamplingRate), session->outChannelCount},
+ {static_cast<int>(session->apmSamplingRate), inCnl},
+ {static_cast<int>(session->apmSamplingRate), inCnl}}};
int status = session->apm->Initialize(processing_config);
if (status < 0) {
return -EINVAL;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index f4dbdeb..baa95fa 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1322,6 +1322,14 @@
meta->setBuffer("sei", sei);
}
+ const void *mpegUserDataPointer;
+ size_t mpegUserDataLength;
+ if (mb->meta_data()->findData(
+ kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) {
+ sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength);
+ meta->setBuffer("mpegUserData", mpegUserData);
+ }
+
if (actualTimeUs) {
*actualTimeUs = timeUs;
}
@@ -1572,7 +1580,7 @@
mIsStreaming = isStreaming;
mAudioTimeUs = 0;
mVideoTimeUs = 0;
- mPrepareBuffering = true;
+ mPrepareBuffering = (cachedSource != NULL || wvmExtractor != NULL);
cancelPollBuffering_l();
mOffloadAudio = false;
mFirstDequeuedBufferRealUs = -1ll;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
index ac3c6b6..13716cf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.cpp
@@ -30,6 +30,9 @@
namespace android {
+// In CEA-708B, the maximum bandwidth of CC is set to 9600bps.
+static const size_t kMaxBandwithSizeBytes = 9600 / 8;
+
struct CCData {
CCData(uint8_t type, uint8_t data1, uint8_t data2)
: mType(type), mData1(data1), mData2(data2) {
@@ -116,15 +119,19 @@
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;
- }
+ mSelectedTrack(-1),
+ mDTVCCPacket(new ABuffer(kMaxBandwithSizeBytes)) {
+ mDTVCCPacket->setRange(0, 0);
+
+ // In CEA-608, streams from packets which have the value 0 of cc_type contain CC1 and CC2, and
+ // streams from packets which have the value 1 of cc_type contain CC3 and CC4.
+ // The following array indicates the current transmitting channels for each value of cc_type.
+ mLine21Channels[0] = 0; // CC1
+ mLine21Channels[1] = 2; // CC3
}
size_t NuPlayer::CCDecoder::getTrackCount() const {
- return mFoundChannels.size();
+ return mTracks.size();
}
sp<AMessage> NuPlayer::CCDecoder::getTrackInfo(size_t index) const {
@@ -134,13 +141,31 @@
sp<AMessage> format = new AMessage();
+ CCTrack track = mTracks[index];
+
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);
+
+ switch (track.mTrackType) {
+ case kTrackTypeCEA608:
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_608);
+ break;
+ case kTrackTypeCEA708:
+ format->setString("mime", MEDIA_MIMETYPE_TEXT_CEA_708);
+ break;
+ default:
+ ALOGE("Unknown track type: %d", track.mTrackType);
+ return NULL;
+ }
+
+ // For CEA-608 CC1, field 0 channel 0
+ bool isDefaultAuto = track.mTrackType == kTrackTypeCEA608
+ && track.mTrackChannel == 0;
+ // For CEA-708, Primary Caption Service.
+ bool isDefaultOnly = track.mTrackType == kTrackTypeCEA708
+ && track.mTrackChannel == 1;
format->setInt32("auto", isDefaultAuto);
- format->setInt32("default", isDefaultAuto);
+ format->setInt32("default", isDefaultAuto || isDefaultOnly);
format->setInt32("forced", 0);
return format;
@@ -167,24 +192,20 @@
mSelectedTrack = -1;
}
+ // Clear the previous track payloads
+ mCCMap.clear();
+
return OK;
}
bool NuPlayer::CCDecoder::isSelected() const {
- return mSelectedTrack >= 0 && mSelectedTrack < (int32_t) getTrackCount();
+ 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) {
sp<ABuffer> sei;
@@ -197,7 +218,7 @@
bool trackAdded = false;
- const NALPosition *nal = (NALPosition *) sei->data();
+ const NALPosition *nal = (NALPosition *)sei->data();
for (size_t i = 0; i < sei->size() / sizeof(NALPosition); ++i, ++nal) {
trackAdded |= parseSEINalUnit(
@@ -208,9 +229,8 @@
}
// returns true if a new CC track is found
-bool NuPlayer::CCDecoder::parseSEINalUnit(
- int64_t timeUs, const uint8_t *nalStart, size_t nalSize) {
- unsigned nalType = nalStart[0] & 0x1f;
+bool NuPlayer::CCDecoder::parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size) {
+ unsigned nalType = data[0] & 0x1f;
// the buffer should only have SEI in it
if (nalType != 6) {
@@ -218,7 +238,8 @@
}
bool trackAdded = false;
- NALBitReader br(nalStart + 1, nalSize - 1);
+ NALBitReader br(data + 1, size - 1);
+
// sei_message()
while (br.atLeastNumBitsLeft(16)) { // at least 16-bit for sei_message()
uint32_t payload_type = 0;
@@ -256,53 +277,7 @@
}
if (isCC && payload_size > 2) {
- // MPEG_cc_data()
- // ATSC A/53 Part 4: 6.2.3.1
- br.skipBits(1); //process_em_data_flag
- bool process_cc_data_flag = br.getBits(1);
- br.skipBits(1); //additional_data_flag
- size_t cc_count = br.getBits(5);
- br.skipBits(8); // em_data;
- payload_size -= 2;
-
- if (process_cc_data_flag) {
- AString out;
-
- sp<ABuffer> ccBuf = new ABuffer(cc_count * sizeof(CCData));
- ccBuf->setRange(0, 0);
-
- for (size_t i = 0; i < cc_count && payload_size >= 3; i++) {
- uint8_t marker = br.getBits(5);
- CHECK_EQ(marker, 0x1f);
-
- bool cc_valid = br.getBits(1);
- uint8_t cc_type = br.getBits(2);
- // remove odd parity bit
- uint8_t cc_data_1 = br.getBits(8) & 0x7f;
- uint8_t cc_data_2 = br.getBits(8) & 0x7f;
-
- payload_size -= 3;
-
- if (cc_valid
- && (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));
- }
- }
- }
-
- mCCMap.add(timeUs, ccBuf);
- break;
- }
+ trackAdded |= parseMPEGCCData(timeUs, br.data(), br.numBitsLeft() / 8);
} else {
ALOGV("Malformed SEI payload type 4");
}
@@ -317,31 +292,202 @@
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);
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::extractFromMPEGUserData(const sp<ABuffer> &accessUnit) {
+ sp<ABuffer> mpegUserData;
+ if (!accessUnit->meta()->findBuffer("mpegUserData", &mpegUserData)
+ || mpegUserData == NULL) {
+ return false;
+ }
- size_t cc_count = ccBuf->size() / sizeof(CCData);
- const CCData* cc_data = (const CCData*)ccBuf->data();
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+ bool trackAdded = false;
+
+ const size_t *userData = (size_t *)mpegUserData->data();
+
+ for (size_t i = 0; i < mpegUserData->size() / sizeof(size_t); ++i) {
+ trackAdded |= parseMPEGUserDataUnit(
+ timeUs, accessUnit->data() + userData[i], accessUnit->size() - userData[i]);
+ }
+
+ return trackAdded;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size) {
+ ABitReader br(data + 4, 5);
+
+ uint32_t user_identifier = br.getBits(32);
+ uint8_t user_data_type = br.getBits(8);
+
+ if (user_identifier == 'GA94' && user_data_type == 0x3) {
+ return parseMPEGCCData(timeUs, data + 9, size - 9);
+ }
+
+ return false;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size) {
+ bool trackAdded = false;
+
+ // MPEG_cc_data()
+ // ATSC A/53 Part 4: 6.2.3.1
+ ABitReader br(data, size);
+
+ if (br.numBitsLeft() <= 16) {
+ return false;
+ }
+
+ br.skipBits(1);
+ bool process_cc_data_flag = br.getBits(1);
+ br.skipBits(1);
+ size_t cc_count = br.getBits(5);
+ br.skipBits(8);
+
+ if (!process_cc_data_flag || 3 * 8 * cc_count >= br.numBitsLeft()) {
+ return false;
+ }
+
+ sp<ABuffer> line21CCBuf = NULL;
+
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));
+ br.skipBits(5);
+ bool cc_valid = br.getBits(1);
+ uint8_t cc_type = br.getBits(2);
+
+ if (cc_valid) {
+ if (cc_type == 3) {
+ if (mDTVCCPacket->size() > 0) {
+ trackAdded |= parseDTVCCPacket(
+ timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
+ mDTVCCPacket->setRange(0, 0);
+ }
+ memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
+ mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
+ br.skipBits(16);
+ } else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
+ memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
+ mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
+ br.skipBits(16);
+ } else if (cc_type == 0 || cc_type == 1) {
+ uint8_t cc_data_1 = br.getBits(8) & 0x7f;
+ uint8_t cc_data_2 = br.getBits(8) & 0x7f;
+
+ CCData cc(cc_type, cc_data_1, cc_data_2);
+
+ if (isNullPad(&cc)) {
+ continue;
+ }
+
+ size_t channel;
+ if (cc.getChannel(&channel)) {
+ mLine21Channels[cc_type] = channel;
+
+ // create a new track if it does not exist.
+ getTrackIndex(kTrackTypeCEA608, channel, &trackAdded);
+ }
+
+ if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
+ && mTracks[mSelectedTrack].mTrackChannel == mLine21Channels[cc_type]) {
+ if (line21CCBuf == NULL) {
+ line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
+ line21CCBuf->setRange(0, 0);
+ }
+ memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
+ line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
+ }
+ } else {
+ br.skipBits(16);
+ }
+ } else {
+ if ((cc_type == 3 || cc_type == 2) && mDTVCCPacket->size() > 0) {
+ trackAdded |= parseDTVCCPacket(timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
+ mDTVCCPacket->setRange(0, 0);
+ }
+ br.skipBits(16);
}
}
- return filteredCCBuf;
+ if (isSelected() && mTracks[mSelectedTrack].mTrackType == kTrackTypeCEA608
+ && line21CCBuf != NULL && line21CCBuf->size() > 0) {
+ mCCMap.add(timeUs, line21CCBuf);
+ }
+
+ return trackAdded;
+}
+
+// returns true if a new CC track is found
+bool NuPlayer::CCDecoder::parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size) {
+ // CEA-708B 5 DTVCC Packet Layer.
+ ABitReader br(data, size);
+ br.skipBits(2);
+
+ size_t packet_size = br.getBits(6);
+ if (packet_size == 0) packet_size = 64;
+ packet_size *= 2;
+
+ if (size != packet_size) {
+ return false;
+ }
+
+ bool trackAdded = false;
+
+ while (br.numBitsLeft() >= 16) {
+ // CEA-708B Figure 5 and 6.
+ uint8_t service_number = br.getBits(3);
+ size_t block_size = br.getBits(5);
+
+ if (service_number == 64) {
+ br.skipBits(2);
+ service_number = br.getBits(6);
+
+ if (service_number < 64) {
+ return trackAdded;
+ }
+ }
+
+ if (br.numBitsLeft() < block_size * 8) {
+ return trackAdded;
+ }
+
+ if (block_size > 0) {
+ size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
+ if (mSelectedTrack == (ssize_t)trackIndex) {
+ sp<ABuffer> ccPacket = new ABuffer(block_size);
+ memcpy(ccPacket->data(), br.data(), block_size);
+ mCCMap.add(timeUs, ccPacket);
+ }
+ }
+ br.skipBits(block_size * 8);
+ }
+
+ return trackAdded;
+}
+
+// return the track index for a given type and channel.
+// if the track does not exist, creates a new one.
+size_t NuPlayer::CCDecoder::getTrackIndex(
+ int32_t trackType, size_t channel, bool *trackAdded) {
+ CCTrack track(trackType, channel);
+ ssize_t index = mTrackIndices.indexOfKey(track);
+
+ if (index < 0) {
+ // A new track is added.
+ index = mTracks.size();
+ mTrackIndices.add(track, index);
+ mTracks.add(track);
+ *trackAdded = true;
+ return index;
+ }
+
+ return mTrackIndices.valueAt(index);
}
void NuPlayer::CCDecoder::decode(const sp<ABuffer> &accessUnit) {
- if (extractFromSEI(accessUnit)) {
- ALOGI("Found CEA-608 track");
+ if (extractFromMPEGUserData(accessUnit) || extractFromSEI(accessUnit)) {
sp<AMessage> msg = mNotify->dup();
msg->setInt32("what", kWhatTrackAdded);
msg->post();
@@ -350,8 +496,7 @@
}
void NuPlayer::CCDecoder::display(int64_t timeUs) {
- if (!isTrackValid(mSelectedTrack)) {
- ALOGE("Could not find current track(index=%d)", mSelectedTrack);
+ if (!isSelected()) {
return;
}
@@ -361,7 +506,26 @@
return;
}
- sp<ABuffer> ccBuf = filterCCBuf(mCCMap.valueAt(index), mSelectedTrack);
+ sp<ABuffer> ccBuf;
+
+ if (index == 0) {
+ ccBuf = mCCMap.valueAt(index);
+ } else {
+ size_t size = 0;
+
+ for (ssize_t i = 0; i <= index; ++i) {
+ size += mCCMap.valueAt(i)->size();
+ }
+
+ ccBuf = new ABuffer(size);
+ ccBuf->setRange(0, 0);
+
+ for (ssize_t i = 0; i <= index; ++i) {
+ sp<ABuffer> buf = mCCMap.valueAt(i);
+ memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
+ ccBuf->setRange(0, ccBuf->size() + buf->size());
+ }
+ }
if (ccBuf->size() > 0) {
#if 0
@@ -384,6 +548,25 @@
void NuPlayer::CCDecoder::flush() {
mCCMap.clear();
+ mDTVCCPacket->setRange(0, 0);
+}
+
+int32_t NuPlayer::CCDecoder::CCTrack::compare(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ int32_t cmp = mTrackType - rhs.mTrackType;
+ if (cmp != 0) return cmp;
+ return mTrackChannel - rhs.mTrackChannel;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ return compare(rhs) < 0;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ return compare(rhs) == 0;
+}
+
+bool NuPlayer::CCDecoder::CCTrack::operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const {
+ return compare(rhs) != 0;
}
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
index 77fb0fe..a297334 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerCCDecoder.h
@@ -28,6 +28,11 @@
kWhatTrackAdded,
};
+ enum {
+ kTrackTypeCEA608,
+ kTrackTypeCEA708,
+ };
+
CCDecoder(const sp<AMessage> ¬ify);
size_t getTrackCount() const;
@@ -39,18 +44,50 @@
void flush();
private:
+ // CC track identifier.
+ struct CCTrack {
+ CCTrack() : mTrackType(0), mTrackChannel(0) { }
+
+ CCTrack(const int32_t trackType, const size_t trackChannel)
+ : mTrackType(trackType), mTrackChannel(trackChannel) { }
+
+ int32_t mTrackType;
+ size_t mTrackChannel;
+
+ // The ordering of CCTracks is to build a map of track to index.
+ // It is necessary to find the index of the matched CCTrack when CC data comes.
+ int compare(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ inline bool operator<(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ inline bool operator==(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ inline bool operator!=(const NuPlayer::CCDecoder::CCTrack& rhs) const;
+ };
+
sp<AMessage> mNotify;
KeyedVector<int64_t, sp<ABuffer> > mCCMap;
- size_t mCurrentChannel;
- int32_t mSelectedTrack;
- int32_t mTrackIndices[4];
- Vector<size_t> mFoundChannels;
+ ssize_t mSelectedTrack;
+ KeyedVector<CCTrack, size_t> mTrackIndices;
+ Vector<CCTrack> mTracks;
+
+ // CEA-608 closed caption
+ size_t mLine21Channels[2]; // The current channels of NTSC_CC_FIELD_{1, 2}
+
+ // CEA-708 closed caption
+ sp<ABuffer> mDTVCCPacket;
bool isTrackValid(size_t index) const;
- int32_t getTrackIndex(size_t channel) const;
+ size_t getTrackIndex(int32_t trackType, size_t channel, bool *trackAdded);
+
+ // Extract from H.264 SEIs
bool extractFromSEI(const sp<ABuffer> &accessUnit);
- bool parseSEINalUnit(int64_t timeUs, const uint8_t *nalStart, size_t nalSize);
- sp<ABuffer> filterCCBuf(const sp<ABuffer> &ccBuf, size_t index);
+ bool parseSEINalUnit(int64_t timeUs, const uint8_t *data, size_t size);
+
+ // Extract from MPEG user data
+ bool extractFromMPEGUserData(const sp<ABuffer> &accessUnit);
+ bool parseMPEGUserDataUnit(int64_t timeUs, const uint8_t *data, size_t size);
+
+ // Extract CC tracks from MPEG_cc_data
+ bool parseMPEGCCData(int64_t timeUs, const uint8_t *data, size_t size);
+ bool parseDTVCCPacket(int64_t timeUs, const uint8_t *data, size_t size);
DISALLOW_EVIL_CONSTRUCTORS(CCDecoder);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index ce87f87..4678956 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -525,7 +525,10 @@
ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
msg->setBuffer("buffer", buffer);
mCSDsToSubmit.removeAt(0);
- CHECK(onInputBufferFetched(msg));
+ if (!onInputBufferFetched(msg)) {
+ handleError(UNKNOWN_ERROR);
+ return false;
+ }
return true;
}
@@ -862,7 +865,11 @@
// copy into codec buffer
if (buffer != codecBuffer) {
- CHECK_LE(buffer->size(), codecBuffer->capacity());
+ if (buffer->size() > codecBuffer->capacity()) {
+ handleError(ERROR_BUFFER_TOO_SMALL);
+ mDequeuedInputBuffers.push_back(bufferIx);
+ return false;
+ }
codecBuffer->setRange(0, buffer->size());
memcpy(codecBuffer->data(), buffer->data(), buffer->size());
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index cb5cfe3..ed5cd85 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -853,6 +853,7 @@
if (type == kMetadataBufferTypeANWBuffer) {
((VideoNativeMetadata *)mem->pointer())->nFenceFd = -1;
}
+ info.mMemRef = mem;
}
mBuffers[portIndex].push(info);
@@ -873,8 +874,7 @@
for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
const BufferInfo &info = mBuffers[portIndex][i];
-
- desc->addBuffer(info.mBufferID, info.mData);
+ desc->addBuffer(info.mBufferID, info.mData, info.mMemRef);
}
notify->setObject("portDesc", desc);
@@ -1134,7 +1134,7 @@
// we use useBuffer for metadata regardless of quirks
err = mOMX->useBuffer(
mNode, kPortIndexOutput, mem, &info.mBufferID, mem->size());
-
+ info.mMemRef = mem;
mBuffers[kPortIndexOutput].push(info);
ALOGV("[%s] allocated meta buffer with ID %u (pointer = %p)",
@@ -1570,6 +1570,8 @@
"video_decoder.vp9", "video_encoder.vp9" },
{ MEDIA_MIMETYPE_AUDIO_RAW,
"audio_decoder.raw", "audio_encoder.raw" },
+ { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+ "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
{ MEDIA_MIMETYPE_AUDIO_FLAC,
"audio_decoder.flac", "audio_encoder.flac" },
{ MEDIA_MIMETYPE_AUDIO_MSGSM,
@@ -2845,6 +2847,7 @@
{ MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 },
{ MEDIA_MIMETYPE_VIDEO_VP8, OMX_VIDEO_CodingVP8 },
{ MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
+ { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
};
static status_t GetVideoCodingTypeFromMime(
@@ -4504,9 +4507,10 @@
}
void ACodec::PortDescription::addBuffer(
- IOMX::buffer_id id, const sp<ABuffer> &buffer) {
+ IOMX::buffer_id id, const sp<ABuffer> &buffer, const sp<RefBase> &memRef) {
mBufferIDs.push_back(id);
mBuffers.push_back(buffer);
+ mMemRefs.push_back(memRef);
}
size_t ACodec::PortDescription::countBuffers() {
@@ -4521,6 +4525,10 @@
return mBuffers.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/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 1211aef..1ffd333 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1334,6 +1334,7 @@
info.mBufferID = portDesc->bufferIDAt(i);
info.mOwnedByClient = false;
info.mData = portDesc->bufferAt(i);
+ info.mMemRef = portDesc->memRefAt(i);
if (portIndex == kPortIndexInput && mCrypto != NULL) {
sp<IMemory> mem = mDealer->allocate(info.mData->capacity());
@@ -1906,7 +1907,7 @@
mCodec->initiateShutdown(
msg->what() == kWhatStop /* keepComponentAllocated */);
- returnBuffersToCodec();
+ returnBuffersToCodec(reclaimed);
if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
pushBlankBuffersToNativeWindow(mSurface.get());
@@ -2309,12 +2310,12 @@
updateBatteryStat();
}
-void MediaCodec::returnBuffersToCodec() {
- returnBuffersToCodecOnPort(kPortIndexInput);
- returnBuffersToCodecOnPort(kPortIndexOutput);
+void MediaCodec::returnBuffersToCodec(bool isReclaim) {
+ returnBuffersToCodecOnPort(kPortIndexInput, isReclaim);
+ returnBuffersToCodecOnPort(kPortIndexOutput, isReclaim);
}
-void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex) {
+void MediaCodec::returnBuffersToCodecOnPort(int32_t portIndex, bool isReclaim) {
CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
Mutex::Autolock al(mBufferLock);
@@ -2326,7 +2327,13 @@
if (info->mNotify != NULL) {
sp<AMessage> msg = info->mNotify;
info->mNotify = NULL;
- info->mOwnedByClient = false;
+ if (isReclaim && info->mOwnedByClient) {
+ ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
+ portIndex, i);
+ } else {
+ info->mMemRef = NULL;
+ info->mOwnedByClient = false;
+ }
if (portIndex == kPortIndexInput) {
/* no error, just returning buffers */
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 2a50692..845462b 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -28,6 +28,7 @@
const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2";
const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
+const char *MEDIA_MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision";
const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
@@ -62,6 +63,7 @@
const char *MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt";
const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608";
+const char *MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
const char *MEDIA_MIMETYPE_DATA_TIMED_ID3 = "application/x-id3v4";
} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 41fbf75..ee1f927 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1307,6 +1307,8 @@
compressionFormat = OMX_VIDEO_CodingVP9;
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
compressionFormat = OMX_VIDEO_CodingMPEG2;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, mime)) {
+ compressionFormat = OMX_VIDEO_CodingDolbyVision;
} else {
ALOGE("Not a supported video mime type: %s", mime);
CHECK(!"Should not be here. Not a supported video mime type.");
@@ -1505,6 +1507,8 @@
"video_decoder.vp9", "video_encoder.vp9" },
{ MEDIA_MIMETYPE_AUDIO_RAW,
"audio_decoder.raw", "audio_encoder.raw" },
+ { MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+ "video_decoder.dolby-vision", "video_encoder.dolby-vision" },
{ MEDIA_MIMETYPE_AUDIO_FLAC,
"audio_decoder.flac", "audio_encoder.flac" },
{ MEDIA_MIMETYPE_AUDIO_MSGSM,
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 9d514a6..9d3bab8 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -159,7 +159,16 @@
}
default:
- return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ {
+ OMX_ERRORTYPE err = SimpleSoftOMXComponent::internalSetParameter(
+ index, params);
+ // In case inPort->mDef.nBufferSize changed, the output buffer size
+ // should match the input buffer size.
+ PortInfo *inPort = editPortInfo(0);
+ PortInfo *outPort = editPortInfo(1);
+ outPort->mDef.nBufferSize = inPort->mDef.nBufferSize;
+ return err;
+ }
}
}
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index cabde32..4fcf7b5 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -216,6 +216,12 @@
mediaBuffer->meta_data()->setData(kKeySEI, 0, sei->data(), sei->size());
}
+ sp<ABuffer> mpegUserData;
+ if (buffer->meta()->findBuffer("mpegUserData", &mpegUserData) && mpegUserData != NULL) {
+ mediaBuffer->meta_data()->setData(
+ kKeyMpegUserData, 0, mpegUserData->data(), mpegUserData->size());
+ }
+
*out = mediaBuffer;
return OK;
}
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index c967463..daf6b3d 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1047,6 +1047,8 @@
const uint8_t *data = mBuffer->data();
size_t size = mBuffer->size();
+ Vector<size_t> userDataPositions;
+
bool sawPictureStart = false;
int pprevStartCode = -1;
int prevStartCode = -1;
@@ -1130,6 +1132,10 @@
brokenLink = (data[offset + 7] & 0x20) != 0;
}
+ if (mFormat != NULL && currentStartCode == 0xb2) {
+ userDataPositions.add(offset);
+ }
+
if (mFormat != NULL && currentStartCode == 0x00) {
// Picture start
@@ -1163,6 +1169,19 @@
// hexdump(accessUnit->data(), accessUnit->size());
+ if (userDataPositions.size() > 0) {
+ sp<ABuffer> mpegUserData =
+ new ABuffer(userDataPositions.size() * sizeof(size_t));
+ if (mpegUserData != NULL && mpegUserData->data() != NULL) {
+ for (size_t i = 0; i < userDataPositions.size(); ++i) {
+ memcpy(
+ mpegUserData->data() + i * sizeof(size_t),
+ &userDataPositions[i], sizeof(size_t));
+ }
+ accessUnit->meta()->setBuffer("mpegUserData", mpegUserData);
+ }
+ }
+
return accessUnit;
}
}