当前位置:网站首页>FFmpeg 视频编码
FFmpeg 视频编码
2022-07-26 04:24:00 【Mr.codeee】
1.简介
编码视频数据,如下图所示,将原始的YUV数据编码为H.264或者H.265。

2.流程

2.1在使用FFmpeg API之前,需要先注册API,然后才能使用API。当然,新版本的库不需要再调用下面的方法。
av_register_all()2.2查找编码器,本例演示编码H.264
AVCodec* codec = nullptr;
//找到编码器
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}2.3申请AVCodecContext
//申请AVCodecContext
AVCodecContext* codec_ctx = nullptr;
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
2.4设置视频参数
比如设置视频的宽、高、fps、码率等等
codec_ctx->bit_rate = 2581504; //码率 清晰度有关
codec_ctx->width = 1920;
codec_ctx->height = 1012;
AVRational time_base = { 1, 25 };
AVRational framerate = { 25, 1 };
codec_ctx->time_base = time_base;
codec_ctx->framerate = framerate;
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;2.5打开编码器
//打开编码器
if (avcodec_open2(codec_ctx, codec, NULL) < 0)
{
fprintf(stderr, "Could not open codec\n");
exit(1);
}2.6设置视频帧的参数
格式、宽、高等。
AVFrame *frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
frame->format = codec_ctx->pix_fmt;
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;2.7为frame分配空间
/* allocate the data buffers */
int ret = av_frame_get_buffer(frame, 0);
if (ret < 0)
{
fprintf(stderr, "Could not allocate audio data buffers\n");
exit(1);
}
2.8获取frame的buffer大小,分配一个buffer
int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
frame->width, frame->height, 1);
uint8_t* buffer = (uint8_t*)av_malloc(bufferSize);2.9将frame的数据指针指向申请好的buffer,后面只需要操作buffer就行了。
ret = av_image_fill_arrays(frame->data, frame->linesize,
buffer, AV_PIX_FMT_YUV420P, 1920, 1012, 1);
if (ret < 0)
{
exit(1);
}2.10读取数据,开始编码
//打开输出的文件
char fileName[20] = "output.h264";
FILE* f = fopen(fileName, "wb");
if (!f)
{
fprintf(stderr, "Could not open %s\n", fileName);
exit(1);
}
//打开输入文件
char inputFile[20] = {0};
for(int i=1;i<256;i++)
{
sprintf(inputFile, "img/%d.yuv", i);
FILE* fp = fopen(inputFile, "rb");
if (!fp)
{
fprintf(stderr, "Could not open %s\n", inputFile);
exit(1);
}
//从文件读取数据
int count = fread(buffer, sizeof(char), bufferSize, fp);
fclose(fp);
frame->pts = i;
//开始编码
ret = avcodec_send_frame(codec_ctx, frame);
while (ret >= 0)
{
ret = avcodec_receive_packet(codec_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
break;
}
//编码后的数据写到本地文件
fwrite(pkt->data, 1, pkt->size, f);
av_packet_unref(pkt);
}
}
fclose(f);3.视频解码为YUV
我在下文中将H.264的数据解码之后,保存了几百帧的YUV数据到本地。
FFmpeg 视频解码(秒懂)_Mr.codeee的博客-CSDN博客
4.源码
将3中的几百帧YUV数据进行编码得到H.264。
#include "pch.h"
#include <iostream>
extern "C"
{
#include "libavformat/avformat.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/timestamp.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h"
};
int main()
{
//av_register_all();
avformat_network_init();
AVCodec* codec = nullptr;
//找到编码器
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
//申请AVCodecContext
AVCodecContext* codec_ctx = nullptr;
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
fprintf(stderr, "Could not allocate audio codec context\n");
exit(1);
}
codec_ctx->bit_rate = 2581504; //码率 清晰度有关
codec_ctx->width = 1920;
codec_ctx->height = 1012;
AVRational time_base = { 1, 25 };
AVRational framerate = { 25, 1 };
codec_ctx->time_base = time_base;
codec_ctx->framerate = framerate;
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
//打开编码器
if (avcodec_open2(codec_ctx, codec, NULL) < 0)
{
fprintf(stderr, "Could not open codec\n");
exit(1);
}
AVPacket *pkt = av_packet_alloc();
if (!pkt)
{
fprintf(stderr, "could not allocate the packet\n");
exit(1);
}
AVFrame *frame = av_frame_alloc();
if (!frame)
{
fprintf(stderr, "Could not allocate audio frame\n");
exit(1);
}
frame->format = codec_ctx->pix_fmt;
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;
/* allocate the data buffers */
int ret = av_frame_get_buffer(frame, 0);
if (ret < 0)
{
fprintf(stderr, "Could not allocate audio data buffers\n");
exit(1);
}
//打开输出的文件
char fileName[20] = "output.h264";
FILE* f = fopen(fileName, "wb");
if (!f)
{
fprintf(stderr, "Could not open %s\n", fileName);
exit(1);
}
int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, frame->width, frame->height, 1);
uint8_t* buffer = (uint8_t*)av_malloc(bufferSize);
ret = av_image_fill_arrays(frame->data, frame->linesize, buffer, AV_PIX_FMT_YUV420P, 1920, 1012, 1);
if (ret < 0)
{
exit(1);
}
//打开输入文件
char inputFile[20] = {0};
for(int i=1;i<256;i++)
{
sprintf(inputFile, "img/%d.yuv", i);
FILE* fp = fopen(inputFile, "rb");
if (!fp)
{
fprintf(stderr, "Could not open %s\n", inputFile);
exit(1);
}
//从文件读取数据
int count = fread(buffer, sizeof(char), bufferSize, fp);
fclose(fp);
frame->pts = i;
//开始编码
ret = avcodec_send_frame(codec_ctx, frame);
while (ret >= 0)
{
ret = avcodec_receive_packet(codec_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
break;
}
//编码后的数据写到本地文件
fwrite(pkt->data, 1, pkt->size, f);
av_packet_unref(pkt);
}
}
fclose(f);
av_free(buffer);
avcodec_close(codec_ctx);
avcodec_free_context(&codec_ctx);
av_frame_free(&frame);
av_packet_free(&pkt);
return 0;
}
边栏推荐
猜你喜欢

