Как я могу получить доступ к аудиосэмплам в течение ближайших 5 секунд с <video> во время его воспроизведения?
Я работаю над инструментом создания субтитров и хотел бы добавить функцию, которая отображает следующие 5 секунд звукового сигнала во время воспроизведения видео. Я считаю, что визуальный просмотр предстоящего аудио позволит пользователю более точно размещать точки для субтитров.
Я нашел этот метод с использованием анализатора, но он ограничивает сэмплы аудио до 2048 (около 1/24 секунды), что слишком мало для предварительного просмотра.
Я также нашел этот метод, улавливая события "аудиопроцесса", но он по-прежнему ограничен 16k сэмплами или 1/3 секунды. Опять же, недостаточно долго, чтобы быть полезным.
Я сделал быстрый тест, чтобы увидеть, сколько времени потребуется для визуализации 5-секундных сэмплов, которые он усредняет в низких 20 мс. Поэтому я думаю, что это выполнимо для обработки в режиме реального времени, если я могу получить доступ к буферу. Возможно, мне придется снизить FPS, но я думаю, что даже при 15 кадрах в секунду это все равно будет полезно для пользователя.
Есть ли способ, с помощью которого я могу получить доступ, например, к следующим 240000 семплов (5 секунд звука) во время воспроизведения видео?
<!DOCTYPE html>
<html>
<body id="body">
<canvas id="canvas" width="1000" height="200"></canvas>
<script>
var count=0;
var samples=new Int32Array(48000*5);
var CANVAS_HEIGHT=200;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
function processSamples() {
var start = new Date().getTime();
ctx.clearRect(0, 0, 1000, 200);
for (var i=0; i < samples.length; i++) {
samples[i]=parseInt(Math.random() * CANVAS_HEIGHT);
}
// We can't display each sample on it's own line... So take the average sample and display it
// 1000 pixels for 5 second preview. So 200px per second. 48,000 samples per second / 200px = 240 samples per pixel
var sample;
for (var i=0; i < samples.length/240; i++) {
sample=0;
for (var j=0; j < 240; j++) {
sample += samples[i*240+j];
}
sample=parseInt(sample/240);
ctx.fillRect(i, 0, 1, sample);
}
if (count < 10)
setTimeout(processSamples, 1000);
count++;
var end = new Date().getTime();
var time = end - start;
console.log('Execution time: ' + time);
}
window.onload=processSamples;
</script>
</body>
</html>
1 ответ
В настоящее время не представляется возможным расширить буфер для получения большего размера выборки во время воспроизведения. Тем не менее, я смог создать статический сигнал всего файла с помощью этого метода. Я изменил его здесь, чтобы использовать File API.
Вы загружаете файл в arrayBuffer и затем передаете в буфер audioContext.decodeAudioData(arrayBuffer, callbackFunction)
var audioContext = new AudioContext();
function drawBuffer( width, height, context, buffer ) {
var data = buffer.getChannelData( 0 );
var step = Math.ceil( data.length / width );
var amp = height / 2;
for(var i=0; i < width; i++){
var min = 1.0;
var max = -1.0;
for (var j=0; j<step; j++) {
var datum = data[(i*step)+j];
if (datum < min)
min = datum;
if (datum > max)
max = datum;
}
context.fillRect(i,(1+min)*amp,1,Math.max(1,(max-min)*amp));
}
}
function initAudio() {
var file = document.getElementById('fileItem').files[0];
var reader = new FileReader();
reader.onerror = function(e) {
console.log("Error reading file");
console.log(e);
}
reader.onload = function(e) {
console.log("loading");
var arrayBuffer = e.target.result;
audioContext.decodeAudioData( arrayBuffer,
function(buffer) {
console.log("drawing");
var canvas = document.getElementById("canvas");
drawBuffer( canvas.width, canvas.height, canvas.getContext('2d'), buffer );
} );
}
reader.readAsArrayBuffer(file);
}
body {
width: 100%;
height: 100%;
}
#canvas {
position: absolute;
top: 0;
left: 0;
width: 800px;
height: 200px;
background-color: blue;
}
#fileItem {
position: absolute;
top: 205px;
left: 0px;
}
#button {
position: absolute;
top: 205px;
left: 250px;
<body>
<canvas id="canvas"></canvas>
<input id="fileItem" type="file"/>
<button id="button" onclick="initAudio();">Draw Waveform</button>
</body>