软件研究之Ffmpeg

标签: 无 分类: 未分类 创建时间:2024-01-13 06:48:32 更新时间:2024-11-23 10:24:26

1.前言

最近遇到的项目就是利用网站播放视频,于是我研究了 流媒体 技术,其中较多的就是利用 ffempeg 将mp4转换为m3u8格式。

参考文章:
【1】.FFmpeg常用推流命令
【2】.网站播放视频较慢,利用mp4转m3u8解决
【3】.视频直播支持的分辨率和对应合适的码率 1920×1080:500 kbps~4000 kbps。
【4】.FFMPEG之视频编码那些事儿 视频压缩:帧内压缩(Intraframe compression)、帧间压缩(Interframe compression)、GOP(Group Of Picture)

2.安装

2.1.windows

(1) 下载
(2) 解压之后,配置环境变量

1
ffmpeg -version

(3) 使用

1
ffmpeg -i E:\demo\demo.MP4 -profile:v baseline -level 3.0 -s 640x360 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls E:\demo\demo.m3u8

2.2.linux

最新版的 ffmpeg-master-latest-linux64-gpl.tar.xz 版本,可以不用编译,直接下载解压配置环境变量就可以使用了。

(1) 下载

(2) 解压

1
2
3
4
# 第一步
xz -d ffmpeg-master-latest-linux64-gpl.tar.xz
# 第二步
tar -xvf ffmpeg-master-latest-linux64-gpl.tar.xz

(3)配置环境变量

1
2
3
vi /etc/profile

export PATH=/usr/local/ffmpeg/bin:$PATH

(4)查看是否安装成功

1
ffmpeg -version

(5)执行命令生成
和windows上一样,也是可以直接使用命令执行的。

3.Java

其实不安装ffmpeg的二进制,直接使用java也是可以的。
(1)引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- Optional GPL builds with (almost) everything enabled -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform-gpl</artifactId>
<version>6.0-1.5.9</version>
</dependency>

<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.0-1.5.9</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.9</version>
</dependency>
参考文章:
【1】.Maven相关依赖

