diff --git a/dist/bundles/mediabunny.cjs b/dist/bundles/mediabunny.cjs index 88cfade7e364dd2b4a2943166642b8e82515a9b0..bf3919b0df74d333f4b024e2795473078be55787 100644 --- a/dist/bundles/mediabunny.cjs +++ b/dist/bundles/mediabunny.cjs @@ -29027,9 +29027,17 @@ var Mediabunny = (() => { stsc(trackData), stsz(trackData), stco(trackData), - stss(trackData) + stss(trackData), + ...aacRollGroup(trackData) ]); }; + var aacRollGroup = (trackData) => { + if (trackData.type !== "audio" || trackData.track.source._codec !== "aac" || trackData.samples.length === 0) return []; + return [ + fullBox("sgpd", 1, 0, [ascii("roll"), u32(2), u32(1), i16(-1)]), + fullBox("sbgp", 0, 0, [ascii("roll"), u32(1), u32(trackData.samples.length), u32(1)]) + ]; + }; var stsd = (trackData) => { let sampleDescription; if (trackData.type === "video") { diff --git a/dist/bundles/mediabunny.mjs b/dist/bundles/mediabunny.mjs index a8a6e969ec0fc1c919ac1f140c5fc24a6ed5080f..08555c15888b64bfaba2a4429a9c2fa24146f16b 100644 --- a/dist/bundles/mediabunny.mjs +++ b/dist/bundles/mediabunny.mjs @@ -28870,9 +28870,17 @@ var stbl = (trackData) => { stsc(trackData), stsz(trackData), stco(trackData), - stss(trackData) + stss(trackData), + ...aacRollGroup(trackData) ]); }; +var aacRollGroup = (trackData) => { + if (trackData.type !== "audio" || trackData.track.source._codec !== "aac" || trackData.samples.length === 0) return []; + return [ + fullBox("sgpd", 1, 0, [ascii("roll"), u32(2), u32(1), i16(-1)]), + fullBox("sbgp", 0, 0, [ascii("roll"), u32(1), u32(trackData.samples.length), u32(1)]) + ]; +}; var stsd = (trackData) => { let sampleDescription; if (trackData.type === "video") { diff --git a/dist/bundles/mediabunny.node.cjs b/dist/bundles/mediabunny.node.cjs index caaf0c6e1112bedfd57314cc12645267517db57d..3a53c9d1da8ae5ac7cd27766e9f086d155b3cbd0 100644 --- a/dist/bundles/mediabunny.node.cjs +++ b/dist/bundles/mediabunny.node.cjs @@ -29030,9 +29030,17 @@ var Mediabunny = (() => { stsc(trackData), stsz(trackData), stco(trackData), - stss(trackData) + stss(trackData), + ...aacRollGroup(trackData) ]); }; + var aacRollGroup = (trackData) => { + if (trackData.type !== "audio" || trackData.track.source._codec !== "aac" || trackData.samples.length === 0) return []; + return [ + fullBox("sgpd", 1, 0, [ascii("roll"), u32(2), u32(1), i16(-1)]), + fullBox("sbgp", 0, 0, [ascii("roll"), u32(1), u32(trackData.samples.length), u32(1)]) + ]; + }; var stsd = (trackData) => { let sampleDescription; if (trackData.type === "video") { diff --git a/dist/modules/src/isobmff/isobmff-boxes.js b/dist/modules/src/isobmff/isobmff-boxes.js index efb916401ee1450ea8f52899233c93b44925319b..4bbfeec4dac43693e2bd677a92d7cb8c2be9b6c9 100644 --- a/dist/modules/src/isobmff/isobmff-boxes.js +++ b/dist/modules/src/isobmff/isobmff-boxes.js @@ -549,6 +549,7 @@ export const stbl = (trackData) => { stsz(trackData), stco(trackData), stss(trackData), + ...aacRollGroup(trackData), ]); }; /** @@ -976,6 +977,18 @@ export const stts = (trackData) => { ]), ]); }; +/** + * AAC roll sample group (roll distance -1, every sample). Without it AVFoundation trims the encoder priming on its own + * as well as through the edit list, so Apple players start 2112 frames into the audio. + */ +export const aacRollGroup = (trackData) => { + if (trackData.type !== 'audio' || trackData.track.source._codec !== 'aac' || trackData.samples.length === 0) + return []; + return [ + fullBox('sgpd', 1, 0, [ascii('roll'), u32(2), u32(1), i16(-1)]), + fullBox('sbgp', 0, 0, [ascii('roll'), u32(1), u32(trackData.samples.length), u32(1)]), + ]; +}; /** Sync Sample Box: Identifies the key frames in the media, marking the random access points within a stream. */ export const stss = (trackData) => { if (trackData.samples.every(x => x.type === 'key'))