Coverage Report

Created: 2022-08-24 06:17

/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
}