/src/x265/source/encoder/nal.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * Copyright (C) 2013-2020 MulticoreWare, Inc |
3 | | * |
4 | | * Authors: Steve Borho <steve@borho.org> |
5 | | * Min Chen <chenm003@163.com> |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * This program is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. |
20 | | * |
21 | | * This program is also available under a commercial proprietary license. |
22 | | * For more information, contact us at license @ x265.com. |
23 | | *****************************************************************************/ |
24 | | |
25 | | #include "common.h" |
26 | | #include "bitstream.h" |
27 | | #include "nal.h" |
28 | | |
29 | | using namespace X265_NS; |
30 | | |
31 | | NALList::NALList() |
32 | | : m_numNal(0) |
33 | | , m_buffer(NULL) |
34 | | , m_occupancy(0) |
35 | | , m_allocSize(0) |
36 | | , m_extraBuffer(NULL) |
37 | | , m_extraOccupancy(0) |
38 | | , m_extraAllocSize(0) |
39 | | , m_annexB(true) |
40 | 0 | {} |
41 | | |
42 | | void NALList::takeContents(NALList& other) |
43 | 0 | { |
44 | | /* take other NAL buffer, discard our old one */ |
45 | 0 | X265_FREE(m_buffer); |
46 | 0 | m_buffer = other.m_buffer; |
47 | 0 | m_allocSize = other.m_allocSize; |
48 | 0 | m_occupancy = other.m_occupancy; |
49 | | |
50 | | /* copy packet data */ |
51 | 0 | m_numNal = other.m_numNal; |
52 | 0 | memcpy(m_nal, other.m_nal, sizeof(x265_nal) * m_numNal); |
53 | | |
54 | | /* reset other list, re-allocate their buffer with same size */ |
55 | 0 | other.m_numNal = 0; |
56 | 0 | other.m_occupancy = 0; |
57 | 0 | other.m_buffer = X265_MALLOC(uint8_t, m_allocSize); |
58 | 0 | } |
59 | | |
60 | | void NALList::serialize(NalUnitType nalUnitType, const Bitstream& bs) |
61 | 0 | { |
62 | 0 | static const char startCodePrefix[] = { 0, 0, 0, 1 }; |
63 | |
|
64 | 0 | uint32_t payloadSize = bs.getNumberOfWrittenBytes(); |
65 | 0 | const uint8_t* bpayload = bs.getFIFO(); |
66 | 0 | if (!bpayload) |
67 | 0 | return; |
68 | | |
69 | 0 | uint32_t nextSize = m_occupancy + sizeof(startCodePrefix) + 2 + payloadSize + (payloadSize >> 1) + m_extraOccupancy; |
70 | 0 | if (nextSize > m_allocSize) |
71 | 0 | { |
72 | 0 | uint8_t *temp = X265_MALLOC(uint8_t, nextSize); |
73 | 0 | if (temp) |
74 | 0 | { |
75 | 0 | memcpy(temp, m_buffer, m_occupancy); |
76 | | |
77 | | /* fixup existing payload pointers */ |
78 | 0 | for (uint32_t i = 0; i < m_numNal; i++) |
79 | 0 | m_nal[i].payload = temp + (m_nal[i].payload - m_buffer); |
80 | |
|
81 | 0 | X265_FREE(m_buffer); |
82 | 0 | m_buffer = temp; |
83 | 0 | m_allocSize = nextSize; |
84 | 0 | } |
85 | 0 | else |
86 | 0 | { |
87 | 0 | x265_log(NULL, X265_LOG_ERROR, "Unable to realloc access unit buffer\n"); |
88 | 0 | return; |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | 0 | uint8_t *out = m_buffer + m_occupancy; |
93 | 0 | uint32_t bytes = 0; |
94 | |
|
95 | 0 | if (!m_annexB) |
96 | 0 | { |
97 | | /* Will write size later */ |
98 | 0 | bytes += 4; |
99 | 0 | } |
100 | 0 | else if (!m_numNal || nalUnitType == NAL_UNIT_VPS || nalUnitType == NAL_UNIT_SPS || nalUnitType == NAL_UNIT_PPS || nalUnitType == NAL_UNIT_UNSPECIFIED) |
101 | 0 | { |
102 | 0 | memcpy(out, startCodePrefix, 4); |
103 | 0 | bytes += 4; |
104 | 0 | } |
105 | 0 | else |
106 | 0 | { |
107 | 0 | memcpy(out, startCodePrefix + 1, 3); |
108 | 0 | bytes += 3; |
109 | 0 | } |
110 | | |
111 | | /* 16 bit NAL header: |
112 | | * forbidden_zero_bit 1-bit |
113 | | * nal_unit_type 6-bits |
114 | | * nuh_reserved_zero_6bits 6-bits |
115 | | * nuh_temporal_id_plus1 3-bits */ |
116 | 0 | out[bytes++] = (uint8_t)nalUnitType << 1; |
117 | 0 | out[bytes++] = 1 + (nalUnitType == NAL_UNIT_CODED_SLICE_TSA_N); |
118 | | |
119 | | /* 7.4.1 ... |
120 | | * Within the NAL unit, the following three-byte sequences shall not occur at |
121 | | * any byte-aligned position: |
122 | | * - 0x000000 |
123 | | * - 0x000001 |
124 | | * - 0x000002 */ |
125 | 0 | for (uint32_t i = 0; i < payloadSize; i++) |
126 | 0 | { |
127 | 0 | if (i > 2 && !out[bytes - 2] && !out[bytes - 3] && out[bytes - 1] <= 0x03 && nalUnitType != NAL_UNIT_UNSPECIFIED) |
128 | 0 | { |
129 | | /* inject 0x03 to prevent emulating a start code */ |
130 | 0 | out[bytes] = out[bytes - 1]; |
131 | 0 | out[bytes - 1] = 0x03; |
132 | 0 | bytes++; |
133 | 0 | } |
134 | |
|
135 | 0 | out[bytes++] = bpayload[i]; |
136 | 0 | } |
137 | |
|
138 | 0 | X265_CHECK(bytes <= 4 + 2 + payloadSize + (payloadSize >> 1), "NAL buffer overflow\n"); |
139 | |
|
140 | 0 | if (m_extraOccupancy) |
141 | 0 | { |
142 | | /* these bytes were escaped by serializeSubstreams */ |
143 | 0 | memcpy(out + bytes, m_extraBuffer, m_extraOccupancy); |
144 | 0 | bytes += m_extraOccupancy; |
145 | 0 | m_extraOccupancy = 0; |
146 | 0 | } |
147 | | |
148 | | /* 7.4.1.1 |
149 | | * ... when the last byte of the RBSP data is equal to 0x00 (which can |
150 | | * only occur when the RBSP ends in a cabac_zero_word), a final byte equal |
151 | | * to 0x03 is appended to the end of the data. */ |
152 | 0 | if (!out[bytes - 1]) |
153 | 0 | out[bytes++] = 0x03; |
154 | |
|
155 | 0 | if (!m_annexB) |
156 | 0 | { |
157 | 0 | uint32_t dataSize = bytes - 4; |
158 | 0 | out[0] = (uint8_t)(dataSize >> 24); |
159 | 0 | out[1] = (uint8_t)(dataSize >> 16); |
160 | 0 | out[2] = (uint8_t)(dataSize >> 8); |
161 | 0 | out[3] = (uint8_t)dataSize; |
162 | 0 | } |
163 | |
|
164 | 0 | m_occupancy += bytes; |
165 | |
|
166 | 0 | X265_CHECK(m_numNal < (uint32_t)MAX_NAL_UNITS, "NAL count overflow\n"); |
167 | |
|
168 | 0 | x265_nal& nal = m_nal[m_numNal++]; |
169 | 0 | nal.type = nalUnitType; |
170 | 0 | nal.sizeBytes = bytes; |
171 | 0 | nal.payload = out; |
172 | 0 | } |
173 | | |
174 | | /* concatenate and escape WPP sub-streams, return escaped row lengths. |
175 | | * These streams will be appended to the next serialized NAL */ |
176 | | uint32_t NALList::serializeSubstreams(uint32_t* streamSizeBytes, uint32_t streamCount, const Bitstream* streams) |
177 | 0 | { |
178 | 0 | uint32_t maxStreamSize = 0; |
179 | 0 | uint32_t estSize = 0; |
180 | 0 | for (uint32_t s = 0; s < streamCount; s++) |
181 | 0 | estSize += streams[s].getNumberOfWrittenBytes(); |
182 | 0 | estSize += estSize >> 1; |
183 | |
|
184 | 0 | if (estSize > m_extraAllocSize) |
185 | 0 | { |
186 | 0 | uint8_t *temp = X265_MALLOC(uint8_t, estSize); |
187 | 0 | if (temp) |
188 | 0 | { |
189 | 0 | X265_FREE(m_extraBuffer); |
190 | 0 | m_extraBuffer = temp; |
191 | 0 | m_extraAllocSize = estSize; |
192 | 0 | } |
193 | 0 | else |
194 | 0 | { |
195 | 0 | x265_log(NULL, X265_LOG_ERROR, "Unable to realloc WPP substream concatenation buffer\n"); |
196 | 0 | return 0; |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | 0 | uint32_t bytes = 0; |
201 | 0 | uint8_t *out = m_extraBuffer; |
202 | 0 | for (uint32_t s = 0; s < streamCount; s++) |
203 | 0 | { |
204 | 0 | const Bitstream& stream = streams[s]; |
205 | 0 | uint32_t inSize = stream.getNumberOfWrittenBytes(); |
206 | 0 | const uint8_t *inBytes = stream.getFIFO(); |
207 | 0 | uint32_t prevBufSize = bytes; |
208 | |
|
209 | 0 | if (inBytes) |
210 | 0 | { |
211 | 0 | for (uint32_t i = 0; i < inSize; i++) |
212 | 0 | { |
213 | 0 | if (bytes >= 2 && !out[bytes - 2] && !out[bytes - 1] && inBytes[i] <= 0x03) |
214 | 0 | { |
215 | | /* inject 0x03 to prevent emulating a start code */ |
216 | 0 | out[bytes++] = 3; |
217 | 0 | } |
218 | |
|
219 | 0 | out[bytes++] = inBytes[i]; |
220 | 0 | } |
221 | 0 | } |
222 | |
|
223 | 0 | if (s < streamCount - 1) |
224 | 0 | { |
225 | 0 | streamSizeBytes[s] = bytes - prevBufSize; |
226 | 0 | if (streamSizeBytes[s] > maxStreamSize) |
227 | 0 | maxStreamSize = streamSizeBytes[s]; |
228 | 0 | } |
229 | 0 | } |
230 | |
|
231 | 0 | m_extraOccupancy = bytes; |
232 | 0 | return maxStreamSize; |
233 | 0 | } |