(2)核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  /**
* mp4, m3u8
*
* @param filePathName 需要转换文件
* @param toFilePath 需要转换的文件路径
*/
public static String mp4ToM3u8(String filePathName, String toFilePath) throws Exception {

avutil.av_log_set_level(avutil.AV_LOG_INFO);
FFmpegLogCallback.set();

//加载文件
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(filePathName);
//grabber.setAudioChannels(1);
grabber.start();
String fileName = FileNameUtil.getName(filePathName);
fileName=fileName.substring(0,fileName.indexOf("."));

if(!FileUtil.isDirectory(toFilePath)){
FileUtil.mkdir(toFilePath);
}
File tempFile3 = new File(toFilePath, fileName + ".m3u8");

FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(tempFile3, grabber.getImageWidth(),
grabber.getImageHeight(), grabber.getAudioChannels());
// 格式方式
recorder.setFormat("hls");
//关于hls_wrap的说明,hls_wrap表示重复覆盖之前ts切片,这是一个过时配置,ffmpeg官方推荐使用hls_list_size 和hls_flags delete_segments代替hls_wrap
//设置单个ts切片的时间长度(以秒为单位)。默认值为2秒
File fromFile=new File(filePathName);
Long fileSize=fromFile.length();
String hlsTime="10"; // 切片时间
long G=1024*1024*1024;
if(fileSize>=0.2*G){
hlsTime="1";
}
recorder.setOption("hls_time", hlsTime);

//不根据gop间隔进行切片,强制使用hls_time时间进行切割ts分片
recorder.setOption("hls_flags", "split_by_time");

//设置播放列表条目的最大数量。如果设置为0,则列表文件将包含所有片段,默认值为5
// 当切片的时间不受控制时,切片数量太小,就会有卡顿的现象
recorder.setOption("hls_list_size", "0");
//自动删除切片,如果切片数量大于hls_list_size的数量,则会开始自动删除之前的ts切片,只保留hls_list_size个数量的切片
recorder.setOption("hls_flags", "delete_segments");
//ts切片自动删除阈值,默认值为1,表示早于hls_list_size+1的切片将被删除
recorder.setOption("hls_delete_threshold", "1");
/*hls的切片类型:
* 'mpegts':以MPEG-2传输流格式输出ts切片文件,可以与所有HLS版本兼容。
* 'fmp4':以Fragmented MP4(简称:fmp4)格式输出切片文件,类似于MPEG-DASH,fmp4文件可用于HLS version 7和更高版本。
*/
recorder.setOption("hls_segment_type", "mpegts");
//指定ts切片生成名称规则,按数字序号生成切片,例如'file%03d.ts',就会生成file000.ts,file001.ts,file002.ts等切片文件
//recorder.setOption("hls_segment_filename", toFilePath + "-%03d.ts");
recorder.setOption("hls_segment_filename", toFilePath + File.separator + fileName + "-%5d.ts");

//加密,生成加密key
// String prefixName = toFilePath + File.separator + fileName;
// String secureFileName = prefixName + ".key";
// byte[] secureRandom = getSecureRandom();
// FileUtil.writeBytes(secureRandom,secureFileName);
// String toHex = Convert.toHex(secureRandom);
// String keyInfoPath = toFilePath + File.separator +"key.keyinfo";
// //写入加密文件
// writeKeyInfo(keyInfoPath,fileName + ".key",secureFileName,toHex);
// recorder.setOption("hls_key_info_file", keyInfoPath);

// 设置第一个切片的编号
// recorder.setOption("start_number", String.valueOf(tsCont));
// recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);

// 转码
log.info("{} | 启动Hls转码录制器……", toFilePath);
// 设置零延迟
//recorder.setVideoOption("tune", "zerolatency");
recorder.setVideoOption("tune", "fastdecode");
// 快速
recorder.setVideoOption("preset", "ultrafast");
// recorder.setVideoOption("crf", "26");
recorder.setVideoOption("threads", "12");
recorder.setVideoOption("vsync", "2");
recorder.setFrameRate(grabber.getFrameRate());// 设置帧率
// recorder.setGopSize(25);// 设置gop,与帧率相同,相当于间隔1秒chan's一个关键帧
// recorder.setVideoBitrate(100 * 1000);// 码率500kb/s

// recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
// 设置编码
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);


//如果想截取规定时间段视频
// recorder.start();
// Frame frame;
// while ((frame = grabber.grabImage()) != null) {
// try {
// recorder.record(frame);
// } catch (FrameRecorder.Exception e) {
// log.error("转码异常:{}", e);
// }
// }
recorder.start(grabber.getFormatContext());
AVPacket packet;
while ((packet = grabber.grabPacket()) != null) {
try {
recorder.recordPacket(packet);
} catch (FrameRecorder.Exception e) {
log.error("转码异常:{}", e);
}
}
recorder.setTimestamp(grabber.getTimestamp());
recorder.stop();
recorder.release();
grabber.stop();
grabber.release();

File dest = new File(filePathName);
if (dest.isFile() && dest.exists()) {
dest.delete();
log.warn("临时文件 {}已删除", dest.getName());
}
log.info("转码m3u8:{}", tempFile3.getAbsolutePath());
return tempFile3.getAbsolutePath();
}
参考文章:
【1】.Java使用FFmpeg实现mp4转m3u8 这里从安装到 java 调用,讲到都非常的详细。
【2】.在 java 中使用 ffmpeg 的四个阶段 阶段一:字符串阶段;阶段二:封装阶段;阶段三:工具类阶段;阶段四:最终阶段
【3】.javacv ffmpeg 本地还需要装ffmpeg吗
【4】. Java整合ffmpeg视频处理的正确使用方式 最后还是使用了命令行的形式进行的。
【5】.springboot 通过javaCV 实现mp4转m3u8 上传oss 这是主要的代码。
【6】.java中File转为MultipartFile的四种方式
【7】.如果通过javacv来调用ffmpeg解析mp4视频为m3u8,内存式hls切片.通过流的方式来保存? 这里还提供了利用 chrome 进行测试的方法,安装Play HLS M3u8 插件,如果没有,那么自己找个离线可以播m3u8的软件即可
【8】.Java实现视频加密及播放 这里使用了 nginx 进行了转发。

