ffmepg6.0 录屏推流 c++示例
时间: 2023-07-05 19:30:52 浏览: 166
以下是使用 ffmpeg 6.0 进行屏幕录制和推流的 C++ 示例代码:
```c++
#include <iostream>
#include <ctime>
#include <chrono>
#include <thread>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
extern "C" {
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libavutil/pixdesc.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/time.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
}
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P
#define STREAM_FRAME_RATE 30
#define STREAM_GOP_SIZE 60
int main(int argc, char *argv[])
{
int ret = 0;
int width = 1280;
int height = 720;
const char *output_url = "rtmp://server/live/stream";
AVFormatContext *oc = nullptr;
AVOutputFormat *ofmt = nullptr;
AVStream *video_st = nullptr;
AVCodecContext *video_ctx = nullptr;
AVCodec *video_codec = nullptr;
av_register_all();
avformat_network_init();
avdevice_register_all();
AVInputFormat *ifmt = av_find_input_format("gdigrab");
if (!ifmt) {
std::cerr << "av_find_input_format error" << std::endl;
return -1;
}
AVDictionary *options = nullptr;
av_dict_set(&options, "framerate", "30", 0);
av_dict_set(&options, "draw_mouse", "0", 0);
AVFormatContext *ifmt_ctx = nullptr;
ret = avformat_open_input(&ifmt_ctx, "desktop", ifmt, &options);
if (ret < 0) {
std::cerr << "avformat_open_input error: " << av_err2str(ret) << std::endl;
return -1;
}
ret = avformat_find_stream_info(ifmt_ctx, nullptr);
if (ret < 0) {
std::cerr << "avformat_find_stream_info error: " << av_err2str(ret) << std::endl;
return -1;
}
int video_index = -1;
for (unsigned int i = 0; i < ifmt_ctx->nb_streams; ++i) {
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_index = i;
break;
}
}
if (video_index == -1) {
std::cerr << "No video stream found" << std::endl;
return -1;
}
AVFrame *frame = av_frame_alloc();
AVPacket *packet = av_packet_alloc();
ret = avformat_alloc_output_context2(&oc, nullptr, "flv", output_url);
if (ret < 0) {
std::cerr << "avformat_alloc_output_context2 error: " << av_err2str(ret) << std::endl;
return -1;
}
ofmt = oc->oformat;
AVStream *out_stream = nullptr;
video_codec = avcodec_find_encoder(ofmt->video_codec);
if (!video_codec) {
std::cerr << "avcodec_find_encoder error" << std::endl;
return -1;
}
video_st = avformat_new_stream(oc, nullptr);
if (!video_st) {
std::cerr << "avformat_new_stream error" << std::endl;
return -1;
}
video_ctx = avcodec_alloc_context3(video_codec);
if (!video_ctx) {
std::cerr << "avcodec_alloc_context3 error" << std::endl;
return -1;
}
out_stream = video_st;
out_stream->id = 0;
video_ctx->codec_id = ofmt->video_codec;
video_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
video_ctx->width = width;
video_ctx->height = height;
video_ctx->pix_fmt = STREAM_PIX_FMT;
video_ctx->time_base = { 1, STREAM_FRAME_RATE };
video_ctx->gop_size = STREAM_GOP_SIZE;
video_ctx->bit_rate = 2000000;
AVDictionary *video_options = nullptr;
av_dict_set(&video_options, "preset", "ultrafast", 0);
av_dict_set(&video_options, "tune", "zerolatency", 0);
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
video_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
ret = avcodec_open2(video_ctx, video_codec, &video_options);
if (ret < 0) {
std::cerr << "avcodec_open2 error: " << av_err2str(ret) << std::endl;
return -1;
}
ret = avcodec_parameters_from_context(out_stream->codecpar, video_ctx);
if (ret < 0) {
std::cerr << "avcodec_parameters_from_context error: " << av_err2str(ret) << std::endl;
return -1;
}
av_dump_format(oc, 0, output_url, 1);
ret = avio_open(&oc->pb, output_url, AVIO_FLAG_WRITE);
if (ret < 0) {
std::cerr << "avio_open error: " << av_err2str(ret) << std::endl;
return -1;
}
ret = avformat_write_header(oc, nullptr);
if (ret < 0) {
std::cerr << "avformat_write_header error: " << av_err2str(ret) << std::endl;
return -1;
}
int64_t start_time = av_gettime();
while (true) {
if (av_read_frame(ifmt_ctx, packet) < 0) {
break;
}
if (packet->stream_index != video_index) {
av_packet_unref(packet);
continue;
}
ret = avcodec_send_packet(video_ctx, packet);
if (ret < 0) {
std::cerr << "avcodec_send_packet error: " << av_err2str(ret) << std::endl;
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(video_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
std::cerr << "avcodec_receive_frame error: " << av_err2str(ret) << std::endl;
break;
}
AVFrame *tmp_frame = av_frame_alloc();
av_image_alloc(tmp_frame->data, tmp_frame->linesize, width, height, STREAM_PIX_FMT, 32);
SwsContext *sws_ctx = sws_getContext(width, height, AV_PIX_FMT_BGRA,
width, height, STREAM_PIX_FMT,
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
sws_scale(sws_ctx, (const uint8_t * const*)frame->data, frame->linesize, 0, height,
tmp_frame->data, tmp_frame->linesize);
sws_freeContext(sws_ctx);
tmp_frame->width = width;
tmp_frame->height = height;
tmp_frame->format = STREAM_PIX_FMT;
tmp_frame->pts = av_rescale_q(av_gettime() - start_time, { 1, AV_TIME_BASE }, video_ctx->time_base);
ret = avcodec_send_frame(video_ctx, tmp_frame);
if (ret < 0) {
std::cerr << "avcodec_send_frame error: " << av_err2str(ret) << std::endl;
break;
}
while (ret >= 0) {
ret = avcodec_receive_packet(video_ctx, packet);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
std::cerr << "avcodec_receive_packet error: " << av_err2str(ret) << std::endl;
break;
}
packet->stream_index = out_stream->index;
packet->pts = av_rescale_q(packet->pts, video_ctx->time_base, out_stream->time_base);
packet->dts = av_rescale_q(packet->dts, video_ctx->time_base, out_stream->time_base);
packet->duration = av_rescale_q(packet->duration, video_ctx->time_base, out_stream->time_base);
ret = av_interleaved_write_frame(oc, packet);
if (ret < 0) {
std::cerr << "av_interleaved_write_frame error: " << av_err2str(ret) << std::endl;
break;
}
av_packet_unref(packet);
}
av_freep(&tmp_frame->data[0]);
av_freep(&tmp_frame);
}
av_packet_unref(packet);
}
av_write_trailer(oc);
avcodec_free_context(&video_ctx);
av_frame_free(&frame);
av_packet_free(&packet);
avformat_close_input(&ifmt_ctx);
avio_closep(&oc->pb);
avformat_free_context(oc);
return 0;
}
```
请注意,此示例代码仅演示如何使用 ffmpeg 进行屏幕录制和推流,并不保证在所有环境下都能正常运行。在实际应用中,您需要根据自己的需求进行修改。
阅读全文