简单封装了一下,只有三个文件 writemp4.h writemp4.cpp main.cpp
采用ffmpeg3.4.1
wirtemp4.h
#pragma once
#ifndef WRITEMP4_H
#define WRITEMP4_H
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfiltergraph.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavutil/avutil.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
#include "libavutil/timestamp.h"
};
#include
#include
typedef struct AVWriteMp4_
{
AVFormatContext *pFormatCtx = nullptr;
AVOutputFormat *fmt = nullptr;
AVStream *video_st = nullptr;
AVCodecContext *pCodecCtx = nullptr;
AVCodec *pCodec = nullptr;
uint8_t *picture_buf = nullptr;
AVFrame *picture = nullptr;
int size;
AVPacket *enpkt;
int y_size;
}AVWriteMp4;
int initWriteMp4(std::string &output, int width, int height, AVWriteMp4 *mAVWriteMp4, int indexValue, int bit_rate);
void uinitWriteMp4(AVWriteMp4 * mAVWriteMp4);
void encode(AVWriteMp4 *pAVWriteMp4, AVFrame *frame, AVPacket *pkt);
#endif // WRITEMP4_H
writemp4.cpp
#pragma once
#include "writemp4.h"
void encode(AVWriteMp4 *pAVWriteMp4, AVFrame *frame, AVPacket *pkt)
{
int ret;
/* send the frame to the encoder */
if (frame)
printf("Send frame %d \n", frame->pts);
ret = avcodec_send_frame(pAVWriteMp4->pCodecCtx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending a frame for encoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(pAVWriteMp4->pCodecCtx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during encoding\n");
exit(1);
}
//printf("Write packet %d" (size=%5d)\n", pkt->pts, pkt->size);
//fwrite(pkt->data, 1, pkt->size, outfile);
//printf("Write packet %d\n", pkt->pts, pkt->size);
//fwrite(pkt->data, 1, pkt->size, outfile);
pAVWriteMp4->enpkt->stream_index = pAVWriteMp4->video_st->index;
av_packet_rescale_ts(pAVWriteMp4->enpkt, pAVWriteMp4->pCodecCtx->time_base, pAVWriteMp4->video_st->time_base);
pAVWriteMp4->enpkt->pos = -1;
ret = av_interleaved_write_frame(pAVWriteMp4->pFormatCtx, pAVWriteMp4->enpkt);
//av_free_packet(&mAVWriteMp4.enpkt);
av_packet_unref(pAVWriteMp4->enpkt);
}
}
int initWriteMp4(std::string &output, int width, int height, AVWriteMp4 *mAVWriteMp4, int indexValue, int bit_rate)
{
mAVWriteMp4->y_size = width * height;
//[2] --初始化AVFormatContext结构体,根据文件名获取到合适的封装格式
avformat_alloc_output_context2(&(mAVWriteMp4->pFormatCtx), NULL, NULL, output.c_str());
//avcodec_copy_context(mAVWriteMp4->pCodecCtx, inCodexc);
mAVWriteMp4->fmt = mAVWriteMp4->pFormatCtx->oformat;
//[3] --打开文件
if (avio_open(&(mAVWriteMp4->pFormatCtx->pb), output.c_str(), AVIO_FLAG_READ_WRITE))
{
printf("output file open fail!");
return -1;
}
//[4] --初始化视频码流
mAVWriteMp4->video_st = avformat_new_stream(mAVWriteMp4->pFormatCtx, NULL);
if (mAVWriteMp4->video_st == NULL)
{
printf("failed allocating output stram\n");
return -2;
}
// avcodec_copy_context(mAVWriteMp4->pCodecCtx, inCodexc);
mAVWriteMp4->video_st->time_base.num = 1;
mAVWriteMp4->video_st->time_base.den = 25;
//[5] --编码器Context设置参数
mAVWriteMp4->pCodecCtx = mAVWriteMp4->video_st->codec;
mAVWriteMp4->pCodecCtx->codec_id = mAVWriteMp4->fmt->video_codec;
mAVWriteMp4->pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
mAVWriteMp4->pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
mAVWriteMp4->pCodecCtx->width = width;
mAVWriteMp4->pCodecCtx->height = height;
mAVWriteMp4->pCodecCtx->time_base.num = 1;
mAVWriteMp4->pCodecCtx->time_base.den = 25;
mAVWriteMp4->pCodecCtx->bit_rate = bit_rate; // 400000
mAVWriteMp4->pCodecCtx->gop_size = 12;
mAVWriteMp4->pCodecCtx->thread_count = 4;
if (mAVWriteMp4->pCodecCtx->codec_id == AV_CODEC_ID_H264)
{
printf("mAVWriteMp4->pCodecCtx->codec_id == AV_CODEC_ID_H264! \n");
mAVWriteMp4->pCodecCtx->qmin = 10;
mAVWriteMp4->pCodecCtx->qmax = indexValue; // 越大编码质量越差51
mAVWriteMp4->pCodecCtx->qcompress = 0.6;
}
if (mAVWriteMp4->pCodecCtx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
{
printf("mAVWriteMp4->pCodecCtx->codec_id == AV_CODEC_ID_MPEG2VIDEO! \n");
mAVWriteMp4->pCodecCtx->max_b_frames = 2;
}
if (mAVWriteMp4->pCodecCtx->codec_id == AV_CODEC_ID_MPEG1VIDEO)
{
printf("mAVWriteMp4->pCodecCtx->codec_id == AV_CODEC_ID_MPEG1VIDEO! \n");
mAVWriteMp4->pCodecCtx->mb_decision = 2;
}
//[5]
//[6] --寻找编码器并打开编码器
mAVWriteMp4->pCodec = avcodec_find_encoder(mAVWriteMp4->pCodecCtx->codec_id);
if (!mAVWriteMp4->pCodec)
{
printf("no right encoder! \n");
return -3;
}
if (avcodec_open2(mAVWriteMp4->pCodecCtx, mAVWriteMp4->pCodec, NULL) < 0)
{
printf("open encoder fail! \n");
return -4;
}
//输出格式信息
av_dump_format(mAVWriteMp4->pFormatCtx, 0, output.c_str(), 1);
//初始化帧
mAVWriteMp4->picture = av_frame_alloc();
mAVWriteMp4->picture->width = mAVWriteMp4->pCodecCtx->width;
mAVWriteMp4->picture->height = mAVWriteMp4->pCodecCtx->height;
mAVWriteMp4->picture->format = mAVWriteMp4->pCodecCtx->pix_fmt;
mAVWriteMp4->size = avpicture_get_size(mAVWriteMp4->pCodecCtx->pix_fmt, mAVWriteMp4->pCodecCtx->width, mAVWriteMp4->pCodecCtx->height);
mAVWriteMp4->picture_buf = (uint8_t*)av_malloc(mAVWriteMp4->size);
avpicture_fill((AVPicture*)mAVWriteMp4->picture, mAVWriteMp4->picture_buf, mAVWriteMp4->pCodecCtx->pix_fmt, mAVWriteMp4->pCodecCtx->width, mAVWriteMp4->pCodecCtx->height);
//[7] --写头文件
avformat_write_header(mAVWriteMp4->pFormatCtx, NULL);
//[7]
//AVPacket enpkt; //创建已编码帧
int y_size = mAVWriteMp4->pCodecCtx->width*mAVWriteMp4->pCodecCtx->height;
//av_new_packet(&mAVWriteMp4->enpkt, mAVWriteMp4->size * 3);
//mAVWriteMp4->pCodecCtx->codec_tag = 828601953;
printf("out_taget = %x %x \n", mAVWriteMp4->pCodecCtx->codec_tag);
mAVWriteMp4->enpkt = av_packet_alloc();
if (!mAVWriteMp4->enpkt)
{
return -1;
}
return 0;
}
void uinitWriteMp4(AVWriteMp4 * mAVWriteMp4)
{
if (mAVWriteMp4->video_st)
{
avcodec_close(mAVWriteMp4->video_st->codec);
av_free(mAVWriteMp4->picture);
av_free(mAVWriteMp4->picture_buf);
}
if (mAVWriteMp4->pFormatCtx)
{
avio_close(mAVWriteMp4->pFormatCtx->pb);
avformat_free_context(mAVWriteMp4->pFormatCtx);
}
av_packet_free(&mAVWriteMp4->enpkt);
}
main.cpp
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "avformat.lib")
#include
using namespace std;
// ffmpeg 库采用3.4.1
// 需要配置一下库的路径
// x64 Debug
#include "writemp4.h"
int main(int argc, char *argv[])
{
int size;
//打开视频
FILE *in_file = fopen("./src01_480x272.yuv", "rb");
if (!in_file)
{
cout << "can not open file!" << endl;
return -1;
}
int in_w = 480, in_h = 272;
int framenum = 50;
const char* out_file = "src01.mp4";
int y_size = in_w * in_h;
AVWriteMp4 mAVWriteMp4;
//[1] --注册所有ffmpeg组件
avcodec_register_all();
av_register_all();
// 说明, 30 和图像质量有关, 10-51 都行的,越大质量越差
// 400000 比特率自行理解,
int ret = initWriteMp4(std::string(out_file), in_w, in_h, &mAVWriteMp4, 30, 400000);
//[8] --循环编码每一帧
for (int i = 0; i < framenum; i++)
{
//读入YUV
if (fread(mAVWriteMp4.picture_buf, 1, y_size * 3 / 2, in_file) < 0)
{
cout << "read file fail!" << endl;
goto end;
}
else if (feof(in_file))
break;
mAVWriteMp4.picture->data[0] = mAVWriteMp4.picture_buf; //亮度Y
mAVWriteMp4.picture->data[1] = mAVWriteMp4.picture_buf + y_size; //U
mAVWriteMp4.picture->data[2] = mAVWriteMp4.picture_buf + y_size * 5 / 4; //V
//AVFrame PTS
mAVWriteMp4.picture->data[0] = mAVWriteMp4.picture_buf; //亮度Y
mAVWriteMp4.picture->data[1] = mAVWriteMp4.picture_buf + mAVWriteMp4.y_size; //U
mAVWriteMp4.picture->data[2] = mAVWriteMp4.picture_buf + mAVWriteMp4.y_size * 5 / 4; //V
//AVFrame PTS
mAVWriteMp4.picture->pts = i;
encode(&mAVWriteMp4, mAVWriteMp4.picture, mAVWriteMp4.enpkt);
}
encode(&mAVWriteMp4, NULL, mAVWriteMp4.enpkt);
//[8]
end:
av_write_trailer(mAVWriteMp4.pFormatCtx);
//[10]
uinitWriteMp4(&mAVWriteMp4);
fclose(in_file);
return 0;
}
可以在项目中直接调用
项目下载地址