XDemuxTask.h

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
#pragma once
#include "xtools.h"
#include "xdemux.h"

enum XSYN_TYPE
{
XSYN_NONE = 0, // 不做同步
XSYN_VIDEO = 1, // 根据视频同步,不处理音频
};

class XDemuxTask : public XThread
{
public:
void Main();

// 打开解封装
// url: rtsp地址
// timeout_ms:超时时间 单位毫秒
bool Open(std::string url, int timeout_ms = 1000);

// 复制视频参数
std::shared_ptr<XPara> CopyVideoPara()
{
return demux_.CopyVideoPara();
}

std::shared_ptr<XPara> CopyAudioPara()
{
return demux_.CopyAudioPara();
}

void set_syn_type(XSYN_TYPE t) { syn_type_ = t; }

private:
XDemux demux_;
std::string url_; // rtsp地址
int timeout_ms_ = 0; // 超时时间

XSYN_TYPE syn_type_ = XSYN_NONE;
};


XDemuxTask.cpp

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
#include "xdemuxTask.h"

extern "C"
{
#include <libavformat/avformat.h>
}

using namespace std;

bool XDemuxTask::Open(std::string url, int timeout_ms)
{
LOGDEBUG("XDemuxTask::Open!");
demux_.set_c(nullptr);
this->url_ = url;
this->timeout_ms_ = timeout_ms;

auto c = demux_.Open(url.c_str());
if (!c) return false;
demux_.set_c(c);
demux_.set_time_out_ms(timeout_ms);
LOGDEBUG("XDemuxTask::End!");
return true;
}

void XDemuxTask::Main()
{
AVPacket pkt;
while (!is_exit_)
{
if (!demux_.Read(&pkt))
{
cout << "-" << flush;
if (!demux_.is_connected())
{
Open(url_, timeout_ms_);
}
this_thread::sleep_for(1ms);
continue;
}

cout << "." << flush;
if (syn_type_ == XSYN_VIDEO &&
pkt.stream_index == demux_.video_index())
{
auto dur = demux_.RescaleToMs(pkt.duration, pkt.stream_index);
if (dur <= 0)
dur = 40;
MSleep(40);
}

Next(&pkt);
av_packet_unref(&pkt);

this_thread::sleep_for(1ms);
}
}

Open()

作用:这个方法通常用于初始化和配置多路复用器,以便后续从指定的 URL 读取和解析多路复用的音视频流。在实际应用中,可以调用该方法打开文件或流媒体 URL,并设置操作的超时时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool XDemuxTask::Open(std::string url, int timeout_ms)
{
LOGDEBUG("XDemuxTask::Open!");
demux_.set_c(nullptr);
this->url_ = url;
this->timeout_ms_ = timeout_ms;

auto c = demux_.Open(url.c_str());
if (!c) return false;
demux_.set_c(c);
demux_.set_time_out_ms(timeout_ms);
LOGDEBUG("XDemuxTask::End!");
return true;
}

Main()

作用:这个方法通常用于一个独立的线程中,持续读取和处理媒体数据包。在实际应用中,可以在一个循环中不断调用 Read 方法,读取和处理媒体流中的每一帧数据,并在读取失败时进行错误处理和重连。

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
void XDemuxTask::Main()
{
AVPacket pkt;
while (!is_exit_)
{
if (!demux_.Read(&pkt))
{
// 读取失败
cout << "-" << flush;

// 如果连接已断开,调用 Open 方法重新打开多路复用器。
if (!demux_.is_connected())
{
Open(url_, timeout_ms_);
}
this_thread::sleep_for(1ms);
continue;
}

// 控制播放时间
if (syn_type_ == XSYN_VIDEO && // 如果枚举类为XSYN_VIDEO,
pkt.stream_index == demux_.video_index()) // 且当前渲染的是video_index()
{
auto dur = demux_.RescaleToMs(pkt.duration, pkt.stream_index);
if (dur <= 0)
dur = 40;
// pkt.duration
MSleep(40);
}
cout << "." << flush;
Next(&pkt);
av_packet_unref(&pkt);

this_thread::sleep_for(1ms);
}
}