#include <iostream>
#include <cstdio>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavutil/imgutils.h>
#include <libavutil/channel_layout.h>
void log_error(const char* message, int errnum) {
char buf[256];
av_strerror(errnum, buf, sizeof(buf));
std::cerr << message << ": " << buf << std::endl;
}
int main() {
avdevice_register_all();
avformat_network_init();
// Open video input
AVFormatContext* inputVideoFmtCtx = nullptr;
const AVInputFormat* inputVideoFmt = av_find_input_format("gdigrab");
AVDictionary* options = nullptr;
av_dict_set(&options, "framerate", "25", 0);
av_dict_set(&options, "video_size", "1920x1080", 0);
if (avformat_open_input(&inputVideoFmtCtx, "desktop", inputVideoFmt, &options) < 0) {
std::cerr << "Failed to open video input" << std::endl;
return -1;
}
if (avformat_find_stream_info(inputVideoFmtCtx, nullptr) < 0) {
std::cerr << "Failed to find video stream info" << std::endl;
return -1;
}
// Open audio input
AVFormatContext* inputAudioFmtCtx = nullptr;
const AVInputFormat* inputAudioFmt = av_find_input_format("dshow");
if (avformat_open_input(&inputAudioFmtCtx, "audio=Microphone (Realtek High Definition Audio)", inputAudioFmt, nullptr) < 0) {
std::cerr << "Failed to open audio input" << std::endl;
return -1;
}
if (avformat_find_stream_info(inputAudioFmtCtx, nullptr) < 0) {
std::cerr << "Failed to find audio stream info" << std::endl;
return -1;
}
// Initialize output format
AVFormatContext* outputFmtCtx = nullptr;
avformat_alloc_output_context2(&outputFmtCtx, nullptr, "mp4", "output.mp4");
if (!outputFmtCtx) {
std::cerr << "Could not create output context" << std::endl;
return -1;
}
// Add video stream
AVStream* videoStream = avformat_new_stream(outputFmtCtx, nullptr);
if (!videoStream) {
std::cerr << "Failed to create video stream" << std::endl;
return -1;
}
const AVCodec* videoCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!videoCodec) {
std::cerr << "H.264 codec not found" << std::endl;
return -1;
}
AVCodecContext* videoCodecCtx = avcodec_alloc_context3(videoCodec);
videoCodecCtx->bit_rate = 400000;
videoCodecCtx->width = 1920;
videoCodecCtx->height = 1080;
videoCodecCtx->time_base = { 1, 25 };
videoCodecCtx->framerate = { 25, 1 };
videoCodecCtx->gop_size = 12;
videoCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
if (avcodec_open2(videoCodecCtx, videoCodec, nullptr) < 0) {
std::cerr << "Could not open video codec" << std::endl;
return -1;
}
if (avcodec_parameters_from_context(videoStream->codecpar, videoCodecCtx) < 0) {
std::cerr << "Could not copy video codec parameters" << std::endl;
return -1;
}
// Add audio stream
AVStream* audioStream = avformat_new_stream(outputFmtCtx, nullptr);
if (!audioStream) {
std::cerr << "Failed to create audio stream" << std::endl;
return -1;
}
const AVCodec* audioCodec = avcodec_find_encoder(AV_CODEC_ID_AAC);
if (!audioCodec) {
std::cerr << "AAC codec not found" << std::endl;
return -1;
}
AVCodecContext* audioCodecCtx = avcodec_alloc_context3(audioCodec);
audioCodecCtx->bit_rate = 64000;
audioCodecCtx->sample_rate = 44100;
audioCodecCtx->channels = 2;
audioCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
audioCodecCtx->sample_fmt = audioCodec->sample_fmts[0];
audioCodecCtx->time_base = { 1, audioCodecCtx->sample_rate };
if (avcodec_open2(audioCodecCtx, audioCodec, nullptr) < 0) {
std::cerr << "Could not open audio codec" << std::endl;
return -1;
}
if (avcodec_parameters_from_context(audioStream->codecpar, audioCodecCtx) < 0) {
std::cerr << "Could not copy audio codec parameters" << std::endl;
return -1;
}
// Open output file
if (!(outputFmtCtx->flags & AVFMT_NOFILE)) {
if (avio_open(&outputFmtCtx->pb, "output.mp4", AVIO_FLAG_WRITE) < 0) {
std::cerr << "Could not open output file" << std::endl;
return -1;
}
}
// Write the stream header
if (avformat_write_header(outputFmtCtx, nullptr) < 0) {
std::cerr << "Error occurred when writing header" << std::endl;
return -1;
}
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
// Read frames and encode
while (true) {
// Video
if (av_read_frame(inputVideoFmtCtx, &pkt) >= 0) {
if (pkt.stream_index == inputVideoFmtCtx->streams[0]->index) {
if (avcodec_send_packet(videoCodecCtx, &pkt) >= 0) {
AVFrame* frame = av_frame_alloc();
while (avcodec_receive_frame(videoCodecCtx, frame) >= 0) {
frame->pts = av_rescale_q(frame->pts, videoCodecCtx->time_base, videoStream->time_base);
if (avcodec_send_frame(videoCodecCtx, frame) >= 0) {
AVPacket outPkt;
av_init_packet(&outPkt);
outPkt.data = nullptr;
outPkt.size = 0;
while (avcodec_receive_packet(videoCodecCtx, &outPkt) >= 0) {
av_interleaved_write_frame(outputFmtCtx, &outPkt);
av_packet_unref(&outPkt);
}
}
av_frame_free(&frame);
}
}
av_packet_unref(&pkt);
}
}
// Audio
if (av_read_frame(inputAudioFmtCtx, &pkt) >= 0) {
if (pkt.stream_index == inputAudioFmtCtx->streams[0]->index) {
if (avcodec_send_packet(audioCodecCtx, &pkt) >= 0) {
AVFrame* frame = av_frame_alloc();
while (avcodec_receive_frame(audioCodecCtx, frame) >= 0) {
frame->pts = av_rescale_q(frame->pts, audioCodecCtx->time_base, audioStream->time_base);
if (avcodec_send_frame(audioCodecCtx, frame) >= 0) {
AVPacket outPkt;
av_init_packet(&outPkt);
outPkt.data = nullptr;
outPkt.size = 0;
while (avcodec_receive_packet(audioCodecCtx, &outPkt) >= 0) {
av_interleaved_write_frame(outputFmtCtx, &outPkt);
av_packet_unref(&outPkt);
}
}
av_frame_free(&frame);
}
}
av_packet_unref(&pkt);
}
}
}
// Write the trailer
av_write_trailer(outputFmtCtx);
// Clean up
avcodec_free_context(&videoCodecCtx);
avcodec_free_context(&audioCodecCtx);
avformat_close_input(&inputVideoFmtCtx);
avformat_close_input(&inputAudioFmtCtx);
if (!(outputFmtCtx->flags & AVFMT_NOFILE)) {
avio_closep(&outputFmtCtx->pb);
}
avformat_free_context(outputFmtCtx);
return 0;
}