From ae3cdb4be3cfe1faccf1d8a74928391570952609 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:05:52 -0500 Subject: [webm] Store LastSeenFrame dimensions as an nsIntSize This simplifies the comparison and update logic. --- dom/media/webm/WebMDemuxer.cpp | 11 +++++------ dom/media/webm/WebMDemuxer.h | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 20ed71581..ac371fa7f 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -651,14 +651,13 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl if (isKeyframe) { // We only look for resolution changes on keyframes for both VP8 and // VP9. Other resolution changes are invalid. - if (mLastSeenFrameWidth.isSome() && mLastSeenFrameHeight.isSome() && - (si.w != mLastSeenFrameWidth.value() || - si.h != mLastSeenFrameHeight.value())) { - mInfo.mVideo.mDisplay = nsIntSize(si.w, si.h); + auto dimensions = nsIntSize(si.w, si.h); + if (mLastSeenFrameSize.isSome() + && (dimensions != mLastSeenFrameSize.value())) { + mInfo.mVideo.mDisplay = dimensions; mSharedVideoTrackInfo = new SharedTrackInfo(mInfo.mVideo, ++sStreamSourceID); } - mLastSeenFrameWidth = Some(si.w); - mLastSeenFrameHeight = Some(si.h); + mLastSeenFrameSize = Some(dimensions); } } } diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index 6fff38e7d..a5008022f 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -237,8 +237,7 @@ private: int64_t mLastWebMBlockOffset; const bool mIsMediaSource; - Maybe mLastSeenFrameWidth; - Maybe mLastSeenFrameHeight; + Maybe mLastSeenFrameSize; // This will be populated only if a resolution change occurs, otherwise it // will be left as null so the original metadata is used RefPtr mSharedVideoTrackInfo; -- cgit v1.2.3 From 5a83ed9ebacfa2bd653953b359dd5456817b03c3 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:10:31 -0500 Subject: [vpx] Store VPXDecoder codec as an enum Use the enum we already have here instead of converting to an int when we pass it around, giving us better type checking. --- dom/media/platforms/agnostic/VPXDecoder.cpp | 4 ++-- dom/media/platforms/agnostic/VPXDecoder.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 77c81b51b..42bb86020 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -22,7 +22,7 @@ namespace mozilla { using namespace gfx; using namespace layers; -static int MimeTypeToCodec(const nsACString& aMimeType) +static VPXDecoder::Codec MimeTypeToCodec(const nsACString& aMimeType) { if (aMimeType.EqualsLiteral("video/webm; codecs=vp8")) { return VPXDecoder::Codec::VP8; @@ -31,7 +31,7 @@ static int MimeTypeToCodec(const nsACString& aMimeType) } else if (aMimeType.EqualsLiteral("video/vp9")) { return VPXDecoder::Codec::VP9; } - return -1; + return VPXDecoder::Codec::Unknown; } VPXDecoder::VPXDecoder(const CreateDecoderParams& aParams) diff --git a/dom/media/platforms/agnostic/VPXDecoder.h b/dom/media/platforms/agnostic/VPXDecoder.h index d420ec069..4d57ebf94 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.h +++ b/dom/media/platforms/agnostic/VPXDecoder.h @@ -36,7 +36,8 @@ public: enum Codec: uint8_t { VP8 = 1 << 0, - VP9 = 1 << 1 + VP9 = 1 << 1, + Unknown = 1 << 7, }; // Return true if aMimeType is a one of the strings used by our demuxers to @@ -61,7 +62,7 @@ private: const VideoInfo& mInfo; - const int mCodec; + const Codec mCodec; }; } // namespace mozilla -- cgit v1.2.3 From 2a00bf1262c48b5f90b8ff2ed81ef4b0bb97e930 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:11:58 -0500 Subject: Add Span support to MediaRawData --- dom/media/MediaData.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'dom/media') diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index a79aac6ed..905b4c1d9 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -14,6 +14,7 @@ #include "nsIMemoryReporter.h" #include "SharedBuffer.h" #include "mozilla/RefPtr.h" +#include "mozilla/Span.h" #include "mozilla/UniquePtr.h" #include "mozilla/UniquePtrExtensions.h" #include "nsTArray.h" @@ -631,6 +632,8 @@ public: { return sizeof(*this) + mBuffer.ComputedSizeOfExcludingThis(); } + // Access the buffer as a Span. + operator Span() { return MakeSpan(Data(), Size()); } const CryptoSample& mCrypto; RefPtr mExtraData; -- cgit v1.2.3 From 55c6aa422da84f581c3bbb0d2c0fa9b282a9d669 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:14:24 -0500 Subject: Implement keyframe and framesize VPXDecoder helpers Encapsulate code from WebMDemuxer to query keyframe and frame resolution inside VPXDecoder, so we have a clean wrapper for all the libvpx functions we use. --- dom/media/platforms/agnostic/VPXDecoder.cpp | 49 +++++++++++++++++++++++------ dom/media/platforms/agnostic/VPXDecoder.h | 7 +++++ 2 files changed, 46 insertions(+), 10 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 42bb86020..f2f84487f 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -101,17 +101,10 @@ MediaResult VPXDecoder::DoDecode(MediaRawData* aSample) { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + #if defined(DEBUG) - vpx_codec_stream_info_t si; - PodZero(&si); - si.sz = sizeof(si); - if (mCodec == Codec::VP8) { - vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aSample->Data(), aSample->Size(), &si); - } else if (mCodec == Codec::VP9) { - vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aSample->Data(), aSample->Size(), &si); - } - NS_ASSERTION(bool(si.is_kf) == aSample->mKeyframe, - "VPX Decode Keyframe error sample->mKeyframe and si.si_kf out of sync"); + NS_ASSERTION(IsKeyframe(*aSample, mCodec) == aSample->mKeyframe, + "VPX Decode Keyframe error sample->mKeyframe and sample data out of sync"); #endif if (vpx_codec_err_t r = vpx_codec_decode(&mVPX, aSample->Data(), aSample->Size(), nullptr, 0)) { @@ -249,5 +242,41 @@ VPXDecoder::IsVP9(const nsACString& aMimeType) return IsVPX(aMimeType, VPXDecoder::VP9); } +/* static */ +bool +VPXDecoder::IsKeyframe(Span aBuffer, Codec aCodec) +{ + vpx_codec_stream_info_t si; + PodZero(&si); + si.sz = sizeof(si); + + if (aCodec == Codec::VP8) { + vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + return bool(si.is_kf); + } else if (aCodec == Codec::VP9) { + vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + return bool(si.is_kf); + } + + return false; +} + +/* static */ +nsIntSize +VPXDecoder::GetFrameSize(Span aBuffer, Codec aCodec) +{ + vpx_codec_stream_info_t si; + PodZero(&si); + si.sz = sizeof(si); + + if (aCodec == Codec::VP8) { + vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + } else if (aCodec == Codec::VP9) { + vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), aBuffer.Elements(), aBuffer.Length(), &si); + } + + return nsIntSize(si.w, si.h); +} + } // namespace mozilla #undef LOG diff --git a/dom/media/platforms/agnostic/VPXDecoder.h b/dom/media/platforms/agnostic/VPXDecoder.h index 4d57ebf94..4e8d83617 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.h +++ b/dom/media/platforms/agnostic/VPXDecoder.h @@ -7,6 +7,7 @@ #define VPXDecoder_h_ #include "PlatformDecoderModule.h" +#include "mozilla/Span.h" #include #define VPX_DONT_DEFINE_STDINT_TYPES @@ -47,6 +48,12 @@ public: static bool IsVP8(const nsACString& aMimeType); static bool IsVP9(const nsACString& aMimeType); + // Return true if a sample is a keyframe for the specified codec. + static bool IsKeyframe(Span aBuffer, Codec aCodec); + + // Return the frame dimensions for a sample for the specified codec. + static nsIntSize GetFrameSize(Span aBuffer, Codec aCodec); + private: void ProcessDecode(MediaRawData* aSample); MediaResult DoDecode(MediaRawData* aSample); -- cgit v1.2.3 From 3ec54eeacb8fcb5b844aa07c803cf52d1aedb0d4 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:16:39 -0500 Subject: Call VPXDecoder libvpx wrappers for WebM Use the new helper functions instead of calling libvpx directly. This simplifies adding other codecs in the future. --- dom/media/webm/WebMDemuxer.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index ac371fa7f..b39bec661 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -9,6 +9,7 @@ #include "AbstractMediaDecoder.h" #include "MediaResource.h" #include "OpusDecoder.h" +#include "VPXDecoder.h" #include "WebMDemuxer.h" #include "WebMBufferedParser.h" #include "gfx2DGlue.h" @@ -24,12 +25,9 @@ #include "mozilla/Sprintf.h" #include +#include #include -#define VPX_DONT_DEFINE_STDINT_TYPES -#include "vpx/vp8dx.h" -#include "vpx/vpx_decoder.h" - #define WEBM_DEBUG(arg, ...) MOZ_LOG(gMediaDemuxerLog, mozilla::LogLevel::Debug, ("WebMDemuxer(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) extern mozilla::LazyLogModule gMediaDemuxerLog; @@ -636,22 +634,25 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl // Packet is encrypted, can't peek, use packet info isKeyframe = nestegg_packet_has_keyframe(holder->Packet()) == NESTEGG_PACKET_HAS_KEYFRAME_TRUE; } else { - vpx_codec_stream_info_t si; - PodZero(&si); - si.sz = sizeof(si); + auto sample = MakeSpan(data, length); switch (mVideoCodec) { case NESTEGG_CODEC_VP8: - vpx_codec_peek_stream_info(vpx_codec_vp8_dx(), data, length, &si); + isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP8); break; case NESTEGG_CODEC_VP9: - vpx_codec_peek_stream_info(vpx_codec_vp9_dx(), data, length, &si); + isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP9); break; + default: + NS_WARNING("Cannot detect keyframes in unknown WebM video codec"); + return NS_ERROR_FAILURE; } - isKeyframe = si.is_kf; if (isKeyframe) { - // We only look for resolution changes on keyframes for both VP8 and - // VP9. Other resolution changes are invalid. - auto dimensions = nsIntSize(si.w, si.h); + // For both VP8 and VP9, we only look for resolution changes + // on keyframes. Other resolution changes are invalid. + auto codec = mVideoCodec == NESTEGG_CODEC_VP8 + ? VPXDecoder::Codec::VP8 + : VPXDecoder::Codec::VP9; + auto dimensions = VPXDecoder::GetFrameSize(sample, codec); if (mLastSeenFrameSize.isSome() && (dimensions != mLastSeenFrameSize.value())) { mInfo.mVideo.mDisplay = dimensions; -- cgit v1.2.3 From 632b67483c9d964cd84ee90d162e88b510a70707 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:43:06 -0500 Subject: [webm] Treat demuxing errors differently than EOS Otherwise the WebM demuxer makes no difference between a genuine EOS and encountering an error. --- dom/media/webm/WebMDemuxer.cpp | 105 ++++++++++++++++++++++++++--------------- dom/media/webm/WebMDemuxer.h | 11 +++-- 2 files changed, 75 insertions(+), 41 deletions(-) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index b39bec661..395262a2e 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -547,7 +547,7 @@ WebMDemuxer::GetTrackCrypto(TrackInfo::TrackType aType, size_t aTrackNumber) { return crypto; } -bool +nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples) { if (mIsMediaSource) { @@ -555,17 +555,18 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl EnsureUpToDateIndex(); } - RefPtr holder(NextPacket(aType)); + RefPtr holder; + nsresult rv = NextPacket(aType, holder); - if (!holder) { - return false; + if (NS_FAILED(rv)) { + return rv; } int r = 0; unsigned int count = 0; r = nestegg_packet_count(holder->Packet(), &count); if (r == -1) { - return false; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } int64_t tstamp = holder->Timestamp(); int64_t duration = holder->Duration(); @@ -576,7 +577,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl // video frame. int64_t next_tstamp = INT64_MIN; if (aType == TrackInfo::kAudioTrack) { - RefPtr next_holder(NextPacket(aType)); + RefPtr next_holder; + rv = NextPacket(aType, next_holder); + if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) { + return rv; + } if (next_holder) { next_tstamp = next_holder->Timestamp(); PushAudioPacket(next_holder); @@ -591,7 +596,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl } mLastAudioFrameTime = Some(tstamp); } else if (aType == TrackInfo::kVideoTrack) { - RefPtr next_holder(NextPacket(aType)); + RefPtr next_holder; + rv = NextPacket(aType, next_holder); + if (NS_FAILED(rv) && rv != NS_ERROR_DOM_MEDIA_END_OF_STREAM) { + return rv; + } if (next_holder) { next_tstamp = next_holder->Timestamp(); PushVideoPacket(next_holder); @@ -608,7 +617,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl } if (mIsMediaSource && next_tstamp == INT64_MIN) { - return false; + return NS_ERROR_DOM_MEDIA_END_OF_STREAM; } int64_t discardPadding = 0; @@ -624,7 +633,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl r = nestegg_packet_data(holder->Packet(), i, &data, &length); if (r == -1) { WEBM_DEBUG("nestegg_packet_data failed r=%d", r); - return false; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } bool isKeyframe = false; if (aType == TrackInfo::kAudioTrack) { @@ -668,7 +677,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl RefPtr sample = new MediaRawData(data, length); if (length && !sample->Data()) { // OOM. - return false; + return NS_ERROR_OUT_OF_MEMORY; } sample->mTimecode = tstamp; sample->mTime = tstamp; @@ -721,11 +730,12 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl } aSamples->Push(sample); } - return true; + return NS_OK; } -RefPtr -WebMDemuxer::NextPacket(TrackInfo::TrackType aType) +nsresult +WebMDemuxer::NextPacket(TrackInfo::TrackType aType, + RefPtr& aPacket) { bool isVideo = aType == TrackInfo::kVideoTrack; @@ -734,56 +744,64 @@ WebMDemuxer::NextPacket(TrackInfo::TrackType aType) bool hasType = isVideo ? mHasVideo : mHasAudio; if (!hasType) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } // The packet queue for the type that we are interested in. WebMPacketQueue &packets = isVideo ? mVideoPackets : mAudioPackets; if (packets.GetSize() > 0) { - return packets.PopFront(); + aPacket = packets.PopFront(); + return NS_OK; } // Track we are interested in uint32_t ourTrack = isVideo ? mVideoTrack : mAudioTrack; do { - RefPtr holder = DemuxPacket(aType); + RefPtr holder; + nsresult rv = DemuxPacket(aType, holder); + if (NS_FAILED(rv)) { + return rv; + } if (!holder) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } if (ourTrack == holder->Track()) { - return holder; + aPacket = holder; + return NS_OK; } } while (true); } -RefPtr -WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType) +nsresult +WebMDemuxer::DemuxPacket(TrackInfo::TrackType aType, + RefPtr& aPacket) { nestegg_packet* packet; int r = nestegg_read_packet(Context(aType), &packet); if (r == 0) { nestegg_read_reset(Context(aType)); - return nullptr; + return NS_ERROR_DOM_MEDIA_END_OF_STREAM; } else if (r < 0) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } unsigned int track = 0; r = nestegg_packet_track(packet, &track); if (r == -1) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } int64_t offset = Resource(aType).Tell(); RefPtr holder = new NesteggPacketHolder(); if (!holder->Init(packet, offset, track, false)) { - return nullptr; + return NS_ERROR_DOM_MEDIA_DEMUXER_ERR; } - return holder; + aPacket = holder; + return NS_OK; } void @@ -943,7 +961,10 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime) media::TimeUnit seekTime = aTime; mSamples.Reset(); mParent->SeekInternal(mType, aTime); - mParent->GetNextPacket(mType, &mSamples); + nsresult rv = mParent->GetNextPacket(mType, &mSamples); + if (NS_FAILED(rv)) { + return SeekPromise::CreateAndReject(rv, __func__); + } mNeedKeyframe = true; // Check what time we actually seeked to. @@ -956,15 +977,18 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime) return SeekPromise::CreateAndResolve(seekTime, __func__); } -RefPtr -WebMTrackDemuxer::NextSample() +nsresult +WebMTrackDemuxer::NextSample(RefPtr& aData) { - while (mSamples.GetSize() < 1 && mParent->GetNextPacket(mType, &mSamples)) { + nsresult rv; + while (mSamples.GetSize() < 1 && + NS_SUCCEEDED((rv = mParent->GetNextPacket(mType, &mSamples)))) { } if (mSamples.GetSize()) { - return mSamples.PopFront(); + aData = mSamples.PopFront(); + return NS_OK; } - return nullptr; + return rv; } RefPtr @@ -973,9 +997,12 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples) RefPtr samples = new SamplesHolder; MOZ_ASSERT(aNumSamples); + nsresult rv = NS_ERROR_DOM_MEDIA_END_OF_STREAM; + while (aNumSamples) { - RefPtr sample(NextSample()); - if (!sample) { + RefPtr sample; + rv = NextSample(sample); + if (NS_FAILED(rv)) { break; } if (mNeedKeyframe && !sample->mKeyframe) { @@ -987,7 +1014,7 @@ WebMTrackDemuxer::GetSamples(int32_t aNumSamples) } if (samples->mSamples.IsEmpty()) { - return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); + return SamplesPromise::CreateAndReject(rv, __func__); } else { UpdateSamples(samples->mSamples); return SamplesPromise::CreateAndResolve(samples, __func__); @@ -1022,7 +1049,8 @@ WebMTrackDemuxer::SetNextKeyFrameTime() } // Demux and buffer frames until we find a keyframe. RefPtr sample; - while (!foundKeyframe && (sample = NextSample())) { + nsresult rv = NS_OK; + while (!foundKeyframe && NS_SUCCEEDED((rv = NextSample(sample)))) { if (sample->mKeyframe) { frameTime = sample->mTime; foundKeyframe = true; @@ -1104,10 +1132,11 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold) uint32_t parsed = 0; bool found = false; RefPtr sample; + nsresult rv = NS_OK; int64_t sampleTime; WEBM_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds()); - while (!found && (sample = NextSample())) { + while (!found && NS_SUCCEEDED((rv = NextSample(sample)))) { parsed++; sampleTime = sample->mTime; if (sample->mKeyframe && sampleTime >= aTimeThreshold.ToMicroseconds()) { @@ -1116,7 +1145,9 @@ WebMTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold) mSamples.PushFront(sample.forget()); } } - SetNextKeyFrameTime(); + if (NS_SUCCEEDED(rv)) { + SetNextKeyFrameTime(); + } if (found) { WEBM_DEBUG("next sample: %f (parsed: %d)", media::TimeUnit::FromMicroseconds(sampleTime).ToSeconds(), diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index a5008022f..09780e8d3 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -111,7 +111,8 @@ public: bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset); // Demux next WebM packet and append samples to MediaRawDataQueue - bool GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples); + nsresult GetNextPacket(TrackInfo::TrackType aType, + MediaRawDataQueue *aSamples); nsresult Reset(TrackInfo::TrackType aType); @@ -175,11 +176,13 @@ private: // Read a packet from the nestegg file. Returns nullptr if all packets for // the particular track have been read. Pass TrackInfo::kVideoTrack or // TrackInfo::kVideoTrack to indicate the type of the packet we want to read. - RefPtr NextPacket(TrackInfo::TrackType aType); + nsresult NextPacket(TrackInfo::TrackType aType, + RefPtr& aPacket); // Internal method that demuxes the next packet from the stream. The caller // is responsible for making sure it doesn't get lost. - RefPtr DemuxPacket(TrackInfo::TrackType aType); + nsresult DemuxPacket(TrackInfo::TrackType aType, + RefPtr& aPacket); // libnestegg audio and video context for webm container. // Access on reader's thread only. @@ -275,7 +278,7 @@ private: ~WebMTrackDemuxer(); void UpdateSamples(nsTArray>& aSamples); void SetNextKeyFrameTime(); - RefPtr NextSample (); + nsresult NextSample(RefPtr& aData); RefPtr mParent; TrackInfo::TrackType mType; UniquePtr mInfo; -- cgit v1.2.3 From 81c39ba87667566a83febdc8c22e300ea8313897 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 8 Oct 2018 21:44:23 -0500 Subject: [webm] Don't reject seeks with EOS The MediaDecoderStateMachine treat seek's EOS as fatal errors, so instead we always resolve the seek promise, and let the next GetSample return EOS. --- dom/media/webm/WebMDemuxer.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index 395262a2e..b54739c06 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -963,6 +963,10 @@ WebMTrackDemuxer::Seek(media::TimeUnit aTime) mParent->SeekInternal(mType, aTime); nsresult rv = mParent->GetNextPacket(mType, &mSamples); if (NS_FAILED(rv)) { + if (rv == NS_ERROR_DOM_MEDIA_END_OF_STREAM) { + // Ignore the error for now, the next GetSample will be rejected with EOS. + return SeekPromise::CreateAndResolve(media::TimeUnit(), __func__); + } return SeekPromise::CreateAndReject(rv, __func__); } mNeedKeyframe = true; -- cgit v1.2.3 From 9aea199da0312640208f3c0a6d47951fb9975984 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 15 Oct 2018 22:09:04 -0500 Subject: Add AOMDecoder Port the VPXDecoder interface to libaom which uses the same api with the names changed. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 244 ++++++++++++++++++++++++++++ dom/media/platforms/agnostic/AOMDecoder.h | 62 +++++++ dom/media/platforms/moz.build | 8 + 3 files changed, 314 insertions(+) create mode 100644 dom/media/platforms/agnostic/AOMDecoder.cpp create mode 100644 dom/media/platforms/agnostic/AOMDecoder.h (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp new file mode 100644 index 000000000..30077ee03 --- /dev/null +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -0,0 +1,244 @@ +/* -*- 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 "AOMDecoder.h" +#include "MediaResult.h" +#include "TimeUnits.h" +#include "aom/aomdx.h" +#include "gfx2DGlue.h" +#include "mozilla/PodOperations.h" +#include "mozilla/SyncRunnable.h" +#include "nsError.h" +#include "prsystem.h" + +#include + +#undef LOG +#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("AOMDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__)) + +namespace mozilla { + +using namespace gfx; +using namespace layers; + +AOMDecoder::AOMDecoder(const CreateDecoderParams& aParams) + : mImageContainer(aParams.mImageContainer) + , mTaskQueue(aParams.mTaskQueue) + , mCallback(aParams.mCallback) + , mIsFlushing(false) + , mInfo(aParams.VideoConfig()) +{ + PodZero(&mCodec); +} + +AOMDecoder::~AOMDecoder() +{ +} + +void +AOMDecoder::Shutdown() +{ + aom_codec_destroy(&mCodec); +} + +RefPtr +AOMDecoder::Init() +{ + int decode_threads = 2; + aom_codec_iface_t* dx = aom_codec_av1_dx(); + if (aInfo.mDisplay.width >= 2048) { + decode_threads = 8; + } + else if (aInfo.mDisplay.width >= 1024) { + decode_threads = 4; + } + decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors()); + + aom_codec_dec_cfg_t config; + PodZero(&config); + config.threads = decode_threads; + config.w = config.h = 0; // set after decode + + aom_codec_flags_t flags = 0; + + if (!dx || aom_codec_dec_init(aCtx, dx, &config, flags) { + return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); + } + return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__); +} + +void +AOMDecoder::Flush() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mIsFlushing = true; + nsCOMPtr r = NS_NewRunnableFunction([this] () { + // nothing to do for now. + }); + SyncRunnable::DispatchToThread(mTaskQueue, r); + mIsFlushing = false; +} + +MediaResult +AOMDecoder::DoDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + +#if defined(DEBUG) + NS_ASSERTION(IsKeyframe(*aSample) == aSample->mKeyframe, + "AOM Decode Keyframe error sample->mKeyframe and si.si_kf out of sync"); +#endif + + if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr, 0)) { + LOG("AOM Decode error: %s", aom_codec_err_to_string(r)); + return MediaResult( + NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("AOM error decoding AV1 sample: %s", aom_codec_err_to_string(r))); + } + + aom_codec_iter_t iter = nullptr; + aom_image_t *img; + + while ((img = aom_codec_get_frame(&mCodec, &iter))) { + NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 || + img->fmt == AOM_IMG_FMT_I444, + "WebM image format not I420 or I444"); + + // Chroma shifts are rounded down as per the decoding examples in the SDK + VideoData::YCbCrBuffer b; + b.mPlanes[0].mData = img->planes[0]; + b.mPlanes[0].mStride = img->stride[0]; + b.mPlanes[0].mHeight = img->d_h; + b.mPlanes[0].mWidth = img->d_w; + b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0; + + b.mPlanes[1].mData = img->planes[1]; + b.mPlanes[1].mStride = img->stride[1]; + b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0; + + b.mPlanes[2].mData = img->planes[2]; + b.mPlanes[2].mStride = img->stride[2]; + b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0; + + if (img->fmt == AOM_IMG_FMT_I420) { + b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift; + b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift; + + b.mPlanes[2].mHeight = (img->d_h + 1) >> img->y_chroma_shift; + b.mPlanes[2].mWidth = (img->d_w + 1) >> img->x_chroma_shift; + } else if (img->fmt == AOM_IMG_FMT_I444) { + b.mPlanes[1].mHeight = img->d_h; + b.mPlanes[1].mWidth = img->d_w; + + b.mPlanes[2].mHeight = img->d_h; + b.mPlanes[2].mWidth = img->d_w; + } else { + LOG("AOM Unknown image format"); + return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("AOM Unknown image format")); + } + + RefPtr v; + v = VideoData::CreateAndCopyData(mInfo, + mImageContainer, + aSample->mOffset, + aSample->mTime, + aSample->mDuration, + b, + aSample->mKeyframe, + aSample->mTimecode, + mInfo.ScaledImageRect(img->d_w, + img->d_h)); + + if (!v) { + LOG( + "Image allocation error source %ux%u display %ux%u picture %ux%u", + img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height, + mInfo.mImage.width, mInfo.mImage.height); + return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); + } + mCallback->Output(v); + } + return NS_OK; +} + +void +AOMDecoder::ProcessDecode(MediaRawData* aSample) +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + if (mIsFlushing) { + return; + } + MediaResult rv = DoDecode(aSample); + if (NS_FAILED(rv)) { + mCallback->Error(rv); + } else { + mCallback->InputExhausted(); + } +} + +void +AOMDecoder::Input(MediaRawData* aSample) +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &AOMDecoder::ProcessDecode, aSample)); +} + +void +AOMDecoder::ProcessDrain() +{ + MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); + mCallback->DrainComplete(); +} + +void +AOMDecoder::Drain() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &AOMDecoder::ProcessDrain)); +} + +/* static */ +bool +AOMDecoder::IsAV1(const nsACString& aMimeType) +{ + return aMimeType.EqualsLiteral("video/webm; codecs=av1") + || aMimeType.EqualsLiteral("video/av1"); +} + +/* static */ +bool +AOMDecoder::IsKeyframe(Span aBuffer) { + aom_codec_stream_info_t info; + PodZero(&info); + info.sz = sizeof(info); + + aom_codec_peek_stream_info(aom_codec_av1_dx(), + aBuffer.Elements(), + aBuffer.Length(), + &info); + + return bool(info.is_kf); +} + +/* static */ +nsIntSize +AOMDecoder::GetFrameSize(Span aBuffer) { + aom_codec_stream_info_t info; + PodZero(&info); + info.sz = sizeof(info); + + aom_codec_peek_stream_info(aom_codec_av1_dx(), + aBuffer.Elements(), + aBuffer.Length(), + &info); + + return nsIntSize(info.w, info.h); +} + +} // namespace mozilla +#undef LOG diff --git a/dom/media/platforms/agnostic/AOMDecoder.h b/dom/media/platforms/agnostic/AOMDecoder.h new file mode 100644 index 000000000..ec6b1f95a --- /dev/null +++ b/dom/media/platforms/agnostic/AOMDecoder.h @@ -0,0 +1,62 @@ +/* -*- 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(AOMDecoder_h_) +#define AOMDecoder_h_ + +#include "PlatformDecoderModule.h" +#include "mozilla/Span.h" + +#include +#include "aom/aom_decoder.h" + +namespace mozilla { + +class AOMDecoder : public MediaDataDecoder +{ +public: + explicit AOMDecoder(const CreateDecoderParams& aParams); + + RefPtr Init() override; + void Input(MediaRawData* aSample) override; + void Flush() override; + void Drain() override; + void Shutdown() override; + const char* GetDescriptionName() const override + { + return "libaom (AV1) video decoder"; + } + + // Return true if aMimeType is a one of the strings used + // by our demuxers to identify AV1 streams. + static bool IsAV1(const nsACString& aMimeType); + + // Return true if a sample is a keyframe. + static bool IsKeyframe(Span aBuffer); + + // Return the frame dimensions for a sample. + static nsIntSize GetFrameSize(Span aBuffer); + +private: + ~AOMDecoder(); + void ProcessDecode(MediaRawData* aSample); + MediaResult DoDecode(MediaRawData* aSample); + void ProcessDrain(); + + const RefPtr mImageContainer; + const RefPtr mTaskQueue; + MediaDataDecoderCallback* mCallback; + Atomic mIsFlushing; + + // AOM decoder state + aom_codec_ctx_t mCodec; + + const VideoInfo& mInfo; +}; + +} // namespace mozilla + +#endif // AOMDecoder_h_ diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 3fb0cc842..be13d31c4 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -55,6 +55,14 @@ if CONFIG['MOZ_FFMPEG']: 'ffmpeg', ] +if CONFIG['MOZ_AV1']: + EXPORTS += [ + 'agnostic/AOMDecoder.h', + ] + UNIFIED_SOURCES += [ + 'agnostic/AOMDecoder.cpp', + ] + if CONFIG['MOZ_APPLEMEDIA']: EXPORTS += [ 'apple/AppleDecoderModule.h', -- cgit v1.2.3 From 3e0443e4c1ea6612d722c3a5b38843e0da451e81 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 15 Oct 2018 22:10:46 -0500 Subject: Add AOMDecoder to AgnosticDecoderModule --- dom/media/platforms/agnostic/AgnosticDecoderModule.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp index 7bd75b7fe..4d4a90bd4 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -12,6 +12,10 @@ #include "WAVDecoder.h" #include "TheoraDecoder.h" +#ifdef MOZ_AV1 +#include "AOMDecoder.h" +#endif + namespace mozilla { bool @@ -20,6 +24,9 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType, { bool supports = VPXDecoder::IsVPX(aMimeType) || +#ifdef MOZ_AV1 + AOMDecoder::IsAV1(aMimeType) || +#endif OpusDataDecoder::IsOpus(aMimeType) || VorbisDataDecoder::IsVorbis(aMimeType) || WaveDataDecoder::IsWave(aMimeType) || @@ -36,7 +43,13 @@ AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) if (VPXDecoder::IsVPX(aParams.mConfig.mMimeType)) { m = new VPXDecoder(aParams); - } else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) { + } +#ifdef MOZ_AV1 + else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType)) { + m = new AOMDecoder(aParams); + } +#endif + else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) { m = new TheoraDecoder(aParams); } -- cgit v1.2.3 From ee2cb65e248717b22104e802584cf1d7a4a916ad Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 15 Oct 2018 22:11:24 -0500 Subject: Recognize AV1 in WebMDemuxer Call AOMDecoder to handle AV1 video tracks from the WebM container. The new decoder is very similar to VPXDecoder so we can use parallel calls. This codec is still build-time conditional. --- dom/media/webm/WebMDemuxer.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDemuxer.cpp b/dom/media/webm/WebMDemuxer.cpp index b54739c06..013da9b2c 100644 --- a/dom/media/webm/WebMDemuxer.cpp +++ b/dom/media/webm/WebMDemuxer.cpp @@ -8,6 +8,9 @@ #include "MediaDecoderStateMachine.h" #include "AbstractMediaDecoder.h" #include "MediaResource.h" +#ifdef MOZ_AV1 +#include "AOMDecoder.h" +#endif #include "OpusDecoder.h" #include "VPXDecoder.h" #include "WebMDemuxer.h" @@ -320,6 +323,9 @@ WebMDemuxer::ReadMetadata() case NESTEGG_CODEC_VP9: mInfo.mVideo.mMimeType = "video/webm; codecs=vp9"; break; + case NESTEGG_CODEC_AV1: + mInfo.mVideo.mMimeType = "video/webm; codecs=av1"; + break; default: NS_WARNING("Unknown WebM video codec"); return NS_ERROR_FAILURE; @@ -651,6 +657,11 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl case NESTEGG_CODEC_VP9: isKeyframe = VPXDecoder::IsKeyframe(sample, VPXDecoder::Codec::VP9); break; +#ifdef MOZ_AV1 + case NESTEGG_CODEC_AV1: + isKeyframe = AOMDecoder::IsKeyframe(sample); + break; +#endif default: NS_WARNING("Cannot detect keyframes in unknown WebM video codec"); return NS_ERROR_FAILURE; @@ -658,10 +669,20 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSampl if (isKeyframe) { // For both VP8 and VP9, we only look for resolution changes // on keyframes. Other resolution changes are invalid. - auto codec = mVideoCodec == NESTEGG_CODEC_VP8 - ? VPXDecoder::Codec::VP8 - : VPXDecoder::Codec::VP9; - auto dimensions = VPXDecoder::GetFrameSize(sample, codec); + auto dimensions = nsIntSize(0, 0); + switch (mVideoCodec) { + case NESTEGG_CODEC_VP8: + dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP8); + break; + case NESTEGG_CODEC_VP9: + dimensions = VPXDecoder::GetFrameSize(sample, VPXDecoder::Codec::VP9); + break; +#ifdef MOZ_AV1 + case NESTEGG_CODEC_AV1: + dimensions = AOMDecoder::GetFrameSize(sample); + break; +#endif + } if (mLastSeenFrameSize.isSome() && (dimensions != mLastSeenFrameSize.value())) { mInfo.mVideo.mDisplay = dimensions; -- cgit v1.2.3 From e5545e10a613bf0584ef8050856df1625551c0d7 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 15 Oct 2018 22:11:48 -0500 Subject: Add missing includes to WebMDemuxer --- dom/media/webm/WebMDemuxer.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDemuxer.h b/dom/media/webm/WebMDemuxer.h index 09780e8d3..36d381e57 100644 --- a/dom/media/webm/WebMDemuxer.h +++ b/dom/media/webm/WebMDemuxer.h @@ -8,9 +8,13 @@ #include "nsTArray.h" #include "MediaDataDemuxer.h" +#include "MediaResource.h" #include "NesteggPacketHolder.h" #include "mozilla/Move.h" +#include +#include + typedef struct nestegg nestegg; namespace mozilla { -- cgit v1.2.3 From 26dc168e353d0e97f996371ddfed63140c864fb9 Mon Sep 17 00:00:00 2001 From: trav90 Date: Mon, 15 Oct 2018 22:47:27 -0500 Subject: Make AOMDecoder actually build --- dom/media/platforms/agnostic/AOMDecoder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 30077ee03..f3e8c7450 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -49,10 +49,10 @@ AOMDecoder::Init() { int decode_threads = 2; aom_codec_iface_t* dx = aom_codec_av1_dx(); - if (aInfo.mDisplay.width >= 2048) { + if (mInfo.mDisplay.width >= 2048) { decode_threads = 8; } - else if (aInfo.mDisplay.width >= 1024) { + else if (mInfo.mDisplay.width >= 1024) { decode_threads = 4; } decode_threads = std::min(decode_threads, PR_GetNumberOfProcessors()); @@ -64,7 +64,7 @@ AOMDecoder::Init() aom_codec_flags_t flags = 0; - if (!dx || aom_codec_dec_init(aCtx, dx, &config, flags) { + if (!dx || aom_codec_dec_init(&mCodec, dx, &config, flags)) { return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); } return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__); -- cgit v1.2.3 From 1036d1fa0b1fe0f1a7136ffe111f577aa35de21e Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 17 Oct 2018 05:46:09 -0500 Subject: Remove aom_codec_stream_info_t sz field references Upstream has removed the requirement to set this when initializing the stream_info struct. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index f3e8c7450..3ab5004e3 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -215,7 +215,6 @@ bool AOMDecoder::IsKeyframe(Span aBuffer) { aom_codec_stream_info_t info; PodZero(&info); - info.sz = sizeof(info); aom_codec_peek_stream_info(aom_codec_av1_dx(), aBuffer.Elements(), @@ -230,7 +229,6 @@ nsIntSize AOMDecoder::GetFrameSize(Span aBuffer) { aom_codec_stream_info_t info; PodZero(&info); - info.sz = sizeof(info); aom_codec_peek_stream_info(aom_codec_av1_dx(), aBuffer.Elements(), -- cgit v1.2.3 From 0cc51bc106250988cc3b89cb5d743a5af52cd35a Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 17 Oct 2018 05:54:22 -0500 Subject: Add av1 to MediaSource.isTypeSupported When av1 video playback is enabled, declare it as supported in the webm container in MediaSource.IsTypeSupported. Also support special mime types of the form video/webm; codecs=vp9.experimental. so test sites can verify playback support of particular encodings while the av1 bitstream is under development. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 13 +++++++++++++ dom/media/platforms/agnostic/AOMDecoder.h | 3 +++ dom/media/webm/WebMDecoder.cpp | 8 ++++++++ 3 files changed, 24 insertions(+) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 3ab5004e3..d1b45cf7f 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -210,6 +210,19 @@ AOMDecoder::IsAV1(const nsACString& aMimeType) || aMimeType.EqualsLiteral("video/av1"); } +/* static */ +bool +AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) +{ + // While AV1 is under development, we describe support + // for a specific aom commit hash so sites can check + // compatibility. + auto version = NS_ConvertASCIItoUTF16("av1.experimental."); + version.AppendLiteral("4d668d7feb1f8abd809d1bca0418570a7f142a36"); + return aCodecType.EqualsLiteral("av1") || + aCodecType.Equals(version); +} + /* static */ bool AOMDecoder::IsKeyframe(Span aBuffer) { diff --git a/dom/media/platforms/agnostic/AOMDecoder.h b/dom/media/platforms/agnostic/AOMDecoder.h index ec6b1f95a..1e2b76c2c 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.h +++ b/dom/media/platforms/agnostic/AOMDecoder.h @@ -34,6 +34,9 @@ public: // by our demuxers to identify AV1 streams. static bool IsAV1(const nsACString& aMimeType); + // Return true if aCodecType is a supported codec description. + static bool IsSupportedCodec(const nsAString& aCodecType); + // Return true if a sample is a keyframe. static bool IsKeyframe(Span aBuffer); diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index b41de6d40..d721a8ccc 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -5,6 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Preferences.h" +#ifdef MOZ_AV1 +#include "AOMDecoder.h" +#endif #include "MediaDecoderStateMachine.h" #include "WebMDemuxer.h" #include "WebMDecoder.h" @@ -65,6 +68,11 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, continue; } +#ifdef MOZ_AV1 + if (isVideo && AOMDecoder::IsSupportedCodec(codec)) { + continue; + } +#endif // Some unsupported codec. return false; } -- cgit v1.2.3 From df9477dfa60ebb5d31bc142e58ce46535c17abce Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 17 Oct 2018 05:59:08 -0500 Subject: Update aom to slightly newer commit ID --- dom/media/platforms/agnostic/AOMDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index d1b45cf7f..7e78e1238 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -218,7 +218,7 @@ AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) // for a specific aom commit hash so sites can check // compatibility. auto version = NS_ConvertASCIItoUTF16("av1.experimental."); - version.AppendLiteral("4d668d7feb1f8abd809d1bca0418570a7f142a36"); + version.AppendLiteral("aadbb0251996c8ebb8310567bea330ab7ae9abe4"); return aCodecType.EqualsLiteral("av1") || aCodecType.Equals(version); } -- cgit v1.2.3 From 4b5e2295672e2858d0e09a458f049772930db825 Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 17 Oct 2018 22:40:32 -0500 Subject: Fix typo (build bustage) --- dom/media/webm/WebMDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index d721a8ccc..32feda6c0 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -69,7 +69,7 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, continue; } #ifdef MOZ_AV1 - if (isVideo && AOMDecoder::IsSupportedCodec(codec)) { + if (isWebMVideo && AOMDecoder::IsSupportedCodec(codec)) { continue; } #endif -- cgit v1.2.3 From dddc2aa9ec0bf7c70910f9846667da2691cd2c2f Mon Sep 17 00:00:00 2001 From: trav90 Date: Wed, 17 Oct 2018 22:49:24 -0500 Subject: Add missing includes to FFmpegLibWrapper --- dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp | 1 + dom/media/platforms/ffmpeg/FFmpegLibWrapper.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp index 6302882a6..e1c326818 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp @@ -7,6 +7,7 @@ #include "MediaPrefs.h" #include "mozilla/PodOperations.h" #include "mozilla/Types.h" +#include "PlatformDecoderModule.h" #include "prlink.h" #define AV_LOG_DEBUG 48 diff --git a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h index d6944a1d8..c6c43a4ae 100644 --- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h +++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.h @@ -5,6 +5,7 @@ #ifndef __FFmpegLibWrapper_h__ #define __FFmpegLibWrapper_h__ +#include "mozilla/Attributes.h" #include "mozilla/Types.h" struct AVCodec; @@ -91,4 +92,4 @@ private: } // namespace mozilla -#endif // FFmpegLibWrapper \ No newline at end of file +#endif // FFmpegLibWrapper -- cgit v1.2.3 From 7369c7d7a5eed32963d8af37658286617919f91c Mon Sep 17 00:00:00 2001 From: trav90 Date: Thu, 18 Oct 2018 06:04:57 -0500 Subject: Update aom to commit id f5bdeac22930ff4c6b219be49c843db35970b918 --- dom/media/platforms/agnostic/AOMDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 7e78e1238..009654a5f 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -218,7 +218,7 @@ AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) // for a specific aom commit hash so sites can check // compatibility. auto version = NS_ConvertASCIItoUTF16("av1.experimental."); - version.AppendLiteral("aadbb0251996c8ebb8310567bea330ab7ae9abe4"); + version.AppendLiteral("f5bdeac22930ff4c6b219be49c843db35970b918"); return aCodecType.EqualsLiteral("av1") || aCodecType.Equals(version); } -- cgit v1.2.3 From 4653be96093a65e8db08e29e10e13029fea861e7 Mon Sep 17 00:00:00 2001 From: trav90 Date: Thu, 18 Oct 2018 19:45:59 -0500 Subject: [aom] Resample high bit depth frames The libaom av1 decoder can return high bit depth frame data now. Handle those frames by downsampling them to 8 bits per channel so they can be passed to our normal playback pipeline. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 84 ++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 009654a5f..c2b62eaa4 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -8,6 +8,7 @@ #include "MediaResult.h" #include "TimeUnits.h" #include "aom/aomdx.h" +#include "aom/aom_image.h" #include "gfx2DGlue.h" #include "mozilla/PodOperations.h" #include "mozilla/SyncRunnable.h" @@ -82,6 +83,62 @@ AOMDecoder::Flush() mIsFlushing = false; } +// Ported from third_party/aom/tools_common.c. +static aom_codec_err_t +highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) { + int plane; + if (dst->d_w != src->d_w || dst->d_h != src->d_h) + return AOM_CODEC_INVALID_PARAM; + if (dst->x_chroma_shift != src->x_chroma_shift) + return AOM_CODEC_INVALID_PARAM; + if (dst->y_chroma_shift != src->y_chroma_shift) + return AOM_CODEC_INVALID_PARAM; + if (dst->fmt != (src->fmt & ~AOM_IMG_FMT_HIGHBITDEPTH)) + return AOM_CODEC_INVALID_PARAM; + if (down_shift < 0) + return AOM_CODEC_INVALID_PARAM; + switch (dst->fmt) { + case AOM_IMG_FMT_I420: + case AOM_IMG_FMT_I422: + case AOM_IMG_FMT_I444: + case AOM_IMG_FMT_I440: + break; + default: + return AOM_CODEC_INVALID_PARAM; + } + switch (src->fmt) { + case AOM_IMG_FMT_I42016: + case AOM_IMG_FMT_I42216: + case AOM_IMG_FMT_I44416: + case AOM_IMG_FMT_I44016: + break; + default: + return AOM_CODEC_UNSUP_BITSTREAM; + } + for (plane = 0; plane < 3; plane++) { + int w = src->d_w; + int h = src->d_h; + int x, y; + if (plane) { + w = (w + src->x_chroma_shift) >> src->x_chroma_shift; + h = (h + src->y_chroma_shift) >> src->y_chroma_shift; + } + for (y = 0; y < h; y++) { + uint16_t *p_src = + (uint16_t *)(src->planes[plane] + y * src->stride[plane]); + uint8_t *p_dst = + dst->planes[plane] + y * dst->stride[plane]; + for (x = 0; x < w; x++) *p_dst++ = (*p_src++ >> down_shift) & 0xFF; + } + } + return AOM_CODEC_OK; +} + +// UniquePtr dtor wrapper for aom_image_t. +struct AomImageFree { + void operator()(aom_image_t* img) { aom_img_free(img); } +}; + MediaResult AOMDecoder::DoDecode(MediaRawData* aSample) { @@ -101,11 +158,36 @@ AOMDecoder::DoDecode(MediaRawData* aSample) aom_codec_iter_t iter = nullptr; aom_image_t *img; + UniquePtr img8; while ((img = aom_codec_get_frame(&mCodec, &iter))) { + if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) { + // Downsample images with more than 8 bits per channel. + aom_img_fmt_t fmt8 = static_cast(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH); + img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16)); + if (img8 == nullptr) { + LOG("Couldn't allocate bitdepth reduction target!"); + return MediaResult( + NS_ERROR_OUT_OF_MEMORY, + RESULT_DETAIL("Couldn't allocate conversion buffer for AV1 frame")); + } + if (aom_codec_err_t r = highbd_img_downshift(img8.get(), img, img->bit_depth - 8)) { + LOG_RESULT(r, "Image downconversion failed"); + return MediaResult( + NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("Error converting AV1 frame to 8 bits: %s", + aom_codec_err_to_string(r))); + } + // img normally points to storage owned by mCodec, so it is not freed. + // To copy out the contents of img8 we can overwrite img with an alias. + // Since img is assigned at the start of the while loop and img8 is held + // outside that loop, the alias won't outlive the storage it points to. + img = img8.get(); + } + NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 || img->fmt == AOM_IMG_FMT_I444, - "WebM image format not I420 or I444"); + "AV1 image format not I420 or I444"); // Chroma shifts are rounded down as per the decoding examples in the SDK VideoData::YCbCrBuffer b; -- cgit v1.2.3 From 0c98b71659b728d80231af7c33214e03114f9a62 Mon Sep 17 00:00:00 2001 From: trav90 Date: Thu, 18 Oct 2018 19:47:53 -0500 Subject: [aom] Don't resample 8-bit images The libaom av1 decoder will return 16 bit per channel aom_image_t structures with only 8 significant bits. Detect this case and use the mSkip fields of PlanarYCbCrImage to handle the extra data instead of allocating and performing an extra copy to obtain the necessary 8 bit representation. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index c2b62eaa4..1571fe352 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -161,8 +161,10 @@ AOMDecoder::DoDecode(MediaRawData* aSample) UniquePtr img8; while ((img = aom_codec_get_frame(&mCodec, &iter))) { - if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) { - // Downsample images with more than 8 bits per channel. + // Track whether the underlying buffer is 8 or 16 bits per channel. + bool highbd = bool(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH); + if (img->bit_depth > 8) { + // Downsample images with more than 8 significant bits per channel. aom_img_fmt_t fmt8 = static_cast(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH); img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16)); if (img8 == nullptr) { @@ -183,10 +185,13 @@ AOMDecoder::DoDecode(MediaRawData* aSample) // Since img is assigned at the start of the while loop and img8 is held // outside that loop, the alias won't outlive the storage it points to. img = img8.get(); + highbd = false; } NS_ASSERTION(img->fmt == AOM_IMG_FMT_I420 || - img->fmt == AOM_IMG_FMT_I444, + img->fmt == AOM_IMG_FMT_I42016 || + img->fmt == AOM_IMG_FMT_I444 || + img->fmt == AOM_IMG_FMT_I44416, "AV1 image format not I420 or I444"); // Chroma shifts are rounded down as per the decoding examples in the SDK @@ -195,17 +200,21 @@ AOMDecoder::DoDecode(MediaRawData* aSample) b.mPlanes[0].mStride = img->stride[0]; b.mPlanes[0].mHeight = img->d_h; b.mPlanes[0].mWidth = img->d_w; - b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0; + b.mPlanes[0].mOffset = 0; + b.mPlanes[0].mSkip = highbd ? 1 : 0; b.mPlanes[1].mData = img->planes[1]; b.mPlanes[1].mStride = img->stride[1]; - b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0; + b.mPlanes[1].mOffset = 0; + b.mPlanes[1].mSkip = highbd ? 1 : 0; b.mPlanes[2].mData = img->planes[2]; b.mPlanes[2].mStride = img->stride[2]; - b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0; + b.mPlanes[2].mOffset = 0; + b.mPlanes[2].mSkip = highbd ? 1 : 0; - if (img->fmt == AOM_IMG_FMT_I420) { + if (img->fmt == AOM_IMG_FMT_I420 || + img->fmt == AOM_IMG_FMT_I42016) { b.mPlanes[1].mHeight = (img->d_h + 1) >> img->y_chroma_shift; b.mPlanes[1].mWidth = (img->d_w + 1) >> img->x_chroma_shift; -- cgit v1.2.3 From ec910d81405c736a4490383a250299a7837c2e64 Mon Sep 17 00:00:00 2001 From: trav90 Date: Thu, 18 Oct 2018 21:53:44 -0500 Subject: Update aom to commit id e87fb2378f01103d5d6e477a4ef6892dc714e614 --- dom/media/platforms/agnostic/AOMDecoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 1571fe352..09ce54225 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -113,6 +113,7 @@ highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) { case AOM_IMG_FMT_I44016: break; default: + // We don't support anything that's not 16 bit return AOM_CODEC_UNSUP_BITSTREAM; } for (plane = 0; plane < 3; plane++) { @@ -174,7 +175,6 @@ AOMDecoder::DoDecode(MediaRawData* aSample) RESULT_DETAIL("Couldn't allocate conversion buffer for AV1 frame")); } if (aom_codec_err_t r = highbd_img_downshift(img8.get(), img, img->bit_depth - 8)) { - LOG_RESULT(r, "Image downconversion failed"); return MediaResult( NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("Error converting AV1 frame to 8 bits: %s", @@ -309,7 +309,7 @@ AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) // for a specific aom commit hash so sites can check // compatibility. auto version = NS_ConvertASCIItoUTF16("av1.experimental."); - version.AppendLiteral("f5bdeac22930ff4c6b219be49c843db35970b918"); + version.AppendLiteral("e87fb2378f01103d5d6e477a4ef6892dc714e614"); return aCodecType.EqualsLiteral("av1") || aCodecType.Equals(version); } -- cgit v1.2.3 From bbcc64772580c8a979288791afa02d30bc476d2e Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 19 Oct 2018 21:52:15 -0500 Subject: Update aom to v1.0.0 Update aom to commit id d14c5bb4f336ef1842046089849dee4a301fbbf0. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 09ce54225..9999aac8f 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -309,7 +309,7 @@ AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) // for a specific aom commit hash so sites can check // compatibility. auto version = NS_ConvertASCIItoUTF16("av1.experimental."); - version.AppendLiteral("e87fb2378f01103d5d6e477a4ef6892dc714e614"); + version.AppendLiteral("d14c5bb4f336ef1842046089849dee4a301fbbf0"); return aCodecType.EqualsLiteral("av1") || aCodecType.Equals(version); } -- cgit v1.2.3 From ee1300453eb6e6d32962476351cf4e0391e8b4c4 Mon Sep 17 00:00:00 2001 From: trav90 Date: Fri, 19 Oct 2018 22:11:39 -0500 Subject: Updates to AOMDecoder for aom v1.0.0 This reflects the API changes to the aom_codec_decode function and the removal of I440. It also sets allow_lowbitdepth to give proper support for 8 bit video, and removes the git version from the mime type. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 9999aac8f..d4ce299b4 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -62,6 +62,7 @@ AOMDecoder::Init() PodZero(&config); config.threads = decode_threads; config.w = config.h = 0; // set after decode + config.allow_lowbitdepth = true; aom_codec_flags_t flags = 0; @@ -101,7 +102,6 @@ highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) { case AOM_IMG_FMT_I420: case AOM_IMG_FMT_I422: case AOM_IMG_FMT_I444: - case AOM_IMG_FMT_I440: break; default: return AOM_CODEC_INVALID_PARAM; @@ -110,7 +110,6 @@ highbd_img_downshift(aom_image_t *dst, aom_image_t *src, int down_shift) { case AOM_IMG_FMT_I42016: case AOM_IMG_FMT_I42216: case AOM_IMG_FMT_I44416: - case AOM_IMG_FMT_I44016: break; default: // We don't support anything that's not 16 bit @@ -150,7 +149,7 @@ AOMDecoder::DoDecode(MediaRawData* aSample) "AOM Decode Keyframe error sample->mKeyframe and si.si_kf out of sync"); #endif - if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr, 0)) { + if (aom_codec_err_t r = aom_codec_decode(&mCodec, aSample->Data(), aSample->Size(), nullptr)) { LOG("AOM Decode error: %s", aom_codec_err_to_string(r)); return MediaResult( NS_ERROR_DOM_MEDIA_DECODE_ERR, @@ -305,13 +304,7 @@ AOMDecoder::IsAV1(const nsACString& aMimeType) bool AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) { - // While AV1 is under development, we describe support - // for a specific aom commit hash so sites can check - // compatibility. - auto version = NS_ConvertASCIItoUTF16("av1.experimental."); - version.AppendLiteral("d14c5bb4f336ef1842046089849dee4a301fbbf0"); - return aCodecType.EqualsLiteral("av1") || - aCodecType.Equals(version); + return aCodecType.EqualsLiteral("av1"); } /* static */ -- cgit v1.2.3 From 6ddf66542bfbc90056ca86023da7bdefcec31aa8 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sat, 20 Oct 2018 08:24:28 -0500 Subject: Put AV1 codec behind a pref Disabled by default. --- dom/media/MediaPrefs.h | 3 +++ dom/media/platforms/agnostic/AgnosticDecoderModule.cpp | 8 ++++++-- dom/media/webm/WebMDecoder.cpp | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'dom/media') diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index b237ecd3d..e67796edd 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -120,6 +120,9 @@ private: #ifdef MOZ_FFVPX DECL_MEDIA_PREF("media.ffvpx.enabled", PDMFFVPXEnabled, bool, true); #endif +#ifdef MOZ_AV1 + DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, false); +#endif #ifdef XP_WIN DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true); DECL_MEDIA_PREF("media.wmf.skip-blacklist", PDMWMFSkipBlacklist, bool, false); diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp index 4d4a90bd4..51ca4e9de 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AgnosticDecoderModule.h" +#include "MediaPrefs.h" #include "mozilla/Logging.h" #include "OpusDecoder.h" #include "VorbisDecoder.h" @@ -25,7 +26,9 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType, bool supports = VPXDecoder::IsVPX(aMimeType) || #ifdef MOZ_AV1 - AOMDecoder::IsAV1(aMimeType) || + if (MediaPrefs::AV1Enabled()) { + supports |= AOMDecoder::IsAV1(aMimeType); + } #endif OpusDataDecoder::IsOpus(aMimeType) || VorbisDataDecoder::IsVorbis(aMimeType) || @@ -45,7 +48,8 @@ AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) m = new VPXDecoder(aParams); } #ifdef MOZ_AV1 - else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType)) { + else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType) && + MediaPrefs::AV1Enabled()) { m = new AOMDecoder(aParams); } #endif diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index 32feda6c0..5a32793ac 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -8,6 +8,7 @@ #ifdef MOZ_AV1 #include "AOMDecoder.h" #endif +#include "MediaPrefs.h" #include "MediaDecoderStateMachine.h" #include "WebMDemuxer.h" #include "WebMDecoder.h" @@ -69,7 +70,8 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, continue; } #ifdef MOZ_AV1 - if (isWebMVideo && AOMDecoder::IsSupportedCodec(codec)) { + if (isWebMVideo && MediaPrefs::AV1Enabled() && + AOMDecoder::IsSupportedCodec(codec)) { continue; } #endif -- cgit v1.2.3 From e5b30fc95e191a50da4b8735aaf52baa8d384a0e Mon Sep 17 00:00:00 2001 From: trav90 Date: Sat, 20 Oct 2018 14:49:17 -0500 Subject: Fix canPlayType/isTypeSupported for AV1 content --- dom/media/VideoUtils.cpp | 8 +++++ dom/media/VideoUtils.h | 5 +++ dom/media/platforms/agnostic/AOMDecoder.cpp | 41 +++++++++------------- dom/media/platforms/agnostic/AOMDecoder.h | 3 -- .../platforms/agnostic/AgnosticDecoderModule.cpp | 8 ++--- dom/media/webm/WebMDecoder.cpp | 3 +- 6 files changed, 35 insertions(+), 33 deletions(-) (limited to 'dom/media') diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index b1a202c03..2c8b67a9d 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -458,6 +458,14 @@ IsVP9CodecString(const nsAString& aCodec) aCodec.EqualsLiteral("vp9.0"); } +#ifdef MOZ_AV1 +bool +IsAV1CodecString(const nsAString& aCodec) +{ + return aCodec.EqualsLiteral("av1"); +} +#endif + template static bool StartsWith(const nsACString& string, const char (&prefix)[N]) diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index 441b63792..aaf0e9903 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -345,6 +345,11 @@ IsVP8CodecString(const nsAString& aCodec); bool IsVP9CodecString(const nsAString& aCodec); +#ifdef MOZ_AV1 +bool +IsAV1CodecString(const nsAString& aCodec); +#endif + // Try and create a TrackInfo with a given codec MIME type. UniquePtr CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType); diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index d4ce299b4..7a5fba052 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -49,6 +49,7 @@ RefPtr AOMDecoder::Init() { int decode_threads = 2; + aom_codec_iface_t* dx = aom_codec_av1_dx(); if (mInfo.mDisplay.width >= 2048) { decode_threads = 8; @@ -231,23 +232,22 @@ AOMDecoder::DoDecode(MediaRawData* aSample) RESULT_DETAIL("AOM Unknown image format")); } - RefPtr v; - v = VideoData::CreateAndCopyData(mInfo, - mImageContainer, - aSample->mOffset, - aSample->mTime, - aSample->mDuration, - b, - aSample->mKeyframe, - aSample->mTimecode, - mInfo.ScaledImageRect(img->d_w, - img->d_h)); + RefPtr v = + VideoData::CreateAndCopyData(mInfo, + mImageContainer, + aSample->mOffset, + aSample->mTime, + aSample->mDuration, + b, + aSample->mKeyframe, + aSample->mTimecode, + mInfo.ScaledImageRect(img->d_w, + img->d_h)); if (!v) { - LOG( - "Image allocation error source %ux%u display %ux%u picture %ux%u", - img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height, - mInfo.mImage.width, mInfo.mImage.height); + LOG("Image allocation error source %ux%u display %ux%u picture %ux%u", + img->d_w, img->d_h, mInfo.mDisplay.width, mInfo.mDisplay.height, + mInfo.mImage.width, mInfo.mImage.height); return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__); } mCallback->Output(v); @@ -296,15 +296,8 @@ AOMDecoder::Drain() bool AOMDecoder::IsAV1(const nsACString& aMimeType) { - return aMimeType.EqualsLiteral("video/webm; codecs=av1") - || aMimeType.EqualsLiteral("video/av1"); -} - -/* static */ -bool -AOMDecoder::IsSupportedCodec(const nsAString& aCodecType) -{ - return aCodecType.EqualsLiteral("av1"); + return aMimeType.EqualsLiteral("video/webm; codecs=av1") || + aMimeType.EqualsLiteral("video/av1"); } /* static */ diff --git a/dom/media/platforms/agnostic/AOMDecoder.h b/dom/media/platforms/agnostic/AOMDecoder.h index 1e2b76c2c..ec6b1f95a 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.h +++ b/dom/media/platforms/agnostic/AOMDecoder.h @@ -34,9 +34,6 @@ public: // by our demuxers to identify AV1 streams. static bool IsAV1(const nsACString& aMimeType); - // Return true if aCodecType is a supported codec description. - static bool IsSupportedCodec(const nsAString& aCodecType); - // Return true if a sample is a keyframe. static bool IsKeyframe(Span aBuffer); diff --git a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp index 51ca4e9de..cf5ed3d22 100644 --- a/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp +++ b/dom/media/platforms/agnostic/AgnosticDecoderModule.cpp @@ -25,15 +25,15 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType, { bool supports = VPXDecoder::IsVPX(aMimeType) || + OpusDataDecoder::IsOpus(aMimeType) || + VorbisDataDecoder::IsVorbis(aMimeType) || + WaveDataDecoder::IsWave(aMimeType) || + TheoraDecoder::IsTheora(aMimeType); #ifdef MOZ_AV1 if (MediaPrefs::AV1Enabled()) { supports |= AOMDecoder::IsAV1(aMimeType); } #endif - OpusDataDecoder::IsOpus(aMimeType) || - VorbisDataDecoder::IsVorbis(aMimeType) || - WaveDataDecoder::IsWave(aMimeType) || - TheoraDecoder::IsTheora(aMimeType); MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type", supports ? "supports" : "rejects")); return supports; diff --git a/dom/media/webm/WebMDecoder.cpp b/dom/media/webm/WebMDecoder.cpp index 5a32793ac..9575d6e42 100644 --- a/dom/media/webm/WebMDecoder.cpp +++ b/dom/media/webm/WebMDecoder.cpp @@ -70,8 +70,7 @@ WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs, continue; } #ifdef MOZ_AV1 - if (isWebMVideo && MediaPrefs::AV1Enabled() && - AOMDecoder::IsSupportedCodec(codec)) { + if (MediaPrefs::AV1Enabled() && IsAV1CodecString(codec)) { continue; } #endif -- cgit v1.2.3 From 070c2cb24ce1ff32a538346c7c1dbbe83fc7e171 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sat, 20 Oct 2018 14:50:33 -0500 Subject: Downsample av1 images unconditionally Adding partial support for 10/12-bit video images seems to have broken the native pixel-stride support we were using to pass 8-bit AV1 frame data formatted in 16-bit pixel values, resulting in vertical green lines. Revert to the earlier behavior of always downsampling to 8 bit data. This is slower, but at least displays correctly. --- dom/media/platforms/agnostic/AOMDecoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'dom/media') diff --git a/dom/media/platforms/agnostic/AOMDecoder.cpp b/dom/media/platforms/agnostic/AOMDecoder.cpp index 7a5fba052..b5d21375e 100644 --- a/dom/media/platforms/agnostic/AOMDecoder.cpp +++ b/dom/media/platforms/agnostic/AOMDecoder.cpp @@ -164,8 +164,8 @@ AOMDecoder::DoDecode(MediaRawData* aSample) while ((img = aom_codec_get_frame(&mCodec, &iter))) { // Track whether the underlying buffer is 8 or 16 bits per channel. bool highbd = bool(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH); - if (img->bit_depth > 8) { - // Downsample images with more than 8 significant bits per channel. + if (highbd) { + // Downsample images with more than 8 bits per channel. aom_img_fmt_t fmt8 = static_cast(img->fmt ^ AOM_IMG_FMT_HIGHBITDEPTH); img8.reset(aom_img_alloc(NULL, fmt8, img->d_w, img->d_h, 16)); if (img8 == nullptr) { -- cgit v1.2.3 From 47a01617ea9bb51ecf40d155155299a0278f09f4 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sat, 20 Oct 2018 14:53:15 -0500 Subject: Use larger stack for media decoder threads This increases the thread size for the platform decoder threads (to prevent stack overflows, particularly when decoding av1), while leaving the others at their default values. --- dom/media/VideoUtils.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'dom/media') diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 2c8b67a9d..80d39a49f 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -207,8 +207,20 @@ already_AddRefed GetMediaThreadPool(MediaThreadType aType) name = "MediaPlayback"; break; } - return SharedThreadPool:: + RefPtr pool = SharedThreadPool:: Get(nsDependentCString(name), MediaPrefs::MediaThreadPoolDefaultCount()); + + // Ensure a larger stack for platform decoder threads + if (aType == MediaThreadType::PLATFORM_DECODER) { + const uint32_t minStackSize = 512*1024; + uint32_t stackSize; + MOZ_ALWAYS_SUCCEEDS(pool->GetThreadStackSize(&stackSize)); + if (stackSize < minStackSize) { + MOZ_ALWAYS_SUCCEEDS(pool->SetThreadStackSize(minStackSize)); + } + } + + return pool.forget(); } bool -- cgit v1.2.3 From 29f718ef78f1a25ca904c6438b59ffc8e365a750 Mon Sep 17 00:00:00 2001 From: trav90 Date: Sat, 20 Oct 2018 17:40:24 -0500 Subject: Add support for AV1 in MP4 --- dom/media/fmp4/MP4Decoder.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'dom/media') diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index fdd6f2c7e..5e288d63f 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -139,6 +139,14 @@ MP4Decoder::CanHandleMediaType(const MediaContentType& aType, NS_LITERAL_CSTRING("audio/flac"), aType)); continue; } +#ifdef MOZ_AV1 + if (IsAV1CodecString(codec)) { + trackInfos.AppendElement( + CreateTrackInfoWithMIMETypeAndContentTypeExtraParameters( + NS_LITERAL_CSTRING("video/av1"), aType)); + continue; + } +#endif // Note: Only accept H.264 in a video content type, not in an audio // content type. if (IsWhitelistedH264Codec(codec) && isMP4Video) { -- cgit v1.2.3 From 23013dda60af6191467a46ce73f1382bf69af01e Mon Sep 17 00:00:00 2001 From: trav90 Date: Sun, 21 Oct 2018 10:14:54 -0500 Subject: Ensure we correctly parse the finalized codec string for av1 --- dom/media/VideoUtils.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'dom/media') diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index 80d39a49f..c06ba9070 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -438,6 +438,16 @@ ParseMIMETypeString(const nsAString& aMIMEType, return ParseCodecsString(codecsStr, aOutCodecs); } +template +static bool +StartsWith(const nsACString& string, const char (&prefix)[N]) +{ + if (N - 1 > string.Length()) { + return false; + } + return memcmp(string.Data(), prefix, N - 1) == 0; +} + bool IsH264CodecString(const nsAString& aCodec) { @@ -474,20 +484,11 @@ IsVP9CodecString(const nsAString& aCodec) bool IsAV1CodecString(const nsAString& aCodec) { - return aCodec.EqualsLiteral("av1"); + return aCodec.EqualsLiteral("av1") || + StartsWith(NS_ConvertUTF16toUTF8(aCodec), "av01"); } #endif -template -static bool -StartsWith(const nsACString& string, const char (&prefix)[N]) -{ - if (N - 1 > string.Length()) { - return false; - } - return memcmp(string.Data(), prefix, N - 1) == 0; -} - UniquePtr CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType) { -- cgit v1.2.3 From 192199b03fa2e56d2728b0de1dbe4bedfc1edc50 Mon Sep 17 00:00:00 2001 From: trav90 Date: Tue, 23 Oct 2018 05:47:41 -0500 Subject: Revert "Add support for AV1 in MP4" This commit was incomplete. Will re-land AV1 in MP4 support properly at a future date. This reverts commit 29f718ef78f1a25ca904c6438b59ffc8e365a750. --- dom/media/fmp4/MP4Decoder.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'dom/media') diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 5e288d63f..fdd6f2c7e 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -139,14 +139,6 @@ MP4Decoder::CanHandleMediaType(const MediaContentType& aType, NS_LITERAL_CSTRING("audio/flac"), aType)); continue; } -#ifdef MOZ_AV1 - if (IsAV1CodecString(codec)) { - trackInfos.AppendElement( - CreateTrackInfoWithMIMETypeAndContentTypeExtraParameters( - NS_LITERAL_CSTRING("video/av1"), aType)); - continue; - } -#endif // Note: Only accept H.264 in a video content type, not in an audio // content type. if (IsWhitelistedH264Codec(codec) && isMP4Video) { -- cgit v1.2.3