• 流的操作(一)视频转音频引发的血案


    转发自白狼栈:查看原文

    有些小伙伴看文章非常细心,对于上一节课不经意提到的一些边缘细节都比较在意,比如 -acodec、-vcodec、流复制等。其实这些都离不开我们今天要讲的重点——流。

    说起流,可能有很多小伙伴第一反应是流媒体,但是我们今天要说的是容器内流的类型。通过前面的介绍,相信你对容器内的音频(audio, a)和视频(video, v)都有了一些印象。除此之外,容器内流的类型还有字幕(subtitle, s)、附加数据(attachment, t)和普通数据(data, d)。我们重点介绍一下音频流、视频流和字幕流。

    流的操作,指的是我们可以从输入文件中选择不同的流进行操作,然后输出我们想要的结果。

    举个例子,家里有小孩的都应该比较清楚,学校现在有很多英语的配音比赛,大屏幕播放一段视频,学生在舞台上配音,非常形象。

    在这个场景中,大屏幕上播放的视频,其实就是无声视频。无声视频并不是把声音调到最小,它指的是没有音频的视频,这样播放的视频只有画面。比方说对于前文案例一的素材视频可以通过 -an 的命令去除音频流,只保留视频流即只有画面(没有下载的可以点击这里下载)。

    ffmpeg -i r1ori.mp4 -an -y r1-silent.mp4

    来看下结果视频r1-silent.mp4的信息,没有了 Stream #0:1(und): Audio 的信息。

    » ffmpeg -i r1-silent.mp4 -hide_banner 
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'r1-silent.mp4':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf58.20.100
      Duration: 00:00:58.53, start: 0.000000, bitrate: 1687 kb/s
        Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 544x960, 1684 kb/s, 29.83 fps, 29.83 tbr, 11456 tbn, 59.67 tbc (default)
        Metadata:
          handler_name    : VideoHandler
    At least one output file must be specified

    现在即使你把音响抱过来,声音加到最大播放这个视频,也不会听到任何声音。

    -an 即 -acodec none。a指的是audio,codec指的是解码器,-acodec就是音频解码器,合起来就是不指定音频解码器,回顾下我们在ffmpeg是怎么转码的一文介绍的转码流程就很容易理解了。

    你应该已经猜到了,类似的我们还可以去除视频流、字幕流等。

    1. -an 去除音频流
    2. -vn 去除视频流
    3. -sn 去除字幕流
    4. -dn 去除数据流

    有同学可能注意到了,我们的原视频的时长是59秒,还不到一分钟,但是 -an 的一条命令要花上十几秒的处理时间,太慢了,有没有办法优化下?

    你仔细思考下,那么慢,时间花在哪里了?对,就是重新编码。

    这里我们只是去除音频流,有必要重新编码吗?没有,所以如果我们可以把视频流复制出来是不是就好了?

    优化后的命令如下

    ffmpeg -i r1ori.mp4 -an -vcodec copy -y r1-silent.mp4

    这条命令瞬间就输出结果了。我们添加了一个参数 -vcodec copy。-vcodec指的是视频解码器,v是视频video,codec是解码器,后跟解码器名称,copy复制输入的视频流,不作解码处理。

    同样,如果我们想提取视频中的音频,或者说把视频转成音频,是不是可以用下面这条命令?

    ffmpeg -i r1ori.mp4 -vn -c:a copy -y r1-silent.mp3

    执行该命令后发现报错了

    [mp3 @ 0x7f97a580f000] Invalid audio stream. Exactly one MP3 audio stream is required. 
    Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument

    提示我们音频流无效,原因是codec的参数错误。我们看下原视频的信息

    » ffmpeg -i r1ori.mp4 -hide_banner 
    ...... 
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 129 kb/s (default) 
    ......

    注意音频流这行信息,我们发现音频流是aac格式的,而我们要输出的是mp3格式的,-c:a copy 参数意味着我们想要把aac格式的音频流装进mp3容器,这是不可行的。aac 音频流需要一个专用的 aac 容器,mp3 音频流需要专用的 mp3 容器。

    注:aac 和 mp3 都是有损压缩音频编码格式。

    找到原因就好办了,我们把输出的mp3格式修改成aac格式

    ffmpeg -i r1ori.mp4 -vn -c:a copy -y r1-silent.aac

    虽然mp4容器内的音频流大多数都是aac格式,但是,试想一下如果我们写好程序,要针对用户上传的视频提取音频并做存储,偏偏用户上传的原视频内的音频是mp3呢?

    为了满足这一场景,我们制作一个含mp3格式的视频,然后再执行上面的命令试试。

    1、把r1ori.mp4视频内的音频流转成mp3

    ffmpeg -i r1ori.mp4 -c:a libmp3lame -c:v copy -y r2.mp4
    注:由于ffmpeg没有原生的mp3编码器,所有我们指定了外部的libmp3lame编码库(虽然 -c:a libmp3lame 你也可以把libmp3lame改为mp3,实际上使用的还是libmp3lame)。如果你执行上面的命令报了一个类似这样的错误 ERROR: libmp3lame >= 3.98.3 not found,说明你本地的ffmpeg没有添加--enable-libmp3lame编译参数,可以参考这篇文章选择对应的方式重新安装ffmpeg;

    2、提取该视频的音频

    ffmpeg -i r2.mp4 -vn -c:a copy -y r1-silent.aac 
    报错:Only AAC streams can be muxed by the ADTS muxer 
    Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument

    所以,-c:a copy 不是万能的,也就是说如果我们想让视频转音频,最好指定一种编码器,用aac还是libmp3lame?就音质质量而言,我们更推荐libmp3lame,尽管ffmpeg自带的最好音频编码器是aac。

    综上,如果你需要输出mp3格式的音频,你可以使用

    ffmpeg -i r1ori.mp4 -vn -c:a libmp3lame -y r1-silent.mp3

    如果你想输出aac格式的音频,你可以使用

    ffmpeg -i r1ori.mp4 -vn -c:a aac -y r1-silent.aac
    注:新版本的ffmpeg是支持原生aac编码的,所以可以直接使用 -c:a aac,低版本的ffmpeg像2.x的版本原生aac编码器是不完全支持的,必须同时指定 -strict -2 才可以使用。

    以上,我们介绍了手动指定音频解码器,成功的将视频转换成了音频。

    既然ffmpeg那么厉害,那如果我们不手动指定,它能自动帮我们选择合适的解码器处理吗?

    非常可以。

    以mp3为例,我们试下

    ffmpeg -i r1ori.mp4 -y r1-silent.mp3 
    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'r1ori.mp4': 
    ...... 
    Stream mapping: Stream #0:1 -> #0:0 (aac (native) -> mp3 (libmp3lame)) 
    ......

    注意看输出的过程代码中包含 Stream mapping 以及其下一行代码,可以看出ffmpeg的确自动为我们选择了libmp3lame解码器。

    如果原视频有多路音频流,又该如何操作呢?我们下节课再说。

  • 相关阅读:
    java期末复习2
    java期末复习
    Educational Codeforces Round 76 (Rated for Div. 2)
    ICPC南昌时间安排
    codeforces 597 div2 ABCDF
    codeforces 597 div2 ABC
    Vue中provide和inject 用法
    Js打印九九乘法表
    document.documentElement和document.body的区别
    移动端关于横屏问题
  • 原文地址:https://www.cnblogs.com/wwolf/p/ffmpeg-stream-selection-video-to-audio.html
Copyright © 2020-2023  润新知