code wiki / _hdl_build / nx_dash_parse.nx
nx_dash_parse.nx source
↩ module page · 141 lines · 6800 B
1// nx_dash_parse.nx -- MPEG-DASH (.mpd) manifest -> segment URL list, the DASH parallel to nx_hls_parse (so
2// the sniffer's `.mpd` route can go from "dash-todo" to a real download: expand -> fetch each -> concat, same
3// shape as nx_hls_get). Scope v1 = the DOMINANT case: SegmentTemplate with $RepresentationID$/$Number$ + a
4// SegmentTimeline (VOD). Picks the highest-bandwidth video Representation. SegmentList / SegmentBase / $Time$
5// / multi-Period = later rungs (declined cleanly = 0 segments). license_tier: ORIGINAL
6import "nx_syscalls.nx"
7
8func dp_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
9// find `needle` in hay[from..hl); return index or -1.
10func dp_find(hay: *u8, hl: i64, needle: *u8, nl: i64, from: i64) -> i64 {
11 if nl == 0 { return from }
12 var i: i64 = from
13 let last: i64 = hl - nl
14 while i <= last { var j: i64 = 0; var m: i64 = 1; while j < nl { if (hay[i+j]&0xff) != (needle[j]&0xff) { m=0; j=nl } else { j=j+1 } } if m==1 { return i } i=i+1 }
15 return 0 - 1
16}
17// extract attr="value" scanning the tag that starts at tagstart (bounded by the next '>'); copy value to out.
18// Returns value length or -1 if the attr is absent in this tag.
19func dp_attr(xml: *u8, xl: i64, tagstart: i64, attr: *u8, out: *u8, cap: i64) -> i64 {
20 // tag end = next '>'
21 var te: i64 = tagstart
22 var fe: i64 = 0
23 while fe == 0 { if te >= xl { fe = 1 } else { if (xml[te]&0xff) == 62 { fe = 1 } else { te = te + 1 } } }
24 let al: i64 = dp_slen(attr)
25 // look for attr=" inside [tagstart, te)
26 let key: *u8 = sys_mmap(al + 4)
27 var k: i64 = 0
28 while k < al { key[k] = attr[k]; k = k + 1 }
29 key[al] = 61 as u8; key[al+1] = 34 as u8; key[al+2] = 0 as u8 // attr="
30 let pos: i64 = dp_find(xml, te, key, al + 2, tagstart)
31 if pos < 0 { return 0 - 1 }
32 var s: i64 = pos + al + 2
33 var w: i64 = 0
34 var go: i64 = 1
35 while go == 1 {
36 if s >= te { go = 0 }
37 else { if (xml[s]&0xff) == 34 { go = 0 } else { if w < (cap-1) { out[w] = xml[s]; w = w + 1 } s = s + 1 } }
38 }
39 out[w] = 0 as u8
40 return w
41}
42func dp_atoi(s: *u8, n: i64) -> i64 { var v: i64=0; var i: i64=0; while i<n { let c: i64=s[i]&0xff; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v }
43func dp_putn(dst: *u8, off: i64, v: i64) -> i64 { var m: i64=v; if m==0 { dst[off]=48 as u8; return off+1 } let t: *u8=sys_mmap(24); var k: i64=0; while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } var j: i64=0; while j<k { dst[off]=t[k-1-j]; off=off+1; j=j+1 } return off }
44// does `lit` (litlen bytes) sit EXACTLY at s[pos]?
45func dp_at(s: *u8, sl: i64, pos: i64, lit: *u8, litlen: i64) -> i64 {
46 if (pos + litlen) > sl { return 0 }
47 var j: i64 = 0
48 while j < litlen { if (s[pos + j] & 0xff) != (lit[j] & 0xff) { return 0 } j = j + 1 }
49 return 1
50}
51// substitute $RepresentationID$ -> id and $Number$ -> num into template; write to out; return length.
52func dp_subst(tmpl: *u8, tl: i64, id: *u8, idl: i64, num: i64, out: *u8, cap: i64) -> i64 {
53 var o: i64 = 0
54 var i: i64 = 0
55 while i < tl {
56 if dp_at(tmpl, tl, i, "$RepresentationID$" as *u8, 18) == 1 { var a: i64=0; while a<idl { if o<(cap-1) { out[o]=id[a]; o=o+1 } a=a+1 } i=i+18 }
57 else { if dp_at(tmpl, tl, i, "$Number$" as *u8, 8) == 1 { o = dp_putn(out, o, num); i=i+8 }
58 else { if o<(cap-1) { out[o]=tmpl[i]; o=o+1 } i=i+1 } }
59 }
60 out[o] = 0 as u8
61 return o
62}
63
64// Parse `mpd` -> newline-separated segment URLs (init first, then media segments) into `out`. Returns the
65// segment COUNT (incl init), or 0 if the manifest isn't a SegmentTemplate+SegmentTimeline DASH we handle.
66func dash_parse(mpd: *u8, ml: i64, out: *u8, cap: i64) -> i64 {
67 // pick the highest-bandwidth <Representation ...> tag
68 var best_pos: i64 = 0 - 1
69 var best_bw: i64 = 0 - 1
70 var scan: i64 = 0
71 var go1: i64 = 1
72 let bwbuf: *u8 = sys_mmap(32)
73 while go1 == 1 {
74 let rp: i64 = dp_find(mpd, ml, "<Representation" as *u8, 15, scan)
75 if rp < 0 { go1 = 0 }
76 else {
77 let bl: i64 = dp_attr(mpd, ml, rp, "bandwidth" as *u8, bwbuf, 32)
78 var bw: i64 = 0
79 if bl > 0 { bw = dp_atoi(bwbuf, bl) }
80 if bw > best_bw { best_bw = bw; best_pos = rp }
81 scan = rp + 15
82 }
83 }
84 if best_pos < 0 { return 0 }
85 // Representation@id
86 let idbuf: *u8 = sys_mmap(256)
87 let idl: i64 = dp_attr(mpd, ml, best_pos, "id" as *u8, idbuf, 256)
88 // the SegmentTemplate after this Representation
89 let st: i64 = dp_find(mpd, ml, "<SegmentTemplate" as *u8, 16, best_pos)
90 if st < 0 { return 0 }
91 let media: *u8 = sys_mmap(1024); let medial: i64 = dp_attr(mpd, ml, st, "media" as *u8, media, 1024)
92 let initt: *u8 = sys_mmap(1024); let initl: i64 = dp_attr(mpd, ml, st, "initialization" as *u8, initt, 1024)
93 let snbuf: *u8 = sys_mmap(32); let snl: i64 = dp_attr(mpd, ml, st, "startNumber" as *u8, snbuf, 32)
94 var startn: i64 = 1
95 if snl > 0 { startn = dp_atoi(snbuf, snl) }
96 if medial <= 0 { return 0 }
97 // segment count from the SegmentTimeline: sum (r+1) over each <S ... r="R" (r defaults 0)
98 var segcount: i64 = 0
99 let tl: i64 = dp_find(mpd, ml, "<SegmentTimeline" as *u8, 16, st)
100 if tl >= 0 {
101 let tlend: i64 = dp_find(mpd, ml, "</SegmentTimeline" as *u8, 17, tl)
102 var send: i64 = tlend; if tlend < 0 { send = ml }
103 var sp: i64 = tl
104 var go2: i64 = 1
105 let rbuf: *u8 = sys_mmap(32)
106 while go2 == 1 {
107 let sq: i64 = dp_find(mpd, send, "<S " as *u8, 3, sp)
108 if sq < 0 { go2 = 0 }
109 else {
110 var rep: i64 = 0
111 let rl: i64 = dp_attr(mpd, send, sq, "r" as *u8, rbuf, 32)
112 if rl > 0 { rep = dp_atoi(rbuf, rl) }
113 segcount = segcount + rep + 1
114 sp = sq + 3
115 }
116 }
117 }
118 if segcount <= 0 { return 0 }
119 // emit: init URL first, then media segments startn..startn+segcount-1
120 var o: i64 = 0
121 var count: i64 = 0
122 if initl > 0 {
123 let ib: *u8 = sys_mmap(2048)
124 let iln: i64 = dp_subst(initt, initl, idbuf, idl, 0, ib, 2048)
125 var a: i64 = 0; while a < iln { if o < (cap-2) { out[o] = ib[a]; o = o + 1 } a = a + 1 }
126 if o < (cap-2) { out[o] = 10 as u8; o = o + 1 }
127 count = count + 1
128 }
129 var n: i64 = 0
130 let mb: *u8 = sys_mmap(2048)
131 while n < segcount {
132 let num: i64 = startn + n
133 let mln: i64 = dp_subst(media, medial, idbuf, idl, num, mb, 2048)
134 var a2: i64 = 0; while a2 < mln { if o < (cap-2) { out[o] = mb[a2]; o = o + 1 } a2 = a2 + 1 }
135 if o < (cap-2) { out[o] = 10 as u8; o = o + 1 }
136 count = count + 1
137 n = n + 1
138 }
139 out[o] = 0 as u8
140 return count
141}