summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/mpeg2ts
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/mpeg2ts')
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp20
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.h8
-rw-r--r--media/libstagefright/mpeg2ts/Android.mk2
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.cpp69
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.h9
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.cpp198
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.h2
7 files changed, 280 insertions, 28 deletions
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 2c8cf8d..6d8866a 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -503,9 +503,10 @@ ATSParser::Stream::Stream(
ElementaryStreamQueue::MPEG4_VIDEO);
break;
- case STREAMTYPE_PCM_AUDIO:
+ case STREAMTYPE_LPCM_AC3:
+ case STREAMTYPE_AC3:
mQueue = new ElementaryStreamQueue(
- ElementaryStreamQueue::PCM_AUDIO);
+ ElementaryStreamQueue::AC3);
break;
default:
@@ -550,7 +551,9 @@ status_t ATSParser::Stream::parse(
}
#endif
- return OK;
+ if (!payload_unit_start_indicator) {
+ return OK;
+ }
}
mExpectedContinuityCounter = (continuity_counter + 1) & 0x0f;
@@ -615,7 +618,8 @@ bool ATSParser::Stream::isAudio() const {
case STREAMTYPE_MPEG1_AUDIO:
case STREAMTYPE_MPEG2_AUDIO:
case STREAMTYPE_MPEG2_AUDIO_ADTS:
- case STREAMTYPE_PCM_AUDIO:
+ case STREAMTYPE_LPCM_AC3:
+ case STREAMTYPE_AC3:
return true;
default:
@@ -661,7 +665,7 @@ void ATSParser::Stream::signalDiscontinuity(
}
if (mSource != NULL) {
- mSource->queueDiscontinuity(type, extra);
+ mSource->queueDiscontinuity(type, extra, true);
}
}
@@ -890,6 +894,12 @@ void ATSParser::Stream::onPayloadData(
ALOGV("Stream PID 0x%08x of type 0x%02x now has data.",
mElementaryPID, mStreamType);
+ const char *mime;
+ if (meta->findCString(kKeyMIMEType, &mime)
+ && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
+ && !IsIDR(accessUnit)) {
+ continue;
+ }
mSource = new AnotherPacketSource(meta);
mSource->queueAccessUnit(accessUnit);
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 8a80069..8986a22 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -89,7 +89,13 @@ struct ATSParser : public RefBase {
STREAMTYPE_MPEG2_AUDIO_ADTS = 0x0f,
STREAMTYPE_MPEG4_VIDEO = 0x10,
STREAMTYPE_H264 = 0x1b,
- STREAMTYPE_PCM_AUDIO = 0x83,
+
+ // From ATSC A/53 Part 3:2009, 6.7.1
+ STREAMTYPE_AC3 = 0x81,
+
+ // Stream type 0x83 is non-standard,
+ // it could be LPCM or TrueHD AC3
+ STREAMTYPE_LPCM_AC3 = 0x83,
};
protected:
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index c1a7a9d..c17a0b7 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -13,6 +13,8 @@ LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/media/libstagefright \
$(TOP)/frameworks/native/include/media/openmax
+LOCAL_CFLAGS += -Werror
+
LOCAL_MODULE:= libstagefright_mpeg2ts
ifeq ($(TARGET_ARCH),arm)
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 6dfaa94..010063f 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AnotherPacketSource"
+
#include "AnotherPacketSource.h"
#include <media/stagefright/foundation/ABuffer.h>
@@ -26,16 +29,20 @@
#include <media/stagefright/MetaData.h>
#include <utils/Vector.h>
+#include <inttypes.h>
+
namespace android {
const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
: mIsAudio(false),
+ mIsVideo(false),
mFormat(NULL),
mLastQueuedTimeUs(0),
mEOSResult(OK),
- mLatestEnqueuedMeta(NULL) {
+ mLatestEnqueuedMeta(NULL),
+ mLatestDequeuedMeta(NULL) {
setFormat(meta);
}
@@ -43,6 +50,7 @@ void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
CHECK(mFormat == NULL);
mIsAudio = false;
+ mIsVideo = false;
if (meta == NULL) {
return;
@@ -54,8 +62,10 @@ void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
if (!strncasecmp("audio/", mime, 6)) {
mIsAudio = true;
+ } else if (!strncasecmp("video/", mime, 6)) {
+ mIsVideo = true;
} else {
- CHECK(!strncasecmp("video/", mime, 6));
+ CHECK(!strncasecmp("text/", mime, 5));
}
}
@@ -86,7 +96,7 @@ sp<MetaData> AnotherPacketSource::getFormat() {
sp<RefBase> object;
if (buffer->meta()->findObject("format", &object)) {
- return static_cast<MetaData*>(object.get());
+ return mFormat = static_cast<MetaData*>(object.get());
}
++it;
@@ -115,6 +125,8 @@ status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
return INFO_DISCONTINUITY;
}
+ mLatestDequeuedMeta = (*buffer)->meta()->dup();
+
sp<RefBase> object;
if ((*buffer)->meta()->findObject("format", &object)) {
mFormat = static_cast<MetaData*>(object.get());
@@ -136,8 +148,10 @@ status_t AnotherPacketSource::read(
}
if (!mBuffers.empty()) {
+
const sp<ABuffer> buffer = *mBuffers.begin();
mBuffers.erase(mBuffers.begin());
+ mLatestDequeuedMeta = buffer->meta()->dup();
int32_t discontinuity;
if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
@@ -173,7 +187,11 @@ bool AnotherPacketSource::wasFormatChange(
return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
}
- return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
+ if (mIsVideo) {
+ return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
+ }
+
+ return false;
}
void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
@@ -186,13 +204,13 @@ void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
int64_t lastQueuedTimeUs;
CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
mLastQueuedTimeUs = lastQueuedTimeUs;
- ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
+ ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
Mutex::Autolock autoLock(mLock);
mBuffers.push_back(buffer);
mCondition.signal();
- if (!mLatestEnqueuedMeta.get()) {
+ if (mLatestEnqueuedMeta == NULL) {
mLatestEnqueuedMeta = buffer->meta();
} else {
int64_t latestTimeUs = 0;
@@ -215,22 +233,30 @@ void AnotherPacketSource::clear() {
void AnotherPacketSource::queueDiscontinuity(
ATSParser::DiscontinuityType type,
- const sp<AMessage> &extra) {
+ const sp<AMessage> &extra,
+ bool discard) {
Mutex::Autolock autoLock(mLock);
- // Leave only discontinuities in the queue.
- List<sp<ABuffer> >::iterator it = mBuffers.begin();
- while (it != mBuffers.end()) {
- sp<ABuffer> oldBuffer = *it;
+ if (discard) {
+ // Leave only discontinuities in the queue.
+ List<sp<ABuffer> >::iterator it = mBuffers.begin();
+ while (it != mBuffers.end()) {
+ sp<ABuffer> oldBuffer = *it;
+
+ int32_t oldDiscontinuityType;
+ if (!oldBuffer->meta()->findInt32(
+ "discontinuity", &oldDiscontinuityType)) {
+ MediaBuffer *mbuf = NULL;
+ oldBuffer->meta()->findPointer("mediaBuffer", (void**)&mbuf);
+ if (mbuf != NULL) {
+ mbuf->release();
+ }
+ it = mBuffers.erase(it);
+ continue;
+ }
- int32_t oldDiscontinuityType;
- if (!oldBuffer->meta()->findInt32(
- "discontinuity", &oldDiscontinuityType)) {
- it = mBuffers.erase(it);
- continue;
+ ++it;
}
-
- ++it;
}
mEOSResult = OK;
@@ -323,9 +349,14 @@ bool AnotherPacketSource::isFinished(int64_t duration) const {
return (mEOSResult != OK);
}
-sp<AMessage> AnotherPacketSource::getLatestMeta() {
+sp<AMessage> AnotherPacketSource::getLatestEnqueuedMeta() {
Mutex::Autolock autoLock(mLock);
return mLatestEnqueuedMeta;
}
+sp<AMessage> AnotherPacketSource::getLatestDequeuedMeta() {
+ Mutex::Autolock autoLock(mLock);
+ return mLatestDequeuedMeta;
+}
+
} // namespace android
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 9b193a2..0c717d7 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -54,7 +54,9 @@ struct AnotherPacketSource : public MediaSource {
void queueAccessUnit(const sp<ABuffer> &buffer);
void queueDiscontinuity(
- ATSParser::DiscontinuityType type, const sp<AMessage> &extra);
+ ATSParser::DiscontinuityType type,
+ const sp<AMessage> &extra,
+ bool discard);
void signalEOS(status_t result);
@@ -62,7 +64,8 @@ struct AnotherPacketSource : public MediaSource {
bool isFinished(int64_t duration) const;
- sp<AMessage> getLatestMeta();
+ sp<AMessage> getLatestEnqueuedMeta();
+ sp<AMessage> getLatestDequeuedMeta();
protected:
virtual ~AnotherPacketSource();
@@ -72,11 +75,13 @@ private:
Condition mCondition;
bool mIsAudio;
+ bool mIsVideo;
sp<MetaData> mFormat;
int64_t mLastQueuedTimeUs;
List<sp<ABuffer> > mBuffers;
status_t mEOSResult;
sp<AMessage> mLatestEnqueuedMeta;
+ sp<AMessage> mLatestDequeuedMeta;
bool wasFormatChange(int32_t discontinuityType) const;
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 1960b27..3c8f03e 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -57,6 +57,122 @@ void ElementaryStreamQueue::clear(bool clearFormat) {
}
}
+// Parse AC3 header assuming the current ptr is start position of syncframe,
+// update metadata only applicable, and return the payload size
+static unsigned parseAC3SyncFrame(
+ const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
+ static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+ static const unsigned samplingRateTable[] = {48000, 44100, 32000};
+ static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
+ 320, 384, 448, 512, 576, 640};
+
+ static const unsigned frameSizeTable[19][3] = {
+ { 64, 69, 96 },
+ { 80, 87, 120 },
+ { 96, 104, 144 },
+ { 112, 121, 168 },
+ { 128, 139, 192 },
+ { 160, 174, 240 },
+ { 192, 208, 288 },
+ { 224, 243, 336 },
+ { 256, 278, 384 },
+ { 320, 348, 480 },
+ { 384, 417, 576 },
+ { 448, 487, 672 },
+ { 512, 557, 768 },
+ { 640, 696, 960 },
+ { 768, 835, 1152 },
+ { 896, 975, 1344 },
+ { 1024, 1114, 1536 },
+ { 1152, 1253, 1728 },
+ { 1280, 1393, 1920 },
+ };
+
+ ABitReader bits(ptr, size);
+ unsigned syncStartPos = 0; // in bytes
+ if (bits.numBitsLeft() < 16) {
+ return 0;
+ }
+ if (bits.getBits(16) != 0x0B77) {
+ return 0;
+ }
+
+ if (bits.numBitsLeft() < 16 + 2 + 6 + 5 + 3 + 3) {
+ ALOGV("Not enough bits left for further parsing");
+ return 0;
+ }
+ bits.skipBits(16); // crc1
+
+ unsigned fscod = bits.getBits(2);
+ if (fscod == 3) {
+ ALOGW("Incorrect fscod in AC3 header");
+ return 0;
+ }
+
+ unsigned frmsizecod = bits.getBits(6);
+ if (frmsizecod > 37) {
+ ALOGW("Incorrect frmsizecod in AC3 header");
+ return 0;
+ }
+
+ unsigned bsid = bits.getBits(5);
+ if (bsid > 8) {
+ ALOGW("Incorrect bsid in AC3 header. Possibly E-AC-3?");
+ return 0;
+ }
+
+ unsigned bsmod = bits.getBits(3);
+ unsigned acmod = bits.getBits(3);
+ unsigned cmixlev = 0;
+ unsigned surmixlev = 0;
+ unsigned dsurmod = 0;
+
+ if ((acmod & 1) > 0 && acmod != 1) {
+ if (bits.numBitsLeft() < 2) {
+ return 0;
+ }
+ cmixlev = bits.getBits(2);
+ }
+ if ((acmod & 4) > 0) {
+ if (bits.numBitsLeft() < 2) {
+ return 0;
+ }
+ surmixlev = bits.getBits(2);
+ }
+ if (acmod == 2) {
+ if (bits.numBitsLeft() < 2) {
+ return 0;
+ }
+ dsurmod = bits.getBits(2);
+ }
+
+ if (bits.numBitsLeft() < 1) {
+ return 0;
+ }
+ unsigned lfeon = bits.getBits(1);
+
+ unsigned samplingRate = samplingRateTable[fscod];
+ unsigned payloadSize = frameSizeTable[frmsizecod >> 1][fscod];
+ if (fscod == 1) {
+ payloadSize += frmsizecod & 1;
+ }
+ payloadSize <<= 1; // convert from 16-bit words to bytes
+
+ unsigned channelCount = channelCountTable[acmod] + lfeon;
+
+ if (metaData != NULL) {
+ (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
+ (*metaData)->setInt32(kKeyChannelCount, channelCount);
+ (*metaData)->setInt32(kKeySampleRate, samplingRate);
+ }
+
+ return payloadSize;
+}
+
+static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) {
+ return parseAC3SyncFrame(ptr, size, NULL) > 0;
+}
+
static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
if (size < 3) {
// Not enough data to verify header.
@@ -149,7 +265,7 @@ status_t ElementaryStreamQueue::appendData(
if (startOffset > 0) {
ALOGI("found something resembling an H.264/MPEG syncword "
- "at offset %d",
+ "at offset %zd",
startOffset);
}
@@ -225,6 +341,33 @@ status_t ElementaryStreamQueue::appendData(
break;
}
+ case AC3:
+ {
+ uint8_t *ptr = (uint8_t *)data;
+
+ ssize_t startOffset = -1;
+ for (size_t i = 0; i < size; ++i) {
+ if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
+ startOffset = i;
+ break;
+ }
+ }
+
+ if (startOffset < 0) {
+ return ERROR_MALFORMED;
+ }
+
+ if (startOffset > 0) {
+ ALOGI("found something resembling an AC3 syncword at "
+ "offset %zd",
+ startOffset);
+ }
+
+ data = &ptr[startOffset];
+ size -= startOffset;
+ break;
+ }
+
case MPEG_AUDIO:
{
uint8_t *ptr = (uint8_t *)data;
@@ -329,6 +472,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
return dequeueAccessUnitH264();
case AAC:
return dequeueAccessUnitAAC();
+ case AC3:
+ return dequeueAccessUnitAC3();
case MPEG_VIDEO:
return dequeueAccessUnitMPEGVideo();
case MPEG4_VIDEO:
@@ -341,6 +486,51 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
}
}
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() {
+ unsigned syncStartPos = 0; // in bytes
+ unsigned payloadSize = 0;
+ sp<MetaData> format = new MetaData;
+ while (true) {
+ if (syncStartPos + 2 >= mBuffer->size()) {
+ return NULL;
+ }
+
+ payloadSize = parseAC3SyncFrame(
+ mBuffer->data() + syncStartPos,
+ mBuffer->size() - syncStartPos,
+ &format);
+ if (payloadSize > 0) {
+ break;
+ }
+ ++syncStartPos;
+ }
+
+ if (mBuffer->size() < syncStartPos + payloadSize) {
+ ALOGV("Not enough buffer size for AC3");
+ return NULL;
+ }
+
+ if (mFormat == NULL) {
+ mFormat = format;
+ }
+
+ sp<ABuffer> accessUnit = new ABuffer(syncStartPos + payloadSize);
+ memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize);
+
+ int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
+ CHECK_GE(timeUs, 0ll);
+ accessUnit->meta()->setInt64("timeUs", timeUs);
+
+ memmove(
+ mBuffer->data(),
+ mBuffer->data() + syncStartPos + payloadSize,
+ mBuffer->size() - syncStartPos - payloadSize);
+
+ mBuffer->setRange(0, mBuffer->size() - syncStartPos - payloadSize);
+
+ return accessUnit;
+}
+
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() {
if (mBuffer->size() < 4) {
return NULL;
@@ -587,6 +777,12 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
+ if (nalType == 6) {
+ sp<ABuffer> sei = new ABuffer(pos.nalSize);
+ memcpy(sei->data(), mBuffer->data() + pos.nalOffset, pos.nalSize);
+ accessUnit->meta()->setBuffer("sei", sei);
+ }
+
#if !LOG_NDEBUG
char tmp[128];
sprintf(tmp, "0x%02x", nalType);
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 66a8087..a2cca77 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -32,6 +32,7 @@ struct ElementaryStreamQueue {
enum Mode {
H264,
AAC,
+ AC3,
MPEG_AUDIO,
MPEG_VIDEO,
MPEG4_VIDEO,
@@ -67,6 +68,7 @@ private:
sp<ABuffer> dequeueAccessUnitH264();
sp<ABuffer> dequeueAccessUnitAAC();
+ sp<ABuffer> dequeueAccessUnitAC3();
sp<ABuffer> dequeueAccessUnitMPEGAudio();
sp<ABuffer> dequeueAccessUnitMPEGVideo();
sp<ABuffer> dequeueAccessUnitMPEG4Video();