目录
一、Linux下FFmpeg库的编译
1.1 yasm库
1.2 安装X264
1.3 安装FFmepg
1.4 实验
报错
二、Linux 下OpenCV库的编译
三、环境变量设置
四、FFmpeg Linux交叉编译
4.1 FFmpeg不依赖其他库编译
4.2 FFmpeg编译依赖库(如X264)
以上3部分验证过得,是正确的,第四步没验证
五、OpenCV的交叉编译
一、Linux下FFmpeg库的编译
1.1 yasm库
hkx@ubuntu:~$ wget http://www.nasm.us/pub/nasm/releasebuilds/2.13.01/nasm-2.13.01.tar.xz
手动解压
cd ~
hkx@ubuntu:~$ cd nasm-2.13.01
hkx@ubuntu:~/nasm-2.13.01$ ./configure
hkx@ubuntu:~/nasm-2.13.01$ make -j8&& sudo make install上面的hkx@ubuntu:~$ ./configure这一步可以设置你的安装路径等,如:
hkx@ubuntu:~/nasm-2.13.01$ ./configure --prefix=/home/hkx/nasm
wc,点的太快忘记配置编译后库的安装路径了
nasm是x264的依赖,旧版本X264依赖是yasm
1.2 安装X264
cd ~
hkx@ubuntu:~$ git -C x264 pull 2> /dev/null || git clone --depth 1 \ https://gitee.com/mirrors_addons/x264.git
hkx@ubuntu:~/x264$ cd x264
hkx@ubuntu:~/x264$ ./configure --enable-shared --enable-static
hkx@ubuntu:~/x264$ make -j8&& sudo make installsudo apt-get install libx11-dev
sudo apt-get install xorg-dev
git这一步\是换行符,注意一下,还有git需要注册账号,麻烦,换个方式吧,直接下载,下载完 cd x264开始安装
x264, the best H.264/AVC encoder - VideoLAN
1.3 安装FFmepg
FFmpeg源码下载地址:Index of /releases
hkx@ubuntu:~/ffmpeg-3.4.9$./configure --enable-static --enable-shared --prefix=/home/hkx/ffmpeg_3_4_9 --enable-gpl --enable-nonfree --enable-libx264 --enable-ffplay
make -j8
make install
如果需要ffmpeg命令录音需要在配置编译选项前执行:
sudo apt-get install libasound2-dev
按照如上配置完成胡没有ffplay命令生成,ffplay依赖SDL库,需下载源码,
SDL2-2.0.14 (linuxfromscratch.org)
编译之前的依赖:
apt-get install libasound2-dev
apt-get install libpulse-dev
apt-get install libx11-dev
apt-get install xorg-dev
#编译
./configure
make && make install
安装完成,配库和BIN的环境
BIN:
sudo gedit /etc/profile
最后加入:
export PATH=xxx:PATH xxx表示你的bin文件路径
source /etc/profile 立即生效
出现error while loading shared libraries的原因:
1-1. 不存在该共享库,如果是这个原因,需要下载或者编译该共享库先了。
1-2. 存在该共享库,但是找不到或者共享库的不对
若是1-2,则sudo gedit /etc/ld.so.conf,输入你库的路径,保存退出,然后执行sudo ldconfig 来重新装载/etc/ld.so.cache文件
系统查看共享库的过程:首先查找 /etc/ld.so.cache文件,如果找不到就查找环境变量里的LD_LIBRARY_PATH的值,如果找到了就到对应的目录加载该共享库,如果找不到就报error while loading shared libraries错误了;
而/etc/ld.so.cache文件的内容是根据,
/lib目录、
/usr/lib目录、
/etc/ld.so.conf(/etc/ld.so.conf文件包含/etc/ld.so.conf.d下所有conf文件)文件、
这三个的内容生成的。
https://www.cnblogs.com/yongfengnice/p/6777930.html
至此,FFmpeg的安装已经完成,但1.4实验的时候没有ffplay命令,查了一下,说是缺少SDL库
ffplay编译主要依赖sdl2环境(针对ffmpeg 3.x版本),未安装sdl2的情况下,不会自动生成关于ffplay的编译选项。
SDL(Simple DirectMedia Layer)是一个跨平台的多媒体和游戏开发包,提供2D,音频,事件驱动,多线程和定时器等服务,它使用C语言写成,提供了多种控制图像、声音、输出的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。
可以通过下面两个命令安装sdl2组件,dev后缀表示安装路径下会包含头文件及动态库等在开发环境下需要的文件
sudo apt-get install libsdl2-2.0
sudo apt-get install libsdl2-dev
如上若还有问题,那么看下面的:
安装SDL依赖
安装编译SDL
重新编译FFmpeg
1.4 实验
采集压缩成H264
ffmpeg -f video4linux2 -i "/dev/video0" -vcodec libx264 -pix_fmt yuv420p mycamera.h264
报错
原因是,虚拟机没连接摄像头,打开虚拟机,可移动设备那里连接
使用上述命令,可以采集摄像头数据,并编码成h264文件。下面详细讲解一下这些参数。
-f video4linux2,表示采用video4linux2驱动程序。
-i “/dev/video0”,表示输入数据的地址是“/dev/video0”,这个设备地址,就是我们的摄像头设备地址。
-vcodec libx264,表示采用libx264编解码器。
-pix_fmt yuv420p,表示编码的数据采用yuv420p。
mycamera.h264,这个就是我们最终的编码好的h264数据
播放:
ffplay mycamera.h264
编解码
- 打开设备
- 打开编码器
- 采集摄像头数据,为yuyv422格式
- 转换摄像头数据,从yuyv422转成yuv420p
- 编码yuv420p数据为h264数据,并写成文件
linux下使用ffmpeg采集摄像头数据并编码成h264文件_snail_hunan的博客-CSDN博客_-vcodec libx264
以上问题待解决,有方法,未验证,不影响如下操作;
采集yuyv422,640*480,30fps,编码有格式转换。
编译命令:(尽管是C代码)
g++ capture.cpp -I/home/hkx/ffmpeg_3_4_9/include -L/home/hkx/ffmpeg_3_4_9/lib -lavformat -lavutil -lavdevice -lavcodec -lm -o capture
代码编译错误参考链接
引入ffmpeg编译错误taking address of temporary array_fantasy_arch的博客-CSDN博客_taking address of temporary array
Linux下基于ffmpeg音视频解码_IT_阿水的博客-CSDN博客_linux 视频解码器
#include <string.h>
extern "C"
{
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
}
#define V_WIDTH 640
#define V_HEIGHT 480
//@brief
// return
static AVFormatContext *open_dev() {
int ret = 0;
char errors[1024] = {
0,
};
// ctx
AVFormatContext *fmt_ctx = NULL;
AVDictionary *options = NULL;
//摄像头的设备文件
char *devicename = "/dev/video0";
// register video device
avdevice_register_all();
// get format
AVInputFormat *iformat = av_find_input_format("video4linux2");
av_dict_set(&options, "video_size", "640x480", 0);
av_dict_set(&options, "framerate", "30", 0);
av_dict_set(&options, "pixel_format", "yuyv422", 0);
// open device
ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options);
if (ret < 0) {
av_strerror(ret, errors, 1024);
fprintf(stderr, "Failed to open video device, [%d]%s\n", ret, errors);
return NULL;
}
return fmt_ctx;
}
static void open_encoder(int width, int height, AVCodecContext **enc_ctx) {
int ret = 0;
AVCodec *codec = NULL;
avcodec_register_all();
codec = avcodec_find_encoder_by_name("libx264");
if (!codec) {
printf("Codec libx264 not found\n");
exit(1);
}
*enc_ctx = avcodec_alloc_context3(codec);
if (!enc_ctx) {
printf("Could not allocate video codec context!\n");
exit(1);
}
// SPS/PPS
(*enc_ctx)->profile = FF_PROFILE_H264_HIGH_444;
(*enc_ctx)->level = 50; //表示LEVEL是5.0
//设置分辫率
(*enc_ctx)->width = width; // 640
(*enc_ctx)->height = height; // 480
// GOP
(*enc_ctx)->gop_size = 250;
(*enc_ctx)->keyint_min = 25; // option
//设置B帧数据
(*enc_ctx)->max_b_frames = 3; // option
(*enc_ctx)->has_b_frames = 1; // option
//参考帧的数量
(*enc_ctx)->refs = 3; // option
//设置输入YUV格式
(*enc_ctx)->pix_fmt = AV_PIX_FMT_YUV420P;
//设置码率
(*enc_ctx)->bit_rate = 600000; // 600kbps
//设置帧率
(*enc_ctx)->time_base = (AVRational){1, 30}; //帧与帧之间的间隔是time_base
(*enc_ctx)->framerate = (AVRational){30, 1}; //帧率,每秒 30帧
ret = avcodec_open2((*enc_ctx), codec, NULL);
if (ret < 0) {
printf("Could not open codec: %s!\n", av_err2str(ret));
exit(1);
}
}
static AVFrame *create_frame(int width, int height) {
int ret = 0;
AVFrame *frame = NULL;
frame = av_frame_alloc();
if (!frame) {
printf("Error, No Memory!\n");
goto __ERROR;
}
//设置参数
frame->width = width;
frame->height = height;
frame->format = AV_PIX_FMT_YUV420P;
// alloc inner memory
ret = av_frame_get_buffer(frame, 32); //按 32 位对齐
if (ret < 0) {
printf("Error, Failed to alloc buffer for frame!\n");
goto __ERROR;
}
return frame;
__ERROR:
if (frame) {
av_frame_free(&frame);
}
return NULL;
}
static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *newpkt,
FILE *outfile) {
int ret = 0;
if (frame) {
printf("send frame to encoder, pts=%lld", frame->pts);
}
//送原始数据给编码器进行编码
ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0) {
printf("Error, Failed to send a frame for enconding!\n");
exit(1);
}
//从编码器获取编码好的数据
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, newpkt);
//如果编码器数据不足时会返回 EAGAIN,或者到数据尾时会返回 AVERROR_EOF
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return;
} else if (ret < 0) {
printf("Error, Failed to encode!\n");
exit(1);
}
fwrite(newpkt->data, 1, newpkt->size, outfile);
fflush(outfile);
av_packet_unref(newpkt);
}
}
void yuyv422ToYuv420p(AVFrame *frame, AVPacket *pkt) {
int i = 0;
int yuv422_length = V_WIDTH * V_HEIGHT * 2;
int y_index = 0;
// copy all y
for (i = 0; i < yuv422_length; i += 2) {
frame->data[0][y_index] = pkt->data[i];
y_index++;
}
// copy u and v
int line_start = 0;
int is_u = 1;
int u_index = 0;
int v_index = 0;
// copy u, v per line. skip a line once
for (i = 0; i < V_HEIGHT; i += 2) {
// line i offset
line_start = i * V_WIDTH * 2;
for (int j = line_start + 1; j < line_start + V_WIDTH * 2; j += 4) {
frame->data[1][u_index] = pkt->data[j];
u_index++;
frame->data[2][v_index] = pkt->data[j + 2];
v_index++;
}
}
}
void rec_video() {
int ret = 0;
int base = 0;
int count = 0;
// pakcet
AVPacket pkt;
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *enc_ctx = NULL;
// set log level
av_log_set_level(AV_LOG_DEBUG);
// create file
char *yuvout = "./video.yuv";
char *out = "./video.h264";
FILE *yuvoutfile = fopen(yuvout, "wb+");
FILE *outfile = fopen(out, "wb+");
//打开设备
fmt_ctx = open_dev();
//打开编码器
open_encoder(V_WIDTH, V_HEIGHT, &enc_ctx);
//创建 AVFrame
AVFrame *frame = create_frame(V_WIDTH, V_HEIGHT);
//创建编码后输出的Packet
AVPacket *newpkt = av_packet_alloc();
if (!newpkt) {
printf("Error, Failed to alloc avpacket!\n");
goto __ERROR;
}
// read data from device
while (((ret = av_read_frame(fmt_ctx, &pkt)) == 0) && (count++ < 100)) {
int i = 0;
av_log(NULL, AV_LOG_INFO, "packet size is %d(%p)\n", pkt.size,
pkt.data);
// YUYVYUYVYUYVYUYV YUYV422
// YYYYYYYYUUVV YUV420
yuyv422ToYuv420p(frame, &pkt);
fwrite(frame->data[0], 1, 307200, yuvoutfile);
fwrite(frame->data[1], 1, 307200 / 4, yuvoutfile);
fwrite(frame->data[2], 1, 307200 / 4, yuvoutfile);
frame->pts = base++;
encode(enc_ctx, frame, newpkt, outfile);
//
av_packet_unref(&pkt); // release pkt
}
encode(enc_ctx, NULL, newpkt, outfile);
__ERROR:
if (yuvoutfile) {
// close file
fclose(yuvoutfile);
}
// close device and release ctx
if (fmt_ctx) {
avformat_close_input(&fmt_ctx);
}
av_log(NULL, AV_LOG_DEBUG, "finish!\n");
return;
}
int main(int argc, char *argv[]) {
rec_video();
return 0;
}
二、Linux 下OpenCV库的编译
预参考:linux下的opencv-4.5.5 及 opencv_contrib 扩展模块安装_顽張先生的博客-CSDN博客
如下是本课题组其他一位同学的文章,作为参考:
ubuntu18.04下opencv4.5.4编译_DemoFY的博客-CSDN博客
Linux下编译Opencv和contrib_偏安一隅,占山为王的博客-CSDN博客_linux 编译opencv
三、环境变量设置
3.1环境变量PATH
这个环境变量,表示“可执行程序的查找路径”。
1、查看PATH的值,输入“echo $PATH”。
2、修改PATH的值的方法
(1)暂时性修改
在命令行输入“export PATH=PATH:xxx”,xxx表示新添加的内容。
这样修改的话,关闭终端后就失效了。
(2)永久性修改修改~/.bashrc(建议)或系统级别的/etc/profile文件,在其中添加“export PATH=xxx:$PATH”,然后“source .bashrc”。xxx表示新添加的内容。
Source命令也称为“点命令”,通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。
在/etc/profile下修改,一个PATH多个值用:隔开,你只写一个,其他的会覆盖掉
export PATH=/home/hkx/ffmpeg_3_4_9/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:PATH
3.2 环境变量LD_LIBRARY_PATH
这个环境变量,表示“动态库的查找路径”。
1、查看LD_LIBRARY_PATH的值,输入“echo $LD_LIBRARY_PATH”。
2、修改LD_LIBRARY_PATH的值的方法
(1)暂时性修改
在命令行输入“export LD_LIBRARY_PATH=LD_LIBRARY_PATH:xxx”,xxx表示新添加的内容。
这样修改的话,关闭终端后就失效了。
(2)永久性修改修改~/.bashrc或系统级别的/etc/profile文件,在其中添加“export PATH=xxx:$LD_LIBRARY_PATH”,然后“source .bashrc”。xxx表示新添加的内容。
(3)不修改LD_LIBRARY_PATH在/etc/ld.so.conf中添加一行/usr/local/mysql/lib,然后在命令行输入命令“ldconfig”。
ldconfig命令的作用:在默认搜寻目录(/lib和/usr/lib))和动态库配置文件/etc/ld.so.conf内所列的目录中,搜索出可共享的动态链接库(格式如lib*、.so*)),进而创建出动态装入程序(ld.so)所需要的链接和缓存文件。缓存文件默认为/etc/ld.so.cache,该文件保存着已排好序的动态链接库的名字列表。
linux环境变量设置方法(PATH等环境变量)_天糊土的博客-CSDN博客_查看ld_library_path
~/ .bashrc或~/.bash_profile是对当前用户有效,而/etc/profile是对所有用户有效,source后无效的话,就重启一下
编译FFmpeg用到的也就上述两个全局路径,其他遇到再补充吧!
四、FFmpeg Linux交叉编译
本文所在系统环境ubuntu18.04
交叉编译工具链gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu
4.1 FFmpeg不依赖其他库编译
ffmpeg arm linux编译_aarch64-linux-gnu+交叉编译x264_csdnLN的博客-CSDN博客_aarch64 ffmpeg
./configure --enable-cross-compile --target-os=linux --arch=arm64 \
--cross-prefix=--cross-prefix=/home/hkx/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- \
--cc=--cross-prefix=/home/hkx/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc \
--prefix=/home/hkx/arm_ffmpeg \
--disable-asm --enable-parsers --disable-decoders --disable-debug --enable-ffmpeg --enable-shared --disable-static --disable-stripping --disable-doc --disable-yasm --disable-libx264
4.2 FFmpeg编译依赖库(如X264)
./configure --enable-cross-compile --target-os=linux --arch=arm64 \
--cross-prefix=--cross-prefix=/home/hkx/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- \
--cc=--cross-prefix=/home/hkx/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc \
--prefix=/home/hkx/arm_ffmpeg \
--disable-asm --enable-parsers --disable-decoders --disable-debug --enable-ffmpeg --enable-shared --disable-static --disable-stripping --disable-doc --disable-yasm --enable-libx264
--extra-cflags=-I/home/jiajia/work/FFmpeg/include --extra-ldflags=-L/home/jiajia/work/FFmpeg/lib
--extra-cflags --extra-ldflags 这一部分不一定正确,这一部分可以在configure文件里详细看到。交叉编译带x264的库的,我我没验证。
后面这个写的我也还没验证:
交叉编译ffmpeg-4.2.2_Golden_Chen的博客-CSDN博客_ffmpeg 交叉编译
如果需要依赖其他库来编译,那么进行如下设置:
FFmpeg: A complete, cross-platform solution to record, convert and stream audio and video.
官网地址: http://ffmpeg.org/
下载最新的 FFmpeg 4.2.2源码。参考了其他文章,FFmpeg编译还需要以下3个开源库:
1)x264 -- library and application for encoding video streams into the H.264/MPEG-4 AVC compression format
官网地址: http://www.videolan.org/developers/x264.html
2)YASM -- a complete rewrite of the NASM assembler
官网地址:http://yasm.tortall.net/
3)SDL2 -- Simple DirectMedia Layer
官网地址:http://www.libsdl.org/index.php
初始化编译工具交叉变量 CROSS_COMPILE
export CROSS_COMPILE=/home/golden/gcc/usr/bin/arm-oe-linux-gnueabi/arm-oe-linux-gnueabi-
export CC=${CROSS_COMPILE}gcc
或者直接这样:
export CC=/home/hkx/Voice_Video/gcc-linaro-5.5.0-2017.10-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc
查看是否设置成功:
echo $CC
1) 编译x264
# wget https://code.videolan.org/videolan/x264/-/archive/master/x264-master.tar.bz2
# tar xvjf x264-master.tar.bz2
# cd x264-master
# ./configure --host=arm-linux --prefix=/usr/local/x264-arm --enable-shared --enable-debug --disable-asm
# make
# make install
--prefix=/usr/local/x264-arm可以自己修改
2) 编译YASM
# wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
# tar xvzf yasm-1.3.0.tar.gz
# cd yasm-1.3.0
# ./configure --prefix=/usr/local/ --host=arm-linux
# make
# make install
3) 编译SDL2
# wget http://www.libsdl.org/release/SDL2-2.0.12.tar.gz
# tar xvzf SDL2-2.0.12.tar.gz
# cd SDL2-2.0.12
# ./configure --prefix=/usr/local/ --host=arm-linux --target=arm-linux
# make
# make install
以上3部分验证过得,是正确的,第四步没验证
4) 最后编译FFmpeg
# wget https://ffmpeg.org/releases/ffmpeg-4.2.2.tar.bz2
# tar xvjf ffmpeg-4.2.2.tar.bz2
# cd ffmpeg-4.2.2
# ./configure --cross-prefix=$CROSS_COMPILE --enable-cross-compile --target-os=linux --cc="$CC" --arch=arm --prefix=/usr/local/arm_ffmpeg --enable-shared --disable-static --enable-gpl --enable-nonfree --enable-swscale --enable-pthreads --disable-armv5te --disable-armv6 --disable-armv6t2 --disable-yasm --enable-ffmpeg --enable-ffplay --enable-sdl2
五、OpenCV的交叉编译
交叉编译Opencv带Contrib_偏安一隅,占山为王的博客-CSDN博客
Linux下编译Opencv和contrib_偏安一隅,占山为王的博客-CSDN博客_linux 编译opencv
六、OpenCV在Windows下的编译 结合VS2019
如下是我很早之前的一次操作了,仅作为参考,不带扩展模块可以直接下载:文章来源:https://www.toymoban.com/news/detail-813547.html
Windows下OpenCV4.1.2和Contrib的编译_偏安一隅,占山为王的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-813547.html
到了这里,关于Linux 下编译和交叉编译FFmpeg、OpenCV(contrib )库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!