| 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 | { |
| 196 | if (bytes >= 2 && !out[bytes - 2] && !out[bytes - 1] && inBytes[i] <= 0x03) |
| 197 | { |
| 198 | /* inject 0x03 to prevent emulating a start code */ |
| 199 | out[bytes++] = 3; |
| 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 | } |