yum install GeoIP-devel GeoIP-data
geoiplookup 119.86.73.30
geoiplookup www.qqvbc.com

waf防火墙modsecurity也支持通过geopip判断IP属地进行拦截

搬自:https://blog.csdn.net/weixin_42799222/article/details/105452373

安装
建议通过Composer来安装PHP-FFMpeg

$ composer require php-ffmpeg/php-ffmpeg

基本使用
注意:tp5需要全部添加斜杠,比如:

$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open('video.mpg');
$video
->filters()
->resize(new FFMpeg\Coordinate\Dimension(320, 240))
->synchronize();
$video
->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(10))
->save('frame.jpg');
$video
->save(new FFMpeg\Format\Video\X264(), 'export-x264.mp4')
->save(new FFMpeg\Format\Video\WMV(), 'export-wmv.wmv')
->save(new FFMpeg\Format\Video\WebM(), 'export-webm.webm');

查看支持的格式和滤镜

#查看支持的编解码器(也就是-vcodec后面可以接的参数):
ffmpeg -codecs > codec.txt

#查看支持的封装格式(也就是-f后面可以接的参数)
命令:ffmpeg -formats > formats.txt

#查看支持的滤镜(也就是-vf后面可以接的参数):
命令:ffmpeg -filters > filters.txt
$ffmpeg = FFMpeg\FFMpeg::create();

FFMpeg会自动探测 ffmpeg和ffprobe的二进制文件。如果你想给出确切的二进制文件路径, 可以通过一个数组来设置。

#A Psr\Logger\LoggerInterface can also be passed to log binary executions.

$ffmpeg = FFMpeg\FFMpeg::create(array(
'ffmpeg.binaries' => '/opt/local/ffmpeg/bin/ffmpeg',
'ffprobe.binaries' => '/opt/local/ffmpeg/bin/ffprobe',
'timeout' => 3600, // The timeout for the underlying process
'ffmpeg.threads' => 12, // The number of threads that FFMpeg should use
), $logger);

媒体操作
FFMpegFFMpeg根据URIs来创建媒体. URIs可以是本地的系统资源, HTTP网络资源,FFmpeg支持的任意资源。

注意:如果你想列出你用的FFmpeg支持的所有资源类型, 使用 -protocols 命令:

ffmpeg -protocols

使用 FFMpegFFMpeg::open 方法来打开一个资源。
$ffmpeg->open('video.mpeg');
两种类型的视频可以被处理: FFMpegMediaAudio 和 FFMpegMediaVideo。第三种类型 FFMpegMediaFrame, 可以通过视频来处理。

Video
FFMpegMediaVideo 可以被转码, ie: change codec, isolate audio or video. 帧可以提取。

转码
你可以通过FFMpegMediaVideo:save方法对视频进行转码,你将通过 FFMpegFormatFormatInterface来实现。

请注意视频或音频的比特率需要在格式中设置。

$format = new Format\Video\X264();
$format->on('progress', function ($video, $format, $percentage) {
echo "$percentage % transcoded";
});

$format
-> setKiloBitrate(1000)
-> setAudioChannels(2)
-> setAudioKiloBitrate(256);

$video->save($format, 'video.avi');

转码的过程可以被实时监控, 看下面有关Format的文档了解更过信息。

提取图片
你可以用FFMpegMediaVideo::frame 方法来提取任意时间的帧画面。

代码返回了一个媒体文件第42秒所对应的FFMpegMediaFrame 实例。你可以使用 FFMpegCoordinateTimeCode 作为参数, 看专业文档了解更多。

$frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(42));
$frame->save('image.jpg');

如果你想从视频中获取多种图片,你可以使用下边的过滤器

$video
->filters()
->extractMultipleFrames(FFMpeg\Filters\Video\ExtractMultipleFramesFilter::FRAMERATE_EVERY_10SEC, '/path/to/destination/folder/')
->synchronize();

$video
->save(new FFMpeg\Format\Video\X264(), '/path/to/new/file');

生成一个波

你可以使用 FFMpegMediaAudio::waveform 方法来从音频文件中生成一个波。

代码返回一个 FFMpegMediaWaveform 实例。你可以设置不同的尺寸作为参数, 查看API文档了解更多。

输出文件必须使用PNG extension.

$waveform = $audio->waveform(640, 120);
$waveform->save('waveform.png');

如果你想从视频文件中得到一个波, 需要先把视频文件转换成音频文件。

// Open your video file
$video = $ffmpeg->open( 'video.mp4' );

// Set an audio format
$audio_format = new FFMpeg\Format\Audio\Mp3();

// Extract the audio into a new file
$video->save('audio.mp3');

// Set the audio file
$audio = $ffmpeg->open( 'audio.mp3' );

// Create the waveform
$waveform = $audio->waveform();
$waveform->save( 'waveform.png' );

Filters

你可以使用 FFMpegMediaVideo::addFilter 方法在 FFMpegMediaVideo上使用过滤器。 视频接受视频和音频的过滤器。

你可以创建你自己的过滤器并且PHP-FFMpeg也附带了一些,你可以通过 FFMpegMediaVideo::filters 方法来使用它们。

过滤器是可以链接的

$video
->filters()
->resize($dimension, $mode, $useStandards)
->framerate($framerate, $gop)
->synchronize();

旋转

用给定的角度来旋转视频。

$video->filters()->rotate($angle);

$angle 的参数必须是下面的一个常量:

FFMpeg\Filters\Video\RotateFilter::ROTATE_90: 90° clockwise
FFMpeg\Filters\Video\RotateFilter::ROTATE_180: 180°
FFMpeg\Filters\Video\RotateFilter::ROTATE_270: 90° counterclockwise

调整尺寸
按照给定的尺寸调整视频的大小。

$video->filters()->resize($dimension, $mode, $useStandards);

调整尺寸的过滤器需要三个参数:

$dimension, 一个 FFMpeg\Coordinate\Dimension实例
$mode, FFMpeg\Filters\Video\ResizeFilter::RESIZEMODE_* constants常量中的一个。
$useStandards, 是否强制使用最新的比率标准的布尔

如果你想要视频处在一个非标准的比率, 你可以使用padding 过滤器 调整视频大小到想要的尺寸,包上黑色的条。

$video->filters()->pad($dimension);

pad 过滤器需要一个参数 :

$dimension, FFMpegCoordinateDimension的实例
然后的话不要忘记保存。

$video->save(new FFMpeg\Format\Video\X264(), $new_file);

水印
用给定的图片给视频文件添加水印。

$video
->filters()
->watermark($watermarkPath, array(
'position' => 'relative',
'bottom' => 50,
'right' => 50,
));

watermark 过滤器需要两个参数:

$watermarkPath, 你水印文件的路径; $coordinates, 一个定义水印放置位置的数组。你可以使用相对路径像上面展示的那样。或者使用绝对路径像这样:

$video
->filters()
->watermark($watermarkPath, array(
'position' => 'absolute',
'x' => 1180,
'y' => 620,
));

帧频

改变视频的帧频

$video->filters()->framerate($framerate, $gop);

framerate(帧频)过滤器需要两个参数:

$framerate, FFMpegCoordinateFramerate的实例
$gop, a GOP value (integer)
Synchronize(同步)
同步的音频和视频

一些容器使用延迟可能会导致不同步的输出。过滤器可以解决这个问题。

$video->filters()->synchronize();

Clip(修剪)

在想要的点减掉视频。

$video->filters()->clip(FFMpeg\Coordinate\TimeCode::fromSeconds(30), FFMpeg\Coordinate\TimeCode::fromSeconds(15));

The clip filter(修剪的过滤器)需要两个参数:

$start, 一个FFMpegCoordinateTimeCode实例, 指定开始剪切的点
$duration, 可选, 一个 FFMpegCoordinateTimeCode实例, 指定要持续的时间
Audio(音频)
FFMpegMediaAudio 可以被转码, ie: 改变编码解码器, 隔离视频和音频。帧可以被提取。

Transcoding(转码)

你可以用FFMpegMediaAudio:save 方法来给音频文件转码。你可以通过FFMpegFormatFormatInterface 来实现。

#Please note that audio kilobitrate is set on the audio format.

$ffmpeg = FFMpeg\FFMpeg::create();
$audio = $ffmpeg->open('track.mp3');

$format = new FFMpeg\Format\Audio\Flac();
$format->on('progress', function ($audio, $format, $percentage) {
echo "$percentage % transcoded";
});

$format
-> setAudioChannels(2)
-> setAudioKiloBitrate(256);

$audio->save($format, 'track.flac');