5.前端播放

可以使用 hls.js 进行播放,还可以使用 xgplay-hls 进行播放。

参考文章:
【1】.xgplayer-hls hls 播放插件,H264 和 H265 编码格式(H265支持解析,能否播放取决于浏览器是否支持H265编码格式)

6.编码加密

因为我在设置的时候,总是无法编码成 h264 格式,所以就想着去尝试下其他的方式,不知道行不行的。

参考文章:
【1】.chrome 如何开启HEVC硬件解码 前期chrome官方版本一直未支持H265,因此前期只能通过自己编译chrome源码来生成H265定制浏览器,但是不支持硬解码的缺陷一直是一个大坑,我们一度准备放弃chrome浏览器,前几天忽然听说chrome 105以上的稳定版本已经集成了HEVC解码并且支持硬解
【2】.ffmpeg 用显卡转码切片hls m3u8文件的方法 key加密 ffmpeg 无损HLS切片参数例如,注意压制时关键帧设置1秒

7.视频压缩

我有几个文件,1080p的文件,没有压缩之前达到了3.7G的大小,就算是用1s钟进行分片,结果还是无法打开播放。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
private static final int FRAME_RATE = 30; // 帧率
private static final int VIDEO_BITRATE = 1024*1024; // 比特率
private static final int COMPRESS_WIDTH = 1080; // 视频宽高

/**
* 在使用时发现视频压缩和视频时长有关系
* 一个9M的56s的视频压缩后视频7M多
* 一个22M的5s的视频压缩后视频624K
* @param inputMp4Path
* @return
*/
public static String compressionVideo(String inputMp4Path) {
File file=new File(inputMp4Path);

FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file.getAbsolutePath());
String fileName = null;

Frame captured_frame = null;

FFmpegFrameRecorder recorder = null;

try {
frameGrabber.start();
fileName = file.getAbsolutePath().replace(".MP4", "_edited.mp4");
log.info("wight:{},height:{}",frameGrabber.getImageWidth(), frameGrabber.getImageHeight());

int height = frameGrabber.getImageHeight();
int widht = frameGrabber.getImageWidth();
if(needCompress(file.length())){
height = calculateHeight(frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), COMPRESS_WIDTH);
widht = COMPRESS_WIDTH;
log.info("new wight:{},height:{}",widht, height);
}
recorder = new FFmpegFrameRecorder(fileName, widht, height, frameGrabber.getAudioChannels());
recorder.setFrameRate(FRAME_RATE);
//下面这行打开就报错
//recorder.setSampleFormat(frameGrabber.getSampleFormat());
recorder.setSampleRate(frameGrabber.getSampleRate());
//recorder.setAudioChannels(1);
recorder.setVideoOption("preset", "veryfast");
// yuv420p,像素
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.setVideoBitrate(VIDEO_BITRATE);
recorder.setFormat("mp4");
//比特
//recorder.setVideoBitrate(VIDEO_BITRATE);
recorder.start();

while (true) {
try {
captured_frame = frameGrabber.grabFrame();
if (captured_frame == null) {
System.out.println("!!! end cvQueryFrame");
break;
}
recorder.setTimestamp(frameGrabber.getTimestamp());
recorder.record(captured_frame);
} catch (Exception e) {
}
}
recorder.stop();
recorder.release();
frameGrabber.stop();
} catch (Exception e) {
e.printStackTrace();
}
//file.delete();
return fileName;
}

