Merge "Initial checkin for pause and resume control" into kraken

This commit is contained in:
James Dong
2010-06-11 14:28:55 -07:00
committed by Android (Google) Code Review
9 changed files with 154 additions and 23 deletions

View File

@@ -37,6 +37,7 @@ struct AMRWriter : public MediaWriter {
virtual bool reachedEOS(); virtual bool reachedEOS();
virtual status_t start(); virtual status_t start();
virtual void stop(); virtual void stop();
virtual void pause();
protected: protected:
virtual ~AMRWriter(); virtual ~AMRWriter();
@@ -46,6 +47,8 @@ private:
status_t mInitCheck; status_t mInitCheck;
sp<MediaSource> mSource; sp<MediaSource> mSource;
bool mStarted; bool mStarted;
volatile bool mPaused;
volatile bool mResumed;
volatile bool mDone; volatile bool mDone;
volatile bool mReachedEOS; volatile bool mReachedEOS;
pthread_t mThread; pthread_t mThread;

View File

@@ -39,6 +39,7 @@ public:
virtual status_t start(); virtual status_t start();
virtual bool reachedEOS(); virtual bool reachedEOS();
virtual void stop(); virtual void stop();
virtual void pause();
void beginBox(const char *fourcc); void beginBox(const char *fourcc);
void writeInt8(int8_t x); void writeInt8(int8_t x);
@@ -59,6 +60,8 @@ private:
class Track; class Track;
FILE *mFile; FILE *mFile;
bool mPaused;
bool mStarted;
off_t mOffset; off_t mOffset;
off_t mMdatOffset; off_t mMdatOffset;
uint8_t *mMoovBoxBuffer; uint8_t *mMoovBoxBuffer;
@@ -77,6 +80,7 @@ private:
void setStartTimestamp(int64_t timeUs); void setStartTimestamp(int64_t timeUs);
int64_t getStartTimestamp(); // Not const int64_t getStartTimestamp(); // Not const
status_t startTracks();
void lock(); void lock();
void unlock(); void unlock();

View File

@@ -32,6 +32,7 @@ struct MediaWriter : public RefBase {
virtual bool reachedEOS() = 0; virtual bool reachedEOS() = 0;
virtual status_t start() = 0; virtual status_t start() = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual void pause() = 0;
virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; } virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; }
virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; } virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; }
virtual void setListener(const sp<IMediaPlayerClient>& listener) { virtual void setListener(const sp<IMediaPlayerClient>& listener) {

View File

@@ -692,6 +692,14 @@ status_t StagefrightRecorder::startMPEG4Recording() {
return OK; return OK;
} }
status_t StagefrightRecorder::pause() {
if (mWriter == NULL) {
return UNKNOWN_ERROR;
}
mWriter->pause();
return OK;
}
status_t StagefrightRecorder::stop() { status_t StagefrightRecorder::stop() {
if (mWriter == NULL) { if (mWriter == NULL) {
return UNKNOWN_ERROR; return UNKNOWN_ERROR;

View File

@@ -47,6 +47,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
virtual status_t setListener(const sp<IMediaPlayerClient>& listener); virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare(); virtual status_t prepare();
virtual status_t start(); virtual status_t start();
virtual status_t pause();
virtual status_t stop(); virtual status_t stop();
virtual status_t close(); virtual status_t close();
virtual status_t reset(); virtual status_t reset();

View File

@@ -29,13 +29,17 @@ namespace android {
AMRWriter::AMRWriter(const char *filename) AMRWriter::AMRWriter(const char *filename)
: mFile(fopen(filename, "wb")), : mFile(fopen(filename, "wb")),
mInitCheck(mFile != NULL ? OK : NO_INIT), mInitCheck(mFile != NULL ? OK : NO_INIT),
mStarted(false) { mStarted(false),
mPaused(false),
mResumed(false) {
} }
AMRWriter::AMRWriter(int fd) AMRWriter::AMRWriter(int fd)
: mFile(fdopen(fd, "wb")), : mFile(fdopen(fd, "wb")),
mInitCheck(mFile != NULL ? OK : NO_INIT), mInitCheck(mFile != NULL ? OK : NO_INIT),
mStarted(false) { mStarted(false),
mPaused(false),
mResumed(false) {
} }
AMRWriter::~AMRWriter() { AMRWriter::~AMRWriter() {
@@ -98,10 +102,19 @@ status_t AMRWriter::start() {
return mInitCheck; return mInitCheck;
} }
if (mStarted || mSource == NULL) { if (mSource == NULL) {
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
if (mStarted && mPaused) {
mPaused = false;
mResumed = true;
return OK;
} else if (mStarted) {
// Already started, does nothing
return OK;
}
status_t err = mSource->start(); status_t err = mSource->start();
if (err != OK) { if (err != OK) {
@@ -123,6 +136,13 @@ status_t AMRWriter::start() {
return OK; return OK;
} }
void AMRWriter::pause() {
if (!mStarted) {
return;
}
mPaused = true;
}
void AMRWriter::stop() { void AMRWriter::stop() {
if (!mStarted) { if (!mStarted) {
return; return;
@@ -163,6 +183,9 @@ void AMRWriter::threadFunc() {
mEstimatedDurationUs = 0; mEstimatedDurationUs = 0;
mEstimatedSizeBytes = 0; mEstimatedSizeBytes = 0;
bool stoppedPrematurely = true; bool stoppedPrematurely = true;
int64_t previousPausedDurationUs = 0;
int64_t maxTimestampUs = 0;
while (!mDone) { while (!mDone) {
MediaBuffer *buffer; MediaBuffer *buffer;
status_t err = mSource->read(&buffer); status_t err = mSource->read(&buffer);
@@ -171,6 +194,12 @@ void AMRWriter::threadFunc() {
break; break;
} }
if (mPaused) {
buffer->release();
buffer = NULL;
continue;
}
mEstimatedSizeBytes += buffer->range_length(); mEstimatedSizeBytes += buffer->range_length();
if (exceedsFileSizeLimit()) { if (exceedsFileSizeLimit()) {
buffer->release(); buffer->release();
@@ -184,6 +213,17 @@ void AMRWriter::threadFunc() {
if (timestampUs > mEstimatedDurationUs) { if (timestampUs > mEstimatedDurationUs) {
mEstimatedDurationUs = timestampUs; mEstimatedDurationUs = timestampUs;
} }
if (mResumed) {
previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
mResumed = false;
}
timestampUs -= previousPausedDurationUs;
LOGV("time stamp: %lld, previous paused duration: %lld",
timestampUs, previousPausedDurationUs);
if (timestampUs > maxTimestampUs) {
maxTimestampUs = timestampUs;
}
if (exceedsFileDurationLimit()) { if (exceedsFileDurationLimit()) {
buffer->release(); buffer->release();
buffer = NULL; buffer = NULL;

View File

@@ -121,11 +121,13 @@ status_t AudioSource::read(
uint32_t numFramesRecorded; uint32_t numFramesRecorded;
mRecord->getPosition(&numFramesRecorded); mRecord->getPosition(&numFramesRecorded);
int64_t latency = mRecord->latency() * 1000;
uint32_t sampleRate = mRecord->getSampleRate();
int64_t timestampUs = (1000000LL * numFramesRecorded) / sampleRate - latency;
LOGV("latency: %lld, sample rate: %d, timestamp: %lld",
latency, sampleRate, timestampUs);
buffer->meta_data()->setInt64( buffer->meta_data()->setInt64(kKeyTime, timestampUs);
kKeyTime,
(1000000ll * numFramesRecorded) / mRecord->getSampleRate()
- mRecord->latency() * 1000);
ssize_t n = 0; ssize_t n = 0;
if (mCollectStats) { if (mCollectStats) {

View File

@@ -43,6 +43,7 @@ public:
status_t start(); status_t start();
void stop(); void stop();
void pause();
bool reachedEOS(); bool reachedEOS();
int64_t getDurationUs() const; int64_t getDurationUs() const;
@@ -54,6 +55,8 @@ private:
sp<MetaData> mMeta; sp<MetaData> mMeta;
sp<MediaSource> mSource; sp<MediaSource> mSource;
volatile bool mDone; volatile bool mDone;
volatile bool mPaused;
volatile bool mResumed;
int64_t mMaxTimeStampUs; int64_t mMaxTimeStampUs;
int64_t mEstimatedTrackSizeBytes; int64_t mEstimatedTrackSizeBytes;
@@ -120,6 +123,8 @@ private:
MPEG4Writer::MPEG4Writer(const char *filename) MPEG4Writer::MPEG4Writer(const char *filename)
: mFile(fopen(filename, "wb")), : mFile(fopen(filename, "wb")),
mPaused(false),
mStarted(false),
mOffset(0), mOffset(0),
mMdatOffset(0), mMdatOffset(0),
mEstimatedMoovBoxSize(0), mEstimatedMoovBoxSize(0),
@@ -129,6 +134,8 @@ MPEG4Writer::MPEG4Writer(const char *filename)
MPEG4Writer::MPEG4Writer(int fd) MPEG4Writer::MPEG4Writer(int fd)
: mFile(fdopen(fd, "wb")), : mFile(fdopen(fd, "wb")),
mPaused(false),
mStarted(false),
mOffset(0), mOffset(0),
mMdatOffset(0), mMdatOffset(0),
mEstimatedMoovBoxSize(0), mEstimatedMoovBoxSize(0),
@@ -153,11 +160,36 @@ status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
return OK; return OK;
} }
status_t MPEG4Writer::startTracks() {
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
status_t err = (*it)->start();
if (err != OK) {
for (List<Track *>::iterator it2 = mTracks.begin();
it2 != it; ++it2) {
(*it2)->stop();
}
return err;
}
}
return OK;
}
status_t MPEG4Writer::start() { status_t MPEG4Writer::start() {
if (mFile == NULL) { if (mFile == NULL) {
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
if (mStarted) {
if (mPaused) {
mPaused = false;
return startTracks();
}
return OK;
}
mStartTimestampUs = 0; mStartTimestampUs = 0;
mStreamableFile = true; mStreamableFile = true;
mWriteMoovBoxToMemory = false; mWriteMoovBoxToMemory = false;
@@ -186,23 +218,26 @@ status_t MPEG4Writer::start() {
mOffset = mMdatOffset; mOffset = mMdatOffset;
fseeko(mFile, mMdatOffset, SEEK_SET); fseeko(mFile, mMdatOffset, SEEK_SET);
write("\x00\x00\x00\x01mdat????????", 16); write("\x00\x00\x00\x01mdat????????", 16);
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
status_t err = (*it)->start();
status_t err = startTracks();
if (err != OK) { if (err != OK) {
for (List<Track *>::iterator it2 = mTracks.begin();
it2 != it; ++it2) {
(*it2)->stop();
}
return err; return err;
} }
} mStarted = true;
return OK; return OK;
} }
void MPEG4Writer::pause() {
if (mFile == NULL) {
return;
}
mPaused = true;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
(*it)->pause();
}
}
void MPEG4Writer::stop() { void MPEG4Writer::stop() {
if (mFile == NULL) { if (mFile == NULL) {
return; return;
@@ -298,6 +333,7 @@ void MPEG4Writer::stop() {
fflush(mFile); fflush(mFile);
fclose(mFile); fclose(mFile);
mFile = NULL; mFile = NULL;
mStarted = false;
} }
status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) { status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
@@ -528,6 +564,8 @@ MPEG4Writer::Track::Track(
mMeta(source->getFormat()), mMeta(source->getFormat()),
mSource(source), mSource(source),
mDone(false), mDone(false),
mPaused(false),
mResumed(false),
mMaxTimeStampUs(0), mMaxTimeStampUs(0),
mEstimatedTrackSizeBytes(0), mEstimatedTrackSizeBytes(0),
mSamplesHaveSameSize(true), mSamplesHaveSameSize(true),
@@ -547,6 +585,11 @@ MPEG4Writer::Track::~Track() {
} }
status_t MPEG4Writer::Track::start() { status_t MPEG4Writer::Track::start() {
if (!mDone && mPaused) {
mPaused = false;
mResumed = true;
return OK;
}
status_t err = mSource->start(); status_t err = mSource->start();
if (err != OK) { if (err != OK) {
@@ -569,6 +612,10 @@ status_t MPEG4Writer::Track::start() {
return OK; return OK;
} }
void MPEG4Writer::Track::pause() {
mPaused = true;
}
void MPEG4Writer::Track::stop() { void MPEG4Writer::Track::stop() {
if (mDone) { if (mDone) {
return; return;
@@ -710,6 +757,7 @@ void MPEG4Writer::Track::threadEntry() {
int64_t lastDuration = 0; // Time spacing between the previous two samples int64_t lastDuration = 0; // Time spacing between the previous two samples
int32_t sampleCount = 1; // Sample count in the current stts table entry int32_t sampleCount = 1; // Sample count in the current stts table entry
uint32_t previousSampleSize = 0; // Size of the previous sample uint32_t previousSampleSize = 0; // Size of the previous sample
int64_t previousPausedDurationUs = 0;
sp<MetaData> meta_data; sp<MetaData> meta_data;
MediaBuffer *buffer; MediaBuffer *buffer;
@@ -721,6 +769,15 @@ void MPEG4Writer::Track::threadEntry() {
continue; continue;
} }
// If the codec specific data has not been received yet, delay pause.
// After the codec specific data is received, discard what we received
// when the track is to be paused.
if (mPaused && !mResumed) {
buffer->release();
buffer = NULL;
continue;
}
++count; ++count;
int32_t isCodecConfig; int32_t isCodecConfig;
@@ -831,6 +888,10 @@ void MPEG4Writer::Track::threadEntry() {
continue; continue;
} }
if (!mGotAllCodecSpecificData) {
mGotAllCodecSpecificData = true;
}
// Make a deep copy of the MediaBuffer and Metadata and release // Make a deep copy of the MediaBuffer and Metadata and release
// the original as soon as we can // the original as soon as we can
MediaBuffer *copy = new MediaBuffer(buffer->range_length()); MediaBuffer *copy = new MediaBuffer(buffer->range_length());
@@ -876,6 +937,14 @@ void MPEG4Writer::Track::threadEntry() {
mStartTimestampUs = (timestampUs - mOwner->getStartTimestamp()); mStartTimestampUs = (timestampUs - mOwner->getStartTimestamp());
} }
if (mResumed) {
previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration);
mResumed = false;
}
timestampUs -= previousPausedDurationUs;
LOGV("time stamp: %lld and previous paused duration %lld",
timestampUs, previousPausedDurationUs);
if (timestampUs > mMaxTimeStampUs) { if (timestampUs > mMaxTimeStampUs) {
mMaxTimeStampUs = timestampUs; mMaxTimeStampUs = timestampUs;
} }

View File

@@ -205,13 +205,15 @@ status_t AACEncoder::read(
buffer->set_range(0, 2); buffer->set_range(0, 2);
buffer->meta_data()->setInt32(kKeyIsCodecConfig, true); buffer->meta_data()->setInt32(kKeyIsCodecConfig, true);
*out = buffer; *out = buffer;
++mFrameCount;
mInputBuffer = NULL; mInputBuffer = NULL;
++mFrameCount;
return OK; return OK;
} else { } else if (mFrameCount == 1) {
buffer->meta_data()->setInt32(kKeyIsCodecConfig, false); buffer->meta_data()->setInt32(kKeyIsCodecConfig, false);
} }
// XXX: We assume that the input buffer contains at least
// (actually, exactly) 1024 PCM samples. This needs to be fixed.
if (mInputBuffer == NULL) { if (mInputBuffer == NULL) {
if (mSource->read(&mInputBuffer, options) != OK) { if (mSource->read(&mInputBuffer, options) != OK) {
LOGE("failed to read from input audio source"); LOGE("failed to read from input audio source");
@@ -252,9 +254,10 @@ status_t AACEncoder::read(
} }
buffer->set_range(0, outputLength); buffer->set_range(0, outputLength);
++mFrameCount;
int64_t timestampUs = (mFrameCount * 1000000LL * 1024) / mSampleRate;
// Each output frame compresses 1024 input PCM samples.
int64_t timestampUs = ((mFrameCount - 1) * 1000000LL * 1024) / mSampleRate;
++mFrameCount;
buffer->meta_data()->setInt64(kKeyTime, timestampUs); buffer->meta_data()->setInt64(kKeyTime, timestampUs);
*out = buffer; *out = buffer;