Upload upstream chromium 94.0.4606.31
[platform/framework/web/chromium-efl.git] / media / video / h265_nalu_parser.cc
1 // Copyright 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/video/h265_nalu_parser.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <cmath>
11
12 #include "base/bits.h"
13 #include "base/cxx17_backports.h"
14 #include "base/logging.h"
15 #include "media/base/decrypt_config.h"
16
17 namespace media {
18
19 namespace {
20
21 // Converts [|start|, |end|) range with |encrypted_ranges| into a vector of
22 // SubsampleEntry. |encrypted_ranges| must be with in the range defined by
23 // |start| and |end|.
24 // It is OK to pass in empty |encrypted_ranges|; this will return a vector
25 // with single SubsampleEntry with clear_bytes set to the size of the buffer.
26 std::vector<SubsampleEntry> EncryptedRangesToSubsampleEntry(
27     const uint8_t* start,
28     const uint8_t* end,
29     const Ranges<const uint8_t*>& encrypted_ranges) {
30   std::vector<SubsampleEntry> subsamples(encrypted_ranges.size());
31   const uint8_t* cur = start;
32   for (size_t i = 0; i < encrypted_ranges.size(); ++i) {
33     const uint8_t* encrypted_start = encrypted_ranges.start(i);
34     DCHECK_GE(encrypted_start, cur)
35         << "Encrypted range started before the current buffer pointer.";
36     subsamples[i].clear_bytes = encrypted_start - cur;
37
38     const uint8_t* encrypted_end = encrypted_ranges.end(i);
39     subsamples[i].cypher_bytes = encrypted_end - encrypted_start;
40
41     cur = encrypted_end;
42     DCHECK_LE(cur, end) << "Encrypted range is outside the buffer range.";
43   }
44
45   // If there is more data in the buffer but not covered by encrypted_ranges,
46   // then it must be in the clear.
47   if (cur < end)
48     subsamples.emplace_back(end - cur, 0);
49
50   return subsamples;
51 }
52
53 }  // namespace
54
55 #define READ_BITS_OR_RETURN(num_bits, out)                                 \
56   do {                                                                     \
57     int _out;                                                              \
58     if (!br_.ReadBits(num_bits, &_out)) {                                  \
59       DVLOG(1)                                                             \
60           << "Error in stream: unexpected EOS while trying to read " #out; \
61       return kInvalidStream;                                               \
62     }                                                                      \
63     *out = _out;                                                           \
64   } while (0)
65
66 #define TRUE_OR_RETURN(a)                                            \
67   do {                                                               \
68     if (!(a)) {                                                      \
69       DVLOG(1) << "Error in stream: invalid value, expected " << #a; \
70       return kInvalidStream;                                         \
71     }                                                                \
72   } while (0)
73
74 H265NALU::H265NALU() {
75   memset(reinterpret_cast<void*>(this), 0, sizeof(*this));
76 }
77
78 H265NaluParser::H265NaluParser() {
79   Reset();
80 }
81
82 H265NaluParser::~H265NaluParser() {}
83
84 void H265NaluParser::Reset() {
85   stream_ = NULL;
86   bytes_left_ = 0;
87   encrypted_ranges_.clear();
88   previous_nalu_range_.clear();
89 }
90
91 void H265NaluParser::SetStream(const uint8_t* stream, off_t stream_size) {
92   std::vector<SubsampleEntry> subsamples;
93   SetEncryptedStream(stream, stream_size, subsamples);
94 }
95
96 void H265NaluParser::SetEncryptedStream(
97     const uint8_t* stream,
98     off_t stream_size,
99     const std::vector<SubsampleEntry>& subsamples) {
100   DCHECK(stream);
101   DCHECK_GT(stream_size, 0);
102
103   stream_ = stream;
104   bytes_left_ = stream_size;
105   previous_nalu_range_.clear();
106
107   encrypted_ranges_.clear();
108   const uint8_t* start = stream;
109   const uint8_t* stream_end = stream_ + bytes_left_;
110   for (size_t i = 0; i < subsamples.size() && start < stream_end; ++i) {
111     start += subsamples[i].clear_bytes;
112
113     const uint8_t* end =
114         std::min(start + subsamples[i].cypher_bytes, stream_end);
115     encrypted_ranges_.Add(start, end);
116     start = end;
117   }
118 }
119
120 bool H265NaluParser::LocateNALU(off_t* nalu_size, off_t* start_code_size) {
121   // Find the start code of next NALU.
122   off_t nalu_start_off = 0;
123   off_t annexb_start_code_size = 0;
124
125   if (!H264Parser::FindStartCodeInClearRanges(
126           stream_, bytes_left_, encrypted_ranges_, &nalu_start_off,
127           &annexb_start_code_size)) {
128     DVLOG(4) << "Could not find start code, end of stream?";
129     return false;
130   }
131
132   // Move the stream to the beginning of the NALU (pointing at the start code).
133   stream_ += nalu_start_off;
134   bytes_left_ -= nalu_start_off;
135
136   const uint8_t* nalu_data = stream_ + annexb_start_code_size;
137   off_t max_nalu_data_size = bytes_left_ - annexb_start_code_size;
138   if (max_nalu_data_size <= 0) {
139     DVLOG(3) << "End of stream";
140     return false;
141   }
142
143   // Find the start code of next NALU;
144   // if successful, |nalu_size_without_start_code| is the number of bytes from
145   // after previous start code to before this one;
146   // if next start code is not found, it is still a valid NALU since there
147   // are some bytes left after the first start code: all the remaining bytes
148   // belong to the current NALU.
149   off_t next_start_code_size = 0;
150   off_t nalu_size_without_start_code = 0;
151   if (!H264Parser::FindStartCodeInClearRanges(
152           nalu_data, max_nalu_data_size, encrypted_ranges_,
153           &nalu_size_without_start_code, &next_start_code_size)) {
154     nalu_size_without_start_code = max_nalu_data_size;
155   }
156   *nalu_size = nalu_size_without_start_code + annexb_start_code_size;
157   *start_code_size = annexb_start_code_size;
158   return true;
159 }
160
161 H265NaluParser::Result H265NaluParser::AdvanceToNextNALU(H265NALU* nalu) {
162   off_t start_code_size;
163   off_t nalu_size_with_start_code;
164   if (!LocateNALU(&nalu_size_with_start_code, &start_code_size)) {
165     DVLOG(4) << "Could not find next NALU, bytes left in stream: "
166              << bytes_left_;
167     return kEOStream;
168   }
169
170   DCHECK(nalu);
171   nalu->data = stream_ + start_code_size;
172   nalu->size = nalu_size_with_start_code - start_code_size;
173   DVLOG(4) << "NALU found: size=" << nalu_size_with_start_code;
174
175   // Initialize bit reader at the start of found NALU.
176   if (!br_.Initialize(nalu->data, nalu->size))
177     return kEOStream;
178
179   // Move parser state to after this NALU, so next time AdvanceToNextNALU
180   // is called, we will effectively be skipping it;
181   // other parsing functions will use the position saved
182   // in bit reader for parsing, so we don't have to remember it here.
183   stream_ += nalu_size_with_start_code;
184   bytes_left_ -= nalu_size_with_start_code;
185
186   // Read NALU header, skip the forbidden_zero_bit, but check for it.
187   int data;
188   READ_BITS_OR_RETURN(1, &data);
189   TRUE_OR_RETURN(data == 0);
190
191   READ_BITS_OR_RETURN(6, &nalu->nal_unit_type);
192   READ_BITS_OR_RETURN(6, &nalu->nuh_layer_id);
193   READ_BITS_OR_RETURN(3, &nalu->nuh_temporal_id_plus1);
194
195   DVLOG(4) << "NALU type: " << static_cast<int>(nalu->nal_unit_type)
196            << " at: " << reinterpret_cast<const void*>(nalu->data)
197            << " size: " << nalu->size;
198
199   previous_nalu_range_.clear();
200   previous_nalu_range_.Add(nalu->data, nalu->data + nalu->size);
201   return kOk;
202 }
203
204 std::vector<SubsampleEntry> H265NaluParser::GetCurrentSubsamples() {
205   DCHECK_EQ(previous_nalu_range_.size(), 1u)
206       << "This should only be called after a "
207          "successful call to AdvanceToNextNalu()";
208
209   auto intersection = encrypted_ranges_.IntersectionWith(previous_nalu_range_);
210   return EncryptedRangesToSubsampleEntry(
211       previous_nalu_range_.start(0), previous_nalu_range_.end(0), intersection);
212 }
213
214 }  // namespace media