Skip to content

Instantly share code, notes, and snippets.

@josiahbryan
Last active February 26, 2020 09:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josiahbryan/2292b7b33860367755513a63f8228282 to your computer and use it in GitHub Desktop.
Save josiahbryan/2292b7b33860367755513a63f8228282 to your computer and use it in GitHub Desktop.
Test of transcoding with beamcoder
// Revised 2/26/20 with a video filter to try using setpts - didn't help...
// Ticket ongoing at https://github.com/Streampunk/beamcoder/issues/36
const beamcoder = require('beamcoder');
async function main() {
// Get this file from http://dl5.webmfiles.org/big-buck-bunny_trailer.webm
let demuxer = await beamcoder.demuxer('file:./big-buck-bunny_trailer.webm');
let decoder = beamcoder.decoder({ demuxer, stream_index: 0 });
const inVideoStream = demuxer.streams[0];
// console.log(JSON.parse(JSON.stringify(inVideoStream)));
let encParams = {
name: 'libx264',
width: inVideoStream.codecpar.width,
height: inVideoStream.codecpar.height,
bit_rate: 2000000,
time_base: [1, 25],
framerate: [25, 1],
gop_size: 10,
max_b_frames: 1,
pix_fmt: inVideoStream.codecpar.format,
priv_data: { preset: 'slow' }
};
let encoder = await beamcoder.encoder(encParams);
// console.log('Encoder', encoder);
const mux = beamcoder.muxer({ format_name: 'mp4' });
let vstr = mux.newStream({
name: 'h264',
time_base: [1, 90000],
interleaved: true }); // Set to false for manual interleaving, true for automatic
Object.assign(vstr.codecpar, {
width: inVideoStream.codecpar.width,
height: inVideoStream.codecpar.height,
format: inVideoStream.codecpar.format
});
// console.log(vstr);
await mux.openIO({
url: 'file:./reencode.mp4'
});
await mux.writeHeader();
const writePackets = async packets => {
for (const pkt of packets.packets) {
pkt.duration = 1;
pkt.stream_index = vstr.index;
pkt.pts = pkt.pts * 90000/25;
pkt.dts = pkt.dts * 90000/25;
await mux.writeFrame(pkt);
}
}
// Filter example derived from https://github.com/Streampunk/beamcoder#filterer
const filterDef = {
filterType: 'video',
inputParams: [{
width: inVideoStream.codecpar.width,
height: inVideoStream.codecpar.height,
pixelFormat: inVideoStream.codecpar.format,
timeBase: inVideoStream.time_base,
pixelAspect: inVideoStream.sample_aspect_ratio,
}],
outputParams: [{
pixelFormat: inVideoStream.codecpar.format,
// FIXME should this be the timeBase of the video stream or the encoder ?
timeBase: [1, 9000],
}],
filterSpec:
// This was just used to make sure filtering was working
//'scale=' + inVideoStream.codecpar.width + ':' + inVideoStream.codecpar.height + ','
// All "setpts" examples taken from https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts
// NOTE: Elsewhere on that page (ffmpeg-filters.html) anytime that 'setpts'
// is used with other filters, it always is "setpts=PTS-STARTPTS"
// However, this does NOTHING to fix the timing problem - time is still way too slow
'setpts=PTS-STARTPTS'
// XXX BAD: Produces visually corrupted video output
// ',setpts=N/SR/TB'
// XXX BAD: "Works" in that time is real time, but when transcoding,
// it will stutter when encoder uses time if not encoding in realtime
// ',setpts=(RTCTIME - RTCSTART) / (TB * 1000000)'
// XXX BAD: Does not work, produces same result as bug
// ',setpts=N/(25*TB)',
// XXX BAD: Does not work, produces same result as bug
// ',setpts=1/(25*TB) * (N + 0.05 * sin(N*2*PI/25))'
// XXX BAD: Does not work, produces same result as bug
// ',setpts=PTS-STARTPTS'
};
const filter = await beamcoder.filterer(filterDef);
let packet = true;
let counter = 0, pts = 0;
while (packet != null && counter ++ < 1000) {
packet = await demuxer.read();
const dec_result = await decoder.decode(packet);
if(dec_result.frames.length > 0) {
// FIXME(1): This works but is messy - and will break when mixing
// multiple sources and audio will not be in sync
// dec_result.frames.forEach(frame => frame.pts = pts ++);
// let packets = await encoder.encode(dec_result.frames);
// FIXME(2): This DOES NOT WORK - video still plays very in wrong time
const output = await filter.filter(dec_result.frames);
let packets = await encoder.encode(output[0].frames);
if ( counter % 10 === 0) console.log('Encoding frame', counter);
await writePackets(packets);
}
}
let p2 = await encoder.flush();
console.log('Flushing', p2.packets.length, 'frames.');
await writePackets(p2);
await mux.writeTrailer();
console.log("Done");
}
main().catch(e => console.warn("Caught:", e));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment