c++调用ffmpeg api录屏 并进行rtmp推流

代码及工程见https://download.csdn.net/download/daqinzl/88156528

开发工具:visual studio 2019

记得启动rtmp流媒体服务 nginx的rtmp服务见https://download.csdn.net/download/daqinzl/20478812

播放,采用ffmpeg工具集里的ffplay.exe, 执行命令 ffplay rtmp://192.168.0.105:1935/live/desktop

主要代码如下:

#include "pch.h"

#include <iostream>

using namespace std;

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

extern "C"

{

#include "include/libavcodec/avcodec.h"

#include "include/libavformat/avformat.h"

#include "include/libswscale/swscale.h"

#include "include/libavdevice/avdevice.h"

#include "include/libavutil/imgutils.h"

#include "include/libavutil/opt.h"

#include "include/libavutil/imgutils.h"

#include "include/libavutil/mathematics.h"

#include "include/libavutil/time.h"

};

#pragma comment (lib,"avcodec.lib")

#pragma comment (lib,"avdevice.lib")

#pragma comment (lib,"avfilter.lib")

#pragma comment (lib,"avformat.lib")

#pragma comment (lib,"avutil.lib")

#pragma comment (lib,"swresample.lib")

#pragma comment (lib,"swscale.lib")

int main(int argc, char* argv[])

{

AVFormatContext* m_fmt_ctx = NULL;

AVInputFormat* m_input_fmt = NULL;

int video_stream = -1;

avdevice_register_all();

avcodec_register_all();

const char* deviceName = "desktop";

const char* inputformat = "gdigrab";

int FPS = 23; //15

m_fmt_ctx = avformat_alloc_context();

m_input_fmt = av_find_input_format(inputformat);

AVDictionary* deoptions = NULL;

av_dict_set_int(&deoptions, "framerate", FPS, AV_DICT_MATCH_CASE);

av_dict_set_int(&deoptions, "rtbufsize", 3041280 * 100 * 5, 0);

int ret = avformat_open_input(&m_fmt_ctx, deviceName, m_input_fmt, &deoptions);

if (ret != 0) {

return ret;

}

av_dict_free(&deoptions);

ret = avformat_find_stream_info(m_fmt_ctx, NULL);

if (ret < 0) {

return ret;

}

av_dump_format(m_fmt_ctx, 0, deviceName, 0);

video_stream = av_find_best_stream(m_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);

if (video_stream < 0) {

return -1;

}

AVCodecContext * _codec_ctx = m_fmt_ctx->streams[video_stream]->codec;

AVCodec* _codec = avcodec_find_decoder(_codec_ctx->codec_id);

if (_codec == NULL) {

return -1;

}

ret = avcodec_open2(_codec_ctx, _codec, NULL);

if (ret != 0) {

return -1;

}

int width = m_fmt_ctx->streams[video_stream]->codec->width;

int height = m_fmt_ctx->streams[video_stream]->codec->height;

int fps = m_fmt_ctx->streams[video_stream]->codec->framerate.num > 0 ? m_fmt_ctx->streams[video_stream]->codec->framerate.num : 25;

AVPixelFormat videoType = m_fmt_ctx->streams[video_stream]->codec->pix_fmt;

std::cout << "avstream timebase : " << m_fmt_ctx->streams[video_stream]->time_base.num << " / " << m_fmt_ctx->streams[video_stream]->time_base.den << endl;

AVDictionary* enoptions = 0;

av_dict_set(&enoptions, "preset", "superfast", 0);

av_dict_set(&enoptions, "tune", "zerolatency", 0);

AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);

if (!codec)

{

std::cout << "avcodec_find_encoder failed!" << endl;

return NULL;

}

AVCodecContext* vc = avcodec_alloc_context3(codec);

if (!vc)

{

std::cout << "avcodec_alloc_context3 failed!" << endl;

return NULL;

}

std::cout << "avcodec_alloc_context3 success!" << endl;

vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

vc->codec_id = AV_CODEC_ID_H264;

vc->codec_type = AVMEDIA_TYPE_VIDEO;

vc->pix_fmt = AV_PIX_FMT_YUV420P;

vc->width = width;

vc->height = height;

vc->time_base.num = 1;

vc->time_base.den = FPS;

vc->framerate = { FPS,1 };

vc->bit_rate = 10241000;

vc->gop_size = 120;

vc->qmin = 10;

vc->qmax = 51;

vc->max_b_frames = 0;

vc->profile = FF_PROFILE_H264_MAIN;

ret = avcodec_open2(vc, codec, &enoptions);

if (ret != 0)

{

return ret;

}

std::cout << "avcodec_open2 success!" << endl;

av_dict_free(&enoptions);

SwsContext *vsc = nullptr;

