Node 使用 VLC 播放音视频开发文档 - 3
增加支持输出到指定的句柄 id 上,并且支持暂停和继续播放
为了支持输出到指定的句柄 ID(例如,一个窗口句柄)以及支持暂停和继续播放功能,你需要进行以下修改:
输出到指定句柄:使用
libvlc_media_player_set_hwnd()
函数来设置播放输出的句柄。暂停和继续播放:使用
libvlc_media_player_pause()
函数来暂停或继续播放。如果播放器处于播放状态,该函数将暂停它;如果处于暂停状态,它将恢复播放。
下面是 C++代码的修改部分:
cpp
libvlc_media_player_t *mp = nullptr; // Make it global to control it from other functions.
void PlayMedia(const FunctionCallbackInfo<Value>& args) {
// ... (The beginning remains the same)
mp = libvlc_media_player_new_from_media(m);
libvlc_media_release(m);
if (args.Length() > 2 && args[2]->IsNumber()) {
uintptr_t hwnd = args[2]->IntegerValue(isolate->GetCurrentContext()).FromJust();
libvlc_media_player_set_hwnd(mp, (void*)hwnd);
}
libvlc_media_player_play(mp);
}
void PauseOrResume(const FunctionCallbackInfo<Value>& args) {
if (mp) {
libvlc_media_player_pause(mp);
}
}
然后,你需要在 Init
函数里注册新的 PauseOrResume
函数:
cpp
void Init(Local<Object> exports) {
// ... (Other initialization code)
NODE_SET_METHOD(exports, "playMedia", PlayMedia);
NODE_SET_METHOD(exports, "pauseOrResume", PauseOrResume);
}
在 JavaScript 端,你的 API 使用方法如下:
javascript
const vlcAddon = require("./your_module_path");
// Play a local or remote media on a given window handle
vlcAddon.playMedia("path_or_url", 1000, windowHandle);
// Pause or resume the current media
vlcAddon.pauseOrResume();
其中,windowHandle
是你想在上面显示视频的窗口的句柄 ID。这通常是一个整数值,但其确切类型和格式取决于你的应用程序和平台。
这些修改应该提供了你需要的功能,但请记住在真实应用中进行充分的测试,确保一切正常工作。
addon.cc 修改内容如下
addon.cc 顶部增加 libvlc_media_player_t *mp
cpp
FILE* log_file = nullptr;
const char* log_filename = "vlc_log.txt";
const char* old_log_filename = "vlc_log.old.txt";
const int default_max_log_size = 1 * 1024 * 1024; // 1MB
int max_log_size = default_max_log_size;
bool logging_enabled = true;
libvlc_media_player_t *mp = nullptr; // Make it global to control it from other functions.
修改后的 PlayMedia 和新增的 PauseOrResume
cpp
void PlayMedia(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() < 1 || !args[0]->IsString()) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Expected a string argument for the media path or URL").ToLocalChecked()));
return;
}
String::Utf8Value mediaPath(isolate, args[0]);
int cache = args[1]->IsNumber() ? args[1]->Int32Value(isolate->GetCurrentContext()).FromJust() : 1000; // Default 1000ms if applicable
libvlc_instance_t *inst;
libvlc_media_t *m;
inst = libvlc_new(0, nullptr);
libvlc_log_set(inst, log_callback, log_file); // Set log callback
// Check if the provided media path is an HTTP URL or a local file
if (strncmp(*mediaPath, "http://", 7) == 0 || strncmp(*mediaPath, "https://", 8) == 0) {
m = libvlc_media_new_location(inst, *mediaPath);
std::string cache_option = ":network-caching=" + std::to_string(cache);
libvlc_media_add_option(m, cache_option.c_str());
} else {
m = libvlc_media_new_path(inst, *mediaPath);
}
mp = libvlc_media_player_new_from_media(m);
libvlc_media_release(m);
if (args.Length() > 2 && args[2]->IsNumber()) {
uintptr_t hwnd = args[2]->IntegerValue(isolate->GetCurrentContext()).FromJust();
libvlc_media_player_set_hwnd(mp, (void*)hwnd);
}
libvlc_media_player_play(mp);
}
void PauseOrResume(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
bool isPlaying = false;
if (mp) {
if (libvlc_media_player_is_playing(mp)) {
libvlc_media_player_pause(mp);
} else {
libvlc_media_player_play(mp);
isPlaying = true;
}
fprintf(log_file, "PauseOrResume has mp: %p\n", mp);
fflush(log_file);
} else {
fprintf(log_file, "PauseOrResume not mp: %p\n", mp);
fflush(log_file);
}
// Return the playing status
args.GetReturnValue().Set(Boolean::New(isolate, isPlaying));
}
void Init(Local<Object> exports) {
log_file = fopen(log_filename, "a"); // Open or append to existing log file
if (!log_file) {
fprintf(stderr, "Failed to open %s for logging\n", log_filename);
return;
}
NODE_SET_METHOD(exports, "playMedia", PlayMedia);
NODE_SET_METHOD(exports, "pauseOrResume", PauseOrResume);
NODE_SET_METHOD(exports, "setLoggingEnabled", SetLoggingEnabled);
NODE_SET_METHOD(exports, "setMaxLogSize", SetMaxLogSize);
}
这里增加日志写入“PauseOrResume has mp” 可以在 vlc_log.txt 查看调用暂停和开始的内容
index.js 修改增加 pauseOrResume 方法
js
module.exports = {
/**
* 播放给定URL的HTTP流。
* @param {string} url - 要播放的流的URL。
* @param {number} [cache=1000] - 缓存大小,单位为毫秒。默认为1000ms。
*/
playMedia: addon.playMedia,
/**
* 暂停或继续当前的媒体播放。
*/
pauseOrResume: addon.pauseOrResume,
};
main.js 中测试使用可用
js
vlcAddon.playMedia(newURL, 5000); // 5000ms caching
setTimeout(() => {
vlcAddon.pauseOrResume();
console.log("调用暂停");
setTimeout(() => {
console.log("调用继续");
vlcAddon.pauseOrResume();
}, 5000);
}, 5000);
printf("PauseOrResume has mp: %p", mp); 是否可以输出到 log_filename 中,怎么修改
如果你想将 printf
的输出写入到 log_filename
(即你的日志文件)中,你应该使用 fprintf
函数,它允许你指定一个文件指针作为输出目标。
更改这一行:
cpp
printf("PauseOrResume has mp: %p", mp);
为:
cpp
fprintf(log_file, "PauseOrResume has mp: %p\n", mp);
和这一行:
cpp
printf("PauseOrResume not mp: %p", mp);
为:
cpp
fprintf(log_file, "PauseOrResume not mp: %p\n", mp);
这样,输出就会写入到你的日志文件中。
另外,确保在写入后,你调用 fflush(log_file);
,以确保日志消息立即被写入文件:
cpp
fprintf(log_file, "PauseOrResume has mp: %p\n", mp);
fflush(log_file);
和:
cpp
fprintf(log_file, "PauseOrResume not mp: %p\n", mp);
fflush(log_file);
这样,即使程序在之后崩溃或被中断,你仍然可以看到这些日志消息。