21 #ifndef GUIVideoEncoder_h 22 #define GUIVideoEncoder_h 34 #define __STDC_CONSTANT_MACROS 38 #pragma warning(disable: 4244) // do not warn about integer conversions 41 #pragma GCC diagnostic push 42 #pragma GCC diagnostic ignored "-Wpedantic" 43 #pragma GCC diagnostic ignored "-Wvariadic-macros" 47 #include <libavutil/opt.h> 48 #include <libavutil/imgutils.h> 49 #include <libavcodec/avcodec.h> 50 #include <libavformat/avformat.h> 51 #include <libswscale/swscale.h> 57 #pragma GCC diagnostic pop 72 GUIVideoEncoder(
const char*
const out_file,
const int width,
const int height,
double frameDelay) {
74 AVFormatContext*
const pFormatCtx =
myFormatContext = avformat_alloc_context();
77 pFormatCtx->oformat = av_guess_format(NULL, out_file, NULL);
78 if (pFormatCtx->oformat == 0) {
79 throw std::runtime_error(
"Unknown format!");
83 if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) {
84 throw std::runtime_error(
"Failed to open output file!");
89 if (frameDelay > 0.) {
90 framerate = (int)(1000. / frameDelay);
95 AVStream*
const video_st = avformat_new_stream(pFormatCtx, 0);
96 video_st->time_base.num = 1;
97 video_st->time_base.den = framerate;
100 AVCodecContext*
const pCodecCtx = video_st->codec;
102 pCodecCtx->codec_id = pFormatCtx->oformat->video_codec;
103 pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
104 pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
106 pCodecCtx->width = (width / 2) * 2;
107 pCodecCtx->height = (height / 2) * 2;
108 pCodecCtx->time_base.num = 1;
109 pCodecCtx->time_base.den = framerate;
110 pCodecCtx->bit_rate = 4000000;
111 pCodecCtx->gop_size = 250;
116 pCodecCtx->qmin = 10;
117 pCodecCtx->qmax = 51;
120 pCodecCtx->max_b_frames = 3;
123 AVDictionary* param = 0;
125 if (pCodecCtx->codec_id == AV_CODEC_ID_H264) {
126 av_dict_set(¶m,
"preset",
"slow", 0);
127 av_dict_set(¶m,
"tune",
"zerolatency", 0);
131 if (pCodecCtx->codec_id == AV_CODEC_ID_HEVC) {
132 av_dict_set(¶m,
"preset",
"ultrafast", 0);
133 av_dict_set(¶m,
"tune",
"zero-latency", 0);
139 AVCodec*
const pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
141 throw std::runtime_error(
"Can not find encoder!");
143 const int ret = avcodec_open2(pCodecCtx, pCodec, ¶m);
145 throw std::runtime_error(
"Failed to open encoder (" +
toString(ret) +
")!");
149 myFrame->format = pCodecCtx->pix_fmt;
150 myFrame->width = pCodecCtx->width;
151 myFrame->height = pCodecCtx->height;
152 av_image_alloc(
myFrame->data,
myFrame->linesize, pCodecCtx->width, pCodecCtx->height,
153 pCodecCtx->pix_fmt, 32);
155 mySwsContext = sws_getContext(pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGBA,
156 pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P,
159 avformat_write_header(pFormatCtx, NULL);
168 if (!(fmt_ctx->streams[0]->codec->codec->capabilities &
169 AV_CODEC_CAP_DELAY)) {
175 av_init_packet(&enc_pkt);
176 ret = avcodec_encode_video2(fmt_ctx->streams[0]->codec, &enc_pkt,
187 ret = av_write_frame(fmt_ctx, &enc_pkt);
192 av_write_trailer(fmt_ctx);
195 if (fmt_ctx->streams[0]) {
196 avcodec_close(fmt_ctx->streams[0]->codec);
200 avio_close(fmt_ctx->pb);
201 avformat_free_context(fmt_ctx);
207 AVCodecContext*
const pCodecCtx = video_st->codec;
209 uint8_t* inData[1] = { buffer };
210 int inLinesize[1] = { 4 * pCodecCtx->width };
211 sws_scale(
mySwsContext, inData, inLinesize, 0, pCodecCtx->height,
214 av_init_packet(&
myPkt);
221 int ret = avcodec_encode_video2(pCodecCtx, &
myPkt,
myFrame, &got_picture);
223 throw std::runtime_error(
"Failed to encode!");
225 if (got_picture == 1) {
226 myPkt.stream_index = video_st->index;
228 av_free_packet(&
myPkt);
AVFormatContext * myFormatContext
void writeFrame(uint8_t *buffer)
GUIVideoEncoder(const char *const out_file, const int width, const int height, double frameDelay)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
A simple video encoder from RGBA pics to anything ffmpeg can handle.
SwsContext * mySwsContext