xref: /aosp_15_r20/external/webrtc/modules/video_coding/codecs/av1/dav1d_decoder.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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