stream-deploy/ZLM/3rdpart/media-server/librtp/payload/rtp-h264-bitstream.c

141 lines
2.8 KiB
C++

#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#define RTP_H2645_BITSTREAM_FORMAT_DETECT 1
static const uint8_t* h264_startcode(const uint8_t* data, int bytes)
{
int i;
for (i = 2; i + 1 < bytes; i++)
{
if (0x01 == data[i] && 0x00 == data[i - 1] && 0x00 == data[i - 2])
return data + i + 1;
}
return NULL;
}
/// @return >0-ok, <=0-error
static inline int h264_avcc_length(const uint8_t* h264, int bytes, int avcc)
{
int i;
uint32_t n;
n = 0;
assert(3 <= avcc && avcc <= 4);
for (i = 0; i < avcc && i < bytes; i++)
n = (n << 8) | h264[i];
return avcc >= bytes ? -1 : (int)n;
}
/// @return 1-true, 0-false
static int h264_avcc_bitstream_valid(const uint8_t* h264, int bytes, int avcc)
{
int n;
while (avcc + 1 < bytes)
{
n = h264_avcc_length(h264, bytes, avcc);
if (n < 0 || n + avcc > bytes)
return 0; // invalid
h264 += n + avcc;
bytes -= n + avcc;
}
return 0 == bytes ? 1 : 0;
}
/// @return 0-annexb, >0-avcc, <0-error
static int h264_bitstream_format(const uint8_t* h264, int bytes)
{
uint32_t n;
if (bytes < 4)
return -1;
n = ((uint32_t)h264[0]) << 16 | ((uint32_t)h264[1]) << 8 | ((uint32_t)h264[2]);
if (0 == n && h264[3] <= 1)
{
return 0; // annexb
}
else if (1 == n)
{
// try avcc & annexb
return h264_avcc_bitstream_valid(h264, bytes, 4) ? 4 : 0;
}
else
{
// try avcc 4/3 bytes
return h264_avcc_bitstream_valid(h264, bytes, 4) ? 4 : (h264_avcc_bitstream_valid(h264, bytes, 3) ? 3 : -1);
}
}
static int h264_avcc_nalu(const void* h264, int bytes, int avcc, int (*handler)(void* param, const uint8_t* nalu, int bytes, int last), void* param)
{
int r;
uint32_t n;
const uint8_t* p, * end;
r = 0;
p = (const uint8_t*)h264;
end = (const uint8_t*)h264 + bytes;
for (n = h264_avcc_length(p, (int)(end - p), avcc); 0 == r && p + n + avcc <= end; n = h264_avcc_length(p, (int)(end - p), avcc))
{
assert(n > 0);
if (n > 0)
{
r = handler(param, p + avcc, (int)n, p + avcc + n < end ? 0 : 1);
}
p += n + avcc;
}
return r;
}
///@param[in] h264 H.264 byte stream format data(A set of NAL units)
int rtp_h264_annexb_nalu(const void* h264, int bytes, int (*handler)(void* param, const uint8_t* nalu, int bytes, int last), void* param)
{
int r;
ptrdiff_t n;
const uint8_t* p, * next, * end;
#if defined(RTP_H2645_BITSTREAM_FORMAT_DETECT)
int avcc;
avcc = h264_bitstream_format(h264, bytes);
if (avcc > 0)
return h264_avcc_nalu(h264, bytes, avcc, handler, param);
#endif
end = (const uint8_t*)h264 + bytes;
p = h264_startcode((const uint8_t*)h264, bytes);
r = 0;
while (p && 0 == r)
{
next = h264_startcode(p, (int)(end - p));
if (next)
{
n = next - p - 3;
}
else
{
n = end - p;
}
while (n > 0 && 0 == p[n - 1]) n--; // filter tailing zero
assert(n > 0);
if (n > 0)
{
r = handler(param, p, (int)n, next ? 0 : 1);
}
p = next;
}
return r;
}