141 lines
2.8 KiB
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;
|
|
}
|