123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573 |
- let _dtsBase;
- let _types = [];
- let datas = {};
- _types = {
- avc1: [], avcC: [], btrt: [], dinf: [],
- dref: [], esds: [], ftyp: [], hdlr: [],
- mdat: [], mdhd: [], mdia: [], mfhd: [],
- minf: [], moof: [], moov: [], mp4a: [],
- mvex: [], mvhd: [], sdtp: [], stbl: [],
- stco: [], stsc: [], stsd: [], stsz: [],
- stts: [], tfdt: [], tfhd: [], traf: [],
- trak: [], trun: [], trex: [], tkhd: [],
- vmhd: [], smhd: []
- };
- class MP4Remux {
- constructor() {
- }
- init() {
- for (let name in _types) {
- _types[name] = [
- name.charCodeAt(0),
- name.charCodeAt(1),
- name.charCodeAt(2),
- name.charCodeAt(3)
- ];
- }
- _dtsBase = 0;
- datas.FTYP = new Uint8Array([
- 0x69, 0x73, 0x6F, 0x6D, // major_brand: isom
- 0x0, 0x0, 0x0, 0x1, // minor_version: 0x01
- 0x69, 0x73, 0x6F, 0x6D, // isom
- 0x61, 0x76, 0x63, 0x31 // avc1
- ]);
- datas.STSD_PREFIX = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x01 // entry_count
- ]);
- datas.STTS = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00 // entry_count
- ]);
- datas.STSC = datas.STCO = datas.STTS;
- datas.STSZ = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00, // sample_size
- 0x00, 0x00, 0x00, 0x00 // sample_count
- ]);
- datas.HDLR_VIDEO = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00, // pre_defined
- 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide'
- 0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x56, 0x69, 0x64, 0x65,
- 0x6F, 0x48, 0x61, 0x6E,
- 0x64, 0x6C, 0x65, 0x72, 0x00 // name: VideoHandler
- ]);
- datas.HDLR_AUDIO = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00, // pre_defined
- 0x73, 0x6F, 0x75, 0x6E, // handler_type: 'soun'
- 0x00, 0x00, 0x00, 0x00, // reserved: 3 * 4 bytes
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x53, 0x6F, 0x75, 0x6E,
- 0x64, 0x48, 0x61, 0x6E,
- 0x64, 0x6C, 0x65, 0x72, 0x00 // name: SoundHandler
- ]);
- datas.DREF = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x0C, // entry_size
- 0x75, 0x72, 0x6C, 0x20, // type 'url '
- 0x00, 0x00, 0x00, 0x01 // version(0) + flags
- ]);
- // Sound media header
- datas.SMHD = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00 // balance(2) + reserved(2)
- ]);
- // video media header
- datas.VMHD = new Uint8Array([
- 0x00, 0x00, 0x00, 0x01, // version(0) + flags
- 0x00, 0x00, // graphicsmode: 2 bytes
- 0x00, 0x00, 0x00, 0x00, // opcolor: 3 * 2 bytes
- 0x00, 0x00
- ]);
- }
- initSegment(meta) {
- let ftyp = box(_types.ftyp, datas.FTYP);
- let moov = Moov(meta);
- let seg = new Uint8Array(ftyp.byteLength + moov.byteLength);
- seg.set(ftyp, 0);
- seg.set(moov, ftyp.byteLength);
- return seg;
- }
- mediaSegment(sequenceNumber, track, data) {
- let moof = Moof(sequenceNumber, track);
- let frameData = mdat(data);
- let seg = new Uint8Array(moof.byteLength + frameData.byteLength);
- seg.set(moof, 0);
- seg.set(frameData, moof.byteLength);
- return seg
- }
- }
- //组装initSegment
- function Moov(meta) {
- let mvhd = Mvhd(meta.timescale, meta.duration);
- let trak = Trak(meta);
- let mvex = Mvex(meta);
- return box(_types.moov, mvhd, trak, mvex);
- }
- //组装moov
- function Mvhd(timescale, duration) {
- return box(_types.mvhd, new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00, // creation_time
- 0x00, 0x00, 0x00, 0x00, // modification_time
- (timescale >>> 24) & 0xFF, // timescale: 4 bytes
- (timescale >>> 16) & 0xFF,
- (timescale >>> 8) & 0xFF,
- (timescale) & 0xFF,
- (duration >>> 24) & 0xFF, // duration: 4 bytes
- (duration >>> 16) & 0xFF,
- (duration >>> 8) & 0xFF,
- (duration) & 0xFF,
- 0x00, 0x01, 0x00, 0x00, // Preferred rate: 1.0
- 0x01, 0x00, 0x00, 0x00, // PreferredVolume(1.0, 2bytes) + reserved(2bytes)
- 0x00, 0x00, 0x00, 0x00, // reserved: 4 + 4 bytes
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x00, 0x00, 0x00, // ----end composition matrix----
- 0x00, 0x00, 0x00, 0x00, // ----begin pre_defined 6 * 4 bytes----
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // ----end pre_defined 6 * 4 bytes----
- 0xFF, 0xFF, 0xFF, 0xFF // next_track_ID
- ]));
- }
- function Trak(meta) {
- return box(_types.trak, Tkhd(meta), Mdia(meta));
- }
- function Mvex(meta) {
- return box(_types.mvex, trex(meta));
- }
- //组装trak
- function Tkhd(meta) {
- let trackId = meta.id;
- let duration = meta.duration;
- let width = meta.width;
- let height = meta.height;
- return box(_types.tkhd, new Uint8Array([
- 0x00, 0x00, 0x00, 0x07, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00, // creation_time
- 0x00, 0x00, 0x00, 0x00, // modification_time
- (trackId >>> 24) & 0xFF, // track_ID: 4 bytes
- (trackId >>> 16) & 0xFF,
- (trackId >>> 8) & 0xFF,
- (trackId) & 0xFF,
- 0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
- (duration >>> 24) & 0xFF, // duration: 4 bytes
- (duration >>> 16) & 0xFF,
- (duration >>> 8) & 0xFF,
- (duration) & 0xFF,
- 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // layer(2bytes) + alternate_group(2bytes)
- 0x00, 0x00, 0x00, 0x00, // volume(2bytes) + reserved(2bytes)
- 0x00, 0x01, 0x00, 0x00, // ----begin composition matrix----
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x40, 0x00, 0x00, 0x00, // ----end composition matrix----
- (width >>> 8) & 0xFF, // width and height
- (width) & 0xFF,
- 0x00, 0x00,
- (height >>> 8) & 0xFF,
- (height) & 0xFF,
- 0x00, 0x00
- ]));
- }
- function Mdia(meta) {
- return box(_types.mdia, mdhd(meta), hdlr(meta), minf(meta));
- }
- //组装mdia
- function mdhd(meta) {
- let timescale = meta.timescale;
- let duration = meta.duration;
- return box(_types.mdhd, new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- 0x00, 0x00, 0x00, 0x00, // creation_time
- 0x00, 0x00, 0x00, 0x00, // modification_time
- (timescale >>> 24) & 0xFF, // timescale: 4 bytes
- (timescale >>> 16) & 0xFF,
- (timescale >>> 8) & 0xFF,
- (timescale) & 0xFF,
- (duration >>> 24) & 0xFF, // duration: 4 bytes
- (duration >>> 16) & 0xFF,
- (duration >>> 8) & 0xFF,
- (duration) & 0xFF,
- 0x55, 0xC4, // language: und (undetermined)
- 0x00, 0x00 // pre_defined = 0
- ]));
- }
- function hdlr(meta) {
- let data = null;
- if (meta.type === 'audio') {
- data = datas.HDLR_AUDIO;
- } else {
- data = datas.HDLR_VIDEO;
- }
- return box(_types.hdlr, data);
- }
- function minf(meta) {
- let xmhd = null;
- if (meta.type === 'audio') {
- xmhd = box(_types.smhd, datas.SMHD);
- } else {
- xmhd = box(_types.vmhd, datas.VMHD);
- }
- return box(_types.minf, xmhd, dinf(), stbl(meta));
- }
- //组装minf
- function dinf() {
- return box(_types.dinf, box(_types.dref, datas.DREF));
- }
- function stbl(meta) {
- let result = box(_types.stbl, // type: stbl
- stsd(meta), // Sample Description Table
- box(_types.stts, datas.STTS), // Time-To-Sample
- box(_types.stsc, datas.STSC), // Sample-To-Chunk
- box(_types.stsz, datas.STSZ), // Sample size
- box(_types.stco, datas.STCO) // Chunk offset
- );
- return result;
- }
- //组装stbl
- function stsd(meta) {
- if (meta.type === 'audio') {
- return box(_types.stsd, datas.STSD_PREFIX, mp4a(meta));
- } else {
- return box(_types.stsd, datas.STSD_PREFIX, avc1(meta));
- }
- }
- //组装stsd
- function mp4a(meta) {
- let channelCount = meta.channelCount;
- let sampleRate = meta.audioSampleRate;
- let data = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // reserved(4)
- 0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
- 0x00, 0x00, 0x00, 0x00, // reserved: 2 * 4 bytes
- 0x00, 0x00, 0x00, 0x00,
- 0x00, channelCount, // channelCount(2)
- 0x00, 0x10, // sampleSize(2)
- 0x00, 0x00, 0x00, 0x00, // reserved(4)
- (sampleRate >>> 8) & 0xFF, // Audio sample rate
- (sampleRate) & 0xFF,
- 0x00, 0x00
- ]);
- return box(_types.mp4a, data, esds(meta));
- }
- function avc1(meta) {
- let width = meta.width;
- let height = meta.height;
- let sps = meta.sps || [], pps = meta.pps || [], sequenceParameterSets = [], pictureParameterSets = [];
- for (let i = 0; i < sps.length; i++) {
- sequenceParameterSets.push((sps[i].byteLength & 65280) >>> 8);
- sequenceParameterSets.push(sps[i].byteLength & 255);
- sequenceParameterSets = sequenceParameterSets.concat(Array.prototype.slice.call(sps[i]))
- }
- for (let i = 0; i < pps.length; i++) {
- pictureParameterSets.push((pps[i].byteLength & 65280) >>> 8);
- pictureParameterSets.push(pps[i].byteLength & 255);
- pictureParameterSets = pictureParameterSets.concat(Array.prototype.slice.call(pps[i]))
- }
- //Todo: 待测,如果视频有问题,修改这里
- // let data = new Uint8Array([
- // 0x00, 0x00, 0x00, 0x00, // reserved(4)
- // 0x00, 0x00, 0x00, 0x01, // reserved(2) + data_reference_index(2)
- // 0x00, 0x00, 0x00, 0x00, // pre_defined(2) + reserved(2)
- // 0x00, 0x00, 0x00, 0x00, // pre_defined: 3 * 4 bytes
- // 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00,
- // (width >>> 8) & 0xFF, // width: 2 bytes
- // (width) & 0xFF,
- // (height >>> 8) & 0xFF, // height: 2 bytes
- // (height) & 0xFF,
- // 0x00, 0x48, 0x00, 0x00, // horizresolution: 4 bytes
- // 0x00, 0x48, 0x00, 0x00, // vertresolution: 4 bytes
- // 0x00, 0x00, 0x00, 0x00, // reserved: 4 bytes
- // 0x00, 0x01, // frame_count
- // 0x0A, // strlen
- // 0x78, 0x71, 0x71, 0x2F, // compressorname: 32 bytes
- // 0x66, 0x6C, 0x76, 0x2E,
- // 0x6A, 0x73, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00, 0x00,
- // 0x00, 0x00, 0x00,
- // 0x00, 0x18, // depth
- // 0xFF, 0xFF // pre_defined = -1
- // ]);
- let data = new Uint8Array(
- [0, 0, 0, 0,
- 0, 0, 0, 1,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- (65280 & width) >> 8,
- 255 & width,
- (65280 & height) >> 8,
- 255 & height,
- 0, 72, 0, 0,
- 0, 72, 0, 0,
- 0, 0, 0, 0,
- 0, 1, 19, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 24, 17, 17]);
- return box(_types.avc1, data, box(_types.avcC, new Uint8Array([1, meta.profileIdc, meta.profileCompatibility, meta.levelIdc, 255].concat([sps.length]).concat(sequenceParameterSets).concat([pps.length]).concat(pictureParameterSets))));
- }
- //组装mp4a
- function esds(meta) {
- let config = meta.config;
- let configSize = config.length;
- let data = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version 0 + flags
- 0x03, // descriptor_type
- 0x17 + configSize, // length3
- 0x00, 0x01, // es_id
- 0x00, // stream_priority
- 0x04, // descriptor_type
- 0x0F + configSize, // length
- 0x40, // codec: mpeg4_audio
- 0x15, // stream_type: Audio
- 0x00, 0x00, 0x00, // buffer_size
- 0x00, 0x00, 0x00, 0x00, // maxBitrate
- 0x00, 0x00, 0x00, 0x00, // avgBitrate
- 0x05 // descriptor_type
- ].concat(
- [configSize]
- ).concat(
- config
- ).concat(
- [0x06, 0x01, 0x02] // GASpecificConfig
- ));
- return box(_types.esds, data);
- }
- //组装mvex
- function trex(meta) {
- var trackId = meta.id;
- var data = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // version(0) + flags
- (trackId >>> 24) & 0xFF, // track_ID
- (trackId >>> 16) & 0xFF,
- (trackId >>> 8) & 0xFF,
- (trackId) & 0xFF,
- 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
- 0x00, 0x00, 0x00, 0x00, // default_sample_duration
- 0x00, 0x00, 0x00, 0x00, // default_sample_size
- 0x00, 0x01, 0x00, 0x01 // default_sample_flags
- ]);
- return box(_types.trex, data);
- }
- //组装mediaSegment
- function Moof(sequenceNumber, track) {
- return box(_types.moof, mfhd(sequenceNumber), traf(track));
- }
- function mdat(data) {
- return box(_types.mdat, data);
- }
- //组装moof
- function mfhd(sequenceNumber) {
- var data = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00,
- (sequenceNumber >>> 24) & 0xFF, // sequence_number: int32
- (sequenceNumber >>> 16) & 0xFF,
- (sequenceNumber >>> 8) & 0xFF,
- (sequenceNumber) & 0xFF
- ]);
- return box(_types.mfhd, data);
- }
- function traf(track) {
- //console.log(track)
- var trackFragmentHeader = null, trackFragmentDecodeTime = null, trackFragmentRun = null, dataOffset = null;
- trackFragmentHeader = box(_types.tfhd, new Uint8Array([0, 2, 0, 0, 0, 0, 0, 1]));
- trackFragmentDecodeTime = box(_types.tfdt,
- new Uint8Array([
- 0, 0, 0, 0,
- track.baseMediaDecodeTime >>> 24 & 255,
- track.baseMediaDecodeTime >>> 16 & 255,
- track.baseMediaDecodeTime >>> 8 & 255,
- track.baseMediaDecodeTime & 255
- ]));
- dataOffset = 16 + 16 + 8 + 16 + 8 + 8;
- trackFragmentRun = trun(track, dataOffset);
- return box(_types.traf, trackFragmentHeader, trackFragmentDecodeTime, trackFragmentRun)
- }
- //组装traf
- function trun(track, offset) {
- if (track.type === "audio") {
- return audioTrun(track, offset)
- }
- return videoTrun(track, offset)
- }
- //组装trun
- function videoTrun(track, _offset) {
- var bytes = null, samples = null, sample = null, i = 0;
- var offset = _offset;
- samples = track.samples || [];
- if (samples[0].frameDuration === null) {
- offset += 8 + 12 + 4 + 4 * samples.length;
- bytes = trunHeader(samples, offset);
- for (i = 0; i < samples.length; i++) {
- sample = samples[i];
- bytes = bytes.concat([(sample.size & 4278190080) >>> 24, (sample.size & 16711680) >>> 16, (sample.size & 65280) >>> 8, sample.size & 255])
- }
- } else {
- offset += 8 + 12 + 4 + 4 * samples.length + 4 * samples.length;
- bytes = trunHeader1(samples, offset);
- for (i = 0; i < samples.length; i++) {
- sample = samples[i];
- bytes = bytes.concat([(sample.frameDuration & 4278190080) >>> 24, (sample.frameDuration & 16711680) >>> 16, (sample.frameDuration & 65280) >>> 8, sample.frameDuration & 255, (sample.size & 4278190080) >>> 24, (sample.size & 16711680) >>> 16, (sample.size & 65280) >>> 8, sample.size & 255])
- }
- }
- return box(_types.trun, new Uint8Array(bytes))
- }
- function audioTrun(track, _offset) {
- var bytes = null, samples = null, sample = null, i = 0;
- var offset = _offset;
- samples = track.samples || [];
- offset += 8 + 12 + 8 * samples.length;
- bytes = trunHeader(samples, offset);
- for (i = 0; i < samples.length; i++) {
- sample = samples[i];
- bytes = bytes.concat([(sample.duration & 4278190080) >>> 24, (sample.duration & 16711680) >>> 16, (sample.duration & 65280) >>> 8, sample.duration & 255, (sample.size & 4278190080) >>> 24, (sample.size & 16711680) >>> 16, (sample.size & 65280) >>> 8, sample.size & 255])
- }
- return box(_types.trun, new Uint8Array(bytes))
- }
- //组装videoTurn
- function trunHeader(samples, offset) {
- return [0, 0, 2, 5, (samples.length & 4278190080) >>> 24, (samples.length & 16711680) >>> 16, (samples.length & 65280) >>> 8, samples.length & 255, (offset & 4278190080) >>> 24, (offset & 16711680) >>> 16, (offset & 65280) >>> 8, offset & 255, 0, 0, 0, 0]
- }
- function trunHeader1(samples, offset) {
- return [0, 0, 3, 5, (samples.length & 4278190080) >>> 24, (samples.length & 16711680) >>> 16, (samples.length & 65280) >>> 8, samples.length & 255, (offset & 4278190080) >>> 24, (offset & 16711680) >>> 16, (offset & 65280) >>> 8, offset & 255, 0, 0, 0, 0]
- }
- /**
- *
- * @param type
- * @returns {Uint8Array}
- */
- function box(type, ...items) {
- let size = 8;
- //Todo: 测试一下这里
- //let arrs = Array.prototype.slice.call(arguments, 1);
- let arrs = [];
- arrs.push(...items);
- for (let i = 0; i < arrs.length; i++) {
- size += arrs[i].byteLength;
- }
- let data = new Uint8Array(size);
- let pos = 0;
- // set size
- data[pos++] = size >>> 24 & 0xFF;
- data[pos++] = size >>> 16 & 0xFF;
- data[pos++] = size >>> 8 & 0xFF;
- data[pos++] = size & 0xFF;
- // set type
- data.set(type, pos);
- pos += 4;
- // set data
- for (let i = 0; i < arrs.length; i++) {
- data.set(arrs[i], pos);
- pos += arrs[i].byteLength;
- }
- return data;
- }
- // let mp4Remux = new MP4Remux();
- // mp4Remux.init();
- export default MP4Remux;
|