/**
* 是否需要压缩,大于3MB
* @param length
* @return
*/
public static boolean needCompress(long length){
log.info("video size:{}", length);
return length >= 3145728;
}

/**
* 等比计算新高度
* @param w
* @param h
* @param nw
* @return
*/
private static int calculateHeight(int w, int h, int nw){
double s = Integer.valueOf(h).doubleValue() / Integer.valueOf(w).doubleValue();
int height = (int) (nw * s);
//如果宽和高不是偶数recorder.start();会报错
if(height % 2 !=0){
height += 1;
}
return height;
}
参考文章:
【1】.JAVA,实现视频压缩(最全) Java压缩视频大小,10M视频压缩完成后大约是1M,用时大约2S
【2】.Java 压缩视频(无需安装插件) 这里用了 jave-nativebin-osx64 这个东西。
【3】.为什么我的带有Hls.js视频播放器的应用程序在3-4个小时后就会结冰呢?
【4】.ffmpeg实例,比特率码率(-b)、帧率(-r)和文件大小(-fs)相关操作 帧率(Frame rate)也叫帧频率,帧率是视频文件中每一秒的帧数,肉眼想看到连续移动图像至少需要15帧。码率也叫比特率(Bit rate)(也叫数据率)是一个确定整体视频/音频质量的参数,秒为单位处理的字节数,码率和视频质量成正比,在视频文件中中比特率用bps来表达。控制输出文件大小。
【5】.JavaCV开发详解之4:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地) 这个的代码里面的注释倒是挺多的,比如比特率、质量、音频等的设置。还包括了一些视频抓取之类的东西。
【6】.javacv FFmpeg 视频压缩 这里的代码还是挺好用的,进行了视频压缩重采样,好用。
【7】.使用ffmpeg缩小视频体积的几种方式 调整视频的分辨率;调整视频的码率;使用更高效的视频编码格式;
【8】.java实现,无损视频大小压缩 这里用了这个插件 it.sauronsoftware

问题

(1)av_interleaved_write_frame() error -2 while writing interleaved audio packet

这个问题就是启用了 加密,如果把加密的地方注销掉,就会出现这个问题,下面的代码就是,可以不加密,但是不能没有加密文件。

1
2
3
4
5
6
7
8
9
10
11
12
//生成加密key
String prefixName = toFilePath + File.separator + fileName;
String secureFileName = prefixName + ".key";
byte[] secureRandom = getSecureRandom();
FileUtil.writeBytes(secureRandom,secureFileName);
String toHex = Convert.toHex(secureRandom);
String keyInfoPath = toFilePath + File.separator +"key.keyinfo";
//写入加密文件
writeKeyInfo(keyInfoPath,fileName + ".key",secureFileName,toHex);

// 加密
recorder.setOption("hls_key_info_file", keyInfoPath);

(2)hls.js 播放黑屏,只有声音

大部分的文章都是因为 h265 编码的问题,但是我设置的编码格式是 h264的编码格式啊。

1
2
3
// 设置编码格式
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);

【尝试方案】
(1) 修改编码方式,多次重新编译。

【解决方案】
最后的解决方案是将 hls_segment_type 设置为 fmp4 而不是 mpegts。

1
2
3
4
5
6
7
8
9
/*hls的切片类型:
* 'mpegts':以MPEG-2传输流格式输出ts切片文件,可以与所有HLS版本兼容。
* 'fmp4':以Fragmented MP4(简称:fmp4)格式输出切片文件,类似于MPEG-DASH,fmp4文件可用于HLS version 7和更高版本。
*/
// 原先
recorder.setOption("hls_segment_type", "mpegts");

