|
|
|
|
@ -156,7 +156,58 @@ static void bitstreams(void) {
|
|
|
|
|
} |
|
|
|
|
puts("video: real AVC Baseline/CB and HEVC IDR, multi-picture DPB, atomic malformed parse PASS"); |
|
|
|
|
} |
|
|
|
|
static void put_bits(uint8_t *data, unsigned *at, unsigned value, unsigned count) { |
|
|
|
|
while (count--) { data[*at / 8] |= ((value >> count) & 1u) << (7 - *at % 8); ++*at; } |
|
|
|
|
} |
|
|
|
|
/* Только синтаксис заголовков: entropy payload здесь не нужен. SPS fixture: CTU32, 40*23 CTB, address=10 bits. */ |
|
|
|
|
static size_t hevc_segment(uint8_t *data, unsigned first, unsigned enabled, unsigned dependent, |
|
|
|
|
unsigned output, unsigned visible, unsigned extra, unsigned address) { |
|
|
|
|
memset(data, 0, 16); data[2] = 1; data[3] = 40; data[4] = 1; |
|
|
|
|
unsigned at = 40; |
|
|
|
|
put_bits(data, &at, first, 1); put_bits(data, &at, 0, 1); put_bits(data, &at, 1, 1); // first, no_output_prior, PPS id=0.
|
|
|
|
|
if (!first) { |
|
|
|
|
if (enabled) put_bits(data, &at, dependent, 1); |
|
|
|
|
put_bits(data, &at, address, 10); |
|
|
|
|
} |
|
|
|
|
if (!dependent) { |
|
|
|
|
put_bits(data, &at, 0, extra); put_bits(data, &at, 3, 3); // reserved bits, I slice ue(2).
|
|
|
|
|
if (output) put_bits(data, &at, visible, 1); |
|
|
|
|
} |
|
|
|
|
put_bits(data, &at, 1, 1); |
|
|
|
|
return (at + 7) / 8; |
|
|
|
|
} |
|
|
|
|
static void hevc_pps_flags(void) { |
|
|
|
|
uint8_t bytes[8192]; struct call_video_bitstream stream; |
|
|
|
|
int size = call_video_probe_key(CALL_VIDEO_H265, CALL_VIDEO_MAIN, bytes, sizeof(bytes)); CHECK(size > 0); |
|
|
|
|
size_t pps = 0, config = 4 + ((unsigned)bytes[2] << 8 | bytes[3]); |
|
|
|
|
for (size_t i = 4; i + 5 < config; ++i) |
|
|
|
|
if (!bytes[i] && !bytes[i + 1] && bytes[i + 2] == 1 && bytes[i + 3] == 68) pps = i + 5; |
|
|
|
|
CHECK(pps && bytes[pps] == 0xc0); // Оба id=0, slice flags отсутствуют.
|
|
|
|
|
bytes[pps] |= 0x20; // Реальный IDR остаётся валиден, когда PPS разрешает dependent segments.
|
|
|
|
|
CHECK(!call_video_inspect_key(CALL_VIDEO_H265, bytes, size, &stream)); |
|
|
|
|
for (unsigned flags = 0; flags < 4; ++flags) for (unsigned extra = 0; extra <= 3; extra += 3) { |
|
|
|
|
unsigned dependent = flags & 1, output = flags >> 1; |
|
|
|
|
bytes[pps] = 0xc0 | dependent << 5 | output << 4 | extra << 1; |
|
|
|
|
size_t end = config + hevc_segment(bytes + config, 1, dependent, 0, output, 1, extra, 0); |
|
|
|
|
CHECK(!call_video_inspect_key(CALL_VIDEO_H265, bytes, end, &stream)); |
|
|
|
|
size_t next = end + hevc_segment(bytes + end, 0, dependent, 0, output, 1, extra, 1); |
|
|
|
|
CHECK(!call_video_inspect_key(CALL_VIDEO_H265, bytes, next, &stream)); |
|
|
|
|
next = end + hevc_segment(bytes + end, 0, dependent, dependent, output, 1, extra, 1); |
|
|
|
|
CHECK(!call_video_inspect_key(CALL_VIDEO_H265, bytes, next, &stream)); |
|
|
|
|
for (unsigned address = 0; address <= 1023; address += 1023) { |
|
|
|
|
next = end + hevc_segment(bytes + end, 0, dependent, dependent, output, 1, extra, address); |
|
|
|
|
CHECK(call_video_inspect_key(CALL_VIDEO_H265, bytes, next, &stream) < 0); |
|
|
|
|
} |
|
|
|
|
if (output) { |
|
|
|
|
next = end + hevc_segment(bytes + end, 0, dependent, 0, output, 0, extra, 1); |
|
|
|
|
CHECK(call_video_inspect_key(CALL_VIDEO_H265, bytes, next, &stream) < 0); |
|
|
|
|
end = config + hevc_segment(bytes + config, 1, dependent, 0, output, 0, extra, 0); |
|
|
|
|
CHECK(call_video_inspect_key(CALL_VIDEO_H265, bytes, end, &stream) < 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
puts("video: HEVC PPS flags, independent/dependent IDR segments, output flag and CTB address validation PASS"); |
|
|
|
|
} |
|
|
|
|
int main(void) { |
|
|
|
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); |
|
|
|
|
capabilities(); envelopes(); roundtrip(); rejected(); bitstreams(); return 0; |
|
|
|
|
capabilities(); envelopes(); roundtrip(); rejected(); bitstreams(); hevc_pps_flags(); return 0; |
|
|
|
|
} |
|
|
|
|
|