nx_mp4_es.nx source
↩ module page · 84 lines · 3604 B
1// nx_mp4_es.nx -- ISO-BMFF -> H.264 elementary-stream helpers, the mp4 counterpart of
2// nx_ts_es.nx. WHY: the full mp4-to-pixels chain already existed inside nx_h264_decode_frame
3// (proven FULL-FRAME Y+U+V BIT-EXACT vs ffmpeg on a real 45MB corpus recording), but it was
4// reachable only through that one organ. In the corpus poster sweep the refusals were 386
5// unsupported_container vs 121 cabac_skipped, so the container share is the LARGER unblocked
6// half and it needs no normative tables -- only a callable entry point.
7// mes_find_tag -- locate a box by 4CC, returning the box start
8// mes_spspps -- SPS/PPS from avcC, unescaped, ready for the h264 parsers
9// mes_first_idr -- the first IDR NAL of sample 0, ready for nx_h264_decode_iframe
10// license_tier: ORIGINAL
11import "nx_syscalls.nx"
12import "nx_mp4_demux.nx"
13import "nx_mp4_stbl.nx"
14import "nx_h264_nal.nx"
15
16const MES_NALCAP: i64 = 256
17
18// locate a box by 4CC; returns the offset of the box START (size field), or -1
19func mes_find_tag(b: *u8, start: i64, end: i64, s: *u8) -> i64 {
20 var i: i64 = start
21 while i + 4 <= end {
22 if mp4_t4(b, i, s) == 1 { return i - 4 }
23 i = i + 1
24 }
25 return 0 - 1
26}
27
28// Extract SPS and PPS from avcC into caller buffers, unescaped (RBSP).
29// Returns 1 on success, 0 if avcC is absent. spslen/ppslen receive the RBSP lengths.
30func mes_spspps(b: *u8, len: i64, spsdst: *u8, ppsdst: *u8, spslen: *i64, ppslen: *i64) -> i64 {
31 let avcc: i64 = mes_find_tag(b, 0, len, "avcC\x00" as *u8)
32 if avcc < 0 { return 0 }
33 let pay: i64 = avcc + 8
34 if pay + 8 > len { return 0 }
35 let sl: i64 = (b[pay + 6] as i64) * 256 + (b[pay + 7] as i64)
36 if sl <= 1 { return 0 }
37 if pay + 9 + sl > len { return 0 }
38 spslen[0] = nx_h264_unescape_rbsp((b as i64 + pay + 9) as *u8, sl - 1, spsdst)
39 let pp: i64 = pay + 8 + sl
40 if pp + 3 > len { return 0 }
41 let pl: i64 = (b[pp + 1] as i64) * 256 + (b[pp + 2] as i64)
42 if pl <= 1 { return 0 }
43 if pp + 4 + pl > len { return 0 }
44 ppslen[0] = nx_h264_unescape_rbsp((b as i64 + pp + 4) as *u8, pl - 1, ppsdst)
45 return 1
46}
47
48// Locate sample 0 and return the first IDR (nal type 5) NAL into dst.
49// Returns the NAL length, or 0 if none found / structure unreadable.
50func mes_first_idr(b: *u8, len: i64, dst: *u8, cap: i64) -> i64 {
51 let vi: *i64 = sys_mmap(64) as *i64
52 if nx_mp4_video_info(b, len, vi) == 0 { return 0 }
53 let s0: i64 = vi[5]
54 let s1: i64 = vi[6]
55 if s1 <= s0 { return 0 }
56 let rco: *i64 = sys_mmap(16) as *i64
57 let rsz: *i64 = sys_mmap(16) as *i64
58 if mp4_find_box(b, s0, s1, "stco\x00" as *u8, rco) == 0 { return 0 }
59 if mp4_find_box(b, s0, s1, "stsz\x00" as *u8, rsz) == 0 { return 0 }
60 let chunk0: i64 = mp4_be32(b, rco[0] + 8)
61 let ssf: i64 = mp4_be32(b, rsz[0] + 4)
62 var samp0: i64 = ssf
63 if ssf == 0 { samp0 = mp4_be32(b, rsz[0] + 12) }
64 if samp0 <= 0 { return 0 }
65 if chunk0 + samp0 > len { return 0 }
66 let offs: *i64 = sys_mmap(MES_NALCAP * 8) as *i64
67 let types: *i64 = sys_mmap(MES_NALCAP * 8) as *i64
68 let nc: i64 = nx_nal_split_avcc(b, chunk0, chunk0 + samp0, 4, offs, types, MES_NALCAP)
69 var i: i64 = 0
70 while i < nc {
71 if types[i] == 5 {
72 var end: i64 = chunk0 + samp0
73 if i + 1 < nc { end = offs[i+1] - 4 }
74 let n: i64 = end - offs[i]
75 if n <= 0 { return 0 }
76 if n > cap { return 0 }
77 var k: i64 = 0
78 while k < n { dst[k] = b[offs[i] + k]; k = k + 1 }
79 return n
80 }
81 i = i + 1
82 }
83 return 0
84}