From 9b55b436e495fe8093e1bd7240524ce3415eb44a Mon Sep 17 00:00:00 2001 From: Munro Chiang Date: Tue, 27 Oct 2015 15:12:26 +0800 Subject: [PATCH] Bug 1205927 - Part 1: [MediaEncoder] Support *.3g2 with EVRC audio format. r=ayang --- dom/media/MediaRecorder.cpp | 6 ++ dom/media/encoder/EncodedFrameContainer.h | 2 + dom/media/encoder/MediaEncoder.cpp | 8 ++ dom/media/encoder/OmxTrackEncoder.cpp | 45 +++++++++- dom/media/encoder/OmxTrackEncoder.h | 16 ++++ dom/media/encoder/TrackMetadataBase.h | 1 + dom/media/encoder/fmp4_muxer/EVRCBox.cpp | 84 +++++++++++++++++++ dom/media/encoder/fmp4_muxer/EVRCBox.h | 50 +++++++++++ dom/media/encoder/fmp4_muxer/ISOControl.cpp | 8 +- .../encoder/fmp4_muxer/ISOMediaBoxes.cpp | 14 ++++ .../encoder/fmp4_muxer/ISOMediaWriter.cpp | 7 +- dom/media/encoder/fmp4_muxer/ISOMediaWriter.h | 4 + .../encoder/fmp4_muxer/ISOTrackMetadata.h | 27 ++++++ dom/media/encoder/fmp4_muxer/moz.build | 1 + dom/media/omx/OMXCodecWrapper.cpp | 32 +++++++ dom/media/omx/OMXCodecWrapper.h | 5 ++ netwerk/mime/nsMimeTypes.h | 1 + .../exthandler/nsExternalHelperAppService.cpp | 1 + 18 files changed, 306 insertions(+), 6 deletions(-) create mode 100644 dom/media/encoder/fmp4_muxer/EVRCBox.cpp create mode 100644 dom/media/encoder/fmp4_muxer/EVRCBox.h diff --git a/dom/media/MediaRecorder.cpp b/dom/media/MediaRecorder.cpp index 1ce8870367e..778dfc437a7 100644 --- a/dom/media/MediaRecorder.cpp +++ b/dom/media/MediaRecorder.cpp @@ -599,6 +599,12 @@ private: mRecorder->GetVideoBitrate(), mRecorder->GetBitrate(), aTrackTypes); + } else if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP2)) { + mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP2), + mRecorder->GetAudioBitrate(), + mRecorder->GetVideoBitrate(), + mRecorder->GetBitrate(), + aTrackTypes); } else { mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), mRecorder->GetAudioBitrate(), diff --git a/dom/media/encoder/EncodedFrameContainer.h b/dom/media/encoder/EncodedFrameContainer.h index c148a850d8e..4f191ebe7f7 100644 --- a/dom/media/encoder/EncodedFrameContainer.h +++ b/dom/media/encoder/EncodedFrameContainer.h @@ -60,6 +60,8 @@ public: AAC_CSD, // AAC codec specific data AMR_AUDIO_CSD, AMR_AUDIO_FRAME, + EVRC_AUDIO_CSD, + EVRC_AUDIO_FRAME, UNKNOWN // FrameType not set }; void SwapInFrameData(nsTArray& aData) diff --git a/dom/media/encoder/MediaEncoder.cpp b/dom/media/encoder/MediaEncoder.cpp index 7c1183466a6..4a7b26ba7df 100644 --- a/dom/media/encoder/MediaEncoder.cpp +++ b/dom/media/encoder/MediaEncoder.cpp @@ -130,6 +130,14 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint32_t aAudioBitrate, writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3GP); NS_ENSURE_TRUE(writer, nullptr); mimeType = NS_LITERAL_STRING(AUDIO_3GPP); + } else if (MediaEncoder::IsOMXEncoderEnabled() && + (aMIMEType.EqualsLiteral(AUDIO_3GPP2))) { + audioEncoder = new OmxEVRCAudioTrackEncoder(); + NS_ENSURE_TRUE(audioEncoder, nullptr); + + writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3G2); + NS_ENSURE_TRUE(writer, nullptr); + mimeType = NS_LITERAL_STRING(AUDIO_3GPP2) ; } #endif // MOZ_OMX_ENCODER else if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled() && diff --git a/dom/media/encoder/OmxTrackEncoder.cpp b/dom/media/encoder/OmxTrackEncoder.cpp index d494d112290..8016e4b1ef0 100644 --- a/dom/media/encoder/OmxTrackEncoder.cpp +++ b/dom/media/encoder/OmxTrackEncoder.cpp @@ -184,7 +184,7 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer) 3000); // wait up to 3ms NS_ENSURE_SUCCESS(rv, rv); - if (!frameData.IsEmpty()) { + if (!frameData.IsEmpty() || outFlags & OMXCodecWrapper::BUFFER_EOS) { // Some hw codec may send out EOS with an empty frame bool isCSD = false; if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) { // codec specific data isCSD = true; @@ -199,6 +199,9 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer) } else if (mEncoder->GetCodecType() == OMXCodecWrapper::AMR_NB_ENC){ audiodata->SetFrameType(isCSD ? EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME); + } else if (mEncoder->GetCodecType() == OMXCodecWrapper::EVRC_ENC){ + audiodata->SetFrameType(isCSD ? + EncodedFrame::EVRC_AUDIO_CSD : EncodedFrame::EVRC_AUDIO_FRAME); } else { MOZ_ASSERT(false, "audio codec not supported"); } @@ -343,4 +346,44 @@ OmxAMRAudioTrackEncoder::GetMetadata() return meta.forget(); } +nsresult +OmxEVRCAudioTrackEncoder::Init(int aChannels, int aSamplingRate) +{ + mChannels = aChannels; + mSamplingRate = aSamplingRate; + + mEncoder = OMXCodecWrapper::CreateEVRCEncoder(); + NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE); + + nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, EVRC_SAMPLERATE); + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + mInitialized = (rv == NS_OK); + + mReentrantMonitor.NotifyAll(); + + return NS_OK; +} + +already_AddRefed +OmxEVRCAudioTrackEncoder::GetMetadata() +{ + PROFILER_LABEL("OmxEVRCAudioTrackEncoder", "GetMetadata", + js::ProfileEntry::Category::OTHER); + { + // Wait if mEncoder is not initialized nor is being canceled. + ReentrantMonitorAutoEnter mon(mReentrantMonitor); + while (!mCanceled && !mInitialized) { + mReentrantMonitor.Wait(); + } + } + + if (mCanceled || mEncodingComplete) { + return nullptr; + } + + RefPtr meta = new EVRCTrackMetadata(); + meta->mChannels = mChannels; + return meta.forget(); +} + } diff --git a/dom/media/encoder/OmxTrackEncoder.h b/dom/media/encoder/OmxTrackEncoder.h index b385b138b9b..d0912c5d50b 100644 --- a/dom/media/encoder/OmxTrackEncoder.h +++ b/dom/media/encoder/OmxTrackEncoder.h @@ -90,5 +90,21 @@ protected: nsresult Init(int aChannels, int aSamplingRate) override; }; +class OmxEVRCAudioTrackEncoder final : public OmxAudioTrackEncoder +{ +public: + OmxEVRCAudioTrackEncoder() + : OmxAudioTrackEncoder() + {} + + enum { + EVRC_SAMPLERATE = 8000, + }; + already_AddRefed GetMetadata() override; + +protected: + nsresult Init(int aChannels, int aSamplingRate) override; +}; + } #endif diff --git a/dom/media/encoder/TrackMetadataBase.h b/dom/media/encoder/TrackMetadataBase.h index 9baf96e917d..a8b818c096e 100644 --- a/dom/media/encoder/TrackMetadataBase.h +++ b/dom/media/encoder/TrackMetadataBase.h @@ -22,6 +22,7 @@ public: METADATA_AVC, METADATA_AAC, METADATA_AMR, + METADATA_EVRC, METADATA_UNKNOWN // Metadata Kind not set }; // Return the specific metadata kind diff --git a/dom/media/encoder/fmp4_muxer/EVRCBox.cpp b/dom/media/encoder/fmp4_muxer/EVRCBox.cpp new file mode 100644 index 00000000000..096e4013d2d --- /dev/null +++ b/dom/media/encoder/fmp4_muxer/EVRCBox.cpp @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "ISOControl.h" +#include "ISOMediaBoxes.h" +#include "EVRCBox.h" +#include "ISOTrackMetadata.h" + +namespace mozilla { + +nsresult +EVRCSampleEntry::Generate(uint32_t* aBoxSize) +{ + uint32_t box_size; + nsresult rv = evrc_special_box->Generate(&box_size); + NS_ENSURE_SUCCESS(rv, rv); + size += box_size; + + *aBoxSize = size; + return NS_OK; +} + +nsresult +EVRCSampleEntry::Write() +{ + BoxSizeChecker checker(mControl, size); + nsresult rv; + rv = AudioSampleEntry::Write(); + NS_ENSURE_SUCCESS(rv, rv); + rv = evrc_special_box->Write(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +EVRCSampleEntry::EVRCSampleEntry(ISOControl* aControl) + : AudioSampleEntry(NS_LITERAL_CSTRING("sevc"), aControl) +{ + evrc_special_box = new EVRCSpecificBox(aControl); + MOZ_COUNT_CTOR(EVRCSampleEntry); +} + +EVRCSampleEntry::~EVRCSampleEntry() +{ + MOZ_COUNT_DTOR(EVRCSampleEntry); +} + +nsresult +EVRCSpecificBox::Generate(uint32_t* aBoxSize) +{ + nsresult rv; + FragmentBuffer* frag = mControl->GetFragment(Audio_Track); + rv = frag->GetCSD(evrcDecSpecInfo); + NS_ENSURE_SUCCESS(rv, rv); + + size += evrcDecSpecInfo.Length(); + *aBoxSize = size; + + return NS_OK; +} + +nsresult +EVRCSpecificBox::Write() +{ + BoxSizeChecker checker(mControl, size); + Box::Write(); + mControl->Write(evrcDecSpecInfo.Elements(), evrcDecSpecInfo.Length()); + return NS_OK; +} + +EVRCSpecificBox::EVRCSpecificBox(ISOControl* aControl) + : Box(NS_LITERAL_CSTRING("devc"), aControl) +{ + MOZ_COUNT_CTOR(EVRCSpecificBox); +} + +EVRCSpecificBox::~EVRCSpecificBox() +{ + MOZ_COUNT_DTOR(EVRCSpecificBox); +} + +} diff --git a/dom/media/encoder/fmp4_muxer/EVRCBox.h b/dom/media/encoder/fmp4_muxer/EVRCBox.h new file mode 100644 index 00000000000..31355849acf --- /dev/null +++ b/dom/media/encoder/fmp4_muxer/EVRCBox.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef EVRCBOX_h_ +#define EVRCBOX_h_ + +#include "nsTArray.h" +#include "MuxerOperation.h" + +namespace mozilla { + +class ISOControl; + +// 3GPP TS 26.244 6.7 'EVRCSpecificBox field for EVRCSampleEntry box' +// Box type: 'devc' +class EVRCSpecificBox : public Box { +public: + // 3GPP members + nsTArray evrcDecSpecInfo; + + // MuxerOperation methods + nsresult Generate(uint32_t* aBoxSize) override; + nsresult Write() override; + + // EVRCSpecificBox methods + EVRCSpecificBox(ISOControl* aControl); + ~EVRCSpecificBox(); +}; + +// 3GPP TS 26.244 6.5 'EVRCSampleEntry box' +// Box type: 'sevc' +class EVRCSampleEntry : public AudioSampleEntry { +public: + // 3GPP members + RefPtr evrc_special_box; + + // MuxerOperation methods + nsresult Generate(uint32_t* aBoxSize) override; + nsresult Write() override; + + // EVRCSampleEntry methods + EVRCSampleEntry(ISOControl* aControl); + ~EVRCSampleEntry(); +}; + +} + +#endif // EVRCBOX_h_ diff --git a/dom/media/encoder/fmp4_muxer/ISOControl.cpp b/dom/media/encoder/fmp4_muxer/ISOControl.cpp index 2ac11065216..6addaeb308d 100644 --- a/dom/media/encoder/fmp4_muxer/ISOControl.cpp +++ b/dom/media/encoder/fmp4_muxer/ISOControl.cpp @@ -62,7 +62,7 @@ FragmentBuffer::AddFrame(EncodedFrame* aFrame) EncodedFrame::FrameType type = aFrame->GetFrameType(); if (type == EncodedFrame::AAC_CSD || type == EncodedFrame::AVC_CSD || - type == EncodedFrame::AMR_AUDIO_CSD) { + type == EncodedFrame::AMR_AUDIO_CSD || type == EncodedFrame::EVRC_AUDIO_CSD) { mCSDFrame = aFrame; // Use CSD's timestamp as the start time. Encoder should send CSD frame first // and then data frames. @@ -168,7 +168,8 @@ ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta) { if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC || aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR || - aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC) { + aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC || + aTrackMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) { mMetaArray.AppendElement(aTrackMeta); return NS_OK; } @@ -180,7 +181,8 @@ ISOControl::GetAudioMetadata(RefPtr& aAudMeta) { for (uint32_t i = 0; i < mMetaArray.Length() ; i++) { if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC || - mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR) { + mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR || + mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_EVRC) { aAudMeta = static_cast(mMetaArray[i].get()); return NS_OK; } diff --git a/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp b/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp index 57f2ec72635..79ad83caae2 100644 --- a/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp +++ b/dom/media/encoder/fmp4_muxer/ISOMediaBoxes.cpp @@ -13,6 +13,7 @@ #include "MP4ESDS.h" #include "AMRBox.h" #include "AVCBox.h" +#include "EVRCBox.h" #include "VideoUtils.h" namespace mozilla { @@ -666,6 +667,8 @@ SampleDescriptionBox::CreateAudioSampleEntry(RefPtr& aSampleEntr aSampleEntry = new AMRSampleEntry(mControl); } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_AAC) { aSampleEntry = new MP4AudioSampleEntry(mControl); + } else if (mAudioMeta->GetKind() == TrackMetadataBase::METADATA_EVRC) { + aSampleEntry = new EVRCSampleEntry(mControl); } else { MOZ_ASSERT(0); } @@ -1250,6 +1253,17 @@ FileTypeBox::Generate(uint32_t* aBoxSize) compatible_brands.AppendElement("3gp7"); compatible_brands.AppendElement("3gp6"); compatible_brands.AppendElement("isom"); + } else if (mControl->GetMuxingType() == ISOMediaWriter::TYPE_FRAG_3G2) { + major_brand = "3g2a"; + // 3GPP2 Release 0 and A and 3GPP Release 6 allow movie fragmentation + compatible_brands.AppendElement("3gp9"); + compatible_brands.AppendElement("3gp8"); + compatible_brands.AppendElement("3gp7"); + compatible_brands.AppendElement("3gp6"); + compatible_brands.AppendElement("isom"); + compatible_brands.AppendElement("3g2c"); + compatible_brands.AppendElement("3g2b"); + compatible_brands.AppendElement("3g2a"); } else { MOZ_ASSERT(0); } diff --git a/dom/media/encoder/fmp4_muxer/ISOMediaWriter.cpp b/dom/media/encoder/fmp4_muxer/ISOMediaWriter.cpp index 6ef02607961..fa23616e98a 100644 --- a/dom/media/encoder/fmp4_muxer/ISOMediaWriter.cpp +++ b/dom/media/encoder/fmp4_muxer/ISOMediaWriter.cpp @@ -104,7 +104,9 @@ ISOMediaWriter::WriteEncodedTrack(const EncodedFrameContainer& aData, if (type == EncodedFrame::AAC_AUDIO_FRAME || type == EncodedFrame::AAC_CSD || type == EncodedFrame::AMR_AUDIO_FRAME || - type == EncodedFrame::AMR_AUDIO_CSD) { + type == EncodedFrame::AMR_AUDIO_CSD || + type == EncodedFrame::EVRC_AUDIO_FRAME || + type == EncodedFrame::EVRC_AUDIO_CSD) { frag = mAudioFragmentBuffer; } else if (type == EncodedFrame::AVC_I_FRAME || type == EncodedFrame::AVC_P_FRAME || @@ -212,7 +214,8 @@ ISOMediaWriter::SetMetadata(TrackMetadataBase* aMetadata) PROFILER_LABEL("ISOMediaWriter", "SetMetadata", js::ProfileEntry::Category::OTHER); if (aMetadata->GetKind() == TrackMetadataBase::METADATA_AAC || - aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR) { + aMetadata->GetKind() == TrackMetadataBase::METADATA_AMR || + aMetadata->GetKind() == TrackMetadataBase::METADATA_EVRC) { mControl->SetMetadata(aMetadata); mAudioFragmentBuffer = new FragmentBuffer(Audio_Track, FRAG_DURATION); mControl->SetFragment(mAudioFragmentBuffer); diff --git a/dom/media/encoder/fmp4_muxer/ISOMediaWriter.h b/dom/media/encoder/fmp4_muxer/ISOMediaWriter.h index 342b9fbaf70..e5db6f964d5 100644 --- a/dom/media/encoder/fmp4_muxer/ISOMediaWriter.h +++ b/dom/media/encoder/fmp4_muxer/ISOMediaWriter.h @@ -26,6 +26,10 @@ public: // Brand names in 'ftyp' box are '3gp9' and 'isom'. const static uint32_t TYPE_FRAG_3GP = 1 << 1; + // Generate an fragmented 3G2 stream, 3GPP2 C.S0050-B + // Brand names in 'ftyp' box are '3g2c' and 'isom' + const static uint32_t TYPE_FRAG_3G2 = 1 << 2; + // aType is the combination of CREATE_AUDIO_TRACK and CREATE_VIDEO_TRACK. // It is a hint to muxer that the output streaming contains audio, video // or both. diff --git a/dom/media/encoder/fmp4_muxer/ISOTrackMetadata.h b/dom/media/encoder/fmp4_muxer/ISOTrackMetadata.h index e11d0a1d934..3613e1e9eb0 100644 --- a/dom/media/encoder/fmp4_muxer/ISOTrackMetadata.h +++ b/dom/media/encoder/fmp4_muxer/ISOTrackMetadata.h @@ -99,6 +99,33 @@ public: ~AMRTrackMetadata() { MOZ_COUNT_DTOR(AMRTrackMetadata); } }; +// EVRC sample rate is 8000 samples/s. +#define EVRC_SAMPLE_RATE 8000 + +class EVRCTrackMetadata : public AudioTrackMetadata { +public: + // AudioTrackMetadata members + // + // The number of sample sets generates by encoder is variant. So the + // frame duration and frame size are both 0. + uint32_t GetAudioFrameDuration() override { return 0; } + uint32_t GetAudioFrameSize() override { return 0; } + uint32_t GetAudioSampleRate() override { return EVRC_SAMPLE_RATE; } + uint32_t GetAudioChannels() override { return mChannels; } + + // TrackMetadataBase member + MetadataKind GetKind() const override { return METADATA_EVRC; } + + // EVRCTrackMetadata members + EVRCTrackMetadata() + : mChannels(0) { + MOZ_COUNT_CTOR(EVRCTrackMetadata); + } + ~EVRCTrackMetadata() { MOZ_COUNT_DTOR(EVRCTrackMetadata); } + + uint32_t mChannels; // Channel number, it should be 1 or 2. +}; + } #endif // ISOTrackMetadata_h_ diff --git a/dom/media/encoder/fmp4_muxer/moz.build b/dom/media/encoder/fmp4_muxer/moz.build index 1b4fe18e068..3c770b13f5b 100644 --- a/dom/media/encoder/fmp4_muxer/moz.build +++ b/dom/media/encoder/fmp4_muxer/moz.build @@ -12,6 +12,7 @@ EXPORTS += [ UNIFIED_SOURCES += [ 'AMRBox.cpp', 'AVCBox.cpp', + 'EVRCBox.cpp', 'ISOControl.cpp', 'ISOMediaBoxes.cpp', 'ISOMediaWriter.cpp', diff --git a/dom/media/omx/OMXCodecWrapper.cpp b/dom/media/omx/OMXCodecWrapper.cpp index 43179ddca2a..1f56010a534 100644 --- a/dom/media/omx/OMXCodecWrapper.cpp +++ b/dom/media/omx/OMXCodecWrapper.cpp @@ -30,6 +30,7 @@ using namespace mozilla::layers; #define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll) // AMR NB kbps #define AMRNB_BITRATE 12200 +#define EVRC_BITRATE 8755 #define CODEC_ERROR(args...) \ do { \ @@ -38,6 +39,8 @@ using namespace mozilla::layers; namespace android { +const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc"; + enum BufferState { BUFFER_OK, @@ -85,6 +88,16 @@ OMXCodecWrapper::CreateAMRNBEncoder() return amr.forget(); } +OMXAudioEncoder* +OMXCodecWrapper::CreateEVRCEncoder() +{ + nsAutoPtr evrc(new OMXAudioEncoder(CodecType::EVRC_ENC)); + // Return the object only when media codec is valid. + NS_ENSURE_TRUE(evrc->IsValid(), nullptr); + + return evrc.forget(); +} + OMXVideoEncoder* OMXCodecWrapper::CreateAVCEncoder() { @@ -99,6 +112,7 @@ OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType) : mCodecType(aCodecType) , mStarted(false) , mAMRCSDProvided(false) + , mEVRCCSDProvided(false) { ProcessState::self()->startThreadPool(); @@ -111,6 +125,8 @@ OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType) mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AMR_NB, true); } else if (aCodecType == CodecType::AAC_ENC) { mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AAC, true); + } else if (aCodecType == CodecType::EVRC_ENC) { + mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_EVRC, true); } else { NS_ERROR("Unknown codec type."); } @@ -633,6 +649,10 @@ OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate, format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB); format->setInt32("bitrate", AMRNB_BITRATE); format->setInt32("sample-rate", aEncodedSampleRate); + } else if (mCodecType == EVRC_ENC) { + format->setString("mime", MEDIA_MIMETYPE_AUDIO_EVRC); + format->setInt32("bitrate", EVRC_BITRATE); + format->setInt32("sample-rate", aEncodedSampleRate); } else { MOZ_ASSERT(false, "Can't support this codec type!!"); } @@ -1070,6 +1090,18 @@ OMXCodecWrapper::GetNextEncodedFrame(nsTArray* aOutputBuf, aOutputBuf->AppendElements(decConfig, sizeof(decConfig)); outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; mAMRCSDProvided = true; + } else if ((mCodecType == EVRC_ENC) && !mEVRCCSDProvided){ + // OMX EVRC codec won't provide csd data, need to generate a fake one. + RefPtr audiodata = new EncodedFrame(); + // Decoder config descriptor + const uint8_t decConfig[] = { + 0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes + 0x0, // decoder version + 0x01, // frames per sample + }; + aOutputBuf->AppendElements(decConfig, sizeof(decConfig)); + outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG; + mEVRCCSDProvided = true; } else { AppendFrame(aOutputBuf, omxBuf->data(), omxBuf->size()); } diff --git a/dom/media/omx/OMXCodecWrapper.h b/dom/media/omx/OMXCodecWrapper.h index 8cce02d28dc..60ac6505977 100644 --- a/dom/media/omx/OMXCodecWrapper.h +++ b/dom/media/omx/OMXCodecWrapper.h @@ -88,6 +88,7 @@ public: AAC_ENC, // AAC encoder. AMR_NB_ENC, // AMR_NB encoder. AVC_ENC, // AVC/H.264 encoder. + EVRC_ENC, // EVRC encoder TYPE_COUNT }; @@ -120,6 +121,9 @@ public: /** Create a AMR audio encoder. Returns nullptr when failed. */ static OMXAudioEncoder* CreateAMRNBEncoder(); + /** Create a EVRC audio encoder. Returns nullptr when failed. */ + static OMXAudioEncoder* CreateEVRCEncoder(); + /** Create a AVC/H.264 video encoder. Returns nullptr when failed. */ static OMXVideoEncoder* CreateAVCEncoder(); @@ -204,6 +208,7 @@ private: int mCodecType; bool mStarted; // Has MediaCodec been started? bool mAMRCSDProvided; + bool mEVRCCSDProvided; }; /** diff --git a/netwerk/mime/nsMimeTypes.h b/netwerk/mime/nsMimeTypes.h index 330641a2d4a..1258fd566f8 100644 --- a/netwerk/mime/nsMimeTypes.h +++ b/netwerk/mime/nsMimeTypes.h @@ -84,6 +84,7 @@ #define AUDIO_AMR "audio/amr" #define AUDIO_FLAC "audio/flac" #define AUDIO_3GPP "audio/3gpp" +#define AUDIO_3GPP2 "audio/3gpp2" #define AUDIO_MIDI "audio/x-midi" #define AUDIO_MATROSKA "audio/x-matroska" diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index b440a88a603..82b2b5e321d 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -618,6 +618,7 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = // app on Firefox OS depends on the "3gp" extension mapping to the // "video/3gpp" MIME type. { AUDIO_3GPP, "3gpp,3gp", "3GPP Audio" }, + { AUDIO_3GPP2, "3g2", "3GPP2 Audio" }, #endif { AUDIO_MIDI, "mid", "Standard MIDI Audio" } };