nx_mp4_stbl.nx source
↩ module page · 99 lines · 4444 B
1// nx_mp4_stbl.nx -- MP4 sample-table reader (real-video bridge rung 1).
2// Descends a video track to stbl and reads: the CODEC (stsd first-entry fourCC),
3// the frame/sample COUNT (stsz), uniform sample size, and chunk count (stco).
4// This is the bridge between "there is a video track" (demux, rung 0) and the
5// coded frame byte ranges the codec decoder will consume (rung 2+).
6//
7// It NAMES the codec: avc1/avc3=H.264, hev1/hvc1=H.265, vp09=VP9, av01=AV1,
8// mp4a=AAC. Pointed at a real recording, this reports exactly what codec the
9// capture used -- the fact the decode arc must target. Reuses nx_mp4_demux
10// box primitives. ISO/IEC 14496-12 sec.8 (stbl/stsd/stsz/stco).
11//
12// genealogy_id: iso_bmff_sample_table + stsd_codec_identification
13// lineage_id: stbl_descent + fourcc_classify + sample_count
14// license_tier: ORIGINAL
15import "nx_syscalls.nx"
16import "nx_mp4_demux.nx"
17
18const NX_CODEC_OTHER: i64 = 0
19const NX_CODEC_H264: i64 = 1
20const NX_CODEC_H265: i64 = 2
21const NX_CODEC_VP9: i64 = 3
22const NX_CODEC_AV1: i64 = 4
23const NX_CODEC_AAC: i64 = 5
24
25func nx_mp4_codec_class(b: *u8, o: i64) -> i64 {
26 if mp4_t4(b, o, "avc1\x00" as *u8) == 1 { return NX_CODEC_H264 }
27 if mp4_t4(b, o, "avc3\x00" as *u8) == 1 { return NX_CODEC_H264 }
28 if mp4_t4(b, o, "hev1\x00" as *u8) == 1 { return NX_CODEC_H265 }
29 if mp4_t4(b, o, "hvc1\x00" as *u8) == 1 { return NX_CODEC_H265 }
30 if mp4_t4(b, o, "vp09\x00" as *u8) == 1 { return NX_CODEC_VP9 }
31 if mp4_t4(b, o, "av01\x00" as *u8) == 1 { return NX_CODEC_AV1 }
32 if mp4_t4(b, o, "mp4a\x00" as *u8) == 1 { return NX_CODEC_AAC }
33 return NX_CODEC_OTHER
34}
35
36// Parse stbl children within [start,end): out[0]=codec_class out[1]=sample_count
37// out[2]=uniform_sample_size out[3]=chunk_count out[4]=fourcc_offset.
38func nx_mp4_parse_stbl(b: *u8, start: i64, end: i64, out: *i64) -> i64 {
39 out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0
40 let r: *i64 = sys_mmap(32) as *i64
41 if mp4_find_box(b, start, end, "stsd\x00" as *u8, r) == 1 {
42 out[4] = r[0] + 12
43 out[0] = nx_mp4_codec_class(b, r[0] + 12)
44 }
45 let r2: *i64 = sys_mmap(32) as *i64
46 if mp4_find_box(b, start, end, "stsz\x00" as *u8, r2) == 1 {
47 out[2] = mp4_be32(b, r2[0] + 4)
48 out[1] = mp4_be32(b, r2[0] + 8)
49 }
50 let r3: *i64 = sys_mmap(32) as *i64
51 if mp4_find_box(b, start, end, "stco\x00" as *u8, r3) == 1 {
52 out[3] = mp4_be32(b, r3[0] + 4)
53 }
54 return 0
55}
56
57// Find the first VIDEO track and parse its stbl into out (same layout as
58// nx_mp4_parse_stbl). Returns 1 if a video track with stbl was found, else 0.
59func nx_mp4_video_info(b: *u8, len: i64, out: *i64) -> i64 {
60 out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0
61 let r: *i64 = sys_mmap(32) as *i64
62 if mp4_find_box(b, 0, len, "moov\x00" as *u8, r) == 0 { return 0 }
63 let ms: i64 = r[0]
64 let me: i64 = r[1]
65 var pos: i64 = ms
66 while pos + 8 <= me {
67 var sz: i64 = mp4_be32(b, pos)
68 var hdr: i64 = 8
69 if sz == 1 { if pos + 16 <= me { sz = mp4_be64(b, pos + 8); hdr = 16 } }
70 if sz == 0 { sz = me - pos }
71 if sz < hdr { pos = me }
72 if sz >= hdr {
73 if mp4_t4(b, pos + 4, "trak\x00" as *u8) == 1 {
74 let ts: i64 = pos + hdr
75 let te: i64 = pos + sz
76 let m: *i64 = sys_mmap(32) as *i64
77 if mp4_find_box(b, ts, te, "mdia\x00" as *u8, m) == 1 {
78 let h: *i64 = sys_mmap(32) as *i64
79 if mp4_find_box(b, m[0], m[1], "hdlr\x00" as *u8, h) == 1 {
80 if mp4_t4(b, h[0] + 8, "vide\x00" as *u8) == 1 {
81 let mi: *i64 = sys_mmap(32) as *i64
82 if mp4_find_box(b, m[0], m[1], "minf\x00" as *u8, mi) == 1 {
83 let st: *i64 = sys_mmap(32) as *i64
84 if mp4_find_box(b, mi[0], mi[1], "stbl\x00" as *u8, st) == 1 {
85 nx_mp4_parse_stbl(b, st[0], st[1], out)
86 out[5] = st[0] // stbl payload range (for sample0 locate)
87 out[6] = st[1]
88 return 1
89 }
90 }
91 }
92 }
93 }
94 }
95 pos = pos + sz
96 }
97 }
98 return 0
99}