From de1e368d8ac5891e03e664a0ea385b896b48db0b Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Tue, 5 Jan 2016 15:21:14 -0800 Subject: stagefright: Forward-port HFR and HSR support * CAF commit bd42a7ac3a60c0d8a079b4567484c9b006bac8ad upstream Change-Id: I457ccab603647f3139ea2199a544f64ac3d1a214 --- media/libavextensions/stagefright/AVExtensions.h | 58 +++++++++- media/libavextensions/stagefright/AVUtils.cpp | 125 +++++++++++++++++++++ .../libmediaplayerservice/StagefrightRecorder.cpp | 13 ++- media/libmediaplayerservice/StagefrightRecorder.h | 4 +- media/libstagefright/MPEG4Writer.cpp | 15 ++- media/libstagefright/MediaCodecSource.cpp | 5 + 6 files changed, 210 insertions(+), 10 deletions(-) (limited to 'media') diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index f14d217..968eb6d 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -153,7 +153,7 @@ struct AVUtils { uint64_t /*eAacProfile*/); virtual void extractCustomCameraKeys( - const CameraParameters& /*params*/, sp &/*meta*/) {} + const CameraParameters& /*params*/, sp &/*meta*/); virtual void printFileName(int /*fd*/) {} virtual void addDecodingTimesFromBatch(MediaBuffer * /*buf*/, List &/*decodeTimeQueue*/) {} @@ -226,12 +226,66 @@ struct AVUtils { int nPFrames, int nBFrames, const sp OMXhandle, IOMX::node_id nodeID); + /* + * This class is a placeholder for the set of methods used + * to enable HFR (High Frame Rate) Recording + * + * HFR is a slow-motion recording feature where framerate + * is increased at capture, but file is composed to play + * back at normal rate, giving a net result of slow-motion. + * If HFR factor = N + * framerate (at capture and encoder) = N * actual value + * bitrate = N * actual value + * (as the encoder still gets actual timestamps) + * timeStamps (at composition) = actual value + * timeScale (at composition) = actual value / N + * (when parser re-generates timestamps, they will be + * up-scaled by factor N, which results in slow-motion) + * + * HSR is a high-framerate recording variant where timestamps + * are not meddled with, yielding a video mux'ed at captured + * fps + */ + struct HFR { + // set kKeyHFR when 'video-hfr' paramater is enabled + // or set kKeyHSR when 'video-hsr' paramater is enabled + virtual void setHFRIfEnabled( + const CameraParameters& params, sp &meta); + + // recalculate file-duration when HFR is enabled + virtual status_t initializeHFR( + const sp &meta, sp &format, + int64_t &maxFileDurationUs, video_encoder videoEncoder); + + virtual void setHFRRatio( + sp &meta, const int32_t hfrRatio); + + virtual int32_t getHFRRatio( + const sp &meta); + + protected: + HFR() {}; + virtual ~HFR() {}; + friend struct AVUtils; + + private: + // Query supported capabilities from target-specific profiles + virtual int32_t getHFRCapabilities( + video_encoder codec, + int& maxHFRWidth, int& maxHFRHeight, int& maxHFRFps, + int& maxBitrate); + }; + virtual inline HFR& HFRUtils() { + return mHFR; + } + private: HEVCMuxer mHEVCMuxer; + HFR mHFR; // ----- NO TRESSPASSING BEYOND THIS LINE ------ DECLARE_LOADABLE_SINGLETON(AVUtils); -}; +}; } #endif // _AV_EXTENSIONS__H_ diff --git a/media/libavextensions/stagefright/AVUtils.cpp b/media/libavextensions/stagefright/AVUtils.cpp index 35ae36b..298434f 100644 --- a/media/libavextensions/stagefright/AVUtils.cpp +++ b/media/libavextensions/stagefright/AVUtils.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #if defined(QCOM_HARDWARE) || defined(FLAC_OFFLOAD_ENABLED) #include "QCMediaDefs.h" @@ -974,6 +975,130 @@ void AVUtils::setIntraPeriod( return; } +void AVUtils::HFR::setHFRIfEnabled( + const CameraParameters& params, + sp &meta) { + const char *hfrParam = params.get("video-hfr"); + int32_t hfr = -1; + if (hfrParam != NULL) { + hfr = atoi(hfrParam); + if (hfr > 0) { + ALOGI("Enabling HFR @ %d fps", hfr); + meta->setInt32(kKeyHFR, hfr); + return; + } else { + ALOGI("Invalid HFR rate specified : %d", hfr); + } + } + + const char *hsrParam = params.get("video-hsr"); + int32_t hsr = -1; + if (hsrParam != NULL ) { + hsr = atoi(hsrParam); + if (hsr > 0) { + ALOGI("Enabling HSR @ %d fps", hsr); + meta->setInt32(kKeyHSR, hsr); + } else { + ALOGI("Invalid HSR rate specified : %d", hfr); + } + } +} + +status_t AVUtils::HFR::initializeHFR( + const sp &meta, sp &format, + int64_t & /*maxFileDurationUs*/, video_encoder videoEncoder) { + status_t retVal = OK; + + int32_t hsr = 0; + if (meta->findInt32(kKeyHSR, &hsr) && hsr > 0) { + ALOGI("HSR cue found. Override encode fps to %d", hsr); + format->setInt32("frame-rate", hsr); + return retVal; + } + + int32_t hfr = 0; + if (!meta->findInt32(kKeyHFR, &hfr) || (hfr <= 0)) { + ALOGW("Invalid HFR rate specified"); + return retVal; + } + + int32_t width = 0, height = 0; + CHECK(meta->findInt32(kKeyWidth, &width)); + CHECK(meta->findInt32(kKeyHeight, &height)); + + int maxW, maxH, MaxFrameRate, maxBitRate = 0; + if (getHFRCapabilities(videoEncoder, + maxW, maxH, MaxFrameRate, maxBitRate) < 0) { + ALOGE("Failed to query HFR target capabilities"); + return ERROR_UNSUPPORTED; + } + + if ((width * height * hfr) > (maxW * maxH * MaxFrameRate)) { + ALOGE("HFR request [%d x %d @%d fps] exceeds " + "[%d x %d @%d fps]. Will stay disabled", + width, height, hfr, maxW, maxH, MaxFrameRate); + return ERROR_UNSUPPORTED; + } + + int32_t frameRate = 0, bitRate = 0; + CHECK(meta->findInt32(kKeyFrameRate, &frameRate)); + CHECK(format->findInt32("bitrate", &bitRate)); + + if (frameRate) { + // scale the bitrate proportional to the hfr ratio + // to maintain quality, but cap it to max-supported. + bitRate = (hfr * bitRate) / frameRate; + bitRate = bitRate > maxBitRate ? maxBitRate : bitRate; + format->setInt32("bitrate", bitRate); + + int32_t hfrRatio = hfr / frameRate; + format->setInt32("frame-rate", hfr); + format->setInt32("hfr-ratio", hfrRatio); + } else { + ALOGE("HFR: Invalid framerate"); + return BAD_VALUE; + } + + return retVal; +} + +void AVUtils::HFR::setHFRRatio( + sp &meta, const int32_t hfrRatio) { + if (hfrRatio > 0) { + meta->setInt32(kKeyHFR, hfrRatio); + } +} + +int32_t AVUtils::HFR::getHFRRatio( + const sp &meta) { + int32_t hfrRatio = 0; + meta->findInt32(kKeyHFR, &hfrRatio); + return hfrRatio ? hfrRatio : 1; +} + +int32_t AVUtils::HFR::getHFRCapabilities( + video_encoder codec, + int& maxHFRWidth, int& maxHFRHeight, int& maxHFRFps, + int& maxBitRate) { + maxHFRWidth = maxHFRHeight = maxHFRFps = maxBitRate = 0; + MediaProfiles *profiles = MediaProfiles::getInstance(); + + if (profiles) { + maxHFRWidth = profiles->getVideoEncoderParamByName("enc.vid.hfr.width.max", codec); + maxHFRHeight = profiles->getVideoEncoderParamByName("enc.vid.hfr.height.max", codec); + maxHFRFps = profiles->getVideoEncoderParamByName("enc.vid.hfr.mode.max", codec); + maxBitRate = profiles->getVideoEncoderParamByName("enc.vid.bps.max", codec); + } + + return (maxHFRWidth > 0) && (maxHFRHeight > 0) && + (maxHFRFps > 0) && (maxBitRate > 0) ? 1 : -1; +} + +void AVUtils::extractCustomCameraKeys( + const CameraParameters& params, sp &meta) { + mHFR.setHFRIfEnabled(params, meta); +} + // ----- NO TRESSPASSING BEYOND THIS LINE ------ AVUtils::AVUtils() {} diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 6baca4d..189bf8f 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -1622,12 +1622,12 @@ status_t StagefrightRecorder::setupVideoEncoder( } } - setupCustomVideoEncoderParams(cameraSource, format); - format->setInt32("bitrate", mVideoBitRate); format->setInt32("frame-rate", mFrameRate); format->setInt32("i-frame-interval", mIFramesIntervalSec); + setupCustomVideoEncoderParams(cameraSource, format); + if (mVideoTimeScale > 0) { format->setInt32("time-scale", mVideoTimeScale); } @@ -2094,4 +2094,13 @@ status_t StagefrightRecorder::setSourcePause(bool pause) { } return err; } + +void StagefrightRecorder::setupCustomVideoEncoderParams(sp cameraSource, + sp &format) { + + // Setup HFR if needed + AVUtils::get()->HFRUtils().initializeHFR(cameraSource->getFormat(), format, + mMaxFileDurationUs, mVideoEncoder); +} + } // namespace android diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 72dc77b..d93fc3b 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -154,8 +154,8 @@ protected: status_t setupCameraSource(sp *cameraSource); status_t setupAudioEncoder(const sp& writer); virtual status_t setupVideoEncoder(sp cameraSource, sp *source); - virtual void setupCustomVideoEncoderParams(sp /*cameraSource*/, - sp &/*format*/) {} + virtual void setupCustomVideoEncoderParams(sp cameraSource, + sp &format); virtual bool setCustomVideoEncoderMime(const video_encoder videoEncoder, sp format); // Encoding parameter handling utilities diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 7f7ddf7..2f1b6ac 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -321,6 +321,7 @@ private: // Simple validation on the codec specific data status_t checkCodecSpecificData() const; int32_t mRotation; + int32_t mHFRRatio; void updateTrackSizeEstimate(); void addOneStscTableEntry(size_t chunkId, size_t sampleId); @@ -390,7 +391,8 @@ MPEG4Writer::MPEG4Writer(int fd) mStartTimeOffsetMs(-1), mMetaKeys(new AMessage()), mIsVideoHEVC(false), - mIsAudioAMR(false) { + mIsAudioAMR(false), + mHFRRatio(1) { addDeviceMeta(); // Verify mFd is seekable @@ -532,6 +534,8 @@ status_t MPEG4Writer::addSource(const sp &source) { Track *track = new Track(this, source, 1 + mTracks.size()); mTracks.push_back(track); + mHFRRatio = AVUtils::get()->HFRUtils().getHFRRatio(source->getFormat()); + return OK; } @@ -1029,7 +1033,7 @@ void MPEG4Writer::writeMvhdBox(int64_t durationUs) { writeInt32(0); // version=0, flags=0 writeInt32(now); // creation time writeInt32(now); // modification time - writeInt32(mTimeScale); // mvhd timescale + writeInt32(mTimeScale / mHFRRatio); // mvhd timescale int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6; writeInt32(duration); writeInt32(0x10000); // rate: 1.0 @@ -1477,7 +1481,8 @@ MPEG4Writer::Track::Track( mCodecSpecificDataSize(0), mGotAllCodecSpecificData(false), mReachedEOS(false), - mRotation(0) { + mRotation(0), + mHFRRatio(1) { getCodecSpecificDataFromInputFormatIfPossible(); const char *mime; @@ -1882,6 +1887,8 @@ status_t MPEG4Writer::Track::start(MetaData *params) { pthread_create(&mThread, &attr, ThreadWrapper, this); pthread_attr_destroy(&attr); + mHFRRatio = AVUtils::get()->HFRUtils().getHFRRatio(mMeta); + return OK; } @@ -3069,7 +3076,7 @@ void MPEG4Writer::Track::writeMdhdBox(uint32_t now) { mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(now); // creation time mOwner->writeInt32(now); // modification time - mOwner->writeInt32(mTimeScale); // media timescale + mOwner->writeInt32(mTimeScale / mHFRRatio); // media timescale int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6; mOwner->writeInt32(mdhdDuration); // use media timescale // Language follows the three letter standard ISO-639-2/T diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index aef6715..adbde54 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -429,9 +429,14 @@ status_t MediaCodecSource::initEncoder() { return err; } + int32_t hfrRatio = 0; + mOutputFormat->findInt32("hfr-ratio", &hfrRatio); + mEncoder->getOutputFormat(&mOutputFormat); convertMessageToMetaData(mOutputFormat, mMeta); + AVUtils::get()->HFRUtils().setHFRRatio(mMeta, hfrRatio); + if (mFlags & FLAG_USE_SURFACE_INPUT) { CHECK(mIsVideo); -- cgit v1.1