diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 10 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 6 | ||||
-rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 171 | ||||
-rw-r--r-- | media/libstagefright/StagefrightMetadataRetriever.cpp | 6 | ||||
-rw-r--r-- | media/libstagefright/Utils.cpp | 20 | ||||
-rw-r--r-- | media/libstagefright/httplive/LiveSession.cpp | 19 | ||||
-rw-r--r-- | media/libstagefright/httplive/LiveSession.h | 2 | ||||
-rw-r--r-- | media/libstagefright/httplive/M3UParser.cpp | 23 | ||||
-rw-r--r-- | media/libstagefright/include/MPEG4Extractor.h | 4 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/AnotherPacketSource.cpp | 5 | ||||
-rw-r--r-- | media/libstagefright/mpeg2ts/ESQueue.cpp | 29 |
11 files changed, 273 insertions, 22 deletions
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index f4cdde2..5bbe786 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -596,15 +596,21 @@ release: return status; } -status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) +status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig) { if (audioBuffer == NULL) { + if (nonContig != NULL) { + *nonContig = 0; + } return BAD_VALUE; } if (mTransfer != TRANSFER_OBTAIN) { audioBuffer->frameCount = 0; audioBuffer->size = 0; audioBuffer->raw = NULL; + if (nonContig != NULL) { + *nonContig = 0; + } return INVALID_OPERATION; } @@ -623,7 +629,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) ALOGE("%s invalid waitCount %d", __func__, waitCount); requested = NULL; } - return obtainBuffer(audioBuffer, requested); + return obtainBuffer(audioBuffer, requested, NULL /*elapsed*/, nonContig); } status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, const struct timespec *requested, diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 89138e2..d32db7c 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1338,12 +1338,18 @@ release: status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount, size_t *nonContig) { if (audioBuffer == NULL) { + if (nonContig != NULL) { + *nonContig = 0; + } return BAD_VALUE; } if (mTransfer != TRANSFER_OBTAIN) { audioBuffer->frameCount = 0; audioBuffer->size = 0; audioBuffer->raw = NULL; + if (nonContig != NULL) { + *nonContig = 0; + } return INVALID_OPERATION; } diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index f7fa2b6..297a186 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -739,6 +739,16 @@ static bool underMetaDataPath(const Vector<uint32_t> &path) { && path[3] == FOURCC('i', 'l', 's', 't'); } +static bool underQTMetaPath(const Vector<uint32_t> &path, int32_t depth) { + return path.size() >= 2 + && path[0] == FOURCC('m', 'o', 'o', 'v') + && path[1] == FOURCC('m', 'e', 't', 'a') + && (depth == 2 + || (depth == 3 + && (path[2] == FOURCC('i', 'l', 's', 't') + || path[2] == FOURCC('k', 'e', 'y', 's')))); +} + // Given a time in seconds since Jan 1 1904, produce a human-readable string. static void convertTimeToDate(int64_t time_1904, String8 *s) { time_t time_1970 = time_1904 - (((66 * 365 + 17) * 24) * 3600); @@ -1732,31 +1742,35 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('m', 'e', 't', 'a'): { - uint8_t buffer[4]; - if (chunk_data_size < (off64_t)sizeof(buffer)) { - *offset += chunk_size; - return ERROR_MALFORMED; - } + off64_t stop_offset = *offset + chunk_size; + *offset = data_offset; + bool isParsingMetaKeys = underQTMetaPath(mPath, 2); + if (!isParsingMetaKeys) { + uint8_t buffer[4]; + if (chunk_data_size < (off64_t)sizeof(buffer)) { + *offset += chunk_size; + return ERROR_MALFORMED; + } - if (mDataSource->readAt( - data_offset, buffer, 4) < 4) { - *offset += chunk_size; - return ERROR_IO; - } + if (mDataSource->readAt( + data_offset, buffer, 4) < 4) { + *offset += chunk_size; + return ERROR_IO; + } - if (U32_AT(buffer) != 0) { - // Should be version 0, flags 0. + if (U32_AT(buffer) != 0) { + // Should be version 0, flags 0. - // If it's not, let's assume this is one of those - // apparently malformed chunks that don't have flags - // and completely different semantics than what's - // in the MPEG4 specs and skip it. - *offset += chunk_size; - return OK; + // If it's not, let's assume this is one of those + // apparently malformed chunks that don't have flags + // and completely different semantics than what's + // in the MPEG4 specs and skip it. + *offset += chunk_size; + return OK; + } + *offset += sizeof(buffer); } - off64_t stop_offset = *offset + chunk_size; - *offset = data_offset + sizeof(buffer); while (*offset < stop_offset) { status_t err = parseChunk(offset, depth + 1); if (err != OK) { @@ -1920,6 +1934,16 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { break; } + case FOURCC('k', 'e', 'y', 's'): + { + *offset += chunk_size; + + if (underQTMetaPath(mPath, 3)) { + parseQTMetaKey(data_offset, chunk_data_size); + } + break; + } + case FOURCC('t', 'r', 'e', 'x'): { *offset += chunk_size; @@ -2050,6 +2074,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { default: { + // check if we're parsing 'ilst' for meta keys + // if so, treat type as a number (key-id). + if (underQTMetaPath(mPath, 3)) { + parseQTMetaVal(chunk_type, data_offset, chunk_data_size); + } + *offset += chunk_size; break; } @@ -2180,7 +2210,108 @@ status_t MPEG4Extractor::parseSegmentIndex(off64_t offset, size_t size) { return OK; } +status_t MPEG4Extractor::parseQTMetaKey(off64_t offset, size_t size) { + if (size < 8) { + return ERROR_MALFORMED; + } + + uint32_t count; + if (!mDataSource->getUInt32(offset + 4, &count)) { + return ERROR_MALFORMED; + } + + if (mMetaKeyMap.size() > 0) { + ALOGW("'keys' atom seen again, discarding existing entries"); + mMetaKeyMap.clear(); + } + + off64_t keyOffset = offset + 8; + off64_t stopOffset = offset + size; + for (size_t i = 1; i <= count; i++) { + if (keyOffset + 8 > stopOffset) { + return ERROR_MALFORMED; + } + + uint32_t keySize; + if (!mDataSource->getUInt32(keyOffset, &keySize) + || keySize < 8 + || keyOffset + keySize > stopOffset) { + return ERROR_MALFORMED; + } + + uint32_t type; + if (!mDataSource->getUInt32(keyOffset + 4, &type) + || type != FOURCC('m', 'd', 't', 'a')) { + return ERROR_MALFORMED; + } + + keySize -= 8; + keyOffset += 8; + + sp<ABuffer> keyData = new ABuffer(keySize); + if (keyData->data() == NULL) { + return ERROR_MALFORMED; + } + if (mDataSource->readAt( + keyOffset, keyData->data(), keySize) < (ssize_t) keySize) { + return ERROR_MALFORMED; + } + + AString key((const char *)keyData->data(), keySize); + mMetaKeyMap.add(i, key); + + keyOffset += keySize; + } + return OK; +} + +status_t MPEG4Extractor::parseQTMetaVal( + int32_t keyId, off64_t offset, size_t size) { + ssize_t index = mMetaKeyMap.indexOfKey(keyId); + if (index < 0) { + // corresponding key is not present, ignore + return ERROR_MALFORMED; + } + if (size <= 16) { + return ERROR_MALFORMED; + } + uint32_t dataSize; + if (!mDataSource->getUInt32(offset, &dataSize) + || dataSize > size || dataSize <= 16) { + return ERROR_MALFORMED; + } + uint32_t atomFourCC; + if (!mDataSource->getUInt32(offset + 4, &atomFourCC) + || atomFourCC != FOURCC('d', 'a', 't', 'a')) { + return ERROR_MALFORMED; + } + uint32_t dataType; + if (!mDataSource->getUInt32(offset + 8, &dataType) + || ((dataType & 0xff000000) != 0)) { + // not well-known type + return ERROR_MALFORMED; + } + + dataSize -= 16; + offset += 16; + + if (dataType == 23 && dataSize >= 4) { + // BE Float32 + uint32_t val; + if (!mDataSource->getUInt32(offset, &val)) { + return ERROR_MALFORMED; + } + if (!strcasecmp(mMetaKeyMap[index].c_str(), "com.android.capture.fps")) { + mFileMetaData->setFloat(kKeyCaptureFramerate, *(float *)&val); + } + } else { + // add more keys if needed + ALOGV("ignoring key: type %d, size %d", dataType, dataSize); + } + + return OK; +} status_t MPEG4Extractor::parseTrackHeader( off64_t data_offset, off64_t data_size) { diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 101fc8a..820b2fc 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -519,6 +519,12 @@ void StagefrightMetadataRetriever::parseMetaData() { mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp)); + float captureFps; + if (meta->findFloat(kKeyCaptureFramerate, &captureFps)) { + sprintf(tmp, "%f", captureFps); + mMetaData.add(METADATA_KEY_CAPTURE_FRAMERATE, String8(tmp)); + } + bool hasAudio = false; bool hasVideo = false; int32_t videoWidth = -1; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 8506e37..dfe8ad1 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -166,6 +166,16 @@ status_t convertMetaDataToMessage( msg->setInt32("max-input-size", maxInputSize); } + int32_t maxWidth; + if (meta->findInt32(kKeyMaxWidth, &maxWidth)) { + msg->setInt32("max-width", maxWidth); + } + + int32_t maxHeight; + if (meta->findInt32(kKeyMaxHeight, &maxHeight)) { + msg->setInt32("max-height", maxHeight); + } + int32_t rotationDegrees; if (meta->findInt32(kKeyRotation, &rotationDegrees)) { msg->setInt32("rotation-degrees", rotationDegrees); @@ -568,6 +578,16 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { meta->setInt32(kKeyMaxInputSize, maxInputSize); } + int32_t maxWidth; + if (msg->findInt32("max-width", &maxWidth)) { + meta->setInt32(kKeyMaxWidth, maxWidth); + } + + int32_t maxHeight; + if (msg->findInt32("max-height", &maxHeight)) { + meta->setInt32(kKeyMaxHeight, maxHeight); + } + // reassemble the csd data into its original form sp<ABuffer> csd0; if (msg->findBuffer("csd-0", &csd0)) { diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp index 74f58e9..4886000 100644 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -171,6 +171,8 @@ LiveSession::LiveSession( mOrigBandwidthIndex(-1), mLastBandwidthBps(-1ll), mBandwidthEstimator(new BandwidthEstimator()), + mMaxWidth(720), + mMaxHeight(480), mStreamMask(0), mNewStreamMask(0), mSwapMask(0), @@ -345,6 +347,9 @@ status_t LiveSession::getStreamFormat(StreamType stream, sp<AMessage> *format) { if (stream == STREAMTYPE_AUDIO) { // set AAC input buffer size to 32K bytes (256kbps x 1sec) meta->setInt32(kKeyMaxInputSize, 32 * 1024); + } else if (stream == STREAMTYPE_VIDEO) { + meta->setInt32(kKeyMaxWidth, mMaxWidth); + meta->setInt32(kKeyMaxHeight, mMaxHeight); } return convertMetaDataToMessage(meta, format); @@ -847,6 +852,9 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { size_t initialBandwidth = 0; size_t initialBandwidthIndex = 0; + int32_t maxWidth = 0; + int32_t maxHeight = 0; + if (mPlaylist->isVariantPlaylist()) { Vector<BandwidthItem> itemsWithVideo; for (size_t i = 0; i < mPlaylist->size(); ++i) { @@ -860,6 +868,14 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { CHECK(meta->findInt32("bandwidth", (int32_t *)&item.mBandwidth)); + int32_t width, height; + if (meta->findInt32("width", &width)) { + maxWidth = max(maxWidth, width); + } + if (meta->findInt32("height", &height)) { + maxHeight = max(maxHeight, height); + } + mBandwidthItems.push(item); if (mPlaylist->hasType(i, "video")) { itemsWithVideo.push(item); @@ -893,6 +909,9 @@ void LiveSession::onConnect(const sp<AMessage> &msg) { mBandwidthItems.push(item); } + mMaxWidth = maxWidth > 0 ? maxWidth : mMaxWidth; + mMaxHeight = maxHeight > 0 ? maxHeight : mMaxHeight; + mPlaylist->pickRandomMediaItems(); changeConfiguration( 0ll /* timeUs */, initialBandwidthIndex, false /* pickTrack */); diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h index 9117bb1..ed74bc2 100644 --- a/media/libstagefright/httplive/LiveSession.h +++ b/media/libstagefright/httplive/LiveSession.h @@ -191,6 +191,8 @@ private: sp<BandwidthEstimator> mBandwidthEstimator; sp<M3UParser> mPlaylist; + int32_t mMaxWidth; + int32_t mMaxHeight; sp<ALooper> mFetcherLooper; KeyedVector<AString, FetcherInfo> mFetcherInfos; diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp index 7bb7f2c..ef9145c 100644 --- a/media/libstagefright/httplive/M3UParser.cpp +++ b/media/libstagefright/httplive/M3UParser.cpp @@ -808,6 +808,29 @@ status_t M3UParser::parseStreamInf( *meta = new AMessage; } (*meta)->setString(key.c_str(), codecs.c_str()); + } else if (!strcasecmp("resolution", key.c_str())) { + const char *s = val.c_str(); + char *end; + unsigned long width = strtoul(s, &end, 10); + + if (end == s || *end != 'x') { + // malformed + continue; + } + + s = end + 1; + unsigned long height = strtoul(s, &end, 10); + + if (end == s || *end != '\0') { + // malformed + continue; + } + + if (meta->get() == NULL) { + *meta = new AMessage; + } + (*meta)->setInt32("width", width); + (*meta)->setInt32("height", height); } else if (!strcasecmp("audio", key.c_str()) || !strcasecmp("video", key.c_str()) || !strcasecmp("subtitles", key.c_str())) { diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h index 8c16251..3067c3d 100644 --- a/media/libstagefright/include/MPEG4Extractor.h +++ b/media/libstagefright/include/MPEG4Extractor.h @@ -104,11 +104,15 @@ private: String8 mLastCommentName; String8 mLastCommentData; + KeyedVector<uint32_t, AString> mMetaKeyMap; + status_t readMetaData(); status_t parseChunk(off64_t *offset, int depth); status_t parseITunesMetaData(off64_t offset, size_t size); status_t parse3GPPMetaData(off64_t offset, size_t size, int depth); void parseID3v2MetaData(off64_t offset); + status_t parseQTMetaKey(off64_t data_offset, size_t data_size); + status_t parseQTMetaVal(int32_t keyId, off64_t data_offset, size_t data_size); status_t updateAudioTrackInfoFromESDS_MPEG4Audio( const void *esds_data, size_t esds_size); diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp index c7912c0..a4f8739 100644 --- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp +++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp @@ -183,6 +183,11 @@ status_t AnotherPacketSource::read( mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); + int32_t isSync; + if (buffer->meta()->findInt32("isSync", &isSync)) { + mediaBuffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync); + } + *out = mediaBuffer; return OK; } diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index b17985c..a279049 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -533,6 +533,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() { int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize); CHECK_GE(timeUs, 0ll); accessUnit->meta()->setInt64("timeUs", timeUs); + accessUnit->meta()->setInt32("isSync", 1); memmove( mBuffer->data(), @@ -582,6 +583,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { int64_t timeUs = fetchTimestamp(payloadSize + 4); CHECK_GE(timeUs, 0ll); accessUnit->meta()->setInt64("timeUs", timeUs); + accessUnit->meta()->setInt32("isSync", 1); int16_t *ptr = (int16_t *)accessUnit->data(); for (size_t i = 0; i < payloadSize / sizeof(int16_t); ++i) { @@ -693,6 +695,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { mBuffer->setRange(0, mBuffer->size() - offset); accessUnit->meta()->setInt64("timeUs", timeUs); + accessUnit->meta()->setInt32("isSync", 1); return accessUnit; } @@ -743,6 +746,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { const uint8_t *nalStart; size_t nalSize; bool foundSlice = false; + bool foundIDR = false; while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) { if (nalSize == 0) continue; @@ -750,6 +754,9 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { bool flush = false; if (nalType == 1 || nalType == 5) { + if (nalType == 5) { + foundIDR = true; + } if (foundSlice) { ABitReader br(nalStart + 1, nalSize); unsigned first_mb_in_slice = parseUE(&br); @@ -838,6 +845,9 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { CHECK_GE(timeUs, 0ll); accessUnit->meta()->setInt64("timeUs", timeUs); + if (foundIDR) { + accessUnit->meta()->setInt32("isSync", 1); + } if (mFormat == NULL) { mFormat = MakeAVCCodecSpecificData(accessUnit); @@ -894,6 +904,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { CHECK_GE(timeUs, 0ll); accessUnit->meta()->setInt64("timeUs", timeUs); + accessUnit->meta()->setInt32("isSync", 1); if (mFormat == NULL) { mFormat = new MetaData; @@ -970,6 +981,9 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { int pprevStartCode = -1; int prevStartCode = -1; int currentStartCode = -1; + bool gopFound = false; + bool isClosedGop = false; + bool brokenLink = false; size_t offset = 0; while (offset + 3 < size) { @@ -1032,6 +1046,13 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { } } + if (mFormat != NULL && currentStartCode == 0xb8) { + // GOP layer + gopFound = true; + isClosedGop = (data[offset + 7] & 0x40) != 0; + brokenLink = (data[offset + 7] & 0x20) != 0; + } + if (mFormat != NULL && currentStartCode == 0x00) { // Picture start @@ -1053,6 +1074,9 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { offset = 0; accessUnit->meta()->setInt64("timeUs", timeUs); + if (gopFound && (!brokenLink || isClosedGop)) { + accessUnit->meta()->setInt32("isSync", 1); + } ALOGV("returning MPEG video access unit at time %" PRId64 " us", timeUs); @@ -1197,6 +1221,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { case SKIP_TO_VOP_START: { if (chunkType == 0xb6) { + int vopCodingType = (data[offset + 4] & 0xc0) >> 6; + offset += chunkSize; sp<ABuffer> accessUnit = new ABuffer(offset); @@ -1212,6 +1238,9 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { offset = 0; accessUnit->meta()->setInt64("timeUs", timeUs); + if (vopCodingType == 0) { // intra-coded VOP + accessUnit->meta()->setInt32("isSync", 1); + } ALOGV("returning MPEG4 video access unit at time %" PRId64 " us", timeUs); |