Recommendation | DBT skills training manual: baby, you are the reason why you live

华为再发“天才少年”全球召集令,有人曾放弃360万年薪加入

Postman imports curl, exports curl, and exports corresponding language codes

Makefile knowledge rearrangement (super detailed)

What are the consequences and problems of computer system restoration

This article takes you to graph transformers

Acwing刷题

Design and implementation of smart campus applet based on cloud development

MySQL的优化分析及效率执行

makefile知识再整理(超详细)
随机推荐
Retail chain store cashier system source code management commodity classification function logic sharing
Use of rule engine drools
人脸数据库收集总结
Huawei executives talk about the 35 year old crisis. How can programmers overcome the worry of age?
egg-ts-sequelize-CLI
远坂凛壁纸
Huawei issued another global convening order of "genius youth", and some people once gave up their annual salary of 3.6 million to join
UE4 多个角色控制权的切换
数据库连接数查看和修改
性能和成本的综合架构:单元化架构
This article takes you to graph transformers
Makefile knowledge rearrangement (super detailed)
Several methods of realizing high-low byte or high-low word exchange in TIA botu s7-1200
Comparison of the relationship between the number of partitions and the number of reducetask in MapReduce
图论:拓扑排序
Dynamic planning for stair climbing
I.MX6U-ALPHA开发板(主频和时钟配置实验)
香甜的黄油
Life related - less expectation, happier
Solution: runtimeerror: expected object of scalar type int but got scalar type double