Files
tubestation/dom/media/webrtc/libwebrtcglue/WebrtcMediaDataDecoderCodec.cpp

194 lines
6.6 KiB
C++

/* 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 "WebrtcMediaDataDecoderCodec.h"
#include "ImageContainer.h"
#include "Layers.h"
#include "MediaDataDecoderProxy.h"
#include "PDMFactory.h"
#include "VideoUtils.h"
#include "ImageContainer.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/media/MediaUtils.h"
#include "webrtc/rtc_base/keep_ref_until_done.h"
namespace mozilla {
WebrtcMediaDataDecoder::WebrtcMediaDataDecoder(nsACString& aCodecMimeType)
: mThreadPool(GetMediaThreadPool(MediaThreadType::SUPERVISOR)),
mTaskQueue(new TaskQueue(do_AddRef(mThreadPool),
"WebrtcMediaDataDecoder::mTaskQueue")),
mImageContainer(MakeAndAddRef<layers::ImageContainer>(
layers::ImageContainer::ASYNCHRONOUS)),
mFactory(new PDMFactory()),
mTrackType(TrackInfo::kUndefinedTrack),
mCodecType(aCodecMimeType) {}
WebrtcMediaDataDecoder::~WebrtcMediaDataDecoder() {}
int32_t WebrtcMediaDataDecoder::InitDecode(
const webrtc::VideoCodec* aCodecSettings, int32_t aNumberOfCores) {
nsCString codec;
mTrackType = TrackInfo::kVideoTrack;
mInfo = VideoInfo(aCodecSettings->width, aCodecSettings->height);
mInfo.mMimeType = mCodecType;
return CreateDecoder();
}
int32_t WebrtcMediaDataDecoder::Decode(
const webrtc::EncodedImage& aInputImage, bool aMissingFrames,
const webrtc::RTPFragmentationHeader* aFragmentation,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
int64_t aRenderTimeMs) {
if (!mCallback || !mDecoder) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (!aInputImage._buffer || !aInputImage._length) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
// Always start with a complete key frame.
if (mNeedKeyframe) {
if (aInputImage._frameType != webrtc::FrameType::kVideoFrameKey)
return WEBRTC_VIDEO_CODEC_ERROR;
// We have a key frame - is it complete?
if (aInputImage._completeFrame) {
mNeedKeyframe = false;
} else {
return WEBRTC_VIDEO_CODEC_ERROR;
}
}
RefPtr<MediaRawData> compressedFrame =
new MediaRawData(aInputImage._buffer, aInputImage._length);
if (!compressedFrame->Data()) {
return WEBRTC_VIDEO_CODEC_MEMORY;
}
compressedFrame->mTime =
media::TimeUnit::FromMicroseconds(aInputImage._timeStamp);
compressedFrame->mTimecode =
media::TimeUnit::FromMicroseconds(aRenderTimeMs * 1000);
compressedFrame->mKeyframe =
aInputImage._frameType == webrtc::FrameType::kVideoFrameKey;
{
media::Await(
do_AddRef(mThreadPool), mDecoder->Decode(compressedFrame),
[&](const MediaDataDecoder::DecodedData& aResults) {
mResults = aResults.Clone();
mError = NS_OK;
},
[&](const MediaResult& aError) { mError = aError; });
for (auto& frame : mResults) {
MOZ_ASSERT(frame->mType == MediaData::Type::VIDEO_DATA);
RefPtr<VideoData> video = frame->As<VideoData>();
MOZ_ASSERT(video);
if (!video->mImage) {
// Nothing to display.
continue;
}
rtc::scoped_refptr<ImageBuffer> image(
new rtc::RefCountedObject<ImageBuffer>(std::move(video->mImage)));
webrtc::VideoFrame videoFrame(image, frame->mTime.ToMicroseconds(),
frame->mDuration.ToMicroseconds() * 1000,
aInputImage.rotation_);
mCallback->Decoded(videoFrame);
}
mResults.Clear();
}
if (NS_FAILED(mError) && mError != NS_ERROR_DOM_MEDIA_CANCELED) {
CreateDecoder();
return WEBRTC_VIDEO_CODEC_ERROR;
}
return NS_SUCCEEDED(mError) ? WEBRTC_VIDEO_CODEC_OK
: WEBRTC_VIDEO_CODEC_ERROR;
}
int32_t WebrtcMediaDataDecoder::RegisterDecodeCompleteCallback(
webrtc::DecodedImageCallback* aCallback) {
mCallback = aCallback;
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t WebrtcMediaDataDecoder::Release() {
if (mDecoder) {
RefPtr<MediaDataDecoder> decoder = std::move(mDecoder);
decoder->Flush()->Then(mTaskQueue, __func__,
[decoder]() { decoder->Shutdown(); });
}
mNeedKeyframe = true;
mError = NS_OK;
return WEBRTC_VIDEO_CODEC_OK;
}
bool WebrtcMediaDataDecoder::OnTaskQueue() const {
return mTaskQueue->IsOnCurrentThread();
}
int32_t WebrtcMediaDataDecoder::CreateDecoder() {
RefPtr<layers::KnowsCompositor> knowsCompositor =
layers::ImageBridgeChild::GetSingleton();
if (mDecoder) {
Release();
}
RefPtr<TaskQueue> tq =
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
"webrtc decode TaskQueue");
RefPtr<MediaDataDecoder> decoder;
media::Await(do_AddRef(mThreadPool), InvokeAsync(tq, __func__, [&] {
RefPtr<GenericPromise> p =
mFactory
->CreateDecoder(
{mInfo,
CreateDecoderParams::OptionSet(
CreateDecoderParams::Option::LowLatency,
CreateDecoderParams::Option::FullH264Parsing,
CreateDecoderParams::Option::
ErrorIfNoInitializationData),
mTrackType, mImageContainer, knowsCompositor})
->Then(
tq, __func__,
[&](RefPtr<MediaDataDecoder>&& aDecoder) {
decoder = std::move(aDecoder);
return GenericPromise::CreateAndResolve(
true, __func__);
},
[](const MediaResult& aResult) {
return GenericPromise::CreateAndReject(
NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
});
return p;
}));
if (!decoder) {
return WEBRTC_VIDEO_CODEC_ERROR;
}
// We need to wrap our decoder in a MediaDataDecoderProxy so that it always
// run on an nsISerialEventTarget (which the webrtc code doesn't do)
mDecoder = new MediaDataDecoderProxy(decoder.forget(), tq.forget());
media::Await(
do_AddRef(mThreadPool), mDecoder->Init(),
[&](TrackInfo::TrackType) { mError = NS_OK; },
[&](const MediaResult& aError) { mError = aError; });
return NS_SUCCEEDED(mError) ? WEBRTC_VIDEO_CODEC_OK
: WEBRTC_VIDEO_CODEC_ERROR;
}
} // namespace mozilla