mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1145926: Part1. Refactor AVCC wrapper. r=cpearce
Add support for future handling of audio remuxing before conversion.
This commit is contained in:
parent
4070c89446
commit
b5bb225e58
@ -1,319 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "AVCCDecoderModule.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
class AVCCMediaDataDecoder : public MediaDataDecoder {
|
||||
public:
|
||||
|
||||
AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
|
||||
virtual ~AVCCMediaDataDecoder();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
virtual bool IsDormantNeeded() override;
|
||||
virtual void AllocateMediaResources() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
private:
|
||||
// Will create the required MediaDataDecoder if we have a AVC SPS.
|
||||
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
|
||||
// will set mError accordingly.
|
||||
nsresult CreateDecoder();
|
||||
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample);
|
||||
void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData);
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mVideoTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsresult mLastError;
|
||||
};
|
||||
|
||||
AVCCMediaDataDecoder::AVCCMediaDataDecoder(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mPDM(aPDM)
|
||||
, mCurrentConfig(aConfig)
|
||||
, mLayersBackend(aLayersBackend)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mVideoTaskQueue(aVideoTaskQueue)
|
||||
, mCallback(aCallback)
|
||||
, mDecoder(nullptr)
|
||||
, mLastError(NS_OK)
|
||||
{
|
||||
CreateDecoder();
|
||||
}
|
||||
|
||||
AVCCMediaDataDecoder::~AVCCMediaDataDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Init()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Init();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv;
|
||||
if (!mDecoder) {
|
||||
// It is not possible to create an AVCC H264 decoder without SPS.
|
||||
// As such, creation will fail if the extra_data just extracted doesn't
|
||||
// contain a SPS.
|
||||
rv = CreateDecoderAndInit(aSample);
|
||||
if (rv == NS_ERROR_NOT_INITIALIZED) {
|
||||
// We are missing the required SPS to create the decoder.
|
||||
// Ignore for the time being, the MP4Sample will be dropped.
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
rv = CheckForSPSChange(aSample);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aSample->extra_data = mCurrentConfig.extra_data;
|
||||
|
||||
return mDecoder->Input(aSample);
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Flush()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Flush();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Drain()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Drain();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::Shutdown()
|
||||
{
|
||||
if (mDecoder) {
|
||||
nsresult rv = mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsWaitingMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
return MediaDataDecoder::IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsDormantNeeded()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::AllocateMediaResources()
|
||||
{
|
||||
// Nothing to do, decoder will be allocated on the fly when required.
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::ReleaseMediaResources()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CreateDecoder()
|
||||
{
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) {
|
||||
// nothing found yet, will try again later
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(mCurrentConfig.extra_data);
|
||||
|
||||
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
|
||||
mLayersBackend,
|
||||
mImageContainer,
|
||||
mVideoTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
mLastError = NS_ERROR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(extra_data);
|
||||
|
||||
nsresult rv = CreateDecoder();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Init();
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCMediaDataDecoder::IsHardwareAccelerated() const
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsHardwareAccelerated();
|
||||
}
|
||||
return MediaDataDecoder::IsHardwareAccelerated();
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCMediaDataDecoder::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
|
||||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
|
||||
mCurrentConfig.extra_data)) {
|
||||
return NS_OK;
|
||||
}
|
||||
// The SPS has changed, signal to flush the current decoder and create a
|
||||
// new one.
|
||||
mDecoder->Flush();
|
||||
ReleaseMediaResources();
|
||||
return CreateDecoderAndInit(aSample);
|
||||
}
|
||||
|
||||
void
|
||||
AVCCMediaDataDecoder::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
|
||||
mCurrentConfig.image_width = spsdata.pic_width;
|
||||
mCurrentConfig.image_height = spsdata.pic_height;
|
||||
mCurrentConfig.display_width = spsdata.display_width;
|
||||
mCurrentConfig.display_height = spsdata.display_height;
|
||||
}
|
||||
mCurrentConfig.extra_data = aExtraData;
|
||||
}
|
||||
|
||||
// AVCCDecoderModule
|
||||
|
||||
AVCCDecoderModule::AVCCDecoderModule(PlatformDecoderModule* aPDM)
|
||||
: mPDM(aPDM)
|
||||
{
|
||||
MOZ_ASSERT(aPDM);
|
||||
}
|
||||
|
||||
AVCCDecoderModule::~AVCCDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
AVCCDecoderModule::Startup()
|
||||
{
|
||||
return mPDM->Startup();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
nsRefPtr<MediaDataDecoder> decoder;
|
||||
|
||||
if ((!aConfig.mime_type.EqualsLiteral("video/avc") &&
|
||||
!aConfig.mime_type.EqualsLiteral("video/mp4")) ||
|
||||
!mPDM->DecoderNeedsAVCC(aConfig)) {
|
||||
// There is no need for an AVCC wrapper for non-AVC content.
|
||||
decoder = mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
} else {
|
||||
decoder = new AVCCMediaDataDecoder(mPDM,
|
||||
aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
AVCCDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
return mPDM->CreateAudioDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return mPDM->SupportsAudioMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
AVCCDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return mPDM->SupportsVideoMimeType(aMimeType);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
@ -1,53 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_AVCCDecoderModule_h
|
||||
#define mozilla_AVCCDecoderModule_h
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AVCCMediaDataDecoder;
|
||||
|
||||
// AVCCDecoderModule is a PlatformDecoderModule wrapper used to ensure that
|
||||
// only AVCC format is fed to the underlying PlatformDecoderModule.
|
||||
// The AVCCDecoderModule allows playback of content where the SPS NAL may not be
|
||||
// provided in the init segment (e.g. AVC3 or Annex B)
|
||||
// AVCCDecoderModule will monitor the input data, and will delay creation of the
|
||||
// MediaDataDecoder until a SPS and PPS NALs have been extracted.
|
||||
//
|
||||
// AVCC-only decoder modules are AppleVideoDecoder and EMEH264Decoder.
|
||||
|
||||
class AVCCDecoderModule : public PlatformDecoderModule {
|
||||
public:
|
||||
explicit AVCCDecoderModule(PlatformDecoderModule* aPDM);
|
||||
virtual ~AVCCDecoderModule();
|
||||
|
||||
virtual nsresult Startup() override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
virtual bool SupportsVideoMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
private:
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AVCCDecoderModule_h
|
@ -238,11 +238,17 @@ public:
|
||||
}
|
||||
|
||||
virtual bool
|
||||
SupportsAudioMimeType(const nsACString& aMimeType) override
|
||||
SupportsMimeType(const nsACString& aMimeType) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return kNeedNone;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule()
|
||||
|
@ -344,7 +344,7 @@ MP4Reader::IsSupportedAudioMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return (aMimeType.EqualsLiteral("audio/mpeg") ||
|
||||
aMimeType.EqualsLiteral("audio/mp4a-latm")) &&
|
||||
mPlatform->SupportsAudioMimeType(aMimeType);
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -353,7 +353,7 @@ MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
|
||||
return (aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/x-vnd.on2.vp6")) &&
|
||||
mPlatform->SupportsVideoMimeType(aMimeType);
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
void
|
||||
@ -514,9 +514,10 @@ MP4Reader::EnsureDecodersSetup()
|
||||
NS_ENSURE_TRUE(IsSupportedAudioMimeType(mDemuxer->AudioConfig().mime_type),
|
||||
false);
|
||||
|
||||
mAudio.mDecoder = mPlatform->CreateAudioDecoder(mDemuxer->AudioConfig(),
|
||||
mAudio.mTaskQueue,
|
||||
mAudio.mCallback);
|
||||
mAudio.mDecoder =
|
||||
mPlatform->CreateDecoder(mDemuxer->AudioConfig(),
|
||||
mAudio.mTaskQueue,
|
||||
mAudio.mCallback);
|
||||
NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, false);
|
||||
nsresult rv = mAudio.mDecoder->Init();
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
@ -535,11 +536,12 @@ MP4Reader::EnsureDecodersSetup()
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
} else {
|
||||
mVideo.mDecoder = mPlatform->CreateVideoDecoder(mDemuxer->VideoConfig(),
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback);
|
||||
mVideo.mDecoder =
|
||||
mPlatform->CreateDecoder(mDemuxer->VideoConfig(),
|
||||
mVideo.mTaskQueue,
|
||||
mVideo.mCallback,
|
||||
mLayersBackendType,
|
||||
mDecoder->GetImageContainer());
|
||||
}
|
||||
NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false);
|
||||
nsresult rv = mVideo.mDecoder->Init();
|
||||
|
@ -5,7 +5,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "AVCCDecoderModule.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
@ -32,6 +31,9 @@
|
||||
#include "SharedThreadPool.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "H264Converter.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
|
||||
@ -107,10 +109,7 @@ PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
}
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> emepdm(
|
||||
new AVCCDecoderModule(new EMEDecoderModule(aProxy,
|
||||
pdm,
|
||||
cdmDecodesAudio,
|
||||
cdmDecodesVideo)));
|
||||
new EMEDecoderModule(aProxy, pdm, cdmDecodesAudio, cdmDecodesVideo));
|
||||
return emepdm.forget();
|
||||
}
|
||||
#endif
|
||||
@ -151,13 +150,12 @@ PlatformDecoderModule::CreatePDM()
|
||||
if (sFFmpegDecoderEnabled) {
|
||||
nsRefPtr<PlatformDecoderModule> m = FFmpegRuntimeLinker::CreateDecoderModule();
|
||||
if (m) {
|
||||
nsRefPtr<PlatformDecoderModule> m2(new AVCCDecoderModule(m));
|
||||
return m2.forget();
|
||||
return m.forget();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_APPLEMEDIA
|
||||
nsRefPtr<PlatformDecoderModule> m(new AVCCDecoderModule(new AppleDecoderModule()));
|
||||
nsRefPtr<PlatformDecoderModule> m(new AppleDecoderModule());
|
||||
return m.forget();
|
||||
#endif
|
||||
#ifdef MOZ_GONK_MEDIACODEC
|
||||
@ -173,28 +171,55 @@ PlatformDecoderModule::CreatePDM()
|
||||
}
|
||||
#endif
|
||||
if (sGMPDecoderEnabled) {
|
||||
nsRefPtr<PlatformDecoderModule> m(new AVCCDecoderModule(new GMPDecoderModule()));
|
||||
nsRefPtr<PlatformDecoderModule> m(new GMPDecoderModule());
|
||||
return m.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
PlatformDecoderModule::CreateDecoder(const mp4_demuxer::TrackConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm");
|
||||
nsRefPtr<MediaDataDecoder> m;
|
||||
|
||||
if (aConfig.IsAudioConfig()) {
|
||||
m = CreateAudioDecoder(static_cast<const mp4_demuxer::AudioDecoderConfig&>(aConfig),
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
return m.forget();
|
||||
}
|
||||
|
||||
if (!aConfig.IsVideoConfig()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (H264Converter::IsH264(aConfig)) {
|
||||
m = new H264Converter(this,
|
||||
static_cast<const mp4_demuxer::VideoDecoderConfig&>(aConfig),
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
} else {
|
||||
m = CreateVideoDecoder(static_cast<const mp4_demuxer::VideoDecoderConfig&>(aConfig),
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aTaskQueue,
|
||||
aCallback);
|
||||
}
|
||||
return m.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType)
|
||||
PlatformDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("video/mp4") || aMimeType.EqualsLiteral("video/avc");
|
||||
}
|
||||
|
||||
bool
|
||||
PlatformDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
return false;
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <queue>
|
||||
|
||||
namespace mp4_demuxer {
|
||||
class TrackConfig;
|
||||
class VideoDecoderConfig;
|
||||
class AudioDecoderConfig;
|
||||
class MP4Sample;
|
||||
@ -86,7 +87,44 @@ public:
|
||||
bool aHasVideo);
|
||||
#endif
|
||||
|
||||
// Creates an H.264 decoder. The layers backend is passed in so that
|
||||
// Creates a decoder.
|
||||
// See CreateVideoDecoder and CreateAudioDecoder for implementation details.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateDecoder(const mp4_demuxer::TrackConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
layers::LayersBackend aLayersBackend = layers::LayersBackend::LAYERS_NONE,
|
||||
layers::ImageContainer* aImageContainer = nullptr);
|
||||
|
||||
// An audio decoder module must support AAC by default.
|
||||
// A video decoder must support H264 by default.
|
||||
// If more codecs are to be supported, SupportsMimeType will have
|
||||
// to be extended
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType);
|
||||
|
||||
enum ConversionRequired {
|
||||
kNeedNone,
|
||||
kNeedAVCC,
|
||||
kNeedAnnexB,
|
||||
};
|
||||
|
||||
// Indicates that the decoder requires a specific format.
|
||||
// The PlatformDecoderModule will convert the demuxed data accordingly before
|
||||
// feeding it to MediaDataDecoder::Input.
|
||||
virtual ConversionRequired DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const = 0;
|
||||
|
||||
virtual void DisableHardwareAcceleration() {}
|
||||
|
||||
virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
|
||||
friend class H264Converter;
|
||||
// Creates a Video decoder. The layers backend is passed in so that
|
||||
// decoders can determine whether hardware accelerated decoding can be used.
|
||||
// Asynchronous decoding of video should be done in runnables dispatched
|
||||
// to aVideoTaskQueue. If the task queue isn't needed, the decoder should
|
||||
@ -99,10 +137,10 @@ public:
|
||||
// This is called on the decode task queue.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Creates an Audio decoder with the specified properties.
|
||||
// Asynchronous decoding of audio should be done in runnables dispatched to
|
||||
@ -119,24 +157,6 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// An audio decoder module must support AAC by default.
|
||||
// If more audio codec is to be supported, SupportsAudioMimeType will have
|
||||
// to be extended
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType);
|
||||
virtual bool SupportsVideoMimeType(const nsACString& aMimeType);
|
||||
|
||||
// Indicates if the video decoder requires AVCC format.
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig);
|
||||
|
||||
virtual void DisableHardwareAcceleration() {}
|
||||
|
||||
virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
PlatformDecoderModule() {}
|
||||
virtual ~PlatformDecoderModule() {}
|
||||
// Caches pref media.fragmented-mp4.use-blank-decoder
|
||||
static bool sUseBlankDecoder;
|
||||
static bool sFFmpegDecoderEnabled;
|
||||
@ -213,7 +233,6 @@ public:
|
||||
// The MP4Reader will not call Input() while it's calling Flush().
|
||||
virtual nsresult Flush() = 0;
|
||||
|
||||
|
||||
// Causes all complete samples in the pipeline that can be decoded to be
|
||||
// output. If the decoder can't produce samples from the current output,
|
||||
// it drops the input samples. The decoder may be holding onto samples
|
||||
@ -244,6 +263,15 @@ public:
|
||||
virtual void AllocateMediaResources() {}
|
||||
virtual void ReleaseMediaResources() {}
|
||||
virtual bool IsHardwareAccelerated() const { return false; }
|
||||
|
||||
// ConfigurationChanged will be called to inform the video or audio decoder
|
||||
// that the format of the next input sample is about to change.
|
||||
// If video decoder, aConfig will be a VideoDecoderConfig object.
|
||||
// If audio decoder, aConfig will be a AudioDecoderConfig object.
|
||||
virtual nsresult ConfigurationChanged(const mp4_demuxer::TrackConfig& aConfig)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -87,11 +87,12 @@ SharedDecoderManager::CreateVideoDecoder(
|
||||
// passed in, so that none of the objects sharing the decoder can shutdown
|
||||
// the task queue while we're potentially still using it for a *different*
|
||||
// object also sharing the decoder.
|
||||
mDecoder = aPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
mTaskQueue,
|
||||
mCallback);
|
||||
mDecoder =
|
||||
aPDM->CreateDecoder(aConfig,
|
||||
mTaskQueue,
|
||||
mCallback,
|
||||
aLayersBackend,
|
||||
aImageContainer);
|
||||
if (!mDecoder) {
|
||||
mPDM = nullptr;
|
||||
return nullptr;
|
||||
@ -119,11 +120,11 @@ SharedDecoderManager::Recreate(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
{
|
||||
mDecoder->Flush();
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
mTaskQueue,
|
||||
mCallback);
|
||||
mDecoder = mPDM->CreateDecoder(aConfig,
|
||||
mTaskQueue,
|
||||
mCallback,
|
||||
aLayersBackend,
|
||||
aImageContainer);
|
||||
if (!mDecoder) {
|
||||
return false;
|
||||
}
|
||||
|
@ -63,10 +63,6 @@ public:
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return MediaCodecDataDecoder::Input(aSample);
|
||||
}
|
||||
|
||||
@ -248,8 +244,13 @@ public:
|
||||
};
|
||||
|
||||
|
||||
bool AndroidDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType) {
|
||||
return static_cast<bool>(CreateDecoder(aMimeType));
|
||||
bool AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
if (aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc")) {
|
||||
return true;
|
||||
}
|
||||
return static_cast<bool>(mozilla::CreateDecoder(aMimeType));
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
@ -296,6 +297,16 @@ AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig&
|
||||
|
||||
}
|
||||
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
AndroidDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAnnexB;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
|
||||
const nsACString& aMimeType,
|
||||
MediaFormat::Param aFormat,
|
||||
|
@ -35,7 +35,10 @@ public:
|
||||
AndroidDecoderModule() {}
|
||||
virtual ~AndroidDecoderModule() {}
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
};
|
||||
|
||||
class MediaCodecDataDecoder : public MediaDataDecoder {
|
||||
|
@ -192,15 +192,20 @@ AppleDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aC
|
||||
}
|
||||
|
||||
bool
|
||||
AppleDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
AppleDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") || aMimeType.EqualsLiteral("audio/mpeg");
|
||||
return aMimeType.EqualsLiteral("audio/mpeg") ||
|
||||
PlatformDecoderModule::SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
bool
|
||||
AppleDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
AppleDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return true;
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -32,9 +32,10 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
|
||||
static void Init();
|
||||
static nsresult CanDecode();
|
||||
|
@ -253,11 +253,12 @@ EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig,
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback));
|
||||
nsRefPtr<MediaDataDecoder> decoder(
|
||||
mPDM->CreateDecoder(aConfig,
|
||||
aVideoTaskQueue,
|
||||
aCallback,
|
||||
aLayersBackend,
|
||||
aImageContainer));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -286,9 +287,8 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAudioDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback));
|
||||
nsRefPtr<MediaDataDecoder> decoder(
|
||||
mPDM->CreateDecoder(aConfig, aAudioTaskQueue, aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -303,10 +303,14 @@ EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
EMEDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
EMEDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return mCDMDecodesVideo && aConfig.crypto.valid;
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -42,8 +42,8 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
|
@ -51,19 +51,22 @@ public:
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
virtual bool SupportsAudioMimeType(const nsACString& aMimeType) override
|
||||
virtual bool SupportsMimeType(const nsACString& aMimeType) override
|
||||
{
|
||||
return FFmpegAudioDecoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
return FFmpegAudioDecoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE ||
|
||||
FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
virtual bool SupportsVideoMimeType(const nsACString& aMimeType) override
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override
|
||||
{
|
||||
return FFmpegH264Decoder<V>::GetCodecId(aMimeType) != AV_CODEC_ID_NONE;
|
||||
}
|
||||
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override
|
||||
{
|
||||
return true;
|
||||
if (aConfig.IsVideoConfig() &&
|
||||
(aConfig.mime_type.EqualsLiteral("video/avc") ||
|
||||
aConfig.mime_type.EqualsLiteral("video/mp4"))) {
|
||||
return PlatformDecoderModule::kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -75,11 +75,15 @@ GMPDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aCon
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
GMPDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
// GMPVideoCodecType::kGMPVideoCodecH264 specifies that encoded frames must be in AVCC format.
|
||||
return true;
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -31,7 +31,8 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -51,4 +51,14 @@ GonkDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aCo
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
GonkDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
if (aConfig.IsVideoConfig()) {
|
||||
return kNeedAVCC;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -31,6 +31,9 @@ public:
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
static void Init();
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -452,20 +452,6 @@ GonkVideoDecoderManager::SendSampleToOMX(mp4_demuxer::MP4Sample* aSample)
|
||||
0);
|
||||
}
|
||||
|
||||
bool
|
||||
GonkVideoDecoderManager::PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (aSample != nullptr) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
GVDM_LOG("Failed to convert sample to annex B!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::ClearQueueFrameTime()
|
||||
{
|
||||
|
@ -58,8 +58,6 @@ public:
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
protected:
|
||||
virtual bool PerformFormatSpecificProcess(mp4_demuxer::MP4Sample* aSample) override;
|
||||
|
||||
virtual android::status_t SendSampleToOMX(mp4_demuxer::MP4Sample* aSample) override;
|
||||
|
||||
private:
|
||||
|
@ -5,21 +5,21 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS += [
|
||||
'AVCCDecoderModule.h',
|
||||
'MP4Decoder.h',
|
||||
'MP4Reader.h',
|
||||
'MP4Stream.h',
|
||||
'PlatformDecoderModule.h',
|
||||
'SharedDecoderManager.h',
|
||||
'wrappers/H264Converter.h'
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AVCCDecoderModule.cpp',
|
||||
'BlankDecoderModule.cpp',
|
||||
'MP4Decoder.cpp',
|
||||
'MP4Stream.cpp',
|
||||
'PlatformDecoderModule.cpp',
|
||||
'SharedDecoderManager.cpp',
|
||||
'wrappers/H264Converter.cpp'
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -121,19 +121,26 @@ WMFDecoderModule::SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig&
|
||||
}
|
||||
|
||||
bool
|
||||
WMFDecoderModule::SupportsVideoMimeType(const nsACString& aMimeType)
|
||||
WMFDecoderModule::SupportsMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return aMimeType.EqualsLiteral("video/mp4") ||
|
||||
aMimeType.EqualsLiteral("video/avc") ||
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp8") ||
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp9");
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp9") ||
|
||||
aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("audio/mpeg");
|
||||
}
|
||||
|
||||
bool
|
||||
WMFDecoderModule::SupportsAudioMimeType(const nsACString& aMimeType)
|
||||
PlatformDecoderModule::ConversionRequired
|
||||
WMFDecoderModule::DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const
|
||||
{
|
||||
return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
|
||||
aMimeType.EqualsLiteral("audio/mpeg");
|
||||
if (aConfig.IsVideoConfig() &&
|
||||
(aConfig.mime_type.EqualsLiteral("video/avc") ||
|
||||
aConfig.mime_type.EqualsLiteral("video/mp4"))) {
|
||||
return kNeedAnnexB;
|
||||
} else {
|
||||
return kNeedNone;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -31,8 +31,7 @@ public:
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
bool SupportsVideoMimeType(const nsACString& aMimeType) override;
|
||||
bool SupportsAudioMimeType(const nsACString& aMimeType) override;
|
||||
bool SupportsMimeType(const nsACString& aMimeType) override;
|
||||
|
||||
virtual void DisableHardwareAcceleration() override
|
||||
{
|
||||
@ -41,6 +40,9 @@ public:
|
||||
|
||||
virtual bool SupportsSharedDecoders(const mp4_demuxer::VideoDecoderConfig& aConfig) const override;
|
||||
|
||||
virtual ConversionRequired
|
||||
DecoderNeedsConversion(const mp4_demuxer::TrackConfig& aConfig) const override;
|
||||
|
||||
// Accessors that report whether we have the required MFTs available
|
||||
// on the system to play various codecs. Windows Vista doesn't have the
|
||||
// H.264/AAC decoders if the "Platform Update Supplement for Windows Vista"
|
||||
|
@ -241,12 +241,6 @@ WMFVideoMFTManager::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
// This can happen during shutdown.
|
||||
return E_FAIL;
|
||||
}
|
||||
if (mStreamType != VP8 && mStreamType != VP9) {
|
||||
// We must prepare samples in AVC Annex B.
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
// Forward sample data to the decoder.
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(aSample->data);
|
||||
uint32_t length = aSample->size;
|
||||
|
249
dom/media/fmp4/wrappers/H264Converter.cpp
Normal file
249
dom/media/fmp4/wrappers/H264Converter.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/* -*- 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 "H264Converter.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
namespace mozilla
|
||||
{
|
||||
|
||||
// H264 AnnexB or AVCC handler
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "mp4_demuxer/AnnexB.h"
|
||||
#include "mp4_demuxer/H264.h"
|
||||
|
||||
H264Converter::H264Converter(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
: mPDM(aPDM)
|
||||
, mCurrentConfig(aConfig)
|
||||
, mLayersBackend(aLayersBackend)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mVideoTaskQueue(aVideoTaskQueue)
|
||||
, mCallback(aCallback)
|
||||
, mDecoder(nullptr)
|
||||
, mNeedAVCC(aPDM->DecoderNeedsConversion(aConfig) == PlatformDecoderModule::kNeedAVCC)
|
||||
, mLastError(NS_OK)
|
||||
{
|
||||
CreateDecoder();
|
||||
}
|
||||
|
||||
H264Converter::~H264Converter()
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Init()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Init();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (!mNeedAVCC) {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
nsresult rv;
|
||||
if (!mDecoder) {
|
||||
// It is not possible to create an AVCC H264 decoder without SPS.
|
||||
// As such, creation will fail if the extra_data just extracted doesn't
|
||||
// contain a SPS.
|
||||
rv = CreateDecoderAndInit(aSample);
|
||||
if (rv == NS_ERROR_NOT_INITIALIZED) {
|
||||
// We are missing the required SPS to create the decoder.
|
||||
// Ignore for the time being, the MP4Sample will be dropped.
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
rv = CheckForSPSChange(aSample);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aSample->extra_data = mCurrentConfig.extra_data;
|
||||
|
||||
return mDecoder->Input(aSample);
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Flush()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Flush();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Drain()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->Drain();
|
||||
}
|
||||
return mLastError;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::Shutdown()
|
||||
{
|
||||
if (mDecoder) {
|
||||
nsresult rv = mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsWaitingMediaResources()
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsWaitingMediaResources();
|
||||
}
|
||||
return MediaDataDecoder::IsWaitingMediaResources();
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsDormantNeeded()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
return true;
|
||||
}
|
||||
return mDecoder ?
|
||||
mDecoder->IsDormantNeeded() : MediaDataDecoder::IsDormantNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::AllocateMediaResources()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
// Nothing to do, decoder will be allocated on the fly when required.
|
||||
return;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->AllocateMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::ReleaseMediaResources()
|
||||
{
|
||||
if (mNeedAVCC) {
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->ReleaseMediaResources();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
H264Converter::IsHardwareAccelerated() const
|
||||
{
|
||||
if (mDecoder) {
|
||||
return mDecoder->IsHardwareAccelerated();
|
||||
}
|
||||
return MediaDataDecoder::IsHardwareAccelerated();
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CreateDecoder()
|
||||
{
|
||||
if (mNeedAVCC && !mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.extra_data)) {
|
||||
// nothing found yet, will try again later
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(mCurrentConfig.extra_data);
|
||||
|
||||
mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
|
||||
mLayersBackend,
|
||||
mImageContainer,
|
||||
mVideoTaskQueue,
|
||||
mCallback);
|
||||
if (!mDecoder) {
|
||||
mLastError = NS_ERROR_FAILURE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data)) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
UpdateConfigFromExtraData(extra_data);
|
||||
|
||||
nsresult rv = CreateDecoder();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return Init();
|
||||
}
|
||||
|
||||
nsresult
|
||||
H264Converter::CheckForSPSChange(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
nsRefPtr<mp4_demuxer::ByteBuffer> extra_data =
|
||||
mp4_demuxer::AnnexB::ExtractExtraData(aSample);
|
||||
if (!mp4_demuxer::AnnexB::HasSPS(extra_data) ||
|
||||
mp4_demuxer::AnnexB::CompareExtraData(extra_data,
|
||||
mCurrentConfig.extra_data)) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (!mNeedAVCC) {
|
||||
UpdateConfigFromExtraData(extra_data);
|
||||
mDecoder->ConfigurationChanged(mCurrentConfig);
|
||||
return NS_OK;
|
||||
}
|
||||
// The SPS has changed, signal to flush the current decoder and create a
|
||||
// new one.
|
||||
mDecoder->Flush();
|
||||
ReleaseMediaResources();
|
||||
return CreateDecoderAndInit(aSample);
|
||||
}
|
||||
|
||||
void
|
||||
H264Converter::UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData)
|
||||
{
|
||||
mp4_demuxer::SPSData spsdata;
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
|
||||
mCurrentConfig.image_width = spsdata.pic_width;
|
||||
mCurrentConfig.image_height = spsdata.pic_height;
|
||||
mCurrentConfig.display_width = spsdata.display_width;
|
||||
mCurrentConfig.display_height = spsdata.display_height;
|
||||
}
|
||||
mCurrentConfig.extra_data = aExtraData;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
H264Converter::IsH264(const mp4_demuxer::TrackConfig& aConfig)
|
||||
{
|
||||
return aConfig.mime_type.EqualsLiteral("video/avc") ||
|
||||
aConfig.mime_type.EqualsLiteral("video/mp4");
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
68
dom/media/fmp4/wrappers/H264Converter.h
Normal file
68
dom/media/fmp4/wrappers/H264Converter.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_H264Converter_h
|
||||
#define mozilla_H264Converter_h
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// H264Converter is a MediaDataDecoder wrapper used to ensure that
|
||||
// only AVCC or AnnexB is fed to the underlying MediaDataDecoder.
|
||||
// The H264Converter allows playback of content where the SPS NAL may not be
|
||||
// provided in the init segment (e.g. AVC3 or Annex B)
|
||||
// H264Converter will monitor the input data, and will delay creation of the
|
||||
// MediaDataDecoder until a SPS and PPS NALs have been extracted.
|
||||
|
||||
class H264Converter : public MediaDataDecoder {
|
||||
public:
|
||||
|
||||
H264Converter(PlatformDecoderModule* aPDM,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback);
|
||||
virtual ~H264Converter();
|
||||
|
||||
virtual nsresult Init() override;
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Flush() override;
|
||||
virtual nsresult Drain() override;
|
||||
virtual nsresult Shutdown() override;
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
virtual bool IsDormantNeeded() override;
|
||||
virtual void AllocateMediaResources() override;
|
||||
virtual void ReleaseMediaResources() override;
|
||||
virtual bool IsHardwareAccelerated() const override;
|
||||
|
||||
// Return true if mimetype is H.264.
|
||||
static bool IsH264(const mp4_demuxer::TrackConfig& aConfig);
|
||||
|
||||
private:
|
||||
// Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL.
|
||||
// Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
|
||||
// will set mError accordingly.
|
||||
nsresult CreateDecoder();
|
||||
nsresult CreateDecoderAndInit(mp4_demuxer::MP4Sample* aSample);
|
||||
nsresult CheckForSPSChange(mp4_demuxer::MP4Sample* aSample);
|
||||
void UpdateConfigFromExtraData(mp4_demuxer::ByteBuffer* aExtraData);
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
mp4_demuxer::VideoDecoderConfig mCurrentConfig;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
nsRefPtr<layers::ImageContainer> mImageContainer;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mVideoTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
bool mNeedAVCC;
|
||||
nsresult mLastError;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_H264Converter_h
|
@ -116,7 +116,7 @@ IntelWebMVideoDecoder::IsSupportedVideoMimeType(const nsACString& aMimeType)
|
||||
{
|
||||
return (aMimeType.EqualsLiteral("video/webm; codecs=vp8") ||
|
||||
aMimeType.EqualsLiteral("video/webm; codecs=vp9")) &&
|
||||
mPlatform->SupportsVideoMimeType(aMimeType);
|
||||
mPlatform->SupportsMimeType(aMimeType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -147,11 +147,12 @@ IntelWebMVideoDecoder::Init(unsigned int aWidth, unsigned int aHeight)
|
||||
if (!IsSupportedVideoMimeType(video.mime_type)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mMediaDataDecoder = mPlatform->CreateVideoDecoder(video,
|
||||
mReader->GetLayersBackendType(),
|
||||
mReader->GetDecoder()->GetImageContainer(),
|
||||
mTaskQueue,
|
||||
this);
|
||||
mMediaDataDecoder =
|
||||
mPlatform->CreateDecoder(video,
|
||||
mTaskQueue,
|
||||
this,
|
||||
mReader->GetLayersBackendType(),
|
||||
mReader->GetDecoder()->GetImageContainer());
|
||||
if (!mMediaDataDecoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -91,13 +91,34 @@ public:
|
||||
class TrackConfig
|
||||
{
|
||||
public:
|
||||
TrackConfig() : mTrackId(0), duration(0), media_time(0) {}
|
||||
enum TrackType {
|
||||
kUndefinedTrack,
|
||||
kAudioTrack,
|
||||
kVideoTrack,
|
||||
};
|
||||
explicit TrackConfig(TrackType aType)
|
||||
: mTrackId(0)
|
||||
, duration(0)
|
||||
, media_time(0)
|
||||
, mType(aType)
|
||||
{
|
||||
}
|
||||
|
||||
nsAutoCString mime_type;
|
||||
uint32_t mTrackId;
|
||||
int64_t duration;
|
||||
int64_t media_time;
|
||||
CryptoTrack crypto;
|
||||
TrackType mType;
|
||||
|
||||
bool IsAudioConfig() const
|
||||
{
|
||||
return mType == kAudioTrack;
|
||||
}
|
||||
bool IsVideoConfig() const
|
||||
{
|
||||
return mType == kVideoTrack;
|
||||
}
|
||||
void Update(stagefright::sp<stagefright::MetaData>& aMetaData,
|
||||
const char* aMimeType);
|
||||
};
|
||||
@ -106,7 +127,8 @@ class AudioDecoderConfig : public TrackConfig
|
||||
{
|
||||
public:
|
||||
AudioDecoderConfig()
|
||||
: channel_count(0)
|
||||
: TrackConfig(kAudioTrack)
|
||||
, channel_count(0)
|
||||
, bits_per_sample(0)
|
||||
, samples_per_second(0)
|
||||
, frequency_index(0)
|
||||
@ -138,7 +160,8 @@ class VideoDecoderConfig : public TrackConfig
|
||||
{
|
||||
public:
|
||||
VideoDecoderConfig()
|
||||
: display_width(0)
|
||||
: TrackConfig(kVideoTrack)
|
||||
, display_width(0)
|
||||
, display_height(0)
|
||||
, image_width(0)
|
||||
, image_height(0)
|
||||
|
Loading…
Reference in New Issue
Block a user