blob: 80f91ad93a776e40fa02dfbb1539c18c0c68ecd3 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_STREAM_ADAPTER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_STREAM_ADAPTER_H_
#include <memory>
#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "media/base/decode_status.h"
#include "media/base/media_switches.h"
#include "media/base/overlay_info.h"
#include "media/base/status.h"
#include "media/base/supported_video_decoder_config.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.h"
#include "media/filters/decoder_stream.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/deque.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/webrtc/api/video_codecs/sdp_video_format.h"
#include "third_party/webrtc/modules/video_coding/include/video_codec_interface.h"
#include "ui/gfx/geometry/size.h"
namespace base {
class SequencedThreadTaskRunner;
} // namespace base
namespace media {
class DecoderBuffer;
class DecoderFactory;
class GpuVideoAcceleratorFactories;
class MediaLog;
} // namespace media
namespace blink {
// This class decodes video for WebRTC using a media::VideoDecoderStream.
//
// VideoDecoderStream is used by almost all non-WebRTC video decoding in
// chromium. It handles selecting the decoder implementation, including between
// hardware and software implementations. It also provides fallback / fall-
// forward between implementations if needed for config changes.
//
// Lifecycle methods are called on the WebRTC worker thread. Decoding happens on
// a WebRTC DecodingThread, which is an rtc::PlatformThread owend by WebRTC; it
// does not have a TaskRunner.
//
// To stop decoding, WebRTC stops the DecodingThread and then calls Release() on
// the worker. Calling the DecodedImageCallback after the DecodingThread is
// stopped is illegal but, because we decode on the media thread, there is no
// way to synchronize this correctly.
class PLATFORM_EXPORT RTCVideoDecoderStreamAdapter
: public webrtc::VideoDecoder {
public:
// Creates and initializes an RTCVideoDecoderStreamAdapter. Returns nullptr if
// |format| cannot be supported.
// Called on the worker thread.
static std::unique_ptr<RTCVideoDecoderStreamAdapter> Create(
media::GpuVideoAcceleratorFactories* gpu_factories,
media::DecoderFactory* decoder_factory,
const webrtc::SdpVideoFormat& format);
// Called on |media_task_runner_|.
~RTCVideoDecoderStreamAdapter() override;
// webrtc::VideoDecoder implementation.
// Called on the DecodingThread.
int32_t InitDecode(const webrtc::VideoCodec* codec_settings,
int32_t number_of_cores) override;
// Called on the DecodingThread.
int32_t RegisterDecodeCompleteCallback(
webrtc::DecodedImageCallback* callback) override;
// Called on the DecodingThread.
int32_t Decode(const webrtc::EncodedImage& input_image,
bool missing_frames,
int64_t render_time_ms) override;
// Called on the worker thread and on the DecodingThread.
int32_t Release() override;
// Called on the worker thread and on the DecodingThread.
DecoderInfo GetDecoderInfo() const override;
private:
class InternalDemuxerStream;
using InitCB = CrossThreadOnceFunction<void(bool)>;
using FlushDoneCB = CrossThreadOnceFunction<void()>;
struct PendingBuffer {
scoped_refptr<media::DecoderBuffer> buffer;
base::Optional<media::VideoDecoderConfig> new_config;
};
// Called on the worker thread.
RTCVideoDecoderStreamAdapter(
media::GpuVideoAcceleratorFactories* gpu_factories,
media::DecoderFactory* decoder_factory,
const media::VideoDecoderConfig& config,
const webrtc::SdpVideoFormat& format);
void InitializeSync(const media::VideoDecoderConfig& config);
void InitializeOnMediaThread(const media::VideoDecoderConfig& config,
InitCB init_cb);
void OnInitializeDone(base::TimeTicks start_time, bool success);
void DecodeOnMediaThread(std::unique_ptr<PendingBuffer>);
void OnFrameReady(media::VideoDecoderStream::ReadResult result);
bool ShouldReinitializeForSettingHDRColorSpace(
const webrtc::EncodedImage& input_image) const;
// If no read is in progress with `decoder_stream_`, and there is undecoded
// input buffers, then start a read. Otherwise, do nothing.
void AttemptRead_Locked();
// Start a `DecoderStream::Reset`.
void ResetOnMediaThread();
// Notification when `DecoderStream::Reset` completes.
void OnResetCompleteOnMediaThread();
// Adjust `allowable_decoder_queue_length_` if needed.
void AdjustQueueLength_Locked();
// Clear as much memory as we can, cancel outstanding callbacks, etc.
void ShutdownOnMediaThread();
// Log the init state, if we know what it is. Will do nothing if Initialize
// has not completed, and also InitDecode() has not been called.
void AttemptLogInitializationState_Locked();
// Called on the media thread when `decoder_stream_` changes the decoder.
void OnDecoderChanged(media::VideoDecoder* decoder);
// Construction parameters.
const scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
media::GpuVideoAcceleratorFactories* const gpu_factories_;
media::DecoderFactory* const decoder_factory_;
const webrtc::SdpVideoFormat format_;
media::VideoDecoderConfig config_;
// Media thread members.
// |media_log_| must outlive |video_decoder_| because it is passed as a raw
// pointer.
std::unique_ptr<media::MediaLog> media_log_;
// Decoding thread members.
bool key_frame_required_ = true;
webrtc::VideoCodecType video_codec_type_ = webrtc::kVideoCodecGeneric;
webrtc::DecodedImageCallback* decode_complete_callback_ = nullptr;
// Shared members.
mutable base::Lock lock_;
bool has_error_ GUARDED_BY(lock_) = false;
// Current maximum number of in-flight undecoded frames.
size_t max_pending_buffer_count_ GUARDED_BY(lock_);
// Current number of in-flight decodes.
size_t pending_buffer_count_ GUARDED_BY(lock_) = 0;
// Has DecoderStream initialization completed? This does not imply that it
// completed successfully.
bool init_complete_ GUARDED_BY(lock_) = false;
// Has InitDecode() been called?
bool init_decode_complete_ GUARDED_BY(lock_) = false;
// Have we logged init status yet?
bool logged_init_status_ GUARDED_BY(lock_) = false;
// Current decoder info, as reported by GetDecoderInfo().
webrtc::VideoDecoder::DecoderInfo decoder_info_ GUARDED_BY(lock_);
// Do we have an outstanding `DecoderStream::Read()`?
// Media thread only.
bool pending_read_ = false;
// Do we have an in-flight `DecoderStream::Reset()`?
// Media thread only.
bool pending_reset_ = false;
// Media thread only.
std::unique_ptr<InternalDemuxerStream> demuxer_stream_;
std::unique_ptr<media::VideoDecoderStream> decoder_stream_;
// Thread management.
SEQUENCE_CHECKER(decoding_sequence_checker_);
base::WeakPtr<RTCVideoDecoderStreamAdapter> weak_this_;
base::WeakPtrFactory<RTCVideoDecoderStreamAdapter> weak_this_factory_{this};
DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderStreamAdapter);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_STREAM_ADAPTER_H_