// 改为
recorder.setOption("hls_segment_type", "fmp4");
参考文章:
【1】.从s3存储桶播放.m3u8文件时出现视频黑屏和仅有声音的问题 这里加了一个 X-Amz-Meta-File-Range-Start=0 请求参数
【2】.hls.js播放m3u8为什么黑屏,控制台的log正常,ts文件也一直在解析? 大概率是因为H.265导致的。
【3】.主流视频编码器特点、优缺点归纳和比较(H.264、HEVC、VP9、AV1) High Efficiency Video Coding,又称H.265/HEVC,是一种新的视频压缩标准,用来扩充H.264/AVC编码标准,2013年1月26号,HEVC正式成为国际标准,收取版税。为了应对互联网流媒体、通信、视频会议、数字存储媒体和电视广播等各种应用对运动图像更高压缩率的日益增长的需求而开发的。
【4】.m3u8流文件在html视频播放器中播放有声音无画面问题 故视频解码时无法正常解码,所以只需要在海康的摄像头中更改流媒体格式为H264,那么视频就可以正常播放了
【5】.JAVA ~ FFmpegFrameRecorder用H264编码封装mp4 有声音无图像 这里设置了 avcodec.AV_CODEC_ID_H264,并设置了 setFormat(“mp4”),但是对我没有效果。
【6】.java网络摄像头播放、截图、rtsp转m3u8 这里提供了 rtsp转m3u8,具体的方法和前面的差不多。

(3)无法加密

当设置了 recorder.setOption(“hls_segment_type”, “fmp4”),但是就无法进行加密了,recorder.setOption(“hls_key_info_file”, keyInfoPath),否则就会报错。

1
2
3
4
5
6
7
/*hls的切片类型:
* 'mpegts':以MPEG-2传输流格式输出ts切片文件,可以与所有HLS版本兼容。
* 'fmp4':以Fragmented MP4(简称:fmp4)格式输出切片文件,类似于MPEG-DASH,fmp4文件可用于HLS version 7和更高版本。
*/
recorder.setOption("hls_segment_type", "fmp4");
//加密
// recorder.setOption("hls_key_info_file", keyInfoPath);

【解决方案】
最后我也没有解决,尝试了很多次,结果也都是这个样子的,没有什么意外,只能先放弃了。

(4)设置 hls_time 不能按时间进行分片,有的多有的少

参考文章:
【1】.关于 javacv hls 切片结果很模糊的为 recorder.setGopSize(2 * frameRate);//设置 gop
【2】. 流媒体直播实时视频延迟时间排查和剖析:gop关键帧间隔导致延迟,流媒体和播放器缓存,B帧等导致的延迟 原创
【3】.使用FFmpeg命令进行hls切片,得到的ts文件时长不准确,如何精确控制m3u8切片时长
【4】.基本概念 为便于您更好的理解视频点播产品,您可以在使用前了解视频格式、视频编码、视频转码等基本概念。

(5)moov atom not found

有些视频文件可以被压缩,有些视频不能压缩,不知道什么原因,压缩的时候报错:[libx264 @ 0x7fc7497d9d00] non-strictly-monotonic PTS。“Application provided invalid, non monotonically increasing dts to muxer in stream 0”

【解决方法】
经过我多方的测试和查找,后来我发现这个原始视频的帧率有些不正确,原视频的帧率是29.53fps,后来我统一改成了 30.0 fps。

