Negotiate HEVC Main High tier with explicit level limits

This commit is contained in:
evgeny committed 2026-10-19 23:32:29 +02:00
1 parent 5c1807a712
commit 7122d70ea6
3 files changed
+35 -9

No files matched your search

+7 -4
View File
@@ -46,7 +46,8 @@ static int limit_valid(const struct call_video_limit *l, int codec) {
return l->width >= 16 && l->width <= 4096 && l->height >= 16 && l->height <= 4096
&& l->fps >= 1 && l->fps <= 60 && l->pixels_per_second >= 256 && l->pixels_per_second <= 4096u * 4096u * 60u
&& l->maximum_bps >= CALL_VIDEO_RATE_MIN_BPS && l->maximum_bps <= CALL_VIDEO_RATE_MAX_BPS
&& l->profiles && !(l->profiles & ~(codec == CALL_VIDEO_H264 ? 3u : 1u)) && level_find(codec, l->level);
&& l->profiles && !(l->profiles & ~3u) && level_find(codec, l->level)
&& !(codec == CALL_VIDEO_H265 && (l->profiles & CALL_VIDEO_MAIN_HIGH_TIER) && l->level < 120);
}
int call_video_caps_valid(const struct call_video_caps *caps) {
if (!caps) return 0;
@@ -71,7 +72,7 @@ static int fits(const struct call_video_limit *l, const struct call_video_format
int call_video_choose(const struct call_video_caps *sender, const struct call_video_caps *receiver,
struct call_video_format *format) {
if (!call_video_caps_valid(sender) || !call_video_caps_valid(receiver) || !format || format->codec > 2
|| format->level || format->profile > 2 || (format->codec == CALL_VIDEO_H265 && format->profile > 1)) {
|| format->level || format->profile > 2) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video choose invalid capabilities/request"); return -1;
}
struct call_video_format f = *format;
@@ -94,7 +95,8 @@ int call_video_choose(const struct call_video_caps *sender, const struct call_vi
unsigned profiles = sender->encode[codec - 1].profiles & receiver->decode[codec - 1].profiles;
if (format->profile) profiles &= format->profile;
if (!profiles) continue;
f.profile = profiles & CALL_VIDEO_CONSTRAINED_BASELINE ? CALL_VIDEO_CONSTRAINED_BASELINE : 1;
f.profile = codec == CALL_VIDEO_H264 ? (profiles & CALL_VIDEO_CONSTRAINED_BASELINE ? CALL_VIDEO_CONSTRAINED_BASELINE : 1)
: (profiles & CALL_VIDEO_MAIN ? CALL_VIDEO_MAIN : CALL_VIDEO_MAIN_HIGH_TIER);
const struct video_level *levels = codec == CALL_VIDEO_H264 ? avc_levels : hevc_levels;
unsigned count = codec == CALL_VIDEO_H264 ? sizeof(avc_levels) / sizeof(*levels) : sizeof(hevc_levels) / sizeof(*levels);
for (unsigned i = 0; i < count; i++) {
@@ -114,7 +116,8 @@ int call_video_format_valid(const struct call_video_format *f) {
&& f->width <= 4096 && f->height <= 4096 && !(f->width % 2) && !(f->height % 2)
&& f->fps >= 1 && f->fps <= 60 && (f->rotation == 0 || f->rotation == 90 || f->rotation == 180 || f->rotation == 270)
&& f->maximum_bps >= CALL_VIDEO_RATE_MIN_BPS && f->maximum_bps <= CALL_VIDEO_RATE_MAX_BPS
&& (f->profile == 1 || (f->codec == CALL_VIDEO_H264 && f->profile == 2)))) return 0;
&& (f->profile == 1 || f->profile == 2))) return 0;
if (f->codec == CALL_VIDEO_H265 && f->profile == CALL_VIDEO_MAIN_HIGH_TIER && f->level < 120) return 0;
const struct video_level *l = level_find(f->codec, f->level);
if (!l) return 0;
// AVC — macroblocks; HEVC резервируем padding до CTU 64, чтобы не зависеть от backend min-CU.
+3 -2
View File
@@ -1,5 +1,5 @@
/* Общий контракт видеотрека. Все операции выполняет владелец в uasync-потоке.
* Кодеки: H.264 Baseline/Constrained Baseline, H.265 Main (Main tier), 8 bit,
* Кодеки: H.264 Baseline/Constrained Baseline, H.265 Main (Main/High tier), 8 bit,
* 4:2:0, progressive, без B-кадров/reorder. DPB ограничен уровнем потока.
* Поколение меняется только при смене формата/камеры; bitrate не меняет поколение.
* KEY: config_length:4BE + Annex B configuration + Annex B access unit (как uAV2).
@@ -23,6 +23,7 @@ extern "C" {
#define CALL_VIDEO_BASELINE 1u
#define CALL_VIDEO_CONSTRAINED_BASELINE 2u
#define CALL_VIDEO_MAIN 1u
#define CALL_VIDEO_MAIN_HIGH_TIER 2u
/* Нулевой limit означает отсутствие проверенного encoder/decoder данного профиля.
* Индексы 0=H.264, 1=H.265. Лимиты независимы для каждого направления.
@@ -32,7 +33,7 @@ extern "C" {
struct call_video_limit {
uint16_t width, height, fps;
uint32_t pixels_per_second, maximum_bps;
uint8_t profiles; // Маска профилей данного codec; decode Baseline включает CB явно.
uint8_t profiles; // Маска режимов: AVC Baseline/CB; HEVC Main с Main/High tier. Приём каждого проверяется отдельно.
uint8_t level;
};
struct call_video_caps { struct call_video_limit encode[2], decode[2]; };
+25 -3
View File
@@ -96,8 +96,8 @@ static int hevc_ptl(struct bits *b, struct call_video_bitstream *s) {
unsigned space = get(b, 2), tier = get(b, 1), profile = get(b, 5);
get(b, 32); // profile compatibility; принимаем только явный Main.
get(b, 1); unsigned interlaced = get(b, 1); get(b, 2);
get(b, 32); get(b, 12); s->level = get(b, 8); s->profile = CALL_VIDEO_MAIN;
if (space || tier || profile != 1 || interlaced) {
get(b, 32); get(b, 12); s->level = get(b, 8); s->profile = tier ? CALL_VIDEO_MAIN_HIGH_TIER : CALL_VIDEO_MAIN;
if (space || (tier && s->level < 120) || profile != 1 || interlaced) {
DEBUG_WARN(DEBUG_CATEGORY_CALL, "video HEVC PTL rejected space=%u profile=%u tier=%u level=%u interlaced=%u",
space, profile, tier, s->level, interlaced); return -1;
}
@@ -343,10 +343,32 @@ int call_video_probe_key(int codec, int profile, unsigned width, unsigned height
size = codec == 1 ? sizeof(call_video_fullhd_1920_1080_1) : sizeof(call_video_fullhd_1920_1080_2);
}
} else if (wide != 1280 || short_side != 720) return bad("probe key geometry");
if ((codec != 1 && codec != 2) || (profile != 1 && !(codec == 1 && profile == 2))
if ((codec != 1 && codec != 2) || (profile != 1 && profile != 2)
|| !out || capacity < size)
return bad("probe key arguments");
memcpy(out, data, size);
if (codec == 1 && profile == 1) out[10] &= ~64u;
if (codec == CALL_VIDEO_H265 && profile == CALL_VIDEO_MAIN_HIGH_TIER) {
// Только эталонные пробы: Main tools и Main BR/CPB также соответствуют High tier level 4.
// Повышение декларации уровня не меняет entropy payload. Производственные VPS/SPS не переписываем.
unsigned patched = 0;
size_t at = start_code(out, size, 4);
while (at < size) {
size_t begin = at + 3, end = start_code(out, size, begin); at = end;
unsigned type = (out[begin] >> 1) & 63;
if (type != 32 && type != 33) continue;
unsigned profile_at = type == 32 ? 6 : 3, raw = 0, zeros = 0;
for (size_t i = begin; i < end; ++i) {
if (zeros == 2 && out[i] == 3) { zeros = 0; continue; }
if (raw == profile_at) {
if (out[i] != 1) return bad("probe HEVC profile");
out[i] |= 32;
}
if (raw == profile_at + 11) { out[i] = 120; ++patched; break; }
zeros = out[i] == 0 ? zeros + 1 : 0; ++raw;
}
}
if (patched != 2) return bad("probe HEVC PTL count");
}
return (int)size;
}