[*] 多线程
This commit is contained in:
@@ -57,10 +57,8 @@ target_include_directories(
|
|||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
${PROJECT_NAME} PUBLIC
|
${PROJECT_NAME} PUBLIC
|
||||||
# NAPI
|
# libuv
|
||||||
libace_napi.z.so
|
libuv.so
|
||||||
# LOG
|
|
||||||
libhilog_ndk.z.so
|
|
||||||
# EGL
|
# EGL
|
||||||
libEGL.so
|
libEGL.so
|
||||||
# OpenGL ES
|
# OpenGL ES
|
||||||
@@ -71,6 +69,10 @@ target_link_libraries(
|
|||||||
libohaudio.so
|
libohaudio.so
|
||||||
# 相机
|
# 相机
|
||||||
libohcamera.so
|
libohcamera.so
|
||||||
|
# NAPI
|
||||||
|
libace_napi.z.so
|
||||||
|
# LOG
|
||||||
|
libhilog_ndk.z.so
|
||||||
# 图片
|
# 图片
|
||||||
libnative_image.so
|
libnative_image.so
|
||||||
# NativeBuffer
|
# NativeBuffer
|
||||||
|
|||||||
@@ -6,11 +6,19 @@
|
|||||||
* @author acgist
|
* @author acgist
|
||||||
*
|
*
|
||||||
* https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/native-lib/napi.md
|
* https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/reference/native-lib/napi.md
|
||||||
|
* https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/napi/use-napi-thread-safety.md
|
||||||
|
* https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/performance/native-threads-call-js.md
|
||||||
|
* https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/performance/develop-Native-modules-using-NAPI-safely-and-efficiently.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <future>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <uv.h>
|
||||||
|
|
||||||
#include <hilog/log.h>
|
#include <hilog/log.h>
|
||||||
|
|
||||||
@@ -42,20 +50,25 @@ static std::recursive_mutex taoyaoMutex;
|
|||||||
size_t length; \
|
size_t length; \
|
||||||
char chars[2048] = { 0 }; \
|
char chars[2048] = { 0 }; \
|
||||||
napi_get_value_string_utf8(env, args[0], chars, sizeof(chars), &length); \
|
napi_get_value_string_utf8(env, args[0], chars, sizeof(chars), &length); \
|
||||||
OH_LOG_INFO(LOG_APP, "解析JSON:%s", chars); \
|
if(length <= 0) { \
|
||||||
|
OH_LOG_WARN(LOG_APP, "TAOYAO ERROR JSON: %{public}s", chars); \
|
||||||
|
napi_create_int32(env, -1, &ret); \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
OH_LOG_DEBUG(LOG_APP, "TAOYAO JSON: %{public}s", chars); \
|
||||||
nlohmann::json json = nlohmann::json::parse(chars, chars + length); \
|
nlohmann::json json = nlohmann::json::parse(chars, chars + length); \
|
||||||
nlohmann::json body = json["body"];
|
nlohmann::json body = json["body"];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 房间检查
|
// 房间检查
|
||||||
#ifndef TAOYAO_ROOM_CHECK
|
#ifndef TAOYAO_ROOM_CHECK
|
||||||
#define TAOYAO_ROOM_CHECK(action) \
|
#define TAOYAO_ROOM_CHECK(action) \
|
||||||
std::string roomId = body["roomId"]; \
|
std::string roomId = body["roomId"]; \
|
||||||
auto room = acgist::roomMap.find(roomId); \
|
auto room = acgist::roomMap.find(roomId); \
|
||||||
if(room == acgist::roomMap.end()) { \
|
if(room == acgist::roomMap.end()) { \
|
||||||
OH_LOG_WARN(LOG_APP, "房间无效:%s %s", #action, roomId.data()); \
|
OH_LOG_WARN(LOG_APP, "TAOYAO ERROR ROOM ID: %{public}s %{public}s", #action, roomId.data()); \
|
||||||
napi_create_int32(env, -1, &ret); \
|
napi_create_int32(env, -1, &ret); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -64,6 +77,7 @@ namespace acgist {
|
|||||||
uint32_t width = 720;
|
uint32_t width = 720;
|
||||||
uint32_t height = 480;
|
uint32_t height = 480;
|
||||||
uint64_t bitrate = 3'000'000L;
|
uint64_t bitrate = 3'000'000L;
|
||||||
|
uint32_t iFrameInterval = 5'000;
|
||||||
double frameRate = 30.0;
|
double frameRate = 30.0;
|
||||||
int32_t samplingRate = 48'000;
|
int32_t samplingRate = 48'000;
|
||||||
int32_t channelCount = 2;
|
int32_t channelCount = 2;
|
||||||
@@ -71,18 +85,30 @@ int32_t bitsPerSample = 16;
|
|||||||
std::string clientId = "";
|
std::string clientId = "";
|
||||||
std::string name = "";
|
std::string name = "";
|
||||||
|
|
||||||
|
// 索引:667-999
|
||||||
|
static uint32_t index = 667;
|
||||||
|
// 最小索引
|
||||||
|
static uint32_t minIndex = 667;
|
||||||
|
// 最大索引
|
||||||
|
static uint32_t maxIndex = 999;
|
||||||
|
// 终端索引
|
||||||
|
static uint32_t clientIndex = 99999;
|
||||||
// ETS环境
|
// ETS环境
|
||||||
static napi_env env = nullptr;
|
static napi_env env = nullptr;
|
||||||
// 是否加载
|
// 是否加载
|
||||||
static bool initTaoyao = false;
|
static bool initTaoyao = false;
|
||||||
// PUSH方法引用
|
// push方法引用
|
||||||
static napi_ref pushRef = nullptr;
|
static napi_ref pushRef = nullptr;
|
||||||
// REQUEST方法引用
|
// request方法引用
|
||||||
static napi_ref requestRef = nullptr;
|
static napi_ref requestRef = nullptr;
|
||||||
|
// request线程安全方法
|
||||||
|
static napi_threadsafe_function requestFunction = nullptr;
|
||||||
// 媒体功能
|
// 媒体功能
|
||||||
static acgist::MediaManager* mediaManager = nullptr;
|
static acgist::MediaManager* mediaManager = nullptr;
|
||||||
// 房间管理
|
// 房间管理
|
||||||
static std::map<std::string, acgist::Room*> roomMap;
|
static std::map<std::string, acgist::Room*> roomMap;
|
||||||
|
// 异步回调
|
||||||
|
static std::map<uint64_t, std::promise<std::string>*> promiseMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支持的编解码
|
* 支持的编解码
|
||||||
@@ -91,58 +117,135 @@ static void printSupportCodec() {
|
|||||||
// TODO: 验证是否需要释放
|
// TODO: 验证是否需要释放
|
||||||
OH_AVCapability* format = nullptr;
|
OH_AVCapability* format = nullptr;
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_OPUS, true);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_OPUS, true);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持OPUS硬件解码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持OPUS硬件解码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_OPUS, false);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_OPUS, false);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持OPUS硬件解码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持OPUS硬件解码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_G711MU, true);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_G711MU, true);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持PCMU硬件编码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持PCMU硬件编码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_G711MU, false);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_G711MU, false);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持PCMU硬件解码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持PCMU硬件解码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持H264硬件编码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持H264硬件编码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, false);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持H264硬件解码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持H264硬件解码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, true);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, true);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持H265硬件编码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持H265硬件编码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, false);
|
format = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_HEVC, false);
|
||||||
OH_LOG_INFO(LOG_APP, "是否支持H265硬件解码:%o", OH_AVCapability_IsHardware(format));
|
OH_LOG_INFO(LOG_APP, "是否支持H265硬件解码:%{public}o", OH_AVCapability_IsHardware(format));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Message {
|
||||||
|
uint64_t id;
|
||||||
|
std::string signal;
|
||||||
|
std::string body;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pushCallback(uv_work_t* work) {
|
||||||
|
// 不能调用ETS函数
|
||||||
|
}
|
||||||
|
|
||||||
|
static void afterPushCallback(uv_work_t* work, int status) {
|
||||||
|
Message* message = (Message*) work->data;
|
||||||
|
napi_handle_scope scope = nullptr;
|
||||||
|
napi_open_handle_scope(acgist::env, &scope);
|
||||||
|
if(scope == nullptr) {
|
||||||
|
delete message;
|
||||||
|
delete work;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
// 开始执行ETS函数
|
||||||
|
napi_value ret;
|
||||||
|
napi_value callback = nullptr;
|
||||||
|
napi_get_reference_value(acgist::env, acgist::pushRef, &callback);
|
||||||
|
napi_value data[3];
|
||||||
|
napi_create_string_utf8(acgist::env, message->signal.data(), NAPI_AUTO_LENGTH, &data[0]);
|
||||||
|
napi_create_string_utf8(acgist::env, message->body.data(), NAPI_AUTO_LENGTH, &data[1]);
|
||||||
|
napi_create_int64(acgist::env, message->id, &data[2]);
|
||||||
|
napi_call_function(acgist::env, nullptr, callback, 3, data, &ret);
|
||||||
|
napi_get_undefined(acgist::env, &ret);
|
||||||
|
// 释放资源
|
||||||
|
napi_close_handle_scope(acgist::env, scope);
|
||||||
|
delete message;
|
||||||
|
delete work;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送消息
|
* 发送消息
|
||||||
*/
|
*/
|
||||||
void push(const std::string& signal, const std::string& body, uint64_t id) {
|
void push(const std::string& signal, const std::string& body, uint64_t id) {
|
||||||
// TODO: 验证是否需要释放
|
uv_loop_s* loop = nullptr;
|
||||||
|
napi_get_uv_event_loop(acgist::env, &loop);
|
||||||
|
uv_work_t* work = new uv_work_t{};
|
||||||
|
work->data = new Message{ id, signal, body };
|
||||||
|
uv_queue_work(loop, work, pushCallback, afterPushCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void requestCallback(uv_work_t* work) {
|
||||||
|
// 不能调用ETS函数
|
||||||
|
}
|
||||||
|
|
||||||
|
static void afterRequestCallback(uv_work_t* work, int status) {
|
||||||
|
Message* message = (Message*) work->data;
|
||||||
|
napi_handle_scope scope = nullptr;
|
||||||
|
napi_open_handle_scope(acgist::env, &scope);
|
||||||
|
if(scope == nullptr) {
|
||||||
|
delete message;
|
||||||
|
delete work;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
// 开始执行ETS函数
|
||||||
napi_value ret;
|
napi_value ret;
|
||||||
napi_value callback = nullptr;
|
napi_value callback = nullptr;
|
||||||
napi_get_reference_value(env, acgist::pushRef, &callback);
|
napi_get_reference_value(env, acgist::requestRef, &callback);
|
||||||
napi_value data[3];
|
napi_value data[3];
|
||||||
napi_create_string_utf8(acgist::env, signal.data(), NAPI_AUTO_LENGTH, &data[0]);
|
napi_create_string_utf8(acgist::env, message->signal.data(), NAPI_AUTO_LENGTH, &data[0]);
|
||||||
napi_create_string_utf8(acgist::env, body.data(), NAPI_AUTO_LENGTH, &data[1]);
|
napi_create_string_utf8(acgist::env, message->body.data(), NAPI_AUTO_LENGTH, &data[1]);
|
||||||
napi_create_int64(acgist::env, id, &data[2]);
|
napi_create_int64(acgist::env, message->id, &data[2]);
|
||||||
napi_call_function(acgist::env, nullptr, callback, 3, data, &ret);
|
napi_call_function(acgist::env, nullptr, callback, 3, data, &ret);
|
||||||
napi_get_undefined(acgist::env, &ret);
|
napi_get_undefined(acgist::env, &ret);
|
||||||
|
// 释放资源
|
||||||
|
napi_close_handle_scope(acgist::env, scope);
|
||||||
|
delete message;
|
||||||
|
delete work;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送请求
|
* 发送请求
|
||||||
*/
|
*/
|
||||||
std::string request(const std::string& signal, const std::string& body, uint64_t id) {
|
std::string request(const std::string& signal, const std::string& body, uint64_t id) {
|
||||||
napi_value ret;
|
uv_loop_s* loop = nullptr;
|
||||||
napi_value callback = nullptr;
|
napi_get_uv_event_loop(acgist::env, &loop);
|
||||||
napi_get_reference_value(env, acgist::requestRef, &callback);
|
uv_work_t* work = new uv_work_t{};
|
||||||
napi_value data[3];
|
if(id <= 0L) {
|
||||||
napi_create_string_utf8(acgist::env, signal.data(), NAPI_AUTO_LENGTH, &data[0]);
|
if (++acgist::index > acgist::maxIndex) {
|
||||||
napi_create_string_utf8(acgist::env, body.data(), NAPI_AUTO_LENGTH, &data[1]);
|
acgist::index = acgist::minIndex;
|
||||||
napi_create_int64(acgist::env, id, &data[2]);
|
}
|
||||||
napi_call_function(acgist::env, nullptr, callback, 3, data, &ret);
|
auto now = std::chrono::system_clock::now();
|
||||||
char chars[TAOYAO_JSON_SIZE];
|
std::time_t time = std::chrono::system_clock::to_time_t(now);
|
||||||
size_t length;
|
std::tm* tm = std::localtime(&time);
|
||||||
napi_get_value_string_utf8(env, ret, chars, sizeof(chars), &length);
|
id =
|
||||||
// TODO: promise
|
100000000000000L * tm->tm_mday +
|
||||||
// napi_create_promise
|
1000000000000 * tm->tm_hour +
|
||||||
// napi_resolve_deferred
|
10000000000 * tm->tm_min +
|
||||||
return chars;
|
100000000 * tm->tm_sec +
|
||||||
|
1000 * acgist::clientIndex +
|
||||||
|
acgist::index;
|
||||||
|
}
|
||||||
|
std::promise<std::string>* promise = new std::promise<std::string>{};
|
||||||
|
acgist::promiseMap.insert({ id, promise });
|
||||||
|
work->data = new Message{ id, signal, body };
|
||||||
|
uv_queue_work(loop, work, requestCallback, afterRequestCallback);
|
||||||
|
std::future<std::string> future = promise->get_future();
|
||||||
|
if(future.wait_for(std::chrono::seconds(5)) == std::future_status::timeout) {
|
||||||
|
OH_LOG_WARN(LOG_APP, "请求超时:%{public}s %{public}s", signal.data(), body.data());
|
||||||
|
acgist::promiseMap.erase(id);
|
||||||
|
delete promise;
|
||||||
|
return "{}";
|
||||||
|
} else {
|
||||||
|
acgist::promiseMap.erase(id);
|
||||||
|
delete promise;
|
||||||
|
return future.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -162,11 +265,12 @@ static napi_value init(napi_env env, napi_callback_info info) {
|
|||||||
napi_create_reference(env, args[1], 1, &acgist::pushRef);
|
napi_create_reference(env, args[1], 1, &acgist::pushRef);
|
||||||
napi_create_reference(env, args[2], 1, &acgist::requestRef);
|
napi_create_reference(env, args[2], 1, &acgist::requestRef);
|
||||||
printSupportCodec();
|
printSupportCodec();
|
||||||
acgist::clientId = json["clientId"];
|
acgist::clientId = json["clientId"];
|
||||||
acgist::name = json["name"];
|
acgist::name = json["name"];
|
||||||
|
acgist::clientIndex = json["clientIndex"];
|
||||||
OH_LOG_INFO(LOG_APP, "加载libtaoyao");
|
OH_LOG_INFO(LOG_APP, "加载libtaoyao");
|
||||||
std::string version = mediasoupclient::Version();
|
std::string version = mediasoupclient::Version();
|
||||||
OH_LOG_INFO(LOG_APP, "加载MediasoupClient:%s", version.data());
|
OH_LOG_INFO(LOG_APP, "加载MediasoupClient:%{public}s", version.data());
|
||||||
mediasoupclient::Initialize();
|
mediasoupclient::Initialize();
|
||||||
OH_LOG_INFO(LOG_APP, "加载媒体功能");
|
OH_LOG_INFO(LOG_APP, "加载媒体功能");
|
||||||
mediaManager = new MediaManager();
|
mediaManager = new MediaManager();
|
||||||
@@ -212,6 +316,23 @@ static napi_value shutdown(napi_env env, napi_callback_info info) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promise回调
|
||||||
|
*/
|
||||||
|
static napi_value callback(napi_env env, napi_callback_info info) {
|
||||||
|
TAOYAO_JSON_BODY(1);
|
||||||
|
nlohmann::json header = json["header"];
|
||||||
|
uint64_t id = header["id"];
|
||||||
|
auto promise = acgist::promiseMap.find(id);
|
||||||
|
if(promise == acgist::promiseMap.end()) {
|
||||||
|
napi_create_int32(env, -1, &ret);
|
||||||
|
} else {
|
||||||
|
napi_create_int32(env, 0, &ret);
|
||||||
|
promise->second->set_value(chars);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 房间关闭
|
* 房间关闭
|
||||||
*/
|
*/
|
||||||
@@ -448,6 +569,7 @@ static napi_value Init(napi_env env, napi_value exports) {
|
|||||||
acgist::env = env;
|
acgist::env = env;
|
||||||
napi_property_descriptor desc[] = {
|
napi_property_descriptor desc[] = {
|
||||||
{ "init", nullptr, acgist::init, nullptr, nullptr, nullptr, napi_default, nullptr },
|
{ "init", nullptr, acgist::init, nullptr, nullptr, nullptr, napi_default, nullptr },
|
||||||
|
{ "callback", nullptr, acgist::callback, nullptr, nullptr, nullptr, napi_default, nullptr },
|
||||||
{ "shutdown", nullptr, acgist::shutdown, nullptr, nullptr, nullptr, napi_default, nullptr },
|
{ "shutdown", nullptr, acgist::shutdown, nullptr, nullptr, nullptr, napi_default, nullptr },
|
||||||
{ "roomClose", nullptr, acgist::roomClose, nullptr, nullptr, nullptr, napi_default, nullptr },
|
{ "roomClose", nullptr, acgist::roomClose, nullptr, nullptr, nullptr, napi_default, nullptr },
|
||||||
{ "roomEnter", nullptr, acgist::roomEnter, nullptr, nullptr, nullptr, napi_default, nullptr },
|
{ "roomEnter", nullptr, acgist::roomEnter, nullptr, nullptr, nullptr, napi_default, nullptr },
|
||||||
|
|||||||
@@ -20,10 +20,8 @@
|
|||||||
#define TAOYAO_CAPTURER_HPP
|
#define TAOYAO_CAPTURER_HPP
|
||||||
|
|
||||||
// OpenGL ES || VULKAN
|
// OpenGL ES || VULKAN
|
||||||
#define __TAOYAO_VULKAN__ true
|
#define __TAOYAO_VULKAN__ false
|
||||||
#ifndef __TAOYAO_VULKAN__
|
|
||||||
#define __TAOYAO_OPENGL__ true
|
#define __TAOYAO_OPENGL__ true
|
||||||
#endif
|
|
||||||
|
|
||||||
// 本地音频采集
|
// 本地音频采集
|
||||||
#define __TAOYAO_AUDIO_LOCAL__ false
|
#define __TAOYAO_AUDIO_LOCAL__ false
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ extern uint32_t width;
|
|||||||
extern uint32_t height;
|
extern uint32_t height;
|
||||||
// 视频码率
|
// 视频码率
|
||||||
extern uint64_t bitrate;
|
extern uint64_t bitrate;
|
||||||
|
// 关键帧的频率
|
||||||
|
extern uint32_t iFrameInterval;
|
||||||
// 视频帧率
|
// 视频帧率
|
||||||
extern double frameRate;
|
extern double frameRate;
|
||||||
// 采样率
|
// 采样率
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ public:
|
|||||||
// 视频编码器
|
// 视频编码器
|
||||||
OH_AVCodec* avCodec = nullptr;
|
OH_AVCodec* avCodec = nullptr;
|
||||||
// 缓冲数据索引
|
// 缓冲数据索引
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
// 缓冲数据
|
// 缓冲数据
|
||||||
OH_AVBuffer* buffer = nullptr;
|
OH_AVBuffer* buffer = nullptr;
|
||||||
// 编码回调
|
// 编码回调
|
||||||
@@ -108,12 +108,14 @@ public:
|
|||||||
TaoyaoVideoEncoder();
|
TaoyaoVideoEncoder();
|
||||||
virtual ~TaoyaoVideoEncoder() override;
|
virtual ~TaoyaoVideoEncoder() override;
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
// 初始配置
|
// 初始配置
|
||||||
void initFormatConfig(OH_AVFormat* format);
|
void initFormatConfig(OH_AVFormat* format);
|
||||||
|
|
||||||
|
public:
|
||||||
// 重新开始
|
// 重新开始
|
||||||
void restart();
|
void restart();
|
||||||
// 动态配置
|
// 动态配置:format自己释放
|
||||||
void reset(OH_AVFormat* format);
|
void reset(OH_AVFormat* format);
|
||||||
// 动态配置
|
// 动态配置
|
||||||
void resetIntConfig(const char* key, int32_t value);
|
void resetIntConfig(const char* key, int32_t value);
|
||||||
@@ -140,6 +142,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
class TaoyaoVideoDecoder : public webrtc::VideoDecoder {
|
class TaoyaoVideoDecoder : public webrtc::VideoDecoder {
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 是否运行
|
||||||
|
bool running = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TaoyaoVideoDecoder();
|
TaoyaoVideoDecoder();
|
||||||
virtual ~TaoyaoVideoDecoder() override;
|
virtual ~TaoyaoVideoDecoder() override;
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
/**
|
|
||||||
* 音频采集不用实现(系统已经实现)
|
|
||||||
* 这里只是用来学习使用
|
|
||||||
*/
|
|
||||||
#include "../include/Capturer.hpp"
|
#include "../include/Capturer.hpp"
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include "../include/Capturer.hpp"
|
#include "../include/Capturer.hpp"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "hilog/log.h"
|
#include "hilog/log.h"
|
||||||
|
|
||||||
#include "rtc_base/time_utils.h"
|
#include "rtc_base/time_utils.h"
|
||||||
@@ -21,6 +23,8 @@
|
|||||||
#include <ohcamera/camera_manager.h>
|
#include <ohcamera/camera_manager.h>
|
||||||
#include <ohcamera/capture_session.h>
|
#include <ohcamera/capture_session.h>
|
||||||
|
|
||||||
|
static std::recursive_mutex videoMutex;
|
||||||
|
|
||||||
// 采集回调
|
// 采集回调
|
||||||
static void onError(Camera_VideoOutput* videoOutput, Camera_ErrorCode errorCode);
|
static void onError(Camera_VideoOutput* videoOutput, Camera_ErrorCode errorCode);
|
||||||
static void onFrameEnd(Camera_VideoOutput* videoOutput, int32_t frameCount);
|
static void onFrameEnd(Camera_VideoOutput* videoOutput, int32_t frameCount);
|
||||||
@@ -33,14 +37,19 @@ static void onFrame(void* context);
|
|||||||
static bool CheckEglExtension(const char* extensions, const char* extension);
|
static bool CheckEglExtension(const char* extensions, const char* extension);
|
||||||
|
|
||||||
acgist::VideoCapturer::VideoCapturer() {
|
acgist::VideoCapturer::VideoCapturer() {
|
||||||
|
#if __TAOYAO_VULKAN__
|
||||||
|
initVulkan();
|
||||||
|
#endif
|
||||||
|
#if __TAOYAO_OPENGL__
|
||||||
initOpenGLES();
|
initOpenGLES();
|
||||||
|
#endif
|
||||||
Camera_ErrorCode ret = OH_Camera_GetCameraManager(&this->cameraManager);
|
Camera_ErrorCode ret = OH_Camera_GetCameraManager(&this->cameraManager);
|
||||||
OH_LOG_INFO(LOG_APP, "获取摄像头管理器:%o", ret);
|
OH_LOG_INFO(LOG_APP, "配置摄像头管理器:%o", ret);
|
||||||
ret = OH_CameraManager_GetSupportedCameras(this->cameraManager, &this->cameraDevice, &this->cameraSize);
|
ret = OH_CameraManager_GetSupportedCameras(this->cameraManager, &this->cameraDevice, &this->cameraSize);
|
||||||
OH_LOG_INFO(LOG_APP, "获取摄像头设备列表:%o %d", ret, this->cameraSize);
|
OH_LOG_INFO(LOG_APP, "获取摄像头设备列表:%o %d", ret, this->cameraSize);
|
||||||
ret = OH_CameraManager_GetSupportedCameraOutputCapability(this->cameraManager, &this->cameraDevice[this->cameraIndex], &this->cameraOutputCapability);
|
ret = OH_CameraManager_GetSupportedCameraOutputCapability(this->cameraManager, &this->cameraDevice[this->cameraIndex], &this->cameraOutputCapability);
|
||||||
OH_LOG_INFO(LOG_APP, "获取摄像头输出功能:%o %d %d", ret, this->cameraIndex, this->cameraOutputCapability->videoProfilesSize);
|
OH_LOG_INFO(LOG_APP, "获取摄像头输出功能:%o %d %d", ret, this->cameraIndex, this->cameraOutputCapability->videoProfilesSize);
|
||||||
// 注册相机状态回调
|
// 注册相机状态回调:可以取消注册
|
||||||
// OH_CameraManager_RegisterCallback(this->cameraManager, CameraManager_Callbacks* callback);
|
// OH_CameraManager_RegisterCallback(this->cameraManager, CameraManager_Callbacks* callback);
|
||||||
// char surfaceId[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
|
// char surfaceId[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
|
||||||
// uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
|
// uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
|
||||||
@@ -55,7 +64,12 @@ acgist::VideoCapturer::VideoCapturer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
acgist::VideoCapturer::~VideoCapturer() {
|
acgist::VideoCapturer::~VideoCapturer() {
|
||||||
|
#if __TAOYAO_VULKAN__
|
||||||
|
releaseVulkan();
|
||||||
|
#endif
|
||||||
|
#if __TAOYAO_OPENGL__
|
||||||
releaseOpenGLES();
|
releaseOpenGLES();
|
||||||
|
#endif
|
||||||
Camera_ErrorCode ret = OH_CaptureSession_Release(this->cameraCaptureSession);
|
Camera_ErrorCode ret = OH_CaptureSession_Release(this->cameraCaptureSession);
|
||||||
this->cameraCaptureSession = nullptr;
|
this->cameraCaptureSession = nullptr;
|
||||||
OH_LOG_INFO(LOG_APP, "释放摄像头视频会话:%o", ret);
|
OH_LOG_INFO(LOG_APP, "释放摄像头视频会话:%o", ret);
|
||||||
@@ -74,6 +88,7 @@ acgist::VideoCapturer::~VideoCapturer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool acgist::VideoCapturer::start() {
|
bool acgist::VideoCapturer::start() {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
if (this->running) {
|
if (this->running) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -90,6 +105,7 @@ bool acgist::VideoCapturer::start() {
|
|||||||
callbacks.onError = onError;
|
callbacks.onError = onError;
|
||||||
callbacks.onFrameEnd = onFrameEnd;
|
callbacks.onFrameEnd = onFrameEnd;
|
||||||
callbacks.onFrameStart = onFrameStart;
|
callbacks.onFrameStart = onFrameStart;
|
||||||
|
// :可以取消注册
|
||||||
ret = OH_VideoOutput_RegisterCallback(this->cameraVideoOutput, &callbacks);
|
ret = OH_VideoOutput_RegisterCallback(this->cameraVideoOutput, &callbacks);
|
||||||
OH_LOG_INFO(LOG_APP, "视频捕获回调:%o", ret);
|
OH_LOG_INFO(LOG_APP, "视频捕获回调:%o", ret);
|
||||||
OH_NativeImage_AttachContext(this->nativeImage, this->textureId);
|
OH_NativeImage_AttachContext(this->nativeImage, this->textureId);
|
||||||
@@ -97,6 +113,7 @@ bool acgist::VideoCapturer::start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool acgist::VideoCapturer::stop() {
|
bool acgist::VideoCapturer::stop() {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
if (!this->running) {
|
if (!this->running) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -247,7 +264,7 @@ void acgist::VideoCapturer::releaseOpenGLES() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void onError(Camera_VideoOutput* videoOutput, Camera_ErrorCode errorCode) {
|
static void onError(Camera_VideoOutput* videoOutput, Camera_ErrorCode errorCode) {
|
||||||
OH_LOG_WARN(LOG_APP, "视频捕获数据帧失败:%d", errorCode);
|
OH_LOG_ERROR(LOG_APP, "视频捕获数据帧失败:%d", errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void onFrameEnd(Camera_VideoOutput* videoOutput, int32_t frameCount) {
|
static void onFrameEnd(Camera_VideoOutput* videoOutput, int32_t frameCount) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "../include/WebRTC.hpp"
|
#include "../include/WebRTC.hpp"
|
||||||
|
|
||||||
#include "hilog/log.h"
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <hilog/log.h>
|
||||||
|
|
||||||
#include <native_window/external_window.h>
|
#include <native_window/external_window.h>
|
||||||
#include <multimedia/player_framework/native_avbuffer.h>
|
#include <multimedia/player_framework/native_avbuffer.h>
|
||||||
@@ -12,6 +14,8 @@
|
|||||||
#include "api/video_codecs/video_encoder.h"
|
#include "api/video_codecs/video_encoder.h"
|
||||||
#include "api/video_codecs/video_decoder.h"
|
#include "api/video_codecs/video_decoder.h"
|
||||||
|
|
||||||
|
static std::recursive_mutex videoMutex;
|
||||||
|
|
||||||
// 编码回调
|
// 编码回调
|
||||||
static void OnError(OH_AVCodec* codec, int32_t errorCode, void* userData);
|
static void OnError(OH_AVCodec* codec, int32_t errorCode, void* userData);
|
||||||
static void OnStreamChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData);
|
static void OnStreamChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData);
|
||||||
@@ -22,18 +26,18 @@ acgist::TaoyaoVideoEncoder::TaoyaoVideoEncoder() {
|
|||||||
OH_AVCapability* capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
|
OH_AVCapability* capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_VIDEO_AVC, true);
|
||||||
const char* codecName = OH_AVCapability_GetName(capability);
|
const char* codecName = OH_AVCapability_GetName(capability);
|
||||||
this->avCodec = OH_VideoEncoder_CreateByName(codecName);
|
this->avCodec = OH_VideoEncoder_CreateByName(codecName);
|
||||||
OH_LOG_INFO(LOG_APP, "视频编码格式:%s", codecName);
|
OH_LOG_INFO(LOG_APP, "配置视频编码格式:%s", codecName);
|
||||||
// 注册回调
|
// 注册视频编码回调
|
||||||
OH_AVCodecCallback callback = { &OnError, &OnStreamChanged, &OnNeedInputBuffer, &OnNewOutputBuffer };
|
OH_AVCodecCallback callback = { &OnError, &OnStreamChanged, &OnNeedInputBuffer, &OnNewOutputBuffer };
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_RegisterCallback(this->avCodec, callback, this);
|
OH_AVErrCode ret = OH_VideoEncoder_RegisterCallback(this->avCodec, callback, this);
|
||||||
OH_LOG_INFO(LOG_APP, "注册编码回调:%o", ret);
|
OH_LOG_INFO(LOG_APP, "注册视频编码回调:%o", ret);
|
||||||
// 配置编码参数
|
// 配置视频编码参数
|
||||||
OH_AVFormat* format = OH_AVFormat_Create();
|
OH_AVFormat* format = OH_AVFormat_Create();
|
||||||
this->initFormatConfig(format);
|
this->initFormatConfig(format);
|
||||||
ret = OH_VideoEncoder_Configure(this->avCodec, format);
|
ret = OH_VideoEncoder_Configure(this->avCodec, format);
|
||||||
OH_AVFormat_Destroy(format);
|
OH_AVFormat_Destroy(format);
|
||||||
OH_LOG_INFO(LOG_APP, "配置编码参数:%o %d %d %f %lld", ret, acgist::width, acgist::height, acgist::frameRate, acgist::bitrate);
|
OH_LOG_INFO(LOG_APP, "配置视频编码参数:%o %d %d %f %d %lld", ret, acgist::width, acgist::height, acgist::frameRate, acgist::iFrameInterval, acgist::bitrate);
|
||||||
// 准备就绪
|
// 视频编码准备就绪
|
||||||
ret = OH_VideoEncoder_Prepare(this->avCodec);
|
ret = OH_VideoEncoder_Prepare(this->avCodec);
|
||||||
OH_LOG_INFO(LOG_APP, "视频编码准备就绪:%o", ret);
|
OH_LOG_INFO(LOG_APP, "视频编码准备就绪:%o", ret);
|
||||||
}
|
}
|
||||||
@@ -48,42 +52,31 @@ acgist::TaoyaoVideoEncoder::~TaoyaoVideoEncoder() {
|
|||||||
|
|
||||||
void acgist::TaoyaoVideoEncoder::initFormatConfig(OH_AVFormat* format) {
|
void acgist::TaoyaoVideoEncoder::initFormatConfig(OH_AVFormat* format) {
|
||||||
// https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/avcodec/video-encoding.md
|
// https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/media/avcodec/video-encoding.md
|
||||||
// 配置视频宽度
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, acgist::width);
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, acgist::width);
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, acgist::height);
|
||||||
// 配置视频高度
|
OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, acgist::bitrate);
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, acgist::height);
|
OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, acgist::frameRate);
|
||||||
// 配置视频比特率
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, acgist::iFrameInterval);
|
||||||
OH_AVFormat_SetLongValue(format, OH_MD_KEY_BITRATE, acgist::bitrate);
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, 0);
|
||||||
// 配置视频帧率
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, false);
|
||||||
OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, acgist::frameRate);
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_YUVI420);
|
||||||
// 配置视频颜色格式
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, static_cast<int32_t>(OH_AVCProfile::AVC_PROFILE_BASELINE));
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_YUVI420);
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, static_cast<int32_t>(OH_ColorPrimary::COLOR_PRIMARY_BT709));
|
||||||
// 配置视频YUV值范围标志
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, static_cast<int32_t>(OH_MatrixCoefficient::MATRIX_COEFFICIENT_IDENTITY));
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_RANGE_FLAG, false);
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, static_cast<int32_t>(OH_TransferCharacteristic::TRANSFER_CHARACTERISTIC_BT709));
|
||||||
// 配置视频原色
|
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, static_cast<int32_t>(OH_VideoEncodeBitrateMode::CBR));
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_COLOR_PRIMARIES, static_cast<int32_t>(OH_ColorPrimary::COLOR_PRIMARY_BT709));
|
|
||||||
// 配置传输特性
|
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_TRANSFER_CHARACTERISTICS, static_cast<int32_t>(OH_TransferCharacteristic::TRANSFER_CHARACTERISTIC_BT709));
|
|
||||||
// 配置最大矩阵系数
|
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_MATRIX_COEFFICIENTS, static_cast<int32_t>(OH_MatrixCoefficient::MATRIX_COEFFICIENT_IDENTITY));
|
|
||||||
// 配置关键帧的间隔(单位为:毫秒)
|
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_I_FRAME_INTERVAL, 5000);
|
|
||||||
// 配置编码Profile
|
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_PROFILE, static_cast<int32_t>(OH_AVCProfile::AVC_PROFILE_BASELINE));
|
|
||||||
// 配置编码比特率模式
|
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE, static_cast<int32_t>(OH_VideoEncodeBitrateMode::CBR));
|
|
||||||
// 配置所需的编码质量:只有在恒定质量模式下配置的编码器才支持此配置
|
|
||||||
OH_AVFormat_SetIntValue(format, OH_MD_KEY_QUALITY, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void acgist::TaoyaoVideoEncoder::restart() {
|
void acgist::TaoyaoVideoEncoder::restart() {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_Flush(this->avCodec);
|
OH_AVErrCode ret = OH_VideoEncoder_Flush(this->avCodec);
|
||||||
OH_LOG_INFO(LOG_APP, "清空编码队列:%o", ret);
|
OH_LOG_INFO(LOG_APP, "清空视频编码队列:%o", ret);
|
||||||
ret = OH_VideoEncoder_Start(this->avCodec);
|
ret = OH_VideoEncoder_Start(this->avCodec);
|
||||||
OH_LOG_INFO(LOG_APP, "开始视频编码:%o", ret);
|
OH_LOG_INFO(LOG_APP, "开始视频编码:%o", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void acgist::TaoyaoVideoEncoder::reset(OH_AVFormat* format) {
|
void acgist::TaoyaoVideoEncoder::reset(OH_AVFormat* format) {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_Reset(this->avCodec);
|
OH_AVErrCode ret = OH_VideoEncoder_Reset(this->avCodec);
|
||||||
OH_LOG_INFO(LOG_APP, "重置视频编码:%o", ret);
|
OH_LOG_INFO(LOG_APP, "重置视频编码:%o", ret);
|
||||||
ret = OH_VideoEncoder_Configure(this->avCodec, format);
|
ret = OH_VideoEncoder_Configure(this->avCodec, format);
|
||||||
@@ -91,6 +84,7 @@ void acgist::TaoyaoVideoEncoder::reset(OH_AVFormat* format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void acgist::TaoyaoVideoEncoder::resetIntConfig(const char* key, int32_t value) {
|
void acgist::TaoyaoVideoEncoder::resetIntConfig(const char* key, int32_t value) {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
OH_AVFormat* format = OH_AVFormat_Create();
|
OH_AVFormat* format = OH_AVFormat_Create();
|
||||||
OH_AVFormat_SetIntValue(format, key, value);
|
OH_AVFormat_SetIntValue(format, key, value);
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_SetParameter(this->avCodec, format);
|
OH_AVErrCode ret = OH_VideoEncoder_SetParameter(this->avCodec, format);
|
||||||
@@ -99,6 +93,7 @@ void acgist::TaoyaoVideoEncoder::resetIntConfig(const char* key, int32_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void acgist::TaoyaoVideoEncoder::resetLongConfig(const char* key, int64_t value) {
|
void acgist::TaoyaoVideoEncoder::resetLongConfig(const char* key, int64_t value) {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
OH_AVFormat* format = OH_AVFormat_Create();
|
OH_AVFormat* format = OH_AVFormat_Create();
|
||||||
OH_AVFormat_SetLongValue(format, key, value);
|
OH_AVFormat_SetLongValue(format, key, value);
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_SetParameter(this->avCodec, format);
|
OH_AVErrCode ret = OH_VideoEncoder_SetParameter(this->avCodec, format);
|
||||||
@@ -107,6 +102,7 @@ void acgist::TaoyaoVideoEncoder::resetLongConfig(const char* key, int64_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void acgist::TaoyaoVideoEncoder::resetDoubleConfig(const char* key, double value) {
|
void acgist::TaoyaoVideoEncoder::resetDoubleConfig(const char* key, double value) {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
OH_AVFormat* format = OH_AVFormat_Create();
|
OH_AVFormat* format = OH_AVFormat_Create();
|
||||||
OH_AVFormat_SetDoubleValue(format, key, value);
|
OH_AVFormat_SetDoubleValue(format, key, value);
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_SetParameter(this->avCodec, format);
|
OH_AVErrCode ret = OH_VideoEncoder_SetParameter(this->avCodec, format);
|
||||||
@@ -115,6 +111,7 @@ void acgist::TaoyaoVideoEncoder::resetDoubleConfig(const char* key, double value
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool acgist::TaoyaoVideoEncoder::start() {
|
bool acgist::TaoyaoVideoEncoder::start() {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
if(this->running) {
|
if(this->running) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -125,20 +122,23 @@ bool acgist::TaoyaoVideoEncoder::start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool acgist::TaoyaoVideoEncoder::stop() {
|
bool acgist::TaoyaoVideoEncoder::stop() {
|
||||||
|
std::lock_guard<std::recursive_mutex> videoLock(videoMutex);
|
||||||
if(!this->running) {
|
if(!this->running) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
this->running = false;
|
this->running = false;
|
||||||
|
// Buffer模式
|
||||||
|
OH_AVErrCode ret = OH_VideoEncoder_Stop(this->avCodec);
|
||||||
|
OH_LOG_INFO(LOG_APP, "结束视频编码:%o", ret);
|
||||||
// Surface模式
|
// Surface模式
|
||||||
// OH_AVErrCode ret = OH_VideoEncoder_NotifyEndOfStream(this->avCodec);
|
// OH_AVErrCode ret = OH_VideoEncoder_NotifyEndOfStream(this->avCodec);
|
||||||
// OH_LOG_INFO(LOG_APP, "通知视频编码结束:%o", ret);
|
// OH_LOG_INFO(LOG_APP, "通知视频编码结束:%o", ret);
|
||||||
OH_AVErrCode ret = OH_VideoEncoder_Stop(this->avCodec);
|
|
||||||
OH_LOG_INFO(LOG_APP, "结束视频编码:%o", ret);
|
|
||||||
return ret == OH_AVErrCode::AV_ERR_OK;
|
return ret == OH_AVErrCode::AV_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t acgist::TaoyaoVideoEncoder::Release() {
|
int32_t acgist::TaoyaoVideoEncoder::Release() {
|
||||||
// TODO: 释放资源
|
// TODO: 释放
|
||||||
|
delete this;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,20 +158,19 @@ webrtc::VideoEncoder::EncoderInfo acgist::TaoyaoVideoEncoder::GetEncoderInfo() c
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t acgist::TaoyaoVideoEncoder::Encode(const webrtc::VideoFrame& videoFrame, const std::vector<webrtc::VideoFrameType>* frame_types) {
|
int32_t acgist::TaoyaoVideoEncoder::Encode(const webrtc::VideoFrame& videoFrame, const std::vector<webrtc::VideoFrameType>* frame_types) {
|
||||||
// frameSize = videoFrame.width * height * 3 / 2
|
|
||||||
// 配置buffer info信息
|
|
||||||
OH_AVCodecBufferAttr info;
|
OH_AVCodecBufferAttr info;
|
||||||
info.size = 0; // TODO
|
info.size = videoFrame.width() * videoFrame.height() * 3 / 2;
|
||||||
info.offset = 0;
|
info.offset = 0;
|
||||||
info.pts = 0;
|
info.pts = 0;
|
||||||
info.flags = 0; // TODO frame_types
|
info.flags = 0;
|
||||||
|
// TODO: videoFrame.video_frame_buffer->
|
||||||
OH_AVErrCode ret = OH_AVBuffer_SetBufferAttr(this->buffer, &info);
|
OH_AVErrCode ret = OH_AVBuffer_SetBufferAttr(this->buffer, &info);
|
||||||
ret = OH_VideoEncoder_PushInputBuffer(this->avCodec, index);
|
ret = OH_VideoEncoder_PushInputBuffer(this->avCodec, index);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnError(OH_AVCodec* codec, int32_t errorCode, void* userData) {
|
static void OnError(OH_AVCodec* codec, int32_t errorCode, void* userData) {
|
||||||
OH_LOG_WARN(LOG_APP, "视频编码发送错误:%d", errorCode);
|
OH_LOG_ERROR(LOG_APP, "视频编码发送错误:%d", errorCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnStreamChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData) {
|
static void OnStreamChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData) {
|
||||||
@@ -210,6 +209,11 @@ static void OnNewOutputBuffer(OH_AVCodec* codec, uint32_t index, OH_AVBuffer* bu
|
|||||||
OH_AVCodecBufferAttr info;
|
OH_AVCodecBufferAttr info;
|
||||||
OH_AVErrCode ret = OH_AVBuffer_GetBufferAttr(buffer, &info);
|
OH_AVErrCode ret = OH_AVBuffer_GetBufferAttr(buffer, &info);
|
||||||
char* data = reinterpret_cast<char*>(OH_AVBuffer_GetAddr(buffer));
|
char* data = reinterpret_cast<char*>(OH_AVBuffer_GetAddr(buffer));
|
||||||
|
// webrtc::VideoFrameType flags =
|
||||||
|
// info.flags == AVCODEC_BUFFER_FLAGS_SYNC_FRAME ? webrtc::VideoFrameType::kVideoFrameKey :
|
||||||
|
// info.flags == AVCODEC_BUFFER_FLAGS_INCOMPLETE_FRAME ? webrtc::VideoFrameType::kVideoFrameDelta :
|
||||||
|
// webrtc::VideoFrameType::kEmptyFrame;
|
||||||
|
// frame_types->push_back(std::move(flags));
|
||||||
// videoEncoder->encodedImageCallback
|
// videoEncoder->encodedImageCallback
|
||||||
// TODO: 继续处理
|
// TODO: 继续处理
|
||||||
ret = OH_VideoEncoder_FreeOutputBuffer(codec, index);
|
ret = OH_VideoEncoder_FreeOutputBuffer(codec, index);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
export const init: (
|
export const init: (
|
||||||
json : string,
|
json : string,
|
||||||
push : (signal: string, body: string, id: number) => void,
|
push : (signal: string, body: string, id: number) => void,
|
||||||
request: (signal: string, body: string, id: number) => Promise<string>
|
request: (signal: string, body: string, id: number) => void
|
||||||
) => number;
|
) => number;
|
||||||
export const shutdown : (json: string) => number;
|
export const shutdown : (json: string) => number;
|
||||||
|
export const callback : (json: string) => number;
|
||||||
export const roomClose : (json: string) => number;
|
export const roomClose : (json: string) => number;
|
||||||
export const roomEnter : (json: string) => number;
|
export const roomEnter : (json: string) => number;
|
||||||
export const roomExpel : (json: string) => number;
|
export const roomExpel : (json: string) => number;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { signal } from "../taoyao/TaoyaoSignal";
|
import { taoyaoSignal } from "../taoyao/TaoyaoSignal";
|
||||||
|
|
||||||
import { setting } from "../taoyao/Setting";
|
import { setting } from "../taoyao/Setting";
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ struct Index {
|
|||||||
.fontSize(20)
|
.fontSize(20)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
signal.connect();
|
taoyaoSignal.connect();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
.width("100%")
|
.width("100%")
|
||||||
@@ -23,7 +23,7 @@ struct Index {
|
|||||||
.fontSize(20)
|
.fontSize(20)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
signal.close();
|
taoyaoSignal.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
.width("100%")
|
.width("100%")
|
||||||
@@ -33,7 +33,7 @@ struct Index {
|
|||||||
.fontSize(20)
|
.fontSize(20)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
signal.init();
|
taoyaoSignal.init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
.width("100%")
|
.width("100%")
|
||||||
@@ -43,7 +43,7 @@ struct Index {
|
|||||||
.fontSize(20)
|
.fontSize(20)
|
||||||
.fontWeight(FontWeight.Bold)
|
.fontWeight(FontWeight.Bold)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
signal.shutdown();
|
taoyaoSignal.shutdown();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
.width("100%")
|
.width("100%")
|
||||||
|
|||||||
@@ -5,34 +5,37 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import fs from '@ohos.file.fs';
|
import fs from '@ohos.file.fs';
|
||||||
import resourceManager from '@ohos.resourceManager';
|
|
||||||
|
|
||||||
class Signal {
|
class Config {
|
||||||
|
|
||||||
// 终端名称
|
// 终端名称
|
||||||
name : string = "鸿蒙";
|
name : string = "鸿蒙";
|
||||||
// 终端ID
|
// 终端ID
|
||||||
clientId : string = "harmony";
|
clientId : string = "harmony";
|
||||||
// 终端类型
|
// 终端类型
|
||||||
clientType: string = "MOBILE";
|
clientType : string = "MOBILE";
|
||||||
// 信令账号
|
// 信令账号
|
||||||
username : string = "taoyao";
|
username : string = "taoyao";
|
||||||
// 信令密码
|
// 信令密码
|
||||||
password : string = "taoyao";
|
password : string = "taoyao";
|
||||||
|
// 当前终端索引
|
||||||
|
clientIndex: number = 99999;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Setting {
|
class Setting {
|
||||||
|
|
||||||
|
// 信令配置
|
||||||
|
config : Config = new Config();
|
||||||
|
// CA证书
|
||||||
|
caPath : string = "/cacert.pem";
|
||||||
|
// 信令版本
|
||||||
|
version: string = "1.0.0";
|
||||||
// 信令地址
|
// 信令地址
|
||||||
// signalAddress: string = "wss://192.168.8.57:8888/websocket.signal";
|
// signalAddress: string = "wss://192.168.8.57:8888/websocket.signal";
|
||||||
signalAddress: string = "wss://192.168.1.100:8888/websocket.signal";
|
signalAddress: string = "wss://192.168.1.100:8888/websocket.signal";
|
||||||
// 信令版本
|
// 启动自动加载系统
|
||||||
version: string = "1.0.0";
|
initOnLoad : boolean = true;
|
||||||
// 信令配置
|
|
||||||
signal : Signal = new Signal();
|
|
||||||
// CA证书
|
|
||||||
caPath : string = "/cacert.pem";
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,21 +24,28 @@ class TaoyaoSignal {
|
|||||||
heartbeatTimer: number = 0;
|
heartbeatTimer: number = 0;
|
||||||
// 同步请求
|
// 同步请求
|
||||||
callbackMapping = new Map<number, Function>();
|
callbackMapping = new Map<number, Function>();
|
||||||
// 当前消息索引
|
// 当前消息索引:0-666
|
||||||
index : number = 0;
|
index : number = 0;
|
||||||
|
// 最小消息索引
|
||||||
|
minIndex: number = 0;
|
||||||
// 最大消息索引
|
// 最大消息索引
|
||||||
maxIndex : number = 999;
|
maxIndex: number = 666;
|
||||||
// 当前终端索引
|
|
||||||
clientIndex: number = 99999;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载系统
|
||||||
|
* 建议注册成功以后加载
|
||||||
|
*/
|
||||||
init() {
|
init() {
|
||||||
hilog.info(0x0000, "TaoyaoSignal", "加载系统");
|
hilog.info(0x0000, "TaoyaoSignal", "加载系统");
|
||||||
taoyaoModule.init(JSON.stringify(setting.signal), this.nativePush, this.nativeRequest);
|
taoyaoModule.init(JSON.stringify(setting.config), this.nativePush, this.nativeRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载系统
|
||||||
|
*/
|
||||||
shutdown() {
|
shutdown() {
|
||||||
hilog.info(0x0000, "TaoyaoSignal", "卸载系统");
|
hilog.info(0x0000, "TaoyaoSignal", "卸载系统");
|
||||||
taoyaoModule.shutdown(JSON.stringify(setting.signal));
|
taoyaoModule.shutdown(JSON.stringify(setting.config));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,19 +132,22 @@ class TaoyaoSignal {
|
|||||||
*/
|
*/
|
||||||
async register() {
|
async register() {
|
||||||
const response: Record<string, Object> = await this.request("client::register", {
|
const response: Record<string, Object> = await this.request("client::register", {
|
||||||
"name" : setting.signal.name,
|
"name" : setting.config.name,
|
||||||
"clientId" : setting.signal.clientId,
|
"clientId" : setting.config.clientId,
|
||||||
"clientType": setting.signal.clientType,
|
"clientType": setting.config.clientType,
|
||||||
"username" : setting.signal.username,
|
"username" : setting.config.username,
|
||||||
"password" : setting.signal.password,
|
"password" : setting.config.password,
|
||||||
"battery" : 100,
|
"battery" : 100,
|
||||||
"charging" : true
|
"charging" : true
|
||||||
});
|
});
|
||||||
const body = response.body as Record<string, Object>;
|
const body = response.body as Record<string, Object>;
|
||||||
const index = body.index as number;
|
const index = body.index as number;
|
||||||
this.clientIndex = index;
|
setting.config.clientIndex = index;
|
||||||
hilog.info(0x0000, "TaoyaoSignal", "信令注册成功:%{public}d", index);
|
hilog.info(0x0000, "TaoyaoSignal", "信令注册成功:%{public}d", index);
|
||||||
this.heartbeat();
|
this.heartbeat();
|
||||||
|
if(setting.initOnLoad) {
|
||||||
|
taoyaoSignal.init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,15 +170,15 @@ class TaoyaoSignal {
|
|||||||
*/
|
*/
|
||||||
buildId(): number {
|
buildId(): number {
|
||||||
if (++this.index > this.maxIndex) {
|
if (++this.index > this.maxIndex) {
|
||||||
this.index = 0;
|
this.index = this.minIndex;
|
||||||
}
|
}
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
return (
|
return (
|
||||||
100000000000000 * date.getDate() +
|
100000000000000 * date.getDate() +
|
||||||
1000000000000 * date.getHours() +
|
1000000000000 * date.getHours() +
|
||||||
10000000000 * date.getMinutes() +
|
10000000000 * date.getMinutes() +
|
||||||
100000000 * date.getSeconds() +
|
100000000 * date.getSeconds() +
|
||||||
1000 * this.clientIndex +
|
1000 * setting.config.clientIndex +
|
||||||
this.index
|
this.index
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -323,7 +333,7 @@ class TaoyaoSignal {
|
|||||||
* @param id ID
|
* @param id ID
|
||||||
*/
|
*/
|
||||||
nativePush(signal: string, body: string, id: number = 0) {
|
nativePush(signal: string, body: string, id: number = 0) {
|
||||||
this.push(signal, JSON.parse(body), id);
|
taoyaoSignal.push(signal, JSON.parse(body), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,18 +342,21 @@ class TaoyaoSignal {
|
|||||||
* @param signal 信令
|
* @param signal 信令
|
||||||
* @param body 主体
|
* @param body 主体
|
||||||
* @param id ID
|
* @param id ID
|
||||||
*
|
|
||||||
* @returns 响应
|
|
||||||
*/
|
*/
|
||||||
async nativeRequest(signal: string, body: string, id: number = 0): Promise<string> {
|
nativeRequest(signal: string, body: string, id: number = 0) {
|
||||||
const response = await this.request(signal, JSON.parse(body), id);
|
taoyaoSignal.request(signal, JSON.parse(body), id).then(response => {
|
||||||
return JSON.stringify(response);
|
taoyaoModule.callback(JSON.stringify(response));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const signal = new TaoyaoSignal();
|
const taoyaoSignal = new TaoyaoSignal();
|
||||||
|
|
||||||
|
if(setting.initOnLoad) {
|
||||||
|
taoyaoSignal.connect();
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
signal
|
taoyaoSignal
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user