tor-browser

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

video_rtp_depacketizer_vp8.cc (6158B)


      1 /*
      2 *  Copyright (c) 2019 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/rtp_rtcp/source/video_rtp_depacketizer_vp8.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 #include <optional>
     16 #include <utility>
     17 
     18 #include "api/array_view.h"
     19 #include "api/video/video_codec_type.h"
     20 #include "api/video/video_frame_type.h"
     21 #include "modules/rtp_rtcp/source/rtp_video_header.h"
     22 #include "modules/rtp_rtcp/source/video_rtp_depacketizer.h"
     23 #include "modules/video_coding/codecs/vp8/include/vp8_globals.h"
     24 #include "rtc_base/checks.h"
     25 #include "rtc_base/copy_on_write_buffer.h"
     26 #include "rtc_base/logging.h"
     27 
     28 // VP8 payload descriptor
     29 // https://datatracker.ietf.org/doc/html/rfc7741#section-4.2
     30 //
     31 //       0 1 2 3 4 5 6 7
     32 //      +-+-+-+-+-+-+-+-+
     33 //      |X|R|N|S|R| PID | (REQUIRED)
     34 //      +-+-+-+-+-+-+-+-+
     35 // X:   |I|L|T|K| RSV   | (OPTIONAL)
     36 //      +-+-+-+-+-+-+-+-+
     37 // I:   |M| PictureID   | (OPTIONAL)
     38 //      +-+-+-+-+-+-+-+-+
     39 //      |   PictureID   |
     40 //      +-+-+-+-+-+-+-+-+
     41 // L:   |   TL0PICIDX   | (OPTIONAL)
     42 //      +-+-+-+-+-+-+-+-+
     43 // T/K: |TID|Y| KEYIDX  | (OPTIONAL)
     44 //      +-+-+-+-+-+-+-+-+
     45 //
     46 // VP8 payload header. Considered part of the actual payload, sent to decoder.
     47 // https://datatracker.ietf.org/doc/html/rfc7741#section-4.3
     48 //
     49 //       0 1 2 3 4 5 6 7
     50 //      +-+-+-+-+-+-+-+-+
     51 //      |Size0|H| VER |P|
     52 //      +-+-+-+-+-+-+-+-+
     53 //      :      ...      :
     54 //      +-+-+-+-+-+-+-+-+
     55 
     56 namespace webrtc {
     57 namespace {
     58 
     59 constexpr int kFailedToParse = 0;
     60 
     61 int ParseVP8Descriptor(RTPVideoHeaderVP8* vp8,
     62                       const uint8_t* data,
     63                       size_t data_length) {
     64  RTC_DCHECK_GT(data_length, 0);
     65  int parsed_bytes = 0;
     66  // Parse mandatory first byte of payload descriptor.
     67  bool extension = (*data & 0x80) ? true : false;             // X bit
     68  vp8->nonReference = (*data & 0x20) ? true : false;          // N bit
     69  vp8->beginningOfPartition = (*data & 0x10) ? true : false;  // S bit
     70  vp8->partitionId = (*data & 0x07);                          // PID field
     71 
     72  data++;
     73  parsed_bytes++;
     74  data_length--;
     75 
     76  if (!extension)
     77    return parsed_bytes;
     78 
     79  if (data_length == 0)
     80    return kFailedToParse;
     81  // Optional X field is present.
     82  bool has_picture_id = (*data & 0x80) ? true : false;   // I bit
     83  bool has_tl0_pic_idx = (*data & 0x40) ? true : false;  // L bit
     84  bool has_tid = (*data & 0x20) ? true : false;          // T bit
     85  bool has_key_idx = (*data & 0x10) ? true : false;      // K bit
     86 
     87  // Advance data and decrease remaining payload size.
     88  data++;
     89  parsed_bytes++;
     90  data_length--;
     91 
     92  if (has_picture_id) {
     93    if (data_length == 0)
     94      return kFailedToParse;
     95 
     96    vp8->pictureId = (*data & 0x7F);
     97    if (*data & 0x80) {
     98      data++;
     99      parsed_bytes++;
    100      if (--data_length == 0)
    101        return kFailedToParse;
    102      // PictureId is 15 bits
    103      vp8->pictureId = (vp8->pictureId << 8) + *data;
    104    }
    105    data++;
    106    parsed_bytes++;
    107    data_length--;
    108  }
    109 
    110  if (has_tl0_pic_idx) {
    111    if (data_length == 0)
    112      return kFailedToParse;
    113 
    114    vp8->tl0PicIdx = *data;
    115    data++;
    116    parsed_bytes++;
    117    data_length--;
    118  }
    119 
    120  if (has_tid || has_key_idx) {
    121    if (data_length == 0)
    122      return kFailedToParse;
    123 
    124    if (has_tid) {
    125      vp8->temporalIdx = ((*data >> 6) & 0x03);
    126      vp8->layerSync = (*data & 0x20) ? true : false;  // Y bit
    127    }
    128    if (has_key_idx) {
    129      vp8->keyIdx = *data & 0x1F;
    130    }
    131    data++;
    132    parsed_bytes++;
    133    data_length--;
    134  }
    135  return parsed_bytes;
    136 }
    137 
    138 }  // namespace
    139 
    140 std::optional<VideoRtpDepacketizer::ParsedRtpPayload>
    141 VideoRtpDepacketizerVp8::Parse(CopyOnWriteBuffer rtp_payload) {
    142  ArrayView<const uint8_t> payload(rtp_payload.cdata(), rtp_payload.size());
    143  std::optional<ParsedRtpPayload> result(std::in_place);
    144  int offset = ParseRtpPayload(payload, &result->video_header);
    145  if (offset == kFailedToParse)
    146    return std::nullopt;
    147  RTC_DCHECK_LT(offset, rtp_payload.size());
    148  result->video_payload =
    149      rtp_payload.Slice(offset, rtp_payload.size() - offset);
    150  return result;
    151 }
    152 
    153 int VideoRtpDepacketizerVp8::ParseRtpPayload(
    154    ArrayView<const uint8_t> rtp_payload,
    155    RTPVideoHeader* video_header) {
    156  RTC_DCHECK(video_header);
    157  if (rtp_payload.empty()) {
    158    RTC_LOG(LS_ERROR) << "Empty rtp payload.";
    159    return kFailedToParse;
    160  }
    161 
    162  video_header->simulcastIdx = 0;
    163  video_header->codec = kVideoCodecVP8;
    164  auto& vp8_header =
    165      video_header->video_type_header.emplace<RTPVideoHeaderVP8>();
    166  vp8_header.InitRTPVideoHeaderVP8();
    167 
    168  const int descriptor_size =
    169      ParseVP8Descriptor(&vp8_header, rtp_payload.data(), rtp_payload.size());
    170  if (descriptor_size == kFailedToParse)
    171    return kFailedToParse;
    172 
    173  RTC_DCHECK_LT(vp8_header.partitionId, 8);
    174 
    175  video_header->is_first_packet_in_frame =
    176      vp8_header.beginningOfPartition && vp8_header.partitionId == 0;
    177 
    178  int vp8_payload_size = rtp_payload.size() - descriptor_size;
    179  if (vp8_payload_size == 0) {
    180    RTC_LOG(LS_WARNING) << "Empty vp8 payload.";
    181    return kFailedToParse;
    182  }
    183  const uint8_t* vp8_payload = rtp_payload.data() + descriptor_size;
    184 
    185  // Read P bit from payload header (only at beginning of first partition).
    186  if (video_header->is_first_packet_in_frame && (*vp8_payload & 0x01) == 0) {
    187    video_header->frame_type = VideoFrameType::kVideoFrameKey;
    188 
    189    if (vp8_payload_size < 10) {
    190      // For an I-frame we should always have the uncompressed VP8 header
    191      // in the beginning of the partition.
    192      return kFailedToParse;
    193    }
    194    video_header->width = ((vp8_payload[7] << 8) + vp8_payload[6]) & 0x3FFF;
    195    video_header->height = ((vp8_payload[9] << 8) + vp8_payload[8]) & 0x3FFF;
    196  } else {
    197    video_header->frame_type = VideoFrameType::kVideoFrameDelta;
    198 
    199    video_header->width = 0;
    200    video_header->height = 0;
    201  }
    202 
    203  return descriptor_size;
    204 }
    205 
    206 }  // namespace webrtc