如何解析ffprobe输出并根据结果运行ffmpeg?

4

我在为我的Mac构建一个ffmpeg二进制文件时遇到了很大的麻烦,因为我的所有需求都无法满足。我有一个旧版本的二进制文件,可以轻松地重新封装h264视频而不出现问题,但是它缺少我需要的库,即libspeex。我基于ffmpeg的git构建了一个新的版本,其中包括libspeex,但是当尝试重新封装带有错误时间码(从rtmpdump中实时转储)的.flv文件的h264时,它会崩溃。因此,我有两个ffmpeg二进制文件,每个文件只能完成我所需的一半功能。这是我当前的.command文件内容:

for f in ~/Desktop/Uploads/*.flv
do
/usr/local/bin/ffmpeg -i "$f" -vcodec copy -acodec libfaac -ab 128k -ar 48000 -async 1 "${f%.*}".mp4 && rmtrash "$f" || rmtrash "${f%.*}".mp4
done

这个FFmpeg二进制文件中包含了libspeex,因此它可以解码.flv输入文件中的speex音频。我想做的是类似于以下伪代码的操作:

for f in ~/Desktop/Uploads/*.flv
do
ffprobe input.flv
    if Stream #0:1 contains speex
        ffmpeg-speex -i input.flv -acodec copy -async 1 output.m4a
    fi
ffmpeg-h264 -i input.flv -vcodec copy output.mp4
MP4Box -add output.mp4 -add output.m4a finaloutput.mp4
done

这种情况有可能吗?有没有其他选择?

ffprobe的输出是什么样子的?在上面运行grep可能会非常简单。 - Lawrence Velázquez
Input #0, flv, from '/Users/Greeny/Desktop/input.flv':Duration: 00:37:01.36, start: 0.000000, bitrate: 351 kb/s Stream #0:0: Video: h264 (Main), yuv420p, 320x240 [SAR 1:1 DAR 4:3], 15 tbr, 1k tbn, 30 tbc Stream #0:1: Audio: speex, 16000 Hz, 1 channels, s16 - Eli Greenberg
注释无法格式化!-. - - Eli Greenberg
我直接问一下换行符应该放在哪里怎么样 :P - Lawrence Velázquez
输入,持续时间,流,流 - Eli Greenberg
2个回答

4
您可以对输出结果运行grep命令,检查它是否包含您想要的字符串:
for f in ~/Desktop/Uploads/*.flv; do
    if ffprobe ${f} 2>&1 | egrep 'Stream #0:1.+speex'; then
        ffmpeg-speex -i ${f} -acodec copy -async 1 ${f/%.flv/.m4a}
        SPEEX_ADD="-add ${f/%.flv/.m4a}"
    fi
    ffmpeg-h264 -i ${f} -vcodec copy ${f/%.flv/.mp4}
    MP4Box -add ${f/%.flv/.mp4} ${SPEEX_ADD} ${f/%.flv/-final.mp4}
done

假设有一个输入文件 abc.flvffmpeg-speex 将会输出 abc.m4affmpeg-h264 将会输出 abc.mp4,而 MP4Box 将会生成 abc-final.mp4 作为输出文件。 编辑: 修正了对 stderr 的 grep,并修复了可能将不存在的 .m4a 文件作为输入传递给 MP4Box 的问题。

它在这段代码的行中找不到speex:/ 直接跳过到视频部分。 - Eli Greenberg
1
显然ffprobe的输出是stderr。 加入2>&1,似乎可以使用提取音频功能。现在我只需要找出为什么MP4Box失败了... - Eli Greenberg
我不知道你是否遇到了这个问题,但我刚刚解决了一个问题,我的答案中MP4Box会将.m4a文件作为输入接收,即使ffmpeg-speex从未创建过它。 - Lawrence Velázquez

1
现在可用的ffprobe版本有一个-print_format标志,这在您的情况下可能会很有用。我遇到了类似的问题,我想获取视频的长度。我使用了-print_format xml标志,然后对结果使用了xmllint来获取值。您只需要查看来自ffprobe的xml输出,并将string(.//format/@duration)替换为您想要的元素的xpath即可。
XML=`ffprobe -v error -hide_banner -show_format -show_streams -print_format xml "$FILEPATH"`
DATA=`echo "$XML" | xmllint --xpath "string(.//format/@duration)" -`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接