am 1824486e: Handle recording file size and/or duration limit
This commit is contained in:
@@ -49,9 +49,13 @@ private:
|
|||||||
volatile bool mDone;
|
volatile bool mDone;
|
||||||
volatile bool mReachedEOS;
|
volatile bool mReachedEOS;
|
||||||
pthread_t mThread;
|
pthread_t mThread;
|
||||||
|
int64_t mEstimatedSizeBytes;
|
||||||
|
int64_t mEstimatedDurationUs;
|
||||||
|
|
||||||
static void *ThreadWrapper(void *);
|
static void *ThreadWrapper(void *);
|
||||||
void threadFunc();
|
void threadFunc();
|
||||||
|
bool exceedsFileSizeLimit();
|
||||||
|
bool exceedsFileDurationLimit();
|
||||||
|
|
||||||
AMRWriter(const AMRWriter &);
|
AMRWriter(const AMRWriter &);
|
||||||
AMRWriter &operator=(const AMRWriter &);
|
AMRWriter &operator=(const AMRWriter &);
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ private:
|
|||||||
off_t addLengthPrefixedSample_l(MediaBuffer *buffer);
|
off_t addLengthPrefixedSample_l(MediaBuffer *buffer);
|
||||||
|
|
||||||
inline size_t write(const void *ptr, size_t size, size_t nmemb, FILE* stream);
|
inline size_t write(const void *ptr, size_t size, size_t nmemb, FILE* stream);
|
||||||
|
bool exceedsFileSizeLimit();
|
||||||
|
bool exceedsFileDurationLimit();
|
||||||
|
|
||||||
MPEG4Writer(const MPEG4Writer &);
|
MPEG4Writer(const MPEG4Writer &);
|
||||||
MPEG4Writer &operator=(const MPEG4Writer &);
|
MPEG4Writer &operator=(const MPEG4Writer &);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#define MEDIA_WRITER_H_
|
#define MEDIA_WRITER_H_
|
||||||
|
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
|
#include <media/IMediaPlayerClient.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -31,10 +32,23 @@ 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 setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; }
|
||||||
|
virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; }
|
||||||
|
virtual void setListener(const sp<IMediaPlayerClient>& listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~MediaWriter() {}
|
virtual ~MediaWriter() {}
|
||||||
|
int64_t mMaxFileSizeLimitBytes;
|
||||||
|
int64_t mMaxFileDurationLimitUs;
|
||||||
|
sp<IMediaPlayerClient> mListener;
|
||||||
|
|
||||||
|
void notify(int msg, int ext1, int ext2) {
|
||||||
|
if (mListener != NULL) {
|
||||||
|
mListener->notify(msg, ext1, ext2);
|
||||||
|
}
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
MediaWriter(const MediaWriter &);
|
MediaWriter(const MediaWriter &);
|
||||||
MediaWriter &operator=(const MediaWriter &);
|
MediaWriter &operator=(const MediaWriter &);
|
||||||
|
|||||||
@@ -523,6 +523,14 @@ status_t StagefrightRecorder::startAMRRecording() {
|
|||||||
CHECK(mOutputFd >= 0);
|
CHECK(mOutputFd >= 0);
|
||||||
mWriter = new AMRWriter(dup(mOutputFd));
|
mWriter = new AMRWriter(dup(mOutputFd));
|
||||||
mWriter->addSource(audioEncoder);
|
mWriter->addSource(audioEncoder);
|
||||||
|
|
||||||
|
if (mMaxFileDurationUs != 0) {
|
||||||
|
mWriter->setMaxFileDuration(mMaxFileDurationUs);
|
||||||
|
}
|
||||||
|
if (mMaxFileSizeBytes != 0) {
|
||||||
|
mWriter->setMaxFileSize(mMaxFileSizeBytes);
|
||||||
|
}
|
||||||
|
mWriter->setListener(mListener);
|
||||||
mWriter->start();
|
mWriter->start();
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
@@ -641,6 +649,13 @@ status_t StagefrightRecorder::startMPEG4Recording() {
|
|||||||
writer->setInterleaveDuration(mInterleaveDurationUs);
|
writer->setInterleaveDuration(mInterleaveDurationUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mMaxFileDurationUs != 0) {
|
||||||
|
mWriter->setMaxFileDuration(mMaxFileDurationUs);
|
||||||
|
}
|
||||||
|
if (mMaxFileSizeBytes != 0) {
|
||||||
|
mWriter->setMaxFileSize(mMaxFileSizeBytes);
|
||||||
|
}
|
||||||
|
mWriter->setListener(mListener);
|
||||||
mWriter->start();
|
mWriter->start();
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <media/stagefright/MediaErrors.h>
|
#include <media/stagefright/MediaErrors.h>
|
||||||
#include <media/stagefright/MediaSource.h>
|
#include <media/stagefright/MediaSource.h>
|
||||||
#include <media/stagefright/MetaData.h>
|
#include <media/stagefright/MetaData.h>
|
||||||
|
#include <media/mediarecorder.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -137,6 +138,20 @@ void AMRWriter::stop() {
|
|||||||
mStarted = false;
|
mStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AMRWriter::exceedsFileSizeLimit() {
|
||||||
|
if (mMaxFileSizeLimitBytes == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AMRWriter::exceedsFileDurationLimit() {
|
||||||
|
if (mMaxFileDurationLimitUs == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void *AMRWriter::ThreadWrapper(void *me) {
|
void *AMRWriter::ThreadWrapper(void *me) {
|
||||||
static_cast<AMRWriter *>(me)->threadFunc();
|
static_cast<AMRWriter *>(me)->threadFunc();
|
||||||
@@ -145,6 +160,8 @@ void *AMRWriter::ThreadWrapper(void *me) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AMRWriter::threadFunc() {
|
void AMRWriter::threadFunc() {
|
||||||
|
mEstimatedDurationUs = 0;
|
||||||
|
mEstimatedSizeBytes = 0;
|
||||||
while (!mDone) {
|
while (!mDone) {
|
||||||
MediaBuffer *buffer;
|
MediaBuffer *buffer;
|
||||||
status_t err = mSource->read(&buffer);
|
status_t err = mSource->read(&buffer);
|
||||||
@@ -153,6 +170,25 @@ void AMRWriter::threadFunc() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mEstimatedSizeBytes += buffer->range_length();
|
||||||
|
if (exceedsFileSizeLimit()) {
|
||||||
|
buffer->release();
|
||||||
|
buffer = NULL;
|
||||||
|
notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t timestampUs;
|
||||||
|
CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs));
|
||||||
|
if (timestampUs > mEstimatedDurationUs) {
|
||||||
|
mEstimatedDurationUs = timestampUs;
|
||||||
|
}
|
||||||
|
if (exceedsFileDurationLimit()) {
|
||||||
|
buffer->release();
|
||||||
|
buffer = NULL;
|
||||||
|
notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
ssize_t n = fwrite(
|
ssize_t n = fwrite(
|
||||||
(const uint8_t *)buffer->data() + buffer->range_offset(),
|
(const uint8_t *)buffer->data() + buffer->range_offset(),
|
||||||
1,
|
1,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include <media/stagefright/MediaErrors.h>
|
#include <media/stagefright/MediaErrors.h>
|
||||||
#include <media/stagefright/MediaSource.h>
|
#include <media/stagefright/MediaSource.h>
|
||||||
#include <media/stagefright/Utils.h>
|
#include <media/stagefright/Utils.h>
|
||||||
|
#include <media/mediarecorder.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ public:
|
|||||||
bool reachedEOS();
|
bool reachedEOS();
|
||||||
|
|
||||||
int64_t getDurationUs() const;
|
int64_t getDurationUs() const;
|
||||||
|
int64_t getEstimatedTrackSizeBytes() const;
|
||||||
void writeTrackHeader(int32_t trackID);
|
void writeTrackHeader(int32_t trackID);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -52,6 +54,7 @@ private:
|
|||||||
sp<MediaSource> mSource;
|
sp<MediaSource> mSource;
|
||||||
volatile bool mDone;
|
volatile bool mDone;
|
||||||
int64_t mMaxTimeStampUs;
|
int64_t mMaxTimeStampUs;
|
||||||
|
int64_t mEstimatedTrackSizeBytes;
|
||||||
|
|
||||||
pthread_t mThread;
|
pthread_t mThread;
|
||||||
|
|
||||||
@@ -455,6 +458,35 @@ void MPEG4Writer::write(const void *data, size_t size) {
|
|||||||
write(data, 1, size, mFile);
|
write(data, 1, size, mFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MPEG4Writer::exceedsFileSizeLimit() {
|
||||||
|
// No limit
|
||||||
|
if (mMaxFileSizeLimitBytes == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t nTotalBytesEstimate = mEstimatedMoovBoxSize;
|
||||||
|
for (List<Track *>::iterator it = mTracks.begin();
|
||||||
|
it != mTracks.end(); ++it) {
|
||||||
|
nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
|
||||||
|
}
|
||||||
|
return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MPEG4Writer::exceedsFileDurationLimit() {
|
||||||
|
// No limit
|
||||||
|
if (mMaxFileDurationLimitUs == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (List<Track *>::iterator it = mTracks.begin();
|
||||||
|
it != mTracks.end(); ++it) {
|
||||||
|
if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MPEG4Writer::reachedEOS() {
|
bool MPEG4Writer::reachedEOS() {
|
||||||
bool allDone = true;
|
bool allDone = true;
|
||||||
for (List<Track *>::iterator it = mTracks.begin();
|
for (List<Track *>::iterator it = mTracks.begin();
|
||||||
@@ -656,6 +688,7 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
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
|
||||||
|
|
||||||
|
mEstimatedTrackSizeBytes = 0;
|
||||||
MediaBuffer *buffer;
|
MediaBuffer *buffer;
|
||||||
while (!mDone && mSource->read(&buffer) == OK) {
|
while (!mDone && mSource->read(&buffer) == OK) {
|
||||||
if (buffer->range_length() == 0) {
|
if (buffer->range_length() == 0) {
|
||||||
@@ -784,6 +817,21 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
#endif
|
#endif
|
||||||
: buffer->range_length();
|
: buffer->range_length();
|
||||||
|
|
||||||
|
// Max file size or duration handling
|
||||||
|
mEstimatedTrackSizeBytes += info.size;
|
||||||
|
if (mOwner->exceedsFileSizeLimit()) {
|
||||||
|
buffer->release();
|
||||||
|
buffer = NULL;
|
||||||
|
mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (mOwner->exceedsFileDurationLimit()) {
|
||||||
|
buffer->release();
|
||||||
|
buffer = NULL;
|
||||||
|
mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_audio = !strncasecmp(mime, "audio/", 6);
|
bool is_audio = !strncasecmp(mime, "audio/", 6);
|
||||||
|
|
||||||
int64_t timestampUs;
|
int64_t timestampUs;
|
||||||
@@ -904,6 +952,10 @@ int64_t MPEG4Writer::Track::getDurationUs() const {
|
|||||||
return mMaxTimeStampUs;
|
return mMaxTimeStampUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
|
||||||
|
return mEstimatedTrackSizeBytes;
|
||||||
|
}
|
||||||
|
|
||||||
void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
||||||
const char *mime;
|
const char *mime;
|
||||||
bool success = mMeta->findCString(kKeyMIMEType, &mime);
|
bool success = mMeta->findCString(kKeyMIMEType, &mime);
|
||||||
|
|||||||
Reference in New Issue
Block a user