mp4-helpers.js 13.5 KB
/**
 * Helper functions for creating test MP4 data.
 */
'use strict';
var box, typeBytes, unityMatrix;

module.exports = {};

// ----------------------
// Box Generation Helpers
// ----------------------

module.exports.typeBytes = typeBytes = function(type) {
  return [
    type.charCodeAt(0),
    type.charCodeAt(1),
    type.charCodeAt(2),
    type.charCodeAt(3)
  ];
};

module.exports.box = box = function(type) {
  var
    array = Array.prototype.slice.call(arguments, 1),
    result = [],
    size,
    i;

  // "unwrap" any arrays that were passed as arguments
  // e.g. box('etc', 1, [2, 3], 4) -> box('etc', 1, 2, 3, 4)
  for (i = 0; i < array.length; i++) {
    if (array[i] instanceof Array) {
      array.splice.apply(array, [i, 1].concat(array[i]));
    }
  }

  size = 8 + array.length;

  result[0] = (size & 0xFF000000) >> 24;
  result[1] = (size & 0x00FF0000) >> 16;
  result[2] = (size & 0x0000FF00) >> 8;
  result[3] = size & 0xFF;
  result = result.concat(typeBytes(type));
  result = result.concat(array);
  return result;
};

module.exports.unityMatrix = unityMatrix = [
  0, 0, 0x10, 0,
  0, 0, 0, 0,
  0, 0, 0, 0,

  0, 0, 0, 0,
  0, 0, 0x10, 0,
  0, 0, 0, 0,

  0, 0, 0, 0,
  0, 0, 0, 0,
  0x40, 0, 0, 0
];

// ------------
// Example Data
// ------------

