mbebenita / Broadway

A JavaScript H.264 decoder.
Other
2.72k stars 424 forks source link

Correct x264 encoder settings for Broadway to decode #115

Open xiaoyaoth opened 8 years ago

xiaoyaoth commented 8 years ago

Hi soliton4,

I have a question about the correct x264 settings for Broadway to decode. My current x264 settings are based on the advice of using FFMEG with Broadway:

The decoder expects an .mp4 file and does not support weighted prediction for P-frames and CABAC entropy encoding. To create such bitstreams use ffmpeg and x264 with the following command line options:

ffmpeg -y -i sourceFile -r 30000/1001 -b:a 2M -bt 4M -vcodec libx264 -pass 1 -coder 0 -bf 0 -flags -loop -wpredp 0 -an targetFile.mp4

So I translate the FFMPEG settings to x264 settings in the following way:

fps=29.97 ratetol=4.0 pass=1 no-cabac bframes=0 no-deblock weightp=0 tune=zerolatency profile=baseline

There is no problem if using FFMPEG with suggested settings for encoding. But encoding with x264 makes the decoded image blurred (pixelated), shown as follows: exp2_ A video clip of the same issue can be found here https://www.dropbox.com/s/ey1u6ob92d94clq/exp2_.mp4?dl=0

Woud you please advise the correct settings of x264 encoder for Broadway to decode? Many thanks.

Best regards, Xiaosong

amitv87 commented 7 years ago

You need to send one nal unit at a time to player, sample code below.

function H264Player(){
  console.log('using', this);
  var p = new Player({
    useWorker: true,
    workerFile: "/Player/Decoder.js",
  });

  document.body.appendChild(p.canvas);
  var parser = new nalParser(p);
  this.play = function(buffer){
    parser.parse(buffer);
  };
}

var h264p = new H264Player();
h264p.play(<your array buffer here>);

function nalParser(player){
  var bufferAr = [];
  var concatUint8 = function(parAr) {
    if (!parAr || !parAr.length){
      return new Uint8Array(0);
    };

    if (parAr.length === 1){
      return parAr[0];
    };

    var completeLength = 0;
    var i = 0;
    var l = parAr.length;
    for (i; i < l; ++i){
      completeLength += parAr[i].byteLength;
    };

    var res = new Uint8Array(completeLength);
    var filledLength = 0;

    for (i = 0; i < l; ++i){
      res.set(new Uint8Array(parAr[i]), filledLength);
      filledLength += parAr[i].byteLength;
    };
    return res;
  };
  this.parse = function(buffer){
    if (!(buffer && buffer.byteLength)){
      return;
    };
    var data = new Uint8Array(buffer);
    var hit = function(subarray){
      if (subarray){
        bufferAr.push(subarray);
      };
      var buff = concatUint8(bufferAr);
      player.decode(buff);
      bufferAr = [];
    };

    var b = 0;
    var lastStart = 0;

    var l = data.length;
    var zeroCnt = 0;

    for (b = 0; b < l; ++b){
      if (data[b] === 0){
        zeroCnt++;
      }else{
        if (data[b] == 1){
          if (zeroCnt >= 3){
            if (lastStart < b - 3){
              hit(data.subarray(lastStart, b - 3));
              lastStart = b - 3;
            }else if (bufferAr.length){
              hit();
            }
          };
        };
        zeroCnt = 0;
      };
    };
    if (lastStart < data.length){
      bufferAr.push(data.subarray(lastStart));
    };
  };
}
OllieJones commented 5 years ago

Your encoder must use the Baseline profile of AVC/H.264, and must use CAVLC (Huffman-style) coding rather than CABAC (arithmetic) coding.

soliton4 commented 5 years ago

i dont think there is evidence for the claim that coding arithmetic would be involed in the bug described here. @OllieJones if you can further elaborate on how you come to the conclusion to blame encoding parameters, please do. otherwise dont confuse new users with noise please.