blob: a5e47848396c9cb6e692b375d88463c73b3f23e0 [file] [log] [blame]
philipelb09d8722021-11-23 11:00:24 +01001/*
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/i420_buffer.h"
18#include "common_video/include/video_frame_buffer_pool.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
24namespace webrtc {
25namespace {
26
27class Dav1dDecoder : public VideoDecoder {
28 public:
29 Dav1dDecoder();
30 Dav1dDecoder(const Dav1dDecoder&) = delete;
31 Dav1dDecoder& operator=(const Dav1dDecoder&) = delete;
32
33 ~Dav1dDecoder() override;
34
35 bool Configure(const Settings& settings) override;
36 int32_t Decode(const EncodedImage& encoded_image,
37 bool missing_frames,
38 int64_t render_time_ms) override;
39 int32_t RegisterDecodeCompleteCallback(
40 DecodedImageCallback* callback) override;
41 int32_t Release() override;
42 DecoderInfo GetDecoderInfo() const override;
43 const char* ImplementationName() const override;
44
45 private:
46 VideoFrameBufferPool buffer_pool_;
47 Dav1dContext* context_ = nullptr;
48 DecodedImageCallback* decode_complete_callback_ = nullptr;
49};
50
51class ScopedDav1dData {
52 public:
53 ~ScopedDav1dData() { dav1d_data_unref(&data_); }
54
55 Dav1dData& Data() { return data_; }
56
57 private:
58 Dav1dData data_ = {};
59};
60
61class ScopedDav1dPicture {
62 public:
63 ~ScopedDav1dPicture() { dav1d_picture_unref(&picture_); }
64
65 Dav1dPicture& Picture() { return picture_; }
66
67 private:
68 Dav1dPicture picture_ = {};
69};
70
71constexpr char kDav1dName[] = "dav1d";
72
73// Calling `dav1d_data_wrap` requires a `free_callback` to be registered.
74void NullFreeCallback(const uint8_t* buffer, void* opaque) {}
75
76Dav1dDecoder::Dav1dDecoder()
77 : buffer_pool_(/*zero_initialize=*/false, /*max_number_of_buffers=*/150) {}
78
79Dav1dDecoder::~Dav1dDecoder() {
80 Release();
81}
82
83bool Dav1dDecoder::Configure(const Settings& settings) {
84 Dav1dSettings s;
85 dav1d_default_settings(&s);
86
87 s.n_threads = std::max(2, settings.number_of_cores());
88 s.max_frame_delay = 1; // For low latency decoding.
89 s.all_layers = 0; // Don't output a frame for every spatial layer.
90 s.operating_point = 31; // Decode all operating points.
91
92 return dav1d_open(&context_, &s) == 0;
93}
94
95int32_t Dav1dDecoder::RegisterDecodeCompleteCallback(
96 DecodedImageCallback* decode_complete_callback) {
97 decode_complete_callback_ = decode_complete_callback;
98 return WEBRTC_VIDEO_CODEC_OK;
99}
100
101int32_t Dav1dDecoder::Release() {
102 dav1d_close(&context_);
103 if (context_ != nullptr) {
104 return WEBRTC_VIDEO_CODEC_MEMORY;
105 }
106 buffer_pool_.Release();
107 return WEBRTC_VIDEO_CODEC_OK;
108}
109
110VideoDecoder::DecoderInfo Dav1dDecoder::GetDecoderInfo() const {
111 DecoderInfo info;
112 info.implementation_name = kDav1dName;
113 info.is_hardware_accelerated = false;
114 return info;
115}
116
117const char* Dav1dDecoder::ImplementationName() const {
118 return kDav1dName;
119}
120
121int32_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 ScopedDav1dPicture scoped_dav1d_picture;
142 Dav1dPicture& dav1d_picture = scoped_dav1d_picture.Picture();
143 if (int get_picture_res = dav1d_get_picture(context_, &dav1d_picture)) {
144 RTC_LOG(LS_WARNING)
145 << "Dav1dDecoder::Decode getting picture failed with error code "
146 << get_picture_res;
147 return WEBRTC_VIDEO_CODEC_ERROR;
148 }
149
150 // Only accept I420 pixel format and 8 bit depth.
151 if (dav1d_picture.p.layout != DAV1D_PIXEL_LAYOUT_I420 ||
152 dav1d_picture.p.bpc != 8) {
153 return WEBRTC_VIDEO_CODEC_ERROR;
154 }
155
156 rtc::scoped_refptr<I420Buffer> buffer =
157 buffer_pool_.CreateI420Buffer(dav1d_picture.p.w, dav1d_picture.p.h);
158 if (!buffer.get()) {
159 RTC_LOG(LS_WARNING)
160 << "Dav1dDecoder::Decode failed to get frame from the buffer pool.";
161 return WEBRTC_VIDEO_CODEC_ERROR;
162 }
163
164 uint8_t* y_data = static_cast<uint8_t*>(dav1d_picture.data[0]);
165 uint8_t* u_data = static_cast<uint8_t*>(dav1d_picture.data[1]);
166 uint8_t* v_data = static_cast<uint8_t*>(dav1d_picture.data[2]);
167 int y_stride = dav1d_picture.stride[0];
168 int uv_stride = dav1d_picture.stride[1];
169 libyuv::I420Copy(y_data, y_stride, //
170 u_data, uv_stride, //
171 v_data, uv_stride, //
172 buffer->MutableDataY(), buffer->StrideY(), //
173 buffer->MutableDataU(), buffer->StrideU(), //
174 buffer->MutableDataV(), buffer->StrideV(), //
175 dav1d_picture.p.w, //
176 dav1d_picture.p.h); //
177
178 VideoFrame decoded_frame = VideoFrame::Builder()
179 .set_video_frame_buffer(buffer)
180 .set_timestamp_rtp(encoded_image.Timestamp())
181 .set_ntp_time_ms(encoded_image.ntp_time_ms_)
182 .set_color_space(encoded_image.ColorSpace())
183 .build();
184
185 decode_complete_callback_->Decoded(decoded_frame, absl::nullopt,
186 absl::nullopt);
187
188 return WEBRTC_VIDEO_CODEC_OK;
189}
190
191} // namespace
192
193std::unique_ptr<VideoDecoder> CreateDav1dDecoder() {
194 return std::make_unique<Dav1dDecoder>();
195}
196
197} // namespace webrtc