File: encoded_video_chunk.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (121 lines) | stat: -rw-r--r-- 4,553 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"

#include <utility>

#include "third_party/blink/renderer/bindings/modules/v8/v8_decrypt_config.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h"
#include "third_party/blink/renderer/modules/webcodecs/decrypt_config_util.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

EncodedVideoChunk* EncodedVideoChunk::Create(ScriptState* script_state,
                                             const EncodedVideoChunkInit* init,
                                             ExceptionState& exception_state) {
  auto array_span = AsSpan<const uint8_t>(init->data());
  auto* isolate = script_state->GetIsolate();

  // Try if we can transfer `init.data` into this chunk without copying it.
  auto buffer_contents = TransferArrayBufferForSpan(
      init->transfer(), array_span, exception_state, isolate);
  if (exception_state.HadException()) {
    return nullptr;
  }

  scoped_refptr<media::DecoderBuffer> buffer;
  if (array_span.empty()) {
    buffer = base::MakeRefCounted<media::DecoderBuffer>(0);
  } else if (buffer_contents.IsValid()) {
    buffer = media::DecoderBuffer::FromExternalMemory(
        std::make_unique<ArrayBufferContentsExternalMemory>(
            std::move(buffer_contents), array_span));
  } else {
    buffer = media::DecoderBuffer::CopyFrom(array_span);
  }
  DCHECK(buffer);

  // Clamp within bounds of our internal TimeDelta-based duration. See
  // media/base/timestamp_constants.h
  auto timestamp = base::Microseconds(init->timestamp());
  if (timestamp == media::kNoTimestamp)
    timestamp = base::TimeDelta::FiniteMin();
  else if (timestamp == media::kInfiniteDuration)
    timestamp = base::TimeDelta::FiniteMax();
  buffer->set_timestamp(timestamp);

  // media::kNoTimestamp corresponds to base::TimeDelta::Min(), and internally
  // denotes the absence of duration. We use base::TimeDelta::FiniteMax() --
  // which is one less than base::TimeDelta::Max() -- because
  // base::TimeDelta::Max() is reserved for media::kInfiniteDuration, and is
  // handled differently.
  buffer->set_duration(
      init->hasDuration()
          ? base::Microseconds(std::min(
                uint64_t{base::TimeDelta::FiniteMax().InMicroseconds()},
                init->duration()))
          : media::kNoTimestamp);

  buffer->set_is_key_frame(init->type() == "key");

  if (init->hasDecryptConfig()) {
    auto decrypt_config = CreateMediaDecryptConfig(*init->decryptConfig());
    if (!decrypt_config) {
      exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
                                        "Unsupported decryptConfig");
      return nullptr;
    }
    buffer->set_decrypt_config(std::move(decrypt_config));
  }

  return MakeGarbageCollected<EncodedVideoChunk>(std::move(buffer));
}

EncodedVideoChunk::EncodedVideoChunk(scoped_refptr<media::DecoderBuffer> buffer)
    : buffer_(std::move(buffer)) {}

V8EncodedVideoChunkType EncodedVideoChunk::type() const {
  return V8EncodedVideoChunkType(buffer_->is_key_frame()
                                     ? V8EncodedVideoChunkType::Enum::kKey
                                     : V8EncodedVideoChunkType::Enum::kDelta);
}

int64_t EncodedVideoChunk::timestamp() const {
  return buffer_->timestamp().InMicroseconds();
}

std::optional<uint64_t> EncodedVideoChunk::duration() const {
  if (buffer_->duration() == media::kNoTimestamp)
    return std::nullopt;
  return buffer_->duration().InMicroseconds();
}

uint64_t EncodedVideoChunk::byteLength() const {
  return buffer_->size();
}

void EncodedVideoChunk::copyTo(const AllowSharedBufferSource* destination,
                               ExceptionState& exception_state) {
  // Validate destination buffer.
  auto dest_wrapper = AsSpan<uint8_t>(destination);
  auto buffer_span = base::span(*buffer_);
  if (dest_wrapper.size() < buffer_span.size()) {
    exception_state.ThrowTypeError("destination is not large enough.");
    return;
  }

  if (buffer_span.empty()) {
    // Calling memcpy with nullptr is UB, even if count is zero.
    return;
  }

  // Copy data.
  dest_wrapper.copy_prefix_from(buffer_span);
}

}  // namespace blink