/***************************************************************************** * Copyright (C) 2013-2020 MulticoreWare, Inc * * Authors: Steve Borho * Min Chen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. * * This program is also available under a commercial proprietary license. * For more information, contact us at license @ x265.com. *****************************************************************************/ #include "common.h" #include "bitstream.h" #include "nal.h" using namespace X265_NS; NALList::NALList() : m_numNal(0) , m_buffer(NULL) , m_occupancy(0) , m_allocSize(0) , m_extraBuffer(NULL) , m_extraOccupancy(0) , m_extraAllocSize(0) , m_annexB(true) {} void NALList::takeContents(NALList& other) { /* take other NAL buffer, discard our old one */ X265_FREE(m_buffer); m_buffer = other.m_buffer; m_allocSize = other.m_allocSize; m_occupancy = other.m_occupancy; /* copy packet data */ m_numNal = other.m_numNal; memcpy(m_nal, other.m_nal, sizeof(x265_nal) * m_numNal); /* reset other list, re-allocate their buffer with same size */ other.m_numNal = 0; other.m_occupancy = 0; other.m_buffer = X265_MALLOC(uint8_t, m_allocSize); } void NALList::serialize(NalUnitType nalUnitType, const Bitstream& bs, int layerId, uint8_t temporalID) { static const char startCodePrefix[] = { 0, 0, 0, 1 }; uint32_t payloadSize = bs.getNumberOfWrittenBytes(); const uint8_t* bpayload = bs.getFIFO(); if (!bpayload) return; uint32_t nextSize = m_occupancy + sizeof(startCodePrefix) + 2 + payloadSize + (payloadSize >> 1) + m_extraOccupancy; if (nextSize > m_allocSize) { uint8_t *temp = X265_MALLOC(uint8_t, nextSize); if (temp) { memcpy(temp, m_buffer, m_occupancy); /* fixup existing payload pointers */ for (uint32_t i = 0; i < m_numNal; i++) m_nal[i].payload = temp + (m_nal[i].payload - m_buffer); X265_FREE(m_buffer); m_buffer = temp; m_allocSize = nextSize; } else { x265_log(NULL, X265_LOG_ERROR, "Unable to realloc access unit buffer\n"); return; } } uint8_t *out = m_buffer + m_occupancy; uint32_t bytes = 0; if (!m_annexB) { /* Will write size later */ bytes += 4; } else if (!m_numNal || nalUnitType == NAL_UNIT_VPS || nalUnitType == NAL_UNIT_SPS || nalUnitType == NAL_UNIT_PPS || nalUnitType == NAL_UNIT_UNSPECIFIED) { memcpy(out, startCodePrefix, 4); bytes += 4; } else { memcpy(out, startCodePrefix + 1, 3); bytes += 3; } /* 16 bit NAL header: * forbidden_zero_bit 1-bit * nal_unit_type 6-bits * nuh_reserved_zero_6bits 6-bits * nuh_temporal_id_plus1 3-bits */ out[bytes++] = (uint8_t)nalUnitType << 1; out[bytes++] = (layerId << 3) | (temporalID); /* 7.4.1 ... * Within the NAL unit, the following three-byte sequences shall not occur at * any byte-aligned position: * - 0x000000 * - 0x000001 * - 0x000002 */ for (uint32_t i = 0; i < payloadSize; i++) { if (i > 2 && !out[bytes - 2] && !out[bytes - 3] && out[bytes - 1] <= 0x03 && nalUnitType != NAL_UNIT_UNSPECIFIED) { /* inject 0x03 to prevent emulating a start code */ out[bytes] = out[bytes - 1]; out[bytes - 1] = 0x03; bytes++; } out[bytes++] = bpayload[i]; } X265_CHECK(bytes <= 4 + 2 + payloadSize + (payloadSize >> 1), "NAL buffer overflow\n"); if (m_extraOccupancy) { /* these bytes were escaped by serializeSubstreams */ memcpy(out + bytes, m_extraBuffer, m_extraOccupancy); bytes += m_extraOccupancy; m_extraOccupancy = 0; } /* 7.4.1.1 * ... when the last byte of the RBSP data is equal to 0x00 (which can * only occur when the RBSP ends in a cabac_zero_word), a final byte equal * to 0x03 is appended to the end of the data. */ if (!out[bytes - 1]) out[bytes++] = 0x03; if (!m_annexB) { uint32_t dataSize = bytes - 4; out[0] = (uint8_t)(dataSize >> 24); out[1] = (uint8_t)(dataSize >> 16); out[2] = (uint8_t)(dataSize >> 8); out[3] = (uint8_t)dataSize; } m_occupancy += bytes; X265_CHECK(m_numNal < (uint32_t)MAX_NAL_UNITS, "NAL count overflow\n"); x265_nal& nal = m_nal[m_numNal++]; nal.type = nalUnitType; nal.sizeBytes = bytes; nal.payload = out; } /* concatenate and escape WPP sub-streams, return escaped row lengths. * These streams will be appended to the next serialized NAL */ uint32_t NALList::serializeSubstreams(uint32_t* streamSizeBytes, uint32_t streamCount, const Bitstream* streams) { uint32_t maxStreamSize = 0; uint32_t estSize = 0; for (uint32_t s = 0; s < streamCount; s++) estSize += streams[s].getNumberOfWrittenBytes(); estSize += estSize >> 1; if (estSize > m_extraAllocSize) { uint8_t *temp = X265_MALLOC(uint8_t, estSize); if (temp) { X265_FREE(m_extraBuffer); m_extraBuffer = temp; m_extraAllocSize = estSize; } else { x265_log(NULL, X265_LOG_ERROR, "Unable to realloc WPP substream concatenation buffer\n"); return 0; } } uint32_t bytes = 0; uint8_t *out = m_extraBuffer; for (uint32_t s = 0; s < streamCount; s++) { const Bitstream& stream = streams[s]; uint32_t inSize = stream.getNumberOfWrittenBytes(); const uint8_t *inBytes = stream.getFIFO(); uint32_t prevBufSize = bytes; if (inBytes) { for (uint32_t i = 0; i < inSize; i++) { if (bytes >= 2 && !out[bytes - 2] && !out[bytes - 1] && inBytes[i] <= 0x03) { /* inject 0x03 to prevent emulating a start code */ out[bytes++] = 3; } out[bytes++] = inBytes[i]; } } if (s < streamCount - 1) { streamSizeBytes[s] = bytes - prevBufSize; if (streamSizeBytes[s] > maxStreamSize) maxStreamSize = streamSizeBytes[s]; } } m_extraOccupancy = bytes; return maxStreamSize; }