blob: f4d3d3ce417eaf35c26b2f1826cbd825f1000414 [file] [log] [blame]
// Copyright 2018 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 CONTENT_RENDERER_MEDIA_WEBRTC_RTC_VIDEO_DECODER_ADAPTER_H_
#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_VIDEO_DECODER_ADAPTER_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "content/common/content_export.h"
#include "media/base/decode_status.h"
#include "media/base/video_codecs.h"
#include "media/base/video_decoder.h"
#include "media/base/video_decoder_config.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 SingleThreadTaskRunner;
} // namespace base
namespace media {
class DecoderBuffer;
class GpuVideoAcceleratorFactories;
class MediaLog;
class VideoFrame;
} // namespace media
namespace content {
// This class decodes video for WebRTC using a media::VideoDecoder. In
// particular, either GpuVideoDecoder or MojoVideoDecoder are used to provide
// access to hardware decoding in the GPU process.
//
// 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 CONTENT_EXPORT RTCVideoDecoderAdapter : public webrtc::VideoDecoder {
public:
// Creates and initializes an RTCVideoDecoderAdapter. Returns nullptr if
// |format| cannot be supported.
// Called on the worker thread.
static std::unique_ptr<RTCVideoDecoderAdapter> Create(
media::GpuVideoAcceleratorFactories* gpu_factories,
const webrtc::SdpVideoFormat& format);
// Called on |media_task_runner_|.
~RTCVideoDecoderAdapter() 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,
const webrtc::CodecSpecificInfo* codec_specific_info,
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.
const char* ImplementationName() const override;
private:
using CreateVideoDecoderCB =
base::RepeatingCallback<std::unique_ptr<media::VideoDecoder>(
media::MediaLog*)>;
using FlushDoneCB = base::OnceCallback<void()>;
// Called on the worker thread.
RTCVideoDecoderAdapter(media::GpuVideoAcceleratorFactories* gpu_factories,
const media::VideoDecoderConfig& config,
const webrtc::SdpVideoFormat& format);
bool InitializeSync(const media::VideoDecoderConfig& config);
void InitializeOnMediaThread(const media::VideoDecoderConfig& config,
const media::VideoDecoder::InitCB& init_cb);
void DecodeOnMediaThread();
void OnDecodeDone(media::DecodeStatus status);
void OnOutput(const scoped_refptr<media::VideoFrame>& frame);
bool ShouldReinitializeForSettingHDRColorSpace(
const webrtc::EncodedImage& input_image) const;
bool ReinitializeSync(const media::VideoDecoderConfig& config);
void FlushOnMediaThread(FlushDoneCB flush_success_cb,
FlushDoneCB flush_fail_cb);
// Construction parameters.
scoped_refptr<base::SingleThreadTaskRunner> media_task_runner_;
media::GpuVideoAcceleratorFactories* gpu_factories_;
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_;
std::unique_ptr<media::VideoDecoder> video_decoder_;
int32_t outstanding_decode_requests_ = 0;
// Shared members.
base::Lock lock_;
int32_t consecutive_error_count_ = 0;
bool has_error_ = false;
webrtc::DecodedImageCallback* decode_complete_callback_ = nullptr;
// Requests that have not been submitted to the decoder yet.
base::circular_deque<scoped_refptr<media::DecoderBuffer>> pending_buffers_;
// Record of timestamps that have been sent to be decoded. Removing a
// timestamp will cause the frame to be dropped when it is output.
base::circular_deque<base::TimeDelta> decode_timestamps_;
// Thread management.
THREAD_CHECKER(worker_thread_checker_);
THREAD_CHECKER(decoding_thread_checker_);
base::WeakPtr<RTCVideoDecoderAdapter> weak_this_;
base::WeakPtrFactory<RTCVideoDecoderAdapter> weak_this_factory_;
DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderAdapter);
};
} // namespace content
#endif // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_VIDEO_DECODER_ADAPTER_H_