tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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