1
recorder.setFrameRate(FRAME_RATE);
参考文章:
【1】.How to Fix Video ‘Moov Atom Not Found’ Error?
【2】.3个方案解决视频“Moov Atom Not Found”错误问题 方法 1. 使用万兴易修的视频修复功能修复视频错误。方法 2. 使用 qtfaststart 修复 FFMPEG “Moov Atom Not Found”。方法 3. 使用 MP4box 解决“Moov Atom Not Found”视频错误。
【3】.ffmpeg使用libx264编码时,为何一直出现x264 [warning]: non-strictly-monotonic PTS?
【4】.FFmpeg h.264 mp4编码告警:non-strictly-monotonic PTS 选用ABR需要注意两个设置,fps和输出帧pts计算。切换到h.265编码倒没这个警告,
【5】.Web端H.265播放器研发解密 音视频编解码对于前端工程师是一个比较少涉足的领域,涉及到流媒体技术中的文本、图形、图像、音频和视频多种理论知识的学习,才能够应用到具体实践中,我们自研web播放器并支持h.265解码,在码率优化的大背景下(保持画质不变情况下,应用图像增强、roi区域检测、智能场景分类和h265编解码等多种技术能力,将码流降低50%。

(6) invalid DTS: PTS is less than DTS

有些视频进行压缩的时候,就出现了问题。出现这种错误是由于视频pts大于dts。解释是:pts是视频播放时间,dts是送入解码器解码时间。所以一帧视频播放时间必须在解码时间点之后。
【尝试方案】
(1).使用packet进行压缩,结果没有效果。

1
2
3
4
for (; (avPacket = frameGrabber.grabPacket()) != null;) {
// 封装/复用
recorder.recordPacket(avPacket);
}

(2).在while循环中的合适位置添加if(pkt.pts < pkt.dts) continue; 这个方法没有搞定。

(3).取消了时间戳设置

1
recorder.setTimestamp(frameGrabber.getTimestamp()); // 注释掉了

(4) 使用只存储关键帧的方法

1
2
3
4
5
if(captured_frame.keyFrame){
recorder.setTimestamp(frameGrabber.getTimestamp());
recorder.record(captured_frame);
}

【解决方法】
最后的解决方法让我非常的崩溃,只是注释了 recorder.setTimestamp(frameGrabber.getTimestamp()); 这句话,让解码器自动计算时间戳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 recorder.start();
Frame captured_frame = null;
while (true) {
try {
captured_frame = frameGrabber.grabFrame();
if (captured_frame == null) {
System.out.println("!!! end cvQueryFrame");
break;
}
// 主要就是删除了这句话
// recorder.setTimestamp(frameGrabber.getTimestamp());
recorder.record(captured_frame);
} catch (Exception e) {
log.error("captured_frame",e);
}
}
参考文章:
【1】.【FFmpeg】关于对错误pts () < dts () in stream的解决方法 在while循环中的合适位置添加 if(pkt.pts < pkt.dts) continue;
【2】.PTS 和 DTS 理解
【3】.深入理解FFmpeg的Packet和Frame数据结构 Packet是FFmpeg中用于封装音视频数据的基本单元。Frame是FFmpeg中用于存储解码后的音视频数据的数据结构。在解码阶段,解码器会将解码后的音视频数据填充到Frame中。一个Frame中包含了一帧完整的音视频数据,通过Frame的成员变量可以获取到这些数据的相关信息,如宽度、高度、采样率等。
【4】.如何跨平台调用ffmpeg?史上最简单基于JavaCV跨平台执行ffmpeg命令 这里有一个地方就是使用
【5】.java 视频转码 视频压缩 这里有视频大小分辨率建议码率,还有码率公式。
【6】.JavaCV 之音视频基础概念 I帧、B帧、P帧、DTS、PTS了解 AVFrame是已解码的帧数据,需重新编码才能正常保存为视频文件;AVPacket是解码前的原始数据,无需重新编码也能正常保存
【7】.javacv 获取 I帧间隔 通过 Frame 类的 keyFrame 属性,我们可以判断是否为I帧
【8】.java cv流媒体处理高频抓帧 FFmpegFrameGrabber 提供了一系列方法来设置视频源、读取视频帧、获取视频信息等操作。通过FFmpegFrameGrabber 类,我们可以获取视频流、抓取视频帧并进行处理。
【9】.javacv I帧转图片 总共有六个步骤:1.导入所需的javacv库;2.初始化视频文件;3.读取视频帧;4.获取帧;5.将帧转为图片;6.保存图片。获取P帧,
1
2
3
4
5
if(frame.image!=null){
if(frame.image.depth()==IPL_DEPTH_BU && frame.image.nChannels()==3){
// 处理 I 帧
}
}

【10】.javacv之视频和音频的合并 当视频长度大于音频长度时,进行和成。

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。