mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 959440 - Various cleanups in MP4Reader. r=kinetik
Change PlatformDecoderModule::Create*Decoder() to take an mp4_demuxer::{Audio,Video}DecoderConfig parameter, instead of enumerating all parameters. This means the platform decoders can have more data if need be, like the AACAudioConfig. Change MediaDataDecoder::Input() to take an nsAutoPtr<MP4Sample>&. The sample will be deleted by the caller (MP4Reader) if Input() returns DECODE_STATUS_OK, but if the MediaDataDecoder wants to assume responsibility of the lifecycle of the sample (say to enqueue it), it can forget() on the nsAutoPtr& passed in and assume responsibility. Call PlatformDecoderModule::Create() on the decode thread. This is a step towards making these classes decode-thread only. Add PlatformDecoderModule::Init(), which caches the pref's we need, since PlatformDecoderModule::Create() is no longer called on the main thread, we can no longer access them in there. Add Init() method to MediaDataDecoder interface. This is so that we can call MediaDataDecoder::Shutdown() to unblock the initialization of a decoder, if that init needs to block. Pass LayersBackend type to WMFVideoDecoder, so it knows whether to init DXVA.
This commit is contained in:
parent
c5b512938d
commit
cb82b1e057
@ -11,6 +11,8 @@
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
#include "mp4_demuxer/audio_decoder_config.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -22,33 +24,36 @@ public:
|
||||
|
||||
BlankMediaDataDecoder(BlankMediaDataCreator* aCreator)
|
||||
: mCreator(aCreator),
|
||||
mNextDTS(-1),
|
||||
mNextTimeStamp(-1),
|
||||
mNextOffset(-1)
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult Init() MOZ_OVERRIDE {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual nsresult Shutdown() MOZ_OVERRIDE {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual DecoderStatus Input(const uint8_t* aData,
|
||||
uint32_t aLength,
|
||||
Microseconds aDTS,
|
||||
Microseconds aPTS,
|
||||
int64_t aOffsetInStream) MOZ_OVERRIDE
|
||||
virtual DecoderStatus Input(nsAutoPtr<mp4_demuxer::MP4Sample>& aSample) MOZ_OVERRIDE
|
||||
{
|
||||
// Accepts input, and outputs on the second input, using the difference
|
||||
// in DTS as the duration.
|
||||
if (mOutput) {
|
||||
return DECODE_STATUS_NOT_ACCEPTING;
|
||||
}
|
||||
if (mNextDTS != -1 && mNextOffset != -1) {
|
||||
Microseconds duration = aDTS - mNextDTS;
|
||||
mOutput = mCreator->Create(mNextDTS, duration, mNextOffset);
|
||||
|
||||
Microseconds timestamp = aSample->composition_timestamp;
|
||||
if (mNextTimeStamp != -1 && mNextOffset != -1) {
|
||||
Microseconds duration = timestamp - mNextTimeStamp;
|
||||
mOutput = mCreator->Create(mNextTimeStamp, duration, mNextOffset);
|
||||
}
|
||||
|
||||
mNextDTS = aDTS;
|
||||
mNextOffset = aOffsetInStream;
|
||||
mNextTimeStamp = timestamp;
|
||||
mNextOffset = aSample->byte_offset;
|
||||
|
||||
return DECODE_STATUS_OK;
|
||||
}
|
||||
|
||||
@ -66,7 +71,7 @@ public:
|
||||
}
|
||||
private:
|
||||
nsAutoPtr<BlankMediaDataCreator> mCreator;
|
||||
Microseconds mNextDTS;
|
||||
Microseconds mNextTimeStamp;
|
||||
int64_t mNextOffset;
|
||||
nsAutoPtr<MediaData> mOutput;
|
||||
bool mHasInput;
|
||||
@ -198,21 +203,19 @@ public:
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
virtual MediaDataDecoder* CreateH264Decoder(layers::LayersBackend aLayersBackend,
|
||||
virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer) MOZ_OVERRIDE {
|
||||
BlankVideoDataCreator* decoder = new BlankVideoDataCreator(aImageContainer);
|
||||
return new BlankMediaDataDecoder<BlankVideoDataCreator>(decoder);
|
||||
}
|
||||
|
||||
// Decode thread.
|
||||
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);
|
||||
virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig) MOZ_OVERRIDE {
|
||||
BlankAudioDataCreator* decoder =
|
||||
new BlankAudioDataCreator(ChannelLayoutToChannelCount(aConfig.channel_layout()),
|
||||
aConfig.samples_per_second(),
|
||||
aConfig.bits_per_channel());
|
||||
return new BlankMediaDataDecoder<BlankAudioDataCreator>(decoder);
|
||||
}
|
||||
};
|
||||
|
@ -123,12 +123,10 @@ nsresult
|
||||
MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
|
||||
PlatformDecoderModule::Init();
|
||||
mMP4Stream = new MP4Stream(mDecoder->GetResource());
|
||||
mDemuxer = new MP4Demuxer(mMP4Stream);
|
||||
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
|
||||
InitLayersBackendType();
|
||||
|
||||
return NS_OK;
|
||||
@ -157,25 +155,28 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
|
||||
if (mHasAudio) {
|
||||
mInfo.mAudio.mRate = audio.samples_per_second();
|
||||
mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(audio.channel_layout());
|
||||
mAudioDecoder = mPlatform->CreateAACDecoder(mInfo.mAudio.mChannels,
|
||||
mInfo.mAudio.mRate,
|
||||
audio.bits_per_channel(),
|
||||
audio.extra_data(),
|
||||
audio.extra_data_size());
|
||||
mAudioDecoder = mPlatform->CreateAACDecoder(audio);
|
||||
NS_ENSURE_TRUE(mAudioDecoder != nullptr, NS_ERROR_FAILURE);
|
||||
nsresult rv = mAudioDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mInfo.mVideo.mHasVideo = mHasVideo = mDemuxer->HasVideo();
|
||||
if (mHasVideo) {
|
||||
const VideoDecoderConfig& config = mDemuxer->VideoConfig();
|
||||
IntSize sz = config.natural_size();
|
||||
IntSize sz = video.natural_size();
|
||||
mInfo.mVideo.mDisplay = nsIntSize(sz.width(), sz.height());
|
||||
mVideoDecoder = mPlatform->CreateH264Decoder(mLayersBackendType,
|
||||
mVideoDecoder = mPlatform->CreateH264Decoder(video,
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer());
|
||||
NS_ENSURE_TRUE(mVideoDecoder != nullptr, NS_ERROR_FAILURE);
|
||||
nsresult rv = mVideoDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Get the duration, and report it to the decoder if we have it.
|
||||
@ -282,16 +283,15 @@ MP4Reader::Decode(TrackType aTrack, nsAutoPtr<MediaData>& aOutData)
|
||||
// frames coming.
|
||||
return false;
|
||||
}
|
||||
const std::vector<uint8_t>* data = compressed->data;
|
||||
status = decoder->Input(&data->front(),
|
||||
data->size(),
|
||||
compressed->decode_timestamp,
|
||||
compressed->composition_timestamp,
|
||||
compressed->byte_offset);
|
||||
status = decoder->Input(compressed);
|
||||
} while (status == DECODE_STATUS_OK);
|
||||
if (status == DECODE_STATUS_NOT_ACCEPTING) {
|
||||
// Decoder should now be able to produce an output.
|
||||
SampleQueue(aTrack).push_front(compressed.forget());
|
||||
if (compressed != nullptr) {
|
||||
// Decoder didn't consume data, attempt to decode the same
|
||||
// sample next time.
|
||||
SampleQueue(aTrack).push_front(compressed.forget());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
LOG("MP4Reader decode failure. track=%d status=%d\n", aTrack, status);
|
||||
@ -401,8 +401,9 @@ MP4Reader::OnDecodeThreadStart()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Must not be on main thread.");
|
||||
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mPlatform);
|
||||
mPlatform->OnDecodeThreadStart();
|
||||
if (mPlatform) {
|
||||
mPlatform->OnDecodeThreadStart();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -410,8 +411,9 @@ MP4Reader::OnDecodeThreadFinish()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread(), "Must not be on main thread.");
|
||||
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||
MOZ_ASSERT(mPlatform);
|
||||
mPlatform->OnDecodeThreadFinish();
|
||||
if (mPlatform) {
|
||||
mPlatform->OnDecodeThreadFinish();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "mp4_demuxer/box_definitions.h"
|
||||
|
||||
#include <deque>
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -82,7 +83,6 @@ private:
|
||||
|
||||
bool mHasAudio;
|
||||
bool mHasVideo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,16 +14,31 @@ namespace mozilla {
|
||||
|
||||
extern PlatformDecoderModule* CreateBlankDecoderModule();
|
||||
|
||||
bool PlatformDecoderModule::sUseBlankDecoder = false;
|
||||
|
||||
/* static */
|
||||
void
|
||||
PlatformDecoderModule::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
static bool alreadyInitialized = false;
|
||||
if (alreadyInitialized) {
|
||||
return;
|
||||
}
|
||||
alreadyInitialized = true;
|
||||
sUseBlankDecoder = Preferences::GetBool("media.fragmented-mp4.use-blank-decoder");
|
||||
}
|
||||
|
||||
/* static */
|
||||
PlatformDecoderModule*
|
||||
PlatformDecoderModule::Create()
|
||||
{
|
||||
if (Preferences::GetBool("media.fragmented-mp4.use-blank-decoder")) {
|
||||
if (sUseBlankDecoder) {
|
||||
return CreateBlankDecoderModule();
|
||||
}
|
||||
#ifdef XP_WIN
|
||||
nsAutoPtr<WMFDecoderModule> m(new WMFDecoderModule());
|
||||
if (NS_SUCCEEDED(m->Init())) {
|
||||
if (NS_SUCCEEDED(m->Startup())) {
|
||||
return m.forget();
|
||||
}
|
||||
#endif
|
||||
|
@ -9,6 +9,13 @@
|
||||
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mp4_demuxer {
|
||||
class VideoDecoderConfig;
|
||||
class AudioDecoderConfig;
|
||||
class MP4Sample;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -35,6 +42,9 @@ typedef int64_t Microseconds;
|
||||
// "media.fragmented-mp4.use-blank-decoder" is true.
|
||||
class PlatformDecoderModule {
|
||||
public:
|
||||
// Call on the main thread to initialize the static state
|
||||
// needed by Create().
|
||||
static void Init();
|
||||
|
||||
// Factory method that creates the appropriate PlatformDecoderModule for
|
||||
// the platform we're running on. Caller is responsible for deleting this
|
||||
@ -56,7 +66,8 @@ public:
|
||||
// decoding can be used. Returns nullptr if the decoder can't be
|
||||
// initialized.
|
||||
// Called on decode thread.
|
||||
virtual MediaDataDecoder* CreateH264Decoder(layers::LayersBackend aLayersBackend,
|
||||
virtual MediaDataDecoder* CreateH264Decoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer) = 0;
|
||||
|
||||
// Creates and initializes an AAC decoder with the specified properties.
|
||||
@ -65,11 +76,7 @@ public:
|
||||
// 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;
|
||||
virtual MediaDataDecoder* CreateAACDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig) = 0;
|
||||
|
||||
// Called when a decode thread is started. Called on decode thread.
|
||||
virtual void OnDecodeThreadStart() {}
|
||||
@ -80,6 +87,8 @@ public:
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
// Caches pref media.fragmented-mp4.use-blank-decoder
|
||||
static bool sUseBlankDecoder;
|
||||
};
|
||||
|
||||
// Return value of the MediaDataDecoder functions.
|
||||
@ -102,10 +111,29 @@ class MediaDataDecoder {
|
||||
public:
|
||||
virtual ~MediaDataDecoder() {};
|
||||
|
||||
// Initialize the decoder. The decoder should be ready to decode after
|
||||
// this returns. The decoder should do any initialization here, rather
|
||||
// than in its constructor, so that if the MP4Reader needs to Shutdown()
|
||||
// during initialization it can call Shutdown() to cancel this.
|
||||
// Any initialization that requires blocking the calling thread *must*
|
||||
// be done here so that it can be canceled by calling Shutdown()!
|
||||
virtual nsresult Init() = 0;
|
||||
|
||||
// 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.
|
||||
// asynchronously.
|
||||
//
|
||||
// If the decoder needs to assume ownership of the sample it may do so by
|
||||
// calling forget() on aSample.
|
||||
//
|
||||
// If Input() returns DECODE_STATUS_NOT_ACCEPTING without forget()ing
|
||||
// aSample, then the next call will have the same aSample. Otherwise
|
||||
// the caller will delete aSample after Input() returns.
|
||||
//
|
||||
// The MP4Reader calls Input() in a loop until Input() stops returning
|
||||
// DECODE_STATUS_OK. Input() should return DECODE_STATUS_NOT_ACCEPTING
|
||||
// once the underlying decoder should have enough data to output decoded
|
||||
// data.
|
||||
//
|
||||
// Called on the media decode thread.
|
||||
// Returns:
|
||||
// - DECODE_STATUS_OK if input was successfully inserted into
|
||||
@ -114,15 +142,13 @@ public:
|
||||
// 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.
|
||||
// after the decoder's Output() function has stopped producing output,
|
||||
// except if Input() called forget() on aSample, whereupon a new sample
|
||||
// will come in next call.
|
||||
// - 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;
|
||||
virtual DecoderStatus Input(nsAutoPtr<mp4_demuxer::MP4Sample>& aSample) = 0;
|
||||
|
||||
// Blocks until a decoded sample is produced by the deoder. The MP4Reader
|
||||
// calls this until it stops returning DECODE_STATUS_OK.
|
||||
|
Loading…
Reference in New Issue
Block a user