#include #include #include #include #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; }