diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index eb830a704314..09ff5ee310d5 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -542,7 +542,6 @@ pref("dom.webapps.useCurrentProfile", true); // Enable system message pref("dom.sysmsg.enabled", true); pref("media.plugins.enabled", false); -pref("media.omx.enabled", true); pref("media.rtsp.enabled", true); pref("media.rtsp.video.enabled", true); diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index acdfcd70a737..0e18046ad703 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -24,12 +24,6 @@ #include "AndroidMediaReader.h" #include "AndroidMediaPluginHost.h" #endif -#ifdef MOZ_OMX_DECODER -#include "MediaOmxDecoder.h" -#include "MediaOmxReader.h" -#include "nsIPrincipal.h" -#include "mozilla/dom/HTMLMediaElement.h" -#endif #ifdef MOZ_DIRECTSHOW #include "DirectShowDecoder.h" #include "DirectShowReader.h" @@ -146,89 +140,6 @@ IsHttpLiveStreamingType(const nsACString& aType) return CodecListContains(gHttpLiveStreamingTypes, aType); } -#ifdef MOZ_OMX_DECODER -static const char* const gOmxTypes[] = { - "audio/mpeg", - "audio/mp4", - "audio/amr", - "audio/3gpp", - "audio/flac", - "video/mp4", - "video/x-m4v", - "video/3gpp", - "video/3gpp2", - "video/quicktime", -#ifdef MOZ_OMX_WEBM_DECODER - "video/webm", - "audio/webm", -#endif - "audio/x-matroska", - "video/mp2t", - "video/avi", - "video/x-matroska", - nullptr -}; - -static const char* const gB2GOnlyTypes[] = { - "audio/3gpp", - "audio/amr", - "audio/x-matroska", - "video/mp2t", - "video/avi", - "video/x-matroska", - nullptr -}; - -static bool -IsOmxSupportedType(const nsACString& aType) -{ - if (!MediaDecoder::IsOmxEnabled()) { - return false; - } - - return CodecListContains(gOmxTypes, aType); -} - -static bool -IsB2GSupportOnlyType(const nsACString& aType) -{ - return CodecListContains(gB2GOnlyTypes, aType); -} - -static char const *const gH264Codecs[9] = { - "avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0 - "avc1.42001E", // H.264 Baseline Profile Level 3.0 - "avc1.58A01E", // H.264 Extended Profile Level 3.0 - "avc1.4D401E", // H.264 Main Profile Level 3.0 - "avc1.64001E", // H.264 High Profile Level 3.0 - "avc1.64001F", // H.264 High Profile Level 3.1 - "mp4v.20.3", // 3GPP - "mp4a.40.2", // AAC-LC - nullptr -}; - -static char const *const gMpegAudioCodecs[2] = { - "mp3", // MP3 - nullptr -}; - -#ifdef MOZ_OMX_WEBM_DECODER -static char const *const gOMXWebMCodecs[] = { - "vorbis", - "vp8", - "vp8.0", - // Since Android KK, VP9 SW decoder is supported. - // http://developer.android.com/guide/appendix/media-formats.html -#if ANDROID_VERSION > 18 - "vp9", - "vp9.0", -#endif - nullptr -}; -#endif //MOZ_OMX_WEBM_DECODER - -#endif - #ifdef MOZ_ANDROID_OMX static bool IsAndroidMediaType(const nsACString& aType) @@ -283,11 +194,7 @@ static bool IsMP3SupportedType(const nsACString& aType, const nsAString& aCodecs = EmptyString()) { -#ifdef MOZ_OMX_DECODER - return false; -#else return MP3Decoder::CanHandleMediaType(aType, aCodecs); -#endif } static bool @@ -364,20 +271,6 @@ CanHandleCodecsType(const MediaContentType& aType, if (IsFlacSupportedType(aType.GetMIMEType(), aType.GetCodecs())) { return CANPLAY_YES; } -#ifdef MOZ_OMX_DECODER - if (IsOmxSupportedType(aType.GetMIMEType())) { - if (aType.GetMIMEType().EqualsASCII("audio/mpeg")) { - codecList = gMpegAudioCodecs; -#ifdef MOZ_OMX_WEBM_DECODER - } else if (aType.GetMIMEType().EqualsASCII("audio/webm") || - aType.GetMIMEType().EqualsASCII("video/webm")) { - codecList = gOMXWebMCodecs; -#endif - } else { - codecList = gH264Codecs; - } - } -#endif #ifdef MOZ_DIRECTSHOW DirectShowDecoder::GetSupportedCodecs(aType.GetMIMEType(), &codecList); #endif @@ -451,11 +344,6 @@ CanHandleMediaType(const MediaContentType& aType, if (IsFlacSupportedType(aType.GetMIMEType())) { return CANPLAY_MAYBE; } -#ifdef MOZ_OMX_DECODER - if (IsOmxSupportedType(aType.GetMIMEType())) { - return CANPLAY_MAYBE; - } -#endif #ifdef MOZ_DIRECTSHOW if (DirectShowDecoder::GetSupportedCodecs(aType.GetMIMEType(), nullptr)) { return CANPLAY_MAYBE; @@ -547,27 +435,6 @@ InstantiateDecoder(const nsACString& aType, decoder = new FlacDecoder(aOwner); return decoder.forget(); } -#ifdef MOZ_OMX_DECODER - if (IsOmxSupportedType(aType)) { - // we are discouraging Web and App developers from using those formats in - // gB2GOnlyTypes, thus we only allow them to be played on WebApps. - if (IsB2GSupportOnlyType(aType)) { - dom::HTMLMediaElement* element = aOwner->GetMediaElement(); - if (!element) { - return nullptr; - } - nsIPrincipal* principal = element->NodePrincipal(); - if (!principal) { - return nullptr; - } - if (principal->GetAppStatus() < nsIPrincipal::APP_STATUS_PRIVILEGED) { - return nullptr; - } - } - decoder = new MediaOmxDecoder(aOwner); - return decoder.forget(); - } -#endif #ifdef MOZ_ANDROID_OMX if (MediaDecoder::IsAndroidMediaPluginEnabled() && EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) { @@ -642,11 +509,6 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac if (IsWaveType(aType)) { decoderReader = new WaveReader(aDecoder); } else -#ifdef MOZ_OMX_DECODER - if (IsOmxSupportedType(aType)) { - decoderReader = new MediaOmxReader(aDecoder); - } else -#endif #ifdef MOZ_ANDROID_OMX if (MediaDecoder::IsAndroidMediaPluginEnabled() && EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) { @@ -680,13 +542,6 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType) return IsOggSupportedType(aType) || -#ifdef MOZ_OMX_DECODER - // We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS - // but not in general web content. Ensure we dont create a VideoDocument - // when accessing those format URLs directly. - (IsOmxSupportedType(aType) && - !IsB2GSupportOnlyType(aType)) || -#endif IsWebMSupportedType(aType) || #ifdef MOZ_ANDROID_OMX (MediaDecoder::IsAndroidMediaPluginEnabled() && IsAndroidMediaType(aType)) || diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index 7e3c70aeceac..0439a7473b7c 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -6,10 +6,6 @@ #include "MediaData.h" #include "MediaInfo.h" -#ifdef MOZ_OMX_DECODER -#include "GrallocImages.h" -#include "mozilla/layers/TextureClient.h" -#endif #include "VideoUtils.h" #include "ImageContainer.h" @@ -384,52 +380,6 @@ VideoData::CreateFromImage(const VideoInfo& aInfo, return v.forget(); } -#ifdef MOZ_OMX_DECODER -/* static */ -already_AddRefed -VideoData::CreateAndCopyIntoTextureClient(const VideoInfo& aInfo, - int64_t aOffset, - int64_t aTime, - int64_t aDuration, - mozilla::layers::TextureClient* aBuffer, - bool aKeyframe, - int64_t aTimecode, - const IntRect& aPicture) -{ - // The following situations could be triggered by invalid input - if (aPicture.width <= 0 || aPicture.height <= 0) { - NS_WARNING("Empty picture rect"); - return nullptr; - } - - // Ensure the picture size specified in the headers can be extracted out of - // the frame we've been supplied without indexing out of bounds. - CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width); - CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height); - if (!xLimit.isValid() || !yLimit.isValid()) - { - // The specified picture dimensions can't be contained inside the video - // frame, we'll stomp memory if we try to copy it. Fail. - NS_WARNING("Overflowing picture rect"); - return nullptr; - } - - RefPtr v(new VideoData(aOffset, - aTime, - aDuration, - aKeyframe, - aTimecode, - aInfo.mDisplay, - 0)); - - RefPtr image = new layers::GrallocImage(); - image->AdoptData(aBuffer, aPicture.Size()); - v->mImage = image; - - return v.forget(); -} -#endif // MOZ_OMX_DECODER - MediaRawData::MediaRawData() : MediaData(RAW_DATA, 0) , mCrypto(mCryptoInternal) diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index e6dfe104f370..7cf8729ffd33 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -1736,14 +1736,6 @@ MediaDecoder::IsWebMEnabled() return Preferences::GetBool("media.webm.enabled"); } -#ifdef MOZ_OMX_DECODER -bool -MediaDecoder::IsOmxEnabled() -{ - return Preferences::GetBool("media.omx.enabled", false); -} -#endif - #ifdef MOZ_ANDROID_OMX bool MediaDecoder::IsAndroidMediaPluginEnabled() diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index 654815e1f52f..ec06725ad529 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -456,10 +456,6 @@ private: static bool IsWaveEnabled(); static bool IsWebMEnabled(); -#ifdef MOZ_OMX_DECODER - static bool IsOmxEnabled(); -#endif - #ifdef MOZ_ANDROID_OMX static bool IsAndroidMediaPluginEnabled(); #endif diff --git a/dom/media/MediaRecorder.cpp b/dom/media/MediaRecorder.cpp index 3558e6ca1bd9..881b9bf0fe49 100644 --- a/dom/media/MediaRecorder.cpp +++ b/dom/media/MediaRecorder.cpp @@ -1328,17 +1328,6 @@ MediaRecorder::IsTypeSupported(const nsAString& aMIMEType) codeclist = gWebMVideoEncoderCodecs; } #endif -#ifdef MOZ_OMX_ENCODER - // We're working on MP4 encoder support for desktop - else if (mimeType.EqualsLiteral(VIDEO_MP4) || - mimeType.EqualsLiteral(AUDIO_3GPP) || - mimeType.EqualsLiteral(AUDIO_3GPP2)) { - if (MediaEncoder::IsOMXEncoderEnabled()) { - // XXX check codecs for MP4/3GPP - return true; - } - } -#endif // codecs don't matter if we don't support the container if (!codeclist) { diff --git a/dom/media/encoder/MediaEncoder.cpp b/dom/media/encoder/MediaEncoder.cpp index af1f7760dbc2..864b486e48f1 100644 --- a/dom/media/encoder/MediaEncoder.cpp +++ b/dom/media/encoder/MediaEncoder.cpp @@ -19,10 +19,6 @@ #include "VP8TrackEncoder.h" #include "WebMWriter.h" #endif -#ifdef MOZ_OMX_ENCODER -#include "OmxTrackEncoder.h" -#include "ISOMediaWriter.h" -#endif #ifdef LOG #undef LOG @@ -180,37 +176,6 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint32_t aAudioBitrate, mimeType = NS_LITERAL_STRING(VIDEO_WEBM); } #endif //MOZ_WEBM_ENCODER -#ifdef MOZ_OMX_ENCODER - else if (MediaEncoder::IsOMXEncoderEnabled() && - (aMIMEType.EqualsLiteral(VIDEO_MP4) || - (aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) { - if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK) { - audioEncoder = new OmxAACAudioTrackEncoder(); - NS_ENSURE_TRUE(audioEncoder, nullptr); - } - videoEncoder = new OmxVideoTrackEncoder(aTrackRate); - writer = new ISOMediaWriter(aTrackTypes); - NS_ENSURE_TRUE(writer, nullptr); - NS_ENSURE_TRUE(videoEncoder, nullptr); - mimeType = NS_LITERAL_STRING(VIDEO_MP4); - } else if (MediaEncoder::IsOMXEncoderEnabled() && - (aMIMEType.EqualsLiteral(AUDIO_3GPP))) { - audioEncoder = new OmxAMRAudioTrackEncoder(); - NS_ENSURE_TRUE(audioEncoder, nullptr); - - 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() && (aMIMEType.EqualsLiteral(AUDIO_OGG) || (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK))) { @@ -419,14 +384,6 @@ MediaEncoder::IsWebMEncoderEnabled() } #endif -#ifdef MOZ_OMX_ENCODER -bool -MediaEncoder::IsOMXEncoderEnabled() -{ - return Preferences::GetBool("media.encoder.omx.enabled"); -} -#endif - /* * SizeOfExcludingThis measures memory being used by the Media Encoder. * Currently it measures the size of the Encoder buffer and memory occupied diff --git a/dom/media/encoder/MediaEncoder.h b/dom/media/encoder/MediaEncoder.h index 9149753ecb19..41d7e71e2e96 100644 --- a/dom/media/encoder/MediaEncoder.h +++ b/dom/media/encoder/MediaEncoder.h @@ -217,10 +217,6 @@ public : static bool IsWebMEncoderEnabled(); #endif -#ifdef MOZ_OMX_ENCODER - static bool IsOMXEncoderEnabled(); -#endif - MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) /* * Measure the size of the buffer, and memory occupied by mAudioEncoder diff --git a/dom/media/encoder/OmxTrackEncoder.cpp b/dom/media/encoder/OmxTrackEncoder.cpp deleted file mode 100644 index f14b8d39b790..000000000000 --- a/dom/media/encoder/OmxTrackEncoder.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/* -*- 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 "OmxTrackEncoder.h" -#include "OMXCodecWrapper.h" -#include "VideoUtils.h" -#include "ISOTrackMetadata.h" -#include "GeckoProfiler.h" - -#ifdef MOZ_WIDGET_GONK -#include -#define OMX_LOG(args...) \ - do { \ - __android_log_print(ANDROID_LOG_INFO, "OmxTrackEncoder", ##args); \ - } while (0) -#else -#define OMX_LOG(args, ...) -#endif - -using namespace android; - -namespace mozilla { - -#define ENCODER_CONFIG_FRAME_RATE 30 // fps -#define GET_ENCODED_VIDEO_FRAME_TIMEOUT 100000 // microseconds - -OmxVideoTrackEncoder::OmxVideoTrackEncoder(TrackRate aTrackRate) - : VideoTrackEncoder(aTrackRate) -{} - -OmxVideoTrackEncoder::~OmxVideoTrackEncoder() -{} - -nsresult -OmxVideoTrackEncoder::Init(int aWidth, int aHeight, int aDisplayWidth, - int aDisplayHeight) -{ - mFrameWidth = aWidth; - mFrameHeight = aHeight; - mDisplayWidth = aDisplayWidth; - mDisplayHeight = aDisplayHeight; - - mEncoder = OMXCodecWrapper::CreateAVCEncoder(); - NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE); - - nsresult rv = mEncoder->Configure(mFrameWidth, mFrameHeight, - ENCODER_CONFIG_FRAME_RATE); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mInitialized = (rv == NS_OK); - - mReentrantMonitor.NotifyAll(); - - return rv; -} - -already_AddRefed -OmxVideoTrackEncoder::GetMetadata() -{ - PROFILER_LABEL("OmxVideoTrackEncoder", "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 AVCTrackMetadata(); - meta->mWidth = mFrameWidth; - meta->mHeight = mFrameHeight; - meta->mDisplayWidth = mDisplayWidth; - meta->mDisplayHeight = mDisplayHeight; - meta->mFrameRate = ENCODER_CONFIG_FRAME_RATE; - return meta.forget(); -} - -nsresult -OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) -{ - PROFILER_LABEL("OmxVideoTrackEncoder", "GetEncodedTrack", - js::ProfileEntry::Category::OTHER); - VideoSegment segment; - { - // Move all the samples from mRawSegment to segment. We only hold the - // monitor in this block. - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - // Wait if mEncoder is not initialized nor is being canceled. - while (!mCanceled && (!mInitialized || - (mRawSegment.GetDuration() == 0 && !mEndOfStream))) { - mReentrantMonitor.Wait(); - } - - if (mCanceled || mEncodingComplete) { - return NS_ERROR_FAILURE; - } - - segment.AppendFrom(&mRawSegment); - } - - nsresult rv; - // Start queuing raw frames to the input buffers of OMXCodecWrapper. - VideoSegment::ChunkIterator iter(segment); - while (!iter.IsEnded()) { - VideoChunk chunk = *iter; - - uint64_t totalDurationUs = mTotalFrameDuration * USECS_PER_S / mTrackRate; - layers::Image* img = (chunk.IsNull() || chunk.mFrame.GetForceBlack()) ? - nullptr : chunk.mFrame.GetImage(); - rv = mEncoder->Encode(img, mFrameWidth, mFrameHeight, totalDurationUs); - NS_ENSURE_SUCCESS(rv, rv); - - mTotalFrameDuration += chunk.GetDuration(); - - iter.Next(); - } - - // Send the EOS signal to OMXCodecWrapper. - if (mEndOfStream && iter.IsEnded() && !mEosSetInEncoder) { - uint64_t totalDurationUs = mTotalFrameDuration * USECS_PER_S / mTrackRate; - layers::Image* img = (!mLastFrame.GetImage() || mLastFrame.GetForceBlack()) - ? nullptr : mLastFrame.GetImage(); - rv = mEncoder->Encode(img, mFrameWidth, mFrameHeight, totalDurationUs, - OMXCodecWrapper::BUFFER_EOS, &mEosSetInEncoder); - NS_ENSURE_SUCCESS(rv, rv); - } - - // Dequeue an encoded frame from the output buffers of OMXCodecWrapper. - nsTArray buffer; - int outFlags = 0; - int64_t outTimeStampUs = 0; - rv = mEncoder->GetNextEncodedFrame(&buffer, &outTimeStampUs, &outFlags, - GET_ENCODED_VIDEO_FRAME_TIMEOUT); - NS_ENSURE_SUCCESS(rv, rv); - if (!buffer.IsEmpty()) { - RefPtr videoData = new EncodedFrame(); - if (outFlags & OMXCodecWrapper::BUFFER_CODEC_CONFIG) { - videoData->SetFrameType(EncodedFrame::AVC_CSD); - } else { - videoData->SetFrameType((outFlags & OMXCodecWrapper::BUFFER_SYNC_FRAME) ? - EncodedFrame::AVC_I_FRAME : EncodedFrame::AVC_P_FRAME); - } - videoData->SwapInFrameData(buffer); - videoData->SetTimeStamp(outTimeStampUs); - aData.AppendEncodedFrame(videoData); - } - - if (outFlags & OMXCodecWrapper::BUFFER_EOS) { - mEncodingComplete = true; - OMX_LOG("Done encoding video."); - } - - return NS_OK; -} - -OmxAudioTrackEncoder::OmxAudioTrackEncoder() - : AudioTrackEncoder() -{} - -OmxAudioTrackEncoder::~OmxAudioTrackEncoder() -{} - -nsresult -OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer) -{ - nsTArray frameData; - int outFlags = 0; - int64_t outTimeUs = -1; - - nsresult rv = mEncoder->GetNextEncodedFrame(&frameData, &outTimeUs, &outFlags, - 3000); // wait up to 3ms - NS_ENSURE_SUCCESS(rv, rv); - - 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; - } else if (outFlags & OMXCodecWrapper::BUFFER_EOS) { // last frame - mEncodingComplete = true; - } - - RefPtr audiodata = new EncodedFrame(); - if (mEncoder->GetCodecType() == OMXCodecWrapper::AAC_ENC) { - audiodata->SetFrameType(isCSD ? - EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME); - } 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"); - } - audiodata->SetTimeStamp(outTimeUs); - audiodata->SwapInFrameData(frameData); - aContainer.AppendEncodedFrame(audiodata); - } - - return NS_OK; -} - -nsresult -OmxAudioTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData) -{ - PROFILER_LABEL("OmxAACAudioTrackEncoder", "GetEncodedTrack", - js::ProfileEntry::Category::OTHER); - AudioSegment segment; - bool EOS; - // Move all the samples from mRawSegment to segment. We only hold - // the monitor in this block. - { - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - - // Wait if mEncoder is not initialized nor canceled. - while (!mInitialized && !mCanceled) { - mReentrantMonitor.Wait(); - } - - if (mCanceled || mEncodingComplete) { - return NS_ERROR_FAILURE; - } - - segment.AppendFrom(&mRawSegment); - EOS = mEndOfStream; - } - - nsresult rv; - if (segment.GetDuration() == 0) { - // Notify EOS at least once, even if segment is empty. - if (EOS && !mEosSetInEncoder) { - rv = mEncoder->Encode(segment, OMXCodecWrapper::BUFFER_EOS, - &mEosSetInEncoder); - NS_ENSURE_SUCCESS(rv, rv); - } - // Nothing to encode but encoder could still have encoded data for earlier - // input. - return AppendEncodedFrames(aData); - } - - // OMX encoder has limited input buffers only so we have to feed input and get - // output more than once if there are too many samples pending in segment. - while (segment.GetDuration() > 0) { - rv = mEncoder->Encode(segment, 0); - NS_ENSURE_SUCCESS(rv, rv); - - rv = AppendEncodedFrames(aData); - NS_ENSURE_SUCCESS(rv, rv); - } - - return NS_OK; -} - -nsresult -OmxAACAudioTrackEncoder::Init(int aChannels, int aSamplingRate) -{ - mChannels = aChannels; - mSamplingRate = aSamplingRate; - - mEncoder = OMXCodecWrapper::CreateAACEncoder(); - NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE); - - nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, mSamplingRate); - - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mInitialized = (rv == NS_OK); - - mReentrantMonitor.NotifyAll(); - - return NS_OK; -} - -already_AddRefed -OmxAACAudioTrackEncoder::GetMetadata() -{ - PROFILER_LABEL("OmxAACAudioTrackEncoder", "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 AACTrackMetadata(); - meta->mChannels = mChannels; - meta->mSampleRate = mSamplingRate; - meta->mFrameSize = OMXCodecWrapper::kAACFrameSize; - meta->mFrameDuration = OMXCodecWrapper::kAACFrameDuration; - return meta.forget(); -} - -nsresult -OmxAMRAudioTrackEncoder::Init(int aChannels, int aSamplingRate) -{ - mChannels = aChannels; - mSamplingRate = aSamplingRate; - - mEncoder = OMXCodecWrapper::CreateAMRNBEncoder(); - NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE); - - nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, AMR_NB_SAMPLERATE); - ReentrantMonitorAutoEnter mon(mReentrantMonitor); - mInitialized = (rv == NS_OK); - - mReentrantMonitor.NotifyAll(); - - return NS_OK; -} - -already_AddRefed -OmxAMRAudioTrackEncoder::GetMetadata() -{ - PROFILER_LABEL("OmxAMRAudioTrackEncoder", "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 AMRTrackMetadata(); - 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 deleted file mode 100644 index fe00ffd7f65c..000000000000 --- a/dom/media/encoder/OmxTrackEncoder.h +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- 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 OmxTrackEncoder_h_ -#define OmxTrackEncoder_h_ - -#include "nsAutoPtr.h" -#include "TrackEncoder.h" - -namespace android { -class OMXVideoEncoder; -class OMXAudioEncoder; -} - -/** - * There are two major classes defined in file OmxTrackEncoder; - * OmxVideoTrackEncoder and OmxAudioTrackEncoder, the video and audio track - * encoder for media type AVC/H.264 and AAC. OMXCodecWrapper wraps and controls - * an instance of MediaCodec, defined in libstagefright, runs on Android Jelly - * Bean platform. - */ - -namespace mozilla { - -class OmxVideoTrackEncoder: public VideoTrackEncoder -{ -public: - explicit OmxVideoTrackEncoder(TrackRate aTrackRate); - ~OmxVideoTrackEncoder(); - - already_AddRefed GetMetadata() override; - - nsresult GetEncodedTrack(EncodedFrameContainer& aData) override; - -protected: - nsresult Init(int aWidth, int aHeight, - int aDisplayWidth, int aDisplayHeight) override; - -private: - nsAutoPtr mEncoder; -}; - -class OmxAudioTrackEncoder : public AudioTrackEncoder -{ -public: - OmxAudioTrackEncoder(); - ~OmxAudioTrackEncoder(); - - already_AddRefed GetMetadata() = 0; - - nsresult GetEncodedTrack(EncodedFrameContainer& aData) override; - -protected: - nsresult Init(int aChannels, int aSamplingRate) = 0; - - // Append encoded frames to aContainer. - nsresult AppendEncodedFrames(EncodedFrameContainer& aContainer); - - nsAutoPtr mEncoder; -}; - -class OmxAACAudioTrackEncoder final : public OmxAudioTrackEncoder -{ -public: - OmxAACAudioTrackEncoder() - : OmxAudioTrackEncoder() - {} - - already_AddRefed GetMetadata() override; - -protected: - nsresult Init(int aChannels, int aSamplingRate) override; -}; - -class OmxAMRAudioTrackEncoder final : public OmxAudioTrackEncoder -{ -public: - OmxAMRAudioTrackEncoder() - : OmxAudioTrackEncoder() - {} - - enum { - AMR_NB_SAMPLERATE = 8000, - }; - already_AddRefed GetMetadata() override; - -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/moz.build b/dom/media/encoder/moz.build index eb591bb5937f..0d5cdc16f1bc 100644 --- a/dom/media/encoder/moz.build +++ b/dom/media/encoder/moz.build @@ -25,10 +25,6 @@ UNIFIED_SOURCES += [ 'TrackEncoder.cpp', ] -if CONFIG['MOZ_OMX_ENCODER']: - EXPORTS += ['OmxTrackEncoder.h'] - UNIFIED_SOURCES += ['OmxTrackEncoder.cpp'] - if CONFIG['MOZ_WEBM_ENCODER']: EXPORTS += ['VP8TrackEncoder.h', ] diff --git a/dom/media/moz.build b/dom/media/moz.build index 70c123110ad2..63754c0a8e20 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -54,9 +54,6 @@ if CONFIG['MOZ_FMP4']: if CONFIG['MOZ_WEBRTC']: DIRS += ['bridge'] -if CONFIG['MOZ_OMX_DECODER']: - DIRS += ['omx'] - TEST_DIRS += [ 'compiledtest', 'gtest', @@ -323,9 +320,6 @@ if CONFIG['OS_TARGET'] == 'WINNT': else: DEFINES['WEBRTC_POSIX'] = True -if CONFIG['MOZ_OMX_DECODER']: - DEFINES['MOZ_OMX_DECODER'] = True - if CONFIG['ANDROID_VERSION'] > '15': DEFINES['MOZ_OMX_WEBM_DECODER'] = True diff --git a/dom/media/omx/AudioOffloadPlayer.cpp b/dom/media/omx/AudioOffloadPlayer.cpp deleted file mode 100644 index 9d514ed1e0e0..000000000000 --- a/dom/media/omx/AudioOffloadPlayer.cpp +++ /dev/null @@ -1,758 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "AudioOffloadPlayer.h" -#include "nsComponentManagerUtils.h" -#include "nsITimer.h" -#include "MediaOmxCommonDecoder.h" -#include "mozilla/dom/HTMLMediaElement.h" -#include "VideoUtils.h" -#include "mozilla/dom/power/PowerManagerService.h" -#include "mozilla/dom/WakeLock.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace android; - -namespace mozilla { - -LazyLogModule gAudioOffloadPlayerLog("AudioOffloadPlayer"); -#define AUDIO_OFFLOAD_LOG(type, msg) \ - MOZ_LOG(gAudioOffloadPlayerLog, type, msg) - -// maximum time in paused state when offloading audio decompression. -// When elapsed, the GonkAudioSink is destroyed to allow the audio DSP to power down. -static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll; - -AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) : - mStarted(false), - mPlaying(false), - mReachedEOS(false), - mIsElementVisible(true), - mSampleRate(0), - mStartPosUs(0), - mPositionTimeMediaUs(-1), - mInputBuffer(nullptr) -{ - MOZ_ASSERT(NS_IsMainThread()); - - CHECK(aObserver); -#if ANDROID_VERSION >= 21 - mSessionId = AudioSystem::newAudioUniqueId(); - AudioSystem::acquireAudioSessionId(mSessionId, -1); -#else - mSessionId = AudioSystem::newAudioSessionId(); - AudioSystem::acquireAudioSessionId(mSessionId); -#endif - mAudioSink = new AudioOutput(mSessionId, - IPCThreadState::self()->getCallingUid()); - - nsCOMPtr thread; - MOZ_ALWAYS_SUCCEEDS(NS_GetMainThread(getter_AddRefs(thread))); - mPositionChanged = mOnPositionChanged.Connect( - thread, aObserver, &MediaOmxCommonDecoder::NotifyOffloadPlayerPositionChanged); - mPlaybackEnded = mOnPlaybackEnded.Connect( - thread, aObserver, &MediaDecoder::PlaybackEnded); - mPlayerTearDown = mOnPlayerTearDown.Connect( - thread, aObserver, &MediaOmxCommonDecoder::AudioOffloadTearDown); - mSeekingStarted = mOnSeekingStarted.Connect( - thread, aObserver, &MediaDecoder::SeekingStarted); -} - -AudioOffloadPlayer::~AudioOffloadPlayer() -{ - Reset(); -#if ANDROID_VERSION >= 21 - AudioSystem::releaseAudioSessionId(mSessionId, -1); -#else - AudioSystem::releaseAudioSessionId(mSessionId); -#endif - - // Disconnect the listeners to prevent notifications from reaching - // the MediaOmxCommonDecoder object after shutdown. - mPositionChanged.Disconnect(); - mPlaybackEnded.Disconnect(); - mPlayerTearDown.Disconnect(); - mSeekingStarted.Disconnect(); -} - -void AudioOffloadPlayer::SetSource(const sp &aSource) -{ - MOZ_ASSERT(NS_IsMainThread()); - CHECK(!mSource.get()); - - mSource = aSource; -} - -status_t AudioOffloadPlayer::Start(bool aSourceAlreadyStarted) -{ - MOZ_ASSERT(NS_IsMainThread()); - CHECK(!mStarted); - CHECK(mSource.get()); - - status_t err; - CHECK(mAudioSink.get()); - - if (!aSourceAlreadyStarted) { - err = mSource->start(); - - if (err != OK) { - return err; - } - } - - sp format = mSource->getFormat(); - const char* mime; - int avgBitRate = -1; - int32_t channelMask; - int32_t numChannels; - int64_t durationUs = -1; - audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; - uint32_t flags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; - audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER; - - CHECK(format->findCString(kKeyMIMEType, &mime)); - CHECK(format->findInt32(kKeySampleRate, &mSampleRate)); - CHECK(format->findInt32(kKeyChannelCount, &numChannels)); - format->findInt32(kKeyBitRate, &avgBitRate); - format->findInt64(kKeyDuration, &durationUs); - - if(!format->findInt32(kKeyChannelMask, &channelMask)) { - channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; - } - - if (mapMimeToAudioFormat(audioFormat, mime) != OK) { - AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Couldn't map mime type \"%s\" to a valid " - "AudioSystem::audio_format", mime)); - audioFormat = AUDIO_FORMAT_INVALID; - } - - offloadInfo.duration_us = durationUs; - offloadInfo.sample_rate = mSampleRate; - offloadInfo.channel_mask = channelMask; - offloadInfo.format = audioFormat; - offloadInfo.stream_type = AUDIO_STREAM_MUSIC; - offloadInfo.bit_rate = avgBitRate; - offloadInfo.has_video = false; - offloadInfo.is_streaming = false; - - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("isOffloadSupported: SR=%u, CM=0x%x, " - "Format=0x%x, StreamType=%d, BitRate=%u, duration=%lld us, has_video=%d", - offloadInfo.sample_rate, offloadInfo.channel_mask, offloadInfo.format, - offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, - offloadInfo.has_video)); - - err = mAudioSink->Open(mSampleRate, - numChannels, - channelMask, - audioFormat, - &AudioOffloadPlayer::AudioSinkCallback, - this, - (audio_output_flags_t) flags, - &offloadInfo); - if (err == OK) { - // If the playback is offloaded to h/w we pass the - // HAL some metadata information - // We don't want to do this for PCM because it will be going - // through the AudioFlinger mixer before reaching the hardware - SendMetaDataToHal(mAudioSink, format); - } - mStarted = true; - mPlaying = false; - - return err; -} - -status_t AudioOffloadPlayer::ChangeState(MediaDecoder::PlayState aState) -{ - MOZ_ASSERT(NS_IsMainThread()); - mPlayState = aState; - - switch (mPlayState) { - case MediaDecoder::PLAY_STATE_PLAYING: { - status_t err = Play(); - if (err != OK) { - return err; - } - StartTimeUpdate(); - } break; - - case MediaDecoder::PLAY_STATE_PAUSED: - case MediaDecoder::PLAY_STATE_SHUTDOWN: - // Just pause here during play state shutdown as well to stop playing - // offload track immediately. Resources will be freed by - // MediaOmxCommonDecoder - Pause(); - break; - - case MediaDecoder::PLAY_STATE_ENDED: - Pause(true); - break; - - default: - break; - } - return OK; -} - -static void ResetCallback(nsITimer* aTimer, void* aClosure) -{ - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __FUNCTION__)); - AudioOffloadPlayer* player = static_cast(aClosure); - if (player) { - player->Reset(); - } -} - -void AudioOffloadPlayer::Pause(bool aPlayPendingSamples) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (mStarted) { - CHECK(mAudioSink.get()); - WakeLockCreate(); - - if (aPlayPendingSamples) { - mAudioSink->Stop(); - } else { - mAudioSink->Pause(); - } - mPlaying = false; - } - - if (mResetTimer) { - return; - } - mResetTimer = do_CreateInstance("@mozilla.org/timer;1"); - mResetTimer->InitWithFuncCallback(ResetCallback, - this, - OFFLOAD_PAUSE_MAX_MSECS, - nsITimer::TYPE_ONE_SHOT); -} - -status_t AudioOffloadPlayer::Play() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (mResetTimer) { - mResetTimer->Cancel(); - mResetTimer = nullptr; - WakeLockRelease(); - } - - status_t err = OK; - - if (!mStarted) { - // Last pause timed out and offloaded audio sink was reset. Start it again - err = Start(false); - if (err != OK) { - return err; - } - // Seek to last play position only when there was no seek during last pause - android::Mutex::Autolock autoLock(mLock); - if (!mSeekTarget.IsValid()) { - mSeekTarget = SeekTarget(mPositionTimeMediaUs, - SeekTarget::Accurate, - MediaDecoderEventVisibility::Suppressed); - DoSeek(); - } - } - - if (!mPlaying) { - CHECK(mAudioSink.get()); - err = mAudioSink->Start(); - if (err == OK) { - mPlaying = true; - } - } - - return err; -} - -void AudioOffloadPlayer::Reset() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!mStarted) { - return; - } - - CHECK(mAudioSink.get()); - - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("reset: mPlaying=%d mReachedEOS=%d", - mPlaying, mReachedEOS)); - - mAudioSink->Stop(); - // If we're closing and have reached EOS, we don't want to flush - // the track because if it is offloaded there could be a small - // amount of residual data in the hardware buffer which we must - // play to give gapless playback. - // But if we're resetting when paused or before we've reached EOS - // we can't be doing a gapless playback and there could be a large - // amount of data queued in the hardware if the track is offloaded, - // so we must flush to prevent a track switch being delayed playing - // the buffered data that we don't want now - if (!mPlaying || !mReachedEOS) { - mAudioSink->Flush(); - } - - mAudioSink->Close(); - // Make sure to release any buffer we hold onto so that the - // source is able to stop(). - - if (mInputBuffer) { - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Releasing input buffer")); - - mInputBuffer->release(); - mInputBuffer = nullptr; - } - mSource->stop(); - - IPCThreadState::self()->flushCommands(); - StopTimeUpdate(); - - mReachedEOS = false; - mStarted = false; - mPlaying = false; - mStartPosUs = 0; - - WakeLockRelease(); -} - -RefPtr AudioOffloadPlayer::Seek(SeekTarget aTarget) -{ - MOZ_ASSERT(NS_IsMainThread()); - android::Mutex::Autolock autoLock(mLock); - - mSeekPromise.RejectIfExists(true, __func__); - mSeekTarget = aTarget; - RefPtr p = mSeekPromise.Ensure(__func__); - DoSeek(); - return p; -} - -status_t AudioOffloadPlayer::DoSeek() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mSeekTarget.IsValid()); - CHECK(mAudioSink.get()); - - AUDIO_OFFLOAD_LOG(LogLevel::Debug, - ("DoSeek ( %lld )", mSeekTarget.GetTime().ToMicroseconds())); - - mReachedEOS = false; - mPositionTimeMediaUs = -1; - mStartPosUs = mSeekTarget.GetTime().ToMicroseconds(); - - if (!mSeekPromise.IsEmpty() && - mSeekTarget.mEventVisibility == MediaDecoderEventVisibility::Observable) { - mOnSeekingStarted.Notify(); - } - - if (mPlaying) { - mAudioSink->Pause(); - mAudioSink->Flush(); - mAudioSink->Start(); - - } else { - if (mStarted) { - mAudioSink->Flush(); - } - - if (!mSeekPromise.IsEmpty()) { - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Fake seek complete during pause")); - // We do not reset mSeekTarget here. - MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); - mSeekPromise.Resolve(val, __func__); - } - } - - return OK; -} - -int64_t AudioOffloadPlayer::GetMediaTimeUs() -{ - android::Mutex::Autolock autoLock(mLock); - - int64_t playPosition = 0; - if (mSeekTarget.IsValid()) { - return mSeekTarget.GetTime().ToMicroseconds(); - } - if (!mStarted) { - return mPositionTimeMediaUs; - } - - playPosition = GetOutputPlayPositionUs_l(); - if (!mReachedEOS) { - mPositionTimeMediaUs = playPosition; - } - - return mPositionTimeMediaUs; -} - -int64_t AudioOffloadPlayer::GetOutputPlayPositionUs_l() const -{ - CHECK(mAudioSink.get()); - uint32_t playedSamples = 0; - - mAudioSink->GetPosition(&playedSamples); - - const int64_t playedUs = (static_cast(playedSamples) * 1000000 ) / - mSampleRate; - - // HAL position is relative to the first buffer we sent at mStartPosUs - const int64_t renderedDuration = mStartPosUs + playedUs; - return renderedDuration; -} - -void AudioOffloadPlayer::NotifyAudioEOS() -{ - android::Mutex::Autolock autoLock(mLock); - // We do not reset mSeekTarget here. - if (!mSeekPromise.IsEmpty()) { - MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); - mSeekPromise.Resolve(val, __func__); - } - mOnPlaybackEnded.Notify(); -} - -void AudioOffloadPlayer::NotifyPositionChanged() -{ - mOnPositionChanged.Notify(); -} - -void AudioOffloadPlayer::NotifyAudioTearDown() -{ - // Fallback to state machine. - // state machine's seeks will be done with - // MediaDecoderEventVisibility::Suppressed. - android::Mutex::Autolock autoLock(mLock); - // We do not reset mSeekTarget here. - if (!mSeekPromise.IsEmpty()) { - MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); - mSeekPromise.Resolve(val, __func__); - } - mOnPlayerTearDown.Notify(); -} - -// static -size_t AudioOffloadPlayer::AudioSinkCallback(GonkAudioSink* aAudioSink, - void* aBuffer, - size_t aSize, - void* aCookie, - GonkAudioSink::cb_event_t aEvent) -{ - AudioOffloadPlayer* me = (AudioOffloadPlayer*) aCookie; - - switch (aEvent) { - - case GonkAudioSink::CB_EVENT_FILL_BUFFER: - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Notify Audio position changed")); - me->NotifyPositionChanged(); - return me->FillBuffer(aBuffer, aSize); - - case GonkAudioSink::CB_EVENT_STREAM_END: - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Notify Audio EOS")); - me->mReachedEOS = true; - me->NotifyAudioEOS(); - break; - - case GonkAudioSink::CB_EVENT_TEAR_DOWN: - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Notify Tear down event")); - me->NotifyAudioTearDown(); - break; - - default: - AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Unknown event %d from audio sink", - aEvent)); - break; - } - return 0; -} - -size_t AudioOffloadPlayer::FillBuffer(void* aData, size_t aSize) -{ - CHECK(mAudioSink.get()); - - if (mReachedEOS) { - return 0; - } - - size_t sizeDone = 0; - size_t sizeRemaining = aSize; - int64_t seekTimeUs = -1; - while (sizeRemaining > 0) { - MediaSource::ReadOptions options; - bool refreshSeekTime = false; - { - android::Mutex::Autolock autoLock(mLock); - - if (mSeekTarget.IsValid()) { - seekTimeUs = mSeekTarget.GetTime().ToMicroseconds(); - options.setSeekTo(seekTimeUs); - refreshSeekTime = true; - - if (mInputBuffer) { - mInputBuffer->release(); - mInputBuffer = nullptr; - } - } - } - - if (!mInputBuffer) { - status_t err; - err = mSource->read(&mInputBuffer, &options); - - CHECK((!err && mInputBuffer) || (err && !mInputBuffer)); - - android::Mutex::Autolock autoLock(mLock); - - if (err != OK) { - if (mSeekTarget.IsValid()) { - mSeekTarget.Reset(); - } - AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Error while reading media source %d " - "Ok to receive EOS error at end", err)); - if (!mReachedEOS) { - // After seek there is a possible race condition if - // OffloadThread is observing state_stopping_1 before - // framesReady() > 0. Ensure sink stop is called - // after last buffer is released. This ensures the - // partial buffer is written to the driver before - // stopping one is observed.The drawback is that - // there will be an unnecessary call to the parser - // after parser signalled EOS. - if (sizeDone > 0) { - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("send Partial buffer down")); - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("skip calling stop till next" - " fillBuffer")); - break; - } - // no more buffers to push - stop() and wait for STREAM_END - // don't set mReachedEOS until stream end received - mAudioSink->Stop(); - } - break; - } - - if(mInputBuffer->range_length() != 0) { - CHECK(mInputBuffer->meta_data()->findInt64( - kKeyTime, &mPositionTimeMediaUs)); - } - - if (mSeekTarget.IsValid() && - seekTimeUs == mSeekTarget.GetTime().ToMicroseconds()) { - MOZ_ASSERT(mSeekTarget.IsValid()); - mSeekTarget.Reset(); - if (!mSeekPromise.IsEmpty()) { - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("FillBuffer posting SEEK_COMPLETE")); - MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); - mSeekPromise.Resolve(val, __func__); - } - } else if (mSeekTarget.IsValid()) { - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("seek is updated during unlocking mLock")); - } - - if (refreshSeekTime) { - NotifyPositionChanged(); - - // need to adjust the mStartPosUs for offload decoding since parser - // might not be able to get the exact seek time requested. - mStartPosUs = mPositionTimeMediaUs; - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Adjust seek time to: %.2f", - mStartPosUs / 1E6)); - } - } - - if (mInputBuffer->range_length() == 0) { - mInputBuffer->release(); - mInputBuffer = nullptr; - continue; - } - - size_t copy = sizeRemaining; - if (copy > mInputBuffer->range_length()) { - copy = mInputBuffer->range_length(); - } - - memcpy((char *)aData + sizeDone, - (const char *)mInputBuffer->data() + mInputBuffer->range_offset(), - copy); - - mInputBuffer->set_range(mInputBuffer->range_offset() + copy, - mInputBuffer->range_length() - copy); - - sizeDone += copy; - sizeRemaining -= copy; - } - return sizeDone; -} - -void AudioOffloadPlayer::SetElementVisibility(bool aIsVisible) -{ - MOZ_ASSERT(NS_IsMainThread()); - mIsElementVisible = aIsVisible; - if (mIsElementVisible) { - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Element is visible. Start time update")); - StartTimeUpdate(); - } -} - -static void TimeUpdateCallback(nsITimer* aTimer, void* aClosure) -{ - AudioOffloadPlayer* player = static_cast(aClosure); - player->TimeUpdate(); -} - -void AudioOffloadPlayer::TimeUpdate() -{ - MOZ_ASSERT(NS_IsMainThread()); - TimeStamp now = TimeStamp::Now(); - - // If TIMEUPDATE_MS has passed since the last fire update event fired, fire - // another timeupdate event. - if ((mLastFireUpdateTime.IsNull() || - now - mLastFireUpdateTime >= - TimeDuration::FromMilliseconds(TIMEUPDATE_MS))) { - mLastFireUpdateTime = now; - NotifyPositionChanged(); - } - - if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING || !mIsElementVisible) { - StopTimeUpdate(); - } -} - -nsresult AudioOffloadPlayer::StartTimeUpdate() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mTimeUpdateTimer) { - return NS_OK; - } - - mTimeUpdateTimer = do_CreateInstance("@mozilla.org/timer;1"); - return mTimeUpdateTimer->InitWithFuncCallback(TimeUpdateCallback, - this, - TIMEUPDATE_MS, - nsITimer::TYPE_REPEATING_SLACK); -} - -nsresult AudioOffloadPlayer::StopTimeUpdate() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!mTimeUpdateTimer) { - return NS_OK; - } - - nsresult rv = mTimeUpdateTimer->Cancel(); - mTimeUpdateTimer = nullptr; - return rv; -} - -MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mSeekTarget.IsValid()) { - return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING; - } else if (mPlayState == MediaDecoder::PLAY_STATE_ENDED) { - return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE; - } else { - return MediaDecoderOwner::NEXT_FRAME_AVAILABLE; - } -} - -void AudioOffloadPlayer::SendMetaDataToHal(sp& aSink, - const sp& aMeta) -{ - int32_t sampleRate = 0; - int32_t bitRate = 0; - int32_t channelMask = 0; - int32_t delaySamples = 0; - int32_t paddingSamples = 0; - CHECK(aSink.get()); - - AudioParameter param = AudioParameter(); - - if (aMeta->findInt32(kKeySampleRate, &sampleRate)) { - param.addInt(String8(AUDIO_OFFLOAD_CODEC_SAMPLE_RATE), sampleRate); - } - if (aMeta->findInt32(kKeyChannelMask, &channelMask)) { - param.addInt(String8(AUDIO_OFFLOAD_CODEC_NUM_CHANNEL), channelMask); - } - if (aMeta->findInt32(kKeyBitRate, &bitRate)) { - param.addInt(String8(AUDIO_OFFLOAD_CODEC_AVG_BIT_RATE), bitRate); - } - if (aMeta->findInt32(kKeyEncoderDelay, &delaySamples)) { - param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), delaySamples); - } - if (aMeta->findInt32(kKeyEncoderPadding, &paddingSamples)) { - param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples); - } - - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("SendMetaDataToHal: bitRate %d," - " sampleRate %d, chanMask %d, delaySample %d, paddingSample %d", bitRate, - sampleRate, channelMask, delaySamples, paddingSamples)); - - aSink->SetParameters(param.toString()); - return; -} - -void AudioOffloadPlayer::SetVolume(double aVolume) -{ - MOZ_ASSERT(NS_IsMainThread()); - CHECK(mAudioSink.get()); - mAudioSink->SetVolume((float) aVolume); -} - -void AudioOffloadPlayer::WakeLockCreate() -{ - MOZ_ASSERT(NS_IsMainThread()); - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __FUNCTION__)); - if (!mWakeLock) { - RefPtr pmService = - dom::power::PowerManagerService::GetInstance(); - NS_ENSURE_TRUE_VOID(pmService); - - ErrorResult rv; - mWakeLock = pmService->NewWakeLock(NS_LITERAL_STRING("cpu"), nullptr, rv); - } -} - -void AudioOffloadPlayer::WakeLockRelease() -{ - MOZ_ASSERT(NS_IsMainThread()); - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __FUNCTION__)); - if (mWakeLock) { - ErrorResult rv; - mWakeLock->Unlock(rv); - mWakeLock = nullptr; - } -} - -} // namespace mozilla diff --git a/dom/media/omx/AudioOffloadPlayer.h b/dom/media/omx/AudioOffloadPlayer.h deleted file mode 100644 index e8b0b009d6ad..000000000000 --- a/dom/media/omx/AudioOffloadPlayer.h +++ /dev/null @@ -1,273 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AUDIO_OFFLOAD_PLAYER_H_ -#define AUDIO_OFFLOAD_PLAYER_H_ - -#include -#include -#include -#include -#include - -#include "AudioOutput.h" -#include "AudioOffloadPlayerBase.h" -#include "MediaDecoderOwner.h" -#include "MediaEventSource.h" - -namespace mozilla { - -namespace dom { -class WakeLock; -} - -/** - * AudioOffloadPlayer adds support for audio tunneling to a digital signal - * processor (DSP) in the device chipset. With tunneling, audio decoding is - * off-loaded to the DSP, waking the application processor less often and using - * less battery - * - * This depends on offloading capability provided by Android KK AudioTrack class - * - * Audio playback is based on pull mechanism, whenever audio sink needs - * data, FillBuffer() will read data from compressed audio source and provide - * it to the sink - * - * Also this class passes state changes (play/pause/seek) from - * MediaOmxCommonDecoder to GonkAudioSink as well as provide GonkAudioSink status - * (position changed, playback ended, seek complete, audio tear down) back to - * MediaOmxCommonDecoder - * - * It acts as a bridge between MediaOmxCommonDecoder and GonkAudioSink during - * offload playback - */ - -class MediaOmxCommonDecoder; - -class AudioOffloadPlayer : public AudioOffloadPlayerBase -{ - typedef android::Mutex Mutex; - typedef android::MetaData MetaData; - typedef android::status_t status_t; - typedef android::AudioTrack AudioTrack; - typedef android::MediaBuffer MediaBuffer; - typedef android::MediaSource MediaSource; - -public: - enum { - REACHED_EOS, - SEEK_COMPLETE - }; - - AudioOffloadPlayer(MediaOmxCommonDecoder* aDecoder); - - ~AudioOffloadPlayer(); - - // Caller retains ownership of "aSource". - void SetSource(const android::sp &aSource) override; - - // Start the source if it's not already started and open the GonkAudioSink to - // create an offloaded audio track - status_t Start(bool aSourceAlreadyStarted = false) override; - - status_t ChangeState(MediaDecoder::PlayState aState) override; - - void SetVolume(double aVolume) override; - - int64_t GetMediaTimeUs() override; - - // To update progress bar when the element is visible - void SetElementVisibility(bool aIsVisible) override; - - // Update ready state based on current play state. Not checking data - // availability since offloading is currently done only when whole compressed - // data is available - MediaDecoderOwner::NextFrameStatus GetNextFrameStatus() override; - - RefPtr Seek(SeekTarget aTarget) override; - - void TimeUpdate(); - - // Close the audio sink, stop time updates, frees the input buffers - void Reset(); - -private: - // Set when audio source is started and GonkAudioSink is initialized - // Used only in main thread - bool mStarted; - - // Set when audio sink is started. i.e. playback started - // Used only in main thread - bool mPlaying; - - // Once playback reached end of stream (last ~100ms), position provided by DSP - // may be reset/corrupted. This bool is used to avoid that. - // Used in main thread and offload callback thread, protected by Mutex - // mLock - bool mReachedEOS; - - // Set when the HTML Audio Element is visible to the user. - // Used only in main thread - bool mIsElementVisible; - - // Session id given by Android::AudioSystem and used while creating audio sink - // Used only in main thread - int mSessionId; - - // Sample rate of current audio track. Used only in main thread - int mSampleRate; - - // After seeking, positions returned by offlaoded tracks (DSP) will be - // relative to the seeked position. And seeked position may be slightly - // different than given mSeekTimeUs, if audio source cannot find a frame at - // that position. Store seeked position in mStartPosUs and provide - // mStartPosUs + GetPosition() (i.e. absolute position) to - // MediaOmxCommonDecoder - // Used in main thread and offload callback thread, protected by Mutex - // mLock - int64_t mStartPosUs; - - // The target of current seek when there is a request to seek - // Used in main thread and offload callback thread, protected by Mutex - // mLock - SeekTarget mSeekTarget; - - // MozPromise of current seek. - // Used in main thread and offload callback thread, protected by Mutex - // mLock - MozPromiseHolder mSeekPromise; - - // Positions obtained from offlaoded tracks (DSP) - // Used in main thread and offload callback thread, protected by Mutex - // mLock - int64_t mPositionTimeMediaUs; - - // State obtained from MediaOmxCommonDecoder. Used only in main thread - MediaDecoder::PlayState mPlayState; - - // Protect accessing audio position related variables between main thread and - // offload callback thread - Mutex mLock; - - // Compressed audio source. - // Used in main thread first and later in offload callback thread - android::sp mSource; - - // Audio sink wrapper to access offloaded audio tracks - // Used in main thread and offload callback thread - // Race conditions are protected in underlying Android::AudioTrack class - android::sp mAudioSink; - - // Buffer used to get date from audio source. Used in offload callback thread - MediaBuffer* mInputBuffer; - - TimeStamp mLastFireUpdateTime; - - // Timer to trigger position changed events - nsCOMPtr mTimeUpdateTimer; - - // Timer to reset GonkAudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS. - // It is triggered in Pause() and canceled when there is a Play() within - // OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed. - nsCOMPtr mResetTimer; - - // To avoid device suspend when mResetTimer is going to be triggered. - // Used only from main thread so no lock is needed. - RefPtr mWakeLock; - - MediaEventProducer mOnPositionChanged; - MediaEventProducer mOnPlaybackEnded; - MediaEventProducer mOnPlayerTearDown; - MediaEventProducer mOnSeekingStarted; - MediaEventListener mPositionChanged; - MediaEventListener mPlaybackEnded; - MediaEventListener mPlayerTearDown; - MediaEventListener mSeekingStarted; - - // Provide the playback position in microseconds from total number of - // frames played by audio track - int64_t GetOutputPlayPositionUs_l() const; - - // Fill the buffer given by audio sink with data from compressed audio - // source. Also handles the seek by seeking audio source and stop the sink in - // case of error - size_t FillBuffer(void *aData, size_t aSize); - - // Called by GonkAudioSink when it needs data, to notify EOS or tear down event - static size_t AudioSinkCallback(GonkAudioSink *aAudioSink, - void *aData, - size_t aSize, - void *aMe, - GonkAudioSink::cb_event_t aEvent); - - bool IsSeeking(); - - // Set mSeekTarget to the given position and restart the sink. Actual seek - // happens in FillBuffer(). If mSeekPromise is not empty, send - // SeekingStarted event always and SeekingStopped event when the play state is - // paused to MediaDecoder. - // When decoding and playing happens separately, if there is a seek during - // pause, we can decode and keep data ready. - // In case of offload player, no way to seek during pause. So just fake that - // seek is done. - status_t DoSeek(); - - // Start/Resume the audio sink so that callback will start being called to get - // compressed data - status_t Play(); - - // Stop the audio sink if we need to play till we drain the current buffer. - // or Pause the sink in case we should stop playing immediately - void Pause(bool aPlayPendingSamples = false); - - // When audio is offloaded, application processor wakes up less frequently - // (>1sec) But when Player UI is visible we need to update progress bar - // atleast once in 250ms. Start a timer when player UI becomes visible or - // audio starts playing to send UpdateLogicalPosition events once in 250ms. - // Stop the timer when UI goes invisible or play state is not playing. - // Also make sure timer functions are always called from main thread - nsresult StartTimeUpdate(); - nsresult StopTimeUpdate(); - - void WakeLockCreate(); - void WakeLockRelease(); - - // Notify end of stream by sending PlaybackEnded event to observer - // (i.e.MediaDecoder) - void NotifyAudioEOS(); - - // Notify position changed event by sending UpdateLogicalPosition event to - // observer - void NotifyPositionChanged(); - - // Offloaded audio track is invalidated due to usecase change. Notify - // MediaDecoder to re-evaluate offloading options - void NotifyAudioTearDown(); - - // Send information from MetaData to the HAL via GonkAudioSink - void SendMetaDataToHal(android::sp& aSink, - const android::sp& aMeta); - - AudioOffloadPlayer(const AudioOffloadPlayer &); - AudioOffloadPlayer &operator=(const AudioOffloadPlayer &); -}; - -} // namespace mozilla - -#endif // AUDIO_OFFLOAD_PLAYER_H_ diff --git a/dom/media/omx/AudioOffloadPlayerBase.h b/dom/media/omx/AudioOffloadPlayerBase.h deleted file mode 100644 index 352993873e0b..000000000000 --- a/dom/media/omx/AudioOffloadPlayerBase.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AUDIO_OFFLOAD_PLAYER_BASE_H_ -#define AUDIO_OFFLOAD_PLAYER_BASE_H_ - -#include "MediaDecoder.h" -#include "MediaDecoderOwner.h" - -namespace mozilla { - -/** - * AudioOffloadPlayer interface class which has funtions used by MediaOmxDecoder - * This is to reduce the dependency of AudioOffloadPlayer in MediaOmxDecoder - */ -class AudioOffloadPlayerBase -{ - typedef android::status_t status_t; - typedef android::MediaSource MediaSource; - -public: - virtual ~AudioOffloadPlayerBase() {}; - - // Caller retains ownership of "aSource". - virtual void SetSource(const android::sp &aSource) {} - - // Start the source if it's not already started and open the AudioSink to - // create an offloaded audio track - virtual status_t Start(bool aSourceAlreadyStarted = false) - { - return android::NO_INIT; - } - - virtual status_t ChangeState(MediaDecoder::PlayState aState) - { - return android::NO_INIT; - } - - virtual void SetVolume(double aVolume) {} - - virtual int64_t GetMediaTimeUs() { return 0; } - - // To update progress bar when the element is visible - virtual void SetElementVisibility(bool aIsVisible) {} - - // Update ready state based on current play state. Not checking data - // availability since offloading is currently done only when whole compressed - // data is available - virtual MediaDecoderOwner::NextFrameStatus GetNextFrameStatus() - { - return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE; - } - - virtual RefPtr Seek(SeekTarget aTarget) = 0; -}; - -} // namespace mozilla - -#endif // AUDIO_OFFLOAD_PLAYER_BASE_H_ diff --git a/dom/media/omx/AudioOutput.cpp b/dom/media/omx/AudioOutput.cpp deleted file mode 100644 index 132d09d77c2d..000000000000 --- a/dom/media/omx/AudioOutput.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "AudioOutput.h" - -#include "mozilla/Logging.h" - -namespace mozilla { - -extern LazyLogModule gAudioOffloadPlayerLog; -#define AUDIO_OFFLOAD_LOG(type, msg) \ - MOZ_LOG(gAudioOffloadPlayerLog, type, msg) - -using namespace android; - -AudioOutput::AudioOutput(int aSessionId, int aUid) : - mCallbackCookie(nullptr), - mCallback(nullptr), - mCallbackData(nullptr), - mUid(aUid), - mSessionId(aSessionId) -{ -} - -AudioOutput::~AudioOutput() -{ - Close(); -} - -ssize_t AudioOutput::FrameSize() const -{ - if (!mTrack.get()) { - return NO_INIT; - } - return mTrack->frameSize(); -} - -status_t AudioOutput::GetPosition(uint32_t *aPosition) const -{ - if (!mTrack.get()) { - return NO_INIT; - } - return mTrack->getPosition(aPosition); -} - -status_t AudioOutput::SetVolume(float aVolume) const -{ - if (!mTrack.get()) { - return NO_INIT; - } - return mTrack->setVolume(aVolume); -} - -status_t AudioOutput::SetParameters(const String8& aKeyValuePairs) -{ - if (!mTrack.get()) { - return NO_INIT; - } - return mTrack->setParameters(aKeyValuePairs); -} - -status_t AudioOutput::Open(uint32_t aSampleRate, - int aChannelCount, - audio_channel_mask_t aChannelMask, - audio_format_t aFormat, - AudioCallback aCb, - void* aCookie, - audio_output_flags_t aFlags, - const audio_offload_info_t *aOffloadInfo) -{ - mCallback = aCb; - mCallbackCookie = aCookie; - - if (((aFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) || !aCb || - !aOffloadInfo) { - return BAD_VALUE; - } - - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", - aSampleRate, aChannelCount, aChannelMask, aFormat, mSessionId, aFlags)); - - if (aChannelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) { - aChannelMask = audio_channel_out_mask_from_count(aChannelCount); - if (0 == aChannelMask) { - AUDIO_OFFLOAD_LOG(LogLevel::Error, ("open() error, can\'t derive mask for" - " %d audio channels", aChannelCount)); - return NO_INIT; - } - } - - sp t; - CallbackData* newcbd = new CallbackData(this); - - t = new AudioTrack( - AUDIO_STREAM_MUSIC, - aSampleRate, - aFormat, - aChannelMask, - 0, // Offloaded tracks will get frame count from AudioFlinger - aFlags, - CallbackWrapper, - newcbd, - 0, // notification frames - mSessionId, - AudioTrack::TRANSFER_CALLBACK, - aOffloadInfo, - mUid); - - if ((!t.get()) || (t->initCheck() != NO_ERROR)) { - AUDIO_OFFLOAD_LOG(LogLevel::Error, ("Unable to create audio track")); - delete newcbd; - return NO_INIT; - } - - mCallbackData = newcbd; - t->setVolume(1.0); - - mTrack = t; - return NO_ERROR; -} - -status_t AudioOutput::Start() -{ - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__)); - if (!mTrack.get()) { - return NO_INIT; - } - mTrack->setVolume(1.0); - return mTrack->start(); -} - -void AudioOutput::Stop() -{ - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__)); - if (mTrack.get()) { - mTrack->stop(); - } -} - -void AudioOutput::Flush() -{ - if (mTrack.get()) { - mTrack->flush(); - } -} - -void AudioOutput::Pause() -{ - if (mTrack.get()) { - mTrack->pause(); - } -} - -void AudioOutput::Close() -{ - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__)); - mTrack.clear(); - - delete mCallbackData; - mCallbackData = nullptr; -} - -// static -void AudioOutput::CallbackWrapper(int aEvent, void* aCookie, void* aInfo) -{ - CallbackData* data = (CallbackData*) aCookie; - data->Lock(); - AudioOutput* me = data->GetOutput(); - AudioTrack::Buffer* buffer = (AudioTrack::Buffer*) aInfo; - if (!me) { - // no output set, likely because the track was scheduled to be reused - // by another player, but the format turned out to be incompatible. - data->Unlock(); - if (buffer) { - buffer->size = 0; - } - return; - } - - switch(aEvent) { - - case AudioTrack::EVENT_MORE_DATA: { - - size_t actualSize = (*me->mCallback)(me, buffer->raw, buffer->size, - me->mCallbackCookie, CB_EVENT_FILL_BUFFER); - - if (actualSize == 0 && buffer->size > 0) { - // We've reached EOS but the audio track is not stopped yet, - // keep playing silence. - memset(buffer->raw, 0, buffer->size); - actualSize = buffer->size; - } - - buffer->size = actualSize; - } break; - - case AudioTrack::EVENT_STREAM_END: - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Callback wrapper: EVENT_STREAM_END")); - (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */, - me->mCallbackCookie, CB_EVENT_STREAM_END); - break; - - case AudioTrack::EVENT_NEW_IAUDIOTRACK : - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("Callback wrapper: EVENT_TEAR_DOWN")); - (*me->mCallback)(me, nullptr /* buffer */, 0 /* size */, - me->mCallbackCookie, CB_EVENT_TEAR_DOWN); - break; - - default: - AUDIO_OFFLOAD_LOG(LogLevel::Debug, ("received unknown event type: %d in" - " Callback wrapper!", aEvent)); - break; - } - - data->Unlock(); -} - -} // namespace mozilla diff --git a/dom/media/omx/AudioOutput.h b/dom/media/omx/AudioOutput.h deleted file mode 100644 index 68fc71f5910c..000000000000 --- a/dom/media/omx/AudioOutput.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef AUDIOOUTPUT_H_ -#define AUDIOOUTPUT_H_ - -#include -#include -#include - -#include "GonkAudioSink.h" - -namespace mozilla { - -/** - * Stripped version of Android KK MediaPlayerService::AudioOutput class - * Android MediaPlayer uses AudioOutput as a wrapper to handle - * Android::AudioTrack - * Similarly to ease handling offloaded tracks, part of AudioOutput is used here - */ -class AudioOutput : public GonkAudioSink -{ - typedef android::Mutex Mutex; - typedef android::String8 String8; - typedef android::status_t status_t; - typedef android::AudioTrack AudioTrack; - - class CallbackData; - -public: - AudioOutput(int aSessionId, int aUid); - virtual ~AudioOutput(); - - ssize_t FrameSize() const override; - status_t GetPosition(uint32_t* aPosition) const override; - status_t SetVolume(float aVolume) const override; - status_t SetParameters(const String8& aKeyValuePairs) override; - - // Creates an offloaded audio track with the given parameters - // TODO: Try to recycle audio tracks instead of creating new audio tracks - // every time - status_t Open(uint32_t aSampleRate, - int aChannelCount, - audio_channel_mask_t aChannelMask, - audio_format_t aFormat, - AudioCallback aCb, - void* aCookie, - audio_output_flags_t aFlags = AUDIO_OUTPUT_FLAG_NONE, - const audio_offload_info_t* aOffloadInfo = nullptr) override; - - status_t Start() override; - void Stop() override; - void Flush() override; - void Pause() override; - void Close() override; - -private: - static void CallbackWrapper(int aEvent, void* aMe, void* aInfo); - - android::sp mTrack; - void* mCallbackCookie; - AudioCallback mCallback; - CallbackData* mCallbackData; - - // Uid of the current process, need to create audio track - int mUid; - - // Session id given by Android::AudioSystem and used to create audio track - int mSessionId; - - // CallbackData is what is passed to the AudioTrack as the "user" data. - // We need to be able to target this to a different Output on the fly, - // so we can't use the Output itself for this. - class CallbackData - { - public: - CallbackData(AudioOutput* aCookie) - { - mData = aCookie; - } - AudioOutput* GetOutput() { return mData;} - void SetOutput(AudioOutput* aNewcookie) { mData = aNewcookie; } - // Lock/Unlock are used by the callback before accessing the payload of - // this object - void Lock() { mLock.lock(); } - void Unlock() { mLock.unlock(); } - private: - AudioOutput* mData; - mutable Mutex mLock; - DISALLOW_EVIL_CONSTRUCTORS(CallbackData); - }; -}; // AudioOutput - -} // namespace mozilla - -#endif /* AUDIOOUTPUT_H_ */ diff --git a/dom/media/omx/GonkAudioSink.h b/dom/media/omx/GonkAudioSink.h deleted file mode 100644 index 83efb61bec1b..000000000000 --- a/dom/media/omx/GonkAudioSink.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* - * Copyright (c) 2014 The Linux Foundation. All rights reserved. - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GONK_AUDIO_SINK_H_ -#define GONK_AUDIO_SINK_H_ - -#include -#include -#include - -#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4 -#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200 -#define DEFAULT_AUDIOSINK_SAMPLERATE 44100 - -// when the channel mask isn't known, use the channel count to derive a mask in -// AudioSink::open() -#define CHANNEL_MASK_USE_CHANNEL_ORDER 0 - -namespace mozilla { - -/** - * AudioSink: abstraction layer for audio output - * Stripped version of Android KK MediaPlayerBase::AudioSink class - */ - -class GonkAudioSink : public android::RefBase -{ - typedef android::String8 String8; - typedef android::status_t status_t; - -public: - enum cb_event_t { - CB_EVENT_FILL_BUFFER, // Request to write more data to buffer. - CB_EVENT_STREAM_END, // Sent after all the buffers queued in AF and HW - // are played back (after stop is called) - CB_EVENT_TEAR_DOWN // The AudioTrack was invalidated due to usecase - // change. Need to re-evaluate offloading options - }; - - // Callback returns the number of bytes actually written to the buffer. - typedef size_t (*AudioCallback)(GonkAudioSink* aAudioSink, - void* aBuffer, - size_t aSize, - void* aCookie, - cb_event_t aEvent); - virtual ~GonkAudioSink() {} - virtual ssize_t FrameSize() const = 0; - virtual status_t GetPosition(uint32_t* aPosition) const = 0; - virtual status_t SetVolume(float aVolume) const = 0; - virtual status_t SetParameters(const String8& aKeyValuePairs) - { - return android::NO_ERROR; - } - - virtual status_t Open(uint32_t aSampleRate, - int aChannelCount, - audio_channel_mask_t aChannelMask, - audio_format_t aFormat=AUDIO_FORMAT_PCM_16_BIT, - AudioCallback aCb = nullptr, - void* aCookie = nullptr, - audio_output_flags_t aFlags = AUDIO_OUTPUT_FLAG_NONE, - const audio_offload_info_t* aOffloadInfo = nullptr) = 0; - - virtual status_t Start() = 0; - virtual void Stop() = 0; - virtual void Flush() = 0; - virtual void Pause() = 0; - virtual void Close() = 0; -}; - -} // namespace mozilla - -#endif // GONK_AUDIO_SINK_H_ diff --git a/dom/media/omx/I420ColorConverterHelper.cpp b/dom/media/omx/I420ColorConverterHelper.cpp deleted file mode 100644 index f1e248499d2a..000000000000 --- a/dom/media/omx/I420ColorConverterHelper.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "I420ColorConverterHelper.h" - -#include - -#include "mozilla/Logging.h" - -mozilla::LazyLogModule gI420ColorConverterHelperLog("I420ColorConverterHelper"); -#define LOG(msg...) MOZ_LOG(gI420ColorConverterHelperLog, mozilla::LogLevel::Warning, (msg)) - -namespace android { - -I420ColorConverterHelper::I420ColorConverterHelper() - : mHandle(nullptr) - , mConverter({nullptr, nullptr, nullptr, nullptr, nullptr}) -{ -} - -I420ColorConverterHelper::~I420ColorConverterHelper() -{ - RWLock::AutoWLock awl(mLock); - unloadLocked(); -} - -// Prerequisite: a writer-lock should be held -bool -I420ColorConverterHelper::loadLocked() -{ - if (loadedLocked()) { - return true; - } - unloadLocked(); - - // Open the shared library - mHandle = dlopen("libI420colorconvert.so", RTLD_NOW); - if (mHandle == nullptr) { - LOG("libI420colorconvert.so not found"); - return false; - } - - // Find the entry point - // Pointer to function with signature - // void getI420ColorConverter(II420ColorConverter *converter) - typedef int (* getConverterFn)(II420ColorConverter *converter); - getConverterFn getI420ColorConverter = - (getConverterFn) dlsym(mHandle, "getI420ColorConverter"); - if (getI420ColorConverter == nullptr) { - LOG("Cannot load getI420ColorConverter from libI420colorconvert.so"); - unloadLocked(); - return false; - } - - // Fill the function pointers. - getI420ColorConverter(&mConverter); - if (mConverter.getDecoderOutputFormat == nullptr || - mConverter.convertDecoderOutputToI420 == nullptr || - mConverter.getEncoderInputFormat == nullptr || - mConverter.convertI420ToEncoderInput == nullptr || - mConverter.getEncoderInputBufferInfo == nullptr) { - LOG("Failed to initialize I420 color converter"); - unloadLocked(); - return false; - } - - return true; -} - -// Prerequisite: a reader-lock or a writer-lock should be held -bool -I420ColorConverterHelper::loadedLocked() const -{ - if (mHandle == nullptr || - mConverter.getDecoderOutputFormat == nullptr || - mConverter.convertDecoderOutputToI420 == nullptr || - mConverter.getEncoderInputFormat == nullptr || - mConverter.convertI420ToEncoderInput == nullptr || - mConverter.getEncoderInputBufferInfo == nullptr) { - return false; - } - return true; -} - -// Prerequisite: a writer-lock should be held -void -I420ColorConverterHelper::unloadLocked() -{ - if (mHandle != nullptr) { - dlclose(mHandle); - } - mHandle = nullptr; - mConverter.getDecoderOutputFormat = nullptr; - mConverter.convertDecoderOutputToI420 = nullptr; - mConverter.getEncoderInputFormat = nullptr; - mConverter.convertI420ToEncoderInput = nullptr; - mConverter.getEncoderInputBufferInfo = nullptr; -} - -bool -I420ColorConverterHelper::ensureLoaded() -{ - { - RWLock::AutoRLock arl(mLock); - // Check whether the library has been loaded or not. - if (loadedLocked()) { - return true; - } - } - - { - RWLock::AutoWLock awl(mLock); - // Check whether the library has been loaded or not on other threads. - if (loadedLocked()) { - return true; - } - - // Reload the library - unloadLocked(); - if (loadLocked()) { - return true; - } - - // Reset the library - unloadLocked(); - } - - return false; -} - -int -I420ColorConverterHelper::getDecoderOutputFormat() -{ - if (!ensureLoaded()) { - return -1; - } - - RWLock::AutoRLock arl(mLock); - if (mConverter.getDecoderOutputFormat != nullptr) { - return mConverter.getDecoderOutputFormat(); - } - return -1; -} - -int -I420ColorConverterHelper::convertDecoderOutputToI420( - void* decoderBits, int decoderWidth, int decoderHeight, - ARect decoderRect, void* dstBits) -{ - if (!ensureLoaded()) { - return -1; - } - - RWLock::AutoRLock arl(mLock); - if (mConverter.convertDecoderOutputToI420 != nullptr) { - return mConverter.convertDecoderOutputToI420(decoderBits, - decoderWidth, decoderHeight, decoderRect, dstBits); - } - return -1; -} - -int -I420ColorConverterHelper::getEncoderInputFormat() -{ - if (!ensureLoaded()) { - return -1; - } - - RWLock::AutoRLock arl(mLock); - if (mConverter.getEncoderInputFormat != nullptr) { - return mConverter.getEncoderInputFormat(); - } - return -1; -} - -int -I420ColorConverterHelper::convertI420ToEncoderInput(void* aSrcBits, - int aSrcWidth, - int aSrcHeight, - int aEncoderWidth, - int aEncoderHeight, - ARect aEncoderRect, - void* aEncoderBits) -{ - if (!ensureLoaded()) { - return -1; - } - - RWLock::AutoRLock arl(mLock); - if (mConverter.convertI420ToEncoderInput != nullptr) { - return mConverter.convertI420ToEncoderInput(aSrcBits, aSrcWidth, aSrcHeight, - aEncoderWidth, aEncoderHeight, aEncoderRect, aEncoderBits); - } - return -1; -} - -int -I420ColorConverterHelper::getEncoderInputBufferInfo(int aSrcWidth, - int aSrcHeight, - int* aEncoderWidth, - int* aEncoderHeight, - ARect* aEncoderRect, - int* aEncoderBufferSize) -{ - if (!ensureLoaded()) { - return -1; - } - - RWLock::AutoRLock arl(mLock); - if (mConverter.getEncoderInputBufferInfo != nullptr) { - return mConverter.getEncoderInputBufferInfo(aSrcWidth, aSrcHeight, - aEncoderWidth, aEncoderHeight, aEncoderRect, aEncoderBufferSize); - } - return -1; -} - -} // namespace android diff --git a/dom/media/omx/I420ColorConverterHelper.h b/dom/media/omx/I420ColorConverterHelper.h deleted file mode 100644 index 9496bb1233db..000000000000 --- a/dom/media/omx/I420ColorConverterHelper.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 I420_COLOR_CONVERTER_HELPER_H -#define I420_COLOR_CONVERTER_HELPER_H - -#include -#include - -#include - -namespace android { - -class I420ColorConverterHelper { -public: - I420ColorConverterHelper(); - ~I420ColorConverterHelper(); - - int getDecoderOutputFormat(); - - int convertDecoderOutputToI420(void* aDecoderBits, - int aDecoderWidth, - int aDecoderHeight, - ARect aDecoderRect, - void* aDstBits); - - int getEncoderInputFormat(); - - int convertI420ToEncoderInput(void* aSrcBits, - int aSrcWidth, - int aSrcHeight, - int aEncoderWidth, - int aEncoderHeight, - ARect aEncoderRect, - void* aEncoderBits); - - int getEncoderInputBufferInfo(int aSrcWidth, - int aSrcHeight, - int* aEncoderWidth, - int* aEncoderHeight, - ARect* aEncoderRect, - int* aEncoderBufferSize); - -private: - mutable RWLock mLock; - void *mHandle; - II420ColorConverter mConverter; - - bool loadLocked(); - bool loadedLocked() const; - void unloadLocked(); - - bool ensureLoaded(); - - I420ColorConverterHelper(const I420ColorConverterHelper &) = delete; - const I420ColorConverterHelper &operator=(const I420ColorConverterHelper &) = delete; -}; - -} // namespace android - -#endif // I420_COLOR_CONVERTER_HELPER_H diff --git a/dom/media/omx/MPAPI.h b/dom/media/omx/MPAPI.h deleted file mode 100644 index 48b1b040eec3..000000000000 --- a/dom/media/omx/MPAPI.h +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(MPAPI_h_) -#define MPAPI_h_ - -#include -#include "mozilla/layers/TextureClient.h" - -namespace MPAPI { - -struct VideoPlane { - VideoPlane() : - mData(nullptr), - mStride(0), - mWidth(0), - mHeight(0), - mOffset(0), - mSkip(0) - {} - - void *mData; - int32_t mStride; - int32_t mWidth; - int32_t mHeight; - int32_t mOffset; - int32_t mSkip; -}; - -struct VideoFrame { - int64_t mTimeUs; - bool mKeyFrame; - bool mShouldSkip; - void *mData; - size_t mSize; - int32_t mStride; - int32_t mSliceHeight; - int32_t mRotation; - VideoPlane Y; - VideoPlane Cb; - VideoPlane Cr; - RefPtr mGraphicBuffer; - - VideoFrame() : - mTimeUs(0), - mKeyFrame(false), - mShouldSkip(false), - mData(nullptr), - mSize(0), - mStride(0), - mSliceHeight(0), - mRotation(0) - {} - - void Set(int64_t aTimeUs, bool aKeyFrame, - void *aData, size_t aSize, int32_t aStride, int32_t aSliceHeight, int32_t aRotation, - void *aYData, int32_t aYStride, int32_t aYWidth, int32_t aYHeight, int32_t aYOffset, int32_t aYSkip, - void *aCbData, int32_t aCbStride, int32_t aCbWidth, int32_t aCbHeight, int32_t aCbOffset, int32_t aCbSkip, - void *aCrData, int32_t aCrStride, int32_t aCrWidth, int32_t aCrHeight, int32_t aCrOffset, int32_t aCrSkip) - { - mTimeUs = aTimeUs; - mKeyFrame = aKeyFrame; - mData = aData; - mSize = aSize; - mStride = aStride; - mSliceHeight = aSliceHeight; - mRotation = aRotation; - mGraphicBuffer = nullptr; - Y.mData = aYData; - Y.mStride = aYStride; - Y.mWidth = aYWidth; - Y.mHeight = aYHeight; - Y.mOffset = aYOffset; - Y.mSkip = aYSkip; - Cb.mData = aCbData; - Cb.mStride = aCbStride; - Cb.mWidth = aCbWidth; - Cb.mHeight = aCbHeight; - Cb.mOffset = aCbOffset; - Cb.mSkip = aCbSkip; - Cr.mData = aCrData; - Cr.mStride = aCrStride; - Cr.mWidth = aCrWidth; - Cr.mHeight = aCrHeight; - Cr.mOffset = aCrOffset; - Cr.mSkip = aCrSkip; - } -}; - -struct AudioFrame { - int64_t mTimeUs; - void *mData; // 16PCM interleaved - size_t mSize; // Size of mData in bytes - int32_t mAudioChannels; - int32_t mAudioSampleRate; - - AudioFrame() : - mTimeUs(0), - mData(0), - mSize(0), - mAudioChannels(0), - mAudioSampleRate(0) - { - } - - void Set(int64_t aTimeUs, - void *aData, size_t aSize, - int32_t aAudioChannels, int32_t aAudioSampleRate) - { - mTimeUs = aTimeUs; - mData = aData; - mSize = aSize; - mAudioChannels = aAudioChannels; - mAudioSampleRate = aAudioSampleRate; - } -}; - -struct Decoder; - -struct PluginHost { - bool (*Read)(Decoder *aDecoder, char *aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes); - uint64_t (*GetLength)(Decoder *aDecoder); - void (*SetMetaDataReadMode)(Decoder *aDecoder); - void (*SetPlaybackReadMode)(Decoder *aDecoder); -}; - -struct Decoder { - void *mResource; - void *mPrivate; - - Decoder(); - - void (*GetDuration)(Decoder *aDecoder, int64_t *durationUs); - void (*GetVideoParameters)(Decoder *aDecoder, int32_t *aWidth, int32_t *aHeight); - void (*GetAudioParameters)(Decoder *aDecoder, int32_t *aNumChannels, int32_t *aSampleRate); - bool (*HasVideo)(Decoder *aDecoder); - bool (*HasAudio)(Decoder *aDecoder); - bool (*ReadVideo)(Decoder *aDecoder, VideoFrame *aFrame, int64_t aSeekTimeUs); - bool (*ReadAudio)(Decoder *aDecoder, AudioFrame *aFrame, int64_t aSeekTimeUs); - void (*DestroyDecoder)(Decoder *); -}; - -struct Manifest { - bool (*CanDecode)(const char *aMimeChars, size_t aMimeLen, const char* const**aCodecs); - bool (*CreateDecoder)(PluginHost *aPluginHost, Decoder *aDecoder, - const char *aMimeChars, size_t aMimeLen); -}; - -} - -#endif diff --git a/dom/media/omx/MediaCodecProxy.cpp b/dom/media/omx/MediaCodecProxy.cpp deleted file mode 100644 index 16e339358307..000000000000 --- a/dom/media/omx/MediaCodecProxy.cpp +++ /dev/null @@ -1,626 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaCodecProxy.h" -#include -#include -#include -#include -#include -#include "stagefright/MediaErrors.h" - -#include -#define MCP_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "MediaCodecProxy", __VA_ARGS__) - -namespace android { - -// General Template: MediaCodec::getOutputGraphicBufferFromIndex(...) -template -struct OutputGraphicBufferStub -{ - static status_t GetOutputGraphicBuffer(T *aMediaCodec, - size_t aIndex, - sp *aGraphicBuffer) - { - return ERROR_UNSUPPORTED; - } -}; - -// Class Template Specialization: MediaCodec::getOutputGraphicBufferFromIndex(...) -template -struct OutputGraphicBufferStub -{ - static status_t GetOutputGraphicBuffer(T *aMediaCodec, - size_t aIndex, - sp *aGraphicBuffer) - { - if (aMediaCodec == nullptr || aGraphicBuffer == nullptr) { - return BAD_VALUE; - } - *aGraphicBuffer = aMediaCodec->getOutputGraphicBufferFromIndex(aIndex); - return OK; - } -}; - -// Wrapper class to handle interface-difference of MediaCodec. -struct MediaCodecInterfaceWrapper -{ - typedef int8_t Supported; - typedef int16_t Unsupported; - - template - static auto TestOutputGraphicBuffer(T *aMediaCodec) -> decltype(aMediaCodec->getOutputGraphicBufferFromIndex(0), Supported()); - - template - static auto TestOutputGraphicBuffer(...) -> Unsupported; - - // SFINAE: Substitution Failure Is Not An Error - static const bool OutputGraphicBufferSupported = sizeof(TestOutputGraphicBuffer(nullptr)) == sizeof(Supported); - - // Class Template Specialization - static OutputGraphicBufferStub sOutputGraphicBufferStub; - - // Wrapper Function - static status_t GetOutputGraphicBuffer(MediaCodec *aMediaCodec, - size_t aIndex, - sp *aGraphicBuffer) - { - return sOutputGraphicBufferStub.GetOutputGraphicBuffer(aMediaCodec, aIndex, aGraphicBuffer); - } - -}; - -sp -MediaCodecProxy::CreateByType(sp aLooper, - const char *aMime, - bool aEncoder) -{ - sp codec = new MediaCodecProxy(aLooper, - aMime, - aEncoder); - return codec; -} - -MediaCodecProxy::MediaCodecProxy(sp aLooper, - const char *aMime, - bool aEncoder) - : mCodecLooper(aLooper) - , mCodecMime(aMime) - , mCodecEncoder(aEncoder) - , mPromiseMonitor("MediaCodecProxy::mPromiseMonitor") -{ - MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr."); - mCodecPromise.SetMonitor(&mPromiseMonitor); -} - -MediaCodecProxy::~MediaCodecProxy() -{ - ReleaseMediaCodec(); -} - -bool -MediaCodecProxy::AllocateAudioMediaCodec() -{ - if (mResourceClient || mCodec.get()) { - return false; - } - - if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) { - if (allocateCodec()) { - return true; - } - } - return false; -} - -RefPtr -MediaCodecProxy::AsyncAllocateVideoMediaCodec() -{ - if (mResourceClient || mCodec.get()) { - return CodecPromise::CreateAndReject(true, __func__); - } - - if (strncasecmp(mCodecMime.get(), "video/", 6) != 0) { - return CodecPromise::CreateAndReject(true, __func__); - } - // request video codec - mozilla::MediaSystemResourceType type = - mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER : - mozilla::MediaSystemResourceType::VIDEO_DECODER; - mResourceClient = new mozilla::MediaSystemResourceClient(type); - mResourceClient->SetListener(this); - mResourceClient->Acquire(); - - mozilla::MonitorAutoLock lock(mPromiseMonitor); - RefPtr p = mCodecPromise.Ensure(__func__); - return p.forget(); -} - -void -MediaCodecProxy::ReleaseMediaCodec() -{ - // At first, release mResourceClient's resource to prevent a conflict with - // mResourceClient's callback. - if (mResourceClient) { - mResourceClient->ReleaseResource(); - mResourceClient = nullptr; - } - - mozilla::MonitorAutoLock lock(mPromiseMonitor); - mCodecPromise.RejectIfExists(true, __func__); - releaseCodec(); -} - -bool -MediaCodecProxy::allocateCodec() -{ - if (mCodecLooper == nullptr) { - return false; - } - - // Write Lock for mCodec - RWLock::AutoWLock awl(mCodecLock); - - // Create MediaCodec - mCodec = MediaCodec::CreateByType(mCodecLooper, mCodecMime.get(), mCodecEncoder); - if (mCodec == nullptr) { - return false; - } - - return true; -} - -void -MediaCodecProxy::releaseCodec() -{ - wp codec; - - { - // Write Lock for mCodec - RWLock::AutoWLock awl(mCodecLock); - - codec = mCodec; - - // Release MediaCodec - if (mCodec != nullptr) { - mCodec->stop(); - mCodec->release(); - mCodec = nullptr; - } - } - - while (codec.promote() != nullptr) { - // this value come from stagefright's AwesomePlayer. - usleep(1000); - } - - // Complete all pending Binder ipc transactions - IPCThreadState::self()->flushCommands(); - -} - -bool -MediaCodecProxy::allocated() const -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - return mCodec != nullptr; -} - -status_t -MediaCodecProxy::configure(const sp &aFormat, - const sp &aNativeWindow, - const sp &aCrypto, - uint32_t aFlags) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->configure(aFormat, aNativeWindow, aCrypto, aFlags); -} - -status_t -MediaCodecProxy::start() -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - - return mCodec->start(); -} - -status_t -MediaCodecProxy::stop() -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->stop(); -} - -status_t -MediaCodecProxy::release() -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->release(); -} - -status_t -MediaCodecProxy::flush() -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->flush(); -} - -status_t -MediaCodecProxy::queueInputBuffer(size_t aIndex, - size_t aOffset, - size_t aSize, - int64_t aPresentationTimeUs, - uint32_t aFlags, - AString *aErrorDetailMessage) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->queueInputBuffer(aIndex, aOffset, aSize, - aPresentationTimeUs, aFlags, aErrorDetailMessage); -} - -status_t -MediaCodecProxy::queueSecureInputBuffer(size_t aIndex, - size_t aOffset, - const CryptoPlugin::SubSample *aSubSamples, - size_t aNumSubSamples, - const uint8_t aKey[16], - const uint8_t aIV[16], - CryptoPlugin::Mode aMode, - int64_t aPresentationTimeUs, - uint32_t aFlags, - AString *aErrorDetailMessage) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->queueSecureInputBuffer(aIndex, aOffset, - aSubSamples, aNumSubSamples, aKey, aIV, aMode, - aPresentationTimeUs, aFlags, aErrorDetailMessage); -} - -status_t -MediaCodecProxy::dequeueInputBuffer(size_t *aIndex, - int64_t aTimeoutUs) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->dequeueInputBuffer(aIndex, aTimeoutUs); -} - -status_t -MediaCodecProxy::dequeueOutputBuffer(size_t *aIndex, - size_t *aOffset, - size_t *aSize, - int64_t *aPresentationTimeUs, - uint32_t *aFlags, - int64_t aTimeoutUs) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->dequeueOutputBuffer(aIndex, aOffset, aSize, - aPresentationTimeUs, aFlags, aTimeoutUs); -} - -status_t -MediaCodecProxy::renderOutputBufferAndRelease(size_t aIndex) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->renderOutputBufferAndRelease(aIndex); -} - -status_t -MediaCodecProxy::releaseOutputBuffer(size_t aIndex) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->releaseOutputBuffer(aIndex); -} - -status_t -MediaCodecProxy::signalEndOfInputStream() -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->signalEndOfInputStream(); -} - -status_t -MediaCodecProxy::getOutputFormat(sp *aFormat) const -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->getOutputFormat(aFormat); -} - -status_t -MediaCodecProxy::getInputBuffers(Vector> *aBuffers) const -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->getInputBuffers(aBuffers); -} - -status_t -MediaCodecProxy::getOutputBuffers(Vector> *aBuffers) const -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return mCodec->getOutputBuffers(aBuffers); -} - -void -MediaCodecProxy::requestActivityNotification(const sp &aNotify) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return; - } - mCodec->requestActivityNotification(aNotify); -} - -status_t -MediaCodecProxy::getOutputGraphicBufferFromIndex(size_t aIndex, - sp *aGraphicBuffer) -{ - // Read Lock for mCodec - RWLock::AutoRLock arl(mCodecLock); - - if (mCodec == nullptr) { - return NO_INIT; - } - return MediaCodecInterfaceWrapper::GetOutputGraphicBuffer(mCodec.get(), aIndex, aGraphicBuffer); -} - -status_t -MediaCodecProxy::getCapability(uint32_t *aCapability) -{ - if (aCapability == nullptr) { - return BAD_VALUE; - } - - uint32_t capability = kEmptyCapability; - - if (MediaCodecInterfaceWrapper::OutputGraphicBufferSupported) { - capability |= kCanExposeGraphicBuffer; - } - - *aCapability = capability; - - return OK; -} - -// Called on ImageBridge thread -void -MediaCodecProxy::ResourceReserved() -{ - MCP_LOG("resourceReserved"); - mozilla::MonitorAutoLock lock(mPromiseMonitor); - // Create MediaCodec - if (!allocateCodec()) { - mCodecPromise.RejectIfExists(true, __func__); - return; - } - mCodecPromise.ResolveIfExists(true, __func__); -} - -// Called on ImageBridge thread -void -MediaCodecProxy::ResourceReserveFailed() -{ - mozilla::MonitorAutoLock lock(mPromiseMonitor); - mCodecPromise.RejectIfExists(true, __func__); -} - -bool MediaCodecProxy::Prepare() -{ - - if (start() != OK) { - MCP_LOG("Couldn't start MediaCodec"); - return false; - } - if (getInputBuffers(&mInputBuffers) != OK) { - MCP_LOG("Couldn't get input buffers from MediaCodec"); - return false; - } - if (getOutputBuffers(&mOutputBuffers) != OK) { - MCP_LOG("Couldn't get output buffers from MediaCodec"); - return false; - } - - return true; -} - -bool MediaCodecProxy::UpdateOutputBuffers() -{ - // Read Lock for mCodec - { - RWLock::AutoRLock autolock(mCodecLock); - if (mCodec == nullptr) { - MCP_LOG("MediaCodec has not been inited from UpdateOutputBuffers"); - return false; - } - } - - status_t err = getOutputBuffers(&mOutputBuffers); - if (err != OK){ - MCP_LOG("Couldn't update output buffers from MediaCodec"); - return false; - } - return true; -} - -status_t MediaCodecProxy::Input(const uint8_t* aData, uint32_t aDataSize, - int64_t aTimestampUsecs, uint64_t aflags, - int64_t aTimeoutUs) -{ - // Read Lock for mCodec - { - RWLock::AutoRLock autolock(mCodecLock); - if (mCodec == nullptr) { - MCP_LOG("MediaCodec has not been inited from input!"); - return NO_INIT; - } - } - - size_t index; - status_t err = dequeueInputBuffer(&index, aTimeoutUs); - if (err != OK) { - if (err != -EAGAIN) { - MCP_LOG("dequeueInputBuffer returned %d", err); - } - return err; - } - - if (aData) { - const sp &dstBuffer = mInputBuffers.itemAt(index); - - CHECK_LE(aDataSize, dstBuffer->capacity()); - dstBuffer->setRange(0, aDataSize); - - memcpy(dstBuffer->data(), aData, aDataSize); - err = queueInputBuffer(index, 0, dstBuffer->size(), aTimestampUsecs, aflags); - } else { - err = queueInputBuffer(index, 0, 0, 0ll, MediaCodec::BUFFER_FLAG_EOS); - } - - if (err != OK) { - MCP_LOG("queueInputBuffer returned %d", err); - return err; - } - return err; -} - -status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs) -{ - // Read Lock for mCodec - { - RWLock::AutoRLock autolock(mCodecLock); - if (mCodec == nullptr) { - MCP_LOG("MediaCodec has not been inited from output!"); - return NO_INIT; - } - } - - size_t index = 0; - size_t offset = 0; - size_t size = 0; - int64_t timeUs = 0; - uint32_t flags = 0; - - *aBuffer = nullptr; - - status_t err = dequeueOutputBuffer(&index, &offset, &size, - &timeUs, &flags, aTimeoutUs); - if (err != OK) { - return err; - } - - MediaBuffer *buffer; - sp graphicBuffer; - - if (getOutputGraphicBufferFromIndex(index, &graphicBuffer) == OK && - graphicBuffer != nullptr) { - buffer = new MediaBuffer(graphicBuffer); - } else { - buffer = new MediaBuffer(mOutputBuffers.itemAt(index)); - } - sp metaData = buffer->meta_data(); - metaData->setInt32(kKeyBufferIndex, index); - metaData->setInt64(kKeyTime, timeUs); - buffer->set_range(buffer->range_offset(), size); - *aBuffer = buffer; - if (flags & MediaCodec::BUFFER_FLAG_EOS) { - return ERROR_END_OF_STREAM; - } - return err; -} - -void MediaCodecProxy::ReleaseMediaResources() -{ - ReleaseMediaCodec(); -} - -void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) { - if (aBuffer) { - sp metaData = aBuffer->meta_data(); - int32_t index; - metaData->findInt32(kKeyBufferIndex, &index); - aBuffer->release(); - releaseOutputBuffer(index); - } -} - -} // namespace android diff --git a/dom/media/omx/MediaCodecProxy.h b/dom/media/omx/MediaCodecProxy.h deleted file mode 100644 index 26435c55dda4..000000000000 --- a/dom/media/omx/MediaCodecProxy.h +++ /dev/null @@ -1,183 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 MEDIA_CODEC_PROXY_H -#define MEDIA_CODEC_PROXY_H - -#include -#include -#include -#include - -#include "mozilla/media/MediaSystemResourceClient.h" -#include "mozilla/Monitor.h" -#include "mozilla/MozPromise.h" -#include "mozilla/RefPtr.h" - -namespace android { -// This class is intended to be a proxy for MediaCodec with codec resource -// management. Basically user can use it like MediaCodec, but need to handle -// the listener when Codec is reserved for Async case. A good example is -// MediaCodecReader.cpp. Another useage is to use configure(), Prepare(), -// Input(), and Output(). It is used in GonkVideoDecoderManager.cpp which -// doesn't need to handle the buffers for codec. -class MediaCodecProxy : public RefBase - , public mozilla::MediaSystemResourceReservationListener -{ -public: - typedef mozilla::MozPromise CodecPromise; - - enum Capability { - kEmptyCapability = 0x00000000, - kCanExposeGraphicBuffer = 0x00000001, - }; - - enum { - kKeyBufferIndex = 'bfin', - }; - - // Check whether MediaCodec has been allocated. - bool allocated() const; - - // Static MediaCodec methods - // Only support MediaCodec::CreateByType() - static sp CreateByType(sp aLooper, - const char *aMime, - bool aEncoder); - - // MediaCodec methods - status_t configure(const sp &aFormat, - const sp &aNativeWindow, - const sp &aCrypto, - uint32_t aFlags); - - status_t start(); - - status_t stop(); - - status_t release(); - - status_t flush(); - - status_t queueInputBuffer(size_t aIndex, - size_t aOffset, - size_t aSize, - int64_t aPresentationTimeUs, - uint32_t aFlags, - AString *aErrorDetailMessage=nullptr); - - status_t queueSecureInputBuffer(size_t aIndex, - size_t aOffset, - const CryptoPlugin::SubSample *aSubSamples, - size_t aNumSubSamples, - const uint8_t aKey[16], - const uint8_t aIV[16], - CryptoPlugin::Mode aMode, - int64_t aPresentationTimeUs, - uint32_t aFlags, - AString *aErrorDetailMessage=nullptr); - - status_t dequeueInputBuffer(size_t *aIndex, - int64_t aTimeoutUs=INT64_C(0)); - - status_t dequeueOutputBuffer(size_t *aIndex, - size_t *aOffset, - size_t *aSize, - int64_t *aPresentationTimeUs, - uint32_t *aFlags, - int64_t aTimeoutUs=INT64_C(0)); - - status_t renderOutputBufferAndRelease(size_t aIndex); - - status_t releaseOutputBuffer(size_t aIndex); - - status_t signalEndOfInputStream(); - - status_t getOutputFormat(sp *aFormat) const; - - status_t getInputBuffers(Vector> *aBuffers) const; - - status_t getOutputBuffers(Vector> *aBuffers) const; - - // Notification will be posted once there "is something to do", i.e. - // an input/output buffer has become available, a format change is - // pending, an error is pending. - void requestActivityNotification(const sp &aNotify); - - status_t getOutputGraphicBufferFromIndex(size_t aIndex, - sp *aGraphicBuffer); - - status_t getCapability(uint32_t *aCapability); - - // Utility functions - - // If aData is null, will notify decoder input EOS - status_t Input(const uint8_t* aData, uint32_t aDataSize, - int64_t aTimestampUsecs, uint64_t flags, int64_t aTimeoutUs = 0); - status_t Output(MediaBuffer** aBuffer, int64_t aTimeoutUs); - bool Prepare(); - void ReleaseMediaResources(); - // This updates mOutputBuffer when receiving INFO_OUTPUT_BUFFERS_CHANGED event. - bool UpdateOutputBuffers(); - - void ReleaseMediaBuffer(MediaBuffer* abuffer); - - // It allocates audio MediaCodec synchronously. - bool AllocateAudioMediaCodec(); - - // It allocates video MediaCodec asynchronously. - RefPtr AsyncAllocateVideoMediaCodec(); - - // Free the OMX codec so others can allocate it. - void ReleaseMediaCodec(); - -protected: - virtual ~MediaCodecProxy(); - - // MediaResourceReservationListener - void ResourceReserved() override; - void ResourceReserveFailed() override; - -private: - // Forbidden - MediaCodecProxy() = delete; - MediaCodecProxy(const MediaCodecProxy &) = delete; - const MediaCodecProxy &operator=(const MediaCodecProxy &) = delete; - - // Constructor for MediaCodecProxy::CreateByType - MediaCodecProxy(sp aLooper, - const char *aMime, - bool aEncoder); - - // Allocate Codec Resource - bool allocateCodec(); - // Release Codec Resource - void releaseCodec(); - - // MediaCodec Parameter - sp mCodecLooper; - nsCString mCodecMime; - bool mCodecEncoder; - - mozilla::MozPromiseHolder mCodecPromise; - // When mPromiseMonitor is held, mResourceClient's functions should not be called. - mozilla::Monitor mPromiseMonitor; - - // Media Resource Management - RefPtr mResourceClient; - - // MediaCodec instance - mutable RWLock mCodecLock; - sp mCodec; - - //MediaCodec buffers to hold input/output data. - Vector > mInputBuffers; - Vector > mOutputBuffers; -}; - -} // namespace android - -#endif // MEDIA_CODEC_PROXY_H diff --git a/dom/media/omx/MediaOmxCommonDecoder.cpp b/dom/media/omx/MediaOmxCommonDecoder.cpp deleted file mode 100644 index fcaf06a6eca7..000000000000 --- a/dom/media/omx/MediaOmxCommonDecoder.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaOmxCommonDecoder.h" - -#include - -#include "AudioOffloadPlayerBase.h" -#include "MediaDecoderStateMachine.h" -#include "MediaOmxCommonReader.h" - -#ifdef MOZ_AUDIO_OFFLOAD -#include "AudioOffloadPlayer.h" -#endif - -using namespace android; - -namespace mozilla { - -extern LazyLogModule gMediaDecoderLog; -#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg) - -MediaOmxCommonDecoder::MediaOmxCommonDecoder(MediaDecoderOwner* aOwner) - : MediaDecoder(aOwner) - , mReader(nullptr) - , mCanOffloadAudio(false) - , mFallbackToStateMachine(false) - , mIsCaptured(false) -{ - mDormantSupported = true; -} - -MediaOmxCommonDecoder::~MediaOmxCommonDecoder() {} - -void -MediaOmxCommonDecoder::SetPlatformCanOffloadAudio(bool aCanOffloadAudio) -{ - if (!aCanOffloadAudio) { - return; - } - - // Stop MDSM from playing to avoid startup glitch (bug 1053186). - GetStateMachine()->DispatchAudioOffloading(true); - - // Modify mCanOffloadAudio in the main thread. - RefPtr self = this; - nsCOMPtr r = NS_NewRunnableFunction([=] () { - self->mCanOffloadAudio = true; - }); - AbstractThread::MainThread()->Dispatch(r.forget()); -} - -void -MediaOmxCommonDecoder::DisableStateMachineAudioOffloading() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mCanOffloadAudio) { - // mCanOffloadAudio is true implies we've called - // |GetStateMachine()->DispatchAudioOffloading(true)| in - // SetPlatformCanOffloadAudio(). We need to turn off audio offloading - // for MDSM so it can start playback. - GetStateMachine()->DispatchAudioOffloading(false); - } -} - -bool -MediaOmxCommonDecoder::CheckDecoderCanOffloadAudio() -{ - MOZ_ASSERT(NS_IsMainThread()); - return (mCanOffloadAudio && !mFallbackToStateMachine && - !mIsCaptured && mPlaybackRate == 1.0); -} - -void -MediaOmxCommonDecoder::FirstFrameLoaded(nsAutoPtr aInfo, - MediaDecoderEventVisibility aEventVisibility) -{ - MOZ_ASSERT(NS_IsMainThread()); - - MediaDecoder::FirstFrameLoaded(aInfo, aEventVisibility); - - if (!CheckDecoderCanOffloadAudio()) { - DECODER_LOG(LogLevel::Debug, ("In %s Offload Audio check failed", - __PRETTY_FUNCTION__)); - DisableStateMachineAudioOffloading(); - return; - } - -#ifdef MOZ_AUDIO_OFFLOAD - mAudioOffloadPlayer = new AudioOffloadPlayer(this); -#endif - if (!mAudioOffloadPlayer) { - DisableStateMachineAudioOffloading(); - return; - } - - mAudioOffloadPlayer->SetSource(mReader->GetAudioOffloadTrack()); - status_t err = mAudioOffloadPlayer->Start(false); - if (err != OK) { - mAudioOffloadPlayer = nullptr; - mFallbackToStateMachine = true; - DECODER_LOG(LogLevel::Debug, ("In %s Unable to start offload audio %d." - "Switching to normal mode", __PRETTY_FUNCTION__, err)); - DisableStateMachineAudioOffloading(); - return; - } - PauseStateMachine(); - if (mLogicallySeeking) { - SeekTarget target = SeekTarget(mLogicalPosition, - SeekTarget::Accurate, - MediaDecoderEventVisibility::Observable); - mSeekRequest.DisconnectIfExists(); - mSeekRequest.Begin(mAudioOffloadPlayer->Seek(target) - ->Then(AbstractThread::MainThread(), __func__, static_cast(this), - &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)); - } - // Call ChangeState() to run AudioOffloadPlayer since offload state enabled - ChangeState(mPlayState); -} - -void -MediaOmxCommonDecoder::PauseStateMachine() -{ - MOZ_ASSERT(NS_IsMainThread()); - DECODER_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__)); - - MOZ_ASSERT(GetStateMachine()); - // enter dormant state - GetStateMachine()->DispatchSetDormant(true); -} - -void -MediaOmxCommonDecoder::ResumeStateMachine() -{ - MOZ_ASSERT(NS_IsMainThread()); - DECODER_LOG(LogLevel::Debug, ("%s current time %f", __PRETTY_FUNCTION__, mLogicalPosition)); - - if (IsShutdown()) { - return; - } - - if (!GetStateMachine()) { - return; - } - - GetStateMachine()->DispatchAudioOffloading(false); - - mFallbackToStateMachine = true; - mAudioOffloadPlayer = nullptr; - SeekTarget target = SeekTarget(mLogicalPosition, - SeekTarget::Accurate, - MediaDecoderEventVisibility::Suppressed); - // Call Seek of MediaDecoderStateMachine to suppress seek events. - GetStateMachine()->InvokeSeek(target); - - // exit dormant state - GetStateMachine()->DispatchSetDormant(false); - UpdateLogicalPosition(); -} - -void -MediaOmxCommonDecoder::AudioOffloadTearDown() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!IsShutdown()); - DECODER_LOG(LogLevel::Debug, ("%s", __PRETTY_FUNCTION__)); - - // mAudioOffloadPlayer can be null here if ResumeStateMachine was called - // just before because of some other error. - if (mAudioOffloadPlayer) { - ResumeStateMachine(); - } -} - -void -MediaOmxCommonDecoder::AddOutputStream(ProcessedMediaStream* aStream, - bool aFinishWhenEnded) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mIsCaptured = true; - - if (mAudioOffloadPlayer) { - ResumeStateMachine(); - } - - MediaDecoder::AddOutputStream(aStream, aFinishWhenEnded); -} - -void -MediaOmxCommonDecoder::SetPlaybackRate(double aPlaybackRate) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (mAudioOffloadPlayer && - ((aPlaybackRate != 0.0) || (aPlaybackRate != 1.0))) { - ResumeStateMachine(); - } - - MediaDecoder::SetPlaybackRate(aPlaybackRate); -} - -void -MediaOmxCommonDecoder::ChangeState(PlayState aState) -{ - MOZ_ASSERT(NS_IsMainThread()); - // Keep MediaDecoder state in sync with MediaElement irrespective of offload - // playback so it will continue to work in normal mode when offloading fails - // in between - MediaDecoder::ChangeState(aState); - - if (!mAudioOffloadPlayer) { - return; - } - - status_t err = mAudioOffloadPlayer->ChangeState(aState); - if (err != OK) { - ResumeStateMachine(); - return; - } -} - -void -MediaOmxCommonDecoder::CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise) -{ - if (!mAudioOffloadPlayer) { - MediaDecoder::CallSeek(aTarget, aPromise); - return; - } - - DiscardOngoingSeekIfExists(); - mSeekDOMPromise = aPromise; - mSeekRequest.Begin(mAudioOffloadPlayer->Seek(aTarget) - ->Then(AbstractThread::MainThread(), __func__, static_cast(this), - &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected)); -} - -int64_t -MediaOmxCommonDecoder::CurrentPosition() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!mAudioOffloadPlayer) { - return MediaDecoder::CurrentPosition(); - } - return mAudioOffloadPlayer->GetMediaTimeUs(); -} - -void -MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible) -{ - MOZ_ASSERT(NS_IsMainThread()); - MediaDecoder::SetElementVisibility(aIsVisible); - if (mAudioOffloadPlayer) { - mAudioOffloadPlayer->SetElementVisibility(aIsVisible); - } -} - -MediaDecoderOwner::NextFrameStatus -MediaOmxCommonDecoder::NextFrameStatus() -{ - MOZ_ASSERT(NS_IsMainThread()); - return mAudioOffloadPlayer ? mAudioOffloadPlayer->GetNextFrameStatus() - : MediaDecoder::NextFrameStatus(); -} - -void -MediaOmxCommonDecoder::SetVolume(double aVolume) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!mAudioOffloadPlayer) { - MediaDecoder::SetVolume(aVolume); - return; - } - mAudioOffloadPlayer->SetVolume(aVolume); -} - -MediaDecoderStateMachine* -MediaOmxCommonDecoder::CreateStateMachine() -{ - mReader = CreateReader(); - if (mReader != nullptr) { - mReader->SetAudioChannel(GetAudioChannel()); - } - return CreateStateMachineFromReader(mReader); -} - -void -MediaOmxCommonDecoder::Shutdown() -{ - mAudioOffloadPlayer = nullptr; - MediaDecoder::Shutdown(); -} - -} // namespace mozilla diff --git a/dom/media/omx/MediaOmxCommonDecoder.h b/dom/media/omx/MediaOmxCommonDecoder.h deleted file mode 100644 index 0e42df45ea31..000000000000 --- a/dom/media/omx/MediaOmxCommonDecoder.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 MEDIA_OMX_COMMON_DECODER_H -#define MEDIA_OMX_COMMON_DECODER_H - -#include "MediaDecoder.h" -#include "nsAutoPtr.h" - -namespace android { -struct MOZ_EXPORT MediaSource; -} // namespace android - -namespace mozilla { - -class AudioOffloadPlayerBase; -class MediaOmxCommonReader; - -class MediaOmxCommonDecoder : public MediaDecoder -{ -public: - explicit MediaOmxCommonDecoder(MediaDecoderOwner* aOwner); - - void FirstFrameLoaded(nsAutoPtr aInfo, - MediaDecoderEventVisibility aEventVisibility) override; - void ChangeState(PlayState aState) override; - void CallSeek(const SeekTarget& aTarget, dom::Promise* aPromise) override; - void SetVolume(double aVolume) override; - int64_t CurrentPosition() override; - MediaDecoderOwner::NextFrameStatus NextFrameStatus() override; - void SetElementVisibility(bool aIsVisible) override; - void SetPlatformCanOffloadAudio(bool aCanOffloadAudio) override; - void AddOutputStream(ProcessedMediaStream* aStream, - bool aFinishWhenEnded) override; - void SetPlaybackRate(double aPlaybackRate) override; - - void AudioOffloadTearDown(); - - MediaDecoderStateMachine* CreateStateMachine() override; - - virtual MediaOmxCommonReader* CreateReader() = 0; - virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader) = 0; - - void NotifyOffloadPlayerPositionChanged() { UpdateLogicalPosition(); } - - void Shutdown() override; - -protected: - virtual ~MediaOmxCommonDecoder(); - void PauseStateMachine(); - void ResumeStateMachine(); - bool CheckDecoderCanOffloadAudio(); - void DisableStateMachineAudioOffloading(); - - MediaOmxCommonReader* mReader; - - // Offloaded audio track - android::sp mAudioTrack; - - nsAutoPtr mAudioOffloadPlayer; - - // Set by Media*Reader to denote current track can be offloaded - bool mCanOffloadAudio; - - // Set when offload playback of current track fails in the middle and need to - // fallback to state machine - bool mFallbackToStateMachine; - - // True if the media element is captured. - bool mIsCaptured; -}; - -} // namespace mozilla - -#endif // MEDIA_OMX_COMMON_DECODER_H diff --git a/dom/media/omx/MediaOmxCommonReader.cpp b/dom/media/omx/MediaOmxCommonReader.cpp deleted file mode 100644 index aa0294f216ea..000000000000 --- a/dom/media/omx/MediaOmxCommonReader.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaOmxCommonReader.h" - -#include - -#include "AbstractMediaDecoder.h" -#include "AudioChannelService.h" -#include "MediaStreamSource.h" -#include "MediaPrefs.h" - -#ifdef MOZ_AUDIO_OFFLOAD -#include -#include -#include -#endif - -using namespace android; - -namespace mozilla { - -extern LazyLogModule gMediaDecoderLog; -#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg) - -MediaOmxCommonReader::MediaOmxCommonReader(AbstractMediaDecoder *aDecoder) - : MediaDecoderReader(aDecoder) - , mStreamSource(nullptr) -{ - mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel(); -} - -bool MediaOmxCommonReader::IsMonoAudioEnabled() -{ - return MediaPrefs::MonoAudio(); -} - -#ifdef MOZ_AUDIO_OFFLOAD -void MediaOmxCommonReader::CheckAudioOffload() -{ - MOZ_ASSERT(OnTaskQueue()); - - char offloadProp[128]; - property_get("audio.offload.disable", offloadProp, "0"); - bool offloadDisable = atoi(offloadProp) != 0; - if (offloadDisable) { - return; - } - - sp audioOffloadTrack = GetAudioOffloadTrack(); - sp meta = audioOffloadTrack.get() - ? audioOffloadTrack->getFormat() : nullptr; - - // Supporting audio offload only when there is no video, no streaming - bool hasNoVideo = !HasVideo(); - bool isNotStreaming - = mDecoder->GetResource()->IsDataCachedToEndOfResource(0); - - // Not much benefit in trying to offload other channel types. Most of them - // aren't supported and also duration would be less than a minute - bool isTypeMusic = mAudioChannel == dom::AudioChannel::Content; - - DECODER_LOG(LogLevel::Debug, ("%s meta %p, no video %d, no streaming %d," - " channel type %d", __FUNCTION__, meta.get(), hasNoVideo, - isNotStreaming, mAudioChannel)); - - if ((meta.get()) && hasNoVideo && isNotStreaming && isTypeMusic && - canOffloadStream(meta, false, false, AUDIO_STREAM_MUSIC) && - !IsMonoAudioEnabled()) { - DECODER_LOG(LogLevel::Debug, ("Can offload this audio stream")); - mDecoder->SetPlatformCanOffloadAudio(true); - } -} -#endif - -} // namespace mozilla diff --git a/dom/media/omx/MediaOmxCommonReader.h b/dom/media/omx/MediaOmxCommonReader.h deleted file mode 100644 index 022ff52f37ae..000000000000 --- a/dom/media/omx/MediaOmxCommonReader.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 MEDIA_OMX_COMMON_READER_H -#define MEDIA_OMX_COMMON_READER_H - -#include "MediaDecoderReader.h" - -#include - -#include "mozilla/dom/AudioChannelBinding.h" - -namespace android { -struct MOZ_EXPORT MediaSource; -class MediaStreamSource; -} // namespace android - -namespace mozilla { - -class AbstractMediaDecoder; - -class MediaOmxCommonReader : public MediaDecoderReader -{ -public: - typedef MozPromise MediaResourcePromise; - - MediaOmxCommonReader(AbstractMediaDecoder* aDecoder); - - void SetAudioChannel(dom::AudioChannel aAudioChannel) { - mAudioChannel = aAudioChannel; - } - - virtual android::sp GetAudioOffloadTrack() = 0; - -#ifdef MOZ_AUDIO_OFFLOAD - // Check whether it is possible to offload current audio track. This access - // canOffloadStream() from libStageFright Utils.cpp, which is not there in - // ANDROID_VERSION < 19 - void CheckAudioOffload(); -#endif - -protected: - dom::AudioChannel mAudioChannel; - // Weak reference to the MediaStreamSource that will be created by either - // MediaOmxReader or MediaCodecReader. - android::MediaStreamSource* mStreamSource; - // Get value from the preferece, if true, we stop the audio offload. - bool IsMonoAudioEnabled(); - -private: - virtual bool HasAudio() = 0; - virtual bool HasVideo() = 0; -}; - -} // namespace mozilla - -#endif // MEDIA_OMX_COMMON_READER_H diff --git a/dom/media/omx/MediaOmxDecoder.cpp b/dom/media/omx/MediaOmxDecoder.cpp deleted file mode 100644 index 2e1d20927432..000000000000 --- a/dom/media/omx/MediaOmxDecoder.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaOmxDecoder.h" -#include "MediaOmxReader.h" -#include "MediaDecoderStateMachine.h" - -using namespace android; - -namespace mozilla { - -MediaDecoder* -MediaOmxDecoder::Clone(MediaDecoderOwner* aOwner) -{ - return new MediaOmxDecoder(aOwner); -} - -MediaOmxCommonReader* -MediaOmxDecoder::CreateReader() -{ - return new MediaOmxReader(this); -} - -MediaDecoderStateMachine* -MediaOmxDecoder::CreateStateMachineFromReader(MediaOmxCommonReader* aReader) -{ - return new MediaDecoderStateMachine(this, aReader); -} - -} // namespace mozilla diff --git a/dom/media/omx/MediaOmxDecoder.h b/dom/media/omx/MediaOmxDecoder.h deleted file mode 100644 index 5f4c60281770..000000000000 --- a/dom/media/omx/MediaOmxDecoder.h +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(MediaOmxDecoder_h_) -#define MediaOmxDecoder_h_ - -#include "MediaOmxCommonDecoder.h" - -namespace mozilla { - -class MediaOmxDecoder : public MediaOmxCommonDecoder -{ -public: - explicit MediaOmxDecoder(MediaDecoderOwner* aOwner) - : MediaOmxCommonDecoder(aOwner) {} - virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner); - virtual MediaOmxCommonReader* CreateReader(); - virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader); -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/omx/MediaOmxReader.cpp b/dom/media/omx/MediaOmxReader.cpp deleted file mode 100644 index 3d57ea6f7a94..000000000000 --- a/dom/media/omx/MediaOmxReader.cpp +++ /dev/null @@ -1,622 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaOmxReader.h" - -#include "MediaDecoderStateMachine.h" -#include "mozilla/TimeStamp.h" -#include "MediaResource.h" -#include "VideoUtils.h" -#include "MediaOmxDecoder.h" -#include "AbstractMediaDecoder.h" -#include "AudioChannelService.h" -#include "OmxDecoder.h" -#include "MPAPI.h" -#include "gfx2DGlue.h" -#include "MediaStreamSource.h" -#include "VideoFrameContainer.h" - -#define MAX_DROPPED_FRAMES 25 -// Try not to spend more than this much time in a single call to DecodeVideoFrame. -#define MAX_VIDEO_DECODE_SECONDS 0.1 - -using namespace mozilla::gfx; -using namespace mozilla::media; -using namespace android; - -namespace mozilla { - -extern LazyLogModule gMediaDecoderLog; -#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg) - -class MediaOmxReader::ProcessCachedDataTask : public Runnable -{ -public: - ProcessCachedDataTask(MediaOmxReader* aOmxReader, int64_t aOffset) - : mOmxReader(aOmxReader), - mOffset(aOffset) - { } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ASSERT(mOmxReader.get()); - mOmxReader->ProcessCachedData(mOffset); - return NS_OK; - } - -private: - RefPtr mOmxReader; - int64_t mOffset; -}; - -// When loading an MP3 stream from a file, we need to parse the file's -// content to find its duration. Reading files of 100 MiB or more can -// delay the player app noticably, so the file is read and decoded in -// smaller chunks. -// -// We first read on the decode thread, but parsing must be done on the -// main thread. After we read the file's initial MiBs in the decode -// thread, an instance of this class is scheduled to the main thread for -// parsing the MP3 stream. The decode thread waits until it has finished. -// -// If there is more data available from the file, the runnable dispatches -// a task to the IO thread for retrieving the next chunk of data, and -// the IO task dispatches a runnable to the main thread for parsing the -// data. This goes on until all of the MP3 file has been parsed. - -class MediaOmxReader::NotifyDataArrivedRunnable : public Runnable -{ -public: - NotifyDataArrivedRunnable(MediaOmxReader* aOmxReader, - uint64_t aLength, - int64_t aOffset, uint64_t aFullLength) - : mOmxReader(aOmxReader), - mLength(aLength), - mOffset(aOffset), - mFullLength(aFullLength) - { - MOZ_ASSERT(mOmxReader.get()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(mOmxReader->OnTaskQueue()); - NotifyDataArrived(); - return NS_OK; - } - -private: - void NotifyDataArrived() - { - if (mOmxReader->IsShutdown()) { - return; - } - - while (mLength) { - uint32_t length = std::min(mLength, UINT32_MAX); - mOmxReader->NotifyDataArrived(); - mLength -= length; - mOffset += length; - } - - if (static_cast(mOffset) < mFullLength) { - // We cannot read data in the main thread because it - // might block for too long. Instead we post an IO task - // to the IO thread if there is more data available. - RefPtr task = new ProcessCachedDataTask(mOmxReader.get(), mOffset); - XRE_GetIOMessageLoop()->PostTask(task.forget()); - } - } - - RefPtr mOmxReader; - uint64_t mLength; - int64_t mOffset; - uint64_t mFullLength; -}; - -MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder) - : MediaOmxCommonReader(aDecoder) - , mShutdownMutex("MediaOmxReader.Shutdown") - , mHasVideo(false) - , mHasAudio(false) - , mVideoSeekTimeUs(-1) - , mAudioSeekTimeUs(-1) - , mLastParserDuration(-1) - , mSkipCount(0) - , mIsShutdown(false) - , mMP3FrameParser(-1) -{ - mAudioChannel = dom::AudioChannelService::GetDefaultAudioChannel(); -} - -MediaOmxReader::~MediaOmxReader() -{ -} - -already_AddRefed -MediaOmxReader::SafeGetDecoder() { - RefPtr decoder; - MutexAutoLock lock(mShutdownMutex); - if (!mIsShutdown) { - decoder = mDecoder; - } - return decoder.forget(); -} - -void MediaOmxReader::ReleaseDecoder() -{ - if (mOmxDecoder.get()) { - mOmxDecoder->ReleaseDecoder(); - } - mOmxDecoder.clear(); -} - -RefPtr -MediaOmxReader::Shutdown() -{ - { - MutexAutoLock lock(mShutdownMutex); - mIsShutdown = true; - } - - RefPtr p = MediaDecoderReader::Shutdown(); - - // Wait for the superclass to finish tearing things down before releasing - // the decoder on the main thread. - p->Then(AbstractThread::MainThread(), __func__, this, &MediaOmxReader::ReleaseDecoder, &MediaOmxReader::ReleaseDecoder); - - return p; -} - -void MediaOmxReader::ReleaseResources() -{ - mMediaResourceRequest.DisconnectIfExists(); - mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); - - ResetDecode(); - // Before freeing a video codec, all video buffers needed to be released - // even from graphics pipeline. - VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); - if (container) { - container->ClearCurrentFrame(); - } - if (mOmxDecoder.get()) { - mOmxDecoder->ReleaseMediaResources(); - } -} - -nsresult MediaOmxReader::InitOmxDecoder() -{ - if (!mOmxDecoder.get()) { - //register sniffers, if they are not registered in this process. - DataSource::RegisterDefaultSniffers(); - - sp dataSource = new MediaStreamSource(mDecoder->GetResource()); - dataSource->initCheck(); - - mExtractor = MediaExtractor::Create(dataSource); - if (!mExtractor.get()) { - return NS_ERROR_FAILURE; - } - mOmxDecoder = new OmxDecoder(mDecoder, OwnerThread()); - if (!mOmxDecoder->Init(mExtractor)) { - return NS_ERROR_FAILURE; - } - mStreamSource = static_cast(dataSource.get()); - } - return NS_OK; -} - -RefPtr -MediaOmxReader::AsyncReadMetadata() -{ - MOZ_ASSERT(OnTaskQueue()); - EnsureActive(); - - // Initialize the internal OMX Decoder. - nsresult rv = InitOmxDecoder(); - if (NS_FAILED(rv)) { - return MediaDecoderReader::MetadataPromise::CreateAndReject( - NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); - } - - bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3); - if (isMP3) { - // When read sdcard's file on b2g platform at constructor, - // the mDecoder->GetResource()->GetLength() would return -1. - // Delay set the total duration on this function. - mMP3FrameParser.SetLength(mDecoder->GetResource()->GetLength()); - ProcessCachedData(0); - } - - RefPtr p = mMetadataPromise.Ensure(__func__); - - RefPtr self = this; - mMediaResourceRequest.Begin(mOmxDecoder->AllocateMediaResources() - ->Then(OwnerThread(), __func__, - [self] (bool) -> void { - self->mMediaResourceRequest.Complete(); - self->HandleResourceAllocated(); - }, [self] (bool) -> void { - self->mMediaResourceRequest.Complete(); - self->mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); - })); - - return p; -} - -void MediaOmxReader::HandleResourceAllocated() -{ - EnsureActive(); - - // After resources are available, set the metadata. - if (!mOmxDecoder->EnsureMetadata()) { - mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); - return; - } - - bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3); - if (isMP3 && mMP3FrameParser.IsMP3()) { - // Check if the MP3 frame parser found a duration. - mLastParserDuration = mMP3FrameParser.GetDuration(); - } - - if (mLastParserDuration >= 0) { - // Prefer the parser duration if we have it. - mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(mLastParserDuration)); - } else { - // MP3 parser failed to find a duration. - // Set the total duration (the max of the audio and video track). - int64_t durationUs; - mOmxDecoder->GetDuration(&durationUs); - if (durationUs) { - mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(durationUs)); - } - } - - if (mOmxDecoder->HasVideo()) { - int32_t displayWidth, displayHeight, width, height; - mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight, - &width, &height); - nsIntRect pictureRect(0, 0, width, height); - - // Validate the container-reported frame and pictureRect sizes. This ensures - // that our video frame creation code doesn't overflow. - nsIntSize displaySize(displayWidth, displayHeight); - nsIntSize frameSize(width, height); - if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) { - mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); - return; - } - - // Video track's frame sizes will not overflow. Activate the video track. - mHasVideo = true; - mInfo.mVideo.mDisplay = displaySize; - mPicture = pictureRect; - mInitialFrame = frameSize; - VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); - if (container) { - container->ClearCurrentFrame(IntSize(displaySize.width, displaySize.height)); - } - } - - if (mOmxDecoder->HasAudio()) { - int32_t numChannels, sampleRate; - mOmxDecoder->GetAudioParameters(&numChannels, &sampleRate); - mHasAudio = true; - mInfo.mAudio.mChannels = numChannels; - mInfo.mAudio.mRate = sampleRate; - } - - mInfo.mMediaSeekable = mExtractor->flags() & MediaExtractor::CAN_SEEK; - - RefPtr metadata = new MetadataHolder(); - metadata->mInfo = mInfo; - metadata->mTags = nullptr; - -#ifdef MOZ_AUDIO_OFFLOAD - CheckAudioOffload(); -#endif - - mMetadataPromise.Resolve(metadata, __func__); -} - -bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, - int64_t aTimeThreshold) -{ - MOZ_ASSERT(OnTaskQueue()); - EnsureActive(); - - // Record number of frames decoded and parsed. Automatically update the - // stats counters using the AutoNotifyDecoded stack-based class. - AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder); - - bool doSeek = mVideoSeekTimeUs != -1; - if (doSeek) { - aTimeThreshold = mVideoSeekTimeUs; - } - - TimeStamp start = TimeStamp::Now(); - - // Read next frame. Don't let this loop run for too long. - while ((TimeStamp::Now() - start) < TimeDuration::FromSeconds(MAX_VIDEO_DECODE_SECONDS)) { - MPAPI::VideoFrame frame; - frame.mGraphicBuffer = nullptr; - frame.mShouldSkip = false; - if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) { - return false; - } - doSeek = false; - mVideoSeekTimeUs = -1; - - // Ignore empty buffer which stagefright media read will sporadically return - if (frame.mSize == 0 && !frame.mGraphicBuffer) { - continue; - } - - a.mStats.mParsedFrames++; - if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) { - mSkipCount++; - continue; - } - - mSkipCount = 0; - - aKeyframeSkip = false; - - IntRect picture = mPicture; - if (frame.Y.mWidth != mInitialFrame.width || - frame.Y.mHeight != mInitialFrame.height) { - - // Frame size is different from what the container reports. This is legal, - // and we will preserve the ratio of the crop rectangle as it - // was reported relative to the picture size reported by the container. - picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width; - picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height; - picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width; - picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height; - } - - // This is the approximate byte position in the stream. - int64_t pos = mStreamSource ? mStreamSource->Tell() : 0; - - RefPtr v; - if (!frame.mGraphicBuffer) { - - VideoData::YCbCrBuffer b; - b.mPlanes[0].mData = static_cast(frame.Y.mData); - b.mPlanes[0].mStride = frame.Y.mStride; - b.mPlanes[0].mHeight = frame.Y.mHeight; - b.mPlanes[0].mWidth = frame.Y.mWidth; - b.mPlanes[0].mOffset = frame.Y.mOffset; - b.mPlanes[0].mSkip = frame.Y.mSkip; - - b.mPlanes[1].mData = static_cast(frame.Cb.mData); - b.mPlanes[1].mStride = frame.Cb.mStride; - b.mPlanes[1].mHeight = frame.Cb.mHeight; - b.mPlanes[1].mWidth = frame.Cb.mWidth; - b.mPlanes[1].mOffset = frame.Cb.mOffset; - b.mPlanes[1].mSkip = frame.Cb.mSkip; - - b.mPlanes[2].mData = static_cast(frame.Cr.mData); - b.mPlanes[2].mStride = frame.Cr.mStride; - b.mPlanes[2].mHeight = frame.Cr.mHeight; - b.mPlanes[2].mWidth = frame.Cr.mWidth; - b.mPlanes[2].mOffset = frame.Cr.mOffset; - b.mPlanes[2].mSkip = frame.Cr.mSkip; - - v = VideoData::CreateAndCopyData(mInfo.mVideo, - mDecoder->GetImageContainer(), - pos, - frame.mTimeUs, - 1, // We don't know the duration. - b, - frame.mKeyFrame, - -1, - picture); - } else { - v = VideoData::CreateAndCopyIntoTextureClient( - mInfo.mVideo, - pos, - frame.mTimeUs, - 1, // We don't know the duration. - frame.mGraphicBuffer, - frame.mKeyFrame, - -1, - picture); - } - - if (!v) { - NS_WARNING("Unable to create VideoData"); - return false; - } - - a.mStats.mDecodedFrames++; - NS_ASSERTION(a.mStats.mDecodedFrames <= a.mStats.mParsedFrames, "Expect to decode fewer frames than parsed in OMX decoder..."); - - mVideoQueue.Push(v); - - break; - } - - return true; -} - -void MediaOmxReader::NotifyDataArrivedInternal() -{ - MOZ_ASSERT(OnTaskQueue()); - RefPtr decoder = SafeGetDecoder(); - if (!decoder) { // reader has shut down - return; - } - if (HasVideo()) { - return; - } - if (!mMP3FrameParser.NeedsData()) { - return; - } - - AutoPinned resource(mDecoder->GetResource()); - MediaByteRangeSet byteRanges; - nsresult rv = resource->GetCachedRanges(byteRanges); - - if (NS_FAILED(rv)) { - return; - } - - if (byteRanges == mLastCachedRanges) { - return; - } - MediaByteRangeSet intervals = byteRanges - mLastCachedRanges; - mLastCachedRanges = byteRanges; - - for (const auto& interval : intervals) { - RefPtr bytes = - resource->MediaReadAt(interval.mStart, interval.Length()); - NS_ENSURE_TRUE_VOID(bytes); - mMP3FrameParser.Parse(bytes->Elements(), interval.Length(), interval.mStart); - if (!mMP3FrameParser.IsMP3()) { - return; - } - } - int64_t duration = mMP3FrameParser.GetDuration(); - if (duration != mLastParserDuration) { - mLastParserDuration = duration; - decoder->DispatchUpdateEstimatedMediaDuration(mLastParserDuration); - } -} - -bool MediaOmxReader::DecodeAudioData() -{ - MOZ_ASSERT(OnTaskQueue()); - EnsureActive(); - - // This is the approximate byte position in the stream. - int64_t pos = mStreamSource ? mStreamSource->Tell() : 0; - - // Read next frame - MPAPI::AudioFrame source; - if (!mOmxDecoder->ReadAudio(&source, mAudioSeekTimeUs)) { - return false; - } - mAudioSeekTimeUs = -1; - - // Ignore empty buffer which stagefright media read will sporadically return - if (source.mSize == 0) { - return true; - } - - uint32_t frames = source.mSize / (source.mAudioChannels * - sizeof(AudioDataValue)); - - typedef AudioCompactor::NativeCopy OmxCopy; - return mAudioCompactor.Push(pos, - source.mTimeUs, - source.mAudioSampleRate, - frames, - source.mAudioChannels, - OmxCopy(static_cast(source.mData), - source.mSize, - source.mAudioChannels)); -} - -RefPtr -MediaOmxReader::Seek(SeekTarget aTarget, int64_t aEndTime) -{ - MOZ_ASSERT(OnTaskQueue()); - EnsureActive(); - RefPtr p = mSeekPromise.Ensure(__func__); - - if (mHasAudio && mHasVideo) { - // The OMXDecoder seeks/demuxes audio and video streams separately. So if - // we seek both audio and video to aTarget, the audio stream can typically - // seek closer to the seek target, since typically every audio block is - // a sync point, whereas for video there are only keyframes once every few - // seconds. So if we have both audio and video, we must seek the video - // stream to the preceeding keyframe first, get the stream time, and then - // seek the audio stream to match the video stream's time. Otherwise, the - // audio and video streams won't be in sync after the seek. - mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds(); - - RefPtr self = this; - mSeekRequest.Begin(DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (MediaData* v) { - self->mSeekRequest.Complete(); - self->mAudioSeekTimeUs = v->mTime; - self->mSeekPromise.Resolve(media::TimeUnit::FromMicroseconds(self->mAudioSeekTimeUs), __func__); - }, [self, aTarget] () { - self->mSeekRequest.Complete(); - self->mAudioSeekTimeUs = aTarget.GetTime().ToMicroseconds(); - self->mSeekPromise.Resolve(aTarget.GetTime(), __func__); - })); - } else { - mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget.GetTime().ToMicroseconds(); - mSeekPromise.Resolve(aTarget.GetTime(), __func__); - } - - return p; -} - -void MediaOmxReader::SetIdle() { - if (!mOmxDecoder.get()) { - return; - } - mOmxDecoder->Pause(); -} - -void MediaOmxReader::EnsureActive() { - if (!mOmxDecoder.get()) { - return; - } - DebugOnly result = mOmxDecoder->Play(); - NS_ASSERTION(result == NS_OK, "OmxDecoder should be in play state to continue decoding"); -} - -int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset) -{ - // Could run on decoder thread or IO thread. - RefPtr decoder = SafeGetDecoder(); - if (!decoder) { // reader has shut down - return -1; - } - // We read data in chunks of 32 KiB. We can reduce this - // value if media, such as sdcards, is too slow. - // Because of SD card's slowness, need to keep sReadSize to small size. - // See Bug 914870. - static const int64_t sReadSize = 32 * 1024; - - NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread."); - - MOZ_ASSERT(decoder->GetResource()); - int64_t resourceLength = decoder->GetResource()->GetCachedDataEnd(0); - NS_ENSURE_TRUE(resourceLength >= 0, -1); - - if (aOffset >= resourceLength) { - return 0; // Cache is empty, nothing to do - } - - int64_t bufferLength = std::min(resourceLength-aOffset, sReadSize); - RefPtr runnable( - new NotifyDataArrivedRunnable(this, bufferLength, aOffset, resourceLength)); - - if (OnTaskQueue()) { - runnable->Run(); - } else { - OwnerThread()->Dispatch(runnable.forget()); - } - - return resourceLength - aOffset - bufferLength; -} - -android::sp MediaOmxReader::GetAudioOffloadTrack() -{ - if (!mOmxDecoder.get()) { - return nullptr; - } - return mOmxDecoder->GetAudioOffloadTrack(); -} - -} // namespace mozilla diff --git a/dom/media/omx/MediaOmxReader.h b/dom/media/omx/MediaOmxReader.h deleted file mode 100644 index f27edcf2b727..000000000000 --- a/dom/media/omx/MediaOmxReader.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ -#if !defined(MediaOmxReader_h_) -#define MediaOmxReader_h_ - -#include "MediaOmxCommonReader.h" -#include "MediaResource.h" -#include "MediaDecoderReader.h" -#include "nsMimeTypes.h" -#include "MP3FrameParser.h" -#include "nsRect.h" - -#include -#include - -namespace android { -class OmxDecoder; -class MOZ_EXPORT MediaExtractor; -} - -namespace mozilla { - -class AbstractMediaDecoder; - -class MediaOmxReader : public MediaOmxCommonReader -{ - typedef MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise; - - // This mutex is held when accessing the mIsShutdown variable, which is - // modified on the decode task queue and read on main and IO threads. - Mutex mShutdownMutex; - nsCString mType; - bool mHasVideo; - bool mHasAudio; - nsIntRect mPicture; - nsIntSize mInitialFrame; - int64_t mVideoSeekTimeUs; - int64_t mAudioSeekTimeUs; - int64_t mLastParserDuration; - int32_t mSkipCount; - // If mIsShutdown is false, and mShutdownMutex is held, then - // AbstractMediaDecoder::mDecoder will be non-null. - bool mIsShutdown; - MozPromiseHolder mMetadataPromise; - MozPromiseRequestHolder mMediaResourceRequest; - - MozPromiseHolder mSeekPromise; - MozPromiseRequestHolder mSeekRequest; -protected: - android::sp mOmxDecoder; - android::sp mExtractor; - MP3FrameParser mMP3FrameParser; - - // Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata() - // on decode thread. It create and initialize the OMX decoder including - // setting up custom extractor. The extractor provide the essential - // information used for creating OMX decoder such as video/audio codec. - virtual nsresult InitOmxDecoder(); - - // Called inside DecodeVideoFrame, DecodeAudioData, ReadMetadata and Seek - // to activate the decoder automatically. - virtual void EnsureActive(); - - virtual void HandleResourceAllocated(); - -public: - MediaOmxReader(AbstractMediaDecoder* aDecoder); - ~MediaOmxReader(); - -protected: - void NotifyDataArrivedInternal() override; -public: - - nsresult ResetDecode( - TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack, - TrackInfo::kVideoTrack)) override - { - mSeekRequest.DisconnectIfExists(); - mSeekPromise.RejectIfExists(NS_OK, __func__); - return MediaDecoderReader::ResetDecode(aTracks); - } - - bool DecodeAudioData() override; - bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override; - - void ReleaseResources() override; - - RefPtr AsyncReadMetadata() override; - - RefPtr - Seek(SeekTarget aTarget, int64_t aEndTime) override; - - void SetIdle() override; - - RefPtr Shutdown() override; - - android::sp GetAudioOffloadTrack(); - - // This method is intended only for private use but public only for - // MozPromise::InvokeCallbackMethod(). - void ReleaseDecoder(); - -private: - class ProcessCachedDataTask; - class NotifyDataArrivedRunnable; - - bool HasAudio() override { return mHasAudio; } - bool HasVideo() override { return mHasVideo; } - - bool IsShutdown() { - MutexAutoLock lock(mShutdownMutex); - return mIsShutdown; - } - - int64_t ProcessCachedData(int64_t aOffset); - - already_AddRefed SafeGetDecoder(); - - MediaByteRangeSet mLastCachedRanges; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/omx/MediaStreamSource.cpp b/dom/media/omx/MediaStreamSource.cpp deleted file mode 100644 index a9dd9630935f..000000000000 --- a/dom/media/omx/MediaStreamSource.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 "MediaStreamSource.h" - -#include - -#include "nsISeekableStream.h" - -namespace android { - -MediaStreamSource::MediaStreamSource(MediaResource *aResource) - : mResource(aResource) -{ -} - -MediaStreamSource::~MediaStreamSource() -{ -} - -status_t MediaStreamSource::initCheck() const -{ - return OK; -} - -ssize_t MediaStreamSource::readAt(off64_t offset, void *data, size_t size) -{ - char *ptr = static_cast(data); - size_t todo = size; - while (todo > 0) { - Mutex::Autolock autoLock(mLock); - uint32_t bytesRead; - if ((offset != mResource.Tell() && - NS_FAILED(mResource.Seek(nsISeekableStream::NS_SEEK_SET, offset))) || - NS_FAILED(mResource.Read(ptr, todo, &bytesRead))) { - return ERROR_IO; - } - - if (bytesRead == 0) { - return size - todo; - } - - offset += bytesRead; - todo -= bytesRead; - ptr += bytesRead; - } - return size; -} - -status_t MediaStreamSource::getSize(off64_t *size) -{ - uint64_t length = mResource.GetLength(); - if (length == static_cast(-1)) - return ERROR_UNSUPPORTED; - - *size = length; - - return OK; -} - -int64_t -MediaStreamSource::Tell() -{ - Mutex::Autolock autoLock(mLock); - return mResource.Tell(); -} - -} // namespace android diff --git a/dom/media/omx/MediaStreamSource.h b/dom/media/omx/MediaStreamSource.h deleted file mode 100644 index dc6a67197c9c..000000000000 --- a/dom/media/omx/MediaStreamSource.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 MEDIA_STREAM_SOURCE_H -#define MEDIA_STREAM_SOURCE_H - -#include - -#include -#include - -#include "MediaResource.h" - -namespace android { - -// MediaStreamSource is a DataSource that reads from a MPAPI media stream. -class MediaStreamSource : public DataSource { - typedef mozilla::MediaResource MediaResource; - typedef mozilla::MediaResourceIndex MediaResourceIndex; - - Mutex mLock; - MediaResourceIndex mResource; -public: - MediaStreamSource(MediaResource* aResource); - - status_t initCheck() const override; - ssize_t readAt(off64_t offset, void *data, size_t size) override; - status_t getSize(off64_t *size) override; - uint32_t flags() override { - return kWantsPrefetching; - } - - int64_t Tell(); - - virtual ~MediaStreamSource(); - -private: - MediaStreamSource(const MediaStreamSource &); - MediaStreamSource &operator=(const MediaStreamSource &); -}; - -} // namespace android - -#endif // MEDIA_STREAM_SOURCE_H diff --git a/dom/media/omx/OMXCodecDescriptorUtil.cpp b/dom/media/omx/OMXCodecDescriptorUtil.cpp deleted file mode 100644 index 0350ad865638..000000000000 --- a/dom/media/omx/OMXCodecDescriptorUtil.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* -*- 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 "OMXCodecDescriptorUtil.h" - -namespace android { - -// The utility functions in this file concatenate two AVC/H.264 parameter sets, -// sequence parameter set(SPS) and picture parameter set(PPS), into byte stream -// format or construct AVC decoder config descriptor blob from them. -// -// * NAL unit defined in ISO/IEC 14496-10 7.3.1 -// * SPS defined ISO/IEC 14496-10 7.3.2.1.1 -// * PPS defined in ISO/IEC 14496-10 7.3.2.2 -// -// Byte stream format: -// Start code <0x00 0x00 0x00 0x01> (4 bytes) -// --- (SPS) NAL unit --- -// ... (3 bits) -// NAL unit type <0x07> (5 bits) -// SPS (3+ bytes) -// Profile (1 byte) -// Compatible profiles (1 byte) -// Level (1 byte) -// ... -// --- End --- -// Start code <0x00 0x00 0x00 0x01> (4 bytes) -// --- (PPS) NAL unit --- -// ... (3 bits) -// NAL unit type <0x08> (5 bits) -// PPS (1+ bytes) -// ... -// --- End --- -// -// Descriptor format: (defined in ISO/IEC 14496-15 5.2.4.1.1) -// --- Header (5 bytes) --- -// Version <0x01> (1 byte) -// Profile (1 byte) -// Compatible profiles (1 byte) -// Level (1 byte) -// Reserved <111111> (6 bits) -// NAL length type (2 bits) -// --- Parameter sets --- -// Reserved <111> (3 bits) -// Number of SPS (5 bits) -// SPS (3+ bytes) -// Length (2 bytes) -// SPS NAL unit (1+ bytes) -// ... -// Number of PPS (1 byte) -// PPS (3+ bytes) -// Length (2 bytes) -// PPS NAL unit (1+ bytes) -// ... -// --- End --- - -// NAL unit start code. -static const uint8_t kNALUnitStartCode[] = { 0x00, 0x00, 0x00, 0x01 }; - -// NAL unit types. -enum { - kNALUnitTypeSPS = 0x07, // Value for sequence parameter set. - kNALUnitTypePPS = 0x08, // Value for picture parameter set. - kNALUnitTypeBad = -1, // Malformed data. -}; - -// Sequence parameter set or picture parameter set. -struct AVCParamSet { - AVCParamSet(const uint8_t* aPtr, const size_t aSize) - : mPtr(aPtr) - , mSize(aSize) - { - MOZ_ASSERT(mPtr && mSize > 0); - } - - size_t Size() { - return mSize + 2; // 2 more bytes for length value. - } - - // Append 2 bytes length value and NAL unit bitstream to aOutputBuf. - void AppendTo(nsTArray* aOutputBuf) - { - // 2 bytes length value. - uint8_t size[] = { - uint8_t((mSize & 0xFF00) >> 8), // MSB. - uint8_t(mSize & 0x00FF), // LSB. - }; - aOutputBuf->AppendElements(size, sizeof(size)); - - aOutputBuf->AppendElements(mPtr, mSize); - } - - const uint8_t* mPtr; // Pointer to NAL unit. - const size_t mSize; // NAL unit length in bytes. -}; - -// Convert SPS and PPS data into decoder config descriptor blob. The generated -// blob will be appended to aOutputBuf. -static status_t -ConvertParamSetsToDescriptorBlob(sp& aSPS, sp& aPPS, - nsTArray* aOutputBuf) -{ - // Strip start code in the input. - AVCParamSet sps(aSPS->data() + sizeof(kNALUnitStartCode), - aSPS->size() - sizeof(kNALUnitStartCode)); - AVCParamSet pps(aPPS->data() + sizeof(kNALUnitStartCode), - aPPS->size() - sizeof(kNALUnitStartCode)); - size_t paramSetsSize = sps.Size() + pps.Size(); - - // Profile/level info in SPS. - uint8_t* info = aSPS->data() + 5; - - uint8_t header[] = { - 0x01, // Version. - info[0], // Profile. - info[1], // Compatible profiles. - info[2], // Level. - 0xFF, // 6 bits reserved value <111111> + 2 bits NAL length type <11> - }; - - // Reserve 1 byte for number of SPS & another 1 for number of PPS. - aOutputBuf->SetCapacity(sizeof(header) + paramSetsSize + 2); - // Build the blob. - aOutputBuf->AppendElements(header, sizeof(header)); // 5 bytes Header. - aOutputBuf->AppendElement(0xE0 | 1); // 3 bits <111> + 5 bits number of SPS. - sps.AppendTo(aOutputBuf); // SPS NALU data. - aOutputBuf->AppendElement(1); // 1 byte number of PPS. - pps.AppendTo(aOutputBuf); // PPS NALU data. - - return OK; -} - -static int -NALType(sp& aBuffer) -{ - if (aBuffer == nullptr) { - return kNALUnitTypeBad; - } - // Start code? - uint8_t* data = aBuffer->data(); - if (aBuffer->size() <= 4 || - memcmp(data, kNALUnitStartCode, sizeof(kNALUnitStartCode))) { - return kNALUnitTypeBad; - } - - return data[4] & 0x1F; -} - -// Generate AVC/H.264 decoder config blob. -// See MPEG4Writer::Track::makeAVCCodecSpecificData() and -// MPEG4Writer::Track::writeAvccBox() implementation in libstagefright. -status_t -GenerateAVCDescriptorBlob(sp& aConfigData, - nsTArray* aOutputBuf, - OMXVideoEncoder::BlobFormat aFormat) -{ - // Search for parameter sets using key "csd-0" and "csd-1". - char key[6] = "csd-"; - sp sps; - sp pps; - for (int i = 0; i < 2; i++) { - snprintf(key + 4, 2, "%d", i); - sp paramSet; - bool found = aConfigData->findBuffer(key, ¶mSet); - int type = NALType(paramSet); - bool valid = ((type == kNALUnitTypeSPS) || (type == kNALUnitTypePPS)); - - MOZ_ASSERT(found && valid); - if (!found || !valid) { - return ERROR_MALFORMED; - } - - switch (type) { - case kNALUnitTypeSPS: - sps = paramSet; - break; - case kNALUnitTypePPS: - pps = paramSet; - break; - default: - NS_NOTREACHED("Should not get here!"); - } - } - - MOZ_ASSERT(sps != nullptr && pps != nullptr); - if (sps == nullptr || pps == nullptr) { - return ERROR_MALFORMED; - } - - if (aFormat == OMXVideoEncoder::BlobFormat::AVC_NAL) { - // SPS + PPS. - aOutputBuf->AppendElements(sps->data(), sps->size()); - aOutputBuf->AppendElements(pps->data(), pps->size()); - return OK; - } else { - status_t result = ConvertParamSetsToDescriptorBlob(sps, pps, aOutputBuf); - MOZ_ASSERT(result == OK); - return result; - } -} - -} // namespace android diff --git a/dom/media/omx/OMXCodecDescriptorUtil.h b/dom/media/omx/OMXCodecDescriptorUtil.h deleted file mode 100644 index 9b289531785d..000000000000 --- a/dom/media/omx/OMXCodecDescriptorUtil.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- 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 OMXCodecDescriptorUtil_h_ -#define OMXCodecDescriptorUtil_h_ - -#include -#include - -#include - -#include "OMXCodecWrapper.h" - -namespace android { -// Generate decoder config blob using aConfigData provided by encoder. -// The output will be stored in aOutputBuf. -// aFormat specifies the output format: AVC_MP4 is for MP4 file, and AVC_NAL is -// for RTP packet used by WebRTC. -status_t GenerateAVCDescriptorBlob(sp& aConfigData, - nsTArray* aOutputBuf, - OMXVideoEncoder::BlobFormat aFormat); - -} - -#endif // OMXCodecDescriptorUtil_h_ diff --git a/dom/media/omx/OMXCodecProxy.cpp b/dom/media/omx/OMXCodecProxy.cpp deleted file mode 100644 index 2fa410765a1f..000000000000 --- a/dom/media/omx/OMXCodecProxy.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "OMXCodecProxy" - -#include -#include -#include -#include -#include -#include - -#include "nsDebug.h" - -#include "OMXCodecProxy.h" - -namespace android { - -// static -sp OMXCodecProxy::Create( - const sp &omx, - const sp &meta, bool createEncoder, - const sp &source, - const char *matchComponentName, - uint32_t flags, - const sp &nativeWindow) -{ - sp proxy; - - const char *mime; - if (!meta->findCString(kKeyMIMEType, &mime)) { - return nullptr; - } - - if (!strncasecmp(mime, "video/", 6)) { - proxy = new OMXCodecProxy(omx, meta, createEncoder, source, matchComponentName, flags, nativeWindow); - } - return proxy; -} - - -OMXCodecProxy::OMXCodecProxy( - const sp &omx, - const sp &meta, - bool createEncoder, - const sp &source, - const char *matchComponentName, - uint32_t flags, - const sp &nativeWindow) - : mOMX(omx), - mSrcMeta(meta), - mComponentName(nullptr), - mIsEncoder(createEncoder), - mFlags(flags), - mNativeWindow(nativeWindow), - mSource(source), - mState(ResourceState::START) -{ -} - -OMXCodecProxy::~OMXCodecProxy() -{ - // At first, release mResourceClient's resource to prevent a conflict with - // mResourceClient's callback. - if (mResourceClient) { - mResourceClient->ReleaseResource(); - mResourceClient = nullptr; - } - - mState = ResourceState::END; - mCodecPromise.RejectIfExists(true, __func__); - - if (mOMXCodec.get()) { - wp tmp = mOMXCodec; - mOMXCodec.clear(); - while (tmp.promote() != nullptr) { - // this value come from stagefrigh's AwesomePlayer. - usleep(1000); - } - } - // Complete all pending Binder ipc transactions - IPCThreadState::self()->flushCommands(); - - mSource.clear(); - free(mComponentName); - mComponentName = nullptr; -} - -RefPtr -OMXCodecProxy::requestResource() -{ - Mutex::Autolock autoLock(mLock); - - if (mResourceClient) { - return CodecPromise::CreateAndReject(true, __func__); - } - mState = ResourceState::WAITING; - - mozilla::MediaSystemResourceType type = mIsEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER : - mozilla::MediaSystemResourceType::VIDEO_DECODER; - mResourceClient = new mozilla::MediaSystemResourceClient(type); - mResourceClient->SetListener(this); - mResourceClient->Acquire(); - - RefPtr p = mCodecPromise.Ensure(__func__); - return p.forget(); -} - -// Called on ImageBridge thread -void -OMXCodecProxy::ResourceReserved() -{ - Mutex::Autolock autoLock(mLock); - - if (mState != ResourceState::WAITING) { - mCodecPromise.RejectIfExists(true, __func__); - return; - } - - const char *mime; - if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) { - mState = ResourceState::END; - mCodecPromise.RejectIfExists(true, __func__); - return; - } - - if (!strncasecmp(mime, "video/", 6)) { - sp codec; - mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow); - if (mOMXCodec == nullptr) { - mState = ResourceState::END; - mCodecPromise.RejectIfExists(true, __func__); - return; - } - // Check if this video is sized such that we're comfortable - // possibly using an OMX decoder. - int32_t maxWidth, maxHeight; - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.moz.omx.hw.max_width", propValue, "-1"); - maxWidth = atoi(propValue); - property_get("ro.moz.omx.hw.max_height", propValue, "-1"); - maxHeight = atoi(propValue); - - int32_t width = -1, height = -1; - if (maxWidth > 0 && maxHeight > 0 && - !(mOMXCodec->getFormat()->findInt32(kKeyWidth, &width) && - mOMXCodec->getFormat()->findInt32(kKeyHeight, &height) && - width * height <= maxWidth * maxHeight)) { - printf_stderr("Failed to get video size, or it was too large for HW decoder ( but )", - width, height, maxWidth, maxHeight); - mOMXCodec.clear(); - mState = ResourceState::END; - mCodecPromise.RejectIfExists(true, __func__); - return; - } - - if (mOMXCodec->start() != OK) { - NS_WARNING("Couldn't start OMX video source"); - mOMXCodec.clear(); - mState = ResourceState::END; - mCodecPromise.RejectIfExists(true, __func__); - return; - } - } - - mState = ResourceState::ACQUIRED; - mCodecPromise.ResolveIfExists(true, __func__); -} - -// Called on ImageBridge thread -void -OMXCodecProxy::ResourceReserveFailed() -{ - Mutex::Autolock autoLock(mLock); - mState = ResourceState::NOT_ACQUIRED; - mCodecPromise.RejectIfExists(true, __func__); -} - -status_t -OMXCodecProxy::start(MetaData *params) -{ - Mutex::Autolock autoLock(mLock); - - if (mState != ResourceState::ACQUIRED) { - return NO_INIT; - } - CHECK(mOMXCodec.get() != nullptr); - return mOMXCodec->start(); -} - -status_t -OMXCodecProxy::stop() -{ - Mutex::Autolock autoLock(mLock); - - if (mState != ResourceState::ACQUIRED) { - return NO_INIT; - } - CHECK(mOMXCodec.get() != nullptr); - return mOMXCodec->stop(); -} - -sp -OMXCodecProxy::getFormat() -{ - Mutex::Autolock autoLock(mLock); - - if (mState != ResourceState::ACQUIRED) { - sp meta = new MetaData; - return meta; - } - CHECK(mOMXCodec.get() != nullptr); - return mOMXCodec->getFormat(); -} - -status_t -OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options) -{ - Mutex::Autolock autoLock(mLock); - - if (mState != ResourceState::ACQUIRED) { - return NO_INIT; - } - CHECK(mOMXCodec.get() != nullptr); - return mOMXCodec->read(buffer, options); -} - -status_t -OMXCodecProxy::pause() -{ - Mutex::Autolock autoLock(mLock); - - if (mState != ResourceState::ACQUIRED) { - return NO_INIT; - } - CHECK(mOMXCodec.get() != nullptr); - return mOMXCodec->pause(); -} - -} // namespace android diff --git a/dom/media/omx/OMXCodecProxy.h b/dom/media/omx/OMXCodecProxy.h deleted file mode 100644 index 199d5d0d91c3..000000000000 --- a/dom/media/omx/OMXCodecProxy.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 OMX_CODEC_PROXY_DECODER_H_ -#define OMX_CODEC_PROXY_DECODER_H_ - - -#include -#include -#include -#include -#include - -#include "mozilla/media/MediaSystemResourceClient.h" -#include "mozilla/MozPromise.h" -#include "mozilla/RefPtr.h" - -namespace android { - -struct MetaData; - -class OMXCodecProxy : public MediaSource - , public mozilla::MediaSystemResourceReservationListener -{ -public: - typedef mozilla::MozPromise CodecPromise; - - // Enumeration for the valid resource allcoation states - enum class ResourceState : int8_t { - START, - WAITING, - ACQUIRED, - NOT_ACQUIRED, - END - }; - - static sp Create( - const sp &omx, - const sp &meta, bool createEncoder, - const sp &source, - const char *matchComponentName = nullptr, - uint32_t flags = 0, - const sp &nativeWindow = nullptr); - - RefPtr requestResource(); - - // MediaSystemResourceReservationListener - void ResourceReserved() override; - void ResourceReserveFailed() override; - - // MediaSource - status_t start(MetaData *params = nullptr) override; - status_t stop() override; - - sp getFormat() override; - - status_t read( - MediaBuffer **buffer, const ReadOptions *options = nullptr) override; - - status_t pause() override; - -protected: - OMXCodecProxy( - const sp &omx, - const sp &meta, - bool createEncoder, - const sp &source, - const char *matchComponentName, - uint32_t flags, - const sp &nativeWindow); - - virtual ~OMXCodecProxy(); - -private: - OMXCodecProxy(const OMXCodecProxy &); - OMXCodecProxy &operator=(const OMXCodecProxy &); - - Mutex mLock; - - sp mOMX; - sp mSrcMeta; - char *mComponentName; - bool mIsEncoder; - // Flags specified in the creation of the codec. - uint32_t mFlags; - sp mNativeWindow; - - sp mSource; - - sp mOMXCodec; - - RefPtr mResourceClient; - ResourceState mState; - mozilla::MozPromiseHolder mCodecPromise; -}; - -} // namespace android - -#endif // OMX_CODEC_PROXY_DECODER_H_ diff --git a/dom/media/omx/OMXCodecWrapper.cpp b/dom/media/omx/OMXCodecWrapper.cpp deleted file mode 100644 index e23db3558eca..000000000000 --- a/dom/media/omx/OMXCodecWrapper.cpp +++ /dev/null @@ -1,1132 +0,0 @@ -/* -*- 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 "OMXCodecWrapper.h" -#include "OMXCodecDescriptorUtil.h" -#include "TrackEncoder.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "AudioChannelFormat.h" -#include "GrallocImages.h" -#include "LayersLogging.h" -#include "libyuv.h" -#include "mozilla/Monitor.h" -#include "mozilla/gfx/2D.h" -#include "mozilla/layers/GrallocTextureClient.h" -#include "nsAutoPtr.h" - -using namespace mozilla; -using namespace mozilla::gfx; -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 { \ - __android_log_print(ANDROID_LOG_ERROR, "OMXCodecWrapper", ##args); \ - } while (0) - -namespace android { - -const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc"; - -enum BufferState -{ - BUFFER_OK, - BUFFER_FAIL, - WAIT_FOR_NEW_BUFFER -}; - -bool -OMXCodecReservation::ReserveOMXCodec() -{ - if (!mClient) { - mClient = new mozilla::MediaSystemResourceClient(mType); - } else { - if (mOwned) { - //CODEC_ERROR("OMX Reservation: (%d) already owned", (int) mType); - return true; - } - //CODEC_ERROR("OMX Reservation: (%d) already NOT owned", (int) mType); - } - mOwned = mClient->AcquireSyncNoWait(); // don't wait if resource is not available - //CODEC_ERROR("OMX Reservation: (%d) Acquire was %s", (int) mType, mOwned ? "Successful" : "Failed"); - return mOwned; -} - -void -OMXCodecReservation::ReleaseOMXCodec() -{ - if (!mClient) { - return; - } - //CODEC_ERROR("OMX Reservation: Releasing resource: (%d) %s", (int) mType, mOwned ? "Owned" : "Not owned"); - if (mOwned) { - mClient->ReleaseResource(); - mClient = nullptr; - mOwned = false; - } -} - -OMXAudioEncoder* -OMXCodecWrapper::CreateAACEncoder() -{ - nsAutoPtr aac(new OMXAudioEncoder(CodecType::AAC_ENC)); - // Return the object only when media codec is valid. - NS_ENSURE_TRUE(aac->IsValid(), nullptr); - - return aac.forget(); -} - -OMXAudioEncoder* -OMXCodecWrapper::CreateAMRNBEncoder() -{ - nsAutoPtr amr(new OMXAudioEncoder(CodecType::AMR_NB_ENC)); - // Return the object only when media codec is valid. - NS_ENSURE_TRUE(amr->IsValid(), nullptr); - - 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() -{ - nsAutoPtr avc(new OMXVideoEncoder(CodecType::AVC_ENC)); - // Return the object only when media codec is valid. - NS_ENSURE_TRUE(avc->IsValid(), nullptr); - - return avc.forget(); -} - -OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType) - : mCodecType(aCodecType) - , mStarted(false) - , mAMRCSDProvided(false) - , mEVRCCSDProvided(false) -{ - ProcessState::self()->startThreadPool(); - - mLooper = new ALooper(); - mLooper->start(); - - if (aCodecType == CodecType::AVC_ENC) { - mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_VIDEO_AVC, true); - } else if (aCodecType == CodecType::AMR_NB_ENC) { - 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."); - } -} - -OMXCodecWrapper::~OMXCodecWrapper() -{ - if (mCodec.get()) { - Stop(); - mCodec->release(); - } - mLooper->stop(); -} - -status_t -OMXCodecWrapper::Start() -{ - // Already started. - NS_ENSURE_FALSE(mStarted, OK); - - status_t result = mCodec->start(); - mStarted = (result == OK); - - // Get references to MediaCodec buffers. - if (result == OK) { - mCodec->getInputBuffers(&mInputBufs); - mCodec->getOutputBuffers(&mOutputBufs); - } - - return result; -} - -status_t -OMXCodecWrapper::Stop() -{ - // Already stopped. - NS_ENSURE_TRUE(mStarted, OK); - - status_t result = mCodec->stop(); - mStarted = !(result == OK); - - return result; -} - -// Check system property to see if we're running on emulator. -static bool -IsRunningOnEmulator() -{ - char qemu[PROPERTY_VALUE_MAX]; - property_get("ro.kernel.qemu", qemu, ""); - return strncmp(qemu, "1", 1) == 0; -} - -#define ENCODER_CONFIG_BITRATE 2000000 // bps -// How many seconds between I-frames. -#define ENCODER_CONFIG_I_FRAME_INTERVAL 1 -// Wait up to 5ms for input buffers. - -nsresult -OMXVideoEncoder::Configure(int aWidth, int aHeight, int aFrameRate, - BlobFormat aBlobFormat) -{ - NS_ENSURE_TRUE(aWidth > 0 && aHeight > 0 && aFrameRate > 0, - NS_ERROR_INVALID_ARG); - - OMX_VIDEO_AVCLEVELTYPE level = OMX_VIDEO_AVCLevel3; - OMX_VIDEO_CONTROLRATETYPE bitrateMode = OMX_Video_ControlRateConstant; - - // Set up configuration parameters for AVC/H.264 encoder. - sp format = new AMessage; - // Fixed values - format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC); - format->setInt32("bitrate", ENCODER_CONFIG_BITRATE); - format->setInt32("i-frame-interval", ENCODER_CONFIG_I_FRAME_INTERVAL); - // See mozilla::layers::GrallocImage, supports YUV 4:2:0, CbCr width and - // height is half that of Y - format->setInt32("color-format", OMX_COLOR_FormatYUV420SemiPlanar); - format->setInt32("profile", OMX_VIDEO_AVCProfileBaseline); - format->setInt32("level", level); - format->setInt32("bitrate-mode", bitrateMode); - format->setInt32("store-metadata-in-buffers", 0); - format->setInt32("prepend-sps-pps-to-idr-frames", 0); - // Input values. - format->setInt32("width", aWidth); - format->setInt32("height", aHeight); - format->setInt32("stride", aWidth); - format->setInt32("slice-height", aHeight); - format->setInt32("frame-rate", aFrameRate); - - return ConfigureDirect(format, aBlobFormat); -} - -nsresult -OMXVideoEncoder::ConfigureDirect(sp& aFormat, - BlobFormat aBlobFormat) -{ - // We now allow re-configuration to handle resolution/framerate/etc changes - if (mStarted) { - Stop(); - } - MOZ_ASSERT(!mStarted, "OMX Stop() failed?"); - - int width = 0; - int height = 0; - int frameRate = 0; - aFormat->findInt32("width", &width); - aFormat->findInt32("height", &height); - aFormat->findInt32("frame-rate", &frameRate); - NS_ENSURE_TRUE(width > 0 && height > 0 && frameRate > 0, - NS_ERROR_INVALID_ARG); - - // Limitation of soft AVC/H.264 encoder running on emulator in stagefright. - static bool emu = IsRunningOnEmulator(); - if (emu) { - if (width > 352 || height > 288) { - CODEC_ERROR("SoftAVCEncoder doesn't support resolution larger than CIF"); - return NS_ERROR_INVALID_ARG; - } - aFormat->setInt32("level", OMX_VIDEO_AVCLevel2); - aFormat->setInt32("bitrate-mode", OMX_Video_ControlRateVariable); - } - - - status_t result = mCodec->configure(aFormat, nullptr, nullptr, - MediaCodec::CONFIGURE_FLAG_ENCODE); - NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE); - - mWidth = width; - mHeight = height; - mBlobFormat = aBlobFormat; - - result = Start(); - - return result == OK ? NS_OK : NS_ERROR_FAILURE; -} - -// Copy pixels from planar YUV (4:4:4/4:2:2/4:2:0) or NV21 (semi-planar 4:2:0) -// format to NV12 (semi-planar 4:2:0) format for QCOM HW encoder. -// Planar YUV: YYY...UUU...VVV... -// NV21: YYY...VUVU... -// NV12: YYY...UVUV... -// For 4:4:4/4:2:2 -> 4:2:0, subsample using odd row/column without -// interpolation. -// aSource contains info about source image data, and the result will be stored -// in aDestination, whose size needs to be >= Y plane size * 3 / 2. -static void -ConvertPlanarYCbCrToNV12(const PlanarYCbCrData* aSource, uint8_t* aDestination) -{ - // Fill Y plane. - uint8_t* y = aSource->mYChannel; - IntSize ySize = aSource->mYSize; - - // Y plane. - for (int i = 0; i < ySize.height; i++) { - memcpy(aDestination, y, ySize.width); - aDestination += ySize.width; - y += aSource->mYStride; - } - - // Fill interleaved UV plane. - uint8_t* u = aSource->mCbChannel; - uint8_t* v = aSource->mCrChannel; - IntSize uvSize = aSource->mCbCrSize; - // Subsample to 4:2:0 if source is 4:4:4 or 4:2:2. - // Y plane width & height should be multiple of U/V plane width & height. - MOZ_ASSERT(ySize.width % uvSize.width == 0 && - ySize.height % uvSize.height == 0); - size_t uvWidth = ySize.width / 2; - size_t uvHeight = ySize.height / 2; - size_t horiSubsample = uvSize.width / uvWidth; - size_t uPixStride = horiSubsample * (1 + aSource->mCbSkip); - size_t vPixStride = horiSubsample * (1 + aSource->mCrSkip); - size_t lineStride = uvSize.height / uvHeight * aSource->mCbCrStride; - - for (size_t i = 0; i < uvHeight; i++) { - // 1st pixel per line. - uint8_t* uSrc = u; - uint8_t* vSrc = v; - for (size_t j = 0; j < uvWidth; j++) { - *aDestination++ = *uSrc; - *aDestination++ = *vSrc; - // Pick next source pixel. - uSrc += uPixStride; - vSrc += vPixStride; - } - // Pick next source line. - u += lineStride; - v += lineStride; - } -} - -// Convert pixels in graphic buffer to NV12 format. aSource is the layer image -// containing source graphic buffer, and aDestination is the destination of -// conversion. Currently 3 source format are supported: -// - NV21/HAL_PIXEL_FORMAT_YCrCb_420_SP (from camera preview window). -// - YV12/HAL_PIXEL_FORMAT_YV12 (from video decoder). -// - QCOM proprietary/HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS (from Flame HW video decoder) -static void -ConvertGrallocImageToNV12(GrallocImage* aSource, uint8_t* aDestination) -{ - // Get graphic buffer. - sp graphicBuffer = aSource->GetGraphicBuffer(); - - int pixelFormat = graphicBuffer->getPixelFormat(); - - void* imgPtr = nullptr; - graphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_MASK, &imgPtr); - // Build PlanarYCbCrData for NV21 or YV12 buffer. - PlanarYCbCrData yuv; - switch (pixelFormat) { - case HAL_PIXEL_FORMAT_YCrCb_420_SP: // From camera. - yuv.mYChannel = static_cast(imgPtr); - yuv.mYSkip = 0; - yuv.mYSize.width = graphicBuffer->getWidth(); - yuv.mYSize.height = graphicBuffer->getHeight(); - yuv.mYStride = graphicBuffer->getStride(); - // 4:2:0. - yuv.mCbCrSize.width = yuv.mYSize.width / 2; - yuv.mCbCrSize.height = yuv.mYSize.height / 2; - // Interleaved VU plane. - yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height); - yuv.mCrSkip = 1; - yuv.mCbChannel = yuv.mCrChannel + 1; - yuv.mCbSkip = 1; - yuv.mCbCrStride = yuv.mYStride; - ConvertPlanarYCbCrToNV12(&yuv, aDestination); - break; - case HAL_PIXEL_FORMAT_YV12: // From video decoder. - // Android YV12 format is defined in system/core/include/system/graphics.h - yuv.mYChannel = static_cast(imgPtr); - yuv.mYSkip = 0; - yuv.mYSize.width = graphicBuffer->getWidth(); - yuv.mYSize.height = graphicBuffer->getHeight(); - yuv.mYStride = graphicBuffer->getStride(); - // 4:2:0. - yuv.mCbCrSize.width = yuv.mYSize.width / 2; - yuv.mCbCrSize.height = yuv.mYSize.height / 2; - yuv.mCrChannel = yuv.mYChannel + (yuv.mYStride * yuv.mYSize.height); - // Aligned to 16 bytes boundary. - yuv.mCbCrStride = (yuv.mYStride / 2 + 15) & ~0x0F; - yuv.mCrSkip = 0; - yuv.mCbChannel = yuv.mCrChannel + (yuv.mCbCrStride * yuv.mCbCrSize.height); - yuv.mCbSkip = 0; - ConvertPlanarYCbCrToNV12(&yuv, aDestination); - break; - // From QCOM video decoder on Flame. See bug 997593. - case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: - // Venus formats are doucmented in kernel/include/media/msm_media_info.h: - yuv.mYChannel = static_cast(imgPtr); - yuv.mYSkip = 0; - yuv.mYSize.width = graphicBuffer->getWidth(); - yuv.mYSize.height = graphicBuffer->getHeight(); - // - Y & UV Width aligned to 128 - yuv.mYStride = (yuv.mYSize.width + 127) & ~127; - yuv.mCbCrSize.width = yuv.mYSize.width / 2; - yuv.mCbCrSize.height = yuv.mYSize.height / 2; - // - Y height aligned to 32 - yuv.mCbChannel = yuv.mYChannel + (yuv.mYStride * ((yuv.mYSize.height + 31) & ~31)); - // Interleaved VU plane. - yuv.mCbSkip = 1; - yuv.mCrChannel = yuv.mCbChannel + 1; - yuv.mCrSkip = 1; - yuv.mCbCrStride = yuv.mYStride; - ConvertPlanarYCbCrToNV12(&yuv, aDestination); - break; - default: - NS_ERROR("Unsupported input gralloc image type. Should never be here."); - } - - graphicBuffer->unlock(); -} - -static nsresult -ConvertSourceSurfaceToNV12(const RefPtr& aSurface, uint8_t* aDestination) -{ - if (!aSurface) { - CODEC_ERROR("Getting surface from image failed"); - return NS_ERROR_FAILURE; - } - - uint32_t width = aSurface->GetSize().width; - uint32_t height = aSurface->GetSize().height; - - uint8_t* y = aDestination; - int yStride = width; - - uint8_t* uv = y + (yStride * height); - int uvStride = width / 2; - - RefPtr data = aSurface->GetDataSurface(); - if (!data) { - CODEC_ERROR("Getting data surface from %s image with %s surface failed", - Stringify(aSurface->GetFormat()).c_str(), - Stringify(aSurface->GetType()).c_str()); - return NS_ERROR_FAILURE; - } - - DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); - if (!map.IsMapped()) { - CODEC_ERROR("Reading DataSourceSurface from %s image with %s surface failed", - Stringify(aSurface->GetFormat()).c_str(), - Stringify(aSurface->GetType()).c_str()); - return NS_ERROR_FAILURE; - } - - int rv; - switch (aSurface->GetFormat()) { - case SurfaceFormat::B8G8R8A8: - case SurfaceFormat::B8G8R8X8: - rv = libyuv::ARGBToNV12(static_cast(map.GetData()), - map.GetStride(), - y, yStride, - uv, uvStride, - width, height); - break; - default: - CODEC_ERROR("Unsupported SourceSurface format %s", - Stringify(aSurface->GetFormat()).c_str()); - NS_ASSERTION(false, "Unsupported SourceSurface format"); - return NS_ERROR_NOT_IMPLEMENTED; - } - - if (rv != 0) { - CODEC_ERROR("%s to I420 conversion failed", - Stringify(aSurface->GetFormat()).c_str()); - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -nsresult -OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight, - int64_t aTimestamp, int aInputFlags, bool* aSendEOS) -{ - MOZ_ASSERT(mStarted, "Configure() should be called before Encode()."); - - NS_ENSURE_TRUE(aWidth == mWidth && aHeight == mHeight && aTimestamp >= 0, - NS_ERROR_INVALID_ARG); - - Image* img = const_cast(aImage); - ImageFormat format = ImageFormat::PLANAR_YCBCR; - if (img) { - format = img->GetFormat(); - gfx::IntSize size = img->GetSize(); - // Validate input image. - NS_ENSURE_TRUE(aWidth == size.width, NS_ERROR_INVALID_ARG); - NS_ENSURE_TRUE(aHeight == size.height, NS_ERROR_INVALID_ARG); - if (format == ImageFormat::PLANAR_YCBCR) { - // Test for data, allowing AdoptData() on an image without an mBuffer - // (as used from WebrtcOMXH264VideoCodec, and a few other places) - bug 1067442 - const PlanarYCbCrData* yuv = static_cast(img)->GetData(); - NS_ENSURE_TRUE(yuv->mYChannel, NS_ERROR_INVALID_ARG); - } else if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) { - // Reject unsupported gralloc-ed buffers. - int halFormat = static_cast(img)->GetGraphicBuffer()->getPixelFormat(); - NS_ENSURE_TRUE(halFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP || - halFormat == HAL_PIXEL_FORMAT_YV12 || - halFormat == GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS, - NS_ERROR_INVALID_ARG); - } else { - RefPtr surface = img->GetAsSourceSurface(); - NS_ENSURE_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8A8 || - surface->GetFormat() == SurfaceFormat::B8G8R8X8, - NS_ERROR_INVALID_ARG); - } - } - - status_t result; - - // Dequeue an input buffer. - uint32_t index; - result = mCodec->dequeueInputBuffer(&index, INPUT_BUFFER_TIMEOUT_US); - if (result == -EAGAIN) { - // Drop the frame when out of input buffer. - return NS_OK; - } - NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE); - - const sp& inBuf = mInputBufs.itemAt(index); - uint8_t* dst = inBuf->data(); - size_t dstSize = inBuf->capacity(); - - size_t yLen = aWidth * aHeight; - size_t uvLen = yLen / 2; - // Buffer should be large enough to hold input image data. - MOZ_ASSERT(dstSize >= yLen + uvLen); - - dstSize = yLen + uvLen; - inBuf->setRange(0, dstSize); - if (!img) { - // Generate muted/black image directly in buffer. - // Fill Y plane. - memset(dst, 0x10, yLen); - // Fill UV plane. - memset(dst + yLen, 0x80, uvLen); - } else { - if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) { - ConvertGrallocImageToNV12(static_cast(img), dst); - } else if (format == ImageFormat::PLANAR_YCBCR) { - ConvertPlanarYCbCrToNV12(static_cast(img)->GetData(), - dst); - } else { - RefPtr surface = img->GetAsSourceSurface(); - nsresult rv = ConvertSourceSurfaceToNV12(surface, dst); - - if (rv != NS_OK) { - return NS_ERROR_FAILURE; - } - } - } - - // Queue this input buffer. - result = mCodec->queueInputBuffer(index, 0, dstSize, aTimestamp, aInputFlags); - - if (aSendEOS && (aInputFlags & BUFFER_EOS) && result == OK) { - *aSendEOS = true; - } - return result == OK ? NS_OK : NS_ERROR_FAILURE; -} - -status_t -OMXVideoEncoder::AppendDecoderConfig(nsTArray* aOutputBuf, - ABuffer* aData) -{ - // Codec already parsed aData. Using its result makes generating config blob - // much easier. - sp format; - mCodec->getOutputFormat(&format); - - // NAL unit format is needed by WebRTC for RTP packets; AVC/H.264 decoder - // config descriptor is needed to construct MP4 'avcC' box. - status_t result = GenerateAVCDescriptorBlob(format, aOutputBuf, mBlobFormat); - - return result; -} - -// Override to replace NAL unit start code with 4-bytes unit length. -// See ISO/IEC 14496-15 5.2.3. -void -OMXVideoEncoder::AppendFrame(nsTArray* aOutputBuf, - const uint8_t* aData, size_t aSize) -{ - aOutputBuf->SetCapacity(aSize); - - if (mBlobFormat == BlobFormat::AVC_NAL) { - // Append NAL format data without modification. - aOutputBuf->AppendElements(aData, aSize); - return; - } - // Replace start code with data length. - uint8_t length[] = { - uint8_t((aSize >> 24) & 0xFF), - uint8_t((aSize >> 16) & 0xFF), - uint8_t((aSize >> 8) & 0xFF), - uint8_t(aSize & 0xFF), - }; - aOutputBuf->AppendElements(length, sizeof(length)); - aOutputBuf->AppendElements(aData + sizeof(length), aSize); -} - -// MediaCodec::setParameters() is available only after API level 18. -#if ANDROID_VERSION >= 18 -nsresult -OMXVideoEncoder::SetBitrate(int32_t aKbps) -{ - sp msg = new AMessage(); -#if ANDROID_VERSION >= 19 - // XXX Do we need a runtime check here? - msg->setInt32("video-bitrate", aKbps * 1000 /* kbps -> bps */); -#else - msg->setInt32("videoBitrate", aKbps * 1000 /* kbps -> bps */); -#endif - status_t result = mCodec->setParameters(msg); - MOZ_ASSERT(result == OK); - return result == OK ? NS_OK : NS_ERROR_FAILURE; -} -#endif - -nsresult -OMXVideoEncoder::RequestIDRFrame() -{ - MOZ_ASSERT(mStarted, "Configure() should be called before RequestIDRFrame()."); - return mCodec->requestIDRFrame() == OK ? NS_OK : NS_ERROR_FAILURE; -} - -nsresult -OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate, - int aEncodedSampleRate) -{ - MOZ_ASSERT(!mStarted); - - NS_ENSURE_TRUE(aChannels > 0 && aInputSampleRate > 0 && aEncodedSampleRate >= 0, - NS_ERROR_INVALID_ARG); - - if (aInputSampleRate != aEncodedSampleRate) { - int error; - mResampler = speex_resampler_init(aChannels, - aInputSampleRate, - aEncodedSampleRate, - SPEEX_RESAMPLER_QUALITY_DEFAULT, - &error); - - if (error != RESAMPLER_ERR_SUCCESS) { - return NS_ERROR_FAILURE; - } - speex_resampler_skip_zeros(mResampler); - } - // Set up configuration parameters for AAC encoder. - sp format = new AMessage; - // Fixed values. - if (mCodecType == AAC_ENC) { - format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC); - format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC); - format->setInt32("bitrate", kAACBitrate); - format->setInt32("sample-rate", aInputSampleRate); - } else if (mCodecType == AMR_NB_ENC) { - 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!!"); - } - // Input values. - format->setInt32("channel-count", aChannels); - - status_t result = mCodec->configure(format, nullptr, nullptr, - MediaCodec::CONFIGURE_FLAG_ENCODE); - NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE); - - mChannels = aChannels; - mSampleDuration = 1000000 / aInputSampleRate; - mResamplingRatio = aEncodedSampleRate > 0 ? 1.0 * - aEncodedSampleRate / aInputSampleRate : 1.0; - result = Start(); - - return result == OK ? NS_OK : NS_ERROR_FAILURE; -} - -class InputBufferHelper final { -public: - InputBufferHelper(sp& aCodec, Vector >& aBuffers, - OMXAudioEncoder& aEncoder, int aInputFlags) - : mCodec(aCodec) - , mBuffers(aBuffers) - , mOMXAEncoder(aEncoder) - , mInputFlags(aInputFlags) - , mIndex(0) - , mData(nullptr) - , mCapicity(0) - , mOffset(0) - {} - - ~InputBufferHelper() - { - // Unflushed data in buffer. - MOZ_ASSERT(!mData); - } - - status_t Dequeue() - { - // Shouldn't have dequeued buffer. - MOZ_ASSERT(!mData); - - status_t result = mCodec->dequeueInputBuffer(&mIndex, - INPUT_BUFFER_TIMEOUT_US); - NS_ENSURE_TRUE(result == OK, result); - sp inBuf = mBuffers.itemAt(mIndex); - mData = inBuf->data(); - mCapicity = inBuf->capacity(); - mOffset = 0; - - return OK; - } - - status_t Enqueue(int64_t aTimestamp, int aFlags) - { - // Should have dequeued buffer. - MOZ_ASSERT(mData); - - // Queue this buffer. - status_t result = mCodec->queueInputBuffer(mIndex, 0, mOffset, aTimestamp, - aFlags); - NS_ENSURE_TRUE(result == OK, result); - mData = nullptr; - - return OK; - } - - // Read audio data in aChunk, resample them if needed, - // and then send the result to OMX input buffer (or buffers if one buffer is not enough). - // aSamplesRead will be the number of samples that have been read from aChunk. - BufferState ReadChunk(AudioChunk& aChunk, size_t* aSamplesRead) - { - size_t chunkSamples = aChunk.GetDuration(); - size_t bytesToCopy = chunkSamples * mOMXAEncoder.mResamplingRatio - * mOMXAEncoder.mChannels * sizeof(AudioDataValue); - size_t bytesCopied = 0; - if (bytesToCopy <= AvailableSize()) { - if (aChunk.IsNull()) { - bytesCopied = SendSilenceToBuffer(chunkSamples); - } else { - bytesCopied = SendChunkToBuffer(aChunk, chunkSamples); - } - UpdateAfterSendChunk(chunkSamples, bytesCopied, aSamplesRead); - } else { - // Interleave data to a temporary buffer. - AutoTArray pcm; - pcm.SetLength(bytesToCopy); - AudioDataValue* interleavedSource = pcm.Elements(); - AudioTrackEncoder::InterleaveTrackData(aChunk, chunkSamples, - mOMXAEncoder.mChannels, - interleavedSource); - - // When the data size of chunk is larger than the buffer capacity, - // we split it into sub-chunks to fill up buffers. - size_t subChunkSamples = 0; - while(GetNextSubChunk(bytesToCopy, subChunkSamples)) { - // To avoid enqueueing an empty buffer, we follow the order that - // clear up buffer first, then create one, send data to it in the end. - if (!IsEmpty()) { - // Submit the filled-up buffer and request a new buffer. - status_t result = Enqueue(mOMXAEncoder.mTimestamp, - mInputFlags & ~OMXCodecWrapper::BUFFER_EOS); - if (result != OK) { - return BUFFER_FAIL; - } - - result = Dequeue(); - if (result == -EAGAIN) { - return WAIT_FOR_NEW_BUFFER; - } - if (result != OK) { - return BUFFER_FAIL; - } - } - if (aChunk.IsNull()) { - bytesCopied = SendSilenceToBuffer(subChunkSamples); - } else { - bytesCopied = SendInterleavedSubChunkToBuffer(interleavedSource, subChunkSamples); - } - UpdateAfterSendChunk(subChunkSamples, bytesCopied, aSamplesRead); - // Move to the position where samples are not yet send to the buffer. - interleavedSource += subChunkSamples * mOMXAEncoder.mChannels; - } - } - return BUFFER_OK; - } - - // No audio data left in segment but we still have to feed something to - // MediaCodec in order to notify EOS. - void SendEOSToBuffer(size_t* aSamplesRead) - { - size_t bytesToCopy = SendSilenceToBuffer(1); - IncreaseOffset(bytesToCopy); - *aSamplesRead = 1; - } - -private: - uint8_t* GetPointer() { return mData + mOffset; } - - size_t AvailableSize() const { return mCapicity - mOffset; } - - void IncreaseOffset(size_t aValue) - { - // Should never out of bound. - MOZ_ASSERT(mOffset + aValue <= mCapicity); - mOffset += aValue; - } - - bool IsEmpty() const - { - return (mOffset == 0); - } - - size_t GetCapacity() const - { - return mCapicity; - } - - // Update buffer offset, timestamp and the total number of copied samples. - void UpdateAfterSendChunk(size_t aSamplesNum, size_t aBytesToCopy, - size_t* aSourceSamplesCopied) - { - *aSourceSamplesCopied += aSamplesNum; - mOMXAEncoder.mTimestamp += aSamplesNum * mOMXAEncoder.mSampleDuration; - IncreaseOffset(aBytesToCopy); - } - - // Send slince auido data when the chunk is null, - // and return the copied bytes number of audio data. - size_t SendSilenceToBuffer(size_t aSamplesNum) - { - AudioDataValue* dst = reinterpret_cast(GetPointer()); - size_t bytesToCopy = aSamplesNum * mOMXAEncoder.mResamplingRatio - * mOMXAEncoder.mChannels * sizeof(AudioDataValue); - memset(dst, 0, bytesToCopy); - return bytesToCopy; - } - - // Interleave chunk data and send it to buffer, - // and return the copied bytes number of audio data. - size_t SendChunkToBuffer(AudioChunk& aSource, size_t aSamplesNum) - { - AudioDataValue* dst = reinterpret_cast(GetPointer()); - size_t bytesToCopy = aSamplesNum * mOMXAEncoder.mResamplingRatio - * mOMXAEncoder.mChannels * sizeof(AudioDataValue); - uint32_t dstSamplesCopied = aSamplesNum; - if (mOMXAEncoder.mResampler) { - AutoTArray pcm; - pcm.SetLength(bytesToCopy); - AudioTrackEncoder::InterleaveTrackData(aSource, aSamplesNum, - mOMXAEncoder.mChannels, - pcm.Elements()); - int16_t* tempSource = reinterpret_cast(pcm.Elements()); - speex_resampler_process_interleaved_int(mOMXAEncoder.mResampler, tempSource, - &aSamplesNum, dst, - &dstSamplesCopied); - } else { - AudioTrackEncoder::InterleaveTrackData(aSource, aSamplesNum, - mOMXAEncoder.mChannels, dst); - } - return dstSamplesCopied * mOMXAEncoder.mChannels * sizeof(AudioDataValue); - } - - // Send the interleaved data of the sub chunk to buffer, - // and return the copied bytes number of audio data. - size_t SendInterleavedSubChunkToBuffer(AudioDataValue* aSource, - size_t aSamplesNum) - { - AudioDataValue* dst = reinterpret_cast(GetPointer()); - uint32_t dstSamplesCopied = aSamplesNum; - if (mOMXAEncoder.mResampler) { - int16_t* tempSource = reinterpret_cast(aSource); - speex_resampler_process_interleaved_int(mOMXAEncoder.mResampler, - tempSource, &aSamplesNum, - dst, &dstSamplesCopied); - } else { - // Directly copy interleaved data into buffer - memcpy(dst, aSource, - aSamplesNum * mOMXAEncoder.mChannels * sizeof(AudioDataValue)); - } - return dstSamplesCopied * mOMXAEncoder.mChannels * sizeof(AudioDataValue); - } - - // Determine the size of sub-chunk (aSamplesToCopy) according to buffer capacity. - // For subsequent call, the number of bytes remain to be copied will also be updated in this function. - bool GetNextSubChunk(size_t& aBytesToCopy, size_t& aSamplesToCopy) - { - size_t bufferCapabity = GetCapacity(); - size_t sampleBytes = mOMXAEncoder.mChannels * mOMXAEncoder.mResamplingRatio - * sizeof(AudioDataValue); - if (aBytesToCopy) { - if (aBytesToCopy > bufferCapabity) { - aSamplesToCopy = bufferCapabity / sampleBytes; - aBytesToCopy -= aSamplesToCopy * sampleBytes; - } else { - aSamplesToCopy = aBytesToCopy / sampleBytes; - aBytesToCopy = 0; - } - return true; - } - return false; - } - - sp& mCodec; - Vector >& mBuffers; - OMXAudioEncoder& mOMXAEncoder; - int mInputFlags; - size_t mIndex; - uint8_t* mData; - size_t mCapicity; - size_t mOffset; -}; - -OMXAudioEncoder::~OMXAudioEncoder() -{ - if (mResampler) { - speex_resampler_destroy(mResampler); - mResampler = nullptr; - } -} - -nsresult -OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags, - bool* aSendEOS) -{ -#ifndef MOZ_SAMPLE_TYPE_S16 -#error MediaCodec accepts only 16-bit PCM data. -#endif - - MOZ_ASSERT(mStarted, "Configure() should be called before Encode()."); - - size_t numSamples = aSegment.GetDuration(); - - // Get input buffer. - InputBufferHelper buffer(mCodec, mInputBufs, *this, aInputFlags); - status_t result = buffer.Dequeue(); - if (result == -EAGAIN) { - // All input buffers are full. Caller can try again later after consuming - // some output buffers. - return NS_OK; - } - NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE); - - size_t sourceSamplesCopied = 0; // Number of copied samples. - - if (numSamples > 0) { - // Copy input PCM data to input buffer until queue is empty. - AudioSegment::ChunkIterator iter(const_cast(aSegment)); - while (!iter.IsEnded()) { - BufferState result = buffer.ReadChunk(*iter, &sourceSamplesCopied); - if (result == WAIT_FOR_NEW_BUFFER) { - // All input buffers are full. Caller can try again later after - // consuming some output buffers. - aSegment.RemoveLeading(sourceSamplesCopied); - return NS_OK; - } else if (result == BUFFER_FAIL) { - return NS_ERROR_FAILURE; - } else { - iter.Next(); - } - } - // Remove the samples already been copied into buffer - if (sourceSamplesCopied > 0) { - aSegment.RemoveLeading(sourceSamplesCopied); - } - } else if (aInputFlags & BUFFER_EOS) { - buffer.SendEOSToBuffer(&sourceSamplesCopied); - } - - // Enqueue the remaining data to buffer - MOZ_ASSERT(sourceSamplesCopied > 0, "No data needs to be enqueued!"); - int flags = aInputFlags; - if (aSegment.GetDuration() > 0) { - // Don't signal EOS until source segment is empty. - flags &= ~BUFFER_EOS; - } - result = buffer.Enqueue(mTimestamp, flags); - NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE); - if (aSendEOS && (aInputFlags & BUFFER_EOS)) { - *aSendEOS = true; - } - return NS_OK; -} - -// Generate decoder config descriptor (defined in ISO/IEC 14496-1 8.3.4.1) for -// AAC. The hard-coded bytes are copied from -// MPEG4Writer::Track::writeMp4aEsdsBox() implementation in libstagefright. -status_t -OMXAudioEncoder::AppendDecoderConfig(nsTArray* aOutputBuf, - ABuffer* aData) -{ - MOZ_ASSERT(aData); - - const size_t csdSize = aData->size(); - - // See - // http://wiki.multimedia.cx/index.php?title=Understanding_AAC#Packaging.2FEncapsulation_And_Setup_Data - // AAC decoder specific descriptor contains 2 bytes. - NS_ENSURE_TRUE(csdSize == 2, ERROR_MALFORMED); - // Encoder output must be consistent with kAACFrameDuration: - // 14th bit (frame length flag) == 0 => 1024 (kAACFrameDuration) samples. - NS_ENSURE_TRUE((aData->data()[1] & 0x04) == 0, ERROR_MALFORMED); - - // Decoder config descriptor - const uint8_t decConfig[] = { - 0x04, // Decoder config descriptor tag. - uint8_t(15 + csdSize), // Size: following bytes + csd size. - 0x40, // Object type: MPEG-4 audio. - 0x15, // Stream type: audio, reserved: 1. - 0x00, 0x03, 0x00, // Buffer size: 768 (kAACFrameSize). - 0x00, 0x01, 0x77, 0x00, // Max bitrate: 96000 (kAACBitrate). - 0x00, 0x01, 0x77, 0x00, // Avg bitrate: 96000 (kAACBitrate). - 0x05, // Decoder specific descriptor tag. - uint8_t(csdSize), // Data size. - }; - // SL config descriptor. - const uint8_t slConfig[] = { - 0x06, // SL config descriptor tag. - 0x01, // Size. - 0x02, // Fixed value. - }; - - aOutputBuf->SetCapacity(sizeof(decConfig) + csdSize + sizeof(slConfig)); - aOutputBuf->AppendElements(decConfig, sizeof(decConfig)); - aOutputBuf->AppendElements(aData->data(), csdSize); - aOutputBuf->AppendElements(slConfig, sizeof(slConfig)); - - return OK; -} - -nsresult -OMXCodecWrapper::GetNextEncodedFrame(nsTArray* aOutputBuf, - int64_t* aOutputTimestamp, - int* aOutputFlags, int64_t aTimeOut) -{ - MOZ_ASSERT(mStarted, - "Configure() should be called before GetNextEncodedFrame()."); - - // Dequeue a buffer from output buffers. - size_t index = 0; - size_t outOffset = 0; - size_t outSize = 0; - int64_t outTimeUs = 0; - uint32_t outFlags = 0; - bool retry = false; - do { - status_t result = mCodec->dequeueOutputBuffer(&index, &outOffset, &outSize, - &outTimeUs, &outFlags, - aTimeOut); - switch (result) { - case OK: - break; - case INFO_OUTPUT_BUFFERS_CHANGED: - // Update our references to new buffers. - result = mCodec->getOutputBuffers(&mOutputBufs); - // Get output from a new buffer. - retry = true; - break; - case INFO_FORMAT_CHANGED: - // It's okay: for encoder, MediaCodec reports this only to inform caller - // that there will be a codec config buffer next. - return NS_OK; - case -EAGAIN: - // Output buffer not available. Caller can try again later. - return NS_OK; - default: - CODEC_ERROR("MediaCodec error:%d", result); - MOZ_ASSERT(false, "MediaCodec error."); - return NS_ERROR_FAILURE; - } - } while (retry); - - if (aOutputBuf) { - aOutputBuf->Clear(); - const sp omxBuf = mOutputBufs.itemAt(index); - if (outFlags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { - // Codec specific data. - if (AppendDecoderConfig(aOutputBuf, omxBuf.get()) != OK) { - mCodec->releaseOutputBuffer(index); - return NS_ERROR_FAILURE; - } - } else if ((mCodecType == AMR_NB_ENC) && !mAMRCSDProvided){ - // OMX AMR 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 - 0x83, 0xFF, // mode set: all enabled - 0x00, // mode change period - 0x01, // frames per sample - }; - 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()); - } - } - mCodec->releaseOutputBuffer(index); - - if (aOutputTimestamp) { - *aOutputTimestamp = outTimeUs; - } - - if (aOutputFlags) { - *aOutputFlags = outFlags; - } - - return NS_OK; -} - -} diff --git a/dom/media/omx/OMXCodecWrapper.h b/dom/media/omx/OMXCodecWrapper.h deleted file mode 100644 index b17f4ad5eefd..000000000000 --- a/dom/media/omx/OMXCodecWrapper.h +++ /dev/null @@ -1,368 +0,0 @@ -/* -*- 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 OMXCodecWrapper_h_ -#define OMXCodecWrapper_h_ - -#include -#include -#include -#include -#include - -#include "AudioSegment.h" -#include "GonkNativeWindow.h" -#include "mozilla/media/MediaSystemResourceClient.h" -#include "mozilla/RefPtr.h" - -#include - -namespace android { - -// Wrapper class for managing HW codec reservations -class OMXCodecReservation : public RefBase -{ -public: - OMXCodecReservation(bool aEncoder) : mOwned(false) - { - mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER : - mozilla::MediaSystemResourceType::VIDEO_DECODER; - } - - virtual ~OMXCodecReservation() - { - ReleaseOMXCodec(); - } - - /** Reserve the Encode or Decode resource for this instance */ - virtual bool ReserveOMXCodec(); - - /** Release the Encode or Decode resource for this instance */ - virtual void ReleaseOMXCodec(); - -private: - mozilla::MediaSystemResourceType mType; - bool mOwned; // We already own this resource - - RefPtr mClient; -}; - - -class OMXAudioEncoder; -class OMXVideoEncoder; - -/** - * This class (and its subclasses) wraps the video and audio codec from - * MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and - * AAC audio encoder are supported. - * - * OMXCodecWrapper has static creator functions that returns actual codec - * instances for different types of codec supported and serves as superclass to - * provide a function to read encoded data as byte array from codec. Two - * subclasses, OMXAudioEncoder and OMXVideoEncoder, respectively provides - * functions for encoding data from audio and video track. - * - * A typical usage is as follows: - * - Call one of the creator function Create...() to get either a - * OMXAudioEncoder or OMXVideoEncoder object. - * - Configure codec by providing characteristics of input raw data, such as - * video frame width and height, using Configure(). - * - Send raw data (and notify end of stream) with Encode(). - * - Get encoded data through GetNextEncodedFrame(). - * - Repeat previous 2 steps until end of stream. - * - Destroy the object. - * - * The lifecycle of underlying OMX codec is binded with construction and - * destruction of OMXCodecWrapper and subclass objects. For some types of - * codecs, such as HW accelerated AVC/H.264 encoder, there can be only one - * instance system-wise at a time, attempting to create another instance will - * fail. - */ -class OMXCodecWrapper -{ -public: - // Codec types. - enum CodecType { - AAC_ENC, // AAC encoder. - AMR_NB_ENC, // AMR_NB encoder. - AVC_ENC, // AVC/H.264 encoder. - EVRC_ENC, // EVRC encoder - TYPE_COUNT - }; - - // Input and output flags. - enum { - // For Encode() and Encode, it indicates the end of input stream; - // For GetNextEncodedFrame(), it indicates the end of output - // stream. - BUFFER_EOS = MediaCodec::BUFFER_FLAG_EOS, - // For GetNextEncodedFrame(). It indicates the output buffer is an I-frame. - BUFFER_SYNC_FRAME = MediaCodec::BUFFER_FLAG_SYNCFRAME, - // For GetNextEncodedFrame(). It indicates that the output buffer contains - // codec specific configuration info. (SPS & PPS for AVC/H.264; - // DecoderSpecificInfo for AAC) - BUFFER_CODEC_CONFIG = MediaCodec::BUFFER_FLAG_CODECCONFIG, - }; - - // Hard-coded values for AAC DecoderConfigDescriptor in libstagefright. - // See MPEG4Writer::Track::writeMp4aEsdsBox() - // Exposed for the need of MP4 container writer. - enum { - kAACBitrate = 96000, // kbps - kAACFrameSize = 768, // bytes - kAACFrameDuration = 1024, // How many samples per AAC frame. - }; - - /** Create a AAC audio encoder. Returns nullptr when failed. */ - static OMXAudioEncoder* CreateAACEncoder(); - - /** 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(); - - virtual ~OMXCodecWrapper(); - - /** - * Get the next available encoded data from MediaCodec. The data will be - * copied into aOutputBuf array, with its timestamp (in microseconds) in - * aOutputTimestamp. - * Wait at most aTimeout microseconds to dequeue a output buffer. - */ - nsresult GetNextEncodedFrame(nsTArray* aOutputBuf, - int64_t* aOutputTimestamp, int* aOutputFlags, - int64_t aTimeOut); - /* - * Get the codec type - */ - int GetCodecType() { return mCodecType; } -protected: - /** - * See whether the object has been initialized successfully and is ready to - * use. - */ - virtual bool IsValid() { return mCodec != nullptr; } - - /** - * Construct codec specific configuration blob with given data aData generated - * by media codec and append it into aOutputBuf. Needed by MP4 container - * writer for generating decoder config box, or WebRTC for generating RTP - * packets. Returns OK if succeed. - */ - virtual status_t AppendDecoderConfig(nsTArray* aOutputBuf, - ABuffer* aData) = 0; - - /** - * Append encoded frame data generated by media codec (stored in aData and - * is aSize bytes long) into aOutputBuf. Subclasses can override this function - * to process the data for specific container writer. - */ - virtual void AppendFrame(nsTArray* aOutputBuf, - const uint8_t* aData, size_t aSize) - { - aOutputBuf->AppendElements(aData, aSize); - } - -private: - // Hide these. User should always use creator functions to get a media codec. - OMXCodecWrapper() = delete; - OMXCodecWrapper(const OMXCodecWrapper&) = delete; - OMXCodecWrapper& operator=(const OMXCodecWrapper&) = delete; - - /** - * Create a media codec of given type. It will be a AVC/H.264 video encoder if - * aCodecType is CODEC_AVC_ENC, or AAC audio encoder if aCodecType is - * CODEC_AAC_ENC. - */ - OMXCodecWrapper(CodecType aCodecType); - - // For subclasses to access hidden constructor and implementation details. - friend class OMXAudioEncoder; - friend class OMXVideoEncoder; - - /** - * Start the media codec. - */ - status_t Start(); - - /** - * Stop the media codec. - */ - status_t Stop(); - - // The actual codec instance provided by libstagefright. - sp mCodec; - - // A dedicate message loop with its own thread used by MediaCodec. - sp mLooper; - - Vector > mInputBufs; // MediaCodec buffers to hold input data. - Vector > mOutputBufs; // MediaCodec buffers to hold output data. - - int mCodecType; - bool mStarted; // Has MediaCodec been started? - bool mAMRCSDProvided; - bool mEVRCCSDProvided; -}; - -/** - * Audio encoder. - */ -class OMXAudioEncoder final : public OMXCodecWrapper -{ -public: - /** - * Configure audio codec parameters and start media codec. It must be called - * before calling Encode() and GetNextEncodedFrame(). - * aReSamplingRate = 0 means no resampler required - */ - nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate); - - /** - * Encode 16-bit PCM audio samples stored in aSegment. To notify end of - * stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers, - * this function might not be able to encode all chunks in one call, however - * it will remove chunks it consumes from aSegment. - * aSendEOS is the output to tell the caller EOS signal sent into MediaCodec - * because the signal might not be sent due to the dequeueInputBuffer timeout. - * And the value of aSendEOS won't be set to any default value, only set to - * true when EOS signal sent into MediaCodec. - */ - nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0, - bool* aSendEOS = nullptr); - - ~OMXAudioEncoder(); -protected: - virtual status_t AppendDecoderConfig(nsTArray* aOutputBuf, - ABuffer* aData) override; -private: - // Hide these. User should always use creator functions to get a media codec. - OMXAudioEncoder() = delete; - OMXAudioEncoder(const OMXAudioEncoder&) = delete; - OMXAudioEncoder& operator=(const OMXAudioEncoder&) = delete; - - /** - * Create a audio codec. It will be a AAC encoder if aCodecType is - * CODEC_AAC_ENC. - */ - OMXAudioEncoder(CodecType aCodecType) - : OMXCodecWrapper(aCodecType) - , mResampler(nullptr) - , mChannels(0) - , mResamplingRatio(0) - , mTimestamp(0) - , mSampleDuration(0) {} - - // For creator function to access hidden constructor. - friend class OMXCodecWrapper; - friend class InputBufferHelper; - - /** - * If the input sample rate does not divide 48kHz evenly, the input data are - * resampled. - */ - SpeexResamplerState* mResampler; - // Number of audio channels. - size_t mChannels; - - float mResamplingRatio; - // The total duration of audio samples that have been encoded in microseconds. - int64_t mTimestamp; - // Time per audio sample in microseconds. - int64_t mSampleDuration; -}; - -/** - * Video encoder. - */ -class OMXVideoEncoder final : public OMXCodecWrapper -{ -public: - // Types of output blob format. - enum BlobFormat { - AVC_MP4, // MP4 file config descripter (defined in ISO/IEC 14496-15 5.2.4.1.1) - AVC_NAL // NAL (Network Abstract Layer) (defined in ITU-T H.264 7.4.1) - }; - - /** - * Configure video codec parameters and start media codec. It must be called - * before calling Encode() and GetNextEncodedFrame(). - * aBlobFormat specifies output blob format provided by encoder. It can be - * AVC_MP4 or AVC_NAL. - * Configure sets up most format value to values appropriate for camera use. - * ConfigureDirect lets the caller determine all the defaults. - */ - nsresult Configure(int aWidth, int aHeight, int aFrameRate, - BlobFormat aBlobFormat = BlobFormat::AVC_MP4); - nsresult ConfigureDirect(sp& aFormat, - BlobFormat aBlobFormat = BlobFormat::AVC_MP4); - - /** - * Encode a aWidth pixels wide and aHeight pixels tall video frame of - * semi-planar YUV420 format stored in the buffer of aImage. aTimestamp gives - * the frame timestamp/presentation time (in microseconds). To notify end of - * stream, set aInputFlags to BUFFER_EOS. - * aSendEOS is the output to tell the caller EOS signal sent into MediaCodec - * because the signal might not be sent due to the dequeueInputBuffer timeout. - * And the value of aSendEOS won't be set to any default value, only set to - * true when EOS signal sent into MediaCodec. - */ - nsresult Encode(const mozilla::layers::Image* aImage, int aWidth, int aHeight, - int64_t aTimestamp, int aInputFlags = 0, - bool* aSendEOS = nullptr); - -#if ANDROID_VERSION >= 18 - /** Set encoding bitrate (in kbps). */ - nsresult SetBitrate(int32_t aKbps); -#endif - - /** - * Ask codec to generate an instantaneous decoding refresh (IDR) frame - * (defined in ISO/IEC 14496-10). - */ - nsresult RequestIDRFrame(); - -protected: - virtual status_t AppendDecoderConfig(nsTArray* aOutputBuf, - ABuffer* aData) override; - - // If configured to output MP4 format blob, AVC/H.264 encoder has to replace - // NAL unit start code with the unit length as specified in - // ISO/IEC 14496-15 5.2.3. - virtual void AppendFrame(nsTArray* aOutputBuf, - const uint8_t* aData, size_t aSize) override; - -private: - // Hide these. User should always use creator functions to get a media codec. - OMXVideoEncoder() = delete; - OMXVideoEncoder(const OMXVideoEncoder&) = delete; - OMXVideoEncoder& operator=(const OMXVideoEncoder&) = delete; - - /** - * Create a video codec. It will be a AVC/H.264 encoder if aCodecType is - * CODEC_AVC_ENC. - */ - OMXVideoEncoder(CodecType aCodecType) - : OMXCodecWrapper(aCodecType) - , mWidth(0) - , mHeight(0) - , mBlobFormat(BlobFormat::AVC_MP4) - {} - - // For creator function to access hidden constructor. - friend class OMXCodecWrapper; - - int mWidth; - int mHeight; - BlobFormat mBlobFormat; -}; - -} // namespace android - -#endif // OMXCodecWrapper_h_ diff --git a/dom/media/omx/OmxDecoder.cpp b/dom/media/omx/OmxDecoder.cpp deleted file mode 100644 index 3c670014f0db..000000000000 --- a/dom/media/omx/OmxDecoder.cpp +++ /dev/null @@ -1,940 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 -#include - -#include "base/basictypes.h" -#include -#include -#include -#include -#include -#include -#include -#include -#if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17 -#include -#endif - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 -#include -#else -#include -#endif - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/TextureClient.h" -#include "mozilla/Types.h" -#include "mozilla/Monitor.h" -#include "nsMimeTypes.h" -#include "MPAPI.h" -#include "mozilla/Logging.h" - -#include "GonkNativeWindow.h" -#include "OMXCodecProxy.h" -#include "OmxDecoder.h" - -#include -#define OD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "OmxDecoder", __VA_ARGS__) - -#undef LOG -mozilla::LazyLogModule gOmxDecoderLog("OmxDecoder"); -#define LOG(type, msg...) MOZ_LOG(gOmxDecoderLog, type, (msg)) - -using namespace MPAPI; -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; -using namespace android; - -OmxDecoder::OmxDecoder(AbstractMediaDecoder *aDecoder, - mozilla::TaskQueue* aTaskQueue) : - mDecoder(aDecoder), - mDisplayWidth(0), - mDisplayHeight(0), - mVideoWidth(0), - mVideoHeight(0), - mVideoColorFormat(0), - mVideoStride(0), - mVideoSliceHeight(0), - mVideoRotation(0), - mAudioChannels(-1), - mAudioSampleRate(-1), - mDurationUs(-1), - mLastSeekTime(-1), - mVideoBuffer(nullptr), - mAudioBuffer(nullptr), - mIsVideoSeeking(false), - mAudioMetadataRead(false), - mTaskQueue(aTaskQueue), - mAudioPaused(false), - mVideoPaused(false) -{ - mLooper = new ALooper; - mLooper->setName("OmxDecoder"); - - mReflector = new AHandlerReflector(this); - // Register AMessage handler to ALooper. - mLooper->registerHandler(mReflector); - // Start ALooper thread. - mLooper->start(); -} - -OmxDecoder::~OmxDecoder() -{ - MOZ_ASSERT(NS_IsMainThread()); - - ReleaseMediaResources(); - - // unregister AMessage handler from ALooper. - mLooper->unregisterHandler(mReflector->id()); - // Stop ALooper thread. - mLooper->stop(); -} - -static sp sOMX = nullptr; -static sp GetOMX() -{ - if(sOMX.get() == nullptr) { - sOMX = new OMX; - } - return sOMX; -} - -bool -OmxDecoder::Init(sp& extractor) { - sp meta = extractor->getMetaData(); - - ssize_t audioTrackIndex = -1; - ssize_t videoTrackIndex = -1; - - for (size_t i = 0; i < extractor->countTracks(); ++i) { - sp meta = extractor->getTrackMetaData(i); - - int32_t bitRate; - if (!meta->findInt32(kKeyBitRate, &bitRate)) - bitRate = 0; - - const char *mime; - if (!meta->findCString(kKeyMIMEType, &mime)) { - continue; - } - - if (videoTrackIndex == -1 && !strncasecmp(mime, "video/", 6)) { - videoTrackIndex = i; - } else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) { - audioTrackIndex = i; - } - } - - if (videoTrackIndex == -1 && audioTrackIndex == -1) { - NS_WARNING("OMX decoder could not find video or audio tracks"); - return false; - } - - if (videoTrackIndex != -1 && mDecoder->GetImageContainer()) { - mVideoTrack = extractor->getTrack(videoTrackIndex); - } - - if (audioTrackIndex != -1) { - mAudioTrack = extractor->getTrack(audioTrackIndex); - -#ifdef MOZ_AUDIO_OFFLOAD - // mAudioTrack is be used by OMXCodec. For offloaded audio track, using same - // object gives undetermined behavior. So get a new track - mAudioOffloadTrack = extractor->getTrack(audioTrackIndex); -#endif - } - return true; -} - -bool -OmxDecoder::EnsureMetadata() { - // calculate duration - int64_t totalDurationUs = 0; - int64_t durationUs = 0; - if (mVideoTrack.get() && mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { - if (durationUs > totalDurationUs) - totalDurationUs = durationUs; - } - if (mAudioTrack.get()) { - durationUs = -1; - sp meta = mAudioTrack->getFormat(); - - if ((durationUs == -1) && meta->findInt64(kKeyDuration, &durationUs)) { - if (durationUs > totalDurationUs) { - totalDurationUs = durationUs; - } - } - } - mDurationUs = totalDurationUs; - - // read video metadata - if (mVideoSource.get() && !SetVideoFormat()) { - NS_WARNING("Couldn't set OMX video format"); - return false; - } - - // read audio metadata - if (mAudioSource.get()) { - // To reliably get the channel and sample rate data we need to read from the - // audio source until we get a INFO_FORMAT_CHANGE status - status_t err = mAudioSource->read(&mAudioBuffer); - if (err != INFO_FORMAT_CHANGED) { - if (err != OK) { - NS_WARNING("Couldn't read audio buffer from OMX decoder"); - return false; - } - sp meta = mAudioSource->getFormat(); - if (!meta->findInt32(kKeyChannelCount, &mAudioChannels) || - !meta->findInt32(kKeySampleRate, &mAudioSampleRate)) { - NS_WARNING("Couldn't get audio metadata from OMX decoder"); - return false; - } - mAudioMetadataRead = true; - } - else if (!SetAudioFormat()) { - NS_WARNING("Couldn't set audio format"); - return false; - } - } - - return true; -} - -static bool isInEmulator() -{ - char propQemu[PROPERTY_VALUE_MAX]; - property_get("ro.kernel.qemu", propQemu, ""); - return !strncmp(propQemu, "1", 1); -} - -RefPtr -OmxDecoder::AllocateMediaResources() -{ - RefPtr p = mMediaResourcePromise.Ensure(__func__); - - if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) { - // OMXClient::connect() always returns OK and abort's fatally if - // it can't connect. - OMXClient client; - DebugOnly err = client.connect(); - NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver."); - sp omx = client.interface(); - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 - sp producer; - sp consumer; - GonkBufferQueue::createBufferQueue(&producer, &consumer); - mNativeWindow = new GonkNativeWindow(consumer); -#else - mNativeWindow = new GonkNativeWindow(); -#endif - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 - mNativeWindowClient = new Surface(producer); -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 - mNativeWindowClient = new Surface(mNativeWindow->getBufferQueue()); -#else - mNativeWindowClient = new SurfaceTextureClient(mNativeWindow); -#endif - - // Experience with OMX codecs is that only the HW decoders are - // worth bothering with, at least on the platforms where this code - // is currently used, and for formats this code is currently used - // for (h.264). So if we don't get a hardware decoder, just give - // up. -#ifdef MOZ_OMX_WEBM_DECODER - int flags = 0;//fallback to omx sw decoder if there is no hw decoder -#else - int flags = kHardwareCodecsOnly; -#endif//MOZ_OMX_WEBM_DECODER - - if (isInEmulator()) { - // If we are in emulator, allow to fall back to software. - flags = 0; - } - mVideoSource = - OMXCodecProxy::Create(omx, - mVideoTrack->getFormat(), - false, // decoder - mVideoTrack, - nullptr, - flags, - mNativeWindowClient); - if (mVideoSource == nullptr) { - NS_WARNING("Couldn't create OMX video source"); - mMediaResourcePromise.Reject(true, __func__); - return p; - } else { - sp self = this; - mVideoCodecRequest.Begin(mVideoSource->requestResource() - ->Then(OwnerThread(), __func__, - [self] (bool) -> void { - self->mVideoCodecRequest.Complete(); - self->mMediaResourcePromise.ResolveIfExists(true, __func__); - }, [self] (bool) -> void { - self->mVideoCodecRequest.Complete(); - self->mMediaResourcePromise.RejectIfExists(true, __func__); - })); - } - } - - if ((mAudioTrack != nullptr) && (mAudioSource == nullptr)) { - // OMXClient::connect() always returns OK and abort's fatally if - // it can't connect. - OMXClient client; - DebugOnly err = client.connect(); - NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver."); - sp omx = client.interface(); - - const char *audioMime = nullptr; - sp meta = mAudioTrack->getFormat(); - if (!meta->findCString(kKeyMIMEType, &audioMime)) { - mMediaResourcePromise.Reject(true, __func__); - return p; - } - if (!strcasecmp(audioMime, "audio/raw")) { - mAudioSource = mAudioTrack; - } else { - // try to load hardware codec in mediaserver process. - int flags = kHardwareCodecsOnly; - mAudioSource = OMXCodec::Create(omx, - mAudioTrack->getFormat(), - false, // decoder - mAudioTrack, - nullptr, - flags); - } - - if (mAudioSource == nullptr) { - // try to load software codec in this process. - int flags = kSoftwareCodecsOnly; - mAudioSource = OMXCodec::Create(GetOMX(), - mAudioTrack->getFormat(), - false, // decoder - mAudioTrack, - nullptr, - flags); - if (mAudioSource == nullptr) { - NS_WARNING("Couldn't create OMX audio source"); - mMediaResourcePromise.Reject(true, __func__); - return p; - } - } - if (mAudioSource->start() != OK) { - NS_WARNING("Couldn't start OMX audio source"); - mAudioSource.clear(); - mMediaResourcePromise.Reject(true, __func__); - return p; - } - } - if (!mVideoSource.get()) { - // No resource allocation wait. - mMediaResourcePromise.Resolve(true, __func__); - } - return p; -} - - -void -OmxDecoder::ReleaseMediaResources() { - mVideoCodecRequest.DisconnectIfExists(); - mMediaResourcePromise.RejectIfExists(true, __func__); - - ReleaseVideoBuffer(); - ReleaseAudioBuffer(); - - { - Mutex::Autolock autoLock(mPendingVideoBuffersLock); - MOZ_ASSERT(mPendingRecycleTexutreClients.empty()); - // Release all pending recycle TextureClients, if they are not recycled yet. - // This should not happen. See Bug 1042308. - if (!mPendingRecycleTexutreClients.empty()) { - printf_stderr("OmxDecoder::ReleaseMediaResources -- TextureClients are not recycled yet\n"); - for (std::set::iterator it=mPendingRecycleTexutreClients.begin(); - it!=mPendingRecycleTexutreClients.end(); it++) - { - GrallocTextureData* client = static_cast((*it)->GetInternalData()); - (*it)->ClearRecycleCallback(); - if (client->GetMediaBuffer()) { - mPendingVideoBuffers.push(BufferItem(client->GetMediaBuffer(), (*it)->GetAndResetReleaseFenceHandle())); - } - } - mPendingRecycleTexutreClients.clear(); - } - } - - { - // Free all pending video buffers. - Mutex::Autolock autoLock(mSeekLock); - ReleaseAllPendingVideoBuffersLocked(); - } - - if (mVideoSource.get()) { - mVideoSource->stop(); - mVideoSource.clear(); - } - - if (mAudioSource.get()) { - mAudioSource->stop(); - mAudioSource.clear(); - } - - mNativeWindowClient.clear(); - mNativeWindow.clear(); - - // Reset this variable to make the first seek go to the previous keyframe - // when resuming - mLastSeekTime = -1; -} - -bool -OmxDecoder::SetVideoFormat() { - const char *componentName; - - if (!mVideoSource->getFormat()->findInt32(kKeyWidth, &mVideoWidth) || - !mVideoSource->getFormat()->findInt32(kKeyHeight, &mVideoHeight) || - !mVideoSource->getFormat()->findCString(kKeyDecoderComponent, &componentName) || - !mVideoSource->getFormat()->findInt32(kKeyColorFormat, &mVideoColorFormat) ) { - return false; - } - - if (!mVideoTrack.get() || !mVideoTrack->getFormat()->findInt32(kKeyDisplayWidth, &mDisplayWidth)) { - mDisplayWidth = mVideoWidth; - NS_WARNING("display width not available, assuming width"); - } - - if (!mVideoTrack.get() || !mVideoTrack->getFormat()->findInt32(kKeyDisplayHeight, &mDisplayHeight)) { - mDisplayHeight = mVideoHeight; - NS_WARNING("display height not available, assuming height"); - } - - if (!mVideoSource->getFormat()->findInt32(kKeyStride, &mVideoStride)) { - mVideoStride = mVideoWidth; - NS_WARNING("stride not available, assuming width"); - } - - if (!mVideoSource->getFormat()->findInt32(kKeySliceHeight, &mVideoSliceHeight)) { - mVideoSliceHeight = mVideoHeight; - NS_WARNING("slice height not available, assuming height"); - } - - // Since ICS, valid video side is caluculated from kKeyCropRect. - // kKeyWidth means decoded video buffer width. - // kKeyHeight means decoded video buffer height. - // On some hardwares, decoded video buffer and valid video size are different. - int32_t crop_left, crop_top, crop_right, crop_bottom; - if (mVideoSource->getFormat()->findRect(kKeyCropRect, - &crop_left, - &crop_top, - &crop_right, - &crop_bottom)) { - mVideoWidth = crop_right - crop_left + 1; - mVideoHeight = crop_bottom - crop_top + 1; - } - - if (!mVideoSource->getFormat()->findInt32(kKeyRotation, &mVideoRotation)) { - mVideoRotation = 0; - NS_WARNING("rotation not available, assuming 0"); - } - - LOG(LogLevel::Debug, "display width: %d display height %d width: %d height: %d component: %s format: %d stride: %d sliceHeight: %d rotation: %d", - mDisplayWidth, mDisplayHeight, mVideoWidth, mVideoHeight, componentName, - mVideoColorFormat, mVideoStride, mVideoSliceHeight, mVideoRotation); - - return true; -} - -bool -OmxDecoder::SetAudioFormat() { - // If the format changed, update our cached info. - if (!mAudioSource->getFormat()->findInt32(kKeyChannelCount, &mAudioChannels) || - !mAudioSource->getFormat()->findInt32(kKeySampleRate, &mAudioSampleRate)) { - return false; - } - - LOG(LogLevel::Debug, "channelCount: %d sampleRate: %d", - mAudioChannels, mAudioSampleRate); - - return true; -} - -void -OmxDecoder::ReleaseDecoder() -{ - mDecoder = nullptr; -} - -void -OmxDecoder::ReleaseVideoBuffer() { - if (mVideoBuffer) { - mVideoBuffer->release(); - mVideoBuffer = nullptr; - } -} - -void -OmxDecoder::ReleaseAudioBuffer() { - if (mAudioBuffer) { - mAudioBuffer->release(); - mAudioBuffer = nullptr; - } -} - -void -OmxDecoder::PlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) { - void *y = aData; - void *u = static_cast(y) + mVideoStride * mVideoSliceHeight; - void *v = static_cast(u) + mVideoStride/2 * mVideoSliceHeight/2; - - aFrame->Set(aTimeUs, aKeyFrame, - aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation, - y, mVideoStride, mVideoWidth, mVideoHeight, 0, 0, - u, mVideoStride/2, mVideoWidth/2, mVideoHeight/2, 0, 0, - v, mVideoStride/2, mVideoWidth/2, mVideoHeight/2, 0, 0); -} - -void -OmxDecoder::CbYCrYFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) { - aFrame->Set(aTimeUs, aKeyFrame, - aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation, - aData, mVideoStride, mVideoWidth, mVideoHeight, 1, 1, - aData, mVideoStride, mVideoWidth/2, mVideoHeight/2, 0, 3, - aData, mVideoStride, mVideoWidth/2, mVideoHeight/2, 2, 3); -} - -void -OmxDecoder::SemiPlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) { - void *y = aData; - void *uv = static_cast(y) + (mVideoStride * mVideoSliceHeight); - - aFrame->Set(aTimeUs, aKeyFrame, - aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation, - y, mVideoStride, mVideoWidth, mVideoHeight, 0, 0, - uv, mVideoStride, mVideoWidth/2, mVideoHeight/2, 0, 1, - uv, mVideoStride, mVideoWidth/2, mVideoHeight/2, 1, 1); -} - -void -OmxDecoder::SemiPlanarYVU420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) { - SemiPlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame); - aFrame->Cb.mOffset = 1; - aFrame->Cr.mOffset = 0; -} - -bool -OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) { - const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; - - aFrame->mGraphicBuffer = nullptr; - - switch (mVideoColorFormat) { - case OMX_COLOR_FormatYUV420Planar: - PlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame); - break; - case OMX_COLOR_FormatCbYCrY: - CbYCrYFrame(aFrame, aTimeUs, aData, aSize, aKeyFrame); - break; - case OMX_COLOR_FormatYUV420SemiPlanar: - SemiPlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame); - break; - case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: - SemiPlanarYVU420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame); - break; - default: - LOG(LogLevel::Debug, "Unknown video color format %08x", mVideoColorFormat); - return false; - } - return true; -} - -bool -OmxDecoder::ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize, int32_t aAudioChannels, int32_t aAudioSampleRate) -{ - aFrame->Set(aTimeUs, static_cast(aData) + aDataOffset, aSize, aAudioChannels, aAudioSampleRate); - return true; -} - -bool -OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs, - bool aKeyframeSkip, bool aDoSeek) -{ - if (!mVideoSource.get()) - return false; - - ReleaseVideoBuffer(); - - status_t err; - - if (aDoSeek) { - { - Mutex::Autolock autoLock(mSeekLock); - ReleaseAllPendingVideoBuffersLocked(); - mIsVideoSeeking = true; - } - MediaSource::ReadOptions options; - MediaSource::ReadOptions::SeekMode seekMode; - // If the last timestamp of decoded frame is smaller than seekTime, - // seek to next key frame. Otherwise seek to the previos one. - OD_LOG("SeekTime: %lld, mLastSeekTime:%lld", aTimeUs, mLastSeekTime); - if (mLastSeekTime == -1 || mLastSeekTime > aTimeUs) { - seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC; - } else { - seekMode = MediaSource::ReadOptions::SEEK_NEXT_SYNC; - } - mLastSeekTime = aTimeUs; - bool findNextBuffer = true; - while (findNextBuffer) { - options.setSeekTo(aTimeUs, seekMode); - findNextBuffer = false; - if (mIsVideoSeeking) { - err = mVideoSource->read(&mVideoBuffer, &options); - Mutex::Autolock autoLock(mSeekLock); - mIsVideoSeeking = false; - PostReleaseVideoBuffer(nullptr, FenceHandle()); - } - else { - err = mVideoSource->read(&mVideoBuffer); - } - - // If there is no next Keyframe, jump to the previous key frame. - if (err == ERROR_END_OF_STREAM && seekMode == MediaSource::ReadOptions::SEEK_NEXT_SYNC) { - seekMode = MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC; - findNextBuffer = true; - { - Mutex::Autolock autoLock(mSeekLock); - mIsVideoSeeking = true; - } - continue; - } else if (err != OK) { - OD_LOG("Unexpected error when seeking to %lld", aTimeUs); - break; - } - // For some codecs, the length of first decoded frame after seek is 0. - // Need to ignore it and continue to find the next one - if (mVideoBuffer->range_length() == 0) { - PostReleaseVideoBuffer(mVideoBuffer, FenceHandle()); - findNextBuffer = true; - } - } - aDoSeek = false; - } else { - err = mVideoSource->read(&mVideoBuffer); - } - - aFrame->mSize = 0; - - if (err == OK) { - int64_t timeUs; - int32_t unreadable; - int32_t keyFrame; - - size_t length = mVideoBuffer->range_length(); - - if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) { - NS_WARNING("OMX decoder did not return frame time"); - return false; - } - - if (!mVideoBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) { - keyFrame = 0; - } - - if (!mVideoBuffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)) { - unreadable = 0; - } - - RefPtr textureClient; - if ((mVideoBuffer->graphicBuffer().get())) { - textureClient = mNativeWindow->getTextureClientFromBuffer(mVideoBuffer->graphicBuffer().get()); - } - - if (textureClient) { - // Manually increment reference count to keep MediaBuffer alive - // during TextureClient is in use. - mVideoBuffer->add_ref(); - static_cast(textureClient->GetInternalData())->SetMediaBuffer(mVideoBuffer); - // Set recycle callback for TextureClient - textureClient->SetRecycleCallback(OmxDecoder::RecycleCallback, this); - { - Mutex::Autolock autoLock(mPendingVideoBuffersLock); - // Store pending recycle TextureClient. - MOZ_ASSERT(mPendingRecycleTexutreClients.find(textureClient) == mPendingRecycleTexutreClients.end()); - mPendingRecycleTexutreClients.insert(textureClient); - } - - aFrame->mGraphicBuffer = textureClient; - aFrame->mRotation = mVideoRotation; - aFrame->mTimeUs = timeUs; - aFrame->mKeyFrame = keyFrame; - aFrame->Y.mWidth = mVideoWidth; - aFrame->Y.mHeight = mVideoHeight; - // Release to hold video buffer in OmxDecoder more. - // MediaBuffer's ref count is changed from 2 to 1. - ReleaseVideoBuffer(); - } else if (length > 0) { - char *data = static_cast(mVideoBuffer->data()) + mVideoBuffer->range_offset(); - - if (unreadable) { - LOG(LogLevel::Debug, "video frame is unreadable"); - } - - if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame)) { - return false; - } - } - // Check if this frame is valid or not. If not, skip it. - if ((aKeyframeSkip && timeUs < aTimeUs) || length == 0) { - aFrame->mShouldSkip = true; - } - } - else if (err == INFO_FORMAT_CHANGED) { - // If the format changed, update our cached info. - if (!SetVideoFormat()) { - return false; - } else { - return ReadVideo(aFrame, aTimeUs, aKeyframeSkip, aDoSeek); - } - } - else if (err == ERROR_END_OF_STREAM) { - return false; - } - else if (err == -ETIMEDOUT) { - LOG(LogLevel::Debug, "OmxDecoder::ReadVideo timed out, will retry"); - return true; - } - else { - // UNKNOWN_ERROR is sometimes is used to mean "out of memory", but - // regardless, don't keep trying to decode if the decoder doesn't want to. - LOG(LogLevel::Debug, "OmxDecoder::ReadVideo failed, err=%d", err); - return false; - } - - return true; -} - -bool -OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs) -{ - status_t err; - - if (mAudioMetadataRead && aSeekTimeUs == -1) { - // Use the data read into the buffer during metadata time - err = OK; - } - else { - ReleaseAudioBuffer(); - if (aSeekTimeUs != -1) { - MediaSource::ReadOptions options; - options.setSeekTo(aSeekTimeUs); - err = mAudioSource->read(&mAudioBuffer, &options); - } else { - err = mAudioSource->read(&mAudioBuffer); - } - } - mAudioMetadataRead = false; - - aSeekTimeUs = -1; - aFrame->mSize = 0; - - if (err == OK && mAudioBuffer && mAudioBuffer->range_length() != 0) { - int64_t timeUs; - if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) - return false; - - return ToAudioFrame(aFrame, timeUs, - mAudioBuffer->data(), - mAudioBuffer->range_offset(), - mAudioBuffer->range_length(), - mAudioChannels, mAudioSampleRate); - } - else if (err == INFO_FORMAT_CHANGED) { - // If the format changed, update our cached info. - if (!SetAudioFormat()) { - return false; - } else { - return ReadAudio(aFrame, aSeekTimeUs); - } - } - else if (err == ERROR_END_OF_STREAM) { - if (aFrame->mSize == 0) { - return false; - } - } - else if (err == -ETIMEDOUT) { - LOG(LogLevel::Debug, "OmxDecoder::ReadAudio timed out, will retry"); - return true; - } - else if (err != OK) { - LOG(LogLevel::Debug, "OmxDecoder::ReadAudio failed, err=%d", err); - return false; - } - - return true; -} - -nsresult -OmxDecoder::Play() -{ - if (!mVideoPaused && !mAudioPaused) { - return NS_OK; - } - - if (mVideoPaused && mVideoSource.get() && mVideoSource->start() != OK) { - return NS_ERROR_UNEXPECTED; - } - mVideoPaused = false; - - if (mAudioPaused && mAudioSource.get() && mAudioSource->start() != OK) { - return NS_ERROR_UNEXPECTED; - } - mAudioPaused = false; - - return NS_OK; -} - -// AOSP didn't give implementation on OMXCodec::Pause() and not define -// OMXCodec::Start() should be called for resuming the decoding. Currently -// it is customized by a specific open source repository only. -// ToDo The one not supported OMXCodec::Pause() should return error code here, -// so OMXCodec::Start() doesn't be called again for resuming. But if someone -// implement the OMXCodec::Pause() and need a following OMXCodec::Read() with -// seek option (define in MediaSource.h) then it is still not supported here. -// We need to fix it until it is really happened. -void -OmxDecoder::Pause() -{ - /* The implementation of OMXCodec::pause is flawed. - * OMXCodec::start will not restore from the paused state and result in - * buffer timeout which causes timeouts in mochitests. - * Since there is not power consumption problem in emulator, we will just - * return when running in emulator to fix timeouts in mochitests. - */ - if (isInEmulator()) { - return; - } - - if (mVideoPaused || mAudioPaused) { - return; - } - - if (mVideoSource.get() && mVideoSource->pause() == OK) { - mVideoPaused = true; - } - - if (mAudioSource.get() && mAudioSource->pause() == OK) { - mAudioPaused = true; - } -} - -// Called on ALooper thread. -void -OmxDecoder::onMessageReceived(const sp &msg) -{ - switch (msg->what()) { - case kNotifyPostReleaseVideoBuffer: - { - Mutex::Autolock autoLock(mSeekLock); - // Free pending video buffers when OmxDecoder is not seeking video. - // If OmxDecoder is seeking video, the buffers are freed on seek exit. - if (!mIsVideoSeeking) { - ReleaseAllPendingVideoBuffersLocked(); - } - break; - } - default: - TRESPASS(); - break; - } -} - -void -OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle) -{ - { - Mutex::Autolock autoLock(mPendingVideoBuffersLock); - if (aBuffer) { - mPendingVideoBuffers.push(BufferItem(aBuffer, aReleaseFenceHandle)); - } - } - - sp notify = - new AMessage(kNotifyPostReleaseVideoBuffer, mReflector->id()); - // post AMessage to OmxDecoder via ALooper. - notify->post(); -} - -void -OmxDecoder::ReleaseAllPendingVideoBuffersLocked() -{ - Vector releasingVideoBuffers; - { - Mutex::Autolock autoLock(mPendingVideoBuffersLock); - - int size = mPendingVideoBuffers.size(); - for (int i = 0; i < size; i++) { - releasingVideoBuffers.push(mPendingVideoBuffers[i]); - } - mPendingVideoBuffers.clear(); - } - // Free all pending video buffers without holding mPendingVideoBuffersLock. - int size = releasingVideoBuffers.size(); - for (int i = 0; i < size; i++) { - MediaBuffer *buffer; - buffer = releasingVideoBuffers[i].mMediaBuffer; -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 - RefPtr fdObj = releasingVideoBuffers.editItemAt(i).mReleaseFenceHandle.GetAndResetFdObj(); - int fenceFd = fdObj->GetAndResetFd(); - - MOZ_ASSERT(buffer->refcount() == 1); - // This code expect MediaBuffer's ref count is 1. - // Return gralloc buffer to ANativeWindow - ANativeWindow* window = static_cast(mNativeWindowClient.get()); - window->cancelBuffer(window, - buffer->graphicBuffer().get(), - fenceFd); - // Mark MediaBuffer as rendered. - // When gralloc buffer is directly returned to ANativeWindow, - // this mark is necesary. - sp metaData = buffer->meta_data(); - metaData->setInt32(kKeyRendered, 1); -#endif - // Return MediaBuffer to OMXCodec. - buffer->release(); - } - releasingVideoBuffers.clear(); -} - -void -OmxDecoder::RecycleCallbackImp(TextureClient* aClient) -{ - aClient->ClearRecycleCallback(); - { - Mutex::Autolock autoLock(mPendingVideoBuffersLock); - if (mPendingRecycleTexutreClients.find(aClient) == mPendingRecycleTexutreClients.end()) { - printf_stderr("OmxDecoder::RecycleCallbackImp -- TextureClient is not pending recycle\n"); - return; - } - mPendingRecycleTexutreClients.erase(aClient); - GrallocTextureData* grallocData = static_cast(aClient->GetInternalData()); - if (grallocData->GetMediaBuffer()) { - mPendingVideoBuffers.push(BufferItem(grallocData->GetMediaBuffer(), aClient->GetAndResetReleaseFenceHandle())); - } - } - sp notify = - new AMessage(kNotifyPostReleaseVideoBuffer, mReflector->id()); - // post AMessage to OmxDecoder via ALooper. - notify->post(); -} - -/* static */ void -OmxDecoder::RecycleCallback(TextureClient* aClient, void* aClosure) -{ - MOZ_ASSERT(aClient && !aClient->IsDead()); - OmxDecoder* decoder = static_cast(aClosure); - decoder->RecycleCallbackImp(aClient); -} diff --git a/dom/media/omx/OmxDecoder.h b/dom/media/omx/OmxDecoder.h deleted file mode 100644 index da71b238cc09..000000000000 --- a/dom/media/omx/OmxDecoder.h +++ /dev/null @@ -1,224 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "GonkNativeWindow.h" -#include "mozilla/layers/FenceUtils.h" -#include "MP3FrameParser.h" -#include "MPAPI.h" -#include "MediaOmxCommonReader.h" -#include "AbstractMediaDecoder.h" -#include "OMXCodecProxy.h" - -namespace android { -class OmxDecoder; -}; - -namespace android { - -class OmxDecoder : public RefBase { - typedef MPAPI::AudioFrame AudioFrame; - typedef MPAPI::VideoFrame VideoFrame; - typedef mozilla::MP3FrameParser MP3FrameParser; - typedef mozilla::MediaResource MediaResource; - typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder; - typedef mozilla::layers::FenceHandle FenceHandle; - typedef mozilla::layers::TextureClient TextureClient; - typedef mozilla::MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise; - - enum { - kPreferSoftwareCodecs = 1, - kSoftwareCodecsOnly = 8, - kHardwareCodecsOnly = 16, - }; - - enum { - kNotifyPostReleaseVideoBuffer = 'noti', - }; - - AbstractMediaDecoder *mDecoder; - sp mNativeWindow; - sp mNativeWindowClient; - - sp mVideoTrack; - sp mVideoSource; - sp mAudioOffloadTrack; - sp mAudioTrack; - sp mAudioSource; - int32_t mDisplayWidth; - int32_t mDisplayHeight; - int32_t mVideoWidth; - int32_t mVideoHeight; - int32_t mVideoColorFormat; - int32_t mVideoStride; - int32_t mVideoSliceHeight; - int32_t mVideoRotation; - int32_t mAudioChannels; - int32_t mAudioSampleRate; - int64_t mDurationUs; - int64_t mLastSeekTime; - - VideoFrame mVideoFrame; - AudioFrame mAudioFrame; - MP3FrameParser mMP3FrameParser; - bool mIsMp3; - - // Lifetime of these should be handled by OMXCodec, as long as we release - // them after use: see ReleaseVideoBuffer(), ReleaseAudioBuffer() - MediaBuffer *mVideoBuffer; - MediaBuffer *mAudioBuffer; - - struct BufferItem { - BufferItem() - : mMediaBuffer(nullptr) - { - } - BufferItem(MediaBuffer* aMediaBuffer, const FenceHandle& aReleaseFenceHandle) - : mMediaBuffer(aMediaBuffer) - , mReleaseFenceHandle(aReleaseFenceHandle) { - } - - MediaBuffer* mMediaBuffer; - // a fence will signal when the current buffer is no longer being read. - FenceHandle mReleaseFenceHandle; - }; - - // Hold video's MediaBuffers that are released during video seeking. - // The holded MediaBuffers are released soon after seek completion. - // OMXCodec does not accept MediaBuffer during seeking. If MediaBuffer is - // returned to OMXCodec during seeking, OMXCodec calls assert. - Vector mPendingVideoBuffers; - - // Hold TextureClients that are waiting to be recycled. - std::set mPendingRecycleTexutreClients; - - // The lock protects mPendingVideoBuffers and mPendingRecycleTexutreClients. - Mutex mPendingVideoBuffersLock; - - // Show if OMXCodec is seeking. - bool mIsVideoSeeking; - // The lock protects video MediaBuffer release()'s pending operations called - // from multiple threads. The pending operations happen only during video - // seeking. Holding mSeekLock long time could affect to video rendering. - // Holding time should be minimum. - Mutex mSeekLock; - - // ALooper is a message loop used in stagefright. - // It creates a thread for messages and handles messages in the thread. - // ALooper is a clone of Looper in android Java. - // http://developer.android.com/reference/android/os/Looper.html - sp mLooper; - // deliver a message to a wrapped object(OmxDecoder). - // AHandlerReflector is similar to Handler in android Java. - // http://developer.android.com/reference/android/os/Handler.html - sp > mReflector; - - // 'true' if a read from the audio stream was done while reading the metadata - bool mAudioMetadataRead; - - RefPtr mTaskQueue; - - mozilla::MozPromiseRequestHolder mVideoCodecRequest; - mozilla::MozPromiseHolder mMediaResourcePromise; - - void ReleaseVideoBuffer(); - void ReleaseAudioBuffer(); - // Call with mSeekLock held. - void ReleaseAllPendingVideoBuffersLocked(); - - void PlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame); - void CbYCrYFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame); - void SemiPlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame); - void SemiPlanarYVU420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame); - bool ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame); - bool ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize, - int32_t aAudioChannels, int32_t aAudioSampleRate); - - //True if decoder is in a paused state - bool mAudioPaused; - bool mVideoPaused; - - mozilla::TaskQueue* OwnerThread() const - { - return mTaskQueue; - } - -public: - explicit OmxDecoder(AbstractMediaDecoder *aDecoder, mozilla::TaskQueue* aTaskQueue); - ~OmxDecoder(); - - // The MediaExtractor provides essential information for creating OMXCodec - // instance. Such as video/audio codec, we can retrieve them through the - // MediaExtractor::getTrackMetaData(). - // In general cases, the extractor is created by a sp which - // connect to a MediaResource like ChannelMediaResource. - // Data is read from the MediaResource to create a suitable extractor which - // extracts data from a container. - // Note: RTSP requires a custom extractor because it doesn't have a container. - bool Init(sp& extractor); - - // Called after resources(video/audio codec) are allocated, set the - // mDurationUs and video/audio metadata. - bool EnsureMetadata(); - - RefPtr AllocateMediaResources(); - void ReleaseMediaResources(); - bool SetVideoFormat(); - bool SetAudioFormat(); - - void ReleaseDecoder(); - - void GetDuration(int64_t *durationUs) { - *durationUs = mDurationUs; - } - - void GetVideoParameters(int32_t* aDisplayWidth, int32_t* aDisplayHeight, - int32_t* aWidth, int32_t* aHeight) { - *aDisplayWidth = mDisplayWidth; - *aDisplayHeight = mDisplayHeight; - *aWidth = mVideoWidth; - *aHeight = mVideoHeight; - } - - void GetAudioParameters(int32_t *numChannels, int32_t *sampleRate) { - *numChannels = mAudioChannels; - *sampleRate = mAudioSampleRate; - } - - bool HasVideo() { - return mVideoSource != nullptr; - } - - bool HasAudio() { - return mAudioSource != nullptr; - } - - bool ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs, - bool aKeyframeSkip = false, - bool aDoSeek = false); - bool ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs); - - //Change decoder into a playing state - nsresult Play(); - - //Change decoder into a paused state - void Pause(); - - // Post kNotifyPostReleaseVideoBuffer message to OmxDecoder via ALooper. - void PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle); - // Receive a message from AHandlerReflector. - // Called on ALooper thread. - void onMessageReceived(const sp &msg); - - sp GetAudioOffloadTrack() { return mAudioOffloadTrack; } - - void RecycleCallbackImp(TextureClient* aClient); - - static void RecycleCallback(TextureClient* aClient, void* aClosure); -}; - -} - diff --git a/dom/media/omx/moz.build b/dom/media/omx/moz.build deleted file mode 100644 index a5b8386bcfe9..000000000000 --- a/dom/media/omx/moz.build +++ /dev/null @@ -1,111 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -EXPORTS += [ - 'AudioOffloadPlayerBase.h', - 'MediaOmxCommonDecoder.h', - 'MediaOmxCommonReader.h', - 'MediaOmxDecoder.h', - 'MediaOmxReader.h', -] - -SOURCES += [ - 'MediaOmxCommonDecoder.cpp', - 'MediaOmxCommonReader.cpp', - 'MediaOmxDecoder.cpp', - 'MediaOmxReader.cpp', - 'MediaStreamSource.cpp', - 'OMXCodecProxy.cpp', - 'OmxDecoder.cpp', -] - -if CONFIG['MOZ_AUDIO_OFFLOAD']: - EXPORTS += [ - 'AudioOffloadPlayer.h', - 'AudioOutput.h', - 'GonkAudioSink.h', - ] - SOURCES += [ - 'AudioOffloadPlayer.cpp', - 'AudioOutput.cpp', - ] - -if CONFIG['MOZ_OMX_ENCODER']: - EXPORTS += [ - 'OMXCodecWrapper.h', - ] - SOURCES += [ - 'OMXCodecDescriptorUtil.cpp', - 'OMXCodecWrapper.cpp', - ] - LOCAL_INCLUDES += ['/media/libyuv/include'] - -if 'rtsp' in CONFIG['NECKO_PROTOCOLS']: - EXPORTS += [ - 'RtspExtractor.h', - 'RtspOmxDecoder.h', - 'RtspOmxReader.h', - ] - SOURCES += [ - 'RtspExtractor.cpp', - 'RtspOmxDecoder.cpp', - 'RtspOmxReader.cpp', - ] - -if CONFIG['ANDROID_VERSION'] >= '18': - EXPORTS += [ - 'I420ColorConverterHelper.h', - 'MediaCodecProxy.h', - ] - SOURCES += [ - 'I420ColorConverterHelper.cpp', - 'MediaCodecProxy.cpp', - ] - -include('/ipc/chromium/chromium-config.mozbuild') - -# Suppress some GCC/clang warnings being treated as errors: -# - about attributes on forward declarations for types that are already -# defined, which complains about an important MOZ_EXPORT for android::AString -# - about multi-character constants which are used in codec-related code -# and are part of Android's libstagefright API style. -if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: - CXXFLAGS += [ - '-Wno-error=attributes', - '-Wno-multichar' - ] - -FINAL_LIBRARY = 'xul' -LOCAL_INCLUDES += [ - '/dom/base', - '/dom/html', - '/ipc/chromium/src', -] - -if CONFIG['ANDROID_VERSION'] == '15': - LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'dalvik/libnativehelper/include/nativehelper', - 'frameworks/base/include', - 'frameworks/base/include/binder', - 'frameworks/base/include/media', - 'frameworks/base/include/media/stagefright/openmax', - 'frameworks/base/include/utils', - 'frameworks/base/media/libstagefright/include', - 'hardware/libhardware/include', - ] - ] -else: - LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/av/include/media', - 'frameworks/native/include', - 'frameworks/native/opengl/include', - ] -] - -if CONFIG['ANDROID_VERSION'] > '15': - DEFINES['MOZ_OMX_WEBM_DECODER'] = True diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html index 99685b4461fc..834bc81f9ffe 100644 --- a/dom/media/test/test_can_play_type_mpeg.html +++ b/dom/media/test/test_can_play_type_mpeg.html @@ -137,7 +137,6 @@ var haveMp4 = (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) || IsMacOSSnowLeopardOrLater() || (IsSupportedAndroid() && (IsJellyBeanOrLater() || getPref("media.plugins.enabled"))) || - getPref("media.omx.enabled") || (IsLinux() && getPref("media.ffmpeg.enabled")); check_mp4(document.getElementById('v'), haveMp4); diff --git a/dom/media/test/test_mediarecorder_unsupported_src.html b/dom/media/test/test_mediarecorder_unsupported_src.html index 3b57dcae4d96..cbbc82e7d6b9 100644 --- a/dom/media/test/test_mediarecorder_unsupported_src.html +++ b/dom/media/test/test_mediarecorder_unsupported_src.html @@ -91,7 +91,6 @@ SpecialPowers.pushPrefEnv( { "set": [ ["media.encoder.webm.enabled", false], - ["media.encoder.omx.enabled", false] ] }, startTest); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 4df5ec35304e..35554f8cd0ad 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -584,9 +584,6 @@ pref("media.webspeech.synth.enabled", false); #ifdef MOZ_WEBM_ENCODER pref("media.encoder.webm.enabled", true); #endif -#ifdef MOZ_OMX_ENCODER -pref("media.encoder.omx.enabled", true); -#endif // Whether to autostart a media element with an |autoplay| attribute pref("media.autoplay.enabled", true); diff --git a/old-configure.in b/old-configure.in index 0276e3491d8f..01ad48f15a7d 100644 --- a/old-configure.in +++ b/old-configure.in @@ -108,26 +108,16 @@ if test -n "$gonkdir"; then 15) CPPFLAGS="-I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/frameworks/base/include -I$gonkdir/frameworks/base/services/camera -I$gonkdir/frameworks/base/include/media/ -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib -I$gonkdir/dalvik/libnativehelper/include/nativehelper $CPPFLAGS" MOZ_NFC=1 - MOZ_OMX_DECODER=1 - AC_SUBST(MOZ_OMX_DECODER) MOZ_SECUREELEMENT=1 ;; 17|18) CPPFLAGS="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include $CPPFLAGS" MOZ_NFC=1 - MOZ_OMX_DECODER=1 - AC_SUBST(MOZ_OMX_DECODER) - MOZ_OMX_ENCODER=1 - AC_SUBST(MOZ_OMX_ENCODER) - AC_DEFINE(MOZ_OMX_ENCODER) MOZ_SECUREELEMENT=1 ;; 19) CPPFLAGS="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include $CPPFLAGS" MOZ_NFC=1 - MOZ_OMX_DECODER=1 - MOZ_OMX_ENCODER=1 - AC_DEFINE(MOZ_OMX_ENCODER) MOZ_AUDIO_OFFLOAD=1 MOZ_SECUREELEMENT=1 AC_SUBST(MOZ_AUDIO_OFFLOAD) @@ -136,9 +126,6 @@ if test -n "$gonkdir"; then 21|22) CPPFLAGS="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include $CPPFLAGS" MOZ_AUDIO_OFFLOAD=1 - MOZ_OMX_DECODER=1 - MOZ_OMX_ENCODER=1 - AC_DEFINE(MOZ_OMX_ENCODER) AC_SUBST(MOZ_AUDIO_OFFLOAD) AC_DEFINE(MOZ_AUDIO_OFFLOAD) MOZ_NFC=1 diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index 9e9ac4b993a8..d539dd9a08e9 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -87,9 +87,6 @@ DEFINES['HAVE_OFF64_T'] = True DEFINES['SK_BUILD_FOR_ANDROID_NDK'] = True DEFINES['HAVE_POSIX_CLOCKS'] = True -if CONFIG['MOZ_OMX_DECODER']: - DEFINES['MOZ_OMX_DECODER'] = True - LOCAL_INCLUDES += [ '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ 'frameworks/native/opengl/include', diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build index f53612307f88..fbcee601c8c0 100644 --- a/widget/gonk/nativewindow/moz.build +++ b/widget/gonk/nativewindow/moz.build @@ -48,7 +48,7 @@ elif CONFIG['ANDROID_VERSION'] in ('17', '18'): 'GonkNativeWindowJB.h', ] -if CONFIG['MOZ_OMX_DECODER'] or CONFIG['MOZ_WEBRTC']: +if CONFIG['MOZ_WEBRTC']: if CONFIG['ANDROID_VERSION'] >= '21': SOURCES += [ 'GonkBufferQueueLL/GonkBufferItem.cpp', diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp index 23757bb05d34..24e791b4b4e3 100644 --- a/widget/gonk/nsAppShell.cpp +++ b/widget/gonk/nsAppShell.cpp @@ -889,9 +889,6 @@ nsAppShell::Init() printf("*** This is stdout. Most of the useful output will be in logcat.\n"); printf("***\n"); printf("*****************************************************************\n"); -#if ANDROID_VERSION >= 18 && defined(MOZ_OMX_DECODER) - android::FakeSurfaceComposer::instantiate(); -#endif GonkPermissionService::instantiate(); // Causes the kernel timezone to be set, which in turn causes the