Bug 1424416 - Add RequiresDrainning method to MediaDataDecoder and update impls. r?jya
Add RequiresDraining method, which indicates if a decoder requires draining in
order to output all frames in the event of an EOS or running out of data. By
default decoders indicate they require draining. This provides safe default
behaviour.
For a number of decoders we can safely avoid draining, override the method for
these. This will allow users of these decoders to simplify handling and offer
performance improvements.
MozReview-Commit-ID: 67ZrWhgFL5i
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -311,16 +311,28 @@ public:
{
return false;
}
// Return the name of the MediaDataDecoder, only used for decoding.
// May be accessed in a non thread-safe fashion.
virtual nsCString GetDescriptionName() const = 0;
+ // Return if a decoder needs to be drained in order to output all samples.
+ // Some decoders may buffer samples in order to decode expected future
+ // samples. In these cases the decoder must be drained to ensure all samples
+ // are output when reaching end of stream or running out of data. However,
+ // if a decoder does not buffer samples, then it does not need draining, and
+ // users can avoid doing so, which can benefit performance and simplify code.
+ // Even if a decoder does not require draining, a sane implementation of
+ // Drain() should be specified. It is safe to say a decoder requires draining
+ // even if it does not strictly need it. However bustages will result if a
+ // decoder reports it does not require draining when it does.
+ virtual bool RequiresDrainning() const { return true; }
+
// Set a hint of seek target time to decoder. Decoder will drop any decoded
// data which pts is smaller than this value. This threshold needs to be clear
// after reset decoder.
// Decoder may not honor this value. However, it'd be better that
// video decoder implements this API to improve seek performance.
// Note: it should be called before Input() or after Flush().
virtual void SetSeekThreshold(const media::TimeUnit& aTime) { }
--- a/dom/media/platforms/agnostic/AOMDecoder.h
+++ b/dom/media/platforms/agnostic/AOMDecoder.h
@@ -27,16 +27,20 @@ public:
RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
RefPtr<DecodePromise> Drain() override;
RefPtr<FlushPromise> Flush() override;
RefPtr<ShutdownPromise> Shutdown() override;
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("av1 libaom video decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
// 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 aCodecType is a supported codec description.
static bool IsSupportedCodec(const nsAString& aCodecType);
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -32,16 +32,20 @@ public:
RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
RefPtr<DecodePromise> Drain() override;
RefPtr<FlushPromise> Flush() override;
RefPtr<ShutdownPromise> Shutdown() override;
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("opus audio decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
// Return true if mimetype is Opus
static bool IsOpus(const nsACString& aMimeType);
// Pack pre-skip/CodecDelay, given in microseconds, into a
// MediaByteBuffer. The decoder expects this value to come
// from the container (if any) and to precede the OpusHead
// block in the CodecSpecificConfig buffer to verify the
--- a/dom/media/platforms/agnostic/TheoraDecoder.h
+++ b/dom/media/platforms/agnostic/TheoraDecoder.h
@@ -31,16 +31,21 @@ public:
// Return true if mimetype is a Theora codec
static bool IsTheora(const nsACString& aMimeType);
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("theora video decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
+
private:
~TheoraDecoder();
nsresult DoDecodeHeader(const unsigned char* aData, size_t aLength);
RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
RefPtr<layers::KnowsCompositor> mImageAllocator;
RefPtr<layers::ImageContainer> mImageContainer;
--- a/dom/media/platforms/agnostic/VPXDecoder.h
+++ b/dom/media/platforms/agnostic/VPXDecoder.h
@@ -30,16 +30,20 @@ public:
RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
RefPtr<DecodePromise> Drain() override;
RefPtr<FlushPromise> Flush() override;
RefPtr<ShutdownPromise> Shutdown() override;
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("libvpx video decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
enum Codec: uint8_t
{
VP8 = 1 << 0,
VP9 = 1 << 1,
Unknown = 1 << 7,
};
--- a/dom/media/platforms/agnostic/VorbisDecoder.h
+++ b/dom/media/platforms/agnostic/VorbisDecoder.h
@@ -32,16 +32,20 @@ public:
RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
RefPtr<DecodePromise> Drain() override;
RefPtr<FlushPromise> Flush() override;
RefPtr<ShutdownPromise> Shutdown() override;
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("vorbis audio decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
// Return true if mimetype is Vorbis
static bool IsVorbis(const nsACString& aMimeType);
static const AudioConfig::Channel* VorbisLayout(uint32_t aChannels);
private:
nsresult DecodeHeader(const unsigned char* aData, size_t aLength);
RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
--- a/dom/media/platforms/agnostic/WAVDecoder.h
+++ b/dom/media/platforms/agnostic/WAVDecoder.h
@@ -27,16 +27,20 @@ public:
RefPtr<DecodePromise> Decode(MediaRawData* aSample) override;
RefPtr<DecodePromise> Drain() override;
RefPtr<FlushPromise> Flush() override;
RefPtr<ShutdownPromise> Shutdown() override;
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("wave audio decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
private:
RefPtr<DecodePromise> ProcessDecode(MediaRawData* aSample);
const AudioInfo& mInfo;
const RefPtr<TaskQueue> mTaskQueue;
};
} // namespace mozilla
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -110,17 +110,16 @@ AppleATDecoder::Flush()
LOG("Flushing AudioToolbox AAC decoder");
return InvokeAsync(mTaskQueue, this, __func__, &AppleATDecoder::ProcessFlush);
}
RefPtr<MediaDataDecoder::DecodePromise>
AppleATDecoder::Drain()
{
LOG("Draining AudioToolbox AAC decoder");
- RefPtr<AppleATDecoder> self = this;
return InvokeAsync(mTaskQueue, __func__, [] {
return DecodePromise::CreateAndResolve(DecodedData(), __func__);
});
}
RefPtr<ShutdownPromise>
AppleATDecoder::Shutdown()
{
--- a/dom/media/platforms/apple/AppleATDecoder.h
+++ b/dom/media/platforms/apple/AppleATDecoder.h
@@ -34,16 +34,21 @@ public:
RefPtr<FlushPromise> Flush() override;
RefPtr<ShutdownPromise> Shutdown() override;
nsCString GetDescriptionName() const override
{
return NS_LITERAL_CSTRING("apple coremedia decoder");
}
+ bool RequiresDrainning() const override
+ {
+ return false;
+ }
+
// Callbacks also need access to the config.
const AudioInfo& mConfig;
// Use to extract magic cookie for HE-AAC detection.
nsTArray<uint8_t> mMagicCookie;
// Will be set to true should an error occurred while attempting to retrieve
// the magic cookie property.
bool mFileStreamError;