Как я могу получить доступ к аудиосэмплам в течение ближайших 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>

Другие вопросы по тегам