Merge "MPEG2TSExtractor: add syncPoint after mSourceImpls has been updated." into nyc-dev
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index e5c24ca..34b9606 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -25,6 +25,8 @@
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
+#include "mpeg2ts/ATSParser.h"
+
namespace android {
struct AMessage;
@@ -55,6 +57,10 @@
sp<ATSParser> mParser;
+ // Used to remember SyncEvent occurred in feedMore() when called from init(),
+ // because init() needs to update |mSourceImpls| before adding SyncPoint.
+ ATSParser::SyncEvent mLastSyncEvent;
+
Vector<sp<AnotherPacketSource> > mSourceImpls;
Vector<KeyedVector<int64_t, off64_t> > mSyncPoints;
@@ -65,7 +71,14 @@
off64_t mOffset;
void init();
- status_t feedMore();
+ // Try to feed more data from source to parser.
+ // |isInit| means this function is called inside init(). This is a signal to
+ // save SyncEvent so that init() can add SyncPoint after it updates |mSourceImpls|.
+ // This function returns OK if expected amount of data is fed from DataSource to
+ // parser and is successfully parsed. Otherwise, various error codes could be
+ // returned, e.g., ERROR_END_OF_STREAM, or no data availalbe from DataSource, or
+ // the data has syntax error during parsing, etc.
+ status_t feedMore(bool isInit = false);
status_t seek(int64_t seekTimeUs,
const MediaSource::ReadOptions::SeekMode& seekMode);
status_t queueDiscontinuityForSeek(int64_t actualSeekTimeUs);
@@ -73,6 +86,9 @@
status_t feedUntilBufferAvailable(const sp<AnotherPacketSource> &impl);
+ // Add a SynPoint derived from |event|.
+ void addSyncPoint_l(const ATSParser::SyncEvent &event);
+
DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSExtractor);
};
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 2790a0e..fb43a38 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -122,7 +122,7 @@
void setPID(unsigned pid) { mElementaryPID = pid; }
// Parse the payload and set event when PES with a sync frame is detected.
- // This method knows when a PES starts; so record mPesStartOffset in that
+ // This method knows when a PES starts; so record mPesStartOffsets in that
// case.
status_t parse(
unsigned continuity_counter,
@@ -157,7 +157,7 @@
bool mEOSReached;
uint64_t mPrevPTS;
- off64_t mPesStartOffset;
+ List<off64_t> mPesStartOffsets;
ElementaryStreamQueue *mQueue;
@@ -205,16 +205,19 @@
};
ATSParser::SyncEvent::SyncEvent(off64_t offset)
- : mInit(false), mOffset(offset), mTimeUs(0) {}
+ : mHasReturnedData(false), mOffset(offset), mTimeUs(0) {}
void ATSParser::SyncEvent::init(off64_t offset, const sp<MediaSource> &source,
int64_t timeUs) {
- mInit = true;
+ mHasReturnedData = true;
mOffset = offset;
mMediaSource = source;
mTimeUs = timeUs;
}
+void ATSParser::SyncEvent::reset() {
+ mHasReturnedData = false;
+}
////////////////////////////////////////////////////////////////////////////////
ATSParser::Program::Program(
@@ -661,6 +664,7 @@
ALOGI("discontinuity on stream pid 0x%04x", mElementaryPID);
mPayloadStarted = false;
+ mPesStartOffsets.clear();
mBuffer->setRange(0, 0);
mExpectedContinuityCounter = -1;
@@ -697,7 +701,7 @@
}
mPayloadStarted = true;
- mPesStartOffset = offset;
+ mPesStartOffsets.push_back(offset);
}
if (!mPayloadStarted) {
@@ -772,6 +776,7 @@
}
mPayloadStarted = false;
+ mPesStartOffsets.clear();
mEOSReached = false;
mBuffer->setRange(0, 0);
@@ -1105,7 +1110,9 @@
int64_t timeUs;
if (accessUnit->meta()->findInt64("timeUs", &timeUs)) {
found = true;
- event->init(mPesStartOffset, mSource, timeUs);
+ off64_t pesStartOffset = *mPesStartOffsets.begin();
+ event->init(pesStartOffset, mSource, timeUs);
+ mPesStartOffsets.erase(mPesStartOffsets.begin());
}
}
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 430a8d5..fb03cd6 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -69,16 +69,18 @@
void init(off64_t offset, const sp<MediaSource> &source,
int64_t timeUs);
- bool isInit() { return mInit; }
- off64_t getOffset() { return mOffset; }
- const sp<MediaSource> &getMediaSource() { return mMediaSource; }
- int64_t getTimeUs() { return mTimeUs; }
+ bool hasReturnedData() const { return mHasReturnedData; }
+ void reset();
+ off64_t getOffset() const { return mOffset; }
+ const sp<MediaSource> &getMediaSource() const { return mMediaSource; }
+ int64_t getTimeUs() const { return mTimeUs; }
private:
- bool mInit;
+ bool mHasReturnedData;
/*
- * mInit == false: the current offset
- * mInit == true: the start offset of sync payload
+ * mHasReturnedData == false: the current offset (or undefined if the returned data
+ has been invalidated via reset())
+ * mHasReturnedData == true: the start offset of sync payload
*/
off64_t mOffset;
/* The media source object for this event. */
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 0b456c3..fb5e079 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -112,6 +112,7 @@
MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
: mDataSource(source),
mParser(new ATSParser),
+ mLastSyncEvent(0),
mOffset(0) {
init();
}
@@ -149,8 +150,10 @@
bool haveVideo = false;
int64_t startTime = ALooper::GetNowUs();
- while (feedMore() == OK) {
+ while (feedMore(true /* isInit */) == OK) {
if (haveAudio && haveVideo) {
+ addSyncPoint_l(mLastSyncEvent);
+ mLastSyncEvent.reset();
break;
}
if (!haveVideo) {
@@ -181,6 +184,9 @@
}
}
+ addSyncPoint_l(mLastSyncEvent);
+ mLastSyncEvent.reset();
+
// Wait only for 2 seconds to detect audio/video streams.
if (ALooper::GetNowUs() - startTime > 2000000ll) {
break;
@@ -245,7 +251,7 @@
haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
}
-status_t MPEG2TSExtractor::feedMore() {
+status_t MPEG2TSExtractor::feedMore(bool isInit) {
Mutex::Autolock autoLock(mLock);
uint8_t packet[kTSPacketSize];
@@ -261,29 +267,41 @@
ATSParser::SyncEvent event(mOffset);
mOffset += n;
status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
- if (event.isInit()) {
- for (size_t i = 0; i < mSourceImpls.size(); ++i) {
- if (mSourceImpls[i].get() == event.getMediaSource().get()) {
- KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i);
- syncPoints->add(event.getTimeUs(), event.getOffset());
- // We're keeping the size of the sync points at most 5mb per a track.
- size_t size = syncPoints->size();
- if (size >= 327680) {
- int64_t firstTimeUs = syncPoints->keyAt(0);
- int64_t lastTimeUs = syncPoints->keyAt(size - 1);
- if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) {
- syncPoints->removeItemsAt(0, 4096);
- } else {
- syncPoints->removeItemsAt(size - 4096, 4096);
- }
- }
- break;
- }
+ if (event.hasReturnedData()) {
+ if (isInit) {
+ mLastSyncEvent = event;
+ } else {
+ addSyncPoint_l(event);
}
}
return err;
}
+void MPEG2TSExtractor::addSyncPoint_l(const ATSParser::SyncEvent &event) {
+ if (!event.hasReturnedData()) {
+ return;
+ }
+
+ for (size_t i = 0; i < mSourceImpls.size(); ++i) {
+ if (mSourceImpls[i].get() == event.getMediaSource().get()) {
+ KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i);
+ syncPoints->add(event.getTimeUs(), event.getOffset());
+ // We're keeping the size of the sync points at most 5mb per a track.
+ size_t size = syncPoints->size();
+ if (size >= 327680) {
+ int64_t firstTimeUs = syncPoints->keyAt(0);
+ int64_t lastTimeUs = syncPoints->keyAt(size - 1);
+ if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) {
+ syncPoints->removeItemsAt(0, 4096);
+ } else {
+ syncPoints->removeItemsAt(size - 4096, 4096);
+ }
+ }
+ break;
+ }
+ }
+}
+
uint32_t MPEG2TSExtractor::flags() const {
return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD;
}