Imported Upstream version 1.4+222+hg5f9f7194267b
[deb_x265.git] / source / encoder / nal.cpp
CommitLineData
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
28using namespace x265;
29
30NALList::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
40void 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
58void 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 */
159uint32_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}