diff --git a/content/media/fmp4/BlankDecoderModule.cpp b/content/media/fmp4/BlankDecoderModule.cpp index bef6244072be..b578ebcc6fe8 100644 --- a/content/media/fmp4/BlankDecoderModule.cpp +++ b/content/media/fmp4/BlankDecoderModule.cpp @@ -198,18 +198,18 @@ public: } // Decode thread. - virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) MOZ_OVERRIDE { + virtual MediaDataDecoder* CreateH264Decoder(layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) MOZ_OVERRIDE { BlankVideoDataCreator* decoder = new BlankVideoDataCreator(aImageContainer); return new BlankMediaDataDecoder(decoder); } // Decode thread. - virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount, - uint32_t aSampleRate, - uint16_t aBitsPerSample, - const uint8_t* aUserData, - uint32_t aUserDataLength) MOZ_OVERRIDE { + virtual MediaDataDecoder* CreateAACDecoder(uint32_t aChannelCount, + uint32_t aSampleRate, + uint16_t aBitsPerSample, + const uint8_t* aUserData, + uint32_t aUserDataLength) MOZ_OVERRIDE { BlankAudioDataCreator* decoder = new BlankAudioDataCreator(aChannelCount, aSampleRate, aBitsPerSample); diff --git a/content/media/fmp4/MP4Reader.cpp b/content/media/fmp4/MP4Reader.cpp index 15e426625877..82358465b237 100644 --- a/content/media/fmp4/MP4Reader.cpp +++ b/content/media/fmp4/MP4Reader.cpp @@ -160,11 +160,11 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo, if (mHasAudio) { mInfo.mAudio.mRate = audio.samples_per_second(); mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(audio.channel_layout()); - mAudioDecoder = mPlatform->CreateAudioDecoder(mInfo.mAudio.mChannels, - mInfo.mAudio.mRate, - audio.bits_per_channel(), - audio.extra_data(), - audio.extra_data_size()); + mAudioDecoder = mPlatform->CreateAACDecoder(mInfo.mAudio.mChannels, + mInfo.mAudio.mRate, + audio.bits_per_channel(), + audio.extra_data(), + audio.extra_data_size()); NS_ENSURE_TRUE(mAudioDecoder != nullptr, NS_ERROR_FAILURE); } @@ -173,8 +173,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo, const VideoDecoderConfig& config = mDemuxer->VideoConfig(); IntSize sz = config.natural_size(); mInfo.mVideo.mDisplay = nsIntSize(sz.width(), sz.height()); - mVideoDecoder = mPlatform->CreateVideoDecoder(mLayersBackendType, - mDecoder->GetImageContainer()); + mVideoDecoder = mPlatform->CreateH264Decoder(mLayersBackendType, + mDecoder->GetImageContainer()); NS_ENSURE_TRUE(mVideoDecoder != nullptr, NS_ERROR_FAILURE); } diff --git a/content/media/fmp4/PlatformDecoderModule.cpp b/content/media/fmp4/PlatformDecoderModule.cpp index fdb37aedb0dd..ed51a6842e7d 100644 --- a/content/media/fmp4/PlatformDecoderModule.cpp +++ b/content/media/fmp4/PlatformDecoderModule.cpp @@ -30,14 +30,4 @@ PlatformDecoderModule::Create() return nullptr; } -void -PlatformDecoderModule::OnDecodeThreadStart() -{ -} - -void -PlatformDecoderModule::OnDecodeThreadFinish() -{ -} - } // namespace mozilla diff --git a/content/media/fmp4/PlatformDecoderModule.h b/content/media/fmp4/PlatformDecoderModule.h index 182c3ce3ebb0..94674acbefd7 100644 --- a/content/media/fmp4/PlatformDecoderModule.h +++ b/content/media/fmp4/PlatformDecoderModule.h @@ -16,69 +16,145 @@ namespace layers { class ImageContainer; } +class MediaDataDecoder; typedef int64_t Microseconds; -enum DecoderStatus { - DECODE_STATUS_NOT_ACCEPTING, // Can't accept input at this time. - DECODE_STATUS_NEED_MORE_INPUT, // Nothing in pipeline to produce output with at this time. - DECODE_STATUS_OK, - DECODE_STATUS_ERROR -}; - -class MediaDataDecoder { -public: - virtual ~MediaDataDecoder() {}; - - virtual nsresult Shutdown() = 0; - - // Returns true if future decodes may produce output, or false - // on end of segment. - // Inserts data into the decoder's pipeline. - virtual DecoderStatus Input(const uint8_t* aData, - uint32_t aLength, - Microseconds aDTS, - Microseconds aPTS, - int64_t aOffsetInStream) = 0; - - // Blocks until decoded sample is produced by the deoder. - virtual DecoderStatus Output(nsAutoPtr& aOutData) = 0; - - virtual DecoderStatus Flush() = 0; -}; - +// The PlatformDecoderModule interface is used by the MP4Reader to abstract +// access to the H264 and AAC decoders provided by various platforms. It +// may be extended to support other codecs in future. Each platform (Windows, +// MacOSX, Linux etc) must implement a PlatformDecoderModule to provide access +// to its decoders in order to get decompressed H.264/AAC from the MP4Reader. +// +// Platforms that don't have a corresponding PlatformDecoderModule won't be +// able to play the H.264/AAC data output by the MP4Reader. In practice this +// means that we won't have fragmented MP4 supported in Media Source +// Extensions on platforms without PlatformDecoderModules. +// +// A cross-platform decoder module that discards input and produces "blank" +// output samples exists for testing, and is created if the pref +// "media.fragmented-mp4.use-blank-decoder" is true. class PlatformDecoderModule { public: - // Creates the appropriate PlatformDecoderModule for this platform. - // Caller is responsible for deleting this instance. It's safe to have - // multiple PlatformDecoderModules alive at the same time. - // There is one PlatformDecoderModule's created per media decoder. + // Factory method that creates the appropriate PlatformDecoderModule for + // the platform we're running on. Caller is responsible for deleting this + // instance. It's expected that there will be multiple + // PlatformDecoderModules alive at the same time. There is one + // PlatformDecoderModule's created per MP4Reader. + // This is called on the main thread. static PlatformDecoderModule* Create(); - // Called when the decoders have shutdown. Main thread only. + // Called to shutdown the decoder module and cleanup state. This should + // block until shutdown is complete. This is called after Shutdown() has + // been called on all MediaDataDecoders created from this + // PlatformDecoderModule. + // Called on the main thread only. virtual nsresult Shutdown() = 0; - // TODO: Parameters for codec type. - // Decode thread. - virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend, - layers::ImageContainer* aImageContainer) = 0; + // Creates and initializes an H.264 decoder. The layers backend is + // passed in so that decoders can determine whether hardware accelerated + // decoding can be used. Returns nullptr if the decoder can't be + // initialized. + // Called on decode thread. + virtual MediaDataDecoder* CreateH264Decoder(layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) = 0; - // Decode thread. - virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount, - uint32_t aSampleRate, - uint16_t aBitsPerSample, - const uint8_t* aUserData, - uint32_t aUserDataLength) = 0; + // Creates and initializes an AAC decoder with the specified properties. + // The raw AAC AudioSpecificConfig as contained in the esds box. Some + // decoders need that to initialize. The caller owns the AAC config, + // so it must be copied if it is to be retained by the decoder. + // Returns nullptr if the decoder can't be initialized. + // Called on decode thread. + virtual MediaDataDecoder* CreateAACDecoder(uint32_t aChannelCount, + uint32_t aSampleRate, + uint16_t aBitsPerSample, + const uint8_t* aAACConfig, + uint32_t aAACConfigLength) = 0; - // Platform decoders can override these. Base implementation does nothing. - virtual void OnDecodeThreadStart(); - virtual void OnDecodeThreadFinish(); + // Called when a decode thread is started. Called on decode thread. + virtual void OnDecodeThreadStart() {} + + // Called just before a decode thread is finishing. Called on decode thread. + virtual void OnDecodeThreadFinish() {} virtual ~PlatformDecoderModule() {} protected: PlatformDecoderModule() {} }; +// Return value of the MediaDataDecoder functions. +enum DecoderStatus { + DECODE_STATUS_NOT_ACCEPTING, // Can't accept input at this time. Decoder can produce output. + DECODE_STATUS_NEED_MORE_INPUT, // Can't produce output. Decoder can accept input. + DECODE_STATUS_OK, + DECODE_STATUS_ERROR +}; + +// MediaDataDecoder is the interface exposed by decoders created by the +// PlatformDecoderModule's Create*Decoder() functions. The type of +// media data that the decoder accepts as valid input and produces as +// output is determined when the MediaDataDecoder is created. +// The decoder is assumed to be in one of three mutually exclusive and +// implicit states: able to accept input, able to produce output, and +// shutdown. The decoder is assumed to be able to accept input by the time +// that it's returned by PlatformDecoderModule::Create*Decoder(). +class MediaDataDecoder { +public: + virtual ~MediaDataDecoder() {}; + + // Inserts aData into the decoding pipeline. Decoding may begin + // asynchronously. The caller owns aData, so it may need to be copied. + // The MP4Reader calls Input() with new input in a loop until Input() + // stops returning DECODE_STATUS_OK. + // Called on the media decode thread. + // Returns: + // - DECODE_STATUS_OK if input was successfully inserted into + // the decode pipeline. + // - DECODE_STATUS_NOT_ACCEPTING if the decoder cannot accept any input + // at this time. The MP4Reader will assume that the decoder can now + // produce one or more output samples, and call the Output() function. + // The MP4Reader will call Input() again with the same data later, + // after the decoder's Output() function has stopped producing output. + // - DECODE_STATUS_ERROR if the decoder has been shutdown, or some + // unspecified error. + // This function should not return DECODE_STATUS_NEED_MORE_INPUT. + virtual DecoderStatus Input(const uint8_t* aData, + uint32_t aLength, + Microseconds aDTS, + Microseconds aPTS, + int64_t aOffsetInStream) = 0; + + // Blocks until a decoded sample is produced by the deoder. The MP4Reader + // calls this until it stops returning DECODE_STATUS_OK. + // Called on the media decode thread. + // Returns: + // - DECODE_STATUS_OK if an output sample was successfully placed in + // aOutData. More samples for output may still be available, the + // MP4Reader will call again to check. + // - DECODE_STATUS_NEED_MORE_INPUT if the decoder needs more input to + // produce a sample. The decoder should return this once it can no + // longer produce output. This signals to the MP4Reader that it should + // start feeding in data via the Input() function. + // - DECODE_STATUS_ERROR if the decoder has been shutdown, or some + // unspecified error. + // This function should not return DECODE_STATUS_NOT_ACCEPTING. + virtual DecoderStatus Output(nsAutoPtr& aOutData) = 0; + + // Causes all samples in the decoding pipeline to be discarded. When + // this function returns, the decoder must be ready to accept new input + // for decoding. This function is called when the demuxer seeks, before + // decoding resumes after the seek. + // Called on the media decode thread. + virtual DecoderStatus Flush() = 0; + + // Cancels all decode operations, and shuts down the decoder. This should + // block until shutdown is complete. The decoder should return + // DECODE_STATUS_ERROR for all calls to its functions once this is called. + // Called on main thread. + virtual nsresult Shutdown() = 0; + +}; + } // namespace mozilla #endif diff --git a/content/media/fmp4/wmf/WMFDecoderModule.cpp b/content/media/fmp4/wmf/WMFDecoderModule.cpp index 331f9b6ee146..7d428bbe5d2b 100644 --- a/content/media/fmp4/wmf/WMFDecoderModule.cpp +++ b/content/media/fmp4/wmf/WMFDecoderModule.cpp @@ -56,8 +56,8 @@ WMFDecoderModule::Shutdown() } MediaDataDecoder* -WMFDecoderModule::CreateVideoDecoder(mozilla::layers::LayersBackend aLayersBackend, - mozilla::layers::ImageContainer* aImageContainer) +WMFDecoderModule::CreateH264Decoder(mozilla::layers::LayersBackend aLayersBackend, + mozilla::layers::ImageContainer* aImageContainer) { nsAutoPtr decoder(new WMFVideoDecoder(mDXVAEnabled)); nsresult rv = decoder->Init(aLayersBackend, aImageContainer); @@ -66,11 +66,11 @@ WMFDecoderModule::CreateVideoDecoder(mozilla::layers::LayersBackend aLayersBacke } MediaDataDecoder* -WMFDecoderModule::CreateAudioDecoder(uint32_t aChannelCount, - uint32_t aSampleRate, - uint16_t aBitsPerSample, - const uint8_t* aUserData, - uint32_t aUserDataLength) +WMFDecoderModule::CreateAACDecoder(uint32_t aChannelCount, + uint32_t aSampleRate, + uint16_t aBitsPerSample, + const uint8_t* aUserData, + uint32_t aUserDataLength) { nsAutoPtr decoder(new WMFAudioDecoder()); nsresult rv = decoder->Init(aChannelCount, diff --git a/content/media/fmp4/wmf/WMFDecoderModule.h b/content/media/fmp4/wmf/WMFDecoderModule.h index 983d807c5cc2..34371cde22de 100644 --- a/content/media/fmp4/wmf/WMFDecoderModule.h +++ b/content/media/fmp4/wmf/WMFDecoderModule.h @@ -26,15 +26,15 @@ public: // Decode thread. virtual MediaDataDecoder* - CreateVideoDecoder(mozilla::layers::LayersBackend aLayersBackend, - mozilla::layers::ImageContainer* aImageContainer) MOZ_OVERRIDE; + CreateH264Decoder(mozilla::layers::LayersBackend aLayersBackend, + mozilla::layers::ImageContainer* aImageContainer) MOZ_OVERRIDE; // Decode thread. - virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount, - uint32_t aSampleRate, - uint16_t aBitsPerSample, - const uint8_t* aUserData, - uint32_t aUserDataLength) MOZ_OVERRIDE; + virtual MediaDataDecoder* CreateAACDecoder(uint32_t aChannelCount, + uint32_t aSampleRate, + uint16_t aBitsPerSample, + const uint8_t* aUserData, + uint32_t aUserDataLength) MOZ_OVERRIDE; // Platform decoders can override these. Base implementation does nothing. virtual void OnDecodeThreadStart() MOZ_OVERRIDE;