FFmpeg RGB转MP4
Posted linuxandmcu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FFmpeg RGB转MP4相关的知识,希望对你有一定的参考价值。
下面是一个读取本地 RGB 文件,转换并输出 MP4 视频文件的一个例子,具体步骤如下:
1、创建编码器
2、创建输出视频上下文
3、添加视频流
4、rgb转yuv
5、写视频文件头
6、写视频文件,循环内部进行H264编码
完整代码如下:
#include <iostream>
extern "C"
{
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")
using namespace std;
int main()
{
char infile[] = "out.rgb";
char outfile[] = "rgb.mp4";
// 注册所有和编解码器有关的组件
av_register_all();
// 打开RGB文件
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; // 设置编码视频高度
c->time_base.num = 1;
c->time_base.den = 25; // 设置帧率,num为分子,den为分母,如果是1/25则表示25帧/s
c->gop_size = 50; // 画面组大小,关键帧
c->max_b_frames = 0; // 设置B帧最大数,该值表示在两个非B帧之间,所允许插入的B帧的最大帧数
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 创建输出视频上下文
AVFormatContext *oc = NULL;
avformat_alloc_output_context2(&oc, 0, 0, outfile);
///3 添加视频流
AVStream *st = avformat_new_stream(oc, NULL);
st->id = 0;
st->codecpar->codec_tag = 0;
// 将AVCodecContext信息拷贝到AVCodecParameterst结构体中
avcodec_parameters_from_context(st->codecpar, c);
cout << "===============================================" << endl;
// 打印AVFormatContext的内容
av_dump_format(oc, 0, outfile, 1);
cout << "===============================================" << endl;
///4 rgb转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 写视频文件头
// 创建并初始化AVIOContext以访问outfile指示的资源
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 pts = 0;
for (;;)
{
// 读取RGB文件的像素数据长度
int len = fread(rgb, 1, width*height * 4, fp);
if (len <= 0)
{
break;
}
// 像素格式转换:RGB转YUV
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 H264编码
// 将未压缩的AVFrame数据(yuv)给编码器
yuv->pts = pts;
//yuv->pict_type = AV_PICTURE_TYPE_I;
pts = pts + 3600;
ret = avcodec_send_frame(c, yuv);
if (ret != 0)
{
continue;
}
// 将编码数据保存在AVPacket
AVPacket pkt;
av_init_packet(&pkt);
ret = avcodec_receive_packet(c, &pkt);
if (ret != 0)
continue;
// 将AVPacket写入输出媒体文件
//av_write_frame(oc, &pkt);
//av_packet_unref(&pkt);
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;
}
以上是关于FFmpeg RGB转MP4的主要内容,如果未能解决你的问题,请参考以下文章
如何把摄像头采集的rgb图像转成yuv格式,并进行H264硬编码?