Loading media/libaudioclient/AudioRecord.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -773,7 +773,7 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String // use case 3: obtain/release mode (mTransfer == TRANSFER_OBTAIN); if (!useCaseAllowed) { ALOGW("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", ALOGD("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", __func__, mPortId, convertTransferToText(mTransfer)); mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST | Loading media/libaudioclient/AudioTrack.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -1632,7 +1632,7 @@ status_t AudioTrack::createTrack_l() mAwaitBoost = true; } } else { ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", ALOGD("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", __func__, mPortId, mReqFrameCount, mFrameCount); } } Loading media/libmediaplayerservice/StagefrightRecorder.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -2011,6 +2011,7 @@ void StagefrightRecorder::setupMPEG4orWEBMMetaData(sp<MetaData> *meta) { } if (mOutputFormat == OUTPUT_FORMAT_MPEG_4 || mOutputFormat == OUTPUT_FORMAT_THREE_GPP) { (*meta)->setInt32(kKeyEmptyTrackMalFormed, true); (*meta)->setInt32(kKey4BitTrackIds, true); } } Loading media/libstagefright/HevcUtils.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) { } if (err != OK) { ALOGE("error parsing VPS or SPS or PPS"); return err; } Loading media/libstagefright/MPEG4Writer.cpp +146 −61 Original line number Diff line number Diff line Loading @@ -103,8 +103,40 @@ static const uint8_t kHevcNalUnitTypes[5] = { //#define SHOW_MODEL_BUILD 1 class MPEG4Writer::Track { struct TrackId { TrackId(uint32_t aId) :mId(aId), mTrackIdValid(false) { } bool isValid(bool akKey4BitTrackIds) { // trackId cannot be zero, ISO/IEC 14496-12 8.3.2.3 if (mId == 0) { return false; } /* MediaRecorder uses only 4 bit to represent track ids during notifying clients. * MediaMuxer's track ids are restricted by container allowed size only. * MPEG4 Container defines unsigned int (32), ISO/IEC 14496-12 8.3.2.2 */ if (akKey4BitTrackIds && mId > 15) { return false; } mTrackIdValid = true; return true; } uint32_t getId() const { CHECK(mTrackIdValid); return mId; } TrackId() = delete; DISALLOW_EVIL_CONSTRUCTORS(TrackId); private: // unsigned int (32), ISO/IEC 14496-12 8.3.2.2 uint32_t mId; bool mTrackIdValid; }; public: Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); Track(MPEG4Writer *owner, const sp<MediaSource> &source, uint32_t aTrackId); ~Track(); Loading @@ -129,7 +161,7 @@ public: void addChunkOffset(off64_t offset); void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif); void flushItemRefs(); int32_t getTrackId() const { return mTrackId; } TrackId& getTrackId() { return mTrackId; } status_t dump(int fd, const Vector<String16>& args) const; static const char *getFourCCForMime(const char *mime); const char *getTrackType() const; Loading Loading @@ -290,7 +322,7 @@ private: bool mIsMPEG4; bool mGotStartKeyFrame; bool mIsMalformed; int32_t mTrackId; TrackId mTrackId; int64_t mTrackDurationUs; int64_t mMaxChunkDurationUs; int64_t mLastDecodingTimeUs; Loading Loading @@ -413,7 +445,7 @@ private: void addOneElstTableEntry(uint32_t segmentDuration, int32_t mediaTime, int16_t mediaRate, int16_t mediaRateFraction); bool isTrackMalFormed() const; bool isTrackMalFormed(); void sendTrackSummary(bool hasMultipleTracks); // Write the boxes Loading Loading @@ -534,7 +566,7 @@ void MPEG4Writer::initInternal(int fd, bool isFirstSession) { release(); } if (fallocate(mFd, 0, 0, 1) == 0) { if (fallocate(mFd, FALLOC_FL_KEEP_SIZE, 0, 1) == 0) { ALOGD("PreAllocation enabled"); mPreAllocationEnabled = true; } else { Loading Loading @@ -744,8 +776,7 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { // where 1MB is the common file size limit for MMS application. // The default MAX _MOOV_BOX_SIZE value is based on about 3 // minute video recording with a bit rate about 3 Mbps, because // statistics also show that most of the video captured are going // to be less than 3 minutes. // statistics show that most captured videos are less than 3 minutes. // If the estimation is wrong, we will pay the price of wasting // some reserved space. This should not happen so often statistically. Loading Loading @@ -796,6 +827,15 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { return size; } status_t MPEG4Writer::validateAllTracksId(bool akKey4BitTrackIds) { for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { if (!(*it)->getTrackId().isValid(akKey4BitTrackIds)) { return BAD_VALUE; } } return OK; } status_t MPEG4Writer::start(MetaData *param) { if (mInitCheck != OK) { return UNKNOWN_ERROR; Loading @@ -810,6 +850,9 @@ status_t MPEG4Writer::start(MetaData *param) { mIsFileSizeLimitExplicitlyRequested = true; } /* mMaxFileSizeLimitBytes has to be set everytime fd is switched, hence the following code is * appropriate in start() method. */ int32_t fileSizeBits = fpathconf(mFd, _PC_FILESIZEBITS); ALOGD("fpathconf _PC_FILESIZEBITS:%" PRId32, fileSizeBits); fileSizeBits = std::min(fileSizeBits, 52 /* cap it below 4 peta bytes */); Loading Loading @@ -944,6 +987,17 @@ status_t MPEG4Writer::start(MetaData *param) { setupAndStartLooper(); int32_t is4bitTrackId = false; if (param && param->findInt32(kKey4BitTrackIds, &is4bitTrackId) && is4bitTrackId) { err = validateAllTracksId(true); } else { err = validateAllTracksId(false); } if (err != OK) { return err; } err = startTracks(param); if (err != OK) { return err; Loading @@ -961,6 +1015,7 @@ status_t MPEG4Writer::pause() { status_t MPEG4Writer::stopWriterThread() { ALOGV("Stopping writer thread"); if (!mWriterThreadStarted) { ALOGD("Writer thread not started"); return OK; } { Loading @@ -975,7 +1030,8 @@ status_t MPEG4Writer::stopWriterThread() { err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); mWriterThreadStarted = false; WARN_UNLESS(err == 0, "stopWriterThread pthread_join retVal: %d, writer thread stopped", err); WARN_UNLESS(err == 0, "stopWriterThread pthread_join retVal: %d", err); ALOGD("Writer thread stopped"); return err; } Loading Loading @@ -1031,26 +1087,32 @@ void MPEG4Writer::writeCompositionMatrix(int degrees) { writeInt32(0x40000000); // w } void MPEG4Writer::release() { status_t MPEG4Writer::release() { ALOGD("release()"); if (mPreAllocationEnabled) { truncatePreAllocation(); } int err = OK; int retVal = fsync(mFd); WARN_UNLESS(retVal == 0, "fsync retVal:%d", retVal); WARN_UNLESS(retVal == 0, "fsync err:%s(%d)", std::strerror(errno), errno); err |= retVal; retVal = close(mFd); WARN_UNLESS(retVal == 0, "close mFd retVal :%d", retVal); WARN_UNLESS(retVal == 0, "close err:%s(%d)", std::strerror(errno), errno); err |= retVal; mFd = -1; if (mNextFd != -1) { retVal = close(mNextFd); mNextFd = -1; WARN_UNLESS(retVal == 0, "close mNextFd retVal :%d", retVal); WARN_UNLESS(retVal == 0, "close mNextFd error:%s(%d)", std::strerror(errno), errno); err |= retVal; } stopAndReleaseLooper(); mInitCheck = NO_INIT; mStarted = false; free(mInMemoryCache); mInMemoryCache = NULL; return err; } void MPEG4Writer::finishCurrentSession() { Loading @@ -1065,7 +1127,7 @@ status_t MPEG4Writer::switchFd() { } if (mNextFd == -1) { ALOGW("No FileDescripter for next recording"); ALOGW("No FileDescriptor for next recording"); return INVALID_OPERATION; } Loading @@ -1084,12 +1146,15 @@ status_t MPEG4Writer::reset(bool stopSource) { } else { if (!mWriterThreadStarted || !mStarted) { status_t err = OK; status_t writerErr = OK; if (mWriterThreadStarted) { err = stopWriterThread(); writerErr = stopWriterThread(); } release(); return err; status_t retErr = release(); if (writerErr != OK) { retErr = writerErr; } return retErr; } } Loading @@ -1100,8 +1165,9 @@ status_t MPEG4Writer::reset(bool stopSource) { for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { status_t trackErr = (*it)->stop(stopSource); WARN_UNLESS(trackErr == 0, "%s track stopped with an error", (*it)->getTrackType()); if (err == OK && trackErr != OK) { ALOGW("%s track stopped with an error", (*it)->getTrackType()); err = trackErr; } Loading @@ -1118,7 +1184,6 @@ status_t MPEG4Writer::reset(bool stopSource) { } } if (nonImageTrackCount > 1) { ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs); Loading @@ -1126,13 +1191,15 @@ status_t MPEG4Writer::reset(bool stopSource) { status_t writerErr = stopWriterThread(); // TODO: which error to propagage, writerErr or trackErr? // Propagating writer error if (err == OK && writerErr != OK) { err = writerErr; } // Do not write out movie header on error except malformed track. // TODO: Remove samples of malformed tracks added in mdat. if (err != OK && err != ERROR_MALFORMED) { // Ignoring release() return value as there was an "err" already. release(); return err; } Loading Loading @@ -1174,6 +1241,7 @@ status_t MPEG4Writer::reset(bool stopSource) { } else { ALOGI("The mp4 file will not be streamable."); } ALOGI("MOOV atom was written to the file"); } mWriteBoxToMemory = false; Loading @@ -1186,7 +1254,7 @@ status_t MPEG4Writer::reset(bool stopSource) { CHECK(mBoxes.empty()); release(); err = release(); return err; } Loading Loading @@ -1354,7 +1422,7 @@ void MPEG4Writer::sendSessionSummary() { for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); it != mChunkInfos.end(); ++it) { int trackNum = it->mTrack->getTrackId() << 28; uint32_t trackNum = (it->mTrack->getTrackId().getId() << 28); notify(MEDIA_RECORDER_TRACK_EVENT_INFO, trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, it->mMaxInterChunkDurUs); Loading Loading @@ -1512,7 +1580,8 @@ void MPEG4Writer::writeOrPostError(int fd, const void* buf, size_t count) { std::strerror(errno), errno); // Can't guarantee that file is usable or write would succeed anymore, hence signal to stop. sp<AMessage> msg = new AMessage(kWhatHandleIOError, mReflector); sp<AMessage> msg = new AMessage(kWhatIOError, mReflector); msg->setInt32("errno", errno); status_t err = msg->post(); ALOGE("writeOrPostError post:%d", err); } Loading @@ -1531,7 +1600,8 @@ void MPEG4Writer::seekOrPostError(int fd, off64_t offset, int whence) { offset, std::strerror(errno), errno); // Can't guarantee that file is usable or seek would succeed anymore, hence signal to stop. sp<AMessage> msg = new AMessage(kWhatHandleIOError, mReflector); sp<AMessage> msg = new AMessage(kWhatIOError, mReflector); msg->setInt32("errno", errno); status_t err = msg->post(); ALOGE("seekOrPostError post:%d", err); } Loading Loading @@ -1768,10 +1838,11 @@ bool MPEG4Writer::preAllocate(uint64_t wantSize) { ALOGV("preAllocateSize :%" PRIu64 " lastFileEndOffset:%" PRIu64, preAllocateSize, lastFileEndOffset); int res = fallocate(mFd, 0, lastFileEndOffset, preAllocateSize); int res = fallocate(mFd, FALLOC_FL_KEEP_SIZE, lastFileEndOffset, preAllocateSize); if (res == -1) { ALOGE("fallocate err:%s, %d, fd:%d", strerror(errno), errno, mFd); sp<AMessage> msg = new AMessage(kWhatHandleFallocateError, mReflector); sp<AMessage> msg = new AMessage(kWhatFallocateError, mReflector); msg->setInt32("errno", errno); status_t err = msg->post(); mFallocateErr = true; ALOGD("preAllocation post:%d", err); Loading Loading @@ -1899,7 +1970,7 @@ size_t MPEG4Writer::numTracks() { //////////////////////////////////////////////////////////////////////////////// MPEG4Writer::Track::Track( MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) MPEG4Writer *owner, const sp<MediaSource> &source, uint32_t aTrackId) : mOwner(owner), mMeta(source->getFormat()), mSource(source), Loading @@ -1909,7 +1980,7 @@ MPEG4Writer::Track::Track( mStarted(false), mGotStartKeyFrame(false), mIsMalformed(false), mTrackId(trackId), mTrackId(aTrackId), mTrackDurationUs(0), mEstimatedTrackSizeBytes(0), mSamplesHaveSameSize(true), Loading Loading @@ -2089,7 +2160,7 @@ void MPEG4Writer::Track::addOneElstTableEntry( void MPEG4Writer::setupAndStartLooper() { if (mLooper == nullptr) { mLooper = new ALooper; mLooper->setName("MP4WriterLooper"); mLooper->setName("MP4WtrCtrlHlpLooper"); mLooper->start(); mReflector = new AHandlerReflector<MPEG4Writer>(this); mLooper->registerHandler(mReflector); Loading @@ -2099,12 +2170,12 @@ void MPEG4Writer::setupAndStartLooper() { void MPEG4Writer::stopAndReleaseLooper() { if (mLooper != nullptr) { if (mReflector != nullptr) { ALOGD("unregisterHandler"); mLooper->unregisterHandler(mReflector->id()); mReflector.clear(); } mLooper->stop(); mLooper.clear(); ALOGD("MP4WtrCtrlHlpLooper stopped"); } } Loading Loading @@ -2329,18 +2400,22 @@ void MPEG4Writer::onMessageReceived(const sp<AMessage> &msg) { break; } // ::write() or lseek64() wasn't a success, file could be malformed case kWhatHandleIOError: { ALOGE("kWhatHandleIOError"); case kWhatIOError: { ALOGE("kWhatIOError"); int32_t err; CHECK(msg->findInt32("errno", &err)); // Stop tracks' threads and main writer thread. notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, ERROR_MALFORMED); notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, err); stop(); break; } // fallocate() failed, hence notify app about it and stop(). case kWhatHandleFallocateError: { ALOGE("kWhatHandleFallocateError"); //TODO: introduce new MEDIA_RECORDER_INFO_STOPPED instead MEDIA_RECORDER_INFO_UNKNOWN? notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_UNKNOWN, ERROR_IO); case kWhatFallocateError: { ALOGE("kWhatFallocateError"); int32_t err; CHECK(msg->findInt32("errno", &err)); //TODO: introduce a suitable MEDIA_RECORDER_ERROR_* instead MEDIA_RECORDER_ERROR_UNKNOWN? notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, err); stop(); break; } Loading Loading @@ -2708,9 +2783,9 @@ status_t MPEG4Writer::Track::stop(bool stopSource) { void *dummy; status_t err = pthread_join(mThread, &dummy); WARN_UNLESS(err == 0, "track::stop: pthread_join status:%d", err); err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); WARN_UNLESS(err == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err, stopSource ? "Stop" : "Not Stop"); status_t threadRetVal = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); WARN_UNLESS(threadRetVal == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err, stopSource ? "Stop" : "Not Stop"); mStarted = false; return err; } Loading Loading @@ -2849,6 +2924,7 @@ status_t MPEG4Writer::Track::parseAVCCodecSpecificData( } if (nextStartCode == NULL) { ALOGE("nextStartCode is null"); return ERROR_MALFORMED; } Loading Loading @@ -3126,11 +3202,11 @@ status_t MPEG4Writer::Track::threadEntry() { int64_t lastSampleDurationTicks = -1; // Timescale based ticks if (mIsAudio) { prctl(PR_SET_NAME, (unsigned long)"AudioTrackWriterThread", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"MP4WtrAudTrkThread", 0, 0, 0); } else if (mIsVideo) { prctl(PR_SET_NAME, (unsigned long)"VideoTrackWriterThread", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"MP4WtrVidTrkThread", 0, 0, 0); } else { prctl(PR_SET_NAME, (unsigned long)"MetadataTrackWriterThread", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"MP4WtrMetaTrkThread", 0, 0, 0); } if (mOwner->isRealTimeRecording()) { Loading Loading @@ -3181,6 +3257,7 @@ status_t MPEG4Writer::Track::threadEntry() { } ++count; int32_t isCodecConfig; if (buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig) { Loading @@ -3204,7 +3281,7 @@ status_t MPEG4Writer::Track::threadEntry() { + buffer->range_offset(), buffer->range_length()); } else if (mIsMPEG4) { copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), err = copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), buffer->range_length()); } } Loading @@ -3213,8 +3290,10 @@ status_t MPEG4Writer::Track::threadEntry() { buffer = NULL; if (OK != err) { mSource->stop(); mIsMalformed = true; uint32_t trackNum = (mTrackId.getId() << 28); mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, mTrackId | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); break; } Loading Loading @@ -3251,7 +3330,7 @@ status_t MPEG4Writer::Track::threadEntry() { * Reserve space in the file for the current sample + to be written MOOV box. If reservation * for a new sample fails, preAllocate(...) stops muxing session completely. Stop() could * write MOOV box successfully as space for the same was reserved in the prior call. * Release the current buffer/sample only here. * Release the current buffer/sample here. */ if (!mOwner->preAllocate(buffer->range_length())) { buffer->release(); Loading Loading @@ -3291,6 +3370,7 @@ status_t MPEG4Writer::Track::threadEntry() { updateTrackSizeEstimate(); if (mOwner->exceedsFileSizeLimit()) { copy->release(); if (mOwner->switchFd() != OK) { ALOGW("Recorded file size exceeds limit %" PRId64 "bytes", mOwner->mMaxFileSizeLimitBytes); Loading @@ -3301,16 +3381,15 @@ status_t MPEG4Writer::Track::threadEntry() { ALOGV("%s Current recorded file size exceeds limit %" PRId64 "bytes. Switching output", getTrackType(), mOwner->mMaxFileSizeLimitBytes); } copy->release(); break; } if (mOwner->exceedsFileDurationLimit()) { ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds", mOwner->mMaxFileDurationLimitUs); mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); copy->release(); mSource->stop(); mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); break; } Loading Loading @@ -3592,13 +3671,13 @@ status_t MPEG4Writer::Track::threadEntry() { } } } if (isTrackMalFormed()) { mIsMalformed = true; dumpTimeStamps(); err = ERROR_MALFORMED; } mOwner->trackProgressStatus(mTrackId, -1, err); mOwner->trackProgressStatus(mTrackId.getId(), -1, err); // Add final entries only for non-empty tracks. if (mStszTableEntries->count() > 0) { Loading Loading @@ -3665,7 +3744,7 @@ status_t MPEG4Writer::Track::threadEntry() { return err; } bool MPEG4Writer::Track::isTrackMalFormed() const { bool MPEG4Writer::Track::isTrackMalFormed() { if (mIsMalformed) { return true; } Loading @@ -3674,23 +3753,29 @@ bool MPEG4Writer::Track::isTrackMalFormed() const { if (mOwner->mStartMeta && mOwner->mStartMeta->findInt32(kKeyEmptyTrackMalFormed, &emptyTrackMalformed) && emptyTrackMalformed) { // MediaRecorder(sets kKeyEmptyTrackMalFormed by default) report empty tracks as malformed. if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written ALOGE("The number of recorded samples is 0"); mIsMalformed = true; return true; } if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video ALOGE("There are no sync frames for video track"); mIsMalformed = true; return true; } } else { // No sync frames for video. // Through MediaMuxer, empty tracks can be added. No sync frames for video. if (mIsVideo && mStszTableEntries->count() > 0 && mStssTableEntries->count() == 0) { ALOGE("There are no sync frames for video track"); mIsMalformed = true; return true; } } if (OK != checkCodecSpecificData()) { // no codec specific data // Don't check for CodecSpecificData when track is empty. if (mStszTableEntries->count() > 0 && OK != checkCodecSpecificData()) { // No codec specific data. mIsMalformed = true; return true; } Loading @@ -3704,7 +3789,7 @@ void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { return; } int trackNum = (mTrackId << 28); uint32_t trackNum = (mTrackId.getId() << 28); mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, Loading Loading @@ -3758,15 +3843,15 @@ void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { if (mTrackEveryTimeDurationUs > 0 && timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); mOwner->trackProgressStatus(mTrackId.getId(), timeUs - mPreviousTrackTimeUs, err); mPreviousTrackTimeUs = timeUs; } } void MPEG4Writer::trackProgressStatus( size_t trackId, int64_t timeUs, status_t err) { uint32_t trackId, int64_t timeUs, status_t err) { Mutex::Autolock lock(mLock); int32_t trackNum = (trackId << 28); uint32_t trackNum = (trackId << 28); // Error notification // Do not consider ERROR_END_OF_STREAM an error Loading Loading @@ -3936,8 +4021,8 @@ int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() { void MPEG4Writer::Track::writeStblBox() { mOwner->beginBox("stbl"); // Add subboxes only for non-empty tracks. if (mStszTableEntries->count() > 0) { // Add subboxes for only non-empty and well-formed tracks. if (mStszTableEntries->count() > 0 && !isTrackMalFormed()) { mOwner->beginBox("stsd"); mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(1); // entry count Loading Loading @@ -4242,7 +4327,7 @@ void MPEG4Writer::Track::writeTkhdBox(uint32_t now) { mOwner->writeInt32(0x07); // version=0, flags=7 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time mOwner->writeInt32(mTrackId); // track id starts with 1 mOwner->writeInt32(mTrackId.getId()); // track id starts with 1 mOwner->writeInt32(0); // reserved int64_t trakDurationUs = getDurationUs(); int32_t mvhdTimeScale = mOwner->getTimeScale(); Loading Loading
media/libaudioclient/AudioRecord.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -773,7 +773,7 @@ status_t AudioRecord::createRecord_l(const Modulo<uint32_t> &epoch, const String // use case 3: obtain/release mode (mTransfer == TRANSFER_OBTAIN); if (!useCaseAllowed) { ALOGW("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", ALOGD("%s(%d): AUDIO_INPUT_FLAG_FAST denied, incompatible transfer = %s", __func__, mPortId, convertTransferToText(mTransfer)); mFlags = (audio_input_flags_t) (mFlags & ~(AUDIO_INPUT_FLAG_FAST | Loading
media/libaudioclient/AudioTrack.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -1632,7 +1632,7 @@ status_t AudioTrack::createTrack_l() mAwaitBoost = true; } } else { ALOGW("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", ALOGD("%s(%d): AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu -> %zu", __func__, mPortId, mReqFrameCount, mFrameCount); } } Loading
media/libmediaplayerservice/StagefrightRecorder.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -2011,6 +2011,7 @@ void StagefrightRecorder::setupMPEG4orWEBMMetaData(sp<MetaData> *meta) { } if (mOutputFormat == OUTPUT_FORMAT_MPEG_4 || mOutputFormat == OUTPUT_FORMAT_THREE_GPP) { (*meta)->setInt32(kKeyEmptyTrackMalFormed, true); (*meta)->setInt32(kKey4BitTrackIds, true); } } Loading
media/libstagefright/HevcUtils.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) { } if (err != OK) { ALOGE("error parsing VPS or SPS or PPS"); return err; } Loading
media/libstagefright/MPEG4Writer.cpp +146 −61 Original line number Diff line number Diff line Loading @@ -103,8 +103,40 @@ static const uint8_t kHevcNalUnitTypes[5] = { //#define SHOW_MODEL_BUILD 1 class MPEG4Writer::Track { struct TrackId { TrackId(uint32_t aId) :mId(aId), mTrackIdValid(false) { } bool isValid(bool akKey4BitTrackIds) { // trackId cannot be zero, ISO/IEC 14496-12 8.3.2.3 if (mId == 0) { return false; } /* MediaRecorder uses only 4 bit to represent track ids during notifying clients. * MediaMuxer's track ids are restricted by container allowed size only. * MPEG4 Container defines unsigned int (32), ISO/IEC 14496-12 8.3.2.2 */ if (akKey4BitTrackIds && mId > 15) { return false; } mTrackIdValid = true; return true; } uint32_t getId() const { CHECK(mTrackIdValid); return mId; } TrackId() = delete; DISALLOW_EVIL_CONSTRUCTORS(TrackId); private: // unsigned int (32), ISO/IEC 14496-12 8.3.2.2 uint32_t mId; bool mTrackIdValid; }; public: Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId); Track(MPEG4Writer *owner, const sp<MediaSource> &source, uint32_t aTrackId); ~Track(); Loading @@ -129,7 +161,7 @@ public: void addChunkOffset(off64_t offset); void addItemOffsetAndSize(off64_t offset, size_t size, bool isExif); void flushItemRefs(); int32_t getTrackId() const { return mTrackId; } TrackId& getTrackId() { return mTrackId; } status_t dump(int fd, const Vector<String16>& args) const; static const char *getFourCCForMime(const char *mime); const char *getTrackType() const; Loading Loading @@ -290,7 +322,7 @@ private: bool mIsMPEG4; bool mGotStartKeyFrame; bool mIsMalformed; int32_t mTrackId; TrackId mTrackId; int64_t mTrackDurationUs; int64_t mMaxChunkDurationUs; int64_t mLastDecodingTimeUs; Loading Loading @@ -413,7 +445,7 @@ private: void addOneElstTableEntry(uint32_t segmentDuration, int32_t mediaTime, int16_t mediaRate, int16_t mediaRateFraction); bool isTrackMalFormed() const; bool isTrackMalFormed(); void sendTrackSummary(bool hasMultipleTracks); // Write the boxes Loading Loading @@ -534,7 +566,7 @@ void MPEG4Writer::initInternal(int fd, bool isFirstSession) { release(); } if (fallocate(mFd, 0, 0, 1) == 0) { if (fallocate(mFd, FALLOC_FL_KEEP_SIZE, 0, 1) == 0) { ALOGD("PreAllocation enabled"); mPreAllocationEnabled = true; } else { Loading Loading @@ -744,8 +776,7 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { // where 1MB is the common file size limit for MMS application. // The default MAX _MOOV_BOX_SIZE value is based on about 3 // minute video recording with a bit rate about 3 Mbps, because // statistics also show that most of the video captured are going // to be less than 3 minutes. // statistics show that most captured videos are less than 3 minutes. // If the estimation is wrong, we will pay the price of wasting // some reserved space. This should not happen so often statistically. Loading Loading @@ -796,6 +827,15 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) { return size; } status_t MPEG4Writer::validateAllTracksId(bool akKey4BitTrackIds) { for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { if (!(*it)->getTrackId().isValid(akKey4BitTrackIds)) { return BAD_VALUE; } } return OK; } status_t MPEG4Writer::start(MetaData *param) { if (mInitCheck != OK) { return UNKNOWN_ERROR; Loading @@ -810,6 +850,9 @@ status_t MPEG4Writer::start(MetaData *param) { mIsFileSizeLimitExplicitlyRequested = true; } /* mMaxFileSizeLimitBytes has to be set everytime fd is switched, hence the following code is * appropriate in start() method. */ int32_t fileSizeBits = fpathconf(mFd, _PC_FILESIZEBITS); ALOGD("fpathconf _PC_FILESIZEBITS:%" PRId32, fileSizeBits); fileSizeBits = std::min(fileSizeBits, 52 /* cap it below 4 peta bytes */); Loading Loading @@ -944,6 +987,17 @@ status_t MPEG4Writer::start(MetaData *param) { setupAndStartLooper(); int32_t is4bitTrackId = false; if (param && param->findInt32(kKey4BitTrackIds, &is4bitTrackId) && is4bitTrackId) { err = validateAllTracksId(true); } else { err = validateAllTracksId(false); } if (err != OK) { return err; } err = startTracks(param); if (err != OK) { return err; Loading @@ -961,6 +1015,7 @@ status_t MPEG4Writer::pause() { status_t MPEG4Writer::stopWriterThread() { ALOGV("Stopping writer thread"); if (!mWriterThreadStarted) { ALOGD("Writer thread not started"); return OK; } { Loading @@ -975,7 +1030,8 @@ status_t MPEG4Writer::stopWriterThread() { err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); mWriterThreadStarted = false; WARN_UNLESS(err == 0, "stopWriterThread pthread_join retVal: %d, writer thread stopped", err); WARN_UNLESS(err == 0, "stopWriterThread pthread_join retVal: %d", err); ALOGD("Writer thread stopped"); return err; } Loading Loading @@ -1031,26 +1087,32 @@ void MPEG4Writer::writeCompositionMatrix(int degrees) { writeInt32(0x40000000); // w } void MPEG4Writer::release() { status_t MPEG4Writer::release() { ALOGD("release()"); if (mPreAllocationEnabled) { truncatePreAllocation(); } int err = OK; int retVal = fsync(mFd); WARN_UNLESS(retVal == 0, "fsync retVal:%d", retVal); WARN_UNLESS(retVal == 0, "fsync err:%s(%d)", std::strerror(errno), errno); err |= retVal; retVal = close(mFd); WARN_UNLESS(retVal == 0, "close mFd retVal :%d", retVal); WARN_UNLESS(retVal == 0, "close err:%s(%d)", std::strerror(errno), errno); err |= retVal; mFd = -1; if (mNextFd != -1) { retVal = close(mNextFd); mNextFd = -1; WARN_UNLESS(retVal == 0, "close mNextFd retVal :%d", retVal); WARN_UNLESS(retVal == 0, "close mNextFd error:%s(%d)", std::strerror(errno), errno); err |= retVal; } stopAndReleaseLooper(); mInitCheck = NO_INIT; mStarted = false; free(mInMemoryCache); mInMemoryCache = NULL; return err; } void MPEG4Writer::finishCurrentSession() { Loading @@ -1065,7 +1127,7 @@ status_t MPEG4Writer::switchFd() { } if (mNextFd == -1) { ALOGW("No FileDescripter for next recording"); ALOGW("No FileDescriptor for next recording"); return INVALID_OPERATION; } Loading @@ -1084,12 +1146,15 @@ status_t MPEG4Writer::reset(bool stopSource) { } else { if (!mWriterThreadStarted || !mStarted) { status_t err = OK; status_t writerErr = OK; if (mWriterThreadStarted) { err = stopWriterThread(); writerErr = stopWriterThread(); } release(); return err; status_t retErr = release(); if (writerErr != OK) { retErr = writerErr; } return retErr; } } Loading @@ -1100,8 +1165,9 @@ status_t MPEG4Writer::reset(bool stopSource) { for (List<Track *>::iterator it = mTracks.begin(); it != mTracks.end(); ++it) { status_t trackErr = (*it)->stop(stopSource); WARN_UNLESS(trackErr == 0, "%s track stopped with an error", (*it)->getTrackType()); if (err == OK && trackErr != OK) { ALOGW("%s track stopped with an error", (*it)->getTrackType()); err = trackErr; } Loading @@ -1118,7 +1184,6 @@ status_t MPEG4Writer::reset(bool stopSource) { } } if (nonImageTrackCount > 1) { ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", minDurationUs, maxDurationUs); Loading @@ -1126,13 +1191,15 @@ status_t MPEG4Writer::reset(bool stopSource) { status_t writerErr = stopWriterThread(); // TODO: which error to propagage, writerErr or trackErr? // Propagating writer error if (err == OK && writerErr != OK) { err = writerErr; } // Do not write out movie header on error except malformed track. // TODO: Remove samples of malformed tracks added in mdat. if (err != OK && err != ERROR_MALFORMED) { // Ignoring release() return value as there was an "err" already. release(); return err; } Loading Loading @@ -1174,6 +1241,7 @@ status_t MPEG4Writer::reset(bool stopSource) { } else { ALOGI("The mp4 file will not be streamable."); } ALOGI("MOOV atom was written to the file"); } mWriteBoxToMemory = false; Loading @@ -1186,7 +1254,7 @@ status_t MPEG4Writer::reset(bool stopSource) { CHECK(mBoxes.empty()); release(); err = release(); return err; } Loading Loading @@ -1354,7 +1422,7 @@ void MPEG4Writer::sendSessionSummary() { for (List<ChunkInfo>::iterator it = mChunkInfos.begin(); it != mChunkInfos.end(); ++it) { int trackNum = it->mTrack->getTrackId() << 28; uint32_t trackNum = (it->mTrack->getTrackId().getId() << 28); notify(MEDIA_RECORDER_TRACK_EVENT_INFO, trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS, it->mMaxInterChunkDurUs); Loading Loading @@ -1512,7 +1580,8 @@ void MPEG4Writer::writeOrPostError(int fd, const void* buf, size_t count) { std::strerror(errno), errno); // Can't guarantee that file is usable or write would succeed anymore, hence signal to stop. sp<AMessage> msg = new AMessage(kWhatHandleIOError, mReflector); sp<AMessage> msg = new AMessage(kWhatIOError, mReflector); msg->setInt32("errno", errno); status_t err = msg->post(); ALOGE("writeOrPostError post:%d", err); } Loading @@ -1531,7 +1600,8 @@ void MPEG4Writer::seekOrPostError(int fd, off64_t offset, int whence) { offset, std::strerror(errno), errno); // Can't guarantee that file is usable or seek would succeed anymore, hence signal to stop. sp<AMessage> msg = new AMessage(kWhatHandleIOError, mReflector); sp<AMessage> msg = new AMessage(kWhatIOError, mReflector); msg->setInt32("errno", errno); status_t err = msg->post(); ALOGE("seekOrPostError post:%d", err); } Loading Loading @@ -1768,10 +1838,11 @@ bool MPEG4Writer::preAllocate(uint64_t wantSize) { ALOGV("preAllocateSize :%" PRIu64 " lastFileEndOffset:%" PRIu64, preAllocateSize, lastFileEndOffset); int res = fallocate(mFd, 0, lastFileEndOffset, preAllocateSize); int res = fallocate(mFd, FALLOC_FL_KEEP_SIZE, lastFileEndOffset, preAllocateSize); if (res == -1) { ALOGE("fallocate err:%s, %d, fd:%d", strerror(errno), errno, mFd); sp<AMessage> msg = new AMessage(kWhatHandleFallocateError, mReflector); sp<AMessage> msg = new AMessage(kWhatFallocateError, mReflector); msg->setInt32("errno", errno); status_t err = msg->post(); mFallocateErr = true; ALOGD("preAllocation post:%d", err); Loading Loading @@ -1899,7 +1970,7 @@ size_t MPEG4Writer::numTracks() { //////////////////////////////////////////////////////////////////////////////// MPEG4Writer::Track::Track( MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId) MPEG4Writer *owner, const sp<MediaSource> &source, uint32_t aTrackId) : mOwner(owner), mMeta(source->getFormat()), mSource(source), Loading @@ -1909,7 +1980,7 @@ MPEG4Writer::Track::Track( mStarted(false), mGotStartKeyFrame(false), mIsMalformed(false), mTrackId(trackId), mTrackId(aTrackId), mTrackDurationUs(0), mEstimatedTrackSizeBytes(0), mSamplesHaveSameSize(true), Loading Loading @@ -2089,7 +2160,7 @@ void MPEG4Writer::Track::addOneElstTableEntry( void MPEG4Writer::setupAndStartLooper() { if (mLooper == nullptr) { mLooper = new ALooper; mLooper->setName("MP4WriterLooper"); mLooper->setName("MP4WtrCtrlHlpLooper"); mLooper->start(); mReflector = new AHandlerReflector<MPEG4Writer>(this); mLooper->registerHandler(mReflector); Loading @@ -2099,12 +2170,12 @@ void MPEG4Writer::setupAndStartLooper() { void MPEG4Writer::stopAndReleaseLooper() { if (mLooper != nullptr) { if (mReflector != nullptr) { ALOGD("unregisterHandler"); mLooper->unregisterHandler(mReflector->id()); mReflector.clear(); } mLooper->stop(); mLooper.clear(); ALOGD("MP4WtrCtrlHlpLooper stopped"); } } Loading Loading @@ -2329,18 +2400,22 @@ void MPEG4Writer::onMessageReceived(const sp<AMessage> &msg) { break; } // ::write() or lseek64() wasn't a success, file could be malformed case kWhatHandleIOError: { ALOGE("kWhatHandleIOError"); case kWhatIOError: { ALOGE("kWhatIOError"); int32_t err; CHECK(msg->findInt32("errno", &err)); // Stop tracks' threads and main writer thread. notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, ERROR_MALFORMED); notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, err); stop(); break; } // fallocate() failed, hence notify app about it and stop(). case kWhatHandleFallocateError: { ALOGE("kWhatHandleFallocateError"); //TODO: introduce new MEDIA_RECORDER_INFO_STOPPED instead MEDIA_RECORDER_INFO_UNKNOWN? notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_UNKNOWN, ERROR_IO); case kWhatFallocateError: { ALOGE("kWhatFallocateError"); int32_t err; CHECK(msg->findInt32("errno", &err)); //TODO: introduce a suitable MEDIA_RECORDER_ERROR_* instead MEDIA_RECORDER_ERROR_UNKNOWN? notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_RECORDER_ERROR_UNKNOWN, err); stop(); break; } Loading Loading @@ -2708,9 +2783,9 @@ status_t MPEG4Writer::Track::stop(bool stopSource) { void *dummy; status_t err = pthread_join(mThread, &dummy); WARN_UNLESS(err == 0, "track::stop: pthread_join status:%d", err); err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); WARN_UNLESS(err == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err, stopSource ? "Stop" : "Not Stop"); status_t threadRetVal = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy)); WARN_UNLESS(threadRetVal == 0, "%s track stopped. Status :%d. %s source", getTrackType(), err, stopSource ? "Stop" : "Not Stop"); mStarted = false; return err; } Loading Loading @@ -2849,6 +2924,7 @@ status_t MPEG4Writer::Track::parseAVCCodecSpecificData( } if (nextStartCode == NULL) { ALOGE("nextStartCode is null"); return ERROR_MALFORMED; } Loading Loading @@ -3126,11 +3202,11 @@ status_t MPEG4Writer::Track::threadEntry() { int64_t lastSampleDurationTicks = -1; // Timescale based ticks if (mIsAudio) { prctl(PR_SET_NAME, (unsigned long)"AudioTrackWriterThread", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"MP4WtrAudTrkThread", 0, 0, 0); } else if (mIsVideo) { prctl(PR_SET_NAME, (unsigned long)"VideoTrackWriterThread", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"MP4WtrVidTrkThread", 0, 0, 0); } else { prctl(PR_SET_NAME, (unsigned long)"MetadataTrackWriterThread", 0, 0, 0); prctl(PR_SET_NAME, (unsigned long)"MP4WtrMetaTrkThread", 0, 0, 0); } if (mOwner->isRealTimeRecording()) { Loading Loading @@ -3181,6 +3257,7 @@ status_t MPEG4Writer::Track::threadEntry() { } ++count; int32_t isCodecConfig; if (buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecConfig) && isCodecConfig) { Loading @@ -3204,7 +3281,7 @@ status_t MPEG4Writer::Track::threadEntry() { + buffer->range_offset(), buffer->range_length()); } else if (mIsMPEG4) { copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), err = copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), buffer->range_length()); } } Loading @@ -3213,8 +3290,10 @@ status_t MPEG4Writer::Track::threadEntry() { buffer = NULL; if (OK != err) { mSource->stop(); mIsMalformed = true; uint32_t trackNum = (mTrackId.getId() << 28); mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_ERROR, mTrackId | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err); break; } Loading Loading @@ -3251,7 +3330,7 @@ status_t MPEG4Writer::Track::threadEntry() { * Reserve space in the file for the current sample + to be written MOOV box. If reservation * for a new sample fails, preAllocate(...) stops muxing session completely. Stop() could * write MOOV box successfully as space for the same was reserved in the prior call. * Release the current buffer/sample only here. * Release the current buffer/sample here. */ if (!mOwner->preAllocate(buffer->range_length())) { buffer->release(); Loading Loading @@ -3291,6 +3370,7 @@ status_t MPEG4Writer::Track::threadEntry() { updateTrackSizeEstimate(); if (mOwner->exceedsFileSizeLimit()) { copy->release(); if (mOwner->switchFd() != OK) { ALOGW("Recorded file size exceeds limit %" PRId64 "bytes", mOwner->mMaxFileSizeLimitBytes); Loading @@ -3301,16 +3381,15 @@ status_t MPEG4Writer::Track::threadEntry() { ALOGV("%s Current recorded file size exceeds limit %" PRId64 "bytes. Switching output", getTrackType(), mOwner->mMaxFileSizeLimitBytes); } copy->release(); break; } if (mOwner->exceedsFileDurationLimit()) { ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds", mOwner->mMaxFileDurationLimitUs); mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); copy->release(); mSource->stop(); mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0); break; } Loading Loading @@ -3592,13 +3671,13 @@ status_t MPEG4Writer::Track::threadEntry() { } } } if (isTrackMalFormed()) { mIsMalformed = true; dumpTimeStamps(); err = ERROR_MALFORMED; } mOwner->trackProgressStatus(mTrackId, -1, err); mOwner->trackProgressStatus(mTrackId.getId(), -1, err); // Add final entries only for non-empty tracks. if (mStszTableEntries->count() > 0) { Loading Loading @@ -3665,7 +3744,7 @@ status_t MPEG4Writer::Track::threadEntry() { return err; } bool MPEG4Writer::Track::isTrackMalFormed() const { bool MPEG4Writer::Track::isTrackMalFormed() { if (mIsMalformed) { return true; } Loading @@ -3674,23 +3753,29 @@ bool MPEG4Writer::Track::isTrackMalFormed() const { if (mOwner->mStartMeta && mOwner->mStartMeta->findInt32(kKeyEmptyTrackMalFormed, &emptyTrackMalformed) && emptyTrackMalformed) { // MediaRecorder(sets kKeyEmptyTrackMalFormed by default) report empty tracks as malformed. if (!mIsHeic && mStszTableEntries->count() == 0) { // no samples written ALOGE("The number of recorded samples is 0"); mIsMalformed = true; return true; } if (mIsVideo && mStssTableEntries->count() == 0) { // no sync frames for video ALOGE("There are no sync frames for video track"); mIsMalformed = true; return true; } } else { // No sync frames for video. // Through MediaMuxer, empty tracks can be added. No sync frames for video. if (mIsVideo && mStszTableEntries->count() > 0 && mStssTableEntries->count() == 0) { ALOGE("There are no sync frames for video track"); mIsMalformed = true; return true; } } if (OK != checkCodecSpecificData()) { // no codec specific data // Don't check for CodecSpecificData when track is empty. if (mStszTableEntries->count() > 0 && OK != checkCodecSpecificData()) { // No codec specific data. mIsMalformed = true; return true; } Loading @@ -3704,7 +3789,7 @@ void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) { return; } int trackNum = (mTrackId << 28); uint32_t trackNum = (mTrackId.getId() << 28); mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO, trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE, Loading Loading @@ -3758,15 +3843,15 @@ void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) { if (mTrackEveryTimeDurationUs > 0 && timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) { ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs); mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err); mOwner->trackProgressStatus(mTrackId.getId(), timeUs - mPreviousTrackTimeUs, err); mPreviousTrackTimeUs = timeUs; } } void MPEG4Writer::trackProgressStatus( size_t trackId, int64_t timeUs, status_t err) { uint32_t trackId, int64_t timeUs, status_t err) { Mutex::Autolock lock(mLock); int32_t trackNum = (trackId << 28); uint32_t trackNum = (trackId << 28); // Error notification // Do not consider ERROR_END_OF_STREAM an error Loading Loading @@ -3936,8 +4021,8 @@ int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() { void MPEG4Writer::Track::writeStblBox() { mOwner->beginBox("stbl"); // Add subboxes only for non-empty tracks. if (mStszTableEntries->count() > 0) { // Add subboxes for only non-empty and well-formed tracks. if (mStszTableEntries->count() > 0 && !isTrackMalFormed()) { mOwner->beginBox("stsd"); mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(1); // entry count Loading Loading @@ -4242,7 +4327,7 @@ void MPEG4Writer::Track::writeTkhdBox(uint32_t now) { mOwner->writeInt32(0x07); // version=0, flags=7 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time mOwner->writeInt32(mTrackId); // track id starts with 1 mOwner->writeInt32(mTrackId.getId()); // track id starts with 1 mOwner->writeInt32(0); // reserved int64_t trakDurationUs = getDurationUs(); int32_t mvhdTimeScale = mOwner->getTimeScale(); Loading