转码过程可以被实时监控, 看API文档了解更多。

Filters(过滤器)

你可以用FFMpegMediaAudio::addFilter 在FFMpegMediaAudio上应用过滤器的效果。只接受音频过滤器。

你可以创建你自己的过滤器并且PHP-FFMpeg也附带了一些,你可以通过 FFMpegMediaAudio::filters 方法来使用它们。

Metadata(元数据)

向音频文件中添加元数据。你可以数组的key=value键值对的形式添加你想要的元数据。如果过滤器中没有任何参数传递进来,那么所有的元数据将被从输入文件中删除。目前支持的数据有 title, artist, album, artist, composer, track, year, description, artwork

$audio->filters()->addMetadata(["title" => "Some Title", "track" => 1]);

//remove all metadata and video streams from audio file
$audio->filters()->addMetadata();

向音频文件中添加artwork

$audio->filters()->addMetadata(["artwork" => "/path/to/image/file.jpg"]);

注意: 当前ffmpeg (version 3.2.2) only supports 只支持 .mp3 文件的artwork输出

Resample(重采样)

重采样一个音频文件。

$audio->filters()->resample($rate);

重采样过滤器需要两个参数:
$rate, a valid audio sample rate value (integer)

帧是视频文件在某一个时间点的图片,看API了解更多。

你可以使用 FFMpegMediaFrame::save 方法来保存帧。

$frame->save('target.jpg');

这个方法还有一个可选的布尔类型的参数。设置这个参数为true可以获得更加精确的图片,可能稍微花多一点的时间去执行。

Gif

GIf是从视频文件中提取的一系列的动画图片。

你可以使用 FFMpegMediaGif::save 方法来保存gif文件。

$video = $ffmpeg->open( '/path/to/video' );
$video
->gif(FFMpeg\Coordinate\TimeCode::fromSeconds(2), new FFMpeg\Coordinate\Dimension(640, 480), 3)
->save($new_file);

这个方法有一个可选的布尔类型的参数,就是动画的持续时间。如果设置的话,可以得到一个确切的gif图片。

Concatenation(串联)

这个特性能够让你用混合的资源来生成一个视频或者音频。

现在有两种串联视频的方式,根据资源的编码解码器。如果你的资源都是采用的同一种编码解码器的话,你使用 FFMpegMediaConcatenate::saveFromSameCodecs 更好一些。 如果你的资源采用不同的编码解码器, 你要用到

FFMpeg\Media\Concatenate::saveFromDifferentCodecs.

#The first function will use the initial codec as the one for the generated file. With the second function, you will be able to choose which codec you want for the generated file.

#You also need to pay attention to the fact that, when using the saveFromDifferentCodecs method, your files MUST have video and audio streams.

#In both cases, you will have to provide an array of files.

To concatenate videos encoded with the same codec, do as follow:串联采用相同编码解码器的视频文件的话,参照下边的方法:

// In order to instantiate the video object, you HAVE TO pass a path to a valid video file.
// We recommand that you put there the path of any of the video you want to use in this concatenation.
$video = $ffmpeg->open( '/path/to/video' );
$video
->concat(array('/path/to/video1', '/path/to/video2'))
->saveFromSameCodecs('/path/to/new_file', TRUE);

保存函数中的布尔参数能让你使用拷贝的参数,这个参数可以大福度提高编码文件的生成过程。

#To concatenate videos encoded with the same codec, do as follow:

// In order to instantiate the video object, you HAVE TO pass a path to a valid video file.
// We recommand that you put there the path of any of the video you want to use in this concatenation.
$video = $ffmpeg->open( '/path/to/video' );

$format = new FFMpeg\Format\Video\X264();
$format->setAudioCodec("libmp3lame");

$video
->concat(array('/path/to/video1', '/path/to/video2'))
->saveFromDifferentCodecs($format, '/path/to/new_file');

在 FFMPEG中更多关于串联的细节 可看这里 here, here and here.

Formats(格式)
格式要实现 FFMpegFormatFormatInterface。 用FFMpegFormatVideoInterface来保存视频文件, 用 FFMpegFormatAudioInterface 来保存音频文件。

FFMpegFormatProgressableInterface的话可以获得转码的实时信息。

预定义的格式已经提供了事件的过程信息。

$format = new Format\Video\X264();
$format->on('progress', function ($video, $format, $percentage) {
echo "$percentage % transcoded";
});

$video->save($format, 'video.avi');

为事件提供的回调函数可以随时调用。

Add additional parameters
你可以根据你的视频格式为你的编码提供额外的参数。

setAdditionalParameters 方法的参数是一个数组。

$format = new Format\Video\X264();
$format->setAdditionalParameters(array('foo', 'bar'));
$video->save($format, 'video.avi');

创建你自己的格式
创建一种新的格式最简单的方法就是集成抽象类 FFMpegFormatVideoDefaultVideo and FFMpegFormatAudioDefaultAudio,并且实现下面的方法。

