File size: 5,942 Bytes
88a11cc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python3
"""Deterministic FLV pre-start metadata tests; no network or FFmpeg required."""
import os
import pathlib
import sys
import tempfile

ROOT=pathlib.Path(sys.argv[1] if len(sys.argv)>1 else pathlib.Path(__file__).parent).resolve()
sys.path.insert(0,str(ROOT))
os.environ.setdefault('PASSWORD','test-pass-not-for-prod')
os.environ.setdefault('DATA_DIR',tempfile.mkdtemp(prefix='source-probe-test-'))
os.environ['YOUTUBE_FLV_PROBE_SECONDS']='0.2'

import youtube_manager as manager_module  # noqa: E402
from relay import Sender  # noqa: E402
from stream_monitor import video_dimensions  # noqa: E402

passed=failed=0
def check(name,ok,detail=''):
    global passed,failed
    if ok:
        passed+=1;print('PASS ',name)
    else:
        failed+=1;print('FAIL ',name,detail)


class Bits:
    def __init__(self):self.data=[]
    def bit(self,value):self.data.append(1 if value else 0)
    def bits(self,value,count):
        for shift in range(count-1,-1,-1):self.bit((value>>shift)&1)
    def ue(self,value):
        code=value+1;size=code.bit_length()
        self.bits(0,size-1);self.bits(code,size)
    def rbsp(self):
        self.bit(1)
        while len(self.data)%8:self.bit(0)
        raw=bytes(sum(self.data[i+j]<<(7-j) for j in range(8)) for i in range(0,len(self.data),8))
        out=bytearray();zeros=0
        for byte in raw:
            if zeros>=2 and byte<=3:
                out.append(3);zeros=0
            out.append(byte);zeros=zeros+1 if byte==0 else 0
        return bytes(out)


def avcc(width,height):
    """Minimal baseline H.264 SPS/PPS with uncropped, frame-only 4:2:0 dimensions."""
    assert width%16==0 and height%16==0
    b=Bits();b.bits(66,8);b.bits(0,8);b.bits(30,8)  # profile/constraints/level
    b.ue(0);b.ue(0);b.ue(0);b.ue(0);b.ue(1);b.bit(0)
    b.ue(width//16-1);b.ue(height//16-1)
    b.bit(1);b.bit(1);b.bit(0);b.bit(0)
    sps=b'\x67'+b.rbsp();pps=bytes.fromhex('68ce0fc8')
    return (bytes([1,66,0,30,0xff,0xe1])+len(sps).to_bytes(2,'big')+sps+
            b'\x01'+len(pps).to_bytes(2,'big')+pps)


def tag(config,ts=0):
    body=b'\x17\x00\x00\x00\x00'+config;size=len(body)
    header=(b'\x09'+size.to_bytes(3,'big')+bytes([
        (ts>>16)&255,(ts>>8)&255,ts&255,(ts>>24)&255,0,0,0]))
    return header+body+(11+size).to_bytes(4,'big')


def flv(*tags):
    return b'FLV\x01\x05\x00\x00\x00\x09\x00\x00\x00\x00'+b''.join(tags)


class Response:
    def __init__(self,chunks):self.chunks=list(chunks);self.closed=False
    def raise_for_status(self):return None
    def iter_content(self):yield from self.chunks
    def close(self):self.closed=True


def manager():
    obj=manager_module.ManagedYouTube.__new__(manager_module.ManagedYouTube)
    obj.headers_for=lambda user:{}
    obj._unstable={};obj.starve={};obj._skip_probe_once={};obj._probe_note=''
    obj.logs=[];obj.log=lambda user,text:obj.logs.append(str(text))
    return obj


def candidate(width=432,height=864):
    return {'url':'https://media.example.test/live.flv','media':'flv','codec':'h264',
            'quality_name':'hd','label':'hd','brief':'hd H264','width':width,'height':height}


def probe_with(chunks,cand=None):
    obj=manager();responses=[]
    original=manager_module.requests.get
    def fake_get(*args,**kwargs):
        response=Response(chunks);responses.append(response);return response
    manager_module.requests.get=fake_get
    try:result=obj.probe('alice',cand or candidate())
    finally:manager_module.requests.get=original
    return result,responses


small=avcc(16,16);real=avcc(640,1280)
check('test SPS generator carries exact dimensions',
      video_dimensions('avc1',small)==(16,16) and video_dimensions('avc1',real)==(640,1280))

blob=flv(tag(real));chunks=[blob[i:i+7] for i in range(0,len(blob),7)]
result,responses=probe_with(chunks)
check('fragmented FLV probe returns actual decoder dimensions',
      isinstance(result,dict) and (result.get('width'),result.get('height'))==(640,1280),str(result))
check('FLV probe closes the source response',bool(responses) and responses[0].closed)

blob=flv(tag(small),tag(real));split=13+len(tag(small))
result,_=probe_with([blob[:split],blob[split:]])
check('sub-32px startup config is not accepted as the final canvas',
      isinstance(result,dict) and (result.get('width'),result.get('height'))==(640,1280),str(result))

result,responses=probe_with([b'FLV'])
check('signature-only FLV keeps the old truthy fallback',result is True,str(result))
check('signature-only fallback also closes the response',bool(responses) and responses[0].closed)
result,_=probe_with([b'NOT AN FLV'])
check('invalid FLV signature is still rejected',result is False,str(result))

obj=manager();obj.probe=lambda user,c:{'width':640,'height':1280,'codec':'avc1'}
selected=obj._select_source('alice',{'sources':[candidate()]})
check('source selection retains a usable candidate',len(selected)==1,str(selected))
if selected:
    chosen=selected[0]
    check('actual dimensions are attached without rewriting the rendition label',
          (chosen.get('width'),chosen.get('height'))==(432,864) and
          (chosen.get('probed_width'),chosen.get('probed_height'))==(640,1280) and
          obj._source_pin(chosen)==obj._source_pin(candidate()),str(chosen))
    sender=Sender('ffmpeg',lambda *args:None)
    check('matchgop locks the actual HD canvas instead of the stale SD label',
          sender.lock_gold(chosen)==(720,1280),str(sender.lock_gold(chosen)))
    check('a declared/probed mismatch is surfaced in operational logs',
          any('640x1280' in line and '432x864' in line for line in obj.logs),str(obj.logs))

fallback=Sender('ffmpeg',lambda *args:None)
check('without decoder metadata the old declared-canvas fallback is unchanged',
      fallback.lock_gold(candidate())==(432,864),str(fallback.lock_gold(candidate())))

print('source probe tests: %d passed, %d failed'%(passed,failed))
raise SystemExit(1 if failed else 0)