summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/mpeg2ts
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-12-15 15:17:42 -0800
committerAndreas Huber <andih@google.com>2010-12-15 15:18:26 -0800
commita15874665fa785c82afa9f2e8cb3512470c297cb (patch)
tree0a2d5bc416eb12e5d4c4c21dfb4e7111389b7a8c /media/libstagefright/mpeg2ts
parentebf90ac7a82c9a0fa5c02702ccba36bc5082240f (diff)
downloadframeworks_base-a15874665fa785c82afa9f2e8cb3512470c297cb.zip
frameworks_base-a15874665fa785c82afa9f2e8cb3512470c297cb.tar.gz
frameworks_base-a15874665fa785c82afa9f2e8cb3512470c297cb.tar.bz2
Initial support for a true streaming player for mpeg2 transport streams.
Change-Id: I153eec439d260a5524b21270e16d36940ec3161a
Diffstat (limited to 'media/libstagefright/mpeg2ts')
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.cpp95
-rw-r--r--media/libstagefright/mpeg2ts/ATSParser.h11
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.cpp48
-rw-r--r--media/libstagefright/mpeg2ts/AnotherPacketSource.h4
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.cpp11
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.h2
-rw-r--r--media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp2
7 files changed, 133 insertions, 40 deletions
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index a559b21..de6346b 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -43,19 +43,21 @@ namespace android {
static const size_t kTSPacketSize = 188;
struct ATSParser::Program : public RefBase {
- Program(unsigned programMapPID);
+ Program(ATSParser *parser, unsigned programMapPID);
bool parsePID(
unsigned pid, unsigned payload_unit_start_indicator,
ABitReader *br);
- void signalDiscontinuity(bool isASeek);
+ void signalDiscontinuity(DiscontinuityType type);
+ void signalEOS(status_t finalResult);
sp<MediaSource> getSource(SourceType type);
int64_t convertPTSToTimestamp(uint64_t PTS);
private:
+ ATSParser *mParser;
unsigned mProgramMapPID;
KeyedVector<unsigned, sp<Stream> > mStreams;
bool mFirstPTSValid;
@@ -73,7 +75,8 @@ struct ATSParser::Stream : public RefBase {
unsigned payload_unit_start_indicator,
ABitReader *br);
- void signalDiscontinuity(bool isASeek);
+ void signalDiscontinuity(DiscontinuityType type);
+ void signalEOS(status_t finalResult);
sp<MediaSource> getSource(SourceType type);
@@ -105,8 +108,9 @@ private:
////////////////////////////////////////////////////////////////////////////////
-ATSParser::Program::Program(unsigned programMapPID)
- : mProgramMapPID(programMapPID),
+ATSParser::Program::Program(ATSParser *parser, unsigned programMapPID)
+ : mParser(parser),
+ mProgramMapPID(programMapPID),
mFirstPTSValid(false),
mFirstPTS(0) {
}
@@ -135,9 +139,15 @@ bool ATSParser::Program::parsePID(
return true;
}
-void ATSParser::Program::signalDiscontinuity(bool isASeek) {
+void ATSParser::Program::signalDiscontinuity(DiscontinuityType type) {
for (size_t i = 0; i < mStreams.size(); ++i) {
- mStreams.editValueAt(i)->signalDiscontinuity(isASeek);
+ mStreams.editValueAt(i)->signalDiscontinuity(type);
+ }
+}
+
+void ATSParser::Program::signalEOS(status_t finalResult) {
+ for (size_t i = 0; i < mStreams.size(); ++i) {
+ mStreams.editValueAt(i)->signalEOS(finalResult);
}
}
@@ -155,7 +165,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned section_length = br->getBits(12);
LOGV(" section_length = %u", section_length);
- CHECK((section_length & 0xc00) == 0);
+ CHECK_EQ(section_length & 0xc00, 0u);
CHECK_LE(section_length, 1021u);
MY_LOGV(" program_number = %u", br->getBits(16));
@@ -170,7 +180,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned program_info_length = br->getBits(12);
LOGV(" program_info_length = %u", program_info_length);
- CHECK((program_info_length & 0xc00) == 0);
+ CHECK_EQ(program_info_length & 0xc00, 0u);
br->skipBits(program_info_length * 8); // skip descriptors
@@ -194,7 +204,7 @@ void ATSParser::Program::parseProgramMap(ABitReader *br) {
unsigned ES_info_length = br->getBits(12);
LOGV(" ES_info_length = %u", ES_info_length);
- CHECK((ES_info_length & 0xc00) == 0);
+ CHECK_EQ(ES_info_length & 0xc00, 0u);
CHECK_GE(infoBytesRemaining - 5, ES_info_length);
@@ -305,7 +315,7 @@ void ATSParser::Stream::parse(
}
size_t payloadSizeBits = br->numBitsLeft();
- CHECK((payloadSizeBits % 8) == 0);
+ CHECK_EQ(payloadSizeBits % 8, 0u);
CHECK_LE(mBuffer->size() + payloadSizeBits / 8, mBuffer->capacity());
@@ -313,27 +323,45 @@ void ATSParser::Stream::parse(
mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
}
-void ATSParser::Stream::signalDiscontinuity(bool isASeek) {
- isASeek = false; // Always signal a "real" discontinuity
-
+void ATSParser::Stream::signalDiscontinuity(DiscontinuityType type) {
mPayloadStarted = false;
mBuffer->setRange(0, 0);
- mQueue.clear();
+ switch (type) {
+ case DISCONTINUITY_HTTPLIVE:
+ {
+ mQueue.clear(true);
- if (isASeek) {
- // This is only a "minor" discontinuity, we stay within the same
- // bitstream.
+ if (mStreamType == 0x1b && mSource != NULL) {
+ // Don't signal discontinuities on audio streams.
+ mSource->queueDiscontinuity();
+ }
+ break;
+ }
+
+ case DISCONTINUITY_SEEK:
+ case DISCONTINUITY_FORMATCHANGE:
+ {
+ bool isASeek = (type == DISCONTINUITY_SEEK);
- if (mSource != NULL) {
- mSource->clear();
+ mQueue.clear(!isASeek);
+
+ if (mSource != NULL) {
+ mSource->clear();
+ mSource->queueDiscontinuity();
+ }
+ break;
}
- return;
+
+ default:
+ TRESPASS();
+ break;
}
+}
- if (mStreamType == 0x1b && mSource != NULL) {
- // Don't signal discontinuities on audio streams.
- mSource->queueDiscontinuity();
+void ATSParser::Stream::signalEOS(status_t finalResult) {
+ if (mSource != NULL) {
+ mSource->signalEOS(finalResult);
}
}
@@ -478,7 +506,7 @@ void ATSParser::Stream::parsePES(ABitReader *br) {
br->data(), br->numBitsLeft() / 8);
size_t payloadSizeBits = br->numBitsLeft();
- CHECK((payloadSizeBits % 8) == 0);
+ CHECK_EQ(payloadSizeBits % 8, 0u);
LOGV("There's %d bytes of payload.", payloadSizeBits / 8);
}
@@ -526,6 +554,7 @@ void ATSParser::Stream::onPayloadData(
if (meta != NULL) {
LOGV("created source!");
mSource = new AnotherPacketSource(meta);
+
mSource->queueAccessUnit(accessUnit);
}
} else if (mQueue.getFormat() != NULL) {
@@ -561,9 +590,17 @@ void ATSParser::feedTSPacket(const void *data, size_t size) {
parseTS(&br);
}
-void ATSParser::signalDiscontinuity(bool isASeek) {
+void ATSParser::signalDiscontinuity(DiscontinuityType type) {
+ for (size_t i = 0; i < mPrograms.size(); ++i) {
+ mPrograms.editItemAt(i)->signalDiscontinuity(type);
+ }
+}
+
+void ATSParser::signalEOS(status_t finalResult) {
+ CHECK_NE(finalResult, (status_t)OK);
+
for (size_t i = 0; i < mPrograms.size(); ++i) {
- mPrograms.editItemAt(i)->signalDiscontinuity(isASeek);
+ mPrograms.editItemAt(i)->signalEOS(finalResult);
}
}
@@ -581,7 +618,7 @@ void ATSParser::parseProgramAssociationTable(ABitReader *br) {
unsigned section_length = br->getBits(12);
LOGV(" section_length = %u", section_length);
- CHECK((section_length & 0xc00) == 0);
+ CHECK_EQ(section_length & 0xc00, 0u);
MY_LOGV(" transport_stream_id = %u", br->getBits(16));
MY_LOGV(" reserved = %u", br->getBits(2));
@@ -606,7 +643,7 @@ void ATSParser::parseProgramAssociationTable(ABitReader *br) {
LOGV(" program_map_PID = 0x%04x", programMapPID);
- mPrograms.push(new Program(programMapPID));
+ mPrograms.push(new Program(this, programMapPID));
}
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 11b1de4..ef78c77 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -21,19 +21,28 @@
#include <sys/types.h>
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
namespace android {
struct ABitReader;
+struct ABuffer;
struct MediaSource;
struct ATSParser : public RefBase {
+ enum DiscontinuityType {
+ DISCONTINUITY_HTTPLIVE,
+ DISCONTINUITY_SEEK,
+ DISCONTINUITY_FORMATCHANGE
+ };
+
ATSParser();
void feedTSPacket(const void *data, size_t size);
- void signalDiscontinuity(bool isASeek = false);
+ void signalDiscontinuity(DiscontinuityType type);
+ void signalEOS(status_t finalResult);
enum SourceType {
AVC_VIDEO,
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index ea747c8..7a1d5b0 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -48,6 +48,32 @@ sp<MetaData> AnotherPacketSource::getFormat() {
return mFormat;
}
+status_t AnotherPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) {
+ buffer->clear();
+
+ Mutex::Autolock autoLock(mLock);
+ while (mEOSResult == OK && mBuffers.empty()) {
+ mCondition.wait(mLock);
+ }
+
+ if (!mBuffers.empty()) {
+ *buffer = *mBuffers.begin();
+ mBuffers.erase(mBuffers.begin());
+
+ int32_t discontinuity;
+ if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)
+ && discontinuity) {
+ buffer->clear();
+
+ return INFO_DISCONTINUITY;
+ }
+
+ return OK;
+ }
+
+ return mEOSResult;
+}
+
status_t AnotherPacketSource::read(
MediaBuffer **out, const ReadOptions *) {
*out = NULL;
@@ -66,9 +92,8 @@ status_t AnotherPacketSource::read(
&& discontinuity) {
return INFO_DISCONTINUITY;
} else {
- uint64_t timeUs;
- CHECK(buffer->meta()->findInt64(
- "time", (int64_t *)&timeUs));
+ int64_t timeUs;
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
@@ -92,7 +117,7 @@ void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
}
int64_t timeUs;
- CHECK(buffer->meta()->findInt64("time", &timeUs));
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
LOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", timeUs, timeUs / 1E6);
Mutex::Autolock autoLock(mLock);
@@ -134,4 +159,19 @@ bool AnotherPacketSource::hasBufferAvailable(status_t *finalResult) {
return false;
}
+status_t AnotherPacketSource::nextBufferTime(int64_t *timeUs) {
+ *timeUs = 0;
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (mBuffers.empty()) {
+ return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK;
+ }
+
+ sp<ABuffer> buffer = *mBuffers.begin();
+ CHECK(buffer->meta()->findInt64("timeUs", timeUs));
+
+ return OK;
+}
+
} // namespace android
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 6999175..2bc7404 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -39,12 +39,16 @@ struct AnotherPacketSource : public MediaSource {
bool hasBufferAvailable(status_t *finalResult);
+ status_t nextBufferTime(int64_t *timeUs);
+
void queueAccessUnit(const sp<ABuffer> &buffer);
void queueDiscontinuity();
void signalEOS(status_t result);
void clear();
+ status_t dequeueAccessUnit(sp<ABuffer> *buffer);
+
protected:
virtual ~AnotherPacketSource();
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 4b4490d..4e7759d 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -40,13 +40,16 @@ sp<MetaData> ElementaryStreamQueue::getFormat() {
return mFormat;
}
-void ElementaryStreamQueue::clear() {
+void ElementaryStreamQueue::clear(bool clearFormat) {
if (mBuffer != NULL) {
mBuffer->setRange(0, 0);
}
mRangeInfos.clear();
- mFormat.clear();
+
+ if (clearFormat) {
+ mFormat.clear();
+ }
}
static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
@@ -289,7 +292,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
mBuffer->setRange(0, mBuffer->size() - offset);
if (timeUs >= 0) {
- accessUnit->meta()->setInt64("time", timeUs);
+ accessUnit->meta()->setInt64("timeUs", timeUs);
} else {
LOGW("no time for AAC access unit");
}
@@ -470,7 +473,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
int64_t timeUs = fetchTimestamp(nextScan);
CHECK_GE(timeUs, 0ll);
- accessUnit->meta()->setInt64("time", timeUs);
+ accessUnit->meta()->setInt64("timeUs", timeUs);
if (mFormat == NULL) {
mFormat = MakeAVCCodecSpecificData(accessUnit);
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index adce153..5b7957e 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -35,7 +35,7 @@ struct ElementaryStreamQueue {
ElementaryStreamQueue(Mode mode);
status_t appendData(const void *data, size_t size, int64_t timeUs);
- void clear();
+ void clear(bool clearFormat);
sp<ABuffer> dequeueAccessUnit();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 600116e..a1f0796 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -214,7 +214,7 @@ status_t MPEG2TSExtractor::feedMore() {
if (isDiscontinuity(packet, n)) {
LOGI("XXX discontinuity detected");
- mParser->signalDiscontinuity();
+ mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_HTTPLIVE);
} else if (n < (ssize_t)kTSPacketSize) {
return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
} else {