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