class CustomWMVFormat extends FFMpeg\Format\Video\DefaultVideo
{
public function __construct($audioCodec = 'wmav2', $videoCodec = 'wmv2')
{
$this
->setAudioCodec($audioCodec)
->setVideoCodec($videoCodec);
}

public function supportBFrames()
{
    return false;
}

public function getAvailableAudioCodecs()
{
    return array('wmav2');
}

public function getAvailableVideoCodecs()
{
    return array('wmv2');
}

Coordinates(坐标)
FFMpeg 使用很多单元来确定时间和空间坐标。

FFMpeg\Coordinate\AspectRatio 表示长宽比
FFMpeg\Coordinate\Dimension 表示一个维度
FFMpeg\Coordinate\FrameRate 表示帧速率
FFMpeg\Coordinate\Point 表示一个点
FFMpeg\Coordinate\TimeCode 表示一个时间码

FFProbe

FFMpegFFMpeg 内部使用FFMpegFFProbe来检查媒体文件。你也可以用它提取元数据。

$ffprobe = FFMpeg\FFProbe::create();
$ffprobe
->streams('/path/to/video/mp4') // extracts streams informations
->videos() // filters video streams
->first() // returns the first video stream
->get('codec_name'); // returns the codec_name property
$ffprobe = FFMpeg\FFProbe::create();
$ffprobe
->format('/path/to/video/mp4') // extracts file informations
->get('duration'); // returns the duration property

使用 Silex Microframework

Service provider is easy to set up:

$app = new Silex\Application();
$app->register(new FFMpeg\FFMpegServiceProvider());

$video = $app['ffmpeg']->open('video.mpeg');

下面是一些可能的选项:

$app->register(new FFMpeg\FFMpegServiceProvider(), array(
'ffmpeg.configuration' => array(
'ffmpeg.threads' => 4,
'ffmpeg.timeout' => 300,
'ffmpeg.binaries' => '/opt/local/ffmpeg/bin/ffmpeg',
'ffprobe.timeout' => 30,
'ffprobe.binaries' => '/opt/local/ffmpeg/bin/ffprobe',
),
'ffmpeg.logger' => $logger,
));

ffprobe是ffmpeg提供的三大工具之一,用来查看音视频文件的各种信息,比如:封装格式、音频/视频流信息、数据包信息等。
ffprobe的源码是ffprobe.c,开发过程中如果想获取ffprobe查看的信息,可以通过分析源码,获得对应字段。 本文主要介绍format、stream、Packet和Frame信息,包含每个字段的说明以及对应的ffmpeg字段。

查看音视频文件的封装格式

ffprobe -show_format inputFile
#输出如下信息:
[FORMAT]
// 文件名
filename=VID_20190811_113717.mp4
// 容器中流的个数,即AVFormatContext->nb_streams
nb_streams=2
// 即AVFormatContext->nb_programs
nb_programs=0
// 封装格式,即AVFormatContext->iformat->name
format_name=mov,mp4,m4a,3gp,3g2,mj2
// 即AVFormatContext->iformat->long_name
format_long_name=QuickTime / MOV
// 即AVFormatContext->start_time,基于AV_TIME_BASE_Q,换算为秒
start_time=0.000000
// 即AVFormatContext->duration,基于AV_TIME_BASE_Q,换算为秒
duration=10.508000
// 单位字节,即avio_size(AVFormatContext->pb)
size=27263322
// 码率,即AVFormatContext->bit_rate
bit_rate=20756240
// 即AVFormatContext->probe_score
probe_score=100
[/FORMAT]

查看音视频文件的流信息

ffprobe -show_streams inputFile
#输出如下信息:
[STREAM]
// 当前流的索引信息,对应于AVStream->index
index=0
// AVCodecDescriptor * cd = avcodec_descriptor_get(AVStream->codecpar->codec_id)
// 编码名称,即cd->name
codec_name=h264
// 编码全称,即cd->long_name
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
// 一个编码参数,可以为Baseline、Main、High等,Baseline无B帧,Main及以后可以包含B帧
// 通过avcodec_profile_name(AVStream->codecpar->codec_id, AVStream->codecpar->profile)获得
profile=High
// 流类型,即av_get_media_type_string(AVStream->codecpar->codec_type)
codec_type=video
// 即AVStream->codec->time_base
codec_time_base=14777/877500
// 通过宏av_fourcc2str(AVStream->codecpar->codec_tag)获得
codec_tag_string=avc1
// 对应AVStream->codecpar->codec_tag
codec_tag=0x31637661
// 有效区域的宽度,即AVStream->codecpar->width
width=1920
// 有效区域的高度,即AVStream->codecpar->height
height=1080
// 视频帧宽度,可能与上面的宽度不同,即AVStream->codec->coded_width,例如:当解码帧在输出前裁剪或启用低分辨率时
coded_width=1920
// 视频帧高度,可能与上面的高度不同,即AVStream->codec->coded_height,例如:当解码帧在输出前裁剪或启用低分辨率时
coded_height=1088
// 视频的延迟帧数,即AVStream->codecpar->video_delay
has_b_frames=0
// sar,单个像素的宽高比
// FFmpeg提供了多个sar:AVStream->sample_aspect_ratio、AVStream->codecpar->sample_aspect_ratio、AVFrame->sample_aspect_ratio
// 通过av_guess_sample_aspect_ratio获取最终的sar
sample_aspect_ratio=1:1
// dar,真正展示的图像宽高比,在渲染视频时,必须根据这个比例进行缩放
// 通过av_reduce计算得到,par * sar = dar
display_aspect_ratio=16:9
// 像素格式,即av_get_pix_fmt_name(AVStream->codecpar->format)
pix_fmt=yuvj420p
// 编码参数,即AVStream->codecpar->level
level=40
// 额外的色彩空间特征,即av_color_range_name(AVStream->codecpar->color_range),AVCOL_RANGE_MPEG对应tv,AVCOL_RANGE_JPEG对应pc
color_range=pc
// YUV彩色空间类型,即av_color_space_name(AVStream->codecpar->color_space)
color_space=bt470bg
// 颜色传输特性,即av_color_transfer_name(AVStream->codecpar->color_trc)
color_transfer=smpte170m
// 即av_color_primaries_name(AVStream->codecpar->color_primaries)
color_primaries=bt470bg
// 色度样品的位置,即av_chroma_location_name(AVStream->codecpar->chroma_location)
chroma_location=left
// 交错视频中字段的顺序,即AVStream->codecpar->field_order
field_order=unknown
// av_timecode_make_mpeg_tc_string处理AVStream->codec->timecode_frame_start获得
timecode=N/A
// 参考帧数量,即AVStream->codec->refs
refs=1
is_avc=true
// 表示用几个字节表示NALU的长度
nal_length_size=4
id=N/A
// 当前流的基本帧率,这个值仅是一个猜测,对应于AVStream->r_frame_rate
r_frame_rate=30/1
// 平均帧率,对应于AVStream->avg_frame_rate
avg_frame_rate=438750/14777
// AVStream的时间基准,即AVStream->time_base
time_base=1/90000
// 流开始时间,基于time_base,即AVStream->start_time
start_pts=0
// 转换(start_pts * time_base)之后的开始时间,单位秒
start_time=0.000000
// 流时长,基于time_base,即AVStream->duration
duration_ts=945728
// 转换(duration_ts * time_base)之后的时长,单位秒
duration=10.508089
// 码率,即AVStream->codecpar->bit_rate
bit_rate=19983544
// 最大码率,即AVStream->codec->rc_max_rate
max_bit_rate=N/A
// Bits per sample/pixel,即AVStream->codec->bits_per_raw_sample
bits_per_raw_sample=8
// 视频流中的帧数,即AVStream->nb_frames
nb_frames=312
nb_read_frames=N/A
nb_read_packets=N/A
// 下面TAG为AVStream->metadata中的信息
// 逆时针的旋转角度(相当于正常视频的逆时针旋转角度)
TAG:rotate=90
// 创建时间
TAG:creation_time=2019-08-11T03:37:28.000000Z
// 语言
TAG:language=eng
TAG:handler_name=VideoHandle
// SIDE_DATA为AVStream->side_data数据
[SIDE_DATA]
// side_data数据类型,Display Matrix表示一个3*3的矩阵,这个矩阵需要应用到解码后的视频帧上,才能正确展示
side_data_type=Display Matrix
displaymatrix=
00000000:            0       65536           0
00000001:       -65536           0           0
00000002:            0           0  1073741824
// 顺时针旋转90度还原视频
rotation=-90
[/SIDE_DATA]
[/STREAM]
[STREAM]
// 当前流的索引信息,对应于AVStream->index
index=1
// AVCodecDescriptor * cd = avcodec_descriptor_get(AVStream->codecpar->codec_id)
// 编码名称,即cd->name
codec_name=aac
// 编码全称,即cd->long_name
codec_long_name=AAC (Advanced Audio Coding)
// 通过avcodec_profile_name(AVStream->codecpar->codec_id, AVStream->codecpar->profile)获得
profile=LC
// 流类型,即av_get_media_type_string(AVStream->codecpar->codec_type)
codec_type=audio
// 即AVStream->codec->time_base
codec_time_base=1/48000
// 通过宏av_fourcc2str(AVStream->codecpar->codec_tag)获得
codec_tag_string=mp4a
// 对应AVStream->codecpar->codec_tag
codec_tag=0x6134706d
// 采样点格式,通过av_get_sample_fmt_name(AVStream->codecpar->format)获取
sample_fmt=fltp
// 采样率,即AVStream->codecpar->sample_rate
sample_rate=48000
// 通道数,即AVStream->codecpar->channels
channels=2
// 通道布局,与channels是相对应,通过av_bprint_channel_layout获取,stereo表示立体声
channel_layout=stereo
// 每个采样点占用多少bit,即av_get_bits_per_sample(par->codec_id)
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
// AVStream的时间基准,即AVStream->time_base
time_base=1/48000
// 流开始时间,基于time_base,即AVStream->start_time
start_pts=0
// 转换(start_pts * time_base)之后的开始时间,单位秒
start_time=0.000000
// 流时长,基于time_base,即AVStream->duration
duration_ts=502776
// 转换(duration_ts * time_base)之后的时长,单位秒
duration=10.474500
// 码率,即AVStream->codecpar->bit_rate
bit_rate=156002
// 最大码率,即AVStream->codec->rc_max_rate
max_bit_rate=156000
// Bits per sample/pixel,即AVStream->codec->bits_per_raw_sample
bits_per_raw_sample=N/A
// 音频流中的帧数,即AVStream->nb_frames
nb_frames=491
nb_read_frames=N/A
nb_read_packets=N/A
TAG:creation_time=2019-08-11T03:37:28.000000Z
TAG:language=eng
TAG:handler_name=SoundHandle
[/STREAM]
  • SAR(Sample Aspect Ratio): 单个像素宽高比,即每个像素宽度与高度的比值,所以可以认为像素不是正方形的。
  • PAR(Pixel Aspect Ratio): 像素数宽高比,图像的横向采集点数与纵向采集点数的比值,即像素个数的比值。。
  • DAR(Display Aspect Ratio): 显示宽高比,图像最终展示的宽高比,播放器在渲染视频帧时,需要保持DAR的比例。
  • 它们之间的关系:PAR * SAR = DAR

下面看一个例子,如下图所示:每个方格代表一个像素,宽度为5像素,高度为4像素,即PAR=5 : 4。 假设图像的显示宽度为160,高度为120,即DAR=4 : 3。 那么可以计算出SAR = DAR / PAR = 16 : 15,表示像素方格是一个长方形。 dar示例

FFmpeg提供了多个SAR:

AVStream->sample_aspect_ratio
AVStream->codecpar->sample_aspect_ratio
AVFrame->sample_aspect_ratio 最终的SAR是通过av_guess_sample_aspect_ratio获取的。 对于DAR,AVStream->display_aspect_ratio的值始终为0:0,参考ffprobe代码,可知DAR是通过av_reduce计算得到的,如下所示:

AVRational sar, dar;
// par
AVCodecParameters *par = AVStream->codecpar;
// 计算出sar
sar = av_guess_sample_aspect_ratio(AVFormatContext, AVStream, NULL);
// 根据par和sar计算出dar
av_reduce(&dar.num, &dar.den, par->width * sar.num, par->height * sar.den,  1024*1024);

查看音视频文件的数据包信息

// -select_streams表示选择音频或者视频
ffprobe -show_format [-select_streams audio | video] inputFile

#首先看下视频流的第一个Packet和第二个Packet:
[PACKET]
//Packet类型,即av_get_media_type_string(AVStream->codecpar->codec_type)
codec_type=video
// 当前帧所属流的索引信息,对应于AVStream->index
stream_index=0
// 帧展示时间,即AVPacket->pts,基于AVStream->time_base时间基准
pts=0
// 换算为秒
pts_time=0.000000
// 帧解码时间,即AVPacket->dts,基于AVStream->time_base时间基准
dts=0
// 换算为秒
dts_time=0.000000
// 当前帧的时长,等于下一帧的pts - 当前帧pts,即AVPacket->duration,基于AVStream->time_base时间基准
duration=12972
// 换算为秒
duration_time=0.144133
// AVPacket->convergence_duration,也是基于AVStream->time_base时间基准
convergence_duration=N/A
// 换算为秒
convergence_duration_time=N/A
// 当前帧的Size,字节,即AVPacket->size
size=187872
// 当前帧地址偏移量,即AVPacket->pos
pos=830842
flags=K_
[/PACKET]
[PACKET]
codec_type=video
stream_index=0
pts=12972
// 即 12972 / 90000
pts_time=0.144133
dts=12972
dts_time=0.144133
duration=2999
duration_time=0.033322
convergence_duration=N/A
convergence_duration_time=N/A
size=31200
// 上一帧的pos + size
pos=1018714
flags=__
[/PACKET]

#然后看下音频流的第一个Packet和第二个Packet:
[PACKET]
// 音频帧
codec_type=audio
// 当前帧所属流的索引信息,对应于AVStream->index
stream_index=1
// 帧展示时间,即AVPacket->pts,基于AVStream->time_base时间基准
pts=0
pts_time=0.000000
// 帧解码时间,即AVPacket->dts,基于AVStream->time_base时间基准
dts=0
dts_time=0.000000
// 当前帧的时长,等于下一帧的pts - 当前帧pts,即AVPacket->duration,基于AVStream->time_base时间基准
duration=1024
// 1024 / 48000
duration_time=0.021333
convergence_duration=N/A
convergence_duration_time=N/A
size=416
pos=810458
flags=K_
[/PACKET]
[PACKET]
// 音频帧
codec_type=audio
stream_index=1
pts=1024 
// 1024 / 48000
pts_time=0.021333
dts=1024
dts_time=0.021333
duration=1024
duration_time=0.021333
convergence_duration=N/A
convergence_duration_time=N/A
size=416
// 上一帧的pos + size
pos=810874
flags=K_
[/PACKET]

查看音视频文件解码后的帧信息

// -select_streams表示选择音频或者视频
ffprobe -show_frames [-select_streams audio | video] inputFile
#首先看下视频流的第一帧和第二帧:
[FRAME]
// 帧类型,即av_get_media_type_string(AVStream->codecpar->codec_type)
media_type=video
// 当前帧所属流的索引信息, 对应于AVStream->index
stream_index=0
// 是否关键帧,1:关键帧,0:非关键帧,即AVFrame->key_frame
key_frame=1
// 帧展示时间, 即AVFrame->pts, 基于AVStream->time_base时间基准
pkt_pts=0
// 换算为秒
pkt_pts_time=0.000000
// 帧解码时间,从对应的AVPacket copy而来,即AVFrame->pkt_dts,基于AVStream->time_base时间基准
pkt_dts=0
// 换算为秒
pkt_dts_time=0.000000
// 帧时间戳,基本与pts相同,即AVFrame->best_effort_timestamp,基于AVStream->time_base时间基准
best_effort_timestamp=0
// 换算为秒
best_effort_timestamp_time=0.000000
// 对应的AVPacket的帧时长,即AVFrame->pkt_duration,基于AVStream->time_base时间基准
pkt_duration=12972
// 换算为秒
pkt_duration_time=0.144133
// 从最后一个已输入解码器的AVPacket重新排序的pos,即AVFrame->pkt_pos
pkt_pos=830842
// 对应的AVPacket的帧size,即AVFrame->pkt_size
pkt_size=187872
// 旋转之前的帧宽度,即AVFrame->width
width=1920
// 旋转之前的帧高度,即AVFrame->height
height=1080
// 视频帧的像素格式,即av_get_pix_fmt_name(AVFrame->format)
pix_fmt=yuvj420p
// sar,图像采集时,横向采集点数与纵向采集点数的比例
// FFmpeg提供了多个sar:AVStream->sample_aspect_ratio、AVStream->codecpar->sample_aspect_ratio、AVFrame->sample_aspect_ratio
// 通过av_guess_sample_aspect_ratio获取最终的sar
sample_aspect_ratio=1:1
// 视频帧的图片类型,此处为I帧,即av_get_picture_type_char(frame->pict_type)
pict_type=I
// picture number in bitstream order, 即AVFrame->coded_picture_number
coded_picture_number=0
// picture number in display order, 即AVFrame->display_picture_number
display_picture_number=0
// 视频帧内容是否是交错的, 即AVFrame->interlaced_frame
interlaced_frame=0
// 若视频帧内容是交错的,表示首先展示的顶部字段,即AVFrame->top_field_first
top_field_first=0
// 当解码时,这个信号表明视频帧必须延迟多少。extra_delay = repeat_pict / (2*fps), 即AVFrame->repeat_pict
repeat_pict=0
// 额外的色彩空间特征,即av_color_range_name(AVFrame->color_range),AVCOL_RANGE_MPEG对应tv,AVCOL_RANGE_JPEG对应pc
color_range=pc
// YUV彩色空间类型,即av_color_space_name(AVFrame->colorspace)
color_space=bt470bg
// 即av_color_primaries_name(AVFrame->color_primaries)
color_primaries=bt470bg
// 颜色传输特性,即av_color_transfer_name(AVFrame->color_trc)
color_transfer=smpte170m
// 色度样品的位置,即av_chroma_location_name(AVFrame->chroma_location)
chroma_location=left
[/FRAME]
[FRAME]
media_type=video
stream_index=0
// 非关键帧
key_frame=0
pkt_pts=12972
// 12972 / 90000
pkt_pts_time=0.144133
pkt_dts=12972
pkt_dts_time=0.144133
best_effort_timestamp=12972
best_effort_timestamp_time=0.144133
pkt_duration=2999
pkt_duration_time=0.033322
pkt_pos=1018714
pkt_size=31200
width=1920
height=1080
pix_fmt=yuvj420p
sample_aspect_ratio=1:1
// 视频帧的图片类型,此处为P帧,即av_get_picture_type_char(frame->pict_type)
pict_type=P
coded_picture_number=1
display_picture_number=0
interlaced_frame=0
top_field_first=0
repeat_pict=0
color_range=pc
color_space=bt470bg
color_primaries=bt470bg
color_transfer=smpte170m
chroma_location=left
[/FRAME]

#然后看下音频流的第一帧和第二帧:
[FRAME]
// 帧类型,即av_get_media_type_string(AVStream->codecpar->codec_type)
media_type=audio
// 当前帧所属流的索引信息, 对应于AVStream->index
stream_index=1
// 是否关键帧
key_frame=1
// 帧展示时间, 即AVFrame->pts, 基于AVStream->time_base时间基准
pkt_pts=0
// 换算为秒
pkt_pts_time=0.000000
// 帧解码时间,从对应的AVPacket copy而来,即AVFrame->pkt_dts,基于AVStream->time_base时间基准
pkt_dts=0
// 换算为秒
pkt_dts_time=0.000000
// 帧时间戳,基本与pts相同,即AVFrame->best_effort_timestamp,基于AVStream->time_base时间基准
best_effort_timestamp=0
// 换算为秒
best_effort_timestamp_time=0.000000
// 对应的AVPacket的帧时长,即AVFrame->pkt_duration,基于AVStream->time_base时间基准
pkt_duration=1024
// 换算为秒
pkt_duration_time=0.021333
// 从最后一个已输入解码器的AVPacket重新排序的pos,即AVFrame->pkt_pos
pkt_pos=810458
// 对应的AVPacket的帧size,即AVFrame->pkt_size
pkt_size=416
// 音频采样点格式,即av_get_sample_fmt_name(AVFrame->format)
sample_fmt=fltp
// 当前音频帧的采样点数,即AVFrame->nb_samples
nb_samples=1024
// 通道数,即AVFrame->channels
channels=2
// 通道布局,通过av_bprint_channel_layout得到,与channels对应
channel_layout=stereo
[/FRAME]
[FRAME]
media_type=audio
stream_index=1
key_frame=1
pkt_pts=1024
pkt_pts_time=0.021333
pkt_dts=1024
pkt_dts_time=0.021333
best_effort_timestamp=1024
best_effort_timestamp_time=0.021333
pkt_duration=1024
pkt_duration_time=0.021333
pkt_pos=810874
pkt_size=416
sample_fmt=fltp
nb_samples=1024
channels=2
channel_layout=stereo
[/FRAME]

相关参考文章列表:
中文文档:https://www.longqi.cf/tools/2015/02/13/ffmpegcn/
https://www.jianshu.com/p/aba78d738c5d
https://blog.csdn.net/yu540135101/article/details/84311244
https://cloud.tencent.com/developer/article/1972715

ffmpeg是一个非常快的视频和音频转换器,还可以抓取实时的音频/视频流。它可以在任意的采样率之间的转换和调整视频,并同时使用高品质的多相滤波器。

ffmpeg从输入“文件”(其可以是常规文件,管道,网络流,录制装置等),由指定任意数量的读取-i选项,并写入到任意数量的输出“文件”,只需指定一个输出的文件名。任何一个命令行中不能被解释为选项的内容都被认为是一个输出文件名。

ffmpeg命令行要点:

作为一般规则,选项作用于下一个指定的文件。因此,命令的顺序是重要,你可以在命令行上多次相同的选项。每次选项的出现都将作用于下一个输入或输出文件。这条规则若有例外将会提前声明(例如冗余级别)。

不要混合输入和输出文件。首先指定所有输入文件,那么所有的输出文件。也不要混用属于不同的文件的选项。所有选项仅适用于下一个输入或输出文件,之后选项将被重置

引用输入文件的选项时,则必须使用他们的索引(从0开始)。例如:第一输入文件是0 ,第二个是1等。类似地,一个文件中的流也通过其索引指定。例如2:3指的是在第三个输入文件中的第四数据流。参见流章节

每个输入或输出文件可以在原则上,包含任意数量的不同类型(视频/音频/字幕/附件/数据)的流。输出文件中允许流的数量和类型是由输出格式容器限制决定的。输入流和输出流直接的映射可以自动完成也可以用-map选项给定(见流选择章节)。

format 选项可能需要指定,对于原始输入文件。

滤镜

在编码之前, ffmpeg可以使用libavfilter库中的滤镜处理原始的音频和视频帧。几个连接的滤镜可以形成一个滤镜组(filtergraphs)。 ffmpeg有两种filtergraphs:简单和复杂。

简单filtergraphs

简单filtergraphs是那些具有相同的类型且正好一个输入和输出的滤镜组。另外,在上图中,他们可以由简单地在解码和编码之间插入附加步骤来表示:

