diff --git a/CHANGELOG.md b/CHANGELOG.md index e94173b79..e2b20c708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Unreleased +## 0.9.0 +* Changelog: + ## 0.8.0 * Add new option for swapping O/X buttons (#168) * Add new option for drawing FPS value (#167) diff --git a/CMakeLists.txt b/CMakeLists.txt index 36c9891ea..bbc5a2834 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,27 +1,40 @@ cmake_minimum_required(VERSION 2.8) -set(CMAKE_SYSTEM_NAME "Generic") -set(CMAKE_C_COMPILER "arm-vita-eabi-gcc") -set(CMAKE_CXX_COMPILER "arm-vita-eabi-g++") +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) + if(DEFINED ENV{DOLCESDK}) + set(CMAKE_TOOLCHAIN_FILE "$ENV{DOLCESDK}/share/dolce.toolchain.cmake" CACHE PATH "toolchain file") + else() + message(FATAL_ERROR "Please define DOLCESDK to point to your SDK path!") + endif() +endif() project(moonlight) -set(TITLE_ID "XYZZ00002") -set(TITLE "Moonlight") -set(VERSION_MAJOR "0") -set(VERSION_MINOR "8") -set(VERSION_PATCH "0") - -execute_process(COMMAND - python -c "print('%02d.%02d' % (${VERSION_MAJOR}, ${VERSION_MINOR}))" - OUTPUT_VARIABLE APP_VER -) -string(REPLACE "\n" "" APP_VER "${APP_VER}") - -add_definitions(-DVERSION_MAJOR=${VERSION_MAJOR}) -add_definitions(-DVERSION_MINOR=${VERSION_MINOR}) -add_definitions(-DVERSION_PATCH=${VERSION_PATCH}) - -set(CMAKE_C_FLAGS "-Wl,-q -O3 -g -std=c99 -Dntohs=__builtin_bswap16 -Dhtons=__builtin_bswap16 -Dntohl=__builtin_bswap32 -Dhtonl=__builtin_bswap32 -DENET_DEBUG=1") +include("${DOLCESDK}/share/dolce.cmake" REQUIRED) + +dolce_gen_libs(SceIniFileProcessor_stubs + SceIniFileProcessor.yml + LIB SceIniFileProcessor_stub_weak) + +dolce_gen_libs(ScePsp2Compat_stubs + ScePsp2Compat.yml + LIB ScePsp2Compat_stub_weak) + +dolce_gen_libs(SceLibc_stubs + SceLibc.yml + LIB SceLibc_stub_weak) + +set(VITA_APP_NAME "Moonlight") +set(VITA_TITLEID "GRVA00010") +set(VITA_VERSION "01.00") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -O3 -std=c99") + +link_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/third_party/mdns + ${CMAKE_SOURCE_DIR}/third_party/h264bitstream + ${CMAKE_SOURCE_DIR}/third_party/libuuid + ${CMAKE_SOURCE_DIR}/third_party/expat + ) include_directories( include/ @@ -31,11 +44,10 @@ include_directories( third_party/libuuid/src/ third_party/h264bitstream/ third_party/enet/include/ - third_party/inih/ third_party/mdns/ ) -add_executable(${PROJECT_NAME}.elf +add_executable(${PROJECT_NAME} src/config.c src/input/mapping.c src/connection.c @@ -50,8 +62,8 @@ add_executable(${PROJECT_NAME}.elf src/audio/vita.c src/video/vita.c src/input/vita.c + src/input/keyboard.c src/power/vita.c - src/graphics.c src/font.c src/gui/guilib.c src/gui/ime.c @@ -59,6 +71,7 @@ add_executable(${PROJECT_NAME}.elf src/gui/ui_settings.c src/gui/ui_connect.c src/gui/ui_device.c + src/ini.c libgamestream/client.c libgamestream/http.c @@ -66,21 +79,6 @@ add_executable(${PROJECT_NAME}.elf libgamestream/sps.c libgamestream/xml.c - third_party/libuuid/src/clear.c - third_party/libuuid/src/compare.c - third_party/libuuid/src/copy.c - third_party/libuuid/src/gen_uuid.c - third_party/libuuid/src/isnull.c - third_party/libuuid/src/pack.c - third_party/libuuid/src/parse.c - third_party/libuuid/src/unpack.c - third_party/libuuid/src/unparse.c - third_party/libuuid/src/uuid_time.c - - third_party/h264bitstream/h264_nal.c - third_party/h264bitstream/h264_sei.c - third_party/h264bitstream/h264_stream.c - third_party/moonlight-common-c/src/AudioStream.c third_party/moonlight-common-c/src/ByteBuffer.c third_party/moonlight-common-c/src/Connection.c @@ -109,62 +107,92 @@ add_executable(${PROJECT_NAME}.elf third_party/enet/peer.c third_party/enet/protocol.c third_party/enet/unix.c - - third_party/inih/ini.c ) -target_link_libraries(${PROJECT_NAME}.elf - -lcrypto - -lexpat - -lcurl - -lz - -lssl - -lcrypto - -lopus - - -lSceDisplay_stub - -lSceCtrl_stub - -lSceTouch_stub - -lSceNet_stub - -lSceSysmodule_stub - -lSceNetCtl_stub - -lScePower_stub - -lSceVideodec_stub - -lSceCommonDialog_stub - -lSceAppMgr_stub - -lSceAudio_stub - -lSceIme_stub - - -lvita2d - -lSceGxm_stub - -lScePgf_stub - -lSceCommonDialog_stub - -lfreetype - -lpng - -ljpeg - -lz - -lm - -lc +target_link_libraries(${PROJECT_NAME} + crypto + opus + + SceDisplay_stub + SceDisplayUser_stub + SceCtrl_stub + SceTouch_stub + SceNet_stub + SceSysmodule_stub + SceNetCtl_stub + ScePower_stub + SceVideodecUser_stub + SceVideodecLowDelayUser_stub + SceVideodecAsyncUser_stub + SceSysmodule_stub + SceAppMgr_stub + SceAudio_stub + SceIme_stub + + SceGxm_stub + ScePgf_stub + ScePvf_stub + SceCommonDialog_stub + SceLibm_stub + SceDbg_stub + SceGxmInternalForVsh_stub + SceSharedFb_stub + SceKernelDmacMgr_stub + SceCodecengine_stub + SceAppMgr_stub + SceIme_stub + SceSystemgesture_stub + SceVshBridge_stub + SceHid_stub + SceIniFileProcessor_stub_weak + ScePsp2Compat_stub_weak + SceLibc_stub_weak + taihen_stub + vita2d_sys_stub + mdns_stub + uuid_stub + h264bitstream_stub + libexpat_stub ) -add_custom_target(${PROJECT_NAME}.velf ALL - COMMAND vita-elf-create ${PROJECT_NAME}.elf ${PROJECT_NAME}.velf +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/boot_param.bin + COMMAND dolce-make-bootparam attribute 0x02 ${CMAKE_CURRENT_BINARY_DIR}/boot_param.bin ) -add_custom_target(param.sfo ALL - COMMAND vita-mksfoex -s TITLE_ID=${TITLE_ID} -s APP_VER=${APP_VER} "${TITLE}" param.sfo +set (DOLCE_ELF_CREATE_FLAGS "${DOLCE_ELF_CREATE_FLAGS} -h 33554432") + +dolce_create_self(eboot.bin ${PROJECT_NAME} UNSAFE BOOT_PARAM ${CMAKE_CURRENT_BINARY_DIR}/boot_param.bin) + +add_executable(exit_module + module/source/main.c ) -add_custom_target(${PROJECT_NAME}.vpk ALL - COMMAND vita-make-fself -s -c ${PROJECT_NAME}.velf eboot.bin - COMMAND vita-pack-vpk -s param.sfo -b eboot.bin - --add ../sce_sys/icon0.png=sce_sys/icon0.png - --add ../sce_sys/livearea/contents/bg.png=sce_sys/livearea/contents/bg.png - --add ../sce_sys/livearea/contents/startup.png=sce_sys/livearea/contents/startup.png - --add ../sce_sys/livearea/contents/template.xml=sce_sys/livearea/contents/template.xml - --add ../assets/nerdfont.ttf=assets/nerdfont.ttf - ${PROJECT_NAME}.vpk +target_compile_options(exit_module PRIVATE -std=gnu99) + +target_link_libraries(exit_module + taihenForKernel_stub + taihenModuleUtils_stub + "-nostdlib" ) -add_dependencies(${PROJECT_NAME}.velf ${PROJECT_NAME}.elf) -add_dependencies(${PROJECT_NAME}.vpk ${PROJECT_NAME}.velf param.sfo) +dolce_create_self(exit_module.skprx exit_module CONFIG module/exit_module.yml UNSAFE) + +set(DOLCE_MKSFOEX_FLAGS "${DOLCE_MKSFOEX_FLAGS} -d ATTRIBUTE=561160 -d ATTRIBUTE2=1 -s CATEGORY=gdc") + +dolce_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} eboot.bin + VERSION ${VITA_VERSION} + NAME ${VITA_APP_NAME} + CONTENT_ID_LABEL "MOONLIGHTVITA000" + FILE sce_sys/icon0.png sce_sys/icon0.png + FILE sce_sys/livearea/contents/bg.png sce_sys/livearea/contents/bg.png + FILE sce_sys/livearea/contents/startup.png sce_sys/livearea/contents/startup.png + FILE sce_sys/livearea/contents/template.xml sce_sys/livearea/contents/template.xml + FILE assets/nerdfont.ttf assets/nerdfont.ttf + FILE ${CMAKE_CURRENT_BINARY_DIR}/exit_module.skprx module/kernel/exit_module.skprx + FILE third_party/mdns/mdns.suprx module/user/mdns.suprx + FILE third_party/libuuid/uuid.suprx module/user/uuid.suprx + FILE third_party/h264bitstream/h264bitstream.suprx module/user/h264bitstream.suprx + FILE third_party/vita2d_sys/vita2d_sys.suprx module/user/vita2d_sys.suprx + FILE third_party/expat/libexpat.suprx module/user/libexpat.suprx + ) diff --git a/README.md b/README.md index 64fc9dcd9..5d378158e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -# Vita Moonlight +# Vita Moonlight HD + +This is a vita port of Moonlight Embedded with support for 1280x720 and 1920x1080 resolutions. + +Original port here: https://github.com/xyzz/vita-moonlight -This is a vita port of Moonlight Embedded. Moonlight is an open source implementation of NVIDIA GameStream. ## Documentation diff --git a/SceIniFileProcessor.yml b/SceIniFileProcessor.yml new file mode 100644 index 000000000..7ac4ddd5a --- /dev/null +++ b/SceIniFileProcessor.yml @@ -0,0 +1,26 @@ +version: 0x2 +firmware: 3.60 +modules: + SceIniFileProcessor: + nid: 0x8C611E4E + libraries: + SceIniFileProcessor: + nid: 0x5EE28724 + kernel: false + functions: + sceIniFileProcessorCreateInstance: 0x0975D396 + sceIniFileProcessorInitializeParam: 0x14146AF5 + sceIniFileProcessorDestroyInstance: 0x2BEF7391 + sceIniFileProcessorDestroyInstanceForError: 0x48A6BDCB + sceIniFileProcessorOpenFile: 0x51B791E8 + sceIniFileProcessorAddKey: 0x703E1BAE + sceIniFileProcessorFindValueByKey: 0x7F22CED1 + sceIniFileProcessorCreateContext: 0xA0F71A2C + sceIniFileProcessorCleanup: 0xA51840C7 + sceIniFileProcessorDestroyContext: 0xACEB88BD + sceIniFileProcessorDeleteKey: 0xC2B3A41C + sceIniFileProcessorParse: 0xD5C7B3EE + sceIniFileProcessorGetKeyNum: 0xD7648B61 + sceIniFileProcessorSetValueForKey: 0xDBC5F9A8 + sceIniFileProcessorCloseFile: 0xEDFAD6B4 + sceIniFileProcessorCreateFile: 0xFD8DE2F8 diff --git a/SceLibc.yml b/SceLibc.yml new file mode 100644 index 000000000..29ea1099b --- /dev/null +++ b/SceLibc.yml @@ -0,0 +1,52 @@ +version: 2 +firmware: 3.60 +modules: + SceLibc: + nid: 0x43FBA801 + libraries: + SceLibc: + kernel: false + nid: 0xBE43BB07 + functions: + sceLibcMallocStats: 0x57A729DB + sceLibcMalloc: 0x775A0CB2 + sceLibcFree: 0x5B9BB802 + sceLibcCalloc: 0xE7EC3D0B + sceLibcRealloc: 0x006B54BA + sceLibcReallocalign: 0x608AC135 + sceLibcMemalign: 0xA9363E6B + sceLibcFclose: 0xEC97321C + sceLibcFdopen: 0xB2F318FE + sceLibcFeof: 0xBF96AD71 + sceLibcFerror: 0xB724BFC1 + sceLibcFflush: 0x5AAD2996 + sceLibcFgetc: 0x672C58E0 + sceLibcFgetpos: 0x3CDA3118 + sceLibcFgets: 0xBA14322F + sceLibcFgetwc: 0x89541CA5 + sceLibcFgetws: 0x982AFA4D + sceLibcFileno: 0xFEC1502E + sceLibcFopen: 0xFFFBE239 + sceLibcFopen_s: 0x1483DF76 + sceLibcFprintf: 0xE0C79764 + sceLibcFprintf_s: 0xE91E72D0 + sceLibcFputc: 0x7E6A6108 + sceLibcFputs: 0xC8FF13E5 + sceLibcFputwc: 0xA597CDC8 + sceLibcFputws: 0xB755927C + sceLibcFread: 0xB31C73A9 + sceLibcFreopen: 0x715C4395 + sceLibcFreopen_s: 0x438765C6 + sceLibcFscanf: 0x505601C6 + sceLibcFscanf_s: 0xB2B03159 + sceLibcFseek: 0xC3A7CDE1 + sceLibcFsetpos: 0xDC1BDBD7 + sceLibcFtell: 0x41C2AF95 + sceLibcFwide: 0xA77327D2 + sceLibcFwprintf: 0xE52278E8 + sceLibcFwprintf_s: 0xD920CD41 + sceLibcFwrite: 0x8BCDCC4E + sceLibcFwscanf: 0x7BFC75C6 + sceLibcFwscanf_s: 0x1E5C4E3D + sceLibcFgetc: 0x672C58E0 + sceLibcUngetc: 0x2BCB3F01 \ No newline at end of file diff --git a/ScePsp2Compat.yml b/ScePsp2Compat.yml new file mode 100644 index 000000000..99130a170 --- /dev/null +++ b/ScePsp2Compat.yml @@ -0,0 +1,24 @@ +version: 0x2 +firmware: 3.60 +modules: + ScePsp2Compat: + nid: 0x1839D11E + libraries: + ScePsp2Compat: + nid: 0x81405F79 + kernel: false + functions: + curl_easy_init: 0xAFCFB0DA + curl_easy_setopt: 0x30E7FB1B + curl_easy_perform: 0xDA3F145E + curl_easy_cleanup: 0xE58ABD18 + curl_easy_strerror: 0xE086D703 + curl_share_setopt: 0x8A84050C + curl_share_init: 0x79197AA2 + curl_global_init: 0x92A0768D + curl_global_init_mem: 0x79151BD4 + curl_global_cleanup: 0x84E081DF + curl_share_cleanup: 0x26AA8E8B + curl_easy_recv: 0xE63B3A56 + curl_easy_send: 0x41837495 + curl_easy_reset: 0xDA1C173A diff --git a/libgamestream/client.c b/libgamestream/client.c index d6631977f..71013c11e 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -38,7 +38,8 @@ #include #include -#include +#include +#include #define UNIQUE_FILE_NAME "uniqueid.dat" #define P12_FILE_NAME "client.p12" @@ -59,10 +60,6 @@ static EVP_PKEY *privateKey; const char* gs_error; -#ifdef __vita__ -#include "../src/graphics.h" -#endif - static int mkdirtree(const char* directory) { char buffer[1024]; char* p = buffer; @@ -96,22 +93,24 @@ static int load_unique_id(const char* keyDirectory) { char uniqueFilePath[4096]; sprintf(uniqueFilePath, "%s/%s", keyDirectory, UNIQUE_FILE_NAME); - FILE *fd = fopen(uniqueFilePath, "r"); - if (fd == NULL) { + SceUID fd = sceIoOpen(uniqueFilePath, SCE_O_RDONLY, 0); + if (fd < 0) { unsigned char unique_data[UNIQUEID_BYTES]; RAND_bytes(unique_data, UNIQUEID_BYTES); + for (int i = 0; i < UNIQUEID_BYTES; i++) { sprintf(unique_id + (i * 2), "%02x", unique_data[i]); } - fd = fopen(uniqueFilePath, "w"); - if (fd == NULL) + fd = sceIoOpen(uniqueFilePath, SCE_O_WRONLY | SCE_O_CREAT, 0777); + if (fd < 0) return GS_FAILED; - fwrite(unique_id, UNIQUEID_CHARS, 1, fd); + sceIoWrite(fd, unique_id, UNIQUEID_CHARS); } else { - fread(unique_id, UNIQUEID_CHARS, 1, fd); + sceIoRead(fd, unique_id, UNIQUEID_CHARS); } - fclose(fd); + + sceIoClose(fd); unique_id[UNIQUEID_CHARS] = 0; return GS_OK; @@ -126,10 +125,10 @@ static int load_cert(const char* keyDirectory) { FILE *fd = fopen(certificateFilePath, "r"); if (fd == NULL) { - printf("Generating certificate..."); - printf(" this is only done once and can take a long time on Vita, allow up to 5 minutes... "); + sceClibPrintf("Generating certificate..."); + sceClibPrintf(" this is only done once and can take a long time on Vita, allow up to 5 minutes... "); CERT_KEY_PAIR cert = mkcert_generate(); - printf("done\n"); + sceClibPrintf("done\n"); char p12FilePath[4096]; sprintf(p12FilePath, "%s/%s", keyDirectory, P12_FILE_NAME); @@ -188,7 +187,6 @@ static int load_server_status(PSERVER_DATA server) { char *currentGameText = NULL; char *stateText = NULL; char *serverCodecModeSupportText = NULL; - ret = GS_INVALID; uuid_generate_random(uuid); @@ -206,6 +204,7 @@ static int load_server_status(PSERVER_DATA server) { ret = GS_OUT_OF_MEMORY; goto cleanup; } + if (http_request(url, data) != GS_OK) { ret = GS_IO_ERROR; goto cleanup; @@ -248,12 +247,12 @@ static int load_server_status(PSERVER_DATA server) { if (!strlen(currentGameText) || !strlen(pairedText) || !strlen(server->serverInfo.serverInfoAppVersion) || !strlen(stateText)) goto cleanup; - server->paired = pairedText != NULL && strcmp(pairedText, "1") == 0; + server->paired = pairedText != NULL && sceClibStrcmp(pairedText, "1") == 0; server->currentGame = currentGameText == NULL ? 0 : atoi(currentGameText); server->supports4K = serverCodecModeSupportText != NULL; server->serverMajorVersion = atoi(server->serverInfo.serverInfoAppVersion); - if (strstr(stateText, "_SERVER_BUSY") == NULL) { + if (sceClibStrstr(stateText, "_SERVER_BUSY") == NULL) { // After GFE 2.8, current game remains set even after streaming // has ended. We emulate the old behavior by forcing it to zero // if streaming is not active. @@ -309,13 +308,13 @@ static int sign_it(const char *msg, size_t mlen, unsigned char **sig, size_t *sl const EVP_MD *md = EVP_get_digestbyname("SHA256"); if (md == NULL) { - printf("openssl error 0x%x\n", ERR_peek_last_error()); + sceClibPrintf("openssl error 0x%x\n", ERR_peek_last_error()); goto cleanup; } int rc = EVP_DigestInit_ex(ctx, md, NULL); - printf("rc = %d\n", rc); + sceClibPrintf("rc = %d\n", rc); if (rc != 1) goto cleanup; @@ -430,7 +429,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { else if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK) goto cleanup; - if (strcmp(result, "1") != 0) { + if (sceClibStrcmp(result, "1") != 0) { gs_error = "Pairing failed"; ret = GS_FAILED; goto cleanup; @@ -452,13 +451,13 @@ int gs_pair(PSERVER_DATA server, char* pin) { sscanf(&result[count], "%2hhx", &plaincert[count / 2]); } plaincert[strlen(result)/2] = '\0'; - printf("%d / %d\n", strlen(result)/2, strlen(plaincert)); + sceClibPrintf("%d / %d\n", strlen(result)/2, strlen(plaincert)); unsigned char salt_pin[20]; unsigned char aes_key_hash[32]; AES_KEY enc_key, dec_key; - memcpy(salt_pin, salt_data, 16); - memcpy(salt_pin+16, pin, 4); + sceClibMemcpy(salt_pin, salt_data, 16); + sceClibMemcpy(salt_pin+16, pin, 4); int hash_length = server->serverMajorVersion >= 7 ? 32 : 20; if (server->serverMajorVersion >= 7) @@ -489,7 +488,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { else if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK) goto cleanup; - if (strcmp(result, "1") != 0) { + if (sceClibStrcmp(result, "1") != 0) { gs_error = "Pairing failed"; ret = GS_FAILED; goto cleanup; @@ -519,9 +518,9 @@ int gs_pair(PSERVER_DATA server, char* pin) { char challenge_response_hash[32]; char challenge_response_hash_enc[32]; char challenge_response_hex[65]; - memcpy(challenge_response, challenge_response_data + hash_length, 16); - memcpy(challenge_response + 16, cert->signature->data, 256); - memcpy(challenge_response + 16 + 256, client_secret_data, 16); + sceClibMemcpy(challenge_response, challenge_response_data + hash_length, 16); + sceClibMemcpy(challenge_response + 16, cert->signature->data, 256); + sceClibMemcpy(challenge_response + 16 + 256, client_secret_data, 16); if (server->serverMajorVersion >= 7) SHA256(challenge_response, 16 + 256 + 16, challenge_response_hash); else @@ -545,7 +544,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { else if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK) goto cleanup; - if (strcmp(result, "1") != 0) { + if (sceClibStrcmp(result, "1") != 0) { gs_error = "Pairing failed"; ret = GS_FAILED; goto cleanup; @@ -579,8 +578,8 @@ int gs_pair(PSERVER_DATA server, char* pin) { char client_pairing_secret[16 + 256]; char client_pairing_secret_hex[(16 + 256) * 2 + 1]; - memcpy(client_pairing_secret, client_secret_data, 16); - memcpy(client_pairing_secret + 16, signature, 256); + sceClibMemcpy(client_pairing_secret, client_secret_data, 16); + sceClibMemcpy(client_pairing_secret + 16, signature, 256); bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, 16 + 256); uuid_generate_random(uuid); @@ -596,7 +595,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { else if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK) goto cleanup; - if (strcmp(result, "1") != 0) { + if (sceClibStrcmp(result, "1") != 0) { gs_error = "Pairing failed"; ret = GS_FAILED; goto cleanup; @@ -615,7 +614,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { else if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK) goto cleanup; - if (strcmp(result, "1") != 0) { + if (sceClibStrcmp(result, "1") != 0) { gs_error = "Pairing failed"; ret = GS_FAILED; goto cleanup; @@ -680,7 +679,7 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b return GS_NOT_SUPPORTED_4K; RAND_bytes(config->remoteInputAesKey, 16); - memset(config->remoteInputAesIv, 0, 16); + sceClibMemset(config->remoteInputAesIv, 0, 16); srand(time(NULL)); char url[4096]; @@ -692,14 +691,14 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b if (data == NULL) return GS_OUT_OF_MEMORY; - printf("gs_start_app\n"); + sceClibPrintf("gs_start_app\n"); uuid_generate_random(uuid); uuid_unparse(uuid, uuid_str); if (server->currentGame == 0) { int channelCounnt = config->audioConfiguration == AUDIO_CONFIGURATION_STEREO ? CHANNEL_COUNT_STEREO : CHANNEL_COUNT_51_SURROUND; int mask = config->audioConfiguration == AUDIO_CONFIGURATION_STEREO ? CHANNEL_MASK_STEREO : CHANNEL_MASK_51_SURROUND; - snprintf(url, sizeof(url), "https://%s:47984/launch?uniqueid=%s&uuid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d&surroundAudioInfo=%d&remoteControllersBitmap=%d&gcmap=%d", server->serverInfo.address, unique_id, uuid_str, appId, config->width, config->height, config->fps, sops, rikey_hex, rikeyid, localaudio, (mask << 16) + channelCounnt, gamepad_mask, gamepad_mask); + sceClibSnprintf(url, sizeof(url), "https://%s:47984/launch?uniqueid=%s&uuid=%s&appid=%d&mode=%dx%dx%d&additionalStates=1&sops=%d&rikey=%s&rikeyid=%d&localAudioPlayMode=%d&surroundAudioInfo=%d&remoteControllersBitmap=%d&gcmap=%d", server->serverInfo.address, unique_id, uuid_str, appId, config->width, config->height, config->fps, sops, rikey_hex, rikeyid, localaudio, (mask << 16) + channelCounnt, gamepad_mask, gamepad_mask); } else sprintf(url, "https://%s:47984/resume?uniqueid=%s&uuid=%s&rikey=%s&rikeyid=%d", server->serverInfo.address, unique_id, uuid_str, rikey_hex, rikeyid); @@ -707,14 +706,14 @@ int gs_start_app(PSERVER_DATA server, STREAM_CONFIGURATION *config, int appId, b server->currentGame = appId; else goto cleanup; - printf("ret = 0x%x\n", ret); + sceClibPrintf("ret = 0x%x\n", ret); if ((ret = xml_status(data->memory, data->size) != GS_OK)) goto cleanup; else if ((ret = xml_search(data->memory, data->size, "gamesession", &result)) != GS_OK) goto cleanup; - if (!strcmp(result, "0")) { + if (!sceClibStrcmp(result, "0")) { ret = GS_FAILED; goto cleanup; } @@ -748,7 +747,7 @@ int gs_quit_app(PSERVER_DATA server) { else if ((ret = xml_search(data->memory, data->size, "cancel", &result)) != GS_OK) goto cleanup; - if (strcmp(result, "0") == 0) { + if (sceClibStrcmp(result, "0") == 0) { ret = GS_FAILED; goto cleanup; } @@ -763,6 +762,7 @@ int gs_quit_app(PSERVER_DATA server) { int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, int log_level, bool unsupported) { mkdirtree(keyDirectory); + if (load_unique_id(keyDirectory) != GS_OK) return GS_FAILED; @@ -770,9 +770,9 @@ int gs_init(PSERVER_DATA server, char *address, const char *keyDirectory, int lo return GS_FAILED; http_init(keyDirectory, log_level); - LiInitializeServerInformation(&server->serverInfo); server->serverInfo.address = address; server->unsupported = unsupported; + return load_server_status(server); } diff --git a/libgamestream/discover.c b/libgamestream/discover.c index 89d59c09c..5cd7284d2 100644 --- a/libgamestream/discover.c +++ b/libgamestream/discover.c @@ -48,7 +48,7 @@ static void resolve_callback(AvahiServiceResolver *r, AvahiIfIndex interface, Av } else { char strAddress[AVAHI_ADDRESS_STR_MAX]; avahi_address_snprint(strAddress, sizeof(strAddress), address); - printf(" %s (%s)\n", host_name, strAddress); + sceClibPrintf(" %s (%s)\n", host_name, strAddress); } } diff --git a/libgamestream/http.c b/libgamestream/http.c index d7b949be1..b2b865f5d 100644 --- a/libgamestream/http.c +++ b/libgamestream/http.c @@ -24,8 +24,9 @@ #include #include +#include + #include -#include "../src/graphics.h" static CURL *curl; @@ -43,7 +44,7 @@ static size_t _write_curl(void *contents, size_t size, size_t nmemb, void *userp if(mem->memory == NULL) return 0; - memcpy(&(mem->memory[mem->size]), contents, realsize); + sceClibMemcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; @@ -86,9 +87,9 @@ int http_request(char* url, PHTTP_DATA data) { curl_easy_setopt(curl, CURLOPT_URL, url); char url_tiny[48] = {0}; - strncpy(url_tiny, url, sizeof(url_tiny) - 1); + sceClibStrncpy(url_tiny, url, sizeof(url_tiny) - 1); if (debug) - printf("GET %s\n", url_tiny); + sceClibPrintf("GET %s\n", url_tiny); if (data->size > 0) { free(data->memory); @@ -108,7 +109,7 @@ int http_request(char* url, PHTTP_DATA data) { } if (debug) - printf("Response:\n%s\n\n", data->memory); + sceClibPrintf("Response:\n%s\n\n", data->memory); return GS_OK; } diff --git a/libgamestream/mkcert.c b/libgamestream/mkcert.c index 1f5143734..9dab64b7b 100644 --- a/libgamestream/mkcert.c +++ b/libgamestream/mkcert.c @@ -15,6 +15,8 @@ #include "mkcert.h" +#include + #include #include @@ -39,23 +41,23 @@ CERT_KEY_PAIR mkcert_generate() { EVP_PKEY *pkey = NULL; PKCS12 *p12 = NULL; - printf("mkcert_generate\n"); + sceClibPrintf("mkcert_generate\n"); CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); - printf("bio_err %d 0x%x\n", bio_err, bio_err); + sceClibPrintf("bio_err %d 0x%x\n", bio_err, bio_err); SSLeay_add_all_algorithms(); - printf("add all algorithms\n"); + sceClibPrintf("add all algorithms\n"); ERR_load_crypto_strings(); - printf("load crypto strings\n"); + sceClibPrintf("load crypto strings\n"); mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS); - printf("mkcert done\n"); + sceClibPrintf("mkcert done\n"); p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0); - printf("p12 = 0x%x\n", p12); + sceClibPrintf("p12 = 0x%x\n", p12); #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); @@ -97,7 +99,7 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) { if (*pkeyp == NULL) { if ((pk=EVP_PKEY_new()) == NULL) { - printf("abort1\n"); + sceClibPrintf("abort1\n"); abort(); return(0); } @@ -107,7 +109,7 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) { if (*x509p == NULL) { if ((x = X509_new()) == NULL) { - printf("goto err\n"); + sceClibPrintf("goto err\n"); goto err; } } else { @@ -120,11 +122,11 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) { int flags = ERR_TXT_STRING; int line; ERR_peek_last_error_line_data(&file, &line, &data, &flags); - printf("openssl error 0x%x => %s:%d %s\n", ERR_peek_last_error(), file, line, data); + sceClibPrintf("openssl error 0x%x => %s:%d %s\n", ERR_peek_last_error(), file, line, data); } - printf("gen rsa %x\n", rsa); + sceClibPrintf("gen rsa %x\n", rsa); if (!EVP_PKEY_assign_RSA(pk, rsa)) { - printf("abort 2\n"); + sceClibPrintf("abort 2\n"); abort(); goto err; } diff --git a/libgamestream/sps.c b/libgamestream/sps.c index 737590f64..d7198073b 100644 --- a/libgamestream/sps.c +++ b/libgamestream/sps.c @@ -19,6 +19,8 @@ #include "sps.h" +#include + #include "h264_stream.h" static h264_stream_t* h264_stream = NULL; @@ -82,7 +84,7 @@ void gs_sps_fix(PLENTRY sps, int flags, uint8_t* out_buf, uint32_t* out_offset) } else // Devices that didn't/couldn't get bitstream restrictions before GFE 2.5.11 will continue to not receive them now h264_stream->sps->vui.bitstream_restriction_flag = 0; - memcpy(out_buf+*out_offset, naluHeader, 4); + sceClibMemcpy(out_buf+*out_offset, naluHeader, 4); *out_offset += 4; *out_offset += write_nal_unit(h264_stream, out_buf+*out_offset, 128); diff --git a/libgamestream/xml.c b/libgamestream/xml.c index acf7fa6dd..f6542f6f2 100644 --- a/libgamestream/xml.c +++ b/libgamestream/xml.c @@ -23,6 +23,8 @@ #include #include +#include + #define STATUS_OK 200 static XML_Parser parser; @@ -36,19 +38,19 @@ struct xml_query { static void XMLCALL _xml_start_element(void *userData, const char *name, const char **atts) { struct xml_query *search = (struct xml_query*) userData; - if (strcmp(search->data, name) == 0) + if (sceClibStrcmp(search->data, name) == 0) search->start++; } static void XMLCALL _xml_end_element(void *userData, const char *name) { struct xml_query *search = (struct xml_query*) userData; - if (strcmp(search->data, name) == 0) + if (sceClibStrcmp(search->data, name) == 0) search->start--; } static void XMLCALL _xml_start_applist_element(void *userData, const char *name, const char **atts) { struct xml_query *search = (struct xml_query*) userData; - if (strcmp("App", name) == 0) { + if (sceClibStrcmp("App", name) == 0) { PAPP_LIST app = malloc(sizeof(APP_LIST)); if (app == NULL) return; @@ -57,7 +59,7 @@ static void XMLCALL _xml_start_applist_element(void *userData, const char *name, app->name = NULL; app->next = (PAPP_LIST) search->data; search->data = app; - } else if (strcmp("ID", name) == 0 || strcmp("AppTitle", name) == 0) { + } else if (sceClibStrcmp("ID", name) == 0 || sceClibStrcmp("AppTitle", name) == 0) { search->memory = malloc(1); search->size = 0; search->start = 1; @@ -71,10 +73,10 @@ static void XMLCALL _xml_end_applist_element(void *userData, const char *name) { if (list == NULL) return; - if (strcmp("ID", name) == 0) { + if (sceClibStrcmp("ID", name) == 0) { list->id = atoi(search->memory); free(search->memory); - } else if (strcmp("AppTitle", name) == 0) { + } else if (sceClibStrcmp("AppTitle", name) == 0) { list->name = search->memory; } search->start = 0; @@ -83,13 +85,13 @@ static void XMLCALL _xml_end_applist_element(void *userData, const char *name) { static void XMLCALL _xml_start_mode_element(void *userData, const char *name, const char **atts) { struct xml_query *search = (struct xml_query*) userData; - if (strcmp("DisplayMode", name) == 0) { + if (sceClibStrcmp("DisplayMode", name) == 0) { PDISPLAY_MODE mode = calloc(1, sizeof(DISPLAY_MODE)); if (mode != NULL) { mode->next = (PDISPLAY_MODE) search->data; search->data = mode; } - } else if (search->data != NULL && (strcmp("Height", name) == 0 || strcmp("Width", name) == 0 || strcmp("RefreshRate", name) == 0)) { + } else if (search->data != NULL && (sceClibStrcmp("Height", name) == 0 || sceClibStrcmp("Width", name) == 0 || sceClibStrcmp("RefreshRate", name) == 0)) { search->memory = malloc(1); search->size = 0; search->start = 1; @@ -100,11 +102,11 @@ static void XMLCALL _xml_end_mode_element(void *userData, const char *name) { struct xml_query *search = (struct xml_query*) userData; if (search->data != NULL && search->start) { PDISPLAY_MODE mode = (PDISPLAY_MODE) search->data; - if (strcmp("Width", name) == 0) + if (sceClibStrcmp("Width", name) == 0) mode->width = atoi(search->memory); - else if (strcmp("Height", name) == 0) + else if (sceClibStrcmp("Height", name) == 0) mode->height = atoi(search->memory); - else if (strcmp("RefreshRate", name) == 0) + else if (sceClibStrcmp("RefreshRate", name) == 0) mode->refresh = atoi(search->memory); free(search->memory); @@ -113,12 +115,12 @@ static void XMLCALL _xml_end_mode_element(void *userData, const char *name) { } static void XMLCALL _xml_start_status_element(void *userData, const char *name, const char **atts) { - if (strcmp("root", name) == 0) { + if (sceClibStrcmp("root", name) == 0) { int* status = (int*) userData; for (int i = 0; atts[i]; i += 2) { - if (strcmp("status_code", atts[i]) == 0) + if (sceClibStrcmp("status_code", atts[i]) == 0) *status = atoi(atts[i + 1]); - else if (*status != STATUS_OK && strcmp("status_message", atts[i]) == 0) + else if (*status != STATUS_OK && sceClibStrcmp("status_message", atts[i]) == 0) gs_error = strdup(atts[i + 1]); } } @@ -133,7 +135,7 @@ static void XMLCALL _xml_write_data(void *userData, const XML_Char *s, int len) if(search->memory == NULL) return; - memcpy(&(search->memory[search->size]), s, len); + sceClibMemcpy(&(search->memory[search->size]), s, len); search->size += len; search->memory[search->size] = 0; } diff --git a/module/exit_module.yml b/module/exit_module.yml new file mode 100644 index 000000000..abf9c0df6 --- /dev/null +++ b/module/exit_module.yml @@ -0,0 +1,8 @@ +exit_module: + attributes: 0 + version: + major: 1 + minor: 0 + main: + start: module_start + stop: module_stop diff --git a/module/source/main.c b/module/source/main.c new file mode 100644 index 000000000..d2a7c1177 --- /dev/null +++ b/module/source/main.c @@ -0,0 +1,32 @@ +#include +#include + +static SceUID g_hooks[1]; + +static int first = 0; + +static tai_hook_ref_t ref_hook0; +int ksceSblACMgrIsNonGameProgram_patched(void) +{ + if (!first) { + first = 1; + return 1; + } + else + return 0; +} + +void _start() __attribute__((weak, alias("module_start"))); +int module_start(SceSize argc, const void *args) +{ + g_hooks[0] = taiHookFunctionExportForKernel(KERNEL_PID, &ref_hook0, + "SceSblACMgr", 0x9AD8E213, 0x6C5AB07F, ksceSblACMgrIsNonGameProgram_patched); + + return SCE_KERNEL_START_SUCCESS; +} + +int module_stop(SceSize argc, const void *args) +{ + if (g_hooks[0] >= 0) taiHookReleaseForKernel(g_hooks[0], ref_hook0); + return SCE_KERNEL_STOP_SUCCESS; +} \ No newline at end of file diff --git a/moonlight.conf b/moonlight.conf deleted file mode 100644 index 785965644..000000000 --- a/moonlight.conf +++ /dev/null @@ -1,42 +0,0 @@ -## Hostname or IP-address of host to connect to -## By default host is autodiscovered using mDNS -#address = 1.2.3.4 - -## Video streaming configuration -#width = 1280 -#height = 720 -#fps = 60 - -## Bitrate depends by default on resolution and fps -## Set to -1 to enable default -## 20Mbps (20000) for 1080p (60 fps) -## 10Mbps (10000) for 1080p or 60 fps -## 5Mbps (5000) for lower resolution or fps -#bitrate = -1 - -## Mapping file -#mapping = mappings/vita.conf - -## Size of network packets should be lower than MTU -#packetsize = 1024 - -## Use of h265/HEVC video codec -#h265 = false - -## Default started application on host -#app = Steam - -## Let GFE change graphical game settings for optimal performance and quality -#sops = true - -## Play audio on host instead of streaming to client -#localaudio = false - -## Use front touch screen for buttons (disables mouse input) -#fronttouchscreen_buttons = false - -## Back touchscreen deadzone in pixels, separated by "," (top, right, bottom, left) -#backtouchscreen_deadzone = 0,0,0,0 - -## Disable power save mode -#disable_powersave = true diff --git a/sce_sys/livearea/contents/template.xml b/sce_sys/livearea/contents/template.xml index d91394e54..b871b5e88 100644 --- a/sce_sys/livearea/contents/template.xml +++ b/sce_sys/livearea/contents/template.xml @@ -28,7 +28,7 @@ NVIDIA GAMESTREAM CLIENT - v0.8.0 + v0.9.2 diff --git a/src/audio/vita.c b/src/audio/vita.c index fd138e02f..8959ea96d 100644 --- a/src/audio/vita.c +++ b/src/audio/vita.c @@ -17,12 +17,18 @@ * along with Moonlight; if not, see . */ +#include "../config.h" #include "../audio.h" #include "../debug.h" +#include "../platform.h" #include #include #include +#include +#include + +int sceAppMgrAcquireBgmPortForMusicPlayer(void); enum { VITA_AUDIO_INIT_OK = 0, @@ -36,16 +42,20 @@ enum { static int decode_offset; static int port; -static int active_audio_thread = true; static OpusMSDecoder* decoder = NULL; static short buffer[BUFFER_SIZE]; +extern SceUID state_evf; + static void vita_renderer_cleanup() { if (decoder != NULL) { opus_multistream_decoder_destroy(decoder); decoder = NULL; } + sceAppMgrReleaseBgmPort(); + sceAudioOutOutput(port, NULL); + sceAudioOutReleasePort(port); } static int vita_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* audioContext, int arFlags) { @@ -60,8 +70,8 @@ static int vita_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGUR if (rc < 0) { return VITA_AUDIO_ERROR_BAD_OPUS; } - - port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, VITA_SAMPLES, 48000, SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO); + + port = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, VITA_SAMPLES, 48000, SCE_AUDIO_OUT_PARAM_FORMAT_S16_STEREO); if (port < 0) { vita_renderer_cleanup(); @@ -73,6 +83,7 @@ static int vita_renderer_init(int audioConfiguration, POPUS_MULTISTREAM_CONFIGUR } static void vita_renderer_decode_and_play_sample(char* data, int length) { + if (!data) return; @@ -84,9 +95,8 @@ static void vita_renderer_decode_and_play_sample(char* data, int length) { if (decode_offset == VITA_SAMPLES) { decode_offset = 0; - if (active_audio_thread) { - sceAudioOutOutput(port, buffer); - } + if (!sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_AUDIO_THREAD, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) + sceAudioOutOutput(port, buffer); } } else { vita_debug_log("Opus error from decode: %d\n", decodeLen); @@ -102,9 +112,11 @@ AUDIO_RENDERER_CALLBACKS audio_callbacks_vita = { void vitaaudio_start() { - active_audio_thread = true; + sceAppMgrAcquireBgmPortForMusicPlayer(); + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_AUDIO_THREAD); } void vitaaudio_stop() { - active_audio_thread = false; + sceAppMgrReleaseBgmPort(); + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_ACTIVE_AUDIO_THREAD); } diff --git a/src/config.c b/src/config.c index 78103a4d2..b04381518 100644 --- a/src/config.c +++ b/src/config.c @@ -1,280 +1,292 @@ -/* - * This file is part of Moonlight Embedded. - * - * Copyright (C) 2015, 2016 Iwan Timmer - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#include "config.h" -#include "audio.h" - -#include -#include -#include -#include -#include -#include -#include "graphics.h" -#include "input/vita.h" - -#include - -#define MOONLIGHT_PATH "/moonlight" -#define USER_PATHS "." -#define DEFAULT_CONFIG_DIR "/.config" -#define DEFAULT_CACHE_DIR "/.cache" - -#define write_config_string(fd, key, value) fprintf(fd, "%s = %s\n", key, value) -#define write_config_int(fd, key, value) fprintf(fd, "%s = %d\n", key, value) -#define write_config_hex(fd, key, value) fprintf(fd, "%s = %X\n", key, value) -#define write_config_bool(fd, key, value) fprintf(fd, "%s = %s\n", key, value?"true":"false"); -#define write_config_section(fd, key) fprintf(fd, "\n[%s]\n", key) - -CONFIGURATION config; -char *config_path; - -bool inputAdded = false; -static bool mapped = true; -const char* audio_device = NULL; - -static int ini_handle(void *out, const char *section, const char *name, - const char *value) { -#define HEX(v) strtol((v), NULL, 16) -#define INT(v) atoi((v)) -#define BOOL(v) strcmp((v), "true") == 0 -#define STR(v) strdup((v)) - - PCONFIGURATION config = (PCONFIGURATION)out; - if (strcmp(section, "backtouchscreen_deadzone") == 0) { - if (strcmp(name, "top") == 0) { - config->back_deadzone.top = INT(value); - } else if (strcmp(name, "right") == 0) { - config->back_deadzone.right = INT(value); - } else if (strcmp(name, "bottom") == 0) { - config->back_deadzone.bottom = INT(value); - } else if (strcmp(name, "left") == 0) { - config->back_deadzone.left = INT(value); - } - } else if (strcmp(section, "special_keys") == 0) { - if (strcmp(name, "nw") == 0) { - config->special_keys.nw = HEX(value); - } else if (strcmp(name, "ne") == 0) { - config->special_keys.ne = HEX(value); - } else if (strcmp(name, "sw") == 0) { - config->special_keys.sw = HEX(value); - } else if (strcmp(name, "se") == 0) { - config->special_keys.se = HEX(value); - } else if (strcmp(name, "offset") == 0) { - config->special_keys.offset = INT(value); - } else if (strcmp(name, "size") == 0) { - config->special_keys.size = INT(value); - } - } else { - if (strcmp(name, "address") == 0) { - config->address = STR(value); - } else if (strcmp(name, "width") == 0) { - config->stream.width = INT(value); - } else if (strcmp(name, "height") == 0) { - config->stream.height = INT(value); - } else if (strcmp(name, "fps") == 0) { - config->stream.fps = INT(value); - } else if (strcmp(name, "bitrate") == 0) { - config->stream.bitrate = INT(value); - } else if (strcmp(name, "sops") == 0) { - config->sops = BOOL(value); - } else if (strcmp(name, "localaudio") == 0) { - config->localaudio = BOOL(value); - } else if (strcmp(name, "enable_frame_pacer") == 0) { - config->enable_frame_pacer = BOOL(value); - } else if (strcmp(name, "center_region_only") == 0) { - config->center_region_only = BOOL(value); - } else if (strcmp(name, "disable_powersave") == 0) { - config->disable_powersave = BOOL(value); - } else if (strcmp(name, "jp_layout") == 0) { - config->jp_layout = BOOL(value); - } else if (strcmp(name, "show_fps") == 0) { - config->show_fps = BOOL(value); - } else if (strcmp(name, "save_debug_log") == 0) { - config->save_debug_log = BOOL(value); - } else if (strcmp(name, "mapping") == 0) { - config->mapping = STR(value); - } else if (strcmp(name, "mouse_acceleration") == 0) { - config->mouse_acceleration = INT(value); - } else if (strcmp(name, "enable_ref_frame_invalidation") == 0) { - config->enable_ref_frame_invalidation = BOOL(value); - } else if (strcmp(name, "enable_remote_stream_optimization") == 0) { - config->stream.streamingRemotely = INT(value); - } - } -} - -bool config_file_parse(char* filename, PCONFIGURATION config) { - return ini_parse(filename, ini_handle, config); -} - -void config_save(const char* filename, PCONFIGURATION config) { - FILE* fd = fopen(filename, "w"); - if (fd == NULL) { - fprintf(stderr, "Can't open configuration file: %s\n", filename); - exit(EXIT_FAILURE); - } - - if (config->address) - write_config_string(fd, "address", config->address); - - if (config->mapping) - write_config_string(fd, "mapping", config->mapping); - - if (config->stream.width != 1280) - write_config_int(fd, "width", config->stream.width); - if (config->stream.height != 720) - write_config_int(fd, "height", config->stream.height); - if (config->stream.fps != 60) - write_config_int(fd, "fps", config->stream.fps); - if (config->stream.bitrate != -1) - write_config_int(fd, "bitrate", config->stream.bitrate); - if (config->stream.packetSize != 1024) - write_config_int(fd, "packetsize", config->stream.packetSize); - if (!config->sops) - write_config_bool(fd, "sops", config->sops); - if (config->localaudio) - write_config_bool(fd, "localaudio", config->localaudio); - - if (strcmp(config->app, "Steam") != 0) - write_config_string(fd, "app", config->app); - - write_config_bool(fd, "enable_frame_pacer", config->enable_frame_pacer); - write_config_bool(fd, "center_region_only", config->center_region_only); - write_config_bool(fd, "disable_powersave", config->disable_powersave); - write_config_bool(fd, "jp_layout", config->jp_layout); - write_config_bool(fd, "show_fps", config->show_fps); - write_config_bool(fd, "save_debug_log", config->save_debug_log); - - write_config_int(fd, "mouse_acceleration", config->mouse_acceleration); - write_config_bool(fd, "enable_ref_frame_invalidation", config->enable_ref_frame_invalidation); - write_config_int(fd, "enable_remote_stream_optimization", config->stream.streamingRemotely); - - write_config_section(fd, "backtouchscreen_deadzone"); - write_config_int(fd, "top", config->back_deadzone.top); - write_config_int(fd, "right", config->back_deadzone.right); - write_config_int(fd, "bottom", config->back_deadzone.bottom); - write_config_int(fd, "left", config->back_deadzone.left); - - write_config_section(fd, "special_keys"); - write_config_hex(fd, "nw", config->special_keys.nw); - write_config_hex(fd, "ne", config->special_keys.ne); - write_config_hex(fd, "sw", config->special_keys.sw); - write_config_hex(fd, "se", config->special_keys.se); - write_config_int(fd, "offset", config->special_keys.offset); - write_config_int(fd, "size", config->special_keys.size); - - fclose(fd); -} - -void update_layout() { - if (config.jp_layout) { - config.btn_confirm = SCE_CTRL_CIRCLE; - config.btn_cancel = SCE_CTRL_CROSS; - } - else { - config.btn_confirm = SCE_CTRL_CROSS; - config.btn_cancel = SCE_CTRL_CIRCLE; - } -} - -void config_parse(int argc, char* argv[], PCONFIGURATION config) { - LiInitializeStreamConfiguration(&config->stream); - - config->stream.width = 1280; - config->stream.height = 720; - config->stream.fps = 60; - config->stream.bitrate = -1; - config->stream.packetSize = 1024; - config->stream.streamingRemotely = 0; - config->stream.audioConfiguration = AUDIO_CONFIGURATION_STEREO; - config->stream.supportsHevc = false; - - config->platform = "vita"; - config->model = sceKernelGetModelForCDialog(); - config->app = "Steam"; - config->action = NULL; - config->address = NULL; - config->config_file = NULL; - config->sops = true; - config->localaudio = false; - config->fullscreen = true; - config->unsupported_version = false; - config->save_debug_log = false; - config->disable_powersave = true; - config->jp_layout = false; - config->show_fps = false; - config->enable_frame_pacer = true; - config->center_region_only = false; - - config->special_keys.nw = INPUT_SPECIAL_KEY_PAUSE | INPUT_TYPE_SPECIAL; - config->special_keys.sw = SPECIAL_FLAG | INPUT_TYPE_GAMEPAD; - config->special_keys.offset = 0; - config->special_keys.size = 150; - - config->mouse_acceleration = 150; - config->enable_ref_frame_invalidation = false; - - config->inputsCount = 0; - config->mapping = NULL; - config->key_dir[0] = 0; - - //char* config_file = get_path("moonlight.conf", "ux0:data/moonlight/"); - char* config_file = config_path; - if (config_file) { - config_file_parse(config_file, config); - } - - update_layout(); - - if (config->config_file != NULL) - config_save(config->config_file, config); - - if (config->key_dir[0] == 0x0) { - const char *xdg_cache_dir = getenv("XDG_CACHE_DIR"); - if (xdg_cache_dir != NULL) - sprintf(config->key_dir, "%s" MOONLIGHT_PATH, xdg_cache_dir); - else { - const char *home_dir = getenv("HOME"); - sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, home_dir); - } - } - - if (config->stream.fps == -1) - config->stream.fps = config->stream.height >= 1080 ? 30 : 60; - - if (config->stream.bitrate == -1) { - if (config->stream.height >= 1080 && config->stream.fps >= 60) - config->stream.bitrate = 20000; - else if (config->stream.height >= 1080 || config->stream.fps >= 60) - config->stream.bitrate = 10000; - else - config->stream.bitrate = 5000; - } - - if (inputAdded) { - if (!mapped) { - fprintf(stderr, "Mapping option should be followed by the input to be mapped.\n"); - exit(-1); - } else if (config->mapping == NULL) { - fprintf(stderr, "Please specify mapping file as default mapping could not be found.\n"); - exit(-1); - } - } -} +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015, 2016 Iwan Timmer + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include "config.h" +#include "audio.h" + +#include +#include +#include +#include +#include +#include "ini.h" +#include "ini_file_processor_c.h" +#include "input/vita.h" + +#include +#include +#include + +#define MOONLIGHT_PATH "/moonlight" +#define USER_PATHS "." +#define DEFAULT_CONFIG_DIR "/.config" +#define DEFAULT_CACHE_DIR "/.cache" + +CONFIGURATION config; +char *config_path; + +bool inputAdded = false; +static bool mapped = true; +const char* audio_device = NULL; + +bool config_file_parse(char* filename, PCONFIGURATION config) { + char iniProcContext[8]; + SceIniFileProcessorParam iniProcInitParam; + SceIniFileProcessorMemCallbacks iniAllocCb; + sceIniFileProcessorCreateContext(iniProcContext); + + sceIniFileProcessorInitializeParam(&iniProcInitParam); + sceIniFileProcessorCreateInstance(iniProcContext, &iniProcInitParam); + + int ret = sceIniFileProcessorOpenFile(iniProcContext, filename, "r", 0); + if (ret < 0) { + sceIniFileProcessorDestroyInstanceForError(iniProcContext); + sceClibPrintf("sceIniFileProcessorOpenFile() returned 0x%X, %s\n", ret, filename); + return 0; + } + + int int_value; + if (!iniGetValueByKey(iniProcContext, "top", INI_VALUE_INT, 0, &int_value)) + config->back_deadzone.top = int_value; + if (!iniGetValueByKey(iniProcContext, "right", INI_VALUE_INT, 0, &int_value)) + config->back_deadzone.right = int_value; + if (!iniGetValueByKey(iniProcContext, "bottom", INI_VALUE_INT, 0, &int_value)) + config->back_deadzone.bottom = int_value; + if (!iniGetValueByKey(iniProcContext, "left", INI_VALUE_INT, 0, &int_value)) + config->back_deadzone.left = int_value; + + if (!iniGetValueByKey(iniProcContext, "nw", INI_VALUE_INT, 16, &int_value)) + config->special_keys.nw = int_value; + if (!iniGetValueByKey(iniProcContext, "ne", INI_VALUE_INT, 16, &int_value)) + config->special_keys.ne = int_value; + if (!iniGetValueByKey(iniProcContext, "sw", INI_VALUE_INT, 16, &int_value)) + config->special_keys.sw = int_value; + if (!iniGetValueByKey(iniProcContext, "se", INI_VALUE_INT, 16, &int_value)) + config->special_keys.se = int_value; + if (!iniGetValueByKey(iniProcContext, "offset", INI_VALUE_INT, 0, &int_value)) + config->special_keys.offset = int_value; + if (!iniGetValueByKey(iniProcContext, "size", INI_VALUE_INT, 0, &int_value)) + config->special_keys.size = int_value; + + iniGetStringByKey(iniProcContext, "address", &config->address); + if (!iniGetValueByKey(iniProcContext, "width", INI_VALUE_INT, 0, &int_value)) + config->stream.width = int_value; + if (!iniGetValueByKey(iniProcContext, "height", INI_VALUE_INT, 0, &int_value)) + config->stream.height = int_value; + if (!iniGetValueByKey(iniProcContext, "fps", INI_VALUE_INT, 0, &int_value)) + config->stream.fps = int_value; + if (!iniGetValueByKey(iniProcContext, "bitrate", INI_VALUE_INT, 0, &int_value)) + config->stream.bitrate = int_value; + if (!iniGetValueByKey(iniProcContext, "sops", INI_VALUE_BOOL, 0, &int_value)) + config->sops = int_value; + if (!iniGetValueByKey(iniProcContext, "localaudio", INI_VALUE_BOOL, 0, &int_value)) + config->localaudio = int_value; + if (!iniGetValueByKey(iniProcContext, "enable_frame_pacer", INI_VALUE_BOOL, 0, &int_value)) + config->enable_frame_pacer = int_value; + if (!iniGetValueByKey(iniProcContext, "center_region_only", INI_VALUE_BOOL, 0, &int_value)) + config->center_region_only = int_value; + if (!iniGetValueByKey(iniProcContext, "disable_powersave", INI_VALUE_BOOL, 0, &int_value)) + config->disable_powersave = int_value; + if (!iniGetValueByKey(iniProcContext, "disable_dimming", INI_VALUE_BOOL, 0, &int_value)) + config->disable_dimming = int_value; + if (!iniGetValueByKey(iniProcContext, "jp_layout", INI_VALUE_BOOL, 0, &int_value)) + config->jp_layout = int_value; + if (!iniGetValueByKey(iniProcContext, "show_fps", INI_VALUE_BOOL, 0, &int_value)) + config->show_fps = int_value; + if (!iniGetValueByKey(iniProcContext, "save_debug_log", INI_VALUE_BOOL, 0, &int_value)) + config->save_debug_log = int_value; + iniGetStringByKey(iniProcContext, "mapping", &config->mapping); + if (!iniGetValueByKey(iniProcContext, "mouse_acceleration", INI_VALUE_INT, 0, &int_value)) + config->mouse_acceleration = int_value; + if (!iniGetValueByKey(iniProcContext, "enable_ref_frame_invalidation", INI_VALUE_BOOL, 0, &int_value)) + config->enable_ref_frame_invalidation = int_value; + if (!iniGetValueByKey(iniProcContext, "enable_remote_stream_optimization", INI_VALUE_BOOL, 0, &int_value)) + config->stream.streamingRemotely = int_value; + + sceIniFileProcessorFinalize(iniProcContext); + + return 1; +} + +void config_save(const char* filename, PCONFIGURATION config) { + char iniProcContext[8]; + SceIniFileProcessorParam iniProcInitParam; + SceIniFileProcessorMemCallbacks iniAllocCb; + sceIniFileProcessorCreateContext(iniProcContext); + + sceIniFileProcessorInitializeParam(&iniProcInitParam); + sceIniFileProcessorCreateInstance(iniProcContext, &iniProcInitParam); + + int ret = sceIniFileProcessorCreateFile(iniProcContext, filename, "rw", 0); + if (ret < 0) { + sceIniFileProcessorDestroyInstanceForError(iniProcContext); + sceClibPrintf("sceIniFileProcessorCreateFile() returned 0x%X, %s\n", ret, filename); + return; + } + + if (config->address) + sceIniFileProcessorAddKey(iniProcContext, "address", config->address); + + if (config->mapping) + sceIniFileProcessorAddKey(iniProcContext, "mapping", config->mapping); + + if (config->stream.width != 1280) + iniCreateSetKey(iniProcContext, "width", INI_VALUE_INT, config->stream.width); + if (config->stream.height != 720) + iniCreateSetKey(iniProcContext, "height", INI_VALUE_INT, config->stream.height); + if (config->stream.fps != 60) + iniCreateSetKey(iniProcContext, "fps", INI_VALUE_INT, config->stream.fps); + if (config->stream.bitrate != -1) + iniCreateSetKey(iniProcContext, "bitrate", INI_VALUE_INT, config->stream.bitrate); + if (config->stream.packetSize != 1024) + iniCreateSetKey(iniProcContext, "packetsize", INI_VALUE_INT, config->stream.packetSize); + if (!config->sops) + iniCreateSetKey(iniProcContext, "sops", INI_VALUE_BOOL, config->sops); + if (config->localaudio) + iniCreateSetKey(iniProcContext, "localaudio", INI_VALUE_BOOL, config->localaudio); + + if (sceClibStrcmp(config->app, "Steam") != 0) + sceIniFileProcessorAddKey(iniProcContext, "app", config->app); + + iniCreateSetKey(iniProcContext, "enable_frame_pacer", INI_VALUE_BOOL, config->enable_frame_pacer); + iniCreateSetKey(iniProcContext, "center_region_only", INI_VALUE_BOOL, config->center_region_only); + iniCreateSetKey(iniProcContext, "disable_powersave", INI_VALUE_BOOL, config->disable_powersave); + iniCreateSetKey(iniProcContext, "disable_dimming", INI_VALUE_BOOL, config->disable_dimming); + iniCreateSetKey(iniProcContext, "jp_layout", INI_VALUE_BOOL, config->jp_layout); + iniCreateSetKey(iniProcContext, "show_fps", INI_VALUE_BOOL, config->show_fps); + iniCreateSetKey(iniProcContext, "save_debug_log", INI_VALUE_BOOL, config->save_debug_log); + + iniCreateSetKey(iniProcContext, "mouse_acceleration", INI_VALUE_INT, config->mouse_acceleration); + iniCreateSetKey(iniProcContext, "enable_ref_frame_invalidation", INI_VALUE_BOOL, config->enable_ref_frame_invalidation); + iniCreateSetKey(iniProcContext, "enable_remote_stream_optimization", INI_VALUE_BOOL, config->stream.streamingRemotely); + + iniCreateSetKey(iniProcContext, "top", INI_VALUE_INT, config->back_deadzone.top); + iniCreateSetKey(iniProcContext, "right", INI_VALUE_INT, config->back_deadzone.right); + iniCreateSetKey(iniProcContext, "bottom", INI_VALUE_INT, config->back_deadzone.bottom); + iniCreateSetKey(iniProcContext, "left", INI_VALUE_INT, config->back_deadzone.left); + + iniCreateSetKey(iniProcContext, "nw", INI_VALUE_HEX, config->special_keys.nw); + iniCreateSetKey(iniProcContext, "ne", INI_VALUE_HEX, config->special_keys.ne); + iniCreateSetKey(iniProcContext, "sw", INI_VALUE_HEX, config->special_keys.sw); + iniCreateSetKey(iniProcContext, "se", INI_VALUE_HEX, config->special_keys.se); + iniCreateSetKey(iniProcContext, "offset", INI_VALUE_INT, config->special_keys.offset); + iniCreateSetKey(iniProcContext, "size", INI_VALUE_INT, config->special_keys.size); + + sceIniFileProcessorFinalize(iniProcContext); +} + +void update_layout() { + if (config.jp_layout) { + config.btn_confirm = SCE_CTRL_CIRCLE; + config.btn_cancel = SCE_CTRL_CROSS; + } + else { + config.btn_confirm = SCE_CTRL_CROSS; + config.btn_cancel = SCE_CTRL_CIRCLE; + } +} + +void config_parse(int argc, char* argv[], PCONFIGURATION config) { + LiInitializeStreamConfiguration(&config->stream); + + config->model = vshSblAimgrIsGenuineDolce(); + + config->stream.width = 960; + config->stream.height = 544; + config->stream.fps = 60; + config->stream.bitrate = -1; + config->stream.packetSize = 1024; + config->stream.streamingRemotely = 0; + config->stream.audioConfiguration = AUDIO_CONFIGURATION_STEREO; + config->stream.supportsHevc = false; + + config->platform = "vita"; + config->model = sceKernelGetModelForCDialog(); + config->app = "Steam"; + config->action = NULL; + config->address = NULL; + config->config_file = NULL; + config->sops = true; + config->localaudio = false; + config->fullscreen = true; + config->unsupported_version = false; + config->save_debug_log = false; + config->disable_powersave = true; + config->disable_dimming = true; + config->jp_layout = false; + config->show_fps = false; + config->enable_frame_pacer = true; + config->center_region_only = false; + + config->special_keys.nw = INPUT_SPECIAL_KEY_PAUSE | INPUT_TYPE_SPECIAL; + config->special_keys.ne = INPUT_SPECIAL_KEY_KEYBOARD | INPUT_TYPE_SPECIAL; + config->special_keys.sw = SPECIAL_FLAG | INPUT_TYPE_GAMEPAD; + config->special_keys.offset = 0; + config->special_keys.size = 150; + + config->mouse_acceleration = 150; + config->enable_ref_frame_invalidation = false; + + config->inputsCount = 0; + config->mapping = NULL; + config->key_dir[0] = 0; + + //char* config_file = get_path("moonlight.conf", "ux0:data/moonlight/"); + char* config_file = config_path; + if (config_file) { + config_file_parse(config_file, config); + } + + update_layout(); + + if (config->config_file != NULL) + config_save(config->config_file, config); + + if (config->key_dir[0] == 0x0) { + const char *xdg_cache_dir = getenv("XDG_CACHE_DIR"); + if (xdg_cache_dir != NULL) + sprintf(config->key_dir, "%s" MOONLIGHT_PATH, xdg_cache_dir); + else { + const char *home_dir = getenv("HOME"); + sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, home_dir); + } + } + + if (config->stream.fps == -1) + config->stream.fps = config->stream.height >= 1080 ? 30 : 60; + + if (config->stream.bitrate == -1) { + if (config->stream.height >= 1080 && config->stream.fps >= 60) + config->stream.bitrate = 20000; + else if (config->stream.height >= 1080 || config->stream.fps >= 60) + config->stream.bitrate = 10000; + else + config->stream.bitrate = 5000; + } + + if (inputAdded) { + if (!mapped) { + fprintf(stderr, "Mapping option should be followed by the input to be mapped.\n"); + exit(-1); + } else if (config->mapping == NULL) { + fprintf(stderr, "Please specify mapping file as default mapping could not be found.\n"); + exit(-1); + } + } +} diff --git a/src/config.h b/src/config.h index b2ee0e20a..33cbb7b0d 100644 --- a/src/config.h +++ b/src/config.h @@ -60,6 +60,7 @@ typedef struct _CONFIGURATION { struct touchscreen_deadzone back_deadzone; struct special_keys special_keys; bool disable_powersave; + bool disable_dimming; bool jp_layout; bool show_fps; bool enable_frame_pacer; diff --git a/src/configuration.h b/src/configuration.h index 615a5ad1e..099923b36 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -18,3 +18,7 @@ */ #define COMPILE_OPTIONS "VITA" + +#define VERSION_MAJOR 0 +#define VERSION_MINOR 9 +#define VERSION_PATCH 1 diff --git a/src/debug.c b/src/debug.c index 7c76f05ca..9efdae127 100644 --- a/src/debug.c +++ b/src/debug.c @@ -18,6 +18,8 @@ */ #include "config.h" +#include + #include #include #include @@ -34,14 +36,14 @@ void vita_debug_log(const char *s, ...) { SceDateTime time; sceRtcGetCurrentClock(&time, 0); - snprintf(buffer, 26, "%04d%02d%02d %02d:%02d:%02d.%06d ", + sceClibSnprintf(buffer, 26, "%04d%02d%02d %02d:%02d:%02d.%06d ", time.year, time.month, time.day, time.hour, time.minute, time.second, time.microsecond); va_list va; va_start(va, s); - int len = vsnprintf(&buffer[25], 998, s, va); + int len = sceClibVsnprintf(&buffer[25], 998, s, va); va_end(va); fprintf(config.log_file, buffer); diff --git a/src/device.c b/src/device.c index 951f2f9fb..86dc729d6 100644 --- a/src/device.c +++ b/src/device.c @@ -1,185 +1,206 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include "device.h" -#include "debug.h" - -#define DATA_DIR "ux0:data/moonlight" -#define DEVICE_FILE "device.ini" - -#define BOOL(v) strcmp((v), "true") == 0 -#define write_bool(fd, key, value) fprintf(fd, "%s = %s\n", key, value ? "true" : "false"); -#define write_string(fd, key, value) fprintf(fd, "%s = %s\n", key, value) - -device_infos_t known_devices = {0}; - -device_info_t* find_device(const char *name) { - // TODO: mutex - for (int i = 0; i < known_devices.count; i++) { - if (!strcmp(name, known_devices.devices[i].name)) { - return &known_devices.devices[i]; - } - } - return NULL; -} - -static void device_file_path(char *out, const char *dir) { - snprintf(out, 512, DATA_DIR "/%s/" DEVICE_FILE, dir); -} - -static int device_ini_handle(void *out, const char *section, const char *name, - const char *value) { - device_info_t *info = out; - - if (strcmp(name, "paired") == 0) { - info->paired = BOOL(value); - } else if (strcmp(name, "internal") == 0) { - strncpy(info->internal, value, 255); - } else if (strcmp(name, "external") == 0) { - strncpy(info->external, value, 255); - } else if (strcmp(name, "prefer_external") == 0) { - info->prefer_external = BOOL(value); - } - return 1; -} - -device_info_t* append_device(device_info_t *info) { - if (find_device(info->name)) { - vita_debug_log("append_device: device %s is already in the list\n", info->name); - return NULL; - } - // FIXME: need mutex - if (known_devices.size == 0) { - vita_debug_log("append_device: allocating memory for the initial device list...\n"); - known_devices.devices = malloc(sizeof(device_info_t) * 4); - if (known_devices.devices == NULL) { - vita_debug_log("append_device: failed to allocate memory for the initial device list\n"); - return NULL; - } - known_devices.size = 4; - } else if (known_devices.size == known_devices.count) { - vita_debug_log("append_device: the device list is full, resizing...\n"); - //if (known_devices.size == 64) { - // return false; - //} - size_t new_size = sizeof(device_info_t) * (known_devices.size * 2); - device_info_t *tmp = realloc(known_devices.devices, new_size); - if (tmp == NULL) { - vita_debug_log("append_device: failed to resize the device list\n"); - return NULL; - } - known_devices.devices = tmp; - known_devices.size *= 2; - } - device_info_t *p = &known_devices.devices[known_devices.count]; - - strncpy(p->name, info->name, 255); - p->paired = info->paired; - strncpy(p->internal, info->internal, 255); - strncpy(p->external, info->external, 255); - p->prefer_external = info->prefer_external; - vita_debug_log("append_device: device %s is added to the list\n", p->name); - - known_devices.count++; - return p; -} - -bool update_device(device_info_t *info) { - device_info_t *p = find_device(info->name); - if (p == NULL) { - return false; - } - - //strncpy(p->name, info->name, 255); - p->paired = info->paired; - strncpy(p->internal, info->internal, 255); - strncpy(p->external, info->external, 255); - p->prefer_external = info->prefer_external; - return true; -} - -void load_all_known_devices() { - struct stat st; - device_info_t info; - - SceUID dfd = sceIoDopen(DATA_DIR); - if (dfd < 0) { - return; - } - do { - SceIoDirent ent = {0}; - if (sceIoDread(dfd, &ent) <= 0) { - break; - } - if (strcmp(".", ent.d_name) == 0 || strcmp("..", ent.d_name) == 0) { - continue; - } - if (!SCE_S_ISDIR(ent.d_stat.st_mode)) { - continue; - } - - memset(&info, 0, sizeof(device_info_t)); - strncpy(info.name, ent.d_name, 255); - if (!load_device_info(&info)) { - continue; - } - append_device(&info); - } while(true); - - sceIoDclose(dfd); - return; -} - -bool load_device_info(device_info_t *info) { - char path[512] = {0}; - device_file_path(path, info->name); - vita_debug_log("load_device_info: reading %s\n", path); - - int ret = ini_parse(path, device_ini_handle, info); - if (!ret) { - vita_debug_log("load_device_info: device found:\n", ret); - vita_debug_log("load_device_info: info->name = %s\n", info->name); - vita_debug_log("load_device_info: info->paired = %s\n", info->paired ? "true" : "false"); - vita_debug_log("load_device_info: info->internal = %s\n", info->internal); - vita_debug_log("load_device_info: info->external = %s\n", info->external); - vita_debug_log("load_device_info: info->prefer_external = %s\n", info->prefer_external ? "true" : "false"); - return true; - } else { - vita_debug_log("load_device_info: ini_parse returned %d\n", ret); - return false; - } -} - -void save_device_info(const device_info_t *info) { - char path[512] = {0}; - device_file_path(path, info->name); - vita_debug_log("save_device_info: device file path: %s\n", path); - - FILE* fd = fopen(path, "w"); - if (!fd) { - // FIXME - vita_debug_log("save_device_info: cannot open device file\n"); - return; - } - - vita_debug_log("save_device_info: paired = %s\n", info->paired ? "true" : "false"); - write_bool(fd, "paired", info->paired); - - vita_debug_log("save_device_info: internal = %s\n", info->internal); - write_string(fd, "internal", info->internal); - - vita_debug_log("save_device_info: external = %s\n", info->external); - write_string(fd, "external", info->external); - - vita_debug_log("save_device_info: prefer_external = %s\n", info->prefer_external ? "true" : "false"); - write_bool(fd, "prefer_external", info->prefer_external); - - fclose(fd); - vita_debug_log("save_device_info: file closed\n"); -} +#include +#include +#include +#include +#include + +#include +#include + +#include "device.h" +#include "debug.h" +#include "ini.h" +#include "ini_file_processor_c.h" + +#define DATA_DIR "savedata0:" +#define DEVICE_FILE "device.ini" + +#define BOOL(v) sceClibStrcmp((v), "true") == 0 +#define write_bool(fd, key, value) fprintf(fd, "%s = %s\n", key, value ? "true" : "false"); +#define write_string(fd, key, value) fprintf(fd, "%s = %s\n", key, value) + +device_infos_t known_devices = {0}; + +device_info_t* find_device(const char *name) { + // TODO: mutex + for (int i = 0; i < known_devices.count; i++) { + if (!sceClibStrcmp(name, known_devices.devices[i].name)) { + return &known_devices.devices[i]; + } + } + return NULL; +} + +static void device_file_path(char *out, const char *dir) { + sceClibSnprintf(out, 512, DATA_DIR "/%s/" DEVICE_FILE, dir); +} + +device_info_t* append_device(device_info_t *info) { + if (find_device(info->name)) { + vita_debug_log("append_device: device %s is already in the list\n", info->name); + return NULL; + } + // FIXME: need mutex + if (known_devices.size == 0) { + vita_debug_log("append_device: allocating memory for the initial device list...\n"); + known_devices.devices = malloc(sizeof(device_info_t) * 4); + if (known_devices.devices == NULL) { + vita_debug_log("append_device: failed to allocate memory for the initial device list\n"); + return NULL; + } + known_devices.size = 4; + } else if (known_devices.size == known_devices.count) { + vita_debug_log("append_device: the device list is full, resizing...\n"); + //if (known_devices.size == 64) { + // return false; + //} + size_t new_size = sizeof(device_info_t) * (known_devices.size * 2); + device_info_t *tmp = realloc(known_devices.devices, new_size); + if (tmp == NULL) { + vita_debug_log("append_device: failed to resize the device list\n"); + return NULL; + } + known_devices.devices = tmp; + known_devices.size *= 2; + } + device_info_t *p = &known_devices.devices[known_devices.count]; + + sceClibStrncpy(p->name, info->name, 255); + p->paired = info->paired; + sceClibStrncpy(p->internal, info->internal, 255); + sceClibStrncpy(p->external, info->external, 255); + p->prefer_external = info->prefer_external; + vita_debug_log("append_device: device %s is added to the list\n", p->name); + + known_devices.count++; + return p; +} + +bool update_device(device_info_t *info) { + device_info_t *p = find_device(info->name); + if (p == NULL) { + return false; + } + + //sceClibStrncpy(p->name, info->name, 255); + p->paired = info->paired; + sceClibStrncpy(p->internal, info->internal, 255); + sceClibStrncpy(p->external, info->external, 255); + p->prefer_external = info->prefer_external; + return true; +} + +void load_all_known_devices() { + struct stat st; + device_info_t info; + + SceUID dfd = sceIoDopen(DATA_DIR); + if (dfd < 0) { + return; + } + do { + SceIoDirent ent = {0}; + if (sceIoDread(dfd, &ent) <= 0) { + break; + } + if (sceClibStrcmp(".", ent.d_name) == 0 || sceClibStrcmp("..", ent.d_name) == 0) { + continue; + } + if (!SCE_STM_ISDIR(ent.d_stat.st_mode)) { + continue; + } + + sceClibMemset(&info, 0, sizeof(device_info_t)); + sceClibStrncpy(info.name, ent.d_name, 255); + if (!load_device_info(&info)) { + continue; + } + append_device(&info); + } while(true); + + sceIoDclose(dfd); + return; +} + +bool load_device_info(device_info_t *info) { + char path[512] = {0}; + device_file_path(path, info->name); + vita_debug_log("load_device_info: reading %s\n", path); + + char iniProcContext[8]; + SceIniFileProcessorParam iniProcInitParam; + SceIniFileProcessorMemCallbacks iniAllocCb; + sceIniFileProcessorCreateContext(iniProcContext); + + sceIniFileProcessorInitializeParam(&iniProcInitParam); + sceIniFileProcessorCreateInstance(iniProcContext, &iniProcInitParam); + + int ret = sceIniFileProcessorOpenFile(iniProcContext, path, "r", 0); + if (ret < 0) { + sceIniFileProcessorDestroyInstanceForError(iniProcContext); + sceClibPrintf("sceIniFileProcessorOpenFile() returned 0x%X, %s\n", ret, path); + return false; + } + + int int_value; + char* string_value; + if (!iniGetValueByKey(iniProcContext, "paired", INI_VALUE_BOOL, 0, &int_value)) + info->paired = int_value; + iniGetStringByKey(iniProcContext, "internal", &string_value); + sceClibStrncpy(info->internal, string_value, 255); + free(string_value); + iniGetStringByKey(iniProcContext, "external", &string_value); + sceClibStrncpy(info->external, string_value, 255); + free(string_value); + if (!iniGetValueByKey(iniProcContext, "prefer_external", INI_VALUE_BOOL, 0, &int_value)) + info->prefer_external = int_value; + + vita_debug_log("load_device_info: device found:\n", ret); + vita_debug_log("load_device_info: info->name = %s\n", info->name); + vita_debug_log("load_device_info: info->paired = %s\n", info->paired ? "true" : "false"); + vita_debug_log("load_device_info: info->internal = %s\n", info->internal); + vita_debug_log("load_device_info: info->external = %s\n", info->external); + vita_debug_log("load_device_info: info->prefer_external = %s\n", info->prefer_external ? "true" : "false"); + + sceIniFileProcessorFinalize(iniProcContext); + + return true; +} + +void save_device_info(const device_info_t *info) { + + char path[512] = {0}; + device_file_path(path, info->name); + vita_debug_log("save_device_info: device file path: %s\n", path); + + char iniProcContext[8]; + SceIniFileProcessorParam iniProcInitParam; + SceIniFileProcessorMemCallbacks iniAllocCb; + sceIniFileProcessorCreateContext(iniProcContext); + + sceIniFileProcessorInitializeParam(&iniProcInitParam); + sceIniFileProcessorCreateInstance(iniProcContext, &iniProcInitParam); + + int ret = sceIniFileProcessorCreateFile(iniProcContext, path, "rw", 0); + if (ret < 0) { + sceIniFileProcessorDestroyInstanceForError(iniProcContext); + sceClibPrintf("sceIniFileProcessorCreateFile() returned 0x%X", ret); + return; + } + + vita_debug_log("save_device_info: paired = %s\n", info->paired ? "true" : "false"); + iniCreateSetKey(iniProcContext, "paired", INI_VALUE_BOOL, info->paired); + + vita_debug_log("save_device_info: internal = %s\n", info->internal); + sceIniFileProcessorAddKey(iniProcContext, "internal", info->internal); + + vita_debug_log("save_device_info: external = %s\n", info->external); + sceIniFileProcessorAddKey(iniProcContext, "external", info->external); + + vita_debug_log("save_device_info: prefer_external = %s\n", info->prefer_external ? "true" : "false"); + iniCreateSetKey(iniProcContext, "prefer_external", INI_VALUE_BOOL, info->prefer_external); + + sceIniFileProcessorFinalize(iniProcContext); + + vita_debug_log("save_device_info: file closed\n"); +} diff --git a/src/graphics.c b/src/graphics.c deleted file mode 100644 index 776eda751..000000000 --- a/src/graphics.c +++ /dev/null @@ -1,169 +0,0 @@ -#include -#include -#include - -#define SCE_DISPLAY_UPDATETIMING_NEXTVSYNC SCE_DISPLAY_SETBUF_NEXTFRAME -#include -#include -#include - -#include "graphics.h" - -enum { - SCREEN_WIDTH = 960, - SCREEN_HEIGHT = 544, - LINE_SIZE = 960, - FRAMEBUFFER_SIZE = 2 * 1024 * 1024, - FRAMEBUFFER_ALIGNMENT = 256 * 1024 -}; - -typedef union -{ - int rgba; - struct - { - char r; - char g; - char b; - char a; - } c; -} color_t; - -extern u8 msx[]; -void* g_vram_base; -static int gX = 0; -static int gY = 0; - -static Color g_fg_color; -static Color g_bg_color; - -static Color* getVramDisplayBuffer() -{ - Color* vram = (Color*) g_vram_base; - return vram; -} - -void *psvDebugScreenGetVram() { - return g_vram_base; -} - -int psvDebugScreenGetX() { - return gX; -} - -int psvDebugScreenGetY() { - return gY; -} - - // #define LOG(args...) vita_logf (__FILE__, __LINE__, args) ///< Write a log entry - -int g_log_mutex; - -void psvDebugScreenInit() { - g_log_mutex = sceKernelCreateMutex("log_mutex", 0, 0, NULL); - - SceKernelAllocMemBlockOpt opt = { 0 }; - opt.size = sizeof(opt); - opt.attr = 0x00000004; - opt.alignment = FRAMEBUFFER_ALIGNMENT; - SceUID displayblock = sceKernelAllocMemBlock("display", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, FRAMEBUFFER_SIZE, &opt); - void *base; - sceKernelGetMemBlockBase(displayblock, &base); - // LOG("base: 0x%08x", base); - - SceDisplayFrameBuf framebuf = { 0 }; - framebuf.size = sizeof(framebuf); - framebuf.base = base; - framebuf.pitch = SCREEN_WIDTH; - framebuf.pixelformat = SCE_DISPLAY_PIXELFORMAT_A8B8G8R8; - framebuf.width = SCREEN_WIDTH; - framebuf.height = SCREEN_HEIGHT; - - g_vram_base = base; - - int ret = sceDisplaySetFrameBuf(&framebuf, SCE_DISPLAY_UPDATETIMING_NEXTVSYNC); - - g_fg_color = 0xFFFFFFFF; - g_bg_color = 0x00000000; -} - -void psvDebugScreenClear(int bg_color) -{ - gX = gY = 0; - int i; - color_t *pixel = (color_t *)getVramDisplayBuffer(); - for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { - pixel->rgba = bg_color; - pixel++; - } -} - -static void printTextScreen(const char * text) -{ - int c, i, j, l; - u8 *font; - Color *vram_ptr; - Color *vram; - - int fontSize = 16; - float zoom = (float) fontSize / 8; - for (c = 0; c < strlen(text); c++) { - if (gX + fontSize > SCREEN_WIDTH) { - gY += fontSize; - gX = 0; - } - if (gY + fontSize > SCREEN_HEIGHT) { - gY = 0; - psvDebugScreenClear(g_bg_color); - } - char ch = text[c]; - if (ch == '\n') { - gX = 0; - gY += fontSize; - continue; - } else if (ch == '\r') { - gX = 0; - continue; - } - - vram = getVramDisplayBuffer() + gX + gY * LINE_SIZE; - - for (i = l = 0; i < fontSize; i++, l += fontSize) { - font = &msx[ (int)ch * 8] + (int) (i / zoom); - vram_ptr = vram; - for (j = 0; j < fontSize; j++) { - if ((*font & (128 >> (int) (j/zoom)))) *vram_ptr = g_fg_color; - else *vram_ptr = g_bg_color; - vram_ptr++; - } - vram += LINE_SIZE; - } - gX += fontSize; - } -} - -void psvDebugScreenPrintf(const char *format, ...) { - char buf[0x1000]; - - sceKernelLockMutex(g_log_mutex, 1, NULL); - - va_list opt; - va_start(opt, format); - vsnprintf(buf, sizeof(buf), format, opt); - printTextScreen(buf); - va_end(opt); - - sceKernelUnlockMutex(g_log_mutex, 1); -} - -Color psvDebugScreenSetFgColor(Color color) { - Color prev_color = g_fg_color; - g_fg_color = color; - return prev_color; -} - -Color psvDebugScreenSetBgColor(Color color) { - Color prev_color = g_bg_color; - g_bg_color = color; - return prev_color; -} diff --git a/src/graphics.h b/src/graphics.h deleted file mode 100644 index 6cb8efb99..000000000 --- a/src/graphics.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -typedef unsigned char u8; -typedef unsigned u32; -typedef u32 Color; - -// allocates memory for framebuffer and initializes it -void psvDebugScreenInit(); - -// clears screen with a given color -void psvDebugScreenClear(int bg_color); - -// printf to the screen -void psvDebugScreenPrintf(const char *format, ...); - -// set foreground (text) color -Color psvDebugScreenSetFgColor(Color color); - -// set background color -Color psvDebugScreenSetBgColor(Color color); - -void *psvDebugScreenGetVram(); -int psvDebugScreenGetX(); -int psvDebugScreenGetY(); - -enum { - COLOR_CYAN = 0xFFFFFF00, - COLOR_WHITE = 0xFFFFFFFF, - COLOR_BLACK = 0xFF000000, - COLOR_RED = 0xFF0000FF, - COLOR_YELLOW = 0xFF00FFFF, - COLOR_GREY = 0xFF808080, - COLOR_GREEN = 0xFF00FF00, -}; - -#define printf psvDebugScreenPrintf diff --git a/src/gui/guilib.c b/src/gui/guilib.c index ac3fb53e9..e11606fa5 100644 --- a/src/gui/guilib.c +++ b/src/gui/guilib.c @@ -1,510 +1,530 @@ -#include "guilib.h" - -#include "../config.h" -#include "../platform.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#define BUTTON_DELAY 150 * 1000 - -static gui_draw_callback gui_global_draw_callback; -static gui_loop_callback gui_global_loop_callback; - -vita2d_font *font; - -menu_geom make_geom_centered(int w, int h) { - menu_geom geom = {0}; - geom.x = WIDTH / 2 - w / 2; - geom.y = HEIGHT / 2 - h / 2; - geom.width = w; - geom.height = h; - geom.total_y = geom.y + geom.height; - geom.el = 24; - return geom; -} - -void draw_border(menu_geom geom, unsigned int border_color) { - vita2d_draw_line(geom.x, geom.y, geom.x+geom.width, geom.y, border_color); - vita2d_draw_line(geom.x, geom.y, geom.x, geom.y+geom.height, border_color); - vita2d_draw_line(geom.x+geom.width, geom.y, geom.x+geom.width, geom.y+geom.height, border_color); - vita2d_draw_line(geom.x, geom.y+geom.height, geom.x+geom.width, geom.y+geom.height, border_color); -} - -void draw_text_hcentered(int x, int y, unsigned int color, char *text) { - int width = vita2d_font_text_width(font, 18, text); - vita2d_font_draw_text(font, x - width / 2, y, color, 18, text); -} - -static int battery_percent; -static bool battery_charging; -static SceRtcTick battery_tick; - -void draw_statusbar(menu_geom geom) { - SceRtcTick current_tick; - sceRtcGetCurrentTick(¤t_tick); - if (current_tick.tick - battery_tick.tick > 10 * 1000 * 1000) { - battery_percent = scePowerGetBatteryLifePercent(); - battery_charging = scePowerIsBatteryCharging(); - - battery_tick = current_tick; - } - - SceDateTime time; - sceRtcGetCurrentClockLocalTime(&time); - - char dt_text[256]; - sprintf(dt_text, "%02d:%02d", time.hour, time.minute); - int dt_width = vita2d_font_text_width(font, 18, dt_text); - int battery_width = 30, - battery_height = 16, - battery_padding = 2, - battery_plus_height = 4, - battery_y_offset = 4, - battery_charge_width = (float) battery_percent / 100 * battery_width; - unsigned int battery_color = battery_charging ? 0xff99ffff : (battery_percent < 20 ? 0xff0000ff : 0xff00ff00); - - vita2d_font_draw_text(font, geom.x + geom.width - dt_width - battery_width - 5, geom.y - 5, 0xffffffff, 18, dt_text); - - vita2d_draw_rectangle( - geom.x + geom.width - battery_width, - geom.y - battery_height - battery_y_offset, - battery_width, - battery_height, - 0xffffffff); - - vita2d_draw_rectangle( - geom.x + geom.width - battery_width - battery_padding, - geom.y - battery_y_offset - ((float) battery_height / 2 + (float) battery_plus_height / 2), - battery_padding, - battery_plus_height, - 0xffffffff - ); - - vita2d_draw_rectangle( - geom.x + geom.width - battery_width + battery_padding, - geom.y - battery_height + battery_padding - battery_y_offset, - battery_width - battery_padding * 2, - battery_height - battery_padding * 2, - 0xff000000); - - vita2d_draw_rectangle( - geom.x + geom.width - battery_charge_width + battery_padding, - geom.y - battery_height + battery_padding - battery_y_offset, - battery_charge_width - battery_padding * 2, - battery_height - battery_padding * 2, - battery_color); -} - -SceTouchData touch_data; -SceCtrlData ctrl_new_pad; - -static SceRtcTick button_current_tick, button_until_tick; -bool was_button_pressed(short id) { - sceRtcGetCurrentTick(&button_current_tick); - - if (ctrl_new_pad.buttons & id) { - if (sceRtcCompareTick(&button_current_tick, &button_until_tick) > 0) { - sceRtcTickAddMicroseconds(&button_until_tick, &button_current_tick, BUTTON_DELAY); - return true; - } - } - - return false; -} - -bool is_button_down(short id) { - return ctrl_new_pad.buttons & id; -} - -#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10) -bool is_rectangle_touched(const SceTouchData *touch, int lx, int ly, int rx, int ry) { - for (int i = 0; i < touch->reportNum; i++) { - int x = lerp(touch->report[i].x, 1919, WIDTH); - int y = lerp(touch->report[i].y, 1087, HEIGHT); - if (x < lx || x > rx || y < ly || y > ry) continue; - return true; - } - - return false; -} - -void draw_menu(menu_entry menu[], int total_elements, menu_geom geom, int cursor, int offset) { - vita2d_draw_rectangle(geom.x, geom.y, geom.width, geom.height, 0x18fffff); - - long border_color = 0xff006000; - draw_border(geom, border_color); - draw_statusbar(geom); - - for (int i = 0, cursor_idx = 0; i < total_elements; i++) { - long color = 0xffffffff; - if (cursor == cursor_idx) { - color = 0xff00ff00; - } - - if (!menu[i].disabled) { - cursor_idx++; - } else { - color = 0xffaaaaaa; - } - - if (menu[i].color) { - color = menu[i].color; - } - - int el_x = geom.x + 10, - el_y = geom.y + i * geom.el - offset + 10; - - if (el_y < geom.y || el_y > geom.total_y - geom.el) - continue; - - int text_width, text_height; - vita2d_font_text_dimensions(font, 18, menu[i].name, &text_width, &text_height); - - if (menu[i].separator) { - int border = strlen(menu[i].name) ? 7 : 0; - int height = strlen(menu[i].name) ? text_height : geom.el / 2; - vita2d_draw_line( - el_x + text_width + border, - el_y + height, - el_x + geom.width - 10 * 2, - el_y + height, - 0xffaaaaaa - ); - } - - if (menu[i].name) { - vita2d_font_draw_text( - font, - el_x + 2, - el_y + text_height, - color, - 18, - menu[i].name - ); - } - - int right_x_offset = 20; - if (menu[i].suffix) { - int text_width = vita2d_font_text_width(font, 18, menu[i].suffix); - vita2d_font_draw_text( - font, - el_x + geom.width - text_width - right_x_offset, - el_y + text_height, - color, - 18, - menu[i].suffix - ); - - right_x_offset += text_width + 10; - } - - if (menu[i].subname) { - int text_width = vita2d_font_text_width(font, 18, menu[i].subname); - vita2d_font_draw_text( - font, - el_x + geom.width - text_width - right_x_offset, - el_y + text_height, - color, - 18, - menu[i].subname - ); - } - } -} - -void draw_alert(char *message, menu_geom geom, char *buttons_captions[], int buttons_count) { - vita2d_draw_rectangle(geom.x, geom.y, geom.width, geom.height, 0x18fffff); - - long border_color = 0xff006000; - draw_border(geom, border_color); - - char *buf = malloc(sizeof(char) * (strlen(message) + 1)); - int top_padding = 30; - int x_border = 10, y = top_padding; - for (int i = 0, idx = 0; i < strlen(message); i++) { - buf[idx] = message[i]; - buf[idx+1] = 0; - - if (message[i] == '\n' || vita2d_font_text_width(font, 18, buf) > geom.width - x_border*2) { - draw_text_hcentered(geom.x + geom.width / 2, y + geom.y, 0xffffffff, buf); - y += vita2d_font_text_height(font, 18, buf); - idx = 0; - } else { - idx++; - } - } - - if (strlen(buf)) { - if (y == top_padding) { - int text_height = vita2d_font_text_height(font, 18, buf); - y = geom.height / 2 - text_height / 2; - } - - draw_text_hcentered(geom.x + geom.width / 2, y + geom.y, 0xffffffff, buf); - } - - free(buf); - - char caption[256]; - strcpy(caption, ""); - - char *o_layout[4] = {"o", "x", "â–³", "â–¡"}; - char *x_layout[4] = {"x", "o", "â–³", "â–¡"}; - char **icons = config.jp_layout ? o_layout : x_layout; - char *default_captions[4] = {"Ok", "Cancel", "Options", "Delete"}; - for (int i = 0; i < buttons_count; i++) { - char single_button_caption[64]; - char button_caption[256]; - if (buttons_captions && buttons_captions[i]) { - strcpy(button_caption, buttons_captions[i]); - } else { - strcpy(button_caption, default_captions[i]); - } - - sprintf(single_button_caption, "%s %s ", icons[i], button_caption); - strcat(caption, single_button_caption); - } - - int caption_width = vita2d_font_text_width(font, 18, caption); - vita2d_font_draw_text(font, geom.x + geom.width - caption_width, geom.total_y - 10, 0xffffffff, 18, caption); -} - -void ui_start() { - vita2d_start_drawing(); - vita2d_clear_screen(); -} - -void ui_end() { - vita2d_end_drawing(); - vita2d_wait_rendering_done(); - vita2d_swap_buffers(); -} - -int read_buttons() { - SceCtrlData pad = {0}; - static int old; - static int hold_times; - int curr, btn; - - sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG_WIDE); - sceCtrlPeekBufferPositive(0, &pad, 1); - - if (pad.ly < 0x10) { - pad.buttons |= SCE_CTRL_UP; - } else if (pad.ly > 0xef) { - pad.buttons |= SCE_CTRL_DOWN; - } - curr = pad.buttons; - btn = pad.buttons & ~old; - if (curr && old == curr) { - hold_times += 1; - if (hold_times >= 10) { - btn = curr; - hold_times = 8; - btn |= SCE_CTRL_HOLD; - } - } else { - hold_times = 0; - old = curr; - } - return btn; -} - -int display_menu(menu_entry menu[], int total_elements, menu_geom *geom_ptr, - gui_loop_callback cb, gui_back_callback back_cb, - gui_draw_callback draw_callback, - void *context) { - ui_end(); - - int offset = 0; - int cursor = 0; - - menu_geom geom; - - if (!geom_ptr) { - geom = make_geom_centered(600, 400); - geom.el = 24; - } else { - geom = *geom_ptr; - } - - int tick_number = 0; - int exit_code = 0; - - while (true) { - int active_elements = 0; - for (int i = 0; i < total_elements; i++) { - active_elements += menu[i].disabled ? 0 : 1; - } - - ui_start(); - tick_number++; - - if (tick_number > 3) { - if (draw_callback) { - draw_callback(); - } - if (gui_global_draw_callback) { - gui_global_draw_callback(); - } - } - - draw_menu(menu, total_elements, geom, cursor, offset); - - int real_cursor = 0; - - for (int c = 0; real_cursor < total_elements; real_cursor++) { - if (menu[real_cursor].disabled) { - continue; - } - if (cursor == c) { - break; - } - c++; - } - - // select item - input_data input = {0}; - input.buttons = read_buttons(); - sceTouchPeek(SCE_TOUCH_PORT_FRONT, &input.touch, 1); - if (input.buttons & SCE_CTRL_DOWN) { - cursor += 1; - } - if (input.buttons & SCE_CTRL_UP) { - cursor -= 1; - } - cursor = cursor < 0 ? 0 : cursor; - cursor = cursor > active_elements - 1 ? active_elements - 1 : cursor; - - int cursor_y = geom.y + ((cursor == 0 ? 0 : real_cursor) * geom.el) - offset; - offset -= cursor_y < geom.y ? 8 : 0; - offset -= cursor_y > geom.total_y - geom.el * 2 ? -8 : 0; - - if (cb) { - exit_code = cb(menu[real_cursor].id, context, &input); - if (exit_code) { - goto error; - } - } - - if (gui_global_loop_callback) { - gui_global_loop_callback(menu[real_cursor].id, context, &input); - } - - if (input.buttons & config.btn_cancel && (input.buttons & SCE_CTRL_HOLD) == 0) { - if (!back_cb || back_cb(context) == 0) { - exit_code = 1; - goto error; - } - } - - ui_end(); - } - - return 0; - -error: - ui_end(); - return exit_code; -} - - -void display_alert(char *message, char *button_captions[], int buttons_count, - gui_loop_callback cb, void *context) { - - menu_geom alert_geom = make_geom_centered(400, 200); - - while (true) { - ui_start(); - - draw_alert(message, alert_geom, button_captions, buttons_count); - - input_data input = {0}; - input.buttons = read_buttons(); - sceTouchPeek(SCE_TOUCH_PORT_FRONT, &input.touch, 1); - - int result = -1; - - if (input.buttons & SCE_CTRL_HOLD) { - ui_end(); - continue; - } - - if (input.buttons & config.btn_confirm) { - result = 0; - } else if (input.buttons & config.btn_cancel) { - result = 1; - } else if (input.buttons & SCE_CTRL_TRIANGLE) { - result = 2; - } else if (input.buttons & SCE_CTRL_SQUARE) { - result = 3; - } - - if (cb && result != -1 && result < buttons_count) { - switch(cb(result, context, &input)) { - case 1: - return; - } - } else if (result == 0) { - return; - } - - ui_end(); - } -} - -void display_error(char *format, ...) { - char buf[0x1000]; - - va_list opt; - va_start(opt, format); - vsnprintf(buf, sizeof(buf), format, opt); - display_alert(buf, NULL, 1, NULL, NULL); - va_end(opt); -} - -void flash_message(char *format, ...) { - char buf[0x1000]; - - va_list opt; - va_start(opt, format); - vsnprintf(buf, sizeof(buf), format, opt); - va_end(opt); - - ui_end(); - - menu_geom alert_geom = make_geom_centered(400, 200); - ui_start(); - - vita2d_draw_rectangle(0, 0, WIDTH, HEIGHT, 0xff000000); - draw_alert(buf, alert_geom, NULL, 0); - - ui_end(); -} - -void drw() { - vita2d_draw_rectangle(0, 0, 150, 150, 0xffffffff); -} - -void guilib_init(gui_loop_callback global_loop_cb, gui_draw_callback global_draw_cb) { - vita2d_init(); - vita2d_set_clear_color(0xff000000); - font = vita2d_load_font_file("app0:assets/nerdfont.ttf"); - - gui_global_draw_callback = global_draw_cb; - gui_global_loop_callback = global_loop_cb; -} +#include "guilib.h" + +#include "../config.h" +#include "../platform.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#define BUTTON_DELAY 150 * 1000 + +extern SceUID state_evf; + +extern int SCREEN_WIDTH; +extern int SCREEN_HEIGHT; +extern int LINE_SIZE; + +static gui_draw_callback gui_global_draw_callback; +static gui_loop_callback gui_global_loop_callback; + +static char cdlg_buf[0x1000]; + +vita2d_pvf *font; + +menu_geom make_geom_centered(int w, int h) { + menu_geom geom = {0}; + geom.x = SCREEN_WIDTH / 2 - w / 2; + geom.y = SCREEN_HEIGHT / 2 - h / 2; + geom.width = w; + geom.height = h; + geom.total_y = geom.y + geom.height; + geom.el = 24; + return geom; +} + +void draw_border(menu_geom geom, unsigned int border_color) { + vita2d_draw_line(geom.x, geom.y, geom.x+geom.width, geom.y, border_color); + vita2d_draw_line(geom.x, geom.y, geom.x, geom.y+geom.height, border_color); + vita2d_draw_line(geom.x+geom.width, geom.y, geom.x+geom.width, geom.y+geom.height, border_color); + vita2d_draw_line(geom.x, geom.y+geom.height, geom.x+geom.width, geom.y+geom.height, border_color); +} + +void draw_text_hcentered(int x, int y, unsigned int color, char *text) { + int width = vita2d_pvf_text_width(font, 1.0f, text); + vita2d_pvf_draw_text(font, x - width / 2, y, color, 1.0f, text); +} + +static int battery_percent; +static bool battery_charging; +static SceRtcTick battery_tick; + +void draw_statusbar(menu_geom geom) { + SceRtcTick current_tick; + sceRtcGetCurrentTick(¤t_tick); + if (current_tick.tick - battery_tick.tick > 10 * 1000 * 1000) { + battery_percent = scePowerGetBatteryLifePercent(); + battery_charging = scePowerIsBatteryCharging(); + + battery_tick = current_tick; + } + + SceDateTime time; + sceRtcGetCurrentClockLocalTime(&time); + + char dt_text[256]; + sprintf(dt_text, "%02d:%02d", time.hour, time.minute); + int dt_width = vita2d_pvf_text_width(font, 1.0f, dt_text); + int battery_width = 30, + battery_height = 16, + battery_padding = 2, + battery_plus_height = 4, + battery_y_offset = 4, + battery_charge_width = (float) battery_percent / 100 * battery_width; + unsigned int battery_color = battery_charging ? 0xff99ffff : (battery_percent < 20 ? 0xff0000ff : 0xff00ff00); + + vita2d_pvf_draw_text(font, geom.x + geom.width - dt_width - battery_width - 5, geom.y - 5, 0xffffffff, 1.0f, dt_text); + + vita2d_draw_rectangle( + geom.x + geom.width - battery_width, + geom.y - battery_height - battery_y_offset, + battery_width, + battery_height, + 0xffffffff); + + vita2d_draw_rectangle( + geom.x + geom.width - battery_width - battery_padding, + geom.y - battery_y_offset - ((float) battery_height / 2 + (float) battery_plus_height / 2), + battery_padding, + battery_plus_height, + 0xffffffff + ); + + vita2d_draw_rectangle( + geom.x + geom.width - battery_width + battery_padding, + geom.y - battery_height + battery_padding - battery_y_offset, + battery_width - battery_padding * 2, + battery_height - battery_padding * 2, + 0xff000000); + + vita2d_draw_rectangle( + geom.x + geom.width - battery_charge_width + battery_padding, + geom.y - battery_height + battery_padding - battery_y_offset, + battery_charge_width - battery_padding * 2, + battery_height - battery_padding * 2, + battery_color); +} + +SceTouchData touch_data; +SceCtrlData ctrl_new_pad; + +static SceRtcTick button_current_tick, button_until_tick; +bool was_button_pressed(short id) { + sceRtcGetCurrentTick(&button_current_tick); + + if (ctrl_new_pad.buttons & id) { + if (sceRtcCompareTick(&button_current_tick, &button_until_tick) > 0) { + sceRtcTickAddMicroseconds(&button_until_tick, &button_current_tick, BUTTON_DELAY); + return true; + } + } + + return false; +} + +bool is_button_down(short id) { + return ctrl_new_pad.buttons & id; +} + +#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10) +bool is_rectangle_touched(const SceTouchData *touch, int lx, int ly, int rx, int ry) { + for (int i = 0; i < touch->reportNum; i++) { + int x = lerp(touch->report[i].x, 1919, WIDTH); + int y = lerp(touch->report[i].y, 1087, HEIGHT); + if (x < lx || x > rx || y < ly || y > ry) continue; + return true; + } + + return false; +} + +void draw_menu(menu_entry menu[], int total_elements, menu_geom geom, int cursor, int offset) { + vita2d_draw_rectangle(geom.x, geom.y, geom.width, geom.height, 0x18fffff); + + long border_color = 0xff006000; + draw_border(geom, border_color); + draw_statusbar(geom); + + for (int i = 0, cursor_idx = 0; i < total_elements; i++) { + long color = 0xffffffff; + if (cursor == cursor_idx) { + color = 0xff00ff00; + } + + if (!menu[i].disabled) { + cursor_idx++; + } else { + color = 0xffaaaaaa; + } + + if (menu[i].color) { + color = menu[i].color; + } + + int el_x = geom.x + 10, + el_y = geom.y + i * geom.el - offset + 10; + + if (el_y < geom.y || el_y > geom.total_y - geom.el) + continue; + + int text_width, text_height; + vita2d_pvf_text_dimensions(font, 1.0f, menu[i].name, &text_width, &text_height); + + if (menu[i].separator) { + int border = strlen(menu[i].name) ? 7 : 0; + int height = strlen(menu[i].name) ? text_height : geom.el / 2; + vita2d_draw_line( + el_x + text_width + border, + el_y + height, + el_x + geom.width - 10 * 2, + el_y + height, + 0xffaaaaaa + ); + } + + if (menu[i].name) { + vita2d_pvf_draw_text( + font, + el_x + 2, + el_y + text_height, + color, + 1.0f, + menu[i].name + ); + } + + int right_x_offset = 20; + if (menu[i].suffix) { + int text_width = vita2d_pvf_text_width(font, 1.0f, menu[i].suffix); + vita2d_pvf_draw_text( + font, + el_x + geom.width - text_width - right_x_offset, + el_y + text_height, + color, + 1.0f, + menu[i].suffix + ); + + right_x_offset += text_width + 10; + } + + if (menu[i].subname) { + int text_width = vita2d_pvf_text_width(font, 1.0f, menu[i].subname); + vita2d_pvf_draw_text( + font, + el_x + geom.width - text_width - right_x_offset, + el_y + text_height, + color, + 1.0f, + menu[i].subname + ); + } + } +} + +void draw_alert(char *message, menu_geom geom, char *buttons_captions[], int buttons_count) { + vita2d_draw_rectangle(geom.x, geom.y, geom.width, geom.height, 0x18fffff); + + long border_color = 0xff006000; + draw_border(geom, border_color); + + char *buf = malloc(sizeof(char) * (sceClibStrnlen(message, 1024) + 1)); + int top_padding = 30; + int x_border = 10, y = top_padding; + for (int i = 0, idx = 0; i < sceClibStrnlen(message, 1024); i++) { + buf[idx] = message[i]; + buf[idx+1] = 0; + + if (message[i] == '\n' || vita2d_pvf_text_width(font, 1.0f, buf) > geom.width - x_border*2) { + draw_text_hcentered(geom.x + geom.width / 2, y + geom.y, 0xffffffff, buf); + y += vita2d_pvf_text_height(font, 1.0f, buf); + idx = 0; + } else { + idx++; + } + } + + if (sceClibStrnlen(buf, 1024)) { + if (y == top_padding) { + int text_height = vita2d_pvf_text_height(font, 1.0f, buf); + y = geom.height / 2 - text_height / 2; + } + + draw_text_hcentered(geom.x + geom.width / 2, y + geom.y, 0xffffffff, buf); + } + + free(buf); + + char caption[256]; + sceClibMemset(caption, 0, 256); + + char *o_layout[4] = {"o", "x", "â–³", "â–¡"}; + char *x_layout[4] = {"x", "o", "â–³", "â–¡"}; + char **icons = config.jp_layout ? o_layout : x_layout; + char *default_captions[4] = {"Ok", "Cancel", "Options", "Delete"}; + for (int i = 0; i < buttons_count; i++) { + char single_button_caption[64]; + char button_caption[256]; + if (buttons_captions && buttons_captions[i]) { + sceClibStrncpy(button_caption, buttons_captions[i], 256); + } else { + sceClibStrncpy(button_caption, default_captions[i], 256); + } + + sceClibSnprintf(single_button_caption, 64, "%s %s ", icons[i], button_caption); + sceClibStrncat(caption, single_button_caption, 64); + } + + int caption_width = vita2d_pvf_text_width(font, 1.0f, caption); + vita2d_pvf_draw_text(font, geom.x + geom.width - caption_width, geom.total_y - 10, 0xffffffff, 1.0f, caption); +} + +void ui_start() { + sceKernelWaitEventFlag(state_evf, FLAG_MOONLIGHT_IS_FG, SCE_KERNEL_EVF_WAITMODE_AND, NULL, NULL); + vita2d_start_drawing(); + vita2d_clear_screen(); +} + +void ui_end() { + vita2d_end_drawing(); + vita2d_wait_rendering_done(); + vita2d_end_shfb(); +} + +int read_buttons() { + SceCtrlData pad = {0}; + static int old; + static int hold_times; + int curr, btn; + + sceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG_WIDE); + sceCtrlPeekBufferPositive(0, &pad, 1); + + if (pad.ly < 0x10) { + pad.buttons |= SCE_CTRL_UP; + } else if (pad.ly > 0xef) { + pad.buttons |= SCE_CTRL_DOWN; + } + curr = pad.buttons; + btn = pad.buttons & ~old; + if (curr && old == curr) { + hold_times += 1; + if (hold_times >= 10) { + btn = curr; + hold_times = 8; + btn |= SCE_CTRL_HOLD; + } + } else { + hold_times = 0; + old = curr; + } + return btn; +} + +int display_menu(menu_entry menu[], int total_elements, menu_geom *geom_ptr, + gui_loop_callback cb, gui_back_callback back_cb, + gui_draw_callback draw_callback, + void *context) { + ui_end(); + + int offset = 0; + int cursor = 0; + + menu_geom geom; + + if (!geom_ptr) { + geom = make_geom_centered(600, 400); + geom.el = 24; + } else { + geom = *geom_ptr; + } + + int tick_number = 0; + int exit_code = 0; + + while (true) { + int active_elements = 0; + for (int i = 0; i < total_elements; i++) { + active_elements += menu[i].disabled ? 0 : 1; + } + + ui_start(); + tick_number++; + + if (tick_number > 3) { + if (draw_callback) { + draw_callback(); + } + if (gui_global_draw_callback) { + gui_global_draw_callback(); + } + } + + draw_menu(menu, total_elements, geom, cursor, offset); + + int real_cursor = 0; + + for (int c = 0; real_cursor < total_elements; real_cursor++) { + if (menu[real_cursor].disabled) { + continue; + } + if (cursor == c) { + break; + } + c++; + } + + // select item + input_data input = {0}; + input.buttons = read_buttons(); + sceTouchPeek(SCE_TOUCH_PORT_FRONT, &input.touch, 1); + if (input.buttons & SCE_CTRL_DOWN) { + cursor += 1; + } + if (input.buttons & SCE_CTRL_UP) { + cursor -= 1; + } + cursor = cursor < 0 ? 0 : cursor; + cursor = cursor > active_elements - 1 ? active_elements - 1 : cursor; + + int cursor_y = geom.y + ((cursor == 0 ? 0 : real_cursor) * geom.el) - offset; + offset -= cursor_y < geom.y ? 8 : 0; + offset -= cursor_y > geom.total_y - geom.el * 2 ? -8 : 0; + + if (cb) { + exit_code = cb(menu[real_cursor].id, context, &input); + if (exit_code) { + goto error; + } + } + + if (gui_global_loop_callback) { + gui_global_loop_callback(menu[real_cursor].id, context, &input); + } + + if (input.buttons & config.btn_cancel && (input.buttons & SCE_CTRL_HOLD) == 0) { + if (!back_cb || back_cb(context) == 0) { + exit_code = 1; + goto error; + } + } + + ui_end(); + } + + return 0; + +error: + + ui_end(); + return exit_code; +} + +void display_alert(char *message, char *button_captions[], int buttons_count, + gui_loop_callback cb, void *context) { + + menu_geom alert_geom = make_geom_centered(400, 200); + + while (true) { + ui_start(); + + draw_alert(message, alert_geom, button_captions, buttons_count); + + input_data input = { 0 }; + input.buttons = read_buttons(); + sceTouchPeek(SCE_TOUCH_PORT_FRONT, &input.touch, 1); + + int result = -1; + + if (input.buttons & SCE_CTRL_HOLD) { + ui_end(); + continue; + } + + if (input.buttons & config.btn_confirm) { + result = 0; + } + else if (input.buttons & config.btn_cancel) { + result = 1; + } + else if (input.buttons & SCE_CTRL_TRIANGLE) { + result = 2; + } + else if (input.buttons & SCE_CTRL_SQUARE) { + result = 3; + } + + if (cb && result != -1 && result < buttons_count) { + switch (cb(result, context, &input)) { + case 1: + return; + } + } + else if (result == 0) { + return; + } + + ui_end(); + } +} + +void display_error(char *format, ...) { + char buf[0x1000]; + + va_list opt; + va_start(opt, format); + sceClibVsnprintf(buf, sizeof(buf), format, opt); + display_alert(buf, NULL, 1, NULL, NULL); + va_end(opt); +} + +void flash_message(char *format, ...) { + char buf[0x1000]; + + va_list opt; + va_start(opt, format); + sceClibVsnprintf(buf, sizeof(buf), format, opt); + va_end(opt); + + ui_end(); + + menu_geom alert_geom = make_geom_centered(400, 200); + ui_start(); + + vita2d_draw_rectangle(0, 0, WIDTH, HEIGHT, 0xff000000); + draw_alert(buf, alert_geom, NULL, 0); + + ui_end(); +} + +void drw() { + vita2d_draw_rectangle(0, 0, 150, 150, 0xffffffff); +} + +void guilib_init(gui_loop_callback global_loop_cb, gui_draw_callback global_draw_cb) { + vita2d_display_set_resolution(SCREEN_WIDTH, SCREEN_HEIGHT); + vita2d_set_vblank_wait(true); + vita2d_init(); + vita2d_set_clear_color(0xff000000); + font = vita2d_load_custom_pvf("app0:assets/nerdfont.ttf", 12.0f, 12.0f); + + gui_global_draw_callback = global_draw_cb; + gui_global_loop_callback = global_loop_cb; +} diff --git a/src/gui/guilib.h b/src/gui/guilib.h index a720d0d6a..dcd4265d0 100644 --- a/src/gui/guilib.h +++ b/src/gui/guilib.h @@ -1,5 +1,5 @@ #include -#include +#include #include @@ -23,7 +23,7 @@ typedef struct menu_geom { int x, y, width, height, el, total_y; } menu_geom; -extern vita2d_font *font; +extern vita2d_pvf *font; struct menu_geom make_geom_centered(int w, int h); diff --git a/src/gui/ime.c b/src/gui/ime.c index f14190acc..fe077d40e 100644 --- a/src/gui/ime.c +++ b/src/gui/ime.c @@ -1,6 +1,8 @@ #include #include +#include "../platform.h" + #include #include #include @@ -10,16 +12,14 @@ #include #include -#include - -#define SCE_IME_DIALOG_MAX_TITLE_LENGTH (128) -#define SCE_IME_DIALOG_MAX_TEXT_LENGTH (512) +#include #define IME_DIALOG_RESULT_NONE 0 #define IME_DIALOG_RESULT_RUNNING 1 #define IME_DIALOG_RESULT_FINISHED 2 #define IME_DIALOG_RESULT_CANCELED 3 +extern SceUID state_evf; static uint16_t ime_title_utf16[SCE_IME_DIALOG_MAX_TITLE_LENGTH]; static uint16_t ime_initial_text_utf16[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; @@ -68,7 +68,7 @@ void utf8_to_utf16(const uint8_t *src, uint16_t *dst) { *dst = '\0'; } -void initImeDialog(SceImeType type, const char *title, char *initial_text, int max_text_length) { +void initImeDialog(int type, const char *title, char *initial_text, int max_text_length) { // Convert UTF8 to UTF16 utf8_to_utf16((const uint8_t *)title, ime_title_utf16); utf8_to_utf16((const uint8_t *)initial_text, ime_initial_text_utf16); @@ -76,7 +76,7 @@ void initImeDialog(SceImeType type, const char *title, char *initial_text, int m SceImeDialogParam param; sceImeDialogParamInit(¶m); - param.sdkVersion = 0x03150021; + param.sdkVersion = SCE_PSP2_SDK_VERSION; param.supportedLanguages = 0x0001FFFF; param.languagesForced = SCE_TRUE; param.type = type; @@ -85,7 +85,6 @@ void initImeDialog(SceImeType type, const char *title, char *initial_text, int m param.initialText = ime_initial_text_utf16; param.inputTextBuffer = ime_input_text_utf16; - //int res = sceImeDialogInit(¶m); return ; } @@ -97,9 +96,7 @@ void oslOskGetText(char *text){ } -int ime_dialog_type(SceImeType type, char *text, const char *title, const char *def) { - sceCommonDialogSetConfigParam(&(SceCommonDialogConfigParam){}); - +int ime_dialog_type(int type, char *text, const char *title, const char *def) { char userText[512]; if (def) { strcpy(userText, def); @@ -109,13 +106,16 @@ int ime_dialog_type(SceImeType type, char *text, const char *title, const char * initImeDialog(type, title, userText, 128); while (1) { + + sceKernelWaitEventFlag(state_evf, FLAG_MOONLIGHT_IS_FG, SCE_KERNEL_EVF_WAITMODE_AND, NULL, NULL); + vita2d_start_drawing(); vita2d_clear_screen(); SceCommonDialogStatus status = sceImeDialogGetStatus(); if (status == IME_DIALOG_RESULT_FINISHED) { SceImeDialogResult result; - memset(&result, 0, sizeof(SceImeDialogResult)); + sceClibMemset(&result, 0, sizeof(SceImeDialogResult)); sceImeDialogGetResult(&result); if (result.button == SCE_IME_DIALOG_BUTTON_CLOSE) { @@ -132,8 +132,8 @@ int ime_dialog_type(SceImeType type, char *text, const char *title, const char * vita2d_end_drawing(); vita2d_common_dialog_update(); - vita2d_swap_buffers(); - sceDisplayWaitVblankStart(); + vita2d_wait_rendering_done(); + vita2d_end_shfb(); } sceImeDialogTerm(); diff --git a/src/gui/ime.h b/src/gui/ime.h index e875f80ce..7c3d3b9e5 100644 --- a/src/gui/ime.h +++ b/src/gui/ime.h @@ -1,3 +1,4 @@ int ime_dialog_string(char *text, const char *title, const char *def); int ime_dialog_number(char *text, const char *title, const char *def); +void utf16_to_utf8(uint16_t *src, uint8_t *dst); diff --git a/src/gui/ui.c b/src/gui/ui.c index 8850a14c6..5bf364338 100644 --- a/src/gui/ui.c +++ b/src/gui/ui.c @@ -10,6 +10,7 @@ #include "../config.h" #include "../device.h" #include "../connection.h" +#include "../configuration.h" #include "../video/vita.h" #include "../input/vita.h" #include "../power/vita.h" @@ -22,6 +23,7 @@ #include #include +#include #include #include @@ -61,7 +63,7 @@ int ui_main_menu_loop(int cursor, void *context, const input_data *input) { if (connection_get_status() != LI_DISCONNECTED) { connection_terminate(); } - exit(0); + vitapower_termninate(); return 0; } } @@ -92,7 +94,7 @@ int ui_main_menu() { } while(0) char program_info[256]; - snprintf(program_info, 256, "Moonlight v%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); + sceClibSnprintf(program_info, 256, "Moonlight v%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); MENU_TITLE(program_info); char name[256] = {0}; diff --git a/src/gui/ui_connect.c b/src/gui/ui_connect.c index ec8e11658..90e826302 100644 --- a/src/gui/ui_connect.c +++ b/src/gui/ui_connect.c @@ -28,10 +28,11 @@ #include #include +#include #include #include -#include -#include +#include +#include SERVER_DATA server; PAPP_LIST server_applist; @@ -39,7 +40,7 @@ int pos[2]; int get_app_id(PAPP_LIST list, char *name) { while (list != NULL) { - if (strcmp(list->name, name) == 0) + if (sceClibStrcmp(list->name, name) == 0) return list->id; list = list->next; @@ -65,11 +66,11 @@ void ui_connect_stream(int appId) { int ret = gs_start_app(&server, &config.stream, appId, config.sops, config.localaudio, 1); if (ret < 0) { if (ret == GS_NOT_SUPPORTED_4K) - display_error("Server doesn't support 4K\n"); + display_error("Server doesn't support 4K\n"); else if (ret == GS_NOT_SUPPORTED_MODE) - display_error("Server doesn't support %dx%d (%d fps)\n", config.stream.width, config.stream.height, config.stream.fps); + display_error("Server doesn't support %dx%d (%d fps)\n", config.stream.width, config.stream.height, config.stream.fps); else - display_error("Errorcode starting app: %d\n", ret); + display_error("Errorcode starting app: %d\n", ret); return; } @@ -108,7 +109,7 @@ void ui_connect_stream(int appId) { case STAGE_INPUT_STREAM_START: stage = "Input stream start"; break; } - display_error("Failed to start stream: error code %d\nFailed stage: %s\n(error code %d)", + display_error("Failed to start stream: error code %d\nFailed stage: %s\n(error code %d)", ret, stage, connection_failed_stage_code); return; } @@ -143,16 +144,16 @@ int ui_connect_loop(int id, void *context, const input_data *input) { switch (id) { case CONNECT_PAIRUNPAIR: if (server.paired) { - flash_message("Unpairing..."); + flash_message("Unpairing..."); ret = gs_unpair(&server); if (ret == GS_OK) { if (connection_terminate()) { - display_error("Reconnect failed: %d", -1); + display_error("Reconnect failed: %d", -1); return 0; } return QUIT_RELOAD; } - display_error("Unpairing failed: %d", ret); + display_error("Unpairing failed: %d", ret); return 0; } @@ -160,32 +161,32 @@ int ui_connect_loop(int id, void *context, const input_data *input) { char message[256]; sprintf(pin, "%d%d%d%d", (int)rand() % 10, (int)rand() % 10, (int)rand() % 10, (int)rand() % 10); - flash_message("Please enter the following PIN\non the target PC:\n\n%s", pin); + flash_message("Please enter the following PIN\non the target PC:\n\n%s", pin); ret = gs_pair(&server, &pin[0]); if (ret == 0) { connection_paired(); if (connection_terminate()) { - display_error("Reconnect failed: %d", -2); + display_error("Reconnect failed: %d", -2); return 0; } return QUIT_RELOAD; } - display_error("Pairing failed: %d", ret); + display_error("Pairing failed: %d", ret); return 0; case CONNECT_DISCONNECT: goto disconnect; case CONNECT_QUITAPP: - flash_message("Quitting..."); + flash_message("Quitting..."); ret = gs_quit_app(&server); if (ret == GS_OK) { connection_paired(); server.currentGame = 0; return QUIT_RELOAD; } - display_error("Quitting failed: %d", ret); + display_error("Quitting failed: %d", ret); return 0; // application launcher / resume @@ -202,7 +203,7 @@ int ui_connect_loop(int id, void *context, const input_data *input) { } // TODO: stop previous stream case LI_PAIRED: - flash_message("Stream starting..."); + flash_message("Stream starting..."); ui_connect_stream(id); break; } @@ -222,7 +223,7 @@ int ui_connect_loop(int id, void *context, const input_data *input) { } disconnect: - flash_message("Disconnecting..."); + flash_message("Disconnecting..."); connection_terminate(); sceKernelDelayThread(1000 * 1000); return 1; @@ -231,33 +232,33 @@ int ui_connect_loop(int id, void *context, const input_data *input) { int ui_connect(char *name, char *address) { int ret; if (!connection_is_ready()) { - flash_message("Connecting to:\n %s...", address); + flash_message("Connecting to:\n %s...", address); char key_dir[4096]; sprintf(key_dir, "%s/%s", config.key_dir, name); - ret = gs_init(&server, address, key_dir, 0, true); if (ret == GS_OUT_OF_MEMORY) { - display_error("Not enough memory"); + display_error("Not enough memory"); return 0; } else if (ret == GS_INVALID) { - display_error("Invalid data received from server: %s\n", address, gs_error); + display_error("Invalid data received from server: %s\n", address, gs_error); return 0; } else if (ret == GS_UNSUPPORTED_VERSION) { if (!config.unsupported_version) { - display_error("Unsupported version: %s\n", gs_error); + display_error("Unsupported version: %s\n", gs_error); return 0; } } else if (ret == GS_ERROR) { - display_error("Gamestream error: %s\n", gs_error); + display_error("Gamestream error: %s\n", gs_error); return 0; } else if (ret != GS_OK) { - display_error("Can't connect to server\n%s", address); + display_error("Can't connect to server\n%s", address); return 0; } connection_reset(); } + return 1; } @@ -267,7 +268,7 @@ int ui_connected_menu() { if (server.paired) { ret = gs_applist(&server, &server_applist); if (ret != GS_OK) { - display_error("Can't get applist!\n%d\n%s", ret, gs_error); + display_error("Can't get applist!\n%d\n%s", ret, gs_error); return 0; } @@ -306,7 +307,7 @@ int ui_connected_menu() { //MENU MENU_MESSAGE("Connected to the server:", 0xffffffff); char server_info[256]; - snprintf(server_info, 256, + sceClibSnprintf(server_info, 256, "IP: %s, GPU %s, GFE %s", server.serverInfo.address, server.gpuType, @@ -367,7 +368,7 @@ int ui_connected_menu() { } device_info_t* ui_connect_and_pairing(device_info_t *info) { - flash_message("Test connecting to:\n %s...", info->internal); + flash_message("Test connecting to:\n %s...", info->internal); char key_dir[4096]; sprintf(key_dir, "%s/%s", config.key_dir, info->name); sceIoMkdir(key_dir, 0777); @@ -375,21 +376,21 @@ device_info_t* ui_connect_and_pairing(device_info_t *info) { int ret = gs_init(&server, info->internal, key_dir, 0, true); if (ret == GS_OUT_OF_MEMORY) { - display_error("Not enough memory"); + display_error("Not enough memory"); return NULL; } else if (ret == GS_INVALID) { - display_error("Invalid data received from server: %s\n", info->internal, gs_error); + display_error("Invalid data received from server: %s\n", info->internal, gs_error); return NULL; } else if (ret == GS_UNSUPPORTED_VERSION) { if (!config.unsupported_version) { - display_error("Unsupported version: %s\n", gs_error); + display_error("Unsupported version: %s\n", gs_error); return NULL; } } else if (ret == GS_ERROR) { - display_error("Gamestream error: %s\n", gs_error); + display_error("Gamestream error: %s\n", gs_error); return NULL; } else if (ret != GS_OK) { - display_error("Can't connect to server\n%s", info->internal); + display_error("Can't connect to server\n%s", info->internal); return NULL; } @@ -397,7 +398,7 @@ device_info_t* ui_connect_and_pairing(device_info_t *info) { device_info_t *p = append_device(info); if (p == NULL) { - display_error("Can't add device list\n%s", info->name); + display_error("Can't add device list\n%s", info->name); return NULL; } @@ -414,11 +415,11 @@ device_info_t* ui_connect_and_pairing(device_info_t *info) { char message[256]; sprintf(pin, "%d%d%d%d", (int)rand() % 10, (int)rand() % 10, (int)rand() % 10, (int)rand() % 10); - flash_message("Please enter the following PIN\non the target PC:\n\n%s", pin); + flash_message("Please enter the following PIN\non the target PC:\n\n%s", pin); ret = gs_pair(&server, pin); if (ret != GS_OK) { - display_error("Pairing failed: %d", ret); + display_error("Pairing failed: %d", ret); connection_terminate(); return NULL; } @@ -430,7 +431,7 @@ device_info_t* ui_connect_and_pairing(device_info_t *info) { save_device_info(info); if (connection_terminate()) { - display_error("Reconnect failed: %d", -2); + display_error("Reconnect failed: %d", -2); return info; } @@ -457,7 +458,7 @@ bool check_connection(const char *name, char *addr) { if (connection_is_ready()) { return false; } - + sceClibPrintf("step1\n"); flash_message("Check connecting to:\n %s...", addr); char key_dir[4096]; @@ -466,13 +467,15 @@ bool check_connection(const char *name, char *addr) { if (gs_init(&server, addr, key_dir, 0, true) != GS_OK) { return false; } + sceClibPrintf("step2\n"); connection_terminate(); + sceClibPrintf("step3\n"); return true; } void ui_connect_paired_device(device_info_t *info) { if (!info->paired) { - display_error("Unpaired device\n%s", info->name); + display_error("Unpaired device\n%s", info->name); return; } @@ -488,7 +491,7 @@ void ui_connect_paired_device(device_info_t *info) { save_device_info(info); if (addr == NULL) { - display_error("Can't connect to server\n%s", info->name); + display_error("Can't connect to server\n%s", info->name); return; } diff --git a/src/gui/ui_device.c b/src/gui/ui_device.c index 8402c01b2..ce13a09c4 100644 --- a/src/gui/ui_device.c +++ b/src/gui/ui_device.c @@ -25,9 +25,10 @@ #include #include #include -#include +#include +#include #include -#include +#include #include #include #include @@ -80,7 +81,7 @@ char* strrstr(const char *str, const char *pat) { if (patlen > len) return NULL; for (p = str + (len - patlen); p > str; --p) - if (*p == *pat && strncmp(p, pat, patlen) == 0) + if (*p == *pat && sceClibStrncmp(p, pat, patlen) == 0) return (char *) p; return NULL; } @@ -92,7 +93,7 @@ static int mdns_discovery_callback(const struct sockaddr* from, size_t length) { switch (type) { case MDNS_RECORDTYPE_PTR: - memset(&devices[found_device], 0, sizeof(device_info_t)); + sceClibMemset(&devices[found_device], 0, sizeof(device_info_t)); break; case MDNS_RECORDTYPE_SRV: { @@ -106,7 +107,7 @@ static int mdns_discovery_callback(const struct sockaddr* from, len = 255; } // FIXME: remove special codes - strncpy(devices[found_device].name, srv.name.str, p - srv.name.str); + sceClibStrncpy(devices[found_device].name, srv.name.str, p - srv.name.str); } break; case MDNS_RECORDTYPE_A: @@ -169,7 +170,7 @@ int mdns_discovery_main(SceSize args, void *argp) { SceUID start_search_thread() { found_device = 0; - SceUID thid = sceKernelCreateThread("mdns", mdns_discovery_main, 0x10000100, 0x10000, 0, 0, NULL); + SceUID thid = sceKernelCreateThread("mdns", mdns_discovery_main, 70, 0x1000, 0, SCE_KERNEL_CPU_MASK_USER_0, NULL); if (thid < 0) { return -1; } @@ -229,7 +230,7 @@ static int ui_search_device_back(void *context) { int ui_search_device_loop() { int idx = 0; menu_entry menu[64]; - memset(DEVICE_ENTRY_IDX, 0, sizeof(DEVICE_ENTRY_IDX)); + sceClibMemset(DEVICE_ENTRY_IDX, 0, sizeof(DEVICE_ENTRY_IDX)); #define MENU_CATEGORY(NAME) \ do { \ diff --git a/src/gui/ui_settings.c b/src/gui/ui_settings.c index 5998d5b63..cc34ef563 100644 --- a/src/gui/ui_settings.c +++ b/src/gui/ui_settings.c @@ -1,736 +1,758 @@ -#include "ui_settings.h" - -#include "guilib.h" -#include "ime.h" - -#include "../config.h" -#include "../input/vita.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static unsigned int settings_special_codes[] = {0, - // special - INPUT_TYPE_DEF_NAME | INPUT_TYPE_SPECIAL, - INPUT_SPECIAL_KEY_PAUSE | INPUT_TYPE_SPECIAL, - // gamepad - INPUT_TYPE_DEF_NAME | INPUT_TYPE_GAMEPAD, - SPECIAL_FLAG | INPUT_TYPE_GAMEPAD, - LB_FLAG | INPUT_TYPE_GAMEPAD, - RB_FLAG | INPUT_TYPE_GAMEPAD, - LS_CLK_FLAG | INPUT_TYPE_GAMEPAD, - RS_CLK_FLAG | INPUT_TYPE_GAMEPAD, - LEFT_TRIGGER | INPUT_TYPE_ANALOG, - RIGHT_TRIGGER | INPUT_TYPE_ANALOG, - // mouse - INPUT_TYPE_DEF_NAME | INPUT_TYPE_MOUSE, - BUTTON_LEFT | INPUT_TYPE_MOUSE, - BUTTON_RIGHT | INPUT_TYPE_MOUSE, - BUTTON_MIDDLE | INPUT_TYPE_MOUSE, - BUTTON_X1 | INPUT_TYPE_MOUSE, - BUTTON_X2 | INPUT_TYPE_MOUSE, - // keyboard - INPUT_TYPE_DEF_NAME | INPUT_TYPE_KEYBOARD, - 27, 73, 77, 9, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123 -}; - -static char *settings_special_names[] = {"None", - // special - "Special inputs", - "Pause stream", - // gamepad - "Gamepad buttons", - "Special (XBox button)", - "LB", "RB", "LS", "RS", "LT", "RT", - // mouse - "Mouse buttons", - "Left", - "Right", - "Middle(wheel)", - "X1(4th)", - "X2(5th)", - // keyboard - "Keyboard input codes", - "Esc", - "I", "M", "Tab", - "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" -}; - -static bool settings_loop_setup = 1; - -/* - * Deadzone - */ - -#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10) -static void deadzone_draw() { - int vertical = (WIDTH - config.back_deadzone.left - config.back_deadzone.right) / 2 + config.back_deadzone.left, - horizontal = (HEIGHT - config.back_deadzone.top - config.back_deadzone.bottom) / 2 + config.back_deadzone.top; - - vita2d_draw_rectangle( - config.back_deadzone.left, - config.back_deadzone.top, - WIDTH - config.back_deadzone.right - config.back_deadzone.left, - HEIGHT - config.back_deadzone.bottom - config.back_deadzone.top, - 0x3000ff00 - ); - - vita2d_draw_line(vertical, config.back_deadzone.top, vertical, HEIGHT - config.back_deadzone.bottom, 0xffffffff); - vita2d_draw_line(config.back_deadzone.left, horizontal, WIDTH - config.back_deadzone.right, horizontal, 0xffffffff); - - SceTouchData touch_data; - sceTouchPeek(SCE_TOUCH_PORT_BACK, &touch_data, 1); - - for (int i = 0; i < touch_data.reportNum; i++) { - int x = lerp(touch_data.report[i].x, 1919, 960); - int y = lerp(touch_data.report[i].y, 1087, 544); - if (x < config.back_deadzone.left || x > WIDTH - config.back_deadzone.right) - continue; - - if (y < config.back_deadzone.top || y > HEIGHT - config.back_deadzone.bottom) - continue; - - vita2d_draw_fill_circle(x, y, 30, 0xffffffff); - } -} - -static int deadzone_loop(int cursor, void *context, const input_data *input) { - menu_entry *menu = context; - - bool left = input->buttons & SCE_CTRL_LEFT; - bool right = input->buttons & SCE_CTRL_RIGHT; - - int delta = left ? -15 : (right ? 15 : 0); - switch (cursor) { - case 0: config.back_deadzone.top += delta; break; - case 1: config.back_deadzone.right += delta; break; - case 2: config.back_deadzone.bottom += delta; break; - case 3: config.back_deadzone.left += delta; break; - } - - settings_loop_setup = 0; - char current[256]; - - int numbers[] = { - config.back_deadzone.top, - config.back_deadzone.right, - config.back_deadzone.bottom, - config.back_deadzone.left - }; - for (int i = 0; i < 4; i++) { - sprintf(current, "%dpx", numbers[i]); - strcpy(menu[i].subname, current); - } - - return 0; -} - -static int deadzone_settings_menu() { - sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START); - - menu_entry menu[16]; - int idx = 0; - menu[idx++] = (menu_entry) { .name = "Top: ", .disabled = false, .id = 0, .suffix = ICON_LEFT_RIGHT_ARROWS }; - menu[idx++] = (menu_entry) { .name = "Left: ", .disabled = false, .id = 1, .suffix = ICON_LEFT_RIGHT_ARROWS }; - menu[idx++] = (menu_entry) { .name = "Bottom: ", .disabled = false, .id = 2, .suffix = ICON_LEFT_RIGHT_ARROWS }; - menu[idx++] = (menu_entry) { .name = "Right: ", .disabled = false, .id = 3, .suffix = ICON_LEFT_RIGHT_ARROWS }; - - menu_geom geom = make_geom_centered(250, 120); - geom.x = 50; - geom.y = 50; - geom.el = 25; - return display_menu(menu, idx, &geom, &deadzone_loop, NULL, &deadzone_draw, &menu); -} - -/* - * Special keys - */ - -static int special_keys_ord(char *text) { - bool did_find = false; - int i = 0; - for (; i < sizeof(settings_special_codes) / sizeof(int); i++) { - if (strcmp(settings_special_names[i], text) == 0) { - did_find = true; - break; - } - } - - if (did_find) { - return settings_special_codes[i]; - } else { - return 0; - } -} - -static void special_keys_name(int ord, char *text) { - if (ord == 0) { - strcpy(text, "None"); - return; - } - - bool did_find = false; - int i = 0; - for (; i < sizeof(settings_special_codes) / sizeof(int); i++) { - if (settings_special_codes[i] == ord) { - did_find = true; - break; - } - } - - if (did_find) { - strcpy(text, settings_special_names[i]); - } else { - sprintf(text, "%d", ord); - } -} - -enum { - SETTINGS_SELECT_SPECIAL_KEY_MANUAL = -1000 -}; - -enum { - SETTINGS_SPECIAL_KEYS_OFFSET, - SETTINGS_SPECIAL_KEYS_SIZE -}; - -enum { - SETTINGS_SPECIAL_KEYS_NW_VIEW = 3 -}; - -static int select_special_key_loop(int id, void *context, const input_data *input) { - int *code = context; - - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - return 0; - } - if (id != SETTINGS_SELECT_SPECIAL_KEY_MANUAL) { - *code = id; - return 1; - } - char key_code_value[512]; - if (ime_dialog_number(key_code_value, "Enter key code:", "") == 0) { - int key_code = atoi(key_code_value); - if (key_code) { - *code = key_code; - return 1; - } else { - display_error("Incorrect key code entered: %s", key_code_value); - } - } - - return 0; -} - -static int select_special_key_menu(int *code) { - // TODO: sizeof(codes) / sizeof(int) ? - menu_entry menu[64]; - int idx = 0; - for (int i = 0; i < sizeof(settings_special_codes) / sizeof(int); i++) { - unsigned int id = settings_special_codes[i]; - menu[idx++] = (menu_entry) { - .id = id, - .name = malloc(sizeof(char) * 256), - .disabled = (id >= INPUT_TYPE_DEF_NAME) - }; - special_keys_name(id, menu[idx-1].name); - } - - menu[idx++] = (menu_entry) { .name = "", .disabled = true, .separator = true }; - menu[idx++] = (menu_entry) { .name = "Enter manually ...", .id = SETTINGS_SELECT_SPECIAL_KEY_MANUAL }; - - int return_code = display_menu(menu, idx, NULL, &select_special_key_loop, NULL, NULL, code); - for (int i = 0; i < sizeof(settings_special_codes) / sizeof(int); i++) { - free(menu[i].name); - } - - return return_code; -} - -static int special_keys_loop(int id, void *context, const input_data *input) { - bool left = input->buttons & SCE_CTRL_LEFT; - bool right = input->buttons & SCE_CTRL_RIGHT; - int selected_ord = -1; - int delta = left ? -15 : (right ? 15 : 0); - - switch (id) { - case SETTINGS_SPECIAL_KEYS_OFFSET: - config.special_keys.offset += delta; - break; - case SETTINGS_SPECIAL_KEYS_SIZE: - config.special_keys.size += delta; - break; - default: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - select_special_key_menu(&selected_ord); - if (selected_ord != -1) { - switch (id) { - case TOUCHSEC_SPECIAL_NW: - config.special_keys.nw = selected_ord; - break; - case TOUCHSEC_SPECIAL_NE: - config.special_keys.ne = selected_ord; - break; - case TOUCHSEC_SPECIAL_SW: - config.special_keys.sw = selected_ord; - break; - case TOUCHSEC_SPECIAL_SE: - config.special_keys.se = selected_ord; - break; - } - } - break; - } - - menu_entry *menu = context; - - int idx = 0; - sprintf(menu[idx++].subname, "%d", config.special_keys.offset); - sprintf(menu[idx++].subname, "%d", config.special_keys.size); - - idx++; - special_keys_name(config.special_keys.nw, menu[idx++].subname); - special_keys_name(config.special_keys.ne, menu[idx++].subname); - special_keys_name(config.special_keys.sw, menu[idx++].subname); - special_keys_name(config.special_keys.se, menu[idx++].subname); - - return 0; -} - -static void special_keys_draw() { - int special_offset = config.special_keys.offset, - special_size = config.special_keys.size; - - unsigned int color = 0xff006000; - - for (int i = TOUCHSEC_SPECIAL_NW; i <= TOUCHSEC_SPECIAL_SE; i++) { - switch (i) { - case TOUCHSEC_SPECIAL_SW: - vita2d_draw_rectangle( - special_offset, - HEIGHT - special_size - special_offset, - special_size, - special_size, - color); - case TOUCHSEC_SPECIAL_SE: - vita2d_draw_rectangle( - WIDTH - special_size - special_offset, - HEIGHT - special_size - special_offset, - special_size, - special_size, - color); - case TOUCHSEC_SPECIAL_NW: - vita2d_draw_rectangle( - special_offset, - special_offset, - special_size, - special_size, - color); - case TOUCHSEC_SPECIAL_NE: - vita2d_draw_rectangle( - WIDTH - special_size - special_offset, - special_offset, - special_size, - special_size, - color); - } - } - -} - -static int special_keys_menu() { - menu_entry menu[16]; - int idx = 0; - - menu[idx++] = (menu_entry) { .name = "Offset", .id = SETTINGS_SPECIAL_KEYS_OFFSET }; - menu[idx++] = (menu_entry) { .name = "Size", .id = SETTINGS_SPECIAL_KEYS_SIZE }; - menu[idx++] = (menu_entry) { .name = "Assignments", .disabled = true, .separator = false }; - menu[idx++] = (menu_entry) { .name = "Top left", .id = TOUCHSEC_SPECIAL_NW }; - menu[idx++] = (menu_entry) { .name = "Top right", .id = TOUCHSEC_SPECIAL_NE }; - menu[idx++] = (menu_entry) { .name = "Bottom left", .id = TOUCHSEC_SPECIAL_SW }; - menu[idx++] = (menu_entry) { .name = "Bottom right", .id = TOUCHSEC_SPECIAL_SE }; - - return display_menu(menu, idx, NULL, &special_keys_loop, NULL, &special_keys_draw, &menu); -} - -/* - * Main menu - */ - -enum { - SETTINGS_RESOLUTION = 100, - SETTINGS_FPS, - SETTINGS_BITRATE, - SETTINGS_SOPS, - SETTINGS_ENABLE_FRAME_INVAL, - SETTINGS_ENABLE_STREAM_OPTIMIZE, - SETTINGS_SAVE_DEBUG_LOG, - SETTINGS_DISABLE_POWERSAVE, - SETTINGS_JP_LAYOUT, - SETTINGS_SHOW_FPS, - SETTINGS_LOCAL_AUDIO, - SETTINGS_ENABLE_FRAME_PACER, - SETTINGS_CENTER_REGION_ONLY, - SETTINGS_ENABLE_MAPPING, - SETTINGS_BACK_DEADZONE, - SETTINGS_SPECIAL_KEYS, - SETTINGS_MOUSE_ACCEL, -}; - -enum { - SETTINGS_VIEW_RESOLUTION, - SETTINGS_VIEW_FPS, - SETTINGS_VIEW_BITRATE, - SETTINGS_VIEW_SOPS, - SETTINGS_VIEW_ENABLE_FRAME_INVAL, - SETTINGS_VIEW_ENABLE_STREAM_OPTIMIZE, - SETTINGS_VIEW_SAVE_DEBUG_LOG, - SETTINGS_VIEW_DISABLE_POWERSAVE, - SETTINGS_VIEW_JP_LAYOUT, - SETTINGS_VIEW_SHOW_FPS, - SETTINGS_VIEW_LOCAL_AUDIO, - SETTINGS_VIEW_ENABLE_FRAME_PACER, - SETTINGS_VIEW_CENTER_REGION_ONLY, - SETTINGS_VIEW_ENABLE_MAPPING, - SETTINGS_VIEW_BACK_DEADZONE, - SETTINGS_VIEW_SPECIAL_KEYS, - SETTINGS_VIEW_MOUSE_ACCEL, -}; - -static int SETTINGS_VIEW_IDX[10]; - -// _countof only works for variable allocated on the stack, not from malloc (sizeof(i) will be incorrect). -#define _countof(i) (sizeof(i) / sizeof((i)[0])) -#define _move_idx_in_array(a, f, i) move_idx_in_array((a), _countof(a), (f), (i)) -static int move_idx_in_array(char *array[], int count, char *find, int index_dist) { - int i = 0; - for (; i < count; i++) { - if (strcmp(find, array[i]) == 0) { - i += index_dist; - break; - } - } - - if (i >= count) { - return count - 1; - } else if (i < 0) { - return 0; - } else { - return i; - } -} - -static int settings_loop(int id, void *context, const input_data *input) { - menu_entry *menu = context; - bool did_change = 0; - bool left = (input->buttons & SCE_CTRL_LEFT) && (input->buttons & SCE_CTRL_HOLD) == 0; - bool right = (input->buttons & SCE_CTRL_RIGHT) && (input->buttons & SCE_CTRL_HOLD) == 0; - - char current[256]; - int new_idx; - - switch (id) { - case SETTINGS_RESOLUTION: - if (!left && !right) { - break; - } - char *resolutions[] = {"960x540", "960x544", "1280x540", "1280x720", "1920x1080"}; - sprintf(current, "%dx%d", config.stream.width, config.stream.height); - - new_idx = _move_idx_in_array(resolutions, current, left ? -1 : +1); - - switch (new_idx) { - case 0: config.stream.width = 960; config.stream.height = 540; break; - case 1: config.stream.width = 960; config.stream.height = 544; break; - case 2: config.stream.width = 1280; config.stream.height = 540; break; - case 3: config.stream.width = 1280; config.stream.height = 720; break; - case 4: config.stream.width = 1920; config.stream.height = 1080; break; - } - - did_change = 1; - break; - case SETTINGS_FPS: - if (!left && !right) { - break; - } - char *settings[] = {"30", "60"}; - sprintf(current, "%d", config.stream.fps); - new_idx = _move_idx_in_array(settings, current, left ? -1 : +1); - - switch (new_idx) { - case 0: config.stream.fps = 30; break; - case 1: config.stream.fps = 60; break; - } - - did_change = 1; - break; - case SETTINGS_BITRATE: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - char value[512]; - int ret; - if ((ret = ime_dialog_number(value, "Enter bitrate: ", "")) == 0) { - int bitrate = atoi(value); - if (bitrate) { - config.stream.bitrate = bitrate; - did_change = 1; - } else { - display_error("Incorrect bitrate entered: %s", value); - } - } - break; - case SETTINGS_SOPS: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.sops = !config.sops; - break; - case SETTINGS_ENABLE_FRAME_INVAL: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.enable_ref_frame_invalidation = !config.enable_ref_frame_invalidation; - break; - case SETTINGS_ENABLE_STREAM_OPTIMIZE: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.stream.streamingRemotely = config.stream.streamingRemotely ? 0 : 1; - break; - case SETTINGS_SAVE_DEBUG_LOG: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.save_debug_log = !config.save_debug_log; - break; - case SETTINGS_DISABLE_POWERSAVE: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.disable_powersave = !config.disable_powersave; - break; - case SETTINGS_JP_LAYOUT: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.jp_layout = !config.jp_layout; - break; - case SETTINGS_SHOW_FPS: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.show_fps = !config.show_fps; - break; - case SETTINGS_LOCAL_AUDIO: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.localaudio = !config.localaudio; - break; - case SETTINGS_ENABLE_FRAME_PACER: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.enable_frame_pacer = !config.enable_frame_pacer; - break; - case SETTINGS_CENTER_REGION_ONLY: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - config.center_region_only = !config.center_region_only; - break; - case SETTINGS_ENABLE_MAPPING: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - did_change = 1; - if (config.mapping) { - free(config.mapping); - config.mapping = NULL; - } else { - config.mapping = strdup("mappings/vita.conf"); - } - break; - case SETTINGS_BACK_DEADZONE: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - deadzone_settings_menu(); - did_change = 1; - break; - case SETTINGS_SPECIAL_KEYS: - if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { - break; - } - special_keys_menu(); - break; - case SETTINGS_MOUSE_ACCEL: - left = input->buttons & SCE_CTRL_LEFT; - right = input->buttons & SCE_CTRL_RIGHT; - if (!left && !right) { - break; - } - if (left) { - config.mouse_acceleration -= 15; - if (config.mouse_acceleration < 0) { - config.mouse_acceleration = 0; - } - } else { - config.mouse_acceleration += 15; - if (config.mouse_acceleration > 300) { - config.mouse_acceleration = 300; - } - } - - did_change = 1; - break; - - } - - if (!did_change && !settings_loop_setup) { - return 0; - } - settings_loop_setup = 0; - -#define MENU_REPLACE(ID, MESSAGE) \ - strcpy(menu[SETTINGS_VIEW_IDX[(ID)]].subname, (MESSAGE)) - - sprintf(current, "%dx%d", config.stream.width, config.stream.height); - MENU_REPLACE(SETTINGS_VIEW_RESOLUTION, current); - - sprintf(current, "%d", config.stream.fps); - MENU_REPLACE(SETTINGS_VIEW_FPS, current); - - sprintf(current, "%d", config.stream.bitrate); - MENU_REPLACE(SETTINGS_VIEW_BITRATE, current); - - sprintf(current, "%s", config.sops ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_SOPS, current); - - sprintf(current, "%s", config.enable_ref_frame_invalidation ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_ENABLE_FRAME_INVAL, current); - - sprintf(current, "%s", config.stream.streamingRemotely ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_ENABLE_STREAM_OPTIMIZE, current); - - sprintf(current, "%s", config.disable_powersave ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_DISABLE_POWERSAVE, current); - - sprintf(current, "%s", config.jp_layout ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_JP_LAYOUT, current); - - sprintf(current, "%s", config.show_fps ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_SHOW_FPS, current); - - sprintf(current, "%s", config.localaudio ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_LOCAL_AUDIO, current); - - sprintf(current, "%s", config.enable_frame_pacer ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_ENABLE_FRAME_PACER, current); - - sprintf(current, "%s", config.center_region_only ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_CENTER_REGION_ONLY, current); - - sprintf(current, "%s", config.save_debug_log ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_SAVE_DEBUG_LOG, current); - - sprintf(current, "%s", config.mapping != 0 ? "yes" : "no"); - MENU_REPLACE(SETTINGS_VIEW_ENABLE_MAPPING, current); - - sprintf(current, "%dpx,%dpx,%dpx,%dpx", - config.back_deadzone.top, - config.back_deadzone.right, - config.back_deadzone.bottom, - config.back_deadzone.left); - MENU_REPLACE(SETTINGS_VIEW_BACK_DEADZONE, current); - - sprintf(current, "%d", config.mouse_acceleration); - MENU_REPLACE(SETTINGS_VIEW_MOUSE_ACCEL, current); - return 0; -} - -static int settings_back(void *context) { - ui_settings_save_config(); - update_layout(); - return 0; -} - -int ui_settings_menu() { - menu_entry menu[32]; - int idx = 0; -#define MENU_CATEGORY(NAME) \ - do { \ - menu[idx] = (menu_entry) { .name = (NAME), .disabled = true, .separator = true }; \ - idx++; \ - } while (0) -#define MENU_ENTRY(ID, TAG, NAME, SUFFIX) \ - do { \ - menu[idx] = (menu_entry) { .name = (NAME), .id = (ID), .suffix = (SUFFIX) }; \ - SETTINGS_VIEW_IDX[(TAG)] = idx; \ - idx++; \ - } while(0) -#define MENU_MESSAGE(MESSAGE) \ - do { \ - menu[idx] = (menu_entry) { .name = "", .disabled = true, .subname = (MESSAGE) }; \ - idx++; \ - } while(0) - - MENU_CATEGORY("Stream"); - MENU_ENTRY(SETTINGS_RESOLUTION, SETTINGS_VIEW_RESOLUTION, "Resolution", ICON_LEFT_RIGHT_ARROWS); - MENU_ENTRY(SETTINGS_FPS, SETTINGS_VIEW_FPS, "FPS", ICON_LEFT_RIGHT_ARROWS); - MENU_ENTRY(SETTINGS_BITRATE, SETTINGS_VIEW_BITRATE, "Bitrate", ""); - MENU_ENTRY(SETTINGS_SOPS, SETTINGS_VIEW_SOPS, "Change graphical game settings for performance", ""); - MENU_ENTRY(SETTINGS_ENABLE_FRAME_INVAL, SETTINGS_VIEW_ENABLE_FRAME_INVAL, "Enable reference frame invalidation", ""); - MENU_ENTRY(SETTINGS_ENABLE_STREAM_OPTIMIZE, SETTINGS_VIEW_ENABLE_STREAM_OPTIMIZE, "Enable stream optimization", ""); - MENU_ENTRY(SETTINGS_ENABLE_FRAME_PACER, SETTINGS_VIEW_ENABLE_FRAME_PACER, "Enable frame pacer", ""); - MENU_ENTRY(SETTINGS_LOCAL_AUDIO, SETTINGS_VIEW_LOCAL_AUDIO, "Enable local audio", ""); - - MENU_CATEGORY("System"); - MENU_ENTRY(SETTINGS_SAVE_DEBUG_LOG, SETTINGS_VIEW_SAVE_DEBUG_LOG, "Enable debug log", ""); - MENU_ENTRY(SETTINGS_DISABLE_POWERSAVE, SETTINGS_VIEW_DISABLE_POWERSAVE, "Disable power save", ""); - MENU_ENTRY(SETTINGS_JP_LAYOUT, SETTINGS_VIEW_JP_LAYOUT, "Swap X & O for Moonlight", ""); - MENU_ENTRY(SETTINGS_SHOW_FPS, SETTINGS_VIEW_SHOW_FPS, "Display streaming FPS", ""); - - MENU_CATEGORY("Input"); - MENU_ENTRY(SETTINGS_MOUSE_ACCEL, SETTINGS_VIEW_MOUSE_ACCEL, "Mouse acceleration", ICON_LEFT_RIGHT_ARROWS); - MENU_ENTRY(SETTINGS_ENABLE_MAPPING, SETTINGS_VIEW_ENABLE_MAPPING, "Enable mapping file", ""); - MENU_MESSAGE("Located at ux0:data/moonlight/mappings/vita.conf"); - MENU_MESSAGE("Example in github repo."); - MENU_ENTRY(SETTINGS_BACK_DEADZONE, SETTINGS_VIEW_BACK_DEADZONE, "Back touchscreen deadzone", ""); - MENU_ENTRY(SETTINGS_SPECIAL_KEYS, SETTINGS_VIEW_SPECIAL_KEYS, "Touchscreen special keys", ""); - - settings_loop_setup = 1; - assert(idx < 32); - return display_menu(menu, idx, NULL, &settings_loop, &settings_back, NULL, &menu); -} - -void ui_settings_save_config() { - config_save(config_path, &config); -} - +#include "ui_settings.h" + +#include "guilib.h" +#include "ime.h" + +#include "../config.h" +#include "../input/vita.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +extern int SCREEN_WIDTH; +extern int SCREEN_HEIGHT; +extern int LINE_SIZE; + +static unsigned int settings_special_codes[] = {0, + // special + INPUT_TYPE_DEF_NAME | INPUT_TYPE_SPECIAL, + INPUT_SPECIAL_KEY_PAUSE | INPUT_TYPE_SPECIAL, + INPUT_SPECIAL_KEY_KEYBOARD | INPUT_TYPE_SPECIAL, + // gamepad + INPUT_TYPE_DEF_NAME | INPUT_TYPE_GAMEPAD, + SPECIAL_FLAG | INPUT_TYPE_GAMEPAD, + LB_FLAG | INPUT_TYPE_GAMEPAD, + RB_FLAG | INPUT_TYPE_GAMEPAD, + LS_CLK_FLAG | INPUT_TYPE_GAMEPAD, + RS_CLK_FLAG | INPUT_TYPE_GAMEPAD, + LEFT_TRIGGER | INPUT_TYPE_ANALOG, + RIGHT_TRIGGER | INPUT_TYPE_ANALOG, + // mouse + INPUT_TYPE_DEF_NAME | INPUT_TYPE_MOUSE, + BUTTON_LEFT | INPUT_TYPE_MOUSE, + BUTTON_RIGHT | INPUT_TYPE_MOUSE, + BUTTON_MIDDLE | INPUT_TYPE_MOUSE, + BUTTON_X1 | INPUT_TYPE_MOUSE, + BUTTON_X2 | INPUT_TYPE_MOUSE, + // keyboard + INPUT_TYPE_DEF_NAME | INPUT_TYPE_KEYBOARD, + 27, 73, 77, 9, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123 +}; + +static char *settings_special_names[] = {"None", + // special + "Special inputs", + "Pause stream", + "Open keyboard", + // gamepad + "Gamepad buttons", + "Special (XBox button)", + "LB", "RB", "LS", "RS", "LT", "RT", + // mouse + "Mouse buttons", + "Left", + "Right", + "Middle(wheel)", + "X1(4th)", + "X2(5th)", + // keyboard + "Keyboard input codes", + "Esc", + "I", "M", "Tab", + "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" +}; + +static bool settings_loop_setup = 1; + +/* + * Deadzone + */ + +#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10) +static void deadzone_draw() { + int vertical = (SCREEN_WIDTH - config.back_deadzone.left - config.back_deadzone.right) / 2 + config.back_deadzone.left, + horizontal = (SCREEN_HEIGHT - config.back_deadzone.top - config.back_deadzone.bottom) / 2 + config.back_deadzone.top; + + vita2d_draw_rectangle( + config.back_deadzone.left, + config.back_deadzone.top, + SCREEN_WIDTH - config.back_deadzone.right - config.back_deadzone.left, + SCREEN_HEIGHT - config.back_deadzone.bottom - config.back_deadzone.top, + 0x3000ff00 + ); + + vita2d_draw_line(vertical, config.back_deadzone.top, vertical, SCREEN_HEIGHT - config.back_deadzone.bottom, 0xffffffff); + vita2d_draw_line(config.back_deadzone.left, horizontal, SCREEN_WIDTH - config.back_deadzone.right, horizontal, 0xffffffff); + + SceTouchData touch_data; + sceTouchPeek(SCE_TOUCH_PORT_BACK, &touch_data, 1); + + for (int i = 0; i < touch_data.reportNum; i++) { + int x = lerp(touch_data.report[i].x, 1919, 960); + int y = lerp(touch_data.report[i].y, 1087, 544); + if (x < config.back_deadzone.left || x > WIDTH - config.back_deadzone.right) + continue; + + if (y < config.back_deadzone.top || y > HEIGHT - config.back_deadzone.bottom) + continue; + + vita2d_draw_fill_circle(x, y, 30, 0xffffffff); + } +} + +static int deadzone_loop(int cursor, void *context, const input_data *input) { + menu_entry *menu = context; + + bool left = input->buttons & SCE_CTRL_LEFT; + bool right = input->buttons & SCE_CTRL_RIGHT; + + int delta = left ? -15 : (right ? 15 : 0); + switch (cursor) { + case 0: config.back_deadzone.top += delta; break; + case 1: config.back_deadzone.right += delta; break; + case 2: config.back_deadzone.bottom += delta; break; + case 3: config.back_deadzone.left += delta; break; + } + + settings_loop_setup = 0; + char current[256]; + + int numbers[] = { + config.back_deadzone.top, + config.back_deadzone.right, + config.back_deadzone.bottom, + config.back_deadzone.left + }; + for (int i = 0; i < 4; i++) { + sprintf(current, "%dpx", numbers[i]); + strcpy(menu[i].subname, current); + } + + return 0; +} + +static int deadzone_settings_menu() { + sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START); + + menu_entry menu[16]; + int idx = 0; + menu[idx++] = (menu_entry) { .name = "Top: ", .disabled = false, .id = 0, .suffix = ICON_LEFT_RIGHT_ARROWS }; + menu[idx++] = (menu_entry) { .name = "Left: ", .disabled = false, .id = 1, .suffix = ICON_LEFT_RIGHT_ARROWS }; + menu[idx++] = (menu_entry) { .name = "Bottom: ", .disabled = false, .id = 2, .suffix = ICON_LEFT_RIGHT_ARROWS }; + menu[idx++] = (menu_entry) { .name = "Right: ", .disabled = false, .id = 3, .suffix = ICON_LEFT_RIGHT_ARROWS }; + + menu_geom geom = make_geom_centered(250, 120); + geom.x = 50; + geom.y = 50; + geom.el = 25; + return display_menu(menu, idx, &geom, &deadzone_loop, NULL, &deadzone_draw, &menu); +} + +/* + * Special keys + */ + +static int special_keys_ord(char *text) { + bool did_find = false; + int i = 0; + for (; i < sizeof(settings_special_codes) / sizeof(int); i++) { + if (sceClibStrcmp(settings_special_names[i], text) == 0) { + did_find = true; + break; + } + } + + if (did_find) { + return settings_special_codes[i]; + } else { + return 0; + } +} + +static void special_keys_name(int ord, char *text) { + if (ord == 0) { + strcpy(text, "None"); + return; + } + + bool did_find = false; + int i = 0; + for (; i < sizeof(settings_special_codes) / sizeof(int); i++) { + if (settings_special_codes[i] == ord) { + did_find = true; + break; + } + } + + if (did_find) { + strcpy(text, settings_special_names[i]); + } else { + sprintf(text, "%d", ord); + } +} + +enum { + SETTINGS_SELECT_SPECIAL_KEY_MANUAL = -1000 +}; + +enum { + SETTINGS_SPECIAL_KEYS_OFFSET, + SETTINGS_SPECIAL_KEYS_SIZE +}; + +enum { + SETTINGS_SPECIAL_KEYS_NW_VIEW = 3 +}; + +static int select_special_key_loop(int id, void *context, const input_data *input) { + int *code = context; + + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + return 0; + } + if (id != SETTINGS_SELECT_SPECIAL_KEY_MANUAL) { + *code = id; + return 1; + } + char key_code_value[512]; + if (ime_dialog_number(key_code_value, "Enter key code:", "") == 0) { + int key_code = atoi(key_code_value); + if (key_code) { + *code = key_code; + return 1; + } else { + display_error("Incorrect key code entered: %s", key_code_value); + } + } + + return 0; +} + +static int select_special_key_menu(int *code) { + // TODO: sizeof(codes) / sizeof(int) ? + menu_entry menu[64]; + int idx = 0; + for (int i = 0; i < sizeof(settings_special_codes) / sizeof(int); i++) { + unsigned int id = settings_special_codes[i]; + menu[idx++] = (menu_entry) { + .id = id, + .name = malloc(sizeof(char) * 256), + .disabled = (id >= INPUT_TYPE_DEF_NAME) + }; + special_keys_name(id, menu[idx-1].name); + } + + menu[idx++] = (menu_entry) { .name = "", .disabled = true, .separator = true }; + menu[idx++] = (menu_entry) { .name = "Enter manually ...", .id = SETTINGS_SELECT_SPECIAL_KEY_MANUAL }; + + int return_code = display_menu(menu, idx, NULL, &select_special_key_loop, NULL, NULL, code); + for (int i = 0; i < sizeof(settings_special_codes) / sizeof(int); i++) { + free(menu[i].name); + } + + return return_code; +} + +static int special_keys_loop(int id, void *context, const input_data *input) { + bool left = input->buttons & SCE_CTRL_LEFT; + bool right = input->buttons & SCE_CTRL_RIGHT; + int selected_ord = -1; + int delta = left ? -15 : (right ? 15 : 0); + + switch (id) { + case SETTINGS_SPECIAL_KEYS_OFFSET: + config.special_keys.offset += delta; + break; + case SETTINGS_SPECIAL_KEYS_SIZE: + config.special_keys.size += delta; + break; + default: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + select_special_key_menu(&selected_ord); + if (selected_ord != -1) { + switch (id) { + case TOUCHSEC_SPECIAL_NW: + config.special_keys.nw = selected_ord; + break; + case TOUCHSEC_SPECIAL_NE: + config.special_keys.ne = selected_ord; + break; + case TOUCHSEC_SPECIAL_SW: + config.special_keys.sw = selected_ord; + break; + case TOUCHSEC_SPECIAL_SE: + config.special_keys.se = selected_ord; + break; + } + } + break; + } + + menu_entry *menu = context; + + int idx = 0; + sprintf(menu[idx++].subname, "%d", config.special_keys.offset); + sprintf(menu[idx++].subname, "%d", config.special_keys.size); + + idx++; + special_keys_name(config.special_keys.nw, menu[idx++].subname); + special_keys_name(config.special_keys.ne, menu[idx++].subname); + special_keys_name(config.special_keys.sw, menu[idx++].subname); + special_keys_name(config.special_keys.se, menu[idx++].subname); + + return 0; +} + +static void special_keys_draw() { + int special_offset = config.special_keys.offset, + special_size = config.special_keys.size; + + unsigned int color = 0xff006000; + + for (int i = TOUCHSEC_SPECIAL_NW; i <= TOUCHSEC_SPECIAL_SE; i++) { + switch (i) { + case TOUCHSEC_SPECIAL_SW: + vita2d_draw_rectangle( + special_offset, + SCREEN_HEIGHT - special_size - special_offset, + special_size, + special_size, + color); + case TOUCHSEC_SPECIAL_SE: + vita2d_draw_rectangle( + SCREEN_WIDTH - special_size - special_offset, + SCREEN_HEIGHT - special_size - special_offset, + special_size, + special_size, + color); + case TOUCHSEC_SPECIAL_NW: + vita2d_draw_rectangle( + special_offset, + special_offset, + special_size, + special_size, + color); + case TOUCHSEC_SPECIAL_NE: + vita2d_draw_rectangle( + SCREEN_WIDTH - special_size - special_offset, + special_offset, + special_size, + special_size, + color); + } + } + +} + +static int special_keys_menu() { + menu_entry menu[16]; + int idx = 0; + + menu[idx++] = (menu_entry) { .name = "Offset", .id = SETTINGS_SPECIAL_KEYS_OFFSET }; + menu[idx++] = (menu_entry) { .name = "Size", .id = SETTINGS_SPECIAL_KEYS_SIZE }; + menu[idx++] = (menu_entry) { .name = "Assignments", .disabled = true, .separator = false }; + menu[idx++] = (menu_entry) { .name = "Top left", .id = TOUCHSEC_SPECIAL_NW }; + menu[idx++] = (menu_entry) { .name = "Top right", .id = TOUCHSEC_SPECIAL_NE }; + menu[idx++] = (menu_entry) { .name = "Bottom left", .id = TOUCHSEC_SPECIAL_SW }; + menu[idx++] = (menu_entry) { .name = "Bottom right", .id = TOUCHSEC_SPECIAL_SE }; + + return display_menu(menu, idx, NULL, &special_keys_loop, NULL, &special_keys_draw, &menu); +} + +/* + * Main menu + */ + +enum { + SETTINGS_RESOLUTION = 100, + SETTINGS_FPS, + SETTINGS_BITRATE, + SETTINGS_SOPS, + SETTINGS_ENABLE_FRAME_INVAL, + SETTINGS_ENABLE_STREAM_OPTIMIZE, + SETTINGS_SAVE_DEBUG_LOG, + SETTINGS_DISABLE_POWERSAVE, + SETTINGS_DISABLE_DIMMING, + SETTINGS_JP_LAYOUT, + SETTINGS_SHOW_FPS, + SETTINGS_LOCAL_AUDIO, + SETTINGS_ENABLE_FRAME_PACER, + SETTINGS_CENTER_REGION_ONLY, + SETTINGS_ENABLE_MAPPING, + SETTINGS_BACK_DEADZONE, + SETTINGS_SPECIAL_KEYS, + SETTINGS_MOUSE_ACCEL, +}; + +enum { + SETTINGS_VIEW_RESOLUTION, + SETTINGS_VIEW_FPS, + SETTINGS_VIEW_BITRATE, + SETTINGS_VIEW_SOPS, + SETTINGS_VIEW_ENABLE_FRAME_INVAL, + SETTINGS_VIEW_ENABLE_STREAM_OPTIMIZE, + SETTINGS_VIEW_SAVE_DEBUG_LOG, + SETTINGS_VIEW_DISABLE_POWERSAVE, + SETTINGS_VIEW_DISABLE_DIMMING, + SETTINGS_VIEW_JP_LAYOUT, + SETTINGS_VIEW_SHOW_FPS, + SETTINGS_VIEW_LOCAL_AUDIO, + SETTINGS_VIEW_ENABLE_FRAME_PACER, + SETTINGS_VIEW_CENTER_REGION_ONLY, + SETTINGS_VIEW_ENABLE_MAPPING, + SETTINGS_VIEW_BACK_DEADZONE, + SETTINGS_VIEW_SPECIAL_KEYS, + SETTINGS_VIEW_MOUSE_ACCEL, +}; + +static int SETTINGS_VIEW_IDX[10]; + +// _countof only works for variable allocated on the stack, not from malloc (sizeof(i) will be incorrect). +#define _countof(i) (sizeof(i) / sizeof((i)[0])) +#define _move_idx_in_array(a, f, i) move_idx_in_array((a), _countof(a), (f), (i)) +static int move_idx_in_array(char *array[], int count, char *find, int index_dist) { + int i = 0; + for (; i < count; i++) { + if (sceClibStrcmp(find, array[i]) == 0) { + i += index_dist; + break; + } + } + + if (i >= count) { + return count - 1; + } else if (i < 0) { + return 0; + } else { + return i; + } +} + +static int settings_loop(int id, void *context, const input_data *input) { + menu_entry *menu = context; + bool did_change = 0; + bool left = (input->buttons & SCE_CTRL_LEFT) && (input->buttons & SCE_CTRL_HOLD) == 0; + bool right = (input->buttons & SCE_CTRL_RIGHT) && (input->buttons & SCE_CTRL_HOLD) == 0; + + char current[256]; + int new_idx; + + switch (id) { + case SETTINGS_RESOLUTION: + if (!left && !right) { + break; + } + char *resolutions[] = {"960x540", "960x544", "1280x540", "1280x720", "1920x1080"}; + sprintf(current, "%dx%d", config.stream.width, config.stream.height); + + new_idx = _move_idx_in_array(resolutions, current, left ? -1 : +1); + + switch (new_idx) { + case 0: config.stream.width = 960; config.stream.height = 540; break; + case 1: config.stream.width = 960; config.stream.height = 544; break; + case 2: config.stream.width = 1280; config.stream.height = 540; break; + case 3: config.stream.width = 1280; config.stream.height = 720; break; + case 4: config.stream.width = 1920; config.stream.height = 1080; break; + } + + did_change = 1; + break; + case SETTINGS_FPS: + if (!left && !right) { + break; + } + char *settings[] = {"30", "60"}; + sprintf(current, "%d", config.stream.fps); + new_idx = _move_idx_in_array(settings, current, left ? -1 : +1); + + switch (new_idx) { + case 0: config.stream.fps = 30; break; + case 1: config.stream.fps = 60; break; + } + + did_change = 1; + break; + case SETTINGS_BITRATE: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + char value[512]; + int ret; + if ((ret = ime_dialog_number(value, "Enter bitrate: ", "")) == 0) { + int bitrate = atoi(value); + if (bitrate) { + config.stream.bitrate = bitrate; + did_change = 1; + } else { + display_error("Incorrect bitrate entered: %s", value); + } + } + break; + case SETTINGS_SOPS: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.sops = !config.sops; + break; + case SETTINGS_ENABLE_FRAME_INVAL: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.enable_ref_frame_invalidation = !config.enable_ref_frame_invalidation; + break; + case SETTINGS_ENABLE_STREAM_OPTIMIZE: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.stream.streamingRemotely = config.stream.streamingRemotely ? 0 : 1; + break; + case SETTINGS_SAVE_DEBUG_LOG: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.save_debug_log = !config.save_debug_log; + break; + case SETTINGS_DISABLE_POWERSAVE: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.disable_powersave = !config.disable_powersave; + break; + case SETTINGS_DISABLE_DIMMING: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.disable_dimming = !config.disable_dimming; + break; + case SETTINGS_JP_LAYOUT: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.jp_layout = !config.jp_layout; + break; + case SETTINGS_SHOW_FPS: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.show_fps = !config.show_fps; + break; + case SETTINGS_LOCAL_AUDIO: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.localaudio = !config.localaudio; + break; + case SETTINGS_ENABLE_FRAME_PACER: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.enable_frame_pacer = !config.enable_frame_pacer; + break; + case SETTINGS_CENTER_REGION_ONLY: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + config.center_region_only = !config.center_region_only; + break; + case SETTINGS_ENABLE_MAPPING: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + did_change = 1; + if (config.mapping) { + free(config.mapping); + config.mapping = NULL; + } else { + config.mapping = strdup("mappings/vita.conf"); + } + break; + case SETTINGS_BACK_DEADZONE: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + deadzone_settings_menu(); + did_change = 1; + break; + case SETTINGS_SPECIAL_KEYS: + if ((input->buttons & config.btn_confirm) == 0 || input->buttons & SCE_CTRL_HOLD) { + break; + } + special_keys_menu(); + break; + case SETTINGS_MOUSE_ACCEL: + left = input->buttons & SCE_CTRL_LEFT; + right = input->buttons & SCE_CTRL_RIGHT; + if (!left && !right) { + break; + } + if (left) { + config.mouse_acceleration -= 15; + if (config.mouse_acceleration < 0) { + config.mouse_acceleration = 0; + } + } else { + config.mouse_acceleration += 15; + if (config.mouse_acceleration > 300) { + config.mouse_acceleration = 300; + } + } + + did_change = 1; + break; + + } + + if (!did_change && !settings_loop_setup) { + return 0; + } + settings_loop_setup = 0; + +#define MENU_REPLACE(ID, MESSAGE) \ + strcpy(menu[SETTINGS_VIEW_IDX[(ID)]].subname, (MESSAGE)) + + sprintf(current, "%dx%d", config.stream.width, config.stream.height); + MENU_REPLACE(SETTINGS_VIEW_RESOLUTION, current); + + sprintf(current, "%d", config.stream.fps); + MENU_REPLACE(SETTINGS_VIEW_FPS, current); + + sprintf(current, "%d", config.stream.bitrate); + MENU_REPLACE(SETTINGS_VIEW_BITRATE, current); + + sprintf(current, "%s", config.sops ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_SOPS, current); + + sprintf(current, "%s", config.enable_ref_frame_invalidation ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_ENABLE_FRAME_INVAL, current); + + sprintf(current, "%s", config.stream.streamingRemotely ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_ENABLE_STREAM_OPTIMIZE, current); + + sprintf(current, "%s", config.disable_powersave ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_DISABLE_POWERSAVE, current); + + sprintf(current, "%s", config.disable_dimming ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_DISABLE_DIMMING, current); + + sprintf(current, "%s", config.jp_layout ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_JP_LAYOUT, current); + + sprintf(current, "%s", config.show_fps ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_SHOW_FPS, current); + + sprintf(current, "%s", config.localaudio ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_LOCAL_AUDIO, current); + + sprintf(current, "%s", config.enable_frame_pacer ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_ENABLE_FRAME_PACER, current); + + sprintf(current, "%s", config.center_region_only ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_CENTER_REGION_ONLY, current); + + sprintf(current, "%s", config.save_debug_log ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_SAVE_DEBUG_LOG, current); + + sprintf(current, "%s", config.mapping != 0 ? "yes" : "no"); + MENU_REPLACE(SETTINGS_VIEW_ENABLE_MAPPING, current); + + sprintf(current, "%dpx,%dpx,%dpx,%dpx", + config.back_deadzone.top, + config.back_deadzone.right, + config.back_deadzone.bottom, + config.back_deadzone.left); + MENU_REPLACE(SETTINGS_VIEW_BACK_DEADZONE, current); + + sprintf(current, "%d", config.mouse_acceleration); + MENU_REPLACE(SETTINGS_VIEW_MOUSE_ACCEL, current); + return 0; +} + +static int settings_back(void *context) { + flash_message("Saving, please wait..."); + ui_settings_save_config(); + update_layout(); + return 0; +} + +int ui_settings_menu() { + menu_entry menu[32]; + int idx = 0; +#define MENU_CATEGORY(NAME) \ + do { \ + menu[idx] = (menu_entry) { .name = (NAME), .disabled = true, .separator = true }; \ + idx++; \ + } while (0) +#define MENU_ENTRY(ID, TAG, NAME, SUFFIX) \ + do { \ + menu[idx] = (menu_entry) { .name = (NAME), .id = (ID), .suffix = (SUFFIX) }; \ + SETTINGS_VIEW_IDX[(TAG)] = idx; \ + idx++; \ + } while(0) +#define MENU_MESSAGE(MESSAGE) \ + do { \ + menu[idx] = (menu_entry) { .name = "", .disabled = true, .subname = (MESSAGE) }; \ + idx++; \ + } while(0) + + MENU_CATEGORY("Stream"); + MENU_ENTRY(SETTINGS_RESOLUTION, SETTINGS_VIEW_RESOLUTION, "Resolution", ICON_LEFT_RIGHT_ARROWS); + MENU_ENTRY(SETTINGS_FPS, SETTINGS_VIEW_FPS, "FPS", ICON_LEFT_RIGHT_ARROWS); + MENU_ENTRY(SETTINGS_BITRATE, SETTINGS_VIEW_BITRATE, "Bitrate", ""); + MENU_ENTRY(SETTINGS_SOPS, SETTINGS_VIEW_SOPS, "Change graphical game settings for performance", ""); + MENU_ENTRY(SETTINGS_ENABLE_FRAME_INVAL, SETTINGS_VIEW_ENABLE_FRAME_INVAL, "Enable reference frame invalidation", ""); + MENU_ENTRY(SETTINGS_ENABLE_STREAM_OPTIMIZE, SETTINGS_VIEW_ENABLE_STREAM_OPTIMIZE, "Enable stream optimization", ""); + MENU_ENTRY(SETTINGS_ENABLE_FRAME_PACER, SETTINGS_VIEW_ENABLE_FRAME_PACER, "Enable frame pacer", ""); + MENU_ENTRY(SETTINGS_LOCAL_AUDIO, SETTINGS_VIEW_LOCAL_AUDIO, "Enable local audio", ""); + + MENU_CATEGORY("System"); + MENU_ENTRY(SETTINGS_SAVE_DEBUG_LOG, SETTINGS_VIEW_SAVE_DEBUG_LOG, "Enable debug log", ""); + MENU_ENTRY(SETTINGS_DISABLE_POWERSAVE, SETTINGS_VIEW_DISABLE_POWERSAVE, "Disable system suspend", ""); + MENU_ENTRY(SETTINGS_DISABLE_DIMMING, SETTINGS_VIEW_DISABLE_DIMMING, "Disable screen dimming", ""); + MENU_ENTRY(SETTINGS_JP_LAYOUT, SETTINGS_VIEW_JP_LAYOUT, "Swap X & O for Moonlight", ""); + MENU_ENTRY(SETTINGS_SHOW_FPS, SETTINGS_VIEW_SHOW_FPS, "Display streaming FPS", ""); + + MENU_CATEGORY("Input"); + MENU_ENTRY(SETTINGS_MOUSE_ACCEL, SETTINGS_VIEW_MOUSE_ACCEL, "Mouse acceleration", ICON_LEFT_RIGHT_ARROWS); + MENU_ENTRY(SETTINGS_ENABLE_MAPPING, SETTINGS_VIEW_ENABLE_MAPPING, "Enable mapping file", ""); + MENU_MESSAGE("Path: ux0:user/00/savedata/mappings/vita.conf"); + MENU_MESSAGE("Example in github repo."); + MENU_ENTRY(SETTINGS_BACK_DEADZONE, SETTINGS_VIEW_BACK_DEADZONE, "Back touchscreen deadzone", ""); + MENU_ENTRY(SETTINGS_SPECIAL_KEYS, SETTINGS_VIEW_SPECIAL_KEYS, "Touchscreen special keys", ""); + + settings_loop_setup = 1; + assert(idx < 32); + return display_menu(menu, idx, NULL, &settings_loop, &settings_back, NULL, &menu); +} + +void ui_settings_save_config() { + config_save(config_path, &config); +} + diff --git a/src/ini.c b/src/ini.c new file mode 100644 index 000000000..38d131db0 --- /dev/null +++ b/src/ini.c @@ -0,0 +1,102 @@ +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2020 Graphene + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include "ini.h" +#include "ini_file_processor_c.h" + +#include + +#include +#include + +int iniCreateSetKey(void* context, const char* key, IniValueType valueType, int inVal) +{ + int ret = -1; + char value[64]; + + switch (valueType) { + case INI_VALUE_INT: + sceClibMemset(value, 0, 64); + sceClibSnprintf(value, 64, "%d", inVal); + ret = sceIniFileProcessorAddKey(context, key, value); + break; + case INI_VALUE_HEX: + sceClibMemset(value, 0, 64); + sceClibSnprintf(value, 64, "%x", inVal); + ret = sceIniFileProcessorAddKey(context, key, value); + break; + case INI_VALUE_BOOL: + if (inVal) + ret = sceIniFileProcessorAddKey(context, key, "true"); + else + ret = sceIniFileProcessorAddKey(context, key, "false"); + break; + } + + return 0; +} + +int iniGetStringByKey(void* context, const char* key, char** string) +{ + void* outBuf = malloc(1024); + sceClibMemset(outBuf, 0, 1024); + + SceInt32 ret = sceIniFileProcessorFindValueByKey(context, key, outBuf, 1024, 0); + if (ret < 0) + return ret; + + *string = (char*)outBuf; + + return 0; +} + +int iniGetValueByKey(void* context, const char* key, IniValueType valueType, int base, void* out) +{ + int ret = 0; + float fret = 0; + char outBuf[256]; + sceClibMemset(outBuf, 0, 256); + + ret = sceIniFileProcessorFindValueByKey(context, key, outBuf, 256, 0); + if (ret < 0) { + *(int *)out = 0; + return ret; + } + + char* retPtr; + + switch (valueType) { + case INI_VALUE_INT: + ret = (int)strtol(outBuf, &retPtr, base); + *(int *)out = ret; + break; + case INI_VALUE_FLOAT: + fret = (float)strtof(outBuf, &retPtr); + *(float *)out = fret; + break; + case INI_VALUE_BOOL: + if (!sceClibStrncmp(outBuf, "true", 4)) + *(int *)out = 1; + else + *(int *)out = 0; + break; + } + + return 0; +} \ No newline at end of file diff --git a/src/ini.h b/src/ini.h new file mode 100644 index 000000000..a873dea41 --- /dev/null +++ b/src/ini.h @@ -0,0 +1,44 @@ +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2020 Graphene + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +typedef struct SceSysmoduleOpt { + int flags; + int *result; + int unused[2]; +} SceSysmoduleOpt; + +typedef struct ScePafInit { + unsigned int global_heap_size; + int a2; + int a3; + int cdlg_mode; + int heap_opt_param1; + int heap_opt_param2; +} ScePafInit; + +typedef enum IniValueType { + INI_VALUE_INT, + INI_VALUE_HEX, + INI_VALUE_FLOAT, + INI_VALUE_BOOL +} IniValueType; + +int iniCreateSetKey(void* context, const char* key, IniValueType valueType, int inVal); +int iniGetStringByKey(void* context, const char* key, char** string); +int iniGetValueByKey(void* context, const char* key, IniValueType valueType, int base, void* out); \ No newline at end of file diff --git a/src/ini_file_processor_c.h b/src/ini_file_processor_c.h new file mode 100644 index 000000000..52bf95f78 --- /dev/null +++ b/src/ini_file_processor_c.h @@ -0,0 +1,67 @@ +#ifndef INI_FILE_PROCESSOR_C +#define INI_FILE_PROCESSOR_C + +#include + +/** + * Errors + */ +#define SCE_INI_FILE_PROCESSOR_ERROR_MODE 0x80840002 +#define SCE_INI_FILE_PROCESSOR_ERROR_EOF 0x80840005 +#define SCE_INI_FILE_PROCESSOR_ERROR_KEY_NOT_FOUND 0x80840010 + +#define SCE_INI_FILE_PROCESSOR_PARSE_COMPLETED 0x00840001 + +typedef void*(*SceIniFileProcessorAllocFunc)(SceSize size); + +typedef void(*SceIniFileProcessorFreeFunc)(void* ptr); + +typedef struct SceIniFileProcessorMemCallbacks { + SceIniFileProcessorAllocFunc allocFunc; + SceIniFileProcessorFreeFunc freeFunc; +} SceIniFileProcessorMemCallbacks; + +typedef struct SceIniFileProcessorParam { + int a1; //size or mode? usually 0, seen: 0x1000, 0x2000 + int a2; //size or mode? usually 0, seen: 0x1000, 0x2000 + SceIniFileProcessorMemCallbacks* pMemCallbacks; //can be NULL + int a4; +} SceIniFileProcessorParam; + +void* sceIniFileProcessorCreateContext(void* context); +void sceIniFileProcessorInitializeParam(SceIniFileProcessorParam* param); +int sceIniFileProcessorCreateInstance(void* context, SceIniFileProcessorParam* param); +int sceIniFileProcessorDeserialize(void* context, const char* ini, SceSize size); +int sceIniFileProcessorOpenFile(void* context, const char* filePath, const char* mode, int unk); +int sceIniFileProcessorCreateFile(void* context, const char* filePath, const char* mode, int unk); +int sceIniFileProcessorSerialize(void* context, const char** ini, SceSize* size); +int sceIniFileProcessorParse(void* context, char* outKeyBuf, char* outValueBuf, SceSize outBufSize); +void* sceIniFileProcessorResetParser(void* context); +int sceIniFileProcessorGetKeyNum(void* context); +int sceIniFileProcessorFindValueByKey(void* context, const char* key, char* outValueBuf, SceSize outValueBufSize, int keyNum); +int sceIniFileProcessorSetValueForKey(void* context, const char* key, const char* value); +int sceIniFileProcessorAddKey(void* context, const char* key, const char* value); +int sceIniFileProcessorDeleteKey(void* context, const char* key); +int sceIniFileProcessorCleanup(void* context); +void sceIniFileProcessorCloseFile(void* context); +void sceIniFileProcessorDestroyInstance(void* context); +void sceIniFileProcessorDestroyInstanceForError(void* context); +void sceIniFileProcessorDestroyContext(void* context); +void sceIniFileProcessorDestroyFreeContext(void* context); + +/** + * Finalize INI file processor library instance + * + * @param[in] context - context buffer + * + */ +inline +void sceIniFileProcessorFinalize(void* context) +{ + sceIniFileProcessorCleanup(context); + sceIniFileProcessorCloseFile(context); + sceIniFileProcessorDestroyInstance(context); + sceIniFileProcessorDestroyContext(context); +} + +#endif /* INI_FILE_PROCESSOR_C */ diff --git a/src/input/keyboard.c b/src/input/keyboard.c new file mode 100644 index 000000000..4eb383acb --- /dev/null +++ b/src/input/keyboard.c @@ -0,0 +1,89 @@ +/* + * This file is part of Moonlight Embedded for PS Vita. + * + * Copyright (C) 2020 Graphene + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include +#include "keyboard.h" + +void vitainput_kb_init_names() +{ + kbNames[KEY_A] = 0x41; //0x04 Keyboard a and A + kbNames[KEY_B] = 0x42; //0x05 // Keyboard b and B + kbNames[KEY_C] = 0x43; //0x06 // Keyboard c and C + kbNames[KEY_D] = 0x44; //0x07 // Keyboard d and D + kbNames[KEY_E] = 0x45; //0x08 // Keyboard e and E + kbNames[KEY_F] = 0x46; //0x09 // Keyboard f and F + kbNames[KEY_G] = 0x47; //0x0a // Keyboard g and G + kbNames[KEY_H] = 0x48; //0x0b // Keyboard h and H + kbNames[KEY_I] = 0x49; //0x0c // Keyboard i and I + kbNames[KEY_J] = 0x4A; //0x0d // Keyboard j and J + kbNames[KEY_K] = 0x4B; //0x0e // Keyboard k and K + kbNames[KEY_L] = 0x4C; //0x0f // Keyboard l and L + kbNames[KEY_M] = 0x4D; //0x10 // Keyboard m and M + kbNames[KEY_N] = 0x4E; //0x11 // Keyboard n and N + kbNames[KEY_O] = 0x4F; //0x12 // Keyboard o and O + kbNames[KEY_P] = 0x50; //0x13 // Keyboard p and P + kbNames[KEY_Q] = 0x51; //0x14 // Keyboard q and Q + kbNames[KEY_R] = 0x52; //0x15 // Keyboard r and R + kbNames[KEY_S] = 0x53; //0x16 // Keyboard s and S + kbNames[KEY_T] = 0x54; //0x17 // Keyboard t and T + kbNames[KEY_U] = 0x55; //0x18 // Keyboard u and U + kbNames[KEY_V] = 0x56; //0x19 // Keyboard v and V + kbNames[KEY_W] = 0x57; //0x1a // Keyboard w and W + kbNames[KEY_X] = 0x58; //0x1b // Keyboard x and X + kbNames[KEY_Y] = 0x59; //0x1c // Keyboard y and Y + kbNames[KEY_Z] = 0x60; //0x1d // Keyboard z and Z + + kbNames[KEY_1] = 0x31; //0x1e // Keyboard 1 and ! + kbNames[KEY_2] = 0x32; //0x1f // Keyboard 2 and @ + kbNames[KEY_3] = 0x33; //0x20 // Keyboard 3 and # + kbNames[KEY_4] = 0x34; //0x21 // Keyboard 4 and $ + kbNames[KEY_5] = 0x35; //0x22 // Keyboard 5 and % + kbNames[KEY_6] = 0x36; //0x23 // Keyboard 6 and ^ + kbNames[KEY_7] = 0x37; //0x24 // Keyboard 7 and & + kbNames[KEY_8] = 0x38; //0x25 // Keyboard 8 and * + kbNames[KEY_9] = 0x39; //0x26 // Keyboard 9 and ( + kbNames[KEY_0] = 0x30; //0x27 // Keyboard 0 and ) + + kbNames[KEY_ENTER] = 0xA; //0x28 // Keyboard Return (ENTER) + kbNames[KEY_ESC] = 0x1B; //0x29 // Keyboard ESCAPE + kbNames[KEY_BACKSPACE] = 0x8; //0x2a // Keyboard DELETE (Backspace) + kbNames[KEY_TAB] = 0x9; //0x2b // Keyboard Tab + kbNames[KEY_SPACE] = 0x20; //0x2c // Keyboard Spacebar + kbNames[KEY_MINUS] = 0x2D; //0x2d // Keyboard - and _ + kbNames[KEY_EQUAL] = 0xBB; //0x2e // Keyboard = and + + + kbNames[KEY_LEFTBRACE] = 0x5B; //0x2f // Keyboard [ and { + kbNames[KEY_RIGHTBRACE] = 0x5D; //0x30 // Keyboard ] and } + + kbNames[KEY_BACKSLASH] = 0x5C; //0x31 // Keyboard \ and | not in spanish + + kbNames[KEY_HASHTILDE] = 0x23; //0x32 // Keyboard Non-US # and ~ in spanish ? + + kbNames[KEY_SEMICOLON] = 0x3B; //0x33 // Keyboard ; and : + + kbNames[KEY_APOSTROPHE] = 0xDE; //0x34 // Keyboard ' and " + + kbNames[KEY_GRAVE] = 0x60; //0x35 // Keyboard ` and ~ in spanish ? + + kbNames[KEY_COMMA] = 0x2C; //0x36 // Keyboard , and < + + kbNames[KEY_DOT] = 0x2E; //0x37 // Keyboard . and > + + kbNames[KEY_SLASH] = 0x2F; //0x38 // Keyboard / and ? in spanish - +} \ No newline at end of file diff --git a/src/input/keyboard.h b/src/input/keyboard.h index 28132541b..1d7dbefa8 100644 --- a/src/input/keyboard.h +++ b/src/input/keyboard.h @@ -17,6 +17,166 @@ * along with Moonlight; if not, see . */ +#define KEY_NONE 0x00 // No key pressed +#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key") + // 0x02 // Keyboard POST Fail + // 0x03 // Keyboard Error Undefined +#define KEY_A 0x04 // Keyboard a and A +#define KEY_B 0x05 // Keyboard b and B +#define KEY_C 0x06 // Keyboard c and C +#define KEY_D 0x07 // Keyboard d and D +#define KEY_E 0x08 // Keyboard e and E +#define KEY_F 0x09 // Keyboard f and F +#define KEY_G 0x0a // Keyboard g and G +#define KEY_H 0x0b // Keyboard h and H +#define KEY_I 0x0c // Keyboard i and I +#define KEY_J 0x0d // Keyboard j and J +#define KEY_K 0x0e // Keyboard k and K +#define KEY_L 0x0f // Keyboard l and L +#define KEY_M 0x10 // Keyboard m and M +#define KEY_N 0x11 // Keyboard n and N +#define KEY_O 0x12 // Keyboard o and O +#define KEY_P 0x13 // Keyboard p and P +#define KEY_Q 0x14 // Keyboard q and Q +#define KEY_R 0x15 // Keyboard r and R +#define KEY_S 0x16 // Keyboard s and S +#define KEY_T 0x17 // Keyboard t and T +#define KEY_U 0x18 // Keyboard u and U +#define KEY_V 0x19 // Keyboard v and V +#define KEY_W 0x1a // Keyboard w and W +#define KEY_X 0x1b // Keyboard x and X +#define KEY_Y 0x1c // Keyboard y and Y +#define KEY_Z 0x1d // Keyboard z and Z + +#define KEY_1 0x1e // Keyboard 1 and ! +#define KEY_2 0x1f // Keyboard 2 and @ +#define KEY_3 0x20 // Keyboard 3 and # +#define KEY_4 0x21 // Keyboard 4 and $ +#define KEY_5 0x22 // Keyboard 5 and % +#define KEY_6 0x23 // Keyboard 6 and ^ +#define KEY_7 0x24 // Keyboard 7 and & +#define KEY_8 0x25 // Keyboard 8 and * +#define KEY_9 0x26 // Keyboard 9 and ( +#define KEY_0 0x27 // Keyboard 0 and ) + +#define KEY_ENTER 0x28 // Keyboard Return (ENTER) +#define KEY_ESC 0x29 // Keyboard ESCAPE +#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace) +#define KEY_TAB 0x2b // Keyboard Tab +#define KEY_SPACE 0x2c // Keyboard Spacebar +#define KEY_MINUS 0x2d // Keyboard - and _ +#define KEY_EQUAL 0x2e // Keyboard = and + +#define KEY_LEFTBRACE 0x2f // Keyboard [ and { +#define KEY_RIGHTBRACE 0x30 // Keyboard ] and } +#define KEY_BACKSLASH 0x31 // Keyboard \ and | +#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~ +#define KEY_SEMICOLON 0x33 // Keyboard ; and : +#define KEY_APOSTROPHE 0x34 // Keyboard ' and " +#define KEY_GRAVE 0x35 // Keyboard ` and ~ +#define KEY_COMMA 0x36 // Keyboard , and < +#define KEY_DOT 0x37 // Keyboard . and > +#define KEY_SLASH 0x38 // Keyboard / and ? +#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock + +#define KEY_F1 0x3a // Keyboard F1 +#define KEY_F2 0x3b // Keyboard F2 +#define KEY_F3 0x3c // Keyboard F3 +#define KEY_F4 0x3d // Keyboard F4 +#define KEY_F5 0x3e // Keyboard F5 +#define KEY_F6 0x3f // Keyboard F6 +#define KEY_F7 0x40 // Keyboard F7 +#define KEY_F8 0x41 // Keyboard F8 +#define KEY_F9 0x42 // Keyboard F9 +#define KEY_F10 0x43 // Keyboard F10 +#define KEY_F11 0x44 // Keyboard F11 +#define KEY_F12 0x45 // Keyboard F12 + +#define KEY_SYSRQ 0x46 // Keyboard Print Screen +#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock +#define KEY_PAUSE 0x48 // Keyboard Pause +#define KEY_INSERT 0x49 // Keyboard Insert +#define KEY_HOME 0x4a // Keyboard Home +#define KEY_PAGEUP 0x4b // Keyboard Page Up +#define KEY_DELETE 0x4c // Keyboard Delete Forward +#define KEY_END 0x4d // Keyboard End +#define KEY_PAGEDOWN 0x4e // Keyboard Page Down +#define KEY_RIGHT 0x4f // Keyboard Right Arrow +#define KEY_LEFT 0x50 // Keyboard Left Arrow +#define KEY_DOWN 0x51 // Keyboard Down Arrow +#define KEY_UP 0x52 // Keyboard Up Arrow + +#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear +#define KEY_KPSLASH 0x54 // Keypad / +#define KEY_KPASTERISK 0x55 // Keypad * +#define KEY_KPMINUS 0x56 // Keypad - +#define KEY_KPPLUS 0x57 // Keypad + +#define KEY_KPENTER 0x58 // Keypad ENTER +#define KEY_KP1 0x59 // Keypad 1 and End +#define KEY_KP2 0x5a // Keypad 2 and Down Arrow +#define KEY_KP3 0x5b // Keypad 3 and PageDn +#define KEY_KP4 0x5c // Keypad 4 and Left Arrow +#define KEY_KP5 0x5d // Keypad 5 +#define KEY_KP6 0x5e // Keypad 6 and Right Arrow +#define KEY_KP7 0x5f // Keypad 7 and Home +#define KEY_KP8 0x60 // Keypad 8 and Up Arrow +#define KEY_KP9 0x61 // Keypad 9 and Page Up +#define KEY_KP0 0x62 // Keypad 0 and Insert +#define KEY_KPDOT 0x63 // Keypad . and Delete + +#define KEY_102ND 0x64 // Keyboard Non-US \ and | +#define KEY_COMPOSE 0x65 // Keyboard Application +#define KEY_POWER 0x66 // Keyboard Power +#define KEY_KPEQUAL 0x67 // Keypad = + +#define KEY_F13 0x68 // Keyboard F13 +#define KEY_F14 0x69 // Keyboard F14 +#define KEY_F15 0x6a // Keyboard F15 +#define KEY_F16 0x6b // Keyboard F16 +#define KEY_F17 0x6c // Keyboard F17 +#define KEY_F18 0x6d // Keyboard F18 +#define KEY_F19 0x6e // Keyboard F19 +#define KEY_F20 0x6f // Keyboard F20 +#define KEY_F21 0x70 // Keyboard F21 +#define KEY_F22 0x71 // Keyboard F22 +#define KEY_F23 0x72 // Keyboard F23 +#define KEY_F24 0x73 // Keyboard F24 + +#define KEY_OPEN 0x74 // Keyboard Execute +#define KEY_HELP 0x75 // Keyboard Help +#define KEY_PROPS 0x76 // Keyboard Menu +#define KEY_FRONT 0x77 // Keyboard Select +#define KEY_STOP 0x78 // Keyboard Stop +#define KEY_AGAIN 0x79 // Keyboard Again +#define KEY_UNDO 0x7a // Keyboard Undo +#define KEY_CUT 0x7b // Keyboard Cut +#define KEY_COPY 0x7c // Keyboard Copy +#define KEY_PASTE 0x7d // Keyboard Paste +#define KEY_FIND 0x7e // Keyboard Find +#define KEY_MUTE 0x7f // Keyboard Mute +#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up +#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down +// 0x82 Keyboard Locking Caps Lock +// 0x83 Keyboard Locking Num Lock +// 0x84 Keyboard Locking Scroll Lock +#define KEY_KPCOMMA 0x85 // Keypad Comma +// 0x86 Keypad Equal Sign +#define KEY_RO 0x87 // Keyboard International1 +#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2 +#define KEY_YEN 0x89 // Keyboard International3 +#define KEY_HENKAN 0x8a // Keyboard International4 +#define KEY_MUHENKAN 0x8b // Keyboard International5 +#define KEY_KPJPCOMMA 0x8c // Keyboard International6 +// 0x8d Keyboard International7 +// 0x8e Keyboard International8 +// 0x8f Keyboard International9 +#define KEY_HANGEUL 0x90 // Keyboard LANG1 +#define KEY_HANJA 0x91 // Keyboard LANG2 +#define KEY_KATAKANA 0x92 // Keyboard LANG3 +#define KEY_HIRAGANA 0x93 // Keyboard LANG4 +#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5 + +static SceUInt16 kbNames[256]; + static const short keyCodes[] = { 0, //VK_RESERVED 0x1B, //VK_ESCAPE @@ -140,3 +300,5 @@ static const short keyCodes[] = { 0x13, //VK_PAUSE 0, //VK_SCALE AL Compiz Scale (Expose) }; + +void vitainput_kb_init_names(); diff --git a/src/input/mapping.c b/src/input/mapping.c index ea9777eed..41283ee20 100644 --- a/src/input/mapping.c +++ b/src/input/mapping.c @@ -1,166 +1,174 @@ -/* - * This file is part of Moonlight Embedded. - * - * Copyright (C) 2015 Iwan Timmer - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#include "mapping.h" - -#include -#include -#include - -#define write_config(fd, key, value) fprintf(fd, "%s = %x\n", key, value) -#define write_config_bool(fd, key, value) fprintf(fd, "%s = %s\n", key, value?"true":"false"); - -void mapping_load(char* fileName, struct mapping* map) { - FILE* fd = fopen(fileName, "r"); - if (fd == NULL) { - printf("Can't open mapping file: %s\n", fileName); - return; - } - - char *line = NULL; - size_t len = 0; - while (__getline(&line, &len, fd) != -1) { - char key[256], value[256]; - if (sscanf(line, "%s = %s", &key, &value) == 2) { - long int_value = strtol(value, NULL, 16); - if (strcmp("abs_x", key) == 0) - map->abs_x = int_value; - else if (strcmp("abs_y", key) == 0) - map->abs_y = int_value; - else if (strcmp("abs_z", key) == 0) - map->abs_z = int_value; - else if (strcmp("abs_rx", key) == 0) - map->abs_rx = int_value; - else if (strcmp("abs_ry", key) == 0) - map->abs_ry = int_value; - else if (strcmp("abs_rz", key) == 0) - map->abs_rz = int_value; - else if (strcmp("abs_deadzone", key) == 0) - map->abs_deadzone = int_value; - else if (strcmp("abs_dpad_x", key) == 0) - map->abs_dpad_x = int_value; - else if (strcmp("abs_dpad_y", key) == 0) - map->abs_dpad_y = int_value; - else if (strcmp("btn_south", key) == 0) - map->btn_south = int_value; - else if (strcmp("btn_north", key) == 0) - map->btn_north = int_value; - else if (strcmp("btn_east", key) == 0) - map->btn_east = int_value; - else if (strcmp("btn_west", key) == 0) - map->btn_west = int_value; - else if (strcmp("btn_select", key) == 0) - map->btn_select = int_value; - else if (strcmp("btn_start", key) == 0) - map->btn_start = int_value; - else if (strcmp("btn_mode", key) == 0) - map->btn_mode = int_value; - else if (strcmp("btn_thumbl", key) == 0) - map->btn_thumbl = int_value; - else if (strcmp("btn_thumbr", key) == 0) - map->btn_thumbr = int_value; - else if (strcmp("btn_tl", key) == 0) - map->btn_tl = int_value; - else if (strcmp("btn_tr", key) == 0) - map->btn_tr = int_value; - else if (strcmp("btn_tl2", key) == 0) - map->btn_tl2 = int_value; - else if (strcmp("btn_tr2", key) == 0) - map->btn_tr2 = int_value; - else if (strcmp("btn_dpad_up", key) == 0) - map->btn_dpad_up = int_value; - else if (strcmp("btn_dpad_down", key) == 0) - map->btn_dpad_down = int_value; - else if (strcmp("btn_dpad_left", key) == 0) - map->btn_dpad_left = int_value; - else if (strcmp("btn_dpad_right", key) == 0) - map->btn_dpad_right = int_value; - else if (strcmp("reverse_x", key) == 0) - map->reverse_x = strcmp("true", value) == 0; - else if (strcmp("reverse_y", key) == 0) - map->reverse_y = strcmp("true", value) == 0; - else if (strcmp("reverse_rx", key) == 0) - map->reverse_rx = strcmp("true", value) == 0; - else if (strcmp("reverse_ry", key) == 0) - map->reverse_ry = strcmp("true", value) == 0; - else if (strcmp("reverse_dpad_x", key) == 0) - map->reverse_dpad_x = strcmp("true", value) == 0; - else if (strcmp("reverse_dpad_y", key) == 0) - map->reverse_dpad_y = strcmp("true", value) == 0; - else - fprintf(stderr, "Can't map (%s)\n", key); - } - } - free(line); - fclose(fd); -} - -void mapping_save(char* fileName, struct mapping* map) { - FILE* fd = fopen(fileName, "w"); - if (fd == NULL) { - fprintf(stderr, "Can't open mapping file: %s\n", fileName); - exit(EXIT_FAILURE); - } - - write_config(fd, "abs_x", map->abs_x); - write_config(fd, "abs_y", map->abs_y); - write_config(fd, "abs_z", map->abs_z); - - write_config_bool(fd, "reverse_x", map->reverse_x); - write_config_bool(fd, "reverse_y", map->reverse_y); - - write_config(fd, "abs_rx", map->abs_rx); - write_config(fd, "abs_ry", map->abs_ry); - write_config(fd, "abs_rz", map->abs_rz); - - write_config_bool(fd, "reverse_rx", map->reverse_rx); - write_config_bool(fd, "reverse_ry", map->reverse_ry); - - write_config(fd, "abs_deadzone", map->abs_deadzone); - - write_config(fd, "abs_dpad_x", map->abs_dpad_x); - write_config(fd, "abs_dpad_y", map->abs_dpad_y); - - write_config_bool(fd, "reverse_dpad_x", map->reverse_dpad_x); - write_config_bool(fd, "reverse_dpad_y", map->reverse_dpad_y); - - write_config(fd, "btn_north", map->btn_north); - write_config(fd, "btn_east", map->btn_east); - write_config(fd, "btn_south", map->btn_south); - write_config(fd, "btn_west", map->btn_west); - - write_config(fd, "btn_select", map->btn_select); - write_config(fd, "btn_start", map->btn_start); - write_config(fd, "btn_mode", map->btn_mode); - - write_config(fd, "btn_thumbl", map->btn_thumbl); - write_config(fd, "btn_thumbr", map->btn_thumbr); - - write_config(fd, "btn_tl", map->btn_tl); - write_config(fd, "btn_tr", map->btn_tr); - write_config(fd, "btn_tl2", map->btn_tl2); - write_config(fd, "btn_tr2", map->btn_tr2); - - write_config(fd, "btn_dpad_up", map->btn_dpad_up); - write_config(fd, "btn_dpad_down", map->btn_dpad_down); - write_config(fd, "btn_dpad_left", map->btn_dpad_left); - write_config(fd, "btn_dpad_right", map->btn_dpad_right); - - fclose(fd); -} +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015,2020 Iwan Timmer, Graphene + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include "mapping.h" +#include "../ini.h" +#include "../ini_file_processor_c.h" + +#include + +void mapping_load(char* fileName, struct mapping* map) { + + char iniProcContext[8]; + SceIniFileProcessorParam iniProcInitParam; + SceIniFileProcessorMemCallbacks iniAllocCb; + sceIniFileProcessorCreateContext(iniProcContext); + + sceIniFileProcessorInitializeParam(&iniProcInitParam); + sceIniFileProcessorCreateInstance(iniProcContext, &iniProcInitParam); + + int ret = sceIniFileProcessorOpenFile(iniProcContext, fileName, "r", 0); + if (ret < 0) { + sceIniFileProcessorDestroyInstanceForError(iniProcContext); + sceClibPrintf("sceIniFileProcessorOpenFile() returned 0x%X, %s\n", ret, fileName); + return; + } + + int int_value; + if (!iniGetValueByKey(iniProcContext, "abs_x", INI_VALUE_INT, 16, &int_value)) + map->abs_x = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_y", INI_VALUE_INT, 16, &int_value)) + map->abs_y = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_z", INI_VALUE_INT, 16, &int_value)) + map->abs_z = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_rx", INI_VALUE_INT, 16, &int_value)) + map->abs_rx = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_ry", INI_VALUE_INT, 16, &int_value)) + map->abs_ry = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_rz", INI_VALUE_INT, 16, &int_value)) + map->abs_rz = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_deadzone", INI_VALUE_INT, 16, &int_value)) + map->abs_deadzone = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_dpad_x", INI_VALUE_INT, 16, &int_value)) + map->abs_dpad_x = int_value; + if (!iniGetValueByKey(iniProcContext, "abs_dpad_y", INI_VALUE_INT, 16, &int_value)) + map->abs_dpad_y = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_south", INI_VALUE_INT, 16, &int_value)) + map->btn_south = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_north", INI_VALUE_INT, 16, &int_value)) + map->btn_north = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_east", INI_VALUE_INT, 16, &int_value)) + map->btn_east = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_west", INI_VALUE_INT, 16, &int_value)) + map->btn_west = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_select", INI_VALUE_INT, 16, &int_value)) + map->btn_select = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_start", INI_VALUE_INT, 16, &int_value)) + map->btn_start = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_mode", INI_VALUE_INT, 16, &int_value)) + map->btn_mode = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_thumbl", INI_VALUE_INT, 16, &int_value)) + map->btn_thumbl = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_thumbr", INI_VALUE_INT, 16, &int_value)) + map->btn_thumbr = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_tl", INI_VALUE_INT, 16, &int_value)) + map->btn_tl = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_tr", INI_VALUE_INT, 16, &int_value)) + map->btn_tr = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_tl2", INI_VALUE_INT, 16, &int_value)) + map->btn_tl2 = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_tr2", INI_VALUE_INT, 16, &int_value)) + map->btn_tr2 = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_dpad_up", INI_VALUE_INT, 16, &int_value)) + map->btn_dpad_up = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_dpad_down", INI_VALUE_INT, 16, &int_value)) + map->btn_dpad_down = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_dpad_left", INI_VALUE_INT, 16, &int_value)) + map->btn_dpad_left = int_value; + if (!iniGetValueByKey(iniProcContext, "btn_dpad_right", INI_VALUE_INT, 16, &int_value)) + map->btn_dpad_right = int_value; + if (!iniGetValueByKey(iniProcContext, "reverse_x", INI_VALUE_BOOL, 16, &int_value)) + map->reverse_x = int_value; + if (!iniGetValueByKey(iniProcContext, "reverse_y", INI_VALUE_BOOL, 16, &int_value)) + map->reverse_y = int_value; + if (!iniGetValueByKey(iniProcContext, "reverse_rx", INI_VALUE_BOOL, 16, &int_value)) + map->reverse_rx = int_value; + if (!iniGetValueByKey(iniProcContext, "reverse_ry", INI_VALUE_BOOL, 16, &int_value)) + map->reverse_ry = int_value; + if (!iniGetValueByKey(iniProcContext, "reverse_dpad_x", INI_VALUE_BOOL, 16, &int_value)) + map->reverse_dpad_x = int_value; + if (!iniGetValueByKey(iniProcContext, "reverse_dpad_y", INI_VALUE_BOOL, 16, &int_value)) + map->reverse_dpad_y = int_value; + + sceIniFileProcessorFinalize(iniProcContext); +} + +void mapping_save(char* fileName, struct mapping* map) { + + char iniProcContext[8]; + SceIniFileProcessorParam iniProcInitParam; + SceIniFileProcessorMemCallbacks iniAllocCb; + sceIniFileProcessorCreateContext(iniProcContext); + + sceIniFileProcessorInitializeParam(&iniProcInitParam); + sceIniFileProcessorCreateInstance(iniProcContext, &iniProcInitParam); + + int ret = sceIniFileProcessorCreateFile(iniProcContext, fileName, "rw", 0); + if (ret < 0) { + sceIniFileProcessorDestroyInstanceForError(iniProcContext); + sceClibPrintf("sceIniFileProcessorCreateFile() returned 0x%X, %s\n", ret, fileName); + return; + } + + iniCreateSetKey(iniProcContext, "abs_x", INI_VALUE_HEX, map->abs_x); + iniCreateSetKey(iniProcContext, "abs_y", INI_VALUE_HEX, map->abs_y); + iniCreateSetKey(iniProcContext, "abs_z", INI_VALUE_HEX, map->abs_z); + + iniCreateSetKey(iniProcContext, "reverse_x", INI_VALUE_BOOL, map->reverse_x); + iniCreateSetKey(iniProcContext, "reverse_y", INI_VALUE_BOOL, map->reverse_y); + + iniCreateSetKey(iniProcContext, "abs_rx", INI_VALUE_HEX, map->abs_rx); + iniCreateSetKey(iniProcContext, "abs_ry", INI_VALUE_HEX, map->abs_ry); + iniCreateSetKey(iniProcContext, "abs_rz", INI_VALUE_HEX, map->abs_rz); + + iniCreateSetKey(iniProcContext, "reverse_rx", INI_VALUE_BOOL, map->reverse_rx); + iniCreateSetKey(iniProcContext, "reverse_ry", INI_VALUE_BOOL, map->reverse_ry); + + iniCreateSetKey(iniProcContext, "abs_deadzone", INI_VALUE_HEX, map->abs_deadzone); + + iniCreateSetKey(iniProcContext, "abs_dpad_x", INI_VALUE_HEX, map->abs_dpad_x); + iniCreateSetKey(iniProcContext, "abs_dpad_y", INI_VALUE_HEX, map->abs_dpad_y); + + iniCreateSetKey(iniProcContext, "reverse_dpad_x", INI_VALUE_BOOL, map->reverse_dpad_x); + iniCreateSetKey(iniProcContext, "reverse_dpad_y", INI_VALUE_BOOL, map->reverse_dpad_y); + + iniCreateSetKey(iniProcContext, "btn_north", INI_VALUE_HEX, map->btn_north); + iniCreateSetKey(iniProcContext, "btn_east", INI_VALUE_HEX, map->btn_east); + iniCreateSetKey(iniProcContext, "btn_south", INI_VALUE_HEX, map->btn_south); + iniCreateSetKey(iniProcContext, "btn_west", INI_VALUE_HEX, map->btn_west); + + iniCreateSetKey(iniProcContext, "btn_select", INI_VALUE_HEX, map->btn_select); + iniCreateSetKey(iniProcContext, "btn_start", INI_VALUE_HEX, map->btn_start); + iniCreateSetKey(iniProcContext, "btn_mode", INI_VALUE_HEX, map->btn_mode); + + iniCreateSetKey(iniProcContext, "btn_thumbl", INI_VALUE_HEX, map->btn_thumbl); + iniCreateSetKey(iniProcContext, "btn_thumbr", INI_VALUE_HEX, map->btn_thumbr); + + iniCreateSetKey(iniProcContext, "btn_tl", INI_VALUE_HEX, map->btn_tl); + iniCreateSetKey(iniProcContext, "btn_tr", INI_VALUE_HEX, map->btn_tr); + iniCreateSetKey(iniProcContext, "btn_tl2", INI_VALUE_HEX, map->btn_tl2); + iniCreateSetKey(iniProcContext, "btn_tr2", INI_VALUE_HEX, map->btn_tr2); + + iniCreateSetKey(iniProcContext, "btn_dpad_up", INI_VALUE_HEX, map->btn_dpad_up); + iniCreateSetKey(iniProcContext, "btn_dpad_down", INI_VALUE_HEX, map->btn_dpad_down); + iniCreateSetKey(iniProcContext, "btn_dpad_left", INI_VALUE_HEX, map->btn_dpad_left); + iniCreateSetKey(iniProcContext, "btn_dpad_right", INI_VALUE_HEX, map->btn_dpad_right); + + sceIniFileProcessorFinalize(iniProcContext); +} diff --git a/src/input/vita.c b/src/input/vita.c index 5398929a5..88ddbec7d 100644 --- a/src/input/vita.c +++ b/src/input/vita.c @@ -1,588 +1,608 @@ -/* - * This file is part of Moonlight Embedded. - * - * Copyright (C) 2016 Ilya Zhuravlev, Sunguk Lee, Vasyl Horbachenko - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../graphics.h" -#include "../config.h" -#include "../connection.h" -#include "vita.h" -#include "mapping.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#define WIDTH 960 -#define HEIGHT 544 - -struct mapping map = {0}; - -typedef struct input_data { - short button; - short lx; - short ly; - short rx; - short ry; - char lt; - char rt; -} input_data; - -typedef struct Point { - short x; - short y; -} Point; - -typedef struct Section { - Point left; - Point right; -} Section; - -typedef struct TouchData { - short button; - short finger; - Point points[4]; -} TouchData; - -#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10) - -double mouse_multiplier; - -#define MOUSE_ACTION_DELAY 100000 // 100ms - -inline bool mouse_click(short finger_count, bool press) { - int mode; - - if (press) { - mode = BUTTON_ACTION_PRESS; - } else { - mode = BUTTON_ACTION_RELEASE; - } - - switch (finger_count) { - case 1: - LiSendMouseButtonEvent(mode, BUTTON_LEFT); - return true; - case 2: - LiSendMouseButtonEvent(mode, BUTTON_RIGHT); - return true; - } - return false; -} - -inline void move_mouse(TouchData old, TouchData cur) { - double delta_x = (cur.points[0].x - old.points[0].x) / 2.; - double delta_y = (cur.points[0].y - old.points[0].y) / 2.; - - if (delta_x == 0 && delta_y == 0) { - return; - } - - int x = lround(delta_x * mouse_multiplier); - int y = lround(delta_y * mouse_multiplier); - - LiSendMouseMoveEvent(x, y); -} - -inline void move_wheel(TouchData old, TouchData cur) { - int old_y = (old.points[0].y + old.points[1].y) / 2; - int cur_y = (cur.points[0].y + cur.points[1].y) / 2; - int delta_y = (cur_y - old_y) / 2; - if (!delta_y) { - return; - } - LiSendScrollEvent(delta_y); -} - -SceCtrlData pad, pad_old; -TouchData touch; -TouchData touch_old, swipe; -SceTouchData front, back; - -int front_state = NO_TOUCH_ACTION; -short finger_count = 0; -SceRtcTick current, until; - - -static int special_status; - -input_data curr, old; -int controller_port; - -// TODO config -static int VERTICAL; -static int HORIZONTAL; - -#define IN_SECTION(SECTION, X, Y) \ - ((SECTION).left.x <= (X) && (X) <= (SECTION).right.x && \ - (SECTION).left.y <= (Y) && (Y) <= (SECTION).right.y) - -// TODO sections -Section BACK_SECTIONS[4]; -Section FRONT_SECTIONS[4]; - -inline uint8_t read_backscreen() { - for (int i = 0; i < back.reportNum; i++) { - int x = lerp(back.report[i].x, 1919, WIDTH); - int y = lerp(back.report[i].y, 1087, HEIGHT); - - if ((touch.button & TOUCHSEC_NORTHWEST) == 0) { - if (IN_SECTION(BACK_SECTIONS[0], x, y)) { - touch.button |= TOUCHSEC_NORTHWEST; - continue; - } - } - - if ((touch.button & TOUCHSEC_NORTHEAST) == 0) { - if (IN_SECTION(BACK_SECTIONS[1], x, y)) { - touch.button |= TOUCHSEC_NORTHEAST; - continue; - } - } - - if ((touch.button & TOUCHSEC_SOUTHWEST) == 0) { - if (IN_SECTION(BACK_SECTIONS[2], x, y)) { - touch.button |= TOUCHSEC_SOUTHWEST; - continue; - } - } - - if ((touch.button & TOUCHSEC_SOUTHEAST) == 0) { - if (IN_SECTION(BACK_SECTIONS[3], x, y)) { - touch.button |= TOUCHSEC_SOUTHEAST; - continue; - } - } - } - return 0; -} - - -inline uint8_t read_frontscreen() { - for (int i = 0; i < front.reportNum; i++) { - int x = lerp(front.report[i].x, 1919, WIDTH); - int y = lerp(front.report[i].y, 1087, HEIGHT); - - if ((touch.button & TOUCHSEC_SPECIAL_NW) == 0) { - if (IN_SECTION(FRONT_SECTIONS[0], x, y)) { - touch.button |= TOUCHSEC_SPECIAL_NW; - continue; - } - } - - if ((touch.button & TOUCHSEC_SPECIAL_NE) == 0) { - if (IN_SECTION(FRONT_SECTIONS[1], x, y)) { - touch.button |= TOUCHSEC_SPECIAL_NE; - continue; - } - } - - if ((touch.button & TOUCHSEC_SPECIAL_SW) == 0) { - if (IN_SECTION(FRONT_SECTIONS[2], x, y)) { - touch.button |= TOUCHSEC_SPECIAL_SW; - continue; - } - } - - if ((touch.button & TOUCHSEC_SPECIAL_SE) == 0) { - if (IN_SECTION(FRONT_SECTIONS[3], x, y)) { - touch.button |= TOUCHSEC_SPECIAL_SE; - continue; - } - } - - // FIXME if touch same section using multiple finger, they can count finger - touch.points[touch.finger].x = x; - touch.points[touch.finger].y = y; - touch.finger += 1; - } - return 0; -} - -inline uint32_t is_pressed(uint32_t defined) { - uint32_t dev_type = defined & INPUT_TYPE_MASK; - uint32_t dev_val = defined & INPUT_VALUE_MASK; - - switch(dev_type) { - case INPUT_TYPE_GAMEPAD: - return pad.buttons & dev_val; - case INPUT_TYPE_TOUCHSCREEN: - return touch.button & dev_val; - } - return 0; -} - -inline uint32_t is_old_pressed(uint32_t defined) { - uint32_t dev_type = defined & INPUT_TYPE_MASK; - uint32_t dev_val = defined & INPUT_VALUE_MASK; - - switch(dev_type) { - case INPUT_TYPE_GAMEPAD: - return pad_old.buttons & dev_val; - case INPUT_TYPE_TOUCHSCREEN: - return touch_old.button & dev_val; - } - return 0; -} - -inline short read_analog(uint32_t defined) { - uint32_t dev_type = defined & INPUT_TYPE_MASK; - uint32_t dev_val = defined & INPUT_VALUE_MASK; - - if (dev_type == INPUT_TYPE_ANALOG) { - int v; - switch(dev_val) { - case LEFTX: - v = pad.lx; - break; - case LEFTY: - v = pad.ly; - break; - case RIGHTX: - v = pad.rx; - break; - case RIGHTY: - v = pad.ry; - break; - case LEFT_TRIGGER: - return pad.lt; - case RIGHT_TRIGGER: - return pad.rt; - default: - return 0; - } - v = v * 256 - (1 << 15) + 128; - return (short)(v); - } - return is_pressed(defined) ? 0xff : 0; -} - -inline void special(uint32_t defined, uint32_t pressed, uint32_t old_pressed) { - uint32_t dev_type = defined & INPUT_TYPE_MASK; - uint32_t dev_val = defined & INPUT_VALUE_MASK; - - if (pressed) { - switch(dev_type) { - case INPUT_TYPE_SPECIAL: - if (dev_val == INPUT_SPECIAL_KEY_PAUSE) { - connection_minimize(); - return; - } - case INPUT_TYPE_GAMEPAD: - curr.button |= dev_val; - return; - case INPUT_TYPE_ANALOG: - switch(dev_val) { - case LEFT_TRIGGER: - curr.lt = 0xff; - return; - case RIGHT_TRIGGER: - curr.rt = 0xff; - return; - } - return; - case INPUT_TYPE_MOUSE: - if (!old_pressed) { - LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, dev_val); - } - return; - case INPUT_TYPE_KEYBOARD: - if (!old_pressed) { - LiSendKeyboardEvent(dev_val, KEY_ACTION_DOWN, 0); - } - return; - } - } else { - // released - switch(dev_type) { - case INPUT_TYPE_MOUSE: - if (old_pressed) { - LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, dev_val); - } - return; - case INPUT_TYPE_KEYBOARD: - if (old_pressed) { - LiSendKeyboardEvent(dev_val, KEY_ACTION_UP, 0); - } - return; - } - } - -} - -static inline void vitainput_process(void) { - memset(&pad, 0, sizeof(pad)); - memset(&touch, 0, sizeof(TouchData)); - memset(&curr, 0, sizeof(input_data)); - - sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); - sceCtrlPeekBufferPositiveExt2(controller_port, &pad, 1); - - sceTouchPeek(SCE_TOUCH_PORT_FRONT, &front, 1); - sceTouchPeek(SCE_TOUCH_PORT_BACK, &back, 1); - read_frontscreen(); - read_backscreen(); - - sceRtcGetCurrentTick(¤t); - - // buttons - curr.button |= is_pressed(map.btn_dpad_up) ? UP_FLAG : 0; - curr.button |= is_pressed(map.btn_dpad_left) ? LEFT_FLAG : 0; - curr.button |= is_pressed(map.btn_dpad_down) ? DOWN_FLAG : 0; - curr.button |= is_pressed(map.btn_dpad_right) ? RIGHT_FLAG : 0; - curr.button |= is_pressed(map.btn_start) ? PLAY_FLAG : 0; - curr.button |= is_pressed(map.btn_select) ? BACK_FLAG : 0; - curr.button |= is_pressed(map.btn_north) ? Y_FLAG : 0; - curr.button |= is_pressed(map.btn_east) ? B_FLAG : 0; - curr.button |= is_pressed(map.btn_south) ? A_FLAG : 0; - curr.button |= is_pressed(map.btn_west) ? X_FLAG : 0; - curr.button |= is_pressed(map.btn_thumbl) ? LB_FLAG : 0; // l1 - curr.button |= is_pressed(map.btn_thumbr) ? RB_FLAG : 0; // r1 - curr.button |= is_pressed(map.btn_tl2) ? LS_CLK_FLAG : 0; // l3 - curr.button |= is_pressed(map.btn_tr2) ? RS_CLK_FLAG : 0; // r3 - - // analogs - curr.lt = read_analog(map.btn_tl); // l2 - curr.rt = read_analog(map.btn_tr); // r2 - curr.lx = read_analog(map.abs_x); - curr.ly = read_analog(map.abs_y); - curr.rx = read_analog(map.abs_rx); - curr.ry = read_analog(map.abs_ry); - - // special touchscreen buttons - special(config.special_keys.nw, - is_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_NW), - is_old_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_NW)); - special(config.special_keys.ne, - is_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_NE), - is_old_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_NE)); - special(config.special_keys.sw, - is_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_SW), - is_old_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_SW)); - special(config.special_keys.se, - is_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_SE), - is_old_pressed(INPUT_TYPE_TOUCHSCREEN | TOUCHSEC_SPECIAL_SE)); - - // mouse - switch (front_state) { - case NO_TOUCH_ACTION: - if (touch.finger > 0) { - front_state = ON_SCREEN_TOUCH; - finger_count = touch.finger; - sceRtcTickAddMicroseconds(&until, ¤t, MOUSE_ACTION_DELAY); - } - break; - case ON_SCREEN_TOUCH: - if (sceRtcCompareTick(¤t, &until) < 0) { - if (touch.finger < finger_count) { - // TAP - if (mouse_click(finger_count, true)) { - front_state = SCREEN_TAP; - sceRtcTickAddMicroseconds(&until, ¤t, MOUSE_ACTION_DELAY); - } else { - front_state = NO_TOUCH_ACTION; - } - } else if (touch.finger > finger_count) { - // finger count changed - finger_count = touch.finger; - } - } else { - front_state = SWIPE_START; - } - break; - case SCREEN_TAP: - if (sceRtcCompareTick(¤t, &until) >= 0) { - mouse_click(finger_count, false); - - front_state = NO_TOUCH_ACTION; - } - break; - case SWIPE_START: - memcpy(&swipe, &touch, sizeof(swipe)); - front_state = ON_SCREEN_SWIPE; - break; - case ON_SCREEN_SWIPE: - if (touch.finger > 0) { - switch (touch.finger) { - case 1: - move_mouse(swipe, touch); - break; - case 2: - move_wheel(swipe, touch); - break; - } - memcpy(&swipe, &touch, sizeof(swipe)); - } else { - front_state = NO_TOUCH_ACTION; - } - break; - } - - if (memcmp(&curr, &old, sizeof(input_data)) != 0) { - LiSendControllerEvent(curr.button, curr.lt, curr.rt, - curr.lx, -1 * curr.ly, curr.rx, -1 * curr.ry); - memcpy(&old, &curr, sizeof(input_data)); - memcpy(&pad_old, &pad, sizeof(SceCtrlData)); - } - if (memcmp(&touch, &touch_old, sizeof(TouchData)) != 0) { - memcpy(&touch_old, &touch, sizeof(TouchData)); - } -} - -static uint8_t active_input_thread = 0; - -int vitainput_thread(SceSize args, void *argp) { - while (1) { - if (active_input_thread) { - vitainput_process(); - } - - sceKernelDelayThread(5000); // 5 ms - } - - return 0; -} - -bool vitainput_init() { - sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); - sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START); - sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START); - - SceUID thid = sceKernelCreateThread("vitainput_thread", vitainput_thread, 0, 0x40000, 0, 0, NULL); - if (thid >= 0) { - sceKernelStartThread(thid, 0, NULL); - return true; - } - - return false; -} - -void vitainput_config(CONFIGURATION config) { - map.abs_x = LEFTX | INPUT_TYPE_ANALOG; - map.abs_y = LEFTY | INPUT_TYPE_ANALOG; - map.abs_rx = RIGHTX | INPUT_TYPE_ANALOG; - map.abs_ry = RIGHTY | INPUT_TYPE_ANALOG; - - map.btn_dpad_up = SCE_CTRL_UP | INPUT_TYPE_GAMEPAD; - map.btn_dpad_down = SCE_CTRL_DOWN | INPUT_TYPE_GAMEPAD; - map.btn_dpad_left = SCE_CTRL_LEFT | INPUT_TYPE_GAMEPAD; - map.btn_dpad_right = SCE_CTRL_RIGHT | INPUT_TYPE_GAMEPAD; - map.btn_south = SCE_CTRL_CROSS | INPUT_TYPE_GAMEPAD; - map.btn_east = SCE_CTRL_CIRCLE | INPUT_TYPE_GAMEPAD; - map.btn_north = SCE_CTRL_TRIANGLE | INPUT_TYPE_GAMEPAD; - map.btn_west = SCE_CTRL_SQUARE | INPUT_TYPE_GAMEPAD; - - map.btn_select = SCE_CTRL_SELECT | INPUT_TYPE_GAMEPAD; - map.btn_start = SCE_CTRL_START | INPUT_TYPE_GAMEPAD; - - map.btn_thumbl = SCE_CTRL_L1 | INPUT_TYPE_GAMEPAD; - map.btn_thumbr = SCE_CTRL_R1 | INPUT_TYPE_GAMEPAD; - - if (config.model == SCE_KERNEL_MODEL_VITATV) { - map.btn_tl = LEFT_TRIGGER | INPUT_TYPE_ANALOG; - map.btn_tr = RIGHT_TRIGGER | INPUT_TYPE_ANALOG; - map.btn_tl2 = SCE_CTRL_L3 | INPUT_TYPE_GAMEPAD; - map.btn_tr2 = SCE_CTRL_R3 | INPUT_TYPE_GAMEPAD; - } else { - map.btn_tl = TOUCHSEC_NORTHWEST | INPUT_TYPE_TOUCHSCREEN; - map.btn_tr = TOUCHSEC_NORTHEAST | INPUT_TYPE_TOUCHSCREEN; - map.btn_tl2 = TOUCHSEC_SOUTHWEST | INPUT_TYPE_TOUCHSCREEN; - map.btn_tr2 = TOUCHSEC_SOUTHEAST | INPUT_TYPE_TOUCHSCREEN; - } - - if (config.mapping) { - char mapping_file_path[256]; - sprintf(mapping_file_path, "ux0:data/moonlight/%s", config.mapping); - printf("Loading mapping at %s\n", mapping_file_path); - mapping_load(mapping_file_path, &map); - } - - controller_port = config.model == SCE_KERNEL_MODEL_VITATV ? 1 : 0; - - VERTICAL = (WIDTH - config.back_deadzone.left - config.back_deadzone.right) / 2 - + config.back_deadzone.left; - HORIZONTAL = (HEIGHT - config.back_deadzone.top - config.back_deadzone.bottom) / 2 - + config.back_deadzone.top; - - BACK_SECTIONS[0].left.x = config.back_deadzone.left; - BACK_SECTIONS[0].left.y = config.back_deadzone.top; - BACK_SECTIONS[0].right.x = VERTICAL; - BACK_SECTIONS[0].right.y = HORIZONTAL; - - BACK_SECTIONS[1].left.x = VERTICAL; - BACK_SECTIONS[1].left.y = config.back_deadzone.top; - BACK_SECTIONS[1].right.x = WIDTH - config.back_deadzone.right; - BACK_SECTIONS[1].right.y = HORIZONTAL; - - BACK_SECTIONS[2].left.x = config.back_deadzone.left; - BACK_SECTIONS[2].left.y = HORIZONTAL; - BACK_SECTIONS[2].right.x = VERTICAL; - BACK_SECTIONS[2].right.y = HEIGHT - config.back_deadzone.bottom; - - BACK_SECTIONS[3].left.x = VERTICAL; - BACK_SECTIONS[3].left.y = HORIZONTAL; - BACK_SECTIONS[3].right.x = WIDTH - config.back_deadzone.right; - BACK_SECTIONS[3].right.y = HEIGHT - config.back_deadzone.bottom; - - FRONT_SECTIONS[0].left.x = config.special_keys.offset; - FRONT_SECTIONS[0].left.y = config.special_keys.offset; - FRONT_SECTIONS[0].right.x = config.special_keys.offset + config.special_keys.size; - FRONT_SECTIONS[0].right.y = config.special_keys.offset + config.special_keys.size; - - FRONT_SECTIONS[1].left.x = WIDTH - config.special_keys.offset - config.special_keys.size; - FRONT_SECTIONS[1].left.y = config.special_keys.offset; - FRONT_SECTIONS[1].right.x = WIDTH - config.special_keys.offset; - FRONT_SECTIONS[1].right.y = config.special_keys.offset + config.special_keys.size; - - FRONT_SECTIONS[2].left.x = config.special_keys.offset; - FRONT_SECTIONS[2].left.y = HEIGHT - config.special_keys.offset - config.special_keys.size; - FRONT_SECTIONS[2].right.x = config.special_keys.offset + config.special_keys.size; - FRONT_SECTIONS[2].right.y = HEIGHT - config.special_keys.offset; - - FRONT_SECTIONS[3].left.x = WIDTH - config.special_keys.offset - config.special_keys.size; - FRONT_SECTIONS[3].left.y = HEIGHT - config.special_keys.offset - config.special_keys.size; - FRONT_SECTIONS[3].right.x = WIDTH - config.special_keys.offset; - FRONT_SECTIONS[3].right.y = HEIGHT - config.special_keys.offset; - - mouse_multiplier = 1 + (0.01 * config.mouse_acceleration); -} - -void vitainput_start(void) { - active_input_thread = true; -} - -void vitainput_stop(void) { - active_input_thread = false; -} +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2016 Ilya Zhuravlev, Sunguk Lee, Vasyl Horbachenko + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../config.h" +#include "../connection.h" +#include "../platform.h" +#include "vita.h" +#include "mapping.h" +#include "keyboard.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define WIDTH 960 +#define HEIGHT 544 + +#define TOUCH_WIDTH 1920 +#define TOUCH_HEIGHT 1088 + +struct mapping map = {0}; + +typedef struct input_data { + short button; + short lx; + short ly; + short rx; + short ry; + char lt; + char rt; +} input_data; + +typedef struct Point { + short x; + short y; +} Point; + +typedef struct Section { + Point left; + Point right; +} Section; + +typedef struct BackTouchState { + int nw; + int ne; + int sw; + int se; +} BackTouchState; + +static SceSystemGestureTouchRecognizer *touch_recognizers; +static bool lhold_rec = false; +static bool scroll_rec = false; + +extern SceUID state_evf; +static unsigned int libime_work[SCE_IME_WORK_BUFFER_SIZE / sizeof(unsigned int)]; +static char libime_initval[8] = { 1 }; +static char libime_out[SCE_IME_MAX_PREEDIT_LENGTH * 2 + 8]; +static char libime_out_old[SCE_IME_MAX_PREEDIT_LENGTH * 2 + 8]; +static int caret_index_old = 0; +static SceImeCaret caret_rev; + +static SceUID keyboard_handle; +static SceUInt8 active_key[4]; +static bool hid_initialized = false; + +double mouse_multiplier; + +static void mouse_lhold(unsigned int reportNum) { + SceSystemGestureTouchEvent hold_event; + SceUInt32 event_num_buffer = 0; + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_MOUSE_LHOLD], &hold_event, 1, &event_num_buffer); + if (event_num_buffer > 0 && reportNum == 1 && hold_event.eventState == SCE_SYSTEM_GESTURE_TOUCH_STATE_BEGIN) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); + lhold_rec = true; + } + else if (lhold_rec && reportNum == 0) { + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + lhold_rec = false; + } +} + +static void mouse_click(unsigned int reportNum) { + SceSystemGestureTouchEvent tap_event; + SceUInt32 event_num_buffer = 0; + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_MOUSE_CLICK], &tap_event, 1, &event_num_buffer); + if (event_num_buffer > 0) + if (event_num_buffer > 0 && reportNum == 0) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + } + else if (event_num_buffer > 0 && reportNum == 1) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); + } +} + +static void mouse_move(unsigned int reportNum) { + SceSystemGestureTouchEvent drag_event; + SceUInt32 mouse_drag_touching = 0; + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_MOUSE_DRAG], &drag_event, 1, &mouse_drag_touching); + if (mouse_drag_touching > 0 && reportNum == 1) { + + int x = lround(drag_event.property.drag.deltaVector.x * mouse_multiplier); + int y = lround(drag_event.property.drag.deltaVector.y * mouse_multiplier); + + LiSendMouseMoveEvent(x, y); + } + else if (mouse_drag_touching > 0 && reportNum == 2) { + int delta = lround(drag_event.property.drag.deltaVector.y * 0.1f); + LiSendScrollEvent(delta); + if (lhold_rec) { + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + lhold_rec = false; + } + scroll_rec = true; + } + else if (scroll_rec && reportNum != 2) + scroll_rec = false; +} + +SceHidKeyboardReport kb_old, kb; +SceCtrlData pad, pad_old; +SceTouchData front, back; + +static int special_status; + +input_data curr, old; +BackTouchState back_touch_state; +int controller_port; + +static int VERTICAL; +static int HORIZONTAL; + +//Virtual IME string: |wchar0(dummy)||wchar1(dummy)|<-caret always returned to that position>|wchar2(value out)||wchar3(dummy)| +//Caret is always set to middle position so we can detect special keys like backspace +void vitainput_ime_event_handler(void *arg, const SceImeEvent *e) +{ + switch (e->id) { + case SCE_IME_EVENT_UPDATE_TEXT:; + if (e->param.text.caretIndex == 0) { + LiSendKeyboardEvent(0x08, KEY_ACTION_DOWN, 0); + LiSendKeyboardEvent(0x08, KEY_ACTION_UP, 0); + sceImeSetText((SceWChar16 *)libime_initval, 4); + } + else { + short upperchar = sceClibToupper(*(short *)&libime_out[2]); + LiSendKeyboardEvent(upperchar, KEY_ACTION_DOWN, 0); + LiSendKeyboardEvent(upperchar, KEY_ACTION_UP, 0); + sceClibMemset(&caret_rev, 0, sizeof(SceImeCaret)); + caret_rev.index = 1; + sceImeSetCaret(&caret_rev); + sceImeSetText((SceWChar16 *)libime_initval, 4); + } + break; + case SCE_IME_EVENT_PRESS_ENTER: + LiSendKeyboardEvent(0x0D, KEY_ACTION_DOWN, 0); + LiSendKeyboardEvent(0x0D, KEY_ACTION_UP, 0); + case SCE_IME_EVENT_PRESS_CLOSE: + sceImeClose(); + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_IS_IME); + break; + } +} + +void open_keyboard(void) { + + if (!sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_IS_IME, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) { + sceImeClose(); + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_IS_IME); + return; + } + + sceClibMemset(libime_out, 0, (SCE_IME_MAX_PREEDIT_LENGTH * 2 + 6)); + + SceImeParam param; + sceImeParamInit(¶m); + //param.supportedLanguages = 0; + param.languagesForced = false; + param.option = SCE_IME_OPTION_NO_ASSISTANCE | SCE_IME_OPTION_NO_AUTO_CAPITALIZATION; + param.filter = NULL; + param.work = libime_work; + param.arg = NULL; + param.type = SCE_IME_TYPE_DEFAULT; + param.inputTextBuffer = (SceWChar16 *)libime_out; + param.maxTextLength = 4; + param.handler = vitainput_ime_event_handler; + param.initialText = (SceWChar16 *)libime_initval; + sceImeOpen(¶m); + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_IS_IME); +} + +static void update_back_touch_state() { + SceSystemGestureTouchEvent drag_event; + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_BACK_NW], &drag_event, 1, &back_touch_state.nw); + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_BACK_NE], &drag_event, 1, &back_touch_state.ne); + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_BACK_SW], &drag_event, 1, &back_touch_state.sw); + sceSystemGestureGetTouchEvents(&touch_recognizers[TOUCHREC_BACK_SE], &drag_event, 1, &back_touch_state.se); +} + +inline uint32_t is_pressed(uint32_t defined) { + uint32_t dev_type = defined & INPUT_TYPE_MASK; + uint32_t dev_val = defined & INPUT_VALUE_MASK; + + switch(dev_type) { + case INPUT_TYPE_GAMEPAD: + return pad.buttons & dev_val; + case INPUT_TYPE_BACK_TOUCHSCREEN: + switch (dev_val) { + case TOUCHSEC_BACK_NORTHWEST: + if (back_touch_state.nw > 0) { + return 1; + } + break; + case TOUCHSEC_BACK_NORTHEAST: + if (back_touch_state.ne > 0) { + return 1; + } + break; + case TOUCHSEC_BACK_SOUTHWEST: + if (back_touch_state.sw > 0) { + return 1; + } + break; + case TOUCHSEC_BACK_SOUTHEAST: + if (back_touch_state.se > 0) { + return 1; + } + break; + } + } + return 0; +} + +inline short read_analog(uint32_t defined) { + uint32_t dev_type = defined & INPUT_TYPE_MASK; + uint32_t dev_val = defined & INPUT_VALUE_MASK; + + if (dev_type == INPUT_TYPE_ANALOG) { + int v; + switch(dev_val) { + case LEFTX: + v = pad.lx; + break; + case LEFTY: + v = pad.ly; + break; + case RIGHTX: + v = pad.rx; + break; + case RIGHTY: + v = pad.ry; + break; + case LEFT_TRIGGER: + return pad.lt; + case RIGHT_TRIGGER: + return pad.rt; + default: + return 0; + } + v = v * 256 - (1 << 15) + 128; + return (short)(v); + } + return is_pressed(defined) ? 0xff : 0; +} + +static void special(uint32_t defined, int touchrec) { + SceSystemGestureTouchEvent tap_event; + SceUInt32 event_num_buffer = 0; + uint32_t dev_type; + uint32_t dev_val; + + sceSystemGestureGetTouchEvents(&touch_recognizers[touchrec], &tap_event, 1, &event_num_buffer); + if (event_num_buffer > 0) { + dev_type = defined & INPUT_TYPE_MASK; + dev_val = defined & INPUT_VALUE_MASK; + switch (dev_type) { + case INPUT_TYPE_SPECIAL: + switch (dev_val) { + case INPUT_SPECIAL_KEY_PAUSE: + connection_minimize(); + return; + case INPUT_SPECIAL_KEY_KEYBOARD: + open_keyboard(); + return; + } + case INPUT_TYPE_GAMEPAD: + curr.button |= dev_val; + return; + case INPUT_TYPE_ANALOG: + switch (dev_val) { + case LEFT_TRIGGER: + curr.lt = 0xff; + return; + case RIGHT_TRIGGER: + curr.rt = 0xff; + return; + } + return; + case INPUT_TYPE_MOUSE: + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, dev_val); + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, dev_val); + return; + case INPUT_TYPE_KEYBOARD: + LiSendKeyboardEvent(dev_val, KEY_ACTION_DOWN, 0); + LiSendKeyboardEvent(dev_val, KEY_ACTION_UP, 0); + return; + } + } +} + +static inline void vitainput_process(void) { + sceClibMemset(&pad, 0, sizeof(pad)); + sceClibMemset(&curr, 0, sizeof(input_data)); + + sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); + sceCtrlPeekBufferPositiveExt2(controller_port, &pad, 1); + + sceTouchPeek(SCE_TOUCH_PORT_FRONT, &front, 1); + sceTouchPeek(SCE_TOUCH_PORT_BACK, &back, 1); + + if (hid_initialized) { + int reportNum = sceHidKeyboardRead(keyboard_handle, &kb, 1); + if (reportNum > 0) { + if ((int)kb.keycodes[0] != (int)kb_old.keycodes[0]) { + for (int i = 0; i++; i < 4) { + if ((kb.keycodes[i] != kb_old.keycodes[i]) && kb.keycodes[i] != 0) { + LiSendKeyboardEvent(kbNames[kb.keycodes[i]], KEY_ACTION_DOWN, 0); + active_key[i] = kb.keycodes[i]; + } + else if (kb.keycodes[i] != kb_old.keycodes[i]) { + LiSendKeyboardEvent(kbNames[kb.keycodes[i]], KEY_ACTION_UP, 0); + } + } + } + } + } + + sceSystemGestureUpdatePrimitiveTouchRecognizer(&front, &back); + for (int i = 0; i < TOUCH_RECOGNIZERS_NUM; i++) + sceSystemGestureUpdateTouchRecognizer(&touch_recognizers[i]); + + update_back_touch_state(); + + // buttons + curr.button |= is_pressed(map.btn_dpad_up) ? UP_FLAG : 0; + curr.button |= is_pressed(map.btn_dpad_left) ? LEFT_FLAG : 0; + curr.button |= is_pressed(map.btn_dpad_down) ? DOWN_FLAG : 0; + curr.button |= is_pressed(map.btn_dpad_right) ? RIGHT_FLAG : 0; + curr.button |= is_pressed(map.btn_start) ? PLAY_FLAG : 0; + curr.button |= is_pressed(map.btn_select) ? BACK_FLAG : 0; + curr.button |= is_pressed(map.btn_north) ? Y_FLAG : 0; + curr.button |= is_pressed(map.btn_east) ? B_FLAG : 0; + curr.button |= is_pressed(map.btn_south) ? A_FLAG : 0; + curr.button |= is_pressed(map.btn_west) ? X_FLAG : 0; + curr.button |= is_pressed(map.btn_thumbl) ? LB_FLAG : 0; // l1 + curr.button |= is_pressed(map.btn_thumbr) ? RB_FLAG : 0; // r1 + curr.button |= is_pressed(map.btn_tl2) ? LS_CLK_FLAG : 0; // l3 + curr.button |= is_pressed(map.btn_tr2) ? RS_CLK_FLAG : 0; // r3 + + // analogs + if (config.model == SCE_KERNEL_MODEL_VITATV) { + curr.lt = read_analog(map.btn_tl); // l2 + curr.rt = read_analog(map.btn_tr); // r2 + } + else { + curr.lt = is_pressed(map.btn_tl) ? 0xFF : 0; + curr.rt = is_pressed(map.btn_tr) ? 0xFF : 0; + } + curr.lx = read_analog(map.abs_x); + curr.ly = read_analog(map.abs_y); + curr.rx = read_analog(map.abs_rx); + curr.ry = read_analog(map.abs_ry); + + // special touchscreen buttons + special(config.special_keys.nw, TOUCHREC_SPECIAL_NW); + special(config.special_keys.ne, TOUCHREC_SPECIAL_NE); + special(config.special_keys.sw, TOUCHREC_SPECIAL_SW); + special(config.special_keys.se, TOUCHREC_SPECIAL_SE); + + if ((sceClibMemcmp(&curr, &old, sizeof(input_data)) != 0) && + sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_IS_IME, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) { + LiSendControllerEvent(curr.button, curr.lt, curr.rt, + curr.lx, -1 * curr.ly, curr.rx, -1 * curr.ry); + sceClibMemcpy(&old, &curr, sizeof(input_data)); + sceClibMemcpy(&pad_old, &pad, sizeof(SceCtrlData)); + } + + sceClibMemcpy(&kb_old, &kb, sizeof(SceHidKeyboardReport)); + + mouse_click(front.reportNum); + mouse_move(front.reportNum); + if (!scroll_rec) + mouse_lhold(front.reportNum); + +} + +int vitainput_thread(SceSize args, void *argp) { + while (1) { + + sceKernelWaitEventFlag(state_evf, FLAG_MOONLIGHT_IS_FG | FLAG_MOONLIGHT_ACTIVE_INPUT_THREAD, SCE_KERNEL_EVF_WAITMODE_AND, NULL, NULL); + + vitainput_process(); + + sceKernelDelayThread(5000); // 5 ms + } + + return 0; +} + +void vitainput_init_touch() { + sceSysmoduleLoadModule(SCE_SYSMODULE_SYSTEM_GESTURE); + sceSystemGestureInitializePrimitiveTouchRecognizer(NULL); + touch_recognizers = (SceSystemGestureTouchRecognizer *)calloc(TOUCH_RECOGNIZERS_NUM, sizeof(SceSystemGestureTouchRecognizer)); + //Mouse events recognizers + SceSystemGestureRectangle rect; + rect.x = 0; + rect.y = 0; + rect.width = 1920; + rect.height = 1088; + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_MOUSE_DRAG], SCE_SYSTEM_GESTURE_TYPE_DRAG, SCE_TOUCH_PORT_FRONT, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_MOUSE_CLICK], SCE_SYSTEM_GESTURE_TYPE_TAP, SCE_TOUCH_PORT_FRONT, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_MOUSE_LHOLD], SCE_SYSTEM_GESTURE_TYPE_TAP_AND_HOLD, SCE_TOUCH_PORT_FRONT, &rect, NULL); + //Special zones + sceClibMemset(&rect, 0, sizeof(SceSystemGestureRectangle)); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_SPECIAL_NW], SCE_SYSTEM_GESTURE_TYPE_TAP, SCE_TOUCH_PORT_FRONT, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_SPECIAL_NE], SCE_SYSTEM_GESTURE_TYPE_TAP, SCE_TOUCH_PORT_FRONT, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_SPECIAL_SW], SCE_SYSTEM_GESTURE_TYPE_TAP, SCE_TOUCH_PORT_FRONT, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_SPECIAL_SE], SCE_SYSTEM_GESTURE_TYPE_TAP, SCE_TOUCH_PORT_FRONT, &rect, NULL); + //Back touchpad + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_BACK_NW], SCE_SYSTEM_GESTURE_TYPE_DRAG, SCE_TOUCH_PORT_BACK, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_BACK_NE], SCE_SYSTEM_GESTURE_TYPE_DRAG, SCE_TOUCH_PORT_BACK, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_BACK_SW], SCE_SYSTEM_GESTURE_TYPE_DRAG, SCE_TOUCH_PORT_BACK, &rect, NULL); + sceSystemGestureCreateTouchRecognizer(&touch_recognizers[TOUCHREC_BACK_SE], SCE_SYSTEM_GESTURE_TYPE_DRAG, SCE_TOUCH_PORT_BACK, &rect, NULL); +} + +int vitainput_init_HID() { + int ret = sceHidKeyboardEnumerate(&keyboard_handle, 1); + if (ret < 0) + return ret; + + vitainput_kb_init_names(); + + hid_initialized = true; + return ret; +} + +bool vitainput_init() { + sceCtrlSetSamplingModeExt(SCE_CTRL_MODE_ANALOG_WIDE); + sceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, SCE_TOUCH_SAMPLING_STATE_START); + sceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, SCE_TOUCH_SAMPLING_STATE_START); + + vitainput_init_touch(); + + if (config.model == SCE_KERNEL_MODEL_VITATV) + vitainput_init_HID(); + + SceUID thid = sceKernelCreateThread("vitainput_thread", vitainput_thread, 70, 0x1000, 0, SCE_KERNEL_CPU_MASK_USER_2, NULL); + if (thid >= 0) { + sceKernelStartThread(thid, 0, NULL); + return true; + } + + return false; +} + +void vitainput_config(CONFIGURATION config) { + map.abs_x = LEFTX | INPUT_TYPE_ANALOG; + map.abs_y = LEFTY | INPUT_TYPE_ANALOG; + map.abs_rx = RIGHTX | INPUT_TYPE_ANALOG; + map.abs_ry = RIGHTY | INPUT_TYPE_ANALOG; + + map.btn_dpad_up = SCE_CTRL_UP | INPUT_TYPE_GAMEPAD; + map.btn_dpad_down = SCE_CTRL_DOWN | INPUT_TYPE_GAMEPAD; + map.btn_dpad_left = SCE_CTRL_LEFT | INPUT_TYPE_GAMEPAD; + map.btn_dpad_right = SCE_CTRL_RIGHT | INPUT_TYPE_GAMEPAD; + map.btn_south = SCE_CTRL_CROSS | INPUT_TYPE_GAMEPAD; + map.btn_east = SCE_CTRL_CIRCLE | INPUT_TYPE_GAMEPAD; + map.btn_north = SCE_CTRL_TRIANGLE | INPUT_TYPE_GAMEPAD; + map.btn_west = SCE_CTRL_SQUARE | INPUT_TYPE_GAMEPAD; + + map.btn_select = SCE_CTRL_SELECT | INPUT_TYPE_GAMEPAD; + map.btn_start = SCE_CTRL_START | INPUT_TYPE_GAMEPAD; + + map.btn_thumbl = SCE_CTRL_L1 | INPUT_TYPE_GAMEPAD; + map.btn_thumbr = SCE_CTRL_R1 | INPUT_TYPE_GAMEPAD; + + if (config.model == SCE_KERNEL_MODEL_VITATV) { + map.btn_tl = LEFT_TRIGGER | INPUT_TYPE_ANALOG; + map.btn_tr = RIGHT_TRIGGER | INPUT_TYPE_ANALOG; + map.btn_tl2 = SCE_CTRL_L3 | INPUT_TYPE_GAMEPAD; + map.btn_tr2 = SCE_CTRL_R3 | INPUT_TYPE_GAMEPAD; + } else { + map.btn_tl = TOUCHSEC_BACK_NORTHWEST | INPUT_TYPE_BACK_TOUCHSCREEN; + map.btn_tr = TOUCHSEC_BACK_NORTHEAST | INPUT_TYPE_BACK_TOUCHSCREEN; + map.btn_tl2 = TOUCHSEC_BACK_SOUTHWEST | INPUT_TYPE_BACK_TOUCHSCREEN; + map.btn_tr2 = TOUCHSEC_BACK_SOUTHEAST | INPUT_TYPE_BACK_TOUCHSCREEN; + } + + if (config.mapping) { + char mapping_file_path[256]; + sprintf(mapping_file_path, "savedata0:%s", config.mapping); + sceClibPrintf("Loading mapping at %s\n", mapping_file_path); + mapping_load(mapping_file_path, &map); + } + + controller_port = config.model == SCE_KERNEL_MODEL_VITATV ? 1 : 0; + + int real_offset = config.special_keys.offset * 2; + int real_size = config.special_keys.size * 2; + + //Update special touch areas + SceSystemGestureRectangle rect; + rect.x = real_offset; + rect.y = real_offset; + rect.width = real_size; + rect.height = real_size; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_SPECIAL_NW], &rect); + rect.x = TOUCH_WIDTH - real_offset - real_size; + rect.y = real_offset; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_SPECIAL_NE], &rect); + rect.x = real_offset; + rect.y = TOUCH_HEIGHT - real_offset - real_size; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_SPECIAL_SW], &rect); + rect.x = TOUCH_WIDTH - real_offset - real_size; + rect.y = TOUCH_HEIGHT - real_offset - real_size; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_SPECIAL_SE], &rect); + + //Update mouse click area + rect.x = real_offset + real_size; + rect.y = real_offset + real_size; + rect.width = TOUCH_WIDTH - real_offset - real_size; + rect.height = TOUCH_HEIGHT - real_offset - real_size; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_MOUSE_CLICK], &rect); + + //Update back touch areas + int back_real_deadzone_left = config.back_deadzone.left * 2; + int back_real_deadzone_right = config.back_deadzone.right * 2; + int back_real_deadzone_top = config.back_deadzone.top * 2; + int back_real_deadzone_bottom = config.back_deadzone.bottom * 2; + + HORIZONTAL = ((WIDTH - config.back_deadzone.left - config.back_deadzone.right) / 2 + + config.back_deadzone.left) * 2; + VERTICAL = ((HEIGHT - config.back_deadzone.top - config.back_deadzone.bottom) / 2 + + config.back_deadzone.top) * 2; + + rect.x = back_real_deadzone_left; + rect.y = back_real_deadzone_top; + rect.width = HORIZONTAL; + rect.height = VERTICAL; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_BACK_NW], &rect); + rect.x = HORIZONTAL; + rect.y = back_real_deadzone_top; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_BACK_NE], &rect); + rect.x = back_real_deadzone_left; + rect.y = VERTICAL; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_BACK_SW], &rect); + rect.x = HORIZONTAL; + rect.y = VERTICAL; + sceSystemGestureUpdateTouchRecognizerRectangle(&touch_recognizers[TOUCHREC_BACK_SE], &rect); + + mouse_multiplier = 0.003 * config.mouse_acceleration; +} + +void vitainput_start(void) { + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_INPUT_THREAD); +} + +void vitainput_stop(void) { + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_ACTIVE_INPUT_THREAD); +} diff --git a/src/input/vita.h b/src/input/vita.h index cff3204ad..a094df54b 100644 --- a/src/input/vita.h +++ b/src/input/vita.h @@ -26,10 +26,10 @@ typedef enum { } TouchScreenState; typedef enum { - TOUCHSEC_NORTHWEST = 0x1, - TOUCHSEC_NORTHEAST = 0x2, - TOUCHSEC_SOUTHWEST = 0x4, - TOUCHSEC_SOUTHEAST = 0x8, + TOUCHSEC_BACK_NORTHWEST = 0x1, + TOUCHSEC_BACK_NORTHEAST = 0x2, + TOUCHSEC_BACK_SOUTHWEST = 0x4, + TOUCHSEC_BACK_SOUTHEAST = 0x8, TOUCHSEC_SPECIAL_NW = 0x10, TOUCHSEC_SPECIAL_NE = 0x20, TOUCHSEC_SPECIAL_SW = 0x40, @@ -45,6 +45,22 @@ typedef enum { RIGHT_TRIGGER } PadSection; +typedef enum { + TOUCHREC_MOUSE_DRAG, + TOUCHREC_MOUSE_CLICK, + TOUCHREC_MOUSE_LHOLD, + TOUCHREC_SPECIAL_NW, + TOUCHREC_SPECIAL_NE, + TOUCHREC_SPECIAL_SW, + TOUCHREC_SPECIAL_SE, + TOUCHREC_BACK_NW, + TOUCHREC_BACK_NE, + TOUCHREC_BACK_SW, + TOUCHREC_BACK_SE +} TouchScreenRecognizer; + +#define TOUCH_RECOGNIZERS_NUM 11 + #define INPUT_TYPE_MASK 0xfff00000 #define INPUT_VALUE_MASK 0x000fffff @@ -53,11 +69,12 @@ typedef enum { #define INPUT_TYPE_MOUSE 0x00200000 #define INPUT_TYPE_GAMEPAD 0x00300000 #define INPUT_TYPE_ANALOG 0x00400000 -#define INPUT_TYPE_TOUCHSCREEN 0x00500000 +#define INPUT_TYPE_BACK_TOUCHSCREEN 0x00500000 #define INPUT_TYPE_DEF_NAME 0xf0000000 enum { - INPUT_SPECIAL_KEY_PAUSE + INPUT_SPECIAL_KEY_PAUSE, + INPUT_SPECIAL_KEY_KEYBOARD }; bool vitainput_init(); diff --git a/src/loop.c b/src/loop.c index 206e439f4..50d66ce4c 100644 --- a/src/loop.c +++ b/src/loop.c @@ -88,8 +88,8 @@ void loop_remove_fd(int fd) { } if (fdindex != numFds && numFds > 0) { - memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd)); - memcpy(&fdHandlers[fdindex], &fdHandlers[numFds], sizeof(FdHandler)); + sceClibMemcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd)); + sceClibMemcpy(&fdHandlers[fdindex], &fdHandlers[numFds], sizeof(FdHandler)); } #endif } diff --git a/src/main.c b/src/main.c index aa86ea0f2..fd8bdfaa3 100644 --- a/src/main.c +++ b/src/main.c @@ -1,131 +1,220 @@ -/* - * This file is part of Moonlight Embedded. - * - * Copyright (C) 2015, 2016 Iwan Timmer - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#include "loop.h" -#include "client.h" -#include "connection.h" -#include "configuration.h" -#include "audio.h" -#include "video.h" -#include "discover.h" -#include "config.h" -#include "platform.h" - -#include "input/vita.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include "graphics.h" -#include "device.h" -#include "gui/ui.h" -#include "power/vita.h" - -static void vita_init() { - // Seed OpenSSL with Sony-grade random number generator - char random_seed[0x40] = {0}; - sceKernelGetRandomNumber(random_seed, sizeof(random_seed)); - RAND_seed(random_seed, sizeof(random_seed)); - OpenSSL_add_all_algorithms(); - - // This is only used for PIN codes, doesn't really matter - srand(time(NULL)); - - printf("Vita Moonlight %d.%d.%d (%s)\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, COMPILE_OPTIONS); - - int ret = 0; - - ret = sceSysmoduleLoadModule(SCE_SYSMODULE_NET); - - size_t net_mem_sz = 100 * 1024; - SceNetInitParam net_param = {0}; - net_param.memory = calloc(net_mem_sz, 1); - net_param.size = net_mem_sz; - ret = sceNetInit(&net_param); - - ret = sceNetCtlInit(); - // TODO(xyz): cURL breaks when socket FD is too big, very hacky workaround below! - int s = sceNetSocket("", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0); - sceNetSocketClose(s); - if (s >= 20) { - printf("Cycling sockets...\n"); - int c = 0; - do { - c = sceNetSocket("", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0); - sceNetSocketClose(c); - } while (c >= 5); - } -} - -void loop_forever(void) { - while (connection_is_ready()) { - sceKernelDelayThread(100 * 1000); - } -} - -int main(int argc, char* argv[]) { - psvDebugScreenInit(); - vita_init(); - - if (!vitapower_init()) { - printf("Failed to init power!"); - loop_forever(); - } - - if (!vitainput_init()) { - printf("Failed to init input!"); - loop_forever(); - } - - sceIoMkdir("ux0:/data/moonlight", 0777); - config_path = "ux0:data/moonlight/moonlight.conf"; - config_parse(argc, argv, &config); - strcpy(config.key_dir, "ux0:data/moonlight/"); - - vitapower_config(config); - vitainput_config(config); - - config.log_file = fopen("ux0:data/moonlight/moonlight.log", "w"); - - load_all_known_devices(); - - gui_loop(); -} +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015, 2016, 2020 Iwan Timmer, Graphene + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include "loop.h" +#include "client.h" +#include "connection.h" +#include "configuration.h" +#include "audio.h" +#include "video.h" +#include "discover.h" +#include "config.h" +#include "platform.h" + +#include "input/vita.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include "device.h" +#include "gui/ui.h" +#include "power/vita.h" + +typedef struct SceKernelModuleLoadStartParam { + SceUInt32 flags; + int *status; + void *option; + int a4; // not used +} SceKernelModuleLoadStartParam; + +SceUID _sceKernelLoadStartModule(const char *moduleFileName, SceSize args, const void *argp, const SceKernelModuleLoadStartParam *pParam); + +typedef struct SceSysmoduleOpt { + int flags; + int *result; + int unused[2]; +} SceSysmoduleOpt; + +typedef struct ScePafInit { + unsigned int global_heap_size; + int a2; + int a3; + int cdlg_mode; + int heap_opt_param1; + int heap_opt_param2; +} ScePafInit; + +extern int SCREEN_WIDTH; +extern int SCREEN_HEIGHT; +extern int LINE_SIZE; + +// We mostly use SceLibc heap +int _newlib_heap_size_user = 1 * 1024 * 1024; +SceUID state_evf = 0; + +static void vita_init() { + + int ret; + + sceDbgSetMinimumLogLevel(SCE_DBG_LOG_LEVEL_ERROR); + + //Global state EVF + state_evf = sceKernelCreateEventFlag( + "moonlight_event_flag", + SCE_KERNEL_ATTR_MULTI, + FLAG_MOONLIGHT_IS_FG | FLAG_MOONLIGHT_ACTIVE_VIDEO_THREAD | FLAG_MOONLIGHT_ACTIVE_AUDIO_THREAD, + NULL); + + //Configure main thread + sceKernelChangeThreadCpuAffinityMask(SCE_KERNEL_THREAD_ID_SELF, SCE_KERNEL_CPU_MASK_USER_0); + sceKernelChangeThreadPriority(SCE_KERNEL_THREAD_ID_SELF, 80); + + //Load stuff + + SceKernelModuleLoadStartParam param = { 0 }; + + sceSysmoduleLoadModule(SCE_SYSMODULE_IME); + sceSysmoduleLoadModule(SCE_SYSMODULE_NET); + //We use direct SceModulemgr function because normal one doesn't always work for ScePsp2Compat for some reason + _sceKernelLoadStartModule("vs0:data/external/webcore/ScePsp2Compat.suprx", 0, NULL, ¶m); + sceKernelLoadStartModule("app0:module/user/mdns.suprx", 0, NULL, 0, NULL, 0); + sceKernelLoadStartModule("app0:module/user/h264bitstream.suprx", 0, NULL, 0, NULL, 0); + sceKernelLoadStartModule("app0:module/user/uuid.suprx", 0, NULL, 0, NULL, 0); + sceKernelLoadStartModule("app0:module/user/libexpat.suprx", 0, NULL, 0, NULL, 0); + sceKernelLoadStartModule("app0:module/user/vita2d_sys.suprx", 0, NULL, 0, NULL, 0); + + //PAF needed for SceIniFileProcessor + SceSysmoduleOpt sysmodule_opt; + ScePafInit init_param; + init_param.global_heap_size = 6 * 1024 * 1024; + init_param.a2 = 0x0000EA60; + init_param.a3 = 0x00040000; + init_param.cdlg_mode = 0; + init_param.heap_opt_param1 = 0; + init_param.heap_opt_param2 = 0; + + sysmodule_opt.flags = 0; + sysmodule_opt.result = &ret; + + sceSysmoduleLoadModuleInternalWithArg(SCE_SYSMODULE_INTERNAL_PAF, sizeof(init_param), &init_param, &sysmodule_opt); + sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_INTERNAL_INI_FILE_PROCESSOR); + + // Seed OpenSSL with Sony-grade random number generator + char random_seed[0x40] = {0}; + sceKernelGetRandomNumber(random_seed, sizeof(random_seed)); + RAND_seed(random_seed, sizeof(random_seed)); + OpenSSL_add_all_algorithms(); + + // This is only used for PIN codes, doesn't really matter + srand(time(NULL)); + + sceClibPrintf("Vita Moonlight %d.%d.%d (%s)\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, COMPILE_OPTIONS); + + size_t net_mem_sz = 100 * 1024; + SceNetInitParam net_param = {0}; + net_param.memory = calloc(net_mem_sz, 1); + net_param.size = net_mem_sz; + ret = sceNetInit(&net_param); + + ret = sceNetCtlInit(); + // TODO(xyz): cURL breaks when socket FD is too big, very hacky workaround below! + int s = sceNetSocket("", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0); + sceNetSocketClose(s); + if (s >= 20) { + sceClibPrintf("Cycling sockets...\n"); + int c = 0; + do { + c = sceNetSocket("", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0); + sceNetSocketClose(c); + } while (c >= 5); + } +} + +void loop_forever(void) { + while (connection_is_ready()) { + sceKernelDelayThread(100 * 1000); + } +} + +int main(int argc, char* argv[]) { + vita_init(); + + if (!vitapower_init()) { + sceClibPrintf("Failed to init power!"); + loop_forever(); + } + + if (!vitainput_init()) { + sceClibPrintf("Failed to init input!"); + loop_forever(); + } + + config_path = "savedata0:moonlight.conf"; + config_parse(argc, argv, &config); + strcpy(config.key_dir, "savedata0:"); + + switch (config.stream.width) { + case 1920: + SCREEN_WIDTH = 1920; + SCREEN_HEIGHT = 1088; + LINE_SIZE = 1920; + break; + case 1280: + SCREEN_WIDTH = 1280; + SCREEN_HEIGHT = 725; + LINE_SIZE = 1280; + break; + default: + break; + } + + vitapower_config(config); + vitainput_config(config); + + config.log_file = fopen("savedata0:moonlight.log", "w"); + + load_all_known_devices(); + + gui_loop(); +} diff --git a/src/platform.c b/src/platform.c index 85dd64bd7..8dfa55989 100644 --- a/src/platform.c +++ b/src/platform.c @@ -25,13 +25,13 @@ #include #include #include -// #include +#include typedef bool(*ImxInit)(); enum platform platform_check(char* name) { - bool std = strcmp(name, "default") == 0; - if (strcmp(name, "vita") == 0) + bool std = sceClibStrcmp(name, "default") == 0; + if (sceClibStrcmp(name, "vita") == 0) return VITA; return 0; } @@ -67,3 +67,25 @@ uid_t getgid(void) { uid_t getegid(void) { return 1; } + +// Allocations override + +void *malloc(size_t size) { + return sceLibcMalloc(size); +} + +void *calloc(size_t nitems, size_t size) { + return sceLibcCalloc(nitems, size); +} + +void *realloc(void *ptr, size_t size) { + return sceLibcRealloc(ptr, size); +} + +void *memalign(size_t blocksize, size_t bytes) { + return sceLibcMemalign(blocksize, bytes); +} + +void free(void *ptr) { + sceLibcFree(ptr); +} diff --git a/src/platform.h b/src/platform.h index dc6b791e9..d28d90de6 100644 --- a/src/platform.h +++ b/src/platform.h @@ -24,6 +24,16 @@ #include #include +typedef enum MoonlightVitaStateEVF { + FLAG_MOONLIGHT_IS_FG = 1, + FLAG_MOONLIGHT_ACTIVE_VIDEO_THREAD = 2, + FLAG_MOONLIGHT_ACTIVE_AUDIO_THREAD = 4, + FLAG_MOONLIGHT_ACTIVE_INPUT_THREAD = 8, + FLAG_MOONLIGHT_ACTIVE_PACER_THREAD = 16, + FLAG_MOONLIGHT_ACTIVE_POWER_THREAD = 32, + FLAG_MOONLIGHT_IS_IME = 64 +} MoonlightVitaStateEVF; + enum platform { VITA }; enum platform platform_check(char*); @@ -32,3 +42,11 @@ PAUDIO_RENDERER_CALLBACKS platform_get_audio(enum platform system); bool platform_supports_hevc(enum platform system); extern DECODER_RENDERER_CALLBACKS decoder_callbacks_vita; + +// Fore allocations override + +void *sceLibcMalloc(size_t size); +void sceLibcFree(void *ptr); +void *sceLibcCalloc(size_t nitems, size_t size); +void *sceLibcRealloc(void *ptr, size_t size); +void *sceLibcMemalign(size_t blocksize, size_t bytes); diff --git a/src/power/vita.c b/src/power/vita.c index 202112bcc..52a15138a 100644 --- a/src/power/vita.c +++ b/src/power/vita.c @@ -1,74 +1,156 @@ -/* - * This file is part of Moonlight Embedded. - * - * Copyright (C) 2015 Iwan Timmer, Sunguk Lee - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ -#include - -#include -#include -#include "../config.h" - -enum { - ENABLE_ALL = 0, - DISABLE_SUSPEND = 1, -}; - -static int powermode = ENABLE_ALL; -static bool active_power_thread = false; - -int vitapower_thread(SceSize args, void *argp) { - while (1) { - if (!active_power_thread) { - sceKernelDelayThread(10 * 1000 * 1000); - continue; - } - if (powermode & DISABLE_SUSPEND) { - sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_AUTO_SUSPEND); - sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_OLED_OFF); - } - if (!scePowerIsBatteryCharging() && scePowerIsLowBattery()) { - // TODO print warning message - } - sceKernelDelayThread(10 * 1000 * 1000); - } - - return 0; -} - -bool vitapower_init() { - SceUID thid = sceKernelCreateThread("vitapower_thread", vitapower_thread, 0x10000100, 0x40000, 0, 0, NULL); - if (thid >= 0) - sceKernelStartThread(thid, 0, NULL); - - return true; -} - -void vitapower_config(CONFIGURATION config) { - powermode = ENABLE_ALL; - - if (config.disable_powersave) { - powermode |= DISABLE_SUSPEND; - } -} - -void vitapower_start() { - active_power_thread = true; -} - -void vitapower_stop() { - active_power_thread = false; -} +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2015 Iwan Timmer, Sunguk Lee + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ +#include + +#include +#include +#include +#include +#include +#include "../config.h" +#include "../platform.h" +#include "../video/vita.h" + +#define SCE_APP_EVENT_UNK0 (0x00000003) +#define SCE_APP_EVENT_ON_ACTIVATE (0x10000001) +#define SCE_APP_EVENT_ON_DEACTIVATE (0x10000002) +#define SCE_APP_EVENT_UNK1 (0x10000300) +#define SCE_APP_EVENT_REQUEST_QUIT (0x20000001) +#define SCE_APP_EVENT_UNK2 (0x30000003) + +typedef struct SceAppMgrEvent { // size is 0x64 + int event; /* Event ID */ + SceUID appId; /* Application ID. Added when required by the event */ + char param[56]; /* Parameters to pass with the event */ +} SceAppMgrEvent; + +int _sceAppMgrReceiveEvent(SceAppMgrEvent *appEvent); +int sceAppMgrQuitForNonSuspendableApp(void); + +enum { + DISABLE_DIMMING = 1, + DISABLE_SUSPEND = 2, +}; + +extern SceUID state_evf; + +static int powermode = 0; + +static SceBool is_deactivated = SCE_FALSE; + +void vitapower_activate(void) +{ + vitavideo_flush_decoder(); + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_IS_FG); +} + +void vitapower_deactivate(void) +{ + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_IS_FG); +} + +void vitapower_termninate() { + SceUID modid = taiLoadStartKernelModule("ux0:app/GRVA00010/module/kernel/exit_module.skprx", 0, NULL, 0); + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_IS_FG); + sceAppMgrQuitForNonSuspendableApp(); + taiStopUnloadKernelModule(modid, 0, NULL, 0, NULL, NULL); +} + +int vitapower_callback(int notifyId, int notifyCount, int powerInfo, void *common) +{ + if (powerInfo & 0x400000) { + if (!is_deactivated) + vitapower_deactivate(); + } + else if (powerInfo & 0x800000) { + if (!is_deactivated) + vitapower_activate(); + } + + return 0; +} + +int vitapower_thread(SceSize args, void *argp) { + + SceAppMgrEvent appEvent; + + SceUID cbid = sceKernelCreateCallback("power_cb", 0, vitapower_callback, NULL); + scePowerRegisterCallback(cbid); + + while (1) { + + //Not sure if flushing is better on activation or deactivation + _sceAppMgrReceiveEvent(&appEvent); + switch (appEvent.event) { + case SCE_APP_EVENT_ON_ACTIVATE: + vitapower_activate(); + is_deactivated = SCE_FALSE; + break; + case SCE_APP_EVENT_ON_DEACTIVATE: + vitapower_deactivate(); + is_deactivated = SCE_TRUE; + break; + case SCE_APP_EVENT_REQUEST_QUIT: + vitapower_termninate(); + break; + } + + if (sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_POWER_THREAD, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) { + sceKernelDelayThreadCB(10 * 1000); + continue; + } + if (powermode & DISABLE_SUSPEND) { + sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_AUTO_SUSPEND); + } + if (powermode & DISABLE_DIMMING) { + sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_OLED_OFF); + sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_OLED_DIMMING); + } + sceKernelDelayThreadCB(10 * 1000); + } + + return 0; +} + +bool vitapower_init() { + SceUID thid = sceKernelCreateThread("vitapower_thread", vitapower_thread, 127, 0x1000, 0, SCE_KERNEL_CPU_MASK_USER_2, NULL); + if (thid >= 0) + sceKernelStartThread(thid, 0, NULL); + + return true; +} + +void vitapower_config(CONFIGURATION config) { + powermode = 0; + + if (config.disable_powersave) { + powermode |= DISABLE_SUSPEND; + } + if (config.disable_dimming) { + powermode |= DISABLE_DIMMING; + } +} + +void vitapower_start() { + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_POWER_THREAD); +} + +void vitapower_stop() { + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_ACTIVE_POWER_THREAD); +} diff --git a/src/power/vita.h b/src/power/vita.h index b132d301a..6ca6db118 100644 --- a/src/power/vita.h +++ b/src/power/vita.h @@ -17,6 +17,8 @@ * along with Moonlight; if not, see . */ +void vitapower_termninate(); + bool vitapower_init(); void vitapower_config(CONFIGURATION config); diff --git a/src/util.c b/src/util.c index f8015b841..2ca3fdd8d 100644 --- a/src/util.c +++ b/src/util.c @@ -1,5 +1,7 @@ #include "util.h" +#include + #include #include #include @@ -31,7 +33,7 @@ void sort_app_list(PAPP_LIST list) { cur = list; while (cur->next != prev) { - if (strcmp(cur->name, cur->next->name) > 0) { + if (sceClibStrcmp(cur->name, cur->next->name) > 0) { swap_app_list_entries(cur, cur->next); swapped = 1; } diff --git a/src/video/vita.c b/src/video/vita.c index 95d0bd2d2..47a7de415 100644 --- a/src/video/vita.c +++ b/src/video/vita.c @@ -1,571 +1,629 @@ -/* - * This file is part of Moonlight Embedded. - * - * Copyright (C) 2016 Ilya Zhuravlev - * - * Moonlight is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Moonlight is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Moonlight; if not, see . - */ - -#include "../video.h" -#include "../config.h" -#include "../debug.h" -#include "../gui/guilib.h" -#include "sps.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if 0 -#define printf vita_debug_log -#endif - -void draw_streaming(vita2d_texture *frame_texture); -void draw_fps(); -void draw_indicators(); - -enum { - VITA_VIDEO_INIT_OK = 0, - VITA_VIDEO_ERROR_NO_MEM = 0x80010001, - VITA_VIDEO_ERROR_INIT_LIB = 0x80010002, - VITA_VIDEO_ERROR_QUERY_DEC_MEMSIZE = 0x80010003, - VITA_VIDEO_ERROR_ALLOC_MEM = 0x80010004, - VITA_VIDEO_ERROR_GET_MEMBASE = 0x80010005, - VITA_VIDEO_ERROR_CREATE_DEC = 0x80010006, - VITA_VIDEO_ERROR_CREATE_PACER_THREAD = 0x80010007, -}; - -#define DECODER_BUFFER_SIZE (92 * 1024) - -static char* decoder_buffer = NULL; - -enum { - SCREEN_WIDTH = 960, - SCREEN_HEIGHT = 544, - LINE_SIZE = 960, - FRAMEBUFFER_SIZE = 2 * 1024 * 1024, - FRAMEBUFFER_ALIGNMENT = 256 * 1024 -}; - -enum VideoStatus { - NOT_INIT, - INIT_GS, - INIT_FRAMEBUFFER, - INIT_AVC_LIB, - INIT_DECODER_MEMBLOCK, - INIT_AVC_DEC, - INIT_FRAME_PACER_THREAD, -}; - -vita2d_texture *frame_texture = NULL; -enum VideoStatus video_status = NOT_INIT; - -SceAvcdecCtrl *decoder = NULL; -SceUID displayblock = -1; -SceUID decoderblock = -1; -SceUID pacer_thread = -1; -SceVideodecQueryInitInfoHwAvcdec *init = NULL; -SceAvcdecQueryDecoderInfo *decoder_info = NULL; - -typedef struct { - bool activated; - uint8_t alpha; - bool plus; -} indicator_status; - -static unsigned numframes; -static bool active_video_thread = true; -static bool active_pacer_thread = false; -static indicator_status poor_net_indicator = {0}; - -uint32_t frame_count = 0; -uint32_t need_drop = 0; -uint32_t curr_fps[2] = {0, 0}; -float carry = 0; - -typedef struct { - unsigned int texture_width; - unsigned int texture_height; - float origin_x; - float origin_y; - float region_x1; - float region_y1; - float region_x2; - float region_y2; -} image_scaling_settings; - -static image_scaling_settings image_scaling = {0}; - -// Vita's sceVideodecInitLibrary only accept resolution that is multiple of 16 on either dimension, -// and the smallest resolution is 64 -// Full supported resolution list can be found at: -// https://github.com/MakiseKurisu/vita-sceVideodecInitLibrary-test/ -#define ROUND_NEAREST_16(x) (round(((double) (x)) / 16) * 16) -#define VITA_DECODER_RESOLUTION_LOWER_BOUND(x) ((x) < 64 ? 64 : (x)) -#define VITA_DECODER_RESOLUTION(x) (VITA_DECODER_RESOLUTION_LOWER_BOUND(ROUND_NEAREST_16(x))) - -void update_scaling_settings(int width, int height) { - image_scaling.texture_width = SCREEN_WIDTH; - image_scaling.texture_height = SCREEN_HEIGHT; - image_scaling.origin_x = 0; - image_scaling.origin_y = 0; - image_scaling.region_x1 = 0; - image_scaling.region_y1 = 0; - image_scaling.region_x2 = image_scaling.texture_width; - image_scaling.region_y2 = image_scaling.texture_height; - - double scaled_width = (double) SCREEN_HEIGHT * width / height; - double scaled_height = (double) SCREEN_WIDTH * height / width; - - if (SCREEN_WIDTH * height == SCREEN_HEIGHT * width) { - // streaming resolution ratio matches Vita's screen ratio - // use default setting - } else if (SCREEN_WIDTH * height > SCREEN_HEIGHT * width) { - // host ratio example: 4:3, 16:10 - // Vita ratio range: 2:16 (64 x 544) - native (960 x 544) - if (config.center_region_only) { - image_scaling.texture_height = VITA_DECODER_RESOLUTION(scaled_height); - image_scaling.region_y1 = VITA_DECODER_RESOLUTION((scaled_height - SCREEN_HEIGHT) / 2); - image_scaling.region_y2 = VITA_DECODER_RESOLUTION((scaled_height + SCREEN_HEIGHT) / 2); - } else { - image_scaling.texture_width = VITA_DECODER_RESOLUTION(scaled_width); - image_scaling.region_x2 = VITA_DECODER_RESOLUTION(scaled_width); - image_scaling.origin_x = round((double) (SCREEN_WIDTH - image_scaling.texture_width) / 2); - } - } else { - // host ratio example: 16:9, 21:9, 32:9 - // Vita ratio range: native (960 x 544) - 15:1 (960 x 64) - if (config.center_region_only) { - image_scaling.texture_width = VITA_DECODER_RESOLUTION(scaled_width); - image_scaling.region_x1 = VITA_DECODER_RESOLUTION((scaled_width - SCREEN_WIDTH) / 2); - image_scaling.region_x2 = VITA_DECODER_RESOLUTION((scaled_width + SCREEN_WIDTH) / 2); - } else { - image_scaling.texture_height = VITA_DECODER_RESOLUTION(scaled_height); - image_scaling.region_y2 = VITA_DECODER_RESOLUTION(scaled_height); - image_scaling.origin_y = round((double) (SCREEN_HEIGHT - image_scaling.texture_height) / 2); - } - } - - printf("update_scaling_settings: width = %u\n", width); - printf("update_scaling_settings: height = %u\n", height); - printf("update_scaling_settings: scaled_width = %f\n", scaled_width); - printf("update_scaling_settings: scaled_height = %f\n", scaled_height); - printf("update_scaling_settings: image_scaling.texture_width = %u\n", image_scaling.texture_width); - printf("update_scaling_settings: image_scaling.texture_height = %u\n", image_scaling.texture_height); - printf("update_scaling_settings: image_scaling.origin_x = %f\n", image_scaling.origin_x); - printf("update_scaling_settings: image_scaling.origin_y = %f\n", image_scaling.origin_y); - printf("update_scaling_settings: image_scaling.region_x1 = %f\n", image_scaling.region_x1); - printf("update_scaling_settings: image_scaling.region_y1 = %f\n", image_scaling.region_y1); - printf("update_scaling_settings: image_scaling.region_x2 = %f\n", image_scaling.region_x2); - printf("update_scaling_settings: image_scaling.region_y2 = %f\n", image_scaling.region_y2); -} - -static int vita_pacer_thread_main(SceSize args, void *argp) { - // 1s - int wait = 1000000; - //float max_fps = 0; - //sceDisplayGetRefreshRate(&max_fps); - //if (config.stream.fps == 30) { - // max_fps /= 2; - //} - int max_fps = config.stream.fps; - uint64_t last_vblank_count = sceDisplayGetVcount(); - uint64_t last_check_time = sceKernelGetSystemTimeWide(); - //float carry = 0; - need_drop = 0; - frame_count = 0; - while (active_pacer_thread) { - uint64_t curr_vblank_count = sceDisplayGetVcount(); - uint32_t vblank_fps = curr_vblank_count - last_vblank_count; - uint32_t curr_frame_count = frame_count; - frame_count = 0; - - if (!active_video_thread) { - // carry = 0; - } else { - if (config.enable_frame_pacer && curr_frame_count > max_fps) { - //carry += curr_frame_count - max_fps; - //if (carry > 1) { - // need_drop += (int)carry; - // carry -= (int)carry; - //} - need_drop += curr_frame_count - max_fps; - } - //vita_debug_log("fps0/fps1/carry/need_drop: %u/%u/%f/%u\n", - // curr_frame_count, vblank_fps, carry, need_drop); - } - - curr_fps[0] = curr_frame_count; - curr_fps[1] = vblank_fps; - - last_vblank_count = curr_vblank_count; - uint64_t curr_check_time = sceKernelGetSystemTimeWide(); - uint32_t lapse = curr_check_time - last_check_time; - last_check_time = curr_check_time; - if (lapse > wait && (lapse - wait) < wait) { - //vita_debug_log("sleep: %d", wait * 2 - lapse); - sceKernelDelayThread(wait * 2 - lapse); - } else { - sceKernelDelayThread(wait); - } - } - return 0; -} - -static void vita_cleanup() { - if (video_status == INIT_FRAME_PACER_THREAD) { - active_pacer_thread = false; - // wait 10sec - SceUInt timeout = 10000000; - int ret; - sceKernelWaitThreadEnd(pacer_thread, &ret, &timeout); - sceKernelDeleteThread(pacer_thread); - video_status--; - } - - if (video_status == INIT_AVC_DEC) { - sceAvcdecDeleteDecoder(decoder); - video_status--; - } - - if (video_status == INIT_DECODER_MEMBLOCK) { - if (decoderblock >= 0) { - sceKernelFreeMemBlock(decoderblock); - decoderblock = -1; - } - if (decoder != NULL) { - free(decoder); - decoder = NULL; - } - if (decoder_info != NULL) { - free(decoder_info); - decoder_info = NULL; - } - video_status--; - } - - if (video_status == INIT_AVC_LIB) { - sceVideodecTermLibrary(SCE_VIDEODEC_TYPE_HW_AVCDEC); - - if (init != NULL) { - free(init); - init = NULL; - } - video_status--; - } - - if (video_status == INIT_FRAMEBUFFER) { - if (frame_texture != NULL) { - vita2d_free_texture(frame_texture); - frame_texture = NULL; - } - - if (decoder_buffer != NULL) { - free(decoder_buffer); - decoder_buffer = NULL; - } - video_status--; - } - - if (video_status == INIT_GS) { - gs_sps_stop(); - video_status--; - } -} - -static int vita_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) { - int ret; - printf("vita video setup\n"); - - if (video_status == NOT_INIT) { - // INIT_GS - gs_sps_init(width, height); - video_status++; - } - - if (video_status == INIT_GS) { - // INIT_FRAMEBUFFER - update_scaling_settings(width, height); - - decoder_buffer = malloc(DECODER_BUFFER_SIZE); - if (decoder_buffer == NULL) { - printf("not enough memory\n"); - ret = VITA_VIDEO_ERROR_NO_MEM; - goto cleanup; - } - - frame_texture = vita2d_create_empty_texture_format(image_scaling.texture_width, image_scaling.texture_height, SCE_GXM_TEXTURE_FORMAT_U8U8U8U8_ABGR); - if (frame_texture == NULL) { - printf("not enough memory\n"); - ret = VITA_VIDEO_ERROR_NO_MEM; - goto cleanup; - } - - video_status++; - } - - if (video_status == INIT_FRAMEBUFFER) { - // INIT_AVC_LIB - if (init == NULL) { - init = calloc(1, sizeof(SceVideodecQueryInitInfoHwAvcdec)); - if (init == NULL) { - printf("not enough memory\n"); - ret = VITA_VIDEO_ERROR_NO_MEM; - goto cleanup; - } - } - init->size = sizeof(SceVideodecQueryInitInfoHwAvcdec); - init->horizontal = VITA_DECODER_RESOLUTION(width); - init->vertical = VITA_DECODER_RESOLUTION(height); - init->numOfRefFrames = 5; - init->numOfStreams = 1; - - ret = sceVideodecInitLibrary(SCE_VIDEODEC_TYPE_HW_AVCDEC, init); - if (ret < 0) { - printf("sceVideodecInitLibrary 0x%x\n", ret); - ret = VITA_VIDEO_ERROR_INIT_LIB; - goto cleanup; - } - video_status++; - } - - if (video_status == INIT_AVC_LIB) { - // INIT_DECODER_MEMBLOCK - if (decoder_info == NULL) { - decoder_info = calloc(1, sizeof(SceAvcdecQueryDecoderInfo)); - if (decoder_info == NULL) { - printf("not enough memory\n"); - ret = VITA_VIDEO_ERROR_NO_MEM; - goto cleanup; - } - } - decoder_info->horizontal = init->horizontal; - decoder_info->vertical = init->vertical; - decoder_info->numOfRefFrames = init->numOfRefFrames; - - SceAvcdecDecoderInfo decoder_info_out = {0}; - - ret = sceAvcdecQueryDecoderMemSize(SCE_VIDEODEC_TYPE_HW_AVCDEC, decoder_info, &decoder_info_out); - if (ret < 0) { - printf("sceAvcdecQueryDecoderMemSize 0x%x size 0x%x\n", ret, decoder_info_out.frameMemSize); - ret = VITA_VIDEO_ERROR_QUERY_DEC_MEMSIZE; - goto cleanup; - } - - decoder = calloc(1, sizeof(SceAvcdecCtrl)); - if (decoder == NULL) { - printf("not enough memory\n"); - ret = VITA_VIDEO_ERROR_ALLOC_MEM; - goto cleanup; - } - - size_t sz = (decoder_info_out.frameMemSize + 0xFFFFF) & ~0xFFFFF; - decoder->frameBuf.size = sz; - printf("allocating size 0x%x\n", sz); - - decoderblock = sceKernelAllocMemBlock("decoder", SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW, sz, NULL); - if (decoderblock < 0) { - printf("decoderblock: 0x%08x\n", decoderblock); - ret = VITA_VIDEO_ERROR_ALLOC_MEM; - goto cleanup; - } - - ret = sceKernelGetMemBlockBase(decoderblock, &decoder->frameBuf.pBuf); - if (ret < 0) { - printf("sceKernelGetMemBlockBase: 0x%x\n", ret); - ret = VITA_VIDEO_ERROR_GET_MEMBASE; - goto cleanup; - } - video_status++; - } - - if (video_status == INIT_DECODER_MEMBLOCK) { - // INIT_AVC_DEC - printf("base: 0x%08x\n", decoder->frameBuf.pBuf); - - ret = sceAvcdecCreateDecoder(SCE_VIDEODEC_TYPE_HW_AVCDEC, decoder, decoder_info); - if (ret < 0) { - printf("sceAvcdecCreateDecoder 0x%x\n", ret); - ret = VITA_VIDEO_ERROR_CREATE_DEC; - goto cleanup; - } - video_status++; - } - - if (video_status == INIT_AVC_DEC) { - // INIT_FRAME_PACER_THREAD - ret = sceKernelCreateThread("frame_pacer", vita_pacer_thread_main, 0, 0x10000, 0, 0, NULL); - if (ret < 0) { - printf("sceKernelCreateThread 0x%x\n", ret); - ret = VITA_VIDEO_ERROR_CREATE_PACER_THREAD; - goto cleanup; - } - pacer_thread = ret; - active_pacer_thread = true; - sceKernelStartThread(pacer_thread, 0, NULL); - video_status++; - } - - return VITA_VIDEO_INIT_OK; - -cleanup: - vita_cleanup(); - return ret; -} - -static int vita_submit_decode_unit(PDECODE_UNIT decodeUnit) { - SceAvcdecAu au = {0}; - SceAvcdecArrayPicture array_picture = {0}; - struct SceAvcdecPicture picture = {0}; - struct SceAvcdecPicture *pictures = { &picture }; - array_picture.numOfElm = 1; - array_picture.pPicture = &pictures; - - //frame->time = decodeUnit->receiveTimeMs; - - picture.size = sizeof(picture); - picture.frame.pixelType = 0; - picture.frame.framePitch = image_scaling.texture_width; - picture.frame.frameWidth = image_scaling.texture_width; - picture.frame.frameHeight = image_scaling.texture_height; - picture.frame.pPicture[0] = vita2d_texture_get_datap(frame_texture); - - if (decodeUnit->fullLength >= DECODER_BUFFER_SIZE) { - printf("Video decode buffer too small\n"); - exit(1); - } - - PLENTRY entry = decodeUnit->bufferList; - uint32_t length = 0; - while (entry != NULL) { - if (entry->bufferType == BUFFER_TYPE_SPS) { - gs_sps_fix(entry, GS_SPS_BITSTREAM_FIXUP, decoder_buffer, &length); - } else { - memcpy(decoder_buffer+length, entry->data, entry->length); - length += entry->length; - } - entry = entry->next; - } - - au.es.pBuf = decoder_buffer; - au.es.size = decodeUnit->fullLength; - au.dts.lower = 0xFFFFFFFF; - au.dts.upper = 0xFFFFFFFF; - au.pts.lower = 0xFFFFFFFF; - au.pts.upper = 0xFFFFFFFF; - - int ret = 0; - ret = sceAvcdecDecode(decoder, &au, &array_picture); - if (ret < 0) { - printf("sceAvcdecDecode (len=0x%x): 0x%x numOfOutput %d\n", decodeUnit->fullLength, ret, array_picture.numOfOutput); - return DR_NEED_IDR; - } - - if (array_picture.numOfOutput != 1) { - //printf("numOfOutput %d\n", array_picture.numOfOutput); - return DR_OK; - } - - if (active_video_thread) { - if (need_drop > 0) { - vita_debug_log("remain frameskip: %d\n", need_drop); - // skip - need_drop--; - } else { - vita2d_start_drawing(); - - draw_streaming(frame_texture); - draw_fps(); - draw_indicators(); - - vita2d_end_drawing(); - - vita2d_wait_rendering_done(); - vita2d_swap_buffers(); - - frame_count++; - } - } - - // if (numframes++ % 6 == 0) - // return DR_NEED_IDR; - - return DR_OK; -} - -void draw_streaming(vita2d_texture *frame_texture) { - // ui is still rendering in the background, clear the screen first - vita2d_clear_screen(); - vita2d_draw_texture_part(frame_texture, - image_scaling.origin_x, - image_scaling.origin_y, - image_scaling.region_x1, - image_scaling.region_y1, - image_scaling.region_x2, - image_scaling.region_y2); -} - -void draw_fps() { - if (config.show_fps) { - vita2d_font_draw_textf(font, 40, 20, RGBA8(0xFF, 0xFF, 0xFF, 0xFF), 16, "fps: %u / %u", curr_fps[0], curr_fps[1]); - } -} - -void draw_indicators() { - if (poor_net_indicator.activated) { - vita2d_font_draw_text(font, 40, 500, RGBA8(0xFF, 0xFF, 0xFF, poor_net_indicator.alpha), 64, ICON_NETWORK); - poor_net_indicator.alpha += (0x4 * (poor_net_indicator.plus ? 1 : -1)); - if (poor_net_indicator.alpha == 0) { - poor_net_indicator.plus = !poor_net_indicator.plus; - poor_net_indicator.alpha += (0x4 * (poor_net_indicator.plus ? 1 : -1)); - } - } -} - -void vitavideo_start() { - active_video_thread = true; - vita2d_set_vblank_wait(false); -} - -void vitavideo_stop() { - vita2d_set_vblank_wait(true); - active_video_thread = false; -} - -void vitavideo_show_poor_net_indicator() { - poor_net_indicator.activated = true; -} - -void vitavideo_hide_poor_net_indicator() { - //poor_net_indicator.activated = false; - memset(&poor_net_indicator, 0, sizeof(indicator_status)); -} - -DECODER_RENDERER_CALLBACKS decoder_callbacks_vita = { - .setup = vita_setup, - .cleanup = vita_cleanup, - .submitDecodeUnit = vita_submit_decode_unit, - .capabilities = CAPABILITY_SLICES_PER_FRAME(2) | CAPABILITY_DIRECT_SUBMIT, -}; +/* + * This file is part of Moonlight Embedded. + * + * Copyright (C) 2016 Ilya Zhuravlev + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include "../video.h" +#include "../config.h" +#include "../debug.h" +#include "../platform.h" +#include "../gui/guilib.h" +#include "sps.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ROUND_UP(x, a) ((((unsigned int)x)+((a)-1u))&(~((a)-1u))) + +#define DECODE_AU_ALIGNMENT (0x100) +#define AU_BUF_SIZE(STREAM_WIDTH, STREAM_HEIGHT) (STREAM_WIDTH*STREAM_HEIGHT*3/2/2) + +#if 0 +#define printf vita_debug_log +#endif + +void draw_streaming(vita2d_texture *frame_texture); +void draw_fps(); +void draw_indicators(); + +enum { + VITA_VIDEO_INIT_OK = 0, + VITA_VIDEO_ERROR_NO_MEM = 0x80010001, + VITA_VIDEO_ERROR_INIT_LIB = 0x80010002, + VITA_VIDEO_ERROR_QUERY_DEC_MEMSIZE = 0x80010003, + VITA_VIDEO_ERROR_ALLOC_MEM = 0x80010004, + VITA_VIDEO_ERROR_GET_MEMBASE = 0x80010005, + VITA_VIDEO_ERROR_CREATE_DEC = 0x80010006, + VITA_VIDEO_ERROR_CREATE_PACER_THREAD = 0x80010007, +}; + +#define DECODER_BUFFER_SIZE (512 * 1024) + +static char* decoder_buffer = NULL; + +int SCREEN_WIDTH = 960; +int SCREEN_HEIGHT = 544; +int LINE_SIZE = 960; + +extern SceUID state_evf; + +enum VideoStatus { + NOT_INIT, + INIT_GS, + INIT_FRAMEBUFFER, + INIT_AVC_LIB, + INIT_DECODER_MEMBLOCK, + INIT_AVC_DEC, + INIT_FRAME_PACER_THREAD, +}; + +vita2d_texture *frame_texture = NULL; +enum VideoStatus video_status = NOT_INIT; + +SceAvcdecCtrl *decoder = NULL; +SceUID displayblock = -1; +SceUID decoderblock = -1; +SceUID videodecblock = -1; +SceUID videodecUnmap = -1; +SceUIntVAddr videodecContext = 0; +SceUID pacer_thread = -1; +SceVideodecQueryInitInfoHwAvcdec *init = NULL; +SceVideodecQueryInitInfo *initVideodec = NULL; +SceAvcdecQueryDecoderInfo *decoder_info = NULL; + +static SceUID frame_id = 0; +static int pictureInt = 0; + +typedef struct { + bool activated; + uint8_t alpha; + bool plus; +} indicator_status; + +static unsigned numframes; +static bool active_pacer_thread = false; +static indicator_status poor_net_indicator = {0}; + +uint32_t frame_count = 0; +uint32_t need_drop = 0; +uint32_t curr_fps[2] = {0, 0}; +float carry = 0; + +typedef struct { + unsigned int texture_width; + unsigned int texture_height; + float origin_x; + float origin_y; + float region_x1; + float region_y1; + float region_x2; + float region_y2; +} image_scaling_settings; + +static image_scaling_settings image_scaling = {0}; + +// Vita's sceVideodecInitLibrary only accept resolution that is multiple of 16 on either dimension, +// and the smallest resolution is 64 +// Maximum supported resolution for internal decoders is 1920x1088 +#define ROUND_NEAREST_16(x) (round(((double) (x)) / 16) * 16) +#define VITA_DECODER_RESOLUTION_LOWER_BOUND(x) ((x) < 64 ? 64 : (x)) +#define VITA_DECODER_RESOLUTION(x) (VITA_DECODER_RESOLUTION_LOWER_BOUND(ROUND_NEAREST_16(x))) + +void update_scaling_settings(int width, int height) { + image_scaling.texture_width = SCREEN_WIDTH; + image_scaling.texture_height = SCREEN_HEIGHT; + image_scaling.origin_x = 0; + image_scaling.origin_y = 0; + image_scaling.region_x1 = 0; + image_scaling.region_y1 = 0; + image_scaling.region_x2 = image_scaling.texture_width; + image_scaling.region_y2 = image_scaling.texture_height; + + double scaled_width = (double) SCREEN_HEIGHT * width / height; + double scaled_height = (double) SCREEN_WIDTH * height / width; + + if (SCREEN_WIDTH * height == SCREEN_HEIGHT * width) { + // streaming resolution ratio matches Vita's screen ratio + // use default setting + } else if (SCREEN_WIDTH * height > SCREEN_HEIGHT * width) { + // host ratio example: 4:3, 16:10 + // Vita ratio range: 2:16 (64 x 544) - native (960 x 544) + if (config.center_region_only) { + image_scaling.texture_height = VITA_DECODER_RESOLUTION(scaled_height); + image_scaling.region_y1 = VITA_DECODER_RESOLUTION((scaled_height - SCREEN_HEIGHT) / 2); + image_scaling.region_y2 = VITA_DECODER_RESOLUTION((scaled_height + SCREEN_HEIGHT) / 2); + } else { + image_scaling.texture_width = VITA_DECODER_RESOLUTION(scaled_width); + image_scaling.region_x2 = VITA_DECODER_RESOLUTION(scaled_width); + image_scaling.origin_x = round((double) (SCREEN_WIDTH - image_scaling.texture_width) / 2); + } + } else { + // host ratio example: 16:9, 21:9, 32:9 + // Vita ratio range: native (960 x 544) - 15:1 (960 x 64) + if (config.center_region_only) { + image_scaling.texture_width = VITA_DECODER_RESOLUTION(scaled_width); + image_scaling.region_x1 = VITA_DECODER_RESOLUTION((scaled_width - SCREEN_WIDTH) / 2); + image_scaling.region_x2 = VITA_DECODER_RESOLUTION((scaled_width + SCREEN_WIDTH) / 2); + } else { + image_scaling.texture_height = VITA_DECODER_RESOLUTION(scaled_height); + image_scaling.region_y2 = VITA_DECODER_RESOLUTION(scaled_height); + image_scaling.origin_y = round((double) (SCREEN_HEIGHT - image_scaling.texture_height) / 2); + } + } + + sceClibPrintf("update_scaling_settings: width = %u\n", width); + sceClibPrintf("update_scaling_settings: height = %u\n", height); + sceClibPrintf("update_scaling_settings: scaled_width = %f\n", scaled_width); + sceClibPrintf("update_scaling_settings: scaled_height = %f\n", scaled_height); + sceClibPrintf("update_scaling_settings: image_scaling.texture_width = %u\n", image_scaling.texture_width); + sceClibPrintf("update_scaling_settings: image_scaling.texture_height = %u\n", image_scaling.texture_height); + sceClibPrintf("update_scaling_settings: image_scaling.origin_x = %f\n", image_scaling.origin_x); + sceClibPrintf("update_scaling_settings: image_scaling.origin_y = %f\n", image_scaling.origin_y); + sceClibPrintf("update_scaling_settings: image_scaling.region_x1 = %f\n", image_scaling.region_x1); + sceClibPrintf("update_scaling_settings: image_scaling.region_y1 = %f\n", image_scaling.region_y1); + sceClibPrintf("update_scaling_settings: image_scaling.region_x2 = %f\n", image_scaling.region_x2); + sceClibPrintf("update_scaling_settings: image_scaling.region_y2 = %f\n", image_scaling.region_y2); +} + +static int vita_pacer_thread_main(SceSize args, void *argp) { + // 1s + int wait = 1000000; + //float max_fps = 0; + //sceDisplayGetRefreshRate(&max_fps); + //if (config.stream.fps == 30) { + // max_fps /= 2; + //} + int max_fps = config.stream.fps; + uint64_t last_vblank_count = sceDisplayGetVcount(); + uint64_t last_check_time = sceKernelGetSystemTimeWide(); + //float carry = 0; + need_drop = 0; + frame_count = 0; + while (active_pacer_thread) { + uint64_t curr_vblank_count = sceDisplayGetVcount(); + uint32_t vblank_fps = curr_vblank_count - last_vblank_count; + uint32_t curr_frame_count = frame_count; + frame_count = 0; + + if (sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_VIDEO_THREAD, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) { + // carry = 0; + } else { + if (config.enable_frame_pacer && curr_frame_count > max_fps) { + //carry += curr_frame_count - max_fps; + //if (carry > 1) { + // need_drop += (int)carry; + // carry -= (int)carry; + //} + need_drop += curr_frame_count - max_fps; + } + //vita_debug_log("fps0/fps1/carry/need_drop: %u/%u/%f/%u\n", + // curr_frame_count, vblank_fps, carry, need_drop); + } + + curr_fps[0] = curr_frame_count; + curr_fps[1] = vblank_fps; + + last_vblank_count = curr_vblank_count; + uint64_t curr_check_time = sceKernelGetSystemTimeWide(); + uint32_t lapse = curr_check_time - last_check_time; + last_check_time = curr_check_time; + if (lapse > wait && (lapse - wait) < wait) { + //vita_debug_log("sleep: %d", wait * 2 - lapse); + sceKernelDelayThread(wait * 2 - lapse); + } else { + sceKernelDelayThread(wait); + } + } + return 0; +} + +static void vita_cleanup() { + if (video_status == INIT_FRAME_PACER_THREAD) { + active_pacer_thread = false; + // wait 10sec + SceUInt timeout = 10000000; + int ret; + sceKernelWaitThreadEnd(pacer_thread, &ret, &timeout); + sceKernelDeleteThread(pacer_thread); + video_status--; + } + + if (video_status == INIT_AVC_DEC) { + sceAvcdecDeleteDecoder(decoder); + video_status--; + } + + if (video_status == INIT_DECODER_MEMBLOCK) { + if (decoderblock >= 0) { + sceKernelFreeMemBlock(decoderblock); + decoderblock = -1; + } + if (decoder != NULL) { + free(decoder); + decoder = NULL; + } + if (decoder_info != NULL) { + free(decoder_info); + decoder_info = NULL; + } + video_status--; + } + + if (video_status == INIT_AVC_LIB) { + sceVideodecTermLibrary(SCE_VIDEODEC_TYPE_HW_AVCDEC); + + if (init != NULL) { + free(init); + init = NULL; + } + video_status--; + } + + if (video_status == INIT_FRAMEBUFFER) { + if (frame_texture != NULL) { + vita2d_free_texture(frame_texture); + frame_texture = NULL; + } + + if (decoder_buffer != NULL) { + free(decoder_buffer); + decoder_buffer = NULL; + } + video_status--; + } + + if (video_status == INIT_GS) { + gs_sps_stop(); + video_status--; + } +} + +static int vita_setup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) { + int ret; + sceClibPrintf("vita video setup\n"); + + if (video_status == NOT_INIT) { + // INIT_GS + gs_sps_init(width, height); + video_status++; + } + + if (video_status == INIT_GS) { + // INIT_FRAMEBUFFER + update_scaling_settings(width, height); + + decoder_buffer = memalign(DECODE_AU_ALIGNMENT, AU_BUF_SIZE(SCREEN_WIDTH, SCREEN_HEIGHT)); + if (decoder_buffer == NULL) { + sceClibPrintf("not enough memory\n"); + ret = VITA_VIDEO_ERROR_NO_MEM; + goto cleanup; + } + + frame_texture = vita2d_create_empty_texture_format(image_scaling.texture_width, image_scaling.texture_height, SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); + if (frame_texture == NULL) { + sceClibPrintf("not enough memory\n"); + ret = VITA_VIDEO_ERROR_NO_MEM; + goto cleanup; + } + + frame_id = frame_texture->data_UID; + + video_status++; + } + + if (video_status == INIT_FRAMEBUFFER) { + // INIT_AVC_LIB + if (init == NULL) { + init = calloc(1, sizeof(SceVideodecQueryInitInfoHwAvcdec)); + if (init == NULL) { + sceClibPrintf("not enough memory\n"); + ret = VITA_VIDEO_ERROR_NO_MEM; + goto cleanup; + } + } + init->size = sizeof(SceVideodecQueryInitInfoHwAvcdec); + init->horizontal = VITA_DECODER_RESOLUTION(width); + init->vertical = VITA_DECODER_RESOLUTION(height); + init->numOfRefFrames = 3; + init->numOfStreams = 1; + + if (initVideodec == NULL) { + initVideodec = calloc(1, sizeof(SceVideodecQueryInitInfo)); + if (initVideodec == NULL) { + sceClibPrintf("not enough memory\n"); + ret = VITA_VIDEO_ERROR_NO_MEM; + goto cleanup; + } + } + initVideodec->hwAvc = *init; + + ret = sceVideodecSetConfigInternal(SCE_VIDEODEC_TYPE_HW_AVCDEC, 2); + if (ret < 0) { + sceClibPrintf("sceVideodecSetConfigInternal 0x%x\n", ret); + ret = VITA_VIDEO_ERROR_INIT_LIB; + goto cleanup; + } + + ret = sceAvcdecSetDecodeModeInternal(SCE_VIDEODEC_TYPE_HW_AVCDEC, SCE_AVCDEC_MODE_EXTENDED); + if (ret < 0) { + sceClibPrintf("sceAvcdecSetDecodeModeInternal 0x%x\n", ret); + ret = VITA_VIDEO_ERROR_INIT_LIB; + goto cleanup; + } + + ret = sceVideodecInitLibraryInternal(SCE_VIDEODEC_TYPE_HW_AVCDEC, init); + if (ret < 0) { + sceClibPrintf("sceVideodecInitLibraryInternal 0x%x\n", ret); + ret = VITA_VIDEO_ERROR_INIT_LIB; + goto cleanup; + } + + video_status++; + } + + if (video_status == INIT_AVC_LIB) { + // INIT_DECODER_MEMBLOCK + if (decoder_info == NULL) { + decoder_info = calloc(1, sizeof(SceAvcdecQueryDecoderInfo)); + if (decoder_info == NULL) { + sceClibPrintf("not enough memory\n"); + ret = VITA_VIDEO_ERROR_NO_MEM; + goto cleanup; + } + } + decoder_info->horizontal = init->horizontal; + decoder_info->vertical = init->vertical; + decoder_info->numOfRefFrames = init->numOfRefFrames; + + SceAvcdecDecoderInfo decoder_info_out = {0}; + + ret = sceAvcdecQueryDecoderMemSizeInternal(SCE_VIDEODEC_TYPE_HW_AVCDEC, decoder_info, &decoder_info_out); + if (ret < 0) { + sceClibPrintf("sceAvcdecQueryDecoderMemSizeInternal 0x%x size 0x%x\n", ret, decoder_info_out.frameMemSize); + ret = VITA_VIDEO_ERROR_QUERY_DEC_MEMSIZE; + goto cleanup; + } + + sceClibPrintf("Requested size 0x%x\n", decoder_info_out.frameMemSize); + + decoder = calloc(1, sizeof(SceAvcdecCtrl)); + if (decoder == NULL) { + sceClibPrintf("not enough memory\n"); + ret = VITA_VIDEO_ERROR_ALLOC_MEM; + goto cleanup; + } + + decoder->frameBuf.size = decoder_info_out.frameMemSize; + + SceKernelAllocMemBlockOpt opt; + opt.size = sizeof(SceKernelAllocMemBlockOpt); + opt.attr = 4; + opt.alignment = 1024 * 1024; + + decoderblock = sceKernelAllocMemBlock("decoder", SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, decoder_info_out.frameMemSize, &opt); + if (decoderblock < 0) { + sceClibPrintf("decoderblock: 0x%08x\n", decoderblock); + ret = VITA_VIDEO_ERROR_ALLOC_MEM; + goto cleanup; + } + + ret = sceKernelGetMemBlockBase(decoderblock, &decoder->frameBuf.pBuf); + if (ret < 0) { + sceClibPrintf("sceKernelGetMemBlockBase: 0x%x\n", ret); + ret = VITA_VIDEO_ERROR_GET_MEMBASE; + goto cleanup; + } + video_status++; + } + + if (video_status == INIT_DECODER_MEMBLOCK) { + // INIT_AVC_DEC + + ret = sceAvcdecCreateDecoderInternal(SCE_VIDEODEC_TYPE_HW_AVCDEC, decoder, decoder_info); + if (ret < 0) { + sceClibPrintf("sceAvcdecCreateDecoderInternal 0x%x\n", ret); + ret = VITA_VIDEO_ERROR_CREATE_DEC; + goto cleanup; + } + video_status++; + } + + if (video_status == INIT_AVC_DEC) { + // INIT_FRAME_PACER_THREAD + ret = sceKernelCreateThread("frame_pacer", vita_pacer_thread_main, 64, 0x1000, 0, SCE_KERNEL_CPU_MASK_USER_0, NULL); + if (ret < 0) { + sceClibPrintf("sceKernelCreateThread 0x%x\n", ret); + ret = VITA_VIDEO_ERROR_CREATE_PACER_THREAD; + goto cleanup; + } + pacer_thread = ret; + active_pacer_thread = true; + sceKernelStartThread(pacer_thread, 0, NULL); + video_status++; + } + + return VITA_VIDEO_INIT_OK; + +cleanup: + vita_cleanup(); + return ret; +} + +static int vita_submit_decode_unit(PDECODE_UNIT decodeUnit) { + +if (!sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_IS_FG | FLAG_MOONLIGHT_ACTIVE_VIDEO_THREAD, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) { + + SceAvcdecAu au = { 0 }; + SceAvcdecArrayPicture array_picture = { 0 }; + SceAvcdecPicture picture = { 0 }; + SceAvcdecPicture *pictures = { &picture }; + array_picture.numOfElm = 1; + array_picture.pPicture = &pictures; + + //frame->time = decodeUnit->receiveTimeMs; + + picture.size = sizeof(picture); + picture.frame.pixelType = SCE_AVCDEC_PIXEL_RGBA8888; + picture.frame.framePitch = image_scaling.texture_width; + picture.frame.frameWidth = image_scaling.texture_width; + picture.frame.frameHeight = image_scaling.texture_height; + picture.frame.pPicture[0] = vita2d_texture_get_datap(frame_texture); + + if (decodeUnit->fullLength > sceAvcdecDecodeAvailableSize(decoder)) { + sceClibPrintf("Video decode buffer too small\n"); + return DR_OK; + } + + PLENTRY entry = decodeUnit->bufferList; + uint32_t length = 0; + while (entry != NULL) { + if (entry->bufferType == BUFFER_TYPE_SPS) { + gs_sps_fix(entry, GS_SPS_BITSTREAM_FIXUP, decoder_buffer, &length); + } + else { + sceClibMemcpy(decoder_buffer + length, entry->data, entry->length); + length += entry->length; + } + entry = entry->next; + } + + au.es.pBuf = decoder_buffer; + au.es.size = decodeUnit->fullLength; + au.dts.lower = SCE_VIDEODEC_VOID_TIMESTAMP; + au.dts.upper = SCE_VIDEODEC_VOID_TIMESTAMP; + au.pts.lower = SCE_VIDEODEC_VOID_TIMESTAMP; + au.pts.upper = SCE_VIDEODEC_VOID_TIMESTAMP; + + int ret = sceAvcdecDecode(decoder, &au, &array_picture); + if (ret < 0) { + sceClibPrintf("sceAvcdecDecode (len=0x%x): 0x%x\n", decodeUnit->fullLength, ret); + return DR_NEED_IDR; + } + + if (array_picture.numOfOutput != 1) { + //Usually means that Vita's video decoder has "outdated" keyframe so we must request new one + //sceClibPrintf("numOfOutput %d\n", array_picture.numOfOutput); + return DR_NEED_IDR; + } + + //if (active_video_thread) { + if (need_drop > 0) { + vita_debug_log("remain frameskip: %d\n", need_drop); + // skip + need_drop--; + } + else { + vita2d_start_drawing(); + + draw_streaming(frame_texture); + draw_fps(); + draw_indicators(); + + vita2d_end_drawing(); + + //For IME keyboard + if (!sceKernelPollEventFlag(state_evf, FLAG_MOONLIGHT_IS_IME, SCE_KERNEL_EVF_WAITMODE_AND, NULL)) + sceImeUpdate(); + + vita2d_end_shfb(); + + frame_count++; + } + + } + + // if (numframes++ % 6 == 0) + // return DR_NEED_IDR; + + return DR_OK; +} + +void draw_streaming(vita2d_texture *frame_texture_in) { + // ui is still rendering in the background, clear the screen first + vita2d_clear_screen(); + vita2d_draw_texture_part(frame_texture_in, + image_scaling.origin_x, + image_scaling.origin_y, + image_scaling.region_x1, + image_scaling.region_y1, + image_scaling.region_x2, + image_scaling.region_y2); +} + +void draw_fps() { + if (config.show_fps) { + vita2d_pvf_draw_textf(font, 40, 20, RGBA8(0xFF, 0xFF, 0xFF, 0xFF), 1.0f, "fps: %u / %u", curr_fps[0], curr_fps[1]); + } +} + +void draw_indicators() { + if (poor_net_indicator.activated) { + vita2d_pvf_draw_text(font, 40, 500, RGBA8(0xFF, 0xFF, 0xFF, poor_net_indicator.alpha), 2.0f, ICON_NETWORK); + poor_net_indicator.alpha += (0x4 * (poor_net_indicator.plus ? 1 : -1)); + if (poor_net_indicator.alpha == 0) { + poor_net_indicator.plus = !poor_net_indicator.plus; + poor_net_indicator.alpha += (0x4 * (poor_net_indicator.plus ? 1 : -1)); + } + } +} + +void vitavideo_start() { + sceKernelSetEventFlag(state_evf, FLAG_MOONLIGHT_ACTIVE_VIDEO_THREAD); + vita2d_set_vblank_wait(false); +} + +void vitavideo_stop() { + vita2d_set_vblank_wait(true); + sceKernelClearEventFlag(state_evf, ~FLAG_MOONLIGHT_ACTIVE_VIDEO_THREAD); + sceAvcdecDecodeFlush(decoder); +} + +void vitavideo_show_poor_net_indicator() { + poor_net_indicator.activated = true; +} + +void vitavideo_hide_poor_net_indicator() { + //poor_net_indicator.activated = false; + sceClibMemset(&poor_net_indicator, 0, sizeof(indicator_status)); +} + +void vitavideo_flush_decoder() { + sceAvcdecDecodeFlush(decoder); +} + +DECODER_RENDERER_CALLBACKS decoder_callbacks_vita = { + .setup = vita_setup, + .cleanup = vita_cleanup, + .submitDecodeUnit = vita_submit_decode_unit, + .capabilities = CAPABILITY_SLICES_PER_FRAME(2) | CAPABILITY_DIRECT_SUBMIT, +}; diff --git a/src/video/vita.h b/src/video/vita.h index 447e007bd..45cda8f78 100644 --- a/src/video/vita.h +++ b/src/video/vita.h @@ -22,3 +22,4 @@ void vitavideo_start(); void vitavideo_stop(); void vitavideo_show_poor_net_indicator(); void vitavideo_hide_poor_net_indicator(); +void vitavideo_flush_decoder(); diff --git a/third_party/expat/libexpat.suprx b/third_party/expat/libexpat.suprx new file mode 100644 index 000000000..661147556 Binary files /dev/null and b/third_party/expat/libexpat.suprx differ diff --git a/third_party/expat/liblibexpat_stub.a b/third_party/expat/liblibexpat_stub.a new file mode 100644 index 000000000..5e6cc5e80 Binary files /dev/null and b/third_party/expat/liblibexpat_stub.a differ diff --git a/third_party/h264bitstream/bs.h b/third_party/h264bitstream/bs.h index 64f028c9e..de9e8372f 100644 --- a/third_party/h264bitstream/bs.h +++ b/third_party/h264bitstream/bs.h @@ -48,8 +48,8 @@ typedef struct #endif -static bs_t* bs_new(uint8_t* buf, size_t size); -static void bs_free(bs_t* b); +bs_t* bs_new(uint8_t* buf, size_t size); +void bs_free(bs_t* b); static bs_t* bs_clone( bs_t* dest, const bs_t* src ); static bs_t* bs_init(bs_t* b, uint8_t* buf, size_t size); static uint32_t bs_byte_aligned(bs_t* b); @@ -87,18 +87,6 @@ static inline bs_t* bs_init(bs_t* b, uint8_t* buf, size_t size) return b; } -static inline bs_t* bs_new(uint8_t* buf, size_t size) -{ - bs_t* b = (bs_t*)malloc(sizeof(bs_t)); - bs_init(b, buf, size); - return b; -} - -static inline void bs_free(bs_t* b) -{ - free(b); -} - static inline bs_t* bs_clone(bs_t* dest, const bs_t* src) { dest->start = src->p; @@ -226,7 +214,7 @@ static inline void bs_write_u1(bs_t* b, uint32_t v) if (! bs_eof(b)) { // FIXME this is slow, but we must clear bit first - // is it better to memset(0) the whole buffer during bs_init() instead? + // is it better to sceClibMemset(0) the whole buffer during bs_init() instead? // if we don't do either, we introduce pretty nasty bugs (*(b->p)) &= ~(0x01 << b->bits_left); (*(b->p)) |= ((v & 0x01) << b->bits_left); @@ -333,7 +321,7 @@ static inline int bs_read_bytes(bs_t* b, uint8_t* buf, int len) int actual_len = len; if (b->end - b->p < actual_len) { actual_len = b->end - b->p; } if (actual_len < 0) { actual_len = 0; } - memcpy(buf, b->p, actual_len); + sceClibMemcpy(buf, b->p, actual_len); if (len < 0) { len = 0; } b->p += len; return actual_len; @@ -344,7 +332,7 @@ static inline int bs_write_bytes(bs_t* b, uint8_t* buf, int len) int actual_len = len; if (b->end - b->p < actual_len) { actual_len = b->end - b->p; } if (actual_len < 0) { actual_len = 0; } - memcpy(b->p, buf, actual_len); + sceClibMemcpy(b->p, buf, actual_len); if (len < 0) { len = 0; } b->p += len; return actual_len; diff --git a/third_party/h264bitstream/h264_nal.c b/third_party/h264bitstream/h264_nal.c deleted file mode 100644 index d3a5b2825..000000000 --- a/third_party/h264bitstream/h264_nal.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * h264bitstream - a library for reading and writing H.264 video - * Copyright (C) 2005-2007 Auroras Entertainment, LLC - * Copyright (C) 2008-2011 Avail-TVN - * - * Written by Alex Izvorski and Alex Giladi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include "bs.h" -#include "h264_stream.h" -#include "h264_sei.h" - -/** - Create a new H264 stream object. Allocates all structures contained within it. - @return the stream object - */ -h264_stream_t* h264_new() -{ - h264_stream_t* h = (h264_stream_t*)calloc(1, sizeof(h264_stream_t)); - - h->nal = (nal_t*)calloc(1, sizeof(nal_t)); - - // initialize tables - for ( int i = 0; i < 32; i++ ) { h->sps_table[i] = (sps_t*)calloc(1, sizeof(sps_t)); } - for ( int i = 0; i < 256; i++ ) { h->pps_table[i] = (pps_t*)calloc(1, sizeof(pps_t)); } - - h->sps = h->sps_table[0]; - h->pps = h->pps_table[0]; - h->aud = (aud_t*)calloc(1, sizeof(aud_t)); - h->num_seis = 0; - h->seis = NULL; - h->sei = NULL; //This is a TEMP pointer at whats in h->seis... - h->sh = (slice_header_t*)calloc(1, sizeof(slice_header_t)); - h->slice_data = (slice_data_rbsp_t*)calloc(1, sizeof(slice_data_rbsp_t)); - - return h; -} - - -/** - Free an existing H264 stream object. Frees all contained structures. - @param[in,out] h the stream object - */ -void h264_free(h264_stream_t* h) -{ - free(h->nal); - - for ( int i = 0; i < 32; i++ ) { free( h->sps_table[i] ); } - for ( int i = 0; i < 256; i++ ) { free( h->pps_table[i] ); } - - free(h->aud); - if(h->seis != NULL) - { - for( int i = 0; i < h->num_seis; i++ ) - { - sei_t* sei = h->seis[i]; - sei_free(sei); - } - free(h->seis); - } - free(h->sh); - free(h); -} - -/** - Find the beginning and end of a NAL (Network Abstraction Layer) unit in a byte buffer containing H264 bitstream data. - @param[in] buf the buffer - @param[in] size the size of the buffer - @param[out] nal_start the beginning offset of the nal - @param[out] nal_end the end offset of the nal - @return the length of the nal, or 0 if did not find start of nal, or -1 if did not find end of nal - */ -// DEPRECATED - this will be replaced by a similar function with a slightly different API -int find_nal_unit(uint8_t* buf, int size, int* nal_start, int* nal_end) -{ - int i; - // find start - *nal_start = 0; - *nal_end = 0; - - i = 0; - while ( //( next_bits( 24 ) != 0x000001 && next_bits( 32 ) != 0x00000001 ) - (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01) && - (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0 || buf[i+3] != 0x01) - ) - { - i++; // skip leading zero - if (i+4 >= size) { return 0; } // did not find nal start - } - - if (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01) // ( next_bits( 24 ) != 0x000001 ) - { - i++; - } - - if (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01) { /* error, should never happen */ return 0; } - i+= 3; - *nal_start = i; - - while ( //( next_bits( 24 ) != 0x000000 && next_bits( 24 ) != 0x000001 ) - (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0) && - (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01) - ) - { - i++; - // FIXME the next line fails when reading a nal that ends exactly at the end of the data - if (i+3 >= size) { *nal_end = size; return -1; } // did not find nal end, stream ended first - } - - *nal_end = i; - return (*nal_end - *nal_start); -} - - -/** - Convert RBSP data to NAL data (Annex B format). - The size of nal_buf must be 4/3 * the size of the rbsp_buf (rounded up) to guarantee the output will fit. - If that is not true, output may be truncated and an error will be returned. - If that is true, there is no possible error during this conversion. - @param[in] rbsp_buf the rbsp data - @param[in] rbsp_size pointer to the size of the rbsp data - @param[in,out] nal_buf allocated memory in which to put the nal data - @param[in,out] nal_size as input, pointer to the maximum size of the nal data; as output, filled in with the actual size of the nal data - @return actual size of nal data, or -1 on error - */ -// 7.3.1 NAL unit syntax -// 7.4.1.1 Encapsulation of an SODB within an RBSP -int rbsp_to_nal(const uint8_t* rbsp_buf, const int* rbsp_size, uint8_t* nal_buf, int* nal_size) -{ - int i; - int j = 0; - int count = 0; - - for ( i = 0; i < *rbsp_size ; i++ ) - { - if ( j >= *nal_size ) - { - // error, not enough space - return -1; - } - - if ( ( count == 2 ) && !(rbsp_buf[i] & 0xFC) ) // HACK 0xFC - { - nal_buf[j] = 0x03; - j++; - count = 0; - } - nal_buf[j] = rbsp_buf[i]; - if ( rbsp_buf[i] == 0x00 ) - { - count++; - } - else - { - count = 0; - } - j++; - } - - *nal_size = j; - return j; -} - -/** - Convert NAL data (Annex B format) to RBSP data. - The size of rbsp_buf must be the same as size of the nal_buf to guarantee the output will fit. - If that is not true, output may be truncated and an error will be returned. - Additionally, certain byte sequences in the input nal_buf are not allowed in the spec and also cause the conversion to fail and an error to be returned. - @param[in] nal_buf the nal data - @param[in,out] nal_size as input, pointer to the size of the nal data; as output, filled in with the actual size of the nal data - @param[in,out] rbsp_buf allocated memory in which to put the rbsp data - @param[in,out] rbsp_size as input, pointer to the maximum size of the rbsp data; as output, filled in with the actual size of rbsp data - @return actual size of rbsp data, or -1 on error - */ -// 7.3.1 NAL unit syntax -// 7.4.1.1 Encapsulation of an SODB within an RBSP -int nal_to_rbsp(const uint8_t* nal_buf, int* nal_size, uint8_t* rbsp_buf, int* rbsp_size) -{ - int i; - int j = 0; - int count = 0; - - for( i = 0; i < *nal_size; i++ ) - { - // in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position - if( ( count == 2 ) && ( nal_buf[i] < 0x03) ) - { - return -1; - } - - if( ( count == 2 ) && ( nal_buf[i] == 0x03) ) - { - // check the 4th byte after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003 - if((i < *nal_size - 1) && (nal_buf[i+1] > 0x03)) - { - return -1; - } - - // if cabac_zero_word is used, the final byte of this NAL unit(0x03) is discarded, and the last two bytes of RBSP must be 0x0000 - if(i == *nal_size - 1) - { - break; - } - - i++; - count = 0; - } - - if ( j >= *rbsp_size ) - { - // error, not enough space - return -1; - } - - rbsp_buf[j] = nal_buf[i]; - if(nal_buf[i] == 0x00) - { - count++; - } - else - { - count = 0; - } - j++; - } - - *nal_size = i; - *rbsp_size = j; - return j; -} - - -/** - Read only the NAL headers (enough to determine unit type) from a byte buffer. - @return unit type if read successfully, or -1 if this doesn't look like a nal -*/ -int peek_nal_unit(h264_stream_t* h, uint8_t* buf, int size) -{ - nal_t* nal = h->nal; - - bs_t* b = bs_new(buf, size); - - nal->forbidden_zero_bit = bs_read_f(b,1); - nal->nal_ref_idc = bs_read_u(b,2); - nal->nal_unit_type = bs_read_u(b,5); - - bs_free(b); - - // basic verification, per 7.4.1 - if ( nal->forbidden_zero_bit ) { return -1; } - if ( nal->nal_unit_type <= 0 || nal->nal_unit_type > 20 ) { return -1; } - if ( nal->nal_unit_type > 15 && nal->nal_unit_type < 19 ) { return -1; } - - if ( nal->nal_ref_idc == 0 ) - { - if ( nal->nal_unit_type == NAL_UNIT_TYPE_CODED_SLICE_IDR ) - { - return -1; - } - } - else - { - if ( nal->nal_unit_type == NAL_UNIT_TYPE_SEI || - nal->nal_unit_type == NAL_UNIT_TYPE_AUD || - nal->nal_unit_type == NAL_UNIT_TYPE_END_OF_SEQUENCE || - nal->nal_unit_type == NAL_UNIT_TYPE_END_OF_STREAM || - nal->nal_unit_type == NAL_UNIT_TYPE_FILLER ) - { - return -1; - } - } - - return nal->nal_unit_type; -} - - diff --git a/third_party/h264bitstream/h264_sei.c b/third_party/h264bitstream/h264_sei.c deleted file mode 100644 index fcf0a85de..000000000 --- a/third_party/h264bitstream/h264_sei.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * h264bitstream - a library for reading and writing H.264 video - * Copyright (C) 2005-2007 Auroras Entertainment, LLC - * Copyright (C) 2008-2011 Avail-TVN - * - * Written by Alex Izvorski and Alex Giladi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "bs.h" -#include "h264_stream.h" -#include "h264_sei.h" - -#include -#include // malloc -#include // memset - -sei_t* sei_new() -{ - sei_t* s = (sei_t*)malloc(sizeof(sei_t)); - memset(s, 0, sizeof(sei_t)); - s->payload = NULL; - return s; -} - -void sei_free(sei_t* s) -{ - if ( s->payload != NULL ) free(s->payload); - free(s); -} - -void read_sei_end_bits(h264_stream_t* h, bs_t* b ) -{ - // if the message doesn't end at a byte border - if ( !bs_byte_aligned( b ) ) - { - if ( !bs_read_u1( b ) ) fprintf(stderr, "WARNING: bit_equal_to_one is 0!!!!\n"); - while ( ! bs_byte_aligned( b ) ) - { - if ( bs_read_u1( b ) ) fprintf(stderr, "WARNING: bit_equal_to_zero is 1!!!!\n"); - } - } - - read_rbsp_trailing_bits(h, b); -} - -// D.1 SEI payload syntax -void read_sei_payload(h264_stream_t* h, bs_t* b, int payloadType, int payloadSize) -{ - sei_t* s = h->sei; - - s->payload = (uint8_t*)malloc(payloadSize); - - int i; - - for ( i = 0; i < payloadSize; i++ ) - s->payload[i] = bs_read_u(b, 8); - - //read_sei_end_bits(h, b); -} - -// D.1 SEI payload syntax -void write_sei_payload(h264_stream_t* h, bs_t* b, int payloadType, int payloadSize) -{ - sei_t* s = h->sei; - - int i; - for ( i = 0; i < s->payloadSize; i++ ) - bs_write_u(b, 8, s->payload[i]); -} - - - diff --git a/third_party/h264bitstream/h264_stream.c b/third_party/h264bitstream/h264_stream.c deleted file mode 100644 index ddad6c4a0..000000000 --- a/third_party/h264bitstream/h264_stream.c +++ /dev/null @@ -1,2788 +0,0 @@ -/* - * h264bitstream - a library for reading and writing H.264 video - * Copyright (C) 2005-2007 Auroras Entertainment, LLC - * Copyright (C) 2008-2011 Avail-TVN - * Copyright (C) 2012 Alex Izvorski - * - * Written by Alex Izvorski and Alex Giladi - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - - -#include -#include -#include - -#include "bs.h" -#include "h264_stream.h" -#include "h264_sei.h" - -FILE* h264_dbgfile = NULL; - -#define printf(...) fprintf((h264_dbgfile == NULL ? stdout : h264_dbgfile), __VA_ARGS__) - -/** - Calculate the log base 2 of the argument, rounded up. - Zero or negative arguments return zero - Idea from http://www.southwindsgames.com/blog/2009/01/19/fast-integer-log2-function-in-cc/ - */ -int intlog2(int x) -{ - int log = 0; - if (x < 0) { x = 0; } - while ((x >> log) > 0) - { - log++; - } - if (log > 0 && x == 1<<(log-1)) { log--; } - return log; -} - -int is_slice_type(int slice_type, int cmp_type) -{ - if (slice_type >= 5) { slice_type -= 5; } - if (cmp_type >= 5) { cmp_type -= 5; } - if (slice_type == cmp_type) { return 1; } - else { return 0; } -} - -int more_rbsp_data(h264_stream_t* h, bs_t* bs) -{ - // TODO this version handles reading only. writing version? - - // no more data - if (bs_eof(bs)) { return 0; } - - // no rbsp_stop_bit yet - if (bs_peek_u1(bs) == 0) { return 1; } - - // next bit is 1, is it the rsbp_stop_bit? only if the rest of bits are 0 - bs_t bs_tmp; - bs_clone(&bs_tmp, bs); - bs_skip_u1(&bs_tmp); - while(!bs_eof(&bs_tmp)) - { - // A later bit was 1, it wasn't the rsbp_stop_bit - if (bs_read_u1(&bs_tmp) == 1) { return 1; } - } - - // All following bits were 0, it was the rsbp_stop_bit - return 0; -} - -int more_rbsp_trailing_data(h264_stream_t* h, bs_t* b) { return !bs_eof(b); } - -int _read_ff_coded_number(bs_t* b) -{ - int n1 = 0; - int n2; - do - { - n2 = bs_read_u8(b); - n1 += n2; - } while (n2 == 0xff); - return n1; -} - -void _write_ff_coded_number(bs_t* b, int n) -{ - while (1) - { - if (n > 0xff) - { - bs_write_u8(b, 0xff); - n -= 0xff; - } - else - { - bs_write_u8(b, n); - break; - } - } -} - -void debug_bytes(uint8_t* buf, int len) -{ - int i; - for (i = 0; i < len; i++) - { - printf("%02X ", buf[i]); - if ((i+1) % 16 == 0) { printf ("\n"); } - } - printf("\n"); -} - - - -void read_seq_parameter_set_rbsp(h264_stream_t* h, bs_t* b); -void read_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int* useDefaultScalingMatrixFlag ); -void read_vui_parameters(h264_stream_t* h, bs_t* b); -void read_hrd_parameters(h264_stream_t* h, bs_t* b); -void read_pic_parameter_set_rbsp(h264_stream_t* h, bs_t* b); -void read_sei_rbsp(h264_stream_t* h, bs_t* b); -void read_sei_message(h264_stream_t* h, bs_t* b); -void read_access_unit_delimiter_rbsp(h264_stream_t* h, bs_t* b); -void read_end_of_seq_rbsp(h264_stream_t* h, bs_t* b); -void read_end_of_stream_rbsp(h264_stream_t* h, bs_t* b); -void read_filler_data_rbsp(h264_stream_t* h, bs_t* b); -void read_slice_layer_rbsp(h264_stream_t* h, bs_t* b); -void read_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b); -void read_rbsp_trailing_bits(h264_stream_t* h, bs_t* b); -void read_slice_header(h264_stream_t* h, bs_t* b); -void read_ref_pic_list_reordering(h264_stream_t* h, bs_t* b); -void read_pred_weight_table(h264_stream_t* h, bs_t* b); -void read_dec_ref_pic_marking(h264_stream_t* h, bs_t* b); - - - -//7.3.1 NAL unit syntax -int read_nal_unit(h264_stream_t* h, uint8_t* buf, int size) -{ - nal_t* nal = h->nal; - - int nal_size = size; - int rbsp_size = size; - uint8_t* rbsp_buf = (uint8_t*)calloc(1, rbsp_size); - - if( 1 ) - { - int rc = nal_to_rbsp(buf, &nal_size, rbsp_buf, &rbsp_size); - - if (rc < 0) { free(rbsp_buf); return -1; } // handle conversion error - } - - if( 0 ) - { - rbsp_size = size*3/4; // NOTE this may have to be slightly smaller (3/4 smaller, worst case) in order to be guaranteed to fit - } - - bs_t* b = bs_new(rbsp_buf, rbsp_size); - /* forbidden_zero_bit */ bs_skip_u(b, 1); - nal->nal_ref_idc = bs_read_u(b, 2); - nal->nal_unit_type = bs_read_u(b, 5); - - switch ( nal->nal_unit_type ) - { - case NAL_UNIT_TYPE_CODED_SLICE_IDR: - case NAL_UNIT_TYPE_CODED_SLICE_NON_IDR: - case NAL_UNIT_TYPE_CODED_SLICE_AUX: - read_slice_layer_rbsp(h, b); - break; - -#ifdef HAVE_SEI - case NAL_UNIT_TYPE_SEI: - read_sei_rbsp(h, b); - break; -#endif - - case NAL_UNIT_TYPE_SPS: - read_seq_parameter_set_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_PPS: - read_pic_parameter_set_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_AUD: - read_access_unit_delimiter_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_END_OF_SEQUENCE: - read_end_of_seq_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_END_OF_STREAM: - read_end_of_stream_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_FILLER: - case NAL_UNIT_TYPE_SPS_EXT: - case NAL_UNIT_TYPE_UNSPECIFIED: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C: - default: - return -1; - } - - if (bs_overrun(b)) { bs_free(b); free(rbsp_buf); return -1; } - - if( 0 ) - { - // now get the actual size used - rbsp_size = bs_pos(b); - - int rc = rbsp_to_nal(rbsp_buf, &rbsp_size, buf, &nal_size); - if (rc < 0) { bs_free(b); free(rbsp_buf); return -1; } - } - - bs_free(b); - free(rbsp_buf); - - return nal_size; -} - - - -//7.3.2.1 Sequence parameter set RBSP syntax -void read_seq_parameter_set_rbsp(h264_stream_t* h, bs_t* b) -{ - int i; - - sps_t* sps = h->sps; - if( 1 ) - { - memset(sps, 0, sizeof(sps_t)); - sps->chroma_format_idc = 1; - } - - sps->profile_idc = bs_read_u8(b); - sps->constraint_set0_flag = bs_read_u1(b); - sps->constraint_set1_flag = bs_read_u1(b); - sps->constraint_set2_flag = bs_read_u1(b); - sps->constraint_set3_flag = bs_read_u1(b); - sps->constraint_set4_flag = bs_read_u1(b); - sps->constraint_set5_flag = bs_read_u1(b); - /* reserved_zero_2bits */ bs_skip_u(b, 2); - sps->level_idc = bs_read_u8(b); - sps->seq_parameter_set_id = bs_read_ue(b); - - if( sps->profile_idc == 100 || sps->profile_idc == 110 || - sps->profile_idc == 122 || sps->profile_idc == 144 ) - { - sps->chroma_format_idc = bs_read_ue(b); - if( sps->chroma_format_idc == 3 ) - { - sps->residual_colour_transform_flag = bs_read_u1(b); - } - sps->bit_depth_luma_minus8 = bs_read_ue(b); - sps->bit_depth_chroma_minus8 = bs_read_ue(b); - sps->qpprime_y_zero_transform_bypass_flag = bs_read_u1(b); - sps->seq_scaling_matrix_present_flag = bs_read_u1(b); - if( sps->seq_scaling_matrix_present_flag ) - { - for( i = 0; i < 8; i++ ) - { - sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b); - if( sps->seq_scaling_list_present_flag[ i ] ) - { - if( i < 6 ) - { - read_scaling_list( b, sps->ScalingList4x4[ i ], 16, - &( sps->UseDefaultScalingMatrix4x4Flag[ i ] ) ); - } - else - { - read_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64, - &( sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ) ); - } - } - } - } - } - sps->log2_max_frame_num_minus4 = bs_read_ue(b); - sps->pic_order_cnt_type = bs_read_ue(b); - if( sps->pic_order_cnt_type == 0 ) - { - sps->log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b); - } - else if( sps->pic_order_cnt_type == 1 ) - { - sps->delta_pic_order_always_zero_flag = bs_read_u1(b); - sps->offset_for_non_ref_pic = bs_read_se(b); - sps->offset_for_top_to_bottom_field = bs_read_se(b); - sps->num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b); - for( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ) - { - sps->offset_for_ref_frame[ i ] = bs_read_se(b); - } - } - sps->num_ref_frames = bs_read_ue(b); - sps->gaps_in_frame_num_value_allowed_flag = bs_read_u1(b); - sps->pic_width_in_mbs_minus1 = bs_read_ue(b); - sps->pic_height_in_map_units_minus1 = bs_read_ue(b); - sps->frame_mbs_only_flag = bs_read_u1(b); - if( !sps->frame_mbs_only_flag ) - { - sps->mb_adaptive_frame_field_flag = bs_read_u1(b); - } - sps->direct_8x8_inference_flag = bs_read_u1(b); - sps->frame_cropping_flag = bs_read_u1(b); - if( sps->frame_cropping_flag ) - { - sps->frame_crop_left_offset = bs_read_ue(b); - sps->frame_crop_right_offset = bs_read_ue(b); - sps->frame_crop_top_offset = bs_read_ue(b); - sps->frame_crop_bottom_offset = bs_read_ue(b); - } - sps->vui_parameters_present_flag = bs_read_u1(b); - if( sps->vui_parameters_present_flag ) - { - read_vui_parameters(h, b); - } - read_rbsp_trailing_bits(h, b); - - if( 1 ) - { - memcpy(h->sps_table[sps->seq_parameter_set_id], h->sps, sizeof(sps_t)); - } -} - - -//7.3.2.1.1 Scaling list syntax -void read_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int* useDefaultScalingMatrixFlag ) -{ - // NOTE need to be able to set useDefaultScalingMatrixFlag when reading, hence passing as pointer - int lastScale = 8; - int nextScale = 8; - int delta_scale; - for( int j = 0; j < sizeOfScalingList; j++ ) - { - if( nextScale != 0 ) - { - if( 0 ) - { - nextScale = scalingList[ j ]; - if (useDefaultScalingMatrixFlag[0]) { nextScale = 0; } - delta_scale = (nextScale - lastScale) % 256 ; - } - - delta_scale = bs_read_se(b); - - if( 1 ) - { - nextScale = ( lastScale + delta_scale + 256 ) % 256; - useDefaultScalingMatrixFlag[0] = ( j == 0 && nextScale == 0 ); - } - } - if( 1 ) - { - scalingList[ j ] = ( nextScale == 0 ) ? lastScale : nextScale; - } - lastScale = scalingList[ j ]; - } -} - -//Appendix E.1.1 VUI parameters syntax -void read_vui_parameters(h264_stream_t* h, bs_t* b) -{ - sps_t* sps = h->sps; - - sps->vui.aspect_ratio_info_present_flag = bs_read_u1(b); - if( sps->vui.aspect_ratio_info_present_flag ) - { - sps->vui.aspect_ratio_idc = bs_read_u8(b); - if( sps->vui.aspect_ratio_idc == SAR_Extended ) - { - sps->vui.sar_width = bs_read_u(b, 16); - sps->vui.sar_height = bs_read_u(b, 16); - } - } - sps->vui.overscan_info_present_flag = bs_read_u1(b); - if( sps->vui.overscan_info_present_flag ) - { - sps->vui.overscan_appropriate_flag = bs_read_u1(b); - } - sps->vui.video_signal_type_present_flag = bs_read_u1(b); - if( sps->vui.video_signal_type_present_flag ) - { - sps->vui.video_format = bs_read_u(b, 3); - sps->vui.video_full_range_flag = bs_read_u1(b); - sps->vui.colour_description_present_flag = bs_read_u1(b); - if( sps->vui.colour_description_present_flag ) - { - sps->vui.colour_primaries = bs_read_u8(b); - sps->vui.transfer_characteristics = bs_read_u8(b); - sps->vui.matrix_coefficients = bs_read_u8(b); - } - } - sps->vui.chroma_loc_info_present_flag = bs_read_u1(b); - if( sps->vui.chroma_loc_info_present_flag ) - { - sps->vui.chroma_sample_loc_type_top_field = bs_read_ue(b); - sps->vui.chroma_sample_loc_type_bottom_field = bs_read_ue(b); - } - sps->vui.timing_info_present_flag = bs_read_u1(b); - if( sps->vui.timing_info_present_flag ) - { - sps->vui.num_units_in_tick = bs_read_u(b, 32); - sps->vui.time_scale = bs_read_u(b, 32); - sps->vui.fixed_frame_rate_flag = bs_read_u1(b); - } - sps->vui.nal_hrd_parameters_present_flag = bs_read_u1(b); - if( sps->vui.nal_hrd_parameters_present_flag ) - { - read_hrd_parameters(h, b); - } - sps->vui.vcl_hrd_parameters_present_flag = bs_read_u1(b); - if( sps->vui.vcl_hrd_parameters_present_flag ) - { - read_hrd_parameters(h, b); - } - if( sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag ) - { - sps->vui.low_delay_hrd_flag = bs_read_u1(b); - } - sps->vui.pic_struct_present_flag = bs_read_u1(b); - sps->vui.bitstream_restriction_flag = bs_read_u1(b); - if( sps->vui.bitstream_restriction_flag ) - { - sps->vui.motion_vectors_over_pic_boundaries_flag = bs_read_u1(b); - sps->vui.max_bytes_per_pic_denom = bs_read_ue(b); - sps->vui.max_bits_per_mb_denom = bs_read_ue(b); - sps->vui.log2_max_mv_length_horizontal = bs_read_ue(b); - sps->vui.log2_max_mv_length_vertical = bs_read_ue(b); - sps->vui.num_reorder_frames = bs_read_ue(b); - sps->vui.max_dec_frame_buffering = bs_read_ue(b); - } -} - - -//Appendix E.1.2 HRD parameters syntax -void read_hrd_parameters(h264_stream_t* h, bs_t* b) -{ - sps_t* sps = h->sps; - - sps->hrd.cpb_cnt_minus1 = bs_read_ue(b); - sps->hrd.bit_rate_scale = bs_read_u(b, 4); - sps->hrd.cpb_size_scale = bs_read_u(b, 4); - for( int SchedSelIdx = 0; SchedSelIdx <= sps->hrd.cpb_cnt_minus1; SchedSelIdx++ ) - { - sps->hrd.bit_rate_value_minus1[ SchedSelIdx ] = bs_read_ue(b); - sps->hrd.cpb_size_value_minus1[ SchedSelIdx ] = bs_read_ue(b); - sps->hrd.cbr_flag[ SchedSelIdx ] = bs_read_u1(b); - } - sps->hrd.initial_cpb_removal_delay_length_minus1 = bs_read_u(b, 5); - sps->hrd.cpb_removal_delay_length_minus1 = bs_read_u(b, 5); - sps->hrd.dpb_output_delay_length_minus1 = bs_read_u(b, 5); - sps->hrd.time_offset_length = bs_read_u(b, 5); -} - - -/* -UNIMPLEMENTED -//7.3.2.1.2 Sequence parameter set extension RBSP syntax -int read_seq_parameter_set_extension_rbsp(bs_t* b, sps_ext_t* sps_ext) { - seq_parameter_set_id = bs_read_ue(b); - aux_format_idc = bs_read_ue(b); - if( aux_format_idc != 0 ) { - bit_depth_aux_minus8 = bs_read_ue(b); - alpha_incr_flag = bs_read_u1(b); - alpha_opaque_value = bs_read_u(v); - alpha_transparent_value = bs_read_u(v); - } - additional_extension_flag = bs_read_u1(b); - read_rbsp_trailing_bits(); -} -*/ - -//7.3.2.2 Picture parameter set RBSP syntax -void read_pic_parameter_set_rbsp(h264_stream_t* h, bs_t* b) -{ - pps_t* pps = h->pps; - if( 1 ) - { - memset(pps, 0, sizeof(pps_t)); - } - - pps->pic_parameter_set_id = bs_read_ue(b); - pps->seq_parameter_set_id = bs_read_ue(b); - pps->entropy_coding_mode_flag = bs_read_u1(b); - pps->pic_order_present_flag = bs_read_u1(b); - pps->num_slice_groups_minus1 = bs_read_ue(b); - - if( pps->num_slice_groups_minus1 > 0 ) - { - pps->slice_group_map_type = bs_read_ue(b); - if( pps->slice_group_map_type == 0 ) - { - for( int i_group = 0; i_group <= pps->num_slice_groups_minus1; i_group++ ) - { - pps->run_length_minus1[ i_group ] = bs_read_ue(b); - } - } - else if( pps->slice_group_map_type == 2 ) - { - for( int i_group = 0; i_group < pps->num_slice_groups_minus1; i_group++ ) - { - pps->top_left[ i_group ] = bs_read_ue(b); - pps->bottom_right[ i_group ] = bs_read_ue(b); - } - } - else if( pps->slice_group_map_type == 3 || - pps->slice_group_map_type == 4 || - pps->slice_group_map_type == 5 ) - { - pps->slice_group_change_direction_flag = bs_read_u1(b); - pps->slice_group_change_rate_minus1 = bs_read_ue(b); - } - else if( pps->slice_group_map_type == 6 ) - { - pps->pic_size_in_map_units_minus1 = bs_read_ue(b); - for( int i = 0; i <= pps->pic_size_in_map_units_minus1; i++ ) - { - int v = intlog2( pps->num_slice_groups_minus1 + 1 ); - pps->slice_group_id[ i ] = bs_read_u(b, v); - } - } - } - pps->num_ref_idx_l0_active_minus1 = bs_read_ue(b); - pps->num_ref_idx_l1_active_minus1 = bs_read_ue(b); - pps->weighted_pred_flag = bs_read_u1(b); - pps->weighted_bipred_idc = bs_read_u(b, 2); - pps->pic_init_qp_minus26 = bs_read_se(b); - pps->pic_init_qs_minus26 = bs_read_se(b); - pps->chroma_qp_index_offset = bs_read_se(b); - pps->deblocking_filter_control_present_flag = bs_read_u1(b); - pps->constrained_intra_pred_flag = bs_read_u1(b); - pps->redundant_pic_cnt_present_flag = bs_read_u1(b); - - int have_more_data = 0; - if( 1 ) { have_more_data = more_rbsp_data(h, b); } - if( 0 ) - { - have_more_data = pps->transform_8x8_mode_flag | pps->pic_scaling_matrix_present_flag | pps->second_chroma_qp_index_offset != 0; - } - - if( have_more_data ) - { - pps->transform_8x8_mode_flag = bs_read_u1(b); - pps->pic_scaling_matrix_present_flag = bs_read_u1(b); - if( pps->pic_scaling_matrix_present_flag ) - { - for( int i = 0; i < 6 + 2* pps->transform_8x8_mode_flag; i++ ) - { - pps->pic_scaling_list_present_flag[ i ] = bs_read_u1(b); - if( pps->pic_scaling_list_present_flag[ i ] ) - { - if( i < 6 ) - { - read_scaling_list( b, pps->ScalingList4x4[ i ], 16, - &( pps->UseDefaultScalingMatrix4x4Flag[ i ] ) ); - } - else - { - read_scaling_list( b, pps->ScalingList8x8[ i - 6 ], 64, - &( pps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ) ); - } - } - } - } - pps->second_chroma_qp_index_offset = bs_read_se(b); - } - read_rbsp_trailing_bits(h, b); - - if( 1 ) - { - memcpy(h->pps, h->pps_table[pps->pic_parameter_set_id], sizeof(pps_t)); - } -} - -#ifdef HAVE_SEI -//7.3.2.3 Supplemental enhancement information RBSP syntax -void read_sei_rbsp(h264_stream_t* h, bs_t* b) -{ - if( 1 ) - { - for( int i = 0; i < h->num_seis; i++ ) - { - sei_free(h->seis[i]); - } - - h->num_seis = 0; - do { - h->num_seis++; - h->seis = (sei_t**)realloc(h->seis, h->num_seis * sizeof(sei_t*)); - h->seis[h->num_seis - 1] = sei_new(); - h->sei = h->seis[h->num_seis - 1]; - read_sei_message(h, b); - } while( more_rbsp_data(h, b) ); - - } - - if( 0 ) - { - for (int i = 0; i < h->num_seis; i++) - { - h->sei = h->seis[i]; - read_sei_message(h, b); - } - h->sei = NULL; - } - - read_rbsp_trailing_bits(h, b); -} - -//7.3.2.3.1 Supplemental enhancement information message syntax -void read_sei_message(h264_stream_t* h, bs_t* b) -{ - if( 0 ) - { - _write_ff_coded_number(b, h->sei->payloadType); - _write_ff_coded_number(b, h->sei->payloadSize); - } - if( 1 ) - { - h->sei->payloadType = _read_ff_coded_number(b); - h->sei->payloadSize = _read_ff_coded_number(b); - } - read_sei_payload( h, b, h->sei->payloadType, h->sei->payloadSize ); -} -#endif - -//7.3.2.4 Access unit delimiter RBSP syntax -void read_access_unit_delimiter_rbsp(h264_stream_t* h, bs_t* b) -{ - h->aud->primary_pic_type = bs_read_u(b, 3); - read_rbsp_trailing_bits(h, b); -} - -//7.3.2.5 End of sequence RBSP syntax -void read_end_of_seq_rbsp(h264_stream_t* h, bs_t* b) -{ -} - -//7.3.2.6 End of stream RBSP syntax -void read_end_of_stream_rbsp(h264_stream_t* h, bs_t* b) -{ -} - -//7.3.2.7 Filler data RBSP syntax -void read_filler_data_rbsp(h264_stream_t* h, bs_t* b) -{ - while( bs_next_bits(b, 8) == 0xFF ) - { - /* ff_byte */ bs_skip_u(b, 8); - } - read_rbsp_trailing_bits(h, b); -} - -//7.3.2.8 Slice layer without partitioning RBSP syntax -void read_slice_layer_rbsp(h264_stream_t* h, bs_t* b) -{ - read_slice_header(h, b); - slice_data_rbsp_t* slice_data = h->slice_data; - - if ( slice_data != NULL ) - { - if ( slice_data->rbsp_buf != NULL ) free( slice_data->rbsp_buf ); - uint8_t *sptr = b->p + (!!b->bits_left); // CABAC-specific: skip alignment bits, if there are any - slice_data->rbsp_size = b->end - sptr; - - slice_data->rbsp_buf = (uint8_t*)malloc(slice_data->rbsp_size); - memcpy( slice_data->rbsp_buf, sptr, slice_data->rbsp_size ); - // ugly hack: since next NALU starts at byte border, we are going to be padded by trailing_bits; - return; - } - - // FIXME should read or skip data - //slice_data( ); /* all categories of slice_data( ) syntax */ - read_rbsp_slice_trailing_bits(h, b); -} - -/* -// UNIMPLEMENTED -//7.3.2.9.1 Slice data partition A RBSP syntax -slice_data_partition_a_layer_rbsp( ) { - read_slice_header( ); // only category 2 - slice_id = bs_read_ue(b) - read_slice_data( ); // only category 2 - read_rbsp_slice_trailing_bits( ); // only category 2 -} - -//7.3.2.9.2 Slice data partition B RBSP syntax -slice_data_partition_b_layer_rbsp( ) { - slice_id = bs_read_ue(b); // only category 3 - if( redundant_pic_cnt_present_flag ) - redundant_pic_cnt = bs_read_ue(b); - read_slice_data( ); // only category 3 - read_rbsp_slice_trailing_bits( ); // only category 3 -} - -//7.3.2.9.3 Slice data partition C RBSP syntax -slice_data_partition_c_layer_rbsp( ) { - slice_id = bs_read_ue(b); // only category 4 - if( redundant_pic_cnt_present_flag ) - redundant_pic_cnt = bs_read_ue(b); - read_slice_data( ); // only category 4 - rbsp_slice_trailing_bits( ); // only category 4 -} -*/ - -//7.3.2.10 RBSP slice trailing bits syntax -void read_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b) -{ - read_rbsp_trailing_bits(h, b); - if( h->pps->entropy_coding_mode_flag ) - { - while( more_rbsp_trailing_data(h, b) ) - { - /* cabac_zero_word */ bs_skip_u(b, 16); - } - } -} - -//7.3.2.11 RBSP trailing bits syntax -void read_rbsp_trailing_bits(h264_stream_t* h, bs_t* b) -{ - /* rbsp_stop_one_bit */ bs_skip_u(b, 1); - - while( !bs_byte_aligned(b) ) - { - /* rbsp_alignment_zero_bit */ bs_skip_u(b, 1); - } -} - -//7.3.3 Slice header syntax -void read_slice_header(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - if( 1 ) - { - memset(sh, 0, sizeof(slice_header_t)); - } - - nal_t* nal = h->nal; - - sh->first_mb_in_slice = bs_read_ue(b); - sh->slice_type = bs_read_ue(b); - sh->pic_parameter_set_id = bs_read_ue(b); - - // TODO check existence, otherwise fail - pps_t* pps = h->pps; - sps_t* sps = h->sps; - memcpy(h->pps_table[sh->pic_parameter_set_id], h->pps, sizeof(pps_t)); - memcpy(h->sps_table[pps->seq_parameter_set_id], h->sps, sizeof(sps_t)); - - sh->frame_num = bs_read_u(b, sps->log2_max_frame_num_minus4 + 4 ); // was u(v) - if( !sps->frame_mbs_only_flag ) - { - sh->field_pic_flag = bs_read_u1(b); - if( sh->field_pic_flag ) - { - sh->bottom_field_flag = bs_read_u1(b); - } - } - if( nal->nal_unit_type == 5 ) - { - sh->idr_pic_id = bs_read_ue(b); - } - if( sps->pic_order_cnt_type == 0 ) - { - sh->pic_order_cnt_lsb = bs_read_u(b, sps->log2_max_pic_order_cnt_lsb_minus4 + 4 ); // was u(v) - if( pps->pic_order_present_flag && !sh->field_pic_flag ) - { - sh->delta_pic_order_cnt_bottom = bs_read_se(b); - } - } - if( sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag ) - { - sh->delta_pic_order_cnt[ 0 ] = bs_read_se(b); - if( pps->pic_order_present_flag && !sh->field_pic_flag ) - { - sh->delta_pic_order_cnt[ 1 ] = bs_read_se(b); - } - } - if( pps->redundant_pic_cnt_present_flag ) - { - sh->redundant_pic_cnt = bs_read_ue(b); - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - sh->direct_spatial_mv_pred_flag = bs_read_u1(b); - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_P ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - sh->num_ref_idx_active_override_flag = bs_read_u1(b); - if( sh->num_ref_idx_active_override_flag ) - { - sh->num_ref_idx_l0_active_minus1 = bs_read_ue(b); // FIXME does this modify the pps? - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - sh->num_ref_idx_l1_active_minus1 = bs_read_ue(b); - } - } - } - read_ref_pic_list_reordering(h, b); - if( ( pps->weighted_pred_flag && ( is_slice_type( sh->slice_type, SH_SLICE_TYPE_P ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) ) ) || - ( pps->weighted_bipred_idc == 1 && is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) ) - { - read_pred_weight_table(h, b); - } - if( nal->nal_ref_idc != 0 ) - { - read_dec_ref_pic_marking(h, b); - } - if( pps->entropy_coding_mode_flag && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - sh->cabac_init_idc = bs_read_ue(b); - } - sh->slice_qp_delta = bs_read_se(b); - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) ) - { - sh->sp_for_switch_flag = bs_read_u1(b); - } - sh->slice_qs_delta = bs_read_se(b); - } - if( pps->deblocking_filter_control_present_flag ) - { - sh->disable_deblocking_filter_idc = bs_read_ue(b); - if( sh->disable_deblocking_filter_idc != 1 ) - { - sh->slice_alpha_c0_offset_div2 = bs_read_se(b); - sh->slice_beta_offset_div2 = bs_read_se(b); - } - } - if( pps->num_slice_groups_minus1 > 0 && - pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) - { - int v = intlog2( pps->pic_size_in_map_units_minus1 + pps->slice_group_change_rate_minus1 + 1 ); - sh->slice_group_change_cycle = bs_read_u(b, v); // FIXME add 2? - } -} - -//7.3.3.1 Reference picture list reordering syntax -void read_ref_pic_list_reordering(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - // FIXME should be an array - - if( ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - sh->rplr.ref_pic_list_reordering_flag_l0 = bs_read_u1(b); - if( sh->rplr.ref_pic_list_reordering_flag_l0 ) - { - int n = -1; - do - { - n++; - sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] = bs_read_ue(b); - if( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 0 || - sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 1 ) - { - sh->rplr.reorder_l0.abs_diff_pic_num_minus1[ n ] = bs_read_ue(b); - } - else if( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 2 ) - { - sh->rplr.reorder_l0.long_term_pic_num[ n ] = bs_read_ue(b); - } - } while( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] != 3 && ! bs_eof(b) ); - } - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - sh->rplr.ref_pic_list_reordering_flag_l1 = bs_read_u1(b); - if( sh->rplr.ref_pic_list_reordering_flag_l1 ) - { - int n = -1; - do - { - n++; - sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] = bs_read_ue(b); - if( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 0 || - sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 1 ) - { - sh->rplr.reorder_l1.abs_diff_pic_num_minus1[ n ] = bs_read_ue(b); - } - else if( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 2 ) - { - sh->rplr.reorder_l1.long_term_pic_num[ n ] = bs_read_ue(b); - } - } while( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] != 3 && ! bs_eof(b) ); - } - } -} - -//7.3.3.2 Prediction weight table syntax -void read_pred_weight_table(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - sps_t* sps = h->sps; - pps_t* pps = h->pps; - - int i, j; - - sh->pwt.luma_log2_weight_denom = bs_read_ue(b); - if( sps->chroma_format_idc != 0 ) - { - sh->pwt.chroma_log2_weight_denom = bs_read_ue(b); - } - for( i = 0; i <= pps->num_ref_idx_l0_active_minus1; i++ ) - { - sh->pwt.luma_weight_l0_flag[i] = bs_read_u1(b); - if( sh->pwt.luma_weight_l0_flag[i] ) - { - sh->pwt.luma_weight_l0[ i ] = bs_read_se(b); - sh->pwt.luma_offset_l0[ i ] = bs_read_se(b); - } - if ( sps->chroma_format_idc != 0 ) - { - sh->pwt.chroma_weight_l0_flag[i] = bs_read_u1(b); - if( sh->pwt.chroma_weight_l0_flag[i] ) - { - for( j =0; j < 2; j++ ) - { - sh->pwt.chroma_weight_l0[ i ][ j ] = bs_read_se(b); - sh->pwt.chroma_offset_l0[ i ][ j ] = bs_read_se(b); - } - } - } - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - for( i = 0; i <= pps->num_ref_idx_l1_active_minus1; i++ ) - { - sh->pwt.luma_weight_l1_flag[i] = bs_read_u1(b); - if( sh->pwt.luma_weight_l1_flag[i] ) - { - sh->pwt.luma_weight_l1[ i ] = bs_read_se(b); - sh->pwt.luma_offset_l1[ i ] = bs_read_se(b); - } - if( sps->chroma_format_idc != 0 ) - { - sh->pwt.chroma_weight_l1_flag[i] = bs_read_u1(b); - if( sh->pwt.chroma_weight_l1_flag[i] ) - { - for( j = 0; j < 2; j++ ) - { - sh->pwt.chroma_weight_l1[ i ][ j ] = bs_read_se(b); - sh->pwt.chroma_offset_l1[ i ][ j ] = bs_read_se(b); - } - } - } - } - } -} - -//7.3.3.3 Decoded reference picture marking syntax -void read_dec_ref_pic_marking(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - // FIXME should be an array - - if( h->nal->nal_unit_type == 5 ) - { - sh->drpm.no_output_of_prior_pics_flag = bs_read_u1(b); - sh->drpm.long_term_reference_flag = bs_read_u1(b); - } - else - { - sh->drpm.adaptive_ref_pic_marking_mode_flag = bs_read_u1(b); - if( sh->drpm.adaptive_ref_pic_marking_mode_flag ) - { - int n = -1; - do - { - n++; - sh->drpm.memory_management_control_operation[ n ] = bs_read_ue(b); - if( sh->drpm.memory_management_control_operation[ n ] == 1 || - sh->drpm.memory_management_control_operation[ n ] == 3 ) - { - sh->drpm.difference_of_pic_nums_minus1[ n ] = bs_read_ue(b); - } - if(sh->drpm.memory_management_control_operation[ n ] == 2 ) - { - sh->drpm.long_term_pic_num[ n ] = bs_read_ue(b); - } - if( sh->drpm.memory_management_control_operation[ n ] == 3 || - sh->drpm.memory_management_control_operation[ n ] == 6 ) - { - sh->drpm.long_term_frame_idx[ n ] = bs_read_ue(b); - } - if( sh->drpm.memory_management_control_operation[ n ] == 4 ) - { - sh->drpm.max_long_term_frame_idx_plus1[ n ] = bs_read_ue(b); - } - } while( sh->drpm.memory_management_control_operation[ n ] != 0 && ! bs_eof(b) ); - } - } -} - - -void write_seq_parameter_set_rbsp(h264_stream_t* h, bs_t* b); -void write_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int* useDefaultScalingMatrixFlag ); -void write_vui_parameters(h264_stream_t* h, bs_t* b); -void write_hrd_parameters(h264_stream_t* h, bs_t* b); -void write_pic_parameter_set_rbsp(h264_stream_t* h, bs_t* b); -void write_sei_rbsp(h264_stream_t* h, bs_t* b); -void write_sei_message(h264_stream_t* h, bs_t* b); -void write_access_unit_delimiter_rbsp(h264_stream_t* h, bs_t* b); -void write_end_of_seq_rbsp(h264_stream_t* h, bs_t* b); -void write_end_of_stream_rbsp(h264_stream_t* h, bs_t* b); -void write_filler_data_rbsp(h264_stream_t* h, bs_t* b); -void write_slice_layer_rbsp(h264_stream_t* h, bs_t* b); -void write_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b); -void write_rbsp_trailing_bits(h264_stream_t* h, bs_t* b); -void write_slice_header(h264_stream_t* h, bs_t* b); -void write_ref_pic_list_reordering(h264_stream_t* h, bs_t* b); -void write_pred_weight_table(h264_stream_t* h, bs_t* b); -void write_dec_ref_pic_marking(h264_stream_t* h, bs_t* b); - - - -//7.3.1 NAL unit syntax -int write_nal_unit(h264_stream_t* h, uint8_t* buf, int size) -{ - nal_t* nal = h->nal; - - int nal_size = size; - int rbsp_size = size; - uint8_t* rbsp_buf = (uint8_t*)calloc(1, rbsp_size); - - if( 0 ) - { - int rc = nal_to_rbsp(buf, &nal_size, rbsp_buf, &rbsp_size); - - if (rc < 0) { free(rbsp_buf); return -1; } // handle conversion error - } - - if( 1 ) - { - rbsp_size = size*3/4; // NOTE this may have to be slightly smaller (3/4 smaller, worst case) in order to be guaranteed to fit - } - - bs_t* b = bs_new(rbsp_buf, rbsp_size); - /* forbidden_zero_bit */ bs_write_u(b, 1, 0); - bs_write_u(b, 2, nal->nal_ref_idc); - bs_write_u(b, 5, nal->nal_unit_type); - - switch ( nal->nal_unit_type ) - { - case NAL_UNIT_TYPE_CODED_SLICE_IDR: - case NAL_UNIT_TYPE_CODED_SLICE_NON_IDR: - case NAL_UNIT_TYPE_CODED_SLICE_AUX: - write_slice_layer_rbsp(h, b); - break; - -#ifdef HAVE_SEI - case NAL_UNIT_TYPE_SEI: - write_sei_rbsp(h, b); - break; -#endif - - case NAL_UNIT_TYPE_SPS: - write_seq_parameter_set_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_PPS: - write_pic_parameter_set_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_AUD: - write_access_unit_delimiter_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_END_OF_SEQUENCE: - write_end_of_seq_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_END_OF_STREAM: - write_end_of_stream_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_FILLER: - case NAL_UNIT_TYPE_SPS_EXT: - case NAL_UNIT_TYPE_UNSPECIFIED: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C: - default: - return -1; - } - - if (bs_overrun(b)) { bs_free(b); free(rbsp_buf); return -1; } - - if( 1 ) - { - // now get the actual size used - rbsp_size = bs_pos(b); - - int rc = rbsp_to_nal(rbsp_buf, &rbsp_size, buf, &nal_size); - if (rc < 0) { bs_free(b); free(rbsp_buf); return -1; } - } - - bs_free(b); - free(rbsp_buf); - - return nal_size; -} - - - -//7.3.2.1 Sequence parameter set RBSP syntax -void write_seq_parameter_set_rbsp(h264_stream_t* h, bs_t* b) -{ - int i; - - sps_t* sps = h->sps; - if( 0 ) - { - memset(sps, 0, sizeof(sps_t)); - sps->chroma_format_idc = 1; - } - - bs_write_u8(b, sps->profile_idc); - bs_write_u1(b, sps->constraint_set0_flag); - bs_write_u1(b, sps->constraint_set1_flag); - bs_write_u1(b, sps->constraint_set2_flag); - bs_write_u1(b, sps->constraint_set3_flag); - bs_write_u1(b, sps->constraint_set4_flag); - bs_write_u1(b, sps->constraint_set5_flag); - /* reserved_zero_2bits */ bs_write_u(b, 2, 0); - bs_write_u8(b, sps->level_idc); - bs_write_ue(b, sps->seq_parameter_set_id); - - if( sps->profile_idc == 100 || sps->profile_idc == 110 || - sps->profile_idc == 122 || sps->profile_idc == 144 ) - { - bs_write_ue(b, sps->chroma_format_idc); - if( sps->chroma_format_idc == 3 ) - { - bs_write_u1(b, sps->residual_colour_transform_flag); - } - bs_write_ue(b, sps->bit_depth_luma_minus8); - bs_write_ue(b, sps->bit_depth_chroma_minus8); - bs_write_u1(b, sps->qpprime_y_zero_transform_bypass_flag); - bs_write_u1(b, sps->seq_scaling_matrix_present_flag); - if( sps->seq_scaling_matrix_present_flag ) - { - for( i = 0; i < 8; i++ ) - { - bs_write_u1(b, sps->seq_scaling_list_present_flag[ i ]); - if( sps->seq_scaling_list_present_flag[ i ] ) - { - if( i < 6 ) - { - write_scaling_list( b, sps->ScalingList4x4[ i ], 16, - &( sps->UseDefaultScalingMatrix4x4Flag[ i ] ) ); - } - else - { - write_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64, - &( sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ) ); - } - } - } - } - } - bs_write_ue(b, sps->log2_max_frame_num_minus4); - bs_write_ue(b, sps->pic_order_cnt_type); - if( sps->pic_order_cnt_type == 0 ) - { - bs_write_ue(b, sps->log2_max_pic_order_cnt_lsb_minus4); - } - else if( sps->pic_order_cnt_type == 1 ) - { - bs_write_u1(b, sps->delta_pic_order_always_zero_flag); - bs_write_se(b, sps->offset_for_non_ref_pic); - bs_write_se(b, sps->offset_for_top_to_bottom_field); - bs_write_ue(b, sps->num_ref_frames_in_pic_order_cnt_cycle); - for( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ) - { - bs_write_se(b, sps->offset_for_ref_frame[ i ]); - } - } - bs_write_ue(b, sps->num_ref_frames); - bs_write_u1(b, sps->gaps_in_frame_num_value_allowed_flag); - bs_write_ue(b, sps->pic_width_in_mbs_minus1); - bs_write_ue(b, sps->pic_height_in_map_units_minus1); - bs_write_u1(b, sps->frame_mbs_only_flag); - if( !sps->frame_mbs_only_flag ) - { - bs_write_u1(b, sps->mb_adaptive_frame_field_flag); - } - bs_write_u1(b, sps->direct_8x8_inference_flag); - bs_write_u1(b, sps->frame_cropping_flag); - if( sps->frame_cropping_flag ) - { - bs_write_ue(b, sps->frame_crop_left_offset); - bs_write_ue(b, sps->frame_crop_right_offset); - bs_write_ue(b, sps->frame_crop_top_offset); - bs_write_ue(b, sps->frame_crop_bottom_offset); - } - bs_write_u1(b, sps->vui_parameters_present_flag); - if( sps->vui_parameters_present_flag ) - { - write_vui_parameters(h, b); - } - write_rbsp_trailing_bits(h, b); - - if( 0 ) - { - memcpy(h->sps_table[sps->seq_parameter_set_id], h->sps, sizeof(sps_t)); - } -} - - -//7.3.2.1.1 Scaling list syntax -void write_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int* useDefaultScalingMatrixFlag ) -{ - // NOTE need to be able to set useDefaultScalingMatrixFlag when reading, hence passing as pointer - int lastScale = 8; - int nextScale = 8; - int delta_scale; - for( int j = 0; j < sizeOfScalingList; j++ ) - { - if( nextScale != 0 ) - { - if( 1 ) - { - nextScale = scalingList[ j ]; - if (useDefaultScalingMatrixFlag[0]) { nextScale = 0; } - delta_scale = (nextScale - lastScale) % 256 ; - } - - bs_write_se(b, delta_scale); - - if( 0 ) - { - nextScale = ( lastScale + delta_scale + 256 ) % 256; - useDefaultScalingMatrixFlag[0] = ( j == 0 && nextScale == 0 ); - } - } - if( 0 ) - { - scalingList[ j ] = ( nextScale == 0 ) ? lastScale : nextScale; - } - lastScale = scalingList[ j ]; - } -} - -//Appendix E.1.1 VUI parameters syntax -void write_vui_parameters(h264_stream_t* h, bs_t* b) -{ - sps_t* sps = h->sps; - - bs_write_u1(b, sps->vui.aspect_ratio_info_present_flag); - if( sps->vui.aspect_ratio_info_present_flag ) - { - bs_write_u8(b, sps->vui.aspect_ratio_idc); - if( sps->vui.aspect_ratio_idc == SAR_Extended ) - { - bs_write_u(b, 16, sps->vui.sar_width); - bs_write_u(b, 16, sps->vui.sar_height); - } - } - bs_write_u1(b, sps->vui.overscan_info_present_flag); - if( sps->vui.overscan_info_present_flag ) - { - bs_write_u1(b, sps->vui.overscan_appropriate_flag); - } - bs_write_u1(b, sps->vui.video_signal_type_present_flag); - if( sps->vui.video_signal_type_present_flag ) - { - bs_write_u(b, 3, sps->vui.video_format); - bs_write_u1(b, sps->vui.video_full_range_flag); - bs_write_u1(b, sps->vui.colour_description_present_flag); - if( sps->vui.colour_description_present_flag ) - { - bs_write_u8(b, sps->vui.colour_primaries); - bs_write_u8(b, sps->vui.transfer_characteristics); - bs_write_u8(b, sps->vui.matrix_coefficients); - } - } - bs_write_u1(b, sps->vui.chroma_loc_info_present_flag); - if( sps->vui.chroma_loc_info_present_flag ) - { - bs_write_ue(b, sps->vui.chroma_sample_loc_type_top_field); - bs_write_ue(b, sps->vui.chroma_sample_loc_type_bottom_field); - } - bs_write_u1(b, sps->vui.timing_info_present_flag); - if( sps->vui.timing_info_present_flag ) - { - bs_write_u(b, 32, sps->vui.num_units_in_tick); - bs_write_u(b, 32, sps->vui.time_scale); - bs_write_u1(b, sps->vui.fixed_frame_rate_flag); - } - bs_write_u1(b, sps->vui.nal_hrd_parameters_present_flag); - if( sps->vui.nal_hrd_parameters_present_flag ) - { - write_hrd_parameters(h, b); - } - bs_write_u1(b, sps->vui.vcl_hrd_parameters_present_flag); - if( sps->vui.vcl_hrd_parameters_present_flag ) - { - write_hrd_parameters(h, b); - } - if( sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag ) - { - bs_write_u1(b, sps->vui.low_delay_hrd_flag); - } - bs_write_u1(b, sps->vui.pic_struct_present_flag); - bs_write_u1(b, sps->vui.bitstream_restriction_flag); - if( sps->vui.bitstream_restriction_flag ) - { - bs_write_u1(b, sps->vui.motion_vectors_over_pic_boundaries_flag); - bs_write_ue(b, sps->vui.max_bytes_per_pic_denom); - bs_write_ue(b, sps->vui.max_bits_per_mb_denom); - bs_write_ue(b, sps->vui.log2_max_mv_length_horizontal); - bs_write_ue(b, sps->vui.log2_max_mv_length_vertical); - bs_write_ue(b, sps->vui.num_reorder_frames); - bs_write_ue(b, sps->vui.max_dec_frame_buffering); - } -} - - -//Appendix E.1.2 HRD parameters syntax -void write_hrd_parameters(h264_stream_t* h, bs_t* b) -{ - sps_t* sps = h->sps; - - bs_write_ue(b, sps->hrd.cpb_cnt_minus1); - bs_write_u(b, 4, sps->hrd.bit_rate_scale); - bs_write_u(b, 4, sps->hrd.cpb_size_scale); - for( int SchedSelIdx = 0; SchedSelIdx <= sps->hrd.cpb_cnt_minus1; SchedSelIdx++ ) - { - bs_write_ue(b, sps->hrd.bit_rate_value_minus1[ SchedSelIdx ]); - bs_write_ue(b, sps->hrd.cpb_size_value_minus1[ SchedSelIdx ]); - bs_write_u1(b, sps->hrd.cbr_flag[ SchedSelIdx ]); - } - bs_write_u(b, 5, sps->hrd.initial_cpb_removal_delay_length_minus1); - bs_write_u(b, 5, sps->hrd.cpb_removal_delay_length_minus1); - bs_write_u(b, 5, sps->hrd.dpb_output_delay_length_minus1); - bs_write_u(b, 5, sps->hrd.time_offset_length); -} - - -/* -UNIMPLEMENTED -//7.3.2.1.2 Sequence parameter set extension RBSP syntax -int write_seq_parameter_set_extension_rbsp(bs_t* b, sps_ext_t* sps_ext) { - bs_write_ue(b, seq_parameter_set_id); - bs_write_ue(b, aux_format_idc); - if( aux_format_idc != 0 ) { - bs_write_ue(b, bit_depth_aux_minus8); - bs_write_u1(b, alpha_incr_flag); - alpha_opaque_value = bs_write_u(v); - alpha_transparent_value = bs_write_u(v); - } - bs_write_u1(b, additional_extension_flag); - write_rbsp_trailing_bits(); -} -*/ - -//7.3.2.2 Picture parameter set RBSP syntax -void write_pic_parameter_set_rbsp(h264_stream_t* h, bs_t* b) -{ - pps_t* pps = h->pps; - if( 0 ) - { - memset(pps, 0, sizeof(pps_t)); - } - - bs_write_ue(b, pps->pic_parameter_set_id); - bs_write_ue(b, pps->seq_parameter_set_id); - bs_write_u1(b, pps->entropy_coding_mode_flag); - bs_write_u1(b, pps->pic_order_present_flag); - bs_write_ue(b, pps->num_slice_groups_minus1); - - if( pps->num_slice_groups_minus1 > 0 ) - { - bs_write_ue(b, pps->slice_group_map_type); - if( pps->slice_group_map_type == 0 ) - { - for( int i_group = 0; i_group <= pps->num_slice_groups_minus1; i_group++ ) - { - bs_write_ue(b, pps->run_length_minus1[ i_group ]); - } - } - else if( pps->slice_group_map_type == 2 ) - { - for( int i_group = 0; i_group < pps->num_slice_groups_minus1; i_group++ ) - { - bs_write_ue(b, pps->top_left[ i_group ]); - bs_write_ue(b, pps->bottom_right[ i_group ]); - } - } - else if( pps->slice_group_map_type == 3 || - pps->slice_group_map_type == 4 || - pps->slice_group_map_type == 5 ) - { - bs_write_u1(b, pps->slice_group_change_direction_flag); - bs_write_ue(b, pps->slice_group_change_rate_minus1); - } - else if( pps->slice_group_map_type == 6 ) - { - bs_write_ue(b, pps->pic_size_in_map_units_minus1); - for( int i = 0; i <= pps->pic_size_in_map_units_minus1; i++ ) - { - int v = intlog2( pps->num_slice_groups_minus1 + 1 ); - bs_write_u(b, v, pps->slice_group_id[ i ]); - } - } - } - bs_write_ue(b, pps->num_ref_idx_l0_active_minus1); - bs_write_ue(b, pps->num_ref_idx_l1_active_minus1); - bs_write_u1(b, pps->weighted_pred_flag); - bs_write_u(b, 2, pps->weighted_bipred_idc); - bs_write_se(b, pps->pic_init_qp_minus26); - bs_write_se(b, pps->pic_init_qs_minus26); - bs_write_se(b, pps->chroma_qp_index_offset); - bs_write_u1(b, pps->deblocking_filter_control_present_flag); - bs_write_u1(b, pps->constrained_intra_pred_flag); - bs_write_u1(b, pps->redundant_pic_cnt_present_flag); - - int have_more_data = 0; - if( 0 ) { have_more_data = more_rbsp_data(h, b); } - if( 1 ) - { - have_more_data = pps->transform_8x8_mode_flag | pps->pic_scaling_matrix_present_flag | pps->second_chroma_qp_index_offset != 0; - } - - if( have_more_data ) - { - bs_write_u1(b, pps->transform_8x8_mode_flag); - bs_write_u1(b, pps->pic_scaling_matrix_present_flag); - if( pps->pic_scaling_matrix_present_flag ) - { - for( int i = 0; i < 6 + 2* pps->transform_8x8_mode_flag; i++ ) - { - bs_write_u1(b, pps->pic_scaling_list_present_flag[ i ]); - if( pps->pic_scaling_list_present_flag[ i ] ) - { - if( i < 6 ) - { - write_scaling_list( b, pps->ScalingList4x4[ i ], 16, - &( pps->UseDefaultScalingMatrix4x4Flag[ i ] ) ); - } - else - { - write_scaling_list( b, pps->ScalingList8x8[ i - 6 ], 64, - &( pps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ) ); - } - } - } - } - bs_write_se(b, pps->second_chroma_qp_index_offset); - } - write_rbsp_trailing_bits(h, b); - - if( 0 ) - { - memcpy(h->pps, h->pps_table[pps->pic_parameter_set_id], sizeof(pps_t)); - } -} - -#ifdef HAVE_SEI -//7.3.2.3 Supplemental enhancement information RBSP syntax -void write_sei_rbsp(h264_stream_t* h, bs_t* b) -{ - if( 0 ) - { - for( int i = 0; i < h->num_seis; i++ ) - { - sei_free(h->seis[i]); - } - - h->num_seis = 0; - do { - h->num_seis++; - h->seis = (sei_t**)realloc(h->seis, h->num_seis * sizeof(sei_t*)); - h->seis[h->num_seis - 1] = sei_new(); - h->sei = h->seis[h->num_seis - 1]; - write_sei_message(h, b); - } while( more_rbsp_data(h, b) ); - - } - - if( 1 ) - { - for (int i = 0; i < h->num_seis; i++) - { - h->sei = h->seis[i]; - write_sei_message(h, b); - } - h->sei = NULL; - } - - write_rbsp_trailing_bits(h, b); -} - -//7.3.2.3.1 Supplemental enhancement information message syntax -void write_sei_message(h264_stream_t* h, bs_t* b) -{ - if( 1 ) - { - _write_ff_coded_number(b, h->sei->payloadType); - _write_ff_coded_number(b, h->sei->payloadSize); - } - if( 0 ) - { - h->sei->payloadType = _read_ff_coded_number(b); - h->sei->payloadSize = _read_ff_coded_number(b); - } - write_sei_payload( h, b, h->sei->payloadType, h->sei->payloadSize ); -} -#endif - -//7.3.2.4 Access unit delimiter RBSP syntax -void write_access_unit_delimiter_rbsp(h264_stream_t* h, bs_t* b) -{ - bs_write_u(b, 3, h->aud->primary_pic_type); - write_rbsp_trailing_bits(h, b); -} - -//7.3.2.5 End of sequence RBSP syntax -void write_end_of_seq_rbsp(h264_stream_t* h, bs_t* b) -{ -} - -//7.3.2.6 End of stream RBSP syntax -void write_end_of_stream_rbsp(h264_stream_t* h, bs_t* b) -{ -} - -//7.3.2.7 Filler data RBSP syntax -void write_filler_data_rbsp(h264_stream_t* h, bs_t* b) -{ - while( bs_next_bits(b, 8) == 0xFF ) - { - /* ff_byte */ bs_write_u(b, 8, 0xFF); - } - write_rbsp_trailing_bits(h, b); -} - -//7.3.2.8 Slice layer without partitioning RBSP syntax -void write_slice_layer_rbsp(h264_stream_t* h, bs_t* b) -{ - write_slice_header(h, b); - slice_data_rbsp_t* slice_data = h->slice_data; - - if ( slice_data != NULL ) - { - if ( slice_data->rbsp_buf != NULL ) free( slice_data->rbsp_buf ); - uint8_t *sptr = b->p + (!!b->bits_left); // CABAC-specific: skip alignment bits, if there are any - slice_data->rbsp_size = b->end - sptr; - - slice_data->rbsp_buf = (uint8_t*)malloc(slice_data->rbsp_size); - memcpy( slice_data->rbsp_buf, sptr, slice_data->rbsp_size ); - // ugly hack: since next NALU starts at byte border, we are going to be padded by trailing_bits; - return; - } - - // FIXME should read or skip data - //slice_data( ); /* all categories of slice_data( ) syntax */ - write_rbsp_slice_trailing_bits(h, b); -} - -/* -// UNIMPLEMENTED -//7.3.2.9.1 Slice data partition A RBSP syntax -slice_data_partition_a_layer_rbsp( ) { - write_slice_header( ); // only category 2 - slice_id = bs_write_ue(b) - write_slice_data( ); // only category 2 - write_rbsp_slice_trailing_bits( ); // only category 2 -} - -//7.3.2.9.2 Slice data partition B RBSP syntax -slice_data_partition_b_layer_rbsp( ) { - bs_write_ue(b, slice_id); // only category 3 - if( redundant_pic_cnt_present_flag ) - bs_write_ue(b, redundant_pic_cnt); - write_slice_data( ); // only category 3 - write_rbsp_slice_trailing_bits( ); // only category 3 -} - -//7.3.2.9.3 Slice data partition C RBSP syntax -slice_data_partition_c_layer_rbsp( ) { - bs_write_ue(b, slice_id); // only category 4 - if( redundant_pic_cnt_present_flag ) - bs_write_ue(b, redundant_pic_cnt); - write_slice_data( ); // only category 4 - rbsp_slice_trailing_bits( ); // only category 4 -} -*/ - -//7.3.2.10 RBSP slice trailing bits syntax -void write_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b) -{ - write_rbsp_trailing_bits(h, b); - if( h->pps->entropy_coding_mode_flag ) - { - while( more_rbsp_trailing_data(h, b) ) - { - /* cabac_zero_word */ bs_write_u(b, 16, 0x0000); - } - } -} - -//7.3.2.11 RBSP trailing bits syntax -void write_rbsp_trailing_bits(h264_stream_t* h, bs_t* b) -{ - /* rbsp_stop_one_bit */ bs_write_u(b, 1, 1); - - while( !bs_byte_aligned(b) ) - { - /* rbsp_alignment_zero_bit */ bs_write_u(b, 1, 0); - } -} - -//7.3.3 Slice header syntax -void write_slice_header(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - if( 0 ) - { - memset(sh, 0, sizeof(slice_header_t)); - } - - nal_t* nal = h->nal; - - bs_write_ue(b, sh->first_mb_in_slice); - bs_write_ue(b, sh->slice_type); - bs_write_ue(b, sh->pic_parameter_set_id); - - // TODO check existence, otherwise fail - pps_t* pps = h->pps; - sps_t* sps = h->sps; - memcpy(h->pps_table[sh->pic_parameter_set_id], h->pps, sizeof(pps_t)); - memcpy(h->sps_table[pps->seq_parameter_set_id], h->sps, sizeof(sps_t)); - - bs_write_u(b, sps->log2_max_frame_num_minus4 + 4 , sh->frame_num); // was u(v) - if( !sps->frame_mbs_only_flag ) - { - bs_write_u1(b, sh->field_pic_flag); - if( sh->field_pic_flag ) - { - bs_write_u1(b, sh->bottom_field_flag); - } - } - if( nal->nal_unit_type == 5 ) - { - bs_write_ue(b, sh->idr_pic_id); - } - if( sps->pic_order_cnt_type == 0 ) - { - bs_write_u(b, sps->log2_max_pic_order_cnt_lsb_minus4 + 4 , sh->pic_order_cnt_lsb); // was u(v) - if( pps->pic_order_present_flag && !sh->field_pic_flag ) - { - bs_write_se(b, sh->delta_pic_order_cnt_bottom); - } - } - if( sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag ) - { - bs_write_se(b, sh->delta_pic_order_cnt[ 0 ]); - if( pps->pic_order_present_flag && !sh->field_pic_flag ) - { - bs_write_se(b, sh->delta_pic_order_cnt[ 1 ]); - } - } - if( pps->redundant_pic_cnt_present_flag ) - { - bs_write_ue(b, sh->redundant_pic_cnt); - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - bs_write_u1(b, sh->direct_spatial_mv_pred_flag); - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_P ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - bs_write_u1(b, sh->num_ref_idx_active_override_flag); - if( sh->num_ref_idx_active_override_flag ) - { - bs_write_ue(b, sh->num_ref_idx_l0_active_minus1); // FIXME does this modify the pps? - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - bs_write_ue(b, sh->num_ref_idx_l1_active_minus1); - } - } - } - write_ref_pic_list_reordering(h, b); - if( ( pps->weighted_pred_flag && ( is_slice_type( sh->slice_type, SH_SLICE_TYPE_P ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) ) ) || - ( pps->weighted_bipred_idc == 1 && is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) ) - { - write_pred_weight_table(h, b); - } - if( nal->nal_ref_idc != 0 ) - { - write_dec_ref_pic_marking(h, b); - } - if( pps->entropy_coding_mode_flag && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - bs_write_ue(b, sh->cabac_init_idc); - } - bs_write_se(b, sh->slice_qp_delta); - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) ) - { - bs_write_u1(b, sh->sp_for_switch_flag); - } - bs_write_se(b, sh->slice_qs_delta); - } - if( pps->deblocking_filter_control_present_flag ) - { - bs_write_ue(b, sh->disable_deblocking_filter_idc); - if( sh->disable_deblocking_filter_idc != 1 ) - { - bs_write_se(b, sh->slice_alpha_c0_offset_div2); - bs_write_se(b, sh->slice_beta_offset_div2); - } - } - if( pps->num_slice_groups_minus1 > 0 && - pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) - { - int v = intlog2( pps->pic_size_in_map_units_minus1 + pps->slice_group_change_rate_minus1 + 1 ); - bs_write_u(b, v, sh->slice_group_change_cycle); // FIXME add 2? - } -} - -//7.3.3.1 Reference picture list reordering syntax -void write_ref_pic_list_reordering(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - // FIXME should be an array - - if( ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - bs_write_u1(b, sh->rplr.ref_pic_list_reordering_flag_l0); - if( sh->rplr.ref_pic_list_reordering_flag_l0 ) - { - int n = -1; - do - { - n++; - bs_write_ue(b, sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ]); - if( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 0 || - sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 1 ) - { - bs_write_ue(b, sh->rplr.reorder_l0.abs_diff_pic_num_minus1[ n ]); - } - else if( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 2 ) - { - bs_write_ue(b, sh->rplr.reorder_l0.long_term_pic_num[ n ]); - } - } while( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] != 3 && ! bs_eof(b) ); - } - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - bs_write_u1(b, sh->rplr.ref_pic_list_reordering_flag_l1); - if( sh->rplr.ref_pic_list_reordering_flag_l1 ) - { - int n = -1; - do - { - n++; - bs_write_ue(b, sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ]); - if( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 0 || - sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 1 ) - { - bs_write_ue(b, sh->rplr.reorder_l1.abs_diff_pic_num_minus1[ n ]); - } - else if( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 2 ) - { - bs_write_ue(b, sh->rplr.reorder_l1.long_term_pic_num[ n ]); - } - } while( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] != 3 && ! bs_eof(b) ); - } - } -} - -//7.3.3.2 Prediction weight table syntax -void write_pred_weight_table(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - sps_t* sps = h->sps; - pps_t* pps = h->pps; - - int i, j; - - bs_write_ue(b, sh->pwt.luma_log2_weight_denom); - if( sps->chroma_format_idc != 0 ) - { - bs_write_ue(b, sh->pwt.chroma_log2_weight_denom); - } - for( i = 0; i <= pps->num_ref_idx_l0_active_minus1; i++ ) - { - bs_write_u1(b, sh->pwt.luma_weight_l0_flag[i]); - if( sh->pwt.luma_weight_l0_flag[i] ) - { - bs_write_se(b, sh->pwt.luma_weight_l0[ i ]); - bs_write_se(b, sh->pwt.luma_offset_l0[ i ]); - } - if ( sps->chroma_format_idc != 0 ) - { - bs_write_u1(b, sh->pwt.chroma_weight_l0_flag[i]); - if( sh->pwt.chroma_weight_l0_flag[i] ) - { - for( j =0; j < 2; j++ ) - { - bs_write_se(b, sh->pwt.chroma_weight_l0[ i ][ j ]); - bs_write_se(b, sh->pwt.chroma_offset_l0[ i ][ j ]); - } - } - } - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - for( i = 0; i <= pps->num_ref_idx_l1_active_minus1; i++ ) - { - bs_write_u1(b, sh->pwt.luma_weight_l1_flag[i]); - if( sh->pwt.luma_weight_l1_flag[i] ) - { - bs_write_se(b, sh->pwt.luma_weight_l1[ i ]); - bs_write_se(b, sh->pwt.luma_offset_l1[ i ]); - } - if( sps->chroma_format_idc != 0 ) - { - bs_write_u1(b, sh->pwt.chroma_weight_l1_flag[i]); - if( sh->pwt.chroma_weight_l1_flag[i] ) - { - for( j = 0; j < 2; j++ ) - { - bs_write_se(b, sh->pwt.chroma_weight_l1[ i ][ j ]); - bs_write_se(b, sh->pwt.chroma_offset_l1[ i ][ j ]); - } - } - } - } - } -} - -//7.3.3.3 Decoded reference picture marking syntax -void write_dec_ref_pic_marking(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - // FIXME should be an array - - if( h->nal->nal_unit_type == 5 ) - { - bs_write_u1(b, sh->drpm.no_output_of_prior_pics_flag); - bs_write_u1(b, sh->drpm.long_term_reference_flag); - } - else - { - bs_write_u1(b, sh->drpm.adaptive_ref_pic_marking_mode_flag); - if( sh->drpm.adaptive_ref_pic_marking_mode_flag ) - { - int n = -1; - do - { - n++; - bs_write_ue(b, sh->drpm.memory_management_control_operation[ n ]); - if( sh->drpm.memory_management_control_operation[ n ] == 1 || - sh->drpm.memory_management_control_operation[ n ] == 3 ) - { - bs_write_ue(b, sh->drpm.difference_of_pic_nums_minus1[ n ]); - } - if(sh->drpm.memory_management_control_operation[ n ] == 2 ) - { - bs_write_ue(b, sh->drpm.long_term_pic_num[ n ]); - } - if( sh->drpm.memory_management_control_operation[ n ] == 3 || - sh->drpm.memory_management_control_operation[ n ] == 6 ) - { - bs_write_ue(b, sh->drpm.long_term_frame_idx[ n ]); - } - if( sh->drpm.memory_management_control_operation[ n ] == 4 ) - { - bs_write_ue(b, sh->drpm.max_long_term_frame_idx_plus1[ n ]); - } - } while( sh->drpm.memory_management_control_operation[ n ] != 0 && ! bs_eof(b) ); - } - } -} - - -void read_debug_seq_parameter_set_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int* useDefaultScalingMatrixFlag ); -void read_debug_vui_parameters(h264_stream_t* h, bs_t* b); -void read_debug_hrd_parameters(h264_stream_t* h, bs_t* b); -void read_debug_pic_parameter_set_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_sei_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_sei_message(h264_stream_t* h, bs_t* b); -void read_debug_access_unit_delimiter_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_end_of_seq_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_end_of_stream_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_filler_data_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_slice_layer_rbsp(h264_stream_t* h, bs_t* b); -void read_debug_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b); -void read_debug_rbsp_trailing_bits(h264_stream_t* h, bs_t* b); -void read_debug_slice_header(h264_stream_t* h, bs_t* b); -void read_debug_ref_pic_list_reordering(h264_stream_t* h, bs_t* b); -void read_debug_pred_weight_table(h264_stream_t* h, bs_t* b); -void read_debug_dec_ref_pic_marking(h264_stream_t* h, bs_t* b); - - - -//7.3.1 NAL unit syntax -int read_debug_nal_unit(h264_stream_t* h, uint8_t* buf, int size) -{ - nal_t* nal = h->nal; - - int nal_size = size; - int rbsp_size = size; - uint8_t* rbsp_buf = (uint8_t*)calloc(1, rbsp_size); - - if( 1 ) - { - int rc = nal_to_rbsp(buf, &nal_size, rbsp_buf, &rbsp_size); - - if (rc < 0) { free(rbsp_buf); return -1; } // handle conversion error - } - - if( 0 ) - { - rbsp_size = size*3/4; // NOTE this may have to be slightly smaller (3/4 smaller, worst case) in order to be guaranteed to fit - } - - bs_t* b = bs_new(rbsp_buf, rbsp_size); - printf("%d.%d: ", b->p - b->start, b->bits_left); int forbidden_zero_bit = bs_read_u(b, 1); printf("forbidden_zero_bit: %d \n", forbidden_zero_bit); - printf("%d.%d: ", b->p - b->start, b->bits_left); nal->nal_ref_idc = bs_read_u(b, 2); printf("nal->nal_ref_idc: %d \n", nal->nal_ref_idc); - printf("%d.%d: ", b->p - b->start, b->bits_left); nal->nal_unit_type = bs_read_u(b, 5); printf("nal->nal_unit_type: %d \n", nal->nal_unit_type); - - switch ( nal->nal_unit_type ) - { - case NAL_UNIT_TYPE_CODED_SLICE_IDR: - case NAL_UNIT_TYPE_CODED_SLICE_NON_IDR: - case NAL_UNIT_TYPE_CODED_SLICE_AUX: - read_debug_slice_layer_rbsp(h, b); - break; - -#ifdef HAVE_SEI - case NAL_UNIT_TYPE_SEI: - read_debug_sei_rbsp(h, b); - break; -#endif - - case NAL_UNIT_TYPE_SPS: - read_debug_seq_parameter_set_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_PPS: - read_debug_pic_parameter_set_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_AUD: - read_debug_access_unit_delimiter_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_END_OF_SEQUENCE: - read_debug_end_of_seq_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_END_OF_STREAM: - read_debug_end_of_stream_rbsp(h, b); - break; - - case NAL_UNIT_TYPE_FILLER: - case NAL_UNIT_TYPE_SPS_EXT: - case NAL_UNIT_TYPE_UNSPECIFIED: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_A: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_B: - case NAL_UNIT_TYPE_CODED_SLICE_DATA_PARTITION_C: - default: - return -1; - } - - if (bs_overrun(b)) { bs_free(b); free(rbsp_buf); return -1; } - - if( 0 ) - { - // now get the actual size used - rbsp_size = bs_pos(b); - - int rc = rbsp_to_nal(rbsp_buf, &rbsp_size, buf, &nal_size); - if (rc < 0) { bs_free(b); free(rbsp_buf); return -1; } - } - - bs_free(b); - free(rbsp_buf); - - return nal_size; -} - - - -//7.3.2.1 Sequence parameter set RBSP syntax -void read_debug_seq_parameter_set_rbsp(h264_stream_t* h, bs_t* b) -{ - int i; - - sps_t* sps = h->sps; - if( 1 ) - { - memset(sps, 0, sizeof(sps_t)); - sps->chroma_format_idc = 1; - } - - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->profile_idc = bs_read_u8(b); printf("sps->profile_idc: %d \n", sps->profile_idc); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->constraint_set0_flag = bs_read_u1(b); printf("sps->constraint_set0_flag: %d \n", sps->constraint_set0_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->constraint_set1_flag = bs_read_u1(b); printf("sps->constraint_set1_flag: %d \n", sps->constraint_set1_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->constraint_set2_flag = bs_read_u1(b); printf("sps->constraint_set2_flag: %d \n", sps->constraint_set2_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->constraint_set3_flag = bs_read_u1(b); printf("sps->constraint_set3_flag: %d \n", sps->constraint_set3_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->constraint_set4_flag = bs_read_u1(b); printf("sps->constraint_set4_flag: %d \n", sps->constraint_set4_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->constraint_set5_flag = bs_read_u1(b); printf("sps->constraint_set5_flag: %d \n", sps->constraint_set5_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); int reserved_zero_2bits = bs_read_u(b, 2); printf("reserved_zero_2bits: %d \n", reserved_zero_2bits); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->level_idc = bs_read_u8(b); printf("sps->level_idc: %d \n", sps->level_idc); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->seq_parameter_set_id = bs_read_ue(b); printf("sps->seq_parameter_set_id: %d \n", sps->seq_parameter_set_id); - - if( sps->profile_idc == 100 || sps->profile_idc == 110 || - sps->profile_idc == 122 || sps->profile_idc == 144 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->chroma_format_idc = bs_read_ue(b); printf("sps->chroma_format_idc: %d \n", sps->chroma_format_idc); - if( sps->chroma_format_idc == 3 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->residual_colour_transform_flag = bs_read_u1(b); printf("sps->residual_colour_transform_flag: %d \n", sps->residual_colour_transform_flag); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->bit_depth_luma_minus8 = bs_read_ue(b); printf("sps->bit_depth_luma_minus8: %d \n", sps->bit_depth_luma_minus8); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->bit_depth_chroma_minus8 = bs_read_ue(b); printf("sps->bit_depth_chroma_minus8: %d \n", sps->bit_depth_chroma_minus8); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->qpprime_y_zero_transform_bypass_flag = bs_read_u1(b); printf("sps->qpprime_y_zero_transform_bypass_flag: %d \n", sps->qpprime_y_zero_transform_bypass_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->seq_scaling_matrix_present_flag = bs_read_u1(b); printf("sps->seq_scaling_matrix_present_flag: %d \n", sps->seq_scaling_matrix_present_flag); - if( sps->seq_scaling_matrix_present_flag ) - { - for( i = 0; i < 8; i++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b); printf("sps->seq_scaling_list_present_flag[ i ]: %d \n", sps->seq_scaling_list_present_flag[ i ]); - if( sps->seq_scaling_list_present_flag[ i ] ) - { - if( i < 6 ) - { - read_debug_scaling_list( b, sps->ScalingList4x4[ i ], 16, - &( sps->UseDefaultScalingMatrix4x4Flag[ i ] ) ); - } - else - { - read_debug_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64, - &( sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ) ); - } - } - } - } - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->log2_max_frame_num_minus4 = bs_read_ue(b); printf("sps->log2_max_frame_num_minus4: %d \n", sps->log2_max_frame_num_minus4); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->pic_order_cnt_type = bs_read_ue(b); printf("sps->pic_order_cnt_type: %d \n", sps->pic_order_cnt_type); - if( sps->pic_order_cnt_type == 0 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b); printf("sps->log2_max_pic_order_cnt_lsb_minus4: %d \n", sps->log2_max_pic_order_cnt_lsb_minus4); - } - else if( sps->pic_order_cnt_type == 1 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->delta_pic_order_always_zero_flag = bs_read_u1(b); printf("sps->delta_pic_order_always_zero_flag: %d \n", sps->delta_pic_order_always_zero_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->offset_for_non_ref_pic = bs_read_se(b); printf("sps->offset_for_non_ref_pic: %d \n", sps->offset_for_non_ref_pic); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->offset_for_top_to_bottom_field = bs_read_se(b); printf("sps->offset_for_top_to_bottom_field: %d \n", sps->offset_for_top_to_bottom_field); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b); printf("sps->num_ref_frames_in_pic_order_cnt_cycle: %d \n", sps->num_ref_frames_in_pic_order_cnt_cycle); - for( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->offset_for_ref_frame[ i ] = bs_read_se(b); printf("sps->offset_for_ref_frame[ i ]: %d \n", sps->offset_for_ref_frame[ i ]); - } - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->num_ref_frames = bs_read_ue(b); printf("sps->num_ref_frames: %d \n", sps->num_ref_frames); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->gaps_in_frame_num_value_allowed_flag = bs_read_u1(b); printf("sps->gaps_in_frame_num_value_allowed_flag: %d \n", sps->gaps_in_frame_num_value_allowed_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->pic_width_in_mbs_minus1 = bs_read_ue(b); printf("sps->pic_width_in_mbs_minus1: %d \n", sps->pic_width_in_mbs_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->pic_height_in_map_units_minus1 = bs_read_ue(b); printf("sps->pic_height_in_map_units_minus1: %d \n", sps->pic_height_in_map_units_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->frame_mbs_only_flag = bs_read_u1(b); printf("sps->frame_mbs_only_flag: %d \n", sps->frame_mbs_only_flag); - if( !sps->frame_mbs_only_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->mb_adaptive_frame_field_flag = bs_read_u1(b); printf("sps->mb_adaptive_frame_field_flag: %d \n", sps->mb_adaptive_frame_field_flag); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->direct_8x8_inference_flag = bs_read_u1(b); printf("sps->direct_8x8_inference_flag: %d \n", sps->direct_8x8_inference_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->frame_cropping_flag = bs_read_u1(b); printf("sps->frame_cropping_flag: %d \n", sps->frame_cropping_flag); - if( sps->frame_cropping_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->frame_crop_left_offset = bs_read_ue(b); printf("sps->frame_crop_left_offset: %d \n", sps->frame_crop_left_offset); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->frame_crop_right_offset = bs_read_ue(b); printf("sps->frame_crop_right_offset: %d \n", sps->frame_crop_right_offset); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->frame_crop_top_offset = bs_read_ue(b); printf("sps->frame_crop_top_offset: %d \n", sps->frame_crop_top_offset); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->frame_crop_bottom_offset = bs_read_ue(b); printf("sps->frame_crop_bottom_offset: %d \n", sps->frame_crop_bottom_offset); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui_parameters_present_flag = bs_read_u1(b); printf("sps->vui_parameters_present_flag: %d \n", sps->vui_parameters_present_flag); - if( sps->vui_parameters_present_flag ) - { - read_debug_vui_parameters(h, b); - } - read_debug_rbsp_trailing_bits(h, b); - - if( 1 ) - { - memcpy(h->sps_table[sps->seq_parameter_set_id], h->sps, sizeof(sps_t)); - } -} - - -//7.3.2.1.1 Scaling list syntax -void read_debug_scaling_list(bs_t* b, int* scalingList, int sizeOfScalingList, int* useDefaultScalingMatrixFlag ) -{ - // NOTE need to be able to set useDefaultScalingMatrixFlag when reading, hence passing as pointer - int lastScale = 8; - int nextScale = 8; - int delta_scale; - for( int j = 0; j < sizeOfScalingList; j++ ) - { - if( nextScale != 0 ) - { - if( 0 ) - { - nextScale = scalingList[ j ]; - if (useDefaultScalingMatrixFlag[0]) { nextScale = 0; } - delta_scale = (nextScale - lastScale) % 256 ; - } - - printf("%d.%d: ", b->p - b->start, b->bits_left); delta_scale = bs_read_se(b); printf("delta_scale: %d \n", delta_scale); - - if( 1 ) - { - nextScale = ( lastScale + delta_scale + 256 ) % 256; - useDefaultScalingMatrixFlag[0] = ( j == 0 && nextScale == 0 ); - } - } - if( 1 ) - { - scalingList[ j ] = ( nextScale == 0 ) ? lastScale : nextScale; - } - lastScale = scalingList[ j ]; - } -} - -//Appendix E.1.1 VUI parameters syntax -void read_debug_vui_parameters(h264_stream_t* h, bs_t* b) -{ - sps_t* sps = h->sps; - - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.aspect_ratio_info_present_flag = bs_read_u1(b); printf("sps->vui.aspect_ratio_info_present_flag: %d \n", sps->vui.aspect_ratio_info_present_flag); - if( sps->vui.aspect_ratio_info_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.aspect_ratio_idc = bs_read_u8(b); printf("sps->vui.aspect_ratio_idc: %d \n", sps->vui.aspect_ratio_idc); - if( sps->vui.aspect_ratio_idc == SAR_Extended ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.sar_width = bs_read_u(b, 16); printf("sps->vui.sar_width: %d \n", sps->vui.sar_width); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.sar_height = bs_read_u(b, 16); printf("sps->vui.sar_height: %d \n", sps->vui.sar_height); - } - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.overscan_info_present_flag = bs_read_u1(b); printf("sps->vui.overscan_info_present_flag: %d \n", sps->vui.overscan_info_present_flag); - if( sps->vui.overscan_info_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.overscan_appropriate_flag = bs_read_u1(b); printf("sps->vui.overscan_appropriate_flag: %d \n", sps->vui.overscan_appropriate_flag); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.video_signal_type_present_flag = bs_read_u1(b); printf("sps->vui.video_signal_type_present_flag: %d \n", sps->vui.video_signal_type_present_flag); - if( sps->vui.video_signal_type_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.video_format = bs_read_u(b, 3); printf("sps->vui.video_format: %d \n", sps->vui.video_format); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.video_full_range_flag = bs_read_u1(b); printf("sps->vui.video_full_range_flag: %d \n", sps->vui.video_full_range_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.colour_description_present_flag = bs_read_u1(b); printf("sps->vui.colour_description_present_flag: %d \n", sps->vui.colour_description_present_flag); - if( sps->vui.colour_description_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.colour_primaries = bs_read_u8(b); printf("sps->vui.colour_primaries: %d \n", sps->vui.colour_primaries); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.transfer_characteristics = bs_read_u8(b); printf("sps->vui.transfer_characteristics: %d \n", sps->vui.transfer_characteristics); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.matrix_coefficients = bs_read_u8(b); printf("sps->vui.matrix_coefficients: %d \n", sps->vui.matrix_coefficients); - } - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.chroma_loc_info_present_flag = bs_read_u1(b); printf("sps->vui.chroma_loc_info_present_flag: %d \n", sps->vui.chroma_loc_info_present_flag); - if( sps->vui.chroma_loc_info_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.chroma_sample_loc_type_top_field = bs_read_ue(b); printf("sps->vui.chroma_sample_loc_type_top_field: %d \n", sps->vui.chroma_sample_loc_type_top_field); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.chroma_sample_loc_type_bottom_field = bs_read_ue(b); printf("sps->vui.chroma_sample_loc_type_bottom_field: %d \n", sps->vui.chroma_sample_loc_type_bottom_field); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.timing_info_present_flag = bs_read_u1(b); printf("sps->vui.timing_info_present_flag: %d \n", sps->vui.timing_info_present_flag); - if( sps->vui.timing_info_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.num_units_in_tick = bs_read_u(b, 32); printf("sps->vui.num_units_in_tick: %d \n", sps->vui.num_units_in_tick); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.time_scale = bs_read_u(b, 32); printf("sps->vui.time_scale: %d \n", sps->vui.time_scale); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.fixed_frame_rate_flag = bs_read_u1(b); printf("sps->vui.fixed_frame_rate_flag: %d \n", sps->vui.fixed_frame_rate_flag); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.nal_hrd_parameters_present_flag = bs_read_u1(b); printf("sps->vui.nal_hrd_parameters_present_flag: %d \n", sps->vui.nal_hrd_parameters_present_flag); - if( sps->vui.nal_hrd_parameters_present_flag ) - { - read_debug_hrd_parameters(h, b); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.vcl_hrd_parameters_present_flag = bs_read_u1(b); printf("sps->vui.vcl_hrd_parameters_present_flag: %d \n", sps->vui.vcl_hrd_parameters_present_flag); - if( sps->vui.vcl_hrd_parameters_present_flag ) - { - read_debug_hrd_parameters(h, b); - } - if( sps->vui.nal_hrd_parameters_present_flag || sps->vui.vcl_hrd_parameters_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.low_delay_hrd_flag = bs_read_u1(b); printf("sps->vui.low_delay_hrd_flag: %d \n", sps->vui.low_delay_hrd_flag); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.pic_struct_present_flag = bs_read_u1(b); printf("sps->vui.pic_struct_present_flag: %d \n", sps->vui.pic_struct_present_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.bitstream_restriction_flag = bs_read_u1(b); printf("sps->vui.bitstream_restriction_flag: %d \n", sps->vui.bitstream_restriction_flag); - if( sps->vui.bitstream_restriction_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.motion_vectors_over_pic_boundaries_flag = bs_read_u1(b); printf("sps->vui.motion_vectors_over_pic_boundaries_flag: %d \n", sps->vui.motion_vectors_over_pic_boundaries_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.max_bytes_per_pic_denom = bs_read_ue(b); printf("sps->vui.max_bytes_per_pic_denom: %d \n", sps->vui.max_bytes_per_pic_denom); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.max_bits_per_mb_denom = bs_read_ue(b); printf("sps->vui.max_bits_per_mb_denom: %d \n", sps->vui.max_bits_per_mb_denom); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.log2_max_mv_length_horizontal = bs_read_ue(b); printf("sps->vui.log2_max_mv_length_horizontal: %d \n", sps->vui.log2_max_mv_length_horizontal); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.log2_max_mv_length_vertical = bs_read_ue(b); printf("sps->vui.log2_max_mv_length_vertical: %d \n", sps->vui.log2_max_mv_length_vertical); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.num_reorder_frames = bs_read_ue(b); printf("sps->vui.num_reorder_frames: %d \n", sps->vui.num_reorder_frames); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->vui.max_dec_frame_buffering = bs_read_ue(b); printf("sps->vui.max_dec_frame_buffering: %d \n", sps->vui.max_dec_frame_buffering); - } -} - - -//Appendix E.1.2 HRD parameters syntax -void read_debug_hrd_parameters(h264_stream_t* h, bs_t* b) -{ - sps_t* sps = h->sps; - - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.cpb_cnt_minus1 = bs_read_ue(b); printf("sps->hrd.cpb_cnt_minus1: %d \n", sps->hrd.cpb_cnt_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.bit_rate_scale = bs_read_u(b, 4); printf("sps->hrd.bit_rate_scale: %d \n", sps->hrd.bit_rate_scale); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.cpb_size_scale = bs_read_u(b, 4); printf("sps->hrd.cpb_size_scale: %d \n", sps->hrd.cpb_size_scale); - for( int SchedSelIdx = 0; SchedSelIdx <= sps->hrd.cpb_cnt_minus1; SchedSelIdx++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.bit_rate_value_minus1[ SchedSelIdx ] = bs_read_ue(b); printf("sps->hrd.bit_rate_value_minus1[ SchedSelIdx ]: %d \n", sps->hrd.bit_rate_value_minus1[ SchedSelIdx ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.cpb_size_value_minus1[ SchedSelIdx ] = bs_read_ue(b); printf("sps->hrd.cpb_size_value_minus1[ SchedSelIdx ]: %d \n", sps->hrd.cpb_size_value_minus1[ SchedSelIdx ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.cbr_flag[ SchedSelIdx ] = bs_read_u1(b); printf("sps->hrd.cbr_flag[ SchedSelIdx ]: %d \n", sps->hrd.cbr_flag[ SchedSelIdx ]); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.initial_cpb_removal_delay_length_minus1 = bs_read_u(b, 5); printf("sps->hrd.initial_cpb_removal_delay_length_minus1: %d \n", sps->hrd.initial_cpb_removal_delay_length_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.cpb_removal_delay_length_minus1 = bs_read_u(b, 5); printf("sps->hrd.cpb_removal_delay_length_minus1: %d \n", sps->hrd.cpb_removal_delay_length_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.dpb_output_delay_length_minus1 = bs_read_u(b, 5); printf("sps->hrd.dpb_output_delay_length_minus1: %d \n", sps->hrd.dpb_output_delay_length_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); sps->hrd.time_offset_length = bs_read_u(b, 5); printf("sps->hrd.time_offset_length: %d \n", sps->hrd.time_offset_length); -} - - -/* -UNIMPLEMENTED -//7.3.2.1.2 Sequence parameter set extension RBSP syntax -int read_debug_seq_parameter_set_extension_rbsp(bs_t* b, sps_ext_t* sps_ext) { - printf("%d.%d: ", b->p - b->start, b->bits_left); seq_parameter_set_id = bs_read_ue(b); printf("seq_parameter_set_id: %d \n", seq_parameter_set_id); - printf("%d.%d: ", b->p - b->start, b->bits_left); aux_format_idc = bs_read_ue(b); printf("aux_format_idc: %d \n", aux_format_idc); - if( aux_format_idc != 0 ) { - printf("%d.%d: ", b->p - b->start, b->bits_left); bit_depth_aux_minus8 = bs_read_ue(b); printf("bit_depth_aux_minus8: %d \n", bit_depth_aux_minus8); - printf("%d.%d: ", b->p - b->start, b->bits_left); alpha_incr_flag = bs_read_u1(b); printf("alpha_incr_flag: %d \n", alpha_incr_flag); - alpha_opaque_value = bs_read_debug_u(v); - alpha_transparent_value = bs_read_debug_u(v); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); additional_extension_flag = bs_read_u1(b); printf("additional_extension_flag: %d \n", additional_extension_flag); - read_debug_rbsp_trailing_bits(); -} -*/ - -//7.3.2.2 Picture parameter set RBSP syntax -void read_debug_pic_parameter_set_rbsp(h264_stream_t* h, bs_t* b) -{ - pps_t* pps = h->pps; - if( 1 ) - { - memset(pps, 0, sizeof(pps_t)); - } - - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_parameter_set_id = bs_read_ue(b); printf("pps->pic_parameter_set_id: %d \n", pps->pic_parameter_set_id); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->seq_parameter_set_id = bs_read_ue(b); printf("pps->seq_parameter_set_id: %d \n", pps->seq_parameter_set_id); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->entropy_coding_mode_flag = bs_read_u1(b); printf("pps->entropy_coding_mode_flag: %d \n", pps->entropy_coding_mode_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_order_present_flag = bs_read_u1(b); printf("pps->pic_order_present_flag: %d \n", pps->pic_order_present_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->num_slice_groups_minus1 = bs_read_ue(b); printf("pps->num_slice_groups_minus1: %d \n", pps->num_slice_groups_minus1); - - if( pps->num_slice_groups_minus1 > 0 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->slice_group_map_type = bs_read_ue(b); printf("pps->slice_group_map_type: %d \n", pps->slice_group_map_type); - if( pps->slice_group_map_type == 0 ) - { - for( int i_group = 0; i_group <= pps->num_slice_groups_minus1; i_group++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->run_length_minus1[ i_group ] = bs_read_ue(b); printf("pps->run_length_minus1[ i_group ]: %d \n", pps->run_length_minus1[ i_group ]); - } - } - else if( pps->slice_group_map_type == 2 ) - { - for( int i_group = 0; i_group < pps->num_slice_groups_minus1; i_group++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->top_left[ i_group ] = bs_read_ue(b); printf("pps->top_left[ i_group ]: %d \n", pps->top_left[ i_group ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->bottom_right[ i_group ] = bs_read_ue(b); printf("pps->bottom_right[ i_group ]: %d \n", pps->bottom_right[ i_group ]); - } - } - else if( pps->slice_group_map_type == 3 || - pps->slice_group_map_type == 4 || - pps->slice_group_map_type == 5 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->slice_group_change_direction_flag = bs_read_u1(b); printf("pps->slice_group_change_direction_flag: %d \n", pps->slice_group_change_direction_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->slice_group_change_rate_minus1 = bs_read_ue(b); printf("pps->slice_group_change_rate_minus1: %d \n", pps->slice_group_change_rate_minus1); - } - else if( pps->slice_group_map_type == 6 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_size_in_map_units_minus1 = bs_read_ue(b); printf("pps->pic_size_in_map_units_minus1: %d \n", pps->pic_size_in_map_units_minus1); - for( int i = 0; i <= pps->pic_size_in_map_units_minus1; i++ ) - { - int v = intlog2( pps->num_slice_groups_minus1 + 1 ); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->slice_group_id[ i ] = bs_read_u(b, v); printf("pps->slice_group_id[ i ]: %d \n", pps->slice_group_id[ i ]); - } - } - } - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->num_ref_idx_l0_active_minus1 = bs_read_ue(b); printf("pps->num_ref_idx_l0_active_minus1: %d \n", pps->num_ref_idx_l0_active_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->num_ref_idx_l1_active_minus1 = bs_read_ue(b); printf("pps->num_ref_idx_l1_active_minus1: %d \n", pps->num_ref_idx_l1_active_minus1); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->weighted_pred_flag = bs_read_u1(b); printf("pps->weighted_pred_flag: %d \n", pps->weighted_pred_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->weighted_bipred_idc = bs_read_u(b, 2); printf("pps->weighted_bipred_idc: %d \n", pps->weighted_bipred_idc); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_init_qp_minus26 = bs_read_se(b); printf("pps->pic_init_qp_minus26: %d \n", pps->pic_init_qp_minus26); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_init_qs_minus26 = bs_read_se(b); printf("pps->pic_init_qs_minus26: %d \n", pps->pic_init_qs_minus26); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->chroma_qp_index_offset = bs_read_se(b); printf("pps->chroma_qp_index_offset: %d \n", pps->chroma_qp_index_offset); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->deblocking_filter_control_present_flag = bs_read_u1(b); printf("pps->deblocking_filter_control_present_flag: %d \n", pps->deblocking_filter_control_present_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->constrained_intra_pred_flag = bs_read_u1(b); printf("pps->constrained_intra_pred_flag: %d \n", pps->constrained_intra_pred_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->redundant_pic_cnt_present_flag = bs_read_u1(b); printf("pps->redundant_pic_cnt_present_flag: %d \n", pps->redundant_pic_cnt_present_flag); - - int have_more_data = 0; - if( 1 ) { have_more_data = more_rbsp_data(h, b); } - if( 0 ) - { - have_more_data = pps->transform_8x8_mode_flag | pps->pic_scaling_matrix_present_flag | pps->second_chroma_qp_index_offset != 0; - } - - if( have_more_data ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->transform_8x8_mode_flag = bs_read_u1(b); printf("pps->transform_8x8_mode_flag: %d \n", pps->transform_8x8_mode_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_scaling_matrix_present_flag = bs_read_u1(b); printf("pps->pic_scaling_matrix_present_flag: %d \n", pps->pic_scaling_matrix_present_flag); - if( pps->pic_scaling_matrix_present_flag ) - { - for( int i = 0; i < 6 + 2* pps->transform_8x8_mode_flag; i++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->pic_scaling_list_present_flag[ i ] = bs_read_u1(b); printf("pps->pic_scaling_list_present_flag[ i ]: %d \n", pps->pic_scaling_list_present_flag[ i ]); - if( pps->pic_scaling_list_present_flag[ i ] ) - { - if( i < 6 ) - { - read_debug_scaling_list( b, pps->ScalingList4x4[ i ], 16, - &( pps->UseDefaultScalingMatrix4x4Flag[ i ] ) ); - } - else - { - read_debug_scaling_list( b, pps->ScalingList8x8[ i - 6 ], 64, - &( pps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] ) ); - } - } - } - } - printf("%d.%d: ", b->p - b->start, b->bits_left); pps->second_chroma_qp_index_offset = bs_read_se(b); printf("pps->second_chroma_qp_index_offset: %d \n", pps->second_chroma_qp_index_offset); - } - read_debug_rbsp_trailing_bits(h, b); - - if( 1 ) - { - memcpy(h->pps, h->pps_table[pps->pic_parameter_set_id], sizeof(pps_t)); - } -} - -#ifdef HAVE_SEI -//7.3.2.3 Supplemental enhancement information RBSP syntax -void read_debug_sei_rbsp(h264_stream_t* h, bs_t* b) -{ - if( 1 ) - { - for( int i = 0; i < h->num_seis; i++ ) - { - sei_free(h->seis[i]); - } - - h->num_seis = 0; - do { - h->num_seis++; - h->seis = (sei_t**)realloc(h->seis, h->num_seis * sizeof(sei_t*)); - h->seis[h->num_seis - 1] = sei_new(); - h->sei = h->seis[h->num_seis - 1]; - read_debug_sei_message(h, b); - } while( more_rbsp_data(h, b) ); - - } - - if( 0 ) - { - for (int i = 0; i < h->num_seis; i++) - { - h->sei = h->seis[i]; - read_debug_sei_message(h, b); - } - h->sei = NULL; - } - - read_debug_rbsp_trailing_bits(h, b); -} - -//7.3.2.3.1 Supplemental enhancement information message syntax -void read_debug_sei_message(h264_stream_t* h, bs_t* b) -{ - if( 0 ) - { - _write_ff_coded_number(b, h->sei->payloadType); - _write_ff_coded_number(b, h->sei->payloadSize); - } - if( 1 ) - { - h->sei->payloadType = _read_ff_coded_number(b); - h->sei->payloadSize = _read_ff_coded_number(b); - } - read_debug_sei_payload( h, b, h->sei->payloadType, h->sei->payloadSize ); -} -#endif - -//7.3.2.4 Access unit delimiter RBSP syntax -void read_debug_access_unit_delimiter_rbsp(h264_stream_t* h, bs_t* b) -{ - printf("%d.%d: ", b->p - b->start, b->bits_left); h->aud->primary_pic_type = bs_read_u(b, 3); printf("h->aud->primary_pic_type: %d \n", h->aud->primary_pic_type); - read_debug_rbsp_trailing_bits(h, b); -} - -//7.3.2.5 End of sequence RBSP syntax -void read_debug_end_of_seq_rbsp(h264_stream_t* h, bs_t* b) -{ -} - -//7.3.2.6 End of stream RBSP syntax -void read_debug_end_of_stream_rbsp(h264_stream_t* h, bs_t* b) -{ -} - -//7.3.2.7 Filler data RBSP syntax -void read_debug_filler_data_rbsp(h264_stream_t* h, bs_t* b) -{ - while( bs_next_bits(b, 8) == 0xFF ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); int ff_byte = bs_read_u(b, 8); printf("ff_byte: %d \n", ff_byte); - } - read_debug_rbsp_trailing_bits(h, b); -} - -//7.3.2.8 Slice layer without partitioning RBSP syntax -void read_debug_slice_layer_rbsp(h264_stream_t* h, bs_t* b) -{ - read_debug_slice_header(h, b); - slice_data_rbsp_t* slice_data = h->slice_data; - - if ( slice_data != NULL ) - { - if ( slice_data->rbsp_buf != NULL ) free( slice_data->rbsp_buf ); - uint8_t *sptr = b->p + (!!b->bits_left); // CABAC-specific: skip alignment bits, if there are any - slice_data->rbsp_size = b->end - sptr; - - slice_data->rbsp_buf = (uint8_t*)malloc(slice_data->rbsp_size); - memcpy( slice_data->rbsp_buf, sptr, slice_data->rbsp_size ); - // ugly hack: since next NALU starts at byte border, we are going to be padded by trailing_bits; - return; - } - - // FIXME should read or skip data - //slice_data( ); /* all categories of slice_data( ) syntax */ - read_debug_rbsp_slice_trailing_bits(h, b); -} - -/* -// UNIMPLEMENTED -//7.3.2.9.1 Slice data partition A RBSP syntax -slice_data_partition_a_layer_rbsp( ) { - read_debug_slice_header( ); // only category 2 - slice_id = bs_read_debug_ue(b) - read_debug_slice_data( ); // only category 2 - read_debug_rbsp_slice_trailing_bits( ); // only category 2 -} - -//7.3.2.9.2 Slice data partition B RBSP syntax -slice_data_partition_b_layer_rbsp( ) { - printf("%d.%d: ", b->p - b->start, b->bits_left); slice_id = bs_read_ue(b); printf("slice_id: %d \n", slice_id); // only category 3 - if( redundant_pic_cnt_present_flag ) - printf("%d.%d: ", b->p - b->start, b->bits_left); redundant_pic_cnt = bs_read_ue(b); printf("redundant_pic_cnt: %d \n", redundant_pic_cnt); - read_debug_slice_data( ); // only category 3 - read_debug_rbsp_slice_trailing_bits( ); // only category 3 -} - -//7.3.2.9.3 Slice data partition C RBSP syntax -slice_data_partition_c_layer_rbsp( ) { - printf("%d.%d: ", b->p - b->start, b->bits_left); slice_id = bs_read_ue(b); printf("slice_id: %d \n", slice_id); // only category 4 - if( redundant_pic_cnt_present_flag ) - printf("%d.%d: ", b->p - b->start, b->bits_left); redundant_pic_cnt = bs_read_ue(b); printf("redundant_pic_cnt: %d \n", redundant_pic_cnt); - read_debug_slice_data( ); // only category 4 - rbsp_slice_trailing_bits( ); // only category 4 -} -*/ - -//7.3.2.10 RBSP slice trailing bits syntax -void read_debug_rbsp_slice_trailing_bits(h264_stream_t* h, bs_t* b) -{ - read_debug_rbsp_trailing_bits(h, b); - if( h->pps->entropy_coding_mode_flag ) - { - while( more_rbsp_trailing_data(h, b) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); int cabac_zero_word = bs_read_u(b, 16); printf("cabac_zero_word: %d \n", cabac_zero_word); - } - } -} - -//7.3.2.11 RBSP trailing bits syntax -void read_debug_rbsp_trailing_bits(h264_stream_t* h, bs_t* b) -{ - printf("%d.%d: ", b->p - b->start, b->bits_left); int rbsp_stop_one_bit = bs_read_u(b, 1); printf("rbsp_stop_one_bit: %d \n", rbsp_stop_one_bit); - - while( !bs_byte_aligned(b) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); int rbsp_alignment_zero_bit = bs_read_u(b, 1); printf("rbsp_alignment_zero_bit: %d \n", rbsp_alignment_zero_bit); - } -} - -//7.3.3 Slice header syntax -void read_debug_slice_header(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - if( 1 ) - { - memset(sh, 0, sizeof(slice_header_t)); - } - - nal_t* nal = h->nal; - - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->first_mb_in_slice = bs_read_ue(b); printf("sh->first_mb_in_slice: %d \n", sh->first_mb_in_slice); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->slice_type = bs_read_ue(b); printf("sh->slice_type: %d \n", sh->slice_type); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pic_parameter_set_id = bs_read_ue(b); printf("sh->pic_parameter_set_id: %d \n", sh->pic_parameter_set_id); - - // TODO check existence, otherwise fail - pps_t* pps = h->pps; - sps_t* sps = h->sps; - memcpy(h->pps_table[sh->pic_parameter_set_id], h->pps, sizeof(pps_t)); - memcpy(h->sps_table[pps->seq_parameter_set_id], h->sps, sizeof(sps_t)); - - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->frame_num = bs_read_u(b, sps->log2_max_frame_num_minus4 + 4 ); printf("sh->frame_num: %d \n", sh->frame_num); // was u(v) - if( !sps->frame_mbs_only_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->field_pic_flag = bs_read_u1(b); printf("sh->field_pic_flag: %d \n", sh->field_pic_flag); - if( sh->field_pic_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->bottom_field_flag = bs_read_u1(b); printf("sh->bottom_field_flag: %d \n", sh->bottom_field_flag); - } - } - if( nal->nal_unit_type == 5 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->idr_pic_id = bs_read_ue(b); printf("sh->idr_pic_id: %d \n", sh->idr_pic_id); - } - if( sps->pic_order_cnt_type == 0 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pic_order_cnt_lsb = bs_read_u(b, sps->log2_max_pic_order_cnt_lsb_minus4 + 4 ); printf("sh->pic_order_cnt_lsb: %d \n", sh->pic_order_cnt_lsb); // was u(v) - if( pps->pic_order_present_flag && !sh->field_pic_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->delta_pic_order_cnt_bottom = bs_read_se(b); printf("sh->delta_pic_order_cnt_bottom: %d \n", sh->delta_pic_order_cnt_bottom); - } - } - if( sps->pic_order_cnt_type == 1 && !sps->delta_pic_order_always_zero_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->delta_pic_order_cnt[ 0 ] = bs_read_se(b); printf("sh->delta_pic_order_cnt[ 0 ]: %d \n", sh->delta_pic_order_cnt[ 0 ]); - if( pps->pic_order_present_flag && !sh->field_pic_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->delta_pic_order_cnt[ 1 ] = bs_read_se(b); printf("sh->delta_pic_order_cnt[ 1 ]: %d \n", sh->delta_pic_order_cnt[ 1 ]); - } - } - if( pps->redundant_pic_cnt_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->redundant_pic_cnt = bs_read_ue(b); printf("sh->redundant_pic_cnt: %d \n", sh->redundant_pic_cnt); - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->direct_spatial_mv_pred_flag = bs_read_u1(b); printf("sh->direct_spatial_mv_pred_flag: %d \n", sh->direct_spatial_mv_pred_flag); - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_P ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->num_ref_idx_active_override_flag = bs_read_u1(b); printf("sh->num_ref_idx_active_override_flag: %d \n", sh->num_ref_idx_active_override_flag); - if( sh->num_ref_idx_active_override_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->num_ref_idx_l0_active_minus1 = bs_read_ue(b); printf("sh->num_ref_idx_l0_active_minus1: %d \n", sh->num_ref_idx_l0_active_minus1); // FIXME does this modify the pps? - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->num_ref_idx_l1_active_minus1 = bs_read_ue(b); printf("sh->num_ref_idx_l1_active_minus1: %d \n", sh->num_ref_idx_l1_active_minus1); - } - } - } - read_debug_ref_pic_list_reordering(h, b); - if( ( pps->weighted_pred_flag && ( is_slice_type( sh->slice_type, SH_SLICE_TYPE_P ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) ) ) || - ( pps->weighted_bipred_idc == 1 && is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) ) - { - read_debug_pred_weight_table(h, b); - } - if( nal->nal_ref_idc != 0 ) - { - read_debug_dec_ref_pic_marking(h, b); - } - if( pps->entropy_coding_mode_flag && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->cabac_init_idc = bs_read_ue(b); printf("sh->cabac_init_idc: %d \n", sh->cabac_init_idc); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->slice_qp_delta = bs_read_se(b); printf("sh->slice_qp_delta: %d \n", sh->slice_qp_delta); - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) || is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_SP ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->sp_for_switch_flag = bs_read_u1(b); printf("sh->sp_for_switch_flag: %d \n", sh->sp_for_switch_flag); - } - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->slice_qs_delta = bs_read_se(b); printf("sh->slice_qs_delta: %d \n", sh->slice_qs_delta); - } - if( pps->deblocking_filter_control_present_flag ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->disable_deblocking_filter_idc = bs_read_ue(b); printf("sh->disable_deblocking_filter_idc: %d \n", sh->disable_deblocking_filter_idc); - if( sh->disable_deblocking_filter_idc != 1 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->slice_alpha_c0_offset_div2 = bs_read_se(b); printf("sh->slice_alpha_c0_offset_div2: %d \n", sh->slice_alpha_c0_offset_div2); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->slice_beta_offset_div2 = bs_read_se(b); printf("sh->slice_beta_offset_div2: %d \n", sh->slice_beta_offset_div2); - } - } - if( pps->num_slice_groups_minus1 > 0 && - pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) - { - int v = intlog2( pps->pic_size_in_map_units_minus1 + pps->slice_group_change_rate_minus1 + 1 ); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->slice_group_change_cycle = bs_read_u(b, v); printf("sh->slice_group_change_cycle: %d \n", sh->slice_group_change_cycle); // FIXME add 2? - } -} - -//7.3.3.1 Reference picture list reordering syntax -void read_debug_ref_pic_list_reordering(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - // FIXME should be an array - - if( ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_I ) && ! is_slice_type( sh->slice_type, SH_SLICE_TYPE_SI ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.ref_pic_list_reordering_flag_l0 = bs_read_u1(b); printf("sh->rplr.ref_pic_list_reordering_flag_l0: %d \n", sh->rplr.ref_pic_list_reordering_flag_l0); - if( sh->rplr.ref_pic_list_reordering_flag_l0 ) - { - int n = -1; - do - { - n++; - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] = bs_read_ue(b); printf("sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ]: %d \n", sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ]); - if( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 0 || - sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 1 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.reorder_l0.abs_diff_pic_num_minus1[ n ] = bs_read_ue(b); printf("sh->rplr.reorder_l0.abs_diff_pic_num_minus1[ n ]: %d \n", sh->rplr.reorder_l0.abs_diff_pic_num_minus1[ n ]); - } - else if( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] == 2 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.reorder_l0.long_term_pic_num[ n ] = bs_read_ue(b); printf("sh->rplr.reorder_l0.long_term_pic_num[ n ]: %d \n", sh->rplr.reorder_l0.long_term_pic_num[ n ]); - } - } while( sh->rplr.reorder_l0.reordering_of_pic_nums_idc[ n ] != 3 && ! bs_eof(b) ); - } - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.ref_pic_list_reordering_flag_l1 = bs_read_u1(b); printf("sh->rplr.ref_pic_list_reordering_flag_l1: %d \n", sh->rplr.ref_pic_list_reordering_flag_l1); - if( sh->rplr.ref_pic_list_reordering_flag_l1 ) - { - int n = -1; - do - { - n++; - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] = bs_read_ue(b); printf("sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ]: %d \n", sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ]); - if( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 0 || - sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 1 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.reorder_l1.abs_diff_pic_num_minus1[ n ] = bs_read_ue(b); printf("sh->rplr.reorder_l1.abs_diff_pic_num_minus1[ n ]: %d \n", sh->rplr.reorder_l1.abs_diff_pic_num_minus1[ n ]); - } - else if( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] == 2 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->rplr.reorder_l1.long_term_pic_num[ n ] = bs_read_ue(b); printf("sh->rplr.reorder_l1.long_term_pic_num[ n ]: %d \n", sh->rplr.reorder_l1.long_term_pic_num[ n ]); - } - } while( sh->rplr.reorder_l1.reordering_of_pic_nums_idc[ n ] != 3 && ! bs_eof(b) ); - } - } -} - -//7.3.3.2 Prediction weight table syntax -void read_debug_pred_weight_table(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - sps_t* sps = h->sps; - pps_t* pps = h->pps; - - int i, j; - - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_log2_weight_denom = bs_read_ue(b); printf("sh->pwt.luma_log2_weight_denom: %d \n", sh->pwt.luma_log2_weight_denom); - if( sps->chroma_format_idc != 0 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_log2_weight_denom = bs_read_ue(b); printf("sh->pwt.chroma_log2_weight_denom: %d \n", sh->pwt.chroma_log2_weight_denom); - } - for( i = 0; i <= pps->num_ref_idx_l0_active_minus1; i++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_weight_l0_flag[i] = bs_read_u1(b); printf("sh->pwt.luma_weight_l0_flag[i]: %d \n", sh->pwt.luma_weight_l0_flag[i]); - if( sh->pwt.luma_weight_l0_flag[i] ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_weight_l0[ i ] = bs_read_se(b); printf("sh->pwt.luma_weight_l0[ i ]: %d \n", sh->pwt.luma_weight_l0[ i ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_offset_l0[ i ] = bs_read_se(b); printf("sh->pwt.luma_offset_l0[ i ]: %d \n", sh->pwt.luma_offset_l0[ i ]); - } - if ( sps->chroma_format_idc != 0 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_weight_l0_flag[i] = bs_read_u1(b); printf("sh->pwt.chroma_weight_l0_flag[i]: %d \n", sh->pwt.chroma_weight_l0_flag[i]); - if( sh->pwt.chroma_weight_l0_flag[i] ) - { - for( j =0; j < 2; j++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_weight_l0[ i ][ j ] = bs_read_se(b); printf("sh->pwt.chroma_weight_l0[ i ][ j ]: %d \n", sh->pwt.chroma_weight_l0[ i ][ j ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_offset_l0[ i ][ j ] = bs_read_se(b); printf("sh->pwt.chroma_offset_l0[ i ][ j ]: %d \n", sh->pwt.chroma_offset_l0[ i ][ j ]); - } - } - } - } - if( is_slice_type( sh->slice_type, SH_SLICE_TYPE_B ) ) - { - for( i = 0; i <= pps->num_ref_idx_l1_active_minus1; i++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_weight_l1_flag[i] = bs_read_u1(b); printf("sh->pwt.luma_weight_l1_flag[i]: %d \n", sh->pwt.luma_weight_l1_flag[i]); - if( sh->pwt.luma_weight_l1_flag[i] ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_weight_l1[ i ] = bs_read_se(b); printf("sh->pwt.luma_weight_l1[ i ]: %d \n", sh->pwt.luma_weight_l1[ i ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.luma_offset_l1[ i ] = bs_read_se(b); printf("sh->pwt.luma_offset_l1[ i ]: %d \n", sh->pwt.luma_offset_l1[ i ]); - } - if( sps->chroma_format_idc != 0 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_weight_l1_flag[i] = bs_read_u1(b); printf("sh->pwt.chroma_weight_l1_flag[i]: %d \n", sh->pwt.chroma_weight_l1_flag[i]); - if( sh->pwt.chroma_weight_l1_flag[i] ) - { - for( j = 0; j < 2; j++ ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_weight_l1[ i ][ j ] = bs_read_se(b); printf("sh->pwt.chroma_weight_l1[ i ][ j ]: %d \n", sh->pwt.chroma_weight_l1[ i ][ j ]); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->pwt.chroma_offset_l1[ i ][ j ] = bs_read_se(b); printf("sh->pwt.chroma_offset_l1[ i ][ j ]: %d \n", sh->pwt.chroma_offset_l1[ i ][ j ]); - } - } - } - } - } -} - -//7.3.3.3 Decoded reference picture marking syntax -void read_debug_dec_ref_pic_marking(h264_stream_t* h, bs_t* b) -{ - slice_header_t* sh = h->sh; - // FIXME should be an array - - if( h->nal->nal_unit_type == 5 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.no_output_of_prior_pics_flag = bs_read_u1(b); printf("sh->drpm.no_output_of_prior_pics_flag: %d \n", sh->drpm.no_output_of_prior_pics_flag); - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.long_term_reference_flag = bs_read_u1(b); printf("sh->drpm.long_term_reference_flag: %d \n", sh->drpm.long_term_reference_flag); - } - else - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.adaptive_ref_pic_marking_mode_flag = bs_read_u1(b); printf("sh->drpm.adaptive_ref_pic_marking_mode_flag: %d \n", sh->drpm.adaptive_ref_pic_marking_mode_flag); - if( sh->drpm.adaptive_ref_pic_marking_mode_flag ) - { - int n = -1; - do - { - n++; - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.memory_management_control_operation[ n ] = bs_read_ue(b); printf("sh->drpm.memory_management_control_operation[ n ]: %d \n", sh->drpm.memory_management_control_operation[ n ]); - if( sh->drpm.memory_management_control_operation[ n ] == 1 || - sh->drpm.memory_management_control_operation[ n ] == 3 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.difference_of_pic_nums_minus1[ n ] = bs_read_ue(b); printf("sh->drpm.difference_of_pic_nums_minus1[ n ]: %d \n", sh->drpm.difference_of_pic_nums_minus1[ n ]); - } - if(sh->drpm.memory_management_control_operation[ n ] == 2 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.long_term_pic_num[ n ] = bs_read_ue(b); printf("sh->drpm.long_term_pic_num[ n ]: %d \n", sh->drpm.long_term_pic_num[ n ]); - } - if( sh->drpm.memory_management_control_operation[ n ] == 3 || - sh->drpm.memory_management_control_operation[ n ] == 6 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.long_term_frame_idx[ n ] = bs_read_ue(b); printf("sh->drpm.long_term_frame_idx[ n ]: %d \n", sh->drpm.long_term_frame_idx[ n ]); - } - if( sh->drpm.memory_management_control_operation[ n ] == 4 ) - { - printf("%d.%d: ", b->p - b->start, b->bits_left); sh->drpm.max_long_term_frame_idx_plus1[ n ] = bs_read_ue(b); printf("sh->drpm.max_long_term_frame_idx_plus1[ n ]: %d \n", sh->drpm.max_long_term_frame_idx_plus1[ n ]); - } - } while( sh->drpm.memory_management_control_operation[ n ] != 0 && ! bs_eof(b) ); - } - } -} diff --git a/third_party/h264bitstream/h264bitstream.suprx b/third_party/h264bitstream/h264bitstream.suprx new file mode 100644 index 000000000..6cdd25428 Binary files /dev/null and b/third_party/h264bitstream/h264bitstream.suprx differ diff --git a/third_party/h264bitstream/libh264bitstream_stub.a b/third_party/h264bitstream/libh264bitstream_stub.a new file mode 100644 index 000000000..1d5400aa4 Binary files /dev/null and b/third_party/h264bitstream/libh264bitstream_stub.a differ diff --git a/third_party/ilclient/ilclient.c b/third_party/ilclient/ilclient.c deleted file mode 100644 index f6c8e2d1c..000000000 --- a/third_party/ilclient/ilclient.c +++ /dev/null @@ -1,1836 +0,0 @@ -/* -Copyright (c) 2012, Broadcom Europe Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - * \file - * - * \brief This API defines helper functions for writing IL clients. - * - * This file defines an IL client side library. This is useful when - * writing IL clients, since there tends to be much repeated and - * common code across both single and multiple clients. This library - * seeks to remove that common code and abstract some of the - * interactions with components. There is a wrapper around a - * component and tunnel, and some operations can be done on lists of - * these. The callbacks from components are handled, and specific - * events can be checked or waited for. -*/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#define VCOS_LOG_CATEGORY (&ilclient_log_category) - -#ifndef ILCLIENT_THREAD_DEFAULT_STACK_SIZE -#define ILCLIENT_THREAD_DEFAULT_STACK_SIZE (6<<10) -#endif - -static VCOS_LOG_CAT_T ilclient_log_category; - -/****************************************************************************** -Static data and types used only in this file. -******************************************************************************/ - -struct _ILEVENT_T { - OMX_EVENTTYPE eEvent; - OMX_U32 nData1; - OMX_U32 nData2; - OMX_PTR pEventData; - struct _ILEVENT_T *next; -}; - -#define NUM_EVENTS 100 -struct _ILCLIENT_T { - ILEVENT_T *event_list; - VCOS_SEMAPHORE_T event_sema; - ILEVENT_T event_rep[NUM_EVENTS]; - - ILCLIENT_CALLBACK_T port_settings_callback; - void *port_settings_callback_data; - ILCLIENT_CALLBACK_T eos_callback; - void *eos_callback_data; - ILCLIENT_CALLBACK_T error_callback; - void *error_callback_data; - ILCLIENT_BUFFER_CALLBACK_T fill_buffer_done_callback; - void *fill_buffer_done_callback_data; - ILCLIENT_BUFFER_CALLBACK_T empty_buffer_done_callback; - void *empty_buffer_done_callback_data; - ILCLIENT_CALLBACK_T configchanged_callback; - void *configchanged_callback_data; -}; - -struct _COMPONENT_T { - OMX_HANDLETYPE comp; - ILCLIENT_CREATE_FLAGS_T flags; - VCOS_SEMAPHORE_T sema; - VCOS_EVENT_FLAGS_T event; - struct _COMPONENT_T *related; - OMX_BUFFERHEADERTYPE *out_list; - OMX_BUFFERHEADERTYPE *in_list; - char name[32]; - char bufname[32]; - unsigned int error_mask; - unsigned int private; - ILEVENT_T *list; - ILCLIENT_T *client; -}; - -#define random_wait() -static char *states[] = {"Invalid", "Loaded", "Idle", "Executing", "Pause", "WaitingForResources"}; - -typedef enum { - ILCLIENT_ERROR_UNPOPULATED = 0x1, - ILCLIENT_ERROR_SAMESTATE = 0x2, - ILCLIENT_ERROR_BADPARAMETER = 0x4 -} ILERROR_MASK_T; - -/****************************************************************************** -Static functions. -******************************************************************************/ - -static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); -static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); -static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent, - OMX_OUT OMX_PTR pAppData, - OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer); -static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent, - OMX_OUT OMX_PTR pAppData, - OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer); -static OMX_ERRORTYPE ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_EVENTTYPE eEvent, - OMX_IN OMX_U32 nData1, - OMX_IN OMX_U32 nData2, - OMX_IN OMX_PTR pEventData); -static void ilclient_lock_events(ILCLIENT_T *st); -static void ilclient_unlock_events(ILCLIENT_T *st); - -/****************************************************************************** -Global functions -******************************************************************************/ - -/*********************************************************** - * Name: ilclient_init - * - * Description: Creates ilclient pointer - * - * Returns: pointer to client structure - ***********************************************************/ -ILCLIENT_T *ilclient_init() -{ - ILCLIENT_T *st = vcos_malloc(sizeof(ILCLIENT_T), "ilclient"); - int i; - - if (!st) - return NULL; - - vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_WARN); - vcos_log_register("ilclient", VCOS_LOG_CATEGORY); - - memset(st, 0, sizeof(ILCLIENT_T)); - - i = vcos_semaphore_create(&st->event_sema, "il:event", 1); - vc_assert(i == VCOS_SUCCESS); - - ilclient_lock_events(st); - st->event_list = NULL; - for (i=0; ievent_rep[i].eEvent = -1; // mark as unused - st->event_rep[i].next = st->event_list; - st->event_list = st->event_rep+i; - } - ilclient_unlock_events(st); - return st; -} - -/*********************************************************** - * Name: ilclient_destroy - * - * Description: frees client state - * - * Returns: void - ***********************************************************/ -void ilclient_destroy(ILCLIENT_T *st) -{ - vcos_semaphore_delete(&st->event_sema); - vcos_free(st); - vcos_log_unregister(VCOS_LOG_CATEGORY); -} - -/*********************************************************** - * Name: ilclient_set_port_settings_callback - * - * Description: sets the callback used when receiving port settings - * changed messages. The data field in the callback function will be - * the port index reporting the message. - * - * Returns: void - ***********************************************************/ -void ilclient_set_port_settings_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata) -{ - st->port_settings_callback = func; - st->port_settings_callback_data = userdata; -} - -/*********************************************************** - * Name: ilclient_set_eos_callback - * - * Description: sets the callback used when receiving eos flags. The - * data parameter in the callback function will be the port index - * reporting an eos flag. - * - * Returns: void - ***********************************************************/ -void ilclient_set_eos_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata) -{ - st->eos_callback = func; - st->eos_callback_data = userdata; -} - -/*********************************************************** - * Name: ilclient_set_error_callback - * - * Description: sets the callback used when receiving error events. - * The data parameter in the callback function will be the error code - * being reported. - * - * Returns: void - ***********************************************************/ -void ilclient_set_error_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata) -{ - st->error_callback = func; - st->error_callback_data = userdata; -} - -/*********************************************************** - * Name: ilclient_set_fill_buffer_done_callback - * - * Description: sets the callback used when receiving - * fill_buffer_done event - * - * Returns: void - ***********************************************************/ -void ilclient_set_fill_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata) -{ - st->fill_buffer_done_callback = func; - st->fill_buffer_done_callback_data = userdata; -} - -/*********************************************************** - * Name: ilclient_set_empty_buffer_done_callback - * - * Description: sets the callback used when receiving - * empty_buffer_done event - * - * Returns: void - ***********************************************************/ -void ilclient_set_empty_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata) -{ - st->empty_buffer_done_callback = func; - st->empty_buffer_done_callback_data = userdata; -} - -/*********************************************************** - * Name: ilclient_set_configchanged_callback - * - * Description: sets the callback used when a config changed - * event is received - * - * Returns: void - ***********************************************************/ -void ilclient_set_configchanged_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata) -{ - st->configchanged_callback = func; - st->configchanged_callback_data = userdata; -} - -/*********************************************************** - * Name: ilclient_create_component - * - * Description: initialises a component state structure and creates - * the IL component. - * - * Returns: 0 on success, -1 on failure - ***********************************************************/ -int ilclient_create_component(ILCLIENT_T *client, COMPONENT_T **comp, char *name, - ILCLIENT_CREATE_FLAGS_T flags) -{ - OMX_CALLBACKTYPE callbacks; - OMX_ERRORTYPE error; - char component_name[128]; - int32_t status; - - *comp = vcos_malloc(sizeof(COMPONENT_T), "il:comp"); - if(!*comp) - return -1; - - memset(*comp, 0, sizeof(COMPONENT_T)); - -#define COMP_PREFIX "OMX.broadcom." - - status = vcos_event_flags_create(&(*comp)->event,"il:comp"); - vc_assert(status == VCOS_SUCCESS); - status = vcos_semaphore_create(&(*comp)->sema, "il:comp", 1); - vc_assert(status == VCOS_SUCCESS); - (*comp)->client = client; - - vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", name); - vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", name); - vcos_snprintf(component_name, sizeof(component_name), "%s%s", COMP_PREFIX, name); - - (*comp)->flags = flags; - - callbacks.EventHandler = ilclient_event_handler; - callbacks.EmptyBufferDone = flags & ILCLIENT_ENABLE_INPUT_BUFFERS ? ilclient_empty_buffer_done : ilclient_empty_buffer_done_error; - callbacks.FillBufferDone = flags & ILCLIENT_ENABLE_OUTPUT_BUFFERS ? ilclient_fill_buffer_done : ilclient_fill_buffer_done_error; - - error = OMX_GetHandle(&(*comp)->comp, component_name, *comp, &callbacks); - - if (error == OMX_ErrorNone) - { - OMX_UUIDTYPE uid; - char name[128]; - OMX_VERSIONTYPE compVersion, specVersion; - - if(OMX_GetComponentVersion((*comp)->comp, name, &compVersion, &specVersion, &uid) == OMX_ErrorNone) - { - char *p = (char *) uid + strlen(COMP_PREFIX); - - vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", p); - (*comp)->name[sizeof((*comp)->name)-1] = 0; - vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", p); - (*comp)->bufname[sizeof((*comp)->bufname)-1] = 0; - } - - if(flags & (ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_OUTPUT_ZERO_BUFFERS)) - { - OMX_PORT_PARAM_TYPE ports; - OMX_INDEXTYPE types[] = {OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit, OMX_IndexParamOtherInit}; - int i; - - ports.nSize = sizeof(OMX_PORT_PARAM_TYPE); - ports.nVersion.nVersion = OMX_VERSION; - - for(i=0; i<4; i++) - { - OMX_ERRORTYPE error = OMX_GetParameter((*comp)->comp, types[i], &ports); - if(error == OMX_ErrorNone) - { - uint32_t j; - for(j=0; jcomp, OMX_IndexParamPortDefinition, &portdef) == OMX_ErrorNone) - { - if(portdef.eDir == OMX_DirOutput && portdef.nBufferCountActual > 0) - { - portdef.nBufferCountActual = 0; - OMX_SetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef); - } - } - } - } - } - } - } - return 0; - } - else - { - vcos_event_flags_delete(&(*comp)->event); - vcos_semaphore_delete(&(*comp)->sema); - vcos_free(*comp); - *comp = NULL; - return -1; - } -} - -/*********************************************************** - * Name: ilclient_remove_event - * - * Description: Removes an event from a component event list. ignore1 - * and ignore2 are flags indicating whether to not match on nData1 and - * nData2 respectively. - * - * Returns: 0 if the event was removed. -1 if no matching event was - * found. - ***********************************************************/ -int ilclient_remove_event(COMPONENT_T *st, OMX_EVENTTYPE eEvent, - OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2) -{ - ILEVENT_T *cur, *prev; - uint32_t set; - ilclient_lock_events(st->client); - - cur = st->list; - prev = NULL; - - while (cur && !(cur->eEvent == eEvent && (ignore1 || cur->nData1 == nData1) && (ignore2 || cur->nData2 == nData2))) - { - prev = cur; - cur = cur->next; - } - - if (cur == NULL) - { - ilclient_unlock_events(st->client); - return -1; - } - - if (prev == NULL) - st->list = cur->next; - else - prev->next = cur->next; - - // add back into spare list - cur->next = st->client->event_list; - st->client->event_list = cur; - cur->eEvent = -1; // mark as unused - - // if we're removing an OMX_EventError or OMX_EventParamOrConfigChanged event, then clear the error bit from the eventgroup, - // since the user might have been notified through the error callback, and then - // can't clear the event bit - this will then cause problems the next time they - // wait for an error. - if(eEvent == OMX_EventError) - vcos_event_flags_get(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set); - else if(eEvent == OMX_EventParamOrConfigChanged) - vcos_event_flags_get(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR_CONSUME, 0, &set); - - ilclient_unlock_events(st->client); - return 0; -} - -/*********************************************************** - * Name: ilclient_state_transition - * - * Description: Transitions a null terminated list of IL components to - * a given state. All components are told to transition in a random - * order before any are checked for transition completion. - * - * Returns: void - ***********************************************************/ -void ilclient_state_transition(COMPONENT_T *list[], OMX_STATETYPE state) -{ - OMX_ERRORTYPE error; - int i, num; - uint32_t set; - - num=0; - while (list[num]) - num++; - - // if we transition the supplier port first, it will call freebuffer on the non - // supplier, which will correctly signal a port unpopulated error. We want to - // ignore these errors. - if (state == OMX_StateLoaded) - for (i=0; ierror_mask |= ILCLIENT_ERROR_UNPOPULATED; - for (i=0; iprivate = ((rand() >> 13) & 0xff)+1; - - for (i=0; iprivate && (min == -1 || list[min]->private > list[j]->private)) - min = j; - - list[min]->private = 0; - - random_wait(); - //Clear error event for this component - vcos_event_flags_get(&list[min]->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set); - - error = OMX_SendCommand(list[min]->comp, OMX_CommandStateSet, state, NULL); - vc_assert(error == OMX_ErrorNone); - } - - random_wait(); - - for (i=0; ierror_mask &= ~ILCLIENT_ERROR_UNPOPULATED; -} - -/*********************************************************** - * Name: ilclient_teardown_tunnels - * - * Description: tears down a null terminated list of tunnels. - * - * Returns: void - ***********************************************************/ -void ilclient_teardown_tunnels(TUNNEL_T *tunnel) -{ - int i; - OMX_ERRORTYPE error; - - i=0;; - while (tunnel[i].source) - { - error = OMX_SetupTunnel(tunnel[i].source->comp, tunnel[i].source_port, NULL, 0); - vc_assert(error == OMX_ErrorNone); - - error = OMX_SetupTunnel(tunnel[i].sink->comp, tunnel[i].sink_port, NULL, 0); - vc_assert(error == OMX_ErrorNone); - i++; - } -} - -/*********************************************************** - * Name: ilclient_disable_tunnel - * - * Description: disables a tunnel by disabling the ports. Allows - * ports to signal same state error if they were already disabled. - * - * Returns: void - ***********************************************************/ -void ilclient_disable_tunnel(TUNNEL_T *tunnel) -{ - OMX_ERRORTYPE error; - - if(tunnel->source == 0 || tunnel->sink == 0) - return; - - tunnel->source->error_mask |= ILCLIENT_ERROR_UNPOPULATED; - tunnel->sink->error_mask |= ILCLIENT_ERROR_UNPOPULATED; - - error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortDisable, tunnel->source_port, NULL); - vc_assert(error == OMX_ErrorNone); - - error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortDisable, tunnel->sink_port, NULL); - vc_assert(error == OMX_ErrorNone); - - if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortDisable, tunnel->source_port) < 0) - vc_assert(0); - - if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortDisable, tunnel->sink_port) < 0) - vc_assert(0); - - tunnel->source->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED; - tunnel->sink->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED; -} - -/*********************************************************** - * Name: ilclient_enable_tunnel - * - * Description: enables a tunnel by enabling the ports - * - * Returns: 0 on success, -1 on failure - ***********************************************************/ -int ilclient_enable_tunnel(TUNNEL_T *tunnel) -{ - OMX_STATETYPE state; - OMX_ERRORTYPE error; - - ilclient_debug_output("ilclient: enable tunnel from %x/%d to %x/%d", - tunnel->source, tunnel->source_port, - tunnel->sink, tunnel->sink_port); - - error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortEnable, tunnel->source_port, NULL); - vc_assert(error == OMX_ErrorNone); - - error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortEnable, tunnel->sink_port, NULL); - vc_assert(error == OMX_ErrorNone); - - // to complete, the sink component can't be in loaded state - error = OMX_GetState(tunnel->sink->comp, &state); - vc_assert(error == OMX_ErrorNone); - if (state == OMX_StateLoaded) - { - int ret = 0; - - if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0 || - OMX_SendCommand(tunnel->sink->comp, OMX_CommandStateSet, OMX_StateIdle, NULL) != OMX_ErrorNone || - (ret = ilclient_wait_for_command_complete_dual(tunnel->sink, OMX_CommandStateSet, OMX_StateIdle, tunnel->source)) < 0) - { - if(ret == -2) - { - // the error was reported fom the source component: clear this error and disable the sink component - ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port); - ilclient_disable_port(tunnel->sink, tunnel->sink_port); - } - - ilclient_debug_output("ilclient: could not change component state to IDLE"); - ilclient_disable_port(tunnel->source, tunnel->source_port); - return -1; - } - } - else - { - if (ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0) - { - ilclient_debug_output("ilclient: could not change sink port %d to enabled", tunnel->sink_port); - - //Oops failed to enable the sink port - ilclient_disable_port(tunnel->source, tunnel->source_port); - //Clean up the port enable event from the source port. - ilclient_wait_for_event(tunnel->source, OMX_EventCmdComplete, - OMX_CommandPortEnable, 0, tunnel->source_port, 0, - ILCLIENT_PORT_ENABLED | ILCLIENT_EVENT_ERROR, VCOS_EVENT_FLAGS_SUSPEND); - return -1; - } - } - - if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port) != 0) - { - ilclient_debug_output("ilclient: could not change source port %d to enabled", tunnel->source_port); - - //Failed to enable the source port - ilclient_disable_port(tunnel->sink, tunnel->sink_port); - return -1; - } - - return 0; -} - - -/*********************************************************** - * Name: ilclient_flush_tunnels - * - * Description: flushes all ports used in a null terminated list of - * tunnels. max specifies the maximum number of tunnels to flush from - * the list, where max=0 means all tunnels. - * - * Returns: void - ***********************************************************/ -void ilclient_flush_tunnels(TUNNEL_T *tunnel, int max) -{ - OMX_ERRORTYPE error; - int i; - - i=0; - while (tunnel[i].source && (max == 0 || i < max)) - { - error = OMX_SendCommand(tunnel[i].source->comp, OMX_CommandFlush, tunnel[i].source_port, NULL); - vc_assert(error == OMX_ErrorNone); - - error = OMX_SendCommand(tunnel[i].sink->comp, OMX_CommandFlush, tunnel[i].sink_port, NULL); - vc_assert(error == OMX_ErrorNone); - - ilclient_wait_for_event(tunnel[i].source, OMX_EventCmdComplete, - OMX_CommandFlush, 0, tunnel[i].source_port, 0, - ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND); - ilclient_wait_for_event(tunnel[i].sink, OMX_EventCmdComplete, - OMX_CommandFlush, 0, tunnel[i].sink_port, 0, - ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND); - i++; - } -} - - -/*********************************************************** - * Name: ilclient_return_events - * - * Description: Returns all events from a component event list to the - * list of unused event structures. - * - * Returns: void - ***********************************************************/ -void ilclient_return_events(COMPONENT_T *comp) -{ - ilclient_lock_events(comp->client); - while (comp->list) - { - ILEVENT_T *next = comp->list->next; - comp->list->next = comp->client->event_list; - comp->client->event_list = comp->list; - comp->list = next; - } - ilclient_unlock_events(comp->client); -} - -/*********************************************************** - * Name: ilclient_cleanup_components - * - * Description: frees all components from a null terminated list and - * deletes resources used in component state structure. - * - * Returns: void - ***********************************************************/ -void ilclient_cleanup_components(COMPONENT_T *list[]) -{ - int i; - OMX_ERRORTYPE error; - - i=0; - while (list[i]) - { - ilclient_return_events(list[i]); - if (list[i]->comp) - { - error = OMX_FreeHandle(list[i]->comp); - - vc_assert(error == OMX_ErrorNone); - } - i++; - } - - i=0; - while (list[i]) - { - vcos_event_flags_delete(&list[i]->event); - vcos_semaphore_delete(&list[i]->sema); - vcos_free(list[i]); - list[i] = NULL; - i++; - } -} - -/*********************************************************** - * Name: ilclient_change_component_state - * - * Description: changes the state of a single component. Note: this - * may not be suitable if the component is tunnelled and requires - * connected components to also change state. - * - * Returns: 0 on success, -1 on failure (note - trying to change to - * the same state which causes a OMX_ErrorSameState is treated as - * success) - ***********************************************************/ -int ilclient_change_component_state(COMPONENT_T *comp, OMX_STATETYPE state) -{ - OMX_ERRORTYPE error; - error = OMX_SendCommand(comp->comp, OMX_CommandStateSet, state, NULL); - vc_assert(error == OMX_ErrorNone); - if(ilclient_wait_for_command_complete(comp, OMX_CommandStateSet, state) < 0) - { - ilclient_debug_output("ilclient: could not change component state to %d", state); - ilclient_remove_event(comp, OMX_EventError, 0, 1, 0, 1); - return -1; - } - return 0; -} - -/*********************************************************** - * Name: ilclient_disable_port - * - * Description: disables a port on a given component. - * - * Returns: void - ***********************************************************/ -void ilclient_disable_port(COMPONENT_T *comp, int portIndex) -{ - OMX_ERRORTYPE error; - error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL); - vc_assert(error == OMX_ErrorNone); - if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0) - vc_assert(0); -} - -/*********************************************************** - * Name: ilclient_enabled_port - * - * Description: enables a port on a given component. - * - * Returns: void - ***********************************************************/ -void ilclient_enable_port(COMPONENT_T *comp, int portIndex) -{ - OMX_ERRORTYPE error; - error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL); - vc_assert(error == OMX_ErrorNone); - if(ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0) - vc_assert(0); -} - - -/*********************************************************** - * Name: ilclient_enable_port_buffers - * - * Description: enables a port on a given component which requires - * buffers to be supplied by the client. - * - * Returns: void - ***********************************************************/ -int ilclient_enable_port_buffers(COMPONENT_T *comp, int portIndex, - ILCLIENT_MALLOC_T ilclient_malloc, - ILCLIENT_FREE_T ilclient_free, - void *private) -{ - OMX_ERRORTYPE error; - OMX_PARAM_PORTDEFINITIONTYPE portdef; - OMX_BUFFERHEADERTYPE *list = NULL, **end = &list; - OMX_STATETYPE state; - int i; - - memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); - portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); - portdef.nVersion.nVersion = OMX_VERSION; - portdef.nPortIndex = portIndex; - - // work out buffer requirements, check port is in the right state - error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef); - if(error != OMX_ErrorNone || portdef.bEnabled != OMX_FALSE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0) - return -1; - - // check component is in the right state to accept buffers - error = OMX_GetState(comp->comp, &state); - if (error != OMX_ErrorNone || !(state == OMX_StateIdle || state == OMX_StateExecuting || state == OMX_StatePause)) - return -1; - - // send the command - error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL); - vc_assert(error == OMX_ErrorNone); - - for (i=0; i != portdef.nBufferCountActual; i++) - { - unsigned char *buf; - if(ilclient_malloc) - buf = ilclient_malloc(private, portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname); - else - buf = vcos_malloc_aligned(portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname); - - if(!buf) - break; - - error = OMX_UseBuffer(comp->comp, end, portIndex, NULL, portdef.nBufferSize, buf); - if(error != OMX_ErrorNone) - { - if(ilclient_free) - ilclient_free(private, buf); - else - vcos_free(buf); - - break; - } - end = (OMX_BUFFERHEADERTYPE **) &((*end)->pAppPrivate); - } - - // queue these buffers - vcos_semaphore_wait(&comp->sema); - - if(portdef.eDir == OMX_DirInput) - { - *end = comp->in_list; - comp->in_list = list; - } - else - { - *end = comp->out_list; - comp->out_list = list; - } - - vcos_semaphore_post(&comp->sema); - - if(i != portdef.nBufferCountActual || - ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0) - { - ilclient_disable_port_buffers(comp, portIndex, NULL, ilclient_free, private); - - // at this point the first command might have terminated with an error, which means that - // the port is disabled before the disable_port_buffers function is called, so we're left - // with the error bit set and an error event in the queue. Clear these now if they exist. - ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0); - - return -1; - } - - // success - return 0; -} - - -/*********************************************************** - * Name: ilclient_disable_port_buffers - * - * Description: disables a port on a given component which has - * buffers supplied by the client. - * - * Returns: void - ***********************************************************/ -void ilclient_disable_port_buffers(COMPONENT_T *comp, int portIndex, - OMX_BUFFERHEADERTYPE *bufferList, - ILCLIENT_FREE_T ilclient_free, - void *private) -{ - OMX_ERRORTYPE error; - OMX_BUFFERHEADERTYPE *list = bufferList; - OMX_BUFFERHEADERTYPE **head, *clist, *prev; - OMX_PARAM_PORTDEFINITIONTYPE portdef; - int num; - - // get the buffers off the relevant queue - memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE)); - portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE); - portdef.nVersion.nVersion = OMX_VERSION; - portdef.nPortIndex = portIndex; - - // work out buffer requirements, check port is in the right state - error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef); - if(error != OMX_ErrorNone || portdef.bEnabled != OMX_TRUE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0) - return; - - num = portdef.nBufferCountActual; - - error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL); - vc_assert(error == OMX_ErrorNone); - - while(num > 0) - { - VCOS_UNSIGNED set; - - if(list == NULL) - { - vcos_semaphore_wait(&comp->sema); - - // take buffers for this port off the relevant queue - head = portdef.eDir == OMX_DirInput ? &comp->in_list : &comp->out_list; - clist = *head; - prev = NULL; - - while(clist) - { - if((portdef.eDir == OMX_DirInput ? clist->nInputPortIndex : clist->nOutputPortIndex) == portIndex) - { - OMX_BUFFERHEADERTYPE *pBuffer = clist; - - if(!prev) - clist = *head = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate; - else - clist = prev->pAppPrivate = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate; - - pBuffer->pAppPrivate = list; - list = pBuffer; - } - else - { - prev = clist; - clist = (OMX_BUFFERHEADERTYPE *) &(clist->pAppPrivate); - } - } - - vcos_semaphore_post(&comp->sema); - } - - while(list) - { - void *buf = list->pBuffer; - OMX_BUFFERHEADERTYPE *next = list->pAppPrivate; - - error = OMX_FreeBuffer(comp->comp, portIndex, list); - vc_assert(error == OMX_ErrorNone); - - if(ilclient_free) - ilclient_free(private, buf); - else - vcos_free(buf); - - num--; - list = next; - } - - if(num) - { - OMX_U32 mask = ILCLIENT_PORT_DISABLED | ILCLIENT_EVENT_ERROR; - mask |= (portdef.eDir == OMX_DirInput ? ILCLIENT_EMPTY_BUFFER_DONE : ILCLIENT_FILL_BUFFER_DONE); - - // also wait for command complete/error in case we didn't have all the buffers allocated - vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, -1, &set); - - if((set & ILCLIENT_EVENT_ERROR) && ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0) >= 0) - return; - - if((set & ILCLIENT_PORT_DISABLED) && ilclient_remove_event(comp, OMX_EventCmdComplete, OMX_CommandPortDisable, 0, portIndex, 0) >= 0) - return; - } - } - - if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0) - vc_assert(0); -} - - -/*********************************************************** - * Name: ilclient_setup_tunnel - * - * Description: creates a tunnel between components that require that - * ports be inititially disabled, then enabled after tunnel setup. If - * timeout is non-zero, it will initially wait until a port settings - * changes message has been received by the output port. If port - * streams are supported by the output port, the requested port stream - * will be selected. - * - * Returns: 0 indicates success, negative indicates failure. - * -1: a timeout waiting for the parameter changed - * -2: an error was returned instead of parameter changed - * -3: no streams are available from this port - * -4: requested stream is not available from this port - * -5: the data format was not acceptable to the sink - ***********************************************************/ -int ilclient_setup_tunnel(TUNNEL_T *tunnel, unsigned int portStream, int timeout) -{ - OMX_ERRORTYPE error; - OMX_PARAM_U32TYPE param; - OMX_STATETYPE state; - int32_t status; - int enable_error; - - // source component must at least be idle, not loaded - error = OMX_GetState(tunnel->source->comp, &state); - vc_assert(error == OMX_ErrorNone); - if (state == OMX_StateLoaded && ilclient_change_component_state(tunnel->source, OMX_StateIdle) < 0) - return -2; - - // wait for the port parameter changed from the source port - if(timeout) - { - status = ilclient_wait_for_event(tunnel->source, OMX_EventPortSettingsChanged, - tunnel->source_port, 0, -1, 1, - ILCLIENT_PARAMETER_CHANGED | ILCLIENT_EVENT_ERROR, timeout); - - if (status < 0) - { - ilclient_debug_output( - "ilclient: timed out waiting for port settings changed on port %d", tunnel->source_port); - return status; - } - } - - // disable ports - ilclient_disable_tunnel(tunnel); - - // if this source port uses port streams, we need to select one of them before proceeding - // if getparameter causes an error that's fine, nothing needs selecting - param.nSize = sizeof(OMX_PARAM_U32TYPE); - param.nVersion.nVersion = OMX_VERSION; - param.nPortIndex = tunnel->source_port; - if (OMX_GetParameter(tunnel->source->comp, OMX_IndexParamNumAvailableStreams, ¶m) == OMX_ErrorNone) - { - if (param.nU32 == 0) - { - // no streams available - // leave the source port disabled, and return a failure - return -3; - } - if (param.nU32 <= portStream) - { - // requested stream not available - // no streams available - // leave the source port disabled, and return a failure - return -4; - } - - param.nU32 = portStream; - error = OMX_SetParameter(tunnel->source->comp, OMX_IndexParamActiveStream, ¶m); - vc_assert(error == OMX_ErrorNone); - } - - // now create the tunnel - error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, tunnel->sink->comp, tunnel->sink_port); - - enable_error = 0; - - if (error != OMX_ErrorNone || (enable_error=ilclient_enable_tunnel(tunnel)) < 0) - { - // probably format not compatible - error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, NULL, 0); - vc_assert(error == OMX_ErrorNone); - error = OMX_SetupTunnel(tunnel->sink->comp, tunnel->sink_port, NULL, 0); - vc_assert(error == OMX_ErrorNone); - - if(enable_error) - { - //Clean up the errors. This does risk removing an error that was nothing to do with this tunnel :-/ - ilclient_remove_event(tunnel->sink, OMX_EventError, 0, 1, 0, 1); - ilclient_remove_event(tunnel->source, OMX_EventError, 0, 1, 0, 1); - } - - ilclient_debug_output("ilclient: could not setup/enable tunnel (setup=0x%x,enable=%d)", - error, enable_error); - return -5; - } - - return 0; -} - -/*********************************************************** - * Name: ilclient_wait_for_event - * - * Description: waits for a given event to appear on a component event - * list. If not immediately present, will wait on that components - * event group for the given event flag. - * - * Returns: 0 indicates success, negative indicates failure. - * -1: a timeout was received. - * -2: an error event was received. - * -3: a config change event was received. - ***********************************************************/ -int ilclient_wait_for_event(COMPONENT_T *comp, OMX_EVENTTYPE event, - OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2, - int event_flag, int suspend) -{ - int32_t status; - uint32_t set; - - while (ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) < 0) - { - // if we want to be notified of errors, check the list for an error now - // before blocking, the event flag may have been cleared already. - if(event_flag & ILCLIENT_EVENT_ERROR) - { - ILEVENT_T *cur; - ilclient_lock_events(comp->client); - cur = comp->list; - while(cur && cur->eEvent != OMX_EventError) - cur = cur->next; - - if(cur) - { - // clear error flag - vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set); - ilclient_unlock_events(comp->client); - return -2; - } - - ilclient_unlock_events(comp->client); - } - // check for config change event if we are asked to be notified of that - if(event_flag & ILCLIENT_CONFIG_CHANGED) - { - ILEVENT_T *cur; - ilclient_lock_events(comp->client); - cur = comp->list; - while(cur && cur->eEvent != OMX_EventParamOrConfigChanged) - cur = cur->next; - - ilclient_unlock_events(comp->client); - - if(cur) - return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3; - } - - status = vcos_event_flags_get(&comp->event, event_flag, VCOS_OR_CONSUME, - suspend, &set); - if (status != 0) - return -1; - if (set & ILCLIENT_EVENT_ERROR) - return -2; - if (set & ILCLIENT_CONFIG_CHANGED) - return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3; - } - - return 0; -} - - - -/*********************************************************** - * Name: ilclient_wait_for_command_complete_dual - * - * Description: Waits for an event signalling command completion. In - * this version we may also return failure if there is an error event - * that has terminated a command on a second component. - * - * Returns: 0 on success, -1 on failure of comp, -2 on failure of other - ***********************************************************/ -int ilclient_wait_for_command_complete_dual(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2, COMPONENT_T *other) -{ - OMX_U32 mask = ILCLIENT_EVENT_ERROR; - int ret = 0; - - switch(command) { - case OMX_CommandStateSet: mask |= ILCLIENT_STATE_CHANGED; break; - case OMX_CommandPortDisable: mask |= ILCLIENT_PORT_DISABLED; break; - case OMX_CommandPortEnable: mask |= ILCLIENT_PORT_ENABLED; break; - default: return -1; - } - - if(other) - other->related = comp; - - while(1) - { - ILEVENT_T *cur, *prev = NULL; - VCOS_UNSIGNED set; - - ilclient_lock_events(comp->client); - - cur = comp->list; - while(cur && - !(cur->eEvent == OMX_EventCmdComplete && cur->nData1 == command && cur->nData2 == nData2) && - !(cur->eEvent == OMX_EventError && cur->nData2 == 1)) - { - prev = cur; - cur = cur->next; - } - - if(cur) - { - if(prev == NULL) - comp->list = cur->next; - else - prev->next = cur->next; - - // work out whether this was a success or a fail event - ret = cur->eEvent == OMX_EventCmdComplete || cur->nData1 == OMX_ErrorSameState ? 0 : -1; - - if(cur->eEvent == OMX_EventError) - vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set); - - // add back into spare list - cur->next = comp->client->event_list; - comp->client->event_list = cur; - cur->eEvent = -1; // mark as unused - - ilclient_unlock_events(comp->client); - break; - } - else if(other != NULL) - { - // check the other component for an error event that terminates a command - cur = other->list; - while(cur && !(cur->eEvent == OMX_EventError && cur->nData2 == 1)) - cur = cur->next; - - if(cur) - { - // we don't remove the event in this case, since the user - // can confirm that this event errored by calling wait_for_command on the - // other component - - ret = -2; - ilclient_unlock_events(comp->client); - break; - } - } - - ilclient_unlock_events(comp->client); - - vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, VCOS_SUSPEND, &set); - } - - if(other) - other->related = NULL; - - return ret; -} - - -/*********************************************************** - * Name: ilclient_wait_for_command_complete - * - * Description: Waits for an event signalling command completion. - * - * Returns: 0 on success, -1 on failure. - ***********************************************************/ -int ilclient_wait_for_command_complete(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2) -{ - return ilclient_wait_for_command_complete_dual(comp, command, nData2, NULL); -} - -/*********************************************************** - * Name: ilclient_get_output_buffer - * - * Description: Returns an output buffer returned from a component - * using the OMX_FillBufferDone callback from the output list for the - * given component and port index. - * - * Returns: pointer to buffer if available, otherwise NULL - ***********************************************************/ -OMX_BUFFERHEADERTYPE *ilclient_get_output_buffer(COMPONENT_T *comp, int portIndex, int block) -{ - OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL; - VCOS_UNSIGNED set; - - do { - vcos_semaphore_wait(&comp->sema); - ret = comp->out_list; - while(ret != NULL && ret->nOutputPortIndex != portIndex) - { - prev = ret; - ret = ret->pAppPrivate; - } - - if(ret) - { - if(prev == NULL) - comp->out_list = ret->pAppPrivate; - else - prev->pAppPrivate = ret->pAppPrivate; - - ret->pAppPrivate = NULL; - } - vcos_semaphore_post(&comp->sema); - - if(block && !ret) - vcos_event_flags_get(&comp->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set); - - } while(block && !ret); - - return ret; -} - -/*********************************************************** - * Name: ilclient_get_input_buffer - * - * Description: Returns an input buffer return from a component using - * the OMX_EmptyBufferDone callback from the output list for the given - * component and port index. - * - * Returns: pointer to buffer if available, otherwise NULL - ***********************************************************/ -OMX_BUFFERHEADERTYPE *ilclient_get_input_buffer(COMPONENT_T *comp, int portIndex, int block) -{ - OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL; - - do { - VCOS_UNSIGNED set; - - vcos_semaphore_wait(&comp->sema); - ret = comp->in_list; - while(ret != NULL && ret->nInputPortIndex != portIndex) - { - prev = ret; - ret = ret->pAppPrivate; - } - - if(ret) - { - if(prev == NULL) - comp->in_list = ret->pAppPrivate; - else - prev->pAppPrivate = ret->pAppPrivate; - - ret->pAppPrivate = NULL; - } - vcos_semaphore_post(&comp->sema); - - if(block && !ret) - vcos_event_flags_get(&comp->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set); - - } while(block && !ret); - - return ret; -} - -/*********************************************************** - * Name: ilclient_debug_output - * - * Description: prints a varg message to the log or the debug screen - * under win32 - * - * Returns: void - ***********************************************************/ -void ilclient_debug_output(char *format, ...) -{ - va_list args; - - va_start(args, format); - vcos_vlog_info(format, args); - va_end(args); -} - -/****************************************************************************** -Static functions -******************************************************************************/ - -/*********************************************************** - * Name: ilclient_lock_events - * - * Description: locks the client event structure - * - * Returns: void - ***********************************************************/ -static void ilclient_lock_events(ILCLIENT_T *st) -{ - vcos_semaphore_wait(&st->event_sema); -} - -/*********************************************************** - * Name: ilclient_unlock_events - * - * Description: unlocks the client event structure - * - * Returns: void - ***********************************************************/ -static void ilclient_unlock_events(ILCLIENT_T *st) -{ - vcos_semaphore_post(&st->event_sema); -} - -/*********************************************************** - * Name: ilclient_event_handler - * - * Description: event handler passed to core to use as component - * callback - * - * Returns: success - ***********************************************************/ -static OMX_ERRORTYPE ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_EVENTTYPE eEvent, - OMX_IN OMX_U32 nData1, - OMX_IN OMX_U32 nData2, - OMX_IN OMX_PTR pEventData) -{ - COMPONENT_T *st = (COMPONENT_T *) pAppData; - ILEVENT_T *event; - OMX_ERRORTYPE error = OMX_ErrorNone; - - ilclient_lock_events(st->client); - - // go through the events on this component and remove any duplicates in the - // existing list, since the client probably doesn't need them. it's better - // than asserting when we run out. - event = st->list; - while(event != NULL) - { - ILEVENT_T **list = &(event->next); - while(*list != NULL) - { - if((*list)->eEvent == event->eEvent && - (*list)->nData1 == event->nData1 && - (*list)->nData2 == event->nData2) - { - // remove this duplicate - ILEVENT_T *rem = *list; - ilclient_debug_output("%s: removing %d/%d/%d", st->name, event->eEvent, event->nData1, event->nData2); - *list = rem->next; - rem->eEvent = -1; - rem->next = st->client->event_list; - st->client->event_list = rem; - } - else - list = &((*list)->next); - } - - event = event->next; - } - - vc_assert(st->client->event_list); - event = st->client->event_list; - - switch (eEvent) { - case OMX_EventCmdComplete: - switch (nData1) { - case OMX_CommandStateSet: - ilclient_debug_output("%s: callback state changed (%s)", st->name, states[nData2]); - vcos_event_flags_set(&st->event, ILCLIENT_STATE_CHANGED, VCOS_OR); - break; - case OMX_CommandPortDisable: - ilclient_debug_output("%s: callback port disable %d", st->name, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_PORT_DISABLED, VCOS_OR); - break; - case OMX_CommandPortEnable: - ilclient_debug_output("%s: callback port enable %d", st->name, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_PORT_ENABLED, VCOS_OR); - break; - case OMX_CommandFlush: - ilclient_debug_output("%s: callback port flush %d", st->name, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_PORT_FLUSH, VCOS_OR); - break; - case OMX_CommandMarkBuffer: - ilclient_debug_output("%s: callback mark buffer %d", st->name, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_MARKED_BUFFER, VCOS_OR); - break; - default: - vc_assert(0); - } - break; - case OMX_EventError: - { - // check if this component failed a command, and we have to notify another command - // of this failure - if(nData2 == 1 && st->related != NULL) - vcos_event_flags_set(&st->related->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - - error = nData1; - switch (error) { - case OMX_ErrorPortUnpopulated: - if (st->error_mask & ILCLIENT_ERROR_UNPOPULATED) - { - ilclient_debug_output("%s: ignore error: port unpopulated (%d)", st->name, nData2); - event = NULL; - break; - } - ilclient_debug_output("%s: port unpopulated %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorSameState: - if (st->error_mask & ILCLIENT_ERROR_SAMESTATE) - { - ilclient_debug_output("%s: ignore error: same state (%d)", st->name, nData2); - event = NULL; - break; - } - ilclient_debug_output("%s: same state %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorBadParameter: - if (st->error_mask & ILCLIENT_ERROR_BADPARAMETER) - { - ilclient_debug_output("%s: ignore error: bad parameter (%d)", st->name, nData2); - event = NULL; - break; - } - ilclient_debug_output("%s: bad parameter %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorIncorrectStateTransition: - ilclient_debug_output("%s: incorrect state transition %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorBadPortIndex: - ilclient_debug_output("%s: bad port index %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorStreamCorrupt: - ilclient_debug_output("%s: stream corrupt %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorInsufficientResources: - ilclient_debug_output("%s: insufficient resources %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorUnsupportedSetting: - ilclient_debug_output("%s: unsupported setting %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorOverflow: - ilclient_debug_output("%s: overflow %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorDiskFull: - ilclient_debug_output("%s: disk full %x (%d)", st->name, error, nData2); - //we do not set the error - break; - case OMX_ErrorMaxFileSize: - ilclient_debug_output("%s: max file size %x (%d)", st->name, error, nData2); - //we do not set the error - break; - case OMX_ErrorDrmUnauthorised: - ilclient_debug_output("%s: drm file is unauthorised %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorDrmExpired: - ilclient_debug_output("%s: drm file has expired %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - case OMX_ErrorDrmGeneral: - ilclient_debug_output("%s: drm library error %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - default: - vc_assert(0); - ilclient_debug_output("%s: unexpected error %x (%d)", st->name, error, nData2); - vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR); - break; - } - } - break; - case OMX_EventBufferFlag: - ilclient_debug_output("%s: buffer flag %d/%x", st->name, nData1, nData2); - if (nData2 & OMX_BUFFERFLAG_EOS) - { - vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_FLAG_EOS, VCOS_OR); - nData2 = OMX_BUFFERFLAG_EOS; - } - else - vc_assert(0); - break; - case OMX_EventPortSettingsChanged: - ilclient_debug_output("%s: port settings changed %d", st->name, nData1); - vcos_event_flags_set(&st->event, ILCLIENT_PARAMETER_CHANGED, VCOS_OR); - break; - case OMX_EventMark: - ilclient_debug_output("%s: buffer mark %p", st->name, pEventData); - vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_MARK, VCOS_OR); - break; - case OMX_EventParamOrConfigChanged: - ilclient_debug_output("%s: param/config 0x%X on port %d changed", st->name, nData2, nData1); - vcos_event_flags_set(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR); - break; - default: - vc_assert(0); - break; - } - - if (event) - { - // fill in details - event->eEvent = eEvent; - event->nData1 = nData1; - event->nData2 = nData2; - event->pEventData = pEventData; - - // remove from top of spare list - st->client->event_list = st->client->event_list->next; - - // put at head of component event queue - event->next = st->list; - st->list = event; - } - ilclient_unlock_events(st->client); - - // now call any callbacks without the event lock so the client can - // remove the event in context - switch(eEvent) { - case OMX_EventError: - if(event && st->client->error_callback) - st->client->error_callback(st->client->error_callback_data, st, error); - break; - case OMX_EventBufferFlag: - if ((nData2 & OMX_BUFFERFLAG_EOS) && st->client->eos_callback) - st->client->eos_callback(st->client->eos_callback_data, st, nData1); - break; - case OMX_EventPortSettingsChanged: - if (st->client->port_settings_callback) - st->client->port_settings_callback(st->client->port_settings_callback_data, st, nData1); - break; - case OMX_EventParamOrConfigChanged: - if (st->client->configchanged_callback) - st->client->configchanged_callback(st->client->configchanged_callback_data, st, nData2); - break; - default: - // ignore - break; - } - - return OMX_ErrorNone; -} - -/*********************************************************** - * Name: ilclient_empty_buffer_done - * - * Description: passed to core to use as component callback, puts - * buffer on list - * - * Returns: - ***********************************************************/ -static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) -{ - COMPONENT_T *st = (COMPONENT_T *) pAppData; - OMX_BUFFERHEADERTYPE *list; - - ilclient_debug_output("%s: empty buffer done %p", st->name, pBuffer); - - vcos_semaphore_wait(&st->sema); - // insert at end of the list, so we process buffers in - // the same order - list = st->in_list; - while(list && list->pAppPrivate) - list = list->pAppPrivate; - - if(!list) - st->in_list = pBuffer; - else - list->pAppPrivate = pBuffer; - - pBuffer->pAppPrivate = NULL; - vcos_semaphore_post(&st->sema); - - vcos_event_flags_set(&st->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR); - - if (st->client->empty_buffer_done_callback) - st->client->empty_buffer_done_callback(st->client->empty_buffer_done_callback_data, st); - - return OMX_ErrorNone; -} - -/*********************************************************** - * Name: ilclient_empty_buffer_done_error - * - * Description: passed to core to use as component callback, asserts - * on use as client not expecting component to use this callback. - * - * Returns: - ***********************************************************/ -static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) -{ - vc_assert(0); - return OMX_ErrorNone; -} - -/*********************************************************** - * Name: ilclient_fill_buffer_done - * - * Description: passed to core to use as component callback, puts - * buffer on list - * - * Returns: - ***********************************************************/ -static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent, - OMX_OUT OMX_PTR pAppData, - OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) -{ - COMPONENT_T *st = (COMPONENT_T *) pAppData; - OMX_BUFFERHEADERTYPE *list; - - ilclient_debug_output("%s: fill buffer done %p", st->name, pBuffer); - - vcos_semaphore_wait(&st->sema); - // insert at end of the list, so we process buffers in - // the correct order - list = st->out_list; - while(list && list->pAppPrivate) - list = list->pAppPrivate; - - if(!list) - st->out_list = pBuffer; - else - list->pAppPrivate = pBuffer; - - pBuffer->pAppPrivate = NULL; - vcos_semaphore_post(&st->sema); - - vcos_event_flags_set(&st->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR); - - if (st->client->fill_buffer_done_callback) - st->client->fill_buffer_done_callback(st->client->fill_buffer_done_callback_data, st); - - return OMX_ErrorNone; -} - -/*********************************************************** - * Name: ilclient_fill_buffer_done_error - * - * Description: passed to core to use as component callback, asserts - * on use as client not expecting component to use this callback. - * - * Returns: - ***********************************************************/ -static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent, - OMX_OUT OMX_PTR pAppData, - OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) -{ - vc_assert(0); - return OMX_ErrorNone; -} - - - -OMX_HANDLETYPE ilclient_get_handle(COMPONENT_T *comp) -{ - vcos_assert(comp); - return comp->comp; -} - - -static struct { - OMX_PORTDOMAINTYPE dom; - int param; -} port_types[] = { - { OMX_PortDomainVideo, OMX_IndexParamVideoInit }, - { OMX_PortDomainAudio, OMX_IndexParamAudioInit }, - { OMX_PortDomainImage, OMX_IndexParamImageInit }, - { OMX_PortDomainOther, OMX_IndexParamOtherInit }, -}; - -int ilclient_get_port_index(COMPONENT_T *comp, OMX_DIRTYPE dir, OMX_PORTDOMAINTYPE type, int index) -{ - uint32_t i; - // for each possible port type... - for (i=0; iILCLIENT_T structure encapsulates the state needed for the IL - * Client API. It contains a set of callback functions used to - * communicate with the user. It also includes a linked list of free - * event structures. - ***********************************************************/ -typedef struct _ILCLIENT_T ILCLIENT_T; - - -/** - * Each ILEVENT_T structure stores the result of an EventHandler - * callback from a component, storing the event message type and any - * parameters returned. - ***********************************************************/ -typedef struct _ILEVENT_T ILEVENT_T; - - - -struct _COMPONENT_T; - -/** - * The COMPONENT_T structure represents an IL component, - * together with the necessary extra information required by the IL - * Client API. This structure stores the handle to the OMX component, - * as well as the event list containing all events sent by this - * component. The component state structure also holds a pair of - * buffer queues, for input and output buffers returned to the client - * by the FillBufferDone and EmptyBufferDone - * callbacks. As some operations result in error callbacks that can - * be ignored, an error mask is maintained to allow some errors to be - * ignored. A pointer to the client state structure is also added. - ***********************************************************/ -typedef struct _COMPONENT_T COMPONENT_T; - - -/** - * The generic callback function is used for communicating events from - * a particular component to the user. - * - * @param userdata The data returned from when the callback was registered. - * - * @param comp The component structure representing the component that - * originated this event. - * - * @param data The relevant data field from the event. - * - * @return Void. - ***********************************************************/ -typedef void (*ILCLIENT_CALLBACK_T)(void *userdata, COMPONENT_T *comp, OMX_U32 data); - - -/** - * The buffer callback function is used for indicating that a - * component has returned a buffer on a port using client buffer - * communication. - * - * @param data The data returned from when the callback was registered. - * - * @param comp The component from which the buffer originated. - * - * @return Void. - ***********************************************************/ -typedef void (*ILCLIENT_BUFFER_CALLBACK_T)(void *data, COMPONENT_T *comp); - - -/** - * The malloc function is passed into - * ilclient_enable_port_buffers() and used for allocating the - * buffer payload. - * - * @param userdata Private pointer passed into - * ilclient_enable_port_buffers() call. - * - * @param size Size in bytes of the requested memory region. - * - * @param align Alignment requirement in bytes for the base memory address. - * - * @param description Text description of the memory being allocated. - * - * @return The memory address on success, NULL on failure. - ***********************************************************/ -typedef void *(*ILCLIENT_MALLOC_T)(void *userdata, VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description); - - -/** - * The free function is passed into - * ilclient_enable_port_buffers() and - * ilclient_disable_port_buffers() and used for freeing the - * buffer payload. - * - * @param userdata Private pointer passed into - * ilclient_enable_port_buffers() and - * ilclient_disable_port_buffers(). - * - * @param pointer Memory address to free, that was previously returned - * from ILCLIENT_MALLOC_T function. - * - * @return Void. - ***********************************************************/ -typedef void (*ILCLIENT_FREE_T)(void *userdata, void *pointer); - - -/** - * The event mask enumeration describes the possible events that the - * user can ask to wait for when waiting for a particular event. - ***********************************************************/ -typedef enum { - ILCLIENT_EMPTY_BUFFER_DONE = 0x1, /**< Set when a buffer is - returned from an input - port */ - - ILCLIENT_FILL_BUFFER_DONE = 0x2, /**< Set when a buffer is - returned from an output - port */ - - ILCLIENT_PORT_DISABLED = 0x4, /**< Set when a port indicates - it has completed a disable - command. */ - - ILCLIENT_PORT_ENABLED = 0x8, /**< Set when a port indicates - is has completed an enable - command. */ - - ILCLIENT_STATE_CHANGED = 0x10, /**< Set when a component - indicates it has completed - a state change command. */ - - ILCLIENT_BUFFER_FLAG_EOS = 0x20, /**< Set when a port signals - an EOS event. */ - - ILCLIENT_PARAMETER_CHANGED = 0x40, /**< Set when a port signals a - port settings changed - event. */ - - ILCLIENT_EVENT_ERROR = 0x80, /**< Set when a component - indicates an error. */ - - ILCLIENT_PORT_FLUSH = 0x100, /**< Set when a port indicates - is has completed a flush - command. */ - - ILCLIENT_MARKED_BUFFER = 0x200, /**< Set when a port indicates - it has marked a buffer. */ - - ILCLIENT_BUFFER_MARK = 0x400, /**< Set when a port indicates - it has received a buffer - mark. */ - - ILCLIENT_CONFIG_CHANGED = 0x800 /**< Set when a config parameter - changed. */ -} ILEVENT_MASK_T; - - -/** - * On component creation the user can set flags to control the - * creation of that component. - ***********************************************************/ -typedef enum { - ILCLIENT_FLAGS_NONE = 0x0, /**< Used if no flags are - set. */ - - ILCLIENT_ENABLE_INPUT_BUFFERS = 0x1, /**< If set we allow the - client to communicate with - input ports via buffer - communication, rather than - tunneling with another - component. */ - - ILCLIENT_ENABLE_OUTPUT_BUFFERS = 0x2, /**< If set we allow the - client to communicate with - output ports via buffer - communication, rather than - tunneling with another - component. */ - - ILCLIENT_DISABLE_ALL_PORTS = 0x4, /**< If set we disable all - ports on creation. */ - - ILCLIENT_HOST_COMPONENT = 0x8, /**< Create a host component. - The default host ilcore - only can create host components - by being locally hosted - so should only be used for testing - purposes. */ - - ILCLIENT_OUTPUT_ZERO_BUFFERS = 0x10 /**< All output ports will have - nBufferCountActual set to zero, - if supported by the component. */ -} ILCLIENT_CREATE_FLAGS_T; - - -/** - * \brief This structure represents a tunnel in the OpenMAX IL API. - * - * Some operations in this API act on a tunnel, so the tunnel state - * structure (TUNNEL_T) is a convenient store of the source and sink - * of the tunnel. For each, a pointer to the relevant component state - * structure and the port index is stored. - ***********************************************************/ -typedef struct { - COMPONENT_T *source; /**< The source component */ - int source_port; /**< The output port index on the source component */ - COMPONENT_T *sink; /**< The sink component */ - int sink_port; /**< The input port index on the sink component */ -} TUNNEL_T; - - -/** - * The set_tunnel macro is a useful function that initialises a - * TUNNEL_T structure. - ***********************************************************/ -#define set_tunnel(t,a,b,c,d) do {TUNNEL_T *_ilct = (t); \ - _ilct->source = (a); _ilct->source_port = (b); \ - _ilct->sink = (c); _ilct->sink_port = (d);} while(0) - -/** - * For calling OpenMAX IL methods directory, we need to access the - * OMX_HANDLETYPE corresponding to the COMPONENT_T structure. This - * macro enables this while keeping the COMPONENT_T structure opaque. - * The parameter x should be of the type *COMPONENT_T. - ***********************************************************/ -#define ILC_GET_HANDLE(x) ilclient_get_handle(x) - -/** - * An IL Client structure is created by the ilclient_init() - * method. This structure is used when creating components, but - * otherwise is not needed in other API functions as a pointer to this - * structure is maintained in the COMPONENT_T structure. - * - * @return pointer to client structure - ***********************************************************/ -VCHPRE_ ILCLIENT_T VCHPOST_ *ilclient_init(void); - -/** - * When all components have been deleted, the IL Client structure can - * be destroyed by calling the ilclient_destroy() function. - * - * @param handle The client handle. After calling this function, this - * handle should not be used. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_destroy(ILCLIENT_T *handle); - -/** - * The ilclient_set_port_settings_callback() function registers a - * callback to be used when the OMX_EventPortSettingsChanged event is - * received. When the event is received, a pointer to the component - * structure and port index is returned by the callback. - * - * @param handle The client handle - * - * @param func The callback function to use. Calling this function - * with a NULL function pointer will deregister any existing - * registered callback. - * - * @param userdata Data to be passed back when calling the callback - * function. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_set_port_settings_callback(ILCLIENT_T *handle, - ILCLIENT_CALLBACK_T func, - void *userdata); - -/** - * The ilclient_set_eos_callback() function registers a callback to be - * used when the OMX_EventBufferFlag is received with the - * OMX_BUFFERFLAG_EOS flag set. When the event is received, a pointer - * to the component structure and port index is returned by the - * callback. - * - * @param handle The client handle - * - * @param func The callback function to use. Calling this function - * with a NULL function pointer will deregister any existing - * registered callback. - * - * @param userdata Data to be passed back when calling the callback - * function. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_set_eos_callback(ILCLIENT_T *handle, - ILCLIENT_CALLBACK_T func, - void *userdata); - -/** - * The ilclient_set_error_callback() function registers a callback to be - * used when the OMX_EventError is received from a component. When - * the event is received, a pointer to the component structure and the - * error code are reported by the callback. - * - * @param handle The client handle - * - * @param func The callback function to use. Calling this function - * with a NULL function pointer will deregister any existing - * registered callback. - * - * @param userdata Data to be passed back when calling the callback - * function. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_set_error_callback(ILCLIENT_T *handle, - ILCLIENT_CALLBACK_T func, - void *userdata); - -/** - * The ilclient_set_configchanged_callback() function - * registers a callback to be used when an - * OMX_EventParamOrConfigChanged event occurs. When the - * event is received, a pointer to the component structure and the - * index value that has changed are reported by the callback. The - * user may then use an OMX_GetConfig call with the index - * as specified to retrieve the updated information. - * - * @param handle The client handle - * - * @param func The callback function to use. Calling this function - * with a NULL function pointer will deregister any existing - * registered callback. - * - * @param userdata Data to be passed back when calling the callback - * function. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_set_configchanged_callback(ILCLIENT_T *handle, - ILCLIENT_CALLBACK_T func, - void *userdata); - - -/** - * The ilclient_set_fill_buffer_done_callback() function registers a - * callback to be used when a buffer passed to an output port using the - * OMX_FillBuffer call is returned with the OMX_FillBufferDone - * callback. When the event is received, a pointer to the component - * structure is returned by the callback. The user may then use the - * ilclient_get_output_buffer() function to retrieve the buffer. - * - * @param handle The client handle - * - * @param func The callback function to use. Calling this function - * with a NULL function pointer will deregister any existing - * registered callback. - * - * @param userdata Data to be passed back when calling the callback - * function. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_set_fill_buffer_done_callback(ILCLIENT_T *handle, - ILCLIENT_BUFFER_CALLBACK_T func, - void *userdata); - -/** - * The ilclient_set_empty_buffer_done_callback() function registers a - * callback to be used when a buffer passed to an input port using the - * OMX_EmptyBuffer call is returned with the OMX_EmptyBufferDone - * callback. When the event is received, a pointer to the component - * structure is returned by the callback. The user may then use the - * ilclient_get_input_buffer() function to retrieve the buffer. - * - * @param handle The client handle - * - * @param func The callback function to use. Calling this function - * with a NULL function pointer will deregister any existing - * registered callback. - * - * @param userdata Data to be passed back when calling the callback - * function. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_set_empty_buffer_done_callback(ILCLIENT_T *handle, - ILCLIENT_BUFFER_CALLBACK_T func, - void *userdata); - - -/** - * Components are created using the ilclient_create_component() - * function. - * - * @param handle The client handle - * - * @param comp On successful creation, the component structure pointer - * will be written back into comp. - * - * @param name The name of the component to be created. Component - * names as provided are automatically prefixed with - * "OMX.broadcom." before passing to the IL core. The name - * provided will also be used in debugging messages added about this - * component. - * - * @param flags The client can specify some creation behaviour by using - * the flags field. The meaning of each flag is defined - * by the ILCLIENT_CREATE_FLAGS_T type. - * - * @return 0 on success, -1 on failure - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_create_component(ILCLIENT_T *handle, - COMPONENT_T **comp, - char *name, - ILCLIENT_CREATE_FLAGS_T flags); - -/** - * The ilclient_cleanup_components() function deallocates all - * state associated with components and frees the OpenMAX component - * handles. All tunnels connecting components should have been torn - * down explicitly, and all components must be in loaded state. - * - * @param list A null-terminated list of component pointers to be - * deallocated. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_cleanup_components(COMPONENT_T *list[]); - - -/** - * The ilclient_change_component_state() function changes the - * state of an individual component. This will trigger the state - * change, and also wait for that state change to be completed. It - * should not be called if this state change has dependencies on other - * components also changing states. Trying to change a component to - * its current state is treated as success. - * - * @param comp The component to change. - * - * @param state The new state to transition to. - * - * @return 0 on success, -1 on failure. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_change_component_state(COMPONENT_T *comp, - OMX_STATETYPE state); - - -/** - * The ilclient_state_transition() function transitions a set of - * components that need to perform a simultaneous state transition; - * for example, when two components are tunnelled and the buffer - * supplier port needs to allocate and pass buffers to a non-supplier - * port. All components are sent a command to change state, then the - * function will wait for all components to signal that they have - * changed state. - * - * @param list A null-terminated list of component pointers. - * - * @param state The new state to which to transition all components. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_state_transition(COMPONENT_T *list[], - OMX_STATETYPE state); - - -/** - * The ilclient_disable_port() function disables a port on a - * given component. This function sends the disable port message to - * the component and waits for the component to signal that this has - * taken place. If the port is already disabled, this is treated as a - * sucess. - * - * @param comp The component containing the port to disable. - * - * @param portIndex The port index of the port to disable. This must - * be a named port index, rather than a OMX_ALL value. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_disable_port(COMPONENT_T *comp, - int portIndex); - - -/** - * The ilclient_enable_port() function enables a port on a - * given component. This function sends the enable port message to - * the component and waits for the component to signal that this has - * taken place. If the port is already disabled, this is treated as a - * sucess. - * - * @param comp The component containing the port to enable. - * - * @param portIndex The port index of the port to enable. This must - * be a named port index, rather than a OMX_ALL value. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_enable_port(COMPONENT_T *comp, - int portIndex); - - - -/** - * The ilclient_enable_port_buffers() function enables a port - * in base profile mode on a given component. The port is not - * tunneled, so requires buffers to be allocated. - * - * @param comp The component containing the port to enable. - * - * @param portIndex The port index of the port to enable. This must - * be a named port index, rather than a OMX_ALL value. - * - * @param ilclient_malloc This function will be used to allocate - * buffer payloads. If NULL then - * vcos_malloc_aligned will be used. - * - * @param ilclient_free If an error occurs, this function is used to - * free previously allocated payloads. If NULL then - * vcos_free will be used. - * - * @param userdata The first argument to calls to - * ilclient_malloc and ilclient_free, if these - * arguments are not NULL. - * - * @return 0 indicates success. -1 indicates failure. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_enable_port_buffers(COMPONENT_T *comp, - int portIndex, - ILCLIENT_MALLOC_T ilclient_malloc, - ILCLIENT_FREE_T ilclient_free, - void *userdata); - - -/** - * The ilclient_disable_port_buffers() function disables a - * port in base profile mode on a given component. The port is not - * tunneled, and has been supplied with buffers by the client. - * - * @param comp The component containing the port to disable. - * - * @param portIndex The port index of the port to disable. This must - * be a named port index, rather than a OMX_ALL value. - * - * @param bufferList A list of buffers, using pAppPrivate - * as the next pointer that were allocated on this port, and currently - * held by the application. If buffers on this port are held by IL - * client or the component then these are automatically freed. - * - * @param ilclient_free This function is used to free the buffer payloads. - * If NULL then vcos_free will be used. - * - * @param userdata The first argument to calls to - * ilclient_free. - * - * @return void - */ -VCHPRE_ void VCHPOST_ ilclient_disable_port_buffers(COMPONENT_T *comp, - int portIndex, - OMX_BUFFERHEADERTYPE *bufferList, - ILCLIENT_FREE_T ilclient_free, - void *userdata); - - -/** - * With a populated tunnel structure, the - * ilclient_setup_tunnel() function connects the tunnel. It - * first transitions the source component to idle if currently in - * loaded state, and then optionally checks the source event list for - * a port settings changed event from the source port. If this event - * is not in the event queue then this function optionally waits for - * it to arrive. To disable this check for the port settings changed - * event, set timeout to zero. - * - * Both ports are then disabled, and the source port is inspected for - * a port streams parameter. If this is supported, then the - * portStream argument is used to select which port stream - * to use. The two ports are then tunnelled using the - * OMX_SetupTunnel function. If this is successful, then - * both ports are enabled. Note that for disabling and enabling the - * tunnelled ports, the functions ilclient_disable_tunnel() - * and ilclient_enable_tunnel() are used, so the relevant - * documentation for those functions applies here. - * - * @param tunnel The tunnel structure representing the tunnel to - * set up. - * - * @param portStream If port streams are supported on the output port - * of the tunnel, then this parameter indicates the port stream to - * select on this port. - * - * @param timeout The time duration in milliseconds to wait for the - * output port to signal a port settings changed event before - * returning a timeout failure. If this is 0, then we do not check - * for a port settings changed before setting up the tunnel. - * - * @return 0 indicates success, negative indicates failure: - * - -1: a timeout waiting for the parameter changed - * - -2: an error was returned instead of parameter changed - * - -3: no streams are available from this port - * - -4: requested stream is not available from this port - * - -5: the data format was not acceptable to the sink - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_setup_tunnel(TUNNEL_T *tunnel, - unsigned int portStream, - int timeout); - - -/** - * The ilclient_disable_tunnel() function disables both ports listed in - * the tunnel structure. It will send a port disable command to each - * port, then waits for both to indicate they have completed the - * transition. The errors OMX_ErrorPortUnpopulated and - * OMX_ErrorSameState are both ignored by this function; the former - * since the first port to disable may deallocate buffers before the - * second port has been disabled, leading to the second port reporting - * the unpopulated error. - * - * @param tunnel The tunnel to disable. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_disable_tunnel(TUNNEL_T *tunnel); - - -/** - * The ilclient_enable_tunnel() function enables both ports listed in - * the tunnel structure. It will first send a port enable command to - * each port. It then checks whether the sink component is not in - * loaded state - if so, the function waits for both ports to complete - * the requested port enable. If the sink component was in loaded - * state, then this component is transitioned to idle to allow the - * ports to exchange buffers and enable the ports. This is since - * typically this function is used when creating a tunnel between two - * components, where the source component is processing data to enable - * it to report the port settings changed event, and the sink port has - * yet to be used. Before transitioning the sink component to idle, - * this function waits for the sink port to be enabled - since the - * component is in loaded state, this will happen quickly. If the - * transition to idle fails, the sink component is transitioned back - * to loaded and the source port disabled. If the transition - * succeeds, the function then waits for the source port to complete - * the requested port enable. - * - * @param tunnel The tunnel to enable. - * - * @return 0 on success, -1 on failure. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_enable_tunnel(TUNNEL_T *tunnel); - - -/** - * The ilclient_flush_tunnels() function will flush a number of tunnels - * from the list of tunnels presented. For each tunnel that is to be - * flushed, both source and sink ports are sent a flush command. The - * function then waits for both ports to report they have completed - * the flush operation. - * - * @param tunnel List of tunnels. The list must be terminated with a - * tunnel structure with NULL component entries. - * - * @param max The maximum number of tunnels to flush from the list. - * A value of 0 indicates that all tunnels in the list are flushed. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_flush_tunnels(TUNNEL_T *tunnel, - int max); - - -/** - * The ilclient_teardown_tunnels() function tears down all tunnels in - * the list of tunnels presented. For each tunnel in the list, the - * OMX_SetupTunnel is called on the source port and on the sink port, - * where for both calls the destination component is NULL and the - * destination port is zero. The VMCSX IL implementation requires - * that all tunnels are torn down in this manner before components are - * freed. - * - * @param tunnels List of tunnels to teardown. The list must be - * terminated with a tunnel structure with NULL component entries. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_teardown_tunnels(TUNNEL_T *tunnels); - - -/** - * The ilclient_get_output_buffer() function returns a buffer - * that was sent to an output port and that has been returned from a - * component using the OMX_FillBufferDone callback. - * - * @param comp The component that returned the buffer. - * - * @param portIndex The port index on the component that the buffer - * was returned from. - * - * @param block If non-zero, the function will block until a buffer is available. - * - * @return Pointer to buffer if available, otherwise NULL. - ***********************************************************/ -VCHPRE_ OMX_BUFFERHEADERTYPE* VCHPOST_ ilclient_get_output_buffer(COMPONENT_T *comp, - int portIndex, - int block); - - -/** - * The ilclient_get_input_buffer() function returns a buffer - * that was sent to an input port and that has been returned from a - * component using the OMX_EmptyBufferDone callback. - * - * @param comp The component that returned the buffer. - * - * @param portIndex The port index on the component from which the buffer - * was returned. - * - * @param block If non-zero, the function will block until a buffer is available. - * - * @return pointer to buffer if available, otherwise NULL - ***********************************************************/ -VCHPRE_ OMX_BUFFERHEADERTYPE* VCHPOST_ ilclient_get_input_buffer(COMPONENT_T *comp, - int portIndex, - int block); - - -/** - * The ilclient_remove_event() function queries the event list for the - * given component, matching against the given criteria. If a matching - * event is found, it is removed and added to the free event list. - * - * @param comp The component that returned the matching event. - * - * @param event The event type of the matching event. - * - * @param nData1 The nData1 field of the matching event. - * - * @param ignore1 Whether to ignore the nData1 field when finding a - * matching event. A value of 0 indicates that nData1 must match, a - * value of 1 indicates that nData1 does not have to match. - * - * @param nData2 The nData2 field of the matching event. - * - * @param ignore2 Whether to ignore the nData2 field when finding a - * matching event. A value of 0 indicates that nData2 must match, a - * value of 1 indicates that nData2 does not have to match. - * - * @return 0 if the event was removed. -1 if no matching event was - * found. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_remove_event(COMPONENT_T *comp, - OMX_EVENTTYPE event, - OMX_U32 nData1, - int ignore1, - OMX_U32 nData2, - int ignore2); - - -/** - * The ilclient_return_events() function removes all events - * from a component event list and adds them to the IL client free - * event list. This function is automatically called when components - * are freed. - * - * @param comp The component from which all events should be moved to - * the free list. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_return_events(COMPONENT_T *comp); - - -/** - * The ilclient_wait_for_event() function is similar to - * ilclient_remove_event(), but allows the caller to block until that - * event arrives. - * - * @param comp The component that returned the matching event. - * - * @param event The event type of the matching event. - * - * @param nData1 The nData1 field of the matching event. - * - * @param ignore1 Whether to ignore the nData1 field when finding a - * matching event. A value of 0 indicates that nData1 must match, a - * value of 1 indicates that nData1 does not have to match. - * - * @param nData2 The nData2 field of the matching event. - * - * @param ignore2 Whether to ignore the nData2 field when finding a - * matching event. A value of 0 indicates that nData2 must match, a - * value of 1 indicates that nData2 does not have to match. - * - * @param event_flag Specifies a bitfield of IL client events to wait - * for, given in ILEVENT_MASK_T. If any of these events - * are signalled by the component, the event list is then re-checked - * for a matching event. If the ILCLIENT_EVENT_ERROR bit - * is included, and an error is signalled by the component, then the - * function will return an error code. If the - * ILCLIENT_CONFIG_CHANGED bit is included, and this bit is - * signalled by the component, then the function will return an error - * code. - * - * @param timeout Specifies how long to block for in milliseconds - * before returning a failure. - * - * @return 0 indicates success, a matching event has been removed from - * the component's event queue. A negative return indicates failure, - * in this case no events have been removed from the component's event - * queue. - * - -1: a timeout was received. - * - -2: an error event was received. - * - -3: a config changed event was received. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_wait_for_event(COMPONENT_T *comp, - OMX_EVENTTYPE event, - OMX_U32 nData1, - int ignore1, - OMX_U32 nData2, - int ignore2, - int event_flag, - int timeout); - - -/** - * The ilclient_wait_for_command_complete() function waits - * for a message from a component that indicates that the command - * has completed. This is either a command success message, or an - * error message that signals the completion of an event. - * - * @param comp The component currently processing a command. - * - * @param command The command being processed. This must be either - * OMX_CommandStateSet, OMX_CommandPortDisable - * or OMX_CommandPortEnable. - * - * @param nData2 The expected value of nData2 in the - * command complete message. - * - * @return 0 indicates success, either the command successfully completed - * or the OMX_ErrorSameState was returned. -1 indicates - * that the command terminated with a different error message. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_wait_for_command_complete(COMPONENT_T *comp, - OMX_COMMANDTYPE command, - OMX_U32 nData2); - - -/** - * The ilclient_wait_for_command_complete_dual() function - * is similar to ilclient_wait_for_command_complete(). The - * difference is that while waiting for the component to complete the - * event or raise an error, we can also report if another reports an - * error that terminates a command. This is useful if the two - * components are tunneled, and we need to wait for one component to - * enable a port, or change state to OMX_StateIdle. If the - * other component is the buffer supplier and reports an error, then - * it will not allocate buffers, so our first component may stall. - * - * @param comp The component currently processing a command. - * - * @param command The command being processed. This must be either - * OMX_CommandStateSet, OMX_CommandPortDisable - * or OMX_CommandPortEnable. - * - * @param nData2 The expected value of nData2 in the - * command complete message. - * - * @param related Another component, where we will return if this - * component raises an error that terminates a command. - * - * @return 0 indicates success, either the command successfully - * completed or the OMX_ErrorSameState was returned. -1 - * indicates that the command terminated with a different error - * message. -2 indicates that the related component raised an error. - * In this case, the error is not cleared from the related - * component's event list. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_wait_for_command_complete_dual(COMPONENT_T *comp, - OMX_COMMANDTYPE command, - OMX_U32 nData2, - COMPONENT_T *related); - - -/** - * The ilclient_debug_output() function adds a message to a - * host-specific debug display. For a local VideoCore host the message is - * added to the internal message log. For a Win32 host the message is - * printed to the debug display. This function should be customised - * when IL client is ported to another platform. - * - * @param format A message to add, together with the variable - * argument list similar to printf and other standard C functions. - * - * @return void - ***********************************************************/ -VCHPRE_ void VCHPOST_ ilclient_debug_output(char *format, ...); - -/** - * The ilclient_get_handle() function returns the - * underlying OMX component held by an IL component handle. This is - * needed when calling methods such as OMX_SetParameter on - * a component created using the IL client library. - * - * @param comp IL component handle - * - * @return The OMX_HANDLETYPE value for the component. - ***********************************************************/ -VCHPRE_ OMX_HANDLETYPE VCHPOST_ ilclient_get_handle(COMPONENT_T *comp); - - -#ifndef OMX_SKIP64BIT - -/** - * Macro to return OMX_TICKS from a signed 64 bit value. - * This is the version where OMX_TICKS is a signed 64 bit - * value, an alternative definition is used when OMX_TICKS - * is a structure. - */ -#define ilclient_ticks_from_s64(s) (s) - -/** - * Macro to return signed 64 bit value from OMX_TICKS. - * This is the version where OMX_TICKS is a signed 64 bit - * value, an alternative definition is used when OMX_TICKS - * is a structure. - */ -#define ilclient_ticks_to_s64(t) (t) - -#else - -/** - * Inline function to return OMX_TICKS from a signed 64 bit - * value. This is the version where OMX_TICKS is a - * structure, an alternative definition is used when - * OMX_TICKS is a signed 64 bit value. - */ -static inline OMX_TICKS ilclient_ticks_from_s64(int64_t s) { - OMX_TICKS ret; - ret.nLowPart = s; - ret.nHighPart = s>>32; - return ret; -} - -/** - * Inline function to return signed 64 bit value from - * OMX_TICKS. This is the version where - * OMX_TICKS is a structure, an alternative definition is - * used when OMX_TICKS is a signed 64 bit value. - */ -static inline int64_t ilclient_ticks_to_s64(OMX_TICKS t) { - uint64_t u = t.nLowPart | ((uint64_t)t.nHighPart << 32); - return u; -} - - -#endif /* OMX_SKIP64BIT */ - -/** - * The ilclient_get_port_index() function returns the n'th - * port index of the specified type and direction for the given - * component. - * - * @param comp The component of interest - * @param dir The direction - * @param type The type, or -1 for any type. - * @param index Which port (counting from 0). - * - * @return The port index, or -1 if not found. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_get_port_index(COMPONENT_T *comp, - OMX_DIRTYPE dir, - OMX_PORTDOMAINTYPE type, - int index); - - -/** - * The ilclient_suggest_bufsize() function gives a - * component a hint about the size of buffer it should use. This size - * is set on the component by setting the - * OMX_IndexParamBrcmOutputBufferSize index on the given - * component. - * - * @param comp IL component handle - * @param nBufSizeHint Size of buffer in bytes - * - * @return 0 indicates success, -1 indicates failure. - ***********************************************************/ -VCHPRE_ int VCHPOST_ ilclient_suggest_bufsize(COMPONENT_T *comp, - OMX_U32 nBufSizeHint); - - -/** - * The ilclient_stack_size() function suggests a minimum - * stack size that tasks calling into with API will require. - * - * @return Suggested stack size in bytes. - ***********************************************************/ -VCHPRE_ unsigned int VCHPOST_ ilclient_stack_size(void); - -#endif /* ILCLIENT_H */ diff --git a/third_party/ilclient/ilcore.c b/third_party/ilclient/ilcore.c deleted file mode 100644 index ebf3294c8..000000000 --- a/third_party/ilclient/ilcore.c +++ /dev/null @@ -1,308 +0,0 @@ -/* -Copyright (c) 2012, Broadcom Europe Ltd -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - * \file - * - * \brief Host core implementation. - */ - -#include -#include - -//includes -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -static int coreInit = 0; -static int nActiveHandles = 0; -static ILCS_SERVICE_T *ilcs_service = NULL; -static VCOS_MUTEX_T lock; -static VCOS_ONCE_T once = VCOS_ONCE_INIT; - -/* Atomic creation of lock protecting shared state */ -static void initOnce(void) -{ - VCOS_STATUS_T status; - status = vcos_mutex_create(&lock, VCOS_FUNCTION); - vcos_demand(status == VCOS_SUCCESS); -} - -/* OMX_Init */ -OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void) -{ - VCOS_STATUS_T status; - OMX_ERRORTYPE err = OMX_ErrorNone; - - status = vcos_once(&once, initOnce); - vcos_demand(status == VCOS_SUCCESS); - - vcos_mutex_lock(&lock); - - if(coreInit == 0) - { - // we need to connect via an ILCS connection to VideoCore - VCHI_INSTANCE_T initialise_instance; - VCHI_CONNECTION_T *connection; - ILCS_CONFIG_T config; - - vc_host_get_vchi_state(&initialise_instance, &connection); - - vcilcs_config(&config); - - ilcs_service = ilcs_init((VCHIQ_INSTANCE_T) initialise_instance, (void **) &connection, &config, 0); - - if(ilcs_service == NULL) - { - err = OMX_ErrorHardware; - goto end; - } - - coreInit = 1; - } - else - coreInit++; - -end: - vcos_mutex_unlock(&lock); - return err; -} - -/* OMX_Deinit */ -OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void) -{ - if(coreInit == 0) // || (coreInit == 1 && nActiveHandles > 0)) - return OMX_ErrorNotReady; - - vcos_mutex_lock(&lock); - - coreInit--; - - if(coreInit == 0) - { - // we need to teardown the ILCS connection to VideoCore - ilcs_deinit(ilcs_service); - ilcs_service = NULL; - } - - vcos_mutex_unlock(&lock); - - return OMX_ErrorNone; -} - - -/* OMX_ComponentNameEnum */ -OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum( - OMX_OUT OMX_STRING cComponentName, - OMX_IN OMX_U32 nNameLength, - OMX_IN OMX_U32 nIndex) -{ - if(ilcs_service == NULL) - return OMX_ErrorBadParameter; - - return vcil_out_component_name_enum(ilcs_get_common(ilcs_service), cComponentName, nNameLength, nIndex); -} - - -/* OMX_GetHandle */ -OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle( - OMX_OUT OMX_HANDLETYPE* pHandle, - OMX_IN OMX_STRING cComponentName, - OMX_IN OMX_PTR pAppData, - OMX_IN OMX_CALLBACKTYPE* pCallBacks) -{ - OMX_ERRORTYPE eError; - OMX_COMPONENTTYPE *pComp; - OMX_HANDLETYPE hHandle = 0; - - if (pHandle == NULL || cComponentName == NULL || pCallBacks == NULL || ilcs_service == NULL) - { - if(pHandle) - *pHandle = NULL; - return OMX_ErrorBadParameter; - } - - { - pComp = (OMX_COMPONENTTYPE *)malloc(sizeof(OMX_COMPONENTTYPE)); - if (!pComp) - { - vcos_assert(0); - return OMX_ErrorInsufficientResources; - } - memset(pComp, 0, sizeof(OMX_COMPONENTTYPE)); - hHandle = (OMX_HANDLETYPE)pComp; - pComp->nSize = sizeof(OMX_COMPONENTTYPE); - pComp->nVersion.nVersion = OMX_VERSION; - eError = vcil_out_create_component(ilcs_get_common(ilcs_service), hHandle, cComponentName); - - if (eError == OMX_ErrorNone) { - // Check that all function pointers have been filled in. - // All fields should be non-zero. - int i; - uint32_t *p = (uint32_t *) pComp; - for(i=0; i>2; i++) - if(*p++ == 0) - eError = OMX_ErrorInvalidComponent; - - if(eError != OMX_ErrorNone && pComp->ComponentDeInit) - pComp->ComponentDeInit(hHandle); - } - - if (eError == OMX_ErrorNone) { - eError = pComp->SetCallbacks(hHandle,pCallBacks,pAppData); - if (eError != OMX_ErrorNone) - pComp->ComponentDeInit(hHandle); - } - if (eError == OMX_ErrorNone) { - *pHandle = hHandle; - } - else { - *pHandle = NULL; - free(pComp); - } - } - - if (eError == OMX_ErrorNone) { - vcos_mutex_lock(&lock); - nActiveHandles++; - vcos_mutex_unlock(&lock); - } - - return eError; -} - -/* OMX_FreeHandle */ -OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle( - OMX_IN OMX_HANDLETYPE hComponent) -{ - OMX_ERRORTYPE eError = OMX_ErrorNone; - OMX_COMPONENTTYPE *pComp; - - if (hComponent == NULL || ilcs_service == NULL) - return OMX_ErrorBadParameter; - - pComp = (OMX_COMPONENTTYPE*)hComponent; - - if (ilcs_service == NULL) - return OMX_ErrorBadParameter; - - eError = (pComp->ComponentDeInit)(hComponent); - if (eError == OMX_ErrorNone) { - vcos_mutex_lock(&lock); - --nActiveHandles; - vcos_mutex_unlock(&lock); - free(pComp); - } - - vcos_assert(nActiveHandles >= 0); - - return eError; -} - -/* OMX_SetupTunnel */ -OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel( - OMX_IN OMX_HANDLETYPE hOutput, - OMX_IN OMX_U32 nPortOutput, - OMX_IN OMX_HANDLETYPE hInput, - OMX_IN OMX_U32 nPortInput) -{ - OMX_ERRORTYPE eError = OMX_ErrorNone; - OMX_COMPONENTTYPE *pCompIn, *pCompOut; - OMX_TUNNELSETUPTYPE oTunnelSetup; - - if ((hOutput == NULL && hInput == NULL) || ilcs_service == NULL) - return OMX_ErrorBadParameter; - - oTunnelSetup.nTunnelFlags = 0; - oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified; - - pCompOut = (OMX_COMPONENTTYPE*)hOutput; - - if (hOutput){ - eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup); - } - - if (eError == OMX_ErrorNone && hInput) { - pCompIn = (OMX_COMPONENTTYPE*)hInput; - eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup); - - if (eError != OMX_ErrorNone && hOutput) { - /* cancel tunnel request on output port since input port failed */ - pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL); - } - } - return eError; -} - -/* OMX_GetComponentsOfRole */ -OMX_ERRORTYPE OMX_GetComponentsOfRole ( - OMX_IN OMX_STRING role, - OMX_INOUT OMX_U32 *pNumComps, - OMX_INOUT OMX_U8 **compNames) -{ - OMX_ERRORTYPE eError = OMX_ErrorNone; - - *pNumComps = 0; - return eError; -} - -/* OMX_GetRolesOfComponent */ -OMX_ERRORTYPE OMX_GetRolesOfComponent ( - OMX_IN OMX_STRING compName, - OMX_INOUT OMX_U32 *pNumRoles, - OMX_OUT OMX_U8 **roles) -{ - OMX_ERRORTYPE eError = OMX_ErrorNone; - - *pNumRoles = 0; - return eError; -} - -/* OMX_GetDebugInformation */ -OMX_ERRORTYPE OMX_GetDebugInformation ( - OMX_OUT OMX_STRING debugInfo, - OMX_INOUT OMX_S32 *pLen) -{ - if(ilcs_service == NULL) - return OMX_ErrorBadParameter; - - return vcil_out_get_debug_information(ilcs_get_common(ilcs_service), debugInfo, pLen); -} - - - -/* File EOF */ - diff --git a/third_party/inih b/third_party/inih deleted file mode 160000 index 1d07c4790..000000000 --- a/third_party/inih +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1d07c4790659fa39af7b662438dd73ed1a97e0b5 diff --git a/third_party/libuuid/Makemodule.am b/third_party/libuuid/Makemodule.am deleted file mode 100644 index 166be5c26..000000000 --- a/third_party/libuuid/Makemodule.am +++ /dev/null @@ -1,10 +0,0 @@ -if BUILD_LIBUUID - -include libuuid/man/Makemodule.am -include libuuid/src/Makemodule.am - -pkgconfig_DATA += libuuid/uuid.pc -PATHFILES += libuuid/uuid.pc -EXTRA_DIST += libuuid/COPYING - -endif # BUILD_LIBUUID diff --git a/third_party/libuuid/libuuid_stub.a b/third_party/libuuid/libuuid_stub.a new file mode 100644 index 000000000..1193db3ed Binary files /dev/null and b/third_party/libuuid/libuuid_stub.a differ diff --git a/third_party/libuuid/man/.gitignore b/third_party/libuuid/man/.gitignore deleted file mode 100644 index 7957ad2cc..000000000 --- a/third_party/libuuid/man/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -uuid_generate_random.3 -uuid_generate_time.3 -uuid_generate_time_safe.3 diff --git a/third_party/libuuid/man/Makemodule.am b/third_party/libuuid/man/Makemodule.am deleted file mode 100644 index 81287d5c7..000000000 --- a/third_party/libuuid/man/Makemodule.am +++ /dev/null @@ -1,14 +0,0 @@ - -dist_man_MANS += \ - libuuid/man/uuid.3 \ - libuuid/man/uuid_clear.3 \ - libuuid/man/uuid_compare.3 \ - libuuid/man/uuid_copy.3 \ - libuuid/man/uuid_generate.3 \ - libuuid/man/uuid_is_null.3 \ - libuuid/man/uuid_parse.3 \ - libuuid/man/uuid_time.3 \ - libuuid/man/uuid_unparse.3 \ - libuuid/man/uuid_generate_random.3 \ - libuuid/man/uuid_generate_time.3 \ - libuuid/man/uuid_generate_time_safe.3 diff --git a/third_party/libuuid/man/uuid.3 b/third_party/libuuid/man/uuid.3 deleted file mode 100644 index 37b04995e..000000000 --- a/third_party/libuuid/man/uuid.3 +++ /dev/null @@ -1,65 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid \- DCE compatible Universally Unique Identifier library -.SH SYNOPSIS -.B #include -.SH DESCRIPTION -The UUID library is used to generate unique identifiers for objects -that may be accessible beyond the local system. This library -generates UUIDs compatible with those created by the Open Software -Foundation (OSF) Distributed Computing Environment (DCE) utility -.BR uuidgen . -.sp -The UUIDs generated by this library can be reasonably expected to be -unique within a system, and unique across all systems. They could -be used, for instance, to generate unique HTTP cookies across multiple -web servers without communication between the servers, and without fear -of a name clash. -.SH "CONFORMING TO" -OSF DCE 1.1 -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.SH "SEE ALSO" -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_is_null (3), -.BR uuid_parse (3), -.BR uuid_time (3), -.BR uuid_unparse (3) diff --git a/third_party/libuuid/man/uuid_clear.3 b/third_party/libuuid/man/uuid_clear.3 deleted file mode 100644 index 70fca02b7..000000000 --- a/third_party/libuuid/man/uuid_clear.3 +++ /dev/null @@ -1,62 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_CLEAR 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_clear \- reset value of UUID variable to the NULL value -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "void uuid_clear(uuid_t " uu ); -.fi -.SH DESCRIPTION -The -.B uuid_clear -function sets the value of the supplied uuid variable -.I uu -to the NULL value. -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_is_null (3), -.BR uuid_parse (3), -.BR uuid_unparse (3) -.ad diff --git a/third_party/libuuid/man/uuid_compare.3 b/third_party/libuuid/man/uuid_compare.3 deleted file mode 100644 index f91181a4e..000000000 --- a/third_party/libuuid/man/uuid_compare.3 +++ /dev/null @@ -1,68 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_COMPARE 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_compare \- compare whether two UUIDs are the same -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "int uuid_compare(uuid_t " uu1 ", uuid_t " uu2) -.fi -.SH DESCRIPTION -The -.B uuid_compare -function compares the two supplied uuid variables -.IR uu1 " and " uu2 -to each other. -.SH RETURN VALUE -Returns an integer less than, equal to, or greater than zero if -.I uu1 -is found, respectively, to be lexicographically less than, equal, or -greater than -.IR uu2 . -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_clear (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_is_null (3), -.BR uuid_parse (3), -.BR uuid_unparse (3) -.ad diff --git a/third_party/libuuid/man/uuid_copy.3 b/third_party/libuuid/man/uuid_copy.3 deleted file mode 100644 index 5159fa662..000000000 --- a/third_party/libuuid/man/uuid_copy.3 +++ /dev/null @@ -1,64 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_COPY 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_copy \- copy a UUID value -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "void uuid_copy(uuid_t " dst ", uuid_t " src); -.fi -.SH DESCRIPTION -The -.B uuid_copy -function copies the UUID variable -.IR src " to " dst . -.SH RETURN VALUE -The copied UUID is returned in the location pointed to by -.IR dst . -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_generate (3), -.BR uuid_is_null (3), -.BR uuid_parse (3), -.BR uuid_unparse (3) -.ad diff --git a/third_party/libuuid/man/uuid_generate.3 b/third_party/libuuid/man/uuid_generate.3 deleted file mode 100644 index 19904d7de..000000000 --- a/third_party/libuuid/man/uuid_generate.3 +++ /dev/null @@ -1,126 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_GENERATE 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_generate, uuid_generate_random, uuid_generate_time, -uuid_generate_time_safe \- create a new unique UUID value -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "void uuid_generate(uuid_t " out ); -.BI "void uuid_generate_random(uuid_t " out ); -.BI "void uuid_generate_time(uuid_t " out ); -.BI "int uuid_generate_time_safe(uuid_t " out ); -.fi -.SH DESCRIPTION -The -.B uuid_generate -function creates a new universally unique identifier (UUID). The uuid will -be generated based on high-quality randomness from -.IR /dev/urandom , -if available. If it is not available, then -.B uuid_generate -will use an alternative algorithm which uses the current time, the -local ethernet MAC address (if available), and random data generated -using a pseudo-random generator. -.sp -The -.B uuid_generate_random -function forces the use of the all-random UUID format, even if -a high-quality random number generator (i.e., -.IR /dev/urandom ) -is not available, in which case a pseudo-random -generator will be substituted. Note that the use of a pseudo-random -generator may compromise the uniqueness of UUIDs -generated in this fashion. -.sp -The -.B uuid_generate_time -function forces the use of the alternative algorithm which uses the -current time and the local ethernet MAC address (if available). -This algorithm used to be the default one used to generate UUID, but -because of the use of the ethernet MAC address, it can leak -information about when and where the UUID was generated. This can cause -privacy problems in some applications, so the -.B uuid_generate -function only uses this algorithm if a high-quality source of -randomness is not available. To guarantee uniqueness of UUIDs generated -by concurrently running processes, the uuid library uses global -clock state counter (if the process has permissions to gain exclusive access -to this file) and/or the -.B uuidd -daemon, if it is running already or can be spawned by the process (if -installed and the process has enough permissions to run it). If neither of -these two synchronization mechanisms can be used, it is theoretically possible -that two concurrently running processes obtain the same UUID(s). To tell -whether the UUID has been generated in a safe manner, use -.BR uuid_generate_time_safe . -.sp -The -.B uuid_generate_time_safe -is similar to -.BR uuid_generate_time , -except that it returns a value which denotes whether any of the synchronization -mechanisms (see above) has been used. -.sp -The UUID is 16 bytes (128 bits) long, which gives approximately 3.4x10^38 -unique values (there are approximately 10^80 elementary particles in -the universe according to Carl Sagan's -.IR Cosmos ). -The new UUID can reasonably be considered unique among all UUIDs created -on the local system, and among UUIDs created on other systems in the past -and in the future. -.SH RETURN VALUE -The newly created UUID is returned in the memory location pointed to by -.IR out . -.B uuid_generate_time_safe -returns zero if the UUID has been generated in a safe manner, \-1 otherwise. -.SH "CONFORMING TO" -OSF DCE 1.1 -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.SH "SEE ALSO" -.BR uuid (3), -.BR uuidgen (1), -.BR uuidd (8), -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_is_null (3), -.BR uuid_parse (3), -.BR uuid_time (3), -.BR uuid_unparse (3) diff --git a/third_party/libuuid/man/uuid_is_null.3 b/third_party/libuuid/man/uuid_is_null.3 deleted file mode 100644 index 86a7a50fe..000000000 --- a/third_party/libuuid/man/uuid_is_null.3 +++ /dev/null @@ -1,64 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_IS_NULL 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_is_null \- compare the value of the UUID to the NULL value -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "int uuid_is_null(uuid_t " uu ); -.fi -.SH DESCRIPTION -The -.B uuid_is_null -function compares the value of the supplied UUID variable -.I uu -to the NULL value. If the value is equal to the NULL UUID, 1 is returned, -otherwise 0 is returned. -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_time (3), -.BR uuid_parse (3), -.BR uuid_unparse (3) -.ad diff --git a/third_party/libuuid/man/uuid_parse.3 b/third_party/libuuid/man/uuid_parse.3 deleted file mode 100644 index 31a59267a..000000000 --- a/third_party/libuuid/man/uuid_parse.3 +++ /dev/null @@ -1,73 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_PARSE 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_parse \- convert an input UUID string into binary representation -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "int uuid_parse( char *" in ", uuid_t " uu ); -.fi -.SH DESCRIPTION -The -.B uuid_parse -function converts the UUID string given by -.I in -into the binary representation. The input UUID is a string of the form -1b4e28ba\-2fa1\-11d2\-883f\-b9a761bde3fb (in -.BR printf (3) -format "%08x\-%04x\-%04x\-%04x\-%012x", 36 bytes plus the trailing '\e0'). -.SH RETURN VALUE -Upon successfully parsing the input string, 0 is returned, and the UUID is -stored in the location pointed to by -.IR uu , -otherwise \-1 is returned. -.SH "CONFORMING TO" -OSF DCE 1.1 -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_is_null (3), -.BR uuid_time (3), -.BR uuid_unparse (3) -.ad diff --git a/third_party/libuuid/man/uuid_time.3 b/third_party/libuuid/man/uuid_time.3 deleted file mode 100644 index 483676b5b..000000000 --- a/third_party/libuuid/man/uuid_time.3 +++ /dev/null @@ -1,78 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_TIME 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_time \- extract the time at which the UUID was created -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "time_t uuid_time(uuid_t " uu ", struct timeval *" ret_tv ) -.fi -.SH DESCRIPTION -The -.B uuid_time -function extracts the time at which the supplied time-based UUID -.I uu -was created. Note that the UUID creation time is only encoded within -certain types of UUIDs. This function can only reasonably expect to -extract the creation time for UUIDs created with the -.BR uuid_generate_time (3) -and -.BR uuid_generate_time_safe (3) -functions. It may or may not work with UUIDs created by other mechanisms. -.SH "RETURN VALUES" -The time at which the UUID was created, in seconds since January 1, 1970 GMT -(the epoch), is returned (see -.BR time "(2))." -The time at which the UUID was created, in seconds and microseconds since -the epoch, is also stored in the location pointed to by -.I ret_tv -(see -.BR gettimeofday "(2))." -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_is_null (3), -.BR uuid_parse (3), -.BR uuid_unparse (3) -.ad diff --git a/third_party/libuuid/man/uuid_unparse.3 b/third_party/libuuid/man/uuid_unparse.3 deleted file mode 100644 index 1e0116d7a..000000000 --- a/third_party/libuuid/man/uuid_unparse.3 +++ /dev/null @@ -1,81 +0,0 @@ -.\" Copyright 1999 Andreas Dilger (adilger@enel.ucalgary.ca) -.\" -.\" %Begin-Header% -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, and the entire permission notice in its entirety, -.\" including the disclaimer of warranties. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote -.\" products derived from this software without specific prior -.\" written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -.\" WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF -.\" WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT -.\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -.\" USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH -.\" DAMAGE. -.\" %End-Header% -.\" -.\" Created Wed Mar 10 17:42:12 1999, Andreas Dilger -.TH UUID_UNPARSE 3 "May 2009" "util-linux" "Libuuid API" -.SH NAME -uuid_unparse \- convert an UUID from binary representation to a string -.SH SYNOPSIS -.nf -.B #include -.sp -.BI "void uuid_unparse(uuid_t " uu ", char *" out ); -.BI "void uuid_unparse_upper(uuid_t " uu ", char *" out ); -.BI "void uuid_unparse_lower(uuid_t " uu ", char *" out ); -.fi -.SH DESCRIPTION -The -.B uuid_unparse -function converts the supplied UUID -.I uu -from the binary representation into a 36-byte string (plus tailing '\e0') -of the form 1b4e28ba\-2fa1\-11d2\-883f\-0016d3cca427 and stores this -value in the character string pointed to by -.IR out . -The case of the hex digits returned by -.B uuid_unparse -may be upper or lower case, and is -dependent on the system-dependent local default. -.PP -If the case of the -hex digits is important then the functions -.B uuid_unparse_upper -and -.B uuid_unparse_lower -may be used. -.SH "CONFORMING TO" -OSF DCE 1.1 -.SH AUTHOR -Theodore Y.\& Ts'o -.SH AVAILABILITY -.B libuuid -is part of the util-linux package since version 2.15.1 and is available from -ftp://ftp.kernel.org/pub/linux/utils/util-linux/. -.na -.SH "SEE ALSO" -.BR uuid (3), -.BR uuid_clear (3), -.BR uuid_compare (3), -.BR uuid_copy (3), -.BR uuid_generate (3), -.BR uuid_time (3), -.BR uuid_is_null (3), -.BR uuid_parse (3) -.ad diff --git a/third_party/libuuid/src/Makemodule.am b/third_party/libuuid/src/Makemodule.am deleted file mode 100644 index d3fc81128..000000000 --- a/third_party/libuuid/src/Makemodule.am +++ /dev/null @@ -1,64 +0,0 @@ - -check_PROGRAMS += test_uuid_parser -test_uuid_parser_SOURCES = libuuid/src/test_uuid.c -test_uuid_parser_LDADD = $(LDADD) libuuid.la $(SOCKET_LIBS) -test_uuid_parser_CFLAGS = $(AM_CFLAGS) -I$(ul_libuuid_incdir) - -# includes -uuidincdir = $(includedir)/uuid -uuidinc_HEADERS = libuuid/src/uuid.h - -usrlib_exec_LTLIBRARIES += libuuid.la - -libuuid_la_SOURCES = \ - libuuid/src/clear.c \ - libuuid/src/compare.c \ - libuuid/src/copy.c \ - libuuid/src/gen_uuid.c \ - libuuid/src/isnull.c \ - libuuid/src/pack.c \ - libuuid/src/parse.c \ - libuuid/src/unpack.c \ - libuuid/src/unparse.c \ - libuuid/src/uuidd.h \ - libuuid/src/uuidd.h \ - libuuid/src/uuidP.h \ - libuuid/src/uuid_time.c \ - $(uuidinc_HEADERS) \ - lib/randutils.c - -libuuid_la_DEPENDENCIES = libuuid/src/libuuid.sym -libuuid_la_LIBADD = $(SOCKET_LIBS) - -libuuid_la_CFLAGS = \ - $(AM_CFLAGS) \ - $(SOLIB_CFLAGS) \ - -I$(ul_libuuid_incdir) \ - -Ilibuuid/src - -libuuid_la_LDFLAGS = $(SOLIB_LDFLAGS) -if HAVE_VSCRIPT -libuuid_la_LDFLAGS += libuuid_la_LDFLAGS += $(VSCRIPT_LDFLAGS),$(top_srcdir)/libuuid/src/libuuid.sym -endif -libuuid_la_LDFLAGS += -version-info $(LIBUUID_VERSION_INFO) - - -EXTRA_DIST += libuuid/src/libuuid.sym - -# move lib from $(usrlib_execdir) to $(libdir) if needed -install-exec-hook-libuuid: - if test "$(usrlib_execdir)" != "$(libdir)" -a -f "$(DESTDIR)$(usrlib_execdir)/libuuid.so"; then \ - $(MKDIR_P) $(DESTDIR)$(libdir); \ - mv $(DESTDIR)$(usrlib_execdir)/libuuid.so.* $(DESTDIR)$(libdir); \ - so_img_name=$$(readlink $(DESTDIR)$(usrlib_execdir)/libuuid.so); \ - so_img_rel_target=$$(echo $(usrlib_execdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ - (cd $(DESTDIR)$(usrlib_execdir) && \ - rm -f libuuid.so && \ - $(LN_S) $$so_img_rel_target$(libdir)/$$so_img_name libuuid.so); \ - fi - -uninstall-hook-libuuid: - rm -f $(DESTDIR)$(libdir)/libuuid.so* - -INSTALL_EXEC_HOOKS += install-exec-hook-libuuid -UNINSTALL_HOOKS += uninstall-hook-libuuid diff --git a/third_party/libuuid/src/clear.c b/third_party/libuuid/src/clear.c deleted file mode 100644 index 2d91fee93..000000000 --- a/third_party/libuuid/src/clear.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * clear.c -- Clear a UUID - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include "string.h" - -#include "uuidP.h" - -void uuid_clear(uuid_t uu) -{ - memset(uu, 0, 16); -} - diff --git a/third_party/libuuid/src/compare.c b/third_party/libuuid/src/compare.c deleted file mode 100644 index 8f3437a2d..000000000 --- a/third_party/libuuid/src/compare.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * compare.c --- compare whether or not two UUIDs are the same - * - * Returns 0 if the two UUIDs are different, and 1 if they are the same. - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include "uuidP.h" -#include - -#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); - -int uuid_compare(const uuid_t uu1, const uuid_t uu2) -{ - struct uuid uuid1, uuid2; - - uuid_unpack(uu1, &uuid1); - uuid_unpack(uu2, &uuid2); - - UUCMP(uuid1.time_low, uuid2.time_low); - UUCMP(uuid1.time_mid, uuid2.time_mid); - UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); - UUCMP(uuid1.clock_seq, uuid2.clock_seq); - return memcmp(uuid1.node, uuid2.node, 6); -} - diff --git a/third_party/libuuid/src/copy.c b/third_party/libuuid/src/copy.c deleted file mode 100644 index ead33aa26..000000000 --- a/third_party/libuuid/src/copy.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * copy.c --- copy UUIDs - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include "uuidP.h" - -void uuid_copy(uuid_t dst, const uuid_t src) -{ - unsigned char *cp1; - const unsigned char *cp2; - int i; - - for (i=0, cp1 = dst, cp2 = src; i < 16; i++) - *cp1++ = *cp2++; -} diff --git a/third_party/libuuid/src/gen_uuid.c b/third_party/libuuid/src/gen_uuid.c deleted file mode 100644 index 1882ae11a..000000000 --- a/third_party/libuuid/src/gen_uuid.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * gen_uuid.c --- generate a DCE-compatible uuid - * - * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#ifdef _WIN32 -#define _WIN32_WINNT 0x0500 -#include -#define UUID MYUUID -#endif -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#include -#ifdef HAVE_SYS_FILE_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_SYS_SOCKIO_H -#include -#endif -#ifdef HAVE_NET_IF_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_NET_IF_DL_H -#include -#endif -#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) -#include -#endif -#if defined(__vita__) -#include -#endif - -#include "uuidP.h" -#include "uuidd.h" - -#ifdef HAVE_TLS -#define THREAD_LOCAL static __thread -#else -#define THREAD_LOCAL static -#endif - -void random_get_bytes(void *buf, size_t sz) { - unsigned char *cbuf = buf; - int size = sz; - while (size > 0) { - int want = (size >= 0x40) ? 0x40 : size; - sceKernelGetRandomNumber(buf, want); - size -= want; - } -} - -#ifdef _WIN32 -static void gettimeofday (struct timeval *tv, void *dummy) -{ - FILETIME ftime; - uint64_t n; - - GetSystemTimeAsFileTime (&ftime); - n = (((uint64_t) ftime.dwHighDateTime << 32) - + (uint64_t) ftime.dwLowDateTime); - if (n) { - n /= 10; - n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000; - } - - tv->tv_sec = n / 1000000; - tv->tv_usec = n % 1000000; -} - -static int getuid (void) -{ - return 1; -} -#endif - -/* - * Get the ethernet hardware address, if we can find it... - * - * XXX for a windows version, probably should use GetAdaptersInfo: - * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451 - * commenting out get_node_id just to get gen_uuid to compile under windows - * is not the right way to go! - */ -static int get_node_id(unsigned char *node_id) -{ -#ifdef HAVE_NET_IF_H - int sd; - struct ifreq ifr, *ifrp; - struct ifconf ifc; - char buf[1024]; - int n, i; - unsigned char *a; -#ifdef HAVE_NET_IF_DL_H - struct sockaddr_dl *sdlp; -#endif - -/* - * BSD 4.4 defines the size of an ifreq to be - * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len - * However, under earlier systems, sa_len isn't present, so the size is - * just sizeof(struct ifreq) - */ -#ifdef HAVE_SA_LEN -#define ifreq_size(i) max(sizeof(struct ifreq),\ - sizeof((i).ifr_name)+(i).ifr_addr.sa_len) -#else -#define ifreq_size(i) sizeof(struct ifreq) -#endif /* HAVE_SA_LEN */ - - sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - if (sd < 0) { - return -1; - } - memset(buf, 0, sizeof(buf)); - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; - if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { - close(sd); - return -1; - } - n = ifc.ifc_len; - for (i = 0; i < n; i+= ifreq_size(*ifrp) ) { - ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); - strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); -#ifdef SIOCGIFHWADDR - if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) - continue; - a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; -#else -#ifdef SIOCGENADDR - if (ioctl(sd, SIOCGENADDR, &ifr) < 0) - continue; - a = (unsigned char *) ifr.ifr_enaddr; -#else -#ifdef HAVE_NET_IF_DL_H - sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr; - if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6)) - continue; - a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen]; -#else - /* - * XXX we don't have a way of getting the hardware - * address - */ - close(sd); - return 0; -#endif /* HAVE_NET_IF_DL_H */ -#endif /* SIOCGENADDR */ -#endif /* SIOCGIFHWADDR */ - if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) - continue; - if (node_id) { - memcpy(node_id, a, 6); - close(sd); - return 1; - } - } - close(sd); -#endif - return 0; -} - -/* Assume that the gettimeofday() has microsecond granularity */ -#define MAX_ADJUSTMENT 10 - -/* - * Get clock from global sequence clock counter. - * - * Return -1 if the clock counter could not be opened/locked (in this case - * pseudorandom value is returned in @ret_clock_seq), otherwise return 0. - */ -static int get_clock(uint32_t *clock_high, uint32_t *clock_low, - uint16_t *ret_clock_seq, int *num) -{ - THREAD_LOCAL int adjustment = 0; - THREAD_LOCAL struct timeval last = {0, 0}; - THREAD_LOCAL int state_fd = -2; - THREAD_LOCAL FILE *state_f; - THREAD_LOCAL uint16_t clock_seq; - struct timeval tv; - uint64_t clock_reg; - mode_t save_umask; - int len; - int ret = 0; - - if (state_fd == -1) - ret = -1; - - if (state_fd == -2) { - ret = -1; - } - #if 0 - if (state_fd >= 0) { - rewind(state_f); - while (flock(state_fd, LOCK_EX) < 0) { - if ((errno == EAGAIN) || (errno == EINTR)) - continue; - fclose(state_f); - close(state_fd); - state_fd = -1; - ret = -1; - break; - } - } - if (state_fd >= 0) { - unsigned int cl; - unsigned long tv1, tv2; - int a; - - if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n", - &cl, &tv1, &tv2, &a) == 4) { - clock_seq = cl & 0x3FFF; - last.tv_sec = tv1; - last.tv_usec = tv2; - adjustment = a; - } - } - #endif - - if ((last.tv_sec == 0) && (last.tv_usec == 0)) { - random_get_bytes(&clock_seq, sizeof(clock_seq)); - clock_seq &= 0x3FFF; - gettimeofday(&last, 0); - last.tv_sec--; - } - -try_again: - gettimeofday(&tv, 0); - if ((tv.tv_sec < last.tv_sec) || - ((tv.tv_sec == last.tv_sec) && - (tv.tv_usec < last.tv_usec))) { - clock_seq = (clock_seq+1) & 0x3FFF; - adjustment = 0; - last = tv; - } else if ((tv.tv_sec == last.tv_sec) && - (tv.tv_usec == last.tv_usec)) { - if (adjustment >= MAX_ADJUSTMENT) - goto try_again; - adjustment++; - } else { - adjustment = 0; - last = tv; - } - - clock_reg = tv.tv_usec*10 + adjustment; - clock_reg += ((uint64_t) tv.tv_sec)*10000000; - clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; - - if (num && (*num > 1)) { - adjustment += *num - 1; - last.tv_usec += adjustment / 10; - adjustment = adjustment % 10; - last.tv_sec += last.tv_usec / 1000000; - last.tv_usec = last.tv_usec % 1000000; - } - #if 0 - if (state_fd >= 0) { - rewind(state_f); - len = fprintf(state_f, - "clock: %04x tv: %016ld %08ld adj: %08d\n", - clock_seq, (long)last.tv_sec, (long)last.tv_usec, adjustment); - fflush(state_f); - if (ftruncate(state_fd, len) < 0) { - fprintf(state_f, " \n"); - fflush(state_f); - } - rewind(state_f); - flock(state_fd, LOCK_UN); - } - #endif - - *clock_high = clock_reg >> 32; - *clock_low = clock_reg; - *ret_clock_seq = clock_seq; - return ret; -} - -#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) - -/* - * Try using the uuidd daemon to generate the UUID - * - * Returns 0 on success, non-zero on failure. - */ -static int get_uuid_via_daemon(int op, uuid_t out, int *num) -{ - char op_buf[64]; - int op_len; - int s; - ssize_t ret; - int32_t reply_len = 0, expected = 16; - struct sockaddr_un srv_addr; - - if (sizeof(UUIDD_SOCKET_PATH) > sizeof(srv_addr.sun_path)) - return -1; - - if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - - srv_addr.sun_family = AF_UNIX; - xstrncpy(srv_addr.sun_path, UUIDD_SOCKET_PATH, sizeof(srv_addr.sun_path)); - - if (connect(s, (const struct sockaddr *) &srv_addr, - sizeof(struct sockaddr_un)) < 0) - goto fail; - - op_buf[0] = op; - op_len = 1; - if (op == UUIDD_OP_BULK_TIME_UUID) { - memcpy(op_buf+1, num, sizeof(*num)); - op_len += sizeof(*num); - expected += sizeof(*num); - } - - ret = write(s, op_buf, op_len); - if (ret < 1) - goto fail; - - ret = read_all(s, (char *) &reply_len, sizeof(reply_len)); - if (ret < 0) - goto fail; - - if (reply_len != expected) - goto fail; - - ret = read_all(s, op_buf, reply_len); - - if (op == UUIDD_OP_BULK_TIME_UUID) - memcpy(op_buf+16, num, sizeof(int)); - - memcpy(out, op_buf, 16); - - close(s); - return ((ret == expected) ? 0 : -1); - -fail: - close(s); - return -1; -} - -#else /* !defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H) */ -static int get_uuid_via_daemon(int op, uuid_t out, int *num) -{ - return -1; -} -#endif - -int __uuid_generate_time(uuid_t out, int *num) -{ - static unsigned char node_id[6]; - static int has_init = 0; - struct uuid uu; - uint32_t clock_mid; - int ret; - - if (!has_init) { - if (get_node_id(node_id) <= 0) { - random_get_bytes(node_id, 6); - /* - * Set multicast bit, to prevent conflicts - * with IEEE 802 addresses obtained from - * network cards - */ - node_id[0] |= 0x01; - } - has_init = 1; - } - ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num); - uu.clock_seq |= 0x8000; - uu.time_mid = (uint16_t) clock_mid; - uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000; - memcpy(uu.node, node_id, 6); - uuid_pack(&uu, out); - return ret; -} - -/* - * Generate time-based UUID and store it to @out - * - * Tries to guarantee uniqueness of the generated UUIDs by obtaining them from the uuidd daemon, - * or, if uuidd is not usable, by using the global clock state counter (see get_clock()). - * If neither of these is possible (e.g. because of insufficient permissions), it generates - * the UUID anyway, but returns -1. Otherwise, returns 0. - */ -static int uuid_generate_time_generic(uuid_t out) { -#ifdef HAVE_TLS - THREAD_LOCAL int num = 0; - THREAD_LOCAL struct uuid uu; - THREAD_LOCAL time_t last_time = 0; - time_t now; - - if (num > 0) { - now = time(0); - if (now > last_time+1) - num = 0; - } - if (num <= 0) { - num = 1000; - if (get_uuid_via_daemon(UUIDD_OP_BULK_TIME_UUID, - out, &num) == 0) { - last_time = time(0); - uuid_unpack(out, &uu); - num--; - return 0; - } - num = 0; - } - if (num > 0) { - uu.time_low++; - if (uu.time_low == 0) { - uu.time_mid++; - if (uu.time_mid == 0) - uu.time_hi_and_version++; - } - num--; - uuid_pack(&uu, out); - return 0; - } -#else - if (get_uuid_via_daemon(UUIDD_OP_TIME_UUID, out, 0) == 0) - return 0; -#endif - - return __uuid_generate_time(out, 0); -} - -/* - * Generate time-based UUID and store it to @out. - * - * Discards return value from uuid_generate_time_generic() - */ -void uuid_generate_time(uuid_t out) -{ - (void)uuid_generate_time_generic(out); -} - - -int uuid_generate_time_safe(uuid_t out) -{ - return uuid_generate_time_generic(out); -} - -void __uuid_generate_random(uuid_t out, int *num) -{ - uuid_t buf; - struct uuid uu; - int i, n; - - if (!num || !*num) - n = 1; - else - n = *num; - - for (i = 0; i < n; i++) { - random_get_bytes(buf, sizeof(buf)); - uuid_unpack(buf, &uu); - - uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; - uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) - | 0x4000; - uuid_pack(&uu, out); - out += sizeof(uuid_t); - } -} - -void uuid_generate_random(uuid_t out) -{ - int num = 1; - /* No real reason to use the daemon for random uuid's -- yet */ - - __uuid_generate_random(out, &num); -} - -/* - * Check whether good random source (/dev/random or /dev/urandom) - * is available. - */ -static int have_random_source(void) -{ - struct stat s; - - return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s)); -} - - -/* - * This is the generic front-end to uuid_generate_random and - * uuid_generate_time. It uses uuid_generate_random only if - * /dev/urandom is available, since otherwise we won't have - * high-quality randomness. - */ -void uuid_generate(uuid_t out) -{ - if (have_random_source()) - uuid_generate_random(out); - else - uuid_generate_time(out); -} diff --git a/third_party/libuuid/src/isnull.c b/third_party/libuuid/src/isnull.c deleted file mode 100644 index 931e7e7db..000000000 --- a/third_party/libuuid/src/isnull.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * isnull.c --- Check whether or not the UUID is null - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include "uuidP.h" - -/* Returns 1 if the uuid is the NULL uuid */ -int uuid_is_null(const uuid_t uu) -{ - const unsigned char *cp; - int i; - - for (i=0, cp = uu; i < 16; i++) - if (*cp++) - return 0; - return 1; -} - diff --git a/third_party/libuuid/src/libuuid.sym b/third_party/libuuid/src/libuuid.sym deleted file mode 100644 index 28a207684..000000000 --- a/third_party/libuuid/src/libuuid.sym +++ /dev/null @@ -1,48 +0,0 @@ -/* - * The symbol versioning ensures that a new application requiring symbol 'foo' - * can't run with old libbrary.so not providing 'foo' - the global SONAME - * version info can't enforce this since we never change the SONAME. - * - * The original libuuid from e2fsprogs (<=1.41.5) does not to use - * symbol versioning -- all the original symbols are in UUID_1.0 now. - * - * Copyright (C) 2011-2014 Karel Zak - */ -UUID_1.0 { -global: - uuid_clear; - uuid_compare; - uuid_copy; - uuid_generate; - uuid_generate_random; - uuid_generate_time; - uuid_is_null; - uuid_parse; - uuid_unparse; - uuid_unparse_lower; - uuid_unparse_upper; - uuid_time; - uuid_type; - uuid_variant; -}; - -/* - * version(s) since util-linux 2.20 - */ -UUID_2.20 { -global: - uuid_generate_time_safe; -} UUID_1.0; - - -/* - * __uuid_* this is not part of the official API, this is - * uuidd (uuid daemon) specific stuff. Hell. - */ -UUIDD_PRIVATE { -global: - __uuid_generate_time; - __uuid_generate_random; -local: - *; -}; diff --git a/third_party/libuuid/src/pack.c b/third_party/libuuid/src/pack.c deleted file mode 100644 index 6e1247669..000000000 --- a/third_party/libuuid/src/pack.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Internal routine for packing UUIDs - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include -#include "uuidP.h" - -void uuid_pack(const struct uuid *uu, uuid_t ptr) -{ - uint32_t tmp; - unsigned char *out = ptr; - - tmp = uu->time_low; - out[3] = (unsigned char) tmp; - tmp >>= 8; - out[2] = (unsigned char) tmp; - tmp >>= 8; - out[1] = (unsigned char) tmp; - tmp >>= 8; - out[0] = (unsigned char) tmp; - - tmp = uu->time_mid; - out[5] = (unsigned char) tmp; - tmp >>= 8; - out[4] = (unsigned char) tmp; - - tmp = uu->time_hi_and_version; - out[7] = (unsigned char) tmp; - tmp >>= 8; - out[6] = (unsigned char) tmp; - - tmp = uu->clock_seq; - out[9] = (unsigned char) tmp; - tmp >>= 8; - out[8] = (unsigned char) tmp; - - memcpy(out+10, uu->node, 6); -} - diff --git a/third_party/libuuid/src/parse.c b/third_party/libuuid/src/parse.c deleted file mode 100644 index 074383efa..000000000 --- a/third_party/libuuid/src/parse.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * parse.c --- UUID parsing - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include -#include -#include -#include - -#include "uuidP.h" - -int uuid_parse(const char *in, uuid_t uu) -{ - struct uuid uuid; - int i; - const char *cp; - char buf[3]; - - if (strlen(in) != 36) - return -1; - for (i=0, cp = in; i <= 36; i++,cp++) { - if ((i == 8) || (i == 13) || (i == 18) || - (i == 23)) { - if (*cp == '-') - continue; - else - return -1; - } - if (i== 36) - if (*cp == 0) - continue; - if (!isxdigit(*cp)) - return -1; - } - uuid.time_low = strtoul(in, NULL, 16); - uuid.time_mid = strtoul(in+9, NULL, 16); - uuid.time_hi_and_version = strtoul(in+14, NULL, 16); - uuid.clock_seq = strtoul(in+19, NULL, 16); - cp = in+24; - buf[2] = 0; - for (i=0; i < 6; i++) { - buf[0] = *cp++; - buf[1] = *cp++; - uuid.node[i] = strtoul(buf, NULL, 16); - } - - uuid_pack(&uuid, uu); - return 0; -} diff --git a/third_party/libuuid/src/test_uuid.c b/third_party/libuuid/src/test_uuid.c deleted file mode 100644 index 4d155b533..000000000 --- a/third_party/libuuid/src/test_uuid.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * tst_uuid.c --- test program from the UUID library - * - * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#ifdef _WIN32 -#define _WIN32_WINNT 0x0500 -#include -#define UUID MYUUID -#endif - -#include -#include -#include -#include -#include - -#include "c.h" -#include "uuid.h" - -static int test_uuid(const char * uuid, int isValid) -{ - static const char * validStr[2] = {"invalid", "valid"}; - uuid_t uuidBits; - int parsedOk; - - parsedOk = uuid_parse(uuid, uuidBits) == 0; - - printf("%s is %s", uuid, validStr[isValid]); - if (parsedOk != isValid) { - printf(" but uuid_parse says %s\n", validStr[parsedOk]); - return 1; - } - printf(", OK\n"); - return 0; -} - -static int check_uuids_in_file(const char *file) -{ - int fd, ret = 0; - size_t sz; - char str[sizeof("01234567-89ab-cdef-0134-567890abcedf")]; - uuid_t uuidBits; - - if ((fd = open(file, O_RDONLY)) < 0) { - warn("%s", file); - return 1; - } - while ((sz = read(fd, str, sizeof(str))) != 0) { - if (isspace(str[sizeof(str) - 1])) - str[sizeof(str) - 1] = '\0'; - if (uuid_parse(str, uuidBits)) { - warnx("%s: %s", file, str); - ret++; - } - } - return ret; -} - -int -main(int argc, char **argv) -{ - int failed = 0; - - if (argc < 2) { - failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981b", 1); - failed += test_uuid("84949CC5-4701-4A84-895B-354C584A981B", 1); - failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981bc", 0); - failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981", 0); - failed += test_uuid("84949cc5x4701-4a84-895b-354c584a981b", 0); - failed += test_uuid("84949cc504701-4a84-895b-354c584a981b", 0); - failed += test_uuid("84949cc5-470104a84-895b-354c584a981b", 0); - failed += test_uuid("84949cc5-4701-4a840895b-354c584a981b", 0); - failed += test_uuid("84949cc5-4701-4a84-895b0354c584a981b", 0); - failed += test_uuid("g4949cc5-4701-4a84-895b-354c584a981b", 0); - failed += test_uuid("84949cc5-4701-4a84-895b-354c584a981g", 0); - failed += test_uuid("00000000-0000-0000-0000-000000000000", 1); - failed += test_uuid("01234567-89ab-cdef-0134-567890abcedf", 1); - failed += test_uuid("ffffffff-ffff-ffff-ffff-ffffffffffff", 1); - } else { - int i; - - for (i = 1; i < argc; i++) - failed += check_uuids_in_file(argv[i]); - } - if (failed) { - printf("%d failures.\n", failed); - exit(1); - } - return 0; -} diff --git a/third_party/libuuid/src/unpack.c b/third_party/libuuid/src/unpack.c deleted file mode 100644 index beaaff3ca..000000000 --- a/third_party/libuuid/src/unpack.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Internal routine for unpacking UUID - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include -#include "uuidP.h" - -void uuid_unpack(const uuid_t in, struct uuid *uu) -{ - const uint8_t *ptr = in; - uint32_t tmp; - - tmp = *ptr++; - tmp = (tmp << 8) | *ptr++; - tmp = (tmp << 8) | *ptr++; - tmp = (tmp << 8) | *ptr++; - uu->time_low = tmp; - - tmp = *ptr++; - tmp = (tmp << 8) | *ptr++; - uu->time_mid = tmp; - - tmp = *ptr++; - tmp = (tmp << 8) | *ptr++; - uu->time_hi_and_version = tmp; - - tmp = *ptr++; - tmp = (tmp << 8) | *ptr++; - uu->clock_seq = tmp; - - memcpy(uu->node, ptr, 6); -} - diff --git a/third_party/libuuid/src/unparse.c b/third_party/libuuid/src/unparse.c deleted file mode 100644 index a95bbb042..000000000 --- a/third_party/libuuid/src/unparse.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * unparse.c -- convert a UUID to string - * - * Copyright (C) 1996, 1997 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#include - -#include "uuidP.h" - -static const char *fmt_lower = - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; - -static const char *fmt_upper = - "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"; - -#ifdef UUID_UNPARSE_DEFAULT_UPPER -#define FMT_DEFAULT fmt_upper -#else -#define FMT_DEFAULT fmt_lower -#endif - -static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt) -{ - struct uuid uuid; - - uuid_unpack(uu, &uuid); - sprintf(out, fmt, - uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, - uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, - uuid.node[0], uuid.node[1], uuid.node[2], - uuid.node[3], uuid.node[4], uuid.node[5]); -} - -void uuid_unparse_lower(const uuid_t uu, char *out) -{ - uuid_unparse_x(uu, out, fmt_lower); -} - -void uuid_unparse_upper(const uuid_t uu, char *out) -{ - uuid_unparse_x(uu, out, fmt_upper); -} - -void uuid_unparse(const uuid_t uu, char *out) -{ - uuid_unparse_x(uu, out, FMT_DEFAULT); -} diff --git a/third_party/libuuid/src/uuid_time.c b/third_party/libuuid/src/uuid_time.c deleted file mode 100644 index 6991ecd53..000000000 --- a/third_party/libuuid/src/uuid_time.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * uuid_time.c --- Interpret the time field from a uuid. This program - * violates the UUID abstraction barrier by reaching into the guts - * of a UUID and interpreting it. - * - * Copyright (C) 1998, 1999 Theodore Ts'o. - * - * %Begin-Header% - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * %End-Header% - */ - -#ifdef _WIN32 -#define _WIN32_WINNT 0x0500 -#include -#define UUID MYUUID -#endif - -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#include -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#include - -#include "uuidP.h" - -time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) -{ - struct timeval tv; - struct uuid uuid; - uint32_t high; - uint64_t clock_reg; - - uuid_unpack(uu, &uuid); - - high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); - clock_reg = uuid.time_low | ((uint64_t) high << 32); - - clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; - tv.tv_sec = clock_reg / 10000000; - tv.tv_usec = (clock_reg % 10000000) / 10; - - if (ret_tv) - *ret_tv = tv; - - return tv.tv_sec; -} - -int uuid_type(const uuid_t uu) -{ - struct uuid uuid; - - uuid_unpack(uu, &uuid); - return ((uuid.time_hi_and_version >> 12) & 0xF); -} - -int uuid_variant(const uuid_t uu) -{ - struct uuid uuid; - int var; - - uuid_unpack(uu, &uuid); - var = uuid.clock_seq; - - if ((var & 0x8000) == 0) - return UUID_VARIANT_NCS; - if ((var & 0x4000) == 0) - return UUID_VARIANT_DCE; - if ((var & 0x2000) == 0) - return UUID_VARIANT_MICROSOFT; - return UUID_VARIANT_OTHER; -} - -#ifdef DEBUG -static const char *variant_string(int variant) -{ - switch (variant) { - case UUID_VARIANT_NCS: - return "NCS"; - case UUID_VARIANT_DCE: - return "DCE"; - case UUID_VARIANT_MICROSOFT: - return "Microsoft"; - default: - return "Other"; - } -} - - -int -main(int argc, char **argv) -{ - uuid_t buf; - time_t time_reg; - struct timeval tv; - int type, variant; - - if (argc != 2) { - fprintf(stderr, "Usage: %s uuid\n", argv[0]); - exit(1); - } - if (uuid_parse(argv[1], buf)) { - fprintf(stderr, "Invalid UUID: %s\n", argv[1]); - exit(1); - } - variant = uuid_variant(buf); - type = uuid_type(buf); - time_reg = uuid_time(buf, &tv); - - printf("UUID variant is %d (%s)\n", variant, variant_string(variant)); - if (variant != UUID_VARIANT_DCE) { - printf("Warning: This program only knows how to interpret " - "DCE UUIDs.\n\tThe rest of the output is likely " - "to be incorrect!!\n"); - } - printf("UUID type is %d", type); - switch (type) { - case 1: - printf(" (time based)\n"); - break; - case 2: - printf(" (DCE)\n"); - break; - case 3: - printf(" (name-based)\n"); - break; - case 4: - printf(" (random)\n"); - break; - default: - printf("\n"); - } - if (type != 1) { - printf("Warning: not a time-based UUID, so UUID time " - "decoding will likely not work!\n"); - } - printf("UUID time is: (%ld, %ld): %s\n", (long)tv.tv_sec, (long)tv.tv_usec, - ctime(&time_reg)); - - return 0; -} -#endif diff --git a/third_party/libuuid/uuid.pc.in b/third_party/libuuid/uuid.pc.in deleted file mode 100644 index 875de19bc..000000000 --- a/third_party/libuuid/uuid.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@usrlib_execdir@ -includedir=@includedir@ - -Name: uuid -Description: Universally unique id library -Version: @LIBUUID_VERSION@ -Requires: -Cflags: -I${includedir}/uuid -Libs: -L${libdir} -luuid diff --git a/third_party/libuuid/uuid.suprx b/third_party/libuuid/uuid.suprx new file mode 100644 index 000000000..a945e1519 Binary files /dev/null and b/third_party/libuuid/uuid.suprx differ diff --git a/third_party/vita2d_sys/vita2d_sys.suprx b/third_party/vita2d_sys/vita2d_sys.suprx new file mode 100644 index 000000000..058ed879d Binary files /dev/null and b/third_party/vita2d_sys/vita2d_sys.suprx differ