|
|
|
@ -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; |
|
|
|
|