diff --git a/dom/media/MediaRecorder.cpp b/dom/media/MediaRecorder.cpp index 62647192f11..ec6258d5346 100644 --- a/dom/media/MediaRecorder.cpp +++ b/dom/media/MediaRecorder.cpp @@ -595,9 +595,17 @@ private: // Make sure the application has permission to assign AUDIO_3GPP if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && Check3gppPermission()) { - mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), aTrackTypes); + mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), + mRecorder->GetAudioBitrate(), + mRecorder->GetVideoBitrate(), + mRecorder->GetBitrate(), + aTrackTypes); } else { - mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes); + mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), + mRecorder->GetAudioBitrate(), + mRecorder->GetVideoBitrate(), + mRecorder->GetBitrate(), + aTrackTypes); } if (!mEncoder) { @@ -1015,6 +1023,17 @@ MediaRecorder::SetOptions(const MediaRecorderOptions& aInitDict) aInitDict.mVideoBitsPerSecond.Value() : 0; mBitsPerSecond = aInitDict.mBitsPerSecond.WasPassed() ? aInitDict.mBitsPerSecond.Value() : 0; + // We're not handling dynamic changes yet. Eventually we'll handle + // setting audio, video and/or total -- and anything that isn't set, + // we'll derive. Calculated versions require querying bitrates after + // the encoder is Init()ed. This happens only after data is + // available and thus requires dynamic changes. + // + // Until dynamic changes are supported, I prefer to be safe and err + // slightly high + if (aInitDict.mBitsPerSecond.WasPassed() && !aInitDict.mVideoBitsPerSecond.WasPassed()) { + mVideoBitsPerSecond = mBitsPerSecond; + } } nsresult diff --git a/dom/media/MediaRecorder.h b/dom/media/MediaRecorder.h index a788f1e6b87..ca1f3877417 100644 --- a/dom/media/MediaRecorder.h +++ b/dom/media/MediaRecorder.h @@ -104,6 +104,9 @@ public: NS_DECL_NSIDOCUMENTACTIVITY + uint32_t GetAudioBitrate() { return mAudioBitsPerSecond; } + uint32_t GetVideoBitrate() { return mVideoBitsPerSecond; } + uint32_t GetBitrate() { return mBitsPerSecond; } protected: virtual ~MediaRecorder(); diff --git a/dom/media/encoder/MediaEncoder.cpp b/dom/media/encoder/MediaEncoder.cpp index e9e10a49283..0c734f4f046 100644 --- a/dom/media/encoder/MediaEncoder.cpp +++ b/dom/media/encoder/MediaEncoder.cpp @@ -73,7 +73,9 @@ MediaEncoder::NotifyEvent(MediaStreamGraph* aGraph, /* static */ already_AddRefed -MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes) +MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint32_t aAudioBitrate, + uint32_t aVideoBitrate, uint32_t aBitrate, + uint8_t aTrackTypes) { if (!gMediaEncoderLog) { gMediaEncoderLog = PR_NewLogModule("MediaEncoder"); @@ -144,8 +146,15 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes) LOG(LogLevel::Debug, ("Create encoder result:a[%d] v[%d] w[%d] mimeType = %s.", audioEncoder != nullptr, videoEncoder != nullptr, writer != nullptr, mimeType.get())); + if (videoEncoder && aVideoBitrate != 0) { + videoEncoder->SetBitrate(aVideoBitrate); + } + if (audioEncoder && aAudioBitrate != 0) { + audioEncoder->SetBitrate(aAudioBitrate); + } encoder = new MediaEncoder(writer.forget(), audioEncoder.forget(), - videoEncoder.forget(), mimeType); + videoEncoder.forget(), mimeType, aAudioBitrate, + aVideoBitrate, aBitrate); return encoder.forget(); } diff --git a/dom/media/encoder/MediaEncoder.h b/dom/media/encoder/MediaEncoder.h index c947840aec0..94a3d6dc621 100644 --- a/dom/media/encoder/MediaEncoder.h +++ b/dom/media/encoder/MediaEncoder.h @@ -62,7 +62,10 @@ public : MediaEncoder(ContainerWriter* aWriter, AudioTrackEncoder* aAudioEncoder, VideoTrackEncoder* aVideoEncoder, - const nsAString& aMIMEType) + const nsAString& aMIMEType, + uint32_t aAudioBitrate, + uint32_t aVideoBitrate, + uint32_t aBitrate) : mWriter(aWriter) , mAudioEncoder(aAudioEncoder) , mVideoEncoder(aVideoEncoder) @@ -96,6 +99,8 @@ public : * Ogg+Opus if it is empty. */ static already_AddRefed CreateEncoder(const nsAString& aMIMEType, + uint32_t aAudioBitrate, uint32_t aVideoBitrate, + uint32_t aBitrate, uint8_t aTrackTypes = ContainerWriter::CREATE_AUDIO_TRACK); /** * Encodes the raw track data and returns the final container data. Assuming diff --git a/dom/media/encoder/OpusTrackEncoder.cpp b/dom/media/encoder/OpusTrackEncoder.cpp index ec6f2352e16..053cf658f69 100644 --- a/dom/media/encoder/OpusTrackEncoder.cpp +++ b/dom/media/encoder/OpusTrackEncoder.cpp @@ -187,8 +187,13 @@ OpusTrackEncoder::Init(int aChannels, int aSamplingRate) mEncoder = opus_encoder_create(GetOutputSampleRate(), mChannels, OPUS_APPLICATION_AUDIO, &error); + mInitialized = (error == OPUS_OK); + if (mAudioBitrate) { + opus_encoder_ctl(mEncoder, OPUS_SET_BITRATE(static_cast(mAudioBitrate))); + } + mReentrantMonitor.NotifyAll(); return error == OPUS_OK ? NS_OK : NS_ERROR_FAILURE; diff --git a/dom/media/encoder/TrackEncoder.h b/dom/media/encoder/TrackEncoder.h index 20612c55198..ac01a8ce61a 100644 --- a/dom/media/encoder/TrackEncoder.h +++ b/dom/media/encoder/TrackEncoder.h @@ -84,6 +84,8 @@ public: mReentrantMonitor.NotifyAll(); } + virtual void SetBitrate(const uint32_t aBitrate) {} + protected: /** * Notifies track encoder that we have reached the end of source stream, and @@ -141,6 +143,7 @@ public: : TrackEncoder() , mChannels(0) , mSamplingRate(0) + , mAudioBitrate(0) {} virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, @@ -191,6 +194,10 @@ public: */ size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + virtual void SetBitrate(const uint32_t aBitrate) override + { + mAudioBitrate = aBitrate; + } protected: /** * Number of samples per channel in a pcm buffer. This is also the value of @@ -239,6 +246,8 @@ protected: * A segment queue of audio track data, protected by mReentrantMonitor. */ AudioSegment mRawSegment; + + uint32_t mAudioBitrate; }; class VideoTrackEncoder : public TrackEncoder @@ -252,6 +261,7 @@ public: , mDisplayHeight(0) , mTrackRate(0) , mTotalFrameDuration(0) + , mVideoBitrate(0) {} /** @@ -267,6 +277,10 @@ public: */ size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + virtual void SetBitrate(const uint32_t aBitrate) override + { + mVideoBitrate = aBitrate; + } protected: /** * Initialized the video encoder. In order to collect the value of width and @@ -332,6 +346,8 @@ protected: * A segment queue of audio track data, protected by mReentrantMonitor. */ VideoSegment mRawSegment; + + uint32_t mVideoBitrate; }; } // namespace mozilla diff --git a/dom/media/encoder/VP8TrackEncoder.cpp b/dom/media/encoder/VP8TrackEncoder.cpp index f6efac6a523..75120524c5e 100644 --- a/dom/media/encoder/VP8TrackEncoder.cpp +++ b/dom/media/encoder/VP8TrackEncoder.cpp @@ -20,7 +20,7 @@ PRLogModuleInfo* gVP8TrackEncoderLog; (msg, ##__VA_ARGS__)) // Debug logging macro with object pointer and class name. -#define DEFAULT_BITRATE 2500 // in kbit/s +#define DEFAULT_BITRATE_BPS 2500000 #define DEFAULT_ENCODE_FRAMERATE 30 using namespace mozilla::layers; @@ -87,7 +87,9 @@ VP8TrackEncoder::Init(int32_t aWidth, int32_t aHeight, int32_t aDisplayWidth, config.g_h = mFrameHeight; // TODO: Maybe we should have various aFrameRate bitrate pair for each devices? // or for different platform - config.rc_target_bitrate = DEFAULT_BITRATE; // in kbit/s + + // rc_target_bitrate needs kbit/s + config.rc_target_bitrate = (mVideoBitrate != 0 ? mVideoBitrate : DEFAULT_BITRATE_BPS)/1000; // Setting the time base of the codec config.g_timebase.num = 1; diff --git a/dom/media/encoder/VorbisTrackEncoder.cpp b/dom/media/encoder/VorbisTrackEncoder.cpp index e40253bf985..500408ef352 100644 --- a/dom/media/encoder/VorbisTrackEncoder.cpp +++ b/dom/media/encoder/VorbisTrackEncoder.cpp @@ -56,9 +56,12 @@ VorbisTrackEncoder::Init(int aChannels, int aSamplingRate) int ret = 0; vorbis_info_init(&mVorbisInfo); + double quality = mAudioBitrate ? (double)mAudioBitrate/aSamplingRate : + BASE_QUALITY; + printf("quality %f \n", quality); ret = vorbis_encode_init_vbr(&mVorbisInfo, mChannels, mSamplingRate, - BASE_QUALITY); + quality); mInitialized = (ret == 0);