dav1d_decoder.cc (8520B)
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 #include <cstdint> 15 #include <memory> 16 #include <optional> 17 18 #include "api/environment/environment.h" 19 #include "api/ref_counted_base.h" 20 #include "api/scoped_refptr.h" 21 #include "api/video/encoded_image.h" 22 #include "api/video/video_frame.h" 23 #include "api/video/video_frame_buffer.h" 24 #include "api/video_codecs/video_decoder.h" 25 #include "common_video/include/video_frame_buffer.h" 26 #include "modules/video_coding/include/video_error_codes.h" 27 #include "rtc_base/logging.h" 28 #include "third_party/dav1d/libdav1d/include/dav1d/data.h" 29 #include "third_party/dav1d/libdav1d/include/dav1d/dav1d.h" 30 #include "third_party/dav1d/libdav1d/include/dav1d/headers.h" 31 #include "third_party/dav1d/libdav1d/include/dav1d/picture.h" 32 33 namespace webrtc { 34 namespace { 35 36 class Dav1dDecoder : public VideoDecoder { 37 public: 38 Dav1dDecoder(); 39 explicit Dav1dDecoder(const Environment& env); 40 Dav1dDecoder(const Dav1dDecoder&) = delete; 41 Dav1dDecoder& operator=(const Dav1dDecoder&) = delete; 42 43 ~Dav1dDecoder() override; 44 45 bool Configure(const Settings& settings) override; 46 int32_t Decode(const EncodedImage& encoded_image, 47 int64_t render_time_ms) override; 48 int32_t RegisterDecodeCompleteCallback( 49 DecodedImageCallback* callback) override; 50 int32_t Release() override; 51 DecoderInfo GetDecoderInfo() const override; 52 const char* ImplementationName() const override; 53 54 private: 55 Dav1dContext* context_ = nullptr; 56 DecodedImageCallback* decode_complete_callback_ = nullptr; 57 58 const bool crop_to_render_resolution_ = false; 59 }; 60 61 class ScopedDav1dData { 62 public: 63 ~ScopedDav1dData() { dav1d_data_unref(&data_); } 64 65 Dav1dData& Data() { return data_; } 66 67 private: 68 Dav1dData data_ = {}; 69 }; 70 71 class ScopedDav1dPicture : public RefCountedNonVirtual<ScopedDav1dPicture> { 72 public: 73 ~ScopedDav1dPicture() { dav1d_picture_unref(&picture_); } 74 75 Dav1dPicture& Picture() { return picture_; } 76 using RefCountedNonVirtual<ScopedDav1dPicture>::HasOneRef; 77 78 private: 79 Dav1dPicture picture_ = {}; 80 }; 81 82 constexpr char kDav1dName[] = "dav1d"; 83 84 // Calling `dav1d_data_wrap` requires a `free_callback` to be registered. 85 void NullFreeCallback(const uint8_t* /* buffer */, void* /* opaque */) {} 86 87 Dav1dDecoder::Dav1dDecoder() = default; 88 89 Dav1dDecoder::Dav1dDecoder(const Environment& env) 90 : crop_to_render_resolution_(env.field_trials().IsEnabled( 91 "WebRTC-Dav1dDecoder-CropToRenderResolution")) {} 92 93 Dav1dDecoder::~Dav1dDecoder() { 94 Release(); 95 } 96 97 bool Dav1dDecoder::Configure(const Settings& settings) { 98 Dav1dSettings s; 99 dav1d_default_settings(&s); 100 101 s.n_threads = std::clamp(settings.number_of_cores(), 1, DAV1D_MAX_THREADS); 102 s.max_frame_delay = 1; // For low latency decoding. 103 s.all_layers = 0; // Don't output a frame for every spatial layer. 104 // Limit max frame size to avoid OOM'ing fuzzers. crbug.com/325284120. 105 s.frame_size_limit = 16384 * 16384; 106 s.operating_point = 31; // Decode all operating points. 107 108 return dav1d_open(&context_, &s) == 0; 109 } 110 111 int32_t Dav1dDecoder::RegisterDecodeCompleteCallback( 112 DecodedImageCallback* decode_complete_callback) { 113 decode_complete_callback_ = decode_complete_callback; 114 return WEBRTC_VIDEO_CODEC_OK; 115 } 116 117 int32_t Dav1dDecoder::Release() { 118 dav1d_close(&context_); 119 if (context_ != nullptr) { 120 return WEBRTC_VIDEO_CODEC_MEMORY; 121 } 122 return WEBRTC_VIDEO_CODEC_OK; 123 } 124 125 VideoDecoder::DecoderInfo Dav1dDecoder::GetDecoderInfo() const { 126 DecoderInfo info; 127 info.implementation_name = kDav1dName; 128 info.is_hardware_accelerated = false; 129 return info; 130 } 131 132 const char* Dav1dDecoder::ImplementationName() const { 133 return kDav1dName; 134 } 135 136 int32_t Dav1dDecoder::Decode(const EncodedImage& encoded_image, 137 int64_t /*render_time_ms*/) { 138 if (!context_ || decode_complete_callback_ == nullptr) { 139 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; 140 } 141 142 ScopedDav1dData scoped_dav1d_data; 143 Dav1dData& dav1d_data = scoped_dav1d_data.Data(); 144 dav1d_data_wrap(&dav1d_data, encoded_image.data(), encoded_image.size(), 145 /*free_callback=*/&NullFreeCallback, 146 /*user_data=*/nullptr); 147 148 if (int decode_res = dav1d_send_data(context_, &dav1d_data)) { 149 RTC_LOG(LS_WARNING) 150 << "Dav1dDecoder::Decode decoding failed with error code " 151 << decode_res; 152 return WEBRTC_VIDEO_CODEC_ERROR; 153 } 154 155 scoped_refptr<ScopedDav1dPicture> scoped_dav1d_picture( 156 new ScopedDav1dPicture{}); 157 Dav1dPicture& dav1d_picture = scoped_dav1d_picture->Picture(); 158 if (int get_picture_res = dav1d_get_picture(context_, &dav1d_picture)) { 159 RTC_LOG(LS_WARNING) 160 << "Dav1dDecoder::Decode getting picture failed with error code " 161 << get_picture_res; 162 return WEBRTC_VIDEO_CODEC_ERROR; 163 } 164 165 if (dav1d_picture.p.bpc != 8) { 166 // Only accept 8 bit depth. 167 RTC_LOG(LS_ERROR) << "Dav1dDecoder::Decode unhandled bit depth: " 168 << dav1d_picture.p.bpc; 169 return WEBRTC_VIDEO_CODEC_ERROR; 170 } 171 172 int width = dav1d_picture.p.w; 173 int height = dav1d_picture.p.h; 174 175 if (crop_to_render_resolution_ && dav1d_picture.frame_hdr) { 176 // Interpret render_width/height as resolution decoded frame should be 177 // cropped to. 178 if (dav1d_picture.frame_hdr->render_width > 0 && 179 dav1d_picture.frame_hdr->render_height > 0) { 180 width = std::min(width, dav1d_picture.frame_hdr->render_width); 181 height = std::min(height, dav1d_picture.frame_hdr->render_height); 182 } else { 183 RTC_LOG(LS_WARNING) << "Dav1dDecoder::Decode invalid render resolution " 184 << dav1d_picture.frame_hdr->render_width << "x" 185 << dav1d_picture.frame_hdr->render_height; 186 } 187 } 188 189 scoped_refptr<VideoFrameBuffer> wrapped_buffer; 190 if (dav1d_picture.p.layout == DAV1D_PIXEL_LAYOUT_I420) { 191 wrapped_buffer = WrapI420Buffer( 192 width, height, static_cast<uint8_t*>(dav1d_picture.data[0]), 193 dav1d_picture.stride[0], static_cast<uint8_t*>(dav1d_picture.data[1]), 194 dav1d_picture.stride[1], static_cast<uint8_t*>(dav1d_picture.data[2]), 195 dav1d_picture.stride[1], 196 // To keep |scoped_dav1d_picture.Picture()| alive 197 [scoped_dav1d_picture] {}); 198 } else if (dav1d_picture.p.layout == DAV1D_PIXEL_LAYOUT_I444) { 199 wrapped_buffer = WrapI444Buffer( 200 width, height, static_cast<uint8_t*>(dav1d_picture.data[0]), 201 dav1d_picture.stride[0], static_cast<uint8_t*>(dav1d_picture.data[1]), 202 dav1d_picture.stride[1], static_cast<uint8_t*>(dav1d_picture.data[2]), 203 dav1d_picture.stride[1], 204 // To keep |scoped_dav1d_picture.Picture()| alive 205 [scoped_dav1d_picture] {}); 206 } else { 207 // Only accept I420 or I444 pixel format. 208 RTC_LOG(LS_ERROR) << "Dav1dDecoder::Decode unhandled pixel layout: " 209 << dav1d_picture.p.layout; 210 return WEBRTC_VIDEO_CODEC_ERROR; 211 } 212 213 if (!wrapped_buffer) { 214 return WEBRTC_VIDEO_CODEC_ERROR; 215 } 216 217 VideoFrame decoded_frame = 218 VideoFrame::Builder() 219 .set_video_frame_buffer(wrapped_buffer) 220 .set_rtp_timestamp(encoded_image.RtpTimestamp()) 221 .set_ntp_time_ms(encoded_image.ntp_time_ms_) 222 .set_color_space(encoded_image.ColorSpace()) 223 .build(); 224 225 // Corresponds to QP_base in 226 // J. Han et al., "A Technical Overview of AV1," in Proceedings of the IEEE, 227 // vol. 109, no. 9, pp. 1435-1462, Sept. 2021, 228 // doi: 10.1109/JPROC.2021.3058584. keywords: 229 // {Encoding;Codecs;Decoding;Streaming media;Video compression;Media;Alliance 230 // of Open Media;AV1;video compression}, 231 std::optional<uint8_t> qp = dav1d_picture.frame_hdr->quant.yac; 232 decode_complete_callback_->Decoded(decoded_frame, 233 /*decode_time_ms=*/std::nullopt, qp); 234 235 return WEBRTC_VIDEO_CODEC_OK; 236 } 237 238 } // namespace 239 240 std::unique_ptr<VideoDecoder> CreateDav1dDecoder() { 241 return std::make_unique<Dav1dDecoder>(); 242 } 243 244 std::unique_ptr<VideoDecoder> CreateDav1dDecoder(const Environment& env) { 245 return std::make_unique<Dav1dDecoder>(env); 246 } 247 248 } // namespace webrtc