function ToWebM()

in spec-main/video-helpers.js [33:247]


function ToWebM (frames) {
  const info = checkFrames(frames);

  // max duration by cluster in milliseconds
  const CLUSTER_MAX_DURATION = 30000;

  const EBML = [
    {
      id: 0x1a45dfa3, // EBML
      data: [
        {
          data: 1,
          id: 0x4286 // EBMLVersion
        },
        {
          data: 1,
          id: 0x42f7 // EBMLReadVersion
        },
        {
          data: 4,
          id: 0x42f2 // EBMLMaxIDLength
        },
        {
          data: 8,
          id: 0x42f3 // EBMLMaxSizeLength
        },
        {
          data: 'webm',
          id: 0x4282 // DocType
        },
        {
          data: 2,
          id: 0x4287 // DocTypeVersion
        },
        {
          data: 2,
          id: 0x4285 // DocTypeReadVersion
        }
      ]
    },
    {
      id: 0x18538067, // Segment
      data: [
        {
          id: 0x1549a966, // Info
          data: [
            {
              data: 1e6, // do things in millisecs (num of nanosecs for duration scale)
              id: 0x2ad7b1 // TimecodeScale
            },
            {
              data: 'whammy',
              id: 0x4d80 // MuxingApp
            },
            {
              data: 'whammy',
              id: 0x5741 // WritingApp
            },
            {
              data: doubleToString(info.duration),
              id: 0x4489 // Duration
            }
          ]
        },
        {
          id: 0x1654ae6b, // Tracks
          data: [
            {
              id: 0xae, // TrackEntry
              data: [
                {
                  data: 1,
                  id: 0xd7 // TrackNumber
                },
                {
                  data: 1,
                  id: 0x73c5 // TrackUID
                },
                {
                  data: 0,
                  id: 0x9c // FlagLacing
                },
                {
                  data: 'und',
                  id: 0x22b59c // Language
                },
                {
                  data: 'V_VP8',
                  id: 0x86 // CodecID
                },
                {
                  data: 'VP8',
                  id: 0x258688 // CodecName
                },
                {
                  data: 1,
                  id: 0x83 // TrackType
                },
                {
                  id: 0xe0, // Video
                  data: [
                    {
                      data: info.width,
                      id: 0xb0 // PixelWidth
                    },
                    {
                      data: info.height,
                      id: 0xba // PixelHeight
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          id: 0x1c53bb6b, // Cues
          data: [
            // cue insertion point
          ]
        }

        // cluster insertion point
      ]
    }
  ];

  const segment = EBML[1];
  const cues = segment.data[2];

  // Generate clusters (max duration)
  let frameNumber = 0;
  let clusterTimecode = 0;
  while (frameNumber < frames.length) {
    const cuePoint = {
      id: 0xbb, // CuePoint
      data: [
        {
          data: Math.round(clusterTimecode),
          id: 0xb3 // CueTime
        },
        {
          id: 0xb7, // CueTrackPositions
          data: [
            {
              data: 1,
              id: 0xf7 // CueTrack
            },
            {
              data: 0, // to be filled in when we know it
              size: 8,
              id: 0xf1 // CueClusterPosition
            }
          ]
        }
      ]
    };

    cues.data.push(cuePoint);

    const clusterFrames = [];
    let clusterDuration = 0;
    do {
      clusterFrames.push(frames[frameNumber]);
      clusterDuration += frames[frameNumber].duration;
      frameNumber++;
    } while (frameNumber < frames.length && clusterDuration < CLUSTER_MAX_DURATION);

    let clusterCounter = 0;
    const cluster = {
      id: 0x1f43b675, // Cluster
      data: [
        {
          data: Math.round(clusterTimecode),
          id: 0xe7 // Timecode
        }
      ].concat(clusterFrames.map(function (webp) {
        const block = makeSimpleBlock({
          discardable: 0,
          frame: webp.data.slice(4),
          invisible: 0,
          keyframe: 1,
          lacing: 0,
          trackNum: 1,
          timecode: Math.round(clusterCounter)
        });
        clusterCounter += webp.duration;
        return {
          data: block,
          id: 0xa3
        };
      }))
    };

    // Add cluster to segment
    segment.data.push(cluster);
    clusterTimecode += clusterDuration;
  }

  // First pass to compute cluster positions
  let position = 0;
  for (let i = 0; i < segment.data.length; i++) {
    if (i >= 3) {
      cues.data[i - 3].data[1].data[1].data = position;
    }
    const data = generateEBML([segment.data[i]]);
    position += data.size || data.byteLength || data.length;
    if (i !== 2) { // not cues
      // Save results to avoid having to encode everything twice
      segment.data[i] = data;
    }
  }

  return generateEBML(EBML);
}