Last active
February 1, 2022 00:21
-
-
Save josiahbryan/5c149b97c8f350c7ff10a66a42ff8d2f to your computer and use it in GitHub Desktop.
Fixed based on feedback
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
/* | |
Aerostat Beam Coder - Node.js native bindings for FFmpeg. | |
Copyright (C) 2019 Streampunk Media Ltd. | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <https://www.gnu.org/licenses/>. | |
https://www.streampunk.media/ mailto:furnace@streampunk.media | |
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K. | |
*/ | |
/* Generate a 200 frame test pattern and encode it as a raw H.264 file. | |
Usage: node encode_h264.js <filename.h264> | |
Output can be viewed in VLC. Make sure "All Files" is selected to see the file. | |
*/ | |
const beamcoder = require('beamcoder'); // Use require('beamcoder') externally | |
async function run() { | |
const mxs = beamcoder.muxers(); | |
const muxerSpecs = mxs.mp4; | |
let start = process.hrtime(); | |
let encParams = { | |
name: 'libx264', | |
width: 1920, | |
height: 1080, | |
bit_rate: 2000000, | |
time_base: [1, 25], | |
framerate: [25, 1], | |
gop_size: 10, | |
max_b_frames: 1, | |
pix_fmt: 'yuv420p', | |
priv_data: { preset: 'slow' } | |
}; | |
let encoder = await beamcoder.encoder(encParams); | |
// console.log('Encoder', encoder); | |
const STREAM_OUT_TIMEBASE = 90000; | |
const mux = beamcoder.muxer({ format_name: muxerSpecs.name }); | |
let vstr = mux.newStream({ | |
name: muxerSpecs.video_codec, | |
time_base: [1, STREAM_OUT_TIMEBASE], | |
interleaved: true }); // Set to false for manual interleaving, true for automatic | |
Object.assign(vstr.codecpar, { | |
width: 1920, | |
height: 1080, | |
format: 'yuv420p' | |
}); | |
// console.log(vstr); | |
const encoders = beamcoder.encoders(); | |
// const videoEncoderSpecs = encoders[muxerSpecs.video_codec]; | |
// const ves2 = Object.values(encoders).find(e => e.name === muxerSpecs.video_codec); | |
// console.dir({ videoEncoderSpecs, video_codec: muxerSpecs.video_codec, ves2 }, { depth: 10 }) | |
// throw new Error(); | |
const audioEncoderSpecs = encoders[muxerSpecs.audio_codec]; | |
const audioEncParams = { | |
name: muxerSpecs.audio_codec, | |
sampleFormat: audioEncoderSpecs.sample_fmts[0], | |
channelLayout: 'stereo', | |
sampleRate: audioEncoderSpecs.supported_samplerates ? audioEncoderSpecs.supported_samplerates[0] : 44100, | |
timeBase: [1, STREAM_OUT_TIMEBASE], | |
}; | |
console.log(audioEncParams); | |
const audioEncoder = beamcoder.encoder({ | |
name: audioEncParams.name, | |
sample_fmt: audioEncParams.sampleFormat, | |
channel_layout: audioEncParams.channelLayout, | |
time_base: audioEncParams.timeBase, | |
sample_rate: audioEncParams.sampleRate, | |
}); | |
const audioStream = mux.newStream({ | |
name: audioEncParams.name, | |
time_base: audioEncParams.timeBase, | |
interleaved: false | |
}); | |
// Setup codec params for audio | |
Object.assign(audioStream.codecpar, { // Object.assign copies over all properties | |
channels: 2, | |
sample_rate: audioEncParams.sampleRate, | |
format: audioEncParams.sampleFormat, | |
channel_layout: audioEncParams.channelLayout, | |
bit_rate: audioEncParams.sampleRate * 4, //48000*4 | |
frame_size: 1024, | |
// block_align: 4, // Should be set for WAV | |
// bits_per_coded_sample: 16, | |
}); | |
console.log({ audioEncParams, audioEncoder, audioStream }) | |
await mux.openIO({ | |
url: 'file:test.mp4' | |
}); | |
await mux.writeHeader(); | |
for ( let i = 0 ; i < 100 ; i++ ) { | |
let frame = beamcoder.frame({ | |
width: encParams.width, | |
height: encParams.height, | |
format: encParams.pix_fmt | |
}).alloc(); | |
let linesize = frame.linesize; | |
let [ ydata, bdata, cdata ] = frame.data; | |
frame.pts = i+100; | |
for ( let y = 0 ; y < frame.height ; y++ ) { | |
for ( let x = 0 ; x < linesize[0] ; x++ ) { | |
ydata[y * linesize[0] + x] = x + y + i * 3; | |
} | |
} | |
for ( let y = 0 ; y < frame.height / 2 ; y++) { | |
for ( let x = 0; x < linesize[1] ; x++) { | |
bdata[y * linesize[1] + x] = 128 + y + i * 2; | |
cdata[y * linesize[1] + x] = 64 + x + i * 5; | |
} | |
} | |
let packets = await encoder.encode(frame); | |
if ( i % 10 === 0) console.log('Encoding frame', i); | |
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); | |
} | |
const audioFrame = beamcoder.frame({ | |
pts: frame.pts, | |
sample_rate: audioEncParams.sampleRate, | |
format: audioEncParams.sampleFormat, | |
channel_layout: audioEncParams.channelLayout, | |
data: [ | |
Buffer.from('AAAAAAAAAAAAAIA/AACAPw=='), | |
Buffer.from('AAAAAAAAAAAAAIA/AACAPw=='), | |
], | |
}); | |
packets = await audioEncoder.encode(audioFrame); | |
for (const pkt of packets.packets) { | |
pkt.duration = 1; | |
pkt.stream_index = audioStream.index; | |
pkt.pts = pkt.pts * 90000/25; | |
pkt.dts = pkt.dts * 90000/25; | |
await mux.writeFrame(pkt); | |
} | |
} | |
let p2 = await encoder.flush(); | |
console.log('Flushing', p2.packets.length, 'frames.'); | |
for (const pkt of p2.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); | |
} | |
await mux.writeTrailer(); | |
console.log('Total time ', process.hrtime(start)); | |
} | |
run(); |
Nah no luck at all - this was really a test to demonstrate an Audio/Video sync problem - never could figure it out. Sorry, I wish I could help!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I tried this example. I just get a buzzing sound in the audio?
Have you had any luck creating your own waveforms in the output buffers?