原始rgb文件
h264编码成功,并封装成MP4文件
运行截图
日志信息
实现方式
extern "C"
{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#include <iostream>
using namespace std;
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
int main()
{
char infile[] = "out.rgb";
char outfile[] = "rgb.mp4";
//注册封装,解封装,格式
av_register_all();
//注册解码器
avcodec_register_all();
FILE *fp = fopen(infile,"rb");
if (!fp)
{
cout << infile << " open failed!" << endl;
getchar();
return -1;
}
int width = 848;
int height = 480;
int fps = 25;
//1 创建编码器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
cout << " avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl;
getchar();
return -1;
}
//编码器上下文
AVCodecContext *c = avcodec_alloc_context3(codec);
if (!c)
{
cout << " avcodec_alloc_context3 failed!" << endl;
getchar();
return -1;
}
//设置视频编码相关参数
//比特率
c->bit_rate = 400000000;
c->width = width;
c->height = height;
//把1秒钟分成fps个单位
c->time_base = { 1,fps };
c->framerate = { fps,1 };
//画面组大小,就是多少帧出现一个关键帧
//GOP 介绍 见 https://blog.csdn.net/xiangjai/article/details/44238005
c->gop_size = 50;
c->max_b_frames = 0;
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->codec_id = AV_CODEC_ID_H264;
c->thread_count = 8;
//全局的编码信息
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
//打开编码器
int ret = avcodec_open2(c,codec,NULL);
if (ret < 0)
{
cout << " avcodec_open2 failed!" << endl;
getchar();
return -1;
}
cout << "avcodec_open2 success!" << endl;
//2 create out context
AVFormatContext *oc = NULL;
avformat_alloc_output_context2(&oc, 0, 0, outfile);
//3 add video stream
AVStream *st = avformat_new_stream(oc,NULL);
st->id = 0;
st->codecpar->codec_tag = 0;
avcodec_parameters_from_context(st->codecpar,c);
cout << "===============================================" << endl;
av_dump_format(oc, 0, outfile, 1);
cout << "===============================================" << endl;
//4 rgb to yuv
//改变视频尺寸
SwsContext *ctx= NULL;
ctx = sws_getCachedContext(ctx,
width,height,AV_PIX_FMT_BGRA,
width,height,AV_PIX_FMT_YUV420P,SWS_BICUBIC,
NULL,NULL,NULL);
//输入空间
unsigned char *rgb = new unsigned char[width*height*4];
//输出空间
AVFrame *yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P;
yuv->width = width;
yuv->height = height;
//分配空间
ret = av_frame_get_buffer(yuv,32);
if (ret < 0)
{
cout << " av_frame_get_buffer failed!" << endl;
getchar();
return -1;
}
//5 write mp4 head
ret = avio_open(&oc->pb,outfile,AVIO_FLAG_WRITE);
if (ret < 0)
{
cout << " avio_open failed!" << endl;
getchar();
return -1;
}
ret = avformat_write_header(oc, NULL);
if (ret < 0)
{
cout << " avformat_write_header failed!" << endl;
getchar();
return -1;
}
int p = 0;
for (;;)
{
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
//ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
//size -- 这是要读取的每个元素的大小,以字节为单位。
//nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
//stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。
int len = fread(rgb,1,width*height*4,fp);
if (len<=0)
{
break;
}
uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
indata[0] = rgb;
int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };
inlinesize[0] = width * 4;
int h = sws_scale(ctx,indata,inlinesize,0,height,yuv->data,yuv->linesize);
if (h<=0)
{
break;
}
//6 encode frame
yuv->pts = p;
p = p + 3600;
//发送到编码器
ret = avcodec_send_frame(c,yuv);
if (ret != 0)
{
continue;
}
AVPacket pkt;
av_init_packet(&pkt);
//接收编码结果
ret = avcodec_receive_packet(c,&pkt);
if (ret != 0)
continue;
//将编码后的帧写入文件
av_interleaved_write_frame(oc,&pkt);
cout << "<" << pkt.size << ">";
}
//写文件尾
av_write_trailer(oc);
//关闭视频输出IO
avio_close(oc->pb);
//清理封装输出上下文
avformat_free_context(oc);
//关闭编码器
avcodec_close(c);
//清理编码器上下文
avcodec_free_context(&c);
//清理视频重采样上下文
sws_freeContext(ctx);
cout << "======================end=========================" << endl;
delete rgb;
getchar();
return 0;
}