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

class XMuxTask : public XThread
{
public:
void Main() override;

bool Open(const char *url,
AVCodecParameters *video_para = nullptr,
AVRational *video_time_base = nullptr,
AVCodecParameters *audio_para = nullptr,
AVRational *audio_time_base = nullptr
);

void Do(AVPacket *pkt);

private:
XMux xmux_;
XAVPacketList pkts_; // 一个线程安全的 AVPacket 列表,用于存储接收到的数据包。
std::mutex mux_;
};


XMuxTask.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
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "xmuxTask.h"

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

using namespace std;

void XMuxTask::Do(AVPacket *pkt)
{
pkts_.Push(pkt);
Next(pkt);
}

void XMuxTask::Main()
{
xmux_.WriteHead();
while (!is_exit_)
{
unique_lock<mutex> lock(mux_);
auto pkt = pkts_.Pop();
if (!pkt)
{
MSleep(1);
continue;
}
if (pkt->stream_index == xmux_.video_index()
&& pkt->flags & AV_PKT_FLAG_KEY)
{
xmux_.Write(pkt);
av_packet_free(&pkt);
break;
}
av_packet_free(&pkt);
}
while (!is_exit_)
{
unique_lock<mutex> lock(mux_);
auto pkt = pkts_.Pop();
if (!pkt)
{
MSleep(1);
continue;
}
xmux_.Write(pkt);
cout << "W" << flush;

av_packet_free(&pkt);
}
xmux_.WriteEnd();
xmux_.set_c(nullptr);
}

bool XMuxTask::Open(const char *url,
AVCodecParameters *video_para,
AVRational *video_time_base,
AVCodecParameters *audio_para,
AVRational *audio_time_base
)
{
auto c = xmux_.Open(url, video_para, audio_para);
if (!c) return false;
xmux_.set_c(c);
xmux_.set_src_video_time_base(video_time_base);
xmux_.set_src_audio_time_base(audio_time_base);

return true;
}

Do()

作用:该方法用于接收音视频数据包,并将其推入一个线程安全的列表中,同时将数据包传递给责任链中的下一个处理节点。

1
2
3
4
5
void XMuxTask::Do(AVPacket *pkt)
{
pkts_.Push(pkt);
Next(pkt);
}

Main()

作用:负责在一个独立的线程中持续处理音视频数据包,将它们写入封装文件,并在退出时进行清理。

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
void XMuxTask::Main()
{
xmux_.WriteHead();

// 找到关键帧,防止录制视频开头出现花屏
while (!is_exit_)
{
unique_lock<mutex> lock(mux_);
auto pkt = pkts_.Pop();
if (!pkt)
{
MSleep(1);
continue;
}

// 用于判断关键帧
if (pkt->stream_index == xmux_.video_index()
&& pkt->flags & AV_PKT_FLAG_KEY)
{
xmux_.Write(pkt);
av_packet_free(&pkt);
break;
}

// 丢掉非视频关键帧
av_packet_free(&pkt);
}

// Main 方法通过一个循环不断处理音视频数据包,直到 is_exit_ 标志变为 true。
while (!is_exit_)
{
unique_lock<mutex> lock(mux_);
auto pkt = pkts_.Pop();
if (!pkt)
{
MSleep(1);
continue;
}
xmux_.Write(pkt);
cout << "W" << flush;

av_packet_free(&pkt);
}
xmux_.WriteEnd();
xmux_.set_c(nullptr);
}

Open()

作用:用于打开一个封装文件并初始化相关参数。

  • url:输出地址
  • video_para:视频参数
  • video_time_base:视频时间基数
  • audio_para:音频参数
  • audio_time_base:音频的时间基数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool XMuxTask::Open(const char *url,
AVCodecParameters *video_para,
AVRational *video_time_base,
AVCodecParameters *audio_para,
AVRational *audio_time_base
)
{
auto c = xmux_.Open(url, video_para, audio_para);
if (!c) return false;
xmux_.set_c(c);
xmux_.set_src_video_time_base(video_time_base);
xmux_.set_src_audio_time_base(audio_time_base);

return true;
}