module.exports.sampleMoov =
  box('moov',
      box('mvhd',
          0x01, // version 1
          0x00, 0x00, 0x00, // flags
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x01, // creation_time
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x02, // modification_time
          0x00, 0x00, 0x03, 0xe8, // timescale = 1000
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
          0x00, 0x01, 0x00, 0x00, // 1.0 rate
          0x01, 0x00, // 1.0 volume
          0x00, 0x00, // reserved
          0x00, 0x00, 0x00, 0x00, // reserved
          0x00, 0x00, 0x00, 0x00, // reserved
          unityMatrix,
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, // pre_defined
          0x00, 0x00, 0x00, 0x02), // next_track_ID
      box('trak',
          box('tkhd',
              0x01, // version 1
              0x00, 0x00, 0x00, // flags
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x02, // creation_time
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x03, // modification_time
              0x00, 0x00, 0x00, 0x01, // track_ID
              0x00, 0x00, 0x00, 0x00, // reserved
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, // reserved
              0x00, 0x00, // layer
              0x00, 0x00, // alternate_group
              0x00, 0x00, // non-audio track volume
              0x00, 0x00, // reserved
              unityMatrix,
              0x01, 0x2c, 0x00, 0x00, // 300 in 16.16 fixed-point
              0x00, 0x96, 0x00, 0x00), // 150 in 16.16 fixed-point
          box('edts',
              box('elst',
                0x00, // version
                0x00, 0x00, 0x00, // flags
                0x00, 0x00, 0x00, 0x01, // entry_count
                0x00, 0x00, 0x00, 0x00, // segment_duration
                0x00, 0x00, 0x04, 0x00, // media_time
                0x00, 0x01, 0x80, 0x00)), // media_rate
          box('mdia',
              box('mdhd',
                  0x01, // version 1
                  0x00, 0x00, 0x00, // flags
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x02, // creation_time
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x03, // modification_time
                  0x00, 0x01, 0x5f, 0x90, // timescale = 90000
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
                  0x15, 0xc7, // 'eng' language
                  0x00, 0x00),
              box('hdlr',
                  0x01, // version 1
                  0x00, 0x00, 0x00, // flags
                  0x00, 0x00, 0x00, 0x00, // pre_defined
                  typeBytes('vide'), // handler_type
                  0x00, 0x00, 0x00, 0x00, // reserved
                  0x00, 0x00, 0x00, 0x00, // reserved
                  0x00, 0x00, 0x00, 0x00, // reserved
                  typeBytes('one'), 0x00), // name
              box('minf',
                  box('dinf',
                      box('dref',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          box('url ',
                              0x00, // version
                              0x00, 0x00, 0x01))), // flags
                  box('stbl',
                      box('stsd',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x00, // entry_count
                          box('avc1',
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00,             // box content
                            typeBytes('avcC'),      // codec profile type
                            0x00, 0x4d, 0x40, 0x0d)), // codec parameters
                      box('stts',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01, // sample_count
                          0x00, 0x00, 0x00, 0x01), // sample_delta
                      box('stsc',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x02, // first_chunk
                          0x00, 0x00, 0x00, 0x03, // samples_per_chunk
                          0x00, 0x00, 0x00, 0x01), // sample_description_index
                      box('stco',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01), // chunk_offset
                      box('stss',
                          0x00, // version 0
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01), // sync_sample
                      box('ctts',
                          0x00, // version 0
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01, // sample_count
                          0x00, 0x00, 0x00, 0x01))))), // sample_offset
      box('trak',
          box('tkhd',
              0x01, // version 1
              0x00, 0x00, 0x00, // flags
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x02, // creation_time
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x03, // modification_time
              0x00, 0x00, 0x00, 0x02, // track_ID
              0x00, 0x00, 0x00, 0x00, // reserved
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
              0x00, 0x00, 0x00, 0x00,
              0x00, 0x00, 0x00, 0x00, // reserved
              0x00, 0x00, // layer
              0x00, 0x00, // alternate_group
              0x00, 0x00, // non-audio track volume
              0x00, 0x00, // reserved
              unityMatrix,
              0x01, 0x2c, 0x00, 0x00, // 300 in 16.16 fixed-point
              0x00, 0x96, 0x00, 0x00), // 150 in 16.16 fixed-point
          box('edts',
              box('elst',
                  0x01, // version
                  0x00, 0x00, 0x00, // flags
                  0x00, 0x00, 0x00, 0x01, // entry_count
                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segment_duration
                  0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // media_time
                  0x00, 0x01, 0x80, 0x00)), // media_rate
          box('mdia',
              box('mdhd',
                  0x01, // version 1
                  0x00, 0x00, 0x00, // flags
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x02, // creation_time
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x00, 0x03, // modification_time
                  0x00, 0x01, 0x5f, 0x90, // timescale = 90000
                  0x00, 0x00, 0x00, 0x00,
                  0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
                  0x15, 0xc7, // 'eng' language
                  0x00, 0x00),
              box('hdlr',
                  0x01, // version 1
                  0x00, 0x00, 0x00, // flags
                  0x00, 0x00, 0x00, 0x00, // pre_defined
                  typeBytes('soun'), // handler_type
                  0x00, 0x00, 0x00, 0x00, // reserved
                  0x00, 0x00, 0x00, 0x00, // reserved
                  0x00, 0x00, 0x00, 0x00, // reserved
                  typeBytes('one'), 0x00), // name
              box('minf',
                  box('dinf',
                      box('dref',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          box('url ',
                              0x00, // version
                              0x00, 0x00, 0x01))), // flags
                  box('stbl',
                      box('stsd',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x00, // entry_count
                          box('mp4a',
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            typeBytes('esds'),      // codec profile type
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00, 0x00, // box content
                            0x00, 0x00, 0x00,       // box content
                            0x40, 0x0a,             // codec params
                            0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00,
                            0x00, 0x00, 0x00, 0x00)),           // codec params
                      box('stts',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01, // sample_count
                          0x00, 0x00, 0x00, 0x01), // sample_delta
                      box('stsc',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x02, // first_chunk
                          0x00, 0x00, 0x00, 0x03, // samples_per_chunk
                          0x00, 0x00, 0x00, 0x01), // sample_description_index
                      box('ctts',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01, // sample_count
                          0xff, 0xff, 0xff, 0xff), // sample_offset
                      box('stco',
                          0x01, // version 1
                          0x00, 0x00, 0x00, // flags
                          0x00, 0x00, 0x00, 0x01, // entry_count
                          0x00, 0x00, 0x00, 0x01)))))); // chunk_offset