 _________                        ______________
|         |                      |              |
| decoded |                      | encoded data |
| frames  |\                   _ | packets      |
|_________| \                  /||______________|
             \   __________   /
  simple     _\||          | /  encoder
  filtergraph   | filtered |/
                | frames   |
                |__________|

简单filtergraphs配置了每个流的筛选器选项(与视频和音频分别-vf和-af别名)。一个简单的FilterGraph动态视频可以看一下这样的例子:

 _______        _____________        _______        ________
|       |      |             |      |       |      |        |
| input | ---> | deinterlace | ---> | scale | ---> | output |
|_______|      |_____________|      |_______|      |________|

需要注意的是一些滤镜改变帧属性而不是画面的内容。例如,在上例中,fps改变帧的数量,但不触及帧的内容。又如setpts滤镜,其仅设置时间戳而保持帧不变。

复杂filtergraphs

复杂filtergraphs是那些不能被描述为简单的线性处理链的滤镜组。例如,当滤镜组具有多个输入和/或输出,或当输出流的类型是不同于输入。它们可以被表示为以下图:

 _________
|         |
| input 0 |\                    __________
|_________| \                  |          |
             \   _________    /| output 0 |
              \ |         |  / |__________|
 _________     \| complex | /
|         |     |         |/
| input 1 |---->| filter  |\
|_________|     |         | \   __________
               /| graph   |  \ |          |
              / |         |   \| output 1 |
 _________   /  |_________|    |__________|
|         | /
| input 2 |/
|_________|

复杂filtergraphs可使用-filter_complex选项配置。注意,此选项是全局性的,因为复杂FilterGraph,就其本质,不能明确地与单个流或文件相关联。

-lavfi选项相当于-filter_complex。

一个复杂FilterGraph动态的简单的例子是在overlay滤镜,它具有两个视频输入和一个视频输出,含有一个视频重叠在另一个的上面。其对应的音频滤镜是amix。

复制流

复制流是通过添加copy选项到-codec选项完成的。它使ffmpeg对指定的流忽略解码和编码步骤,所以它只能混合和拆包。它用于改变所述容器的格式或修改容器级别的元数据是有用的。在这种情况下,可以简化为这样:

