转发自白狼栈:查看原文

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

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