|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #include "mpeg-types.h"
- #include "mpeg-util.h"
- #include <assert.h>
- #include <string.h>
-
- #define H264_NAL_IDR 5
- #define H264_NAL_AUD 9
-
- /// e.g.
- /// 1. 0x00 00 00 00 00 01 09 EF => return 6(09), leading 4
- /// 2. 0x80 00 00 00 00 01 09 EF => return 6(09), leading 4
- ///
- /// Find h264 nalu start position
- /// @param[out] leading leading bytes before nalu position
- /// @return -1-not found, other nalu position(after 00 00 01)
- int mpeg_h264_find_nalu(const uint8_t* p, size_t bytes, size_t* leading)
- {
- size_t i, zeros;
- for (zeros = i = 0; i + 2 /*naltype + 1-data*/ < bytes; i++)
- {
- if (0x01 == p[i] && zeros >= 2)
- {
- assert(i >= zeros);
- if (leading)
- *leading = (zeros > 2 ? 3 : zeros) + 1; // zeros + 0x01
- return (int)(i + 1);
- }
-
- zeros = 0x00 != p[i] ? 0 : (zeros + 1);
- }
-
- return -1;
- }
-
- /// @param[out] leading optional leading zero bytes
- /// @return -1-not found, other-AUD position(include start code)
- static int mpeg_h264_find_access_unit_delimiter(const uint8_t* p, size_t bytes, size_t* leading)
- {
- int i;
- size_t off;
- for (off = 0; off < bytes; off += i + 1)
- {
- i = mpeg_h264_find_nalu(p + off, bytes - off, leading);
- if (-1 == i)
- return -1;
-
- if (H264_NAL_AUD == (p[i + off] & 0x1f))
- return (int)(i + off);
- }
-
- return -1;
- }
-
- int mpeg_h264_find_keyframe(const uint8_t* p, size_t bytes)
- {
- size_t i;
- uint8_t type;
- for (i = 2; i + 1 < bytes; i++)
- {
- if (0x01 == p[i] && 0x00 == p[i - 1] && 0x00 == p[i - 2])
- {
- type = p[i + 1] & 0x1f;
- if (H264_NAL_IDR >= type && 1 <= type)
- return H264_NAL_IDR == type ? 1 : 0;
- }
- }
-
- return 0;
- }
-
- /// h264_is_new_access_unit H.264 new access unit(frame)
- /// @return 1-new access, 0-not a new access
- static int mpeg_h264_is_new_access_unit(const uint8_t* nalu, size_t bytes)
- {
- enum { NAL_NIDR = 1, NAL_PARTITION_A = 2, NAL_IDR = 5, NAL_SEI = 6, NAL_SPS = 7, NAL_PPS = 8, NAL_AUD = 9, };
-
- uint8_t nal_type;
-
- if(bytes < 2)
- return 0;
-
- nal_type = nalu[0] & 0x1f;
-
- // 7.4.1.2.3 Order of NAL units and coded pictures and association to access units
- if(NAL_AUD == nal_type || NAL_SPS == nal_type || NAL_PPS == nal_type || NAL_SEI == nal_type || (14 <= nal_type && nal_type <= 18))
- return 1;
-
- // 7.4.1.2.4 Detection of the first VCL NAL unit of a primary coded picture
- if(NAL_NIDR == nal_type || NAL_PARTITION_A == nal_type || NAL_IDR == nal_type)
- {
- // Live555 H264or5VideoStreamParser::parse
- // The high-order bit of the byte after the "nal_unit_header" tells us whether it's
- // the start of a new 'access unit' (and thus the current NAL unit ends an 'access unit'):
- return (nalu[1] & 0x80) ? 1 : 0; // first_mb_in_slice
- }
-
- return 0;
- }
-
- int mpeg_h264_find_new_access_unit(const uint8_t* data, size_t bytes, int* vcl)
- {
- int n;
- size_t leading;
- uint8_t nal_type;
- const uint8_t* p, *end;
-
- end = data + bytes;
- for (p = data; p && p < end; p += n)
- {
- n = mpeg_h264_find_nalu(p, end - p, &leading);
- if (n < 0)
- return -1;
-
- nal_type = p[n] & 0x1f;
- if (*vcl > 0 && mpeg_h264_is_new_access_unit(p + n, end - p - n))
- {
- return (int)(p - data + n - leading);
- }
- else if (nal_type > 0 && nal_type < 6)
- {
- *vcl = H264_NAL_IDR == nal_type ? 1 : 2;
- }
- else
- {
- // nothing to do
- }
- }
-
- return -1;
- }
-
- /// @param[out] codec 1-h264, 2-h265
- /// @return 0-ok, other-error
- int mpeg_h26x_verify(const uint8_t* data, size_t bytes, int* codec)
- {
- uint32_t h264_flags = 0x01A0U; // sps/pps/idr
- uint64_t h265_flags = 0x700000000ULL; // vps/sps/pps
-
- int n, count;
- size_t leading;
- uint8_t h26x[4][10];
- const uint8_t* p, * end;
-
- count = 0;
- end = data + bytes;
- for (p = data; p && p < end && count < sizeof(h26x[0])/sizeof(h26x[0][0]); p += n)
- {
- n = mpeg_h264_find_nalu(p, end - p, &leading);
- if (n < 0 || p + n + 1 > end)
- break;
-
- h26x[0][count] = p[n] & 0x1f;
- h26x[1][count] = (p[n] >> 1) & 0x3f;
- h26x[2][count] = p[n]; // for mpeg4 vop_start_code
- h26x[3][count] = p[n+1]; // for mpeg4 vop_coding_type
- ++count;
- }
-
- for(n = 0; n < count; n++)
- {
- h264_flags &= ~(1U << h26x[0][n]);
- h265_flags &= ~(1ULL << h26x[1][n]);
- }
-
- if (0 == h264_flags && 0 != h265_flags)
- {
- // match sps/pps/idr
- *codec = 1;
- return 0;
- }
- else if (0 == h265_flags && 0 != h264_flags)
- {
- // match vps/sps/pps
- *codec = 2;
- return 0;
- }
- else if (0xB0 == h26x[2][0] && 0 == (0x30 & h26x[3][0]))
- {
- // match VOP start code
- *codec = 3;
- return 0;
- }
-
- return -1;
- }
|