 _______              ______________            ________
|       |            |              |          |        |
| input |  demuxer   | encoded data |  muxer   | output |
| file  | ---------> | packets      | -------> | file   |
|_______|            |______________|          |________|

由于不存在解码或编码,它是非常快,没有质量损失。然而因为许多因素的工作,它可能无法在某些情况下使用。应用滤镜显然也是不可能的,因为滤镜仅能作用在未压缩的数据上。

4 选择流

默认情况下, ffmpeg只包含输入文件中每个类型流各一个(视频,音频,字幕),并将它们添加到每个输出文件。它选择“最好”的每一个流基于以下标准:用于视频,它选择最高分辨率的流;对于音频,它使用最多声道的流;对于字幕,它是第一个字幕流。在相同类型中,参数相等的若干流中具有最低索引的流被选择。

您可以通过-vn/-an/-sn选项禁用其中的一些默认值。若需全手动控制,请使用-map选项,它将禁用刚才所描述的默认设置。

5 选项

所有的数值选项中,如果不另外指明,均表示接受数作为输入,其后可添加一个SI单位的字符串,例如:K,M,或G。

如果i被附加在SI单位,完整的前缀将被解释为一个单元前缀的二进制倍数,也即1024倍,而不是1000倍。追加B可使数值增加8倍。这允许使用,例如:KB,MiB,G和B的数量后缀。

选项​​不带参数是布尔选项,并设置相应的值设置为true。他们可以通过在选项前添加no来将选项设置为false。例如使用-nofoo将设置名称为foo为假

流标识符

有些选项是按流的,例如比特率或编解码器。流标识符被用来精确地指定一个给定的选项作用于哪一个数据流(多个)。

一个标识符一般是选项名称加冒号分隔的字符串。例如-codec:a:1 ac3包含流标识符a:1,它匹配第二音频流。因此,将选择AC3编解码器的第二音频流。

一个标识符可以匹配多个流,这个选项将适用于所有流。比如,流标识符-b:a 128k标识了所有的音频流。

空标识符匹配所有的流。例如, -codec copy或-codec: copy会复制所有的数据流而不重新编码。

流标识符的可能形式有:

stream_index

匹配与该索引对应的流。例如-threads:1 4将设置第二个流的线程计数为4。

stream_type[:stream_index]

流类型是下列字母之一:v为视频,a为声音,s为字幕,d为数据,t为附件。如果stream_index给出,则它匹配该类型的索引为stream_index的流。否则,它匹配所有这种类型的流。

p:program_id[:stream_index]

如果给定stream_index,那其将与在与ID为 program_id的program的stream_index的流相匹配。否则,它将匹配在program_id中的所有流。

#stream_id 或者 i:stream_id

按流索引逐一匹配流(如在MPEG-TS容器中的PID)。

m:key[:value]

匹配流的元数据标签中具有指定key的流。如果value 没有给出,将匹配包含给定标签的所有流。

请注意,在ffmpeg中,按元数据匹配仅能用于输入文件

================== 以上内容摘自 https://www.longqi.cf/tools/2015/02/13/ffmpegcn

比较重要和复杂的两个参数

-filter_complex
-map

查看文件的详情流信息

ffprobe -show_streams -of json video/concataudio.mp4

ffprobe  input.mp4
ffprobe -show_data input.mp4
ffprobe -show_packets input.mp4
ffprobe -show_format input.mp4
ffprobe -show_frames input.mp4
ffprobe -show_streams input.mp4

//打印帧数
ffprobe -v error -count_frames -select_streams v:0 
        -show_entries stream=nb_read_frames 
        -of default=nokey=1:noprint_wrappers=1 input.mp4

-v error这隐藏了“info”输出(版本信息等),使解析更容易。
-count_frames计算每个流的帧数,并在相应的流部分中报告。
-select_streams v:0仅选择视频流中第一条流。
-show_entries stream = nb_read_frames只显示读取的帧数。
-of default = nokey = 1:noprint_wrappers = 1将输出格式设置为默认值,不打印每个字段的键(nokey = 1),不打印节头和页脚(noprint_wrappers = 1)。

ffprobe -print_format json -show_streams input.mp4

(1)-print_format json 以json格式打印
(2)-show_streams 打印所有的流信息

剪裁视频

-vf crop的参数格式为w:h:x:y,
w、h为输出视频的宽和高,
x、y标记输入视频中的某点,将该点作为基准点,向右下进行裁剪得到输出视频。如果x y不写的话,默认居中剪切
例子:

ffmpeg -i 3.mp4 -vf crop=400:400 33.mp4 -y
ffmpeg -i 3.mp4 -vf crop=400:400:0:0 333.mp4 -y

剪切视频

ffmpeg -ss 00:00:00 -t 00:00:30 -i test.mp4 -vcodec copy -acodec copy output.mp4
  • -ss 指定从什么时间开始
  • -t 指定需要截取多长时间
  • -i 指定输入文件

用以上命令剪的视频可能会发现多出几秒?

原因是剪切点不是关键帧,命令会在关键帧处进行剪切

将所有的帧的编码方式转为帧内编码,这个问题就有解了。

ffmpeg -i INPUT -sameq -intra OUTPUT

-i 输入,后面是空格,紧跟着就是输入视频文件;
INPUT 输入文件;
-sameq 表示保持同样的视频质量;
-intra, 帧内编码;
OUTPUT 输出文件名。

如:

ffmpeg -i ./MyVideo.mpg -sameq -intra ./temp.mpg

## 注意:上面的命令在新版本中已经废弃,可以参考下面的命令
ffmpeg -i output.mp4 -strict -2  -qscale 0 -intra keyoutput.mp4

以下两个参数还不明白有什么用,有大佬提到过这两个参数,有兴趣可以研究下:
-accurate_seek 使时间更精准
-avoid_negative_ts 1 寻找结尾时关键帧进行补全

剪辑合并例子

#截取从头开始的30s
ffmpeg -ss 00:00:00 -t 00:00:30 -i keyoutput.mp4 -vcodec copy -acodec copy split.mp4
#截取从30s开始的30s
ffmpeg -ss 00:00:30 -t 00:00:30 -i keyoutput.mp4 -vcodec copy -acodec copy split1.mp4
#进行视频的合并
ffmpeg -f concat -i list.txt -c copy concat.mp4
#如果报错:Operation not permitted,加上-safe 0参数
ffmpeg -f concat -i list.txt -safe 0 -c copy concat.mp4
#合并视频,并去掉音频(-an),如果存在文件则自动覆盖
ffmpeg -f concat -i list.txt -c copy -an concat.mp4 -y
#合并后的视频在浏览器查看时,总时长和视频时长不对,播放到中间时直接跳到结束,合并时用-to参数,而不要用-t参数
ffmpeg -f concat -i list.txt -c copy -an -to 10 concat.mp4 -y

在list.txt文件中,对要合并的视频片段进行了描述。
内容如下

file ./split.mp4
file ./split1.mp4

视频旋转和翻转

参考文章:https://cloud.tencent.com/developer/article/1638406

ffmpeg -i input.mp4 -vf "transpose=1" output.mp4
#或者使用语义化的参数名称。
ffmpeg -i input.mp4 -vf "transpose=clock" output.mp4

这里,transspose=1 表示顺时针90度转置给定的视频。

下面是转置功能可用的参数列表:

0-逆时针旋转90度,垂直翻转。这也是默认设置。
1-顺时针旋转90度。
2-逆时针旋转90度。
3-顺时针旋转90度,垂直翻转。
要将视频顺时针旋转180度,需要像下面这样转置两次。

ffmpeg -i input.mp4 -vf "transpose=2,transpose=2" output.mp4
##要把视频水平翻转的话,可以先0,再1转回去
ffmpeg -i input.mp4 -vf "transpose=0,transpose=1" output.mp4

hue:调整视频色调、饱和度、亮度

h:色调角度度数(0到360),默认值为0,对应CSS3的 filter: hue-rotate(0deg);
s:饱和度(-10到10),默认值为1, 请注意 0 值表示黑白图片,对应CSS3的 filter: saturate(100%);
b:亮度(-10到10),默认值为0,对应CSS3的 filter: brightness(100%);
命令格式:ffmpeg -i 源视频地址 -vf hue=s=1:b=1:h=90 -b 输出比特率 输出视频地址
使用例子:(调整饱和度)

ffmpeg -i d:\2.flv -vf hue=b=1 -b 600k d:\outTemp.flv

colorbalance:颜色平衡,调整RGB得值的权重,分为三个阶层,用于调整饱和度和调整颜色偏移值

rs、gs、bs:调整红色,绿色和蓝色阴影(最暗的像素)(范围:-1到1)
rm、gm、bm:调整红色,绿色和蓝色中间色(中等像素)(范围:-1到1)
rh、gh、bh:调整红色,绿色和蓝色的亮点(最亮的像素)(范围:-1到1)
命令格式:ffmpeg -i 源视频地址 -vf colorbalance=rh=.3:gh=.3:bh=.3 -b 输出比特率 输出视频地址
使用例子:(增加红色权重)

ffmpeg -i d:\2.flv -vf colorbalance=rh=.3 -b 600k d:\outTemp.flv

给视频增加背景音乐

ffmpeg -y -i input.mp4 -i back.wav -filter_complex "[0:a] pan=stereo|c0=1*c0|c1=1*c1 [a1], [1:a] pan=stereo|c0=1*c0|c1=1*c1 [a2],[a1][a2]amix=duration=first,adelay=3000|3000,pan=stereo|c0<c0+c1|c1<c2+c3,pan=mono|c0=c0+c1[a]" -map "[a]" -map 0:v -c:v libx264 -c:a aac -strict -2 -ac 2 output.mp4

添加文字 drawtext

ffmpeg -i original.mp4 -vf drawtext=fontcolor=black:fontsize=50:text='Hello World':x=0:y=100 -y out.mp4. 

#前5秒加文字
ffmpeg -i bunny.mp4 -vf drawtext=fontcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='test':x=50:y=50:enable='lte(t\,5)'   -y out.mp4. 

#后五秒加文字
ffmpeg -i original.mp4 -vf drawtext=fontcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='test':x=50:y=50:enable='gte(t\,5)'   -y out.mp4. 

#第十秒到第二十秒加文字
ffmpeg -i original.mp4 -vf drawtext=fontcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='test':x=50:y=50:enable='between(t\,10\,20)'   -y out.mp4. 

#切片的时候使用 比如每个切片10秒 对第二个切片的前5秒 加文字 也就是总文件的10~15秒 当前切片的前5秒
ffmpeg -i original.mp4 -vf drawtext=fontcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='test':x=50:y=50:enable='between(t+10\,0\,15)'   -y out.mp4 

#显示5秒 然后5秒不显示 然后再显示5秒 然后5秒不显示; 依次。。
ffmpeg -i original.mp4 -vf drawtext=fontcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='test':x=50:y=50:enable='lte(mod(t\,10)\,5)'   -y out.mp4

#5秒显示hello 接着5秒显示world 依次。
ffmpeg -i original.mp4 -vf drawtext=fontcolor=red:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='hello':x=50:y=50:enable='lte(mod(t\,2)\,1)',drawtext=fontcolor=red:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='world':x=50:y=50:enable='gte(mod(t\,2)\,1)'  -y out.mp4

参数:
between(x, min, max)
Return 1 if x is greater than or equal to min and lesser than or equal to max, 0 otherwise.
...
gt(x, y)
Return 1 if x is greater than y, 0 otherwise.

gte(x, y)
Return 1 if x is greater than or equal to y, 0 otherwise.

...
if(x, y)
Evaluate x, and if the result is non-zero return the result of the evaluation of y, return 0 otherwise.

if(x, y, z)
Evaluate x, and if the result is non-zero return the evaluation result of y, otherwise the evaluation result of z.
...
lt(x, y)
Return 1 if x is lesser than y, 0 otherwise.

lte(x, y)
Return 1 if x is lesser than or equal to y, 0 otherwise.

...
mod(x, y)
Compute the remainder of division of x by y.

如何通过FFmpeg删除某个特定音轨,如果有多个音轨的时候会有用的?

使用FFmpeg删除特定音频,map命令来删除特定音轨。

map命令的通用语法是:

-map input_file_index:stream_type_specifier:stream_index

然后,你可以通过-map 0:a:1(从0开始计数)从视频中选择第二个音轨。在上文的例子中,如果你的文件中有一个视频和两个音轨,那么你就可以使用-map 0:a:1只选择第二个音轨,并将它复制到你的最终输出文件中。

同样,-map 0是指选择第一个输入文件中的所有数据(包括音频和视频),所以你需要先选择所有数据,然后取消选择音频。

ffmpeg.exe -i videoWithAudio.mp4 -map 0 -map 0:a:1 -copy videoOutput.mp4

如果电影中有5个音轨,除了第一个,其他你都想选择。这个时候你可以使用反向的map命令(在map命令的参数前加负号)。使用-map -0:a:0 这一命令,FFmpeg在选择时就会忽略第一个音轨。反向的map非常强大!

实际上,我们已在前文学习了使用 -an命令从视频中删除音频。你可以通过如下方式,使用反向的map来达到相同的效果。

ffmpeg -i videoWithAudio.mp4 -map 0 -map -0:a videoWithoutAudio.mp4

添加音频

#如果音频时长>视频时长,则后面没有画面更新,相反则没有音频内容
ffmpeg -i video.mp4 -i audio.mp3 -c copy -map 0:v:0 -map 1:a:0 videoWithAudio.mp4
#加上 -shortest 参数时,确保当达到较短的输入文件(两个输入文件之一)长度时停止转换(但是播放时视频时长仍然显示最长的资源时长,使用-to参数可解决这个问题)
ffmpeg -i video.mp4 -i audio.mp3 -map 0:0 -map 1:0 -c:v copy -c:a libmp3lame -q:a 1 -shortest videoWithAudio.mp4

#使用 -to position (output)参数,在position位置停止输出,-to和-t是相互排斥的,-t具有优先权。
#position可能是一个表示秒数的数,或hh:mm:ss[.xxx]形式。
#使用 -fs limit_size (output) 设置文件大小限制,以字节表示。

##视频mp4重新编码,音频也重新编码(也可以用“-c:v h264”、“-c:a mp3”来进行上述操作,这样的话不用知道编码器名)
ffmpeg -i video.mp4 -i audio.mp3 -map 0:0 -map 1:0 -c:v libx264  -c:a libmp3lame -q:a 1 -shortest videoWithAudio.mp4

使用map命令将视频和音频分别从不同的文件中复制到同一个输出文件。
-map 0:v:0 选择了第0个输入文件(视频输入)的第0个轨道。
–map 1:a:0 选择了第一个输入文件(音频输入)的第0个轨道。
不用重新编码,-c copy同时复制音轨和视轨到输出文件。如果你想要重新编码,可以选择合适的音视频编解码器,配置相应的编码质量。

提取视频中的音频, -vn 不要视频画面

#提取音频,使用-acodec copy 复制而不是重新编码
ffmpeg -i videoWithAudio.mp4 -vn -acodec copy onlyAudio.aac

#提取时重新编码 libmp3lame 格式, -q:a 1 音频质量(质量分布范围为0~6,其中0表示高质量音频,6表示低质量音频)
ffmpeg.exe -i videoWithAudio.mp4 -vn -c:a libmp3lame -q:a 1 onlyAudio.mp3

替换音频内容 -map 选择通道,-c:v 视频编码 -c:a 音频编码

语法 : -map input_file_index:stream_type_specifier:stream_index.

ffmpeg -i video_with_audio.mp4 -i newAudio.wav \
-map 0:0 \
-map 1:0 \
-c:v copy \
-c:a libmp3lame -q:a 1 \
-shortest \  video_with_newAudio.mp4

在上文的例子中,我们需要从一个文件中获取视频以及另一个文件中获取音频。而map命令非常便捷地完成了上述操作。我们从第一个输入文件(视频)中选择第0个轨道,并从第2个输入文件(音频)中选择第0个轨道。
然后我们原样复制视频并重新编码音频,再将它们一起放入新的文件中。如果你不想重新编码音频,你只需使用-a:c copy命令,那么音频就只被复制而不会重新编码。

加上 -shortest 参数时,确保当达到较短的输入文件(两个输入文件之一)长度时停止转换

画面淡入淡出,用到了 -vf fade滤镜功能

#0秒处淡入,时长1秒,并在9秒处淡出,时长1秒
ffmpeg -i video.mp4 -vf fade=t=in:st=0:d=1,fade=t=out:st=9:d=1  video1.mp4

#长视频在剪切的时候,加入淡入淡出的效果
ffmpeg -ss 00:00:00 -t 00:00:10 -i video.mp4 -vf fade=t=in:st=0:d=0.5,fade=t=out:st=9.5:d=0.5 video1.mp4

制作视频水印需求

给一段视频加上一张静态图片制作的logo,在网上已经有很多例子了,只要把它放置在视频的固定位置即可,这个功能非常容易实现:

ffmpeg -i video.mp4 -i logo.jpg -filter_complex "[1:v]scale=w=120:h=120:\
force_original_aspect_ratio=decrease:force_divisible_by=2[logo];\
[0:v][logo]overlay=x=32:y=64" \
new_video.mp4

详细的操作步骤是:
将输入的任意尺寸图片都等比例缩放至不大于120x120大小的小图,并且缩放时计算的尺寸保持宽高均为偶数;
将上一步缩放好的图片放置在主视频的(32,64)位置上。
输入的logo是一张静态图片,从视频的角度上说,它只有1帧,因此它会一直“卡”在这一帧上,然后经过缩放后交给后续滤镜处理

淡入淡出水印的实现思路
但正是在制作带淡入淡出的水印时,遇到了标题中所述的问题。
淡入淡出功能,在FFmpeg中有现成的fade滤镜。但是如果直接加入此滤镜,输出结果与想象的结果完全不同——画面没有logo出现。
下面的命令是有问题的:

ffmpeg -i video.mp4 -i logo.jpg -filter_complex "[1:v]scale=w=120:h=120:\
force_original_aspect_ratio=decrease:force_divisible_by=2,\
fade=t=in:s=160:n=15:alpha=1,\
fade=t=out:s=230:n=20:alpha=1[logo];\
[0:v][logo]overlay=x=32:y=64" \
new_video.mp4

但是总体思路是没有问题的:

微信图片_20220807142014.png

那么问题出在哪里了?其实问题是因为上面提到的logo图片一直“卡”在一帧上,导致fade滤镜无法触发后续的计算,而fade滤镜启用了alpha通道方式淡入,在淡入之前,alpha会被设置为0,因此后续logo一直是透明输入,看不到叠加效果。

改进实现
知道了问题所在,那是不是让FFmpeg把logo图片当做视频流输入,就可以触发淡入淡出滤镜的计算了呢?答案是:正确。

ffmpeg -i video.mp4 -loop 1 -i logo.jpg ... -shortest new_video.mp4

在输入logo图片前增加-loop 1参数,开启此输入的循环选项;
这样图片就会变成一个永不停止的静态视频源
在输出文件前增加-shortest参数,让生成的视频最短化。
由于logo图片已经变成了永不停止的视频源,如果不加此参数,会一直输出,因此千万不要忘了。
问题又来了:原视频流时长:10.04秒,加入logo后视频流时长:12.36秒,夸张地增加了2秒多

ffprobe -show_streams -of json new_video.mp4
# 加logo后视频长度
"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 158208,
"duration": "12.360000",
# 加logo后音频长度
"time_base": "1/44100",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 443381,
"duration": "10.053991",

通过查阅文档,发现overlay滤镜中提供了一个类似的shortest选项,专门用来处理这种情况。
在overlay滤镜后启用该选项即可

overlay=x=32:y=64:shortest=1

既然在overlay滤镜中已经将logo视频流截断了,那么就可以去掉-shortest输出参数了。

ffmpeg -i video.mp4 -loop 1 -i logo.jpg ...overlay=x=32:y=64:shortest=1... new_video.mp4

此时再查看输出视频信息:

# 加logo后视频长度
"time_base": "1/12800",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 128512,
"duration": "10.040000",
# 加logo后音频长度
"time_base": "1/44100",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 443381,
"duration": "10.053991",

可以看到,输出文件视频流时间长度与原视频一致。音频流时长稍微长一点点,可以在拼接时修正掉,如果是单个文件播放,可忽略不计。

常用命令如下

# 去掉视频中的音频
ffmpeg -i input.mp4 -vcodec copy -an output.mp4
# -an: 去掉音频;-vcodec:视频选项,一般后面加copy表示拷贝

# 提取视频中的音频
ffmpeg -i input.mp4 -acodec copy -vn output.mp3
# -vn: 去掉视频;-acodec: 音频选项, 一般后面加copy表示拷贝

# 音视频合成
ffmpeg -y –i input.mp4 –i input.mp3 –vcodec copy –acodec copy output.mp4
# -y 覆盖输出文件

#剪切视频
ffmpeg -ss 0:1:30 -t 0:0:20 -i input.mp4 -vcodec copy -acodec copy output.mp4
# -ss 开始时间; -t 持续时间

# 视频截图
ffmpeg –i test.mp4 –f image2 -t 0.001 -s 320x240 image-%3d.jpg
# -s 设置分辨率; -f 强迫采用格式fmt;

# 视频分解为图片
ffmpeg –i test.mp4 –r 1 –f image2 image-%3d.jpg
# -r 指定截屏频率

# 将图片合成视频
ffmpeg -f image2 -i image%d.jpg output.mp4

#视频拼接
ffmpeg -f concat -i filelist.txt -c copy output.mp4

# 将视频转为gif
ffmpeg -i input.mp4 -ss 0:0:30 -t 10 -s 320x240 -pix_fmt rgb24 output.gif
# -pix_fmt 指定编码

# 将视频前30帧转为gif
ffmpeg -i input.mp4 -vframes 30 -f gif output.gif

# 旋转视频
ffmpeg -i input.mp4 -vf rotate=PI/2 output.mp4

# 缩放视频
ffmpeg -i input.mp4 -vf scale=iw/2:-1 output.mp4
# iw 是输入的宽度, iw/2就是一半;-1 为保持宽高比

#视频变速
ffmpeg -i input.mp4 -filter:v setpts=0.5*PTS output.mp4

#如果担心会出现丢帧的情况,可以使用 -r 指定输入帧数,我们想4倍播放:
ffmpeg -i input.mkv -r 60 -filter:v "setpts=0.25*PTS" output.mkv

#音频变速(2表示2倍速)
ffmpeg -i input.mp3 -filter:a atempo=2.0 output.mp3

#音视频同时变速,但是音视频为互倒关系
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mp4

#音视频同时变速(setpts=0.5相当于2倍速,atempo就=2,换算:1/0.5,setpts=2,atempo=0.5 (换算1/2))
ffmpeg -i input.mkv -r 60 -filter:v "setpts=0.5*PTS" -filter:a atempo=2 output.mkv

# 视频添加水印
ffmpeg -i input.mp4 -i logo.jpg -filter_complex [0:v][1:v]overlay=main_w-overlay_w-10:main_h-overlay_h-10[out] -map [out] -map 0:a -codec:a copy output.mp4
# main_w-overlay_w-10 视频的宽度-水印的宽度-水印边距;

# 截取视频局部
ffmpeg -i in.mp4 -filter:v "crop=out_w:out_h:x:y" out.mp4
# 截取部分视频,从[80,60]的位置开始,截取宽200,高100的视频
ffmpeg -i in.mp4 -filter:v "crop=80:60:200:100" -c:a copy out.mp4
# 截取右下角的四分之一
ffmpeg -i in.mp4 -filter:v "crop=in_w/2:in_h/2:in_w/2:in_h/2" -c:a copy out.mp4
# 截去底部40像素高度
ffmpeg -i in.mp4 -filter:v "crop=in_w:in_h-40" -c:a copy out.mp4

参数说明

参数说明:

-vcodec xvid 使用xvid压缩
-s 320x240 指定分辨率
-r fps 设置帧频 缺省25
-b <比特率> 指定压缩比特

-acodec aac 设定声音编码
-ac <数值> 设定声道数,1就是单声道,2就是立体声
-ar <采样率> 设定声音采样率,PSP只认24000
-ab <比特率> 设定声音比特率
-vol <百分比> 设定音量

-y(覆盖输出文件

-t duration 设置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持
-ss position 搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持
-title string 设置标题
-author string 设置作者
-copyright string 设置版权
-hq 激活高质量设置

-aspect aspect 设置横纵比 4:3 16:9 或 1.3333 1.7777
-croptop size 设置顶部切除带大小 像素单位
-cropbottom size -cropleft size -cropright size
-padtop size 设置顶部补齐的大小 像素单位
-padbottom size -padleft size -padright size -padcolor color 设置补齐条颜色(hex,6个16进制的数,红:绿:兰排列,比如 000000代表黑色)
-bt tolerance 设置视频码率容忍度kbit/s
-maxrate bitrate设置最大视频码率容忍度
-minrate bitreate 设置最小视频码率容忍度
-bufsize size 设置码率控制缓冲区大小
-vcodec codec 强制使用codec编解码方式。 如果用copy表示原始编解码数据必须被拷贝。
-sameq 使用同样视频质量作为源(VBR)
-pass n 选择处理遍数(1或者2)。两遍编码非常有用。第一遍生成统计信息,第二遍生成精确的请求的码率
-passlogfile file 选择两遍的纪录文件名为file

-map file:stream 设置输入流映射
-debug 打印特定调试信息
0.常用参数快捷:
主要参数:
-i——设置输入文件名。
-f——设置输出格式。
-y——若输出文件已存在时则覆盖文件。
-fs——超过指定的文件大小时则结束转换。
-t——指定输出文件的持续时间,以秒为单位。
-ss——从指定时间开始转换,以秒为单位。
-t从-ss时间开始转换(如-ss 00:00:01.00 -t 00:00:10.00即从00:00:01.00开始到00:00:11.00)。
-title——设置标题。
-timestamp——设置时间戳。
-vsync——增减Frame使影音同步。
-c——指定输出文件的编码。
-metadata——更改输出文件的元数据。
-help——查看帮助信息
影像参数:
-b:v——设置影像流量,默认为200Kbit/秒。(单位请引用下方注意事项)
-r——设置帧率值,默认为25。
-s——设置画面的宽与高。
-aspect——设置画面的比例。
-vn——不处理影像,于仅针对声音做处理时使用。
-vcodec( -c:v )——设置影像影像编解码器,未设置时则使用与输入文件相同之编解码器。
声音参数:
-b:a——设置每Channel(最近的SVN版为所有Channel的总合)的流量。(单位请引用下方注意事项)
-ar——设置采样率。
-ac——设置声音的Channel数。
-acodec ( -c:a ) ——设置声音编解码器,未设置时与影像相同,使用与输入文件相同之编解码器。
-an——不处理声音,于仅针对影像做处理时使用。
-vol——设置音量大小,256为标准音量。(要设置成两倍音量时则输入512,依此类推。)

工具使用

virtualenv

python环境,利用这个工具可以使用不同的python环境

pip3 install virtualenv
#use:在这个目录创建一个环境
virtualenv --system-site-package -p python ./tf112
#cmd 使用这个环境,进去后命令行前面会有一个tf112标识
.\tf112\Scripts\activate

anaconda

python环境,利用这个工具可以使用不同的python环境

jupyter

jupyter是一个web应用,交互式的python代码的在线运行、测试工具
官网:https://jupyter.org/
安装:

pip install jupyterlab
pip install notebook
#运行
jupyter notebook
#通过 Voilà 可以将Jupyter Notebook转换为交互式仪表板,以便与他人共享您的作品。
#Voilà可以用作独立应用程序,也可以用作Jupyter的扩展。
#安装
pip install voila
#独立运行
voila <path-to-notebook> <options>
#将第三方小部件与瞧声结合使用,默认情况下,Voilà 不提供作为经典笔记本扩展 (nbextension) 安装的 Jupyter Widgets。要让 Voilà 独立应用程序为 nbextensions 提供服务,请按如下方式使用该标志:enable_nbextensions
voila --enable_nbextensions=True
#使用 Voilà 作为服务器扩展时:
jupyter notebook --VoilaConfiguration.enable_nbextensions=True

matplotlib

官网:https://matplotlib.org/
如下即可画一个线条图:
请输入图片描述

import numpy as np 
from matplotlib import pyplot as plt 
 
x = np.arange(1,11) 
y =  2  * x +  5 
plt.title("Matplotlib demo") 
plt.xlabel("x axis caption") 
plt.ylabel("y axis caption") 
plt.plot(x,y) 
plt.show()

更多简单的列子:https://www.runoob.com/numpy/numpy-matplotlib.html

pandas 使用:
以后的学习笔记参见:git@e.coding.net:youxianbo/rengongzhinengxuexixiangmu/jupyter.git