65 avformat_network_init();
68 int ret = avformat_alloc_output_context2(&format_ctx_,
nullptr,
nullptr,
71 std::cerr <<
"Could not create output context: " << ret << std::endl;
76 const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
78 std::cerr <<
"H.264 encoder not found" << std::endl;
83 video_stream_ = avformat_new_stream(format_ctx_, codec);
85 std::cerr <<
"Could not create video stream" << std::endl;
90 codec_ctx_ = avcodec_alloc_context3(codec);
92 std::cerr <<
"Could not allocate codec context" << std::endl;
96 codec_ctx_->codec_id = AV_CODEC_ID_H264;
97 codec_ctx_->bit_rate = 4000000;
98 codec_ctx_->width = width();
99 codec_ctx_->height = height();
100 codec_ctx_->time_base = {1, frame_rate()};
101 codec_ctx_->framerate = {frame_rate(), 1};
102 codec_ctx_->gop_size = 12;
103 codec_ctx_->max_b_frames = 2;
104 codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P;
107 av_opt_set(codec_ctx_->priv_data,
"preset",
"medium", 0);
108 av_opt_set(codec_ctx_->priv_data,
"crf",
"23", 0);
111 ret = avcodec_open2(codec_ctx_, codec,
nullptr);
113 std::cerr <<
"Could not open codec: " << ret << std::endl;
118 ret = avcodec_parameters_from_context(video_stream_->codecpar, codec_ctx_);
120 std::cerr <<
"Could not copy codec parameters: " << ret << std::endl;
124 video_stream_->time_base = codec_ctx_->time_base;
127 if (!(format_ctx_->oformat->flags & AVFMT_NOFILE)) {
128 ret = avio_open(&format_ctx_->pb, filename().c_str(), AVIO_FLAG_WRITE);
130 std::cerr <<
"Could not open output file: " << ret << std::endl;
136 ret = avformat_write_header(format_ctx_,
nullptr);
138 std::cerr <<
"Error writing header: " << ret << std::endl;
143 frame_ = av_frame_alloc();
145 std::cerr <<
"Could not allocate video frame" << std::endl;
149 frame_->format = codec_ctx_->pix_fmt;
150 frame_->width = codec_ctx_->width;
151 frame_->height = codec_ctx_->height;
153 ret = av_frame_get_buffer(frame_, 0);
155 std::cerr <<
"Could not allocate frame data: " << ret << std::endl;
160 rgba_frame_ = av_frame_alloc();
162 std::cerr <<
"Could not allocate RGBA frame" << std::endl;
166 rgba_frame_->format = AV_PIX_FMT_RGBA;
167 rgba_frame_->width = width();
168 rgba_frame_->height = height();
170 ret = av_frame_get_buffer(rgba_frame_, 0);
172 std::cerr <<
"Could not allocate RGBA frame data: " << ret << std::endl;
177 if (!setup_scaler()) {
178 std::cerr <<
"Could not setup scaler" << std::endl;
183 std::cout <<
"Video encoder initialized successfully" << std::endl;
188 sws_ctx_ = sws_getContext(width(), height(), AV_PIX_FMT_RGBA, width(),
189 height(), AV_PIX_FMT_YUV420P, SWS_BILINEAR,
196 const std::vector<char>& rgba_data) {
197 if (!initialized_ && !open()) {
202 std::cerr <<
"Encoder already finished" << std::endl;
206 if (rgba_data.size() !=
static_cast<size_t>(width() * height() * 4)) {
207 std::cerr <<
"Invalid RGBA data size. Expected: "
208 << width() * height() * 4 <<
", Got: " << rgba_data.size()
214 for (
int y = 0; y < height(); y++) {
215 memcpy(rgba_frame_->data[0] + y * rgba_frame_->linesize[0],
216 rgba_data.data() + y * width() * 4, width() * 4);
219 rgba_frame_->pts = encoded_frames_;
222 sws_scale(sws_ctx_, rgba_frame_->data, rgba_frame_->linesize, 0, height(),
223 frame_->data, frame_->linesize);
225 frame_->pts = encoded_frames_;
228 if (!encode_frame(frame_)) {