Browse Source

Check VPS HRD and log actual codec constraints on rejection

stream-multiview
evgeny 1 week ago
parent
commit
047927a7a5
  1. 3
      src/call/call_video.c
  2. 24
      src/call/call_video_bitstream.c

3
src/call/call_video.c

@ -60,7 +60,8 @@ 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, int call_video_choose(const struct call_video_caps *sender, const struct call_video_caps *receiver,
struct call_video_format *format) { struct call_video_format *format) {
if (!call_video_caps_valid(sender) || !call_video_caps_valid(receiver) || !format || format->codec > 2 || format->level) { 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)) {
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video choose invalid capabilities/request"); return -1; DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video choose invalid capabilities/request"); return -1;
} }
struct call_video_format f = *format; struct call_video_format f = *format;

24
src/call/call_video_bitstream.c

@ -95,7 +95,10 @@ static int hevc_ptl(struct bits *b, struct call_video_bitstream *s) {
get(b, 32); // profile compatibility; принимаем только явный Main. get(b, 32); // profile compatibility; принимаем только явный Main.
get(b, 1); unsigned interlaced = get(b, 1); get(b, 2); 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; get(b, 32); get(b, 12); s->level = get(b, 8); s->profile = CALL_VIDEO_MAIN;
if (space || tier || profile != 1 || interlaced) return bad("HEVC profile/tier/interlace"); if (space || tier || 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;
}
return b->error ? bad("truncated HEVC PTL") : 0; return b->error ? bad("truncated HEVC PTL") : 0;
} }
/* HEVC HRD для единственного temporal layer; sub-picture HRD звонкам не требуется. */ /* HEVC HRD для единственного temporal layer; sub-picture HRD звонкам не требуется. */
@ -219,13 +222,24 @@ int call_video_inspect_key(int codec, const uint8_t *data, size_t length, struct
if (have_sps && (memcmp(&parsed, &stream, sizeof(parsed)) || id != sps_id)) { bad("multiple AVC SPS"); goto done; } if (have_sps && (memcmp(&parsed, &stream, sizeof(parsed)) || id != sps_id)) { bad("multiple AVC SPS"); goto done; }
stream = parsed; sps_id = id; have_sps = 1; stream = parsed; sps_id = id; have_sps = 1;
} else if (codec == 2 && type == 32) { } else if (codec == 2 && type == 32) {
struct call_video_bitstream parsed = {0};
unsigned id = get(&b, 4); get(&b, 2); unsigned id = get(&b, 4); get(&b, 2);
if (get(&b, 6) || get(&b, 3) || !get(&b, 1) || get(&b, 16) != 65535 || hevc_ptl(&b, &vp)) { if (get(&b, 6) || get(&b, 3) || !get(&b, 1) || get(&b, 16) != 65535 || hevc_ptl(&b, &parsed)) {
bad("HEVC VPS layers/PTL"); goto done; bad("HEVC VPS layers/PTL"); goto done;
} }
get(&b, 1); unsigned dpb = ue(&b) + 1, reorder = ue(&b); ue(&b); get(&b, 1); unsigned dpb = ue(&b) + 1, reorder = ue(&b); ue(&b);
if (b.error || reorder || dpb > 16 || (have_vps && id != vps_id)) { bad("HEVC VPS DPB"); goto done; } if (b.error || reorder || dpb > 16) { bad("HEVC VPS DPB"); goto done; }
vp.dpb = dpb; vps_id = id; have_vps = 1; parsed.dpb = dpb;
if (have_vps && (id != vps_id || memcmp(&parsed, &vp, sizeof(vp)))) { bad("multiple HEVC VPS"); goto done; }
if (get(&b, 6) || ue(&b)) { bad("HEVC VPS layer sets"); goto done; }
if (get(&b, 1)) {
get(&b, 32); get(&b, 32); if (get(&b, 1)) ue(&b);
unsigned count = ue(&b);
if (count > 1) { bad("HEVC VPS HRD count"); goto done; }
if (count) { if (ue(&b)) { bad("HEVC VPS HRD layer"); goto done; } hevc_hrd(&b, parsed.level); }
}
if (get(&b, 1) || b.error) { bad("HEVC VPS extension/truncation/HRD"); goto done; }
vp = parsed; vps_id = id; have_vps = 1;
} else if (codec == 2 && type == 33) { } else if (codec == 2 && type == 33) {
struct call_video_bitstream parsed = {0}; unsigned id, vps; struct call_video_bitstream parsed = {0}; unsigned id, vps;
if (hevc_sps(&b, &parsed, &id, &vps)) goto done; if (hevc_sps(&b, &parsed, &id, &vps)) goto done;
@ -271,6 +285,8 @@ int call_video_inspect_key(int codec, const uint8_t *data, size_t length, struct
|| vp.profile != stream.profile || vp.level != stream.level || stream.dpb > vp.dpb))) { || vp.profile != stream.profile || vp.level != stream.level || stream.dpb > vp.dpb))) {
bad("missing/inconsistent parameter sets or IDR"); goto done; bad("missing/inconsistent parameter sets or IDR"); goto done;
} }
DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video bitstream verified codec=%d profile=%u level=%u size=%ux%u dpb=%u slices=%u",
codec, stream.profile, stream.level, stream.width, stream.height, stream.dpb, slices);
*out = stream; result = 0; *out = stream; result = 0;
done: done:
u_free(scratch); return result; u_free(scratch); return result;

Loading…
Cancel
Save