- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章C++ 封装 DLL 供 C# 调用详细介绍由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
首先需要配置可使用 VLC 正常播放的 QT(C++)工程,获取VLC每一帧并渲染到Qwidget 。
Libvlcapi 。
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
public
static
class
LIBVLCAPI
{
#region[libvlc.dll 导出函数]
// 创建一个libvlc实例,它是引用计数的
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
private
static
extern
IntPtr libvlc_new(
int
argc, IntPtr argv);
// 释放libvlc实例
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_release(IntPtr libvlc_instance);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
String libvlc_get_version();
// 从视频来源(例如Url)构建一个libvlc_meida
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
private
static
extern
IntPtr libvlc_media_new_location(IntPtr libvlc_instance, IntPtr path);
// 从视频来源(例如Url)抓图
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
private
static
extern
int
libvlc_video_take_snapshot(IntPtr libvlc_mediaplayer,
int
num, IntPtr filepath,
int
i_width,
int
i_height);
// 从本地文件路径构建一个libvlc_media
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
private
static
extern
IntPtr libvlc_media_new_path(IntPtr libvlc_instance, IntPtr path);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_release(IntPtr libvlc_media_inst);
// 创建libvlc_media_player(播放核心)
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
IntPtr libvlc_media_player_new(IntPtr libvlc_instance);
// 将视频(libvlc_media)绑定到播放器上
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_set_media(IntPtr libvlc_media_player, IntPtr libvlc_media);
// 设置图像输出的窗口
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_set_hwnd(IntPtr libvlc_mediaplayer, Int32 drawable);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_play(IntPtr libvlc_mediaplayer);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_pause(IntPtr libvlc_mediaplayer);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_stop(IntPtr libvlc_mediaplayer);
// 解析视频资源的媒体信息(如时长等)
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_parse(IntPtr libvlc_media);
// 返回视频的时长(必须先调用libvlc_media_parse之后,该函数才会生效)
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
Int64 libvlc_media_get_duration(IntPtr libvlc_media);
// 当前播放的时间
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
Int64 libvlc_media_player_get_time(IntPtr libvlc_mediaplayer);
// 设置播放位置(拖动)
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_set_time(IntPtr libvlc_mediaplayer, Int64
time
);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_media_player_release(IntPtr libvlc_mediaplayer);
// 获取和设置音量
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
int
libvlc_audio_get_volume(IntPtr libvlc_media_player);
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_audio_set_volume(IntPtr libvlc_media_player,
int
volume);
// 设置全屏
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_set_fullscreen(IntPtr libvlc_media_player,
int
isFullScreen);
// 设置屏幕因子
[DllImport(
"libvlc"
, CallingConvention = CallingConvention.Cdecl, ExactSpelling =
true
)]
[SuppressUnmanagedCodeSecurity]
public
static
extern
void
libvlc_video_set_scale(IntPtr libvlc_media_player,
float
f_factor);
#endregion
#region[VLC方法]
public
struct
PointerToArrayOfPointerHelper
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)]
public
IntPtr[] pointers;
}
public
static
IntPtr libvlc_new(string[] arguments)
{
PointerToArrayOfPointerHelper argv =
new
PointerToArrayOfPointerHelper();
argv.pointers =
new
IntPtr[11];
for
(
int
i = 0; i < arguments.Length; i++)
{
argv.pointers[i] = Marshal.StringToHGlobalAnsi(arguments[i]);
}
IntPtr argvPtr = IntPtr.Zero;
try
{
int
size = Marshal.SizeOf(typeof(PointerToArrayOfPointerHelper));
argvPtr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(argv, argvPtr,
false
);
return
libvlc_new(arguments.Length, argvPtr);
}
finally
{
for
(
int
i = 0; i < arguments.Length + 1; i++)
{
if
(argv.pointers[i] != IntPtr.Zero)
{
Marshal.FreeHGlobal(argv.pointers[i]);
}
}
if
(argvPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(argvPtr);
}
}
}
public
static
IntPtr libvlc_media_new_path(IntPtr libvlc_instance, string path)
{
IntPtr pMrl = IntPtr.Zero;
try
{
byte[] bytes = Encoding.UTF8.GetBytes(path);
pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, pMrl, bytes.Length);
Marshal.WriteByte(pMrl, bytes.Length, 0);
return
libvlc_media_new_path(libvlc_instance, pMrl);
}
finally
{
if
(pMrl != IntPtr.Zero)
{
Marshal.FreeHGlobal(pMrl);
}
}
}
public
static
int
libvlc_video_take_snapshot(IntPtr libvlc_mediaplayer,
int
num, string path,
int
width,
int
height)
{
IntPtr pMrl = IntPtr.Zero;
try
{
byte[] bytes = Encoding.UTF8.GetBytes(path);
pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, pMrl, bytes.Length);
Marshal.WriteByte(pMrl, bytes.Length, 0);
return
libvlc_video_take_snapshot(libvlc_mediaplayer, num, pMrl, width, height);
}
finally
{
if
(pMrl != IntPtr.Zero)
{
Marshal.FreeHGlobal(pMrl);
}
}
}
public
static
IntPtr libvlc_media_new_location(IntPtr libvlc_instance, string path)
{
IntPtr pMrl = IntPtr.Zero;
try
{
byte[] bytes = Encoding.UTF8.GetBytes(path);
pMrl = Marshal.AllocHGlobal(bytes.Length + 1);
Marshal.Copy(bytes, 0, pMrl, bytes.Length);
Marshal.WriteByte(pMrl, bytes.Length, 0);
return
libvlc_media_new_path(libvlc_instance, pMrl);
}
finally
{
if
(pMrl != IntPtr.Zero)
{
Marshal.FreeHGlobal(pMrl);
}
}
}
#endregion
}
|
VLCPlayer 。
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
|
public
class
VLCPlayer
{
private
IntPtr libvlc_instance_;
private
IntPtr libvlc_media_player_;
private
double
duration_;
public
VLCPlayer(string pluginPath,
bool
is_record)
{
if
(is_record ==
true
)
{
string plugin_arg =
"--plugin-path="
+ pluginPath;
string filename =
"c:\\"
+ DateTime.Now.ToString(
"yyyyMMddhhmmss"
) +
".mp4"
;
string record_paramter =
"--sout=#duplicate{dst=display,dst=std{accs=file,mux=ts,dst="
+ filename;
string[] arguments = {
"-I"
,
"--fullscreen"
,
"dummy"
,
"--ignore-config"
,
"--no-video-title"
,
"--width=100"
,
"--height=100"
, plugin_arg, record_paramter };
// "--sout=#duplicate{dst=display,dst=std{accs=file,mux=ts,dst=c:\\1.mp4" };
libvlc_instance_ = LIBVLCAPI.libvlc_new(arguments);
libvlc_media_player_ = LIBVLCAPI.libvlc_media_player_new(libvlc_instance_);
}
else
{
string plugin_arg =
"--plugin-path="
+ pluginPath;
string[] arguments = {
"-I"
,
"--fullscreen"
,
"dummy"
,
"--ignore-config"
,
"--no-video-title"
, plugin_arg };
libvlc_instance_ = LIBVLCAPI.libvlc_new(arguments);
libvlc_media_player_ = LIBVLCAPI.libvlc_media_player_new(libvlc_instance_);
//float f1=0.1f;
//LIBVLCAPI.libvlc_video_set_scale(libvlc_media_player_,f1);
}
}
public
void
Vlc_release()
{
if
(libvlc_instance_ != IntPtr.Zero)
LIBVLCAPI.libvlc_release(libvlc_instance_);
// if (libvlc_media_player_ != IntPtr.Zero)
// LIBVLCAPI.libvlc_media_release(libvlc_media_player_);
}
public
void
SetRenderWindow(
int
wndHandle)
{
if
(libvlc_instance_ != IntPtr.Zero && wndHandle != 0)
{
LIBVLCAPI.libvlc_media_player_set_hwnd(libvlc_media_player_, wndHandle);
}
}
public
void
PlayFile(string filePath)
{
IntPtr libvlc_media = LIBVLCAPI.libvlc_media_new_path(libvlc_instance_, filePath);
if
(libvlc_media != IntPtr.Zero)
{
LIBVLCAPI.libvlc_media_parse(libvlc_media);
duration_ = LIBVLCAPI.libvlc_media_get_duration(libvlc_media) / 1000.0;
LIBVLCAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media);
LIBVLCAPI.libvlc_media_release(libvlc_media);
LIBVLCAPI.libvlc_media_player_play(libvlc_media_player_);
}
}
public
void
PlayFile_rtsp(string filePath)
//libvlc_media_new_location
{
IntPtr libvlc_media = LIBVLCAPI.libvlc_media_new_location(libvlc_instance_, filePath);
if
(libvlc_media != IntPtr.Zero)
{
// LIBVLCAPI.libvlc_media_parse(libvlc_media);
// duration_ = LIBVLCAPI.libvlc_media_get_duration(libvlc_media) / 1000.0;
LIBVLCAPI.libvlc_media_player_set_media(libvlc_media_player_, libvlc_media);
LIBVLCAPI.libvlc_media_release(libvlc_media);
LIBVLCAPI.libvlc_media_player_play(libvlc_media_player_);
}
}
public
void
Pause()
{
if
(libvlc_media_player_ != IntPtr.Zero)
{
LIBVLCAPI.libvlc_media_player_pause(libvlc_media_player_);
}
}
public
void
take_snapshot()
{
if
(libvlc_media_player_ != IntPtr.Zero)
{
string filepath =
"c:\\"
;
LIBVLCAPI.libvlc_video_take_snapshot(libvlc_media_player_, 0, filepath, 0, 0);
}
}
public
void
full_screen()
{
if
(libvlc_media_player_ != IntPtr.Zero)
{
LIBVLCAPI.libvlc_set_fullscreen(libvlc_media_player_, 0);
}
}
public
void
Stop()
{
if
(libvlc_media_player_ != IntPtr.Zero)
{
LIBVLCAPI.libvlc_media_player_stop(libvlc_media_player_);
}
}
public
double
GetPlayTime()
{
return
LIBVLCAPI.libvlc_media_player_get_time(libvlc_media_player_) / 1000.0;
}
public
void
SetPlayTime(
double
seekTime)
{
LIBVLCAPI.libvlc_media_player_set_time(libvlc_media_player_, (Int64)(seekTime * 1000));
}
public
int
GetVolume()
{
return
LIBVLCAPI.libvlc_audio_get_volume(libvlc_media_player_);
}
public
void
SetVolume(
int
volume)
{
LIBVLCAPI.libvlc_audio_set_volume(libvlc_media_player_, volume);
}
public
void
SetFullScreen(
bool
istrue)
{
LIBVLCAPI.libvlc_set_fullscreen(libvlc_media_player_, istrue ? 1 : 0);
}
public
double
Duration()
{
return
duration_;
}
public
string Version()
{
return
LIBVLCAPI.libvlc_get_version();
}
}
|
如下:
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
|
#pragma once
#include <memory>
#include <basetsd.h>
typedef
SSIZE_T
ssize_t;
#include "vlc/vlc.h"
#include <mutex>
struct
libvlc_media_track_info_t;
struct
libvlc_media_t;
struct
libvlc_instance_t;
struct
libvlc_media_player_t;
struct
libvlc_event_t;
class
context;
enum
MediaState {
NothingSpecial = 0,
Opening = 1,
Buffering = 2,
Playing = 3,
Paused = 4,
Stopped = 5,
Ended = 6,
Error = 7
};
class
TestVlcVideo
{
public
:
TestVlcVideo();
void
init( std::function<
void
(
int
)> eventCallback);
void
setHwnd(
const
int64_t iHwnd) ;
bool
loadMedia(
const
char
* &url) ;
int
play() ;
void
pause() ;
void
stop() ;
void
setRatio(
const
char
* &ratio) ;
int
getVolume() ;
int
setVolume(
const
int
volume) ;
int
getMediaState() ;
libvlc_instance_t * getVlcInstance();
libvlc_media_player_t * getVlcMediaPlayer();
private
:
static
void
vlcEvents(
const
libvlc_event_t *ev,
void
*param);
static
libvlc_instance_t *m_instance;
libvlc_media_player_t *m_mediaPlayer = nullptr;
int64_t m_durationMS;
std::function<
void
(
int
)> m_eventCallback;
MediaState m_currentMediaState;
};
|
上面 static 声明的 m_instance 是为了优化效率,不必每次播放视频的时候都新建.
这是第二步工作.
需要封装真正的 DLL 了,向C#暴露的也是这个类里面的方法.
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
|
#pragma once
typedef
int
(*CallBackMediaState)(
int
);
#ifdef DLLVLC_EXPORTS // 用来导出函数
#define DLLVLC_API __declspec(dllexport)
#else // 用来标识为导入函数,对于引用该头文件的外部模块来说dllimport这个标记对编译优化有作用
#define DLLVLC_API __declspec(dllimport)
#endif
#include "Testvlcvideo.h"
namespace
TestVLCDLL {
extern
"C"
{
/*
* @brief VLC Instance和Player实例初始化
* @param CallBackMediaState callback 回调函数为媒体播放状态
* @return 每次vlcInit会返回一个VLC的Player ID,此ID唯一,后面的接口都需要此ID找到对应的Player
*/
DLLVLC_API
int
vlcInit(CallBackMediaState callback);
/*
* @brief VLC 媒体加载接口
* @param int index PlayerID
* @param const char *path 媒体路径
*/
DLLVLC_API
bool
vlcLoad(
int
index,
const
char
*path);
/*
* @brief 设置句柄,如不设置则为默认窗口播放
* @param const int64_t iHwnd windows窗口句柄
*/
DLLVLC_API
bool
vlcSetHwnd(
int
index,
const
int64_t iHwnd);
DLLVLC_API
bool
play(
int
index);
DLLVLC_API
bool
pause(
int
index);
DLLVLC_API
bool
stop(
int
index);
/*
* @brief 设置播放窗口比例
* @param 形如 16:9 4:3 等字符串
*/
DLLVLC_API
bool
setRatio(
int
index,
const
char
* ratio);
/*
* @brief 设置媒体播放音量
*/
DLLVLC_API
bool
setVolume(
int
index,
int
volume);
/*
* @brief 获取媒体总时长
*/
DLLVLC_API int64_t getMediaLength(
int
index);
/*
* @brief 获取当前播放状态
*/
DLLVLC_API
int
getMediaState(
int
index);
/*
* @brief 销毁VLC Player
*/
DLLVLC_API
bool
vlcDisponse(
int
index);
}
}
|
首先在最开始定义了 CallBackMediaState 回调函数,对应C++ 层使用函数指针和std::function 都可以。然后使用 DLLVLC_EXPORTS 指示本类为导出类,然后再使用 DLLVLC_API 宏定义导出函数,这些方法都是 dll 暴露给外部调用的方法.
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
|
// DLLVLC.cpp : 定义 DLL 应用程序的导出函数。
#define DLLVLC_EXPORTS
#include "DLLVLC.h"
#include "Testvlcvideo.h"
#include <iostream>
#include <map>
#include <mutex>
#include <atomic>
std::map<
int
, TestVlcVideo*> g_mapVLC;
std::atomic_int g_iIndex = 0;
std::mutex g_mt;
DLLVLC_API
int
TestVLCDLL::vlcInit(CallBackMediaState callback)
{
//如果是初次调用,则初始化instance,否则复用instance
std::lock_guard<std::mutex> l(g_mt);
++g_iIndex;
TestVlcVideo *vlcVideo =
new
TestVlcVideo;
g_mapVLC.emplace(g_iIndex, vlcVideo);
g_mapVLC.at(g_iIndex)->init(callback);
return
g_iIndex;
}
DLLVLC_API
bool
TestVLCDLL::play(
int
index)
{
std::lock_guard<std::mutex> l(g_mt);
TestVlcVideo *vlcVideo = g_mapVLC.at(index);
if
(nullptr == vlcVideo)
{
return
false
;
}
vlcVideo->play();
return
true
;
}
.......
|
因为我们采用的是导出接口方法,而不是导出类(导出类比较麻烦,自己测试未能成功),因此在制作 dll 库时,使用静态 map 保存相关实例,使用对应的 init方法和 dispose 方法借助 id 参数创建和销毁对象.
下来再看下我们第一段代码的 cpp 文件,就是 vlc 简单封装的具体实现:
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
|
#include "Testvlcvideo.h"
#include <iostream>
libvlc_instance_t *TestVlcVideo::m_instance = nullptr;
TestVlcVideo::TestVlcVideo()
: m_mediaPlayer(nullptr)
, m_durationMS(0)
, m_eventCallback(nullptr)
{
}
void
TestVlcVideo::init(std::function<
void
(
int
)> eventCallback)
{
getVlcInstance();
{
getVlcMediaPlayer();
libvlc_event_manager_t *em = libvlc_media_player_event_manager(m_mediaPlayer);
{
libvlc_event_attach(em, libvlc_MediaPlayerPlaying, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerPaused, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerStopped, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerNothingSpecial, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerOpening, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerBuffering, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerEndReached, vlcEvents,
this
);
libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, vlcEvents,
this
);
}
m_eventCallback = std::move(eventCallback);
}
}
void
TestVlcVideo::setHwnd(
const
int64_t iHwnd)
{
libvlc_media_player_set_hwnd(m_mediaPlayer, (
void
*)iHwnd);
}
bool
TestVlcVideo::loadMedia(
const
char
* &url)
{
libvlc_media_t *m_media = nullptr;
std::string url_ = url;
if
(url_.find(
"://"
) == std::string::npos)
{
m_media = libvlc_media_new_path(getVlcInstance (), url);
}
else
{
m_media = libvlc_media_new_location(getVlcInstance(), url);
}
if
(nullptr == m_media)
{
m_currentMediaState = MediaState::Error;
return
false
;
}
libvlc_media_player_set_media(getVlcMediaPlayer (), m_media);
libvlc_media_parse(m_media);
m_durationMS = libvlc_media_get_duration(m_media);
libvlc_media_release(m_media);
return
true
;
}
libvlc_instance_t * TestVlcVideo::getVlcInstance()
{
if
(nullptr == m_instance)
{
m_instance = libvlc_new(0, NULL);
}
return
m_instance;
}
libvlc_media_player_t * TestVlcVideo::getVlcMediaPlayer()
{
if
(nullptr == m_mediaPlayer)
{
m_mediaPlayer = libvlc_media_player_new(m_instance);
}
return
m_mediaPlayer;
}
int
TestVlcVideo::play()
{
return
libvlc_media_player_play(m_mediaPlayer);
}
void
TestVlcVideo::pause()
{
if
(libvlc_media_player_is_playing(m_mediaPlayer))
{
libvlc_media_player_set_pause(m_mediaPlayer, 1);
}
else
{
libvlc_media_player_set_pause(m_mediaPlayer, 0);
}
}
|
到这儿,一般情况下我们还需要配置 def 文件,以避免导出的函数名被增加额外的信息,而不是简短的“play”等。但是可以看到我们在所有的导出函数前增加了“extern C ”标识。意思是这些函数按照 C 标准进行编译,由于C++ 的函数重载,再加上各个编译器的不同,导致编译而出的函数名被(mangled name),且各不相同,但是C不支持重载,因此采用统一的编译规定,同时也可以保证此函数被 C 正确调用,所以我们就无需写 def 文件也可以保证函数名不被破坏.
上面简要说完了 C++ 端关于 DLL 的封装,再总结一下大概就是这几点:
1
2
3
4
5
|
#ifdef DLLVLC_EXPORTS // 用来导出函数
#define DLLVLC_API __declspec(dllexport)
#else // 用来标识为导入函数,对于引用该头文件的外部模块来说dllimport这个标记对编译优化有作用
#define DLLVLC_API __declspec(dllimport)
#endif
|
导出函数添加 extern "C" DLLVLC_API 声明.
1
2
3
4
5
6
7
8
9
10
|
[DllImport(@
"C:\Users\HiWin10\Desktop\DLLVLC\DLLVLC\DLLVLC\x64\Release\DLLVLC.dll"
, EntryPoint =
"vlcInit"
,
SetLastError =
true
,
CharSet = CharSet.Ansi,
ExactSpelling =
false
,
CallingConvention = CallingConvention.Cdecl)]
public
extern
static
int
vlcInit(DllcallBack pfun);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public
delegate
int
DllcallBack(
int
MediaState);
|
C# 的回调函数即为委托,需要提前定义委托 DllcallBack ,然后我们假定它是被 C++ 认可的,作为参数传入 vlcInit。在下面我们需要写此委托函数具体的实现:
1
2
3
4
5
|
public
static
int
CsharpCall(
int
MediaState)
{
Console.WriteLine(MediaState);
return
MediaState;
}
|
使用的时候:
1
2
3
4
5
6
7
8
|
static
int
index;
static
void
Main(string[] args)
{
DllcallBack mycall;
mycall =
new
DllcallBack(Program.CsharpCall);
index = vlcInit(mycall);
......
}
|
经过验证,此种方式的回调函数能被 C++ 承认,对应于C++的 std::function.
1
2
3
4
5
6
7
|
[DllImport(@
"C:\Users\HiWin10\Desktop\DLLVLC\DLLVLC\DLLVLC\x64\Release\DLLVLC.dll"
, EntryPoint =
"vlcLoad"
,
CallingConvention = CallingConvention.Cdecl)]
public
extern
static
bool
vlcLoad(
int
index, string path);
[DllImport(@
"C:\Users\HiWin10\Desktop\DLLVLC\DLLVLC\DLLVLC\x64\Release\DLLVLC.dll"
, EntryPoint =
"vlcSetHwnd"
,
CallingConvention = CallingConvention.Cdecl)]
public
extern
static
bool
vlcSetHwnd(
int
index,
int
iHwnd);
|
上面是 C# 关于普通导出函数的加载方法,在 main 函数中直接进行调用即可.
1
2
3
4
5
6
7
8
9
10
|
static
int
index;
static
void
Main(string[] args)
{
DllcallBack mycall;
mycall =
new
DllcallBack(Program.CsharpCall);
index = vlcInit(mycall);
Console.WriteLine(vlcLoad(index, @
"D:\1.mp4"
));
Console.WriteLine(getMediaLength(index));
play(index);
setRatio(index,
"16:9"
);
|
其实 C# 端的调用还是比较简单的,上面的方式是采用静态加载的方式,需要将C++ 的 dll 放到 C# 工程 bin 目录下,而动态加载的方式笔者未进行尝试.
整个过程就完成了,使用 C++ 封装的方式可以使用一些只支持 C++,只有 C++ API 的强大库,也可以防止反编译,还可以使代码更好的分层等.
下面附上demo链接,有需要的小伙伴可下载运行(VS2015) 。
DLLVLCfor.rar 。
到此这篇关于C++ 封装 DLL 供 C# 调用详细介绍的文章就介绍到这了,更多相关C++ 封装 DLL 供 C# 调用内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.tuicool.com/articles/beiqauN 。
最后此篇关于C++ 封装 DLL 供 C# 调用详细介绍的文章就讲到这里了,如果你想了解更多关于C++ 封装 DLL 供 C# 调用详细介绍的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
晚上在 QQ 上看到昵称为“乱码”的好友回答了搜搜问问里一个问题: 在VBS中有办法定义字节数组么? 在VBS中有办法定义字节数组么?就是字节子类型数组(VarType是8209的那种)注意不是V
例如,员工管理应用程序可能包括一个EmPloyee 类。然后可以用这个类来创建和维护特定实例,比如Gonn和Sally。 根据预定义的类创建对象常称为类的实例化(class insta
在自然语言中,我们理解抽象的概念是,一个物体的一种大的描述,这种描述对某类物体来说是共有的特性。那么在PHP中也是一样的,我们把一个类进行抽象,可以指明类的一般行为,这个类应该是一个模板,它指示它的
DBA_2PC_PENDING Oracle会自动处理分布事务,保证分布事务的一致性,所有站点全部提交或全部回滚。一般情况下,处理过程在很短的时间内完成,根本无法察觉到。但是,如果在commit或
目录 计算过程 投影分量计算 假设你有一家理发店,已经记录了过去一年中所有顾客的头发长度和发型偏好的数据。现在你想从这些数据中提取一些主要的信息,比如顾客最常
Object.defineProperty函数会直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性,并返回此对象。 一、简单使用 const obj = {} Object.defineP
SPL官网 http://www.scudata.com.cn/ 介绍 业务逻辑经常包含较复杂的流程和计算,同时涉及数据库的读写。由于授权麻烦、影响数据库安全、无法迁移、技术要求高、编写困难等原因,很
SPL官网 http://www.scudata.com.cn/ 介绍 业务逻辑经常包含较复杂的流程和计算,同时涉及数据库的读写。由于授权麻烦、影响数据库安全、无法迁移、技术要求高、编写困难等原因,很
一 点睛 Thrift 是一歀基于 CS 架构的 RPC 框架,最初由 Facebook 研发,2008 年转入 Apache 组织。开发人员可以使用 Thrift 提供的 IDL(接口定义语言)来定
数据库应用程序与主应用程序分开存在,并存储数据集合。 每个数据库都使用一个或多个API来创建,访问,管理,搜索和复制其包含的数据。 数据库还使用非关系数据源,例如对象或文件。 然而,数据库证明是大数
介绍 Ant是一个 Apache 基金会下的跨平台的基于 Java 语言开发的构件工具。在我们详细了解 Apache Ant 之前, 让我们来讲解为什么构建工具是需要最先了解的。 构建工具的需求
我现在正在尝试学习ocaml,并希望从一个小程序开始,生成所有位组合: [“0”,“0”,“0”] [“0”,“0”,“1”] [“0”,“1”,“0”] ... 等等 我的想法是下面的代码: let
我正在做我的介绍 C 类(class)作业,我的任务是执行以下任务...... 为一个函数编写代码,该函数通过值接收两个参数(a 和 b)并通过引用具有另外两个参数(c 和 d)。所有参数都是双倍的。
我希望提供有关我网站内容的快速演示,以及如何在用户访问我的页面后立即以正确的方式使用它们。我希望使用顶部的弹出式窗口进行演示。 我的意思是小信息框,一个接一个地通知用户各个步骤。任何人都可以帮助我如何
与C、Java等语言一样,JavaScript中可以用&&、||、!三个逻辑判断符来对boolean值进行逻辑判断。与C、Java不同的是,JavaScript中逻辑与(&&
JavaScript中,==与===操作符均可用于判断两个值是否相等;不同之处在于,如果进行判断的两个值类型不一致,===操作符会直接返回false,而==操作符则会在类型转换后再进行判断。详细的判
JavaScript中,object转换为boolean的操作非常简单:所有的object转换成boolean后均为true;即使是new Boolean(false)这样的object在转换为bo
在android开发中,当不满足触发条件就按返回键的时候,就要对此进行检测。尤其是当前Activity需要往前一个Activity传送消息时。即Activity1跳转到Activity3如果采用的是
背景 当要求系统启动一个应用程序时,系统会先查找当前命令是否是内部命令,若不是,则在当前目录下查找,如果仍没有找到,则在系统变量 Path 指定的路径去查找。JDK(Java Developmen
概述 想做一个微信的公众平台,阅读了微信官方给的网址接入的示例代码,发现有个问题好像一直都是半知半解的,就是在类里边直接使用$_GET。仔细查了下关于这方面的知识,发现PHP中这部分的基础知识掌握
我是一名优秀的程序员,十分优秀!