Skip to content

Commit a93c804

Browse files
authored
Merge pull request #2057 from kontell/fix/hevc-ts-extradata
Fix HEVC TS extra data construction for 3-byte start codes
2 parents e481ed8 + ca06c19 commit a93c804

2 files changed

Lines changed: 47 additions & 42 deletions

File tree

lib/mpegts/mpegts/ES_hevc.cpp

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include "bitstream.h"
1111
#include "debug.h"
1212

13-
#include <cstring> // for memset memcpy
13+
#include <cstring> // for memset memcpy memcmp
1414

1515
using namespace TSDemux;
1616

@@ -43,7 +43,9 @@ void ES_hevc::Parse(STREAM_PKT* pkt)
4343
uint32_t startcode = m_StartCode;
4444
bool frameComplete = false;
4545

46-
if (m_NeedSPS)
46+
// Reset extra data only on a fresh capture, so a VPS from a previous PES
47+
// payload isn't discarded while waiting for its SPS/PPS.
48+
if (m_NeedVPS && m_NeedSPS && m_NeedPPS)
4749
stream_info.extra_data_size = 0;
4850

4951
while (p < es_len)
@@ -167,20 +169,9 @@ void ES_hevc::Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool &comp
167169
switch (hdr.nal_unit_type)
168170
{
169171
case NAL_VPS_NUT:
170-
if (m_NeedVPS)
171-
{
172-
if (stream_info.extra_data_size + NumBytesInNalUnit <= sizeof(stream_info.extra_data))
173-
{
174-
memcpy(stream_info.extra_data + stream_info.extra_data_size, es_buf + (buf_ptr - 4), NumBytesInNalUnit);
175-
stream_info.extra_data_size += NumBytesInNalUnit;
176-
m_NeedVPS = false;
177-
}
178-
else
179-
{
180-
DBG(DEMUX_DBG_INFO, "HEVC fixme: stream_info.extra_data too small! %i\n", stream_info.extra_data_size + NumBytesInNalUnit);
181-
}
182-
}
183-
break;
172+
if (m_NeedVPS && AppendExtraData(buf_ptr, NumBytesInNalUnit))
173+
m_NeedVPS = false;
174+
break;
184175

185176
case NAL_SPS_NUT:
186177
{
@@ -191,19 +182,8 @@ void ES_hevc::Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool &comp
191182
return;
192183
}
193184
Parse_SPS(buf, NumBytesInNalUnit, hdr);
194-
if (m_NeedSPS)
195-
{
196-
if (stream_info.extra_data_size + NumBytesInNalUnit <= sizeof(stream_info.extra_data))
197-
{
198-
memcpy(stream_info.extra_data + stream_info.extra_data_size, es_buf + (buf_ptr - 4), NumBytesInNalUnit);
199-
stream_info.extra_data_size += NumBytesInNalUnit;
200-
m_NeedSPS = false;
201-
}
202-
else
203-
{
204-
DBG(DEMUX_DBG_INFO, "HEVC fixme: stream_info.extra_data too small! %i\n", stream_info.extra_data_size + NumBytesInNalUnit);
205-
}
206-
}
185+
if (m_NeedSPS && AppendExtraData(buf_ptr, NumBytesInNalUnit))
186+
m_NeedSPS = false;
207187
break;
208188
}
209189

@@ -216,19 +196,8 @@ void ES_hevc::Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool &comp
216196
return;
217197
}
218198
Parse_PPS(buf, NumBytesInNalUnit);
219-
if (m_NeedPPS)
220-
{
221-
if (stream_info.extra_data_size + NumBytesInNalUnit <= sizeof(stream_info.extra_data))
222-
{
223-
memcpy(stream_info.extra_data + stream_info.extra_data_size, es_buf + (buf_ptr - 4), NumBytesInNalUnit);
224-
stream_info.extra_data_size += NumBytesInNalUnit;
225-
m_NeedPPS = false;
226-
}
227-
else
228-
{
229-
DBG(DEMUX_DBG_INFO, "HEVC fixme: stream_info.extra_data too small! %i\n", stream_info.extra_data_size + NumBytesInNalUnit);
230-
}
231-
}
199+
if (m_NeedPPS && AppendExtraData(buf_ptr, NumBytesInNalUnit))
200+
m_NeedPPS = false;
232201
break;
233202
}
234203

@@ -269,6 +238,41 @@ void ES_hevc::Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool &comp
269238
}
270239
}
271240

241+
// Append a parameter set NAL (VPS/SPS/PPS) to the extra data as Annex B.
242+
// numBytes spans to the end of the next start code (3 or 4 bytes), stripped here if present.
243+
bool ES_hevc::AppendExtraData(int buf_ptr, unsigned int numBytes)
244+
{
245+
if (numBytes < 3)
246+
return false;
247+
248+
unsigned int nalSize = numBytes;
249+
const unsigned char* tail = es_buf + buf_ptr + numBytes;
250+
if (numBytes >= 4 && std::memcmp(tail - 4, "\0\0\0\x01", 4) == 0)
251+
nalSize = numBytes - 4;
252+
else if (std::memcmp(tail - 3, "\0\0\x01", 3) == 0)
253+
nalSize = numBytes - 3;
254+
255+
if (nalSize == 0)
256+
return false;
257+
258+
if (static_cast<size_t>(stream_info.extra_data_size) + 4 + nalSize >
259+
sizeof(stream_info.extra_data))
260+
{
261+
DBG(DEMUX_DBG_INFO, "HEVC fixme: stream_info.extra_data too small! %u\n",
262+
static_cast<unsigned int>(stream_info.extra_data_size) + 4 + nalSize);
263+
return false;
264+
}
265+
266+
uint8_t* ed = stream_info.extra_data + stream_info.extra_data_size;
267+
ed[0] = 0;
268+
ed[1] = 0;
269+
ed[2] = 0;
270+
ed[3] = 1;
271+
std::memcpy(ed + 4, es_buf + buf_ptr, nalSize);
272+
stream_info.extra_data_size += 4 + nalSize;
273+
return true;
274+
}
275+
272276
void ES_hevc::Parse_PPS(uint8_t *buf, int len)
273277
{
274278
CBitstream bs(buf, len*8, true);

lib/mpegts/mpegts/ES_hevc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ namespace TSDemux
9090
bool m_Interlaced;
9191

9292
void Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool &complete);
93+
bool AppendExtraData(int buf_ptr, unsigned int numBytes);
9394
void Parse_PPS(uint8_t *buf, int len);
9495
void Parse_SLH(uint8_t *buf, int len, HDR_NAL hdr, hevc_private::VCL_NAL &vcl);
9596
void Parse_SPS(uint8_t *buf, int len, HDR_NAL hdr);

0 commit comments

Comments
 (0)