forked from zhuohengfeng/OpenCVFFmpegRtmp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathXRtmp.cpp
More file actions
162 lines (133 loc) · 4.19 KB
/
XRtmp.cpp
File metadata and controls
162 lines (133 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//
// Created by hengfeng zhuo on 2019-07-20.
//
#include "XRtmp.h"
#include "main.h"
using namespace std;
// 定义实现的子类
class CXRtmp : public XRtmp {
public:
// 初始化封装器MUX上下文
bool InitMux(const char* url) {
// 输出封装器和视频流配置
int ret = avformat_alloc_output_context2(&avFormatContext, 0, "flv", url);
this->outURL = url;
if (ret != 0) {
qDebug() << "avformat_alloc_output_context2 出错";
return false;
}
return true;
}
// 添加视频或者音频流---这里的codecContext是XMediaEncode中创建后传入
int AddStream(const AVCodecContext* codecContext) {
if (!codecContext) {
return -1;
}
// 添加视频流
AVStream* avStream = avformat_new_stream(avFormatContext, NULL);
if (!avStream) {
qDebug() << "avformat_new_stream 出错";
return -1;
}
avStream->codecpar->codec_tag = 0; //
// 从编码器复制参数
avcodec_parameters_from_context(avStream->codecpar, codecContext);
av_dump_format(avFormatContext, 0, outURL.c_str(), 1);
if (codecContext->codec_type == AVMEDIA_TYPE_VIDEO) {
this->videoCodecContext = codecContext;
this->videoStream = avStream;
}
else if (codecContext->codec_type == AVMEDIA_TYPE_AUDIO) {
this->audioCodecContext = codecContext;
this->audioStream = avStream;
}
return avStream->index;
}
// 打开RTMP网络IO,发送封装头MUX
bool SendMuxHead() {
///打开rtmp 的网络输出IO
int ret = avio_open(&avFormatContext->pb, outURL.c_str(), AVIO_FLAG_WRITE);
if (ret != 0)
{
qDebug() << "avio_open 出错";
return false;
}
//写入封装头
ret = avformat_write_header(avFormatContext, NULL);
if (ret != 0)
{
qDebug() << "avformat_write_header 出错";
return false;
}
return true;
}
// RTMP推流
bool SendFrame(AVPacket* pack, int streamIndex) {
if (!pack || pack->size <= 0 || !pack->data)return false;
pack->stream_index = streamIndex;
AVRational stime;
AVRational dtime;
//判断是音频还是视频
if (videoStream && videoCodecContext && pack->stream_index == videoStream->index)
{
stime = videoCodecContext->time_base;
dtime = videoStream->time_base;
}
else if (audioStream && audioCodecContext &&pack->stream_index == audioStream->index)
{
stime = audioCodecContext->time_base;
dtime = audioStream->time_base;
}
else
{
cout << "[Error] SendFrame 类型错误!!!! " << endl;
return false;
}
//推流
pack->pts = av_rescale_q(pack->pts, stime, dtime);
pack->dts = av_rescale_q(pack->dts, stime, dtime);
pack->duration = av_rescale_q(pack->duration, stime, dtime);
int ret = av_interleaved_write_frame(avFormatContext, pack);
if (ret == 0)
{
return true;
}
qDebug() << "SendFrame 出错";
return false;
}
void Close() {
if (avFormatContext) {
avformat_close_input(&avFormatContext);
avFormatContext = NULL;
}
videoStream = NULL;
outURL = "";
}
private:
// RTMP FLV 封装器
AVFormatContext* avFormatContext = NULL;
// 视频编码器流
const AVCodecContext *videoCodecContext = NULL;
// 音频编码器流
const AVCodecContext *audioCodecContext = NULL;
// 新创建的视频流
AVStream *videoStream = NULL;
// 新创建的音频流
AVStream *audioStream = NULL;
string outURL = "";
};
XRtmp *XRtmp::getInstance(unsigned char index) {
static CXRtmp rtmp[255];
static bool isFirst = true;
if (isFirst) {
qDebug() << "XRtmp 首次启动初始化";
av_register_all();
avformat_network_init();
isFirst = false;
}
return &rtmp[index];
}
XRtmp::XRtmp() {
}
XRtmp::~XRtmp() {
}