关于ffmpeg:流的操作一视频转音频引发的血案

54次阅读

共计 3330 个字符,预计需要花费 9 分钟才能阅读完成。

转发自白狼栈:查看原文

有些小伙伴看文章十分仔细,对于上一节课不经意提到的一些边缘细节都比拟在意,比方 -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

执行该命令后发现报错了

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 解码器。

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

正文完
 0