#include <fstream>
#include <iostream>
extern "C"
{
#include <libavcodec/avcodec.h>
}
#define print(x) std::cout << x << std::endl
void print_av_err(int ret)
{
char buf[1024] = {0};
av_strerror(ret, buf, sizeof(buf) - 1);
std::cerr << buf << std::endl;
}
#define H264
int main(int argc, char **argv)
{
// 一定要注册,不然会找不到编码器!!!!!!!!!!!!!!!!!
avcodec_register_all();
AVCodecID codec_id = AV_CODEC_ID_H264;
std::string filename = "400_300_25.h264";
// std::ifstream ifs;
// ifs.open("/workspace/ffmpeg_tutorials/tutorials/ch02/resource/400_300_25.yuv", std::ios::binary);
// if (!ifs)
// {
// std::cerr << "file1 open failed!" << std::endl;
// return -1;
// }
std::ofstream ofs;
ofs.open(filename, std::ios::binary);
if (!ofs)
{
std::cerr << "file2 open failed!" << std::endl;
return -1;
}
// 1.查找编码器
AVCodec *codec = avcodec_find_encoder(codec_id);
if (!codec)
{
std::cerr << "codec not found!" << std::endl;
return -1;
}
// 2.编码上下文
AVCodecContext *ctx = avcodec_alloc_context3(codec);
if (!ctx)
{
std::cerr << "context alloc failed!" << std::endl;
return -1;
}
// 3.设定上下文参数
ctx->width = 400;
ctx->height = 300;
ctx->pix_fmt = AV_PIX_FMT_YUV420P;
ctx->time_base = {1, 25}; //帧时间戳单位,pts帧id,每帧时间=pts*1/25
ctx->thread_count = 8; //编码线程数,可以用过调用系统接口获得cpu核心数量
// 4.打开编码上下文
auto ret = avcodec_open2(ctx, codec, NULL);
if (ret)
{
char buf[1024] = {0};
av_strerror(ret, buf, sizeof(buf) - 1);
std::cerr << "avcodec_open2 failed!" << buf << std::endl;
return -1;
}
std::cout << "codec context 创建成功!" << std::endl;
// 创建AVFrame
AVFrame *frame = av_frame_alloc();
frame->width = ctx->width;
frame->height = ctx->height;
frame->format = ctx->pix_fmt;
// frame->linesize[0] = ctx->width;
// frame->linesize[1] = ctx->width / 2;
// frame->linesize[2] = ctx->width / 2;
ret = av_frame_get_buffer(frame, 0);
if (ret)
{
char buf[1024] = {0};
av_strerror(ret, buf, sizeof(buf) - 1);
std::cerr << "frame create failed!" << buf << std::endl;
return -1;
}
// 创建AVPacket
AVPacket *packet = av_packet_alloc();
// 开始生成视频文件 10s 25fps
for (int i = 0; i < 250; ++i)
{
// Y
for (int y = 0; y < ctx->height; ++y)
{
for (int x = 0; x < ctx->width; ++x)
{
frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
}
}
// UV
for (int y = 0; y < ctx->height / 2; ++y)
{
for (int x = 0; x < ctx->width / 2; ++x)
{
frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
}
}
frame->pts = i; //帧序列id
//开始压缩
ret = avcodec_send_frame(ctx, frame);
if (ret)
{
std::cerr << "avcodec_send_frame failed!" << std::endl;
break;
}
// 等待接收压缩完的数据
// 一般情况下,前几次会返回null,编码未完成
// 编码实在独立的线程中执行的,每次调用会重新分配packet中的空间
while (1)
{
ret = avcodec_receive_packet(ctx, packet);
// 如果读完当前帧, 则退出循环
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
{
std::cerr << "avcodec_receive_packet failed!" << std::endl;
break;
}
if (ret)
{
char buf[1024] = {0};
av_strerror(ret, buf, sizeof(buf) - 1);
// std::cerr << "avcodec_receive_packet failed!" << buf << std::endl;
// break;
continue;
}
std::cout << "压缩之后数据大小为:" << packet->size << std::endl;
ofs.write((char *)packet->data, packet->size);
// 每次释放packet资源并重新分配
av_packet_unref(packet);
}
}
av_packet_free(&packet);
av_frame_free(&frame);
//释放编码器上下文
avcodec_free_context(&ctx);
// ifs.close();
ofs.close();
return 0;
}
cmake_minimum_required(VERSION 3.4.1)
SET(CMAKE_CXX_STANDARD 11)
project(main)
add_executable(main main.cpp)
target_link_libraries(main avcodec avutil )
|