text: /** 
   * Requires: avc-codec.js
   **/
  
  assert (Module);
  
  var advancedCCOptimizations = Module.CC_VARIABLE_MAP ? true : false;
  
  if (advancedCCOptimizations) {
    console.info("Advanced CC Optimizations");
    HEAPU8 = Module.CC_VARIABLE_MAP["HEAP8"];
    HEAP16 = Module.CC_VARIABLE_MAP["HEAP16"];
    HEAP32 = Module.CC_VARIABLE_MAP["HEAP32"];
    _h264bsdClip = Module.CC_VARIABLE_MAP["_h264bsdClip"];
  }
  
  var Avc = (function avc() {
    const MAX_STREAM_BUFFER_LENGTH = 1024 * 1024;
    
    function constructor() {
      Module._broadwayInit();
      this.streamBuffer = toU8Array(Module._broadwayCreateStream(MAX_STREAM_BUFFER_LENGTH), MAX_STREAM_BUFFER_LENGTH);
      this.pictureBuffers = {};
      
      this.onPictureDecoded = function (buffer, width, height) {
        // console.info(buffer.length);
      }
      
      _broadwayOnPictureDecoded = function ($buffer, width, height) {
        var buffer = this.pictureBuffers[$buffer];
        if (!buffer) {
          buffer = this.pictureBuffers[$buffer] = toU8Array($buffer, (width * height * 3) / 2);
        }
        this.onPictureDecoded(buffer, width, height);
      }.bind(this);
    }
  
    /**
     * Creates a typed array from a HEAP8 pointer. 
     */
    function toU8Array(ptr, length) {
      return HEAPU8.subarray(ptr, ptr + length);
    }
    
    constructor.prototype = {
      /**
       * Decodes a stream buffer. This may be one single (unframed) NAL unit without the
       * start code, or a sequence of NAL units with framing start code prefixes. This
       * function overwrites stream buffer allocated by the codec with the supplied buffer.
       */
      decode: function decode(buffer) {
        // console.info("Decoding: " + buffer.length);
        this.streamBuffer.set(buffer);
        Module._broadwaySetStreamLength(buffer.length);
        Module._broadwayPlayStream();
      },
      configure: function (config) {
        patchOptimizations(config, patches);
        console.info("Broadway Configured: " + JSON.stringify(config));
      }
    };
    
    return constructor;
  })();
  
  function patchOptimizations(config, patches) { 
    var scope = getGlobalScope();
    for (var name in patches) {
      var patch = patches[name];
      var option = config[name];
      if (!option) option = "original";
      console.info(name + ": " + option);
      assert (option in patch.options);
      var fn = patch.options[option].fn;
      if (fn) {
        scope[patch.original] = Module.patch(null, patch.name, fn);
        console.info("Patching: " + patch.name + ", with: " + option);
      }
    }
  }
  
  var patches = {
    "filter": {
      name: "_h264bsdFilterPicture",
      display: "Filter Picture",
      original: "Original_h264bsdFilterPicture",
      options: {
        none: {display: "None", fn: function () {}},
        original: {display: "Original", fn: null},
      }
    },
    "filterHorLuma": {
      name: "_FilterHorLuma",
      display: "Filter Hor Luma",
      original: "OriginalFilterHorLuma",
      options: {
        none: {display: "None", fn: function () {}},
        original: {display: "Original", fn: null},
        optimized: {display: "Optimized", fn: OptimizedFilterHorLuma}
      }
    },
    "filterVerLumaEdge": {
      name: "_FilterVerLumaEdge",
      display: "Filter Ver Luma Edge",
      original: "OriginalFilterVerLumaEdge",
      options: {
        none: {display: "None", fn: function () {}},
        original: {display: "Original", fn: null},
        optimized: {display: "Optimized", fn: OptimizedFilterVerLumaEdge}
      }
    },
    "getBoundaryStrengthsA": {
      name: "_GetBoundaryStrengthsA",
      display: "Get Boundary Strengths",
      original: "OriginalGetBoundaryStrengthsA",
      options: {
        none: {display: "None", fn: function () {}},
        original: {display: "Original", fn: null},
        optimized: {display: "Optimized", fn: OptimizedGetBoundaryStrengthsA}
      }
    }
  };
  
  function getGlobalScope() {
    return function () { return this; }.call(null);
  }
  
  /* Optimizations */
  
  function clip(x, y, z) {
    return z < x ? x : (z > y ? y : z);
  }
  
  _abs = Math.abs;
  _clip = clip;
  
  function OptimizedGetBoundaryStrengthsA($mb, $bS) {
    var $totalCoeff = $mb + 28;
    
    var tc0 = HEAP16[$totalCoeff + 0 >> 1];
    var tc1 = HEAP16[$totalCoeff + 2 >> 1];
    var tc2 = HEAP16[$totalCoeff + 4 >> 1];
    var tc3 = HEAP16[$totalCoeff + 6 >> 1];
    var tc4 = HEAP16[$totalCoeff + 8 >> 1];
    var tc5 = HEAP16[$totalCoeff + 10 >> 1];
    var tc6 = HEAP16[$totalCoeff + 12 >> 1];
    var tc7 = HEAP16[$totalCoeff + 14 >> 1];
    var tc8 = HEAP16[$totalCoeff + 16 >> 1];
    var tc9 = HEAP16[$totalCoeff + 18 >> 1];
    var tc10 = HEAP16[$totalCoeff + 20 >> 1];
    var tc11 = HEAP16[$totalCoeff + 22 >> 1];
    var tc12 = HEAP16[$totalCoeff + 24 >> 1];
    var tc13 = HEAP16[$totalCoeff + 26 >> 1];
    var tc14 = HEAP16[$totalCoeff + 28 >> 1];
    var tc15 = HEAP16[$totalCoeff + 30 >> 1];
    
    HEAP32[$bS + 32 >> 2] = tc2 || tc0 ? 2 : 0;
    HEAP32[$bS + 40 >> 2] = tc3 || tc1 ? 2 : 0;
    HEAP32[$bS + 48 >> 2] = tc6 || tc4 ? 2 : 0;
    HEAP32[$bS + 56 >> 2] = tc7 || tc5 ? 2 : 0;
    HEAP32[$bS + 64 >> 2] = tc8 || tc2 ? 2 : 0;
    HEAP32[$bS + 72 >> 2] = tc9 || tc3 ? 2 : 0;
    HEAP32[$bS + 80 >> 2] = tc12 || tc6 ? 2 : 0;
    HEAP32[$bS + 88 >> 2] = tc13 || tc7 ? 2 : 0;
    HEAP32[$bS + 96 >> 2] = tc10 || tc8 ? 2 : 0;
    HEAP32[$bS + 104 >> 2] = tc11 || tc9 ? 2 : 0;
    HEAP32[$bS + 112 >> 2] = tc14 || tc12 ? 2 : 0;
    HEAP32[$bS + 120 >> 2] = tc15 || tc13 ? 2 : 0;
  
    HEAP32[$bS + 12 >> 2] = tc1 || tc0 ? 2 : 0;
    HEAP32[$bS + 20 >> 2] = tc4 || tc1 ? 2 : 0;
    HEAP32[$bS + 28 >> 2] = tc5 || tc4 ? 2 : 0;
    HEAP32[$bS + 44 >> 2] = tc3 || tc2 ? 2 : 0;
    HEAP32[$bS + 52 >> 2] = tc6 || tc3 ? 2 : 0;
    HEAP32[$bS + 60 >> 2] = tc7 || tc6 ? 2 : 0;
    HEAP32[$bS + 76 >> 2] = tc9 || tc8 ? 2 : 0;
    HEAP32[$bS + 84 >> 2] = tc12 || tc9 ? 2 : 0;
    HEAP32[$bS + 92 >> 2] = tc13 || tc12 ? 2 : 0;
    HEAP32[$bS + 108 >> 2] = tc11 || tc10 ? 2 : 0;
    HEAP32[$bS + 116 >> 2] = tc14 || tc11 ? 2 : 0;
    HEAP32[$bS + 124 >> 2] = tc15 || tc14 ? 2 : 0;
  }
  
  function OptimizedFilterVerLumaEdge ($data, bS, $thresholds, imageWidth) {
    var delta, tc, tmp;
    var p0, q0, p1, q1, p2, q2;
    var tmpFlag;
    var $clp = _h264bsdClip + 512;
    var alpha = HEAP32[$thresholds + 4 >> 2];
    var beta = HEAP32[$thresholds + 8 >> 2];
    var val;
    
    if (bS < 4) {
      tmp = tc = HEAPU8[HEAP32[$thresholds >> 2] + (bS - 1)] & 255;
      for (var i = 4; i > 0; i--) {
        p1 = HEAPU8[$data + -2] & 255;
        p0 = HEAPU8[$data + -1] & 255;
        q0 = HEAPU8[$data] & 255;
        q1 = HEAPU8[$data + 1] & 255;
        if ((Math.abs(p0 - q0) < alpha) && (Math.abs(p1 - p0) < beta) && (Math.abs(q1 - q0) < beta)) {
          p2 = HEAPU8[$data - 3] & 255;
          if (Math.abs(p2 - p0) < beta) {
            val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1;
            HEAP8[$data - 2] = p1 + clip(-tc, tc, val);
            tmp++;
          }
          
          q2 = HEAPU8[$data + 2] & 255;
          if (Math.abs(q2 - q0) < beta) {
            val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1;
            HEAP8[$data + 1] = (q1 + clip(-tc, tc, val));
            tmp++;
          }
          
          val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3);
          delta = clip(-tmp, tmp, val);
          
          p0 = HEAPU8[$clp + (p0 + delta)] & 255;
          q0 = HEAPU8[$clp + (q0 - delta)] & 255;
          tmp = tc;
          HEAP8[$data - 1] = p0;
          HEAP8[$data] = q0;
          
          $data += imageWidth;
        }
      }
    } else {
      OriginalFilterVerLumaEdge($data, bS, $thresholds, imageWidth);
    }
  }
  
  /**
   * Filter all four successive horizontal 4-pixel luma edges. This can be done when bS is equal to all four edges.
   */
  function OptimizedFilterHorLuma ($data, bS, $thresholds, imageWidth) {
    var delta, tc, tmp;
    var p0, q0, p1, q1, p2, q2;
    var tmpFlag;
    var $clp = _h264bsdClip + 512;
    var alpha = HEAP32[$thresholds + 4 >> 2];
    var beta = HEAP32[$thresholds + 8 >> 2];
    var val;
    
    if (bS < 4) {
      tmp = tc = HEAPU8[HEAP32[$thresholds >> 2] + (bS - 1)] & 255;
      for (var i = 16; i > 0; i--) {
        p1 = HEAPU8[$data + (-imageWidth << 1)] & 255;
        p0 = HEAPU8[$data + -imageWidth] & 255;
        q0 = HEAPU8[$data] & 255;
        q1 = HEAPU8[$data + imageWidth] & 255;
        
        if ((Math.abs(p0 - q0) < alpha) && (Math.abs(p1 - p0) < beta) && (Math.abs(q1 - q0) < beta)) {
          p2 = HEAPU8[$data + (-imageWidth * 3)] & 255;
          if (Math.abs(p2 - p0) < beta) {
            val = (p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1;
            HEAP8[$data + (-imageWidth << 1)] = p1 + clip(-tc, tc, val);
            tmp++;
          }
          
          q2 = HEAPU8[$data + (imageWidth << 2)] & 255;
          if (Math.abs(q2 - q0) < beta) {
              val = (q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1;
              HEAP8[$data + imageWidth] = (q1 + clip(-tc, tc, val));
              tmp++;
          }
          
          val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3);
          delta = clip(-tmp, tmp, val);
          
          p0 = HEAPU8[$clp + (p0 + delta)] & 255;
          q0 = HEAPU8[$clp + (q0 - delta)] & 255;
          tmp = tc;
          HEAP8[$data - imageWidth] = p0;
          HEAP8[$data] = q0;
          
          $data ++;
        }
      }
    } else {
      OriginalFilterHorLuma($data, bS, $thresholds, imageWidth);
    }
  }
  