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}