图片数据编码为视频的步骤如下:
1、 BGR数据转换为YUV格式;
2.、YUV格式进行编码;
其中对YUV格式进行编码又分为以下步骤:
- 通过
avcodec_find_encoder
函数找到需要的编码器; - 通过
avcodec_alloc_context3
初始化编码器上下文,并设置编码器上下文的参数(包括码率、时间基、视频宽高等); - 通过
avcodec_open2
函数打开编码器; - 通过
avformat_alloc_output_context2
函数初始化输出文件上下文; - 通过
avformat_new_stream
函数新建一个视频流,并通过avcodec_parameters_from_context
函数拷贝编码器的参数; - 通过
avio_open
函数打开输出文件; - 通过
avformat_write_header
写文件头; - 循环处理YUV数据:
①将YUV帧通过avcodec_send_frame
发送给编码器;
②并通过avcodec_receive_packet
取出编码后的数据;
③通过函数av_packet_rescale_ts
将时间戳缩放到输出流的时间基上;
④并将处理后的包通过av_interleaved_write_frame
函数写入文件; - 通过
av_write_trailer
函数写入文件尾,并关闭编码器等。
完整代码如下:
// muxer.h
#pragma once
#include <memory>
class AVFrame;
class AVStream;
class AVCodecContext;
class AVFormatContext;
class muxer
{
public:
muxer();
~muxer();
bool init(int w, int h, int fps, int bit_rate, char* outfile_name);
void uninit();
bool write_image(const uint8_t* bgr);
bool write_yuv(const uint8_t* yuv_data);
bool write_frame(const AVFrame* frame);
bool flush();
private:
bool bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p);
private:
int width_;
int height_;
int y_size_;
int uv_size_;
int pts_;
AVCodecContext* codec_ctx_;
AVFormatContext* fmt_ctx_;
AVStream* out_stream_;
AVFrame* yuv_frame_;
};
// muxer.cpp
#include "muxer.h"
#include <tuple>
#include <array>
#include <vector>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/timestamp.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
muxer::muxer()
:width_{
},
height_{
},
y_size_{
},
uv_size_{
},
pts_{
},
codec_ctx_{
nullptr },
fmt_ctx_{
nullptr },
out_stream_{
nullptr },
yuv_frame_{
nullptr }
{
}
muxer::~muxer()
{
uninit();
}
bool muxer::init(int w, int h, int fps, int bit_rate, char* outfile_name)
{
uninit();
width_ = w