diff options
Diffstat (limited to 'media/libstagefright/MPEG4Writer.cpp')
-rw-r--r-- | media/libstagefright/MPEG4Writer.cpp | 150 |
1 files changed, 98 insertions, 52 deletions
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 58a4487..4b8440b 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -16,13 +16,17 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "MPEG4Writer" -#include <inttypes.h> -#include <utils/Log.h> #include <arpa/inet.h> - +#include <fcntl.h> +#include <inttypes.h> #include <pthread.h> #include <sys/prctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <utils/Log.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MPEG4Writer.h> @@ -34,13 +38,15 @@ #include <media/stagefright/Utils.h> #include <media/mediarecorder.h> #include <cutils/properties.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> #include "include/ESDS.h" +#define WARN_UNLESS(condition, message, ...) \ +( (CONDITION(condition)) ? false : ({ \ + ALOGW("Condition %s failed " message, #condition, ##__VA_ARGS__); \ + true; \ +})) + namespace android { static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; @@ -435,7 +441,7 @@ status_t MPEG4Writer::addSource(const sp<MediaSource> &source) { // At most 2 tracks can be supported. if (mTracks.size() >= 2) { - ALOGE("Too many tracks (%d) to add", mTracks.size()); + ALOGE("Too many tracks (%zu) to add", mTracks.size()); return ERROR_UNSUPPORTED; } @@ -549,8 +555,8 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { size = MAX_MOOV_BOX_SIZE; } - ALOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated" - " moov size %lld bytes", + ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the" + " estimated moov size %" PRId64 " bytes", mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size); return factor * size; } @@ -586,8 +592,8 @@ status_t MPEG4Writer::start(MetaData *param) { // If file size is set to be larger than the 32 bit file // size limit, treat it as an error. if (mMaxFileSizeLimitBytes > kMax32BitFileSize) { - ALOGW("32-bit file size limit (%lld bytes) too big. " - "It is changed to %lld bytes", + ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. " + "It is changed to %" PRId64 " bytes", mMaxFileSizeLimitBytes, kMax32BitFileSize); mMaxFileSizeLimitBytes = kMax32BitFileSize; } @@ -848,7 +854,7 @@ status_t MPEG4Writer::reset() { } if (mTracks.size() > 1) { - ALOGD("Duration from tracks range is [%lld, %lld] us", + ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs); } @@ -975,13 +981,16 @@ void MPEG4Writer::writeFtypBox(MetaData *param) { if (param && param->findInt32(kKeyFileType, &fileType) && fileType != OUTPUT_FORMAT_MPEG_4) { writeFourcc("3gp4"); + writeInt32(0); + writeFourcc("isom"); + writeFourcc("3gp4"); } else { + writeFourcc("mp42"); + writeInt32(0); writeFourcc("isom"); + writeFourcc("mp42"); } - writeInt32(0); - writeFourcc("isom"); - writeFourcc("3gp4"); endBox(); } @@ -1312,12 +1321,12 @@ bool MPEG4Writer::reachedEOS() { } void MPEG4Writer::setStartTimestampUs(int64_t timeUs) { - ALOGI("setStartTimestampUs: %lld", timeUs); + ALOGI("setStartTimestampUs: %" PRId64, timeUs); CHECK_GE(timeUs, 0ll); Mutex::Autolock autoLock(mLock); if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) { mStartTimestampUs = timeUs; - ALOGI("Earliest track starting time: %lld", mStartTimestampUs); + ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs); } } @@ -1518,7 +1527,7 @@ void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) { { int64_t timeUs; if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) { - ALOGV("Receive request to track progress status for every %lld us", timeUs); + ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs); mTrackEveryTimeDurationUs = timeUs; mTrackingProgressStatus = true; } @@ -1552,7 +1561,7 @@ void MPEG4Writer::bufferChunk(const Chunk& chunk) { } void MPEG4Writer::writeChunkToFile(Chunk* chunk) { - ALOGV("writeChunkToFile: %lld from %s track", + ALOGV("writeChunkToFile: %" PRId64 " from %s track", chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video"); int32_t isFirstSample = true; @@ -1728,7 +1737,7 @@ status_t MPEG4Writer::Track::start(MetaData *params) { startTimeOffsetUs = kInitialDelayTimeUs; } startTimeUs += startTimeOffsetUs; - ALOGI("Start time offset: %lld us", startTimeOffsetUs); + ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs); } meta->setInt64(kKeyTime, startTimeUs); @@ -1763,7 +1772,7 @@ status_t MPEG4Writer::Track::pause() { } status_t MPEG4Writer::Track::stop() { - ALOGD("Stopping %s track", mIsAudio? "Audio": "Video"); + ALOGD("%s track stopping", mIsAudio? "Audio": "Video"); if (!mStarted) { ALOGE("Stop() called but track is not started"); return ERROR_END_OF_STREAM; @@ -1774,19 +1783,14 @@ status_t MPEG4Writer::Track::stop() { } mDone = true; + ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); + mSource->stop(); + ALOGD("%s track source stopped", mIsAudio? "Audio": "Video"); + void *dummy; pthread_join(mThread, &dummy); - status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); - ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video"); - { - status_t status = mSource->stop(); - if (err == OK && status != OK && status != ERROR_END_OF_STREAM) { - err = status; - } - } - ALOGD("%s track stopped", mIsAudio? "Audio": "Video"); return err; } @@ -1813,7 +1817,7 @@ static void getNalUnitType(uint8_t byte, uint8_t* type) { static const uint8_t *findNextStartCode( const uint8_t *data, size_t length) { - ALOGV("findNextStartCode: %p %d", data, length); + ALOGV("findNextStartCode: %p %zu", data, length); size_t bytesLeft = length; while (bytesLeft > 4 && @@ -2100,6 +2104,7 @@ status_t MPEG4Writer::Track::threadEntry() { status_t err = OK; MediaBuffer *buffer; + const char *trackName = mIsAudio ? "Audio" : "Video"; while (!mDone && (err = mSource->read(&buffer)) == OK) { if (buffer->range_length() == 0) { buffer->release(); @@ -2195,15 +2200,27 @@ status_t MPEG4Writer::Track::threadEntry() { if (mResumed) { int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs; - CHECK_GE(durExcludingEarlierPausesUs, 0ll); + if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs; - CHECK_GE(pausedDurationUs, lastDurationUs); + if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + previousPausedDurationUs += pausedDurationUs - lastDurationUs; mResumed = false; } timestampUs -= previousPausedDurationUs; - CHECK_GE(timestampUs, 0ll); + if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + if (!mIsAudio) { /* * Composition time: timestampUs @@ -2215,15 +2232,23 @@ status_t MPEG4Writer::Track::threadEntry() { decodingTimeUs -= previousPausedDurationUs; cttsOffsetTimeUs = timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; - CHECK_GE(cttsOffsetTimeUs, 0ll); + if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + timestampUs = decodingTimeUs; - ALOGV("decoding time: %lld and ctts offset time: %lld", + ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64, timestampUs, cttsOffsetTimeUs); // Update ctts box table if necessary currCttsOffsetTimeTicks = (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL; - CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL); + if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + if (mStszTableEntries->count() == 0) { // Force the first ctts table entry to have one single entry // so that we can do adjustment for the initial track start @@ -2261,9 +2286,13 @@ status_t MPEG4Writer::Track::threadEntry() { } } - CHECK_GE(timestampUs, 0ll); - ALOGV("%s media time stamp: %lld and previous paused duration %lld", - mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs); + if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) { + copy->release(); + return ERROR_MALFORMED; + } + + ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64, + trackName, timestampUs, previousPausedDurationUs); if (timestampUs > mTrackDurationUs) { mTrackDurationUs = timestampUs; } @@ -2277,11 +2306,28 @@ status_t MPEG4Writer::Track::threadEntry() { ((timestampUs * mTimeScale + 500000LL) / 1000000LL - (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL); if (currDurationTicks < 0ll) { - ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track", - timestampUs, lastTimestampUs, mIsAudio? "Audio": "Video"); + ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track", + timestampUs, lastTimestampUs, trackName); + copy->release(); return UNKNOWN_ERROR; } + // if the duration is different for this sample, see if it is close enough to the previous + // duration that we can fudge it and use the same value, to avoid filling the stts table + // with lots of near-identical entries. + // "close enough" here means that the current duration needs to be adjusted by less + // than 0.1 milliseconds + if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) { + int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL + + (mTimeScale / 2)) / mTimeScale; + if (deltaUs > -100 && deltaUs < 100) { + // use previous ticks, and adjust timestamp as if it was actually that number + // of ticks + currDurationTicks = lastDurationTicks; + timestampUs += deltaUs; + } + } + mStszTableEntries->add(htonl(sampleSize)); if (mStszTableEntries->count() > 2) { @@ -2301,8 +2347,8 @@ status_t MPEG4Writer::Track::threadEntry() { } previousSampleSize = sampleSize; } - ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld", - mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs); + ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64, + trackName, timestampUs, lastTimestampUs); lastDurationUs = timestampUs - lastTimestampUs; lastDurationTicks = currDurationTicks; lastTimestampUs = timestampUs; @@ -2407,9 +2453,9 @@ status_t MPEG4Writer::Track::threadEntry() { sendTrackSummary(hasMultipleTracks); ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s", - count, nZeroLengthFrames, mStszTableEntries->count(), mIsAudio? "audio": "video"); + count, nZeroLengthFrames, mStszTableEntries->count(), trackName); if (mIsAudio) { - ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs()); + ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs()); } if (err == ERROR_END_OF_STREAM) { @@ -2492,11 +2538,11 @@ void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { } void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { - ALOGV("trackProgressStatus: %lld us", timeUs); + ALOGV("trackProgressStatus: %" PRId64 " us", timeUs); if (mTrackEveryTimeDurationUs > 0 && timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { - ALOGV("Fire time tracking progress status at %lld us", timeUs); + ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); mPreviousTrackTimeUs = timeUs; } @@ -2530,13 +2576,13 @@ void MPEG4Writer::trackProgressStatus( } void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) { - ALOGV("setDriftTimeUs: %lld us", driftTimeUs); + ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs); Mutex::Autolock autolock(mLock); mDriftTimeUs = driftTimeUs; } int64_t MPEG4Writer::getDriftTimeUs() { - ALOGV("getDriftTimeUs: %lld us", mDriftTimeUs); + ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs); Mutex::Autolock autolock(mLock); return mDriftTimeUs; } @@ -2992,7 +3038,7 @@ void MPEG4Writer::Track::writeCttsBox() { return; } - ALOGV("ctts box has %d entries with range [%lld, %lld]", + ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]", mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs); mOwner->beginBox("ctts"); |