Estou tentando fazer fatias de segmentos de fala de um arquivo de áudio e mesclá-los. O áudio de origem é um arquivo PCM Wav de trilha única com 16Khz e 16 bits.
Uma fatia feita com -ss -i input.wav -t output.wav tem uma duração diferente de uma fatia feita com -ss -i input.wav -t -acodec copy output.wav
Para ser exato:
- -ss 20.125 -i input.wav -t 10.125 output-reencode.wav produz uma fatia com duração de 10s:125ms
- -ss 20.125 -i input.wav -t 10.125 -acodec copy output-copy.wav produz uma fatia com duração de 10s:176ms
Por que há uma diferença de 51 ms?
É seguro dizer que a versão recodificada não é mais lenta porque não há compactação envolvida com PCM?
C:\Users\someuser>ffmpeg.exe -ss 20.125 -i "C:\input.wav" -t 10.125 "C:\output-reencode.wav"
ffmpeg version 7.0-essentials_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
[aist#0:0/pcm_s16le @ 000001923d036b40] Guessed Channel Layout: mono
Input #0, wav, from 'C:\input.wav':
Metadata:
encoder : Lavf61.1.100
timecode : 00:00:00:00
Duration: 00:27:33.20, bitrate: 256 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (pcm_s16le (native) -> pcm_s16le (native))
Output #0, wav, to 'C:\output-reencode.wav':
Metadata:
ISMP : 00:00:00:00
ISFT : Lavf61.1.100
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s
Metadata:
encoder : Lavc61.3.100 pcm_s16le
[out#0/wav @ 000001923d029e80] video:0KiB audio:316KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.030247%
size= 317KiB time=00:00:10.12 bitrate= 256.1kbits/s speed=1.25e+03x
C:\Users\someuser>ffmpeg.exe -ss 20.125 -i "C:\input.wav" -acodec copy -t 10.125 "C:\output-copy.wav"
ffmpeg version 7.0-essentials_build-www.gyan.dev Copyright (c) 2000-2024 the FFmpeg developers
built with gcc 13.2.0 (Rev5, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
libavutil 59. 8.100 / 59. 8.100
libavcodec 61. 3.100 / 61. 3.100
libavformat 61. 1.100 / 61. 1.100
libavdevice 61. 1.100 / 61. 1.100
libavfilter 10. 1.100 / 10. 1.100
libswscale 8. 1.100 / 8. 1.100
libswresample 5. 1.100 / 5. 1.100
libpostproc 58. 1.100 / 58. 1.100
[aist#0:0/pcm_s16le @ 000001ad5f9c9b80] Guessed Channel Layout: mono
Input #0, wav, from 'C:\input.wav':
Metadata:
encoder : Lavf61.1.100
timecode : 00:00:00:00
Duration: 00:27:33.20, bitrate: 256 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Output #0, wav, to 'C:\output-copy.wav':
Metadata:
ISMP : 00:00:00:00
ISFT : Lavf61.1.100
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s
Press [q] to stop, [?] for help
[out#0/wav @ 000001ad5f9c9d40] video:0KiB audio:318KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.030095%
size= 318KiB time=00:00:10.24 bitrate= 254.5kbits/s speed=2.76e+03x
Um fluxo de áudio PCM geralmente é processado em quadros com 1024 amostras por quadro.
Ao recodificar com um especificador de duração, o ffmpeg truncará o quadro final, se necessário, para satisfazer a duração o mais próximo possível. Ao fazer streamcopy, ele lidará apenas com quadros inteiros.
Seu fluxo de áudio é de 16000 Hz, então um quadro mede 1024/16000 = 64 ms. 10,125 s abrange 158,203125 quadros. Ao fazer streamcopy, o 159º quadro será de tamanho completo (1024 amostras), então a duração da saída será 159 * 64 ms = 10176 ms
Quando você copia o fluxo de áudio, o ffmpeg só vai dividir nos keyframes. Como os keyframes não estão localizados nos timestamps específicos dos quais você está iniciando e parando, o corte é impreciso.
Quando você recodifica o fluxo, o ffmpeg não se importa com os quadros-chave existentes, pois ele cria novos por meio do codificador.
Você deve conseguir visualizar os carimbos de data/hora dos quadros-chave do seu arquivo de mídia usando algo como
ffprobe -loglevel error -skip_frame nokey -select_streams v:0 -show_entries frame=pkt_pts_time -of csv=print_section=0 input.mp4
Para informações adicionais: