【问题标题】:Problems piping ffmpeg to flac encoder将ffmpeg管道传输到flac编码器的问题
【发布时间】:2019-10-01 22:48:15
【问题描述】:

我需要用seektables编码一个flac文件,ffmpeg的flac编码器不包含seektables,所以我需要使用flac CLI。我正在尝试通过首先通过 ffmpeg 管道将任意音频文件转换为可搜索的 flac 文件,然后将其传输到 flac 编码器。

export const transcodeToFlac: AudioTranscoder<{}> = ({
  source,
  destination
}) => {
  return new Promise((resolve, reject) => {
    let totalSize = 0

    const { stdout: ffmpegOutput, stderr: ffmpegError } = spawn("ffmpeg", [
      "-i",
      source,
      "-f",
      "wav",
      "pipe:1"
    ])

    const { stdout: flacOutput, stdin: flacInput, stderr: flacError } = spawn(
      "flac",
      ["-"]
    )

    flacOutput.on("data", (buffer: Buffer) => {
      totalSize += buffer.byteLength
    })

    ffmpegError.on("data", error => {
      console.log(error.toString())
    })

    flacError.on("data", error => {
      console.log(error.toString())
    })

    //stream.on("error", reject)

    destination.on("finish", () => {
      resolve({
        mime: "audio/flac",
        size: totalSize,
        codec: "flac",
        bitdepth: 16,
        ext: "flac"
      })
    })

    ffmpegOutput.pipe(flacInput)
    flacOutput.pipe(destination)
  })
}

虽然此代码有效,但生成的 flac 文件不正确。源音频的持续时间为06:14,但flac 文件的持续时间为06:45:47。手动编码 flac 而不将 ffmpeg 传递给它可以正常工作,但我无法在需要使用流的服务器环境中执行此操作。

以下是flac编码器在转码时输出的内容:

flac 1.3.2
Copyright (C) 2000-2009  Josh Coalson, 2011-2016  Xiph.Org Foundation
flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
welcome to redistribute it under certain conditions.  Type `flac' for details.

-: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)
-: WARNING, cannot write back seekpoints when encoding to stdout
-: 0% complete, ratio=0.357
0% complete, ratio=0.432
0% complete, ratio=0.482
0% complete, ratio=0.527
0% complete, ratio=0.541
1% complete, ratio=0.554
1% complete, ratio=0.563
1% complete, ratio=0.571
size=   36297kB time=00:03:30.70 bitrate=1411.2kbits/s speed= 421x
1% complete, ratio=0.572
1% complete, ratio=0.570
1% complete, ratio=0.577
1% complete, ratio=0.583
1% complete, ratio=0.584
1% complete, ratio=0.590
1% complete, ratio=0.592
size=   64512kB time=00:06:14.49 bitrate=1411.2kbits/s speed= 421x
video:0kB audio:64512kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead:
0.000185%

-: WARNING: unexpected EOF; expected 1073741823 samples, got 16510976 samples
2% complete, ratio=0.579

【问题讨论】:

    标签: typescript ffmpeg flac


    【解决方案1】:

    第一件事:

    我需要用 seektables 编码一个 flac 文件,
    -: WARNING, cannot write back seekpoints when encoding to stdout

    来自flac -H

    A single INPUTFILE may be - for stdin.  No INPUTFILE implies stdin.  Use of
    stdin implies -c (write to stdout).  Normally you should use:
       flac [options] -o outfilename  or  flac -d [options] -o outfilename
    instead of:
       flac [options] > outfilename   or  flac -d [options] > outfilename
    since the former allows flac to seek backwards to write the STREAMINFO or
    WAVE/AIFF header contents when necessary.
    

    尝试使用flac - -o outfilename.flac 而不仅仅是flac -

    这似乎对我有用,并且生成的音频长度正确(在我的情况下 - 这与你的不同):
    $ rm out.flac; ffmpeg -nostdin -i ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a -f wav - | flac - -o out.flac

    
    flac 1.3.2
    Copyright (C) 2000-2009  Josh Coalson, 2011-2016  Xiph.Org Foundation
    flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
    welcome to redistribute it under certain conditions.  Type `flac' for details.
    
    ffmpeg version n4.1.3 Copyright (c) 2000-2019 the FFmpeg developers
      built with gcc 8.2.1 (GCC) 20181127
      configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3
      libavutil      56. 22.100 / 56. 22.100
      libavcodec     58. 35.100 / 58. 35.100
      libavformat    58. 20.100 / 58. 20.100
      libavdevice    58.  5.100 / 58.  5.100
      libavfilter     7. 40.101 /  7. 40.101
      libswscale      5.  3.100 /  5.  3.100
      libswresample   3.  3.100 /  3.  3.100
      libpostproc    55.  3.100 / 55.  3.100
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/user/audio/asmr/ASMR _ Camera Touching _ No Mouthsounds _ NO TALKING-lQlZJ82ebBk.m4a':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2mp41
        encoder         : Lavf58.3.100
      Duration: 00:53:29.09, start: 0.000000, bitrate: 126 kb/s
        Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
    Stream mapping:
      Stream #0:0 -> #0:0 (aac (native) -> pcm_s16le (native))
    Output #0, wav, to 'pipe:':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2mp41
        ISFT            : Lavf58.20.100
        Stream #0:0(und): Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
          encoder         : Lavc58.35.100 pcm_s16le
    -: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)
    13% complete, ratio=0.284size=  552816kB time=00:53:29.09 bitrate=1411.2kbits/s speed= 665x      
    video:0kB audio:552816kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000014%
    -: WARNING: unexpected EOF; expected 1073741823 samples, got 141516800 samples
    13% complete, ratio=0.283
    
    $ ffprobe ./out.flac 
    ffprobe version n4.1.3 Copyright (c) 2007-2019 the FFmpeg developers
      built with gcc 8.2.1 (GCC) 20181127
      configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3
      libavutil      56. 22.100 / 56. 22.100
      libavcodec     58. 35.100 / 58. 35.100
      libavformat    58. 20.100 / 58. 20.100
      libavdevice    58.  5.100 / 58.  5.100
      libavfilter     7. 40.101 /  7. 40.101
      libswscale      5.  3.100 /  5.  3.100
      libswresample   3.  3.100 /  3.  3.100
      libpostproc    55.  3.100 / 55.  3.100
    Input #0, flac, from './out.flac':
      Duration: 00:53:29.09, start: 0.000000, bitrate: 399 kb/s
        Stream #0:0: Audio: flac, 44100 Hz, stereo, s16
    
    $ ffprobe ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a
    ffprobe version n4.1.3 Copyright (c) 2007-2019 the FFmpeg developers
      built with gcc 8.2.1 (GCC) 20181127
      configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-omx --enable-shared --enable-version3
      libavutil      56. 22.100 / 56. 22.100
      libavcodec     58. 35.100 / 58. 35.100
      libavformat    58. 20.100 / 58. 20.100
      libavdevice    58.  5.100 / 58.  5.100
      libavfilter     7. 40.101 /  7. 40.101
      libswscale      5.  3.100 /  5.  3.100
      libswresample   3.  3.100 /  3.  3.100
      libpostproc    55.  3.100 / 55.  3.100
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/user/audio/asmr/ASMR _ Camera Touching _ No Mouthsounds _ NO TALKING-lQlZJ82ebBk.m4a':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2mp41
        encoder         : Lavf58.3.100
      Duration: 00:53:29.09, start: 0.000000, bitrate: 126 kb/s
        Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 125 kb/s (default)
        Metadata:
          handler_name    : SoundHandler
    
    $ vlc out.flac
    #sounds ok, even at the end
    

    这个
    -: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)
    没办法:
    ERROR: --keep-foreign-metadata cannot be used when encoding from stdin or to stdout

    但是,即使我得到了
    -: WARNING: unexpected EOF; expected 1073741823 samples, got 141516800 samples
    这就是它停止在 13% (141516800 * 100 / 1073741823 = 13.2%) 的原因,输出看起来很好并且与输入的长度相同!

    更新: 发生这种情况是因为ffmpeg 没有填充正确的ChunkSize 输出值wav,因为它被发送到管道而不是文件,所以 ffmpeg 最初使用四个 0xFF 字节作为 ChunkSize 和 wav编码完成后,ffmpeg 知道正确的值是什么,但它无法返回输出管道以更新 ChunkSize 部分。当输出到文件时,它可以。

    The canonical WAVE format starts with the RIFF header:
    
    0         4   ChunkID          Contains the letters "RIFF" in ASCII form
                                   (0x52494646 big-endian form).
    4         4   ChunkSize        36 + SubChunk2Size, or more precisely:
                                   4 + (8 + SubChunk1Size) + (8 + SubChunk2Size)
                                   This is the size of the rest of the chunk 
                                   following this number.  This is the size of the 
                                   entire file in bytes minus 8 bytes for the
                                   two fields not included in this count:
                                   ChunkID and ChunkSize.
    8         4   Format           Contains the letters "WAVE"
                                   (0x57415645 big-endian form).
    

    以下是ffmpeg wav 输出到文件时与输出到管道时的不同之处:

    (注意:不要运行这个,它需要几分钟的 100% CPU 使用率,也就是一个内核,即使在快速处理器上也是如此)

    $ colordiff -up <(hexdump -C toafile.wav) <(hexdump -C piped.wav)
    --- /dev/fd/63  2019-05-19 21:28:20.621944056 +0200
    +++ /dev/fd/62  2019-05-19 21:28:20.621944056 +0200
    @@ -1,8 +1,8 @@
    -00000000  52 49 46 46 46 c0 bd 21  57 41 56 45 66 6d 74 20  |RIFFF..!WAVEfmt |
    +00000000  52 49 46 46 ff ff ff ff  57 41 56 45 66 6d 74 20  |RIFF....WAVEfmt |
     00000010  10 00 00 00 01 00 02 00  44 ac 00 00 10 b1 02 00  |........D.......|
     00000020  04 00 10 00 4c 49 53 54  1a 00 00 00 49 4e 46 4f  |....LIST....INFO|
     00000030  49 53 46 54 0e 00 00 00  4c 61 76 66 35 38 2e 32  |ISFT....Lavf58.2|
    -00000040  37 2e 31 30 33 00 64 61  74 61 00 c0 bd 21 00 00  |7.103.data...!..|
    +00000040  37 2e 31 30 33 00 64 61  74 61 ff ff ff ff 00 00  |7.103.data......|
     00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
     *
     00003440  00 00 01 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
    -----------
    
    1. 管道 wav(当输出到管道时由 ffmpeg 生成)将导致 flac 给你一个额外的警告:

    一个。生成管道 wav:ffmpeg -nostdin -i ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a -f wav - &gt; piped.wav

    b.管它到flac:

    cat piped.wav | flac - -o out2.flac
    
    flac 1.3.2
    Copyright (C) 2000-2009  Josh Coalson, 2011-2016  Xiph.Org Foundation
    flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
    welcome to redistribute it under certain conditions.  Type `flac' for details.
    
    -: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)
    -: 13% complete, ratio=0.284-: WARNING: unexpected EOF; expected 1073741823 samples, got 141516800 samples
    13% complete, ratio=0.283
    

    flac 不知道输入的正确大小(ChunkSize 为 0xFFFFFFFF)

    1. 但是wav文件(输出到文件时由ffmpeg生成)就可以了:

    一个。生成wav成文件:ffmpeg -nostdin -i ~/audio/asmr/ASMR\ _\ Camera\ Touching\ _\ No\ Mouthsounds\ _\ NO\ TALKING-lQlZJ82ebBk.m4a -f wav toafile.wav

    b.管它到flac:

    $ rm out2.flac; cat toafile.wav | flac - -o out2.flac
    
    flac 1.3.2
    Copyright (C) 2000-2009  Josh Coalson, 2011-2016  Xiph.Org Foundation
    flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are
    welcome to redistribute it under certain conditions.  Type `flac' for details.
    
    -: WARNING: skipping unknown chunk 'LIST' (use --keep-foreign-metadata to keep)
    -: wrote 160381819 bytes, ratio=0.283
    

    这是因为它正确设置了ChunkSize 值。 (ChunkSize 为 0x21BDC046 = 566,083,654,比总大小为 566,083,662 字节的输出 infile.wav 少 8 个字节)

    【讨论】:

    • 问题是我仍然需要在从 flac 管道时使用流。在我的代码中,目标流可以通过管道传输到 GCS 等外部远程存储解决方案。
    • 啊,我的错误,在阅读了您的问题后,我错误地理解您只想从 ffmpeg 管道传输到 flac。那么问题是,正如flac -H 所说,flac 无法返回到流中(因为它是一个流)来写入你说你需要的那些搜索点。所以我不明白你怎么能摆脱对管道的flac写入。也许尝试修改 flac 以写入临时文件? (可能是 O_TMPFILE,所以没有其他东西可以看到它 - 我从未尝试过,但 man 2 open)然后仅在 flac 进程退出后才开始将该文件传输到流中。似乎是一个糟糕的解决方案,恕我直言:(
    • 这实际上是我现在正在做的事情,但我讨厌它。我宁愿不使用磁盘,因为这应该是一个可扩展的解决方案。我想我只能忍气吞声了。不过,我注意到一些奇怪的事情是,如果我将 wav 文件直接流式传输到 flac,而不使用 ffmpeg,它似乎可以工作。
    • 看起来ffmpeg 也无法回溯(因为它是一个流),因此如果将 wav ffmpeg 到管道而不是文件,则会得到 4x2=8 个字节,即 0xFF。 4 个字节是ChunkSize,另外 4 个似乎是 Lavf58.2.7 LIST 标头的一部分(我不知道),但其中 3 个与前 4 个相同。也许这个信息对于 flac 来说已经足够了不必回溯,因为现在它知道计算寻找点所需的大小(块和文件),因此可以在没有回溯的情况下正常写入,因此甚至可以写入流。
    • 我更新了答案以包含上述信息,但我猜你仍然坚持必须从 ffmpeg 或从 flac 输出到临时文件,尽管后者似乎占用更少的空间(flac vs wav),前者似乎避免了unexpected EOF看似危险的flac警告。 (注:此评论可以删除)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 1970-01-01
    • 2015-03-30
    • 2014-05-25
    • 2019-04-28
    • 1970-01-01
    相关资源
    最近更新 更多