雷霄骅-CSDN博客 讲FFMpeg感觉很详细
代码是在雷霄骅的基础上稍加修改
Ubuntu FFMpeg与x264安装
x264安装:
git clone https://code.videolan.org/videolan/x264.git
cd x264/
./configure --prefix=/usr/local/x264 --disable-asm
make &&sudo make install
sudo vim /etc/profile
export PATH="/usr/local/x264/bin:$PATH"
ffmpeg安装
wget http://ffmpeg.org/releases/ffmpeg-4.2.tar.bz2
tar xvjf ffmpeg-4.2.tar.bz2
cd ffmpeg-4.2/
./configure --enable-shared --disable-x86asm --enable-libx264 --enable-gpl --prefix=/usr/local/ffmpeg
make && sudo make install
sudo ldconfig
将yuv视频文件编码成H264文件存储
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libavformat/version.h>
#include <libavutil/time.h>
#include <libavutil/mathematics.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavutil/pixfmt.h>
#include <libswresample/swresample.h>
#include <libavutil/opt.h>
}
#include <stdio.h>
int main()
{
int i = 0, ret, got_output;
AVPacket pkt;
int framecnt=0;
char filename_in[]="/mnt/hgfs/shareVM/welcom_to_beijing.yuv";
char filename_out[]="/mnt/hgfs/shareVM/welcom_to_beijing.h264";
int in_w=720,in_h=480;
avcodec_register_all();
AVCodecID codec_id=AV_CODEC_ID_H264;
AVCodec *pCodec = avcodec_find_encoder(codec_id);
if (!pCodec) {
printf("Codec not found\n");
return -1;
}
AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx) {
printf("Could not allocate video codec context\n");
return -1;
}
pCodecCtx->codec_id = pCodec->id; // 编解码器的id 根据他可以找到对应的编解码器
pCodecCtx->bit_rate = 400000; // 平均比特率
pCodecCtx->width = in_w; // 编码宽度
pCodecCtx->height = in_h; // 编码高度
pCodecCtx->time_base = {1, 30}; //根据该参数,可以把PTS转化为实际的时间(单位为秒s)
pCodecCtx->framerate = {30, 1}; // 帧率
pCodecCtx->gop_size = 10; //每10帧插入1个I帧 编码时设置,解码时不使用
pCodecCtx->max_b_frames = 1; //两个非B帧之间允许出现多少个B帧数,设置0表示不使用B帧,b 帧越多,图片越小
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 像素传输格式
if (codec_id == AV_CODEC_ID_H264) {
// 预设值 速度慢 编码质量高
// 可选: ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo
av_opt_set(pCodecCtx->priv_data, "preset", "fast", 0);
// 在上一个选项基础上进一步优化输入。如果定义了一个tune值,它将在preset之后,其它选项之前生效
// 可选: film、animation、grain、stillimage、psnr、ssim、fastdecode、zerolatency
av_opt_set(pCodecCtx->priv_data, "tune", "zerolatency", 0);
// 限制输出文件的profile。这个参数将覆盖其它所有值,此选项能保证输出profile兼容的视频流。如果使用了这个选项,将不能进行无损压缩
// 可选: baseline, extended, main, high
// 默认: baseline
av_opt_set(pCodecCtx->priv_data, "profile", "baseline", 0); //
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
printf("Could not open codec\n");
return -1;
}
AVFrame *pFrame = av_frame_alloc();
if (!pFrame) {
printf("Could not allocate video frame\n");
return -1;
}
pFrame->format = pCodecCtx->pix_fmt;
pFrame->width = pCodecCtx->width;
pFrame->height = pCodecCtx->height;
ret = av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, 16);
if (ret < 0) {
printf("Could not allocate raw picture buffer\n");
return -1;
}
//Input raw data
FILE *fp_in = fopen(filename_in, "rb");
if (!fp_in) {
printf("Could not open %s\n", filename_in);
return -1;
}
//Output bitstream
FILE *fp_out = fopen(filename_out, "wb");
if (!fp_out) {
printf("Could not open %s\n", filename_out);
return -1;
}
int y_size = pCodecCtx->width * pCodecCtx->height;
//Encode
while (true) {
//Read raw YUV data
if (fread(pFrame->data[0],1,y_size,fp_in)<= 0|| // Y
fread(pFrame->data[1],1,y_size/4,fp_in)<= 0|| // U
fread(pFrame->data[2],1,y_size/4,fp_in)<= 0){ // V
return -1;
}else if(feof(fp_in)){
break;
}
/* encode the image */
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);
pFrame->pts++;
if (ret < 0) {
printf("Error encoding frame\n");
return -1;
}
if (got_output) {
printf("Succeed to encode frame: %5d\tsize:%5d\tgot_output:%5d\n",framecnt,pkt.size,got_output);
framecnt++;
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
}
//Flush Encoder 编码器中剩余的视频帧输出
for (got_output = 1; got_output; i++) {
ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);
if (ret < 0) {
printf("Error encoding frame\n");
return -1;
}
if (got_output) {
printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",pkt.size);
fwrite(pkt.data, 1, pkt.size, fp_out);
av_free_packet(&pkt);
}
}
fclose(fp_out);
avcodec_close(pCodecCtx);
av_free(pCodecCtx);
av_freep(&pFrame->data[0]);
av_frame_free(&pFrame);
return 0;
}
编译:
g++ main.cpp -I/usr/local/ffmpeg/include -L/usr/local/ffmpeg/lib -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc -lswresample -lswscale