参考:https://blog.csdn.net/tph5559/article/details/79093293
#include "stdafx.h"
#include
#include
#include
extern "C"
{
#include
#include
#include
#include
#include
#include
}
extern "C"
{
#include "libavutil/opt.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
};
//encode one frame
static int encode(AVCodecContext *pCodecCtx, AVFrame *pFrame, AVPacket *pPkt, FILE *out_file) {
int got_packet = 0;
int ret = avcodec_send_frame(pCodecCtx, pFrame);
if (ret < 0) {
//failed to send frame for encoding
return -1;
}
while (!ret) {
ret = avcodec_receive_packet(pCodecCtx, pPkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
return 0;
}
else if (ret < 0) {
//error during encoding
return -1;
}
printf("Write frame %d, size=%d\n", pPkt->pts, pPkt->size);
fwrite(pPkt->data, 1, pPkt->size, out_file);
av_packet_unref(pPkt);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
AVFormatContext *pFormatCtx;
AVOutputFormat *pOutputFmt;
AVStream *pStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVPacket *pPkt;
AVFrame *pFrame;
/*读入文件,并创建输出文件*/
FILE *in_file = NULL;
FILE *out_file = NULL;
in_file = fopen("yuv_test.yuv", "rb");
if (in_file == NULL) {
printf("cannot open input file\n");
return -1;
}
out_file = fopen("out.h264", "wb");
if (out_file == NULL) {
printf("cannot create out file\n");
return -1;
}
int nWidth = 1920;
int nHeight = 1080;
int nFrameNum = 100;
unsigned char* pFrameBuf = NULL;//存储buffer
int nFrameBufSize = 0;//buffer大小
int nReadSize = 0;
int nEncodedFrameCount = 0;
unsigned char endcode[] = { 0, 0, 1, 0xb7 };
av_register_all();//初始化
pFormatCtx = avformat_alloc_context();//申请AVFormatContext
pOutputFmt = av_guess_format(NULL, "out.h264", NULL);//猜测类型,返回输出类型。
pFormatCtx->oformat = pOutputFmt;
//除了以下方法,另外还可以使用avcodec_find_encoder_by_name()来获取AVCodec
pCodec = avcodec_find_encoder(pOutputFmt->video_codec);//获取编码器
if (!pCodec) {
//cannot find encoder
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);//申请AVCodecContext,并初始化。
if (!pCodecCtx) {
//failed get AVCodecContext
return -1;
}
pPkt = av_packet_alloc();//申请Packet资源
if (!pPkt) {
return -1;
}
//编码参数设定
pCodecCtx->codec_id = pOutputFmt->video_codec; //编码类型对应的ID。
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; //编码类型,音频、视频等等。
pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; //像素格式。
pCodecCtx->width = nWidth; //宽
pCodecCtx->height = nHeight; //高
pCodecCtx->time_base.num = 1; //时间戳,分子
pCodecCtx->time_base.den = 25; //时间戳,分母
pCodecCtx->bit_rate = 400000; //比特率
pCodecCtx->gop_size = 250; //连续的画面组
pCodecCtx->qmin = 10; //最小量化参数
pCodecCtx->qmax = 51; //最大量化参数
pCodecCtx->max_b_frames = 3; //最大B帧
//Set Option
AVDictionary *param = NULL;
//H.264
if (pCodecCtx->codec_id == AV_CODEC_ID_H264) {
av_dict_set(¶m, "preset", "slow", 0);
av_dict_set(¶m, "tune", "zerolatency", 0);
//av_dict_set(¶m, "profile", "main", 0);
}
//H.265
if (pCodecCtx->codec_id == AV_CODEC_ID_H265) {
av_dict_set(¶m, "preset", "ultrafast", 0);
av_dict_set(¶m, "tune", "zero-latency", 0);
}
// 用已有的AVCodec 初始化AVCodecContext
if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) {
//failed to open codec
return -1;
}
pFrame = av_frame_alloc();//申请AVFrame
if (!pFrame) {
fprintf(stderr, "Could not allocate the video frame data\n");
return -1;
}
pFrame->format = pCodecCtx->pix_fmt;
pFrame->width = pCodecCtx->width;
pFrame->height = pCodecCtx->height;
int ret = av_frame_get_buffer(pFrame, 32);//申请buffer大小。
if (ret < 0) {
fprintf(stderr, "Could not allocate the video frame data\n");
return -1;
}
/*计算buffer大小*/
nFrameBufSize = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1);
pFrameBuf = (unsigned char *)av_malloc(nFrameBufSize);
av_image_fill_arrays(pFrame->data, pFrame->linesize, pFrameBuf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1);
nReadSize = pCodecCtx->width * pCodecCtx->height;
for (int i = 0; i < nFrameNum; i++) {
//读取YUV数据,读取大小为nReadSize
if (fread(pFrameBuf, 1, nReadSize * 3 / 2, in_file) <= 0) {
//读取数据失败
return -1;
}
else if (feof(in_file)) {
break;
}
ret = av_frame_make_writable(pFrame);//判断帧数据是否可写。
if (ret < 0) {
return -1;
}
pFrame->data[0] = pFrameBuf; //Y
pFrame->data[1] = pFrameBuf + nReadSize; //U
pFrame->data[2] = pFrameBuf + nReadSize * 5 / 4; //V
pFrame->pts = i; //PTS
//encode
encode(pCodecCtx, pFrame, pPkt, out_file);
}
//flush the encoder
encode(pCodecCtx, NULL, pPkt, out_file);
//写数据
fwrite(endcode, 1, sizeof(endcode), out_file);
avcodec_free_context(&pCodecCtx);
avformat_free_context(pFormatCtx);
av_frame_free(&pFrame);
av_packet_free(&pPkt);
av_free(pFrameBuf);
return 0;
}