Last active
February 26, 2020 09:25
-
-
Save josiahbryan/2292b7b33860367755513a63f8228282 to your computer and use it in GitHub Desktop.
Test of transcoding with beamcoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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