vsc = sws_getCachedContext(vsc,

width, height, (AVPixelFormat)videoType, //源宽、高、像素格式

width, height, AV_PIX_FMT_YUV420P,//目标宽、高、像素格式

SWS_BICUBIC, // 尺寸变化使用算法

0, 0, 0

);

if (!vsc)

{

cout << "sws_getCachedContext failed!";

return false;

}

AVFrame* yuv = av_frame_alloc();

yuv->format = AV_PIX_FMT_YUV420P;

yuv->width = width;

yuv->height = height;

yuv->pts = 0;

ret = av_frame_get_buffer(yuv, 32);

if (ret != 0)

{

return ret;

}

const char* rtmpurl = "rtmp://192.168.0.105:1935/live/desktop";

AVFormatContext * ic = NULL;

ret = avformat_alloc_output_context2(&ic, 0, "flv", rtmpurl);

if (ret < 0)

{

return ret;

}

AVStream* st = avformat_new_stream(ic, NULL);

if (!st)

{

return -1;

}

st->codecpar->codec_tag = 0;

avcodec_parameters_from_context(st->codecpar, vc);

av_dump_format(ic, 0, rtmpurl, 1);

ret = avio_open(&ic->pb, rtmpurl, AVIO_FLAG_WRITE);

if (ret != 0)

{

return ret;

}

ret = avformat_write_header(ic, NULL);

if (ret != 0)

{

return ret;

}

AVPacket* packet = av_packet_alloc();

AVPacket* Encodepacket = av_packet_alloc();

int frameIndex = 0;

int EncodeIndex = 0;

AVFrame* rgb = av_frame_alloc();

AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");

long long startpts = m_fmt_ctx->start_time;

long long lastpts = 0;

long long duration = av_rescale_q(1, { 1,FPS }, { 1,AV_TIME_BASE });

int got_picture = 0;

while (frameIndex < 2000000)

{

ret = av_read_frame(m_fmt_ctx, packet);

if (ret < 0) {

break;

}

if (packet->stream_index == video_stream)

{

ret = avcodec_decode_video2(_codec_ctx, rgb, &got_picture, packet);

if (ret < 0) {

printf("Decode Error.\n");

return ret;

}

if (got_picture) {

int h = sws_scale(vsc, rgb->data, rgb->linesize, 0, height, //源数据

yuv->data, yuv->linesize);

int guesspts = frameIndex * duration;

yuv->pts = guesspts;

frameIndex++;

ret = avcodec_encode_video2(vc, Encodepacket, yuv, &got_picture);

if (ret < 0) {

printf("Failed to encode!\n");

break;

}

if (got_picture == 1) {

Encodepacket->pts = av_rescale_q(EncodeIndex, vc->time_base, st->time_base);

Encodepacket->dts = Encodepacket->pts;

std::cout << "frameindex : " << EncodeIndex << " pts : " << Encodepacket->pts << " dts: " << Encodepacket->dts << " encodeSize:" << Encodepacket->size << " curtime - lasttime " << Encodepacket->pts - lastpts << endl;

lastpts = Encodepacket->pts;

ret = av_interleaved_write_frame(ic, Encodepacket);

EncodeIndex++;

av_packet_unref(Encodepacket);

}

}

}

av_packet_unref(packet);

}

ret = avcodec_send_frame(vc, NULL);

while (ret >= 0) {

ret = avcodec_receive_packet(vc, Encodepacket);

if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {

break;

}

if (ret < 0) {

break;

}

ret = av_interleaved_write_frame(ic, Encodepacket);

EncodeIndex++;

}

av_write_trailer(ic);

av_packet_free(&packet);

av_packet_free(&Encodepacket);

av_frame_free(&rgb);

av_frame_free(&yuv);

av_bitstream_filter_close(h264bsfc);

h264bsfc = NULL;

if (vsc)

{

sws_freeContext(vsc);

vsc = NULL;

}

if (_codec_ctx)

avcodec_close(_codec_ctx);

_codec_ctx = NULL;

_codec = NULL;

if (vc)

avcodec_free_context(&vc);

if (m_fmt_ctx)

avformat_close_input(&m_fmt_ctx);

if (ic && !(ic->flags & AVFMT_NOFILE))

avio_closep(&ic->pb);

if (ic) {

avformat_free_context(ic);

ic = NULL;

}

m_input_fmt = NULL;

return 0;

}

相关推荐
白子寰17 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_0122 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj27 分钟前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT29 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
-Even-32 分钟前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
我是谁??1 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
发霉的闲鱼2 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc
小c君tt2 小时前
MFC中Excel的导入以及使用步骤
c++·excel·mfc
xiaoxiao涛2 小时前
协程6 --- HOOK
c++·协程
羊小猪~~4 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio