mp4.html 9.34 KB
<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title></title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width">

  <link rel="stylesheet" href="css/normalize.min.css">
  <link rel="stylesheet" href="css/main.css">

  <script src="js/vendor/modernizr-2.6.2.min.js"></script>
</head>
<body>
  <!--[if lt IE 7]>
      <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
      <![endif]-->

  <div class="header-container">
    <header class="wrapper clearfix">
      <h1 class="title">Transmux Analyzer</h1>
    </header>
  </div>

  <div class="main-container">
    <div class="main wrapper clearfix">

      <article>
        <header>
          <p>
            This page can help you inspect the results of the
            transmuxing to mp4 files performed by
            videojs-contrib-hls. It's still a bit tricky to create a
            MSE-compatible fragmented MP4. We've had luck
            with <a href="http://www.bento4.com/developers/dash/">Bento4</a>
            and ffmpeg. If you have both of those utilities installed,
            you can create a working MP4 like this:
            <pre>
ffmpeg -i movie.ts -vn -codec copy -absf aac_adtstoasc movie-audio.mp4
mp4fragment --track audio --fragment-duration 11000 movie-audio.mp4 movie-audio.m4s
            </pre>
          <small>Looking for the <a href="index.html">FLV tool</a>?</small>
        </header>
        <section>
          <h2>Inputs</h2>
          <form id="inputs">
            <label>
              Your original MP2T segment:
              <input type="file" id="original">
            </label>
            <label>
              A working, MP4 version of the underlying stream
              produced by another tool:
              <input type="file" id="working">
            </label>
          </form>
        </section>
        <section>
          <h2>Comparision</h2>
          <div id="comparison">
            A diff of the structure of the two MP4s will appear here
            once you've specified an input TS file and a known working
            MP4.
          </div>
        </section>
        <section>
          <h2>Structure</h2>
          <div class="result-wrapper">
            <h3>videojs-contrib-hls</h3>
            <pre class="vjs-boxes">
            </pre>
          </div>
          <div class="result-wrapper">
            <h3>Working</h3>
            <pre class="working-boxes"></pre>
          </div>
        </section>
        <section>
          <h2>Results</h2>
          <div class="result-wrapper">
            <h3>videojs-contrib-hls</h3>
            <div class="vjs-hls-output result">
              <p>
                The results of transmuxing your input file with
                videojs-contrib-hls will show up here.
              </p>
            </div>
          </div>
          <div class="result-wrapper">
            <h3>Working</h3>
            <div class="working-output result">
              <p>
                The "good" version of the file will show up here.
              </p>
            </div>
          </div>
        </section>
      </article>

    </div> <!-- #main -->
  </div> <!-- #main-container -->

  <div class="footer-container">
    <footer class="wrapper">
      <h3>footer</h3>
    </footer>
  </div>


  <script>
    window.videojs = window.videojs || {
      Hls: {}
    };
  </script>
  <script src="../../src/stream.js"></script>
  <script src="../../src/mp4-generator.js"></script>
  <script src="../../src/transmuxer.js"></script>
  <script src="../../src/flv-tag.js"></script>
  <script src="../../src/exp-golomb.js"></script>
  <script src="js/mp4-inspector.js"></script>

  <script src="../../src/bin-utils.js"></script>

  <!-- Include QUnit for object diffs -->
  <script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
  <script>
    var inputs = document.getElementById('inputs'),
        original = document.getElementById('original'),
        working = document.getElementById('working'),

        vjsParsed,
        workingParsed,
        diffParsed,
        vjsBytes,
        workingBytes,

        vjsBoxes = document.querySelector('.vjs-boxes'),
        workingBoxes = document.querySelector('.working-boxes'),

        vjsOutput = document.querySelector('.vjs-hls-output'),
        workingOutput = document.querySelector('.working-output'),

        video = document.createElement('video'),
        mediaSource = new MediaSource(),
        FlvTag = videojs.Hls.FlvTag;

        logevent = function(event) {
          console.log(event.type);
        };

    // output a diff of the two parsed MP4s
    diffParsed = function() {
      var comparison, diff, transmuxed;
      if (!vjsParsed || !workingParsed) {
        // wait until both inputs have been provided
        return;
      }
      comparison = document.querySelector('#comparison');
      if (workingParsed[0].type === 'moof') {
        diff = '<h3>Media Segment Comparision</h3>';
        transmuxed = vjsParsed.slice(2);
      } else if (workingParsed.length === 2) {
        diff = '<h3>Init Segment Comparision</h3>';
        transmuxed = vjsParsed.slice(0, 2);
      } else {
        diff = '<h3>General Comparision</h3>';
        transmuxed = vjsParsed;
      }
      diff += '<p>A <del>red background</del> indicates ' +
        'properties present in the transmuxed file but missing from the ' +
        'working version. A <ins>green background</ins> indicates ' +
        'properties present in the working version but missing in the ' +
        'transmuxed output.</p>';
      diff += '<pre class="mp4-diff">' +
        QUnit.diff(videojs.textifyMp4(transmuxed, null, ' '),
                   videojs.textifyMp4(workingParsed, null, ' ')) +
        '</pre>';

      comparison.innerHTML = diff;
    };

    mediaSource.addEventListener('sourceopen', function() {
      var
        // buffer = mediaSource.addSourceBuffer('video/mp4;codecs=avc1.4d400d');
        buffer = mediaSource.addSourceBuffer('audio/mp4;codecs=mp4a.40.2');
      buffer.addEventListener('updatestart', logevent);
      buffer.addEventListener('updateend', logevent);
      buffer.addEventListener('error', logevent);
      window.vjsMediaSource = mediaSource;
      window.vjsSourceBuffer = buffer;
      window.vjsVideo = video;
    });
    mediaSource.addEventListener('error', logevent);
    mediaSource.addEventListener('opened', logevent);
    mediaSource.addEventListener('closed', logevent);
    mediaSource.addEventListener('sourceended', logevent);
    video.src = URL.createObjectURL(mediaSource);
    video.addEventListener('error', console.log.bind(console));


    videojs.log = console.log.bind(console);

    original.addEventListener('change', function() {
      var reader = new FileReader(),
        videoSegments= [],
        audioSegments = [],
        videoBuffer = [],
        audioBuffer = [];

      reader.addEventListener('loadend', function() {
        var segment = new Uint8Array(reader.result),
            transmuxer = new videojs.mp2t.Transmuxer(),
            events = [],
            bytesLength = 0,
            bytes,
            i, j,
            hex = '';

        transmuxer.on('data', function(data) {
          if (data && data.type === 'audio') {
            events.push(data.data);
            bytesLength += data.data.byteLength;
          }
        });
        transmuxer.push(segment);
        transmuxer.end();

        bytes = new Uint8Array(bytesLength);
        for (j = 0, i = 0; j < events.length; j++) {
          bytes.set(events[j], i);
          i += events[j].byteLength;
        }

        vjsBytes = bytes;
        vjsParsed = videojs.inspectMp4(bytes);
        console.log('transmuxed', vjsParsed);
        diffParsed();

        // clear old box info
        vjsBoxes.innerHTML = videojs.textifyMp4(vjsParsed, null, ' ');

        // write out the result
        hex += '<pre>';
        hex += 'nothing to see here';
        hex += '</pre>';
        vjsOutput.innerHTML = hex;

        // XXX Media Sources Testing
        //window.vjsSourceBuffer.appendBuffer(bytes);
      });
      reader.readAsArrayBuffer(this.files[0]);
    }, false);

    working.addEventListener('change', function() {
      var reader = new FileReader();
      reader.addEventListener('loadend', function() {
        var hex = '',
            bytes = new Uint8Array(reader.result);


        workingBytes = bytes;
        workingParsed = videojs.inspectMp4(bytes);
        console.log('working', workingParsed);
        diffParsed();

        // clear old box info
        workingBoxes.innerHTML = videojs.textifyMp4(workingParsed, null, ' ');

        // output the hex dump
        hex += '<pre>';
        hex += videojs.Hls.utils.hexDump(bytes);
        hex += '</pre>';
        workingOutput.innerHTML = hex;

        // XXX Media Sources Testing
        window.vjsSourceBuffer.appendBuffer(bytes);
      });
      reader.readAsArrayBuffer(this.files[0]);
    }, false);
  </script>
</body>
</html>