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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9985345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:56:45  来源:igfitidea点击:

How can I parse ffprobe output and run ffmpeg depending on the result?

bashffmpeg

提问by Eli Greenberg

I have had incredible trouble building a binary of ffmpeg for Mac that works correctly for all of my needs. I have an older build that works great remuxing h264 video without problems but lacks a library I need, namely libspeex. I built a newer build based on ffmpeg's git that includes libspeex but crashes when trying to remux h264 from .flv files with bad timecodes (live dumps from rtmpdump). So I have two ffmpeg binaries that each do half of what I need. This is what I have as my current .command file:

我在为 Mac 构建一个 ffmpeg 二进制文件时遇到了令人难以置信的麻烦,它可以正确地满足我的所有需求。我有一个较旧的版本,可以很好地重新混合 h264 视频而没有问题,但缺少我需要的库,即 libspeex。我基于 ffmpeg 的 git 构建了一个较新的版本,其中包含 libspeex,但在尝试从时间码错误的 .flv 文件(来自 rtmpdump 的实时转储)重新混合 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

This ffmpeg binary has libspeex included so it can decode speex audio in the .flv input files. What I'm looking to do is something like this pseudocode:

这个 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

Is something like this possible? Are there any alternatives?

这样的事情可能吗?有没有其他选择?

采纳答案by Lawrence Velázquez

You could run grepon its output and test whether it found your desired string:

你可以运行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

Assuming an input file abc.flv, ffmpeg-speexwould output abc.m4a, ffmpeg-h264would output abc.mp4, and MP4Boxwould output abc-final.mp4.

假设一个输入文件abc.flvffmpeg-speex会输出abc.m4affmpeg-h264会输出abc.mp4MP4Box会输出abc-final.mp4

Edit:Fixed to grepon stderr also; fixed problem where non-existent .m4a file might be given to MP4Boxas an input.

编辑:也固定grep在 stderr 上;修复了可能将不存在的 .m4a 文件MP4Box作为输入提供的问题。

回答by Sam

The version of ffprobe that is out now has a -print_format flag that may be useful in your situation. I had a similar issue where I wanted to get the length of a video. I used the -print_format xml flag and then used xmllint on the result to get the value. You will just need to look at the xml output from ffprobe and replace string(.//format/@duration)with the xpath to the elements you want.

现已发布的 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)" -`