# Pc Player

* [功能使用](#功能使用)
  * [SDK 名词含义及功能说明](#sdk-名词含义及功能说明)
  * [SDK 全局函数](#sdk-全局函数)
  * [SDK 防录制功能](#sdk-防录制功能)
  * [SDK 下载器](#sdk-下载器)
  * [SDK 播放器](#sdk-播放器)
  * [SDK 注意事项](#sdk-注意事项)

本文档提供了使用 C++SDK 的操作步骤及代码示例，通过本文您可以快速了解如何使用 SDK 提供的功能。您也可以通过 Demo 中的示例进行了解和自有业务开发。

## SDK 名词含义及功能说明

* 参见 **`plv-player-def.h`**

## SDK 全局函数

1. 设置日志，日志过滤项。
2. 设置观众信息（用于后台数据追踪）。
3. 设置相关参数（硬解开关，网络请求类型等）。
4. 初始化（userid, key）。
5. 退出析构。

```cpp
std::count << "the sdk version:" << PLVGetSdkVersion() << std::endl;
// 设置日志信息,路径须使用utf8
PLVSetSdkLogMessageCallback(true,[](LOG_FILTER_TYPE, const char*, void*){}, nullptr);
PLVSetSdkLogLevel(LOG_FILTER_INFO);
int ret = PLVSetSdkLogFile("C:/log/sdk.log");
std::count << "the log file result:" << ret << std::endl;
// 设置 viewer 信息，用于定位播放质量问题，在线播放下可以通过后台来查看，建议调用此接口设置信息
// 最新 vrm12/vrm13 下必须设置，否则播放会报错
std::string viewerId = "业务id";// 唯一值
std::string viewerName = "业务nick";
std::string viewerAvatar= "业务Avatar";
PLVSetSdkViewerInfo(viewerId.c_str(), viewerName.c_str(), viewerAvatar.c_str());
//初始化SDK,建议不要传入secretKey与appSecret,相关信息由业务服务器获取后传给客户端
PLVAccountInfo accountInfo;
accountInfo.userId = "xxxx";
ret = PLVInitSdkLibrary(&accountInfo);
std::cout << "init sdk result:" << ret << std::endl;
//释放SDK
PLVReleaseSdkLibrary();

//以下为播放相关全局设置,详见文档信息
PLVSetSdkLocalRememberPlay(true);
PLVSetSdkKeepLastFrame(true);
PLVSetSdkHwdecEnable(false);
PLVSetSdkVideoOutputDevice(VIDEO_OUTPUT_GPU, nullptr);
PLVSetSdkSeed("xxxxxxx");
//以下为下载相关全局设置,详见文档信息
PLVSetSdkRetryAttempts();

// 获取错误描述
auto desc = PLVGetSdkErrorDescription(ret);
std::cout<< "the error info: << desc << std::endl;
```

## SDK 防录制功能

防录制功能的说明，必须 SDK 初始化之后才能使用，操作步骤及功能示例如下：

```cpp
// 注意通知回调都是子线程，如果更新 ui 及操作 api 都需要 post 到主线程
class Record{
public:
    Record(void){
        // 软件录制通知或者破解注入通知
        PLVSetDetectSoftwareRecordingHandler(true, []（SOFTWARE_RECORDING_NOTIFY_TYPE type, const char* softwares, void* data）{
            // 有插件注入通知，可能有软件在录制你的播放界面，可以在业务上做处理
            // PostMessage
        }, userdata);
        
        // 硬件设备变动的回调通知, 此回调可以用于防止 HDMI 硬件录制, 业务侧可以根据回调类型进行播放器是否禁播操作
        PLVSetDetectHardwareRecordingHandler(true, [](DEVICE_CHANGED_TYPE type, const char* device, void* data){
            // HDMI 设备有变动，请根据 type 类型判断，可能是 HDMI 设备在录制你的屏幕
            // PostMessage
        }, userdata);
    }
    // 软件防录制
    int SetPreventSoftwareRecording(void* window, bool enable){
        return PLVSetPreventSoftwareRecording(window, enable);
    }
    int GetPreventSoftwareRecording(void* window, bool* enable){
        return PLVGetPreventSoftwareRecording(window, enable);
    }
    
};
```

## SDK 下载器

视频下载的操作步骤及功能示例如下：

```cpp
// 注意通知回调都是子线程，如果更新 ui 及操作 api 都需要 post 到主线程
class Download{
private:
    PLVDownloadPtr downolader = nullptr;
public:
    Download(void){
        // 创建下载器
        downolader = PLVDownloadCreate();
        
        // 设置错误回调通知
        PLVDownloadSetErrorHandler(downolader, [](const char* vid, int code, void* data) {
            // 错误通知 code 为错误码
            // PostMessage
        }, userdata);
        // 设置下载进度回调通知
        PLVDownloadSetProgressHandler(downolader, [](const char* vid, long long receivedBytes, long long totalBytes, void* data) {
            // 下载进度
            // PostMessage
        }, userdata);
        // 设置下载结果回调通知
        PLVDownloadSetResultHandler(downolader, [](const char* vid, int rate, int code, void* data) {
            // 下载结果
            // PostMessage
        }, userdata);
    }
    ~Download(void){
        PLVDownloadDestroy(downolader);
        downolader = nullptr;
    }
    // 设置下载信息，操作前必须先调用此接口
    int SetInfo(const char* vid, const char* path, int rate){
        return PLVDownloadSetInfo(downolader, vid, path, rate);
    }
    // 开始下载
    // autoDownRate 是否自动降清晰度，false 如果没有这个清晰度则返回错误码
    int Start(const char* token, bool autoDownRate){
        return PLVDownloadStart(downolader, token, autoDownRate);
    }
    // 结束下载，退出线程
    int Stop(void){
        return PLVDownloadStop(downolader);
    }
    // 暂停下载，不退出线程，可以快速切换下载状态
    int Pause(bool pause){
        return PLVDownloadPause(downolader);
    }
    // 删除下载文件
    int Delete(void){
        return PLVDownloadDelete(downolader);
    }  
    // 取消所有回调设置
    int Reset(void){
        return PLVDownloadResetHandler(downolader);
    }
};
```

## SDK 播放器

视频播放的操作步骤及功能示例如下：

```cpp
// 注意通知回调都是子线程，如果更新 ui 及操作 api 都需要 post 到主线程
class Player{
private:
    PLVPlayer mediaPlayer = nullptr;
public:
    Player((void*)window){
        // 创建播放器
        mediaPlayer = PLVPlayerCreate(window);
        
        // 设置播放器的播放状态通知
        PLVPlayerSetStateHandler(mediaPlayer, [](const char* vid, int state, void* data) {
            // 播放器的状态，state 参见 PLAYER_MEDIA_STATE
            // PostMessage();
        }, userdata);
        // 设置视频的属性回调通知
        PLVPlayerSetPropertyHandler(mediaPlayer, [](const char* vid, int property, int format, const char* value, void* data) {
            // 播放器的属性值
            // PostMessage();
        }, userdata);
        // 设置码率清晰度变化通知 （只有输入的码率不存在，自动降值才会触发此通知）
        PLVPlayerSetRateChangeHandler(mediaPlayer, [](const char* vid, int inputBitRate, int realBitRate, void* data) {
            // 真实的清晰度，比如目标清晰度为超清，但不存在此清晰度，会自动降值为 realBitRate
            // PostMessage();
        }, userdata);
        // 设置播放器播放进度回调通知
        PLVPlayerSetProgressHandler(mediaPlayer, [](const char* vid, int millisecond, void* data) {
            // 播放位置
            // PostMessage();
        }, userdata);
        // 设置扬声器设备有热插拔的变动通知
        PLVPlayerSetAudioDeviceHandler(mediaPlayer, [](int audioDeviceCount, void* data) {
            // 扬声器设备变动，此为设备热插拔变动通知，可以 post 到主线程再调用 ReloadAudio();
            // PostMessage();
        }, userdata);
    }
    ~Player(void){
        PLVPlayerDestroy(mediaPlayer);
        mediaPlayer = nullptr;
    }
    
    // 设置跑马灯
    int SetOSD(bool enable, const PLVOsdConfigInfo* config){
        return PLVPlayerSetOSDConfig(mediaPlayer, enable, config);
    }
    int GetOSD(PLVOsdConfigInfo& config){
        return PLVPlayerGetOSDConfig(config);
    }
    // 设置 LOGO text
    int SetLogo(bool enable, const PLVLogoTextInfo* config);
    int GetLogo(PLVLogoTextInfo& config);
    // 设置缓存，可以不设置，播放器会有默认值
    int SetCache(bool enable, int maxCacheBytes, int maxCacheSeconds);
    int GetCache(int* maxCacheBytes, int* maxCacheSeconds);
    // 播放前要先设置 vid
    int SetInfo(const char* vid, const char* path, int rate);
    // 播放，token 外部获取，seekMillisecond 为要跳转到播放位置，sync 由于会先请求 vid 的信息，会有 http 请求，如果网络好请使用 true 同步，否则可以用 false
    int Play(const char* token, int seekMillisecond, bool autoDownRate, bool playWithToken, bool sync);
    // 本地播放
    int PlayLocal(int seekMillisecond, bool autoDownRate);
    // 本地加载，不播放
    int LoadLocal(int seekMillisecond, bool autoDownRate);
    int Pause(bool pause);
    int Stop(void);
    int SetMute(bool mute);
    // 跳转，由于视频文件都是经过后台编码过，关键帧会被优化，跳转会不准确。可以对比 mp4 与 m3u8，差别会比较大，mp4 拖动很准，m3u8 跳动很大。
    int SetSeek(int millisecond);
    // 跳转到结束，由于 m3u8 跳转不准，有需要跳转到尾部的请使用此接口
    int SeekToEnd(void);
    int SetVolume(int volume);
    // 声音增益，最大可到 1000
    int SetVolumeMax(int volume);
    // 倍数播放
    int SetSpeed(double speed);
    // 截图，注意使用 utf8
    int Screenshot(const char* filename);
       
    // 扬声器热插拔相关
    int GetAudioDeviceCount();
    int GetAudioDeviceInfo(int index, char deviceId[PLV_MAX_DEVICE_ID_LENGTH], char deviceName[PLV_MAX_DEVICE_ID_LENGTH]);
    int GetCurrentAudioDevice(char deviceId[PLV_MAX_DEVICE_ID_LENGTH]);
    int SetCurrentAudioDevice(const char deviceId[PLV_MAX_DEVICE_ID_LENGTH]);
};
```

## SDK 注意事项

1. 所有接口与路径相关，都必须使用 utf8 编码。
2. 所有回调通知，都不能在里面更新界面或者调用其它 api，更新界面必须 post 到 ui 线程，调用 api 必须在其它线程操作。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://polyv.gitbook.io/document/docs/vod/pc_player.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
