1 /*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/video_coding/codecs/av1/dav1d_decoder.h"
12
13 #include <algorithm>
14
15 #include "api/scoped_refptr.h"
16 #include "api/video/encoded_image.h"
17 #include "api/video/video_frame_buffer.h"
18 #include "common_video/include/video_frame_buffer.h"
19 #include "modules/video_coding/include/video_error_codes.h"
20 #include "rtc_base/logging.h"
21 #include "third_party/dav1d/libdav1d/include/dav1d/dav1d.h"
22 #include "third_party/libyuv/include/libyuv/convert.h"
23 #include "third_party/libyuv/include/libyuv/planar_functions.h"
24
25 namespace webrtc {
26 namespace {
27
28 class Dav1dDecoder : public VideoDecoder {
29 public:
30 Dav1dDecoder();
31 Dav1dDecoder(const Dav1dDecoder&) = delete;
32 Dav1dDecoder& operator=(const Dav1dDecoder&) = delete;
33
34 ~Dav1dDecoder() override;
35
36 bool Configure(const Settings& settings) override;
37 int32_t Decode(const EncodedImage& encoded_image,
38 bool missing_frames,
39 int64_t render_time_ms) override;
40 int32_t RegisterDecodeCompleteCallback(
41 DecodedImageCallback* callback) override;
42 int32_t Release() override;
43 DecoderInfo GetDecoderInfo() const override;
44 const char* ImplementationName() const override;
45
46 private:
47 Dav1dContext* context_ = nullptr;
48 DecodedImageCallback* decode_complete_callback_ = nullptr;
49 };
50
51 class ScopedDav1dData {
52 public:
~ScopedDav1dData()53 ~ScopedDav1dData() { dav1d_data_unref(&data_); }
54
Data()55 Dav1dData& Data() { return data_; }
56
57 private:
58 Dav1dData data_ = {};
59 };
60
61 class ScopedDav1dPicture
62 : public rtc::RefCountedNonVirtual<ScopedDav1dPicture> {
63 public:
~ScopedDav1dPicture()64 ~ScopedDav1dPicture() { dav1d_picture_unref(&picture_); }
65
Picture()66 Dav1dPicture& Picture() { return picture_; }
67 using rtc::RefCountedNonVirtual<ScopedDav1dPicture>::HasOneRef;
68
69 private:
70 Dav1dPicture picture_ = {};
71 };
72
73 constexpr char kDav1dName[] = "dav1d";
74
75 // Calling `dav1d_data_wrap` requires a `free_callback` to be registered.
NullFreeCallback(const uint8_t * buffer,void * opaque)76 void NullFreeCallback(const uint8_t* buffer, void* opaque) {}
77
78 Dav1dDecoder::Dav1dDecoder() = default;
79
~Dav1dDecoder()80 Dav1dDecoder::~Dav1dDecoder() {
81 Release();
82 }
83
Configure(const Settings & settings)84 bool Dav1dDecoder::Configure(const Settings& settings) {
85 Dav1dSettings s;
86 dav1d_default_settings(&s);
87
88 s.n_threads = std::max(2, settings.number_of_cores());
89 s.max_frame_delay = 1; // For low latency decoding.
90 s.all_layers = 0; // Don't output a frame for every spatial layer.
91 s.operating_point = 31; // Decode all operating points.
92
93 return dav1d_open(&context_, &s) == 0;
94 }
95
RegisterDecodeCompleteCallback(DecodedImageCallback * decode_complete_callback)96 int32_t Dav1dDecoder::RegisterDecodeCompleteCallback(
97 DecodedImageCallback* decode_complete_callback) {
98 decode_complete_callback_ = decode_complete_callback;
99 return WEBRTC_VIDEO_CODEC_OK;
100 }
101
Release()102 int32_t Dav1dDecoder::Release() {
103 dav1d_close(&context_);
104 if (context_ != nullptr) {
105 return WEBRTC_VIDEO_CODEC_MEMORY;
106 }
107 return WEBRTC_VIDEO_CODEC_OK;
108 }
109
GetDecoderInfo() const110 VideoDecoder::DecoderInfo Dav1dDecoder::GetDecoderInfo() const {
111 DecoderInfo info;
112 info.implementation_name = kDav1dName;
113 info.is_hardware_accelerated = false;
114 return info;
115 }
116
ImplementationName() const117 const char* Dav1dDecoder::ImplementationName() const {
118 return kDav1dName;
119 }
120
Decode(const EncodedImage & encoded_image,bool,int64_t)121 int32_t Dav1dDecoder::Decode(const EncodedImage& encoded_image,
122 bool /*missing_frames*/,
123 int64_t /*render_time_ms*/) {
124 if (!context_ || decode_complete_callback_ == nullptr) {
125 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
126 }
127
128 ScopedDav1dData scoped_dav1d_data;
129 Dav1dData& dav1d_data = scoped_dav1d_data.Data();
130 dav1d_data_wrap(&dav1d_data, encoded_image.data(), encoded_image.size(),
131 /*free_callback=*/&NullFreeCallback,
132 /*user_data=*/nullptr);
133
134 if (int decode_res = dav1d_send_data(context_, &dav1d_data)) {
135 RTC_LOG(LS_WARNING)
136 << "Dav1dDecoder::Decode decoding failed with error code "
137 << decode_res;
138 return WEBRTC_VIDEO_CODEC_ERROR;
139 }
140
141 rtc::scoped_refptr<ScopedDav1dPicture> scoped_dav1d_picture(
142 new ScopedDav1dPicture{});
143 Dav1dPicture& dav1d_picture = scoped_dav1d_picture->Picture();
144 if (int get_picture_res = dav1d_get_picture(context_, &dav1d_picture)) {
145 RTC_LOG(LS_WARNING)
146 << "Dav1dDecoder::Decode getting picture failed with error code "
147 << get_picture_res;
148 return WEBRTC_VIDEO_CODEC_ERROR;
149 }
150
151 if (dav1d_picture.p.bpc != 8) {
152 // Only accept 8 bit depth.
153 RTC_LOG(LS_ERROR) << "Dav1dDecoder::Decode unhandled bit depth: "
154 << dav1d_picture.p.bpc;
155 return WEBRTC_VIDEO_CODEC_ERROR;
156 }
157
158 rtc::scoped_refptr<VideoFrameBuffer> wrapped_buffer;
159 if (dav1d_picture.p.layout == DAV1D_PIXEL_LAYOUT_I420) {
160 wrapped_buffer = WrapI420Buffer(
161 dav1d_picture.p.w, dav1d_picture.p.h,
162 static_cast<uint8_t*>(dav1d_picture.data[0]), dav1d_picture.stride[0],
163 static_cast<uint8_t*>(dav1d_picture.data[1]), dav1d_picture.stride[1],
164 static_cast<uint8_t*>(dav1d_picture.data[2]), dav1d_picture.stride[1],
165 // To keep |scoped_dav1d_picture.Picture()| alive
166 [scoped_dav1d_picture] {});
167 } else if (dav1d_picture.p.layout == DAV1D_PIXEL_LAYOUT_I444) {
168 wrapped_buffer = WrapI444Buffer(
169 dav1d_picture.p.w, dav1d_picture.p.h,
170 static_cast<uint8_t*>(dav1d_picture.data[0]), dav1d_picture.stride[0],
171 static_cast<uint8_t*>(dav1d_picture.data[1]), dav1d_picture.stride[1],
172 static_cast<uint8_t*>(dav1d_picture.data[2]), dav1d_picture.stride[1],
173 // To keep |scoped_dav1d_picture.Picture()| alive
174 [scoped_dav1d_picture] {});
175 } else {
176 // Only accept I420 or I444 pixel format.
177 RTC_LOG(LS_ERROR) << "Dav1dDecoder::Decode unhandled pixel layout: "
178 << dav1d_picture.p.layout;
179 return WEBRTC_VIDEO_CODEC_ERROR;
180 }
181
182 if (!wrapped_buffer.get()) {
183 return WEBRTC_VIDEO_CODEC_ERROR;
184 }
185
186 VideoFrame decoded_frame = VideoFrame::Builder()
187 .set_video_frame_buffer(wrapped_buffer)
188 .set_timestamp_rtp(encoded_image.Timestamp())
189 .set_ntp_time_ms(encoded_image.ntp_time_ms_)
190 .set_color_space(encoded_image.ColorSpace())
191 .build();
192
193 decode_complete_callback_->Decoded(decoded_frame, absl::nullopt,
194 absl::nullopt);
195
196 return WEBRTC_VIDEO_CODEC_OK;
197 }
198
199 } // namespace
200
CreateDav1dDecoder()201 std::unique_ptr<VideoDecoder> CreateDav1dDecoder() {
202 return std::make_unique<Dav1dDecoder>();
203 }
204
205 } // namespace webrtc
206