XDecode.h

Send 函数用于向解码器发送编码数据包。

Recv 函数用于从解码器接收解码后的帧数据。

InitHW 函数用于初始化硬件加速设备。

End 函数用于获取解码器中剩余的所有帧数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once
#include "xcodec.h"
struct AVBufferRef;

class XDecode :public XCodec
{
public:
bool Send(const AVPacket* pkt);
bool Recv(AVFrame* frame);
std::vector<AVFrame*> End();

// 初始化硬件加速
// 默认AV_HWDEVICE_TYPE_DXVA2 值为4
bool InitHW(int type = 4);
};

AVHWDeviceType:int type = 4代表AV_HWDEVICE_TYPE_DXVA2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enum AVHWDeviceType {
AV_HWDEVICE_TYPE_NONE,
AV_HWDEVICE_TYPE_VDPAU,
AV_HWDEVICE_TYPE_CUDA,
AV_HWDEVICE_TYPE_VAAPI,
AV_HWDEVICE_TYPE_DXVA2,
AV_HWDEVICE_TYPE_QSV,
AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
AV_HWDEVICE_TYPE_D3D11VA,
AV_HWDEVICE_TYPE_DRM,
AV_HWDEVICE_TYPE_OPENCL,
AV_HWDEVICE_TYPE_MEDIACODEC,
AV_HWDEVICE_TYPE_VULKAN,
AV_HWDEVICE_TYPE_D3D12VA,
};

XDecode.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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "xdecode.h"
#include <iostream>
#include "xtools.h"

using namespace std;

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}

bool XDecode::Send(const AVPacket* pkt)
{
unique_lock<mutex> lock(mux_);
if (!c_) return false;
auto re = avcodec_send_packet(c_, pkt);
if (re != 0) return false;

return true;
}

bool XDecode::Recv(AVFrame* frame)
{
unique_lock<mutex> lock(mux_);
if (!c_) return false;
auto f = frame;
if (c_->hw_device_ctx)
{
f = av_frame_alloc();
}
auto re = avcodec_receive_frame(c_, f);
if (re == 0)
{
if (c_->hw_device_ctx)
{
re = av_hwframe_transfer_data(frame, f, 0);
av_frame_free(&f);
if (re != 0)
{
PrintErr(re);
return false;
}
}

return true;
}
if (c_->hw_device_ctx)
av_frame_free(&f);
return false;
}

bool XDecode::InitHW(int type)
{
unique_lock<mutex> lock(mux_);
if (!c_) return false;

AVBufferRef *ctx = nullptr;
auto re = av_hwdevice_ctx_create(&ctx, (AVHWDeviceType)type, NULL, NULL, 0);
if (re != 0)
{
PrintErr(re);
return false;
}
c_->hw_device_ctx = ctx;
cout << "硬件加速: " << type << endl;

return true;
}


std::vector<AVFrame*> XDecode::End()
{
std::vector<AVFrame*> res;

unique_lock<mutex> lock(mux_);
if (!c_) return res;

int ret = avcodec_send_packet(c_, NULL);
while (ret >= 0)
{
auto frame = av_frame_alloc();
ret = avcodec_receive_frame(c_, frame);
if (ret < 0)
{
av_frame_free(&frame);
break;
}
res.push_back(frame);
}

return res;
}

Send()

作用:函数用于向解码器发送编码数据包。

1
2
3
4
5
6
7
8
9
10
11
bool XDecode::Send(const AVPacket* pkt)
{
unique_lock<mutex> lock(mux_);
if (!c_) return false;

// 将数据包pkt发送到解码器c_
auto re = avcodec_send_packet(c_, pkt);
if (re != 0) return false;

return true;
}

Recv()

作用:该函数的作用是从解码器中接收解码后的帧数据,并处理硬件加速解码的情况。

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
bool XDecode::Recv(AVFrame* frame)		 // 获取解码 
{
unique_lock<mutex> lock(mux_);
if (!c_) return false;
auto f = frame;
if (c_->hw_device_ctx) // 硬件加速
{
// 如果使用硬件加速,则分配一个新的 AVFrame 给局部变量 f。
f = av_frame_alloc();
}

// 从解码器接收解码后的帧
auto re = avcodec_receive_frame(c_, f);
if (re == 0) // 0表示成功
{
if (c_->hw_device_ctx)
{
// 如果使用硬件加速,需要将硬件帧数据从显存转换到内存。
// av_hwframe_transfer_data 将硬件加速帧数据从显存传输到内存中的 frame。
re = av_hwframe_transfer_data(frame, f, 0);
av_frame_free(&f);
if (re != 0)
{
PrintErr(re);
return false;
}
}

return true;
}

// 作用:如果解码器使用硬件加速且接收解码帧失败,释放之前分配的 AVFrame。
// 目的:避免内存泄漏。
if (c_->hw_device_ctx)
av_frame_free(&f);
return false;
}

InitHW()

作用:函数用于初始化硬件加速设备。

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
bool XDecode::InitHW(int type)
{
unique_lock<mutex> lock(mux_);
if (!c_) return false;

AVBufferRef *ctx = nullptr; // 存储硬件硬件加速上下文

/*
&ctx:指向 AVBufferRef 指针的地址,用于存储创建的硬件加速上下文。
(AVHWDeviceType)type:硬件设备类型,type 是输入参数。
NULL:设备创建时的选项,通常为 NULL。
NULL:设备创建时的选项,通常为 NULL。
0:设备创建时的标志,通常为 0。
*/
auto re = av_hwdevice_ctx_create(&ctx, (AVHWDeviceType)type, NULL, NULL, 0);
if (re != 0)
{
PrintErr(re);
return false;
}
c_->hw_device_ctx = ctx;
cout << "硬件加速: " << type << endl;

return true;
}

End()

作用:函数用于获取解码器中剩余的所有帧数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
std::vector<AVFrame*> XDecode::End()     // 获取缓存数据
{
std::vector<AVFrame*> res;

unique_lock<mutex> lock(mux_);
if (!c_) return res;

// 取出缓冲中的数据
int ret = avcodec_send_packet(c_, NULL);
while (ret >= 0)
{
auto frame = av_frame_alloc();
ret = avcodec_receive_frame(c_, frame);
if (ret < 0)
{
av_frame_free(&frame);
break;
}
res.push_back(frame);
}

return res;
}