code wiki / (root) / nx_mp4_stbl.nx

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}