Projects
Multimedia
obs-studio
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 40
View file
obs-studio.changes
Changed
@@ -1,4 +1,119 @@ ------------------------------------------------------------------- +Mon Dec 26 08:32:58 UTC 2016 - jimmy@boombatower.com + +- Update to version 0.17.0: + * rtmp-services: Update ingest list for Restream.io + * Revert "CI: Build on OSX 10.10 on travis" + * Remove python dep + * win-capture: Use static runtimes for hooks/helpers + * cmake: Fix OSX fixup_bundle.sh to copy non-system deps + * cmake: Fix permissions with OSX fixup_bundle.sh + * libobs-opengl: Add xcb message poll to empty out the queue + * frontend-tools: Add options to start output timers every time + * libobs-d3d11: Add optional macro to log shader disassembly + * Revert "obs-transitions: Avoid branching in slide_transition.effect" + * rtmp-services: remove shut down services + * libff: Allow custom demuxer options + * obs-outputs: Fix librtmp IP bind / resolve behavior + * UI: Fix frontend-api event call for adding scenes + * libobs/util: Add function to get circlebuf data offset + * libobs/util: Add function to generate formatted filenames + * libobs: Fix bug where outputs cannot initialize hotkeys + * cmake: Add _CRT_SECURE_NO_WARNINGS to all projects + * libobs: Fix deprecated macro + * libobs/util: Do not ignore deprecation on windows + * libobs: Use reference counting for encoder packets + * obs-ffmpeg: Add replay buffer output + * UI: Disable simple output rec. settings when active + * UI: Add replay buffer options to simple output mode + * UI: Clarify replay buf. hotkey error message + * UI: Separate replay buffer from recording + * UI: Add file prefix/suffix options for replay buffer + * UI: Fix replay buffer compile issues on older compilers + * win-capture: Only duplicate to get cur thread handle + * win-capture: Always use minimal access rights within hook + * win-capture: Do not require pipe/mutex within hook + * win-capture: Fix getting proper UWP window handles + * win-capture: Use window for keepalive check + * win-capture: Create all named objects within hook + * win-capture: Don't use "Local\" for game capture shared mem + * win-capture: Remove redundant function + * win-capture: Use wide strings for named objects + * win-capture: Add ability to open UWP named kernel objects + * win-capture: Open UWP named objects with helper functions + * win-capture: Output hook debug messages if addresses missing + * win-capture: Log plugin-side when capture successful/lost + * win-capture: Don't hook suspended processes + * win-capture: Wait a few frames for hook to load + * win-capture: Fix "attempting to hook [executable]" message + * win-capture: Add ApplicationFrameHost to game capture blacklist + * win-capture: Don't hard fail if thread ID not found + * win-capture: Fix cursor not painting with UWP windows + * win-capture: Add debug messages when hooking + * win-capture: Do not fall back to other windows for UWP windows + * UI: Fix property name bug in frontend API + * libobs: Fix possible reverse order mutex hard lock + * UI: Remove deleteLater view from filter window layout + * libobs: Convert Y800 to RGBX manually + * UI: Use dedicated GPU on Hybrid AMD GPU systems + * libobs: Fix format not being set for new source frames + * libobs: Fix line size issue when copying Y800 data + * obs-ffmpeg: Don't allow 32kb/s with FFmpeg AAC encoder + * libobs/graphics: Fix the 2D vector dot product func + * UI: Make close button default in transform dialog + * UI: Add ability to copy-paste scene item transforms + * UI: Add import/export of scene collections & profiles + * enc-amf: Update to 1.4.3.4 for AMD Driver 16.12.1 + * obs-filters: Improve "Color Correction" filter + * image-source: Do not change blend state + * obs-text: Do not reset blend state + * libobs-d3d11: Don't crash if unable to rebuild shared texture + * libobs: Increase maximum audio tracks to 6 + * UI: Increase maximum audio tracks to 6 + * UI: Update locale for 6 tracks + * UI: Fix endif in installer + * UI: Use 64bit desktop link by default in installer + * UI: Clarify startup error messages related to video + * obs-ffmpeg: Fix nvenc_h264 deprecated message + * libobs: Fix bug drawing RGB/BGR async sources + * libobs: Process all scene audio actions if no audio playing + * UI: Fix buddy controls with new audio tracks + * UI: Add default audio track bitrates + * UI: Fix video initialization failure error message + * UI: Fix settings window stacked widget index + * win-capture: Capture all D3D12 backbuffers + * win-capture: Use FindWindowEx to traverse window list + * win-capture: Fix possible null pointer dereference + * win-capture: Do not add certain windows to window lists + * win-capture: Add a few new blacklisted game capture exes + * obs-filters: Add "Color" option to color correction filter + * obs-filters: Fix comment messages + * obs-qsv11: Use d3d9 allocator on Win7 + * win-capture: Fix possible access of array beyond size + * win-capture: Refactor DX12 backbuffer code + * win-capture: If backbuffer count is 1, disable dxgi 1.4 use + * win-capture: Release backbuffers immediately upon init + * libobs/util: Fix C++ compilation issue + * Add libcaption library + * libobs: Add ability to insert captions into frames + * frontend-tools: Move source helper functions to a header + * frontend-tools: Add caption generation tool (windows) + * Update translations from Crowdin + * frontend-tools: Add ability to select caption language + * frontend-tools: Detach caption thread if critical failure + * frontend-tools: Reset stop event before starting captions + * frontend-tools: Don't include colon in "Audio Source" + * frontend-tools: Set buddied controls for captions dialog + * libobs: Fix caption encoder packet reallocation + * libobs: Create referenced parsed AVC encoder packet + * obs-outputs: Free encoder packet data manually + * libobs: Fix bug in AVC encoder packet allocation + * UI: Fix Export QFileDialog parent + * libobs: Eliminate an unnecessary allocation with captions + * frontend-tools: Fix output-timer translation bug + * libobs: Update to version 17.0.0 + +------------------------------------------------------------------- Mon Nov 21 18:55:11 UTC 2016 - jimmy@boombatower.com - Update to version 0.16.6:
View file
obs-studio.spec
Changed
@@ -1,5 +1,5 @@ Name: obs-studio -Version: 0.16.6 +Version: 0.17.0 Release: 0 Summary: A recording/broadcasting program
View file
_service
Changed
@@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> <param name="versionformat">@PARENT_TAG@</param> - <param name="revision">refs/tags/0.16.6</param> + <param name="revision">refs/tags/0.17.0</param> <param name="url">git://github.com/jp9000/obs-studio.git</param> <param name="scm">git</param> <param name="changesgenerate">enable</param>
View file
_servicedata
Changed
@@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/jp9000/obs-studio.git</param> - <param name="changesrevision">b7b8ad476f1f62376833a224d64aa7b747d3b58b</param> + <param name="changesrevision">93e084088f3c1f3979d78eea3c5d9220b1cea3f7</param> </service> </servicedata>
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/CONTRIBUTORS.md
Deleted
@@ -1,85 +0,0 @@ -# The Great Contributors - -These great People have helped create this plugin: - -| Who | What | -| --- | ---- | -| [jackun](http://github.com/jackun) | The awesome person that started it all with his own Classic and Studio fork.<br>Thanks to him this project even exists today. | -| [Xaymar](http://github.com/Xaymar) | Just the guy who spent a week staring at his monitors, trying to figure out how to make it work. | -| [leporel](https://github.com/leporel) | Provided ru-RU language files (Russian) | -| [max20091](https://github.com/max20091) | Provided vi-VN language files (Vietnamese) | -| [M4RK22](https://github.com/M4RK22) | Provided es-ES language files (Spanish) | -| [niteforce](https://github.com/niteforce) | Provided hu-HU language files (Hungarian) | -| [nwgat](https://github.com/nwgat) | Provided nb-NO language files (Norwegian) | -| [wazerstar](https://github.com/wazerstar) | Provided da-DK language files (Danish) | -| [Jim](https://github.com/jp9000) | General OBS Support for development questions. | -| GolDAce | CrowdIn integration stuff. | - -# The Amazing Supporters - -And these great people have decided to support the project by one or another means. - -## September 2016 -### Marcos Vidal -Spanish translator. -[Website](https://markitos.ovh), [Steam](http://steamcommunity.com/id/markitos22/) - -### nwgat.ninja -nwgat.ninja is proud to support Xaymars Technology Projects. -[Website](https://nwgat.ninja) - -### AJ -Este espacio para el alquiler. - -### Jeremy "razorlikes" Nieth -I like to support this project becuase it gives me a way to stream without having to sacrifice immense amounts of cpu resources for encoding. -[Twitch](https://twitch.tv/razorlikes), [GitHub](https://github.com/razorlikes) - -### Kristian Kirkes(ae)ther -Kristian has not been able to provide a comment in time. - -### Markus Wiegand -Earth has not been able to find Markus and make him respond in time. -[Twitter](https://twitter.com/Morphy2k/), [GitHub](https://github.com/Morphy2k) - -### SneakyJoe -Russian streamer and stream teacher, AMD fanboy. Wants to make AMD great again. -[Website](http://sneakyjoe.ru/), [YouTube](https://www.youtube.com/channel/UCUmRv5GwQcsnxXRzuPCGr-Q) - -### vektorDex -Well, he's my big brother. Could at least have responded. ;_; (just kidding) -[Website](http://blog-of-dex.de/), [Twitter](https://twitter.com/vektordex), [Studio](http://digitaldawnstudios.com) - -### Daniel Bagge -Kini nga luna alang sa abang. - -### John Difool -John Difool der alte Sack -[YouTube](https://www.youtube.com/channel/UC5FPsFLQh4ah0-vz-eoZlOA) - -### Nucu -Thanks AMD and Xaymar to make hardware encoding possible. - -### DaOrgest -Currently studying computer and I do YouTube for a hobby - -[Website](http://daorgest.me), [YouTube](http://youtube.com/daorgest) - -## August 2016 -### Jeremy Nieth -Jeremy has decided to not specify what he wanted to be written here. So this will have to do for now. - -### Marcos Vidal -Spanish translator. -[Website](https://markitos.ovh), [Steam](http://steamcommunity.com/id/markitos22/) - -### Markus Wiegand -Markus has also decided to not specify what should be here. So instead, I've decided to write these two sentences for him. -[Twitter](https://twitter.com/Morphy2k/), [GitHub](https://github.com/Morphy2k) - -### nwgat.ninja -nwgat.ninja is proud to support Xaymars Technology Projects. -[Website](https://nwgat.ninja) - -### Nico Thate -Even though he has chosen to not receive a reward for being a patron, he'll get an entry anyway. \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/amd-amf-vce-capabilities.h
Deleted
@@ -1,105 +0,0 @@ -/* -MIT License - -Copyright (c) 2016 Michael Fabian Dirks - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once -////////////////////////////////////////////////////////////////////////// -// Includes -////////////////////////////////////////////////////////////////////////// -#include <stdint.h> -#include <inttypes.h> -#include <vector> -#include <list> -#include <map> - -// Plugin -#include "plugin.h" -#include "amd-amf.h" -#include "amd-amf-vce.h" -#include "api-base.h" - -// AMF -#include "components\ComponentCaps.h" - -////////////////////////////////////////////////////////////////////////// -// Code -////////////////////////////////////////////////////////////////////////// - -namespace Plugin { - namespace AMD { - struct VCEDeviceCapabilities { - amf::AMF_ACCELERATION_TYPE acceleration_type; - uint32_t maxProfile; - uint32_t maxProfileLevel; - uint32_t maxBitrate; - uint32_t minReferenceFrames; - uint32_t maxReferenceFrames; - bool supportsBFrames; - bool supportsFixedSliceMode; - uint32_t maxTemporalLayers; - uint32_t maxNumOfStreams; - uint32_t maxNumOfHwInstances; - - struct IOCaps { - int32_t minWidth, maxWidth; - int32_t minHeight, maxHeight; - bool isInterlacedSupported; - uint32_t verticalAlignment; - - std::vector<std::pair<amf::AMF_SURFACE_FORMAT, bool>> formats; - std::vector<std::pair<amf::AMF_MEMORY_TYPE, bool>> memoryTypes; - } input, output; - }; - - class VCECapabilities { - ////////////////////////////////////////////////////////////////////////// - // Singleton - ////////////////////////////////////////////////////////////////////////// - public: - static std::shared_ptr<Plugin::AMD::VCECapabilities> GetInstance(); - static void ReportCapabilities(); - static void ReportDeviceCapabilities(Plugin::API::Device device); - static void ReportDeviceIOCapabilities(Plugin::API::Device device, VCEEncoderType type, bool output); - - ////////////////////////////////////////////////////////////////////////// - // Class - ////////////////////////////////////////////////////////////////////////// - public: - VCECapabilities(); - ~VCECapabilities(); - - //void QueryCapabilitiesForDevice(VCEMemoryType type, Plugin::API::Device device = Plugin::API::Device()); - - bool Refresh(); - std::vector<Plugin::API::Device> GetDevices(); - VCEDeviceCapabilities GetDeviceCaps(Plugin::API::Device device, VCEEncoderType type); - VCEDeviceCapabilities::IOCaps GetDeviceIOCaps(Plugin::API::Device device, VCEEncoderType type, bool output); - - private: - //std::map<VCEMemoryType, std::map<Plugin::API::Device, std::map<VCEEncoderType, VCEDeviceCapabilities>>> tstMap; - - std::vector<Plugin::API::Device> devices; - std::map<std::pair<Plugin::API::Device, Plugin::AMD::VCEEncoderType>, VCEDeviceCapabilities> deviceToCapabilities; - }; - } -} \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/amd-amf-vce.h
Deleted
@@ -1,500 +0,0 @@ -/* -MIT License - -Copyright (c) 2016 Michael Fabian Dirks - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once -////////////////////////////////////////////////////////////////////////// -// Includes -////////////////////////////////////////////////////////////////////////// -#include <condition_variable> -#include <algorithm> -#include <mutex> -#include <queue> -#include <thread> -#include <vector> -#include <chrono> - -// Plugin -#include "plugin.h" -#include "amd-amf.h" -#include "api-base.h" - -////////////////////////////////////////////////////////////////////////// -// Code -////////////////////////////////////////////////////////////////////////// - -namespace Plugin { - namespace AMD { - // Internal Properties - enum VCEEncoderType { - VCEEncoderType_AVC, // Advanced Video Coding - VCEEncoderType_SVC, // Scalable Video Coding - VCEEncoderType_HEVC, // High-Efficiency Video Coding (Discovered in amfrt64.dll) - }; - enum VCEMemoryType { - VCEMemoryType_Host, // Host-Managed Memory - VCEMemoryType_DirectX9, // DirectX9 - VCEMemoryType_DirectX11, // DirectX11 - VCEMemoryType_OpenGL, // OpenGL - }; - enum VCEColorFormat { - // 4:2:0 Formats - VCEColorFormat_NV12, // NV12 - VCEColorFormat_I420, // YUV 4:2:0 - // 4:2:2 Formats - VCEColorFormat_YUY2, - // Uncompressed - VCEColorFormat_BGRA, // ARGB - VCEColorFormat_RGBA, // RGBA - // Other - VCEColorFormat_GRAY, - }; - enum VCEColorProfile { - VCEColorProfile_601, - VCEColorProfile_709, - VCEColorProfile_2020, // HDR - }; - - // Static Properties - enum VCEUsage { - VCEUsage_Transcoding, - VCEUsage_UltraLowLatency, - VCEUsage_LowLatency, - VCEUsage_Webcam, // For SVC - }; - enum VCEQualityPreset { - VCEQualityPreset_Speed, - VCEQualityPreset_Balanced, - VCEQualityPreset_Quality, - }; - enum VCEProfile { - VCEProfile_Baseline = 66, - VCEProfile_Main = 77, - VCEProfile_High = 100, - VCEProfile_ConstrainedBaseline = 256, - VCEProfile_ConstrainedHigh = 257 - }; - enum VCEProfileLevel { - VCEProfileLevel_Automatic = 0, - VCEProfileLevel_10 = 10, - VCEProfileLevel_11, - VCEProfileLevel_12, - VCEProfileLevel_13, - VCEProfileLevel_20 = 20, - VCEProfileLevel_21, - VCEProfileLevel_22, - VCEProfileLevel_30 = 30, - VCEProfileLevel_31, - VCEProfileLevel_32, - VCEProfileLevel_40 = 40, - VCEProfileLevel_41, - VCEProfileLevel_42, - VCEProfileLevel_50 = 50, - VCEProfileLevel_51, - VCEProfileLevel_52, - VCEProfileLevel_60 = 60, - VCEProfileLevel_61, - VCEProfileLevel_62, - }; - enum VCEScanType { - VCEScanType_Progressive, - VCEScanType_Interlaced, - }; - enum VCECodingType { - VCECodingType_Default, - VCECodingType_CALV, - VCECodingType_CABAC, - }; - - // Dynamic Properties - enum VCERateControlMethod { - VCERateControlMethod_ConstantQP, - VCERateControlMethod_ConstantBitrate, - VCERateControlMethod_VariableBitrate_PeakConstrained, - VCERateControlMethod_VariableBitrate_LatencyConstrained, - }; - enum VCEBPicturePattern { - VCEBPicturePattern_None, - VCEBPicturePattern_One, - VCEBPicturePattern_Two, - VCEBPicturePattern_Three, - }; - - class VCEEncoder { - ////////////////////////////////////////////////////////////////////////// - #pragma region Functions - ////////////////////////////////////////////////////////////////////////// - private: - static void InputThreadMain(Plugin::AMD::VCEEncoder* p_this); - static void OutputThreadMain(Plugin::AMD::VCEEncoder* p_this); - - #pragma endregion Functions - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - #pragma region Initializer & Finalizer - ////////////////////////////////////////////////////////////////////////// - public: - VCEEncoder(VCEEncoderType p_Type, - std::string p_DeviceId = "", - bool p_OpenCL = false, - VCEColorFormat p_SurfaceFormat = VCEColorFormat_NV12 - ); - ~VCEEncoder(); - #pragma endregion Initializer & Finalizer - - ////////////////////////////////////////////////////////////////////////// - #pragma region Methods - ////////////////////////////////////////////////////////////////////////// - public: - void Start(); - void Restart(); - void Stop(); - bool IsStarted(); - bool SendInput(struct encoder_frame* frame); - bool GetOutput(struct encoder_packet* packet, bool* received_packet); - bool GetExtraData(uint8_t**& data, size_t*& size); - void GetVideoInfo(struct video_scale_info*& vsi); - - // Threading - private: - void InputThreadLogic(); - void OutputThreadLogic(); - - // Utility - inline amf::AMFSurfacePtr CreateSurfaceFromFrame(struct encoder_frame*& frame); - - public: - void LogProperties(); - - /************************************************************************/ - /* Static Properties */ - /************************************************************************/ - - /* Usage Type - * Sets up the entire encoder to a specific set of properties. - * Must be called first if you want to override properties. */ - void SetUsage(VCEUsage usage); - VCEUsage GetUsage(); - - /** Quality Preset - * Static Property, changes cause a restart. */ - void SetQualityPreset(VCEQualityPreset preset); - VCEQualityPreset GetQualityPreset(); - - /* H.264 Profile */ - void SetProfile(VCEProfile profile); - VCEProfile GetProfile(); - - /* H.264 Profile Level */ - void SetProfileLevel(VCEProfileLevel level); - VCEProfileLevel GetProfileLevel(); - - /* The number of long-term references controlled by the user. - * - * Remarks: - * - When == 0, the encoder may or may not use LTRs during encoding. - * - When >0, the user has control over all LTR. - * - With user control of LTR, B-pictures and Intra-refresh features are not supported. - * - The actual maximum number of LTRs allowed depends on H.264 Annex A Table A-1 Level limits, which defines dependencies between the H.264 Level number, encoding resolution, and DPB size. The DPB size limit impacts the maximum number of LTR allowed. - **/ - void SetMaximumLongTermReferenceFrames(uint32_t maximumLTRFrames); // Long-Term Reference Frames. If 0, Encoder decides, if non-0 B-Pictures and Intra-Refresh are not supported. - uint32_t GetMaximumLongTermReferenceFrames(); - - /* Coding Type */ - void SetCodingType(VCECodingType type); - VCECodingType GetCodingType(); - - /************************************************************************/ - /* Frame Properties */ - /************************************************************************/ - - void SetColorProfile(VCEColorProfile profile); - VCEColorProfile GetColorProfile(); - - void SetFullColorRangeEnabled(bool enabled); - bool IsFullColorRangeEnabled(); - - /* Selects progressive or interlaced scan - * Static Property, changes cause a restart. */ - void SetScanType(VCEScanType scanType); - VCEScanType GetScanType(); - - /* Output Resolution */ - void SetFrameSize(uint32_t width, uint32_t height); - std::pair<uint32_t, uint32_t> GetFrameSize(); - - /* Sets the Frame Rate numerator and denumerator */ - void SetFrameRate(uint32_t num, uint32_t den); - std::pair<uint32_t, uint32_t> GetFrameRate(); - - /************************************************************************/ - /* Rate Control Properties */ - /************************************************************************/ - - /* Selects the rate control method: - * - CQP - Constrained QP, - * - CBR - Constant Bitrate, - * - VBR - Peak Constrained VBR, - * - VBR_LAT - Latency Constrained VBR - * - * Remarks: - * - When SVC encoding is enabled, all Rate-control parameters (with some restrictions) can be configured differently for a particular SVC-layer. An SVC-layer is denoted by an index pair [SVC-Temporal Layer index][SVC-Quality Layer index]. E.g. The bitrate may be configured differently for SVC-layers [0][0] and [1][0]. - * - We restrict all SVC layers to have the same Rate Control method. Some RC parameters are not enabled with SVC encoding (e.g. all parameters related to B-pictures). - **/ - void SetRateControlMethod(VCERateControlMethod method); - VCERateControlMethod GetRateControlMethod(); - - /* Sets the target bitrate */ - void SetTargetBitrate(uint32_t bitrate); - uint32_t GetTargetBitrate(); - - /* Sets the peak bitrate */ - void SetPeakBitrate(uint32_t bitrate); - uint32_t GetPeakBitrate(); - - /* Sets the minimum QP */ - void SetMinimumQP(uint8_t qp); - uint8_t GetMinimumQP(); - - /* Sets the maximum QP */ - void SetMaximumQP(uint8_t qp); - uint8_t GetMaximumQP(); - - /* Sets the Constant QP for I-Pictures. - * - * Remarks: - * - Only available for CQP rate control method. - **/ - void SetIFrameQP(uint8_t qp); - uint8_t GetIFrameQP(); - - /* Sets the Constant QP for P-Pictures. - * - * Remarks: - * - Only available for CQP rate control method. - **/ - void SetPFrameQP(uint8_t qp); - uint8_t GetPFrameQP(); - - /* Sets the Constant QP for B-Pictures. - * - * Remarks: - * - Only available for CQP rate control method. - **/ - void SetBFrameQP(uint8_t qp); - uint8_t GetBFrameQP(); - - /* Selects the delta QP of non-reference B-Pictures with respect to I pictures */ - void SetBPictureDeltaQP(int8_t qp); - int8_t GetBPictureDeltaQP(); - - /* Selects delta QP of reference B-Pictures with respect to I pictures */ - void SetReferenceBPictureDeltaQP(int8_t qp); - int8_t GetReferenceBPictureDeltaQP(); - - /* Sets the VBV Buffer Size in bits */ - void SetVBVBufferSize(uint32_t size); - void SetVBVBufferAutomatic(double_t strictness); - uint32_t GetVBVBufferSize(); - - /* Sets the initial VBV Buffer Fullness */ - void SetInitialVBVBufferFullness(double_t fullness); - double_t GetInitialVBVBufferFullness(); - - /* Sets Maximum AU Size in bits */ - void SetMaximumAccessUnitSize(uint32_t size); - uint32_t GetMaximumAccessUnitSize(); - - /* Enables/Disables filler data */ - void SetFillerDataEnabled(bool enabled); - bool IsFillerDataEnabled(); - - /* Enables skip frame for rate control */ - void SetFrameSkippingEnabled(bool enabled); - bool IsFrameSkippingEnabled(); - - /* Enables/Disables constraints on QP variation within a picture to meet HRD requirement(s) */ - void SetEnforceHRDRestrictionsEnabled(bool enforce); - bool IsEnforceHRDRestrictionsEnabled(); - - /************************************************************************/ - /* Picture Control Properties */ - /************************************************************************/ - - /* Sets IDR period. IDRPeriod= 0 turns IDR off */ - void SetIDRPeriod(uint32_t period); - uint32_t GetIDRPeriod(); - - /* Sets the headers insertion spacing */ - void SetHeaderInsertionSpacing(uint32_t spacing); // Similar to IDR Period, spacing (in frames) between headers. - uint32_t GetHeaderInsertionSpacing(); - - /* Sets the number of consecutive B-pictures in a GOP. BPicturesPattern = 0 indicates that B-pictures are not used */ - void SetBPicturePattern(VCEBPicturePattern pattern); - VCEBPicturePattern GetBPicturePattern(); - - /* Enables or disables using B-pictures as references */ - void SetBPictureReferenceEnabled(bool enabled); - bool IsBPictureReferenceEnabled(); - - /* Turns on/off the Deblocking Filter */ - void SetDeblockingFilterEnabled(bool enabled); - bool IsDeblockingFilterEnabled(); - - /* Sets the number of slices per frame */ - void SetSlicesPerFrame(uint32_t slices); - uint32_t GetSlicesPerFrame(); - - /* Sets the number of intra-refresh macro-blocks per slot */ - void SetIntraRefreshMBsNumberPerSlot(uint32_t mbs); - uint32_t GetIntraRefreshMBsNumberPerSlot(); - - /************************************************************************/ - /* Miscellaneous Control Properties */ - /************************************************************************/ - - /* Turns on/off half-pixel motion estimation */ - void SetHalfPixelMotionEstimationEnabled(bool enabled); - bool IsHalfPixelMotionEstimationEnabled(); - - /* Turns on/off quarter-pixel motion estimation */ - void SetQuarterPixelMotionEstimationEnabled(bool enabled); - bool IsQuarterPixelMotionEstimationEnabled(); - - /************************************************************************/ - /* Hidden Properties */ - /************************************************************************/ - - void SetGOPSize(uint32_t gopSize); - uint32_t GetGOPSize(); - - void SetWaitForTaskEnabled(bool enabled); - bool IsWaitForTaskEnabled(); - - void SetAspectRatio(uint32_t x, uint32_t y); - std::pair<uint32_t, uint32_t> GetAspectRatio(); - - void SetMaximumNumberOfReferenceFrames(uint32_t frameCount); - uint32_t GetMaximumNumberOfReferenceFrames(); - - uint32_t GetMaxMBPerSec(); - - void SetInstanceID(uint32_t instanceId); - uint32_t GetInstanceID(); - - void SetVBAQEnabled(bool enabled); - bool IsVBAQEnabled(); - - void SetRateControlPreanalysisEnabled(bool enabled); - bool IsRateControlPreanalysisEnabled(); - - void SetIntraRefreshNumberOfStripes(uint32_t stripes); // 0 - INT_MAX - uint32_t GetIntraRefreshNumberOfStripes(); - - void SetSliceMode(uint32_t mode); // 1 or 2 - uint32_t GetSliceMode(); - - void SetMaximumSliceSize(uint32_t size); // 0 - INT_MAX - uint32_t GetMaximumSliceSize(); - - // - SliceControlMode: AMF_VIDEO_ENCODER_SLICE_CTRL_MODE_MB_ROW, AMF_VIDEO_ENCODER_SLICE_CTRL_MODE_MB - void SetSliceControlMode(uint32_t mode); // 0, 1, 2, 3 - uint32_t GetSliceControlMode(); - - void SetSliceControlSize(uint32_t size); // 0 - INT_MAX - uint32_t GetSliceControlSize(); - - // HEVC Parameters - // - MinQP_I, MaxQP_I - // - MinQP_P, MaxQP_P - // - QPCBOFFSET, QPCROFFSET - // - GOPPerIDR - // - GOPSizeMin, GOPSizeMax - // - EnableGOPAlignment - - #pragma endregion Methods - ////////////////////////////////////////////////////////////////////////// - - ////////////////////////////////////////////////////////////////////////// - #pragma region Members - ////////////////////////////////////////////////////////////////////////// - private: - - // AMF Data References - std::shared_ptr<Plugin::AMD::AMF> m_AMF; - amf::AMFFactory* m_AMFFactory; - amf::AMFContextPtr m_AMFContext; - amf::AMFComponentPtr m_AMFConverter; - amf::AMFComponentPtr m_AMFEncoder; - amf::AMFComputePtr m_AMFCompute; - - // API References - std::unique_ptr<Plugin::API::APIBase> m_APIDevice; - - // Static Buffers - std::vector<uint8_t> m_PacketDataBuffer; - std::vector<uint8_t> m_ExtraDataBuffer; - - // Structured Queue - struct { - std::queue<amf::AMFSurfacePtr> queue; - - // Threading - std::thread thread; - std::mutex mutex; - std::condition_variable condvar; - std::mutex queuemutex; - } m_Input; - struct { - std::queue<amf::AMFDataPtr> queue; - - // Threading - std::thread thread; - std::mutex mutex; - std::condition_variable condvar; - std::mutex queuemutex; - } m_Output; - - // Internal Properties - VCEEncoderType m_EncoderType; - VCEMemoryType m_MemoryType; - bool m_UseOpenCL; - VCEColorFormat m_SurfaceFormat; - bool m_Flag_IsStarted, - m_Flag_FirstFrameSubmitted, - m_Flag_FirstFrameReceived; - std::pair<uint32_t, uint32_t> m_FrameSize, - m_FrameRate; - double_t m_FrameRateDivisor, - m_FrameRateReverseDivisor; - size_t m_InputQueueLimit, - m_InputQueueLastSize; - uint32_t m_TimerPeriod; - VCEColorProfile m_ColorProfile; - - #pragma endregion Members - ////////////////////////////////////////////////////////////////////////// - }; - } -} \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/amd-amf-vce-capabilities.cpp
Deleted
@@ -1,364 +0,0 @@ -/* -MIT License - -Copyright (c) 2016 Michael Fabian Dirks - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#pragma once - -////////////////////////////////////////////////////////////////////////// -// Includes -////////////////////////////////////////////////////////////////////////// -#include <string> -#include <sstream> - -#ifdef _WIN32 -#include <windows.h> -#include <VersionHelpers.h> -#endif - -#include "amd-amf-vce-capabilities.h" -#include "api-d3d11.h" -#include "api-d3d9.h" -#include "misc-util.cpp" - -////////////////////////////////////////////////////////////////////////// -// Code -////////////////////////////////////////////////////////////////////////// - -std::shared_ptr<Plugin::AMD::VCECapabilities> Plugin::AMD::VCECapabilities::GetInstance() { - static std::shared_ptr<VCECapabilities> __instance = std::make_shared<VCECapabilities>(); - static std::mutex __mutex; - - const std::lock_guard<std::mutex> lock(__mutex); - return __instance; -} - -void Plugin::AMD::VCECapabilities::ReportCapabilities() { - auto inst = GetInstance(); - - auto devs = inst->GetDevices(); - for (auto dev : devs) { - ReportDeviceCapabilities(dev); - } -} - -void Plugin::AMD::VCECapabilities::ReportDeviceCapabilities(Plugin::API::Device device) { - auto inst = GetInstance(); - - AMF_LOG_INFO("Capabilities for Device '%s':", device.Name.c_str()); - - VCEEncoderType types[] = { VCEEncoderType_AVC, VCEEncoderType_SVC }; - for (VCEEncoderType type : types) { - auto caps = inst->GetDeviceCaps(device, type); - - AMF_LOG_INFO(" %s (Acceleration: %s)", - (type == VCEEncoderType_AVC ? "AVC" : (type == VCEEncoderType_SVC ? "SVC" : (type == VCEEncoderType_HEVC ? "HEVC" : "Unknown"))), - (caps.acceleration_type == amf::AMF_ACCEL_SOFTWARE ? "Software" : (caps.acceleration_type == amf::AMF_ACCEL_GPU ? "GPU" : (caps.acceleration_type == amf::AMF_ACCEL_HARDWARE ? "Hardware" : "None"))) - ); - - if (caps.acceleration_type == amf::AMF_ACCEL_NOT_SUPPORTED) - continue; - - AMF_LOG_INFO(" Limits"); - AMF_LOG_INFO(" # of Streams: %ld", caps.maxNumOfStreams); - AMF_LOG_INFO(" # of Instances: %ld", caps.maxNumOfHwInstances); - AMF_LOG_INFO(" Profile: %s", Plugin::Utility::ProfileAsString((VCEProfile)caps.maxProfile)); - AMF_LOG_INFO(" Level: %ld.%ld", caps.maxProfileLevel / 10, caps.maxProfileLevel % 10); - AMF_LOG_INFO(" Bitrate: %ld", caps.maxBitrate); - AMF_LOG_INFO(" Temporal Layers: %ld", caps.maxTemporalLayers); - AMF_LOG_INFO(" Reference Frames: %ld (min) - %ld (max)", caps.minReferenceFrames, caps.maxReferenceFrames); - AMF_LOG_INFO(" Features") - AMF_LOG_INFO(" B-Frames: %s", caps.supportsBFrames ? "Supported" : "Not Supported"); - AMF_LOG_INFO(" Fixed Slice Mode: %s", caps.supportsFixedSliceMode ? "Supported" : "Not Supported"); - AMF_LOG_INFO(" Input"); - ReportDeviceIOCapabilities(device, type, false); - AMF_LOG_INFO(" Output"); - ReportDeviceIOCapabilities(device, type, true); - } -} - -void Plugin::AMD::VCECapabilities::ReportDeviceIOCapabilities(Plugin::API::Device device, VCEEncoderType type, bool output) { - auto amf = Plugin::AMD::AMF::GetInstance(); - auto inst = GetInstance(); - auto ioCaps = inst->GetDeviceIOCaps(device, type, output); - AMF_LOG_INFO(" Resolution: %ldx%ld - %ldx%ld", - ioCaps.minWidth, ioCaps.minHeight, - ioCaps.maxWidth, ioCaps.maxHeight); - AMF_LOG_INFO(" Vertical Alignment: %ld", ioCaps.verticalAlignment); - AMF_LOG_INFO(" Interlaced: %s", ioCaps.isInterlacedSupported ? "Supported" : "Not Supported"); - std::stringstream formatstr; - for (auto format : ioCaps.formats) { - std::vector<char> buf(1024); - wcstombs(buf.data(), amf->GetTrace()->SurfaceGetFormatName(format.first), 1024); - formatstr - << buf.data() - << (format.second ? " (Native)" : "") - << ", "; - } - AMF_LOG_INFO(" Formats: %s", formatstr.str().c_str()); - std::stringstream memorystr; - for (auto memory : ioCaps.memoryTypes) { - std::vector<char> buf(1024); - wcstombs(buf.data(), amf->GetTrace()->GetMemoryTypeName(memory.first), 1024); - memorystr - << buf.data() - << (memory.second ? " (Native)" : "") - << ", "; - } - AMF_LOG_INFO(" Memory Types: %s", memorystr.str().c_str()); -} - -Plugin::AMD::VCECapabilities::VCECapabilities() { - this->Refresh(); -} - -Plugin::AMD::VCECapabilities::~VCECapabilities() {} - -static AMF_RESULT GetIOCapability(bool output, amf::AMFCapsPtr amfCaps, Plugin::AMD::VCEDeviceCapabilities::IOCaps* caps) { - AMF_RESULT res = AMF_OK; - amf::AMFIOCapsPtr amfIOCaps; - if (output) - res = amfCaps->GetOutputCaps(&amfIOCaps); - else - res = amfCaps->GetInputCaps(&amfIOCaps); - if (res != AMF_OK) - return res; - - amfIOCaps->GetWidthRange(&(caps->minWidth), &(caps->maxWidth)); - amfIOCaps->GetHeightRange(&(caps->minHeight), &(caps->maxHeight)); - caps->isInterlacedSupported = amfIOCaps->IsInterlacedSupported(); - caps->verticalAlignment = amfIOCaps->GetVertAlign(); - - int32_t numFormats = amfIOCaps->GetNumOfFormats(); - caps->formats.resize(numFormats); - for (int32_t formatIndex = 0; formatIndex < numFormats; formatIndex++) { - amf::AMF_SURFACE_FORMAT format = amf::AMF_SURFACE_UNKNOWN; - bool isNative = false; - - amfIOCaps->GetFormatAt(formatIndex, &format, &isNative); - caps->formats[formatIndex].first = format; - caps->formats[formatIndex].second = isNative; - } - - int32_t numMemoryTypes = amfIOCaps->GetNumOfMemoryTypes(); - caps->memoryTypes.resize(numMemoryTypes); - for (int32_t memoryTypeIndex = 0; memoryTypeIndex < numMemoryTypes; memoryTypeIndex++) { - amf::AMF_MEMORY_TYPE type = amf::AMF_MEMORY_UNKNOWN; - bool isNative = false; - - amfIOCaps->GetMemoryTypeAt(memoryTypeIndex, &type, &isNative); - caps->memoryTypes[memoryTypeIndex].first = type; - caps->memoryTypes[memoryTypeIndex].second = isNative; - } - - return AMF_OK; -} - -bool Plugin::AMD::VCECapabilities::Refresh() { - AMF_RESULT res; - - // Build a list of Devices - #ifdef _WIN32 - if (IsWindows8OrGreater()) { - devices = Plugin::API::Direct3D11::EnumerateDevices(); - } else if (IsWindowsXPOrGreater()) { - devices = Plugin::API::Direct3D9::EnumerateDevices(); - } else - #endif - { // OpenGL - //devices = Plugin::API::OpenGL::EnumerateDevices(); - } - //devices.insert(devices.begin(), Plugin::API::Device()); - - // Query Information for each Device - std::shared_ptr<AMD::AMF> amfInstance = AMD::AMF::GetInstance(); - amf::AMFFactory* amfFactory = amfInstance->GetFactory(); - for (Plugin::API::Device device : devices) { - amf::AMFContextPtr amfContext; - res = amfFactory->CreateContext(&amfContext); - if (res != AMF_OK) { - AMF_LOG_ERROR("Unable to gather capabilities for device '%s', error %ls (code %d).", - device.Name.c_str(), amfInstance->GetTrace()->GetResultText(res), res); - continue; - } - - auto apiDev = Plugin::API::APIBase::CreateBestAvailableAPI(device); - switch (apiDev->GetType()) { - case Plugin::API::APIType_Direct3D11: - res = amfContext->InitDX11(apiDev->GetContext()); - break; - case Plugin::API::APIType_Direct3D9: - res = amfContext->InitDX9(apiDev->GetContext()); - break; - case Plugin::API::APIType_OpenGL: - res = amfContext->InitOpenGL(apiDev->GetContext(), nullptr, nullptr); - break; - } - if (res != AMF_OK) { - AMF_LOG_ERROR("Unable to gather capabilities for device '%s' after initialization, error %ls (code %d).", - device.Name.c_str(), amfInstance->GetTrace()->GetResultText(res), res); - continue; - } - - VCEDeviceCapabilities devAVCCaps, devSVCCaps; - const wchar_t* capsString[] = { - AMFVideoEncoderVCE_AVC, - AMFVideoEncoderVCE_SVC, - }; - VCEDeviceCapabilities* caps[] = { - &devAVCCaps, - &devSVCCaps, - }; - VCEEncoderType capsType[] = { - VCEEncoderType_AVC, - VCEEncoderType_SVC, - }; - - for (uint8_t capsIndex = 0; capsIndex < _countof(caps); capsIndex++) { - #pragma region Null Structure - caps[capsIndex]->acceleration_type = amf::AMF_ACCEL_NOT_SUPPORTED; - caps[capsIndex]->maxBitrate = - caps[capsIndex]->maxNumOfStreams = - caps[capsIndex]->maxProfile = - caps[capsIndex]->maxProfileLevel = - caps[capsIndex]->minReferenceFrames = - caps[capsIndex]->maxReferenceFrames = - caps[capsIndex]->maxTemporalLayers = - caps[capsIndex]->maxNumOfHwInstances = - caps[capsIndex]->input.minWidth = - caps[capsIndex]->input.maxWidth = - caps[capsIndex]->input.minHeight = - caps[capsIndex]->input.maxHeight = - caps[capsIndex]->input.verticalAlignment = - caps[capsIndex]->output.minWidth = - caps[capsIndex]->output.maxWidth = - caps[capsIndex]->output.minHeight = - caps[capsIndex]->output.maxHeight = - caps[capsIndex]->output.verticalAlignment = 0; - caps[capsIndex]->supportsBFrames = - caps[capsIndex]->supportsFixedSliceMode = - caps[capsIndex]->input.isInterlacedSupported = - caps[capsIndex]->output.isInterlacedSupported = false; - caps[capsIndex]->input.formats.clear(); - caps[capsIndex]->output.formats.clear(); - caps[capsIndex]->input.memoryTypes.clear(); - caps[capsIndex]->output.memoryTypes.clear(); - #pragma endregion Null Structure - - #pragma region Initialization - amf::AMFComponentPtr amfComponent; - res = amfFactory->CreateComponent(amfContext, capsString[capsIndex], &amfComponent); - if (res != AMF_OK) { - AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Failed to create component for device '%s' with codec '%ls', error %ls (code %d).", - device.Name.c_str(), capsString[capsIndex], - amfInstance->GetTrace()->GetResultText(res), res); - continue; - } - - amf::AMFCapsPtr amfCaps; - res = amfComponent->GetCaps(&amfCaps); - if (res != AMF_OK) { - AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Failed to gather capabilities for device '%s' with codec '%ls', error %ls (code %d).", - device.Name.c_str(), capsString[capsIndex], - amfInstance->GetTrace()->GetResultText(res), res); - amfComponent->Terminate(); - continue; - } - #pragma endregion Initialization - - #pragma region Basic Capabilities - caps[capsIndex]->acceleration_type = amfCaps->GetAccelerationType(); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_BITRATE, &(caps[capsIndex]->maxBitrate)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_NUM_OF_STREAMS, &(caps[capsIndex]->maxNumOfStreams)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_PROFILE, &(caps[capsIndex]->maxProfile)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_LEVEL, &(caps[capsIndex]->maxProfileLevel)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_BFRAMES, &(caps[capsIndex]->supportsBFrames)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MIN_REFERENCE_FRAMES, &(caps[capsIndex]->minReferenceFrames)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_REFERENCE_FRAMES, &(caps[capsIndex]->maxReferenceFrames)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_TEMPORAL_LAYERS, &(caps[capsIndex]->maxTemporalLayers)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_FIXED_SLICE_MODE, &(caps[capsIndex]->supportsFixedSliceMode)); - amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_NUM_OF_HW_INSTANCES, &(caps[capsIndex]->maxNumOfHwInstances)); - #pragma endregion Basic Capabilities - - if (GetIOCapability(false, amfCaps, &(caps[capsIndex]->input))) { - AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Failed to gather input capabilities for device '%s' with codec '%ls', error %ls (code %d).", - device.Name.c_str(), capsString[capsIndex], - amfInstance->GetTrace()->GetResultText(res), res); - } - if (GetIOCapability(true, amfCaps, &(caps[capsIndex]->output))) { - AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Failed to gather output capabilities for device '%s' with codec '%ls', error %ls (code %d).", - device.Name.c_str(), capsString[capsIndex], - amfInstance->GetTrace()->GetResultText(res), res); - } - - amfComponent->Terminate(); - - // Register - std::pair<Plugin::API::Device, Plugin::AMD::VCEEncoderType> devkv(device, capsType[capsIndex]); - deviceToCapabilities.insert(std::make_pair(devkv, *caps[capsIndex])); - } - - amfContext->Terminate(); - } - - return true; -} - -std::vector<Plugin::API::Device> Plugin::AMD::VCECapabilities::GetDevices() { - return std::vector<Plugin::API::Device>(devices); -} - -Plugin::AMD::VCEDeviceCapabilities Plugin::AMD::VCECapabilities::GetDeviceCaps(Plugin::API::Device device, VCEEncoderType type) { - if (deviceToCapabilities.empty()) - return Plugin::AMD::VCEDeviceCapabilities(); - - if (device.UniqueId == "") - return deviceToCapabilities.begin()->second; - - auto dt = std::pair<Plugin::API::Device, Plugin::AMD::VCEEncoderType>(device, type); - if (deviceToCapabilities.count(dt) == 0) - return Plugin::AMD::VCEDeviceCapabilities(); - - return deviceToCapabilities.find(dt)->second; -} - -Plugin::AMD::VCEDeviceCapabilities::IOCaps Plugin::AMD::VCECapabilities::GetDeviceIOCaps(Plugin::API::Device device, VCEEncoderType type, bool output) { - if (deviceToCapabilities.empty()) - return Plugin::AMD::VCEDeviceCapabilities::IOCaps(); - - if (device.UniqueId == "") { - if (output) - return deviceToCapabilities.begin()->second.output; - else - return deviceToCapabilities.begin()->second.input; - } - - auto dt = std::pair<Plugin::API::Device, Plugin::AMD::VCEEncoderType>(device, type); - if (deviceToCapabilities.count(dt) == 0) - return Plugin::AMD::VCEDeviceCapabilities::IOCaps(); - - if (output) - return deviceToCapabilities.find(dt)->second.output; - else - return deviceToCapabilities.find(dt)->second.input; -} -
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/amd-amf-vce.cpp
Deleted
@@ -1,1868 +0,0 @@ -/* -MIT License - -Copyright (c) 2016 Michael Fabian Dirks - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -////////////////////////////////////////////////////////////////////////// -// Includes -////////////////////////////////////////////////////////////////////////// -#include <chrono> - -#include "amd-amf-vce.h" -#include "amd-amf-vce-capabilities.h" -#include "misc-util.cpp" - -// AMF -#include "components/VideoEncoderVCE.h" -#include "components/VideoConverter.h" - -// Windows -#ifdef _WIN32 -#include <windows.h> -#include <VersionHelpers.h> - -#include "api-d3d9.h" -#include "api-d3d11.h" -#endif - -////////////////////////////////////////////////////////////////////////// -// Code -////////////////////////////////////////////////////////////////////////// - -// Logging and Exception Helpers -static void FormatTextWithAMFError(std::vector<char>* buffer, const char* format, AMF_RESULT res) { - sprintf(buffer->data(), format, Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res); -} - -template<typename _T> -static void FormatTextWithAMFError(std::vector<char>* buffer, const char* format, _T other, AMF_RESULT res) { - sprintf(buffer->data(), format, other, Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res); -} - -// Class -void Plugin::AMD::VCEEncoder::InputThreadMain(Plugin::AMD::VCEEncoder* p_this) { - p_this->InputThreadLogic(); -} - -void Plugin::AMD::VCEEncoder::OutputThreadMain(Plugin::AMD::VCEEncoder* p_this) { - p_this->OutputThreadLogic(); -} - -static void fastPrintVariant(const char* text, amf::AMFVariantStruct variant) { - std::vector<char> buf(1024); - switch (variant.type) { - case amf::AMF_VARIANT_EMPTY: - sprintf(buf.data(), "%s%s", text, "Empty"); - break; - case amf::AMF_VARIANT_BOOL: - sprintf(buf.data(), "%s%s", text, variant.boolValue ? "true" : "false"); - break; - case amf::AMF_VARIANT_INT64: - sprintf(buf.data(), "%s%lld", text, variant.int64Value); - break; - case amf::AMF_VARIANT_DOUBLE: - sprintf(buf.data(), "%s%f", text, variant.doubleValue); - break; - case amf::AMF_VARIANT_RECT: - sprintf(buf.data(), "%s[%ld,%ld,%ld,%ld]", text, - variant.rectValue.top, variant.rectValue.left, - variant.rectValue.bottom, variant.rectValue.right); - break; - case amf::AMF_VARIANT_SIZE: - sprintf(buf.data(), "%s%ldx%ld", text, - variant.sizeValue.width, variant.sizeValue.height); - break; - case amf::AMF_VARIANT_POINT: - sprintf(buf.data(), "%s[%ld,%ld]", text, - variant.pointValue.x, variant.pointValue.y); - break; - case amf::AMF_VARIANT_RATE: - sprintf(buf.data(), "%s%ld/%ld", text, - variant.rateValue.num, variant.rateValue.den); - break; - case amf::AMF_VARIANT_RATIO: - sprintf(buf.data(), "%s%ld:%ld", text, - variant.ratioValue.num, variant.ratioValue.den); - break; - case amf::AMF_VARIANT_COLOR: - sprintf(buf.data(), "%s(%d,%d,%d,%d)", text, - variant.colorValue.r, - variant.colorValue.g, - variant.colorValue.b, - variant.colorValue.a); - break; - case amf::AMF_VARIANT_STRING: - sprintf(buf.data(), "%s'%s'", text, - variant.stringValue); - break; - case amf::AMF_VARIANT_WSTRING: - sprintf(buf.data(), "%s'%ls'", text, - variant.wstringValue); - break; - } - AMF_LOG_INFO("%s", buf.data()); -}; - -static void printDebugInfo(amf::AMFComponentPtr m_AMFEncoder) { - #ifdef _DEBUG - amf::AMFPropertyInfo* pInfo; - size_t propCount = m_AMFEncoder->GetPropertyCount(); - AMF_LOG_INFO("-- Internal AMF Encoder Properties --"); - for (size_t propIndex = 0; propIndex < propCount; propIndex++) { - static const char* typeToString[] = { - "Empty", - "Boolean", - "Int64", - "Double", - "Rect", - "Size", - "Point", - "Rate", - "Ratio", - "Color", - "String", - "WString", - "Interface" - }; - - AMF_RESULT res = m_AMFEncoder->GetPropertyInfo(propIndex, (const amf::AMFPropertyInfo**) &pInfo); - if (res != AMF_OK) - continue; - AMF_LOG_INFO(" [%ls] %ls (Type: %s, Index %d)", - pInfo->name, pInfo->desc, typeToString[pInfo->type], propIndex); - AMF_LOG_INFO(" Content Type: %d", - pInfo->contentType); - AMF_LOG_INFO(" Access: %s%s%s", - (pInfo->accessType & amf::AMF_PROPERTY_ACCESS_READ) ? "R" : "", - (pInfo->accessType & amf::AMF_PROPERTY_ACCESS_WRITE) ? "W" : "", - (pInfo->accessType & amf::AMF_PROPERTY_ACCESS_WRITE_RUNTIME) ? "X" : ""); - - AMF_LOG_INFO(" Values:"); - amf::AMFVariantStruct curStruct = amf::AMFVariantStruct(); - m_AMFEncoder->GetProperty(pInfo->name, &curStruct); - fastPrintVariant(" Current: ", curStruct); - fastPrintVariant(" Default: ", pInfo->defaultValue); - fastPrintVariant(" Minimum: ", pInfo->minValue); - fastPrintVariant(" Maximum: ", pInfo->maxValue); - if (pInfo->pEnumDescription) { - AMF_LOG_INFO(" Enumeration: "); - const amf::AMFEnumDescriptionEntry* pEnumEntry = pInfo->pEnumDescription; - while (pEnumEntry->name != nullptr) { - AMF_LOG_INFO(" %ls (%ld)", - pEnumEntry->name, - pEnumEntry->value); - pEnumEntry++; - } - } - } - #endif -} - -Plugin::AMD::VCEEncoder::VCEEncoder(VCEEncoderType p_Type, - std::string p_DeviceId/* = ""*/, - bool p_OpenCL/* = false*/, - VCEColorFormat p_SurfaceFormat/* = VCESurfaceFormat_NV12*/ -) { - AMF_RESULT res; - - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Initializing..."); - - // Solve the optimized away issue. - m_EncoderType = p_Type; - m_SurfaceFormat = p_SurfaceFormat; - m_UseOpenCL = p_OpenCL; - m_Flag_IsStarted = false; - m_Flag_FirstFrameReceived = false; - m_Flag_FirstFrameSubmitted = false; - m_FrameSize.first = 64; m_FrameSize.second = 64; - m_FrameRate.first = 30; m_FrameRate.second = 1; - m_FrameRateDivisor = ((double_t)m_FrameRate.first / (double_t)m_FrameRate.second); - m_FrameRateReverseDivisor = ((double_t)m_FrameRate.second / (double_t)m_FrameRate.first); - m_InputQueueLimit = (uint32_t)(m_FrameRateDivisor * 3); - m_InputQueueLastSize = 0; - m_TimerPeriod = 1; - - // AMF - m_AMF = AMF::GetInstance(); - m_AMFFactory = m_AMF->GetFactory(); - /// AMF Context - res = m_AMFFactory->CreateContext(&m_AMFContext); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Creating a context object failed with error %ls (code %ld).", res); - } - - // API Init - if (p_DeviceId == "") { // Use primary/available AMD devices only. - p_DeviceId = Plugin::AMD::VCECapabilities::GetInstance()->GetDevices().begin()->UniqueId; - } - m_APIDevice = Plugin::API::APIBase::CreateBestAvailableAPI(Plugin::API::APIBase::GetDeviceForUniqueId(p_DeviceId)); - switch (m_APIDevice->GetType()) { - case Plugin::API::APIType_Direct3D11: - res = m_AMFContext->InitDX11(m_APIDevice->GetContext()); - m_MemoryType = VCEMemoryType_DirectX11; - break; - case Plugin::API::APIType_Direct3D9: - res = m_AMFContext->InitDX9(m_APIDevice->GetContext()); - m_MemoryType = VCEMemoryType_DirectX9; - break; - case Plugin::API::APIType_OpenGL: - res = m_AMFContext->InitOpenGL(m_APIDevice->GetContext(), nullptr, nullptr); - m_MemoryType = VCEMemoryType_OpenGL; - break; - case Plugin::API::APIType_Base: // Not the best case, but whatever. - m_UseOpenCL = false; - m_MemoryType = VCEMemoryType_Host; - break; - } - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Initializing 3D queue failed with error %ls (code %ld).", res); - - if (m_UseOpenCL) { - res = m_AMFContext->InitOpenCL(nullptr); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> InitOpenCL failed with error %ls (code %ld).", res); - m_AMFContext->GetCompute(amf::AMF_MEMORY_OPENCL, &m_AMFCompute); - } - - /// AMF Component (Encoder) - switch (p_Type) { - case VCEEncoderType_AVC: - res = m_AMFFactory->CreateComponent(m_AMFContext, AMFVideoEncoderVCE_AVC, &m_AMFEncoder); - break; - case VCEEncoderType_SVC: - res = m_AMFFactory->CreateComponent(m_AMFContext, AMFVideoEncoderVCE_SVC, &m_AMFEncoder); - break; - case VCEEncoderType_HEVC: - res = m_AMFFactory->CreateComponent(m_AMFContext, L"AMFVideoEncoderHW_HEVC", &m_AMFEncoder); - break; - } - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Creating a component object failed with error %ls (code %ld).", res); - - /// AMF Component (Converter) - res = m_AMFFactory->CreateComponent(m_AMFContext, AMFVideoConverter, &m_AMFConverter); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to create VideoConverter component, error %ls (code %ld).", res); - m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_MEMORY_TYPE, Utility::MemoryTypeAsAMF(m_MemoryType)); - m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_OUTPUT_FORMAT, Utility::SurfaceFormatAsAMF(m_SurfaceFormat)); - - printDebugInfo(m_AMFEncoder); - - AMF_LOG_DEBUG("Initialization complete!"); -} - -Plugin::AMD::VCEEncoder::~VCEEncoder() { - if (m_Flag_IsStarted) - Stop(); - - // AMF - if (m_AMFConverter) { - m_AMFConverter->Terminate(); - m_AMFConverter = nullptr; - } - if (m_AMFEncoder) { - m_AMFEncoder->Terminate(); - m_AMFEncoder = nullptr; - } - if (m_AMFContext) { - m_AMFContext->Terminate(); - m_AMFContext = nullptr; - } - m_AMFFactory = nullptr; -} - -void Plugin::AMD::VCEEncoder::Start() { - // Set proper Timer resolution. - m_TimerPeriod = 1; - while (timeBeginPeriod(m_TimerPeriod) == TIMERR_NOCANDO) { - ++m_TimerPeriod; - } - - // Create Encoder - AMF_RESULT res = m_AMFEncoder->Init(Utility::SurfaceFormatAsAMF(m_SurfaceFormat), - m_FrameSize.first, m_FrameSize.second); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Encoder initialization failed with error %ls (code %ld).", res); - - // Create Converter - m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_COLOR_PROFILE, AMF_VIDEO_CONVERTER_COLOR_PROFILE_709); - //m_AMFConverter->SetProperty(L"NominalRange", this->IsFullColorRangeEnabled()); - res = m_AMFConverter->Init(Utility::SurfaceFormatAsAMF(m_SurfaceFormat), m_FrameSize.first, m_FrameSize.second); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Converter initialization failed with error %ls (code %ld).", res); - - m_Flag_IsStarted = true; - - // Threading - m_Input.thread = std::thread(&(Plugin::AMD::VCEEncoder::InputThreadMain), this); - m_Output.thread = std::thread(&(Plugin::AMD::VCEEncoder::OutputThreadMain), this); -} - -void Plugin::AMD::VCEEncoder::Restart() { - if (!m_Flag_IsStarted) - return; - - std::unique_lock<std::mutex> ilock(m_Input.mutex); - std::unique_lock<std::mutex> olock(m_Output.mutex); - - // Create Encoder - AMF_RESULT res = m_AMFEncoder->ReInit(m_FrameSize.first, m_FrameSize.second); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Initialization failed with error %ls (code %ld).", res); -} - -void Plugin::AMD::VCEEncoder::Stop() { - // Restore Timer precision. - if (m_TimerPeriod != 0) { - timeEndPeriod(m_TimerPeriod); - } - - m_Flag_IsStarted = false; - - // Threading - m_Output.condvar.notify_all(); - #if defined _WIN32 || defined _WIN64 - { // Windows: Force terminate Thread after 1 second of waiting. - std::thread::native_handle_type hnd = m_Output.thread.native_handle(); - - uint32_t res = WaitForSingleObject((HANDLE)hnd, 1000); - switch (res) { - case WAIT_OBJECT_0: - m_Output.thread.join(); - break; - default: - m_Output.thread.detach(); - TerminateThread((HANDLE)hnd, 0); - break; - } - } - #else - m_Output.thread.join(); - #endif - - m_Input.condvar.notify_all(); - #if defined _WIN32 || defined _WIN64 - { // Windows: Force terminate Thread after 1 second of waiting. - std::thread::native_handle_type hnd = m_Input.thread.native_handle(); - - uint32_t res = WaitForSingleObject((HANDLE)hnd, 1000); - switch (res) { - case WAIT_OBJECT_0: - m_Input.thread.join(); - break; - default: - m_Input.thread.detach(); - TerminateThread((HANDLE)hnd, 0); - break; - } - } - #else - m_Input.thread.join(); - #endif - - // Stop AMF Encoder - if (m_AMFEncoder) { - m_AMFEncoder->Drain(); - m_AMFEncoder->Flush(); - } - - // Clear Queues, Data - std::queue<amf::AMFSurfacePtr>().swap(m_Input.queue); - std::queue<amf::AMFDataPtr>().swap(m_Output.queue); - m_PacketDataBuffer.clear(); - m_ExtraDataBuffer.clear(); -} - -bool Plugin::AMD::VCEEncoder::IsStarted() { - return m_Flag_IsStarted; -} - -bool Plugin::AMD::VCEEncoder::SendInput(struct encoder_frame* frame) { - // Early-Exception if not encoding. - if (!m_Flag_IsStarted) { - const char* error = "<" __FUNCTION_NAME__ "> Attempted to send input while not running."; - AMF_LOG_ERROR("%s", error); - throw std::exception(error); - } - - // Convert Frame into a Surface and queue it. - if (frame != nullptr) { - amf::AMFSurfacePtr pAMFSurface = CreateSurfaceFromFrame(frame); - if (pAMFSurface) { - // Set Surface Properties - pAMFSurface->SetPts(frame->pts / m_FrameRate.second); - pAMFSurface->SetProperty(L"Frame", frame->pts); - pAMFSurface->SetDuration((uint64_t)ceil(m_FrameRateReverseDivisor * AMF_SECOND)); - - // Add to Queue - std::unique_lock<std::mutex> qlock(m_Input.queuemutex); - size_t uiQueueSize = m_Input.queue.size(); - - if (uiQueueSize >= m_InputQueueLimit) { - AMF_LOG_WARNING("Submission queue is full, dropping frame instead..."); - } else { - m_Input.queue.push(pAMFSurface); - if (m_InputQueueLastSize != uiQueueSize) { - int32_t delta = ((int32_t)uiQueueSize - (int32_t)m_InputQueueLastSize); - if (uiQueueSize == 0) { - AMF_LOG_DEBUG("Submission queue is empty. (%d/%d/%d)", uiQueueSize, delta, m_InputQueueLimit); - m_InputQueueLastSize = uiQueueSize; - } else if (delta >= 5) { - AMF_LOG_WARNING("Submission queue size is growing. (%d/%d/%d)", uiQueueSize, delta, m_InputQueueLimit); - m_InputQueueLastSize = uiQueueSize; - } else if (delta <= -5) { - AMF_LOG_INFO("Submission queue size is shrinking. (%d/%d/%d)", uiQueueSize, delta, m_InputQueueLimit); - m_InputQueueLastSize = uiQueueSize; - } - } - } - } else { - AMF_LOG_ERROR("Unable copy frame for submission, terminating..."); - return false; - } - } - - /// Signal Thread Wakeup - m_Input.condvar.notify_all(); - - // WORKAROUND: Block for at most 5 seconds until the first frame has been submitted. - if (!m_Flag_FirstFrameSubmitted) { - auto startsubmit = std::chrono::high_resolution_clock::now(); - auto diff = std::chrono::high_resolution_clock::now() - startsubmit; - do { - diff = std::chrono::high_resolution_clock::now() - startsubmit; - std::this_thread::sleep_for(std::chrono::milliseconds(m_TimerPeriod)); - } while ((diff <= std::chrono::seconds(5)) && !m_Flag_FirstFrameSubmitted); - if (!m_Flag_FirstFrameSubmitted) - throw std::exception("Unable to submit first frame, terminating..."); - else - AMF_LOG_INFO("First submission took %d nanoseconds.", diff.count()); - } - - return true; -} - -bool Plugin::AMD::VCEEncoder::GetOutput(struct encoder_packet* packet, bool* received_packet) { - // Early-Exception if not encoding. - if (!m_Flag_IsStarted) { - const char* error = "<" __FUNCTION_NAME__ "> Attempted to send input while not running."; - AMF_LOG_ERROR("%s", error); - throw std::exception(error); - } - - /// Signal Thread Wakeup - m_Output.condvar.notify_all(); - - if (received_packet != nullptr) { - amf::AMFDataPtr pAMFData; - { // Attempt to dequeue an Item. - std::unique_lock<std::mutex> qlock(m_Output.queuemutex); - if (m_Output.queue.size() == 0) - return true; - - pAMFData = m_Output.queue.front(); - m_Output.queue.pop(); - } - - // We've got a DataPtr, let's use it. - amf::AMFBufferPtr pAMFBuffer = amf::AMFBufferPtr(pAMFData); - - // Assemble Packet - packet->type = OBS_ENCODER_VIDEO; - /// Data - size_t oldBufferSize = pAMFBuffer->GetSize(); - if (m_PacketDataBuffer.size() < oldBufferSize) { - size_t newBufferSize = (size_t)exp2(ceil(log2(oldBufferSize))); - AMF_LOG_DEBUG("Packet Buffer was resized to %d byte from %d byte.", newBufferSize, m_PacketDataBuffer.size()); - m_PacketDataBuffer.resize(newBufferSize); - } - packet->data = m_PacketDataBuffer.data(); - packet->size = oldBufferSize; - std::memcpy(packet->data, pAMFBuffer->GetNative(), packet->size); - /// Timestamps - packet->dts = (pAMFData->GetPts() - 2) * m_FrameRate.second; // Offset by 2 to support B-Pictures - pAMFBuffer->GetProperty(L"Frame", &packet->pts); - { /// Packet Priority & Keyframe - uint64_t pktType; - pAMFData->GetProperty(AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &pktType); - - switch ((AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_ENUM)pktType) { - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR:// - packet->keyframe = true; // IDR-Frames are Key-Frames that contain a lot of information. - packet->priority = 3; // Highest priority, always continue streaming with these. - //packet->drop_priority = 3; // Dropped IDR-Frames can only be replaced by the next IDR-Frame. - break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I: // I-Frames need only a previous I- or IDR-Frame. - packet->priority = 2; // I- and IDR-Frames will most likely be present. - // packet->drop_priority = 2; // So we can continue with a I-Frame when streaming. - // break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_P: // P-Frames need either a previous P-, I- or IDR-Frame. - packet->priority = 1; // We can safely assume that at least one of these is present. - // packet->drop_priority = 1; // So we can continue with a P-Frame when streaming. - // break; - case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_B: // B-Frames need either a parent B-, P-, I- or IDR-Frame. - packet->priority = 0; // We don't know if the last non-dropped frame was a B-Frame. - // packet->drop_priority = 1; // So require a P-Frame or better to continue streaming. - // break; - } - } - *received_packet = true; - - // Debug: Packet Information - std::vector<wchar_t> fileName(128); - mbstowcs(fileName.data(), __FILE__, fileName.size()); - std::vector<wchar_t> functionName(128); - mbstowcs(functionName.data(), __FUNCTION__, functionName.size()); - m_AMF->GetTrace()->TraceW(fileName.data(), __LINE__, AMF_TRACE_TRACE, L"Plugin::GetOutput", 4, L"Packet: Type(%lld), PTS(%4lld), DTS(%4lld), Size(%8lld)", (int64_t)packet->priority, (int64_t)packet->pts, (int64_t)packet->dts, (int64_t)packet->size); - } - - return true; -} - -bool Plugin::AMD::VCEEncoder::GetExtraData(uint8_t**& extra_data, size_t*& extra_data_size) { - if (!m_AMFContext || !m_AMFEncoder) - throw std::exception("<" __FUNCTION_NAME__ "> Called while not initialized."); - - if (!m_Flag_IsStarted) - throw std::exception("<" __FUNCTION_NAME__ "> Called while not encoding."); - - amf::AMFVariant var; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_EXTRADATA, &var); - if (res == AMF_OK && var.type == amf::AMF_VARIANT_INTERFACE) { - amf::AMFBufferPtr buf(var.pInterface); - - *extra_data_size = buf->GetSize(); - m_ExtraDataBuffer.resize(*extra_data_size); - std::memcpy(m_ExtraDataBuffer.data(), buf->GetNative(), *extra_data_size); - *extra_data = m_ExtraDataBuffer.data(); - - return true; - } - return false; -} - -void Plugin::AMD::VCEEncoder::GetVideoInfo(struct video_scale_info*& vsi) { - if (!m_AMFContext || !m_AMFEncoder) - throw std::exception("<" __FUNCTION_NAME__ "> Called while not initialized."); - - if (!m_Flag_IsStarted) - throw std::exception("<" __FUNCTION_NAME__ "> Called while not encoding."); - - switch (m_SurfaceFormat) { - // 4:2:0 Formats - case VCEColorFormat_NV12: - vsi->format = VIDEO_FORMAT_NV12; - break; - case VCEColorFormat_I420: - vsi->format = VIDEO_FORMAT_I420; - break; - // 4:2:2 Formats - case VCEColorFormat_YUY2: - vsi->format = VIDEO_FORMAT_YUY2; - break; - // Uncompressed - case VCEColorFormat_RGBA: - vsi->format = VIDEO_FORMAT_RGBA; - break; - case VCEColorFormat_BGRA: - vsi->format = VIDEO_FORMAT_BGRA; - break; - // Other - case VCEColorFormat_GRAY: - vsi->format = VIDEO_FORMAT_Y800; - break; - } - - // AMF requires Partial Range for some reason. - if (this->IsFullColorRangeEnabled()) { // Only use Full range if actually enabled. - vsi->range = VIDEO_RANGE_FULL; - } else { - vsi->range = VIDEO_RANGE_PARTIAL; - } - // Also Colorspace is automatic, see: https://github.com/GPUOpen-LibrariesAndSDKs/AMF/issues/6#issuecomment-243473568 - //if (this->GetFrameSize().second <= 780) { // SD content is .601, HD content is .709 - // vsi->colorspace = VIDEO_CS_601; - //} else { - // vsi->colorspace = VIDEO_CS_709; - //} -} - -void Plugin::AMD::VCEEncoder::InputThreadLogic() { // Thread Loop that handles Surface Submission - // Assign Thread Name - static const char* __threadName = "enc-amf Input Thread"; - SetThreadName(__threadName); - - // Core Loop - std::unique_lock<std::mutex> lock(m_Input.mutex); - uint32_t repeatSurfaceSubmission = 0; - do { - m_Input.condvar.wait(lock); - - // Assign Thread Name - static const char* __threadName = "enc-amf Input Thread"; - SetThreadName(__threadName); - - // Skip to check if isStarted is false. - if (!m_Flag_IsStarted) - continue; - - // Dequeue Surface - amf::AMFSurfacePtr surface; - { - std::unique_lock<std::mutex> qlock(m_Input.queuemutex); - if (m_Input.queue.size() == 0) - continue; // Queue is empty, - surface = m_Input.queue.front(); - } - - /// Convert Frame - AMF_RESULT res; - amf::AMFDataPtr outbuf; - - res = m_AMFConverter->SubmitInput(surface); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to submit Frame to Converter, error %ls (code %ld).", res); - res = m_AMFConverter->QueryOutput(&outbuf); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to retrieve Frame from Converter, error %ls (code %ld).", res); - - /// Submit to AMF - res = m_AMFEncoder->SubmitInput(outbuf); - if (res == AMF_OK) { - m_Flag_FirstFrameSubmitted = true; - - { // Remove Surface from Queue - std::unique_lock<std::mutex> qlock(m_Input.queuemutex); - m_Input.queue.pop(); - } - - // Reset AMF_INPUT_FULL retries. - repeatSurfaceSubmission = 0; - - // Continue with next Surface. - m_Input.condvar.notify_all(); - } else if (res == AMF_INPUT_FULL) { - m_Output.condvar.notify_all(); - if (repeatSurfaceSubmission < 5) { - repeatSurfaceSubmission++; - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - m_Input.condvar.notify_all(); - } - } else if (res == AMF_EOF) { - // This should never happen, but on the off-chance that it does, just straight up leave the loop. - break; - } else { - // Unknown, unexpected return code. - std::vector<char> msgBuf(128); - FormatTextWithAMFError(&msgBuf, "%ls (code %d)", Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res); - AMF_LOG_WARNING("<" __FUNCTION_NAME__ "> SubmitInput failed with error %s.", msgBuf.data()); - } - } while (m_Flag_IsStarted); -} - -void Plugin::AMD::VCEEncoder::OutputThreadLogic() { // Thread Loop that handles Querying - // Assign Thread Name - static const char* __threadName = "enc-amf Output Thread"; - SetThreadName(__threadName); - - // Core Loop - std::unique_lock<std::mutex> lock(m_Output.mutex); - do { - m_Output.condvar.wait(lock); - - // Assign Thread Name - static const char* __threadName = "enc-amf Output Thread"; - SetThreadName(__threadName); - - // Skip to check if isStarted is false. - if (!m_Flag_IsStarted) - continue; - - amf::AMFDataPtr pData = amf::AMFDataPtr(); - AMF_RESULT res = m_AMFEncoder->QueryOutput(&pData); - if (res == AMF_OK) { - m_Flag_FirstFrameReceived = true; - - { // Queue - std::unique_lock<std::mutex> qlock(m_Output.queuemutex); - m_Output.queue.push(pData); - } - - // Continue querying until nothing is left. - m_Output.condvar.notify_all(); - } else if (res == AMF_REPEAT) { - m_Input.condvar.notify_all(); - } else if (res == AMF_EOF) { - // This should never happen, but on the off-chance that it does, just straight up leave the loop. - break; - } else { - // Unknown, unexpected return code. - std::vector<char> msgBuf(128); - FormatTextWithAMFError(&msgBuf, "%s (code %d)", res); - AMF_LOG_WARNING("<" __FUNCTION_NAME__ "> QueryOutput failed with error %s.", msgBuf.data()); - } - } while (m_Flag_IsStarted); -} - -amf::AMFSurfacePtr Plugin::AMD::VCEEncoder::CreateSurfaceFromFrame(struct encoder_frame*& frame) { - AMF_RESULT res = AMF_UNEXPECTED; - amf::AMFSurfacePtr pSurface = nullptr; - if (m_UseOpenCL) { - amf_size l_origin[] = { 0, 0, 0 }; - amf_size l_size0[] = { m_FrameSize.first, m_FrameSize.second, 1 }; - amf_size l_size1[] = { m_FrameSize.first >> 1, m_FrameSize.second >> 1, 1 }; - - res = m_AMFContext->AllocSurface(Utility::MemoryTypeAsAMF(m_MemoryType), - Utility::SurfaceFormatAsAMF(m_SurfaceFormat), - m_FrameSize.first, m_FrameSize.second, &pSurface); - if (res != AMF_OK) // Unable to create Surface - ThrowExceptionWithAMFError("AllocSurface failed with error %ls (code %d).", res); - - amf::AMFComputeSyncPointPtr pSyncPoint; - m_AMFCompute->PutSyncPoint(&pSyncPoint); - pSurface->Convert(amf::AMF_MEMORY_OPENCL); - m_AMFCompute->CopyPlaneFromHost(frame->data[0], l_origin, l_size0, frame->linesize[0], pSurface->GetPlaneAt(0), false); - m_AMFCompute->CopyPlaneFromHost(frame->data[1], l_origin, l_size1, frame->linesize[1], pSurface->GetPlaneAt(1), false); - m_AMFCompute->FinishQueue(); - pSurface->Convert(Utility::MemoryTypeAsAMF(m_MemoryType)); - pSyncPoint->Wait(); - } else { - res = m_AMFContext->AllocSurface(amf::AMF_MEMORY_HOST, Utility::SurfaceFormatAsAMF(m_SurfaceFormat), - m_FrameSize.first, m_FrameSize.second, &pSurface); - if (res != AMF_OK) // Unable to create Surface - ThrowExceptionWithAMFError("AllocSurface failed with error %ls (code %d).", res); - - size_t planeCount = pSurface->GetPlanesCount(); - for (uint8_t i = 0; i < planeCount; i++) { - amf::AMFPlanePtr plane = pSurface->GetPlaneAt(i); - void* plane_nat = plane->GetNative(); - int32_t height = plane->GetHeight(); - int32_t hpitch = plane->GetHPitch(); - - for (int32_t py = 0; py < height; py++) { - int32_t plane_off = py * hpitch; - int32_t frame_off = py * frame->linesize[i]; - std::memcpy(static_cast<void*>(static_cast<uint8_t*>(plane_nat) + plane_off), static_cast<void*>(frame->data[i] + frame_off), frame->linesize[i]); - } - } - - // Convert to AMF native type. - pSurface->Convert(Utility::MemoryTypeAsAMF(m_MemoryType)); - } - - return pSurface; -} - -////////////////////////////////////////////////////////////////////////// -// AMF Properties -////////////////////////////////////////////////////////////////////////// - -void Plugin::AMD::VCEEncoder::LogProperties() { - AMF_LOG_INFO("-- AMD Advanced Media Framework VCE Encoder --"); - AMF_LOG_INFO("Initialization Parameters: "); - AMF_LOG_INFO(" Memory Type: %s", Utility::MemoryTypeAsString(m_MemoryType)); - if (m_MemoryType != VCEMemoryType_Host) { - AMF_LOG_INFO(" Device: %s", m_APIDevice->GetDevice().Name.c_str()); - AMF_LOG_INFO(" OpenCL: %s", m_UseOpenCL ? "Enabled" : "Disabled"); - } - AMF_LOG_INFO(" Surface Format: %s", Utility::SurfaceFormatAsString(m_SurfaceFormat)); - try { AMF_LOG_INFO(" Color Profile: %s", this->GetColorProfile() == VCEColorProfile_709 ? "709" : "601"); } catch (...) {} - try { AMF_LOG_INFO(" Color Range: %s", this->IsFullColorRangeEnabled() ? "Full" : "Partial"); } catch (...) {} - AMF_LOG_INFO("Static Parameters: "); - AMF_LOG_INFO(" Usage: %s", Utility::UsageAsString(this->GetUsage())); - AMF_LOG_INFO(" Profile: %s %d.%d", Utility::ProfileAsString(this->GetProfile()), this->GetProfileLevel() / 10, this->GetProfileLevel() % 10); - AMF_LOG_INFO(" Maximum Long-Term Reference Frames: %d", this->GetMaximumLongTermReferenceFrames()); - AMF_LOG_INFO(" Frame Size: %dx%d", this->GetFrameSize().first, this->GetFrameSize().second); - AMF_LOG_INFO(" Frame Rate: %d/%d", this->GetFrameRate().first, this->GetFrameRate().second); - AMF_LOG_INFO(" Quality Preset: %s", Utility::QualityPresetAsString(this->GetQualityPreset())); - AMF_LOG_INFO(" Scan Type: %s", this->GetScanType() == VCEScanType_Progressive ? "Progressive" : "Interlaced"); - try { AMF_LOG_INFO(" Coding Type: %s", Utility::CodingTypeAsString(this->GetCodingType())); } catch (...) {} - AMF_LOG_INFO("Rate Control Parameters: "); - AMF_LOG_INFO(" Method: %s", Utility::RateControlMethodAsString(this->GetRateControlMethod())); - AMF_LOG_INFO(" Bitrate: "); - AMF_LOG_INFO(" Target: %d bits", this->GetTargetBitrate()); - AMF_LOG_INFO(" Peak: %d bits", this->GetPeakBitrate()); - AMF_LOG_INFO(" Quantization Parameter: "); - AMF_LOG_INFO(" Minimum: %d", this->GetMinimumQP()); - AMF_LOG_INFO(" Maximum: %d", this->GetMaximumQP()); - AMF_LOG_INFO(" I-Frame: %d", this->GetIFrameQP()); - AMF_LOG_INFO(" P-Frame: %d", this->GetPFrameQP()); - if (VCECapabilities::GetInstance()->GetDeviceCaps(m_APIDevice->GetDevice(), VCEEncoderType_AVC).supportsBFrames) { - try { AMF_LOG_INFO(" B-Frame: %d", this->GetBFrameQP()); } catch (...) {} - try { AMF_LOG_INFO(" B-Picture Delta QP: %d", this->GetBPictureDeltaQP()); } catch (...) {} - try { AMF_LOG_INFO(" Reference B-Picture Delta QP: %d", this->GetReferenceBPictureDeltaQP()); } catch (...) {} - } else { - AMF_LOG_INFO(" B-Frame: N/A"); - AMF_LOG_INFO(" B-Picture Delta QP: N/A"); - AMF_LOG_INFO(" Reference B-Picture Delta QP: N/A"); - } - AMF_LOG_INFO(" VBV Buffer: "); - AMF_LOG_INFO(" Size: %d bits", this->GetVBVBufferSize()); - AMF_LOG_INFO(" Initial Fullness: %f%%", this->GetInitialVBVBufferFullness() * 100.0); - AMF_LOG_INFO(" Flags: "); - AMF_LOG_INFO(" Filler Data: %s", this->IsFillerDataEnabled() ? "Enabled" : "Disabled"); - AMF_LOG_INFO(" Frame Skipping: %s", this->IsFrameSkippingEnabled() ? "Enabled" : "Disabled"); - AMF_LOG_INFO(" Enforce HRD Restrictions: %s", this->IsEnforceHRDRestrictionsEnabled() ? "Enabled" : "Disabled"); - AMF_LOG_INFO(" Maximum Access Unit Size: %d bits", this->GetMaximumAccessUnitSize()); - AMF_LOG_INFO("Picture Control Parameters: "); - AMF_LOG_INFO(" IDR Period: %d frames", this->GetIDRPeriod()); - AMF_LOG_INFO(" Header Insertion Spacing: %d frames", this->GetHeaderInsertionSpacing()); - AMF_LOG_INFO(" Deblocking Filter: %s", this->IsDeblockingFilterEnabled() ? "Enabled" : "Disabled"); - if (VCECapabilities::GetInstance()->GetDeviceCaps(m_APIDevice->GetDevice(), VCEEncoderType_AVC).supportsBFrames) { - AMF_LOG_INFO(" B-Picture Pattern: %d", this->GetBPicturePattern()); - AMF_LOG_INFO(" B-Picture Reference: %s", this->IsBPictureReferenceEnabled() ? "Enabled" : "Disabled"); - } else { - AMF_LOG_INFO(" B-Picture Pattern: N/A"); - AMF_LOG_INFO(" B-Picture Reference: N/A"); - } - AMF_LOG_INFO(" Intra-Refresh MBs Number per Slot: %d", this->GetIntraRefreshMBsNumberPerSlot()); - AMF_LOG_INFO(" Slices Per Frame: %d", this->GetSlicesPerFrame()); - AMF_LOG_INFO("Motion Estimation Parameters: "); - AMF_LOG_INFO(" Half Pixel: %s", this->IsHalfPixelMotionEstimationEnabled() ? "Enabled" : "Disabled"); - AMF_LOG_INFO(" Quarter Pixel: %s", this->IsQuarterPixelMotionEstimationEnabled() ? "Enabled" : "Disabled"); - AMF_LOG_INFO("Experimental Parameters: "); - try { AMF_LOG_INFO(" Wait For Task: %s", this->IsWaitForTaskEnabled() ? "Enabled" : "Disabled"); } catch (...) {} - try { AMF_LOG_INFO(" Aspect Ratio: %d:%d", this->GetAspectRatio().first, this->GetAspectRatio().second); } catch (...) {} - try { AMF_LOG_INFO(" MaxNumRefFrames: %d", this->GetMaximumNumberOfReferenceFrames()); } catch (...) {} - try { AMF_LOG_INFO(" MaxMBPerSec: %d", this->GetMaxMBPerSec()); } catch (...) {} - try { AMF_LOG_INFO(" Pre-Analysis Pass: %s", this->IsRateControlPreanalysisEnabled() ? "Enabled" : "Disabled"); } catch (...) {} - //try { AMF_LOG_INFO(" Quality Enhancement Mode: %s", Utility::QualityEnhancementModeAsString(this->GetQualityEnhancementMode())); } catch (...) {} - try { AMF_LOG_INFO(" VBAQ: %s", this->IsVBAQEnabled() ? "Enabled" : "Disabled"); } catch (...) {} - - Plugin::AMD::VCECapabilities::ReportDeviceCapabilities(m_APIDevice->GetDevice()); - - printDebugInfo(m_AMFEncoder); - AMF_LOG_INFO("-- AMD Advanced Media Framework VCE Encoder --"); -} - -/************************************************************************/ -/* Static Properties */ -/************************************************************************/ - -void Plugin::AMD::VCEEncoder::SetUsage(VCEUsage usage) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_USAGE, - (uint32_t)Utility::UsageAsAMF(usage)); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", - res, Utility::UsageAsString(usage)); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::UsageAsString(usage)); -} - -Plugin::AMD::VCEUsage Plugin::AMD::VCEEncoder::GetUsage() { - uint32_t usage; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_USAGE, &usage); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", - Utility::UsageAsString(Utility::UsageFromAMF(usage))); - return Utility::UsageFromAMF(usage); -} - -void Plugin::AMD::VCEEncoder::SetQualityPreset(VCEQualityPreset preset) { - static AMF_VIDEO_ENCODER_QUALITY_PRESET_ENUM CustomToAMF[] = { - AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED, - AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, - AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, - }; - static char* CustomToName[] = { - "Speed", - "Balanced", - "Quality", - }; - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QUALITY_PRESET, (uint32_t)CustomToAMF[preset]); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, CustomToName[preset]); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", CustomToName[preset]); -} - -Plugin::AMD::VCEQualityPreset Plugin::AMD::VCEEncoder::GetQualityPreset() { - static VCEQualityPreset AMFToCustom[] = { - VCEQualityPreset_Balanced, - VCEQualityPreset_Speed, - VCEQualityPreset_Quality, - }; - static char* CustomToName[] = { - "Speed", - "Balanced", - "Quality", - }; - - uint32_t preset; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QUALITY_PRESET, &preset); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", CustomToName[AMFToCustom[preset]]); - return AMFToCustom[preset]; -} - -void Plugin::AMD::VCEEncoder::SetProfile(VCEProfile profile) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE, (uint32_t)profile); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, Utility::ProfileAsString(profile)); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::ProfileAsString(profile)); -} - -Plugin::AMD::VCEProfile Plugin::AMD::VCEEncoder::GetProfile() { - uint32_t profile; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_PROFILE, &profile); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", Utility::ProfileAsString((VCEProfile)profile)); - return (VCEProfile)profile; -} - -void Plugin::AMD::VCEEncoder::SetProfileLevel(VCEProfileLevel level) { - // Automatic Detection - if (level == VCEProfileLevel_Automatic) { - auto frameSize = this->GetFrameSize(); - auto frameRate = this->GetFrameRate(); - level = Plugin::Utility::GetMinimumProfileLevel(frameSize, frameRate); - } - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE_LEVEL, (uint32_t)level); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, level); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", level); -} - -Plugin::AMD::VCEProfileLevel Plugin::AMD::VCEEncoder::GetProfileLevel() { - uint32_t profileLevel; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_PROFILE_LEVEL, &profileLevel); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", profileLevel); - return (VCEProfileLevel)(profileLevel); -} - -void Plugin::AMD::VCEEncoder::SetMaximumLongTermReferenceFrames(uint32_t maximumLTRFrames) { - // Clamp Parameter Value - maximumLTRFrames = max(min(maximumLTRFrames, 2), 0); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MAX_LTR_FRAMES, (uint32_t)maximumLTRFrames); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, maximumLTRFrames); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", maximumLTRFrames); -} - -uint32_t Plugin::AMD::VCEEncoder::GetMaximumLongTermReferenceFrames() { - uint32_t maximumLTRFrames; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MAX_LTR_FRAMES, &maximumLTRFrames); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", maximumLTRFrames); - return maximumLTRFrames; -} - -void Plugin::AMD::VCEEncoder::SetCodingType(VCECodingType type) { - AMF_RESULT res = m_AMFEncoder->SetProperty(L"CABACEnable", type); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, Utility::CodingTypeAsString(type)); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::CodingTypeAsString(type)); -} - -VCECodingType Plugin::AMD::VCEEncoder::GetCodingType() { - uint64_t type; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"CABACEnable", &type); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", Utility::CodingTypeAsString((VCECodingType)type)); - return (VCECodingType)type; -} - -/************************************************************************/ -/* Frame Properties */ -/************************************************************************/ - -void Plugin::AMD::VCEEncoder::SetColorProfile(VCEColorProfile profile) { - AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM pluginToAMF[] = { - AMF_VIDEO_CONVERTER_COLOR_PROFILE_601, - AMF_VIDEO_CONVERTER_COLOR_PROFILE_709, - AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020, - }; - const char* pluginToString[] = { - "601", - "709", - "2020", - }; - - AMF_RESULT res = m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_COLOR_PROFILE, - pluginToAMF[profile]); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to set Color Profile, error %ls (code %ld).", res); - m_ColorProfile = profile; - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", pluginToString[profile]); -} - -Plugin::AMD::VCEColorProfile Plugin::AMD::VCEEncoder::GetColorProfile() { - return m_ColorProfile; -} - -void Plugin::AMD::VCEEncoder::SetFullColorRangeEnabled(bool enabled) { - // Info from Mikhail: - // - Name may change in the future - // - Use GetProperty or GetPropertyDescription to test for older or newer drivers. - const wchar_t* names[] = { - L"NominalRange", // 16.11.2 and below. - L"FullRange" - }; - - bool enabledTest; - AMF_RESULT res = AMF_INVALID_ARG; - for (size_t i = 0; i < 2; i++) { - if (m_AMFEncoder->GetProperty(names[i], &enabledTest) == AMF_OK) { - m_AMFConverter->SetProperty(names[i], enabled); - res = m_AMFEncoder->SetProperty(names[i], enabled); - break; - } - } - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsFullColorRangeEnabled() { - // Info from Mikhail: - // - Name may change in the future - // - Use GetProperty or GetPropertyDescription to test for older or newer drivers. - const wchar_t* names[] = { - L"NominalRange", // 16.11.2 and below. - L"FullRange" - }; - - bool enabled; - AMF_RESULT res = AMF_INVALID_ARG; - for (size_t i = 0; i < 2; i++) { - res = m_AMFEncoder->GetProperty(names[i], &enabled); - if (res == AMF_OK) { - break; - } - } - if (res != AMF_OK) - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetScanType(VCEScanType scanType) { - static AMF_VIDEO_ENCODER_SCANTYPE_ENUM CustomToAMF[] = { - AMF_VIDEO_ENCODER_SCANTYPE_PROGRESSIVE, - AMF_VIDEO_ENCODER_SCANTYPE_INTERLACED, - }; - static char* CustomToName[] = { - "Progressive", - "Interlaced", - }; - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_SCANTYPE, (uint32_t)CustomToAMF[scanType]); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, CustomToName[scanType]); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", CustomToName[scanType]); -} - -Plugin::AMD::VCEScanType Plugin::AMD::VCEEncoder::GetScanType() { - static char* CustomToName[] = { - "Progressive", - "Interlaced", - }; - - uint32_t scanType; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_SCANTYPE, &scanType); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", CustomToName[scanType]); - return (Plugin::AMD::VCEScanType)scanType; -} - -void Plugin::AMD::VCEEncoder::SetFrameSize(uint32_t width, uint32_t height) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_FRAMESIZE, ::AMFConstructSize(width, height)); - if (res != AMF_OK) { - std::vector<char> msgBuf(128); - sprintf(msgBuf.data(), "%dx%d", width, height); - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, msgBuf.data()); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %dx%d.", width, height); - m_FrameSize.first = width; - m_FrameSize.second = height; - - if (this->GetProfileLevel() == VCEProfileLevel_Automatic) - this->SetProfileLevel(VCEProfileLevel_Automatic); -} - -std::pair<uint32_t, uint32_t> Plugin::AMD::VCEEncoder::GetFrameSize() { - AMFSize frameSize; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_FRAMESIZE, &frameSize); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %dx%d.", frameSize.width, frameSize.height); - m_FrameSize.first = frameSize.width; - m_FrameSize.second = frameSize.height; - - if (this->GetProfileLevel() == VCEProfileLevel_Automatic) - this->SetProfileLevel(VCEProfileLevel_Automatic); - - return std::pair<uint32_t, uint32_t>(m_FrameSize); -} - -void Plugin::AMD::VCEEncoder::SetFrameRate(uint32_t num, uint32_t den) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_FRAMERATE, ::AMFConstructRate(num, den)); - if (res != AMF_OK) { - std::vector<char> msgBuf; - sprintf(msgBuf.data(), "%d/%d", num, den); - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, msgBuf.data()); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d/%d.", num, den); - m_FrameRate.first = num; - m_FrameRate.second = den; - m_FrameRateDivisor = (double_t)m_FrameRate.first / (double_t)m_FrameRate.second; - m_FrameRateReverseDivisor = ((double_t)m_FrameRate.second / (double_t)m_FrameRate.first); - m_InputQueueLimit = (uint32_t)ceil(m_FrameRateDivisor * 3); - - if (this->GetProfileLevel() == VCEProfileLevel_Automatic) - this->SetProfileLevel(VCEProfileLevel_Automatic); -} - -std::pair<uint32_t, uint32_t> Plugin::AMD::VCEEncoder::GetFrameRate() { - AMFRate frameRate; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_FRAMERATE, &frameRate); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d/%d.", frameRate.num, frameRate.den); - m_FrameRate.first = frameRate.num; - m_FrameRate.second = frameRate.den; - m_FrameRateDivisor = (double_t)frameRate.num / (double_t)frameRate.den; - m_InputQueueLimit = (uint32_t)ceil(m_FrameRateDivisor * 3); - - if (this->GetProfileLevel() == VCEProfileLevel_Automatic) - this->SetProfileLevel(VCEProfileLevel_Automatic); - - return std::pair<uint32_t, uint32_t>(m_FrameRate); -} - -/************************************************************************/ -/* Rate Control Properties */ -/************************************************************************/ - -void Plugin::AMD::VCEEncoder::SetRateControlMethod(VCERateControlMethod method) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, - (uint64_t)Utility::RateControlMethodAsAMF(method)); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", - res, Utility::RateControlMethodAsString(method)); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", - Utility::RateControlMethodAsString(method)); -} - -Plugin::AMD::VCERateControlMethod Plugin::AMD::VCEEncoder::GetRateControlMethod() { - uint32_t method; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, &method); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", - Utility::RateControlMethodAsString(Utility::RateControlMethodFromAMF(method))); - return Utility::RateControlMethodFromAMF(method); -} - -void Plugin::AMD::VCEEncoder::SetTargetBitrate(uint32_t bitrate) { - // Clamp Value - bitrate = clamp(bitrate, 10000, - Plugin::AMD::VCECapabilities::GetInstance()->GetDeviceCaps(m_APIDevice->GetDevice(), VCEEncoderType_AVC).maxBitrate); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_TARGET_BITRATE, bitrate); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, bitrate); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", bitrate); -} - -uint32_t Plugin::AMD::VCEEncoder::GetTargetBitrate() { - uint32_t bitrate; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_TARGET_BITRATE, &bitrate); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d bits.", bitrate); - return bitrate; -} - -void Plugin::AMD::VCEEncoder::SetPeakBitrate(uint32_t bitrate) { - // Clamp Value - bitrate = clamp(bitrate, 10000, - Plugin::AMD::VCECapabilities::GetInstance()->GetDeviceCaps(m_APIDevice->GetDevice(), VCEEncoderType_AVC).maxBitrate); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_PEAK_BITRATE, (uint32_t)bitrate); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, bitrate); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", bitrate); -} - -uint32_t Plugin::AMD::VCEEncoder::GetPeakBitrate() { - uint32_t bitrate; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_PEAK_BITRATE, &bitrate); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d bits.", bitrate); - return bitrate; -} - -void Plugin::AMD::VCEEncoder::SetMinimumQP(uint8_t qp) { - // Clamp Value - qp = clamp(qp, 0, 51); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MIN_QP, (uint32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -uint8_t Plugin::AMD::VCEEncoder::GetMinimumQP() { - uint32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MIN_QP, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (uint8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetMaximumQP(uint8_t qp) { - // Clamp Value - qp = clamp(qp, 0, 51); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MAX_QP, (uint32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -uint8_t Plugin::AMD::VCEEncoder::GetMaximumQP() { - uint32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MAX_QP, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (uint8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetIFrameQP(uint8_t qp) { - // Clamp Value - qp = clamp(qp, 0, 51); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QP_I, (uint32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -uint8_t Plugin::AMD::VCEEncoder::GetIFrameQP() { - uint32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QP_I, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (uint8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetPFrameQP(uint8_t qp) { - // Clamp Value - qp = clamp(qp, 0, 51); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QP_P, (uint32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -uint8_t Plugin::AMD::VCEEncoder::GetPFrameQP() { - uint32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QP_P, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (uint8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetBFrameQP(uint8_t qp) { - // Clamp Value - qp = clamp(qp, 0, 51); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QP_B, (uint32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -uint8_t Plugin::AMD::VCEEncoder::GetBFrameQP() { - uint32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QP_B, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (uint8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetBPictureDeltaQP(int8_t qp) { - // Clamp Value - qp = clamp(qp, -10, 10); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, (int32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -int8_t Plugin::AMD::VCEEncoder::GetBPictureDeltaQP() { - int32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (int8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetReferenceBPictureDeltaQP(int8_t qp) { - // Clamp Value - qp = clamp(qp, -10, 10); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, (int32_t)qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); -} - -int8_t Plugin::AMD::VCEEncoder::GetReferenceBPictureDeltaQP() { - int32_t qp; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, &qp); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); - return (int8_t)qp; -} - -void Plugin::AMD::VCEEncoder::SetVBVBufferSize(uint32_t size) { - // Clamp Value - size = clamp(size, 1000, 100000000); // 1kbit to 100mbit. - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, (uint32_t)size); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, size); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", size); -} - -void Plugin::AMD::VCEEncoder::SetVBVBufferAutomatic(double_t strictness) { - uint32_t strictBitrate = 1000, looseBitrate = 100000000; - - // Strict VBV Buffer Size = Bitrate / FPS - // Loose VBV Buffer Size = Bitrate - - switch (this->GetRateControlMethod()) { - case VCERateControlMethod_ConstantBitrate: - case VCERateControlMethod_VariableBitrate_LatencyConstrained: - looseBitrate = this->GetTargetBitrate(); - break; - case VCERateControlMethod_VariableBitrate_PeakConstrained: - looseBitrate = max(this->GetTargetBitrate(), this->GetPeakBitrate()); - break; - case VCERateControlMethod_ConstantQP: - // When using Constant QP, one will have to pick a QP that is decent - // in both quality and bitrate. We can easily calculate both the QP - // required for an average bitrate and the average bitrate itself - // with these formulas: - // BITRATE = ((1 - (QP / 51)) ^ 2) * ((Width * Height) * 1.5 * (FPSNumerator / FPSDenumerator)) - // QP = (1 - sqrt(BITRATE / ((Width * Height) * 1.5 * (FPSNumerator / FPSDenumerator)))) * 51 - - auto frameSize = this->GetFrameSize(); - auto frameRate = this->GetFrameRate(); - - double_t bitrate = frameSize.first * frameSize.second; - switch (this->m_SurfaceFormat) { - case VCEColorFormat_NV12: - case VCEColorFormat_I420: - bitrate *= 1.5; - break; - case VCEColorFormat_YUY2: - bitrate *= 4; - break; - case VCEColorFormat_BGRA: - case VCEColorFormat_RGBA: - bitrate *= 3; - break; - case VCEColorFormat_GRAY: - bitrate *= 1; - break; - } - bitrate *= frameRate.first / frameRate.second; - - uint8_t qp_i, qp_p, qp_b; - qp_i = this->GetIFrameQP(); - qp_p = this->GetPFrameQP(); - try { qp_b = this->GetBFrameQP(); } catch (...) { qp_b = 51; } - double_t qp = 1 - ((double_t)(min(min(qp_i, qp_p), qp_b)) / 51.0); - qp = max(qp * qp, 0.001); // Needs to be at least 0.001. - - looseBitrate = static_cast<uint32_t>(bitrate * qp); - break; - } - strictBitrate = static_cast<uint32_t>(looseBitrate * m_FrameRateReverseDivisor); - - #define PI 3.14159265 - double_t interpVal = (sin(max(min(strictness, 1.0), 0.0) * 90 * (PI / 180))); // sin curve? - uint32_t realBitrate = static_cast<uint32_t>(ceil((strictBitrate * interpVal) + (looseBitrate * (1.0 - interpVal)))); - this->SetVBVBufferSize(realBitrate); -} - -uint32_t Plugin::AMD::VCEEncoder::GetVBVBufferSize() { - uint32_t size; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, &size); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); - return size; -} - -void Plugin::AMD::VCEEncoder::SetInitialVBVBufferFullness(double_t fullness) { - // Clamp Value - fullness = max(min(fullness, 1), 0); // 0 to 100 % - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, (uint32_t)(fullness * 64)); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %f%% failed with error %ls (code %d).", res, fullness * 100); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %f%%.", fullness * 100); -} - -double_t Plugin::AMD::VCEEncoder::GetInitialVBVBufferFullness() { - uint32_t vbvBufferFullness; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, &vbvBufferFullness); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %f%%.", vbvBufferFullness / 64.0 * 100.0); - return ((double_t)vbvBufferFullness / 64.0); -} - -void Plugin::AMD::VCEEncoder::SetMaximumAccessUnitSize(uint32_t size) { - // Clamp Value - size = max(min(size, 100000000), 0); // 1kbit to 100mbit. - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MAX_AU_SIZE, (uint32_t)size); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, size); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", size); -} - -uint32_t Plugin::AMD::VCEEncoder::GetMaximumAccessUnitSize() { - uint32_t size; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MAX_AU_SIZE, &size); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); - return size; -} - -void Plugin::AMD::VCEEncoder::SetFillerDataEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsFillerDataEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetFrameSkippingEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsFrameSkippingEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetEnforceHRDRestrictionsEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_ENFORCE_HRD, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsEnforceHRDRestrictionsEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_ENFORCE_HRD, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -/************************************************************************/ -/* Picture Control Properties */ -/************************************************************************/ - -void Plugin::AMD::VCEEncoder::SetIDRPeriod(uint32_t period) { - // Clamp Value - period = max(min(period, m_FrameRate.second * 1000), 1); // 1-1000 so that OBS can actually quit. - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_IDR_PERIOD, (uint32_t)period); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, period); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", period); -} - -uint32_t Plugin::AMD::VCEEncoder::GetIDRPeriod() { - int32_t period; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_IDR_PERIOD, &period); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", period); - return period; -} - -void Plugin::AMD::VCEEncoder::SetHeaderInsertionSpacing(uint32_t spacing) { - // Clamp Value - spacing = max(min(spacing, m_FrameRate.second * 1000), 0); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, (uint32_t)spacing); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, spacing); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", spacing); -} - -uint32_t Plugin::AMD::VCEEncoder::GetHeaderInsertionSpacing() { - int32_t headerInsertionSpacing; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, &headerInsertionSpacing); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", headerInsertionSpacing); - return headerInsertionSpacing; -} - -void Plugin::AMD::VCEEncoder::SetBPicturePattern(VCEBPicturePattern pattern) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_B_PIC_PATTERN, (uint32_t)pattern); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, pattern); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", pattern); -} - -Plugin::AMD::VCEBPicturePattern Plugin::AMD::VCEEncoder::GetBPicturePattern() { - uint32_t pattern; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_B_PIC_PATTERN, &pattern); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", pattern); - return (Plugin::AMD::VCEBPicturePattern)pattern; -} - -void Plugin::AMD::VCEEncoder::SetBPictureReferenceEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_B_REFERENCE_ENABLE, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsBPictureReferenceEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_B_REFERENCE_ENABLE, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetDeblockingFilterEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsDeblockingFilterEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetSlicesPerFrame(uint32_t slices) { - slices = max(slices, 1); - - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_SLICES_PER_FRAME, (uint32_t)slices); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, slices); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", slices); -} - -uint32_t Plugin::AMD::VCEEncoder::GetSlicesPerFrame() { - uint32_t slices; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_SLICES_PER_FRAME, &slices); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", slices); - return slices; -} - -void Plugin::AMD::VCEEncoder::SetIntraRefreshMBsNumberPerSlot(uint32_t mbs) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, (uint32_t)mbs); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, mbs); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", mbs); -} - -uint32_t Plugin::AMD::VCEEncoder::GetIntraRefreshMBsNumberPerSlot() { - int32_t mbs; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, &mbs); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", mbs); - return mbs; -} - -/************************************************************************/ -/* Miscellaneous Control Properties */ -/************************************************************************/ - -void Plugin::AMD::VCEEncoder::SetHalfPixelMotionEstimationEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsHalfPixelMotionEstimationEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetQuarterPixelMotionEstimationEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsQuarterPixelMotionEstimationEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -/************************************************************************/ -/* Hidden Properties */ -/************************************************************************/ - -void Plugin::AMD::VCEEncoder::SetGOPSize(uint32_t size) { - AMF_LOG_WARNING("Using unsupported SetGOPSize function. Unexpected behaviour may happen."); - - AMF_RESULT res = m_AMFEncoder->SetProperty(L"GOPSize", (uint32_t)size); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, size); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", size); -} - -uint32_t Plugin::AMD::VCEEncoder::GetGOPSize() { - AMF_LOG_WARNING("Using unsupported GetGOPSize function. Unexpected behaviour may happen."); - - uint32_t size; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"GOPSize", &size); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); - return size; -} - -void Plugin::AMD::VCEEncoder::SetWaitForTaskEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(L"WaitForTask", enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsWaitForTaskEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"WaitForTask", &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -} - -void Plugin::AMD::VCEEncoder::SetAspectRatio(uint32_t num, uint32_t den) { - AMF_RESULT res = m_AMFEncoder->SetProperty(L"AspectRatio", ::AMFConstructRate(num, den)); - if (res != AMF_OK) { - std::vector<char> msgBuf; - sprintf(msgBuf.data(), "%d:%d", num, den); - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, msgBuf.data()); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d:%d.", num, den); -} - -std::pair<uint32_t, uint32_t> Plugin::AMD::VCEEncoder::GetAspectRatio() { - AMFRate aspectRatio; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"AspectRatio", &aspectRatio); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d:%d.", aspectRatio.num, aspectRatio.den); - return std::pair<uint32_t, uint32_t>(aspectRatio.num, aspectRatio.den); -} - -void Plugin::AMD::VCEEncoder::SetMaximumNumberOfReferenceFrames(uint32_t numFrames) { - AMF_RESULT res = m_AMFEncoder->SetProperty(L"MaxNumRefFrames", (uint32_t)numFrames); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, numFrames); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", numFrames); -} - -uint32_t Plugin::AMD::VCEEncoder::GetMaximumNumberOfReferenceFrames() { - uint32_t numFrames; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"MaxNumRefFrames", &numFrames); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", numFrames); - return numFrames; -} - -uint32_t Plugin::AMD::VCEEncoder::GetMaxMBPerSec() { - uint32_t maxMBPerSec; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"MaxMBPerSec", &maxMBPerSec); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", maxMBPerSec); - return maxMBPerSec; -} - -void Plugin::AMD::VCEEncoder::SetVBAQEnabled(bool enabled) { - -} - -bool Plugin::AMD::VCEEncoder::IsVBAQEnabled() { - return false; -} - -void Plugin::AMD::VCEEncoder::SetRateControlPreanalysisEnabled(bool enabled) { - AMF_RESULT res = m_AMFEncoder->SetProperty(L"RateControlPreanalysisEnable", enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); -} - -bool Plugin::AMD::VCEEncoder::IsRateControlPreanalysisEnabled() { - bool enabled; - AMF_RESULT res = m_AMFEncoder->GetProperty(L"RateControlPreanalysisEnable", &enabled); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); - } - AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); - return enabled; -}
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/amd-amf.cpp
Deleted
@@ -1,264 +0,0 @@ -/* -MIT License - -Copyright (c) 2016 Michael Fabian Dirks - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -////////////////////////////////////////////////////////////////////////// -// Includes -////////////////////////////////////////////////////////////////////////// -#include <vector> -#include <mutex> - -#include "amd-amf.h" -#include "windows.h" - -// AMD AMF SDK -#include "components\Component.h" -#include "components\ComponentCaps.h" -#include "components\VideoEncoderVCE.h" - -////////////////////////////////////////////////////////////////////////// -// Code -////////////////////////////////////////////////////////////////////////// -using namespace Plugin::AMD; - -class CustomWriter : public amf::AMFTraceWriter { - public: - virtual void Write(const wchar_t* scope, const wchar_t* message) override { - const wchar_t* realmsg = &(message[(33 + wcslen(scope) + 2)]); // Skip Time & Scope - size_t msgLen = wcslen(realmsg) - (sizeof(wchar_t)); - - blog(LOG_INFO, "[%ls] %.*ls", scope, msgLen, realmsg); - } - - virtual void Flush() override {} - - static std::shared_ptr<CustomWriter> GetInstance() { - static std::shared_ptr<CustomWriter> __instance = std::make_shared<CustomWriter>(); - static std::mutex __mutex; - - const std::lock_guard<std::mutex> lock(__mutex); - return __instance; - } -}; - -std::shared_ptr<Plugin::AMD::AMF> Plugin::AMD::AMF::GetInstance() { - static std::shared_ptr<AMF> __instance = std::make_shared<AMF>(); - static std::mutex __mutex; - - const std::lock_guard<std::mutex> lock(__mutex); - return __instance; -} - -Plugin::AMD::AMF::AMF() { - AMF_RESULT res = AMF_OK; - - // Initialize AMF Library - AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Initializing..."); - - #pragma region Null Class Members - m_TimerPeriod = 0; - m_AMFVersion_Compiler = 0; - m_AMFVersion_Runtime = 0; - m_AMFModule = 0; - - m_AMFFactory = nullptr; - m_AMFTrace = nullptr; - m_AMFDebug = nullptr; - AMFQueryVersion = nullptr; - AMFInit = nullptr; - #pragma endregion Null Class Members - - /// Load AMF Runtime into Memory. - m_AMFModule = LoadLibraryW(AMF_DLL_NAME); - if (!m_AMFModule) { - DWORD error = GetLastError(); - std::vector<char> buf(1024); - sprintf(buf.data(), "Unable to load '%ls', error code %ld.", AMF_DLL_NAME, error); - AMF_LOG_ERROR("%s", buf.data()); - throw std::exception(buf.data(), error); - } - AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Loaded '%ls'.", AMF_DLL_NAME); - #ifdef _WIN32 // Windows: Get Product Version - std::vector<char> verbuf(GetFileVersionInfoSizeW(AMF_DLL_NAME, nullptr)); - GetFileVersionInfoW(AMF_DLL_NAME, 0, (DWORD)verbuf.size(), verbuf.data()); - - void* pBlock = verbuf.data(); - - // Read the list of languages and code pages. - struct LANGANDCODEPAGE { - WORD wLanguage; - WORD wCodePage; - } *lpTranslate; - UINT cbTranslate = sizeof(LANGANDCODEPAGE); - - VerQueryValueA(pBlock, "\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate); - - std::vector<char> buf(1024); - sprintf(buf.data(), "%s%04x%04x%s", - "\\StringFileInfo\\", - lpTranslate[0].wLanguage, - lpTranslate[0].wCodePage, - "\\ProductVersion"); - - // Retrieve file description for language and code page "i". - void* lpBuffer; - uint32_t dwBytes; - VerQueryValueA(pBlock, buf.data(), &lpBuffer, &dwBytes); - - AMF_LOG_INFO("Runtime Library is on Version %.*s.", dwBytes, lpBuffer); - #endif _WIN32 // Windows: Get Product Version - - /// Find Function for Querying AMF Version. - #pragma region Query AMF Runtime Version - AMFQueryVersion = (AMFQueryVersion_Fn)GetProcAddress(m_AMFModule, AMF_QUERY_VERSION_FUNCTION_NAME); - if (!AMFQueryVersion) { - DWORD error = GetLastError(); - std::vector<char> buf(1024); - sprintf(buf.data(), "<Plugin::AMD::AMF::AMF> Finding Address of Function '%s' failed with error code %ld.", AMF_QUERY_VERSION_FUNCTION_NAME, error); - AMF_LOG_ERROR("%s", buf.data()); - throw std::exception(buf.data(), error); - } - /// Query Runtime Version - m_AMFVersion_Compiler = AMF_FULL_VERSION; - res = AMFQueryVersion(&m_AMFVersion_Runtime); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<Plugin::AMD::AMF::AMF> Querying Version failed with error %ls (code %ld).", res); - /// Log some Information for Supporters. - AMF_LOG_INFO("Runtime is on Version %d.%d.%d.%d, compiled against Version %d.%d.%d.%d.", - (uint16_t)((m_AMFVersion_Runtime >> 48ull) & 0xFFFF), - (uint16_t)((m_AMFVersion_Runtime >> 32ull) & 0xFFFF), - (uint16_t)((m_AMFVersion_Runtime >> 16ull) & 0xFFFF), - (uint16_t)((m_AMFVersion_Runtime & 0xFFFF)), - (uint16_t)((m_AMFVersion_Compiler >> 48ull) & 0xFFFF), - (uint16_t)((m_AMFVersion_Compiler >> 32ull) & 0xFFFF), - (uint16_t)((m_AMFVersion_Compiler >> 16ull) & 0xFFFF), - (uint16_t)((m_AMFVersion_Compiler & 0xFFFF))); - #pragma endregion Query AMF Runtime Version - - /// Find Function for Initializing AMF. - AMFInit = (AMFInit_Fn)GetProcAddress(m_AMFModule, AMF_INIT_FUNCTION_NAME); - if (!AMFInit) { - DWORD error = GetLastError(); - std::vector<char> buf(1024); - sprintf(buf.data(), "<Plugin::AMD::AMF::AMF> Finding Address of Function '%s' failed with error code %ld.", AMF_INIT_FUNCTION_NAME, error); - AMF_LOG_ERROR("%s", buf.data()); - throw std::exception(buf.data(), error); - } else { - res = AMFInit(m_AMFVersion_Runtime, &m_AMFFactory); - if (res != AMF_OK) - ThrowExceptionWithAMFError("<Plugin::AMD::AMF::AMF> Initializing AMF Library failed with error %ls (code %ld).", res); - } - AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> AMF Library initialized."); - - /// Retrieve Trace Object. - res = m_AMFFactory->GetTrace(&m_AMFTrace); - if (res != AMF_OK) { - ThrowExceptionWithAMFError("<Plugin::AMD::AMF::AMF> Retrieving Trace object failed with error %ls (code %ld).", res); - } - - /// Retrieve Debug Object. - res = m_AMFFactory->GetDebug(&m_AMFDebug); - if (res != AMF_OK) { - AMF_LOG_ERROR("<Plugin::AMD::AMF::AMF> Retrieving Debug object failed with error code %ls (code %ld).", res); - throw std::exception("", res); - } - - /// Register Custom Trace Writer and disable Debug Tracing. - m_AMFTrace->RegisterWriter(L"OBSWriter", CustomWriter::GetInstance().get(), true); - this->EnableDebugTrace(false); - - AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Initialized."); -} - -Plugin::AMD::AMF::~AMF() { - AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Finalizing."); - - /// Unregister Writer - if (m_AMFTrace) - m_AMFTrace->UnregisterWriter(L"OBSWriter"); - - // Free Library again - if (m_AMFModule) - FreeLibrary(m_AMFModule); - - #pragma region Null Class Members - m_TimerPeriod = 0; - m_AMFVersion_Compiler = 0; - m_AMFVersion_Runtime = 0; - m_AMFModule = 0; - - m_AMFFactory = nullptr; - m_AMFTrace = nullptr; - m_AMFDebug = nullptr; - AMFQueryVersion = nullptr; - AMFInit = nullptr; - #pragma endregion Null Class Members - - AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Finalized."); -} - -amf::AMFFactory* Plugin::AMD::AMF::GetFactory() { - return m_AMFFactory; -} - -amf::AMFTrace* Plugin::AMD::AMF::GetTrace() { - return m_AMFTrace; -} - -amf::AMFDebug* Plugin::AMD::AMF::GetDebug() { - return m_AMFDebug; -} - -void Plugin::AMD::AMF::EnableDebugTrace(bool enable) { - if (!m_AMFTrace) - throw std::exception(__FUNCTION_NAME__ " called without a AMFTrace object!"); - if (!m_AMFDebug) - throw std::exception(__FUNCTION_NAME__ " called without a AMFDebug object!"); - - m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_CONSOLE, false); - m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_CONSOLE, AMF_TRACE_ERROR); - #ifdef DEBUG - m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_DEBUG_OUTPUT, true); - m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TEST); - m_AMFTrace->SetPath(L"C:/AMFTrace.log"); - #else - m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_DEBUG_OUTPUT, false); - m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_ERROR); - #endif - m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_FILE, false); - m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_FILE, AMF_TRACE_ERROR); - - if (enable) { - m_AMFDebug->AssertsEnable(true); - m_AMFDebug->EnablePerformanceMonitor(true); - m_AMFTrace->TraceEnableAsync(true); - m_AMFTrace->SetGlobalLevel(AMF_TRACE_TEST); - m_AMFTrace->SetWriterLevel(L"OBSWriter", AMF_TRACE_TEST); - } else { - m_AMFDebug->AssertsEnable(false); - m_AMFDebug->EnablePerformanceMonitor(false); - m_AMFTrace->TraceEnableAsync(true); - m_AMFTrace->SetGlobalLevel(AMF_TRACE_WARNING); - m_AMFTrace->SetWriterLevel(L"OBSWriter", AMF_TRACE_WARNING); - } -}
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/color-filter.c
Deleted
@@ -1,174 +0,0 @@ -#include <obs-module.h> -#include <graphics/vec4.h> - -#define SETTING_COLOR "color" -#define SETTING_OPACITY "opacity" -#define SETTING_CONTRAST "contrast" -#define SETTING_BRIGHTNESS "brightness" -#define SETTING_GAMMA "gamma" - -#define TEXT_COLOR obs_module_text("Color") -#define TEXT_OPACITY obs_module_text("Opacity") -#define TEXT_CONTRAST obs_module_text("Contrast") -#define TEXT_BRIGHTNESS obs_module_text("Brightness") -#define TEXT_GAMMA obs_module_text("Gamma") - -#define MIN_CONTRAST 0.5f -#define MAX_CONTRAST 2.0f -#define MIN_BRIGHTNESS -1.0 -#define MAX_BRIGHTNESS 1.0 - -struct color_filter_data { - obs_source_t *context; - - gs_effect_t *effect; - - gs_eparam_t *color_param; - gs_eparam_t *contrast_param; - gs_eparam_t *brightness_param; - gs_eparam_t *gamma_param; - - struct vec4 color; - float contrast; - float brightness; - float gamma; -}; - -static const char *color_filter_name(void *unused) -{ - UNUSED_PARAMETER(unused); - return obs_module_text("ColorFilter"); -} - -static void color_filter_update(void *data, obs_data_t *settings) -{ - struct color_filter_data *filter = data; - uint32_t color = (uint32_t)obs_data_get_int(settings, SETTING_COLOR); - uint32_t opacity = (uint32_t)obs_data_get_int(settings, - SETTING_OPACITY); - double contrast = obs_data_get_double(settings, SETTING_CONTRAST); - double brightness = obs_data_get_double(settings, SETTING_BRIGHTNESS); - double gamma = obs_data_get_double(settings, SETTING_GAMMA); - - color &= 0xFFFFFF; - color |= ((opacity * 255) / 100) << 24; - - vec4_from_rgba(&filter->color, color); - - contrast = (contrast < 0.0) ? - (1.0 / (-contrast + 1.0)) : (contrast + 1.0); - - brightness *= 0.5; - - gamma = (gamma < 0.0) ? (-gamma + 1.0) : (1.0 / (gamma + 1.0)); - - filter->contrast = (float)contrast; - filter->brightness = (float)brightness; - filter->gamma = (float)gamma; -} - -static void color_filter_destroy(void *data) -{ - struct color_filter_data *filter = data; - - if (filter->effect) { - obs_enter_graphics(); - gs_effect_destroy(filter->effect); - obs_leave_graphics(); - } - - bfree(data); -} - -static void *color_filter_create(obs_data_t *settings, obs_source_t *context) -{ - struct color_filter_data *filter = - bzalloc(sizeof(struct color_filter_data)); - char *effect_path = obs_module_file("color_filter.effect"); - - filter->context = context; - - obs_enter_graphics(); - - filter->effect = gs_effect_create_from_file(effect_path, NULL); - if (filter->effect) { - filter->color_param = gs_effect_get_param_by_name( - filter->effect, "color"); - filter->contrast_param = gs_effect_get_param_by_name( - filter->effect, "contrast"); - filter->brightness_param = gs_effect_get_param_by_name( - filter->effect, "brightness"); - filter->gamma_param = gs_effect_get_param_by_name( - filter->effect, "gamma"); - } - - obs_leave_graphics(); - - bfree(effect_path); - - if (!filter->effect) { - color_filter_destroy(filter); - return NULL; - } - - color_filter_update(filter, settings); - return filter; -} - -static void color_filter_render(void *data, gs_effect_t *effect) -{ - struct color_filter_data *filter = data; - - if (!obs_source_process_filter_begin(filter->context, GS_RGBA, - OBS_ALLOW_DIRECT_RENDERING)) - return; - - gs_effect_set_vec4(filter->color_param, &filter->color); - gs_effect_set_float(filter->contrast_param, filter->contrast); - gs_effect_set_float(filter->brightness_param, filter->brightness); - gs_effect_set_float(filter->gamma_param, filter->gamma); - - obs_source_process_filter_end(filter->context, filter->effect, 0, 0); - - UNUSED_PARAMETER(effect); -} - -static obs_properties_t *color_filter_properties(void *data) -{ - obs_properties_t *props = obs_properties_create(); - - obs_properties_add_color(props, SETTING_COLOR, TEXT_COLOR); - obs_properties_add_int(props, SETTING_OPACITY, TEXT_OPACITY, - 0, 100, 1); - obs_properties_add_float_slider(props, SETTING_CONTRAST, - TEXT_CONTRAST, -1.0, 1.0, 0.01); - obs_properties_add_float_slider(props, SETTING_BRIGHTNESS, - TEXT_BRIGHTNESS, -1.0, 1.0, 0.01); - obs_properties_add_float_slider(props, SETTING_GAMMA, - TEXT_GAMMA, -1.0, 1.0, 0.01); - - UNUSED_PARAMETER(data); - return props; -} - -static void color_filter_defaults(obs_data_t *settings) -{ - obs_data_set_default_int(settings, SETTING_COLOR, 0xFFFFFF); - obs_data_set_default_int(settings, SETTING_OPACITY, 100); - obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0); - obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0); - obs_data_set_default_double(settings, SETTING_GAMMA, 0.0); -} - -struct obs_source_info color_filter = { - .id = "color_filter", - .type = OBS_SOURCE_TYPE_FILTER, - .output_flags = OBS_SOURCE_VIDEO, - .get_name = color_filter_name, - .create = color_filter_create, - .destroy = color_filter_destroy, - .video_render = color_filter_render, - .update = color_filter_update, - .get_properties = color_filter_properties, - .get_defaults = color_filter_defaults -};
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/color_filter.effect
Deleted
@@ -1,46 +0,0 @@ -uniform float4x4 ViewProj; -uniform texture2d image; - -uniform float4 color; -uniform float contrast; -uniform float brightness; -uniform float gamma; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; - -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -VertData VSDefault(VertData v_in) -{ - VertData vert_out; - vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj); - vert_out.uv = v_in.uv; - return vert_out; -} - -float4 CalcColor(float4 rgba) -{ - return float4(pow(rgba.rgb, float3(gamma, gamma, gamma)) * contrast + brightness, rgba.a); -} - -float4 PSColorFilterRGBA(VertData v_in) : TARGET -{ - float4 rgba = image.Sample(textureSampler, v_in.uv) * color; - return CalcColor(rgba); -} - -technique Draw -{ - pass - { - vertex_shader = VSDefault(v_in); - pixel_shader = PSColorFilterRGBA(v_in); - } -}
View file
obs-studio-0.16.6.tar.xz/.travis.yml -> obs-studio-0.17.0.tar.xz/.travis.yml
Changed
@@ -1,5 +1,4 @@ os: osx -osx_image: xcode7.1 env: matrix: - CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake @@ -9,14 +8,11 @@ - secure: "MfhOg+84yb4ZHB2tM8PIPFQX2Y+WLN0I0iiAgyLC4KaHPUoNOyloe9yk6OjV7Lj7SZWqTlQUsqHa8S9mOUswGIody1Ydglo4RvyGOKCd8I6b2ri/jE8qHVuD9sO+sNlIxq4YqqG/qReTsbSs2YEgLneZUCYLCk/fihl8L6eVuSc=" # secret - secure: "JRQVU2zgC3hY6CEY+Crmh/upp93En0BzKaLcsuBT538johNlK7m5hn3m2UOw63seLvBvVaKKWUDj9N986a3DwcXxWPMyF/9ctXgNWy39WzaVWxrbVR5nQB1fdiRp5YEgkoVN+gEm3OVF7sV5AGzh5/8CvEdRCoTLIGgMGHxW9mc=" - language: cpp - before_install: "./CI/install-dependencies-osx.sh" before_script: "./CI/before-script-osx.sh" script: cd ./build && make -j4 && cd - before_deploy: "./CI/before-deploy-osx.sh" - deploy: provider: s3 access_key_id: $AWS_ACCESS_KEY
View file
obs-studio-0.16.6.tar.xz/CI/install-dependencies-osx.sh -> obs-studio-0.17.0.tar.xz/CI/install-dependencies-osx.sh
Changed
@@ -1,7 +1,7 @@ brew update #Base OBS Deps -brew install ffmpeg x264 qt5 python cmake +brew install ffmpeg x264 qt5 # CEF Stuff cd ../
View file
obs-studio-0.16.6.tar.xz/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/CMakeLists.txt
Changed
@@ -2,6 +2,8 @@ project(obs-studio) +option(BUILD_CAPTIONS "Build captions" FALSE) + if(WIN32) if (QTDIR OR DEFINED ENV{QTDIR} OR DEFINED ENV{QTDIR32} OR DEFINED ENV{QTDIR64}) # Qt path set by user or env var @@ -60,7 +62,7 @@ endif() if(WIN32) - add_definitions(-DUNICODE -D_UNICODE) + add_definitions(-DUNICODE -D_UNICODE -D_CRT_SECURE_NO_WARNINGS) endif() if(MSVC)
View file
obs-studio-0.16.6.tar.xz/UI/adv-audio-control.cpp -> obs-studio-0.17.0.tar.xz/UI/adv-audio-control.cpp
Changed
@@ -35,6 +35,8 @@ mixer2 = new QCheckBox(); mixer3 = new QCheckBox(); mixer4 = new QCheckBox(); + mixer5 = new QCheckBox(); + mixer6 = new QCheckBox(); volChangedSignal.Connect(handler, "volume", OBSSourceVolumeChanged, this); @@ -93,6 +95,10 @@ mixer3->setChecked(mixers & (1<<2)); mixer4->setText("4"); mixer4->setChecked(mixers & (1<<3)); + mixer5->setText("5"); + mixer5->setChecked(mixers & (1<<4)); + mixer6->setText("6"); + mixer6->setChecked(mixers & (1<<5)); panningContainer->layout()->addWidget(labelL); panningContainer->layout()->addWidget(panning); @@ -103,6 +109,8 @@ mixerContainer->layout()->addWidget(mixer2); mixerContainer->layout()->addWidget(mixer3); mixerContainer->layout()->addWidget(mixer4); + mixerContainer->layout()->addWidget(mixer5); + mixerContainer->layout()->addWidget(mixer6); QWidget::connect(volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); @@ -120,6 +128,10 @@ this, SLOT(mixer3Changed(bool))); QWidget::connect(mixer4, SIGNAL(clicked(bool)), this, SLOT(mixer4Changed(bool))); + QWidget::connect(mixer5, SIGNAL(clicked(bool)), + this, SLOT(mixer5Changed(bool))); + QWidget::connect(mixer6, SIGNAL(clicked(bool)), + this, SLOT(mixer6Changed(bool))); int lastRow = layout->rowCount(); @@ -209,6 +221,8 @@ setCheckboxState(mixer2, mixers & (1<<1)); setCheckboxState(mixer3, mixers & (1<<2)); setCheckboxState(mixer4, mixers & (1<<3)); + setCheckboxState(mixer5, mixers & (1<<4)); + setCheckboxState(mixer6, mixers & (1<<5)); } /* ------------------------------------------------------------------------- */ @@ -281,3 +295,13 @@ { setMixer(source, 3, checked); } + +void OBSAdvAudioCtrl::mixer5Changed(bool checked) +{ + setMixer(source, 4, checked); +} + +void OBSAdvAudioCtrl::mixer6Changed(bool checked) +{ + setMixer(source, 5, checked); +}
View file
obs-studio-0.16.6.tar.xz/UI/adv-audio-control.hpp -> obs-studio-0.17.0.tar.xz/UI/adv-audio-control.hpp
Changed
@@ -31,6 +31,8 @@ QPointer<QCheckBox> mixer2; QPointer<QCheckBox> mixer3; QPointer<QCheckBox> mixer4; + QPointer<QCheckBox> mixer5; + QPointer<QCheckBox> mixer6; OBSSignal volChangedSignal; OBSSignal syncOffsetSignal; @@ -62,4 +64,6 @@ void mixer2Changed(bool checked); void mixer3Changed(bool checked); void mixer4Changed(bool checked); + void mixer5Changed(bool checked); + void mixer6Changed(bool checked); };
View file
obs-studio-0.16.6.tar.xz/UI/api-interface.cpp -> obs-studio-0.17.0.tar.xz/UI/api-interface.cpp
Changed
@@ -234,6 +234,21 @@ return main->outputHandler->RecordingActive(); } + void obs_frontend_replay_buffer_start(void) override + { + QMetaObject::invokeMethod(main, "StartReplayBuffer"); + } + + void obs_frontend_replay_buffer_stop(void) override + { + QMetaObject::invokeMethod(main, "StopReplayBuffer"); + } + + bool obs_frontend_replay_buffer_active(void) override + { + return main->outputHandler->ReplayBufferActive(); + } + void *obs_frontend_add_tools_menu_qaction(const char *name) override { main->ui->menuTools->setEnabled(true); @@ -286,6 +301,13 @@ return out; } + obs_output_t *obs_frontend_get_replay_buffer_output(void) override + { + OBSOutput out = main->outputHandler->replayBuffer; + obs_output_addref(out); + return out; + } + config_t *obs_frontend_get_profile_config(void) override { return main->basicConfig;
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ar-SA.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ar-SA.ini
Changed
@@ -58,7 +58,6 @@ QuickTransitions.HotkeyName="الانتقال السريع: %1" Basic.AddTransition="إضافة المراحل الانتقالية للتكوين" -Basic.RemoveTransition="سلاو" Basic.TransitionProperties="خصائص تأثير الإنتقال" Basic.SceneTransitions="تأثير انتقال المشهد" Basic.TransitionDuration="مدة الانتقال"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/bg-BG.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/bg-BG.ini
Changed
@@ -284,10 +284,6 @@ Basic.Settings.Hotkeys="Горещи клавиши" -Basic.Hotkeys.StartStreaming="Започни стрийм" -Basic.Hotkeys.StopStreaming="Спри стрийм" -Basic.Hotkeys.StartRecording="Започни запис" -Basic.Hotkeys.StopRecording="Спри запис" Basic.Hotkeys.SelectScene="Премини към сцена"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ca-ES.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ca-ES.ini
Changed
@@ -492,10 +492,6 @@ Basic.Settings.Hotkeys="Dreceres de teclat" Basic.Settings.Hotkeys.Pair="Combinacions de tecles compartides amb '%1' actuen com a palanques" -Basic.Hotkeys.StartStreaming="Inicia el directe" -Basic.Hotkeys.StopStreaming="Atura el directe" -Basic.Hotkeys.StartRecording="Inicia l'enregistrament" -Basic.Hotkeys.StopRecording="Atura l'enregistrament" Basic.Hotkeys.SelectScene="Canviar a escena" Basic.SystemTray.Show="Mostra"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/cs-CZ.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/cs-CZ.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Minuty" Seconds="Vteřiny" Deprecated="Zastaralé" +ReplayBuffer="Záznam do paměti" +Import="Importovat" +Export="Exportovat" QuickTransitions.SwapScenes="Prohodit scény náhledu a výstupu po přechodu" QuickTransitions.SwapScenesTT="Prohodí scény náhledu a výstupu po přechodu (pokud originální výstupní scéna stále existuje).\nTato funkce nevrátí provedené změny, které byly provedeny v originální scéně výstupu." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Pro pokračování nahrávání není dostatek místa na disku." Output.RecordError.Title="Chyba při nahrávání" Output.RecordError.Msg="Při nahrávání došlo k nespecifikované chybě." +Output.ReplayBuffer.NoHotkey.Title="Nepřiřazena žádná klávesová zkratka!" +Output.ReplayBuffer.NoHotkey.Msg="Není nastavena žádná klávesová zkratka pro uložení záznamu. Nastavte ji prosím, abyste jej mohli ukládat." Output.BadPath.Title="Špatná cesta k souboru" Output.BadPath.Text="Nastavená cesta k výstupnímu souboru je chybná. Zkontrolujte nastavení, zda není cesta špatně napsána." @@ -262,9 +267,12 @@ Basic.Main.Sources="Zdroje" Basic.Main.Connecting="Připojování..." Basic.Main.StartRecording="Začít nahrávat" +Basic.Main.StartReplayBuffer="Spustit záznam do paměti" Basic.Main.StartStreaming="Začít vysílat" Basic.Main.StopRecording="Zastavit nahrávání" Basic.Main.StoppingRecording="Zastavuji nahrávání..." +Basic.Main.StopReplayBuffer="Zastavit záznam do paměti" +Basic.Main.StoppingReplayBuffer="Zastavuji záznam do paměti..." Basic.Main.StopStreaming="Zastavit vysílání" Basic.Main.StoppingStreaming="Zastavuji vysílání..." Basic.Main.ForceStopStreaming="Zastavit vysání (bez zpoždění)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Výstup (%1x%2)" Basic.MainMenu.Edit.Transform="Pozicování (&T)" Basic.MainMenu.Edit.Transform.EditTransform="Upravit pozici... (&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="Kopírovat transformaci" +Basic.MainMenu.Edit.Transform.PasteTransform="Vložit transformaci" Basic.MainMenu.Edit.Transform.ResetTransform="Obnovit pozici (&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="Otočit o 90 stupňů vpravo" Basic.MainMenu.Edit.Transform.Rotate90CCW="Otočit o 90 stupňů vlevo" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="Kolekce &scén" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile.Import="Importovat profil" +Basic.MainMenu.Profile.Export="Exportovat profil" +Basic.MainMenu.SceneCollection.Import="Importovat kolekci scén" +Basic.MainMenu.SceneCollection.Export="Exportovat kolekci scén" +Basic.MainMenu.Profile.Exists="Tento profil již existuje" +Basic.MainMenu.SceneCollection.Exists="Tato kolekce scén již existuje" Basic.MainMenu.Tools="Nás&troje" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Jednoduché" Basic.Settings.Output.Mode.Adv="Rozšířené" Basic.Settings.Output.Mode.FFmpeg="Výstup FFmpeg" +Basic.Settings.Output.UseReplayBuffer="Povolit záznam od paměti" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximální čas záznamu (s)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximální využití paměti (MB)" +Basic.Settings.Output.ReplayBuffer.Estimate="Přibližné využití paměti: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nedokáži odhadnout využití paměti. Nastavte, prosím, maximální využití paměti." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Poznámka: Nezapomeňte si nastavit klávesovou zkratku pro tuto funkci)" +Basic.Settings.Output.ReplayBuffer.Prefix="Přípona souboru záznamu do paměti" +Basic.Settings.Output.ReplayBuffer.Suffix="Přípona" Basic.Settings.Output.Simple.SavePath="Cesta pro nahrávání" Basic.Settings.Output.Simple.RecordingQuality="Nahrávací kvalita" Basic.Settings.Output.Simple.RecordingQuality.Stream="Stejná jako vysílaná" @@ -497,10 +521,6 @@ Basic.Settings.Hotkeys="Zkratky" Basic.Settings.Hotkeys.Pair="Kombinace kláves je sdílená s '%1' funguje jako přepínač" -Basic.Hotkeys.StartStreaming="Začít vysílat" -Basic.Hotkeys.StopStreaming="Zastavit vysílání" -Basic.Hotkeys.StartRecording="Začít nahrávat" -Basic.Hotkeys.StopRecording="Zastavit nahrávání" Basic.Hotkeys.SelectScene="Přepnout na scénu" Basic.SystemTray.Show="Zobrazit"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/da-DK.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/da-DK.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Minutter" Seconds="Sekunder" Deprecated="Ophørt" +ReplayBuffer="Genafspilningsbuffer" +Import="Importér" +Export="Eksportér" QuickTransitions.SwapScenes="Byt om på forhåndsvisning/output scener efter overgang" QuickTransitions.SwapScenesTT="Ombytter uddrag- og output-scener efter omskiftning (hvis oprindelige output-scene stadig eksisterer).\nDette vil ikke omgøre eventuelle ændringer, der måtte været udført på den oprindelige output-scene." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Der er ikke tilstrækkelig diskplads til at fortsætte optagelsen." Output.RecordError.Title="Optagelsesfejl" Output.RecordError.Msg="Der opstod en uangivet fejl under optagelsen." +Output.ReplayBuffer.NoHotkey.Title="Ingen genvejstast sat!" +Output.ReplayBuffer.NoHotkey.Msg="Ingen Gem-genvejstast sat til genafspilningsbuffer. Sæt venligst \"Gem\"-genvejstasten til brug for at gemme genafspilningsoptagelser." Output.BadPath.Title="Dårlig filsti" Output.BadPath.Text="Den konfigureret output sti er ugyldig. Kontroller indstillinger for at bekræfte, at en gyldig filsti er angivet." @@ -262,9 +267,12 @@ Basic.Main.Sources="Kilder" Basic.Main.Connecting="Forbinder..." Basic.Main.StartRecording="Start optagelse" +Basic.Main.StartReplayBuffer="Start Genafspilningsbuffer" Basic.Main.StartStreaming="Start streaming" Basic.Main.StopRecording="Stop optagelse" Basic.Main.StoppingRecording="Stopper optagelse..." +Basic.Main.StopReplayBuffer="Stop Genafspilningsbuffer" +Basic.Main.StoppingReplayBuffer="Stopper Genafspilningsbuffer..." Basic.Main.StopStreaming="Stop streaming" Basic.Main.StoppingStreaming="Stopper stream..." Basic.Main.ForceStopStreaming="Stop streaming (ignorer forsinkelse)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Output (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformering" Basic.MainMenu.Edit.Transform.EditTransform="Rediger transformering... (&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="Kopiér transformation" +Basic.MainMenu.Edit.Transform.PasteTransform="Indsæt transformation" Basic.MainMenu.Edit.Transform.ResetTransform="Nulstille transformering (&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="Roter 90 grader CW" Basic.MainMenu.Edit.Transform.Rotate90CCW="Roter 90 grader CCW" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Scenesamling" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile.Import="Importér profil" +Basic.MainMenu.Profile.Export="Eksportér profil" +Basic.MainMenu.SceneCollection.Import="Importér scenesamling" +Basic.MainMenu.SceneCollection.Export="Eksportér scenesamling" +Basic.MainMenu.Profile.Exists="Profilen findes allerede" +Basic.MainMenu.SceneCollection.Exists="Scenesamlingen findes allerede" Basic.MainMenu.Tools="Værk&tøjer" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Simpel" Basic.Settings.Output.Mode.Adv="Avanceret" Basic.Settings.Output.Mode.FFmpeg="FFmpeg output" +Basic.Settings.Output.UseReplayBuffer="Aktivér Genafspilningsbuffer" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksimal genafspilningstid (sek.)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksimal hukommelse (MB)" +Basic.Settings.Output.ReplayBuffer.Estimate="Anslået hukommelsesforbrug: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Ikke kan beregne hukommelsesforbrug. Sæt venligst maks. hukommelsesgrænse." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Bemærk: Sørg for at sætte en genvejstast til genafspilningsbufferen i sektionen for genvejstaster)" +Basic.Settings.Output.ReplayBuffer.Prefix="Genafspilningsbuffer filnavn præfiks" +Basic.Settings.Output.ReplayBuffer.Suffix="Endelse" Basic.Settings.Output.Simple.SavePath="Optagelsessti" Basic.Settings.Output.Simple.RecordingQuality="Optagelseskvalitet" Basic.Settings.Output.Simple.RecordingQuality.Stream="Samme som stream" @@ -497,10 +521,6 @@ Basic.Settings.Hotkeys="Genvejstaster" Basic.Settings.Hotkeys.Pair="Tastekombinationer delt med '%1' fungerer som omskiftere" -Basic.Hotkeys.StartStreaming="Start streaming" -Basic.Hotkeys.StopStreaming="Stop streaming" -Basic.Hotkeys.StartRecording="Start optagelse" -Basic.Hotkeys.StopRecording="Stop optagelse" Basic.Hotkeys.SelectScene="Skift til scene" Basic.SystemTray.Show="Vis"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/de-DE.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/de-DE.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Minute(n)" Seconds="Sekunde(n)" Deprecated="Veraltet" +ReplayBuffer="Replaypuffer" +Import="Importieren" +Export="Exportieren" QuickTransitions.SwapScenes="Tausche Vorschau/Ausgabe-Szenen nach dem Übergang" QuickTransitions.SwapScenesTT="Vertauscht die Vorschau- und Ausgabe-Szenen nach dem Übergang (falls die ursprüngliche Ausgabe-Szene noch vorhanden ist).\nEventuelle Änderungen an der original Ausgabe-Szene werden hierbei nicht rückgängig gemacht." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Es gibt nicht genügend Speicherplatz, um die Aufnahme fortzusetzen." Output.RecordError.Title="Aufnahmefehler" Output.RecordError.Msg="Während der Aufnahme ist ein unbekannter Fehler aufgetreten." +Output.ReplayBuffer.NoHotkey.Title="Kein Hotkey festgelegt!" +Output.ReplayBuffer.NoHotkey.Msg="Kein Speichern Hotkey festgelegt für Replaypuffer. Legen Sie bitte den \"Speichern\" Hotkey fest, der zum Speichern der Replayaufnahmen verwendet werden soll." Output.BadPath.Title="Ungültiger Dateipfad" Output.BadPath.Text="Der konfigurierte Ausgabepfad ist ungültig. Bitte überprüfen Sie Ihre Einstellungen und stellen Sie sicher, dass ein gültiger Pfad angegeben wurde." @@ -262,9 +267,12 @@ Basic.Main.Sources="Quellen" Basic.Main.Connecting="Verbinden..." Basic.Main.StartRecording="Aufnahme starten" +Basic.Main.StartReplayBuffer="Replaypuffer starten" Basic.Main.StartStreaming="Streaming starten" Basic.Main.StopRecording="Aufnahme stoppen" Basic.Main.StoppingRecording="Stoppe Aufnahme..." +Basic.Main.StopReplayBuffer="Replaypuffer stoppen" +Basic.Main.StoppingReplayBuffer="Stoppe Replaypuffer..." Basic.Main.StopStreaming="Streaming stoppen" Basic.Main.StoppingStreaming="Stoppe Stream..." Basic.Main.ForceStopStreaming="Streaming stoppen (Verzögerung verwerfen)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Ausgabe (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformieren" Basic.MainMenu.Edit.Transform.EditTransform="Transformation b&earbeiten..." +Basic.MainMenu.Edit.Transform.CopyTransform="Transformation kopieren" +Basic.MainMenu.Edit.Transform.PasteTransform="Transformation einfügen" Basic.MainMenu.Edit.Transform.ResetTransform="Transformation zu&rücksetzen" Basic.MainMenu.Edit.Transform.Rotate90CW="Um 90° im Uhrzeigersinn drehen" Basic.MainMenu.Edit.Transform.Rotate90CCW="Um 90° gegen den Uhrzeigersinn drehen" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Szenen-Sammlung" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile.Import="Profil importieren" +Basic.MainMenu.Profile.Export="Profil exportieren" +Basic.MainMenu.SceneCollection.Import="Szenen-Sammlung importieren" +Basic.MainMenu.SceneCollection.Export="Szenen-Sammlung exportieren" +Basic.MainMenu.Profile.Exists="Das Profil ist bereits vorhanden" +Basic.MainMenu.SceneCollection.Exists="Die Szenen-Sammlung existiert bereits" Basic.MainMenu.Tools="Werkzeuge (&T)" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Einfach" Basic.Settings.Output.Mode.Adv="Erweitert" Basic.Settings.Output.Mode.FFmpeg="FFmpeg Ausgabe" +Basic.Settings.Output.UseReplayBuffer="Replaypuffer aktivieren" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximale Replayzeit (Sekunden)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximale Speichernutzung (RAM) in Megabyte" +Basic.Settings.Output.ReplayBuffer.Estimate="Geschätzte Speichernutzung (RAM): %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Speichernutzung kann nicht geschätzt werden. Stellen Sie bitte die maximale Speichergrenze ein." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Hinweis: Achten Sie darauf, einen Hotkey für den Replaypuffer im Abschnitt Hotkeys festzulegen)" +Basic.Settings.Output.ReplayBuffer.Prefix="Replaypuffer Dateiname Prefix" +Basic.Settings.Output.ReplayBuffer.Suffix="Suffix" Basic.Settings.Output.Simple.SavePath="Aufnahmepfad" Basic.Settings.Output.Simple.RecordingQuality="Aufnahmequalität" Basic.Settings.Output.Simple.RecordingQuality.Stream="Gleiche wie Stream" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Spur 2" Basic.Settings.Output.Adv.Audio.Track3="Spur 3" Basic.Settings.Output.Adv.Audio.Track4="Spur 4" +Basic.Settings.Output.Adv.Audio.Track5="Spur 5" +Basic.Settings.Output.Adv.Audio.Track6="Spur 6" Basic.Settings.Output.Adv.Recording="Aufnehmen" Basic.Settings.Output.Adv.Recording.Type="Art" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="Hotkeys" Basic.Settings.Hotkeys.Pair="Mit '%1' geteilte Tastenkombinationen funktionieren als Schalter" -Basic.Hotkeys.StartStreaming="Streaming starten" -Basic.Hotkeys.StopStreaming="Streaming stoppen" -Basic.Hotkeys.StartRecording="Aufnahme starten" -Basic.Hotkeys.StopRecording="Aufnahme stoppen" Basic.Hotkeys.SelectScene="Zu Szene wechseln" Basic.SystemTray.Show="Anzeigen"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/el-GR.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/el-GR.ini
Changed
@@ -361,10 +361,6 @@ Basic.AdvAudio.AudioTracks="Κομμάτια" -Basic.Hotkeys.StartStreaming="Έναρξη Μετάδοσης" -Basic.Hotkeys.StopStreaming="Διακοπή Μετάδοσης" -Basic.Hotkeys.StartRecording="Έναρξη Καταγραφής" -Basic.Hotkeys.StopRecording="Διακοπή Καταγραφής" Basic.Hotkeys.SelectScene="Μετάβαση σε σκηνή"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/en-US.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/en-US.ini
Changed
@@ -58,6 +58,9 @@ Minutes="Minutes" Seconds="Seconds" Deprecated="Deprecated" +ReplayBuffer="Replay Buffer" +Import="Import" +Export="Export" # quick transitions QuickTransitions.SwapScenes="Swap Preview/Output Scenes After Transitioning" @@ -123,6 +126,8 @@ Output.RecordNoSpace.Msg="There is not sufficient disk space to continue recording." Output.RecordError.Title="Recording error" Output.RecordError.Msg="An unspecified error occurred while recording." +Output.ReplayBuffer.NoHotkey.Title="No hotkey set!" +Output.ReplayBuffer.NoHotkey.Msg="No save hotkey set for replay buffer. Please set the \"Save\" hotkey to use for saving replay recordings." # output recording messages Output.BadPath.Title="Bad File Path" @@ -304,9 +309,12 @@ Basic.Main.Sources="Sources" Basic.Main.Connecting="Connecting..." Basic.Main.StartRecording="Start Recording" +Basic.Main.StartReplayBuffer="Start Replay Buffer" Basic.Main.StartStreaming="Start Streaming" Basic.Main.StopRecording="Stop Recording" Basic.Main.StoppingRecording="Stopping Recording..." +Basic.Main.StopReplayBuffer="Stop Replay Buffer" +Basic.Main.StoppingReplayBuffer="Stopping Replay Buffer..." Basic.Main.StopStreaming="Stop Streaming" Basic.Main.StoppingStreaming="Stopping Stream..." Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)" @@ -336,6 +344,8 @@ Basic.MainMenu.Edit.Scale.Output="Output (%1x%2)" Basic.MainMenu.Edit.Transform="&Transform" Basic.MainMenu.Edit.Transform.EditTransform="&Edit Transform..." +Basic.MainMenu.Edit.Transform.CopyTransform="Copy Transform" +Basic.MainMenu.Edit.Transform.PasteTransform="Paste Transform" Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform" Basic.MainMenu.Edit.Transform.Rotate90CW="Rotate 90 degrees CW" Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotate 90 degrees CCW" @@ -362,6 +372,12 @@ # basic mode profile/scene collection menus Basic.MainMenu.SceneCollection="&Scene Collection" Basic.MainMenu.Profile="&Profile" +Basic.MainMenu.Profile.Import="Import Profile" +Basic.MainMenu.Profile.Export="Export Profile" +Basic.MainMenu.SceneCollection.Import="Import Scene Collection" +Basic.MainMenu.SceneCollection.Export="Export Scene Collection" +Basic.MainMenu.Profile.Exists="The profile already exists" +Basic.MainMenu.SceneCollection.Exists="The scene collection already exists" # basic mode help menu Basic.MainMenu.Tools="&Tools" @@ -414,6 +430,14 @@ Basic.Settings.Output.Mode.Simple="Simple" Basic.Settings.Output.Mode.Adv="Advanced" Basic.Settings.Output.Mode.FFmpeg="FFmpeg Output" +Basic.Settings.Output.UseReplayBuffer="Enable Replay Buffer" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximum Replay Time (Seconds)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximum Memory (Megabytes)" +Basic.Settings.Output.ReplayBuffer.Estimate="Estimated memory usage: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Cannot estimate memory usage. Please set maximum memory limit." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Note: Make sure to set a hotkey for the replay buffer in the hotkeys section)" +Basic.Settings.Output.ReplayBuffer.Prefix="Replay Buffer Filename Prefix" +Basic.Settings.Output.ReplayBuffer.Suffix="Suffix" Basic.Settings.Output.Simple.SavePath="Recording Path" Basic.Settings.Output.Simple.RecordingQuality="Recording Quality" Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream" @@ -452,6 +476,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Track 2" Basic.Settings.Output.Adv.Audio.Track3="Track 3" Basic.Settings.Output.Adv.Audio.Track4="Track 4" +Basic.Settings.Output.Adv.Audio.Track5="Track 5" +Basic.Settings.Output.Adv.Audio.Track6="Track 6" # basic mode 'output' settings - advanced section - recording subsection Basic.Settings.Output.Adv.Recording="Recording" @@ -560,10 +586,6 @@ Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles" # basic mode hotkeys -Basic.Hotkeys.StartStreaming="Start Streaming" -Basic.Hotkeys.StopStreaming="Stop Streaming" -Basic.Hotkeys.StartRecording="Start Recording" -Basic.Hotkeys.StopRecording="Stop Recording" Basic.Hotkeys.SelectScene="Switch to scene" # system tray
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/es-ES.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/es-ES.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Minutos" Seconds="Segundos" Deprecated="Obsoleto" +ReplayBuffer="Búfer de reproducción" +Import="Importar" +Export="Exportar" QuickTransitions.SwapScenes="Cambiar vista previa y salida escenas después de la transición" QuickTransitions.SwapScenesTT="Cambia la vista previa y salida escenas después de la transición (si todavía existe la escena original de la salida). \nEsto no deshará cualquier cambio que pueda haber hecho a la escena original de la salida." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="No hay suficiente espacio en disco para continuar grabando." Output.RecordError.Title="Error en la grabación" Output.RecordError.Msg="Se ha producido un error no especificado durante la grabación." +Output.ReplayBuffer.NoHotkey.Title="¡Sin tecla de acceso rápido!" +Output.ReplayBuffer.NoHotkey.Msg="Sin tecla de acceso rápido establecida para el búfer de reproducción. Configure la tecla de acceso \"Guardar\" para guardar las grabaciones de reproducción." Output.BadPath.Title="Ruta de archivo incorrecta" Output.BadPath.Text="La ruta de salida de archivos establecida no es válida. Por favor, compruebe su configuración para confirmar que se ha establecido una ruta de archivos válida." @@ -262,9 +267,12 @@ Basic.Main.Sources="Fuentes" Basic.Main.Connecting="Conectando..." Basic.Main.StartRecording="Iniciar grabación" +Basic.Main.StartReplayBuffer="Iniciar la reproducción del búfer" Basic.Main.StartStreaming="Iniciar Transmisión" Basic.Main.StopRecording="Detener grabación" Basic.Main.StoppingRecording="Deteniendo la grabación..." +Basic.Main.StopReplayBuffer="Detener la reproducción del búfer" +Basic.Main.StoppingReplayBuffer="Deteniendo la reproducción del búfer..." Basic.Main.StopStreaming="Detener Transmisión" Basic.Main.StoppingStreaming="Deteniendo la trasmisión..." Basic.Main.ForceStopStreaming="Parar Transmisión (descartar retraso)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Salida (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformar" Basic.MainMenu.Edit.Transform.EditTransform="&Editar Transformación..." +Basic.MainMenu.Edit.Transform.CopyTransform="Copiar transformación" +Basic.MainMenu.Edit.Transform.PasteTransform="Pegar trasformación" Basic.MainMenu.Edit.Transform.ResetTransform="&Restablecer transformación" Basic.MainMenu.Edit.Transform.Rotate90CW="Girar 90 grados en el sentido de las agujas del reloj" Basic.MainMenu.Edit.Transform.Rotate90CCW="Girar 90 grados contra el sentido de las agujas del reloj" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Colección de Escenas" Basic.MainMenu.Profile="&Perfil" +Basic.MainMenu.Profile.Import="Importar perfil" +Basic.MainMenu.Profile.Export="Exportar perfil" +Basic.MainMenu.SceneCollection.Import="Importar colección de escenas" +Basic.MainMenu.SceneCollection.Export="Exportar colección de escenas" +Basic.MainMenu.Profile.Exists="El perfil ya existe" +Basic.MainMenu.SceneCollection.Exists="La colección de escenas ya existe" Basic.MainMenu.Tools="&Herramientas" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Sencillo" Basic.Settings.Output.Mode.Adv="Avanzado" Basic.Settings.Output.Mode.FFmpeg="Salida de FFmpeg" +Basic.Settings.Output.UseReplayBuffer="Activar la reproducción del búfer" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Tiempo de reproducción máximo (segundos)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Memoria máxima (MB)" +Basic.Settings.Output.ReplayBuffer.Estimate="Uso estimado de memoria: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="No se puede estimar el uso de memoria. Establezca el límite máximo de memoria." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Nota: Asegúrese de establecer una tecla de acceso rápido para el búfer de reproducción en la sección de teclas rápidas)" +Basic.Settings.Output.ReplayBuffer.Prefix="Prefijo del nombre de archivo del búfer" +Basic.Settings.Output.ReplayBuffer.Suffix="Sufijo" Basic.Settings.Output.Simple.SavePath="Ruta de grabación" Basic.Settings.Output.Simple.RecordingQuality="Calidad de grabación" Basic.Settings.Output.Simple.RecordingQuality.Stream="Igual a la emision" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Pista 2" Basic.Settings.Output.Adv.Audio.Track3="Pista 3" Basic.Settings.Output.Adv.Audio.Track4="Pista 4" +Basic.Settings.Output.Adv.Audio.Track5="Pista 5" +Basic.Settings.Output.Adv.Audio.Track6="Pista 6" Basic.Settings.Output.Adv.Recording="Grabando" Basic.Settings.Output.Adv.Recording.Type="Tipo" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="Atajos" Basic.Settings.Hotkeys.Pair="Combinaciones de teclas con '%1' actúan como interruptores" -Basic.Hotkeys.StartStreaming="Iniciar Transmisión" -Basic.Hotkeys.StopStreaming="Detener Transmisión" -Basic.Hotkeys.StartRecording="Iniciar grabación" -Basic.Hotkeys.StopRecording="Detener grabación" Basic.Hotkeys.SelectScene="Cambiar a la escena" Basic.SystemTray.Show="Mostrar"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/eu-ES.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/eu-ES.ini
Changed
@@ -53,6 +53,9 @@ Minutes="minutu" Seconds="segundo" Deprecated="Zaharkitua" +ReplayBuffer="Erreprodukzio bufferra" +Import="Inportatu" +Export="Esportatu" QuickTransitions.SwapScenes="Trukatu Aurrebista/Irteera-eszenak trantsizioen ondoren" QuickTransitions.SwapScenesTT="Trukatu aurrebistak eta irteera-eszenak trantsizioen ondoren (baldin eta irteerakoaren jatorrizkoa eszena badago).\n Honek ez du desegingo irteerakoaren jatorrizko eszenari egindako aldaketak." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Ez dago nahikoa tokirik diskoan grabatzen jarraitzeko." Output.RecordError.Title="Grabazio akatsa" Output.RecordError.Msg="Zehaztugabeko akats bat gertatu da grabatzerakoan." +Output.ReplayBuffer.NoHotkey.Title="Laster tekla ezarri gabe!" +Output.ReplayBuffer.NoHotkey.Msg="Ez da ezarri gordetzeko laster teklarik erreprodukzio bufferrerako. Ezarri \"Gorde\" laster tekla erreprodukzio bufferrak gordetzeko." Output.BadPath.Title="Fitxategi-bide okerra" Output.BadPath.Text="Ezarritako fitxategiaren irteera-bidea baliogabea da. Egiaztatu zure ezarpenak baieztatzeko baliozko fitxategi-bidea ezarri dela." @@ -262,9 +267,12 @@ Basic.Main.Sources="Iturburuak" Basic.Main.Connecting="Konektatzen..." Basic.Main.StartRecording="Hasi grabazioa" +Basic.Main.StartReplayBuffer="Abiatu erreprodukzio bufferra" Basic.Main.StartStreaming="Hasi transmisioa" Basic.Main.StopRecording="Gelditu grabazioa" Basic.Main.StoppingRecording="Grabazioa gelditzen..." +Basic.Main.StopReplayBuffer="Gelditu erreprodukzio buferra" +Basic.Main.StoppingReplayBuffer="Erreprodukzio bufferra gelditzen..." Basic.Main.StopStreaming="Gelditu transmisioa" Basic.Main.StoppingStreaming="Transmisioa gelditzen..." Basic.Main.ForceStopStreaming="Gelditu transmisioa (baztertu atzerapena)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Irteera (%1x%2)" Basic.MainMenu.Edit.Transform="&Eraldatu" Basic.MainMenu.Edit.Transform.EditTransform="E&ditatu eraldaketa..." +Basic.MainMenu.Edit.Transform.CopyTransform="Kopiatu eraldaketa" +Basic.MainMenu.Edit.Transform.PasteTransform="Itsatsi eraldaketa" Basic.MainMenu.Edit.Transform.ResetTransform="&Berrezarri eraldaketa" Basic.MainMenu.Edit.Transform.Rotate90CW="Biratu 90 gradu erlojuaren norabidean" Basic.MainMenu.Edit.Transform.Rotate90CCW="Biratu 90 gradu erlojuaren kontrako norabidean" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Eszena-bilduma" Basic.MainMenu.Profile="&Profila" +Basic.MainMenu.Profile.Import="Inportatu profila" +Basic.MainMenu.Profile.Export="Esportatu profila" +Basic.MainMenu.SceneCollection.Import="Inportatu eszena bilduma" +Basic.MainMenu.SceneCollection.Export="Esportatu eszena bilduma" +Basic.MainMenu.Profile.Exists="Profila lehendik ere badago" +Basic.MainMenu.SceneCollection.Exists="Eszena bilduma lehendik ere badago" Basic.MainMenu.Tools="&Tresnak" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Arrunta" Basic.Settings.Output.Mode.Adv="Aurreratua" Basic.Settings.Output.Mode.FFmpeg="FFmpeg Irteera" +Basic.Settings.Output.UseReplayBuffer="Gaitu erreprodukzio bufferra" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Erreprodukzioaren gehienezko denbora (segundotan)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Gehienezko memoria (megabytetan)" +Basic.Settings.Output.ReplayBuffer.Estimate="Ustezko memoria erabilera: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Ezin da kalkulatu memoria erabilera. Ezarri gehienezko memoria." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Oharra: Aseguratu bufferraren erreprodukziorako laster tekla bat ezarri duzula laster teklen atalean)" +Basic.Settings.Output.ReplayBuffer.Prefix="Erreprodukzio bufferraren fitxategi aurrizkia" +Basic.Settings.Output.ReplayBuffer.Suffix="Atzizkia" Basic.Settings.Output.Simple.SavePath="Grabazio-bidea" Basic.Settings.Output.Simple.RecordingQuality="Grabazio-kalitatea" Basic.Settings.Output.Simple.RecordingQuality.Stream="Transmisioaren berdina" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="2 pista" Basic.Settings.Output.Adv.Audio.Track3="3 pista" Basic.Settings.Output.Adv.Audio.Track4="4 pista" +Basic.Settings.Output.Adv.Audio.Track5="5. pista" +Basic.Settings.Output.Adv.Audio.Track6="6. pista" Basic.Settings.Output.Adv.Recording="Grabatzen" Basic.Settings.Output.Adv.Recording.Type="Mota" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="Laster-teklak" Basic.Settings.Hotkeys.Pair="'%1'-rekin egindako tekla konbinazioek txandakatze moduan jokatzen dute" -Basic.Hotkeys.StartStreaming="Hasi transmisioa" -Basic.Hotkeys.StopStreaming="Gelditu transmisioa" -Basic.Hotkeys.StartRecording="Hasi Grabazioa" -Basic.Hotkeys.StopRecording="Gelditu grabazioa" Basic.Hotkeys.SelectScene="Aldatu eszenara" Basic.SystemTray.Show="Erakutsi"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/fi-FI.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/fi-FI.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Minuuttia" Seconds="Sekuntia" Deprecated="Vanhentunut" +ReplayBuffer="Toistopuskuri" +Import="Tuo" +Export="Vie" QuickTransitions.SwapScenes="Vaihda esikatselu- ja ulostulo-skenet siirtymän jälkeen" QuickTransitions.SwapScenesTT="Vaihda esikatselu- ja ulostulo-skenet siirtymän jälkeen (jos ulostulon alkuperäinen skene on yhä olemassa).\nTämä ei peruuta muutoksia joita on tehty alkuperäiseen skeneen." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Levytilaa ei ole riittävästi tallennuksen jatkamiseen." Output.RecordError.Title="Tallennusvirhe" Output.RecordError.Msg="Tallennuksen aikana tapahtui määrittelemätön virhe." +Output.ReplayBuffer.NoHotkey.Title="Pikanäppäintä ei ole asetettu!" +Output.ReplayBuffer.NoHotkey.Msg="Tallennuksen pikanäppäintä ei ole asetettu toistopuskurille. Aseta \"Tallenna\"-pikanäppäin tallentaaksesi uusinnat." Output.BadPath.Title="Viallinen tiedostopolku" Output.BadPath.Text="Asetettu tiedostopolku on viallinen. Tarkista asetuksistasi, että tiedostopolku on asetettu oikein." @@ -262,9 +267,12 @@ Basic.Main.Sources="Lähteet" Basic.Main.Connecting="Yhdistetään..." Basic.Main.StartRecording="Aloita tallennus" +Basic.Main.StartReplayBuffer="Käynnistä toistopuskuri" Basic.Main.StartStreaming="Aloita lähetys" Basic.Main.StopRecording="Pysäytä tallennus" Basic.Main.StoppingRecording="Pysäytetään tallennusta..." +Basic.Main.StopReplayBuffer="Pysäytä toistopuskuri" +Basic.Main.StoppingReplayBuffer="Pysäytetään toistopuskuri..." Basic.Main.StopStreaming="Pysäytä lähetys" Basic.Main.StoppingStreaming="Pysäytetään lähetystä..." Basic.Main.ForceStopStreaming="Lopeta lähetys (ohita viive)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Ulostulo (%1x%2)" Basic.MainMenu.Edit.Transform="Muu&nna" Basic.MainMenu.Edit.Transform.EditTransform="M&uokkaa muunnosta..." +Basic.MainMenu.Edit.Transform.CopyTransform="Kopioi muunnos" +Basic.MainMenu.Edit.Transform.PasteTransform="Liitä muunnos" Basic.MainMenu.Edit.Transform.ResetTransform="&Nollaa muunnos" Basic.MainMenu.Edit.Transform.Rotate90CW="Kierrä 90 astetta myötäpäivään" Basic.MainMenu.Edit.Transform.Rotate90CCW="Kierrä 90 astetta vastapäivään" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Skene-kokoelma" Basic.MainMenu.Profile="&Profiili" +Basic.MainMenu.Profile.Import="Tuo profiili" +Basic.MainMenu.Profile.Export="Vie profiili" +Basic.MainMenu.SceneCollection.Import="Tuo skene-kokoelma" +Basic.MainMenu.SceneCollection.Export="Vie skene-kokoelma" +Basic.MainMenu.Profile.Exists="Profiili on jo olemassa" +Basic.MainMenu.SceneCollection.Exists="Skene-kokoelma on jo olemassa" Basic.MainMenu.Tools="T&yökalut" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Yksinkertainen" Basic.Settings.Output.Mode.Adv="Kehittynyt" Basic.Settings.Output.Mode.FFmpeg="FFmpeg ulostulo" +Basic.Settings.Output.UseReplayBuffer="Ota toistopuskuri käyttöön" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Uusinnan pisin aika (Sekunteina)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Muistiraja (Megatavuja)" +Basic.Settings.Output.ReplayBuffer.Estimate="Arvioitu muistinkäyttö: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Muistin käyttöä ei voida arvioida. Valitse muistiraja." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Huomio: Varmista että toistopuskurin pikanäppäin on asetettuna asetuksista)" +Basic.Settings.Output.ReplayBuffer.Prefix="Toistopuskurin tiedostonimen etuliite" +Basic.Settings.Output.ReplayBuffer.Suffix="Pääte" Basic.Settings.Output.Simple.SavePath="Tallennuksen polku" Basic.Settings.Output.Simple.RecordingQuality="Tallennuksen laatu" Basic.Settings.Output.Simple.RecordingQuality.Stream="Sama kuin lähetyksessä" @@ -497,10 +521,6 @@ Basic.Settings.Hotkeys="Pikanäppäimet" Basic.Settings.Hotkeys.Pair="Yhteiset näppäinyhdistelmät '%1':n kanssa toimivat 'togglena'" -Basic.Hotkeys.StartStreaming="Aloita lähetys" -Basic.Hotkeys.StopStreaming="Pysäytä lähetys" -Basic.Hotkeys.StartRecording="Aloita tallennus" -Basic.Hotkeys.StopRecording="Pysäytä tallennus" Basic.Hotkeys.SelectScene="Vaihda skeneen" Basic.SystemTray.Show="Näytä"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/fr-FR.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/fr-FR.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Minutes" Seconds="Secondes" Deprecated="Obsolète" +ReplayBuffer="Tampon de relecture" +Import="Importer" +Export="Exporter" QuickTransitions.SwapScenes="Permuter les scènes d'aperçu et de sortie après la transition" QuickTransitions.SwapScenesTT="Permute les scènes d'aperçu et de sortie après la transition (si la scène d'origine de la sortie existe toujours). \nCela n'annulera pas les modifications qui auront pu être faites sur la scène d'origine de la sortie." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Il n'y a pas suffisamment d'espace disque pour continuer l'enregistrement." Output.RecordError.Title="Erreur d'enregistrement" Output.RecordError.Msg="Une erreur non spécifiée s'est produite lors de l'enregistrement." +Output.ReplayBuffer.NoHotkey.Title="Aucun raccourci clavier défini !" +Output.ReplayBuffer.NoHotkey.Msg="Aucun raccourci clavier défini pour le tampon de relecture. Veuillez en définir un pour utiliser cette fonction." Output.BadPath.Title="Chemin d'accès au fichier incorrect" Output.BadPath.Text="Le chemin configuré pour le flux sortant est invalide. Veuillez vérifier vos paramètres pour confirmer la présence d'un chemin valide." @@ -262,9 +267,12 @@ Basic.Main.Sources="Sources" Basic.Main.Connecting="Connexion en cours..." Basic.Main.StartRecording="Démarrer l'enregistrement" +Basic.Main.StartReplayBuffer="Démarrer le tampon de relecture" Basic.Main.StartStreaming="Commencer le streaming" Basic.Main.StopRecording="Arrêter l'enregistrement" Basic.Main.StoppingRecording="Arrêt de l'enregistrement..." +Basic.Main.StopReplayBuffer="Arrêter le tampon de relecture" +Basic.Main.StoppingReplayBuffer="Arrêt du tampon de relecture..." Basic.Main.StopStreaming="Arrêter le streaming" Basic.Main.StoppingStreaming="Arrêt du stream..." Basic.Main.ForceStopStreaming="Arrêter le streaming (annule le retard)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Sortie (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformer" Basic.MainMenu.Edit.Transform.EditTransform="Éditer la transformation..." +Basic.MainMenu.Edit.Transform.CopyTransform="Copier la transformation" +Basic.MainMenu.Edit.Transform.PasteTransform="Coller la transformation" Basic.MainMenu.Edit.Transform.ResetTransform="Réinitialiser la transformation" Basic.MainMenu.Edit.Transform.Rotate90CW="Rotation de 90° sens horaire" Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotation de 90° sens antihoraire" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="Collection de &scènes" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile.Import="Importer un profil" +Basic.MainMenu.Profile.Export="Exporter un profil" +Basic.MainMenu.SceneCollection.Import="Importer une collection de scènes" +Basic.MainMenu.SceneCollection.Export="Exporter une collection de scènes" +Basic.MainMenu.Profile.Exists="Ce profil existe déjà" +Basic.MainMenu.SceneCollection.Exists="Cette collection de scène existe déjà" Basic.MainMenu.Tools="Outils" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Simple" Basic.Settings.Output.Mode.Adv="Avancé" Basic.Settings.Output.Mode.FFmpeg="Sortie FFmpeg" +Basic.Settings.Output.UseReplayBuffer="Activer le tampon de relecture" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Temps de relecture maximal (secondes)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Mémoire maximum (mégaoctets)" +Basic.Settings.Output.ReplayBuffer.Estimate="Estimation de la mémoire utilisée : %1 Mo" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Impossible d'estimer l'utilisation de la mémoire. Veuillez définir une limite de mémoire maximale." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Remarque : veillez à définir un raccourci clavier pour le tampon de relecture dans la section des raccourcis clavier)" +Basic.Settings.Output.ReplayBuffer.Prefix="Nom du fichier du tampon commençant par" +Basic.Settings.Output.ReplayBuffer.Suffix="Finissant par" Basic.Settings.Output.Simple.SavePath="Chemin d'accès de l'enregistrement" Basic.Settings.Output.Simple.RecordingQuality="Qualité d'enregistrement" Basic.Settings.Output.Simple.RecordingQuality.Stream="Identique au stream" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Piste 2" Basic.Settings.Output.Adv.Audio.Track3="Piste 3" Basic.Settings.Output.Adv.Audio.Track4="Piste 4" +Basic.Settings.Output.Adv.Audio.Track5="Piste 5" +Basic.Settings.Output.Adv.Audio.Track6="Piste 6" Basic.Settings.Output.Adv.Recording="Enregistrement" Basic.Settings.Output.Adv.Recording.Type="Type " @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="Raccourcis clavier" Basic.Settings.Hotkeys.Pair="Les combinaisons de touches partagées avec '%1' agissent comme déclancheur" -Basic.Hotkeys.StartStreaming="Commencer le streaming" -Basic.Hotkeys.StopStreaming="Arrêter le streaming" -Basic.Hotkeys.StartRecording="Démarrer l'enregistrement" -Basic.Hotkeys.StopRecording="Arrêter l'enregistrement" Basic.Hotkeys.SelectScene="Passer à la scène" Basic.SystemTray.Show="Restaurer"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/gl-ES.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/gl-ES.ini
Changed
@@ -362,10 +362,6 @@ Basic.AdvAudio.AudioTracks="Pistas" -Basic.Hotkeys.StartStreaming="Iniciar retransmisión" -Basic.Hotkeys.StopStreaming="Deter retransmisión" -Basic.Hotkeys.StartRecording="Iniciar gravación" -Basic.Hotkeys.StopRecording="Deter gravación"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/he-IL.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/he-IL.ini
Changed
@@ -483,10 +483,6 @@ Basic.Settings.Hotkeys="מקשי קיצור" Basic.Settings.Hotkeys.Pair="צירופי מקשים משותים עם '%1' משמשים כמחליפים" -Basic.Hotkeys.StartStreaming="התחל הזרמת נתונים" -Basic.Hotkeys.StopStreaming="עצור הזרמת נתונים" -Basic.Hotkeys.StartRecording="התחל הקלטה" -Basic.Hotkeys.StopRecording="עצור הקלטה" Basic.Hotkeys.SelectScene="עבור לסצנה" Basic.SystemTray.Show="הצג"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/hr-HR.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/hr-HR.ini
Changed
@@ -52,6 +52,7 @@ Hours="Sati" Minutes="Minuta" Seconds="Sekundi" +Deprecated="Prevaziđeno" QuickTransitions.SwapScenes="Zameni scene pregleda/izlaza nakon prelaza" QuickTransitions.SwapScenesTT="Zamenjuje scene pregleda i izlaza nakon prelaza (ako originalna scena izlaza još uvek postoji).\nOvo neće poništiti promene koje su načinjene nad originalnom scenom izlaza." @@ -285,6 +286,10 @@ Basic.MainMenu.Edit.UndoAction="Vrati $1 (&U)" Basic.MainMenu.Edit.RedoAction="U&radi ponovo $1" Basic.MainMenu.Edit.LockPreview="Zak&ljučaj prikaz" +Basic.MainMenu.Edit.Scale="Pregled &skaliranja" +Basic.MainMenu.Edit.Scale.Window="Skaliraj na veličinu prozora" +Basic.MainMenu.Edit.Scale.Canvas="Platno (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Izlaz (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformiši" Basic.MainMenu.Edit.Transform.EditTransform="Izm&eni transformaciju..." Basic.MainMenu.Edit.Transform.ResetTransform="Poništi t&ransformaciju" @@ -492,10 +497,6 @@ Basic.Settings.Hotkeys="Prečice" Basic.Settings.Hotkeys.Pair="Kombinacije tastera deljene sa '%1' se ponašaju kao prekidači" -Basic.Hotkeys.StartStreaming="Započni strimovanje" -Basic.Hotkeys.StopStreaming="Zaustavi strimovanje" -Basic.Hotkeys.StartRecording="Počni snimanje" -Basic.Hotkeys.StopRecording="Zaustavi snimanje" Basic.Hotkeys.SelectScene="Prebaci na scenu" Basic.SystemTray.Show="Prikaži"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/hu-HU.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/hu-HU.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Perc" Seconds="Másodperc" Deprecated="Elavult" +ReplayBuffer="Visszajátszás puffer" +Import="Importálás" +Export="Exportálás" QuickTransitions.SwapScenes="Előnézeti/Kimeneti Jelenetek cseréje átmenet után" QuickTransitions.SwapScenesTT="Az előnézet és a kimeneti jelenet cseréje átmenet után (ha a kimenet eredeti jelenete még létezik).\nEz nincs kihatással a kimenet eredeti jelenetére." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="Nincs elegendő lemezterület a felvétel folytatásához." Output.RecordError.Title="Felvételi hiba" Output.RecordError.Msg="Ismeretlen hiba lépett fel a felvétel során." +Output.ReplayBuffer.NoHotkey.Title="Nincs gyorsbillentyű beállítva!" +Output.ReplayBuffer.NoHotkey.Msg="Nincs mentés gyorsbillentyű a visszajátszási pufferhez. Kérem állítson be egy \"Mentés\" gyorsbillentyűt a visszajátszások felvételeinek mentésére." Output.BadPath.Title="A fájl elérési útja hibás" Output.BadPath.Text="A beállított elérési útvonal érvénytelen. Kérem ellenőrizze a beállításait és győződjön meg arról, hogy a fájl elérési útja érvényes." @@ -262,9 +267,12 @@ Basic.Main.Sources="Források" Basic.Main.Connecting="Kapcsolódás..." Basic.Main.StartRecording="Felvétel indítása" +Basic.Main.StartReplayBuffer="Visszajátszás puffer indítása" Basic.Main.StartStreaming="Stream indítása" Basic.Main.StopRecording="Felvétel leállítása" Basic.Main.StoppingRecording="Felvétel leállítása..." +Basic.Main.StopReplayBuffer="Visszajátszás puffer megállítása" +Basic.Main.StoppingReplayBuffer="Visszajátszás puffer leáll..." Basic.Main.StopStreaming="Stream leállítása" Basic.Main.StoppingStreaming="Stream leállítása..." Basic.Main.ForceStopStreaming="Stream leállítása (Késleltetés elvetése)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="Kimenet (%1x%2)" Basic.MainMenu.Edit.Transform="&Alakítás" Basic.MainMenu.Edit.Transform.EditTransform="&Alakítás átszerkesztése..." +Basic.MainMenu.Edit.Transform.CopyTransform="Alakítás másolása" +Basic.MainMenu.Edit.Transform.PasteTransform="Átalakítás beillesztése" Basic.MainMenu.Edit.Transform.ResetTransform="&Alakítás visszaállítása" Basic.MainMenu.Edit.Transform.Rotate90CW="Forgatás 90 fokkal balra" Basic.MainMenu.Edit.Transform.Rotate90CCW="Forgatás 90 fokkal jobbra" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Jelenet gyűjtemény" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile.Import="Profil importálása" +Basic.MainMenu.Profile.Export="Profil exportálása" +Basic.MainMenu.SceneCollection.Import="Jelenet gyűjtemény importálása" +Basic.MainMenu.SceneCollection.Export="Jelenet gyűjtemény exportálása" +Basic.MainMenu.Profile.Exists="A profil már létezik" +Basic.MainMenu.SceneCollection.Exists="A jelenet gyűjtemény már létezik" Basic.MainMenu.Tools="&Eszközök" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Egyszerű" Basic.Settings.Output.Mode.Adv="Haladó" Basic.Settings.Output.Mode.FFmpeg="FFmpeg kimenet" +Basic.Settings.Output.UseReplayBuffer="Visszajátszás puffer engedélyezése" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximális visszajátszási idő (Másodperc)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximális memória (Megabájt)" +Basic.Settings.Output.ReplayBuffer.Estimate="Becsült memóriaigény: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nem lehet megbecsülni a memóriaigényt. Kérem állítson be egy maximális memória limitet." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Megjegyzés: Bizonyosodjon meg róla, hogy beállított egy billentyűparancsot az újrajátszás pufferre a gyorsbillentyű szekcióban)" +Basic.Settings.Output.ReplayBuffer.Prefix="Visszajátszási puffer fájlév előtag" +Basic.Settings.Output.ReplayBuffer.Suffix="Utótag" Basic.Settings.Output.Simple.SavePath="Felvétel helye" Basic.Settings.Output.Simple.RecordingQuality="Felvétel minősége" Basic.Settings.Output.Simple.RecordingQuality.Stream="Ugyanaz, mint a stream" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Sáv 2" Basic.Settings.Output.Adv.Audio.Track3="Sáv 3" Basic.Settings.Output.Adv.Audio.Track4="Sáv 4" +Basic.Settings.Output.Adv.Audio.Track5="Sáv 5" +Basic.Settings.Output.Adv.Audio.Track6="Sáv 6" Basic.Settings.Output.Adv.Recording="Rögzítés" Basic.Settings.Output.Adv.Recording.Type="Típus" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="Gyorsbillentyűk" Basic.Settings.Hotkeys.Pair="Azonos billentyűkombináció a '%1' mezővel, ezért kapcsolóként működik" -Basic.Hotkeys.StartStreaming="Stream indítása" -Basic.Hotkeys.StopStreaming="Stream leállítása" -Basic.Hotkeys.StartRecording="Felvétel indítása" -Basic.Hotkeys.StopRecording="Felvétel leállítása" Basic.Hotkeys.SelectScene="Jelenethez kapcsolás" Basic.SystemTray.Show="Mutat"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/it-IT.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/it-IT.ini
Changed
@@ -497,10 +497,6 @@ Basic.Settings.Hotkeys="Tasti di scelta rapida" Basic.Settings.Hotkeys.Pair="La combinazione di chiavi condivisa con '%1' funziona da commutatore" -Basic.Hotkeys.StartStreaming="Inizia diretta" -Basic.Hotkeys.StopStreaming="Termina diretta" -Basic.Hotkeys.StartRecording="Inizia registrazione" -Basic.Hotkeys.StopRecording="Ferma registrazione" Basic.Hotkeys.SelectScene="Passa alla scena" Basic.SystemTray.Show="Mostra"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ja-JP.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ja-JP.ini
Changed
@@ -53,6 +53,9 @@ Minutes="分" Seconds="秒" Deprecated="非推奨" +ReplayBuffer="リプレイバッファー" +Import="インポート" +Export="エクスポート" QuickTransitions.SwapScenes="トランジション後にプレビュー/出力シーンを入れ替え" QuickTransitions.SwapScenesTT="(出力のオリジナルシーンがまだ存在する場合)、トランジション後のプレビューと出力シーンを入れ替えます。\nこれは出力のオリジナルシーンに加えられた可能性があるすべての変更を元に戻しません。" @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="録画を継続する十分なディスク領域がありません。" Output.RecordError.Title="録画エラー" Output.RecordError.Msg="録画中に不明なエラーが発生しました。" +Output.ReplayBuffer.NoHotkey.Title="ホットキーが設定されていません!" +Output.ReplayBuffer.NoHotkey.Msg="リプレイバッファー保存のホットキー設定がありません。 リプレイ録画保存用に使用する「保存」のホットキーを設定してください。" Output.BadPath.Title="無効なパス" Output.BadPath.Text="設定されたファイルの出力パスが無効です。有効なファイルパスが設定されていることを確認してください。" @@ -262,9 +267,12 @@ Basic.Main.Sources="ソース" Basic.Main.Connecting="接続中..." Basic.Main.StartRecording="録画開始" +Basic.Main.StartReplayBuffer="リプレイバッファー開始" Basic.Main.StartStreaming="配信開始" Basic.Main.StopRecording="録画終了" Basic.Main.StoppingRecording="録画停止処理中..." +Basic.Main.StopReplayBuffer="リプレイバッファー停止" +Basic.Main.StoppingReplayBuffer="リプレイバッファー停止処理中..." Basic.Main.StopStreaming="配信終了" Basic.Main.StoppingStreaming="配信停止処理中..." Basic.Main.ForceStopStreaming="配信停止 (遅延破棄)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="出力(スケーリング) (%1x%2)" Basic.MainMenu.Edit.Transform="変換(&T)" Basic.MainMenu.Edit.Transform.EditTransform="変換の編集...(&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="変換をコピー" +Basic.MainMenu.Edit.Transform.PasteTransform="変換を貼り付け" Basic.MainMenu.Edit.Transform.ResetTransform="変換をリセット(&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="時計回りに 90 度回転" Basic.MainMenu.Edit.Transform.Rotate90CCW="反時計回りに 90 度回転" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="シーンコレクション(&S)" Basic.MainMenu.Profile="プロファイル(&P)" +Basic.MainMenu.Profile.Import="プロファイルをインポート" +Basic.MainMenu.Profile.Export="プロファイルをエクスポート" +Basic.MainMenu.SceneCollection.Import="シーンコレクションをインポート" +Basic.MainMenu.SceneCollection.Export="シーンコレクションをエクスポート" +Basic.MainMenu.Profile.Exists="プロファイルは既に存在します" +Basic.MainMenu.SceneCollection.Exists="シーンコレクションは既に存在します" Basic.MainMenu.Tools="ツール(&T)" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="基本" Basic.Settings.Output.Mode.Adv="詳細" Basic.Settings.Output.Mode.FFmpeg="FFmpeg の出力" +Basic.Settings.Output.UseReplayBuffer="リプレイバッファーを有効にする" +Basic.Settings.Output.ReplayBuffer.SecondsMax="最大リプレイ時間 (秒)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="最大メモリ (メガバイト)" +Basic.Settings.Output.ReplayBuffer.Estimate="概算メモリ使用量: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="メモリ使用量を見積もることができません。 最大メモリ制限を設定してください。" +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(注: ホットキーでリプレイバッファーのホットキーを設定してください)" +Basic.Settings.Output.ReplayBuffer.Prefix="リプレイバッファーのファイル名の接頭辞" +Basic.Settings.Output.ReplayBuffer.Suffix="接尾辞" Basic.Settings.Output.Simple.SavePath="録画ファイルのパス" Basic.Settings.Output.Simple.RecordingQuality="録画品質" Basic.Settings.Output.Simple.RecordingQuality.Stream="配信と同じ" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="トラック 2" Basic.Settings.Output.Adv.Audio.Track3="トラック 3" Basic.Settings.Output.Adv.Audio.Track4="トラック 4" +Basic.Settings.Output.Adv.Audio.Track5="トラック 5" +Basic.Settings.Output.Adv.Audio.Track6="トラック 6" Basic.Settings.Output.Adv.Recording="録画" Basic.Settings.Output.Adv.Recording.Type="種別" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="ホットキー" Basic.Settings.Hotkeys.Pair="'%1' との組合せでトグルスイッチとして機能します" -Basic.Hotkeys.StartStreaming="配信開始" -Basic.Hotkeys.StopStreaming="配信終了" -Basic.Hotkeys.StartRecording="録画開始" -Basic.Hotkeys.StopRecording="録画終了" Basic.Hotkeys.SelectScene="シーン切り替え" Basic.SystemTray.Show="表示"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ko-KR.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ko-KR.ini
Changed
@@ -53,6 +53,9 @@ Minutes="분" Seconds="초" Deprecated="사용하지 않음" +ReplayBuffer="리플레이 버퍼" +Import="가져오기" +Export="내보내기" QuickTransitions.SwapScenes="전환 후 미리 보기/출력 장면을 교체" QuickTransitions.SwapScenesTT="(만약 출력 쪽 원본 장면이 있을 때) 전환 작업 이후 미리 보기와 출력 장면을 교체합니다. \n출력 쪽 원본 장면에서 변경한 내용은 사라지지 않습니다." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="녹화를 계속하기 위한 디스크 공간이 부족합니다." Output.RecordError.Title="녹화 오류" Output.RecordError.Msg="녹화 중 예기치 못한 오류가 발생했습니다." +Output.ReplayBuffer.NoHotkey.Title="단축키가 없습니다!" +Output.ReplayBuffer.NoHotkey.Msg="리플레이를 저장하는 단축키를 지정하지 않았습니다. 리플레이 녹화 기능을 사용하려면 \"저장\" 단축키를 지정하십시오." Output.BadPath.Title="잘못된 파일 경로" Output.BadPath.Text="설정된 출력 파일 경로가 올바르지 않습니다. 경로가 제대로 설정이 되었는지 확인하십시오. " @@ -262,9 +267,12 @@ Basic.Main.Sources="소스 목록:" Basic.Main.Connecting="연결 중..." Basic.Main.StartRecording="녹화 시작" +Basic.Main.StartReplayBuffer="리플레이 버퍼 시작" Basic.Main.StartStreaming="방송 시작" Basic.Main.StopRecording="녹화 중단" Basic.Main.StoppingRecording="녹화를 중단합니다...." +Basic.Main.StopReplayBuffer="리플레이 버퍼 중단" +Basic.Main.StoppingReplayBuffer="리플레이 버퍼를 멈추고 있습니다..," Basic.Main.StopStreaming="방송 중단" Basic.Main.StoppingStreaming="방송을 중지합니다..." Basic.Main.ForceStopStreaming="방송 중지(지연된 분량도 마무리없이 즉시 송출 중단)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="출력 (%1x%2)" Basic.MainMenu.Edit.Transform="변환(&T)" Basic.MainMenu.Edit.Transform.EditTransform="변환 편집(&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="변환 복사" +Basic.MainMenu.Edit.Transform.PasteTransform="변환 붙여넣기" Basic.MainMenu.Edit.Transform.ResetTransform="변환 초기화(&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="시계 방향으로 90도 회전" Basic.MainMenu.Edit.Transform.Rotate90CCW="반시계 방향으로 90도 회전" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="장면 모음(&S)" Basic.MainMenu.Profile="프로파일(&P)" +Basic.MainMenu.Profile.Import="프로파일 가져오기" +Basic.MainMenu.Profile.Export="프로파일 내보내기" +Basic.MainMenu.SceneCollection.Import="장면 모음 가져오기" +Basic.MainMenu.SceneCollection.Export="장면 모음 내보내기" +Basic.MainMenu.Profile.Exists="그 프로파일은 이미 존재합니다." +Basic.MainMenu.SceneCollection.Exists="그 장면 모음은 이미 존재합니다." Basic.MainMenu.Tools="도구(&T)" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="단순" Basic.Settings.Output.Mode.Adv="고급" Basic.Settings.Output.Mode.FFmpeg="FFmpeg 출력" +Basic.Settings.Output.UseReplayBuffer="리플레이 버퍼 활성화" +Basic.Settings.Output.ReplayBuffer.SecondsMax="최대 리플레이 시간 (초 단위)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="최대 메모리 (메가바이트 단위)" +Basic.Settings.Output.ReplayBuffer.Estimate="예상되는 메모리 사용량: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="메모리 사용량을 계산할 수 없습니다. 최대 메모리 사용량을 설정하세요." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(참고: 단축키 설정에서 리플레이 버퍼의 단축키를 꼭 지정하세요)" +Basic.Settings.Output.ReplayBuffer.Prefix="리플레이 버퍼 파일이름 접두사" +Basic.Settings.Output.ReplayBuffer.Suffix="접미사" Basic.Settings.Output.Simple.SavePath="녹화 경로" Basic.Settings.Output.Simple.RecordingQuality="녹화 품질" Basic.Settings.Output.Simple.RecordingQuality.Stream="방송 품질과 동일하게" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="트랙 2" Basic.Settings.Output.Adv.Audio.Track3="트랙 3" Basic.Settings.Output.Adv.Audio.Track4="트랙 4" +Basic.Settings.Output.Adv.Audio.Track5="트랙 5" +Basic.Settings.Output.Adv.Audio.Track6="트랙 6" Basic.Settings.Output.Adv.Recording="녹화" Basic.Settings.Output.Adv.Recording.Type="형식" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="단축키" Basic.Settings.Hotkeys.Pair="'%1'과 공유하는 키 조합을 토글 형식으로 설정" -Basic.Hotkeys.StartStreaming="방송 시작" -Basic.Hotkeys.StopStreaming="방송 중단" -Basic.Hotkeys.StartRecording="녹화 시작" -Basic.Hotkeys.StopRecording="녹화 중단" Basic.Hotkeys.SelectScene="장면 전환" Basic.SystemTray.Show="보이기"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ms-MY.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ms-MY.ini
Changed
@@ -384,9 +384,6 @@ Basic.Settings.Hotkeys="Kekunci Pantas" -Basic.Hotkeys.StartStreaming="Mula 'Streaming'" -Basic.Hotkeys.StartRecording="Mula Rakaman" -Basic.Hotkeys.StopRecording="Hentikan Rakaman" Basic.SystemTray.Show="Papar" Basic.SystemTray.Hide="Sembunyi"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/nb-NO.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/nb-NO.ini
Changed
@@ -464,10 +464,6 @@ Basic.Settings.Hotkeys="Hurtigtaster" Basic.Settings.Hotkeys.Pair="Tastekombinasjoner delt med '%1' vil veksle" -Basic.Hotkeys.StartStreaming="Start strømming" -Basic.Hotkeys.StopStreaming="Stopp strømming" -Basic.Hotkeys.StartRecording="Start opptak" -Basic.Hotkeys.StopRecording="Stopp opptak" Basic.Hotkeys.SelectScene="Bytt til scene"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/nl-NL.ini
Changed
@@ -52,6 +52,10 @@ Hours="Uren" Minutes="Minuten" Seconds="Seconden" +Deprecated="Verouderd" +ReplayBuffer="Replay Buffer" +Import="Importeer" +Export="Exporteer" QuickTransitions.SwapScenes="Preview-/uitvoerscenes verwisselen na overgang" QuickTransitions.SwapScenesTT="Verwisselt de preview- en uitvoercenes na een overgang (als de originele uitvoerscène nog bestaat.)\nDit zal geen veranderingen ongedaan maken die mogelijk zijn gemaakt aan de originele uitvoerscène." @@ -106,6 +110,8 @@ Output.RecordNoSpace.Msg="Er is niet voldoende schijfruimte om door te gaan met opnemen." Output.RecordError.Title="Opnamefout" Output.RecordError.Msg="Er is een onbekende fout opgetreden tijdens het opnemen." +Output.ReplayBuffer.NoHotkey.Title="Er is geen sneltoets ingesteld!" +Output.ReplayBuffer.NoHotkey.Msg="Er is geen opslaan sneltoets ingesteld voor de replay buffer. Zet aub de \"Opslaan\" sneltoets voor het opslaan van replay-opnames." Output.BadPath.Title="Ongeldig Bestandspad" Output.BadPath.Text="Het geconfigureerde bestandsuitvoerpad is ongeldig. Controleer a.u.b. je instellingen om te bevestigen dat er een geldig bestandspad is ingesteld." @@ -261,9 +267,12 @@ Basic.Main.Sources="Bronnen" Basic.Main.Connecting="Verbinden..." Basic.Main.StartRecording="Opname Starten" +Basic.Main.StartReplayBuffer="Start Replay Buffer" Basic.Main.StartStreaming="Stream Starten" Basic.Main.StopRecording="Opname Stoppen" Basic.Main.StoppingRecording="Opname Stoppen..." +Basic.Main.StopReplayBuffer="Stop Replay Buffer" +Basic.Main.StoppingReplayBuffer="Replay Buffer aan het stoppen..." Basic.Main.StopStreaming="Stream Stoppen" Basic.Main.StoppingStreaming="Stream Stoppen..." Basic.Main.ForceStopStreaming="Stop Stream (vertraging negeren)" @@ -285,8 +294,14 @@ Basic.MainMenu.Edit.UndoAction="$1 ongedaan maken (&U)" Basic.MainMenu.Edit.RedoAction="$1 opnieuw toepassen (&R)" Basic.MainMenu.Edit.LockPreview="Preview vergrende&len" +Basic.MainMenu.Edit.Scale="Preview &schalen" +Basic.MainMenu.Edit.Scale.Window="Schaal naar venster" +Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Uitvoer (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformeren" Basic.MainMenu.Edit.Transform.EditTransform="Transformatie bewerken... (&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="Kopieer transformatie" +Basic.MainMenu.Edit.Transform.PasteTransform="Plak transformatie" Basic.MainMenu.Edit.Transform.ResetTransform="Transformatie herstellen (&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="Rechtsom kantelen" Basic.MainMenu.Edit.Transform.Rotate90CCW="Linksom kantelen" @@ -311,6 +326,12 @@ Basic.MainMenu.SceneCollection="&Scèneverzameling" Basic.MainMenu.Profile="&Profiel" +Basic.MainMenu.Profile.Import="Importeer profiel" +Basic.MainMenu.Profile.Export="Exporteer profiel" +Basic.MainMenu.SceneCollection.Import="Importeer scèneverzameling" +Basic.MainMenu.SceneCollection.Export="Exporteer scèneverzameling" +Basic.MainMenu.Profile.Exists="Het profiel bestaat al" +Basic.MainMenu.SceneCollection.Exists="De scèneverzameling bestaat al" Basic.MainMenu.Tools="&Tools" @@ -357,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Simpel" Basic.Settings.Output.Mode.Adv="Geavanceerd" Basic.Settings.Output.Mode.FFmpeg="FFmpeg-uitvoer" +Basic.Settings.Output.UseReplayBuffer="Replay Buffer Inschakelen" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maximale Replay-tijd (Seconden)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximale hoeveelheid geheugen (Megabytes)" +Basic.Settings.Output.ReplayBuffer.Estimate="Geschat geheugengebruik: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Kan geheugengebruik niet inschatten. Stel een limiet in op het geheugengebruik." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Let op: Maak een sneltoets voor de replay buffer in de Sneltoetsen sectie)" +Basic.Settings.Output.ReplayBuffer.Prefix="Replay Buffer Bestandsnaam Prefix" +Basic.Settings.Output.ReplayBuffer.Suffix="Achtervoegsel" Basic.Settings.Output.Simple.SavePath="Opnamepad" Basic.Settings.Output.Simple.RecordingQuality="Opnamekwaliteit" Basic.Settings.Output.Simple.RecordingQuality.Stream="Hetzelfde als de stream" @@ -394,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Spoor 2" Basic.Settings.Output.Adv.Audio.Track3="Spoor 3" Basic.Settings.Output.Adv.Audio.Track4="Spoor 4" +Basic.Settings.Output.Adv.Audio.Track5="Spoor 5" +Basic.Settings.Output.Adv.Audio.Track6="Spoor 6" Basic.Settings.Output.Adv.Recording="Opnemen" Basic.Settings.Output.Adv.Recording.Type="Type" @@ -492,10 +523,6 @@ Basic.Settings.Hotkeys="Sneltoetsen" Basic.Settings.Hotkeys.Pair="Toetsencombinaties gedeeld met '%1' werken als toggle" -Basic.Hotkeys.StartStreaming="Stream Starten" -Basic.Hotkeys.StopStreaming="Stream Stoppen" -Basic.Hotkeys.StartRecording="Opname Starten" -Basic.Hotkeys.StopRecording="Opname Stoppen" Basic.Hotkeys.SelectScene="Wissel naar scène" Basic.SystemTray.Show="Weergeven"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/pl-PL.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/pl-PL.ini
Changed
@@ -52,6 +52,10 @@ Hours="Godziny" Minutes="Minuty" Seconds="Sekundy" +Deprecated="Wycofywane" +ReplayBuffer="Buffer replayu" +Import="Importuj" +Export="Eksportuj" QuickTransitions.SwapScenes="Zamień podgląd/wyjście scen po przejściu" QuickTransitions.SwapScenesTT="Zamienia podgląd i wyjście scen po przejściu (jeżeli wyjście oryginalnej sceny istnieje).\nNie przywraca to zmian jakie zostały dokonane w oryginalnej scenie." @@ -106,6 +110,8 @@ Output.RecordNoSpace.Msg="Za mało miejsca na dysku, aby kontynuować nagrywanie." Output.RecordError.Title="Błąd nagrywania" Output.RecordError.Msg="Wystąpił nieokreślony błąd podczas nagrywania." +Output.ReplayBuffer.NoHotkey.Title="Brak klawisza skrótu!" +Output.ReplayBuffer.NoHotkey.Msg="Klawisz skrótu nie jest zapisany dla buforu replay. Ustaw skrót \"Zapisz\" aby zapisać nagrania replay." Output.BadPath.Title="Nieprawidłowa ścieżka pliku" Output.BadPath.Text="Ustawiona ścieżka pliku wynikowego jest nieprawidłowa. Proszę sprawdzić ustawienia." @@ -261,9 +267,12 @@ Basic.Main.Sources="Źródła obrazu" Basic.Main.Connecting="Łączenie..." Basic.Main.StartRecording="Rozpocznij nagrywanie" +Basic.Main.StartReplayBuffer="Rozpocznij bufor replayu" Basic.Main.StartStreaming="Rozpocznij stream" Basic.Main.StopRecording="Zatrzymaj nagrywanie" Basic.Main.StoppingRecording="Zatrzymywanie nagrywania..." +Basic.Main.StopReplayBuffer="Zatrzymaj bufor replayu" +Basic.Main.StoppingReplayBuffer="Zatrzymywanie buforu replay..." Basic.Main.StopStreaming="Zatrzymaj stream" Basic.Main.StoppingStreaming="Zatrzymywanie streamowania..." Basic.Main.ForceStopStreaming="Zatrzymaj stream (anuluj opóźnienie)" @@ -285,8 +294,14 @@ Basic.MainMenu.Edit.UndoAction="&Cofnij $1" Basic.MainMenu.Edit.RedoAction="&Wykonaj ponownie $1" Basic.MainMenu.Edit.LockPreview="Zab&lokuj podgląd" +Basic.MainMenu.Edit.Scale="&Skalowanie widoku" +Basic.MainMenu.Edit.Scale.Window="Skaluj do okna" +Basic.MainMenu.Edit.Scale.Canvas="Powierzchnia robocza (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Powierzchnia wyjściowa (%1x%2)" Basic.MainMenu.Edit.Transform="&Przekształcanie obrazu" Basic.MainMenu.Edit.Transform.EditTransform="&Edycja przekształceń..." +Basic.MainMenu.Edit.Transform.CopyTransform="Skopiuj transformacje" +Basic.MainMenu.Edit.Transform.PasteTransform="Wklej transformacje" Basic.MainMenu.Edit.Transform.ResetTransform="&Reset przekształceń" Basic.MainMenu.Edit.Transform.Rotate90CW="Obróć o 90 stopni zgodnie z ruchem wskazówkek zegara" Basic.MainMenu.Edit.Transform.Rotate90CCW="Obróć o 90 stopni przeciwnie do ruchu wskazówek zegara" @@ -311,6 +326,12 @@ Basic.MainMenu.SceneCollection="Zbiór &scen" Basic.MainMenu.Profile="P&rofil" +Basic.MainMenu.Profile.Import="Importuj profil" +Basic.MainMenu.Profile.Export="Eksportuj profil" +Basic.MainMenu.SceneCollection.Import="Importuj kolekcje sceny" +Basic.MainMenu.SceneCollection.Export="Exportuj kolekcje sceny" +Basic.MainMenu.Profile.Exists="Profil już istnieje" +Basic.MainMenu.SceneCollection.Exists="Kolekcja sceny już istnieje" Basic.MainMenu.Tools="&Narzędzia" @@ -357,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="Proste" Basic.Settings.Output.Mode.Adv="Zaawansowane" Basic.Settings.Output.Mode.FFmpeg="Wyjście FFmpeg" +Basic.Settings.Output.UseReplayBuffer="Włącz bufor replay" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksymalny czas replay (w sekundach)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksymalna ilość pamięci (w megabajtach)" +Basic.Settings.Output.ReplayBuffer.Estimate="Szacowane użycie pamięci: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Nie można oszacować użycie pamięci. Należy ustawić limit maksymalnej pamięci." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Uwaga: Upewnij się aby ustawić klawisz skrótu dla buforu replay w sekcji Skróty klawiszowe)" +Basic.Settings.Output.ReplayBuffer.Prefix="Prefiks nazwy pliku buforu replay" +Basic.Settings.Output.ReplayBuffer.Suffix="Sufiks" Basic.Settings.Output.Simple.SavePath="Ścieżka pliku" Basic.Settings.Output.Simple.RecordingQuality="Jakość nagrywania" Basic.Settings.Output.Simple.RecordingQuality.Stream="Taki sam jak stream" @@ -394,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="Ścieżka 2" Basic.Settings.Output.Adv.Audio.Track3="Ścieżka 3" Basic.Settings.Output.Adv.Audio.Track4="Ścieżka 4" +Basic.Settings.Output.Adv.Audio.Track5="Ścieżka 5" +Basic.Settings.Output.Adv.Audio.Track6="Ścieżka 6" Basic.Settings.Output.Adv.Recording="Nagrywanie" Basic.Settings.Output.Adv.Recording.Type="Typ" @@ -492,10 +523,6 @@ Basic.Settings.Hotkeys="Skróty klawiszowe" Basic.Settings.Hotkeys.Pair="Komibnacje klawiszy wspólne z '%1' działają jako przełączniki" -Basic.Hotkeys.StartStreaming="Rozpocznij stream" -Basic.Hotkeys.StopStreaming="Zakończ stream" -Basic.Hotkeys.StartRecording="Rozpocznij nagrywanie" -Basic.Hotkeys.StopRecording="Zatrzymaj nagrywanie" Basic.Hotkeys.SelectScene="Przełącz na scenę" Basic.SystemTray.Show="Pokaż"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/pt-BR.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/pt-BR.ini
Changed
@@ -495,10 +495,6 @@ Basic.Settings.Hotkeys="Teclas de atalho" Basic.Settings.Hotkeys.Pair="Combinações de teclas compartilhadas com '%1' agem como alternaçoes" -Basic.Hotkeys.StartStreaming="Iniciar transmissão" -Basic.Hotkeys.StopStreaming="Parar transmissão" -Basic.Hotkeys.StartRecording="Iniciar gravação" -Basic.Hotkeys.StopRecording="Parar gravação" Basic.Hotkeys.SelectScene="Mudar de cena" Basic.SystemTray.Show="Exibir"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/pt-PT.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/pt-PT.ini
Changed
@@ -472,10 +472,6 @@ Basic.Settings.Hotkeys="Teclas de atalho" Basic.Settings.Hotkeys.Pair="Combinações de teclas partilhadas com '%1' atuam como alavancas" -Basic.Hotkeys.StartStreaming="Iniciar transmissão" -Basic.Hotkeys.StopStreaming="Parar transmissão" -Basic.Hotkeys.StartRecording="Iniciar gravação" -Basic.Hotkeys.StopRecording="Parar gravação" Basic.Hotkeys.SelectScene="Mudar para cena" Basic.SystemTray.Show="Mostrar"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ro-RO.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ro-RO.ini
Changed
@@ -455,10 +455,6 @@ Basic.Settings.Hotkeys="Taste rapide" Basic.Settings.Hotkeys.Pair="Combinațiile de taste partajate cu '%1' acționează ca comutatoare" -Basic.Hotkeys.StartStreaming="Pornește streamingul" -Basic.Hotkeys.StopStreaming="Oprește streamingul" -Basic.Hotkeys.StartRecording="Pornește înregistrarea" -Basic.Hotkeys.StopRecording="Oprește înregistrarea" Basic.Hotkeys.SelectScene="Comută la scenă"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/ru-RU.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/ru-RU.ini
Changed
@@ -106,6 +106,7 @@ Output.RecordNoSpace.Msg="На диске недостаточно места для продолжения записи." Output.RecordError.Title="Ошибка записи" Output.RecordError.Msg="Во время записи произошла неопознанная ошибка." +Output.ReplayBuffer.NoHotkey.Title="Нет набора горячих клавиш!" Output.BadPath.Title="Неправильный путь к файлу" Output.BadPath.Text="Некорректный путь к файлу. Пожалуйста, проверьте настройки, чтобы убедиться в корректности установленного пути." @@ -285,6 +286,8 @@ Basic.MainMenu.Edit.UndoAction="&Отменить $1" Basic.MainMenu.Edit.RedoAction="&Повторить $1" Basic.MainMenu.Edit.LockPreview="&Заблокировать предпросмотр" +Basic.MainMenu.Edit.Scale="Просмотр и масштабирование" +Basic.MainMenu.Edit.Scale.Window="Масштаб окна" Basic.MainMenu.Edit.Transform="&Преобразовать" Basic.MainMenu.Edit.Transform.EditTransform="&Изменить преобразование..." Basic.MainMenu.Edit.Transform.ResetTransform="&Сбросить преобразование" @@ -357,6 +360,8 @@ Basic.Settings.Output.Mode.Simple="Простой" Basic.Settings.Output.Mode.Adv="Расширенные" Basic.Settings.Output.Mode.FFmpeg="Вывод FFmpeg" +Basic.Settings.Output.ReplayBuffer.Estimate="Предполагаемое использование памяти: %1 МБ" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Невозможно оценить использование памяти. Пожалуйста, установите максимальный объем памяти." Basic.Settings.Output.Simple.SavePath="Путь к записи" Basic.Settings.Output.Simple.RecordingQuality="Качество записи" Basic.Settings.Output.Simple.RecordingQuality.Stream="То же, что у трансляции" @@ -492,10 +497,6 @@ Basic.Settings.Hotkeys="Горячие клавиши" Basic.Settings.Hotkeys.Pair="Сочетания клавиш вместе с '%1' действуют как переключатели" -Basic.Hotkeys.StartStreaming="Запустить трансляцию" -Basic.Hotkeys.StopStreaming="Остановить трансляцию" -Basic.Hotkeys.StartRecording="Начать запись" -Basic.Hotkeys.StopRecording="Остановить запись" Basic.Hotkeys.SelectScene="Перейти на сцену" Basic.SystemTray.Show="Показать"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/sr-CS.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/sr-CS.ini
Changed
@@ -52,6 +52,7 @@ Hours="Sati" Minutes="Minuta" Seconds="Sekundi" +Deprecated="Prevaziđeno" QuickTransitions.SwapScenes="Zameni scene pregleda/izlaza nakon prelaza" QuickTransitions.SwapScenesTT="Zamenjuje scene pregleda i izlaza nakon prelaza (ako originalna scena izlaza još uvek postoji).\nOvo neće poništiti promene koje su načinjene nad originalnom scenom izlaza." @@ -285,6 +286,10 @@ Basic.MainMenu.Edit.UndoAction="Vrati $1 (&U)" Basic.MainMenu.Edit.RedoAction="U&radi ponovo $1" Basic.MainMenu.Edit.LockPreview="Zak&ljučaj prikaz" +Basic.MainMenu.Edit.Scale="Pregled &skaliranja" +Basic.MainMenu.Edit.Scale.Window="Skaliraj na veličinu prozora" +Basic.MainMenu.Edit.Scale.Canvas="Platno (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Izlaz (%1x%2)" Basic.MainMenu.Edit.Transform="&Transformiši" Basic.MainMenu.Edit.Transform.EditTransform="Izm&eni transformaciju..." Basic.MainMenu.Edit.Transform.ResetTransform="Poništi t&ransformaciju" @@ -492,10 +497,6 @@ Basic.Settings.Hotkeys="Prečice" Basic.Settings.Hotkeys.Pair="Kombinacije tastera deljene sa '%1' se ponašaju kao prekidači" -Basic.Hotkeys.StartStreaming="Započni strimovanje" -Basic.Hotkeys.StopStreaming="Zaustavi strimovanje" -Basic.Hotkeys.StartRecording="Počni snimanje" -Basic.Hotkeys.StopRecording="Zaustavi snimanje" Basic.Hotkeys.SelectScene="Prebaci na scenu" Basic.SystemTray.Show="Prikaži"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/sr-SP.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/sr-SP.ini
Changed
@@ -52,6 +52,7 @@ Hours="Сати" Minutes="Минута" Seconds="Секунди" +Deprecated="Превазиђено" QuickTransitions.SwapScenes="Замени сцене прегледа/излаза након прелаза" QuickTransitions.SwapScenesTT="Замењује сцене прегледа и излаза након прелаза (ако оригинална сцена још увек постоји).\nОво неће поништити промене које су начињене над оригиналном сценом излаза." @@ -285,6 +286,10 @@ Basic.MainMenu.Edit.UndoAction="Врати $1 (&U)" Basic.MainMenu.Edit.RedoAction="Уради поново $1 (&R)" Basic.MainMenu.Edit.LockPreview="Закључај приказ (&L)" +Basic.MainMenu.Edit.Scale="Преглед скалирања (&s)" +Basic.MainMenu.Edit.Scale.Window="Скалирај на величину прозора" +Basic.MainMenu.Edit.Scale.Canvas="Платно (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Излаз (%1x%2)" Basic.MainMenu.Edit.Transform="&Трансформиши" Basic.MainMenu.Edit.Transform.EditTransform="Изм&ени трансформацију..." Basic.MainMenu.Edit.Transform.ResetTransform="Поништи трансформацију (&R)" @@ -492,10 +497,6 @@ Basic.Settings.Hotkeys="Пречице" Basic.Settings.Hotkeys.Pair="Комбинације тастера дељене са '%1' се понашају као прекидачи" -Basic.Hotkeys.StartStreaming="Почни стримовање" -Basic.Hotkeys.StopStreaming="Заустави стримовање" -Basic.Hotkeys.StartRecording="Почни снимање" -Basic.Hotkeys.StopRecording="Заустави снимање" Basic.Hotkeys.SelectScene="Пребаци на сцену" Basic.SystemTray.Show="Прикажи"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/sv-SE.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/sv-SE.ini
Changed
@@ -107,6 +107,7 @@ Output.RecordNoSpace.Msg="Det finns inte tillräckligt med diskutrymme för att fortsätta inspelningen." Output.RecordError.Title="Inspelningsfel" Output.RecordError.Msg="Ett okänt fel uppstod vid inspelning." +Output.ReplayBuffer.NoHotkey.Title="Ingen angivet kortkommando!" Output.BadPath.Title="Ogiltig sökväg" Output.BadPath.Text="Den angivna sökvägen för utmatningsfil är ogiltig. Kontrollera att dina inställningar är korrekta och att en giltig sökväg har angetts." @@ -362,6 +363,8 @@ Basic.Settings.Output.Mode.Simple="Simpel" Basic.Settings.Output.Mode.Adv="Avancerat" Basic.Settings.Output.Mode.FFmpeg="FFmpeg-utmatning" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maximalt minne (Megabyte)" +Basic.Settings.Output.ReplayBuffer.Estimate="Uppskattad minnesanvändning: %1 MB" Basic.Settings.Output.Simple.SavePath="Inspelningssökväg" Basic.Settings.Output.Simple.RecordingQuality="Inspelningskvalitet" Basic.Settings.Output.Simple.RecordingQuality.Stream="Samma som ström" @@ -496,10 +499,6 @@ Basic.Settings.Hotkeys="Kortkommandon" Basic.Settings.Hotkeys.Pair="Tangentkombinationer som delas med \"%1\" fungerar som strömbrytare" -Basic.Hotkeys.StartStreaming="Börja strömma" -Basic.Hotkeys.StopStreaming="Sluta strömma" -Basic.Hotkeys.StartRecording="Starta inspelning" -Basic.Hotkeys.StopRecording="Stoppa inspelning" Basic.Hotkeys.SelectScene="Byt till scen" Basic.SystemTray.Show="Visa"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/th-TH.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/th-TH.ini
Changed
@@ -5,19 +5,34 @@ OK="ตกลง" Apply="นำไปใช้" Cancel="ยกเลิก" +Close="ปิด" +Save="บันทึก" +Discard="ละทิ้ง" +Disable="ไม่ใช้" Yes="ใช่" No="ไม่" Add="เพิ่ม" Remove="ลบ" Rename="เปลี่ยนชื่อ" +Filters="ฟิลเตอร์" Properties="คุณสมบัติ" MoveUp="เลื่อนขึ้น" MoveDown="เลื่อนลง" Settings="ตั้งค่า" +Display="แสดงผล" +Name="ชื่อ" Exit="ออก" Browse="เปิดหา" Mono="โมโน" Stereo="สเตอริโอ" +PreviewProjector="แสดงผลแบบเต็มจอ (ตัวอย่าง)" +Clear="ล้าง" +Revert="กลับค่าเดิม" +Show="แสดง" +Hide="ซ่อน" +Untitled="ไม่มีชื่อ" +New="ใหม่" +Enable="เปิดใช้งาน"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/tr-TR.ini
Changed
@@ -40,16 +40,35 @@ Duplicate="Çoğalt" Enable="Etkinleştir" DisableOSXVSync="OSX V-Sync Devre Dışı Bırakma" +HighResourceUsage="Kodlama aşırı yüklendi! Video ayarlarını kapatmayı veya daha hızlı bir kodlama ön ayarını kullanmayı düşünün." Transition="Geçiş" QuickTransitions="Hızlı Geçiş" Left="Sol" Right="Sağ" Top="Üst" Bottom="Alt" - - +Reset="Sıfırla" +Hours="Saat" +Minutes="Dakika" +Seconds="Saniye" +Deprecated="Kullanım dışı" +ReplayBuffer="Tekrar Oynatma Arabelleği" +Import="İçe Aktar" +Export="Dışa Aktar" + +QuickTransitions.DuplicateScene="Sahneyi Çoğalt" +QuickTransitions.EditProperties="Kaynakları Çoğalt" +QuickTransitions.HotkeyName="Hızlı Geçiş: %1" + +Basic.AddTransition="Yapılandırılabilir Geçiş Ekle" +Basic.RemoveTransition="Yapılandırılabilir Geçiş Kaldır" +Basic.TransitionProperties="Geçiş Özellikleri" +Basic.SceneTransitions="Sahne Geçişleri" Basic.TransitionDuration="Süre" +Basic.TogglePreviewProgramMode="Stüdyo Modu" +TransitionNameDlg.Text="Lütfen geçiş adını girin" +TransitionNameDlg.Title="Geçiş Adı" TitleBar.Profile="Profil" TitleBar.Scenes="Sahneler" @@ -60,13 +79,18 @@ NoNameEntered.Title="Lütfen geçerli bir isim girin" NoNameEntered.Text="İsmi boş kullanamazsınız." +ConfirmStart.Title="Yayın Başlatılsın Mı?" +ConfirmStart.Text="Yayını gerçekten başlatmak istiyor musunuz?" +ConfirmStop.Title="Yayın Durdurulsun Mu?" +ConfirmStop.Text="Yayını gerçekten durdurmak istiyor musunuz?" ConfirmExit.Title="OBS'den Çıkılsın mı?" ConfirmExit.Text="OBS şu anda etkin. Tüm yayınlar / kayıtlar kapatılacak. Çıkmak istediğinize emin misiniz?" ConfirmRemove.Title="Kaldırmayı Onayla" ConfirmRemove.Text="'$1''i kaldırmak istediğinizden emin misiniz?" +ConfirmRemove.TextMultiple="%1 öğeyi kaldırmak istediğinizden emin misiniz?" Output.ConnectFail.Title="Bağlantı kurulamadı" Output.ConnectFail.BadPath="Bağlantı adresiniz geçersiz. Ayarlarınızı kontrol edin ve geçerli bir adres giriniz." @@ -80,6 +104,7 @@ Output.RecordNoSpace.Msg="Kayıt'aa devam etmek yeterli disk alanı yok." Output.RecordError.Title="Kayıt Hatası" Output.RecordError.Msg="Kayıt anında bir hata oluştu." +Output.ReplayBuffer.NoHotkey.Title="Kısayol tuşu ayarlanmadı!" Output.BadPath.Title="Dosya Yolu Geçersiz" Output.BadPath.Text="Ayarlanan dosya kayıt yolu geçersiz. Lütfen ayarlarınızı kontrol ederek geçerli bir dosya yolunun girilmiş olduğundan emin olunuz." @@ -123,7 +148,23 @@ Basic.Main.PreviewConextMenu.Enable="Önizlemeyi Etkinleştir" - +ScaleFiltering="Ölçek Filtreleme" +ScaleFiltering.Point="Nokta" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicubic" +ScaleFiltering.Lanczos="Lanczos" + +Deinterlacing="Deinterlacing" +Deinterlacing.Discard="Discard" +Deinterlacing.Retro="Retro" +Deinterlacing.Blend="Blend" +Deinterlacing.Blend2x="Blend 2x" +Deinterlacing.Linear="Linear" +Deinterlacing.Linear2x="Linear 2x" +Deinterlacing.Yadif="Yadif" +Deinterlacing.Yadif2x="Yadif 2x" +Deinterlacing.TopFieldFirst="Önce Üst Alan" +Deinterlacing.BottomFieldFirst="Önce Alt Alan" Basic.Main.AddSceneDlg.Title="Sahne Ekle" Basic.Main.AddSceneDlg.Text="Lütfen sahne adını giriniz" @@ -155,11 +196,16 @@ Basic.PropertiesWindow.Confirm="Kaydedilmeyen değişikler var. Yaptığınız değişikleri kaydetmek istiyor musunuz?" Basic.PropertiesWindow.NoProperties="Hiçbir özellik mevcut değil" Basic.PropertiesWindow.AddFiles="Dosya Ekle" +Basic.PropertiesWindow.AddDir="Dizin Ekle" Basic.PropertiesWindow.AddURL="DosyaYolu/URL Ekle" +Basic.PropertiesWindow.AddEditableListDir="'%1' dizinine ekle" Basic.PropertiesWindow.AddEditableListFiles="Dosyaları '%1' 'e ekle" Basic.PropertiesWindow.AddEditableListEntry="Girişi '%1' 'e ekle" Basic.PropertiesWindow.EditEditableListEntry="'%1' 'den giriş ekle" +Basic.PropertiesView.FPS.Simple="Basit FPS Değerleri" +Basic.PropertiesView.FPS.Rational="Rasyonel FPS Değerleri" +Basic.PropertiesView.FPS.ValidFPSRanges="Geçerli Kare Aralıkları:" Basic.InteractionWindow="Etkileşime geçilen '%1'" @@ -214,11 +260,15 @@ Basic.Main.Sources="Kaynaklar" Basic.Main.Connecting="Bağlanıyor..." Basic.Main.StartRecording="Kaydı Başlat" +Basic.Main.StartReplayBuffer="Tekrar Oynatma Arabelleğini Başlat" Basic.Main.StartStreaming="Yayını Başlat" Basic.Main.StopRecording="Kaydı Durdur" Basic.Main.StoppingRecording="Kayıt Durduruluyor..." +Basic.Main.StopReplayBuffer="Tekrar Oynatma Arabelleğini Durdur" +Basic.Main.StoppingReplayBuffer="Tekrar Oynatma Arabelleği Durduruluyor..." Basic.Main.StopStreaming="Yayını Durdur" Basic.Main.StoppingStreaming="Canlı Yayın Durduruluyor..." +Basic.Main.ForceStopStreaming="Yayını Durdur (gecikmeyi yoksay)" Basic.MainMenu.File="&Dosya" Basic.MainMenu.File.Export="Dışa Aktar" @@ -228,6 +278,7 @@ Basic.MainMenu.File.Settings="&Ayarlar" Basic.MainMenu.File.ShowSettingsFolder="Ayarlar Dosyasını Göster" Basic.MainMenu.File.ShowProfileFolder="Profil Dosyasını Göster" +Basic.MainMenu.AlwaysOnTop="&Her Zaman Üstte" Basic.MainMenu.File.Exit="Ç&ıkış" Basic.MainMenu.Edit="&Düzenle" @@ -235,8 +286,15 @@ Basic.MainMenu.Edit.Redo="&Tekrar Yap" Basic.MainMenu.Edit.UndoAction="&$1 Geri al" Basic.MainMenu.Edit.RedoAction="&$1 Yinele" +Basic.MainMenu.Edit.LockPreview="&Önizlemeyi Kilitle" +Basic.MainMenu.Edit.Scale="Ölçekleme &Önizleme" +Basic.MainMenu.Edit.Scale.Window="Pencereye Ölçekle" +Basic.MainMenu.Edit.Scale.Canvas="Tuval (%1x%2)" +Basic.MainMenu.Edit.Scale.Output="Çıktı (%1x%2)" Basic.MainMenu.Edit.Transform="&Dönüştür" Basic.MainMenu.Edit.Transform.EditTransform="&Dönüştürmeyi Düzenle..." +Basic.MainMenu.Edit.Transform.CopyTransform="Dönüştürmeyi Kopyala" +Basic.MainMenu.Edit.Transform.PasteTransform="Dönüştürmeyi Yapıştır" Basic.MainMenu.Edit.Transform.ResetTransform="&Dönüştürmeyi Sıfırla" Basic.MainMenu.Edit.Transform.Rotate90CW="90 derece saat yönüne döndür" Basic.MainMenu.Edit.Transform.Rotate90CCW="90 derece saatin tersi yönüne döndür" @@ -253,10 +311,22 @@ Basic.MainMenu.Edit.Order.MoveToBottom="En &Alta Taşı" Basic.MainMenu.Edit.AdvAudio="&Gelişmiş Ses Özellikleri" +Basic.MainMenu.View="&Görünüm" +Basic.MainMenu.View.Toolbars="&Araç Çubukları" +Basic.MainMenu.View.Toolbars.Listboxes="&Liste Kutuları" +Basic.MainMenu.View.SceneTransitions="S&ahne Geçişleri" +Basic.MainMenu.View.StatusBar="&Durum Çubuğu" Basic.MainMenu.SceneCollection="&Sahne Koleksiyonu" Basic.MainMenu.Profile="&Profil" +Basic.MainMenu.Profile.Import="Profili İçe Aktar" +Basic.MainMenu.Profile.Export="Profili Dışa Aktar" +Basic.MainMenu.SceneCollection.Import="Sahne Koleksiyonunu İçe Aktar" +Basic.MainMenu.SceneCollection.Export="Sahne Koleksiyonunu Dışa Aktar" +Basic.MainMenu.Profile.Exists="Profil zaten var" +Basic.MainMenu.SceneCollection.Exists="Sahne koleksiyonu zaten var" +Basic.MainMenu.Tools="&Araçlar" Basic.MainMenu.Help="&Yardım" Basic.MainMenu.Help.Website="&Siteyi Ziyaret Et" @@ -274,6 +344,19 @@ Basic.Settings.General="Genel" Basic.Settings.General.Theme="Tema" Basic.Settings.General.Language="Dil" +Basic.Settings.General.WarnBeforeStartingStream="Yayın başlatırken onay iletişim kutusunu göster" +Basic.Settings.General.WarnBeforeStoppingStream="Yayın durduğunda onay iletişim kutusunu göster" +Basic.Settings.General.HideProjectorCursor="Projektörler üzerinde imleci gizle" +Basic.Settings.General.ProjectorAlwaysOnTop="Projektörleri her zaman üstte tut" +Basic.Settings.General.Snapping="Kaynak Hizalama" +Basic.Settings.General.ScreenSnapping="Kaynakları ekranın kenarına yasla" +Basic.Settings.General.CenterSnapping="Kaynakları dikey ve yatay merkeze yasla" +Basic.Settings.General.SourceSnapping="Kaynakları diğer kaynaklara yasla" +Basic.Settings.General.SnapDistance="Yaslama Hassasiyeti" +Basic.Settings.General.RecordWhenStreaming="Yayın sırasında otomatik olarak kayıt yap" +Basic.Settings.General.KeepRecordingWhenStreamStops="Yayın durduğunda kaydı tut" +Basic.Settings.General.SysTrayEnabled="Sistem tepsisi simgesini etkinleştir" +Basic.Settings.General.SysTrayWhenStarted="Başladığında sistem tepsisine küçült" Basic.Settings.Stream="Yayın" Basic.Settings.Stream.StreamType="Yayın Türü" @@ -283,10 +366,18 @@ Basic.Settings.Output.Encoder="Kodlayıcı" Basic.Settings.Output.SelectDirectory="Kayıt Dizinini Seçin" Basic.Settings.Output.SelectFile="Kayıt Dosyasını Seçin" +Basic.Settings.Output.EnforceBitrate="Yayın hizmetini bit hızı sınırlarına zorla" Basic.Settings.Output.Mode="Çıkış modu" Basic.Settings.Output.Mode.Simple="Basit" Basic.Settings.Output.Mode.Adv="Gelişmiş" Basic.Settings.Output.Mode.FFmpeg="FFmpeg Çıkışı" +Basic.Settings.Output.UseReplayBuffer="Tekrar Oynatma Arabelleğini Etkinleştir" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Maksimum Yeniden Oynatma Süresi (Seconds)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Maksimum Bellek (Megabayt)" +Basic.Settings.Output.ReplayBuffer.Estimate="Tahmini bellek kullanımı: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Bellek kullanımını tahmin edemezsin. Lütfen maksimum bellek sınırını ayarlayın." +Basic.Settings.Output.ReplayBuffer.Prefix="Tekrar Oynatma Arabelleği Dosya Adı Öneki" +Basic.Settings.Output.ReplayBuffer.Suffix="Suffix" Basic.Settings.Output.Simple.SavePath="Kayıt Yolu" Basic.Settings.Output.Simple.RecordingQuality="Kayıt Kalitesi" Basic.Settings.Output.Simple.RecordingQuality.Stream="Canlı Yayın ile Aynı" @@ -296,31 +387,38 @@ Basic.Settings.Output.Simple.Warn.Lossless.Msg="Kayıpsız kalitede kullanmak istediğinizden emin misiniz?" Basic.Settings.Output.Simple.Warn.Lossless.Title="Kayıpsız kalite uyarısı!" Basic.Settings.Output.Simple.Encoder.Software="Yazılım (x264)" +Basic.Settings.Output.Simple.Encoder.Hardware.QSV="Donanım (QSV)" +Basic.Settings.Output.Simple.Encoder.Hardware.AMD="Donanım (AMD)" +Basic.Settings.Output.Simple.Encoder.Hardware.NVENC="Donanım (NVENC)" Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Yazılım (x264 düşük CPU kullanım önayarı, dosya boyutunu artırır)" -Basic.Settings.Output.VideoBitrate="Video Bithızı" -Basic.Settings.Output.AudioBitrate="Ses Bithızı" +Basic.Settings.Output.VideoBitrate="Video Bit Hızı" +Basic.Settings.Output.AudioBitrate="Ses Bit Hızı" Basic.Settings.Output.Reconnect="Otomatik Yeniden Bağlan" Basic.Settings.Output.RetryDelay="Yeniden Deneme Gecikmesi (saniye)" Basic.Settings.Output.MaxRetries="En fazla yeniden deneme sayısı" Basic.Settings.Output.Advanced="Gelişmiş Kodlayıcı Ayarlarını Etkinleştir" Basic.Settings.Output.EncoderPreset="Kodlayıcı Önayarı (yüksek = daha az İŞLEMCİ)" Basic.Settings.Output.CustomEncoderSettings="Özel Kodlayıcı Ayarları" +Basic.Settings.Output.CustomMuxerSettings="Özel Muxer Ayarları" Basic.Settings.Output.NoSpaceFileName="Dosya ismini boşluk olmadan oluştur" Basic.Settings.Output.Adv.Rescale="Çıkışı Yeniden Ölçeklendir" Basic.Settings.Output.Adv.AudioTrack="Ses Parçası" Basic.Settings.Output.Adv.Streaming="Yayın" -Basic.Settings.Output.Adv.ApplyServiceSettings="Gerçek zamanlı ayayın hizmeti kodlayıcı ayarlarını zorla" +Basic.Settings.Output.Adv.ApplyServiceSettings="Yayın hizmetini kodlayıcı ayarlarına zorla" Basic.Settings.Output.Adv.Audio.Track1="Parça 1" Basic.Settings.Output.Adv.Audio.Track2="Ses İzi 2" Basic.Settings.Output.Adv.Audio.Track3="Ses İzi 3" Basic.Settings.Output.Adv.Audio.Track4="Ses İzi 4" +Basic.Settings.Output.Adv.Audio.Track5="Parça 5" +Basic.Settings.Output.Adv.Audio.Track6="Parça 6" Basic.Settings.Output.Adv.Recording="Kayıt" Basic.Settings.Output.Adv.Recording.Type="Tür" Basic.Settings.Output.Adv.Recording.Type.Standard="Standart" Basic.Settings.Output.Adv.Recording.Type.FFmpegOutput="Özel Çıkış (FFmpeg)" Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Yayın kodlayıcı kullan)" +Basic.Settings.Output.Adv.Recording.Filename="Dosya Adı Biçimi" Basic.Settings.Output.Adv.Recording.OverwriteIfExists="Dosya varsa üzerine yaz" Basic.Settings.Output.Adv.FFmpeg.Type="FFmpeg Çıkış Türü" Basic.Settings.Output.Adv.FFmpeg.Type.URL="URL'ye Çıkış" @@ -378,9 +476,11 @@ Basic.Settings.Audio.UnknownAudioDevice="[Cihaz bağlı yada kullanılabilir değil]" Basic.Settings.Advanced="Gelişmiş" +Basic.Settings.Advanced.General.ProcessPriority="İşlem Önceliği" Basic.Settings.Advanced.General.ProcessPriority.High="Yüksek" Basic.Settings.Advanced.General.ProcessPriority.AboveNormal="Normalin Üstünde" Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal" +Basic.Settings.Advanced.General.ProcessPriority.Idle="Boşta" Basic.Settings.Advanced.FormatWarning="Uyarı: NV12 dışındaki renk biçimleri esas olarak kayıt için tasarlanmıştır ve yayın anında kullanma önerilmez. Yayın nedeni ile renk biçimini dönüştürme çok fazla İŞLEMCİ kullanımına sebep olabilir." Basic.Settings.Advanced.Audio.BufferingTime="Ses Ön Bellekleme Süresi" Basic.Settings.Advanced.Video.ColorFormat="Renk Biçimi" @@ -392,26 +492,30 @@ Basic.Settings.Advanced.StreamDelay.Duration="Süre (saniye)" Basic.Settings.Advanced.StreamDelay.Preserve="Tatbik ederken kesim noktasını (gecikme artışı) koru" Basic.Settings.Advanced.StreamDelay.MemoryUsage="Tahmini Bellek Kullanımı: %1 MB" +Basic.Settings.Advanced.Network="Ağ" +Basic.Settings.Advanced.Network.BindToIP="IP Bağla" Basic.AdvAudio="Gelişmiş Ses Özellikleri" Basic.AdvAudio.Name="İsim" Basic.AdvAudio.Volume="Ses Düzeyi (%)" Basic.AdvAudio.Mono="Mono Karıştırmayı Azalt" +Basic.AdvAudio.Panning="Kaydırma" +Basic.AdvAudio.SyncOffset="Eşitleme Uzaklığı (ms)" Basic.AdvAudio.AudioTracks="Parçalar" Basic.Settings.Hotkeys="Kısayollar" -Basic.Hotkeys.StartStreaming="Yayını Başlat" -Basic.Hotkeys.StopStreaming="Yayını Durdur" -Basic.Hotkeys.StartRecording="Kaydı Başlat" -Basic.Hotkeys.StopRecording="Kaydı Durdur" Basic.Hotkeys.SelectScene="Sahneye geçiş yap" +Basic.SystemTray.Show="Göster" +Basic.SystemTray.Hide="Gizle" +Basic.SystemTray.Message.Reconnecting="Bağlantı kesildi. Yeniden bağlanılıyor..." Hotkeys.Insert="Ekle" Hotkeys.Delete="Sil" Hotkeys.Home="Ana Sayfa" +Hotkeys.End="End" Hotkeys.PageUp="Page Up" Hotkeys.PageDown="Page Down" Hotkeys.NumLock="Num Lock" @@ -420,6 +524,7 @@ Hotkeys.Backspace="Backspace" Hotkeys.Tab="Tab" Hotkeys.Print="Yazdır" +Hotkeys.Pause="Duraklat" Hotkeys.Left="Sol" Hotkeys.Right="Sağ" Hotkeys.Up="Yukarı" @@ -429,6 +534,11 @@ Hotkeys.Menu="Menü" Hotkeys.Space="Boşluk" Hotkeys.NumpadNum="Numpad %1" +Hotkeys.NumpadMultiply="Numpad *" +Hotkeys.NumpadDivide="Numpad /" +Hotkeys.NumpadAdd="Numpad Ekle" +Hotkeys.NumpadSubtract="Numpad -" +Hotkeys.NumpadDecimal="Numpad ," Hotkeys.AppleKeypadNum="%1 (Tuş takımı)" Hotkeys.AppleKeypadMultiply="* (Tuş takımı)" Hotkeys.AppleKeypadDivide="/ (Tuş takımı)"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/uk-UA.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/uk-UA.ini
Changed
@@ -53,6 +53,9 @@ Minutes="Хвилин" Seconds="Секунд" Deprecated="Припинено підтримку" +ReplayBuffer="Буфер Повторів" +Import="Імпорт" +Export="Експорт" QuickTransitions.SwapScenes="Поміняти місцями сцени Перегляд/Вивід після Відео-переходу" QuickTransitions.SwapScenesTT="Міняє місцями сцени Перегляд та Вивід після закінчення Відео-переходу (якщо сцена Вивід ще існує).\nЗміни внесені до обох сцен залишаються." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="На диску недостатньо простору для запису." Output.RecordError.Title="Помилка запису" Output.RecordError.Msg="Під час запису відбулася несподівана помилка." +Output.ReplayBuffer.NoHotkey.Title="Гарячу клавішу не вказано!" +Output.ReplayBuffer.NoHotkey.Msg="Гарячу клавішу для Буферу Повторів не вказано. Будь ласка, встановіть гарячу клавішу на дію \"Зберегти Повтор\", щоб використовувати її для збереження повторів." Output.BadPath.Title="Недійсний шлях до файлу" Output.BadPath.Text="Шлях вказаний для виводу файлу недійсний. Будь ласка, перевірте у налаштуваннях, що шлях було вказано вірно." @@ -262,9 +267,12 @@ Basic.Main.Sources="Джерела" Basic.Main.Connecting="З'єднання..." Basic.Main.StartRecording="Почати запис" +Basic.Main.StartReplayBuffer="Запустити Буфер Повторів" Basic.Main.StartStreaming="Почати трансляцію" Basic.Main.StopRecording="Зупинити запис" Basic.Main.StoppingRecording="Запис зупиняється..." +Basic.Main.StopReplayBuffer="Зупинити Буфер Повторів" +Basic.Main.StoppingReplayBuffer="Буфер Повторів зупиняється..." Basic.Main.StopStreaming="Закінчити трансляцію" Basic.Main.StoppingStreaming="Припинення трансляції..." Basic.Main.ForceStopStreaming="Закінчити трансляцію (миттєво)" @@ -362,6 +370,14 @@ Basic.Settings.Output.Mode.Simple="Простий" Basic.Settings.Output.Mode.Adv="Розширений" Basic.Settings.Output.Mode.FFmpeg="Вивід FFmpeg" +Basic.Settings.Output.UseReplayBuffer="Увімкнути Буфер Повторів" +Basic.Settings.Output.ReplayBuffer.SecondsMax="Максимальна тривалість Повтору (у секундах)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="Максимальний об'єм пам'яті (у мегабайтах)" +Basic.Settings.Output.ReplayBuffer.Estimate="Буде використано пам'яті: %1 МБ" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="Не вдалося оцінити об'єм використання пам'яті. Будь ласка, встановіть максимальний об'єм пам'яті для Буферу Повторів вручну." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(Примітка: переконайтеся, що встановили гарячу клавішу для Буферу Повторів в розділі гарячі клавіші)" +Basic.Settings.Output.ReplayBuffer.Prefix="Буфер Повторів, Ім'я файлу, Префікс" +Basic.Settings.Output.ReplayBuffer.Suffix="Суфікс" Basic.Settings.Output.Simple.SavePath="Шлях до запису" Basic.Settings.Output.Simple.RecordingQuality="Якість запису" Basic.Settings.Output.Simple.RecordingQuality.Stream="Так само як трансляція" @@ -497,10 +513,6 @@ Basic.Settings.Hotkeys="Гарячі клавіші" Basic.Settings.Hotkeys.Pair="Однакові комбінації клавіш задані до '%1' діють як перемикач" -Basic.Hotkeys.StartStreaming="Почати трансляцію" -Basic.Hotkeys.StopStreaming="Закінчити трансляцію" -Basic.Hotkeys.StartRecording="Почати запис" -Basic.Hotkeys.StopRecording="Зупинити запис" Basic.Hotkeys.SelectScene="Перейти до сцени" Basic.SystemTray.Show="Показати"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/vi-VN.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/vi-VN.ini
Changed
@@ -253,56 +253,56 @@ Basic.Main.Scenes="Cảnh" Basic.Main.Sources="Nguồn" Basic.Main.Connecting="Đang kết nối..." -Basic.Main.StartRecording="Bắt đầu ghi âm" +Basic.Main.StartRecording="Bắt đầu ghi" Basic.Main.StartStreaming="Bắt đầu Streaming" -Basic.Main.StopRecording="Dừng ghi âm" +Basic.Main.StopRecording="Dừng ghi" Basic.Main.StoppingRecording="Dừng ghi video..." Basic.Main.StopStreaming="Ngừng Streaming" Basic.Main.StoppingStreaming="Dừng stream..." Basic.Main.ForceStopStreaming="Ngừng Streaming (huỷ chậm trễ)" Basic.MainMenu.File="&Tập tin" -Basic.MainMenu.File.Export="&Xuất khẩu" -Basic.MainMenu.File.Import="&Nhập khẩu" -Basic.MainMenu.File.ShowRecordings="Bản ghi âm & Hiển thị" -Basic.MainMenu.File.Remux="Re & mux bản ghi âm" +Basic.MainMenu.File.Export="&Xuất" +Basic.MainMenu.File.Import="&Nhập" +Basic.MainMenu.File.ShowRecordings="Hiển thị &Bản ghi" +Basic.MainMenu.File.Remux="Re&mux bản ghi" Basic.MainMenu.File.Settings="&Cài đặt" -Basic.MainMenu.File.ShowSettingsFolder="Hiển thị cài đặt thư mục" +Basic.MainMenu.File.ShowSettingsFolder="Hiển thị thư mục cài đặt" Basic.MainMenu.File.ShowProfileFolder="Hiển thị thư mục hồ sơ" Basic.MainMenu.AlwaysOnTop="&Luôn trên đầu trang" Basic.MainMenu.File.Exit="&Thoát" -Basic.MainMenu.Edit="& Chỉnh sửa" -Basic.MainMenu.Edit.Undo="& Hoàn tác" -Basic.MainMenu.Edit.Redo="& Làm lại" -Basic.MainMenu.Edit.UndoAction="& Hoàn tác $1" -Basic.MainMenu.Edit.RedoAction="& Làm lại $1" +Basic.MainMenu.Edit="&Chỉnh sửa" +Basic.MainMenu.Edit.Undo="&Hoàn tác" +Basic.MainMenu.Edit.Redo="&Làm lại" +Basic.MainMenu.Edit.UndoAction="&Hoàn tác $1" +Basic.MainMenu.Edit.RedoAction="&Làm lại $1" Basic.MainMenu.Edit.LockPreview="&Khóa xem trước" -Basic.MainMenu.Edit.Transform="Biến đổi" -Basic.MainMenu.Edit.Transform.EditTransform="& Chỉnh sửa biến đổi..." -Basic.MainMenu.Edit.Transform.ResetTransform="& Đặt lại biến đổi" +Basic.MainMenu.Edit.Transform="&Biến đổi" +Basic.MainMenu.Edit.Transform.EditTransform="&Chỉnh sửa biến đổi..." +Basic.MainMenu.Edit.Transform.ResetTransform="&Đặt lại biến đổi" Basic.MainMenu.Edit.Transform.Rotate90CW="Xoay 90 độ bên phải" Basic.MainMenu.Edit.Transform.Rotate90CCW="Xoay 90 độ bên trái" Basic.MainMenu.Edit.Transform.Rotate180="Xoay 180 độ" -Basic.MainMenu.Edit.Transform.FlipHorizontal="Flip & ngang" -Basic.MainMenu.Edit.Transform.FlipVertical="Flip & dọc" -Basic.MainMenu.Edit.Transform.FitToScreen="Phù hợp với màn hình" -Basic.MainMenu.Edit.Transform.StretchToScreen="& Căng để màn hình" +Basic.MainMenu.Edit.Transform.FlipHorizontal="Lật &Ngang" +Basic.MainMenu.Edit.Transform.FlipVertical="Lật &Dọc" +Basic.MainMenu.Edit.Transform.FitToScreen="&Vừa với màn hình" +Basic.MainMenu.Edit.Transform.StretchToScreen="&Giãn ra để lấp đầy m.hình" Basic.MainMenu.Edit.Transform.CenterToScreen="& Trung tâm màn hình" -Basic.MainMenu.Edit.Order="& Đặt hàng" -Basic.MainMenu.Edit.Order.MoveUp="Chuyển Lên" -Basic.MainMenu.Edit.Order.MoveDown="Chuyển xuống" -Basic.MainMenu.Edit.Order.MoveToTop="Chuyển đến đầu trang" -Basic.MainMenu.Edit.Order.MoveToBottom="Chuyển đến dưới cùng" -Basic.MainMenu.Edit.AdvAudio="Thuộc tính âm thanh nâng cao" +Basic.MainMenu.Edit.Order="&Đặt" +Basic.MainMenu.Edit.Order.MoveUp="Chuyển &Lên" +Basic.MainMenu.Edit.Order.MoveDown="Chuyển &Xuống" +Basic.MainMenu.Edit.Order.MoveToTop="Chuyển đến &Đầu" +Basic.MainMenu.Edit.Order.MoveToBottom="Chuyển xuống &Dưới" +Basic.MainMenu.Edit.AdvAudio="Các thuộc tính âm thanh nâng cao" Basic.MainMenu.View="&Hiển thị" Basic.MainMenu.View.Toolbars="&Thanh công cụ" Basic.MainMenu.View.Toolbars.Listboxes="&Listboxes" Basic.MainMenu.View.StatusBar="&Thanh trạng thái" -Basic.MainMenu.SceneCollection="& Cảnh bộ sưu tập" -Basic.MainMenu.Profile="& Hồ sơ" +Basic.MainMenu.SceneCollection="& Bộ sưu tập cảnh" +Basic.MainMenu.Profile="&Hồ sơ" Basic.MainMenu.Tools="&Công cụ" @@ -431,9 +431,9 @@ Basic.Settings.Audio.AuxDevice="Thiết bị âm thanh mic/phụ trợ" Basic.Settings.Audio.AuxDevice2="Thiết bị âm thanh mic/phụ trợ 2" Basic.Settings.Audio.AuxDevice3="Thiết bị âm thanh mic/phụ trợ 3" -Basic.Settings.Audio.EnablePushToMute="Sử đẩy để tắt tiếng" -Basic.Settings.Audio.PushToMuteDelay="Sự chậm trễ đẩy để tắt tiếng" -Basic.Settings.Audio.EnablePushToTalk="Sử Push-to-talk" +Basic.Settings.Audio.EnablePushToMute="Bật bấm để tắt tiếng" +Basic.Settings.Audio.PushToMuteDelay="Bấm để tắt tiếng trễ" +Basic.Settings.Audio.EnablePushToTalk="Bật bắm để nói" Basic.Settings.Audio.PushToTalkDelay="Bấm để nói trễ" Basic.Settings.Audio.UnknownAudioDevice="[Thiết bị không được kết nối hoặc không sẵn dùng]" @@ -468,10 +468,6 @@ Basic.Settings.Hotkeys="Phím nóng" Basic.Settings.Hotkeys.Pair="Tổ hợp phím được chia sẻ với '%1' hành động như chuyển" -Basic.Hotkeys.StartStreaming="Bắt đầu Streaming" -Basic.Hotkeys.StopStreaming="Ngừng Streaming" -Basic.Hotkeys.StartRecording="Bắt đầu ghi âm" -Basic.Hotkeys.StopRecording="Dừng ghi âm" Basic.Hotkeys.SelectScene="Chuyển cảnh" Basic.SystemTray.Show="Hiện"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/zh-CN.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/zh-CN.ini
Changed
@@ -53,6 +53,9 @@ Minutes="分钟" Seconds="秒" Deprecated="不推荐使用" +ReplayBuffer="重拨缓存" +Import="导入" +Export="导出" QuickTransitions.SwapScenes="在过渡动画后交换预览/输出场景" QuickTransitions.SwapScenesTT="在过渡后,交换预览和输出场景(如果输出的原始场景仍然存在). \n 这个不会撤消任何可能对输出的原始场景的更改." @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="没有足够磁盘空间来继续录像." Output.RecordError.Title="录像错误" Output.RecordError.Msg="录像时发生未指定错误." +Output.ReplayBuffer.NoHotkey.Title="没有快捷键设置!" +Output.ReplayBuffer.NoHotkey.Msg="没有为回放缓存设置快捷键. 请设置保存跨借鉴来用于保存回放录像." Output.BadPath.Title="错误的文件路径" Output.BadPath.Text="无效的输出路径。请检查您的设置,确认文件路径是否有效。" @@ -262,9 +267,12 @@ Basic.Main.Sources="来源" Basic.Main.Connecting="连接中..." Basic.Main.StartRecording="开始录制" +Basic.Main.StartReplayBuffer="开始回放缓存" Basic.Main.StartStreaming="开始串流" Basic.Main.StopRecording="停止录制" Basic.Main.StoppingRecording="停止录制..." +Basic.Main.StopReplayBuffer="停止回放缓存" +Basic.Main.StoppingReplayBuffer="正在停止回放缓存..." Basic.Main.StopStreaming="停止串流" Basic.Main.StoppingStreaming="停止推流..." Basic.Main.ForceStopStreaming="停止流 (放弃延迟)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="输出 (%1x%2)" Basic.MainMenu.Edit.Transform="变换 (&T)" Basic.MainMenu.Edit.Transform.EditTransform="编辑变换 (&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="复制变换" +Basic.MainMenu.Edit.Transform.PasteTransform="粘贴变换" Basic.MainMenu.Edit.Transform.ResetTransform="重置变换 (&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="顺时针旋转 90 度(&9)" Basic.MainMenu.Edit.Transform.Rotate90CCW="逆时针旋转 90 度(&D)" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="场景集合 (&S)" Basic.MainMenu.Profile="配置文件 (&P)" +Basic.MainMenu.Profile.Import="导入配置文件" +Basic.MainMenu.Profile.Export="导出配置文件" +Basic.MainMenu.SceneCollection.Import="导入场景集合" +Basic.MainMenu.SceneCollection.Export="导出场景集合" +Basic.MainMenu.Profile.Exists="配置文件已存在" +Basic.MainMenu.SceneCollection.Exists="场景机会已存在" Basic.MainMenu.Tools="工具 (&T)" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="简单" Basic.Settings.Output.Mode.Adv="高级" Basic.Settings.Output.Mode.FFmpeg="FFmpeg 输出" +Basic.Settings.Output.UseReplayBuffer="启用回放缓存" +Basic.Settings.Output.ReplayBuffer.SecondsMax="最大回放时间(秒)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="最大内存(Mb)" +Basic.Settings.Output.ReplayBuffer.Estimate="估计内存使用率: %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="无法估计内存使用率. 请设置最大内存限制." +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(注意: 确保在快捷键部分设置一个回放缓冲区的快捷键)" +Basic.Settings.Output.ReplayBuffer.Prefix="回放缓存文件名前缀" +Basic.Settings.Output.ReplayBuffer.Suffix="后缀" Basic.Settings.Output.Simple.SavePath="录像路径" Basic.Settings.Output.Simple.RecordingQuality="录像质量" Basic.Settings.Output.Simple.RecordingQuality.Stream="与流相同" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="轨道 2" Basic.Settings.Output.Adv.Audio.Track3="轨道 3" Basic.Settings.Output.Adv.Audio.Track4="轨道 4" +Basic.Settings.Output.Adv.Audio.Track5="轨道 5" +Basic.Settings.Output.Adv.Audio.Track6="轨道 6" Basic.Settings.Output.Adv.Recording="录像" Basic.Settings.Output.Adv.Recording.Type="类型" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="热键" Basic.Settings.Hotkeys.Pair="作为切换的键组合与 '%1' 共享" -Basic.Hotkeys.StartStreaming="开始串流" -Basic.Hotkeys.StopStreaming="停止串流" -Basic.Hotkeys.StartRecording="开始录像" -Basic.Hotkeys.StopRecording="停止录像" Basic.Hotkeys.SelectScene="切换到场景" Basic.SystemTray.Show="显示"
View file
obs-studio-0.16.6.tar.xz/UI/data/locale/zh-TW.ini -> obs-studio-0.17.0.tar.xz/UI/data/locale/zh-TW.ini
Changed
@@ -53,6 +53,9 @@ Minutes="分鐘" Seconds="秒" Deprecated="不再維護" +ReplayBuffer="重播緩衝" +Import="匯入" +Export="匯出" QuickTransitions.SwapScenes="轉場後交換預覽/輸出場景" QuickTransitions.SwapScenesTT="(如果輸出的原始場景仍然存在) 轉場後交換預覽和輸出場景。\n這並不會復原任何對輸出原始場景所作的改動。" @@ -107,6 +110,8 @@ Output.RecordNoSpace.Msg="沒有足夠的空間存放錄製影片" Output.RecordError.Title="錄製錯誤" Output.RecordError.Msg="在錄製時發生了預料外的錯誤。" +Output.ReplayBuffer.NoHotkey.Title="沒有設定熱鍵 !" +Output.ReplayBuffer.NoHotkey.Msg="沒有為重播緩衝設定儲存重播熱鍵。請設定\"儲存重播\"熱鍵以保存重播。" Output.BadPath.Title="無效的路徑" Output.BadPath.Text="無效的輸出路徑。 請確認您的檔案路徑是正確的。" @@ -262,9 +267,12 @@ Basic.Main.Sources="來源" Basic.Main.Connecting="連線中……" Basic.Main.StartRecording="開始錄製" +Basic.Main.StartReplayBuffer="開始重播緩衝" Basic.Main.StartStreaming="開始串流" Basic.Main.StopRecording="停止錄製" Basic.Main.StoppingRecording="停止錄製..." +Basic.Main.StopReplayBuffer="停止重播緩衝" +Basic.Main.StoppingReplayBuffer="正在停止重播緩衝..." Basic.Main.StopStreaming="停止串流" Basic.Main.StoppingStreaming="停止串流..." Basic.Main.ForceStopStreaming="停止實況(丟棄延遲)" @@ -292,6 +300,8 @@ Basic.MainMenu.Edit.Scale.Output="輸出 (%1x%2)" Basic.MainMenu.Edit.Transform="變型 (&T)" Basic.MainMenu.Edit.Transform.EditTransform="編輯變型設定…… (&E)" +Basic.MainMenu.Edit.Transform.CopyTransform="複製變型" +Basic.MainMenu.Edit.Transform.PasteTransform="貼上變型" Basic.MainMenu.Edit.Transform.ResetTransform="重設變型設定 (&R)" Basic.MainMenu.Edit.Transform.Rotate90CW="順時針旋轉 90°" Basic.MainMenu.Edit.Transform.Rotate90CCW="逆時針旋轉 90°" @@ -316,6 +326,12 @@ Basic.MainMenu.SceneCollection="場景群組 (&S)" Basic.MainMenu.Profile="設定檔 (&P)" +Basic.MainMenu.Profile.Import="匯入設定檔" +Basic.MainMenu.Profile.Export="匯出設定檔" +Basic.MainMenu.SceneCollection.Import="匯入場景群組" +Basic.MainMenu.SceneCollection.Export="匯出場景群組" +Basic.MainMenu.Profile.Exists="已有該設定檔" +Basic.MainMenu.SceneCollection.Exists="已有該場景群組" Basic.MainMenu.Tools="工具(&T)" @@ -362,6 +378,14 @@ Basic.Settings.Output.Mode.Simple="簡易" Basic.Settings.Output.Mode.Adv="進階" Basic.Settings.Output.Mode.FFmpeg="FFmpeg 輸出" +Basic.Settings.Output.UseReplayBuffer="啟用重播緩衝" +Basic.Settings.Output.ReplayBuffer.SecondsMax="最大重播時間(秒)" +Basic.Settings.Output.ReplayBuffer.MegabytesMax="最大記憶體使用量(MB)" +Basic.Settings.Output.ReplayBuffer.Estimate="估計記憶體使用量︰ %1 MB" +Basic.Settings.Output.ReplayBuffer.EstimateUnknown="無法預估記憶體使用量。請設定最大記憶體使用量。" +Basic.Settings.Output.ReplayBuffer.HotkeyMessage="(注意:請確定在熱鍵區有為重播緩衝設定熱鍵)" +Basic.Settings.Output.ReplayBuffer.Prefix="重播緩衝檔案名稱前綴" +Basic.Settings.Output.ReplayBuffer.Suffix="後綴" Basic.Settings.Output.Simple.SavePath="錄影路徑" Basic.Settings.Output.Simple.RecordingQuality="錄影畫質" Basic.Settings.Output.Simple.RecordingQuality.Stream="與串流同等畫質" @@ -399,6 +423,8 @@ Basic.Settings.Output.Adv.Audio.Track2="音軌 2" Basic.Settings.Output.Adv.Audio.Track3="音軌 3" Basic.Settings.Output.Adv.Audio.Track4="音軌 4" +Basic.Settings.Output.Adv.Audio.Track5="音軌 5" +Basic.Settings.Output.Adv.Audio.Track6="音軌 6" Basic.Settings.Output.Adv.Recording="錄影" Basic.Settings.Output.Adv.Recording.Type="類型" @@ -497,10 +523,6 @@ Basic.Settings.Hotkeys="快捷鍵" Basic.Settings.Hotkeys.Pair="按鍵組合與'%1'共用作為切換鍵" -Basic.Hotkeys.StartStreaming="開始串流" -Basic.Hotkeys.StopStreaming="停止串流" -Basic.Hotkeys.StartRecording="開始錄影" -Basic.Hotkeys.StopRecording="停止錄影" Basic.Hotkeys.SelectScene="切換到場景" Basic.SystemTray.Show="顯示"
View file
obs-studio-0.16.6.tar.xz/UI/forms/OBSBasic.ui -> obs-studio-0.17.0.tar.xz/UI/forms/OBSBasic.ui
Changed
@@ -850,6 +850,8 @@ <string>Basic.MainMenu.Edit.Transform</string> </property> <addaction name="actionEditTransform"/> + <addaction name="actionCopyTransform"/> + <addaction name="actionPasteTransform"/> <addaction name="actionResetTransform"/> <addaction name="separator"/> <addaction name="actionRotate90CW"/> @@ -896,6 +898,8 @@ <addaction name="actionDupProfile"/> <addaction name="actionRenameProfile"/> <addaction name="actionRemoveProfile"/> + <addaction name="actionImportProfile"/> + <addaction name="actionExportProfile"/> <addaction name="separator"/> </widget> <widget class="QMenu" name="sceneCollectionMenu"> @@ -906,6 +910,8 @@ <addaction name="actionDupSceneCollection"/> <addaction name="actionRenameSceneCollection"/> <addaction name="actionRemoveSceneCollection"/> + <addaction name="actionImportSceneCollection"/> + <addaction name="actionExportSceneCollection"/> <addaction name="separator"/> </widget> <widget class="QMenu" name="viewMenu"> @@ -1129,6 +1135,19 @@ <string>Basic.MainMenu.Edit.Transform.EditTransform</string> </property> </action> + <action name="actionCopyTransform"> + <property name="text"> + <string>Basic.MainMenu.Edit.Transform.CopyTransform</string> + </property> + </action> + <action name="actionPasteTransform"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Basic.MainMenu.Edit.Transform.PasteTransform</string> + </property> + </action> <action name="actionRotate90CW"> <property name="text"> <string>Basic.MainMenu.Edit.Transform.Rotate90CW</string> @@ -1258,6 +1277,16 @@ <string>Remove</string> </property> </action> + <action name="actionImportSceneCollection"> + <property name="text"> + <string>Import</string> + </property> + </action> + <action name="actionExportSceneCollection"> + <property name="text"> + <string>Export</string> + </property> + </action> <action name="actionNewProfile"> <property name="text"> <string>New</string> @@ -1278,6 +1307,16 @@ <string>Remove</string> </property> </action> + <action name="actionImportProfile"> + <property name="text"> + <string>Import</string> + </property> + </action> + <action name="actionExportProfile"> + <property name="text"> + <string>Export</string> + </property> + </action> <action name="actionShowSettingsFolder"> <property name="text"> <string>Basic.MainMenu.File.ShowSettingsFolder</string>
View file
obs-studio-0.16.6.tar.xz/UI/forms/OBSBasicSettings.ui -> obs-studio-0.17.0.tar.xz/UI/forms/OBSBasicSettings.ui
Changed
@@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>981</width> - <height>667</height> + <height>748</height> </rect> </property> <property name="sizePolicy"> @@ -722,7 +722,7 @@ </widget> </item> <item> - <widget class="QGroupBox" name="groupBox_9"> + <widget class="QGroupBox" name="simpleRecordingGroupBox"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> <horstretch>0</horstretch> @@ -739,6 +739,25 @@ <property name="labelAlignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_18"> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Basic.Settings.Output.Simple.SavePath</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>simpleOutputPath</cstring> + </property> + </widget> + </item> <item row="0" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_5"> <item> @@ -760,32 +779,36 @@ </item> </layout> </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_18"> - <property name="minimumSize"> - <size> - <width>170</width> - <height>0</height> - </size> - </property> + <item row="1" column="1"> + <widget class="QCheckBox" name="simpleNoSpace"> <property name="text"> - <string>Basic.Settings.Output.Simple.SavePath</string> + <string>Basic.Settings.Output.NoSpaceFileName</string> </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>Basic.Settings.Output.Simple.RecordingQuality</string> </property> <property name="buddy"> - <cstring>simpleOutputPath</cstring> + <cstring>simpleOutRecQuality</cstring> </property> </widget> </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="simpleNoSpace"> + <item row="2" column="1"> + <widget class="QComboBox" name="simpleOutRecQuality"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="simpleOutRecFormatLabel"> <property name="text"> - <string>Basic.Settings.Output.NoSpaceFileName</string> + <string>Basic.Settings.Output.Format</string> </property> - <property name="checked"> - <bool>true</bool> + <property name="buddy"> + <cstring>simpleOutRecFormat</cstring> </property> </widget> </item> @@ -823,54 +846,116 @@ </item> </widget> </item> - <item row="3" column="0"> - <widget class="QLabel" name="simpleOutRecFormatLabel"> + <item row="4" column="0"> + <widget class="QLabel" name="simpleOutRecEncoderLabel"> <property name="text"> - <string>Basic.Settings.Output.Format</string> + <string>Basic.Settings.Output.Encoder</string> </property> <property name="buddy"> - <cstring>simpleOutRecFormat</cstring> + <cstring>simpleOutRecEncoder</cstring> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QComboBox" name="simpleOutRecQuality"/> + <item row="4" column="1"> + <widget class="QComboBox" name="simpleOutRecEncoder"/> </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_26"> + <item row="5" column="0"> + <widget class="QLabel" name="label_420"> <property name="text"> - <string>Basic.Settings.Output.Simple.RecordingQuality</string> + <string>Basic.Settings.Output.CustomMuxerSettings</string> </property> <property name="buddy"> - <cstring>simpleOutRecQuality</cstring> + <cstring>simpleOutMuxCustom</cstring> </property> </widget> </item> - <item row="4" column="1"> - <widget class="QComboBox" name="simpleOutRecEncoder"/> + <item row="5" column="1"> + <widget class="QLineEdit" name="simpleOutMuxCustom"/> </item> - <item row="4" column="0"> - <widget class="QLabel" name="simpleOutRecEncoderLabel"> + <item row="6" column="1"> + <widget class="QCheckBox" name="simpleReplayBuf"> <property name="text"> - <string>Basic.Settings.Output.Encoder</string> + <string>Basic.Settings.Output.UseReplayBuffer</string> </property> - <property name="buddy"> - <cstring>simpleOutRecEncoder</cstring> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> - <item row="5" column="0"> - <widget class="QLabel" name="label_420"> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="replayBufferGroupBox"> + <property name="title"> + <string>ReplayBuffer</string> + </property> + <layout class="QFormLayout" name="formLayout_24"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_35"> <property name="text"> - <string>Basic.Settings.Output.CustomMuxerSettings</string> + <string>Basic.Settings.Output.ReplayBuffer.SecondsMax</string> </property> - <property name="buddy"> - <cstring>simpleOutMuxCustom</cstring> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="simpleRBSecMax"> + <property name="suffix"> + <string notr="true"> sec</string> + </property> + <property name="minimum"> + <number>5</number> + </property> + <property name="maximum"> + <number>21600</number> + </property> + <property name="value"> + <number>15</number> </property> </widget> </item> - <item row="5" column="1"> - <widget class="QLineEdit" name="simpleOutMuxCustom"/> + <item row="1" column="0"> + <widget class="QLabel" name="simpleRBMegsMaxLabel"> + <property name="text"> + <string>Basic.Settings.Output.ReplayBuffer.MegabytesMax</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSpinBox" name="simpleRBMegsMax"> + <property name="suffix"> + <string notr="true"> MB</string> + </property> + <property name="minimum"> + <number>20</number> + </property> + <property name="maximum"> + <number>8192</number> + </property> + <property name="value"> + <number>512</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_45"> + <property name="text"> + <string>Basic.Settings.Output.ReplayBuffer.HotkeyMessage</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="simpleRBEstimate"> + <property name="text"> + <string notr="true"/> + </property> + </widget> </item> </layout> </widget> @@ -1064,6 +1149,20 @@ </property> </widget> </item> + <item> + <widget class="QRadioButton" name="advOutTrack5"> + <property name="text"> + <string notr="true">5</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="advOutTrack6"> + <property name="text"> + <string notr="true">6</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -1407,6 +1506,20 @@ </property> </widget> </item> + <item> + <widget class="QCheckBox" name="advOutRecTrack5"> + <property name="text"> + <string notr="true">5</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="advOutRecTrack6"> + <property name="text"> + <string notr="true">6</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -1774,6 +1887,20 @@ </property> </widget> </item> + <item> + <widget class="QRadioButton" name="advOutFFTrack5"> + <property name="text"> + <string notr="true">5</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="advOutFFTrack6"> + <property name="text"> + <string notr="true">6</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -2357,6 +2484,236 @@ </layout> </widget> </item> + <item> + <widget class="QGroupBox" name="groupBox_9"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Basic.Settings.Output.Adv.Audio.Track5</string> + </property> + <layout class="QFormLayout" name="formLayout_25"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_59"> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Basic.Settings.Output.AudioBitrate</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>advOutTrack5Bitrate</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="advOutTrack5Bitrate"> + <property name="currentIndex"> + <number>8</number> + </property> + <item> + <property name="text"> + <string>32</string> + </property> + </item> + <item> + <property name="text"> + <string>48</string> + </property> + </item> + <item> + <property name="text"> + <string>64</string> + </property> + </item> + <item> + <property name="text"> + <string>80</string> + </property> + </item> + <item> + <property name="text"> + <string>96</string> + </property> + </item> + <item> + <property name="text"> + <string>112</string> + </property> + </item> + <item> + <property name="text"> + <string>128</string> + </property> + </item> + <item> + <property name="text"> + <string>160</string> + </property> + </item> + <item> + <property name="text"> + <string>192</string> + </property> + </item> + <item> + <property name="text"> + <string>256</string> + </property> + </item> + <item> + <property name="text"> + <string>320</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_60"> + <property name="text"> + <string>Name</string> + </property> + <property name="buddy"> + <cstring>advOutTrack5Name</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="advOutTrack5Name"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_12"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Basic.Settings.Output.Adv.Audio.Track6</string> + </property> + <layout class="QFormLayout" name="formLayout_26"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_61"> + <property name="minimumSize"> + <size> + <width>170</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Basic.Settings.Output.AudioBitrate</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>advOutTrack6Bitrate</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="advOutTrack6Bitrate"> + <property name="currentIndex"> + <number>8</number> + </property> + <item> + <property name="text"> + <string>32</string> + </property> + </item> + <item> + <property name="text"> + <string>48</string> + </property> + </item> + <item> + <property name="text"> + <string>64</string> + </property> + </item> + <item> + <property name="text"> + <string>80</string> + </property> + </item> + <item> + <property name="text"> + <string>96</string> + </property> + </item> + <item> + <property name="text"> + <string>112</string> + </property> + </item> + <item> + <property name="text"> + <string>128</string> + </property> + </item> + <item> + <property name="text"> + <string>160</string> + </property> + </item> + <item> + <property name="text"> + <string>192</string> + </property> + </item> + <item> + <property name="text"> + <string>256</string> + </property> + </item> + <item> + <property name="text"> + <string>320</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_62"> + <property name="text"> + <string>Name</string> + </property> + <property name="buddy"> + <cstring>advOutTrack6Name</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="advOutTrack6Name"/> + </item> + </layout> + </widget> + </item> </layout> </widget> </item> @@ -2545,8 +2902,8 @@ <rect> <x>0</x> <y>0</y> - <width>80</width> - <height>16</height> + <width>800</width> + <height>69</height> </rect> </property> </widget> @@ -2911,8 +3268,8 @@ <rect> <x>0</x> <y>0</y> - <width>559</width> - <height>681</height> + <width>593</width> + <height>709</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout_16"> @@ -3108,6 +3465,9 @@ <string>Basic.Settings.Output.Adv.Recording</string> </property> <layout class="QFormLayout" name="formLayout_17"> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> <item row="0" column="0"> <widget class="QLabel" name="label_7"> <property name="text"> @@ -3125,6 +3485,42 @@ </property> </widget> </item> + <item row="2" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_14"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLineEdit" name="simpleRBPrefix"/> + </item> + <item> + <widget class="QLabel" name="label_58"> + <property name="text"> + <string>Basic.Settings.Output.ReplayBuffer.Suffix</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="simpleRBSuffix"/> + </item> + </layout> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_57"> + <property name="text"> + <string>Basic.Settings.Output.ReplayBuffer.Prefix</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -3384,12 +3780,12 @@ <slot>setCurrentIndex(int)</slot> <hints> <hint type="sourcelabel"> - <x>310</x> - <y>29</y> + <x>159</x> + <y>30</y> </hint> <hint type="destinationlabel"> <x>241</x> - <y>34</y> + <y>30</y> </hint> </hints> </connection> @@ -3400,12 +3796,12 @@ <slot>setCurrentIndex(int)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>586</x> + <y>38</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>401</x> + <y>102</y> </hint> </hints> </connection> @@ -3416,12 +3812,12 @@ <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>180</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>229</y> </hint> </hints> </connection> @@ -3432,12 +3828,12 @@ <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>180</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>383</x> + <y>229</y> </hint> </hints> </connection> @@ -3448,12 +3844,12 @@ <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>180</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>255</y> </hint> </hints> </connection> @@ -3464,12 +3860,12 @@ <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>180</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>383</x> + <y>255</y> </hint> </hints> </connection> @@ -3480,12 +3876,12 @@ <slot>setCurrentIndex(int)</slot> <hints> <hint type="sourcelabel"> - <x>259</x> - <y>48</y> + <x>606</x> + <y>113</y> </hint> <hint type="destinationlabel"> - <x>241</x> - <y>30</y> + <x>394</x> + <y>191</y> </hint> </hints> </connection> @@ -3496,12 +3892,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>259</x> - <y>60</y> + <x>397</x> + <y>323</y> </hint> <hint type="destinationlabel"> - <x>228</x> - <y>50</y> + <x>676</x> + <y>323</y> </hint> </hints> </connection> @@ -3512,12 +3908,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>259</x> - <y>39</y> + <x>330</x> + <y>191</y> </hint> <hint type="destinationlabel"> - <x>228</x> - <y>29</y> + <x>591</x> + <y>191</y> </hint> </hints> </connection> @@ -3528,12 +3924,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>259</x> - <y>60</y> + <x>353</x> + <y>277</y> </hint> <hint type="destinationlabel"> - <x>228</x> - <y>50</y> + <x>614</x> + <y>277</y> </hint> </hints> </connection> @@ -3544,12 +3940,12 @@ <slot>setCurrentIndex(int)</slot> <hints> <hint type="sourcelabel"> - <x>259</x> - <y>60</y> + <x>676</x> + <y>148</y> </hint> <hint type="destinationlabel"> - <x>259</x> - <y>60</y> + <x>676</x> + <y>177</y> </hint> </hints> </connection> @@ -3560,12 +3956,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>436</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>397</x> + <y>462</y> </hint> </hints> </connection> @@ -3576,12 +3972,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>436</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>485</y> </hint> </hints> </connection> @@ -3592,12 +3988,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>436</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>462</y> </hint> </hints> </connection> @@ -3608,12 +4004,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>541</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>332</x> + <y>567</y> </hint> </hints> </connection> @@ -3624,12 +4020,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>541</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>567</y> </hint> </hints> </connection> @@ -3640,12 +4036,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>541</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>332</x> + <y>593</y> </hint> </hints> </connection> @@ -3656,12 +4052,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>541</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>724</x> + <y>593</y> </hint> </hints> </connection> @@ -3672,12 +4068,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>720</x> - <y>280</y> + <x>951</x> + <y>349</y> </hint> <hint type="destinationlabel"> <x>346</x> - <y>306</y> + <y>375</y> </hint> </hints> </connection> @@ -3688,12 +4084,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>761</x> - <y>280</y> + <x>951</x> + <y>349</y> </hint> <hint type="destinationlabel"> - <x>778</x> - <y>306</y> + <x>951</x> + <y>375</y> </hint> </hints> </connection> @@ -3704,12 +4100,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>820</x> - <y>280</y> + <x>951</x> + <y>349</y> </hint> <hint type="destinationlabel"> - <x>810</x> - <y>329</y> + <x>951</x> + <y>398</y> </hint> </hints> </connection> @@ -3720,12 +4116,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>862</x> - <y>280</y> + <x>951</x> + <y>349</y> </hint> <hint type="destinationlabel"> - <x>859</x> - <y>352</y> + <x>951</x> + <y>421</y> </hint> </hints> </connection> @@ -3736,12 +4132,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>866</x> - <y>280</y> + <x>951</x> + <y>349</y> </hint> <hint type="destinationlabel"> - <x>866</x> - <y>375</y> + <x>951</x> + <y>444</y> </hint> </hints> </connection> @@ -3752,12 +4148,12 @@ <slot>setVisible(bool)</slot> <hints> <hint type="sourcelabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>180</y> </hint> <hint type="destinationlabel"> - <x>250</x> - <y>39</y> + <x>640</x> + <y>203</y> </hint> </hints> </connection> @@ -3768,12 +4164,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>404</x> - <y>193</y> + <x>705</x> + <y>225</y> </hint> <hint type="destinationlabel"> - <x>404</x> - <y>219</y> + <x>705</x> + <y>248</y> </hint> </hints> </connection> @@ -3784,12 +4180,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>404</x> - <y>245</y> + <x>705</x> + <y>271</y> </hint> <hint type="destinationlabel"> - <x>404</x> - <y>271</y> + <x>705</x> + <y>294</y> </hint> </hints> </connection>
View file
obs-studio-0.16.6.tar.xz/UI/forms/OBSBasicTransform.ui -> obs-studio-0.17.0.tar.xz/UI/forms/OBSBasicTransform.ui
Changed
@@ -648,5 +648,12 @@ </layout> </widget> <resources/> - <connections/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>OBSBasicTransform</receiver> + <slot>reject()</slot> + </connection> + </connections> </ui>
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/CMakeLists.txt
Changed
@@ -17,9 +17,15 @@ ) endif() +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/frontend-tools-config.h.in" + "${CMAKE_BINARY_DIR}/config/frontend-tools-config.h") + set(frontend-tools_HEADERS ${frontend-tools_HEADERS} + "${CMAKE_BINARY_DIR}/config/frontend-tools-config.h" output-timer.hpp + tool-helpers.hpp ) set(frontend-tools_SOURCES ${frontend-tools_SOURCES} @@ -34,6 +40,18 @@ if(WIN32) set(frontend-tools_PLATFORM_SOURCES auto-scene-switcher-win.cpp) + + if(BUILD_CAPTIONS) + set(frontend-tools_PLATFORM_SOURCES + ${frontend-tools_PLATFORM_SOURCES} + captions.cpp + captions-stream.cpp) + set(frontend-tools_PLATFORM_HEADERS + captions.hpp + captions-stream.hpp) + set(frontend-tools_PLATFORM_UI + forms/captions.ui) + endif() elseif(APPLE) set(frontend-tools_PLATFORM_SOURCES auto-scene-switcher-osx.mm) @@ -44,13 +62,16 @@ ${COCOA}) endif() -qt5_wrap_ui(frontend-tools_UI_HEADERS ${frontend-tools_UI}) +qt5_wrap_ui(frontend-tools_UI_HEADERS + ${frontend-tools_UI} + ${frontend-tools_PLATFORM_UI}) add_library(frontend-tools MODULE ${frontend-tools_HEADERS} ${frontend-tools_SOURCES} - ${frontend-tools_PLATFORM_SOURCES} ${frontend-tools_UI_HEADERS} + ${frontend-tools_PLATFORM_SOURCES} + ${frontend-tools_PLATFORM_HEADERS} ) target_link_libraries(frontend-tools ${frontend-tools_PLATFORM_LIBS}
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/auto-scene-switcher.cpp
Changed
@@ -6,6 +6,7 @@ #include <QMessageBox> #include <QAction> #include "auto-scene-switcher.hpp" +#include "tool-helpers.hpp" #include <condition_variable> #include <chrono> @@ -82,37 +83,6 @@ return QStringLiteral("[") + scene + QStringLiteral("]: ") + window; } -static inline string GetWeakSourceName(obs_weak_source_t *weak_source) -{ - string name; - - obs_source_t *source = obs_weak_source_get_source(weak_source); - if (source) { - name = obs_source_get_name(source); - obs_source_release(source); - } - - return name; -} - -static inline OBSWeakSource GetWeakSourceByName(const char *name) -{ - OBSWeakSource weak; - obs_source_t *source = obs_get_source_by_name(name); - if (source) { - weak = obs_source_get_weak_source(source); - obs_weak_source_release(weak); - obs_source_release(source); - } - - return weak; -} - -static inline OBSWeakSource GetWeakSourceByQString(const QString &name) -{ - return GetWeakSourceByName(name.toUtf8().constData()); -} - SceneSwitcher::SceneSwitcher(QWidget *parent) : QDialog(parent), ui(new Ui_SceneSwitcher)
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/captions-stream.cpp
Added
@@ -0,0 +1,418 @@ +#include "captions-stream.hpp" +#include <mmreg.h> +#include <util/windows/CoTaskMemPtr.hpp> +#include <util/threading.h> +#include <util/base.h> + +using namespace std; + +#if 0 +#define debugfunc(format, ...) blog(LOG_DEBUG, "[Captions] %s(" format ")", \ + __FUNCTION__, ##__VA_ARGS__) +#else +#define debugfunc(format, ...) +#endif + +CaptionStream::CaptionStream(DWORD samplerate_) : + samplerate(samplerate_), + event(CreateEvent(nullptr, false, false, nullptr)) +{ + buf_info.ulMsMinNotification = 50; + buf_info.ulMsBufferSize = 500; + buf_info.ulMsEventBias = 0; + + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 1; + format.nSamplesPerSec = 16000; + format.nAvgBytesPerSec = format.nSamplesPerSec * sizeof(uint16_t); + format.nBlockAlign = 2; + format.wBitsPerSample = 16; + format.cbSize = sizeof(format); + + resampler.Reset(&format); +} + +void CaptionStream::Stop() +{ + { + lock_guard<mutex> lock(m); + circlebuf_free(buf); + } + + cv.notify_one(); +} + +void CaptionStream::PushAudio(const struct audio_data *data, bool muted) +{ + uint8_t *output[MAX_AV_PLANES] = {}; + uint32_t frames = data->frames; + uint64_t ts_offset; + bool ready = false; + + audio_resampler_resample(resampler, output, &frames, &ts_offset, + data->data, data->frames); + + if (output[0]) { + if (muted) + memset(output[0], 0, frames * sizeof(int16_t)); + + lock_guard<mutex> lock(m); + circlebuf_push_back(buf, output[0], frames * sizeof(int16_t)); + write_pos += frames * sizeof(int16_t); + + if (wait_size && buf->size >= wait_size) + ready = true; + } + + if (ready) + cv.notify_one(); +} + +// IUnknown methods + +STDMETHODIMP CaptionStream::QueryInterface(REFIID riid, void **ppv) +{ + if (riid == IID_IUnknown) { + AddRef(); + *ppv = this; + + } else if (riid == IID_IStream) { + AddRef(); + *ppv = (IStream*)this; + + } else if (riid == IID_ISpStreamFormat) { + AddRef(); + *ppv = (ISpStreamFormat*)this; + + } else if (riid == IID_ISpAudio) { + AddRef(); + *ppv = (ISpAudio*)this; + + } else { + *ppv = nullptr; + return E_NOINTERFACE; + } + + return NOERROR; +} + +STDMETHODIMP_(ULONG) CaptionStream::AddRef() +{ + return (ULONG)os_atomic_inc_long(&refs); +} + +STDMETHODIMP_(ULONG) CaptionStream::Release() +{ + ULONG new_refs = (ULONG)os_atomic_dec_long(&refs); + if (!new_refs) + delete this; + + return new_refs; +} + +// ISequentialStream methods + +STDMETHODIMP CaptionStream::Read(void *data, ULONG bytes, ULONG *read_bytes) +{ + HRESULT hr = S_OK; + size_t cur_size; + + debugfunc("data, %lu, read_bytes", bytes); + if (!data) + return STG_E_INVALIDPOINTER; + + { + lock_guard<mutex> lock1(m); + wait_size = bytes; + cur_size = buf->size; + } + + unique_lock<mutex> lock(m); + + if (bytes > cur_size) + cv.wait(lock); + + if (bytes > (ULONG)buf->size) { + bytes = (ULONG)buf->size; + hr = S_FALSE; + } + if (bytes) + circlebuf_pop_front(buf, data, bytes); + if (read_bytes) + *read_bytes = bytes; + + wait_size = 0; + pos.QuadPart += bytes; + return hr; +} + +STDMETHODIMP CaptionStream::Write(const void *, ULONG bytes, + ULONG*) +{ + debugfunc("data, %lu, written_bytes", bytes); + UNUSED_PARAMETER(bytes); + + return STG_E_INVALIDFUNCTION; +} + +// IStream methods + +STDMETHODIMP CaptionStream::Seek(LARGE_INTEGER move, DWORD origin, + ULARGE_INTEGER *new_pos) +{ + debugfunc("%lld, %lx, new_pos", move, origin); + UNUSED_PARAMETER(move); + UNUSED_PARAMETER(origin); + + if (!new_pos) + return E_POINTER; + + if (origin != SEEK_CUR || move.QuadPart != 0) + return E_NOTIMPL; + + *new_pos = pos; + return S_OK; +} + +STDMETHODIMP CaptionStream::SetSize(ULARGE_INTEGER new_size) +{ + debugfunc("%llu", new_size); + UNUSED_PARAMETER(new_size); + return STG_E_INVALIDFUNCTION; +} + +STDMETHODIMP CaptionStream::CopyTo(IStream *stream, ULARGE_INTEGER bytes, + ULARGE_INTEGER *read_bytes, + ULARGE_INTEGER *written_bytes) +{ + HRESULT hr; + + debugfunc("stream, %llu, read_bytes, written_bytes", bytes); + + if (!stream) + return STG_E_INVALIDPOINTER; + + ULONG written = 0; + if (bytes.QuadPart > (ULONGLONG)buf->size) + bytes.QuadPart = (ULONGLONG)buf->size; + + lock_guard<mutex> lock(m); + temp_buf.resize((size_t)bytes.QuadPart); + circlebuf_peek_front(buf, &temp_buf[0], (size_t)bytes.QuadPart); + + hr = stream->Write(temp_buf.data(), (ULONG)bytes.QuadPart, &written); + + if (read_bytes) + *read_bytes = bytes; + if (written_bytes) + written_bytes->QuadPart = written; + + return hr; +} + +STDMETHODIMP CaptionStream::Commit(DWORD commit_flags) +{ + debugfunc("%lx", commit_flags); + UNUSED_PARAMETER(commit_flags); + /* TODO? */ + return S_OK; +} + +STDMETHODIMP CaptionStream::Revert(void) +{ + debugfunc(""); + return S_OK; +} + +STDMETHODIMP CaptionStream::LockRegion(ULARGE_INTEGER offset, + ULARGE_INTEGER size, DWORD type) +{ + debugfunc("%llu, %llu, %ld", offset, size, type); + UNUSED_PARAMETER(offset); + UNUSED_PARAMETER(size); + UNUSED_PARAMETER(type); + /* TODO? */ + return STG_E_INVALIDFUNCTION; +} + +STDMETHODIMP CaptionStream::UnlockRegion(ULARGE_INTEGER offset, + ULARGE_INTEGER size, DWORD type) +{ + debugfunc("%llu, %llu, %ld", offset, size, type); + UNUSED_PARAMETER(offset); + UNUSED_PARAMETER(size); + UNUSED_PARAMETER(type); + /* TODO? */ + return STG_E_INVALIDFUNCTION; +} + +static const wchar_t *stat_name = L"Caption stream"; + +STDMETHODIMP CaptionStream::Stat(STATSTG *stg, DWORD flag) +{ + debugfunc("stg, %lu", flag); + + if (!stg) + return E_POINTER; + + lock_guard<mutex> lock(m); + *stg = {}; + stg->type = STGTY_STREAM; + stg->cbSize.QuadPart = (ULONGLONG)buf->size; + + if (flag == STATFLAG_DEFAULT) { + stg->pwcsName = (wchar_t*)CoTaskMemAlloc(sizeof(stat_name)); + memcpy(stg->pwcsName, stat_name, sizeof(stat_name)); + } + + return S_OK; +} + +STDMETHODIMP CaptionStream::Clone(IStream **stream) +{ + debugfunc("stream"); + *stream = nullptr; + return E_NOTIMPL; +} + +// ISpStreamFormat methods + +STDMETHODIMP CaptionStream::GetFormat(GUID *guid, + WAVEFORMATEX **co_mem_wfex_out) +{ + debugfunc("guid, co_mem_wfex_out"); + + if (!guid || !co_mem_wfex_out) + return E_POINTER; + + if (format.wFormatTag == 0) { + *co_mem_wfex_out = nullptr; + return S_OK; + } + + void *wfex = CoTaskMemAlloc(sizeof(format)); + memcpy(wfex, &format, sizeof(format)); + + *co_mem_wfex_out = (WAVEFORMATEX*)wfex; + return S_OK; +} + +// ISpAudio methods + +STDMETHODIMP CaptionStream::SetState(SPAUDIOSTATE state_, ULONGLONG) +{ + debugfunc("%lu, reserved", state_); + state = state_; + return S_OK; +} + +STDMETHODIMP CaptionStream::SetFormat(REFGUID guid_ref, + const WAVEFORMATEX *wfex) +{ + debugfunc("guid, wfex"); + if (!wfex) + return E_INVALIDARG; + + if (guid_ref == SPDFID_WaveFormatEx) { + lock_guard<mutex> lock(m); + memcpy(&format, wfex, sizeof(format)); + resampler.Reset(wfex); + + /* 50 msec */ + DWORD size = format.nSamplesPerSec / 20; + DWORD byte_size = size * format.nBlockAlign; + circlebuf_reserve(buf, (size_t)byte_size); + } + return S_OK; +} + +STDMETHODIMP CaptionStream::GetStatus(SPAUDIOSTATUS *status) +{ + debugfunc("status"); + + if (!status) + return E_POINTER; + + /* TODO? */ + lock_guard<mutex> lock(m); + *status = {}; + status->cbNonBlockingIO = (ULONG)buf->size; + status->State = state; + status->CurSeekPos = pos.QuadPart; + status->CurDevicePos = write_pos; + return S_OK; +} + +STDMETHODIMP CaptionStream::SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info_) +{ + debugfunc("buf_info"); + + /* TODO */ + buf_info = *buf_info_; + return S_OK; +} + +STDMETHODIMP CaptionStream::GetBufferInfo(SPAUDIOBUFFERINFO *buf_info_) +{ + debugfunc("buf_info"); + if (!buf_info_) + return E_POINTER; + + *buf_info_ = buf_info; + return S_OK; +} + +STDMETHODIMP CaptionStream::GetDefaultFormat(GUID *format, + WAVEFORMATEX **co_mem_wfex_out) +{ + debugfunc("format, co_mem_wfex_out"); + + if (!format || !co_mem_wfex_out) + return E_POINTER; + + void *wfex = CoTaskMemAlloc(sizeof(format)); + memcpy(wfex, &format, sizeof(format)); + + *format = SPDFID_WaveFormatEx; + *co_mem_wfex_out = (WAVEFORMATEX*)wfex; + return S_OK; +} + +STDMETHODIMP_(HANDLE) CaptionStream::EventHandle(void) +{ + debugfunc(""); + return event; +} + +STDMETHODIMP CaptionStream::GetVolumeLevel(ULONG *level) +{ + debugfunc("level"); + if (!level) + return E_POINTER; + + *level = vol; + return S_OK; +} + +STDMETHODIMP CaptionStream::SetVolumeLevel(ULONG level) +{ + debugfunc("%lu", level); + vol = level; + return S_OK; +} + +STDMETHODIMP CaptionStream::GetBufferNotifySize(ULONG *size) +{ + debugfunc("size"); + if (!size) + return E_POINTER; + *size = notify_size; + return S_OK; +} + +STDMETHODIMP CaptionStream::SetBufferNotifySize(ULONG size) +{ + debugfunc("%lu", size); + notify_size = size; + return S_OK; +}
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/captions-stream.hpp
Added
@@ -0,0 +1,119 @@ +#include <windows.h> +#include <sapi.h> +#include <condition_variable> +#include <mutex> +#include <vector> +#include <obs.h> +#include <media-io/audio-resampler.h> +#include <util/circlebuf.h> +#include <util/windows/WinHandle.hpp> + +#include <fstream> + +class CircleBuf { + circlebuf buf = {}; +public: + inline ~CircleBuf() {circlebuf_free(&buf);} + inline operator circlebuf*() {return &buf;} + inline circlebuf *operator->() {return &buf;} +}; + +class Resampler { + audio_resampler_t *resampler = nullptr; + +public: + inline void Reset(const WAVEFORMATEX *wfex) + { + const struct audio_output_info *aoi = + audio_output_get_info(obs_get_audio()); + + struct resample_info src; + src.samples_per_sec = aoi->samples_per_sec; + src.format = aoi->format; + src.speakers = aoi->speakers; + + struct resample_info dst; + dst.samples_per_sec = uint32_t(wfex->nSamplesPerSec); + dst.format = AUDIO_FORMAT_16BIT; + dst.speakers = (enum speaker_layout)wfex->nChannels; + + if (resampler) + audio_resampler_destroy(resampler); + resampler = audio_resampler_create(&dst, &src); + } + + inline ~Resampler() {audio_resampler_destroy(resampler);} + inline operator audio_resampler_t*() {return resampler;} +}; + +class CaptionStream : public ISpAudio { + volatile long refs = 1; + SPAUDIOBUFFERINFO buf_info = {}; + ULONG notify_size = 0; + SPAUDIOSTATE state; + WinHandle event; + ULONG vol = 0; + + std::condition_variable cv; + std::mutex m; + std::vector<int16_t> temp_buf; + WAVEFORMATEX format = {}; + Resampler resampler; + + CircleBuf buf; + ULONG wait_size = 0; + DWORD samplerate = 0; + ULARGE_INTEGER pos = {}; + ULONGLONG write_pos = 0; + +public: + CaptionStream(DWORD samplerate); + + void Stop(); + void PushAudio(const struct audio_data *audio_data, bool muted); + + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID riid, void **ppv) override; + STDMETHODIMP_(ULONG) AddRef() override; + STDMETHODIMP_(ULONG) Release() override; + + // ISequentialStream methods + STDMETHODIMP Read(void *data, ULONG bytes, ULONG *read_bytes) override; + STDMETHODIMP Write(const void *data, ULONG bytes, ULONG *written_bytes) + override; + + // IStream methods + STDMETHODIMP Seek(LARGE_INTEGER move, DWORD origin, + ULARGE_INTEGER *new_pos) override; + STDMETHODIMP SetSize(ULARGE_INTEGER new_size) override; + STDMETHODIMP CopyTo(IStream *stream, ULARGE_INTEGER bytes, + ULARGE_INTEGER *read_bytes, + ULARGE_INTEGER *written_bytes) override; + STDMETHODIMP Commit(DWORD commit_flags) override; + STDMETHODIMP Revert(void) override; + STDMETHODIMP LockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size, + DWORD type) override; + STDMETHODIMP UnlockRegion(ULARGE_INTEGER offset, ULARGE_INTEGER size, + DWORD type) override; + STDMETHODIMP Stat(STATSTG *stg, DWORD flags) override; + STDMETHODIMP Clone(IStream **stream) override; + + // ISpStreamFormat methods + STDMETHODIMP GetFormat(GUID *guid, WAVEFORMATEX **co_mem_wfex_out) + override; + + // ISpAudio methods + STDMETHODIMP SetState(SPAUDIOSTATE state, ULONGLONG reserved) override; + STDMETHODIMP SetFormat(REFGUID guid_ref, const WAVEFORMATEX *wfex) + override; + STDMETHODIMP GetStatus(SPAUDIOSTATUS *status) override; + STDMETHODIMP SetBufferInfo(const SPAUDIOBUFFERINFO *buf_info) override; + STDMETHODIMP GetBufferInfo(SPAUDIOBUFFERINFO *buf_info) override; + STDMETHODIMP GetDefaultFormat(GUID *format, + WAVEFORMATEX **co_mem_wfex_out) override; + STDMETHODIMP_(HANDLE) EventHandle(void) override; + STDMETHODIMP GetVolumeLevel(ULONG *level) override; + STDMETHODIMP SetVolumeLevel(ULONG level) override; + STDMETHODIMP GetBufferNotifySize(ULONG *size) override; + STDMETHODIMP SetBufferNotifySize(ULONG size) override; +};
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/captions.cpp
Added
@@ -0,0 +1,533 @@ +#include <obs-frontend-api.h> +#include "captions-stream.hpp" +#include "captions.hpp" +#include "tool-helpers.hpp" +#include <sphelper.h> +#include <util/dstr.hpp> +#include <util/platform.h> +#include <util/windows/HRError.hpp> +#include <util/windows/ComPtr.hpp> +#include <util/windows/CoTaskMemPtr.hpp> +#include <util/threading.h> +#include <obs-module.h> + +#include <string> +#include <thread> +#include <mutex> + +#define do_log(type, format, ...) blog(type, "[Captions] " format, \ + ##__VA_ARGS__) + +#define error(format, ...) do_log(LOG_ERROR, format, ##__VA_ARGS__) +#define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__) + +using namespace std; + +struct obs_captions { + thread th; + recursive_mutex m; + WinHandle stop_event; + + string source_name; + OBSWeakSource source; + LANGID lang_id; + + void main_thread(); + void start(); + void stop(); + + inline obs_captions() : + stop_event(CreateEvent(nullptr, false, false, nullptr)), + lang_id(GetUserDefaultUILanguage()) + { + } + + inline ~obs_captions() {stop();} +}; + +static obs_captions *captions = nullptr; + +/* ------------------------------------------------------------------------- */ + +struct locale_info { + DStr name; + LANGID id; + + inline locale_info() {} + inline locale_info(const locale_info &) = delete; + inline locale_info(locale_info &&li) + : name(std::move(li.name)), + id(li.id) + {} +}; + +static void get_valid_locale_names(vector<locale_info> &names); +static bool valid_lang(LANGID id); + +/* ------------------------------------------------------------------------- */ + +CaptionsDialog::CaptionsDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui_CaptionsDialog) +{ + ui->setupUi(this); + + lock_guard<recursive_mutex> lock(captions->m); + + auto cb = [this] (obs_source_t *source) + { + uint32_t caps = obs_source_get_output_flags(source); + QString name = obs_source_get_name(source); + + if (caps & OBS_SOURCE_AUDIO) + ui->source->addItem(name); + + OBSWeakSource weak = OBSGetWeakRef(source); + if (weak == captions->source) + ui->source->setCurrentText(name); + return true; + }; + + using cb_t = decltype(cb); + + ui->source->blockSignals(true); + ui->source->addItem(QStringLiteral("")); + ui->source->setCurrentIndex(0); + obs_enum_sources([] (void *data, obs_source_t *source) { + return (*static_cast<cb_t*>(data))(source);}, &cb); + ui->source->blockSignals(false); + + ui->enable->blockSignals(true); + ui->enable->setChecked(captions->th.joinable()); + ui->enable->blockSignals(false); + + vector<locale_info> locales; + get_valid_locale_names(locales); + + bool set_language = false; + + ui->language->blockSignals(true); + for (int idx = 0; idx < (int)locales.size(); idx++) { + locale_info &locale = locales[idx]; + + ui->language->addItem(locale.name->array, (int)locale.id); + + if (locale.id == captions->lang_id) { + ui->language->setCurrentIndex(idx); + set_language = true; + } + } + + if (!set_language && locales.size()) + ui->language->setCurrentIndex(0); + + ui->language->blockSignals(false); + + if (!locales.size()) { + ui->source->setEnabled(false); + ui->enable->setEnabled(false); + ui->language->setEnabled(false); + + } else if (!set_language) { + bool started = captions->th.joinable(); + if (started) + captions->stop(); + + captions->m.lock(); + captions->lang_id = locales[0].id; + captions->m.unlock(); + + if (started) + captions->start(); + } +} + +void CaptionsDialog::on_source_currentIndexChanged(int) +{ + bool started = captions->th.joinable(); + if (started) + captions->stop(); + + captions->m.lock(); + captions->source_name = ui->source->currentText().toUtf8().constData(); + captions->source = GetWeakSourceByName(captions->source_name.c_str()); + captions->m.unlock(); + + if (started) + captions->start(); +} + +void CaptionsDialog::on_enable_clicked(bool checked) +{ + if (checked) + captions->start(); + else + captions->stop(); +} + +void CaptionsDialog::on_language_currentIndexChanged(int) +{ + bool started = captions->th.joinable(); + if (started) + captions->stop(); + + captions->m.lock(); + captions->lang_id = (LANGID)ui->language->currentData().toInt(); + captions->m.unlock(); + + if (started) + captions->start(); +} + +/* ------------------------------------------------------------------------- */ + +void obs_captions::main_thread() +try { + ComPtr<CaptionStream> audio; + ComPtr<ISpObjectToken> token; + ComPtr<ISpRecoGrammar> grammar; + ComPtr<ISpRecognizer> recognizer; + ComPtr<ISpRecoContext> context; + HRESULT hr; + + auto cb = [&] (const struct audio_data *audio_data, + bool muted) + { + audio->PushAudio(audio_data, muted); + }; + + using cb_t = decltype(cb); + + auto pre_cb = [] (void *param, obs_source_t*, + const struct audio_data *audio_data, bool muted) + { + return (*static_cast<cb_t*>(param))(audio_data, muted); + }; + + os_set_thread_name(__FUNCTION__); + + CoInitialize(nullptr); + + wchar_t lang_str[32]; + _snwprintf(lang_str, 31, L"language=%x", (int)captions->lang_id); + + hr = SpFindBestToken(SPCAT_RECOGNIZERS, lang_str, nullptr, &token); + if (FAILED(hr)) + throw HRError("SpFindBestToken failed", hr); + + hr = CoCreateInstance(CLSID_SpInprocRecognizer, nullptr, CLSCTX_ALL, + __uuidof(ISpRecognizer), (void**)&recognizer); + if (FAILED(hr)) + throw HRError("CoCreateInstance for recognizer failed", hr); + + hr = recognizer->SetRecognizer(token); + if (FAILED(hr)) + throw HRError("SetRecognizer failed", hr); + + hr = recognizer->SetRecoState(SPRST_INACTIVE); + if (FAILED(hr)) + throw HRError("SetRecoState(SPRST_INACTIVE) failed", hr); + + hr = recognizer->CreateRecoContext(&context); + if (FAILED(hr)) + throw HRError("CreateRecoContext failed", hr); + + ULONGLONG interest = SPFEI(SPEI_RECOGNITION) | + SPFEI(SPEI_END_SR_STREAM); + hr = context->SetInterest(interest, interest); + if (FAILED(hr)) + throw HRError("SetInterest failed", hr); + + HANDLE notify; + + hr = context->SetNotifyWin32Event(); + if (FAILED(hr)) + throw HRError("SetNotifyWin32Event", hr); + + notify = context->GetNotifyEventHandle(); + if (notify == INVALID_HANDLE_VALUE) + throw HRError("GetNotifyEventHandle failed", E_NOINTERFACE); + + size_t sample_rate = audio_output_get_sample_rate(obs_get_audio()); + audio = new CaptionStream((DWORD)sample_rate); + audio->Release(); + + hr = recognizer->SetInput(audio, false); + if (FAILED(hr)) + throw HRError("SetInput failed", hr); + + hr = context->CreateGrammar(1, &grammar); + if (FAILED(hr)) + throw HRError("CreateGrammar failed", hr); + + hr = grammar->LoadDictation(nullptr, SPLO_STATIC); + if (FAILED(hr)) + throw HRError("LoadDictation failed", hr); + + hr = grammar->SetDictationState(SPRS_ACTIVE); + if (FAILED(hr)) + throw HRError("SetDictationState failed", hr); + + hr = recognizer->SetRecoState(SPRST_ACTIVE); + if (FAILED(hr)) + throw HRError("SetRecoState(SPRST_ACTIVE) failed", hr); + + HANDLE events[] = {notify, stop_event}; + + { + captions->source = GetWeakSourceByName( + captions->source_name.c_str()); + OBSSource strong = OBSGetStrongRef(source); + if (strong) + obs_source_add_audio_capture_callback(strong, + pre_cb, &cb); + } + + for (;;) { + DWORD ret = WaitForMultipleObjects(2, events, false, INFINITE); + if (ret != WAIT_OBJECT_0) + break; + + CSpEvent event; + bool exit = false; + + while (event.GetFrom(context) == S_OK) { + if (event.eEventId == SPEI_RECOGNITION) { + ISpRecoResult *result = event.RecoResult(); + + CoTaskMemPtr<wchar_t> text; + hr = result->GetText((ULONG)-1, (ULONG)-1, + true, &text, nullptr); + if (FAILED(hr)) + continue; + + char text_utf8[512]; + os_wcs_to_utf8(text, 0, text_utf8, 512); + + obs_output_t *output = + obs_frontend_get_streaming_output(); + if (output) + obs_output_output_caption_text1(output, + text_utf8); + + debug("\"%s\"", text_utf8); + + obs_output_release(output); + + } else if (event.eEventId == SPEI_END_SR_STREAM) { + exit = true; + break; + } + } + + if (exit) + break; + } + + { + OBSSource strong = OBSGetStrongRef(source); + if (strong) + obs_source_remove_audio_capture_callback(strong, + pre_cb, &cb); + } + + audio->Stop(); + + CoUninitialize(); + +} catch (HRError err) { + error("%s failed: %s (%lX)", __FUNCTION__, err.str, err.hr); + CoUninitialize(); + captions->th.detach(); +} + +void obs_captions::start() +{ + if (!captions->th.joinable()) { + ResetEvent(captions->stop_event); + + if (valid_lang(captions->lang_id)) + captions->th = thread([] () {captions->main_thread();}); + } +} + +void obs_captions::stop() +{ + if (!captions->th.joinable()) + return; + + SetEvent(captions->stop_event); + captions->th.join(); +} + +static bool get_locale_name(LANGID id, char *out) +{ + wchar_t name[256]; + + int size = GetLocaleInfoW(id, LOCALE_SENGLISHLANGUAGENAME, name, 256); + if (size <= 0) + return false; + + os_wcs_to_utf8(name, 0, out, 256); + return true; +} + +static bool valid_lang(LANGID id) +{ + ComPtr<ISpObjectToken> token; + wchar_t lang_str[32]; + HRESULT hr; + + _snwprintf(lang_str, 31, L"language=%x", (int)id); + + hr = SpFindBestToken(SPCAT_RECOGNIZERS, lang_str, nullptr, &token); + return SUCCEEDED(hr); +} + +static void get_valid_locale_names(vector<locale_info> &locales) +{ + locale_info cur; + char locale_name[256]; + + static const LANGID default_locales[] = { + 0x0409, + 0x0401, + 0x0402, + 0x0403, + 0x0404, + 0x0405, + 0x0406, + 0x0407, + 0x0408, + 0x040a, + 0x040b, + 0x040c, + 0x040d, + 0x040e, + 0x040f, + 0x0410, + 0x0411, + 0x0412, + 0x0413, + 0x0414, + 0x0415, + 0x0416, + 0x0417, + 0x0418, + 0x0419, + 0x041a, + 0 + }; + + /* ---------------------------------- */ + + LANGID def_id = GetUserDefaultUILanguage(); + LANGID id = def_id; + if (valid_lang(id) && get_locale_name(id, locale_name)) { + dstr_copy(cur.name, obs_module_text( + "Captions.CurrentSystemLanguage")); + dstr_replace(cur.name, "%1", locale_name); + cur.id = id; + + locales.push_back(std::move(cur)); + } + + /* ---------------------------------- */ + + const LANGID *locale = default_locales; + + while (*locale) { + id = *locale; + + if (id != def_id && + valid_lang(id) && + get_locale_name(id, locale_name)) { + + dstr_copy(cur.name, locale_name); + cur.id = id; + + locales.push_back(std::move(cur)); + } + + locale++; + } +} + +/* ------------------------------------------------------------------------- */ + +extern "C" void FreeCaptions() +{ + delete captions; + captions = nullptr; +} + +static void obs_event(enum obs_frontend_event event, void *) +{ + if (event == OBS_FRONTEND_EVENT_EXIT) + FreeCaptions(); +} + +static void save_caption_data(obs_data_t *save_data, bool saving, void*) +{ + if (saving) { + lock_guard<recursive_mutex> lock(captions->m); + obs_data_t *obj = obs_data_create(); + + obs_data_set_string(obj, "source", + captions->source_name.c_str()); + obs_data_set_bool(obj, "enabled", captions->th.joinable()); + obs_data_set_int(obj, "lang_id", captions->lang_id); + + obs_data_set_obj(save_data, "captions", obj); + obs_data_release(obj); + } else { + captions->stop(); + + captions->m.lock(); + + obs_data_t *obj = obs_data_get_obj(save_data, "captions"); + if (!obj) + obj = obs_data_create(); + + obs_data_set_default_int(obj, "lang_id", + GetUserDefaultUILanguage()); + + bool enabled = obs_data_get_bool(obj, "enabled"); + captions->source_name = obs_data_get_string(obj, "source"); + captions->lang_id = (int)obs_data_get_int(obj, "lang_id"); + captions->source = GetWeakSourceByName( + captions->source_name.c_str()); + obs_data_release(obj); + + captions->m.unlock(); + + if (enabled) + captions->start(); + } +} + +extern "C" void InitCaptions() +{ + QAction *action = (QAction*)obs_frontend_add_tools_menu_qaction( + obs_module_text("Captions")); + + captions = new obs_captions; + + auto cb = [] () + { + obs_frontend_push_ui_translation(obs_module_get_string); + + QWidget *window = + (QWidget*)obs_frontend_get_main_window(); + + CaptionsDialog dialog(window); + dialog.exec(); + + obs_frontend_pop_ui_translation(); + }; + + obs_frontend_add_save_callback(save_caption_data, nullptr); + obs_frontend_add_event_callback(obs_event, nullptr); + + action->connect(action, &QAction::triggered, cb); +}
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/captions.hpp
Added
@@ -0,0 +1,20 @@ +#pragma once + +#include <QDialog> +#include <memory> + +#include "ui_captions.h" + +class CaptionsDialog : public QDialog { + Q_OBJECT + + std::unique_ptr<Ui_CaptionsDialog> ui; + +public: + CaptionsDialog(QWidget *parent); + +public slots: + void on_source_currentIndexChanged(int idx); + void on_enable_clicked(bool checked); + void on_language_currentIndexChanged(int idx); +};
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ca-ES.ini
Changed
@@ -11,6 +11,7 @@ Start="Inicia" Stop="Atura" + OutputTimer="Temporitzador de sortida" OutputTimer.Stream="Atura la transmissió després de:" OutputTimer.Record="Atura la gravació després de:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/cs-CZ.ini
Changed
@@ -11,9 +11,12 @@ Start="Spustit" Stop="Zastavit" + OutputTimer="Časovač" OutputTimer.Stream="Přestat vysílat po:" OutputTimer.Record="Přestat nahrávat po:" OutputTimer.Stream.StoppingIn="Vysílání se zastaví za:" OutputTimer.Record.StoppingIn="Nahrávání se zastaví za:" +OutputTimer.Stream.EnableEverytime="Pokaždé povolit časovač vysílání" +OutputTimer.Record.EnableEverytime="Pokaždé povolit časovač nahrávání"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/da-DK.ini
Changed
@@ -11,9 +11,12 @@ Start="Start" Stop="Stop" + OutputTimer="Output-timer" OutputTimer.Stream="Stands streaming efter:" OutputTimer.Record="Stands optagelse efter:" OutputTimer.Stream.StoppingIn="Streaming standser om:" OutputTimer.Record.StoppingIn="Streaming standser om:" +OutputTimer.Stream.EnableEverytime="Aktivér streaming-timer hver gang" +OutputTimer.Record.EnableEverytime="Aktivér optage-timer hver gang"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/de-DE.ini
Changed
@@ -11,9 +11,14 @@ Start="Start" Stop="Stop" +Captions="Untertitel (experimentell)" +Captions.AudioSource="Audioquelle:" + OutputTimer="Ausgabetimer" OutputTimer.Stream="Stoppe Stream nach:" OutputTimer.Record="Stoppe Aufnahme nach:" OutputTimer.Stream.StoppingIn="Stream stoppt in:" OutputTimer.Record.StoppingIn="Aufnahme stoppt in:" +OutputTimer.Stream.EnableEverytime="Streaming-Timer jedes Mal aktivieren" +OutputTimer.Record.EnableEverytime="Aufnahme-Timer jedes Mal aktivieren"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/en-US.ini
Changed
@@ -11,8 +11,14 @@ Start="Start" Stop="Stop" +Captions="Captions (Experimental)" +Captions.AudioSource="Audio source" +Captions.CurrentSystemLanguage="Current System Language (%1)" + OutputTimer="Output Timer" OutputTimer.Stream="Stop streaming after:" OutputTimer.Record="Stop recording after:" OutputTimer.Stream.StoppingIn="Streaming stopping in:" OutputTimer.Record.StoppingIn="Recording stopping in:" +OutputTimer.Stream.EnableEverytime="Enable streaming timer every time" +OutputTimer.Record.EnableEverytime="Enable recording timer every time"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/es-ES.ini
Changed
@@ -11,9 +11,12 @@ Start="Iniciar" Stop="Detener" + OutputTimer="Temporizador de salida" OutputTimer.Stream="Detener la transmisión después de:" OutputTimer.Record="Detener la grabación después de:" OutputTimer.Stream.StoppingIn="Finalizando transmisión en:" OutputTimer.Record.StoppingIn="Finalizando grabación en:" +OutputTimer.Stream.EnableEverytime="Activar temporizador en cada transmisión" +OutputTimer.Record.EnableEverytime="Activar temporizador en cada grabación"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/eu-ES.ini
Changed
@@ -11,9 +11,12 @@ Start="Hasi" Stop="Gelditu" + OutputTimer="Irteera tenporizadorea" OutputTimer.Stream="Gelditu transmisioa hau pasata:" OutputTimer.Record="Gelditu grabazioa hau pasata:" OutputTimer.Stream.StoppingIn="Transmisioa geldituko da: hau barru:" OutputTimer.Record.StoppingIn="Grabazioa geldituko da hau barru:" +OutputTimer.Stream.EnableEverytime="Gaitu transmisio tenporizadorea aldiro" +OutputTimer.Record.EnableEverytime="Gaitu grabazio tenporizadorea aldiro"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/fi-FI.ini
Changed
@@ -11,9 +11,12 @@ Start="Käynnistä" Stop="Pysäytä" + OutputTimer="Ulostulo-ajastin" OutputTimer.Stream="Pysäyttää lähetyksen:" OutputTimer.Record="Pysäyttää tallennuksen:" OutputTimer.Stream.StoppingIn="Lähetys pysäytetään:" OutputTimer.Record.StoppingIn="Tallennus pysäytetään:" +OutputTimer.Stream.EnableEverytime="Ota lähetysajastin käyttöön aina" +OutputTimer.Record.EnableEverytime="Ota tallennusajastin käyttöön aina"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/fr-FR.ini
Changed
@@ -11,9 +11,12 @@ Start="Démarrer" Stop="Arrêter" + OutputTimer="Minuterie des sorties" OutputTimer.Stream="Arrêter le streaming dans :" OutputTimer.Record="Arrêter l'enregistrement dans :" OutputTimer.Stream.StoppingIn="Arrêt du streaming dans :" OutputTimer.Record.StoppingIn="Arrêt de l'enregistrement dans :" +OutputTimer.Stream.EnableEverytime="Activer le minuteur automatiquement à chaque stream" +OutputTimer.Record.EnableEverytime="Activer le minuteur automatiquement à chaque enregistrement"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/hr-HR.ini
Changed
@@ -11,9 +11,12 @@ Start="Pokreni" Stop="Zaustavi" + OutputTimer="Tempomat snimanja i emitovanja" OutputTimer.Stream="Zaustavi emitovanje nakon:" OutputTimer.Record="Zaustavi snimanje nakon:" OutputTimer.Stream.StoppingIn="Prekidanje emitovanja za:" OutputTimer.Record.StoppingIn="Prekidanje snimanja za:" +OutputTimer.Stream.EnableEverytime="Omogući štopovanje emitovanja svaki put" +OutputTimer.Record.EnableEverytime="Omogući štopovanje snimanja svaki put"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/hu-HU.ini
Changed
@@ -11,9 +11,12 @@ Start="Start" Stop="Stop" + OutputTimer="Kimeneti időzítő" OutputTimer.Stream="Stream leállítása:" OutputTimer.Record="Felvétel leállítása:" OutputTimer.Stream.StoppingIn="A stream leáll:" OutputTimer.Record.StoppingIn="Felvétel leáll:" +OutputTimer.Stream.EnableEverytime="Stream időzítő indítása minden alkalommal" +OutputTimer.Record.EnableEverytime="Felvétel időzítő indítása minden alkalommal"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/it-IT.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/it-IT.ini
Changed
@@ -11,6 +11,7 @@ Start="Inizio" Stop="Stop" + OutputTimer="Timer Output" OutputTimer.Stream="Termina diretta dopo:" OutputTimer.Record="Termina registrazione dopo:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ja-JP.ini
Changed
@@ -11,9 +11,12 @@ Start="開始" Stop="停止" + OutputTimer="出力タイマー" OutputTimer.Stream="配信停止の時間設定:" OutputTimer.Record="録画停止の時間設定:" OutputTimer.Stream.StoppingIn="配信停止まで:" OutputTimer.Record.StoppingIn="録画停止まで:" +OutputTimer.Stream.EnableEverytime="毎回配信タイマーを有効にする" +OutputTimer.Record.EnableEverytime="毎回録画タイマーを有効にする"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ko-KR.ini
Changed
@@ -11,9 +11,12 @@ Start="시작" Stop="중단" + OutputTimer="출력 시간 설정" OutputTimer.Stream="이 시간 이후 방송 중단:" OutputTimer.Record="이 시간 이후 녹화 중단:" OutputTimer.Stream.StoppingIn="방송 중지까지 남은 시간:" OutputTimer.Record.StoppingIn="녹화 중지까지 남은 시간:" +OutputTimer.Stream.EnableEverytime="매번 방송 시간 기록기 활성화" +OutputTimer.Record.EnableEverytime="매번 녹화 시간 기록기 활성화"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ms-MY.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ms-MY.ini
Changed
@@ -3,6 +3,7 @@ Start="Mula" Stop="Berhenti" + OutputTimer.Stream="Berhenti 'streaming' selepas:" OutputTimer.Record="Berhenti merakam selepas:" OutputTimer.Stream.StoppingIn="'Streaming' dihentikan dalam:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/nb-NO.ini
Changed
@@ -5,3 +5,4 @@ Stop="Stopp" +
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/nl-NL.ini
Changed
@@ -11,9 +11,12 @@ Start="Start" Stop="Stop" + OutputTimer="Uitvoertimer" OutputTimer.Stream="Stop met streamen na:" OutputTimer.Record="Stop met opnemen na:" OutputTimer.Stream.StoppingIn="Stream stopt over:" OutputTimer.Record.StoppingIn="Opname stopt over:" +OutputTimer.Stream.EnableEverytime="Schakel streaming timer elke keer in" +OutputTimer.Record.EnableEverytime="Schakel opnametimer elke keer in"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/pl-PL.ini
Changed
@@ -11,9 +11,12 @@ Start="Start" Stop="Stop" + OutputTimer="Wyłącznik czasowy" OutputTimer.Stream="Zatrzymaj stream po:" OutputTimer.Record="Zatrzymaj nagrywanie po:" OutputTimer.Stream.StoppingIn="Zatrzymanie streamu za:" OutputTimer.Record.StoppingIn="Zatrzymanie nagrywania za:" +OutputTimer.Stream.EnableEverytime="Włącz timer streamu za każdym razem" +OutputTimer.Record.EnableEverytime="Włącz timer nagrywania za każdym razem"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/pt-BR.ini
Changed
@@ -11,6 +11,7 @@ Start="Iniciar" Stop="Parar" + OutputTimer="Temporizador de saída" OutputTimer.Stream="Parar a transmissão após:" OutputTimer.Record="Parar a gravação após:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/pt-PT.ini
Changed
@@ -11,6 +11,7 @@ Start="Iniciar" Stop="Parar" + OutputTimer="Temporizador de saída" OutputTimer.Stream="Para a transmissão após:" OutputTimer.Record="Parar a gravação após:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/ru-RU.ini
Changed
@@ -11,9 +11,12 @@ Start="Запустить" Stop="Остановить" + OutputTimer="Таймер записи и стрима" OutputTimer.Stream="Завершить стрим через:" OutputTimer.Record="Завершить запись через:" OutputTimer.Stream.StoppingIn="Стрим будет завершён через:" OutputTimer.Record.StoppingIn="Запись будет завершена через:" +OutputTimer.Stream.EnableEverytime="Включать таймер стрима каждый раз" +OutputTimer.Record.EnableEverytime="Включать таймер записи каждый раз"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sk-SK.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sk-SK.ini
Changed
@@ -4,6 +4,7 @@ Start="Spustiť" Stop="Zastaviť" + OutputTimer.Stream="Zastaviť stream po:" OutputTimer.Record="Zastaviť nahrávanie po:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sr-CS.ini
Changed
@@ -11,9 +11,12 @@ Start="Pokreni" Stop="Zaustavi" + OutputTimer="Tempomat snimanja i emitovanja" OutputTimer.Stream="Zaustavi emitovanje nakon:" OutputTimer.Record="Zaustavi snimanje nakon:" OutputTimer.Stream.StoppingIn="Prekidanje emitovanja za:" OutputTimer.Record.StoppingIn="Prekidanje snimanja za:" +OutputTimer.Stream.EnableEverytime="Omogući štopovanje emitovanja svaki put" +OutputTimer.Record.EnableEverytime="Omogući štopovanje snimanja svaki put"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sr-SP.ini
Changed
@@ -11,9 +11,12 @@ Start="Покрени" Stop="Заустави" + OutputTimer="Темпомат снимања и емитовања" OutputTimer.Stream="Заустави емитовање након:" OutputTimer.Record="Заустави снимање након:" OutputTimer.Stream.StoppingIn="Прекидање емитовања за:" OutputTimer.Record.StoppingIn="Прекидање снимања за:" +OutputTimer.Stream.EnableEverytime="Омогући штоповање емитовање сваки пут" +OutputTimer.Record.EnableEverytime="Омогући штоповање снимања сваки пут"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/sv-SE.ini
Changed
@@ -11,9 +11,12 @@ Start="Starta" Stop="Stoppa" + OutputTimer="Utdatatimer" OutputTimer.Stream="Sluta streama efter:" OutputTimer.Record="Stoppa inspelningen efter:" OutputTimer.Stream.StoppingIn="Streamen stoppas om:" OutputTimer.Record.StoppingIn="Inspelningen stoppas om:" +OutputTimer.Stream.EnableEverytime="Aktivera strömtimer varje gång" +OutputTimer.Record.EnableEverytime="Aktivera inspelningstimer varje gång"
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/tr-TR.ini
Added
@@ -0,0 +1,17 @@ +SceneSwitcher="Otomatik Sahne Değiştirici" +SceneSwitcher.OnNoMatch.DontSwitch="Geçiş yapma" +SceneSwitcher.OnNoMatch.SwitchTo="Şuna geç:" +SceneSwitcher.CheckInterval="Etkin pencere başlığını kontrol et:" +SceneSwitcher.ActiveOrNotActive="Sahne Değiştirici:" +Active="Etkin" +Inactive="Devre Dışı" +Start="Başlat" +Stop="Durdur" + + +OutputTimer="Çıkış Zamanlayıcısı" +OutputTimer.Stream="Şuradan sonra yayını durdur:" +OutputTimer.Record="Şuradan sonra kaydı durdur:" +OutputTimer.Stream.EnableEverytime="Her zaman yayın zamanlayıcıyı etkinleştir" +OutputTimer.Record.EnableEverytime="Her zaman kayıt zamanlayıcıyı etkinleştir" +
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/uk-UA.ini
Changed
@@ -11,9 +11,12 @@ Start="Запустити" Stop="Зупинити" + OutputTimer="Таймер для Виводу" OutputTimer.Stream="Закінчити трансляцію за:" OutputTimer.Record="Зупинити запис за:" OutputTimer.Stream.StoppingIn="Трансляція припиниться за:" OutputTimer.Record.StoppingIn="Запис зупиниться за:" +OutputTimer.Stream.EnableEverytime="Щоразу запускається трансляція - вмикати Таймер для Виводу" +OutputTimer.Record.EnableEverytime="Щоразу починається запис - вмикати Таймер для Виводу"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/vi-VN.ini
Changed
@@ -9,6 +9,7 @@ Start="Bắt đầu" Stop="Dừng" + OutputTimer.Stream="Dừng stream sau:" OutputTimer.Record="Dừng ghi video sau:" OutputTimer.Stream.StoppingIn="Stream sẽ dừng trong:"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/zh-CN.ini
Changed
@@ -11,9 +11,12 @@ Start="开始" Stop="停止" + OutputTimer="输出计时器" OutputTimer.Stream="停止流处理后:" OutputTimer.Record="停止录制后:" OutputTimer.Stream.StoppingIn="串流停止在:" OutputTimer.Record.StoppingIn="录制停止在:" +OutputTimer.Stream.EnableEverytime="每次启用流计时器" +OutputTimer.Record.EnableEverytime="每次启用录制计时器"
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/data/locale/zh-TW.ini
Changed
@@ -11,9 +11,12 @@ Start="開始" Stop="停止" + OutputTimer="輸出計時器" OutputTimer.Stream="在下面時間後停止串流:" OutputTimer.Record="在下面時間後停止錄影:" OutputTimer.Stream.StoppingIn="串流將在下面時間內停止" OutputTimer.Record.StoppingIn="錄影將在下面時間內停止" +OutputTimer.Stream.EnableEverytime="每次都啟動串流計時器" +OutputTimer.Record.EnableEverytime="每次都啟動錄影計時器"
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/forms/captions.ui
Added
@@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CaptionsDialog</class> + <widget class="QDialog" name="CaptionsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>519</width> + <height>140</height> + </rect> + </property> + <property name="windowTitle"> + <string>Captions</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="labelAlignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Captions.AudioSource</string> + </property> + <property name="buddy"> + <cstring>source</cstring> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="source"> + <property name="insertPolicy"> + <enum>QComboBox::InsertAlphabetically</enum> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="enable"> + <property name="text"> + <string>Enable</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Basic.Settings.General.Language</string> + </property> + <property name="buddy"> + <cstring>language</cstring> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="language"/> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="accept"> + <property name="text"> + <string>OK</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>accept</sender> + <signal>clicked()</signal> + <receiver>CaptionsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>268</x> + <y>331</y> + </hint> + <hint type="destinationlabel"> + <x>229</x> + <y>-11</y> + </hint> + </hints> + </connection> + </connections> +</ui>
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/forms/output-timer.ui -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/forms/output-timer.ui
Changed
@@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>600</width> - <height>150</height> + <height>200</height> </rect> </property> <property name="windowTitle"> @@ -85,28 +85,28 @@ </property> </widget> </item> - <item row="1" column="1"> + <item row="2" column="1"> <widget class="QLabel" name="streamStoppingIn"> <property name="text"> <string>OutputTimer.Stream.StoppingIn</string> </property> </widget> </item> - <item row="1" column="2"> + <item row="2" column="2"> <widget class="QLabel" name="streamTime"> <property name="text"> <string>00:00:00</string> </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <widget class="QLabel" name="recordingLabel"> <property name="text"> <string>OutputTimer.Record</string> </property> </widget> </item> - <item row="2" column="2"> + <item row="3" column="2"> <widget class="QSpinBox" name="recordingTimerHours"> <property name="minimum"> <number>0</number> @@ -119,14 +119,14 @@ </property> </widget> </item> - <item row="2" column="3"> + <item row="3" column="3"> <widget class="QLabel" name="hoursLabel_2"> <property name="text"> <string>Hours</string> </property> </widget> </item> - <item row="2" column="4"> + <item row="3" column="4"> <widget class="QSpinBox" name="recordingTimerMinutes"> <property name="minimum"> <number>0</number> @@ -139,14 +139,14 @@ </property> </widget> </item> - <item row="2" column="5"> + <item row="3" column="5"> <widget class="QLabel" name="minutesLabel_2"> <property name="text"> <string>Minutes</string> </property> </widget> </item> - <item row="2" column="6"> + <item row="3" column="6"> <widget class="QSpinBox" name="recordingTimerSeconds"> <property name="minimum"> <number>0</number> @@ -159,34 +159,48 @@ </property> </widget> </item> - <item row="2" column="7"> + <item row="3" column="7"> <widget class="QLabel" name="secondsLabel_2"> <property name="text"> <string>Seconds</string> </property> </widget> </item> - <item row="2" column="8"> + <item row="3" column="8"> <widget class="QPushButton" name="outputTimerRecord"> <property name="text"> <string>Start</string> </property> </widget> </item> - <item row="3" column="1"> + <item row="5" column="1"> <widget class="QLabel" name="recordStoppingIn"> <property name="text"> <string>OutputTimer.Record.StoppingIn</string> </property> </widget> </item> - <item row="3" column="2"> + <item row="5" column="2"> <widget class="QLabel" name="recordTime"> <property name="text"> <string>00:00:00</string> </property> </widget> </item> + <item row="1" column="1" colspan="3"> + <widget class="QCheckBox" name="autoStartStreamTimer"> + <property name="text"> + <string>OutputTimer.Stream.EnableEverytime</string> + </property> + </widget> + </item> + <item row="4" column="1" colspan="3"> + <widget class="QCheckBox" name="autoStartRecordTimer"> + <property name="text"> + <string>OutputTimer.Record.EnableEverytime</string> + </property> + </widget> + </item> </layout> </widget> <resources />
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/frontend-tools-config.h.in
Added
@@ -0,0 +1,3 @@ +#pragma once + +#define BUILD_CAPTIONS @BUILD_CAPTIONS@
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/frontend-tools.c -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/frontend-tools.c
Changed
@@ -1,4 +1,5 @@ #include <obs-module.h> +#include "frontend-tools-config.h" OBS_DECLARE_MODULE() OBS_MODULE_USE_DEFAULT_LOCALE("frontend-tools", "en-US") @@ -7,6 +8,12 @@ void InitSceneSwitcher(); void FreeSceneSwitcher(); #endif + +#if defined(_WIN32) && BUILD_CAPTIONS +void InitCaptions(); +void FreeCaptions(); +#endif + void InitOutputTimer(); void FreeOutputTimer(); @@ -15,6 +22,9 @@ #if defined(_WIN32) || defined(__APPLE__) InitSceneSwitcher(); #endif +#if defined(_WIN32) && BUILD_CAPTIONS + InitCaptions(); +#endif InitOutputTimer(); return true; } @@ -24,5 +34,8 @@ #if defined(_WIN32) || defined(__APPLE__) FreeSceneSwitcher(); #endif +#if defined(_WIN32) && BUILD_CAPTIONS + FreeCaptions(); +#endif FreeOutputTimer(); }
View file
obs-studio-0.16.6.tar.xz/UI/frontend-plugins/frontend-tools/output-timer.cpp -> obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/output-timer.cpp
Changed
@@ -61,7 +61,7 @@ void OutputTimer::StreamTimerStart() { - if (!isVisible()) { + if (!isVisible() && ui->autoStartStreamTimer->isChecked() == false) { streamingAlreadyActive = true; return; } @@ -88,14 +88,14 @@ streamingTimer->start(); streamingTimerDisplay->start(1000); - ui->outputTimerStream->setText(tr("Stop")); + ui->outputTimerStream->setText(obs_module_text("Stop")); UpdateStreamTimerDisplay(); } void OutputTimer::RecordTimerStart() { - if (!isVisible()) { + if (!isVisible() && ui->autoStartRecordTimer->isChecked() == false) { recordingAlreadyActive = true; return; } @@ -122,7 +122,7 @@ recordingTimer->start(); recordingTimerDisplay->start(1000); - ui->outputTimerRecord->setText(tr("Stop")); + ui->outputTimerRecord->setText(obs_module_text("Stop")); UpdateRecordTimerDisplay(); } @@ -137,7 +137,7 @@ if (streamingTimer->isActive()) streamingTimer->stop(); - ui->outputTimerStream->setText(tr("Start")); + ui->outputTimerStream->setText(obs_module_text("Start")); if (streamingTimerDisplay->isActive()) streamingTimerDisplay->stop(); @@ -155,7 +155,7 @@ if (recordingTimer->isActive()) recordingTimer->stop(); - ui->outputTimerRecord->setText(tr("Start")); + ui->outputTimerRecord->setText(obs_module_text("Start")); if (recordingTimerDisplay->isActive()) recordingTimerDisplay->stop(); @@ -229,6 +229,11 @@ obs_data_set_int(obj, "recordTimerSeconds", ot->ui->recordingTimerSeconds->value()); + obs_data_set_bool(obj, "autoStartStreamTimer", + ot->ui->autoStartStreamTimer->isChecked()); + obs_data_set_bool(obj, "autoStartRecordTimer", + ot->ui->autoStartRecordTimer->isChecked()); + obs_data_set_obj(save_data, "output-timer", obj); obs_data_release(obj); @@ -253,6 +258,11 @@ ot->ui->recordingTimerSeconds->setValue( obs_data_get_int(obj, "recordTimerSeconds")); + ot->ui->autoStartStreamTimer->setChecked( + obs_data_get_bool(obj, "autoStartStreamTimer")); + ot->ui->autoStartRecordTimer->setChecked( + obs_data_get_bool(obj, "autoStartRecordTimer")); + obs_data_release(obj); } }
View file
obs-studio-0.17.0.tar.xz/UI/frontend-plugins/frontend-tools/tool-helpers.hpp
Added
@@ -0,0 +1,36 @@ +#pragma once + +#include <obs.hpp> +#include <string> +#include <QString> + +static inline OBSWeakSource GetWeakSourceByName(const char *name) +{ + OBSWeakSource weak; + obs_source_t *source = obs_get_source_by_name(name); + if (source) { + weak = obs_source_get_weak_source(source); + obs_weak_source_release(weak); + obs_source_release(source); + } + + return weak; +} + +static inline OBSWeakSource GetWeakSourceByQString(const QString &name) +{ + return GetWeakSourceByName(name.toUtf8().constData()); +} + +static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source) +{ + std::string name; + + obs_source_t *source = obs_weak_source_get_source(weak_source); + if (source) { + name = obs_source_get_name(source); + obs_source_release(source); + } + + return name; +}
View file
obs-studio-0.16.6.tar.xz/UI/installer/mp-installer.nsi -> obs-studio-0.17.0.tar.xz/UI/installer/mp-installer.nsi
Changed
@@ -224,7 +224,11 @@ ${endif} SetOutPath "$INSTDIR\bin\32bit" - CreateShortCut "$DESKTOP\OBS Studio.lnk" "$INSTDIR\bin\32bit\obs32.exe" + ${if} ${RunningX64} + CreateShortCut "$DESKTOP\OBS Studio.lnk" "$INSTDIR\bin\64bit\obs64.exe" + ${else} + CreateShortCut "$DESKTOP\OBS Studio.lnk" "$INSTDIR\bin\32bit\obs32.exe" + ${endif} CreateDirectory "$SMPROGRAMS\OBS Studio" CreateShortCut "$SMPROGRAMS\OBS Studio\OBS Studio (32bit).lnk" "$INSTDIR\bin\32bit\obs32.exe" CreateShortCut "$SMPROGRAMS\OBS Studio\Uninstall.lnk" "$INSTDIR\uninstall.exe" @@ -288,7 +292,7 @@ File "intel_rs_sdk_runtime_websetup_10.0.26.0396.exe" ExecWait '"$PLUGINSDIR\realsense\intel_rs_sdk_runtime_websetup_10.0.26.0396.exe" --finstall=personify --fnone=all' - {endif} + ${endif} SetOutPath "$INSTDIR\bin\32bit" SectionEnd
View file
obs-studio-0.16.6.tar.xz/UI/obs-app.cpp -> obs-studio-0.17.0.tar.xz/UI/obs-app.cpp
Changed
@@ -67,6 +67,11 @@ string opt_starting_profile; string opt_starting_scene; +// AMD PowerXpress High Performance Flags +#ifdef _MSC_VER +extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; +#endif + QObject *CreateShortcutFilter() { return new OBSEventFilter([](QObject *obj, QEvent *event) @@ -1110,79 +1115,9 @@ string GenerateSpecifiedFilename(const char *extension, bool noSpace, const char *format) { - time_t now = time(0); - struct tm *cur_time; - cur_time = localtime(&now); - - const size_t spec_count = 23; - const char *spec[][2] = { - {"%CCYY", "%Y"}, - {"%YY", "%y"}, - {"%MM", "%m"}, - {"%DD", "%d"}, - {"%hh", "%H"}, - {"%mm", "%M"}, - {"%ss", "%S"}, - {"%%", "%%"}, - - {"%a", ""}, - {"%A", ""}, - {"%b", ""}, - {"%B", ""}, - {"%d", ""}, - {"%H", ""}, - {"%I", ""}, - {"%m", ""}, - {"%M", ""}, - {"%p", ""}, - {"%S", ""}, - {"%y", ""}, - {"%Y", ""}, - {"%z", ""}, - {"%Z", ""}, - }; - - char convert[128] = {}; - string sf = format; - string c; - size_t pos = 0, len; - - while (pos < sf.length()) { - len = 0; - for (size_t i = 0; i < spec_count && len == 0; i++) { - - if (sf.find(spec[i][0], pos) == pos) { - if (strlen(spec[i][1])) - strftime(convert, sizeof(convert), - spec[i][1], cur_time); - else - strftime(convert, sizeof(convert), - spec[i][0], cur_time); - - len = strlen(spec[i][0]); - - c = convert; - if (c.length() && c.find_first_not_of(' ') != - std::string::npos) - sf.replace(pos, len, convert); - } - } - - if (len) - pos += strlen(convert); - else if (!len && sf.at(pos) == '%') - sf.erase(pos,1); - else - pos++; - } - - if (noSpace) - replace(sf.begin(), sf.end(), ' ', '_'); - - sf += '.'; - sf += extension; - - return (sf.length() < 256) ? sf : sf.substr(0, 255); + BPtr<char> filename = os_generate_formatted_filename(extension, + !noSpace, format); + return string(filename); } vector<pair<string, string>> GetLocaleNames()
View file
obs-studio-0.16.6.tar.xz/UI/obs-frontend-api/obs-frontend-api.cpp -> obs-studio-0.17.0.tar.xz/UI/obs-frontend-api/obs-frontend-api.cpp
Changed
@@ -205,6 +205,23 @@ : false; } +void obs_frontend_replay_buffer_start(void) +{ + if (callbacks_valid()) c->obs_frontend_replay_buffer_start(); +} + +void obs_frontend_replay_buffer_stop(void) +{ + if (callbacks_valid()) c->obs_frontend_replay_buffer_stop(); +} + +bool obs_frontend_replay_buffer_active(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_replay_buffer_active() + : false; +} + void *obs_frontend_add_tools_menu_qaction(const char *name) { return !!callbacks_valid() @@ -248,6 +265,13 @@ : nullptr; } +obs_output_t *obs_frontend_get_replay_buffer_output(void) +{ + return !!callbacks_valid() + ? c->obs_frontend_get_replay_buffer_output() + : nullptr; +} + config_t *obs_frontend_get_profile_config(void) { return !!callbacks_valid()
View file
obs-studio-0.16.6.tar.xz/UI/obs-frontend-api/obs-frontend-api.h -> obs-studio-0.17.0.tar.xz/UI/obs-frontend-api/obs-frontend-api.h
Changed
@@ -70,6 +70,10 @@ EXPORT void obs_frontend_recording_stop(void); EXPORT bool obs_frontend_recording_active(void); +EXPORT void obs_frontend_replay_buffer_start(void); +EXPORT void obs_frontend_replay_buffer_stop(void); +EXPORT bool obs_frontend_replay_buffer_active(void); + typedef void (*obs_frontend_cb)(void *private_data); EXPORT void *obs_frontend_add_tools_menu_qaction(const char *name); @@ -94,7 +98,12 @@ OBS_FRONTEND_EVENT_SCENE_COLLECTION_LIST_CHANGED, OBS_FRONTEND_EVENT_PROFILE_CHANGED, OBS_FRONTEND_EVENT_PROFILE_LIST_CHANGED, - OBS_FRONTEND_EVENT_EXIT + OBS_FRONTEND_EVENT_EXIT, + + OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING, + OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED, + OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING, + OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED }; typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event, @@ -116,6 +125,7 @@ EXPORT obs_output_t *obs_frontend_get_streaming_output(void); EXPORT obs_output_t *obs_frontend_get_recording_output(void); +EXPORT obs_output_t *obs_frontend_get_replay_buffer_output(void); EXPORT config_t *obs_frontend_get_profile_config(void); EXPORT config_t *obs_frontend_get_global_config(void);
View file
obs-studio-0.16.6.tar.xz/UI/obs-frontend-api/obs-frontend-internal.hpp -> obs-studio-0.17.0.tar.xz/UI/obs-frontend-api/obs-frontend-internal.hpp
Changed
@@ -39,6 +39,10 @@ virtual void obs_frontend_recording_stop(void)=0; virtual bool obs_frontend_recording_active(void)=0; + virtual void obs_frontend_replay_buffer_start(void)=0; + virtual void obs_frontend_replay_buffer_stop(void)=0; + virtual bool obs_frontend_replay_buffer_active(void)=0; + virtual void *obs_frontend_add_tools_menu_qaction(const char *name)=0; virtual void obs_frontend_add_tools_menu_item(const char *name, obs_frontend_cb callback, void *private_data)=0; @@ -50,6 +54,7 @@ virtual obs_output_t *obs_frontend_get_streaming_output(void)=0; virtual obs_output_t *obs_frontend_get_recording_output(void)=0; + virtual obs_output_t *obs_frontend_get_replay_buffer_output(void)=0; virtual config_t *obs_frontend_get_profile_config(void)=0; virtual config_t *obs_frontend_get_global_config(void)=0;
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-filters.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-filters.cpp
Changed
@@ -147,6 +147,7 @@ void OBSBasicFilters::UpdatePropertiesView(int row, bool async) { if (view) { + ui->rightLayout->removeWidget(view); view->deleteLater(); view = nullptr; }
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-main-outputs.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-main-outputs.cpp
Changed
@@ -84,6 +84,36 @@ UNUSED_PARAMETER(params); } +static void OBSStartReplayBuffer(void *data, calldata_t *params) +{ + BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data); + + output->replayBufferActive = true; + QMetaObject::invokeMethod(output->main, "ReplayBufferStart"); + + UNUSED_PARAMETER(params); +} + +static void OBSStopReplayBuffer(void *data, calldata_t *params) +{ + BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data); + int code = (int)calldata_int(params, "code"); + + output->replayBufferActive = false; + QMetaObject::invokeMethod(output->main, + "ReplayBufferStop", Q_ARG(int, code)); + + UNUSED_PARAMETER(params); +} + +static void OBSReplayBufferStopping(void *data, calldata_t *params) +{ + BasicOutputHandler *output = static_cast<BasicOutputHandler*>(data); + QMetaObject::invokeMethod(output->main, "ReplayBufferStopping"); + + UNUSED_PARAMETER(params); +} + static void FindBestFilename(string &strPath, bool noSpace) { int num = 2; @@ -154,6 +184,7 @@ string videoEncoder; string videoQuality; bool usingRecordingPreset = false; + bool recordingConfigured = false; bool ffmpegOutput = false; bool lowCPUx264 = false; @@ -179,12 +210,18 @@ void LoadStreamingPreset_h264(const char *encoder); + void UpdateRecording(); + bool ConfigureRecording(bool useReplayBuffer); + virtual bool StartStreaming(obs_service_t *service) override; virtual bool StartRecording() override; + virtual bool StartReplayBuffer() override; virtual void StopStreaming(bool force) override; virtual void StopRecording(bool force) override; + virtual void StopReplayBuffer(bool force) override; virtual bool StreamingActive() const override; virtual bool RecordingActive() const override; + virtual bool ReplayBufferActive() const override; }; void SimpleOutput::LoadRecordingPreset_Lossless() @@ -306,6 +343,32 @@ LoadRecordingPreset(); if (!ffmpegOutput) { + bool useReplayBuffer = config_get_bool(main->Config(), + "SimpleOutput", "RecRB"); + if (useReplayBuffer) { + const char *str = config_get_string(main->Config(), + "Hotkeys", "ReplayBuffer"); + obs_data_t *hotkey = obs_data_create_from_json(str); + replayBuffer = obs_output_create("replay_buffer", + Str("ReplayBuffer"), nullptr, hotkey); + + obs_data_release(hotkey); + if (!replayBuffer) + throw "Failed to create replay buffer output " + "(simple output)"; + obs_output_release(replayBuffer); + + signal_handler_t *signal = + obs_output_get_signal_handler(replayBuffer); + + startReplayBuffer.Connect(signal, "start", + OBSStartReplayBuffer, this); + stopReplayBuffer.Connect(signal, "stop", + OBSStopReplayBuffer, this); + replayBufferStopping.Connect(signal, "stopping", + OBSReplayBufferStopping, this); + } + fileOutput = obs_output_create("ffmpeg_muxer", "simple_file_output", nullptr, nullptr); if (!fileOutput) @@ -624,6 +687,19 @@ return false; } +static void remove_reserved_file_characters(string &s) +{ + replace(s.begin(), s.end(), '/', '_'); + replace(s.begin(), s.end(), '\\', '_'); + replace(s.begin(), s.end(), '*', '_'); + replace(s.begin(), s.end(), '?', '_'); + replace(s.begin(), s.end(), '"', '_'); + replace(s.begin(), s.end(), '|', '_'); + replace(s.begin(), s.end(), ':', '_'); + replace(s.begin(), s.end(), '>', '_'); + replace(s.begin(), s.end(), '<', '_'); +} + static void ensure_directory_exists(string &path) { replace(path.begin(), path.end(), '\\', '/'); @@ -636,8 +712,11 @@ os_mkdirs(directory.c_str()); } -bool SimpleOutput::StartRecording() +void SimpleOutput::UpdateRecording() { + if (replayBufferActive || recordingActive) + return; + if (usingRecordingPreset) { if (!ffmpegOutput) UpdateRecordingSettings(); @@ -648,6 +727,20 @@ if (!Active()) SetupOutputs(); + if (!ffmpegOutput) { + obs_output_set_video_encoder(fileOutput, h264Recording); + obs_output_set_audio_encoder(fileOutput, aacRecording, 0); + } + if (replayBuffer) { + obs_output_set_video_encoder(replayBuffer, h264Recording); + obs_output_set_audio_encoder(replayBuffer, aacRecording, 0); + } + + recordingConfigured = true; +} + +bool SimpleOutput::ConfigureRecording(bool updateReplayBuffer) +{ const char *path = config_get_string(main->Config(), "SimpleOutput", "FilePath"); const char *format = config_get_string(main->Config(), @@ -660,6 +753,14 @@ "FilenameFormatting"); bool overwriteIfExists = config_get_bool(main->Config(), "Output", "OverwriteIfExists"); + const char *rbPrefix = config_get_string(main->Config(), "SimpleOutput", + "RecRBPrefix"); + const char *rbSuffix = config_get_string(main->Config(), "SimpleOutput", + "RecRBSuffix"); + int rbTime = config_get_int(main->Config(), "SimpleOutput", + "RecRBTime"); + int rbSize = config_get_int(main->Config(), "SimpleOutput", + "RecRBSize"); os_dir_t *dir = path ? os_opendir(path) : nullptr; @@ -689,25 +790,66 @@ if (!overwriteIfExists) FindBestFilename(strPath, noSpace); - if (!ffmpegOutput) { - obs_output_set_video_encoder(fileOutput, h264Recording); - obs_output_set_audio_encoder(fileOutput, aacRecording, 0); + obs_data_t *settings = obs_data_create(); + if (updateReplayBuffer) { + string f; + + if (rbPrefix && *rbPrefix) { + f += rbPrefix; + if (f.back() != ' ') + f += " "; + } + + f += filenameFormat; + + if (rbSuffix && *rbSuffix) { + if (*rbSuffix != ' ') + f += " "; + f += rbSuffix; + } + + remove_reserved_file_characters(f); + + obs_data_set_string(settings, "directory", path); + obs_data_set_string(settings, "format", f.c_str()); + obs_data_set_string(settings, "extension", format); + obs_data_set_int(settings, "max_time_sec", rbTime); + obs_data_set_int(settings, "max_size_mb", + usingRecordingPreset ? rbSize : 0); + } else { + obs_data_set_string(settings, ffmpegOutput ? "url" : "path", + strPath.c_str()); } - obs_data_t *settings = obs_data_create(); - obs_data_set_string(settings, ffmpegOutput ? "url" : "path", - strPath.c_str()); obs_data_set_string(settings, "muxer_settings", mux); - obs_output_update(fileOutput, settings); + if (updateReplayBuffer) + obs_output_update(replayBuffer, settings); + else + obs_output_update(fileOutput, settings); obs_data_release(settings); + return true; +} - if (obs_output_start(fileOutput)) { - return true; - } +bool SimpleOutput::StartRecording() +{ + UpdateRecording(); + if (!ConfigureRecording(false)) + return false; + if (!obs_output_start(fileOutput)) + return false; + return true; +} - return false; +bool SimpleOutput::StartReplayBuffer() +{ + UpdateRecording(); + if (!ConfigureRecording(true)) + return false; + if (!obs_output_start(replayBuffer)) + return false; + return true; } void SimpleOutput::StopStreaming(bool force) @@ -726,6 +868,14 @@ obs_output_stop(fileOutput); } +void SimpleOutput::StopReplayBuffer(bool force) +{ + if (force) + obs_output_force_stop(replayBuffer); + else + obs_output_stop(replayBuffer); +} + bool SimpleOutput::StreamingActive() const { return obs_output_active(streamOutput); @@ -736,10 +886,15 @@ return obs_output_active(fileOutput); } +bool SimpleOutput::ReplayBufferActive() const +{ + return obs_output_active(replayBuffer); +} + /* ------------------------------------------------------------------------ */ struct AdvancedOutput : BasicOutputHandler { - OBSEncoder aacTrack[4]; + OBSEncoder aacTrack[MAX_AUDIO_MIXES]; OBSEncoder h264Streaming; OBSEncoder h264Recording; @@ -747,7 +902,7 @@ bool ffmpegRecording; bool useStreamEncoder; - string aacEncoderID[4]; + string aacEncoderID[MAX_AUDIO_MIXES]; AdvancedOutput(OBSBasic *main_); @@ -844,7 +999,7 @@ "(advanced output)"; obs_encoder_release(h264Streaming); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < MAX_AUDIO_MIXES; i++) { char name[9]; sprintf(name, "adv_aac%d", i); @@ -939,7 +1094,7 @@ for (; i < trackCount; i++) obs_output_set_audio_encoder(streamOutput, aacTrack[i], i); - for (; i < 4; i++) + for (; i < MAX_AUDIO_MIXES; i++) obs_output_set_audio_encoder(streamOutput, nullptr, i); } else { @@ -1064,31 +1219,30 @@ inline void AdvancedOutput::UpdateAudioSettings() { - const char *name1 = config_get_string(main->Config(), "AdvOut", - "Track1Name"); - const char *name2 = config_get_string(main->Config(), "AdvOut", - "Track2Name"); - const char *name3 = config_get_string(main->Config(), "AdvOut", - "Track3Name"); - const char *name4 = config_get_string(main->Config(), "AdvOut", - "Track4Name"); bool applyServiceSettings = config_get_bool(main->Config(), "AdvOut", "ApplyServiceSettings"); int streamTrackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex"); - obs_data_t *settings[4]; + obs_data_t *settings[MAX_AUDIO_MIXES]; - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { settings[i] = obs_data_create(); obs_data_set_int(settings[i], "bitrate", GetAudioBitrate(i)); } - SetEncoderName(aacTrack[0], name1, "Track1"); - SetEncoderName(aacTrack[1], name2, "Track2"); - SetEncoderName(aacTrack[2], name3, "Track3"); - SetEncoderName(aacTrack[3], name4, "Track4"); + for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { + string cfg_name = "Track"; + cfg_name += to_string((int)i + 1); + cfg_name += "Name"; + const char *name = config_get_string(main->Config(), "AdvOut", + cfg_name.c_str()); + + string def_name = "Track"; + def_name += to_string((int)i + 1); + SetEncoderName(aacTrack[i], name, def_name.c_str()); + } - for (size_t i = 0; i < 4; i++) { + for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) { if (applyServiceSettings && (int)(i + 1) == streamTrackIndex) obs_service_apply_encoder_settings(main->GetService(), nullptr, settings[i]); @@ -1103,10 +1257,8 @@ obs_encoder_set_video(h264Streaming, obs_get_video()); if (h264Recording) obs_encoder_set_video(h264Recording, obs_get_video()); - obs_encoder_set_audio(aacTrack[0], obs_get_audio()); - obs_encoder_set_audio(aacTrack[1], obs_get_audio()); - obs_encoder_set_audio(aacTrack[2], obs_get_audio()); - obs_encoder_set_audio(aacTrack[3], obs_get_audio()); + for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) + obs_encoder_set_audio(aacTrack[i], obs_get_audio()); SetupStreaming(); @@ -1118,9 +1270,10 @@ int AdvancedOutput::GetAudioBitrate(size_t i) const { - const char *names[] = { + static const char *names[] = { "Track1Bitrate", "Track2Bitrate", "Track3Bitrate", "Track4Bitrate", + "Track5Bitrate", "Track6Bitrate", }; int bitrate = (int)config_get_uint(main->Config(), "AdvOut", names[i]); return FindClosestAvailableAACBitrate(bitrate);
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-main-outputs.hpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-main-outputs.hpp
Changed
@@ -5,18 +5,23 @@ struct BasicOutputHandler { OBSOutput fileOutput; OBSOutput streamOutput; + OBSOutput replayBuffer; bool streamingActive = false; bool recordingActive = false; bool delayActive = false; + bool replayBufferActive = false; OBSBasic *main; OBSSignal startRecording; OBSSignal stopRecording; + OBSSignal startReplayBuffer; + OBSSignal stopReplayBuffer; OBSSignal startStreaming; OBSSignal stopStreaming; OBSSignal streamDelayStarting; OBSSignal streamStopping; OBSSignal recordStopping; + OBSSignal replayBufferStopping; inline BasicOutputHandler(OBSBasic *main_) : main(main_) {} @@ -24,16 +29,20 @@ virtual bool StartStreaming(obs_service_t *service) = 0; virtual bool StartRecording() = 0; + virtual bool StartReplayBuffer() {return false;} virtual void StopStreaming(bool force = false) = 0; virtual void StopRecording(bool force = false) = 0; + virtual void StopReplayBuffer(bool force = false) {(void)force;} virtual bool StreamingActive() const = 0; virtual bool RecordingActive() const = 0; + virtual bool ReplayBufferActive() const {return false;} virtual void Update() = 0; inline bool Active() const { - return streamingActive || recordingActive || delayActive; + return streamingActive || recordingActive || delayActive || + replayBufferActive; } };
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-main-profiles.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-main-profiles.cpp
Changed
@@ -20,6 +20,7 @@ #include <util/util.hpp> #include <QMessageBox> #include <QVariant> +#include <QFileDialog> #include "window-basic-main.hpp" #include "window-namedialog.hpp" #include "qt-wrappers.hpp" @@ -448,6 +449,85 @@ } } +void OBSBasic::on_actionImportProfile_triggered() +{ + char path[512]; + + QString home = QDir::homePath(); + + int ret = GetConfigPath(path, 512, "obs-studio/basic/profiles/"); + if (ret <= 0) { + blog(LOG_WARNING, "Failed to get profile config path"); + return; + } + + QString dir = QFileDialog::getExistingDirectory( + this, + QTStr("Basic.MainMenu.Profile.Import"), + home, + QFileDialog::ShowDirsOnly | + QFileDialog::DontResolveSymlinks); + + if (!dir.isEmpty() && !dir.isNull()) { + QString inputPath = QString::fromUtf8(path); + QFileInfo finfo(dir); + QString directory = finfo.fileName(); + QString profileDir = inputPath + directory; + QDir folder(profileDir); + + if (!folder.exists()) { + folder.mkpath(profileDir); + QFile::copy(dir + "/basic.ini", + profileDir + "/basic.ini"); + QFile::copy(dir + "/service.json", + profileDir + "/service.json"); + RefreshProfiles(); + } else { + QMessageBox::information(this, + QTStr("Basic.MainMenu.Profile.Import"), + QTStr("Basic.MainMenu.Profile.Exists")); + } + } +} + +void OBSBasic::on_actionExportProfile_triggered() +{ + char path[512]; + + QString home = QDir::homePath(); + + QString currentProfile = + QString::fromUtf8(config_get_string(App()->GlobalConfig(), + "Basic", "ProfileDir")); + + int ret = GetConfigPath(path, 512, "obs-studio/basic/profiles/"); + if (ret <= 0) { + blog(LOG_WARNING, "Failed to get profile config path"); + return; + } + + QString dir = QFileDialog::getExistingDirectory( + this, + QTStr("Basic.MainMenu.Profile.Export"), + home, + QFileDialog::ShowDirsOnly | + QFileDialog::DontResolveSymlinks); + + if (!dir.isEmpty() && !dir.isNull()) { + QString outputDir = dir + "/" + currentProfile; + QString inputPath = QString::fromUtf8(path); + QDir folder(outputDir); + + if (!folder.exists()) { + folder.mkpath(outputDir); + QFile::copy(inputPath + currentProfile + "/basic.ini", + outputDir + "/basic.ini"); + QFile::copy(inputPath + currentProfile + "/service.json", + outputDir + "/service.json"); + } + } +} + void OBSBasic::ChangeProfile() { QAction *action = reinterpret_cast<QAction*>(sender());
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-main-scene-collections.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-main-scene-collections.cpp
Changed
@@ -19,6 +19,8 @@ #include <util/util.hpp> #include <QMessageBox> #include <QVariant> +#include <QFileDialog> +#include <QStandardPaths> #include "item-widget-helpers.hpp" #include "window-basic-main.hpp" #include "window-namedialog.hpp" @@ -191,7 +193,7 @@ int count = 0; for (int i = 0; i < menuActions.count(); i++) { - QVariant v = menuActions[i]->property("fileName"); + QVariant v = menuActions[i]->property("file_name"); if (v.typeName() != nullptr) delete menuActions[i]; } @@ -205,7 +207,7 @@ file.erase(file.size() - 5, 5); QAction *action = new QAction(QT_UTF8(name), this); - action->setProperty("fileName", QT_UTF8(path)); + action->setProperty("file_name", QT_UTF8(path)); connect(action, &QAction::triggered, this, &OBSBasic::ChangeSceneCollection); action->setCheckable(true); @@ -347,6 +349,67 @@ } } +void OBSBasic::on_actionImportSceneCollection_triggered() +{ + char path[512]; + + QString home = QDir::homePath(); + + int ret = GetConfigPath(path, 512, "obs-studio/basic/scenes/"); + if (ret <= 0) { + blog(LOG_WARNING, "Failed to get scene collection config path"); + return; + } + + QString file = QFileDialog::getOpenFileName( + this, + QTStr("Basic.MainMenu.SceneCollection.Import"), + home, + "JSON Files (*.json)"); + + QFileInfo finfo(file); + QString filename = finfo.fileName(); + QFileInfo destinfo(path + filename); + + if (!file.isEmpty() && !file.isNull()) { + if (!destinfo.exists()) { + QFile::copy(file, path + filename); + RefreshSceneCollections(); + } else { + QMessageBox::information(this, + QTStr("Basic.MainMenu.SceneCollection.Import"), + QTStr("Basic.MainMenu.SceneCollection.Exists")); + } + } +} + +void OBSBasic::on_actionExportSceneCollection_triggered() +{ + char path[512]; + + QString home = QDir::homePath(); + + QString currentFile = QT_UTF8(config_get_string(App()->GlobalConfig(), + "Basic", "SceneCollectionFile")); + + int ret = GetConfigPath(path, 512, "obs-studio/basic/scenes/"); + if (ret <= 0) { + blog(LOG_WARNING, "Failed to get scene collection config path"); + return; + } + + QString exportFile = QFileDialog::getSaveFileName( + this, + QTStr("Basic.MainMenu.SceneCollection.Export"), + home + "/" + currentFile, + "JSON Files (*.json)"); + + string file = QT_TO_UTF8(exportFile); + + if (!exportFile.isEmpty() && !exportFile.isNull()) + QFile::copy(path + currentFile + ".json", exportFile); +} + void OBSBasic::ChangeSceneCollection() { QAction *action = reinterpret_cast<QAction*>(sender()); @@ -355,7 +418,7 @@ if (!action) return; - fileName = QT_TO_UTF8(action->property("fileName").value<QString>()); + fileName = QT_TO_UTF8(action->property("file_name").value<QString>()); if (fileName.empty()) return;
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-main.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-main.cpp
Changed
@@ -847,6 +847,11 @@ "Stream"); config_set_default_string(basicConfig, "SimpleOutput", "RecEncoder", SIMPLE_ENCODER_X264); + config_set_default_bool(basicConfig, "SimpleOutput", "RecRB", false); + config_set_default_int(basicConfig, "SimpleOutput", "RecRBTime", 20); + config_set_default_int(basicConfig, "SimpleOutput", "RecRBSize", 512); + config_set_default_string(basicConfig, "SimpleOutput", "RecRBPrefix", + "Replay"); config_set_default_bool (basicConfig, "AdvOut", "ApplyServiceSettings", true); @@ -880,6 +885,8 @@ config_set_default_uint (basicConfig, "AdvOut", "Track2Bitrate", 160); config_set_default_uint (basicConfig, "AdvOut", "Track3Bitrate", 160); config_set_default_uint (basicConfig, "AdvOut", "Track4Bitrate", 160); + config_set_default_uint (basicConfig, "AdvOut", "Track5Bitrate", 160); + config_set_default_uint (basicConfig, "AdvOut", "Track6Bitrate", 160); config_set_default_uint (basicConfig, "Video", "BaseCX", cx); config_set_default_uint (basicConfig, "Video", "BaseCY", cy); @@ -1029,6 +1036,14 @@ obs_leave_graphics(); } +void OBSBasic::ReplayBufferClicked() +{ + if (outputHandler->ReplayBufferActive()) + StopReplayBuffer(); + else + StartReplayBuffer(); +}; + void OBSBasic::ResetOutputs() { ProfileScope("OBSBasic::ResetOutputs"); @@ -1041,6 +1056,24 @@ outputHandler.reset(advOut ? CreateAdvancedOutputHandler(this) : CreateSimpleOutputHandler(this)); + + delete replayBufferButton; + + if (outputHandler->replayBuffer) { + replayBufferButton = new QPushButton( + QTStr("Basic.Main.StartReplayBuffer"), + this); + connect(replayBufferButton.data(), + &QPushButton::clicked, + this, + &OBSBasic::ReplayBufferClicked); + + ui->buttonsVLayout->insertWidget(2, replayBufferButton); + } + + if (sysTrayReplayBuffer) + sysTrayReplayBuffer->setEnabled( + !!outputHandler->replayBuffer); } else { outputHandler->Update(); } @@ -1053,6 +1086,14 @@ extern obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main); +#define UNSUPPORTED_ERROR \ + "Failed to initialize video:\n\nRequired graphics API functionality " \ + "not found. Your GPU may not be supported." + +#define UNKNOWN_ERROR \ + "Failed to initialize video. Your GPU may not be supported, " \ + "or your graphics drivers may need to be updated." + void OBSBasic::OBSInit() { ProfileScope("OBSBasic::OBSInit"); @@ -1086,14 +1127,12 @@ case OBS_VIDEO_MODULE_NOT_FOUND: throw "Failed to initialize video: Graphics module not found"; case OBS_VIDEO_NOT_SUPPORTED: - throw "Failed to initialize video: Required graphics API " - "functionality not found on these drivers or " - "unavailable on this equipment"; + throw UNSUPPORTED_ERROR; case OBS_VIDEO_INVALID_PARAM: throw "Failed to initialize video: Invalid parameters"; default: if (ret != OBS_VIDEO_SUCCESS) - throw "Failed to initialize video: Unspecified error"; + throw UNKNOWN_ERROR; } InitOBSCallbacks(); @@ -1344,9 +1383,9 @@ streamingHotkeys = obs_hotkey_pair_register_frontend( "OBSBasic.StartStreaming", - Str("Basic.Hotkeys.StartStreaming"), + Str("Basic.Main.StartStreaming"), "OBSBasic.StopStreaming", - Str("Basic.Hotkeys.StopStreaming"), + Str("Basic.Main.StopStreaming"), MAKE_CALLBACK(!basic.outputHandler->StreamingActive(), basic.StartStreaming), MAKE_CALLBACK(basic.outputHandler->StreamingActive(), @@ -1372,9 +1411,9 @@ recordingHotkeys = obs_hotkey_pair_register_frontend( "OBSBasic.StartRecording", - Str("Basic.Hotkeys.StartRecording"), + Str("Basic.Main.StartRecording"), "OBSBasic.StopRecording", - Str("Basic.Hotkeys.StopRecording"), + Str("Basic.Main.StopRecording"), MAKE_CALLBACK(!basic.outputHandler->RecordingActive(), basic.StartRecording), MAKE_CALLBACK(basic.outputHandler->RecordingActive(), @@ -1382,6 +1421,19 @@ this, this); LoadHotkeyPair(recordingHotkeys, "OBSBasic.StartRecording", "OBSBasic.StopRecording"); + + replayBufHotkeys = obs_hotkey_pair_register_frontend( + "OBSBasic.StartReplayBuffer", + Str("Basic.Main.StartReplayBuffer"), + "OBSBasic.StopReplayBuffer", + Str("Basic.Main.StopReplayBuffer"), + MAKE_CALLBACK(!basic.outputHandler->ReplayBufferActive(), + basic.StartReplayBuffer), + MAKE_CALLBACK(basic.outputHandler->ReplayBufferActive(), + basic.StopReplayBuffer), + this, this); + LoadHotkeyPair(replayBufHotkeys, + "OBSBasic.StartReplayBuffer", "OBSBasic.StopReplayBuffer"); #undef MAKE_CALLBACK auto togglePreviewProgram = [] (void *data, obs_hotkey_id, @@ -1418,6 +1470,7 @@ { obs_hotkey_pair_unregister(streamingHotkeys); obs_hotkey_pair_unregister(recordingHotkeys); + obs_hotkey_pair_unregister(replayBufHotkeys); obs_hotkey_unregister(forceStreamingStopHotkey); obs_hotkey_unregister(togglePreviewProgramHotkey); obs_hotkey_unregister(transitionHotkey); @@ -1719,6 +1772,9 @@ blog(LOG_INFO, "User added scene '%s'", obs_source_get_name(source)); } + + if (api) + api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED); } void OBSBasic::RemoveScene(OBSSource source) @@ -2111,8 +2167,6 @@ SetCurrentScene(source, true); obs_scene_release(scene); - if (api) - api->on_event(OBS_FRONTEND_EVENT_SCENE_LIST_CHANGED); break; } } @@ -3647,6 +3701,10 @@ "==== Recording Start ===============================================" #define RECORDING_STOP \ "==== Recording Stop ================================================" +#define REPLAY_BUFFER_START \ + "==== Replay Buffer Start ===========================================" +#define REPLAY_BUFFER_STOP \ + "==== Replay Buffer Stop ============================================" #define STREAMING_START \ "==== Streaming Start ===============================================" #define STREAMING_STOP \ @@ -3963,6 +4021,7 @@ if (sysTrayRecord) sysTrayRecord->setText(ui->recordButton->text()); + blog(LOG_INFO, RECORDING_STOP); if (code == OBS_OUTPUT_UNSUPPORTED && isVisible()) { @@ -3999,6 +4058,131 @@ OnDeactivate(); } +#define RP_NO_HOTKEY_TITLE QTStr("Output.ReplayBuffer.NoHotkey.Title") +#define RP_NO_HOTKEY_TEXT QTStr("Output.ReplayBuffer.NoHotkey.Msg") + +void OBSBasic::StartReplayBuffer() +{ + if (!outputHandler || !outputHandler->replayBuffer) + return; + if (outputHandler->ReplayBufferActive()) + return; + + obs_output_t *output = outputHandler->replayBuffer; + obs_data_t *hotkeys = obs_hotkeys_save_output(output); + obs_data_array_t *bindings = obs_data_get_array(hotkeys, + "ReplayBuffer.Save"); + size_t count = obs_data_array_count(bindings); + obs_data_array_release(bindings); + obs_data_release(hotkeys); + + if (!count) { + QMessageBox::information(this, + RP_NO_HOTKEY_TITLE, + RP_NO_HOTKEY_TEXT); + return; + } + + if (api) + api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTING); + + SaveProject(); + outputHandler->StartReplayBuffer(); +} + +void OBSBasic::ReplayBufferStopping() +{ + if (!outputHandler || !outputHandler->replayBuffer) + return; + + replayBufferButton->setText(QTStr("Basic.Main.StoppingReplayBuffer")); + + if (sysTrayReplayBuffer) + sysTrayReplayBuffer->setText(replayBufferButton->text()); + + replayBufferStopping = true; + if (api) + api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPING); +} + +void OBSBasic::StopReplayBuffer() +{ + if (!outputHandler || !outputHandler->replayBuffer) + return; + + SaveProject(); + + if (outputHandler->ReplayBufferActive()) + outputHandler->StopReplayBuffer(replayBufferStopping); + + OnDeactivate(); +} + +void OBSBasic::ReplayBufferStart() +{ + if (!outputHandler || !outputHandler->replayBuffer) + return; + + replayBufferButton->setText(QTStr("Basic.Main.StopReplayBuffer")); + + if (sysTrayReplayBuffer) + sysTrayReplayBuffer->setText(replayBufferButton->text()); + + replayBufferStopping = false; + if (api) + api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED); + + OnActivate(); + + blog(LOG_INFO, REPLAY_BUFFER_START); +} + +void OBSBasic::ReplayBufferStop(int code) +{ + if (!outputHandler || !outputHandler->replayBuffer) + return; + + replayBufferButton->setText(QTStr("Basic.Main.StartReplayBuffer")); + + if (sysTrayReplayBuffer) + sysTrayReplayBuffer->setText(replayBufferButton->text()); + + blog(LOG_INFO, REPLAY_BUFFER_STOP); + + if (code == OBS_OUTPUT_UNSUPPORTED && isVisible()) { + QMessageBox::information(this, + QTStr("Output.RecordFail.Title"), + QTStr("Output.RecordFail.Unsupported")); + + } else if (code == OBS_OUTPUT_NO_SPACE && isVisible()) { + QMessageBox::information(this, + QTStr("Output.RecordNoSpace.Title"), + QTStr("Output.RecordNoSpace.Msg")); + + } else if (code != OBS_OUTPUT_SUCCESS && isVisible()) { + QMessageBox::information(this, + QTStr("Output.RecordError.Title"), + QTStr("Output.RecordError.Msg")); + + } else if (code == OBS_OUTPUT_UNSUPPORTED && !isVisible()) { + SysTrayNotify(QTStr("Output.RecordFail.Unsupported"), + QSystemTrayIcon::Warning); + + } else if (code == OBS_OUTPUT_NO_SPACE && !isVisible()) { + SysTrayNotify(QTStr("Output.RecordNoSpace.Msg"), + QSystemTrayIcon::Warning); + + } else if (code != OBS_OUTPUT_SUCCESS && !isVisible()) { + SysTrayNotify(QTStr("Output.RecordError.Msg"), + QSystemTrayIcon::Warning); + } + + if (api) + api->on_event(OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED); + + OnDeactivate(); +} + void OBSBasic::on_streamButton_clicked() { if (outputHandler->StreamingActive()) { @@ -4211,6 +4395,50 @@ transformWindow->setAttribute(Qt::WA_DeleteOnClose, true); } +static obs_transform_info copiedTransformInfo; +static obs_sceneitem_crop copiedCropInfo; + +void OBSBasic::on_actionCopyTransform_triggered() +{ + auto func = [](obs_scene_t *scene, obs_sceneitem_t *item, void *param) + { + if (!obs_sceneitem_selected(item)) + return true; + + obs_sceneitem_defer_update_begin(item); + obs_sceneitem_get_info(item, &copiedTransformInfo); + obs_sceneitem_get_crop(item, &copiedCropInfo); + obs_sceneitem_defer_update_end(item); + + UNUSED_PARAMETER(scene); + UNUSED_PARAMETER(param); + return true; + }; + + obs_scene_enum_items(GetCurrentScene(), func, nullptr); + ui->actionPasteTransform->setEnabled(true); +} + +void OBSBasic::on_actionPasteTransform_triggered() +{ + auto func = [](obs_scene_t *scene, obs_sceneitem_t *item, void *param) + { + if (!obs_sceneitem_selected(item)) + return true; + + obs_sceneitem_defer_update_begin(item); + obs_sceneitem_set_info(item, &copiedTransformInfo); + obs_sceneitem_set_crop(item, &copiedCropInfo); + obs_sceneitem_defer_update_end(item); + + UNUSED_PARAMETER(scene); + UNUSED_PARAMETER(param); + return true; + }; + + obs_scene_enum_items(GetCurrentScene(), func, nullptr); +} + void OBSBasic::on_actionResetTransform_triggered() { auto func = [] (obs_scene_t *scene, obs_sceneitem_t *item, void *param) @@ -4693,9 +4921,14 @@ trayIcon); sysTrayRecord = new QAction(QTStr("Basic.Main.StartRecording"), trayIcon); + sysTrayReplayBuffer = new QAction(QTStr("Basic.Main.StartReplayBuffer"), + trayIcon); exit = new QAction(QTStr("Exit"), trayIcon); + if (outputHandler && !outputHandler->replayBuffer) + sysTrayReplayBuffer->setEnabled(false); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(IconActivated(QSystemTrayIcon::ActivationReason))); @@ -4705,6 +4938,8 @@ this, SLOT(on_streamButton_clicked())); connect(sysTrayRecord, SIGNAL(triggered()), this, SLOT(on_recordButton_clicked())); + connect(sysTrayReplayBuffer.data(), &QAction::triggered, + this, &OBSBasic::ReplayBufferClicked); connect(exit, SIGNAL(triggered()), this, SLOT(close())); @@ -4712,6 +4947,7 @@ trayMenu->addAction(showHide); trayMenu->addAction(sysTrayStream); trayMenu->addAction(sysTrayRecord); + trayMenu->addAction(sysTrayReplayBuffer); trayMenu->addAction(exit); trayIcon->setContextMenu(trayMenu); }
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-main.hpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-main.hpp
Changed
@@ -86,6 +86,7 @@ friend class OBSBasicPreview; friend class OBSBasicStatusBar; friend class OBSBasicSourceSelect; + friend class OBSBasicSettings; friend struct OBSStudioAPI; enum class MoveDir { @@ -130,6 +131,7 @@ std::unique_ptr<BasicOutputHandler> outputHandler; bool streamingStopping = false; bool recordingStopping = false; + bool replayBufferStopping = false; gs_vertbuffer_t *box = nullptr; gs_vertbuffer_t *boxLeft = nullptr; @@ -151,9 +153,12 @@ QPointer<QMenu> startStreamMenu; + QPointer<QPushButton> replayBufferButton; + QPointer<QSystemTrayIcon> trayIcon; QPointer<QAction> sysTrayStream; QPointer<QAction> sysTrayRecord; + QPointer<QAction> sysTrayReplayBuffer; QPointer<QAction> showHide; QPointer<QAction> exit; QPointer<QMenu> trayMenu; @@ -244,7 +249,8 @@ QListWidgetItem *GetTopSelectedSourceItem(); - obs_hotkey_pair_id streamingHotkeys, recordingHotkeys; + obs_hotkey_pair_id streamingHotkeys, recordingHotkeys, + replayBufHotkeys; obs_hotkey_id forceStreamingStopHotkey; void InitDefaultTransitions(); @@ -313,6 +319,8 @@ void dragMoveEvent(QDragMoveEvent *event) override; void dropEvent(QDropEvent *event) override; + void ReplayBufferClicked(); + public slots: void StartStreaming(); void StopStreaming(); @@ -332,6 +340,13 @@ void RecordStopping(); void RecordingStop(int code); + void StartReplayBuffer(); + void StopReplayBuffer(); + + void ReplayBufferStart(); + void ReplayBufferStopping(); + void ReplayBufferStop(int code); + void SaveProjectDeferred(); void SaveProject(); @@ -483,6 +498,8 @@ void on_actionCheckForUpdates_triggered(); void on_actionEditTransform_triggered(); + void on_actionCopyTransform_triggered(); + void on_actionPasteTransform_triggered(); void on_actionRotate90CW_triggered(); void on_actionRotate90CCW_triggered(); void on_actionRotate180_triggered(); @@ -535,11 +552,15 @@ void on_actionDupSceneCollection_triggered(); void on_actionRenameSceneCollection_triggered(); void on_actionRemoveSceneCollection_triggered(); + void on_actionImportSceneCollection_triggered(); + void on_actionExportSceneCollection_triggered(); void on_actionNewProfile_triggered(); void on_actionDupProfile_triggered(); void on_actionRenameProfile_triggered(); void on_actionRemoveProfile_triggered(); + void on_actionImportProfile_triggered(); + void on_actionExportProfile_triggered(); void on_actionShowSettingsFolder_triggered(); void on_actionShowProfileFolder_triggered();
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-settings.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-settings.cpp
Changed
@@ -44,6 +44,7 @@ #include "qt-wrappers.hpp" #include "window-basic-main.hpp" #include "window-basic-settings.hpp" +#include "window-basic-main-outputs.hpp" #include <util/platform.h> @@ -261,7 +262,8 @@ PopulateAACBitrates({ui->simpleOutputABitrate, ui->advOutTrack1Bitrate, ui->advOutTrack2Bitrate, - ui->advOutTrack3Bitrate, ui->advOutTrack4Bitrate}); + ui->advOutTrack3Bitrate, ui->advOutTrack4Bitrate, + ui->advOutTrack5Bitrate, ui->advOutTrack6Bitrate}); ui->listWidget->setAttribute(Qt::WA_MacShowFocusRect, false); @@ -299,6 +301,9 @@ HookWidget(ui->simpleOutRecQuality, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutRecEncoder, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->simpleOutMuxCustom, EDIT_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->simpleReplayBuf, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->simpleRBSecMax, SCROLL_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->simpleRBMegsMax, SCROLL_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutEncoder, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutUseRescale, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRescale, CBEDIT_CHANGED, OUTPUTS_CHANGED); @@ -306,6 +311,8 @@ HookWidget(ui->advOutTrack2, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack3, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack4, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutTrack5, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutTrack6, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutApplyService, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRecType, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRecPath, EDIT_CHANGED, OUTPUTS_CHANGED); @@ -319,6 +326,8 @@ HookWidget(ui->advOutRecTrack2, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRecTrack3, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutRecTrack4, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutRecTrack5, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutRecTrack6, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFType, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFRecPath, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFNoSpace, CHECK_CHANGED, OUTPUTS_CHANGED); @@ -335,6 +344,8 @@ HookWidget(ui->advOutFFTrack2, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFTrack3, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFTrack4, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutFFTrack5, CHECK_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutFFTrack6, CHECK_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFAEncoder, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutFFACfg, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack1Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED); @@ -345,6 +356,10 @@ HookWidget(ui->advOutTrack3Name, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack4Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->advOutTrack4Name, EDIT_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutTrack5Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutTrack5Name, EDIT_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutTrack6Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED); + HookWidget(ui->advOutTrack6Name, EDIT_CHANGED, OUTPUTS_CHANGED); HookWidget(ui->channelSetup, COMBO_CHANGED, AUDIO_RESTART); HookWidget(ui->sampleRate, COMBO_CHANGED, AUDIO_RESTART); HookWidget(ui->desktopAudioDevice1, COMBO_CHANGED, AUDIO_CHANGED); @@ -370,6 +385,8 @@ HookWidget(ui->resetOSXVSync, CHECK_CHANGED, ADV_CHANGED); HookWidget(ui->filenameFormatting, EDIT_CHANGED, ADV_CHANGED); HookWidget(ui->overwriteIfExists, CHECK_CHANGED, ADV_CHANGED); + HookWidget(ui->simpleRBPrefix, EDIT_CHANGED, ADV_CHANGED); + HookWidget(ui->simpleRBSuffix, EDIT_CHANGED, ADV_CHANGED); HookWidget(ui->streamDelayEnable, CHECK_CHANGED, ADV_CHANGED); HookWidget(ui->streamDelaySec, SCROLL_CHANGED, ADV_CHANGED); HookWidget(ui->streamDelayPreserve, CHECK_CHANGED, ADV_CHANGED); @@ -451,6 +468,10 @@ this, SLOT(UpdateStreamDelayEstimate())); connect(ui->advOutTrack4Bitrate, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateStreamDelayEstimate())); + connect(ui->advOutTrack5Bitrate, SIGNAL(currentIndexChanged(int)), + this, SLOT(UpdateStreamDelayEstimate())); + connect(ui->advOutTrack6Bitrate, SIGNAL(currentIndexChanged(int)), + this, SLOT(UpdateStreamDelayEstimate())); //Apply button disabled until change. EnableApplyButton(false); @@ -525,6 +546,14 @@ this, SLOT(SimpleRecordingEncoderChanged())); connect(ui->simpleOutEnforce, SIGNAL(toggled(bool)), this, SLOT(SimpleRecordingEncoderChanged())); + connect(ui->simpleReplayBuf, SIGNAL(toggled(bool)), + this, SLOT(SimpleReplayBufferChanged())); + connect(ui->simpleOutputVBitrate, SIGNAL(valueChanged(int)), + this, SLOT(SimpleReplayBufferChanged())); + connect(ui->simpleOutputABitrate, SIGNAL(currentIndexChanged(int)), + this, SLOT(SimpleReplayBufferChanged())); + connect(ui->simpleRBSecMax, SIGNAL(valueChanged(int)), + this, SLOT(SimpleReplayBufferChanged())); connect(ui->listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(SimpleRecordingEncoderChanged())); @@ -553,6 +582,10 @@ this, SLOT(AdvOutRecCheckWarnings())); connect(ui->advOutRecTrack4, SIGNAL(clicked()), this, SLOT(AdvOutRecCheckWarnings())); + connect(ui->advOutRecTrack5, SIGNAL(clicked()), + this, SLOT(AdvOutRecCheckWarnings())); + connect(ui->advOutRecTrack6, SIGNAL(clicked()), + this, SLOT(AdvOutRecCheckWarnings())); AdvOutRecCheckWarnings(); SimpleRecordingQualityChanged(); @@ -1216,6 +1249,12 @@ "RecEncoder"); const char *muxCustom = config_get_string(main->Config(), "SimpleOutput", "MuxerCustom"); + bool replayBuf = config_get_bool(main->Config(), "SimpleOutput", + "RecRB"); + int rbTime = config_get_int(main->Config(), "SimpleOutput", + "RecRBTime"); + int rbSize = config_get_int(main->Config(), "SimpleOutput", + "RecRBSize"); curPreset = preset; curQSVPreset = qsvPreset; @@ -1252,6 +1291,10 @@ ui->simpleOutMuxCustom->setText(muxCustom); + ui->simpleReplayBuf->setChecked(replayBuf); + ui->simpleRBSecMax->setValue(rbTime); + ui->simpleRBMegsMax->setValue(rbSize); + SimpleStreamingEncoderChanged(); } @@ -1284,6 +1327,8 @@ case 2: ui->advOutTrack2->setChecked(true); break; case 3: ui->advOutTrack3->setChecked(true); break; case 4: ui->advOutTrack4->setChecked(true); break; + case 5: ui->advOutTrack5->setChecked(true); break; + case 6: ui->advOutTrack6->setChecked(true); break; } } @@ -1378,6 +1423,8 @@ ui->advOutRecTrack2->setChecked(tracks & (1<<1)); ui->advOutRecTrack3->setChecked(tracks & (1<<2)); ui->advOutRecTrack4->setChecked(tracks & (1<<3)); + ui->advOutRecTrack5->setChecked(tracks & (1<<4)); + ui->advOutRecTrack6->setChecked(tracks & (1<<5)); } void OBSBasicSettings::LoadAdvOutputRecordingEncoderProperties() @@ -1492,6 +1539,8 @@ case 2: ui->advOutFFTrack2->setChecked(true); break; case 3: ui->advOutFFTrack3->setChecked(true); break; case 4: ui->advOutFFTrack4->setChecked(true); break; + case 5: ui->advOutFFTrack5->setChecked(true); break; + case 6: ui->advOutFFTrack6->setChecked(true); break; } } @@ -1505,6 +1554,10 @@ "Track3Bitrate"); int track4Bitrate = config_get_uint(main->Config(), "AdvOut", "Track4Bitrate"); + int track5Bitrate = config_get_uint(main->Config(), "AdvOut", + "Track5Bitrate"); + int track6Bitrate = config_get_uint(main->Config(), "AdvOut", + "Track6Bitrate"); const char *name1 = config_get_string(main->Config(), "AdvOut", "Track1Name"); const char *name2 = config_get_string(main->Config(), "AdvOut", @@ -1513,11 +1566,17 @@ "Track3Name"); const char *name4 = config_get_string(main->Config(), "AdvOut", "Track4Name"); + const char *name5 = config_get_string(main->Config(), "AdvOut", + "Track5Name"); + const char *name6 = config_get_string(main->Config(), "AdvOut", + "Track6Name"); track1Bitrate = FindClosestAvailableAACBitrate(track1Bitrate); track2Bitrate = FindClosestAvailableAACBitrate(track2Bitrate); track3Bitrate = FindClosestAvailableAACBitrate(track3Bitrate); track4Bitrate = FindClosestAvailableAACBitrate(track4Bitrate); + track5Bitrate = FindClosestAvailableAACBitrate(track5Bitrate); + track6Bitrate = FindClosestAvailableAACBitrate(track6Bitrate); SetComboByName(ui->advOutTrack1Bitrate, std::to_string(track1Bitrate).c_str()); @@ -1527,11 +1586,17 @@ std::to_string(track3Bitrate).c_str()); SetComboByName(ui->advOutTrack4Bitrate, std::to_string(track4Bitrate).c_str()); + SetComboByName(ui->advOutTrack5Bitrate, + std::to_string(track5Bitrate).c_str()); + SetComboByName(ui->advOutTrack6Bitrate, + std::to_string(track6Bitrate).c_str()); ui->advOutTrack1Name->setText(name1); ui->advOutTrack2Name->setText(name2); ui->advOutTrack3Name->setText(name3); ui->advOutTrack4Name->setText(name4); + ui->advOutTrack5Name->setText(name5); + ui->advOutTrack6Name->setText(name6); } void OBSBasicSettings::LoadOutputSettings() @@ -1554,6 +1619,8 @@ if (video_output_active(obs_get_video())) { ui->outputMode->setEnabled(false); ui->outputModeLabel->setEnabled(false); + ui->simpleRecordingGroupBox->setEnabled(false); + ui->replayBufferGroupBox->setEnabled(false); ui->advOutTopContainer->setEnabled(false); ui->advOutRecTopContainer->setEnabled(false); ui->advOutRecTypeContainer->setEnabled(false); @@ -1586,6 +1653,8 @@ ui->advOutFFTrack2->setEnabled(enabled); ui->advOutFFTrack3->setEnabled(enabled); ui->advOutFFTrack4->setEnabled(enabled); + ui->advOutFFTrack5->setEnabled(enabled); + ui->advOutFFTrack6->setEnabled(enabled); default: break; } @@ -1845,6 +1914,10 @@ "OverwriteIfExists"); const char *bindIP = config_get_string(main->Config(), "Output", "BindIP"); + const char *rbPrefix = config_get_string(main->Config(), "SimpleOutput", + "RecRBPrefix"); + const char *rbSuffix = config_get_string(main->Config(), "SimpleOutput", + "RecRBSuffix"); loading = true; @@ -1852,6 +1925,8 @@ ui->filenameFormatting->setText(filename); ui->overwriteIfExists->setChecked(overwriteIfExists); + ui->simpleRBPrefix->setText(rbPrefix); + ui->simpleRBSuffix->setText(rbSuffix); ui->reconnectEnable->setChecked(reconnect); ui->reconnectRetryDelay->setValue(retryDelay); @@ -2358,6 +2433,8 @@ SaveCombo(ui->colorSpace, "Video", "ColorSpace"); SaveComboData(ui->colorRange, "Video", "ColorRange"); SaveEdit(ui->filenameFormatting, "Output", "FilenameFormatting"); + SaveEdit(ui->simpleRBPrefix, "SimpleOutput", "RecRBPrefix"); + SaveEdit(ui->simpleRBSuffix, "SimpleOutput", "RecRBSuffix"); SaveCheckBox(ui->overwriteIfExists, "Output", "OverwriteIfExists"); SaveCheckBox(ui->streamDelayEnable, "Output", "DelayEnable"); SaveSpinBox(ui->streamDelaySec, "Output", "DelaySec"); @@ -2406,12 +2483,16 @@ QAbstractButton *check1, QAbstractButton *check2, QAbstractButton *check3, - QAbstractButton *check4) + QAbstractButton *check4, + QAbstractButton *check5, + QAbstractButton *check6) { if (check1->isChecked()) config_set_int(config, section, name, 1); else if (check2->isChecked()) config_set_int(config, section, name, 2); else if (check3->isChecked()) config_set_int(config, section, name, 3); else if (check4->isChecked()) config_set_int(config, section, name, 4); + else if (check5->isChecked()) config_set_int(config, section, name, 5); + else if (check6->isChecked()) config_set_int(config, section, name, 6); } void OBSBasicSettings::SaveFormat(QComboBox *combo) @@ -2488,6 +2569,9 @@ SaveComboData(ui->simpleOutRecQuality, "SimpleOutput", "RecQuality"); SaveComboData(ui->simpleOutRecEncoder, "SimpleOutput", "RecEncoder"); SaveEdit(ui->simpleOutMuxCustom, "SimpleOutput", "MuxerCustom"); + SaveCheckBox(ui->simpleReplayBuf, "SimpleOutput", "RecRB"); + SaveSpinBox(ui->simpleRBSecMax, "SimpleOutput", "RecRBTime"); + SaveSpinBox(ui->simpleRBMegsMax, "SimpleOutput", "RecRBSize"); curAdvStreamEncoder = GetComboData(ui->advOutEncoder); @@ -2497,7 +2581,8 @@ SaveCombo(ui->advOutRescale, "AdvOut", "RescaleRes"); SaveTrackIndex(main->Config(), "AdvOut", "TrackIndex", ui->advOutTrack1, ui->advOutTrack2, - ui->advOutTrack3, ui->advOutTrack4); + ui->advOutTrack3, ui->advOutTrack4, + ui->advOutTrack5, ui->advOutTrack6); config_set_string(main->Config(), "AdvOut", "RecType", RecTypeFromIdx(ui->advOutRecType->currentIndex())); @@ -2516,7 +2601,9 @@ (ui->advOutRecTrack1->isChecked() ? (1<<0) : 0) | (ui->advOutRecTrack2->isChecked() ? (1<<1) : 0) | (ui->advOutRecTrack3->isChecked() ? (1<<2) : 0) | - (ui->advOutRecTrack4->isChecked() ? (1<<3) : 0)); + (ui->advOutRecTrack4->isChecked() ? (1<<3) : 0) | + (ui->advOutRecTrack5->isChecked() ? (1<<4) : 0) | + (ui->advOutRecTrack6->isChecked() ? (1<<5) : 0)); config_set_bool(main->Config(), "AdvOut", "FFOutputToFile", ui->advOutFFType->currentIndex() == 0 ? true : false); @@ -2535,16 +2622,21 @@ SaveEdit(ui->advOutFFACfg, "AdvOut", "FFACustom"); SaveTrackIndex(main->Config(), "AdvOut", "FFAudioTrack", ui->advOutFFTrack1, ui->advOutFFTrack2, - ui->advOutFFTrack3, ui->advOutFFTrack4); + ui->advOutFFTrack3, ui->advOutFFTrack4, + ui->advOutFFTrack5, ui->advOutFFTrack6); SaveCombo(ui->advOutTrack1Bitrate, "AdvOut", "Track1Bitrate"); SaveCombo(ui->advOutTrack2Bitrate, "AdvOut", "Track2Bitrate"); SaveCombo(ui->advOutTrack3Bitrate, "AdvOut", "Track3Bitrate"); SaveCombo(ui->advOutTrack4Bitrate, "AdvOut", "Track4Bitrate"); + SaveCombo(ui->advOutTrack5Bitrate, "AdvOut", "Track5Bitrate"); + SaveCombo(ui->advOutTrack6Bitrate, "AdvOut", "Track6Bitrate"); SaveEdit(ui->advOutTrack1Name, "AdvOut", "Track1Name"); SaveEdit(ui->advOutTrack2Name, "AdvOut", "Track2Name"); SaveEdit(ui->advOutTrack3Name, "AdvOut", "Track3Name"); SaveEdit(ui->advOutTrack4Name, "AdvOut", "Track4Name"); + SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name"); + SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name"); WriteJsonData(streamEncoderProps, "streamEncoder.json"); WriteJsonData(recordEncoderProps, "recordEncoder.json"); @@ -2635,6 +2727,18 @@ obs_data_release(data); obs_data_array_release(array); } + + if (!main->outputHandler || !main->outputHandler->replayBuffer) + return; + + const char *id = obs_obj_get_id(main->outputHandler->replayBuffer); + if (strcmp(id, "replay_buffer") == 0) { + obs_data_t *hotkeys = obs_hotkeys_save_output( + main->outputHandler->replayBuffer); + config_set_string(config, "Hotkeys", "ReplayBuffer", + obs_data_get_json(hotkeys)); + obs_data_release(hotkeys); + } } #define MINOR_SEPARATOR \ @@ -3134,7 +3238,9 @@ Checked(ui->advOutRecTrack1) + Checked(ui->advOutRecTrack2) + Checked(ui->advOutRecTrack3) + - Checked(ui->advOutRecTrack4); + Checked(ui->advOutRecTrack4) + + Checked(ui->advOutRecTrack5) + + Checked(ui->advOutRecTrack6); const char *objectName = nullptr; if (tracks == 0) { @@ -3192,6 +3298,8 @@ case 2: aBitrateText = ui->advOutTrack2Bitrate->currentText(); break; case 3: aBitrateText = ui->advOutTrack3Bitrate->currentText(); break; case 4: aBitrateText = ui->advOutTrack4Bitrate->currentText(); break; + case 5: aBitrateText = ui->advOutTrack5Bitrate->currentText(); break; + case 6: aBitrateText = ui->advOutTrack6Bitrate->currentText(); break; } int seconds = ui->streamDelaySec->value(); @@ -3291,6 +3399,7 @@ ui->simpleOutRecFormatLabel->setVisible(!losslessQuality); SimpleRecordingEncoderChanged(); + SimpleReplayBufferChanged(); } void OBSBasicSettings::SimpleStreamingEncoderChanged() @@ -3363,6 +3472,39 @@ ui->simpleOutPreset->setCurrentIndex(idx); } +#define ESTIMATE_STR "Basic.Settings.Output.ReplayBuffer.Estimate" +#define ESTIMATE_UNKNOWN_STR \ + "Basic.Settings.Output.ReplayBuffer.EstimateUnknown" + +void OBSBasicSettings::SimpleReplayBufferChanged() +{ + QString qual = ui->simpleOutRecQuality->currentData().toString(); + bool replayBufferEnabled = ui->simpleReplayBuf->isChecked(); + bool lossless = qual == "Lossless"; + bool streamQuality = qual == "Stream"; + + ui->simpleRBMegsMax->setVisible(!streamQuality); + ui->simpleRBMegsMaxLabel->setVisible(!streamQuality); + + int vbitrate = ui->simpleOutputVBitrate->value(); + int abitrate = ui->simpleOutputABitrate->currentText().toInt(); + int seconds = ui->simpleRBSecMax->value(); + + int64_t memMB = int64_t(seconds) * int64_t(vbitrate + abitrate) * + 1000 / 8 / 1024 / 1024; + if (memMB < 1) memMB = 1; + + if (streamQuality) + ui->simpleRBEstimate->setText( + QTStr(ESTIMATE_STR).arg( + QString::number(int(memMB)))); + else + ui->simpleRBEstimate->setText(QTStr(ESTIMATE_UNKNOWN_STR)); + + ui->replayBufferGroupBox->setVisible(!lossless && replayBufferEnabled); + ui->simpleReplayBuf->setVisible(!lossless); +} + #define SIMPLE_OUTPUT_WARNING(str) \ QTStr("Basic.Settings.Output.Simple.Warn." str)
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-settings.hpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-settings.hpp
Changed
@@ -290,6 +290,8 @@ void SimpleRecordingEncoderChanged(); void SimpleRecordingQualityLosslessWarning(int idx); + void SimpleReplayBufferChanged(); + void SimpleStreamingEncoderChanged(); protected:
View file
obs-studio-0.16.6.tar.xz/UI/window-basic-transform.cpp -> obs-studio-0.17.0.tar.xz/UI/window-basic-transform.cpp
Changed
@@ -56,10 +56,10 @@ HookWidget(ui->cropTop, ISCROLL_CHANGED, SLOT(OnCropChanged())); HookWidget(ui->cropBottom, ISCROLL_CHANGED, SLOT(OnCropChanged())); + ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true); + connect(ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(on_resetButton_clicked())); - connect(ui->buttonBox, - SIGNAL(rejected()), this, SLOT(close())); installEventFilter(CreateShortcutFilter());
View file
obs-studio-0.16.6.tar.xz/cmake/osxbundle/fixup_bundle.sh -> obs-studio-0.17.0.tar.xz/cmake/osxbundle/fixup_bundle.sh
Changed
@@ -9,7 +9,9 @@ function buildlist() { otool -L "$@" | - grep -E "(opt|Users)" | + grep -E '^\s+/' | + grep -vE '^\s+/System/' | + grep -vE '^\s+/usr/lib/' | perl -pe 's|^\s+(/.*)\s\(.*$|$1|' | grep -vE ":$" | sort -u @@ -34,6 +36,7 @@ INTOOL_CALL+=(-change "$lib" "$LDEST/$libname") cp "$lib" "$DEST/$libname" + chmod 644 "$DEST/$libname" echo "Fixing up dependency: $libname" done
View file
obs-studio-0.16.6.tar.xz/deps/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/deps/CMakeLists.txt
Changed
@@ -8,6 +8,10 @@ add_subdirectory(libff) add_subdirectory(file-updater) +if(BUILD_CAPTIONS) + add_subdirectory(libcaption) +endif() + find_package(Jansson 2.5 QUIET) if(NOT JANSSON_FOUND)
View file
obs-studio-0.16.6.tar.xz/deps/ipc-util/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/deps/ipc-util/CMakeLists.txt
Changed
@@ -22,6 +22,10 @@ ipc-util/pipe-posix.c) endif() +if(MSVC) + add_compile_options("$<$<CONFIG:RelWithDebInfo>:/MT>") +endif() + add_library(ipc-util STATIC ${ipc-util_SOURCES} ${ipc-util_HEADERS})
View file
obs-studio-0.17.0.tar.xz/deps/libcaption
Added
+(directory)
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/CMakeLists.txt
Added
@@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 2.8) +project(libcaption) +add_definitions(-D__STDC_CONSTANT_MACROS) +if (WIN32) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) +endif() + +# Don't need to prefix local includes with "caption/*" +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/caption) + +set(CAPTION_SOURCES + src/utf8.c + src/srt.c + src/scc.c + src/avc.c + src/xds.c + src/cea708.c + src/caption.c + src/eia608_charmap.c + src/eia608.c +) + +set(CAPTION_HEADERS + caption/utf8.h + caption/sei.h + caption/scc.h + caption/avc.c + caption/cea708.h + caption/eia608.h + caption/caption.h + caption/eia608_charmap.h +) + +add_library(caption STATIC ${CAPTION_SOURCES})
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/Doxyfile.in
Added
@@ -0,0 +1,2406 @@ +# Doxyfile 1.8.11 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "libcaption" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./docs + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include @CMAKE_CURRENT_SOURCE_DIR@/examples + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, +# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.h *.c *.re2c + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/LICENSE.txt
Added
@@ -0,0 +1,21 @@ +The MIT License + +Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/README.md
Added
@@ -0,0 +1,99 @@ +# version +v0.6 +Matthew Szatmary m3u8@twitch.tv / matt@szatmary.org + +# libcaption + +libcaption is a small library written in C to aid in the creating and parsing of closed caption data for use in the twitch player, open sourced to use within community developed broadcast tools. To maintain consistency across platforms libcaption aims to implement a subset of EIA608, CEA708 as supported by the Apple iOS platform. + +608 support is currently limited to encoding and decoding the necessary control and preamble codes as well as support for the Basic North American, Special North American and Extended Western European character sets. + +708 support is limited to encoding the 608 data in NTSC field 1 user data type structure. + +In addition, utility functions to create h.264 SEI (Supplementary enhancement information) NALUs (Network Abstraction Layer Unit) for inclusion into an h.264 elementary stream are provided. + +H.264 utility functions are limited to wrapping the 708 payload into a SEI NALU. This is accomplished by prepending the 708 payload with 3 bytes (nal_unit_type = 6, payloadType = 4, and PayloadSize = variable), and appending a stop bit encoded into a full byte (with a value of 127). In addition if the 708 payload contains an emulated start code, a three byte sequence equaling 0,0,1 an emulation prevention byte (3) is inserted. Functions to reverse this operation are also provided. + +## Characters +| | | | | | | | | | | | | | | | | | +|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +|BNA| |!|"|#|$|%|&|’|(|)|á|+|,|-|.|/| +|BNA|0|1|2|3|4|5|6|7|8|9|:|;|<|=|>|?| +|BNA|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O| +|BNA|P|Q|R|S|T|U|V|W|X|Y|Z|[|é|]|í|ó| +|BNA|ú|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o| +|BNA|p|q|r|s|t|u|v|w|x|y|z|ç|÷|Ñ|ñ|█| +|SNA|®|°|½|¿|™|¢|£|♪|à| |è|â|ê|î|ô|û| +|WES|Á|É|Ó|Ú|Ü|ü|‘|¡|*|'|—|©|℠|•|“|”| +|WEF|À|Â|Ç|È|Ê|Ë|ë|Î|Ï|ï|Ô|Ù|ù|Û|«|»| +|WEP|Ã|ã|Í|Ì|ì|Ò|ò|Õ|õ|{|}|\\|^|_|\||~| +|WEG|Ä|ä|Ö|ö|ß|¥|¤|¦|Å|å|Ø|ø|┌|┐|└|┘| + +* BNA = Basic North American character set +* SNA = Special North American character set +* WES = Extended Western European character set : Extended Spanish/Miscellaneous +* WEF = Extended Western European character set : Extended French +* WEP = Extended Western European character set : Portuguese +* WEG = Extended Western European character set : German/Danish + + +------ +eia608_screen_t is the default internal representation. `screens` can be +converted to and from SEI messages 608/708 buffers and SRT files + +## JSON format +A JSON rendered format is provided for convenience of integration. The JSON +format is as follows: + +``` +{ + "format": "eia608", + "mode": "pop-on", + "roll-up": 0, + "data": [ + { "row":0, "col":0, "char":"A", "style":"white" }, + { "row":0, "col":1, "char":"B", "style":"white" }, + // ... + ] +} +``` + +### `format` +The only current valid value is `"eia608"`. This field exists for +future expansion. Any values other than `"eia608"`, and the object should be +ignored for now. + +### `mode` +Defines the method by which screen contents are adjusted in response to +new data, such as content in excess of the normal grid size. + +Possible modes are: + +`"clear"`: Generated when a screen is initialized, but not entered a "loading" +state. `"clear"` mode occurs frequently when the display is to be erased. + +`"pop-on"`: Normally used for pre recorded content where. A pop-on screen should +completely replace all previous screen contents. + +`"paint-on"`: Normally used for live content. In this mode, new characters +appear one or two at a time. The `data` array does include the complete state of +the screen. In practice, it may not be different that `"pop-on"`. + +An internal "loading" mode also exists. + +### `roll-up` +Normally used for live content such as news broadcasts. Text is moved up the +screen as new rows appear. The number of rows to be displayed is also encoded in +the JSON key `"roll-up"` where value is an integer of `0`, `1`, `2`, `3`, or `4`. +Like `"paint-on"`, the `data` array does include the complete state of the screen. + +### `data` +Contains a object for every character to be displayed. The screen is a grid of +15 rows and 32 columns. The position of the character is available in the `row` +and `col` fields. The character itself is in the `char` field. The full +character set is available in the document, but any valid UTF-8 should be +supported for future. The style field will contain one of the following values: + +`"white"`, `"green"`, `"blue"`, `"cyan"`, `"red"`, `"yellow"`, `"magenta"`, `"italics"` + +Characters with the `"italics"` style should be displayed in white.
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption
Added
+(directory)
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/avc.h
Added
@@ -0,0 +1,198 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_AVC_H +#define LIBCAPTION_AVC_H +#include "cea708.h" +#include "caption.h" +#include <float.h> +//////////////////////////////////////////////////////////////////////////////// +#define MAX_NALU_SIZE (4*1024*1024) +typedef struct { + size_t size; + uint8_t data[MAX_NALU_SIZE]; +} avcnalu_t; + +void avcnalu_init (avcnalu_t* nalu); +int avcnalu_parse_annexb (avcnalu_t* nalu, const uint8_t** data, size_t* size); +static inline uint8_t avcnalu_type (avcnalu_t* nalu) { return nalu->data[0] & 0x1F; } +static inline uint8_t* avcnalu_data (avcnalu_t* nalu) { return &nalu->data[0]; } +static inline size_t avcnalu_size (avcnalu_t* nalu) { return nalu->size; } +//////////////////////////////////////////////////////////////////////////////// +typedef struct _sei_message_t sei_message_t; + +typedef enum { + sei_type_buffering_period = 0, + sei_type_pic_timing = 1, + sei_type_pan_scan_rect = 2, + sei_type_filler_payload = 3, + sei_type_user_data_registered_itu_t_t35 = 4, + sei_type_user_data_unregistered = 5, + sei_type_recovery_point = 6, + sei_type_dec_ref_pic_marking_repetition = 7, + sei_type_spare_pic = 8, + sei_type_scene_info = 9, + sei_type_sub_seq_info = 10, + sei_type_sub_seq_layer_characteristics = 11, + sei_type_sub_seq_characteristics = 12, + sei_type_full_frame_freeze = 13, + sei_type_full_frame_freeze_release = 14, + sei_type_full_frame_snapshot = 15, + sei_type_progressive_refinement_segment_start = 16, + sei_type_progressive_refinement_segment_end = 17, + sei_type_motion_constrained_slice_group_set = 18, + sei_type_film_grain_characteristics = 19, + sei_type_deblocking_filter_display_preference = 20, + sei_type_stereo_video_info = 21, +} sei_msgtype_t; +//////////////////////////////////////////////////////////////////////////////// +// time in seconds +typedef struct { + double dts; + double cts; + sei_message_t* head; + sei_message_t* tail; +} sei_t; + +/*! \brief + \param +*/ +void sei_init (sei_t* sei); +/*! \brief + \param +*/ +void sei_free (sei_t* sei); +/*! \brief + \param +*/ +static inline double sei_dts (sei_t* sei) { return sei->dts; } +static inline double sei_cts (sei_t* sei) { return sei->cts; } +static inline double sei_pts (sei_t* sei) { return sei->dts + sei->cts; } +/*! \brief + \param +*/ +int sei_parse_nalu (sei_t* sei, const uint8_t* data, size_t size, double dts, double cts); +/*! \brief + \param +*/ +// TODO add dts,cts to nalu +static inline int sei_parse_avcnalu (sei_t* sei, avcnalu_t* nalu, double dts, double cts) { return sei_parse_nalu (sei,avcnalu_data (nalu),avcnalu_size (nalu),dts,cts); } +/*! \brief + \param +*/ +static inline int sei_finish (sei_t* sei) { return sei_parse_nalu (sei,0,0,0.0,DBL_MAX); } +/*! \brief + \param +*/ +static inline sei_message_t* sei_message_head (sei_t* sei) { return sei->head; } +/*! \brief + \param +*/ +static inline sei_message_t* sei_message_tail (sei_t* sei) { return sei->tail; } +/*! \brief + \param +*/ +sei_message_t* sei_message_next (sei_message_t* msg); +/*! \brief + \param +*/ +sei_msgtype_t sei_message_type (sei_message_t* msg); +/*! \brief + \param +*/ +size_t sei_message_size (sei_message_t* msg); +/*! \brief + \param +*/ +uint8_t* sei_message_data (sei_message_t* msg); +/*! \brief + \param +*/ +sei_message_t* sei_message_new (sei_msgtype_t type, uint8_t* data, size_t size); +/*! \brief + \param +*/ +static inline sei_message_t* sei_message_copy (sei_message_t* msg) +{ + return sei_message_new (sei_message_type (msg), sei_message_data (msg), sei_message_size (msg)); +} +/** +Free message and all accoiated data. Messaged added to sei_t by using sei_append_message MUST NOT be freed +These messages will be freed by calling sei_free() +*/ +/*! \brief + \param +*/ +void sei_message_free (sei_message_t* msg); +//////////////////////////////////////////////////////////////////////////////// +/*! \brief + \param +*/ +static inline int sei_decode_cea708 (sei_message_t* msg, cea708_t* cea708) +{ + if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) { + return cea708_parse (sei_message_data (msg), sei_message_size (msg), cea708); + } else { + return 0; + } +} +//////////////////////////////////////////////////////////////////////////////// +/*! \brief + \param +*/ +size_t sei_render_size (sei_t* sei); +/*! \brief + \param +*/ +size_t sei_render (sei_t* sei, uint8_t* data); +/*! \brief + \param +*/ +void sei_dump (sei_t* sei); +/*! \brief + \param +*/ +void sei_dump_messages (sei_message_t* head); +//////////////////////////////////////////////////////////////////////////////// +/*! \brief + \param +*/ +int sei_from_caption_frame (sei_t* sei, caption_frame_t* frame); +/*! \brief + \param +*/ +libcaption_stauts_t sei_to_caption_frame (sei_t* sei, caption_frame_t* frame); +/*! \brief + \param +*/ +static inline int nalu_to_caption_frame (caption_frame_t* frame, const uint8_t* data, size_t size, double pts, double dts) +{ + sei_t sei; + sei_init (&sei); + sei_parse_nalu (&sei, data, size, pts, dts); + sei_to_caption_frame (&sei,frame); + sei_free (&sei); + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/caption.h
Added
@@ -0,0 +1,141 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_H +#define LIBCAPTION_H +#include "utf8.h" +#include "xds.h" +#include "eia608.h" + +// ssize_t is POSIX and does not exist on Windows +#if defined(_MSC_VER) +#if defined(_WIN64) +typedef signed long ssize_t; +#else +typedef signed int ssize_t; +#endif +#endif + +typedef enum { + LIBCAPTION_OK = 1, + LIBCAPTION_ERROR = 0, + LIBCAPTION_READY = 2 +} libcaption_stauts_t; + + +/*! \brief + \param +*/ +static inline libcaption_stauts_t libcaption_status_update (libcaption_stauts_t old_stat, libcaption_stauts_t new_stat) { return (LIBCAPTION_ERROR == old_stat || LIBCAPTION_ERROR == new_stat) ? LIBCAPTION_ERROR : (LIBCAPTION_READY == old_stat) ? LIBCAPTION_READY : new_stat; } + +#define SCREEN_ROWS 15 +#define SCREEN_COLS 32 + +typedef struct { + unsigned int uln : 1; //< underline + unsigned int sty : 3; //< style + utf8_char_t data[5]; //< 4 byte utf8 values plus null term +} caption_frame_cell_t; + +typedef struct { + caption_frame_cell_t cell[SCREEN_ROWS][SCREEN_COLS]; +} caption_frame_buffer_t; + + +typedef struct { + unsigned int uln : 1; //< underline + unsigned int sty : 3; //< style + unsigned int mod : 3; //< current mode + unsigned int rup : 2; //< roll-up line count minus 1 + uint16_t row, col, cc_data; +} caption_frame_state_t; + +// timestamp and duration are in seconds +typedef struct { + double timestamp; + double duration; + xds_t xds; + caption_frame_state_t state; + caption_frame_buffer_t front; + caption_frame_buffer_t back; +} caption_frame_t; + +// typedef enum { +// eia608_paint_on = 0, +// eia608_pop_on = 1, +// eia608_rollup_2 = 2, +// eia608_rollup_3 = 3, +// eia608_rollup_4 = 4, +// } eia608_display_mode_t; +// eia608_display_mode_t caption_frame_mode (caption_frame_t* frame); + + +/*! + \brief Initializes an allocated caption_frame_t instance + \param frame Pointer to prealocated caption_frame_t object +*/ +void caption_frame_init (caption_frame_t* frame); +/*! \brief Writes a single charcter to a caption_frame_t object + \param frame A pointer to an allocted and initialized caption_frame_t object + \param row Row position to write charcter, must be between 0 and SCREEN_ROWS-1 + \param col Column position to write charcter, must be between 0 and SCREEN_ROWS-1 + \param style Style to apply to charcter + \param underline Set underline attribute, 0 = off any other value = on + \param c pointer to a single valid utf8 charcter. Bytes are automatically determined, and a NULL terminator is not required +*/ +int caption_frame_write_char (caption_frame_t* frame, int row, int col, eia608_style_t style, int underline, const utf8_char_t* c); +/*! \brief + \param +*/ +const utf8_char_t* caption_frame_read_char (caption_frame_t* frame, int row, int col, eia608_style_t* style, int* underline); +/*! \brief + \param +*/ + +/*! \brief + \param +*/ +libcaption_stauts_t caption_frame_decode (caption_frame_t* frame, uint16_t cc_data, double timestamp); + +/*! \brief + \param +*/ +int caption_frame_from_text (caption_frame_t* frame, const utf8_char_t* data); +/*! \brief + \param +*/ +#define CAPTION_FRAME_TEXT_BYTES (((2+SCREEN_ROWS)*SCREEN_COLS*4)+1) +void caption_frame_to_text (caption_frame_t* frame, utf8_char_t* data); +/*! \brief + \param +*/ +#define CAPTION_FRAME_DUMP_BUF_SIZE 4096 +size_t caption_frame_dump_buffer (caption_frame_t* frame, utf8_char_t* buf); +void caption_frame_dump (caption_frame_t* frame); +/*! \brief + \param +*/ +#define CAPTION_FRAME_JSON_BUF_SIZE 32768 +size_t caption_frame_json (caption_frame_t* frame, utf8_char_t* buf); + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/cea708.h
Added
@@ -0,0 +1,110 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_CEA708_H +#define LIBCAPTION_CEA708_H + +#include "caption.h" +#define CEA608_MAX_SIZE (255) + +//////////////////////////////////////////////////////////////////////////////// +typedef enum { + cc_type_ntsc_cc_field_1 = 0, + cc_type_ntsc_cc_field_2 = 1, + cc_type_dtvcc_packet_data = 2, + cc_type_dtvcc_packet_start = 3, +} cea708_cc_type_t; + +typedef struct { + unsigned int marker_bits : 5; + unsigned int cc_valid : 1; + unsigned int cc_type : 2; // castable to cea708_cc_type_t + unsigned int cc_data : 16; +} cc_data_t; + +typedef struct { + unsigned int process_em_data_flag : 1; + unsigned int process_cc_data_flag : 1; + unsigned int additional_data_flag : 1; + unsigned int cc_count : 5; + unsigned int em_data : 8; + cc_data_t cc_data[32]; +} user_data_t; + +/*! \brief + \param +*/ +cc_data_t cea708_encode_cc_data (int cc_valid, cea708_cc_type_t type, uint16_t cc_data); +/*! \brief + \param +*/ +int cea708_cc_count (user_data_t* data); +/*! \brief + \param +*/ +uint16_t cea708_cc_data (user_data_t* data, int index, int* valid, cea708_cc_type_t* type); +//////////////////////////////////////////////////////////////////////////////// + +typedef enum { + country_united_states = 181, +} itu_t_t35_country_code_t; + +typedef enum { + t35_provider_direct_tv = 47, + t35_provider_atsc = 49, +} itu_t_t35_provider_code_t; + +typedef struct { + itu_t_t35_country_code_t country; + itu_t_t35_provider_code_t provider; + uint32_t user_identifier; + uint8_t atsc1_data_user_data_type_code; + uint8_t directv_user_data_length; + user_data_t user_data; +} cea708_t; + +/*! \brief + \param +*/ +int cea708_init (cea708_t* cea708); // will confgure using HLS compatiable defaults +/*! \brief + \param +*/ +int cea708_parse (uint8_t* data, size_t size, cea708_t* cea708); +/*! \brief + \param +*/ +libcaption_stauts_t cea708_to_caption_frame (caption_frame_t* frame, cea708_t* cea708, double pts); +/*! \brief + \param +*/ +int cea708_add_cc_data (cea708_t* cea708, int valid, cea708_cc_type_t type, uint16_t cc_data); +/*! \brief + \param +*/ +int cea708_render (cea708_t* cea708, uint8_t* data, size_t size); +/*! \brief + \param +*/ +void cea708_dump (cea708_t* cea708); +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/eia608.h
Added
@@ -0,0 +1,206 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_EIA608_H +#define LIBCAPTION_EIA608_H + +#include "utf8.h" +#include "eia608_charmap.h" +//////////////////////////////////////////////////////////////////////////////// +// Parity +#define EIA608_BX(B,X) (((B)>>X)&0x01) +#define EIA608_BP(B) ((B)&0x7F) | ((EIA608_BX((B),0)^EIA608_BX(B,1)^EIA608_BX((B),2)^EIA608_BX((B),3)^EIA608_BX((B),4)^EIA608_BX((B),5)^EIA608_BX((B),6)^(0x01))<<7) +#define EIA608_B2(B) EIA608_BP((B)+0), EIA608_BP((B)+1), EIA608_BP((B)+2), EIA608_BP((B)+3), EIA608_BP((B)+4), EIA608_BP((B)+5), EIA608_BP((B)+6), EIA608_BP((B)+7) +#define EIA608_B1(B) EIA608_B2((B)+0), EIA608_B2((B)+8), EIA608_B2((B)+16), EIA608_B2((B)+24), EIA608_B2((B)+32), EIA608_B2((B)+40), EIA608_B2((B)+48), EIA608_B2((B)+56) + +static const uint8_t eia608_parity_table[] = { EIA608_B1 (0), EIA608_B1 (64) }; +extern const char* eia608_mode_map[]; +extern const char* eia608_style_map[]; + +#ifdef _MSC_VER +#ifndef inline +#define inline __inline +#endif +#endif + +/*! \brief + \param +*/ +static inline uint8_t eia608_parity_byte (uint8_t cc_data) { return eia608_parity_table[0x7F & cc_data]; } +/*! \brief + \param +*/ +static inline uint16_t eia608_parity_word (uint16_t cc_data) { return (uint16_t) ( (eia608_parity_byte ( (uint8_t) (cc_data>>8)) <<8) | eia608_parity_byte ( (uint8_t) cc_data)); } +/*! \brief + \param +*/ +static inline uint16_t eia608_parity (uint16_t cc_data) { return eia608_parity_word (cc_data); } +/*! \brief + \param +*/ +static inline int eia608_parity_varify (uint16_t cc_data) { return eia608_parity_word (cc_data) == cc_data ? 1 : 0; } +/*! \brief + \param +*/ +static inline int eia608_parity_strip (uint16_t cc_data) { return cc_data & 0x7F7F; } +/*! \brief + \param +*/ +static inline int eia608_test_second_channel_bit (uint16_t cc_data) { return (cc_data & 0x0800); } + +//////////////////////////////////////////////////////////////////////////////// +// cc_data types +/*! \brief + \param +*/ +static inline int eia608_is_basicna (uint16_t cc_data) { return 0x0000 != (0x6000 & cc_data); /*&& 0x1F00 < (0x7F00 & cc_data);*/ } +/*! \brief + \param +*/ +static inline int eia608_is_preamble (uint16_t cc_data) { return 0x1040 == (0x7040 & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_midrowchange (uint16_t cc_data) { return 0x1120 == (0x7770 & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_specialna (uint16_t cc_data) { return 0x1130 == (0x7770 & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_xds (uint16_t cc_data) { return 0x0000 == (0x7070 & cc_data) && 0x0000 != (0x0F0F & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_westeu (uint16_t cc_data) { return 0x1220 == (0x7660 & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_control (uint16_t cc_data) { return 0x1420 == (0x7670 & cc_data) || 0x1720 == (0x7770 & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_norpak (uint16_t cc_data) { return 0x1724 == (0x777C & cc_data) || 0x1728 == (0x777C & cc_data); } +/*! \brief + \param +*/ +static inline int eia608_is_padding (uint16_t cc_data) { return 0x8080 == cc_data; } + +//////////////////////////////////////////////////////////////////////////////// +// preamble +typedef enum { + eia608_style_white = 0, + eia608_style_green = 1, + eia608_style_blue = 2, + eia608_style_cyan = 3, + eia608_style_red = 4, + eia608_style_yellow = 5, + eia608_style_magenta = 6, + eia608_style_italics = 7, +} eia608_style_t; + +/*! \brief + \param +*/ +int eia608_parse_preamble (uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline); +/*! \brief + \param +*/ +int eia608_parse_midrowchange (uint16_t cc_data, int* chan, eia608_style_t* style, int* underline); +/*! \brief + \param +*/ +uint16_t eia608_row_column_pramble (int row, int col, int chan, int underline); +/*! \brief + \param +*/ +uint16_t eia608_row_style_pramble (int row, eia608_style_t style, int chan, int underline); + +//////////////////////////////////////////////////////////////////////////////// +// control command +typedef enum { // yes, no? + eia608_tab_offset_0 = 0x1720, + eia608_tab_offset_1 = 0x1721, + eia608_tab_offset_2 = 0x1722, + eia608_tab_offset_3 = 0x1723, + eia608_control_resume_caption_loading = 0x1420, + eia608_control_backspace = 0x1421, + eia608_control_alarm_off = 0x1422, + eia608_control_alarm_on = 0x1423, + eia608_control_delete_to_end_of_row = 0x1424, + eia608_control_roll_up_2 = 0x1425, + eia608_control_roll_up_3 = 0x1426, + eia608_control_roll_up_4 = 0x1427, + eia608_control_resume_direct_captioning = 0x1429, + eia608_control_text_restart = 0x142A, + eia608_control_text_resume_text_display = 0x142B, + eia608_control_erase_display_memory = 0x142C, + eia608_control_carriage_return = 0x142D, + eia608_control_erase_non_displayed_memory = 0x142E, + eia608_control_end_of_caption = 0x142F, +} eia608_control_t; + +#define eia608_control_popon eia608_control_resume_caption_loading +#define eia608_control_painton eia608_control_resume_direct_captioning + +/*! \brief + \param +*/ +uint16_t eia608_control_command (eia608_control_t cmd, int cc); +/*! \brief + \param +*/ +static inline uint16_t eia608_tab (int size, int cc) { return eia608_control_command ( (eia608_control_t) (eia608_tab_offset_0 | (size&0x0F)),cc); } +/*! \brief + \param +*/ +eia608_control_t eia608_parse_control (uint16_t cc_data, int* cc); + +//////////////////////////////////////////////////////////////////////////////// +// text +/*! \brief + \param c +*/ +uint16_t eia608_from_utf8_1 (const utf8_char_t* c, int chan); +/*! \brief + \param +*/ +uint16_t eia608_from_utf8_2 (const utf8_char_t* c1, const utf8_char_t* c2); +/*! \brief + \param +*/ +uint16_t eia608_from_basicna (uint16_t bna1, uint16_t bna2); +/*! \brief + \param +*/ +int eia608_to_utf8 (uint16_t c, int* chan, utf8_char_t* char1, utf8_char_t* char2); +//////////////////////////////////////////////////////////////////////////////// +/*! \brief + \param +*/ +void eia608_dump (uint16_t cc_data); +//////////////////////////////////////////////////////////////////////////////// + + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/eia608_charmap.h
Added
@@ -0,0 +1,230 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_EIA608_CHARMAP_H +#define LIBCAPTION_EIA608_CHARMAP_H + +#define EIA608_CHAR_COUNT 176 +extern const char* eia608_char_map[EIA608_CHAR_COUNT]; + +// Helper char +#define EIA608_CHAR_NULL "" +// Basic North American character set +#define EIA608_CHAR_SPACE "\x20" +#define EIA608_CHAR_EXCLAMATION_MARK "\x21" +#define EIA608_CHAR_QUOTATION_MARK "\x22" +#define EIA608_CHAR_NUMBER_SIGN "\x23" +#define EIA608_CHAR_DOLLAR_SIGN "\x24" +#define EIA608_CHAR_PERCENT_SIGN "\x25" +#define EIA608_CHAR_AMPERSAND "\x26" +#define EIA608_CHAR_LEFT_SINGLE_QUOTATION_MARK "\xE2\x80\x98" +#define EIA608_CHAR_LEFT_PARENTHESIS "\x28" +#define EIA608_CHAR_RIGHT_PARENTHESIS "\x29" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_ACUTE "\xC3\xA1" +#define EIA608_CHAR_PLUS_SIGN "\x2B" +#define EIA608_CHAR_COMMA "\x2C" +#define EIA608_CHAR_HYPHEN_MINUS "\x2D" +#define EIA608_CHAR_FULL_STOP "\x2E" +#define EIA608_CHAR_SOLIDUS "\x2F" + +// Basic North American character set +#define EIA608_CHAR_DIGIT_ZERO "\x30" +#define EIA608_CHAR_DIGIT_ONE "\x31" +#define EIA608_CHAR_DIGIT_TWO "\x32" +#define EIA608_CHAR_DIGIT_THREE "\x33" +#define EIA608_CHAR_DIGIT_FOUR "\x34" +#define EIA608_CHAR_DIGIT_FIVE "\x35" +#define EIA608_CHAR_DIGIT_SIX "\x36" +#define EIA608_CHAR_DIGIT_SEVEN "\x37" +#define EIA608_CHAR_DIGIT_EIGHT "\x38" +#define EIA608_CHAR_DIGIT_NINE "\x39" +#define EIA608_CHAR_COLON "\x3A" +#define EIA608_CHAR_SEMICOLON "\x3B" +#define EIA608_CHAR_LESS_THAN_SIGN "\x3C" +#define EIA608_CHAR_EQUALS_SIGN "\x3D" +#define EIA608_CHAR_GREATER_THAN_SIGN "\x3E" +#define EIA608_CHAR_QUESTION_MARK "\x3F" + +// Basic North American character set +#define EIA608_CHAR_COMMERCIAL_AT "\x40" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A "\x41" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_B "\x42" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_C "\x43" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_D "\x44" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E "\x45" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_F "\x46" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_G "\x47" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_H "\x48" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I "\x49" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_J "\x4A" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_K "\x4B" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_L "\x4C" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_M "\x4D" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_N "\x4E" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O "\x4F" + +// Basic North American character set +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_P "\x50" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_Q "\x51" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_R "\x52" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_S "\x53" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_T "\x54" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U "\x55" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_V "\x56" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_W "\x57" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_X "\x58" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_Y "\x59" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_Z "\x5A" +#define EIA608_CHAR_LEFT_SQUARE_BRACKET "\x5B" +#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_ACUTE "\xC3\xA9" +#define EIA608_CHAR_RIGHT_SQUARE_BRACKET "\x5D" +#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_ACUTE "\xC3\xAD" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_ACUTE "\xC3\xB3" + +// Basic North American character set +#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_ACUTE "\xC3\xBA" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A "\x61" +#define EIA608_CHAR_LATIN_SMALL_LETTER_B "\x62" +#define EIA608_CHAR_LATIN_SMALL_LETTER_C "\x63" +#define EIA608_CHAR_LATIN_SMALL_LETTER_D "\x64" +#define EIA608_CHAR_LATIN_SMALL_LETTER_E "\x65" +#define EIA608_CHAR_LATIN_SMALL_LETTER_F "\x66" +#define EIA608_CHAR_LATIN_SMALL_LETTER_G "\x67" +#define EIA608_CHAR_LATIN_SMALL_LETTER_H "\x68" +#define EIA608_CHAR_LATIN_SMALL_LETTER_I "\x69" +#define EIA608_CHAR_LATIN_SMALL_LETTER_J "\x6A" +#define EIA608_CHAR_LATIN_SMALL_LETTER_K "\x6B" +#define EIA608_CHAR_LATIN_SMALL_LETTER_L "\x6C" +#define EIA608_CHAR_LATIN_SMALL_LETTER_M "\x6D" +#define EIA608_CHAR_LATIN_SMALL_LETTER_N "\x6E" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O "\x6F" + +// Basic North American character set +#define EIA608_CHAR_LATIN_SMALL_LETTER_P "\x70" +#define EIA608_CHAR_LATIN_SMALL_LETTER_Q "\x71" +#define EIA608_CHAR_LATIN_SMALL_LETTER_R "\x72" +#define EIA608_CHAR_LATIN_SMALL_LETTER_S "\x73" +#define EIA608_CHAR_LATIN_SMALL_LETTER_T "\x74" +#define EIA608_CHAR_LATIN_SMALL_LETTER_U "\x75" +#define EIA608_CHAR_LATIN_SMALL_LETTER_V "\x76" +#define EIA608_CHAR_LATIN_SMALL_LETTER_W "\x77" +#define EIA608_CHAR_LATIN_SMALL_LETTER_X "\x78" +#define EIA608_CHAR_LATIN_SMALL_LETTER_Y "\x79" +#define EIA608_CHAR_LATIN_SMALL_LETTER_Z "\x7A" +#define EIA608_CHAR_LATIN_SMALL_LETTER_C_WITH_CEDILLA "\xC3\xA7" +#define EIA608_CHAR_DIVISION_SIGN "\xC3\xB7" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_N_WITH_TILDE "\xC3\x91" +#define EIA608_CHAR_LATIN_SMALL_LETTER_N_WITH_TILDE "\xC3\xB1" +#define EIA608_CHAR_FULL_BLOCK "\xE2\x96\x88" + +// Special North American character set[edit] +#define EIA608_CHAR_REGISTERED_SIGN "\xC2\xAE" +#define EIA608_CHAR_DEGREE_SIGN "\xC2\xB0" +#define EIA608_CHAR_VULGAR_FRACTION_ONE_HALF "\xC2\xBD" +#define EIA608_CHAR_INVERTED_QUESTION_MARK "\xC2\xBF" +#define EIA608_CHAR_TRADE_MARK_SIGN "\xE2\x84\xA2" +#define EIA608_CHAR_CENT_SIGN "\xC2\xA2" +#define EIA608_CHAR_POUND_SIGN "\xC2\xA3" +#define EIA608_CHAR_EIGHTH_NOTE "\xE2\x99\xAA" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_GRAVE "\xC3\xA0" +#define EIA608_CHAR_NO_BREAK_SPACE "\xC2\xA0" +#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_GRAVE "\xC3\xA8" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX "\xC3\xA2" +#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX "\xC3\xAA" +#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX "\xC3\xAE" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX "\xC3\xB4" +#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX "\xC3\xBB" + +// Extended Western European character set : Extended Spanish/Miscellaneous +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_ACUTE "\xC3\x81" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_ACUTE "\xC3\x89" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_ACUTE "\xC3\x93" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_ACUTE "\xC3\x9A" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS "\xC3\x9C" +#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_DIAERESIS "\xC3\xBC" +#define EIA608_CHAR_RIGHT_SINGLE_QUOTATION_MARK "\xE2\x80\x99" +#define EIA608_CHAR_INVERTED_EXCLAMATION_MARK "\xC2\xA1" +#define EIA608_CHAR_ASTERISK "\x2A" +#define EIA608_CHAR_APOSTROPHE "\x27" +#define EIA608_CHAR_EM_DASH "\xE2\x80\x94" +#define EIA608_CHAR_COPYRIGHT_SIGN "\xC2\xA9" +#define EIA608_CHAR_SERVICE_MARK "\xE2\x84\xA0" +#define EIA608_CHAR_BULLET "\xE2\x80\xA2" +#define EIA608_CHAR_LEFT_DOUBLE_QUOTATION_MARK "\xE2\x80\x9C" +#define EIA608_CHAR_RIGHT_DOUBLE_QUOTATION_MARK "\xE2\x80\x9D" + +// Extended Western European character set : Extended French +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_GRAVE "\xC3\x80" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX "\xC3\x82" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA "\xC3\x87" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_GRAVE "\xC3\x88" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX "\xC3\x8A" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS "\xC3\x8B" +#define EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_DIAERESIS "\xC3\xAB" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX "\xC3\x8E" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS "\xC3\x8F" +#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_DIAERESIS "\xC3\xAF" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX "\xC3\x94" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_GRAVE "\xC3\x99" +#define EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_GRAVE "\xC3\xB9" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX "\xC3\x9B" +#define EIA608_CHAR_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK "\xC2\xAB" +#define EIA608_CHAR_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK "\xC2\xBB" + +// Extended Western European character set : Portuguese +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_TILDE "\xC3\x83" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_TILDE "\xC3\xA3" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_ACUTE "\xC3\x8D" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_GRAVE "\xC3\x8C" +#define EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_GRAVE "\xC3\xAC" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_GRAVE "\xC3\x92" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_GRAVE "\xC3\xB2" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_TILDE "\xC3\x95" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_TILDE "\xC3\xB5" +#define EIA608_CHAR_LEFT_CURLY_BRACKET "\x7B" +#define EIA608_CHAR_RIGHT_CURLY_BRACKET "\x7D" +#define EIA608_CHAR_REVERSE_SOLIDUS "\x5C" +#define EIA608_CHAR_CIRCUMFLEX_ACCENT "\x5E" +#define EIA608_CHAR_LOW_LINE "\x5F" +#define EIA608_CHAR_VERTICAL_LINE "\x7C" +#define EIA608_CHAR_TILDE "\x7E" + +// Extended Western European character set : German/Danish +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS "\xC3\x84" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_DIAERESIS "\xC3\xA4" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS "\xC3\x96" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_DIAERESIS "\xC3\xB6" +#define EIA608_CHAR_LATIN_SMALL_LETTER_SHARP_S "\xC3\x9F" +#define EIA608_CHAR_YEN_SIGN "\xC2\xA5" +#define EIA608_CHAR_CURRENCY_SIGN "\xC2\xA4" +#define EIA608_CHAR_BROKEN_BAR "\xC2\xA6" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE "\xC3\x85" +#define EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE "\xC3\xA5" +#define EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_STROKE "\xC3\x98" +#define EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_STROKE "\xC3\xB8" +#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT "\xE2\x94\x8C" // top left +#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT "\xE2\x94\x90" // top right +#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT "\xE2\x94\x94" // lower left +#define EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT "\xE2\x94\x98" // bottom right + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/scc.h
Added
@@ -0,0 +1,31 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_SCC_H +#define LIBCAPTION_SCC_H + +#include "eia608.h" + +int scc_to_608 (const char* line, double* pts, uint16_t* cc, int cc_max); + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/srt.h
Added
@@ -0,0 +1,87 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_SRT_H +#define LIBCAPTION_SRT_H + +#include "eia608.h" +#include "caption.h" + +// timestamp and duration are in seconds +typedef struct _srt_t { + struct _srt_t* next; + double timestamp; + double duration; + size_t aloc; +} srt_t; + + + + +/*! \brief + \param +*/ +srt_t* srt_new (const utf8_char_t* data, size_t size, double timestamp, srt_t* prev, srt_t** head); +/*! \brief + \param +*/ +srt_t* srt_free_head (srt_t* head); +// returns the head of the link list. must bee freed when done +/*! \brief + \param +*/ +srt_t* srt_parse (const utf8_char_t* data, size_t size); +/*! \brief + \param +*/ +void srt_free (srt_t* srt); + +/*! \brief + \param +*/ +static inline srt_t* srt_next (srt_t* srt) { return srt->next; } +/*! \brief + \param +*/ +static inline utf8_char_t* srt_data (srt_t* srt) { return (utf8_char_t*) (srt) + sizeof (srt_t); } +// This only converts teh surrent SRT, It does not walk the list +/*! \brief + \param +*/ +int srt_to_caption_frame (srt_t* srt, caption_frame_t* frame); + +// returns teh new srt. Head is not tracher internally. +/*! \brief + \param +*/ +srt_t* srt_from_caption_frame (caption_frame_t* frame, srt_t* prev, srt_t** head); +/*! \brief + \param +*/ +void srt_dump (srt_t* srt); +/*! \brief + \param +*/ +void vtt_dump (srt_t* srt); + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/utf8.h
Added
@@ -0,0 +1,97 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_UTF8_H +#define LIBCAPTION_UTF8_H + +#include <stddef.h> +#include <inttypes.h> + +// These types exist to make the code more self dcoumenting +// utf8_char_t point is a null teminate string of utf8 encodecd chars +// +// utf8_size_t is the length of a string in chars +// size_t is bytes +typedef char utf8_char_t; +typedef size_t utf8_size_t; +/*! \brief + \param + + Skiped continuation bytes +*/ +const utf8_char_t* utf8_char_next (const char* s); +/*! \brief + \param + + returnes the length of the char in bytes +*/ +size_t utf8_char_length (const utf8_char_t* c); + +/*! \brief + \param + + returns length of the string in bytes + size is number of charcter to count (0 to count until NULL term) +*/ +size_t utf8_string_length (const utf8_char_t* data, utf8_size_t size); +/*! \brief + \param +*/ +size_t utf8_char_copy (utf8_char_t* dst, const utf8_char_t* src); + +/*! \brief + \param + + returnes the number of utf8 charcters in a string givne the numbe of bytes + to coutn until the a null terminator, pass 0 for size +*/ +utf8_size_t utf8_char_count (const char* data, size_t size); +/*! \brief + \param + + returnes the length of the line in bytes triming not printable charcters at the end +*/ +size_t utf8_trimmed_length (const char* data, size_t size); +/*! \brief + \param + + returns the length in bytes of the line including the new line charcter(s) + auto detects between windows(CRLF), unix(LF), mac(CR) and riscos (LFCR) line endings +*/ +size_t utf8_line_length (const char* data); +/*! \brief + \param + + returns number of chars to include before split +*/ +utf8_size_t utf8_wrap_length (const utf8_char_t* data, utf8_size_t size); + +/*! \brief + \param + + returns number of new lins in teh string +*/ +int utf8_line_count (const utf8_char_t* data); + + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/caption/xds.h
Added
@@ -0,0 +1,32 @@ +/**********************************************************************************************/ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file */ +/* except in compliance with the License. A copy of the License is located at */ +/* */ +/* http://aws.amazon.com/apache2.0/ */ +/* */ +/* or in the "license" file accompanying this file. This file is distributed on an "AS IS" */ +/* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the */ +/* License for the specific language governing permissions and limitations under the License. */ +/**********************************************************************************************/ + +#ifndef LIBCAPTION_XDS_H +#define LIBCAPTION_XDS_H + +#include <stddef.h> +#include <inttypes.h> + +typedef struct { + int state; + uint8_t class; + uint8_t type; + uint32_t size; + uint8_t content[32]; + uint8_t checksum; +} xds_t; + +void xds_init (xds_t* xds); +int xds_decode (xds_t* xds, uint16_t cc); + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples
Added
+(directory)
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/add_captions.sh
Added
@@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +if [ $# -lt 2 ] +then + echo "Need at least 2 arguments." + echo "$0 InputVideo InputSRT [OutputFilename]" + exit 1 +fi + +VIDEO=$1 +SRT=$2 + +if [ -z "$3" ] +then + OUTFILE="out.flv" +else + OUTFILE="$3" +fi + +echo "Video=$VIDEO" +echo "Captions=$SRT" +echo "Outfile=$OUTFILE" + +# ffmpeg -i $VIDEO -acodec copy -vcodec copy -f flv - | ./flv+srt - $SRT - | ffmpeg -i - -acodec copy -vcodec copy $OUTFILE +ffmpeg -i $VIDEO -threads 0 -vcodec libx264 -profile:v main -preset:v medium \ +-r 30 -g 60 -keyint_min 60 -sc_threshold 0 -b:v 4000k -maxrate 4000k \ +-bufsize 4000k -filter:v scale="trunc(oh*a/2)*2:720" \ +-sws_flags lanczos+accurate_rnd -strict -2 -acodec aac -b:a 96k -ar 48000 -ac 2 \ +-f flv - | ./flv+srt - $SRT - | ffmpeg -i - -acodec copy -vcodec copy -y $OUTFILE
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/captioner.c
Added
@@ -0,0 +1,117 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <linux/input.h> +#include <string.h> +#include <stdio.h> +#include "caption.h" +#include "flv.h" + +char charcode[] = { + 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, 0, + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']','\n', 0, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', 0, '\\', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, +}; + +int data_ready (int fd) +{ + fd_set set; + struct timeval timeout = {0,0}; + FD_ZERO (&set); + FD_SET (fd,&set); + int cnt = select (fd+1, &set, 0, 0, &timeout); + FD_ZERO (&set); + return (0 < cnt); +} + +#define MAX_CAP_LENGTH (SCREEN_ROWS*SCREEN_COLS) +int main (int argc, char** argv) +{ + int fd; + ssize_t n; + flvtag_t tag; + struct input_event ev; + int has_audio, has_video; + const char* dev = argv[1]; + char text[MAX_CAP_LENGTH+1]; + memset (text,0,MAX_CAP_LENGTH+1); + + FILE* flv = flv_open_read ("-"); + FILE* out = flv_open_write ("-"); + fd = open (dev, O_RDONLY); + + if (fd == -1) { + fprintf (stderr, "Cannot open %s: %s.\n", dev, strerror (errno)); + return EXIT_FAILURE; + } + + if (!flv_read_header (flv,&has_audio,&has_video)) { + fprintf (stderr,"%s is not an flv file\n", argv[1]); + return EXIT_FAILURE; + } + + if (!flv_write_header (out,has_audio,has_video)) { + return EXIT_FAILURE; + } + + flvtag_init (&tag); + + while (flv_read_tag (flv,&tag)) { + if (flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag)) { + if (data_ready (fd)) { + n = read (fd, &ev, sizeof ev); + + if (n == (ssize_t)-1) { + if (errno == EINTR) { + continue; + } else { + break; + } + } else if (n != sizeof ev) { + errno = EIO; + break; + } + + int len = strlen (text); + char c = (EV_KEY == ev.type && 1 == ev.value && ev.code < 64) ? charcode[ev.code] : 0; + + if (0 < len && '\n' == c) { + fprintf (stderr,"='%s'\n", text); + flvtag_addcaption (&tag, text); + memset (text,0,MAX_CAP_LENGTH+1); + } else if (0 != c && len < MAX_CAP_LENGTH) { + text[len] = c; + } + } + } + + flv_write_tag (out,&tag); + } + + return EXIT_SUCCESS; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/flv+scc.c
Added
@@ -0,0 +1,23 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/flv+srt.c
Added
@@ -0,0 +1,96 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "srt.h" +#include "flv.h" +#include "avc.h" +// #include "sei.h" + +#define MAX_SRT_SIZE (10*1024*1024) +#define MAX_READ_SIZE 4096 + +srt_t* srt_from_file (const char* path) +{ + srt_t* head = 0; + size_t read, totl = 0; + FILE* file = fopen (path,"r"); + + if (file) { + char* srt_data = malloc (MAX_SRT_SIZE); + size_t srt_size = 0; + size_t size = MAX_SRT_SIZE; + char* data = srt_data; + + while (0 < (read = fread (data,1,size,file))) { + totl += read; data += read; size -= read; srt_size += read; + } + + head = srt_parse (srt_data,srt_size); + free (srt_data); + } + + return head; +} + +int main (int argc, char** argv) +{ + flvtag_t tag; + FILE* flv = flv_open_read (argv[1]); + FILE* out = flv_open_write (argv[3]); + + int has_audio, has_video; + flvtag_init (&tag); + + if (!flv_read_header (flv,&has_audio,&has_video)) { + fprintf (stderr,"%s is not an flv file\n", argv[1]); + return EXIT_FAILURE; + } + + srt_t* head = srt_from_file (argv[2]); + srt_t* srt = head; + + if (! head) { + fprintf (stderr,"%s is not an srt file\n", argv[2]); + return EXIT_FAILURE; + } + + flv_write_header (out,has_audio,has_video); + + while (flv_read_tag (flv,&tag)) { + // TODO handle B freame! + if (srt && flvtag_pts_seconds (&tag) >= srt->timestamp && flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag)) { + fprintf (stderr,"%f: %s\n", srt->timestamp, srt_data (srt)); + flvtag_addcaption (&tag, srt_data (srt)); + srt = srt->next; + } + + flv_write_tag (out,&tag); + // Write tag out here + } + + srt_free (head); + return EXIT_SUCCESS; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/flv.c
Added
@@ -0,0 +1,383 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "flv.h" +#include <stdlib.h> +#include <string.h> + +void flvtag_init (flvtag_t* tag) +{ + memset (tag,0,sizeof (flvtag_t)); +} + +void flvtag_free (flvtag_t* tag) +{ + if (tag->data) { + free (tag->data); + } + + flvtag_init (tag); +} + +int flvtag_reserve (flvtag_t* tag, uint32_t size) +{ + size += FLV_TAG_HEADER_SIZE + FLV_TAG_FOOTER_SIZE; + + if (size > tag->aloc) { + tag->data = realloc (tag->data,size); + tag->aloc = size; + } + + return 1; +} + +FILE* flv_open_read (const char* flv) +{ + if (0 == flv || 0 == strcmp ("-",flv)) { + return stdin; + } + + return fopen (flv,"rb"); +} + +FILE* flv_open_write (const char* flv) +{ + if (0 == flv || 0 == strcmp ("-",flv)) { + return stdout; + } + + return fopen (flv,"wb"); +} + +FILE* flv_close (FILE* flv) +{ + fclose (flv); + return 0; +} + +int flv_read_header (FILE* flv, int* has_audio, int* has_video) +{ + uint8_t h[FLV_HEADER_SIZE]; + + if (FLV_HEADER_SIZE != fread (&h[0],1,FLV_HEADER_SIZE,flv)) { + return 0; + } + + if ('F' != h[0] || 'L' != h[1] || 'V' != h[2]) { + return 0; + } + + (*has_audio) = h[4]&0x04; + (*has_video) = h[4]&0x01; + return 1; +} + +int flv_write_header (FILE* flv, int has_audio, int has_video) +{ + uint8_t h[FLV_HEADER_SIZE] = {'F', 'L', 'V', 1, (has_audio?0x04:0x00) | (has_video?0x01:0x00), 0, 0, 0, 9, 0, 0, 0, 0 }; + return FLV_HEADER_SIZE == fwrite (&h[0],1,FLV_HEADER_SIZE,flv); +} + +int flv_read_tag (FILE* flv, flvtag_t* tag) +{ + uint32_t size; + uint8_t h[FLV_TAG_HEADER_SIZE]; + + if (FLV_TAG_HEADER_SIZE != fread (&h[0],1,FLV_TAG_HEADER_SIZE,flv)) { + return 0; + } + + size = ( (h[1]<<16) | (h[2]<<8) |h[3]); + flvtag_reserve (tag, size); + // copy header to buffer + memcpy (tag->data,&h[0],FLV_TAG_HEADER_SIZE); + + if (size+FLV_TAG_FOOTER_SIZE != fread (&tag->data[FLV_TAG_HEADER_SIZE],1,size+FLV_TAG_FOOTER_SIZE,flv)) { + return 0; + } + + return 1; +} + +int flv_write_tag (FILE* flv, flvtag_t* tag) +{ + size_t size = flvtag_raw_size (tag); + return size == fwrite (flvtag_raw_data (tag),1,size,flv); +} +//////////////////////////////////////////////////////////////////////////////// +size_t flvtag_header_size (flvtag_t* tag) +{ + switch (flvtag_type (tag)) { + case flvtag_type_audio: + return FLV_TAG_HEADER_SIZE + (flvtag_soundformat_aac != flvtag_soundformat (tag) ? 1 : 2); + + case flvtag_type_video: + // CommandFrame does not have a compositionTime + return FLV_TAG_HEADER_SIZE + (flvtag_codecid_avc != flvtag_codecid (tag) ? 1 : (flvtag_frametype_commandframe != flvtag_frametype (tag) ? 5 : 2)); + + default: + return FLV_TAG_HEADER_SIZE; + } +} + +size_t flvtag_payload_size (flvtag_t* tag) +{ + return FLV_TAG_HEADER_SIZE + flvtag_size (tag) - flvtag_header_size (tag); +} + +uint8_t* flvtag_payload_data (flvtag_t* tag) +{ + size_t payload_offset = flvtag_header_size (tag); + return &tag->data[payload_offset]; +} +//////////////////////////////////////////////////////////////////////////////// +int flvtag_updatesize (flvtag_t* tag, uint32_t size) +{ + tag->data[1] = size>>16; // DataSize + tag->data[2] = size>>8; // DataSize + tag->data[3] = size>>0; // DataSize + size += 11; + tag->data[size+0] = size>>24; // PrevTagSize + tag->data[size+1] = size>>16; // PrevTagSize + tag->data[size+2] = size>>8; // PrevTagSize + tag->data[size+3] = size>>0; // PrevTagSize + return 1; +} + +#define FLVTAG_PREALOC 2048 +int flvtag_initavc (flvtag_t* tag, uint32_t dts, int32_t cts, flvtag_frametype_t type) +{ + flvtag_init (tag); + flvtag_reserve (tag,5+FLVTAG_PREALOC); + tag->data[0] = flvtag_type_video; + tag->data[4] = dts>>16; + tag->data[5] = dts>>8; + tag->data[6] = dts>>0; + tag->data[7] = dts>>24; + tag->data[8] = 0; // StreamID + tag->data[9] = 0; // StreamID + tag->data[10] = 0; // StreamID + // VideoTagHeader + tag->data[11] = ( (type<<4) %0xF0) |0x07; // CodecId + tag->data[12] = 0x01; // AVC NALU + tag->data[13] = cts>>16; + tag->data[14] = cts>>8; + tag->data[15] = cts>>0; + flvtag_updatesize (tag,5); + return 1; +} + +int flvtag_initamf (flvtag_t* tag, uint32_t dts) +{ + flvtag_init (tag); + flvtag_reserve (tag,FLVTAG_PREALOC); + tag->data[0] = flvtag_type_scriptdata; + tag->data[4] = dts>>16; + tag->data[5] = dts>>8; + tag->data[6] = dts>>0; + tag->data[7] = dts>>24; + tag->data[8] = 0; // StreamID + tag->data[9] = 0; // StreamID + tag->data[10] = 0; // StreamID + flvtag_updatesize (tag,0); + return 1; +} + +// shamelessly taken from libtomcrypt, an public domain project +static void base64_encode (const unsigned char* in, unsigned long inlen, unsigned char* out, unsigned long* outlen) +{ + static const char* codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned long i, len2, leven; + unsigned char* p; + + /* valid output size ? */ + len2 = 4 * ( (inlen + 2) / 3); + + if (*outlen < len2 + 1) { + *outlen = len2 + 1; + fprintf (stderr,"\n\nHERE\n\n"); + return; + } + + p = out; + leven = 3* (inlen / 3); + + for (i = 0; i < leven; i += 3) { + *p++ = codes[ (in[0] >> 2) & 0x3F]; + *p++ = codes[ ( ( (in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F]; + *p++ = codes[ ( ( (in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F]; + *p++ = codes[in[2] & 0x3F]; + in += 3; + } + + if (i < inlen) { + unsigned a = in[0]; + unsigned b = (i+1 < inlen) ? in[1] : 0; + + *p++ = codes[ (a >> 2) & 0x3F]; + *p++ = codes[ ( ( (a & 3) << 4) + (b >> 4)) & 0x3F]; + *p++ = (i+1 < inlen) ? codes[ ( ( (b & 0xf) << 2)) & 0x3F] : '='; + *p++ = '='; + } + + /* return ok */ + *outlen = p - out; +} + +const char onCaptionInfo708[] = { 0x02,0x00,0x0D, 'o','n','C','a','p','t','i','o','n','I','n','f','o', + 0x08, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x04, 't','y','p','e', + 0x02, 0x00, 0x03, '7','0','8', + 0x00, 0x04, 'd','a','t','a', + 0x02, 0x00,0x00 + }; + +int flvtag_amfcaption_708 (flvtag_t* tag, uint32_t timestamp, sei_message_t* msg) +{ + flvtag_initamf (tag,timestamp); + unsigned long size = 1 + (4 * ( (sei_message_size (msg) + 2) / 3)); + flvtag_reserve (tag, sizeof (onCaptionInfo708) + size + 3); + memcpy (flvtag_payload_data (tag),onCaptionInfo708,sizeof (onCaptionInfo708)); + uint8_t* data = flvtag_payload_data (tag) + sizeof (onCaptionInfo708); + base64_encode (sei_message_data (msg), sei_message_size (msg), data, &size); + + // Update the size of the base64 string + data[-2] = size >> 8; + data[-1] = size >> 0; + // write the last array element + data[size+0] = 0x00; + data[size+1] = 0x00; + data[size+2] = 0x09; + flvtag_updatesize (tag, sizeof (onCaptionInfo708) + size + 3); + + return 1; +} + +const char onCaptionInfoUTF8[] = { 0x02,0x00,0x0D, 'o','n','C','a','p','t','i','o','n','I','n','f','o', + 0x08, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x04, 't','y','p','e', + 0x02, 0x00, 0x04, 'U','T','F','8', + 0x00, 0x04, 'd','a','t','a', + 0x02, 0x00,0x00 + }; + +#define MAX_AMF_STRING 65636 +int flvtag_amfcaption_utf8 (flvtag_t* tag, uint32_t timestamp, const utf8_char_t* text) +{ + flvtag_initamf (tag,timestamp); + unsigned long size = strlen (text); + + if (MAX_AMF_STRING < size) { + size = MAX_AMF_STRING; + } + + flvtag_reserve (tag, sizeof (onCaptionInfoUTF8) + size + 3); + memcpy (flvtag_payload_data (tag),onCaptionInfoUTF8,sizeof (onCaptionInfoUTF8)); + uint8_t* data = flvtag_payload_data (tag) + sizeof (onCaptionInfo708); + memcpy (data,text,size); + // Update the size of the string + data[-2] = size >> 8; + data[-1] = size >> 0; + // write the last array element + data[size+0] = 0x00; + data[size+1] = 0x00; + data[size+2] = 0x09; + flvtag_updatesize (tag, sizeof (onCaptionInfoUTF8) + size + 3); + + return 1; +} + +#define LENGTH_SIZE 4 + +int flvtag_avcwritenal (flvtag_t* tag, uint8_t* data, size_t size) +{ + uint32_t flvsize = flvtag_size (tag); + flvtag_reserve (tag,flvsize+LENGTH_SIZE+size); + uint8_t* payload = tag->data + FLV_TAG_HEADER_SIZE + flvsize; + payload[0] = size>>24; // nalu size + payload[1] = size>>16; + payload[2] = size>>8; + payload[3] = size>>0; + memcpy (&payload[LENGTH_SIZE],data,size); + flvtag_updatesize (tag,flvsize+LENGTH_SIZE+size); + + return 1; +} + +int flvtag_addcaption (flvtag_t* tag, const utf8_char_t* text) +{ + if (flvtag_avcpackettype_nalu != flvtag_avcpackettype (tag)) { + return 0; + } + + sei_t sei; + caption_frame_t frame; + + sei_init (&sei); + caption_frame_init (&frame); + caption_frame_from_text (&frame, text); + sei_from_caption_frame (&sei, &frame); + + uint8_t* sei_data = malloc (sei_render_size (&sei)); + size_t sei_size = sei_render (&sei, sei_data); + + // rewrite tag + flvtag_t new_tag; + flvtag_initavc (&new_tag, flvtag_dts (tag), flvtag_cts (tag), flvtag_frametype (tag)); + uint8_t* data = flvtag_payload_data (tag); + ssize_t size = flvtag_payload_size (tag); + + while (0<size) { + uint8_t* nalu_data = &data[LENGTH_SIZE]; + uint8_t nalu_type = nalu_data[0]&0x1F; + uint32_t nalu_size = (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3]; + data += LENGTH_SIZE + nalu_size; + size -= LENGTH_SIZE + nalu_size; + + if (0 < sei_size && 7 != nalu_type && 8 != nalu_type && 9 != nalu_type ) { + // fprintf (stderr,"Wrote SEI %d '%d'\n\n", sei_size, sei_data[3]); + flvtag_avcwritenal (&new_tag,sei_data,sei_size); + sei_size = 0; + } + + flvtag_avcwritenal (&new_tag,nalu_data,nalu_size); + } + + // On the off chance we have an empty frame, + // We still wish to append the sei + if (0<sei_size) { + // fprintf (stderr,"Wrote SEI %d\n\n", sei_size); + flvtag_avcwritenal (&new_tag,sei_data,sei_size); + sei_size = 0; + } + + if (sei_data) { + free (sei_data); + } + + free (tag->data); + sei_free (&sei); + tag->data = new_tag.data; + tag->aloc = new_tag.aloc; + return 1; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/flv.h
Added
@@ -0,0 +1,142 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_FLV_H +#define LIBCAPTION_FLV_H + +#include <stdio.h> +#include <stddef.h> +#include <inttypes.h> +#define FLV_HEADER_SIZE 13 +#define FLV_FOOTER_SIZE 4 +#define FLV_TAG_HEADER_SIZE 11 +#define FLV_TAG_FOOTER_SIZE 4 +//////////////////////////////////////////////////////////////////////////////// +#include "avc.h" +//////////////////////////////////////////////////////////////////////////////// +typedef struct { + uint8_t* data; + size_t aloc; +} flvtag_t; + +void flvtag_init (flvtag_t* tag); +void flvtag_free (flvtag_t* tag); +void flvtag_swap (flvtag_t* tag1, flvtag_t* tag2); +//////////////////////////////////////////////////////////////////////////////// +typedef enum { + flvtag_type_audio = 0x08, + flvtag_type_video = 0x09, + flvtag_type_scriptdata = 0x12, +} flvtag_type_t; + +static inline flvtag_type_t flvtag_type (flvtag_t* tag) { return (flvtag_type_t) tag->data[0]&0x1F; } +//////////////////////////////////////////////////////////////////////////////// +typedef enum { + flvtag_soundformat_unknown = -1, + flvtag_soundformat_linearpcmplatformendian = 0, + flvtag_soundformat_adpcm = 1, + flvtag_soundformat_mp3 = 2, + flvtag_soundformat_linearpcmlittleendian = 3, + flvtag_soundformat_nellymoser_16khzmono = 4, + flvtag_soundformat_nellymoser_8khzmono = 5, + flvtag_soundformat_nellymoser = 6, + flvtag_soundformat_g711alawlogarithmicpcm = 7, + flvtag_soundformat_g711mulawlogarithmicpcm = 8, + flvtag_soundformat_reserved = 9, + flvtag_soundformat_aac = 10, + flvtag_soundformat_speex = 11, + flvtag_soundformat_mp3_8khz = 14, + flvtag_soundformat_devicespecificsound = 15 +} flvtag_soundformat_t; + +static inline flvtag_soundformat_t flvtag_soundformat (flvtag_t* tag) { return (flvtag_type_audio!=flvtag_type (tag)) ?flvtag_soundformat_unknown: (flvtag_soundformat_t) (tag->data[0]>>4) &0x0F; } +//////////////////////////////////////////////////////////////////////////////// +typedef enum { + flvtag_codecid_unknown = -1, + flvtag_codecid_sorensonh263 = 2, + flvtag_codecid_screenvideo = 3, + flvtag_codecid_on2vp6 = 4, + flvtag_codecid_on2vp6withalphachannel = 5, + flvtag_codecid_screenvideoversion2 = 6, + flvtag_codecid_avc = 7 +} flvtag_codecid_t; + +static inline flvtag_codecid_t flvtag_codecid (flvtag_t* tag) { return (flvtag_type_video!=flvtag_type (tag)) ? (flvtag_codecid_unknown) : (tag->data[11]&0x0F); } +//////////////////////////////////////////////////////////////////////////////// +typedef enum { + flvtag_frametype_unknown = -1, + flvtag_frametype_keyframe = 1, + flvtag_frametype_interframe = 2, + flvtag_frametype_disposableinterframe = 3, + flvtag_frametype_generatedkeyframe = 4, + flvtag_frametype_commandframe = 5 +} flvtag_frametype_t; + +static inline flvtag_frametype_t flvtag_frametype (flvtag_t* tag) { return (flvtag_type_video!=flvtag_type (tag)) ?flvtag_frametype_keyframe: ( (tag->data[11]>>4) &0x0F); } +//////////////////////////////////////////////////////////////////////////////// +typedef enum { + flvtag_avcpackettype_unknown = -1, + flvtag_avcpackettype_sequenceheader = 0, + flvtag_avcpackettype_nalu = 1, + flvtag_avcpackettype_endofsequence = 2 +} flvtag_avcpackettype_t; + +static inline flvtag_avcpackettype_t flvtag_avcpackettype (flvtag_t* tag) { return (flvtag_codecid_avc!=flvtag_codecid (tag)) ?flvtag_avcpackettype_unknown:tag->data[12]; } +//////////////////////////////////////////////////////////////////////////////// +static inline size_t flvtag_size (flvtag_t* tag) { return (tag->data[1]<<16) | (tag->data[2]<<8) | tag->data[3]; } +static inline uint32_t flvtag_timestamp (flvtag_t* tag) { return (tag->data[7]<<24) | (tag->data[4]<<16) | (tag->data[5]<<8) | tag->data[6]; } +static inline uint32_t flvtag_dts (flvtag_t* tag) { return flvtag_timestamp (tag); } +static inline uint32_t flvtag_cts (flvtag_t* tag) { return (flvtag_avcpackettype_nalu!=flvtag_avcpackettype (tag)) ?0: (tag->data[13]<<16) | (tag->data[14]<<8) |tag->data[15]; } +static inline uint32_t flvtag_pts (flvtag_t* tag) { return flvtag_dts (tag)+flvtag_cts (tag); } +static inline double flvtag_dts_seconds (flvtag_t* tag) { return flvtag_dts (tag) / 1000.0; } +static inline double flvtag_cts_seconds (flvtag_t* tag) { return flvtag_cts (tag) / 1000.0; } +static inline double flvtag_pts_seconds (flvtag_t* tag) { return flvtag_pts (tag) / 1000.0; } +//////////////////////////////////////////////////////////////////////////////// +size_t flvtag_header_size (flvtag_t* tag); +size_t flvtag_payload_size (flvtag_t* tag); +uint8_t* flvtag_payload_data (flvtag_t* tag); +//////////////////////////////////////////////////////////////////////////////// +FILE* flv_open_read (const char* flv); +FILE* flv_open_write (const char* flv); +FILE* flv_close (FILE* flv); +//////////////////////////////////////////////////////////////////////////////// +static inline const uint8_t* flvtag_raw_data (flvtag_t* tag) { return tag->data; } +static inline const size_t flvtag_raw_size (flvtag_t* tag) { return flvtag_size (tag)+FLV_TAG_HEADER_SIZE+FLV_TAG_FOOTER_SIZE; } +//////////////////////////////////////////////////////////////////////////////// +int flv_read_tag (FILE* flv, flvtag_t* tag); +int flv_write_tag (FILE* flv, flvtag_t* tag); +int flv_read_header (FILE* flv, int* has_audio, int* has_video); +int flv_write_header (FILE* flv, int has_audio, int has_video); +//////////////////////////////////////////////////////////////////////////////// +// If the tage has more that on sei message, they will be combined into one +sei_t* flv_read_sei (FILE* flv, flvtag_t* tag); +//////////////////////////////////////////////////////////////////////////////// +int flvtag_initavc (flvtag_t* tag, uint32_t dts, int32_t cts, flvtag_frametype_t type); +int flvtag_avcwritenal (flvtag_t* tag, uint8_t* data, size_t size); +int flvtag_addcaption (flvtag_t* tag, const utf8_char_t* text); +//////////////////////////////////////////////////////////////////////////////// +int flvtag_amfcaption_708 (flvtag_t* tag, uint32_t timestamp, sei_message_t* msg); +//////////////////////////////////////////////////////////////////////////////// +// This method is expermental, and not currently available on Twitch +int flvtag_amfcaption_utf8 (flvtag_t* tag, uint32_t timestamp, const utf8_char_t* text); +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/flv2srt.c
Added
@@ -0,0 +1,92 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "flv.h" +#include "srt.h" +#include "avc.h" + +#define LENGTH_SIZE 4 +int main (int argc, char** argv) +{ + const char* path = argv[1]; + + sei_t sei; + flvtag_t tag; + srt_t* srt = 0, *head = 0; + int i, has_audio, has_video; + caption_frame_t frame; + + flvtag_init (&tag); + caption_frame_init (&frame); + + FILE* flv = flv_open_read (path); + + if (!flv_read_header (flv,&has_audio,&has_video)) { + fprintf (stderr,"'%s' Not an flv file\n", path); + } else { + fprintf (stderr,"Reading from '%s'\n", path); + } + + while (flv_read_tag (flv,&tag)) { + if (flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag)) { + ssize_t size = flvtag_payload_size (&tag); + uint8_t* data = flvtag_payload_data (&tag); + + while (0<size) { + ssize_t nalu_size = (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3]; + uint8_t* nalu_data = &data[4]; + uint8_t nalu_type = nalu_data[0]&0x1F; + data += nalu_size + LENGTH_SIZE; + size -= nalu_size + LENGTH_SIZE; + + if (6 == nalu_type) { + sei_init (&sei); + sei_parse_nalu (&sei, nalu_data, nalu_size, flvtag_dts (&tag), flvtag_cts (&tag)); + + cea708_t cea708; + sei_message_t* msg; + cea708_init (&cea708); + + // for (msg = sei_message_head (&sei) ; msg ; msg = sei_message_next (msg)) { + // if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) { + // cea708_parse (sei_message_data (msg), sei_message_size (msg), &cea708); + // cea708_dump (&cea708); + // } + // } + + // sei_dump(&sei); + sei_to_caption_frame (&sei,&frame); + sei_free (&sei); + + // caption_frame_dump (&frame); + srt = srt_from_caption_frame (&frame,srt,&head); + } + } + } + } + + srt_dump (head); + srt_free (head); + + return 1; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/party.c
Added
@@ -0,0 +1,122 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "flv.h" +#include "avc.h" + +#define CAPTION_METHOD_SEI_708 0 // embedded 708 +#define CAPTION_METHOD_AMF_708 1 // onCaptionInfo type = 708 +#define CAPTION_METHOD_AMF_UTF8 2 // onCaptionInfo type = utf8 +#define CAPTION_METHOD CAPTION_METHOD_SEI_708 + +void get_dudes (char* str) +{ + sprintf (str, " %s%s %s(-_-)%s %s(-_-)%s.%s(-_-)%s %s%s", EIA608_CHAR_EIGHTH_NOTE, EIA608_CHAR_EIGHTH_NOTE, + ! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, + ! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, + ! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, + ! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, + ! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, + ! (rand() % 2) ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, + EIA608_CHAR_EIGHTH_NOTE, EIA608_CHAR_EIGHTH_NOTE); +} + +void write_amfcaptions_708 (FILE* out, uint32_t timestamp, const char* text) +{ + sei_t sei; + flvtag_t tag; + sei_message_t* msg; + caption_frame_t frame; + sei_init (&sei); + flvtag_init (&tag); + caption_frame_init (&frame); + caption_frame_from_text (&frame, text); + sei_from_caption_frame (&sei, &frame); + // caption_frame_dump (&frame); + + for (msg = sei_message_head (&sei); msg; msg=sei_message_next (msg),++timestamp) { + flvtag_amfcaption_708 (&tag,timestamp,msg); + flv_write_tag (out,&tag); + } + + sei_free (&sei); + flvtag_free (&tag); +} + + +void write_amfcaptions_utf8 (FILE* out, uint32_t timestamp, const utf8_char_t* text) +{ + flvtag_t tag; + flvtag_init (&tag); + flvtag_amfcaption_utf8 (&tag,timestamp,text); + flv_write_tag (out,&tag); + flvtag_free (&tag); +} + +int main (int argc, char** argv) +{ + flvtag_t tag; + uint32_t nextParty = 1000; + int has_audio, has_video; + FILE* flv = flv_open_read (argv[1]); + FILE* out = flv_open_write (argv[2]); + char partyDudes[64]; + + flvtag_init (&tag); + + if (!flv_read_header (flv,&has_audio,&has_video)) { + fprintf (stderr,"%s is not an flv file\n", argv[1]); + return EXIT_FAILURE; + } + + flv_write_header (out,has_audio,has_video); + + while (flv_read_tag (flv,&tag)) { + + if (flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag) && nextParty <= flvtag_timestamp (&tag)) { + get_dudes (partyDudes); + + if (CAPTION_METHOD == CAPTION_METHOD_SEI_708) { + flvtag_addcaption (&tag, partyDudes); + } else if (CAPTION_METHOD == CAPTION_METHOD_AMF_708) { + write_amfcaptions_708 (out,nextParty,partyDudes); + } else if (CAPTION_METHOD == CAPTION_METHOD_AMF_708) { + write_amfcaptions_utf8 (out, nextParty, partyDudes); + } else { + fprintf (stderr,"Unknnow method\n"); + return EXIT_FAILURE; + + } + + fprintf (stderr,"%d: %s\n",nextParty, partyDudes); + nextParty += 500; // party all the time + } + + flv_write_tag (out,&tag); + } + + return EXIT_SUCCESS; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/rollup.c
Added
@@ -0,0 +1,95 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "flv.h" +#include "avc.h" +#include "srt.h" +#include "wonderland.h" + +#define SECONDS_PER_LINE 3.0 +srt_t* appennd_caption (const utf8_char_t* data, srt_t* prev, srt_t** head) +{ + + int r, c, chan = 0; + ssize_t size = (ssize_t) strlen (data); + size_t char_count, char_length, line_length = 0, trimmed_length = 0; + + for (r = 0 ; 0 < size && SCREEN_ROWS > r ; ++r) { + line_length = utf8_line_length (data); + trimmed_length = utf8_trimmed_length (data,line_length); + char_count = utf8_char_count (data,trimmed_length); + + // If char_count is greater than one line can display, split it. + if (SCREEN_COLS < char_count) { + char_count = utf8_wrap_length (data,SCREEN_COLS); + line_length = utf8_string_length (data,char_count+1); + } + + // fprintf (stderr,"%.*s\n", line_length, data); + prev = srt_new (data, line_length, prev ? prev->timestamp + SECONDS_PER_LINE : 0, prev, head); + + data += line_length; + size -= (ssize_t) line_length; + } + + return prev; +} + +int main (int argc, char** argv) +{ + int i = 0; + flvtag_t tag; + srt_t* head = 0, *tail = 0; + int has_audio, has_video; + FILE* flv = flv_open_read (argv[1]); + FILE* out = flv_open_write (argv[2]); + flvtag_init (&tag); + + for (i = 0 ; wonderland[i][0]; ++i) { + tail = appennd_caption (wonderland[i], tail, &head); + } + + + if (!flv_read_header (flv,&has_audio,&has_video)) { + fprintf (stderr,"%s is not an flv file\n", argv[1]); + return EXIT_FAILURE; + } + + flv_write_header (out,has_audio,has_video); + + while (flv_read_tag (flv,&tag)) { + if (head && flvtag_avcpackettype_nalu == flvtag_avcpackettype (&tag) && head->timestamp <= flvtag_pts_seconds (&tag)) { + fprintf (stderr,"%f %s\n", flvtag_pts_seconds (&tag), srt_data (head)); + flvtag_addcaption (&tag, srt_data (head)); + head = srt_free_head (head); + } + + + flv_write_tag (out,&tag); + } + + return EXIT_SUCCESS; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/rtmpspit.c
Added
@@ -0,0 +1,165 @@ +#include "flv.h" +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/select.h> +#include <librtmp/log.h> +#include <librtmp/rtmp.h> + + +int MyRTMP_Write (RTMP* r, const char* buf, int size) +{ + RTMPPacket* pkt = &r->m_write; + char* enc; + int s2 = size, ret, num; + + pkt->m_nChannel = 0x04; /* source channel */ + pkt->m_nInfoField2 = r->m_stream_id; + + while (s2) { + if (!pkt->m_nBytesRead) { + if (size < 11) { + /* FLV pkt too small */ + return 0; + } + + if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V') { + buf += 13; + s2 -= 13; + } + + pkt->m_packetType = *buf++; + pkt->m_nBodySize = AMF_DecodeInt24 (buf); + buf += 3; + pkt->m_nTimeStamp = AMF_DecodeInt24 (buf); + buf += 3; + pkt->m_nTimeStamp |= *buf++ << 24; + buf += 3; + s2 -= 11; + + if ( ( (pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO + || pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) && + !pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO) { + pkt->m_headerType = RTMP_PACKET_SIZE_LARGE; + } else { + pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM; + } + + if (!RTMPPacket_Alloc (pkt, pkt->m_nBodySize)) { + RTMP_Log (RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__); + return FALSE; + } + + enc = pkt->m_body; + } else { + enc = pkt->m_body + pkt->m_nBytesRead; + } + + num = pkt->m_nBodySize - pkt->m_nBytesRead; + + if (num > s2) { + num = s2; + } + + memcpy (enc, buf, num); + pkt->m_nBytesRead += num; + s2 -= num; + buf += num; + + if (pkt->m_nBytesRead == pkt->m_nBodySize) { + ret = RTMP_SendPacket (r, pkt, FALSE); + RTMPPacket_Free (pkt); + pkt->m_nBytesRead = 0; + + if (!ret) { + return -1; + } + + buf += 4; + s2 -= 4; + + if (s2 < 0) { + break; + } + } + } + + return size+s2; +} + +int main (int argc, const char** argv) +{ + FILE* flv; + RTMP* rtmp; + RTMPPacket rtmpPacket; + + flvtag_t tag; + int32_t timestamp = 0; + int has_audio, has_video; + char* url = 0; + + if (2 >= argc) { + fprintf (stderr,"Usage %s [input] [url]\n",argv[0]); + } + + url = (char*) argv[2]; + flv = flv_open_read (argv[1]); + + if (! flv) { + fprintf (stderr,"Could not open %s\n",argv[1]); + return EXIT_FAILURE; + } + + if (! flv_read_header (flv, &has_audio, &has_video)) { + fprintf (stderr,"Not an flv file %s\n",argv[1]); + return EXIT_FAILURE; + } + + flvtag_init (&tag); + rtmp = RTMP_Alloc(); + RTMP_Init (rtmp); + fprintf (stderr,"Connecting to %s\n", url); + RTMP_SetupURL (rtmp, url); + RTMP_EnableWrite (rtmp); + + RTMP_Connect (rtmp, NULL); + RTMP_ConnectStream (rtmp, 0); + memset (&rtmpPacket, 0, sizeof (RTMPPacket)); + + if (! RTMP_IsConnected (rtmp)) { + fprintf (stderr,"RTMP_IsConnected() Error\n"); + return EXIT_FAILURE; + } + + while (flv_read_tag (flv,&tag)) { + if (! RTMP_IsConnected (rtmp) || RTMP_IsTimedout (rtmp)) { + fprintf (stderr,"RTMP_IsConnected() Error\n"); + return EXIT_FAILURE; + } + + if (flvtag_timestamp (&tag) > timestamp) { + usleep (1000 * (flvtag_timestamp (&tag) - timestamp)); + timestamp = flvtag_timestamp (&tag); + } + + MyRTMP_Write (rtmp, (const char*) flvtag_raw_data (&tag),flvtag_raw_size (&tag)); + + // Handle RTMP ping and such + fd_set sockset; struct timeval timeout = {0,0}; + FD_ZERO (&sockset); FD_SET (RTMP_Socket (rtmp), &sockset); + register int result = select (RTMP_Socket (rtmp) + 1, &sockset, NULL, NULL, &timeout); + + if (result == 1 && FD_ISSET (RTMP_Socket (rtmp), &sockset)) { + RTMP_ReadPacket (rtmp, &rtmpPacket); + + if (! RTMPPacket_IsReady (&rtmpPacket)) { + fprintf (stderr,"Received RTMP packet\n"); + RTMP_ClientPacket (rtmp,&rtmpPacket); + RTMPPacket_Free (&rtmpPacket); + } + } + } + + return EXIT_SUCCESS; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/scc2srt.c
Added
@@ -0,0 +1,96 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "srt.h" +#include "scc.h" + +#define MAX_SCC_SIZE (10*1024*1024) +#define MAX_READ_SIZE 4096 +#define MAX_CC 128 + +size_t read_file (FILE* file, utf8_char_t* data, size_t size) +{ + size_t read, totl = 0; + + while (0 < (read = fread (data,1,MAX_READ_SIZE<size?MAX_READ_SIZE:size,file))) { + totl += read; data += read; size -= read; + } + + return totl; +} + +srt_t* scc2srt (const char* data) +{ + double pts; + size_t line_size = 0; + int cc_idx, count, i; + srt_t* srt = 0, *head = 0; + caption_frame_t frame; + uint16_t cc_data[MAX_CC]; + + while (0 < (line_size = utf8_line_length (data))) { + caption_frame_init (&frame); + int cc_count = scc_to_608 (data, &pts, (uint16_t*) &cc_data, MAX_CC); + data += line_size; + data += utf8_line_length (data); // skip empty line + + // fprintf (stderr,"%f, %d| %.*s\n", pts, cc_count, (int) line_size,data); + + for (cc_idx = 0 ; cc_idx < cc_count ; ++cc_idx) { + // eia608_dump (cc_data[cc_idx]); + caption_frame_decode (&frame,cc_data[cc_idx],pts); + } + + // utf8_char_t buff[CAPTION_FRAME_DUMP_BUF_SIZE]; + // size_t size = caption_frame_dump (&frame, buff); + // fprintf (stderr,"%s\n", buff); + srt = srt_from_caption_frame (&frame,srt,&head); + } + + return head; +} + +int main (int argc, char** argv) +{ + char frame_buf[CAPTION_FRAME_DUMP_BUF_SIZE]; + + if (argc < 2) { + return 0; + } + + FILE* file = fopen (argv[1],"r"); + + if (! file) { + return 0; + } + + utf8_char_t* data = malloc (MAX_SCC_SIZE); + read_file (file,data,MAX_SCC_SIZE); + srt_t* srt = scc2srt (data); + srt_dump (srt); + srt_free (srt); + free (data); +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/srt2vtt.c
Added
@@ -0,0 +1,64 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "srt.h" + +#define MAX_SRT_SIZE (10*1024*1024) +#define MAX_READ_SIZE 4096 + +size_t read_file (FILE* file, utf8_char_t* data, size_t size) +{ + size_t read, totl = 0; + + while (0 < (read = fread (data,1,MAX_READ_SIZE<size?MAX_READ_SIZE:size,file))) { + totl += read; data += read; size -= read; + } + + return totl; +} + +int main (int argc, char** argv) +{ + srt_t* srt; + caption_frame_t frame; + char frame_buf[CAPTION_FRAME_DUMP_BUF_SIZE]; + + if (argc < 2) { + return 0; + } + + FILE* file = fopen (argv[1],"r"); + + if (! file) { + return 0; + } + + utf8_char_t* data = malloc (MAX_SRT_SIZE); + size_t size = read_file (file,data,MAX_SRT_SIZE); + srt_t* head = srt_parse (data,size); + vtt_dump (head); + srt_free (head); +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/srtdump.c
Added
@@ -0,0 +1,71 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "srt.h" +#include "avc.h" +// #include "sei.h" + +#define MAX_SRT_SIZE (10*1024*1024) +#define MAX_READ_SIZE 4096 + +size_t read_file (FILE* file, utf8_char_t* data, size_t size) +{ + size_t read, totl = 0; + + while (0 < (read = fread (data,1,MAX_READ_SIZE<size?MAX_READ_SIZE:size,file))) { + totl += read; data += read; size -= read; + } + + return totl; +} + +int main (int argc, char** argv) +{ + srt_t* srt; + caption_frame_t frame; + + if (argc < 2) { + return 0; + } + + FILE* file = fopen (argv[1],"r"); + + if (! file) { + return 0; + } + + utf8_char_t* data = (utf8_char_t*) malloc (MAX_SRT_SIZE); + size_t size = read_file (file,data,MAX_SRT_SIZE); + srt_t* head = srt_parse (data,size); + + for (srt = head ; srt ; srt = srt->next) { + caption_frame_init (&frame); + srt_to_caption_frame (srt,&frame); + caption_frame_dump (&frame); + } + + srt_free (head); +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/ts.c
Added
@@ -0,0 +1,117 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "ts.h" +#include <string.h> + +void ts_init (ts_t* ts) +{ + memset (ts,0,sizeof (ts_t)); +} + +static int64_t ts_parse_pts (const uint8_t* data) +{ + // 0000 1110 1111 1111 1111 1110 1111 1111 1111 1110 + uint64_t pts = 0; + pts |= (uint64_t) (data[0] & 0x0E) << 29; + pts |= (uint64_t) (data[1] & 0xFF) << 22; + pts |= (uint64_t) (data[2] & 0xFE) << 14; + pts |= (uint64_t) (data[3] & 0xFF) << 7; + pts |= (uint64_t) (data[4] & 0xFE) >> 1; + return pts; +} + +int ts_parse_packet (ts_t* ts, const uint8_t* data) +{ + size_t i = 0; + int pusi = !! (data[i + 1] & 0x40); // Payload Unit Start Indicator + int16_t pid = ( (data[i + 1] & 0x1F) << 8) | data[i + 2]; // PID + int adaption_present = !! (data[i + 3] & 0x20); // Adaptation field exist + int payload_present = !! (data[i + 3] & 0x10); // Contains payload + i += 4; + + ts->data = 0; + ts->size = 0; + + if (adaption_present) { + uint8_t adaption_length = data[i + 0]; // adaption field length + i += 1 + adaption_length; + } + + if (pid == 0) { + if (payload_present) { + // Skip the payload. + i += data[i] + 1; + } + + ts->pmtpid = ( (data[i + 10] & 0x1F) << 8) | data[i + 11]; + } else if (pid == ts->pmtpid) { + // PMT + if (payload_present) { + // Skip the payload. + i += data[i] + 1; + } + + uint16_t section_length = ( (data[i + 1] & 0x0F) << 8) | data[i + 2]; + int current = data[i + 5] & 0x01; + int16_t program_info_length = ( (data[i + 10] & 0x0F) << 8) | data[i + 11]; + int16_t descriptor_loop_length = section_length - (9 + program_info_length + 4); // 4 for the crc + + i += 12 + program_info_length; + + if (current) { + while (descriptor_loop_length >= 5) { + uint8_t stream_type = data[i]; + int16_t elementary_pid = ( (data[i + 1] & 0x1F) << 8) | data[i + 2]; + int16_t esinfo_length = ( (data[i + 3] & 0x0F) << 8) | data[i + 4]; + + if (0x1B == stream_type) { + ts->avcpid = elementary_pid; + } + + i += 5 + esinfo_length; + descriptor_loop_length -= 5 + esinfo_length; + } + } + } else if (payload_present && pid == ts->avcpid) { + if (pusi) { + // int data_alignment = !! (data[i + 6] & 0x04); + int has_pts = !! (data[i + 7] & 0x80); + int has_dts = !! (data[i + 7] & 0x40); + uint8_t header_length = data[i + 8]; + + if (has_pts) { + ts->pts = ts_parse_pts (&data[i + 9]); + ts->dts = has_dts ? ts_parse_pts (&data[i + 14]) : ts->pts; + } + + i += 9 + header_length; + } + + ts->data = &data[i]; + ts->size = TS_PACKET_SIZE-i; + return LIBCAPTION_READY; + } + + return LIBCAPTION_OK; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/ts.h
Added
@@ -0,0 +1,49 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#ifndef LIBCAPTION_TS_H +#define LIBCAPTION_TS_H +#include "caption.h" +typedef struct { + int16_t pmtpid; + int16_t avcpid; + int64_t pts; + int64_t dts; + size_t size; + const uint8_t* data; +} ts_t; + +/*! \brief + \param + + Expects 188 byte TS packet +*/ +#define TS_PACKET_SIZE 188 +void ts_init (ts_t* ts); +int ts_parse_packet (ts_t* ts, const uint8_t* data); +// return timestamp in seconds +static inline double ts_dts_seconds (ts_t* ts) { return ts->dts / 90000.0; } +static inline double ts_pts_seconds (ts_t* ts) { return ts->pts / 90000.0; } +static inline double ts_cts_seconds (ts_t* ts) { return (ts->dts - ts->pts) / 90000.0; } + +#endif
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/ts2srt.c
Added
@@ -0,0 +1,101 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "ts.h" +#include "srt.h" +#include "avc.h" +#include <stdio.h> + +int main (int argc, char** argv) +{ + const char* path = argv[1]; + + ts_t ts; + sei_t sei; + avcnalu_t nalu; + srt_t* srt = 0, *head = 0; + caption_frame_t frame; + uint8_t pkt[TS_PACKET_SIZE]; + ts_init (&ts); + avcnalu_init (&nalu); + caption_frame_init (&frame); + + FILE* file = fopen (path,"rb+"); + + while (TS_PACKET_SIZE == fread (&pkt[0],1,TS_PACKET_SIZE, file)) { + switch (ts_parse_packet (&ts,&pkt[0])) { + case LIBCAPTION_OK: + // fprintf (stderr,"read ts packet\n"); + break; + + case LIBCAPTION_READY: { + // fprintf (stderr,"read ts packet DATA\n"); + while (ts.size) { + // fprintf (stderr,"ts.size %d (%02X%02X%02X%02X)\n",ts.size, ts.data[0], ts.data[1], ts.data[2], ts.data[3]); + + switch (avcnalu_parse_annexb (&nalu, &ts.data, &ts.size)) { + case LIBCAPTION_OK: + break; + + case LIBCAPTION_ERROR: + // fprintf (stderr,"LIBCAPTION_ERROR == avcnalu_parse_annexb()\n"); + avcnalu_init (&nalu); + break; + + case LIBCAPTION_READY: { + + if (6 == avcnalu_type (&nalu)) { + // fprintf (stderr,"NALU %d (%d)\n", avcnalu_type (&nalu), avcnalu_size (&nalu)); + sei_init (&sei); + sei_parse_avcnalu (&sei, &nalu, ts_dts_seconds (&ts), ts_cts_seconds (&ts)); + + // sei_dump (&sei); + + if (LIBCAPTION_READY == sei_to_caption_frame (&sei,&frame)) { + // caption_frame_dump (&frame); + srt = srt_from_caption_frame (&frame,srt,&head); + + // srt_dump (srt); + } + + sei_free (&sei); + } + + avcnalu_init (&nalu); + } break; + } + } + } break; + + case LIBCAPTION_ERROR: + // fprintf (stderr,"read ts packet ERROR\n"); + break; + } + + } + + srt_dump (head); + srt_free (head); + + return 1; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/examples/wonderland.h
Added
@@ -0,0 +1,2794 @@ +const char* wonderland[] = { + "Project Gutenberg’s Alice’s Adventures in Wonderland, by Lewis Carroll", + "This eBook is for the use of anyone anywhere at no cost and with", + "almost no restrictions whatsoever. You may copy it, give it away or", + "re-use it under the terms of the Project Gutenberg License included", + "with this eBook or online at www.gutenberg.org", + "Title: Alice’s Adventures in Wonderland", + "Author: Lewis Carroll", + "Posting Date: June 25, 2008 [EBook #11]", + "Release Date: March, 1994", + "Last Updated: October 6, 2016", + "Language: English", + "Character set encoding: UTF-8", + "*** START OF THIS PROJECT GUTENBERG EBOOK ALICE’S ADVENTURES IN WONDERLAND ***", + "ALICE’S ADVENTURES IN WONDERLAND", + "Lewis Carroll", + "THE MILLENNIUM FULCRUM EDITION 3.0", + "CHAPTER I. Down the Rabbit-Hole", + "Alice was beginning to get very tired of sitting by her sister on the", + "bank, and of having nothing to do: once or twice she had peeped into the", + "book her sister was reading, but it had no pictures or conversations in", + "it, ‘and what is the use of a book,’ thought Alice ‘without pictures or", + "conversations?’", + "So she was considering in her own mind (as well as she could, for the", + "hot day made her feel very sleepy and stupid), whether the pleasure", + "of making a daisy-chain would be worth the trouble of getting up and", + "picking the daisies, when suddenly a White Rabbit with pink eyes ran", + "close by her.", + "There was nothing so VERY remarkable in that; nor did Alice think it so", + "VERY much out of the way to hear the Rabbit say to itself, ‘Oh dear!", + "Oh dear! I shall be late!’ (when she thought it over afterwards, it", + "occurred to her that she ought to have wondered at this, but at the time", + "it all seemed quite natural); but when the Rabbit actually TOOK A WATCH", + "OUT OF ITS WAISTCOAT-POCKET, and looked at it, and then hurried on,", + "Alice started to her feet, for it flashed across her mind that she had", + "never before seen a rabbit with either a waistcoat-pocket, or a watch", + "to take out of it, and burning with curiosity, she ran across the field", + "after it, and fortunately was just in time to see it pop down a large", + "rabbit-hole under the hedge.", + "In another moment down went Alice after it, never once considering how", + "in the world she was to get out again.", + "The rabbit-hole went straight on like a tunnel for some way, and then", + "dipped suddenly down, so suddenly that Alice had not a moment to think", + "about stopping herself before she found herself falling down a very deep", + "well.", + "Either the well was very deep, or she fell very slowly, for she had", + "plenty of time as she went down to look about her and to wonder what was", + "going to happen next. First, she tried to look down and make out what", + "she was coming to, but it was too dark to see anything; then she", + "looked at the sides of the well, and noticed that they were filled with", + "cupboards and book-shelves; here and there she saw maps and pictures", + "hung upon pegs. She took down a jar from one of the shelves as", + "she passed; it was labelled ‘ORANGE MARMALADE’, but to her great", + "disappointment it was empty: she did not like to drop the jar for fear", + "of killing somebody, so managed to put it into one of the cupboards as", + "she fell past it.", + "‘Well!’ thought Alice to herself, ‘after such a fall as this, I shall", + "think nothing of tumbling down stairs! How brave they’ll all think me at", + "home! Why, I wouldn’t say anything about it, even if I fell off the top", + "of the house!’ (Which was very likely true.)", + "Down, down, down. Would the fall NEVER come to an end! ‘I wonder how", + "many miles I’ve fallen by this time?’ she said aloud. ‘I must be getting", + "somewhere near the centre of the earth. Let me see: that would be four", + "thousand miles down, I think--’ (for, you see, Alice had learnt several", + "things of this sort in her lessons in the schoolroom, and though this", + "was not a VERY good opportunity for showing off her knowledge, as there", + "was no one to listen to her, still it was good practice to say it over)", + "‘--yes, that’s about the right distance--but then I wonder what Latitude", + "or Longitude I’ve got to?’ (Alice had no idea what Latitude was, or", + "Longitude either, but thought they were nice grand words to say.)", + "Presently she began again. ‘I wonder if I shall fall right THROUGH the", + "earth! How funny it’ll seem to come out among the people that walk with", + "their heads downward! The Antipathies, I think--’ (she was rather glad", + "there WAS no one listening, this time, as it didn’t sound at all the", + "right word) ‘--but I shall have to ask them what the name of the country", + "is, you know. Please, Ma’am, is this New Zealand or Australia?’ (and", + "she tried to curtsey as she spoke--fancy CURTSEYING as you’re falling", + "through the air! Do you think you could manage it?) ‘And what an", + "ignorant little girl she’ll think me for asking! No, it’ll never do to", + "ask: perhaps I shall see it written up somewhere.’", + "Down, down, down. There was nothing else to do, so Alice soon began", + "talking again. ‘Dinah’ll miss me very much to-night, I should think!’", + "(Dinah was the cat.) ‘I hope they’ll remember her saucer of milk at", + "tea-time. Dinah my dear! I wish you were down here with me! There are no", + "mice in the air, I’m afraid, but you might catch a bat, and that’s very", + "like a mouse, you know. But do cats eat bats, I wonder?’ And here Alice", + "began to get rather sleepy, and went on saying to herself, in a dreamy", + "sort of way, ‘Do cats eat bats? Do cats eat bats?’ and sometimes, ‘Do", + "bats eat cats?’ for, you see, as she couldn’t answer either question,", + "it didn’t much matter which way she put it. She felt that she was dozing", + "off, and had just begun to dream that she was walking hand in hand with", + "Dinah, and saying to her very earnestly, ‘Now, Dinah, tell me the truth:", + "did you ever eat a bat?’ when suddenly, thump! thump! down she came upon", + "a heap of sticks and dry leaves, and the fall was over.", + "Alice was not a bit hurt, and she jumped up on to her feet in a moment:", + "she looked up, but it was all dark overhead; before her was another", + "long passage, and the White Rabbit was still in sight, hurrying down it.", + "There was not a moment to be lost: away went Alice like the wind, and", + "was just in time to hear it say, as it turned a corner, ‘Oh my ears", + "and whiskers, how late it’s getting!’ She was close behind it when she", + "turned the corner, but the Rabbit was no longer to be seen: she found", + "herself in a long, low hall, which was lit up by a row of lamps hanging", + "from the roof.", + "There were doors all round the hall, but they were all locked; and when", + "Alice had been all the way down one side and up the other, trying every", + "door, she walked sadly down the middle, wondering how she was ever to", + "get out again.", + "Suddenly she came upon a little three-legged table, all made of solid", + "glass; there was nothing on it except a tiny golden key, and Alice’s", + "first thought was that it might belong to one of the doors of the hall;", + "but, alas! either the locks were too large, or the key was too small,", + "but at any rate it would not open any of them. However, on the second", + "time round, she came upon a low curtain she had not noticed before, and", + "behind it was a little door about fifteen inches high: she tried the", + "little golden key in the lock, and to her great delight it fitted!", + "Alice opened the door and found that it led into a small passage, not", + "much larger than a rat-hole: she knelt down and looked along the passage", + "into the loveliest garden you ever saw. How she longed to get out of", + "that dark hall, and wander about among those beds of bright flowers and", + "those cool fountains, but she could not even get her head through the", + "doorway; ‘and even if my head would go through,’ thought poor Alice, ‘it", + "would be of very little use without my shoulders. Oh, how I wish I could", + "shut up like a telescope! I think I could, if I only knew how to begin.’", + "For, you see, so many out-of-the-way things had happened lately,", + "that Alice had begun to think that very few things indeed were really", + "impossible.", + "There seemed to be no use in waiting by the little door, so she went", + "back to the table, half hoping she might find another key on it, or at", + "any rate a book of rules for shutting people up like telescopes: this", + "time she found a little bottle on it, [‘which certainly was not here", + "before,’ said Alice,) and round the neck of the bottle was a paper", + "label, with the words ‘DRINK ME’ beautifully printed on it in large", + "letters.", + "It was all very well to say ‘Drink me,’ but the wise little Alice was", + "not going to do THAT in a hurry. ‘No, I’ll look first,’ she said, ‘and", + "see whether it’s marked “poison” or not’; for she had read several nice", + "little histories about children who had got burnt, and eaten up by wild", + "beasts and other unpleasant things, all because they WOULD not remember", + "the simple rules their friends had taught them: such as, that a red-hot", + "poker will burn you if you hold it too long; and that if you cut your", + "finger VERY deeply with a knife, it usually bleeds; and she had never", + "forgotten that, if you drink much from a bottle marked ‘poison,’ it is", + "almost certain to disagree with you, sooner or later.", + "However, this bottle was NOT marked ‘poison,’ so Alice ventured to taste", + "it, and finding it very nice, (it had, in fact, a sort of mixed flavour", + "of cherry-tart, custard, pine-apple, roast turkey, toffee, and hot", + "buttered toast,) she very soon finished it off.", + " * * * * * * *", + " * * * * * *", + " * * * * * * *", + "‘What a curious feeling!’ said Alice; ‘I must be shutting up like a", + "telescope.’", + "And so it was indeed: she was now only ten inches high, and her face", + "brightened up at the thought that she was now the right size for going", + "through the little door into that lovely garden. First, however, she", + "waited for a few minutes to see if she was going to shrink any further:", + "she felt a little nervous about this; ‘for it might end, you know,’ said", + "Alice to herself, ‘in my going out altogether, like a candle. I wonder", + "what I should be like then?’ And she tried to fancy what the flame of a", + "candle is like after the candle is blown out, for she could not remember", + "ever having seen such a thing.", + "After a while, finding that nothing more happened, she decided on going", + "into the garden at once; but, alas for poor Alice! when she got to the", + "door, she found she had forgotten the little golden key, and when she", + "went back to the table for it, she found she could not possibly reach", + "it: she could see it quite plainly through the glass, and she tried her", + "best to climb up one of the legs of the table, but it was too slippery;", + "and when she had tired herself out with trying, the poor little thing", + "sat down and cried.", + "‘Come, there’s no use in crying like that!’ said Alice to herself,", + "rather sharply; ‘I advise you to leave off this minute!’ She generally", + "gave herself very good advice, (though she very seldom followed it),", + "and sometimes she scolded herself so severely as to bring tears into", + "her eyes; and once she remembered trying to box her own ears for having", + "cheated herself in a game of croquet she was playing against herself,", + "for this curious child was very fond of pretending to be two people.", + "‘But it’s no use now,’ thought poor Alice, ‘to pretend to be two people!", + "Why, there’s hardly enough of me left to make ONE respectable person!’", + "Soon her eye fell on a little glass box that was lying under the table:", + "she opened it, and found in it a very small cake, on which the words", + "‘EAT ME’ were beautifully marked in currants. ‘Well, I’ll eat it,’ said", + "Alice, ‘and if it makes me grow larger, I can reach the key; and if it", + "makes me grow smaller, I can creep under the door; so either way I’ll", + "get into the garden, and I don’t care which happens!’", + "She ate a little bit, and said anxiously to herself, ‘Which way? Which", + "way?’, holding her hand on the top of her head to feel which way it was", + "growing, and she was quite surprised to find that she remained the same", + "size: to be sure, this generally happens when one eats cake, but Alice", + "had got so much into the way of expecting nothing but out-of-the-way", + "things to happen, that it seemed quite dull and stupid for life to go on", + "in the common way.", + "So she set to work, and very soon finished off the cake.", + " * * * * * * *", + " * * * * * *", + " * * * * * * *", + "CHAPTER II. The Pool of Tears", + "‘Curiouser and curiouser!’ cried Alice (she was so much surprised, that", + "for the moment she quite forgot how to speak good English); ‘now I’m", + "opening out like the largest telescope that ever was! Good-bye, feet!’", + "(for when she looked down at her feet, they seemed to be almost out of", + "sight, they were getting so far off). ‘Oh, my poor little feet, I wonder", + "who will put on your shoes and stockings for you now, dears? I’m sure", + "_I_ shan’t be able! I shall be a great deal too far off to trouble", + "myself about you: you must manage the best way you can;--but I must be", + "kind to them,’ thought Alice, ‘or perhaps they won’t walk the way I want", + "to go! Let me see: I’ll give them a new pair of boots every Christmas.’", + "And she went on planning to herself how she would manage it. ‘They must", + "go by the carrier,’ she thought; ‘and how funny it’ll seem, sending", + "presents to one’s own feet! And how odd the directions will look!", + " ALICE’S RIGHT FOOT, ESQ.", + " HEARTHRUG,", + " NEAR THE FENDER,", + " (WITH ALICE’S LOVE).", + "Oh dear, what nonsense I’m talking!’", + "Just then her head struck against the roof of the hall: in fact she was", + "now more than nine feet high, and she at once took up the little golden", + "key and hurried off to the garden door.", + "Poor Alice! It was as much as she could do, lying down on one side, to", + "look through into the garden with one eye; but to get through was more", + "hopeless than ever: she sat down and began to cry again.", + "‘You ought to be ashamed of yourself,’ said Alice, ‘a great girl like", + "you,’ (she might well say this), ‘to go on crying in this way! Stop this", + "moment, I tell you!’ But she went on all the same, shedding gallons of", + "tears, until there was a large pool all round her, about four inches", + "deep and reaching half down the hall.", + "After a time she heard a little pattering of feet in the distance, and", + "she hastily dried her eyes to see what was coming. It was the White", + "Rabbit returning, splendidly dressed, with a pair of white kid gloves in", + "one hand and a large fan in the other: he came trotting along in a great", + "hurry, muttering to himself as he came, ‘Oh! the Duchess, the Duchess!", + "Oh! won’t she be savage if I’ve kept her waiting!’ Alice felt so", + "desperate that she was ready to ask help of any one; so, when the Rabbit", + "came near her, she began, in a low, timid voice, ‘If you please, sir--’", + "The Rabbit started violently, dropped the white kid gloves and the fan,", + "and skurried away into the darkness as hard as he could go.", + "Alice took up the fan and gloves, and, as the hall was very hot, she", + "kept fanning herself all the time she went on talking: ‘Dear, dear! How", + "queer everything is to-day! And yesterday things went on just as usual.", + "I wonder if I’ve been changed in the night? Let me think: was I the", + "same when I got up this morning? I almost think I can remember feeling a", + "little different. But if I’m not the same, the next question is, Who", + "in the world am I? Ah, THAT’S the great puzzle!’ And she began thinking", + "over all the children she knew that were of the same age as herself, to", + "see if she could have been changed for any of them.", + "‘I’m sure I’m not Ada,’ she said, ‘for her hair goes in such long", + "ringlets, and mine doesn’t go in ringlets at all; and I’m sure I can’t", + "be Mabel, for I know all sorts of things, and she, oh! she knows such a", + "very little! Besides, SHE’S she, and I’m I, and--oh dear, how puzzling", + "it all is! I’ll try if I know all the things I used to know. Let me", + "see: four times five is twelve, and four times six is thirteen, and", + "four times seven is--oh dear! I shall never get to twenty at that rate!", + "However, the Multiplication Table doesn’t signify: let’s try Geography.", + "London is the capital of Paris, and Paris is the capital of Rome, and", + "Rome--no, THAT’S all wrong, I’m certain! I must have been changed for", + "Mabel! I’ll try and say “How doth the little--“’ and she crossed her", + "hands on her lap as if she were saying lessons, and began to repeat it,", + "but her voice sounded hoarse and strange, and the words did not come the", + "same as they used to do:--", + " ‘How doth the little crocodile", + " Improve his shining tail,", + " And pour the waters of the Nile", + " On every golden scale!", + " ‘How cheerfully he seems to grin,", + " How neatly spread his claws,", + " And welcome little fishes in", + " With gently smiling jaws!’", + "‘I’m sure those are not the right words,’ said poor Alice, and her eyes", + "filled with tears again as she went on, ‘I must be Mabel after all, and", + "I shall have to go and live in that poky little house, and have next to", + "no toys to play with, and oh! ever so many lessons to learn! No, I’ve", + "made up my mind about it; if I’m Mabel, I’ll stay down here! It’ll be no", + "use their putting their heads down and saying “Come up again, dear!” I", + "shall only look up and say “Who am I then? Tell me that first, and then,", + "if I like being that person, I’ll come up: if not, I’ll stay down here", + "till I’m somebody else”--but, oh dear!’ cried Alice, with a sudden burst", + "of tears, ‘I do wish they WOULD put their heads down! I am so VERY tired", + "of being all alone here!’", + "As she said this she looked down at her hands, and was surprised to see", + "that she had put on one of the Rabbit’s little white kid gloves while", + "she was talking. ‘How CAN I have done that?’ she thought. ‘I must", + "be growing small again.’ She got up and went to the table to measure", + "herself by it, and found that, as nearly as she could guess, she was now", + "about two feet high, and was going on shrinking rapidly: she soon found", + "out that the cause of this was the fan she was holding, and she dropped", + "it hastily, just in time to avoid shrinking away altogether.", + "‘That WAS a narrow escape!’ said Alice, a good deal frightened at the", + "sudden change, but very glad to find herself still in existence; ‘and", + "now for the garden!’ and she ran with all speed back to the little door:", + "but, alas! the little door was shut again, and the little golden key was", + "lying on the glass table as before, ‘and things are worse than ever,’", + "thought the poor child, ‘for I never was so small as this before, never!", + "And I declare it’s too bad, that it is!’", + "As she said these words her foot slipped, and in another moment, splash!", + "she was up to her chin in salt water. Her first idea was that she", + "had somehow fallen into the sea, ‘and in that case I can go back by", + "railway,’ she said to herself. (Alice had been to the seaside once in", + "her life, and had come to the general conclusion, that wherever you go", + "to on the English coast you find a number of bathing machines in the", + "sea, some children digging in the sand with wooden spades, then a row", + "of lodging houses, and behind them a railway station.) However, she soon", + "made out that she was in the pool of tears which she had wept when she", + "was nine feet high.", + "‘I wish I hadn’t cried so much!’ said Alice, as she swam about, trying", + "to find her way out. ‘I shall be punished for it now, I suppose, by", + "being drowned in my own tears! That WILL be a queer thing, to be sure!", + "However, everything is queer to-day.’", + "Just then she heard something splashing about in the pool a little way", + "off, and she swam nearer to make out what it was: at first she thought", + "it must be a walrus or hippopotamus, but then she remembered how small", + "she was now, and she soon made out that it was only a mouse that had", + "slipped in like herself.", + "‘Would it be of any use, now,’ thought Alice, ‘to speak to this mouse?", + "Everything is so out-of-the-way down here, that I should think very", + "likely it can talk: at any rate, there’s no harm in trying.’ So she", + "began: ‘O Mouse, do you know the way out of this pool? I am very tired", + "of swimming about here, O Mouse!’ (Alice thought this must be the right", + "way of speaking to a mouse: she had never done such a thing before, but", + "she remembered having seen in her brother’s Latin Grammar, ‘A mouse--of", + "a mouse--to a mouse--a mouse--O mouse!’) The Mouse looked at her rather", + "inquisitively, and seemed to her to wink with one of its little eyes,", + "but it said nothing.", + "‘Perhaps it doesn’t understand English,’ thought Alice; ‘I daresay it’s", + "a French mouse, come over with William the Conqueror.’ (For, with all", + "her knowledge of history, Alice had no very clear notion how long ago", + "anything had happened.) So she began again: ‘Ou est ma chatte?’ which", + "was the first sentence in her French lesson-book. The Mouse gave a", + "sudden leap out of the water, and seemed to quiver all over with fright.", + "‘Oh, I beg your pardon!’ cried Alice hastily, afraid that she had hurt", + "the poor animal’s feelings. ‘I quite forgot you didn’t like cats.’", + "‘Not like cats!’ cried the Mouse, in a shrill, passionate voice. ‘Would", + "YOU like cats if you were me?’", + "‘Well, perhaps not,’ said Alice in a soothing tone: ‘don’t be angry", + "about it. And yet I wish I could show you our cat Dinah: I think you’d", + "take a fancy to cats if you could only see her. She is such a dear quiet", + "thing,’ Alice went on, half to herself, as she swam lazily about in the", + "pool, ‘and she sits purring so nicely by the fire, licking her paws and", + "washing her face--and she is such a nice soft thing to nurse--and she’s", + "such a capital one for catching mice--oh, I beg your pardon!’ cried", + "Alice again, for this time the Mouse was bristling all over, and she", + "felt certain it must be really offended. ‘We won’t talk about her any", + "more if you’d rather not.’", + "‘We indeed!’ cried the Mouse, who was trembling down to the end of his", + "tail. ‘As if I would talk on such a subject! Our family always HATED", + "cats: nasty, low, vulgar things! Don’t let me hear the name again!’", + "‘I won’t indeed!’ said Alice, in a great hurry to change the subject of", + "conversation. ‘Are you--are you fond--of--of dogs?’ The Mouse did not", + "answer, so Alice went on eagerly: ‘There is such a nice little dog near", + "our house I should like to show you! A little bright-eyed terrier, you", + "know, with oh, such long curly brown hair! And it’ll fetch things when", + "you throw them, and it’ll sit up and beg for its dinner, and all sorts", + "of things--I can’t remember half of them--and it belongs to a farmer,", + "you know, and he says it’s so useful, it’s worth a hundred pounds! He", + "says it kills all the rats and--oh dear!’ cried Alice in a sorrowful", + "tone, ‘I’m afraid I’ve offended it again!’ For the Mouse was swimming", + "away from her as hard as it could go, and making quite a commotion in", + "the pool as it went.", + "So she called softly after it, ‘Mouse dear! Do come back again, and we", + "won’t talk about cats or dogs either, if you don’t like them!’ When the", + "Mouse heard this, it turned round and swam slowly back to her: its", + "face was quite pale (with passion, Alice thought), and it said in a low", + "trembling voice, ‘Let us get to the shore, and then I’ll tell you my", + "history, and you’ll understand why it is I hate cats and dogs.’", + "It was high time to go, for the pool was getting quite crowded with the", + "birds and animals that had fallen into it: there were a Duck and a Dodo,", + "a Lory and an Eaglet, and several other curious creatures. Alice led the", + "way, and the whole party swam to the shore.", + "CHAPTER III. A Caucus-Race and a Long Tale", + "They were indeed a queer-looking party that assembled on the bank--the", + "birds with draggled feathers, the animals with their fur clinging close", + "to them, and all dripping wet, cross, and uncomfortable.", + "The first question of course was, how to get dry again: they had a", + "consultation about this, and after a few minutes it seemed quite natural", + "to Alice to find herself talking familiarly with them, as if she had", + "known them all her life. Indeed, she had quite a long argument with the", + "Lory, who at last turned sulky, and would only say, ‘I am older than", + "you, and must know better’; and this Alice would not allow without", + "knowing how old it was, and, as the Lory positively refused to tell its", + "age, there was no more to be said.", + "At last the Mouse, who seemed to be a person of authority among them,", + "called out, ‘Sit down, all of you, and listen to me! I’LL soon make you", + "dry enough!’ They all sat down at once, in a large ring, with the Mouse", + "in the middle. Alice kept her eyes anxiously fixed on it, for she felt", + "sure she would catch a bad cold if she did not get dry very soon.", + "‘Ahem!’ said the Mouse with an important air, ‘are you all ready? This", + "is the driest thing I know. Silence all round, if you please! “William", + "the Conqueror, whose cause was favoured by the pope, was soon submitted", + "to by the English, who wanted leaders, and had been of late much", + "accustomed to usurpation and conquest. Edwin and Morcar, the earls of", + "Mercia and Northumbria--“’", + "‘Ugh!’ said the Lory, with a shiver.", + "‘I beg your pardon!’ said the Mouse, frowning, but very politely: ‘Did", + "you speak?’", + "‘Not I!’ said the Lory hastily.", + "‘I thought you did,’ said the Mouse. ‘--I proceed. “Edwin and Morcar,", + "the earls of Mercia and Northumbria, declared for him: and even Stigand,", + "the patriotic archbishop of Canterbury, found it advisable--“’", + "‘Found WHAT?’ said the Duck.", + "‘Found IT,’ the Mouse replied rather crossly: ‘of course you know what", + "“it” means.’", + "‘I know what “it” means well enough, when I find a thing,’ said the", + "Duck: ‘it’s generally a frog or a worm. The question is, what did the", + "archbishop find?’", + "The Mouse did not notice this question, but hurriedly went on, ‘“--found", + "it advisable to go with Edgar Atheling to meet William and offer him the", + "crown. William’s conduct at first was moderate. But the insolence of his", + "Normans--” How are you getting on now, my dear?’ it continued, turning", + "to Alice as it spoke.", + "‘As wet as ever,’ said Alice in a melancholy tone: ‘it doesn’t seem to", + "dry me at all.’", + "‘In that case,’ said the Dodo solemnly, rising to its feet, ‘I move", + "that the meeting adjourn, for the immediate adoption of more energetic", + "remedies--’", + "‘Speak English!’ said the Eaglet. ‘I don’t know the meaning of half", + "those long words, and, what’s more, I don’t believe you do either!’ And", + "the Eaglet bent down its head to hide a smile: some of the other birds", + "tittered audibly.", + "‘What I was going to say,’ said the Dodo in an offended tone, ‘was, that", + "the best thing to get us dry would be a Caucus-race.’", + "‘What IS a Caucus-race?’ said Alice; not that she wanted much to know,", + "but the Dodo had paused as if it thought that SOMEBODY ought to speak,", + "and no one else seemed inclined to say anything.", + "‘Why,’ said the Dodo, ‘the best way to explain it is to do it.’ (And, as", + "you might like to try the thing yourself, some winter day, I will tell", + "you how the Dodo managed it.)", + "First it marked out a race-course, in a sort of circle, [‘the exact", + "shape doesn’t matter,’ it said,) and then all the party were placed", + "along the course, here and there. There was no ‘One, two, three, and", + "away,’ but they began running when they liked, and left off when they", + "liked, so that it was not easy to know when the race was over. However,", + "when they had been running half an hour or so, and were quite dry again,", + "the Dodo suddenly called out ‘The race is over!’ and they all crowded", + "round it, panting, and asking, ‘But who has won?’", + "This question the Dodo could not answer without a great deal of thought,", + "and it sat for a long time with one finger pressed upon its forehead", + "(the position in which you usually see Shakespeare, in the pictures", + "of him), while the rest waited in silence. At last the Dodo said,", + "‘EVERYBODY has won, and all must have prizes.’", + "‘But who is to give the prizes?’ quite a chorus of voices asked.", + "‘Why, SHE, of course,’ said the Dodo, pointing to Alice with one finger;", + "and the whole party at once crowded round her, calling out in a confused", + "way, ‘Prizes! Prizes!’", + "Alice had no idea what to do, and in despair she put her hand in her", + "pocket, and pulled out a box of comfits, (luckily the salt water had", + "not got into it), and handed them round as prizes. There was exactly one", + "a-piece all round.", + "‘But she must have a prize herself, you know,’ said the Mouse.", + "‘Of course,’ the Dodo replied very gravely. ‘What else have you got in", + "your pocket?’ he went on, turning to Alice.", + "‘Only a thimble,’ said Alice sadly.", + "‘Hand it over here,’ said the Dodo.", + "Then they all crowded round her once more, while the Dodo solemnly", + "presented the thimble, saying ‘We beg your acceptance of this elegant", + "thimble’; and, when it had finished this short speech, they all cheered.", + "Alice thought the whole thing very absurd, but they all looked so grave", + "that she did not dare to laugh; and, as she could not think of anything", + "to say, she simply bowed, and took the thimble, looking as solemn as she", + "could.", + "The next thing was to eat the comfits: this caused some noise and", + "confusion, as the large birds complained that they could not taste", + "theirs, and the small ones choked and had to be patted on the back.", + "However, it was over at last, and they sat down again in a ring, and", + "begged the Mouse to tell them something more.", + "‘You promised to tell me your history, you know,’ said Alice, ‘and why", + "it is you hate--C and D,’ she added in a whisper, half afraid that it", + "would be offended again.", + "‘Mine is a long and a sad tale!’ said the Mouse, turning to Alice, and", + "sighing.", + "‘It IS a long tail, certainly,’ said Alice, looking down with wonder at", + "the Mouse’s tail; ‘but why do you call it sad?’ And she kept on puzzling", + "about it while the Mouse was speaking, so that her idea of the tale was", + "something like this:--", + " ‘Fury said to a", + " mouse, That he", + " met in the", + " house,", + " “Let us", + " both go to", + " law: I will", + " prosecute", + " YOU.--Come,", + " I’ll take no", + " denial; We", + " must have a", + " trial: For", + " really this", + " morning I’ve", + " nothing", + " to do.”", + " Said the", + " mouse to the", + " cur, “Such", + " a trial,", + " dear Sir,", + " With", + " no jury", + " or judge,", + " would be", + " wasting", + " our", + " breath.”", + " “I’ll be", + " judge, I’ll", + " be jury,”", + " Said", + " cunning", + " old Fury:", + " “I’ll", + " try the", + " whole", + " cause,", + " and", + " condemn", + " you", + " to", + " death.”’", + "‘You are not attending!’ said the Mouse to Alice severely. ‘What are you", + "thinking of?’", + "‘I beg your pardon,’ said Alice very humbly: ‘you had got to the fifth", + "bend, I think?’", + "‘I had NOT!’ cried the Mouse, sharply and very angrily.", + "‘A knot!’ said Alice, always ready to make herself useful, and looking", + "anxiously about her. ‘Oh, do let me help to undo it!’", + "‘I shall do nothing of the sort,’ said the Mouse, getting up and walking", + "away. ‘You insult me by talking such nonsense!’", + "‘I didn’t mean it!’ pleaded poor Alice. ‘But you’re so easily offended,", + "you know!’", + "The Mouse only growled in reply.", + "‘Please come back and finish your story!’ Alice called after it; and the", + "others all joined in chorus, ‘Yes, please do!’ but the Mouse only shook", + "its head impatiently, and walked a little quicker.", + "‘What a pity it wouldn’t stay!’ sighed the Lory, as soon as it was quite", + "out of sight; and an old Crab took the opportunity of saying to her", + "daughter ‘Ah, my dear! Let this be a lesson to you never to lose", + "YOUR temper!’ ‘Hold your tongue, Ma!’ said the young Crab, a little", + "snappishly. ‘You’re enough to try the patience of an oyster!’", + "‘I wish I had our Dinah here, I know I do!’ said Alice aloud, addressing", + "nobody in particular. ‘She’d soon fetch it back!’", + "‘And who is Dinah, if I might venture to ask the question?’ said the", + "Lory.", + "Alice replied eagerly, for she was always ready to talk about her pet:", + "‘Dinah’s our cat. And she’s such a capital one for catching mice you", + "can’t think! And oh, I wish you could see her after the birds! Why,", + "she’ll eat a little bird as soon as look at it!’", + "This speech caused a remarkable sensation among the party. Some of the", + "birds hurried off at once: one old Magpie began wrapping itself up very", + "carefully, remarking, ‘I really must be getting home; the night-air", + "doesn’t suit my throat!’ and a Canary called out in a trembling voice to", + "its children, ‘Come away, my dears! It’s high time you were all in bed!’", + "On various pretexts they all moved off, and Alice was soon left alone.", + "‘I wish I hadn’t mentioned Dinah!’ she said to herself in a melancholy", + "tone. ‘Nobody seems to like her, down here, and I’m sure she’s the best", + "cat in the world! Oh, my dear Dinah! I wonder if I shall ever see you", + "any more!’ And here poor Alice began to cry again, for she felt very", + "lonely and low-spirited. In a little while, however, she again heard", + "a little pattering of footsteps in the distance, and she looked up", + "eagerly, half hoping that the Mouse had changed his mind, and was coming", + "back to finish his story.", + "CHAPTER IV. The Rabbit Sends in a Little Bill", + "It was the White Rabbit, trotting slowly back again, and looking", + "anxiously about as it went, as if it had lost something; and she heard", + "it muttering to itself ‘The Duchess! The Duchess! Oh my dear paws! Oh", + "my fur and whiskers! She’ll get me executed, as sure as ferrets are", + "ferrets! Where CAN I have dropped them, I wonder?’ Alice guessed in a", + "moment that it was looking for the fan and the pair of white kid gloves,", + "and she very good-naturedly began hunting about for them, but they were", + "nowhere to be seen--everything seemed to have changed since her swim in", + "the pool, and the great hall, with the glass table and the little door,", + "had vanished completely.", + "Very soon the Rabbit noticed Alice, as she went hunting about, and", + "called out to her in an angry tone, ‘Why, Mary Ann, what ARE you doing", + "out here? Run home this moment, and fetch me a pair of gloves and a fan!", + "Quick, now!’ And Alice was so much frightened that she ran off at once", + "in the direction it pointed to, without trying to explain the mistake it", + "had made.", + "‘He took me for his housemaid,’ she said to herself as she ran. ‘How", + "surprised he’ll be when he finds out who I am! But I’d better take him", + "his fan and gloves--that is, if I can find them.’ As she said this, she", + "came upon a neat little house, on the door of which was a bright brass", + "plate with the name ‘W. RABBIT’ engraved upon it. She went in without", + "knocking, and hurried upstairs, in great fear lest she should meet the", + "real Mary Ann, and be turned out of the house before she had found the", + "fan and gloves.", + "‘How queer it seems,’ Alice said to herself, ‘to be going messages for", + "a rabbit! I suppose Dinah’ll be sending me on messages next!’ And she", + "began fancying the sort of thing that would happen: ‘“Miss Alice! Come", + "here directly, and get ready for your walk!” “Coming in a minute,", + "nurse! But I’ve got to see that the mouse doesn’t get out.” Only I don’t", + "think,’ Alice went on, ‘that they’d let Dinah stop in the house if it", + "began ordering people about like that!’", + "By this time she had found her way into a tidy little room with a table", + "in the window, and on it (as she had hoped) a fan and two or three pairs", + "of tiny white kid gloves: she took up the fan and a pair of the gloves,", + "and was just going to leave the room, when her eye fell upon a little", + "bottle that stood near the looking-glass. There was no label this time", + "with the words ‘DRINK ME,’ but nevertheless she uncorked it and put it", + "to her lips. ‘I know SOMETHING interesting is sure to happen,’ she said", + "to herself, ‘whenever I eat or drink anything; so I’ll just see what", + "this bottle does. I do hope it’ll make me grow large again, for really", + "I’m quite tired of being such a tiny little thing!’", + "It did so indeed, and much sooner than she had expected: before she had", + "drunk half the bottle, she found her head pressing against the ceiling,", + "and had to stoop to save her neck from being broken. She hastily put", + "down the bottle, saying to herself ‘That’s quite enough--I hope I shan’t", + "grow any more--As it is, I can’t get out at the door--I do wish I hadn’t", + "drunk quite so much!’", + "Alas! it was too late to wish that! She went on growing, and growing,", + "and very soon had to kneel down on the floor: in another minute there", + "was not even room for this, and she tried the effect of lying down with", + "one elbow against the door, and the other arm curled round her head.", + "Still she went on growing, and, as a last resource, she put one arm out", + "of the window, and one foot up the chimney, and said to herself ‘Now I", + "can do no more, whatever happens. What WILL become of me?’", + "Luckily for Alice, the little magic bottle had now had its full effect,", + "and she grew no larger: still it was very uncomfortable, and, as there", + "seemed to be no sort of chance of her ever getting out of the room", + "again, no wonder she felt unhappy.", + "‘It was much pleasanter at home,’ thought poor Alice, ‘when one wasn’t", + "always growing larger and smaller, and being ordered about by mice and", + "rabbits. I almost wish I hadn’t gone down that rabbit-hole--and yet--and", + "yet--it’s rather curious, you know, this sort of life! I do wonder what", + "CAN have happened to me! When I used to read fairy-tales, I fancied that", + "kind of thing never happened, and now here I am in the middle of one!", + "There ought to be a book written about me, that there ought! And when I", + "grow up, I’ll write one--but I’m grown up now,’ she added in a sorrowful", + "tone; ‘at least there’s no room to grow up any more HERE.’", + "‘But then,’ thought Alice, ‘shall I NEVER get any older than I am", + "now? That’ll be a comfort, one way--never to be an old woman--but", + "then--always to have lessons to learn! Oh, I shouldn’t like THAT!’", + "‘Oh, you foolish Alice!’ she answered herself. ‘How can you learn", + "lessons in here? Why, there’s hardly room for YOU, and no room at all", + "for any lesson-books!’", + "And so she went on, taking first one side and then the other, and making", + "quite a conversation of it altogether; but after a few minutes she heard", + "a voice outside, and stopped to listen.", + "‘Mary Ann! Mary Ann!’ said the voice. ‘Fetch me my gloves this moment!’", + "Then came a little pattering of feet on the stairs. Alice knew it was", + "the Rabbit coming to look for her, and she trembled till she shook the", + "house, quite forgetting that she was now about a thousand times as large", + "as the Rabbit, and had no reason to be afraid of it.", + "Presently the Rabbit came up to the door, and tried to open it; but, as", + "the door opened inwards, and Alice’s elbow was pressed hard against it,", + "that attempt proved a failure. Alice heard it say to itself ‘Then I’ll", + "go round and get in at the window.’", + "‘THAT you won’t’ thought Alice, and, after waiting till she fancied", + "she heard the Rabbit just under the window, she suddenly spread out her", + "hand, and made a snatch in the air. She did not get hold of anything,", + "but she heard a little shriek and a fall, and a crash of broken glass,", + "from which she concluded that it was just possible it had fallen into a", + "cucumber-frame, or something of the sort.", + "Next came an angry voice--the Rabbit’s--‘Pat! Pat! Where are you?’ And", + "then a voice she had never heard before, ‘Sure then I’m here! Digging", + "for apples, yer honour!’", + "‘Digging for apples, indeed!’ said the Rabbit angrily. ‘Here! Come and", + "help me out of THIS!’ (Sounds of more broken glass.)", + "‘Now tell me, Pat, what’s that in the window?’", + "‘Sure, it’s an arm, yer honour!’ (He pronounced it ‘arrum.’)", + "‘An arm, you goose! Who ever saw one that size? Why, it fills the whole", + "window!’", + "‘Sure, it does, yer honour: but it’s an arm for all that.’", + "‘Well, it’s got no business there, at any rate: go and take it away!’", + "There was a long silence after this, and Alice could only hear whispers", + "now and then; such as, ‘Sure, I don’t like it, yer honour, at all, at", + "all!’ ‘Do as I tell you, you coward!’ and at last she spread out her", + "hand again, and made another snatch in the air. This time there were", + "TWO little shrieks, and more sounds of broken glass. ‘What a number of", + "cucumber-frames there must be!’ thought Alice. ‘I wonder what they’ll do", + "next! As for pulling me out of the window, I only wish they COULD! I’m", + "sure I don’t want to stay in here any longer!’", + "She waited for some time without hearing anything more: at last came a", + "rumbling of little cartwheels, and the sound of a good many voices", + "all talking together: she made out the words: ‘Where’s the other", + "ladder?--Why, I hadn’t to bring but one; Bill’s got the other--Bill!", + "fetch it here, lad!--Here, put ‘em up at this corner--No, tie ‘em", + "together first--they don’t reach half high enough yet--Oh! they’ll", + "do well enough; don’t be particular--Here, Bill! catch hold of this", + "rope--Will the roof bear?--Mind that loose slate--Oh, it’s coming", + "down! Heads below!’ (a loud crash)--‘Now, who did that?--It was Bill, I", + "fancy--Who’s to go down the chimney?--Nay, I shan’t! YOU do it!--That I", + "won’t, then!--Bill’s to go down--Here, Bill! the master says you’re to", + "go down the chimney!’", + "‘Oh! So Bill’s got to come down the chimney, has he?’ said Alice to", + "herself. ‘Shy, they seem to put everything upon Bill! I wouldn’t be in", + "Bill’s place for a good deal: this fireplace is narrow, to be sure; but", + "I THINK I can kick a little!’", + "She drew her foot as far down the chimney as she could, and waited", + "till she heard a little animal (she couldn’t guess of what sort it was)", + "scratching and scrambling about in the chimney close above her: then,", + "saying to herself ‘This is Bill,’ she gave one sharp kick, and waited to", + "see what would happen next.", + "The first thing she heard was a general chorus of ‘There goes Bill!’", + "then the Rabbit’s voice along--‘Catch him, you by the hedge!’ then", + "silence, and then another confusion of voices--‘Hold up his head--Brandy", + "now--Don’t choke him--How was it, old fellow? What happened to you? Tell", + "us all about it!’", + "Last came a little feeble, squeaking voice, [‘That’s Bill,’ thought", + "Alice,) ‘Well, I hardly know--No more, thank ye; I’m better now--but I’m", + "a deal too flustered to tell you--all I know is, something comes at me", + "like a Jack-in-the-box, and up I goes like a sky-rocket!’", + "‘So you did, old fellow!’ said the others.", + "‘We must burn the house down!’ said the Rabbit’s voice; and Alice called", + "out as loud as she could, ‘If you do. I’ll set Dinah at you!’", + "There was a dead silence instantly, and Alice thought to herself, ‘I", + "wonder what they WILL do next! If they had any sense, they’d take the", + "roof off.’ After a minute or two, they began moving about again, and", + "Alice heard the Rabbit say, ‘A barrowful will do, to begin with.’", + "‘A barrowful of WHAT?’ thought Alice; but she had not long to doubt,", + "for the next moment a shower of little pebbles came rattling in at the", + "window, and some of them hit her in the face. ‘I’ll put a stop to this,’", + "she said to herself, and shouted out, ‘You’d better not do that again!’", + "which produced another dead silence.", + "Alice noticed with some surprise that the pebbles were all turning into", + "little cakes as they lay on the floor, and a bright idea came into her", + "head. ‘If I eat one of these cakes,’ she thought, ‘it’s sure to make", + "SOME change in my size; and as it can’t possibly make me larger, it must", + "make me smaller, I suppose.’", + "So she swallowed one of the cakes, and was delighted to find that she", + "began shrinking directly. As soon as she was small enough to get through", + "the door, she ran out of the house, and found quite a crowd of little", + "animals and birds waiting outside. The poor little Lizard, Bill, was", + "in the middle, being held up by two guinea-pigs, who were giving it", + "something out of a bottle. They all made a rush at Alice the moment she", + "appeared; but she ran off as hard as she could, and soon found herself", + "safe in a thick wood.", + "‘The first thing I’ve got to do,’ said Alice to herself, as she wandered", + "about in the wood, ‘is to grow to my right size again; and the second", + "thing is to find my way into that lovely garden. I think that will be", + "the best plan.’", + "It sounded an excellent plan, no doubt, and very neatly and simply", + "arranged; the only difficulty was, that she had not the smallest idea", + "how to set about it; and while she was peering about anxiously among", + "the trees, a little sharp bark just over her head made her look up in a", + "great hurry.", + "An enormous puppy was looking down at her with large round eyes, and", + "feebly stretching out one paw, trying to touch her. ‘Poor little thing!’", + "said Alice, in a coaxing tone, and she tried hard to whistle to it; but", + "she was terribly frightened all the time at the thought that it might be", + "hungry, in which case it would be very likely to eat her up in spite of", + "all her coaxing.", + "Hardly knowing what she did, she picked up a little bit of stick, and", + "held it out to the puppy; whereupon the puppy jumped into the air off", + "all its feet at once, with a yelp of delight, and rushed at the stick,", + "and made believe to worry it; then Alice dodged behind a great thistle,", + "to keep herself from being run over; and the moment she appeared on the", + "other side, the puppy made another rush at the stick, and tumbled head", + "over heels in its hurry to get hold of it; then Alice, thinking it was", + "very like having a game of play with a cart-horse, and expecting every", + "moment to be trampled under its feet, ran round the thistle again; then", + "the puppy began a series of short charges at the stick, running a very", + "little way forwards each time and a long way back, and barking hoarsely", + "all the while, till at last it sat down a good way off, panting, with", + "its tongue hanging out of its mouth, and its great eyes half shut.", + "This seemed to Alice a good opportunity for making her escape; so she", + "set off at once, and ran till she was quite tired and out of breath, and", + "till the puppy’s bark sounded quite faint in the distance.", + "‘And yet what a dear little puppy it was!’ said Alice, as she leant", + "against a buttercup to rest herself, and fanned herself with one of the", + "leaves: ‘I should have liked teaching it tricks very much, if--if I’d", + "only been the right size to do it! Oh dear! I’d nearly forgotten that", + "I’ve got to grow up again! Let me see--how IS it to be managed? I", + "suppose I ought to eat or drink something or other; but the great", + "question is, what?’", + "The great question certainly was, what? Alice looked all round her at", + "the flowers and the blades of grass, but she did not see anything that", + "looked like the right thing to eat or drink under the circumstances.", + "There was a large mushroom growing near her, about the same height as", + "herself; and when she had looked under it, and on both sides of it, and", + "behind it, it occurred to her that she might as well look and see what", + "was on the top of it.", + "She stretched herself up on tiptoe, and peeped over the edge of the", + "mushroom, and her eyes immediately met those of a large caterpillar,", + "that was sitting on the top with its arms folded, quietly smoking a long", + "hookah, and taking not the smallest notice of her or of anything else.", + "CHAPTER V. Advice from a Caterpillar", + "The Caterpillar and Alice looked at each other for some time in silence:", + "at last the Caterpillar took the hookah out of its mouth, and addressed", + "her in a languid, sleepy voice.", + "‘Who are YOU?’ said the Caterpillar.", + "This was not an encouraging opening for a conversation. Alice replied,", + "rather shyly, ‘I--I hardly know, sir, just at present--at least I know", + "who I WAS when I got up this morning, but I think I must have been", + "changed several times since then.’", + "‘What do you mean by that?’ said the Caterpillar sternly. ‘Explain", + "yourself!’", + "‘I can’t explain MYSELF, I’m afraid, sir’ said Alice, ‘because I’m not", + "myself, you see.’", + "‘I don’t see,’ said the Caterpillar.", + "‘I’m afraid I can’t put it more clearly,’ Alice replied very politely,", + "‘for I can’t understand it myself to begin with; and being so many", + "different sizes in a day is very confusing.’", + "‘It isn’t,’ said the Caterpillar.", + "‘Well, perhaps you haven’t found it so yet,’ said Alice; ‘but when you", + "have to turn into a chrysalis--you will some day, you know--and then", + "after that into a butterfly, I should think you’ll feel it a little", + "queer, won’t you?’", + "‘Not a bit,’ said the Caterpillar.", + "‘Well, perhaps your feelings may be different,’ said Alice; ‘all I know", + "is, it would feel very queer to ME.’", + "‘You!’ said the Caterpillar contemptuously. ‘Who are YOU?’", + "Which brought them back again to the beginning of the conversation.", + "Alice felt a little irritated at the Caterpillar’s making such VERY", + "short remarks, and she drew herself up and said, very gravely, ‘I think,", + "you ought to tell me who YOU are, first.’", + "‘Why?’ said the Caterpillar.", + "Here was another puzzling question; and as Alice could not think of any", + "good reason, and as the Caterpillar seemed to be in a VERY unpleasant", + "state of mind, she turned away.", + "‘Come back!’ the Caterpillar called after her. ‘I’ve something important", + "to say!’", + "This sounded promising, certainly: Alice turned and came back again.", + "‘Keep your temper,’ said the Caterpillar.", + "‘Is that all?’ said Alice, swallowing down her anger as well as she", + "could.", + "‘No,’ said the Caterpillar.", + "Alice thought she might as well wait, as she had nothing else to do, and", + "perhaps after all it might tell her something worth hearing. For some", + "minutes it puffed away without speaking, but at last it unfolded its", + "arms, took the hookah out of its mouth again, and said, ‘So you think", + "you’re changed, do you?’", + "‘I’m afraid I am, sir,’ said Alice; ‘I can’t remember things as I", + "used--and I don’t keep the same size for ten minutes together!’", + "‘Can’t remember WHAT things?’ said the Caterpillar.", + "‘Well, I’ve tried to say “HOW DOTH THE LITTLE BUSY BEE,” but it all came", + "different!’ Alice replied in a very melancholy voice.", + "‘Repeat, “YOU ARE OLD, FATHER WILLIAM,”’ said the Caterpillar.", + "Alice folded her hands, and began:--", + " ‘You are old, Father William,’ the young man said,", + " ‘And your hair has become very white;", + " And yet you incessantly stand on your head--", + " Do you think, at your age, it is right?’", + " ‘In my youth,’ Father William replied to his son,", + " ‘I feared it might injure the brain;", + " But, now that I’m perfectly sure I have none,", + " Why, I do it again and again.’", + " ‘You are old,’ said the youth, ‘as I mentioned before,", + " And have grown most uncommonly fat;", + " Yet you turned a back-somersault in at the door--", + " Pray, what is the reason of that?’", + " ‘In my youth,’ said the sage, as he shook his grey locks,", + " ‘I kept all my limbs very supple", + " By the use of this ointment--one shilling the box--", + " Allow me to sell you a couple?’", + " ‘You are old,’ said the youth, ‘and your jaws are too weak", + " For anything tougher than suet;", + " Yet you finished the goose, with the bones and the beak--", + " Pray how did you manage to do it?’", + " ‘In my youth,’ said his father, ‘I took to the law,", + " And argued each case with my wife;", + " And the muscular strength, which it gave to my jaw,", + " Has lasted the rest of my life.’", + " ‘You are old,’ said the youth, ‘one would hardly suppose", + " That your eye was as steady as ever;", + " Yet you balanced an eel on the end of your nose--", + " What made you so awfully clever?’", + " ‘I have answered three questions, and that is enough,’", + " Said his father; ‘don’t give yourself airs!", + " Do you think I can listen all day to such stuff?", + " Be off, or I’ll kick you down stairs!’", + "‘That is not said right,’ said the Caterpillar.", + "‘Not QUITE right, I’m afraid,’ said Alice, timidly; ‘some of the words", + "have got altered.’", + "‘It is wrong from beginning to end,’ said the Caterpillar decidedly, and", + "there was silence for some minutes.", + "The Caterpillar was the first to speak.", + "‘What size do you want to be?’ it asked.", + "‘Oh, I’m not particular as to size,’ Alice hastily replied; ‘only one", + "doesn’t like changing so often, you know.’", + "‘I DON’T know,’ said the Caterpillar.", + "Alice said nothing: she had never been so much contradicted in her life", + "before, and she felt that she was losing her temper.", + "‘Are you content now?’ said the Caterpillar.", + "‘Well, I should like to be a LITTLE larger, sir, if you wouldn’t mind,’", + "said Alice: ‘three inches is such a wretched height to be.’", + "‘It is a very good height indeed!’ said the Caterpillar angrily, rearing", + "itself upright as it spoke (it was exactly three inches high).", + "‘But I’m not used to it!’ pleaded poor Alice in a piteous tone. And", + "she thought of herself, ‘I wish the creatures wouldn’t be so easily", + "offended!’", + "‘You’ll get used to it in time,’ said the Caterpillar; and it put the", + "hookah into its mouth and began smoking again.", + "This time Alice waited patiently until it chose to speak again. In", + "a minute or two the Caterpillar took the hookah out of its mouth", + "and yawned once or twice, and shook itself. Then it got down off the", + "mushroom, and crawled away in the grass, merely remarking as it went,", + "‘One side will make you grow taller, and the other side will make you", + "grow shorter.’", + "‘One side of WHAT? The other side of WHAT?’ thought Alice to herself.", + "‘Of the mushroom,’ said the Caterpillar, just as if she had asked it", + "aloud; and in another moment it was out of sight.", + "Alice remained looking thoughtfully at the mushroom for a minute, trying", + "to make out which were the two sides of it; and as it was perfectly", + "round, she found this a very difficult question. However, at last she", + "stretched her arms round it as far as they would go, and broke off a bit", + "of the edge with each hand.", + "‘And now which is which?’ she said to herself, and nibbled a little of", + "the right-hand bit to try the effect: the next moment she felt a violent", + "blow underneath her chin: it had struck her foot!", + "She was a good deal frightened by this very sudden change, but she felt", + "that there was no time to be lost, as she was shrinking rapidly; so she", + "set to work at once to eat some of the other bit. Her chin was pressed", + "so closely against her foot, that there was hardly room to open her", + "mouth; but she did it at last, and managed to swallow a morsel of the", + "lefthand bit.", + " * * * * * * *", + " * * * * * *", + " * * * * * * *", + "‘Come, my head’s free at last!’ said Alice in a tone of delight, which", + "changed into alarm in another moment, when she found that her shoulders", + "were nowhere to be found: all she could see, when she looked down, was", + "an immense length of neck, which seemed to rise like a stalk out of a", + "sea of green leaves that lay far below her.", + "‘What CAN all that green stuff be?’ said Alice. ‘And where HAVE my", + "shoulders got to? And oh, my poor hands, how is it I can’t see you?’", + "She was moving them about as she spoke, but no result seemed to follow,", + "except a little shaking among the distant green leaves.", + "As there seemed to be no chance of getting her hands up to her head, she", + "tried to get her head down to them, and was delighted to find that her", + "neck would bend about easily in any direction, like a serpent. She had", + "just succeeded in curving it down into a graceful zigzag, and was going", + "to dive in among the leaves, which she found to be nothing but the tops", + "of the trees under which she had been wandering, when a sharp hiss made", + "her draw back in a hurry: a large pigeon had flown into her face, and", + "was beating her violently with its wings.", + "‘Serpent!’ screamed the Pigeon.", + "‘I’m NOT a serpent!’ said Alice indignantly. ‘Let me alone!’", + "‘Serpent, I say again!’ repeated the Pigeon, but in a more subdued tone,", + "and added with a kind of sob, ‘I’ve tried every way, and nothing seems", + "to suit them!’", + "‘I haven’t the least idea what you’re talking about,’ said Alice.", + "‘I’ve tried the roots of trees, and I’ve tried banks, and I’ve tried", + "hedges,’ the Pigeon went on, without attending to her; ‘but those", + "serpents! There’s no pleasing them!’", + "Alice was more and more puzzled, but she thought there was no use in", + "saying anything more till the Pigeon had finished.", + "‘As if it wasn’t trouble enough hatching the eggs,’ said the Pigeon;", + "‘but I must be on the look-out for serpents night and day! Why, I", + "haven’t had a wink of sleep these three weeks!’", + "‘I’m very sorry you’ve been annoyed,’ said Alice, who was beginning to", + "see its meaning.", + "‘And just as I’d taken the highest tree in the wood,’ continued the", + "Pigeon, raising its voice to a shriek, ‘and just as I was thinking I", + "should be free of them at last, they must needs come wriggling down from", + "the sky! Ugh, Serpent!’", + "‘But I’m NOT a serpent, I tell you!’ said Alice. ‘I’m a--I’m a--’", + "‘Well! WHAT are you?’ said the Pigeon. ‘I can see you’re trying to", + "invent something!’", + "‘I--I’m a little girl,’ said Alice, rather doubtfully, as she remembered", + "the number of changes she had gone through that day.", + "‘A likely story indeed!’ said the Pigeon in a tone of the deepest", + "contempt. ‘I’ve seen a good many little girls in my time, but never ONE", + "with such a neck as that! No, no! You’re a serpent; and there’s no use", + "denying it. I suppose you’ll be telling me next that you never tasted an", + "egg!’", + "‘I HAVE tasted eggs, certainly,’ said Alice, who was a very truthful", + "child; ‘but little girls eat eggs quite as much as serpents do, you", + "know.’", + "‘I don’t believe it,’ said the Pigeon; ‘but if they do, why then they’re", + "a kind of serpent, that’s all I can say.’", + "This was such a new idea to Alice, that she was quite silent for a", + "minute or two, which gave the Pigeon the opportunity of adding, ‘You’re", + "looking for eggs, I know THAT well enough; and what does it matter to me", + "whether you’re a little girl or a serpent?’", + "‘It matters a good deal to ME,’ said Alice hastily; ‘but I’m not looking", + "for eggs, as it happens; and if I was, I shouldn’t want YOURS: I don’t", + "like them raw.’", + "‘Well, be off, then!’ said the Pigeon in a sulky tone, as it settled", + "down again into its nest. Alice crouched down among the trees as well as", + "she could, for her neck kept getting entangled among the branches, and", + "every now and then she had to stop and untwist it. After a while she", + "remembered that she still held the pieces of mushroom in her hands, and", + "she set to work very carefully, nibbling first at one and then at the", + "other, and growing sometimes taller and sometimes shorter, until she had", + "succeeded in bringing herself down to her usual height.", + "It was so long since she had been anything near the right size, that it", + "felt quite strange at first; but she got used to it in a few minutes,", + "and began talking to herself, as usual. ‘Come, there’s half my plan done", + "now! How puzzling all these changes are! I’m never sure what I’m going", + "to be, from one minute to another! However, I’ve got back to my right", + "size: the next thing is, to get into that beautiful garden--how IS that", + "to be done, I wonder?’ As she said this, she came suddenly upon an open", + "place, with a little house in it about four feet high. ‘Whoever lives", + "there,’ thought Alice, ‘it’ll never do to come upon them THIS size: why,", + "I should frighten them out of their wits!’ So she began nibbling at the", + "righthand bit again, and did not venture to go near the house till she", + "had brought herself down to nine inches high.", + "CHAPTER VI. Pig and Pepper", + "For a minute or two she stood looking at the house, and wondering what", + "to do next, when suddenly a footman in livery came running out of the", + "wood--(she considered him to be a footman because he was in livery:", + "otherwise, judging by his face only, she would have called him a", + "fish)--and rapped loudly at the door with his knuckles. It was opened", + "by another footman in livery, with a round face, and large eyes like a", + "frog; and both footmen, Alice noticed, had powdered hair that curled all", + "over their heads. She felt very curious to know what it was all about,", + "and crept a little way out of the wood to listen.", + "The Fish-Footman began by producing from under his arm a great letter,", + "nearly as large as himself, and this he handed over to the other,", + "saying, in a solemn tone, ‘For the Duchess. An invitation from the Queen", + "to play croquet.’ The Frog-Footman repeated, in the same solemn tone,", + "only changing the order of the words a little, ‘From the Queen. An", + "invitation for the Duchess to play croquet.’", + "Then they both bowed low, and their curls got entangled together.", + "Alice laughed so much at this, that she had to run back into the", + "wood for fear of their hearing her; and when she next peeped out the", + "Fish-Footman was gone, and the other was sitting on the ground near the", + "door, staring stupidly up into the sky.", + "Alice went timidly up to the door, and knocked.", + "‘There’s no sort of use in knocking,’ said the Footman, ‘and that for", + "two reasons. First, because I’m on the same side of the door as you", + "are; secondly, because they’re making such a noise inside, no one could", + "possibly hear you.’ And certainly there was a most extraordinary noise", + "going on within--a constant howling and sneezing, and every now and then", + "a great crash, as if a dish or kettle had been broken to pieces.", + "‘Please, then,’ said Alice, ‘how am I to get in?’", + "‘There might be some sense in your knocking,’ the Footman went on", + "without attending to her, ‘if we had the door between us. For instance,", + "if you were INSIDE, you might knock, and I could let you out, you know.’", + "He was looking up into the sky all the time he was speaking, and this", + "Alice thought decidedly uncivil. ‘But perhaps he can’t help it,’ she", + "said to herself; ‘his eyes are so VERY nearly at the top of his head.", + "But at any rate he might answer questions.--How am I to get in?’ she", + "repeated, aloud.", + "‘I shall sit here,’ the Footman remarked, ‘till tomorrow--’", + "At this moment the door of the house opened, and a large plate came", + "skimming out, straight at the Footman’s head: it just grazed his nose,", + "and broke to pieces against one of the trees behind him.", + "‘--or next day, maybe,’ the Footman continued in the same tone, exactly", + "as if nothing had happened.", + "‘How am I to get in?’ asked Alice again, in a louder tone.", + "‘ARE you to get in at all?’ said the Footman. ‘That’s the first", + "question, you know.’", + "It was, no doubt: only Alice did not like to be told so. ‘It’s really", + "dreadful,’ she muttered to herself, ‘the way all the creatures argue.", + "It’s enough to drive one crazy!’", + "The Footman seemed to think this a good opportunity for repeating his", + "remark, with variations. ‘I shall sit here,’ he said, ‘on and off, for", + "days and days.’", + "‘But what am I to do?’ said Alice.", + "‘Anything you like,’ said the Footman, and began whistling.", + "‘Oh, there’s no use in talking to him,’ said Alice desperately: ‘he’s", + "perfectly idiotic!’ And she opened the door and went in.", + "The door led right into a large kitchen, which was full of smoke from", + "one end to the other: the Duchess was sitting on a three-legged stool in", + "the middle, nursing a baby; the cook was leaning over the fire, stirring", + "a large cauldron which seemed to be full of soup.", + "‘There’s certainly too much pepper in that soup!’ Alice said to herself,", + "as well as she could for sneezing.", + "There was certainly too much of it in the air. Even the Duchess", + "sneezed occasionally; and as for the baby, it was sneezing and howling", + "alternately without a moment’s pause. The only things in the kitchen", + "that did not sneeze, were the cook, and a large cat which was sitting on", + "the hearth and grinning from ear to ear.", + "‘Please would you tell me,’ said Alice, a little timidly, for she was", + "not quite sure whether it was good manners for her to speak first, ‘why", + "your cat grins like that?’", + "‘It’s a Cheshire cat,’ said the Duchess, ‘and that’s why. Pig!’", + "She said the last word with such sudden violence that Alice quite", + "jumped; but she saw in another moment that it was addressed to the baby,", + "and not to her, so she took courage, and went on again:--", + "‘I didn’t know that Cheshire cats always grinned; in fact, I didn’t know", + "that cats COULD grin.’", + "‘They all can,’ said the Duchess; ‘and most of ‘em do.’", + "‘I don’t know of any that do,’ Alice said very politely, feeling quite", + "pleased to have got into a conversation.", + "‘You don’t know much,’ said the Duchess; ‘and that’s a fact.’", + "Alice did not at all like the tone of this remark, and thought it would", + "be as well to introduce some other subject of conversation. While she", + "was trying to fix on one, the cook took the cauldron of soup off the", + "fire, and at once set to work throwing everything within her reach at", + "the Duchess and the baby--the fire-irons came first; then followed a", + "shower of saucepans, plates, and dishes. The Duchess took no notice of", + "them even when they hit her; and the baby was howling so much already,", + "that it was quite impossible to say whether the blows hurt it or not.", + "‘Oh, PLEASE mind what you’re doing!’ cried Alice, jumping up and down in", + "an agony of terror. ‘Oh, there goes his PRECIOUS nose’; as an unusually", + "large saucepan flew close by it, and very nearly carried it off.", + "‘If everybody minded their own business,’ the Duchess said in a hoarse", + "growl, ‘the world would go round a deal faster than it does.’", + "‘Which would NOT be an advantage,’ said Alice, who felt very glad to get", + "an opportunity of showing off a little of her knowledge. ‘Just think of", + "what work it would make with the day and night! You see the earth takes", + "twenty-four hours to turn round on its axis--’", + "‘Talking of axes,’ said the Duchess, ‘chop off her head!’", + "Alice glanced rather anxiously at the cook, to see if she meant to take", + "the hint; but the cook was busily stirring the soup, and seemed not to", + "be listening, so she went on again: ‘Twenty-four hours, I THINK; or is", + "it twelve? I--’", + "‘Oh, don’t bother ME,’ said the Duchess; ‘I never could abide figures!’", + "And with that she began nursing her child again, singing a sort of", + "lullaby to it as she did so, and giving it a violent shake at the end of", + "every line:", + " ‘Speak roughly to your little boy,", + " And beat him when he sneezes:", + " He only does it to annoy,", + " Because he knows it teases.’", + " CHORUS.", + " (In which the cook and the baby joined):--", + " ‘Wow! wow! wow!’", + "While the Duchess sang the second verse of the song, she kept tossing", + "the baby violently up and down, and the poor little thing howled so,", + "that Alice could hardly hear the words:--", + " ‘I speak severely to my boy,", + " I beat him when he sneezes;", + " For he can thoroughly enjoy", + " The pepper when he pleases!’", + " CHORUS.", + " ‘Wow! wow! wow!’", + "‘Here! you may nurse it a bit, if you like!’ the Duchess said to Alice,", + "flinging the baby at her as she spoke. ‘I must go and get ready to play", + "croquet with the Queen,’ and she hurried out of the room. The cook threw", + "a frying-pan after her as she went out, but it just missed her.", + "Alice caught the baby with some difficulty, as it was a queer-shaped", + "little creature, and held out its arms and legs in all directions, ‘just", + "like a star-fish,’ thought Alice. The poor little thing was snorting", + "like a steam-engine when she caught it, and kept doubling itself up and", + "straightening itself out again, so that altogether, for the first minute", + "or two, it was as much as she could do to hold it.", + "As soon as she had made out the proper way of nursing it, (which was to", + "twist it up into a sort of knot, and then keep tight hold of its right", + "ear and left foot, so as to prevent its undoing itself,) she carried", + "it out into the open air. ‘IF I don’t take this child away with me,’", + "thought Alice, ‘they’re sure to kill it in a day or two: wouldn’t it be", + "murder to leave it behind?’ She said the last words out loud, and the", + "little thing grunted in reply (it had left off sneezing by this time).", + "‘Don’t grunt,’ said Alice; ‘that’s not at all a proper way of expressing", + "yourself.’", + "The baby grunted again, and Alice looked very anxiously into its face to", + "see what was the matter with it. There could be no doubt that it had", + "a VERY turn-up nose, much more like a snout than a real nose; also its", + "eyes were getting extremely small for a baby: altogether Alice did not", + "like the look of the thing at all. ‘But perhaps it was only sobbing,’", + "she thought, and looked into its eyes again, to see if there were any", + "tears.", + "No, there were no tears. ‘If you’re going to turn into a pig, my dear,’", + "said Alice, seriously, ‘I’ll have nothing more to do with you. Mind", + "now!’ The poor little thing sobbed again (or grunted, it was impossible", + "to say which), and they went on for some while in silence.", + "Alice was just beginning to think to herself, ‘Now, what am I to do with", + "this creature when I get it home?’ when it grunted again, so violently,", + "that she looked down into its face in some alarm. This time there could", + "be NO mistake about it: it was neither more nor less than a pig, and she", + "felt that it would be quite absurd for her to carry it further.", + "So she set the little creature down, and felt quite relieved to see", + "it trot away quietly into the wood. ‘If it had grown up,’ she said", + "to herself, ‘it would have made a dreadfully ugly child: but it makes", + "rather a handsome pig, I think.’ And she began thinking over other", + "children she knew, who might do very well as pigs, and was just saying", + "to herself, ‘if one only knew the right way to change them--’ when she", + "was a little startled by seeing the Cheshire Cat sitting on a bough of a", + "tree a few yards off.", + "The Cat only grinned when it saw Alice. It looked good-natured, she", + "thought: still it had VERY long claws and a great many teeth, so she", + "felt that it ought to be treated with respect.", + "‘Cheshire Puss,’ she began, rather timidly, as she did not at all know", + "whether it would like the name: however, it only grinned a little wider.", + "‘Come, it’s pleased so far,’ thought Alice, and she went on. ‘Would you", + "tell me, please, which way I ought to go from here?’", + "‘That depends a good deal on where you want to get to,’ said the Cat.", + "‘I don’t much care where--’ said Alice.", + "‘Then it doesn’t matter which way you go,’ said the Cat.", + "‘--so long as I get SOMEWHERE,’ Alice added as an explanation.", + "‘Oh, you’re sure to do that,’ said the Cat, ‘if you only walk long", + "enough.’", + "Alice felt that this could not be denied, so she tried another question.", + "‘What sort of people live about here?’", + "‘In THAT direction,’ the Cat said, waving its right paw round, ‘lives", + "a Hatter: and in THAT direction,’ waving the other paw, ‘lives a March", + "Hare. Visit either you like: they’re both mad.’", + "‘But I don’t want to go among mad people,’ Alice remarked.", + "‘Oh, you can’t help that,’ said the Cat: ‘we’re all mad here. I’m mad.", + "You’re mad.’", + "‘How do you know I’m mad?’ said Alice.", + "‘You must be,’ said the Cat, ‘or you wouldn’t have come here.’", + "Alice didn’t think that proved it at all; however, she went on ‘And how", + "do you know that you’re mad?’", + "‘To begin with,’ said the Cat, ‘a dog’s not mad. You grant that?’", + "‘I suppose so,’ said Alice.", + "‘Well, then,’ the Cat went on, ‘you see, a dog growls when it’s angry,", + "and wags its tail when it’s pleased. Now I growl when I’m pleased, and", + "wag my tail when I’m angry. Therefore I’m mad.’", + "‘I call it purring, not growling,’ said Alice.", + "‘Call it what you like,’ said the Cat. ‘Do you play croquet with the", + "Queen to-day?’", + "‘I should like it very much,’ said Alice, ‘but I haven’t been invited", + "yet.’", + "‘You’ll see me there,’ said the Cat, and vanished.", + "Alice was not much surprised at this, she was getting so used to queer", + "things happening. While she was looking at the place where it had been,", + "it suddenly appeared again.", + "‘By-the-bye, what became of the baby?’ said the Cat. ‘I’d nearly", + "forgotten to ask.’", + "‘It turned into a pig,’ Alice quietly said, just as if it had come back", + "in a natural way.", + "‘I thought it would,’ said the Cat, and vanished again.", + "Alice waited a little, half expecting to see it again, but it did not", + "appear, and after a minute or two she walked on in the direction in", + "which the March Hare was said to live. ‘I’ve seen hatters before,’ she", + "said to herself; ‘the March Hare will be much the most interesting, and", + "perhaps as this is May it won’t be raving mad--at least not so mad as", + "it was in March.’ As she said this, she looked up, and there was the Cat", + "again, sitting on a branch of a tree.", + "‘Did you say pig, or fig?’ said the Cat.", + "‘I said pig,’ replied Alice; ‘and I wish you wouldn’t keep appearing and", + "vanishing so suddenly: you make one quite giddy.’", + "‘All right,’ said the Cat; and this time it vanished quite slowly,", + "beginning with the end of the tail, and ending with the grin, which", + "remained some time after the rest of it had gone.", + "‘Well! I’ve often seen a cat without a grin,’ thought Alice; ‘but a grin", + "without a cat! It’s the most curious thing I ever saw in my life!’", + "She had not gone much farther before she came in sight of the house", + "of the March Hare: she thought it must be the right house, because the", + "chimneys were shaped like ears and the roof was thatched with fur. It", + "was so large a house, that she did not like to go nearer till she had", + "nibbled some more of the lefthand bit of mushroom, and raised herself to", + "about two feet high: even then she walked up towards it rather timidly,", + "saying to herself ‘Suppose it should be raving mad after all! I almost", + "wish I’d gone to see the Hatter instead!’", + "CHAPTER VII. A Mad Tea-Party", + "There was a table set out under a tree in front of the house, and the", + "March Hare and the Hatter were having tea at it: a Dormouse was sitting", + "between them, fast asleep, and the other two were using it as a", + "cushion, resting their elbows on it, and talking over its head. ‘Very", + "uncomfortable for the Dormouse,’ thought Alice; ‘only, as it’s asleep, I", + "suppose it doesn’t mind.’", + "The table was a large one, but the three were all crowded together at", + "one corner of it: ‘No room! No room!’ they cried out when they saw Alice", + "coming. ‘There’s PLENTY of room!’ said Alice indignantly, and she sat", + "down in a large arm-chair at one end of the table.", + "‘Have some wine,’ the March Hare said in an encouraging tone.", + "Alice looked all round the table, but there was nothing on it but tea.", + "‘I don’t see any wine,’ she remarked.", + "‘There isn’t any,’ said the March Hare.", + "‘Then it wasn’t very civil of you to offer it,’ said Alice angrily.", + "‘It wasn’t very civil of you to sit down without being invited,’ said", + "the March Hare.", + "‘I didn’t know it was YOUR table,’ said Alice; ‘it’s laid for a great", + "many more than three.’", + "‘Your hair wants cutting,’ said the Hatter. He had been looking at Alice", + "for some time with great curiosity, and this was his first speech.", + "‘You should learn not to make personal remarks,’ Alice said with some", + "severity; ‘it’s very rude.’", + "The Hatter opened his eyes very wide on hearing this; but all he SAID", + "was, ‘Why is a raven like a writing-desk?’", + "‘Come, we shall have some fun now!’ thought Alice. ‘I’m glad they’ve", + "begun asking riddles.--I believe I can guess that,’ she added aloud.", + "‘Do you mean that you think you can find out the answer to it?’ said the", + "March Hare.", + "‘Exactly so,’ said Alice.", + "‘Then you should say what you mean,’ the March Hare went on.", + "‘I do,’ Alice hastily replied; ‘at least--at least I mean what I", + "say--that’s the same thing, you know.’", + "‘Not the same thing a bit!’ said the Hatter. ‘You might just as well say", + "that “I see what I eat” is the same thing as “I eat what I see”!’", + "‘You might just as well say,’ added the March Hare, ‘that “I like what I", + "get” is the same thing as “I get what I like”!’", + "‘You might just as well say,’ added the Dormouse, who seemed to be", + "talking in his sleep, ‘that “I breathe when I sleep” is the same thing", + "as “I sleep when I breathe”!’", + "‘It IS the same thing with you,’ said the Hatter, and here the", + "conversation dropped, and the party sat silent for a minute, while Alice", + "thought over all she could remember about ravens and writing-desks,", + "which wasn’t much.", + "The Hatter was the first to break the silence. ‘What day of the month", + "is it?’ he said, turning to Alice: he had taken his watch out of his", + "pocket, and was looking at it uneasily, shaking it every now and then,", + "and holding it to his ear.", + "Alice considered a little, and then said ‘The fourth.’", + "‘Two days wrong!’ sighed the Hatter. ‘I told you butter wouldn’t suit", + "the works!’ he added looking angrily at the March Hare.", + "‘It was the BEST butter,’ the March Hare meekly replied.", + "‘Yes, but some crumbs must have got in as well,’ the Hatter grumbled:", + "‘you shouldn’t have put it in with the bread-knife.’", + "The March Hare took the watch and looked at it gloomily: then he dipped", + "it into his cup of tea, and looked at it again: but he could think of", + "nothing better to say than his first remark, ‘It was the BEST butter,", + "you know.’", + "Alice had been looking over his shoulder with some curiosity. ‘What a", + "funny watch!’ she remarked. ‘It tells the day of the month, and doesn’t", + "tell what o’clock it is!’", + "‘Why should it?’ muttered the Hatter. ‘Does YOUR watch tell you what", + "year it is?’", + "‘Of course not,’ Alice replied very readily: ‘but that’s because it", + "stays the same year for such a long time together.’", + "‘Which is just the case with MINE,’ said the Hatter.", + "Alice felt dreadfully puzzled. The Hatter’s remark seemed to have no", + "sort of meaning in it, and yet it was certainly English. ‘I don’t quite", + "understand you,’ she said, as politely as she could.", + "‘The Dormouse is asleep again,’ said the Hatter, and he poured a little", + "hot tea upon its nose.", + "The Dormouse shook its head impatiently, and said, without opening its", + "eyes, ‘Of course, of course; just what I was going to remark myself.’", + "‘Have you guessed the riddle yet?’ the Hatter said, turning to Alice", + "again.", + "‘No, I give it up,’ Alice replied: ‘what’s the answer?’", + "‘I haven’t the slightest idea,’ said the Hatter.", + "‘Nor I,’ said the March Hare.", + "Alice sighed wearily. ‘I think you might do something better with the", + "time,’ she said, ‘than waste it in asking riddles that have no answers.’", + "‘If you knew Time as well as I do,’ said the Hatter, ‘you wouldn’t talk", + "about wasting IT. It’s HIM.’", + "‘I don’t know what you mean,’ said Alice.", + "‘Of course you don’t!’ the Hatter said, tossing his head contemptuously.", + "‘I dare say you never even spoke to Time!’", + "‘Perhaps not,’ Alice cautiously replied: ‘but I know I have to beat time", + "when I learn music.’", + "‘Ah! that accounts for it,’ said the Hatter. ‘He won’t stand beating.", + "Now, if you only kept on good terms with him, he’d do almost anything", + "you liked with the clock. For instance, suppose it were nine o’clock in", + "the morning, just time to begin lessons: you’d only have to whisper a", + "hint to Time, and round goes the clock in a twinkling! Half-past one,", + "time for dinner!’", + "[‘I only wish it was,’ the March Hare said to itself in a whisper.)", + "‘That would be grand, certainly,’ said Alice thoughtfully: ‘but then--I", + "shouldn’t be hungry for it, you know.’", + "‘Not at first, perhaps,’ said the Hatter: ‘but you could keep it to", + "half-past one as long as you liked.’", + "‘Is that the way YOU manage?’ Alice asked.", + "The Hatter shook his head mournfully. ‘Not I!’ he replied. ‘We", + "quarrelled last March--just before HE went mad, you know--’ (pointing", + "with his tea spoon at the March Hare,) ‘--it was at the great concert", + "given by the Queen of Hearts, and I had to sing", + " “Twinkle, twinkle, little bat!", + " How I wonder what you’re at!”", + "You know the song, perhaps?’", + "‘I’ve heard something like it,’ said Alice.", + "‘It goes on, you know,’ the Hatter continued, ‘in this way:--", + " “Up above the world you fly,", + " Like a tea-tray in the sky.", + " Twinkle, twinkle--“’", + "Here the Dormouse shook itself, and began singing in its sleep ‘Twinkle,", + "twinkle, twinkle, twinkle--’ and went on so long that they had to pinch", + "it to make it stop.", + "‘Well, I’d hardly finished the first verse,’ said the Hatter, ‘when the", + "Queen jumped up and bawled out, “He’s murdering the time! Off with his", + "head!”’", + "‘How dreadfully savage!’ exclaimed Alice.", + "‘And ever since that,’ the Hatter went on in a mournful tone, ‘he won’t", + "do a thing I ask! It’s always six o’clock now.’", + "A bright idea came into Alice’s head. ‘Is that the reason so many", + "tea-things are put out here?’ she asked.", + "‘Yes, that’s it,’ said the Hatter with a sigh: ‘it’s always tea-time,", + "and we’ve no time to wash the things between whiles.’", + "‘Then you keep moving round, I suppose?’ said Alice.", + "‘Exactly so,’ said the Hatter: ‘as the things get used up.’", + "‘But what happens when you come to the beginning again?’ Alice ventured", + "to ask.", + "‘Suppose we change the subject,’ the March Hare interrupted, yawning.", + "‘I’m getting tired of this. I vote the young lady tells us a story.’", + "‘I’m afraid I don’t know one,’ said Alice, rather alarmed at the", + "proposal.", + "‘Then the Dormouse shall!’ they both cried. ‘Wake up, Dormouse!’ And", + "they pinched it on both sides at once.", + "The Dormouse slowly opened his eyes. ‘I wasn’t asleep,’ he said in a", + "hoarse, feeble voice: ‘I heard every word you fellows were saying.’", + "‘Tell us a story!’ said the March Hare.", + "‘Yes, please do!’ pleaded Alice.", + "‘And be quick about it,’ added the Hatter, ‘or you’ll be asleep again", + "before it’s done.’", + "‘Once upon a time there were three little sisters,’ the Dormouse began", + "in a great hurry; ‘and their names were Elsie, Lacie, and Tillie; and", + "they lived at the bottom of a well--’", + "‘What did they live on?’ said Alice, who always took a great interest in", + "questions of eating and drinking.", + "‘They lived on treacle,’ said the Dormouse, after thinking a minute or", + "two.", + "‘They couldn’t have done that, you know,’ Alice gently remarked; ‘they’d", + "have been ill.’", + "‘So they were,’ said the Dormouse; ‘VERY ill.’", + "Alice tried to fancy to herself what such an extraordinary ways of", + "living would be like, but it puzzled her too much, so she went on: ‘But", + "why did they live at the bottom of a well?’", + "‘Take some more tea,’ the March Hare said to Alice, very earnestly.", + "‘I’ve had nothing yet,’ Alice replied in an offended tone, ‘so I can’t", + "take more.’", + "‘You mean you can’t take LESS,’ said the Hatter: ‘it’s very easy to take", + "MORE than nothing.’", + "‘Nobody asked YOUR opinion,’ said Alice.", + "‘Who’s making personal remarks now?’ the Hatter asked triumphantly.", + "Alice did not quite know what to say to this: so she helped herself", + "to some tea and bread-and-butter, and then turned to the Dormouse, and", + "repeated her question. ‘Why did they live at the bottom of a well?’", + "The Dormouse again took a minute or two to think about it, and then", + "said, ‘It was a treacle-well.’", + "‘There’s no such thing!’ Alice was beginning very angrily, but the", + "Hatter and the March Hare went ‘Sh! sh!’ and the Dormouse sulkily", + "remarked, ‘If you can’t be civil, you’d better finish the story for", + "yourself.’", + "‘No, please go on!’ Alice said very humbly; ‘I won’t interrupt again. I", + "dare say there may be ONE.’", + "‘One, indeed!’ said the Dormouse indignantly. However, he consented to", + "go on. ‘And so these three little sisters--they were learning to draw,", + "you know--’", + "‘What did they draw?’ said Alice, quite forgetting her promise.", + "‘Treacle,’ said the Dormouse, without considering at all this time.", + "‘I want a clean cup,’ interrupted the Hatter: ‘let’s all move one place", + "on.’", + "He moved on as he spoke, and the Dormouse followed him: the March Hare", + "moved into the Dormouse’s place, and Alice rather unwillingly took", + "the place of the March Hare. The Hatter was the only one who got any", + "advantage from the change: and Alice was a good deal worse off than", + "before, as the March Hare had just upset the milk-jug into his plate.", + "Alice did not wish to offend the Dormouse again, so she began very", + "cautiously: ‘But I don’t understand. Where did they draw the treacle", + "from?’", + "‘You can draw water out of a water-well,’ said the Hatter; ‘so I should", + "think you could draw treacle out of a treacle-well--eh, stupid?’", + "‘But they were IN the well,’ Alice said to the Dormouse, not choosing to", + "notice this last remark.", + "‘Of course they were’, said the Dormouse; ‘--well in.’", + "This answer so confused poor Alice, that she let the Dormouse go on for", + "some time without interrupting it.", + "‘They were learning to draw,’ the Dormouse went on, yawning and rubbing", + "its eyes, for it was getting very sleepy; ‘and they drew all manner of", + "things--everything that begins with an M--’", + "‘Why with an M?’ said Alice.", + "‘Why not?’ said the March Hare.", + "Alice was silent.", + "The Dormouse had closed its eyes by this time, and was going off into", + "a doze; but, on being pinched by the Hatter, it woke up again with", + "a little shriek, and went on: ‘--that begins with an M, such as", + "mouse-traps, and the moon, and memory, and muchness--you know you say", + "things are “much of a muchness”--did you ever see such a thing as a", + "drawing of a muchness?’", + "‘Really, now you ask me,’ said Alice, very much confused, ‘I don’t", + "think--’", + "‘Then you shouldn’t talk,’ said the Hatter.", + "This piece of rudeness was more than Alice could bear: she got up in", + "great disgust, and walked off; the Dormouse fell asleep instantly, and", + "neither of the others took the least notice of her going, though she", + "looked back once or twice, half hoping that they would call after her:", + "the last time she saw them, they were trying to put the Dormouse into", + "the teapot.", + "‘At any rate I’ll never go THERE again!’ said Alice as she picked her", + "way through the wood. ‘It’s the stupidest tea-party I ever was at in all", + "my life!’", + "Just as she said this, she noticed that one of the trees had a door", + "leading right into it. ‘That’s very curious!’ she thought. ‘But", + "everything’s curious today. I think I may as well go in at once.’ And in", + "she went.", + "Once more she found herself in the long hall, and close to the little", + "glass table. ‘Now, I’ll manage better this time,’ she said to herself,", + "and began by taking the little golden key, and unlocking the door that", + "led into the garden. Then she went to work nibbling at the mushroom (she", + "had kept a piece of it in her pocket) till she was about a foot high:", + "then she walked down the little passage: and THEN--she found herself at", + "last in the beautiful garden, among the bright flower-beds and the cool", + "fountains.", + "CHAPTER VIII. The Queen’s Croquet-Ground", + "A large rose-tree stood near the entrance of the garden: the roses", + "growing on it were white, but there were three gardeners at it, busily", + "painting them red. Alice thought this a very curious thing, and she went", + "nearer to watch them, and just as she came up to them she heard one of", + "them say, ‘Look out now, Five! Don’t go splashing paint over me like", + "that!’", + "‘I couldn’t help it,’ said Five, in a sulky tone; ‘Seven jogged my", + "elbow.’", + "On which Seven looked up and said, ‘That’s right, Five! Always lay the", + "blame on others!’", + "‘YOU’D better not talk!’ said Five. ‘I heard the Queen say only", + "yesterday you deserved to be beheaded!’", + "‘What for?’ said the one who had spoken first.", + "‘That’s none of YOUR business, Two!’ said Seven.", + "‘Yes, it IS his business!’ said Five, ‘and I’ll tell him--it was for", + "bringing the cook tulip-roots instead of onions.’", + "Seven flung down his brush, and had just begun ‘Well, of all the unjust", + "things--’ when his eye chanced to fall upon Alice, as she stood watching", + "them, and he checked himself suddenly: the others looked round also, and", + "all of them bowed low.", + "‘Would you tell me,’ said Alice, a little timidly, ‘why you are painting", + "those roses?’", + "Five and Seven said nothing, but looked at Two. Two began in a low", + "voice, ‘Why the fact is, you see, Miss, this here ought to have been a", + "RED rose-tree, and we put a white one in by mistake; and if the Queen", + "was to find it out, we should all have our heads cut off, you know.", + "So you see, Miss, we’re doing our best, afore she comes, to--’ At this", + "moment Five, who had been anxiously looking across the garden, called", + "out ‘The Queen! The Queen!’ and the three gardeners instantly threw", + "themselves flat upon their faces. There was a sound of many footsteps,", + "and Alice looked round, eager to see the Queen.", + "First came ten soldiers carrying clubs; these were all shaped like", + "the three gardeners, oblong and flat, with their hands and feet at the", + "corners: next the ten courtiers; these were ornamented all over with", + "diamonds, and walked two and two, as the soldiers did. After these came", + "the royal children; there were ten of them, and the little dears came", + "jumping merrily along hand in hand, in couples: they were all ornamented", + "with hearts. Next came the guests, mostly Kings and Queens, and among", + "them Alice recognised the White Rabbit: it was talking in a hurried", + "nervous manner, smiling at everything that was said, and went by without", + "noticing her. Then followed the Knave of Hearts, carrying the King’s", + "crown on a crimson velvet cushion; and, last of all this grand", + "procession, came THE KING AND QUEEN OF HEARTS.", + "Alice was rather doubtful whether she ought not to lie down on her face", + "like the three gardeners, but she could not remember ever having heard", + "of such a rule at processions; ‘and besides, what would be the use of", + "a procession,’ thought she, ‘if people had all to lie down upon their", + "faces, so that they couldn’t see it?’ So she stood still where she was,", + "and waited.", + "When the procession came opposite to Alice, they all stopped and looked", + "at her, and the Queen said severely ‘Who is this?’ She said it to the", + "Knave of Hearts, who only bowed and smiled in reply.", + "‘Idiot!’ said the Queen, tossing her head impatiently; and, turning to", + "Alice, she went on, ‘What’s your name, child?’", + "‘My name is Alice, so please your Majesty,’ said Alice very politely;", + "but she added, to herself, ‘Why, they’re only a pack of cards, after", + "all. I needn’t be afraid of them!’", + "‘And who are THESE?’ said the Queen, pointing to the three gardeners who", + "were lying round the rosetree; for, you see, as they were lying on their", + "faces, and the pattern on their backs was the same as the rest of the", + "pack, she could not tell whether they were gardeners, or soldiers, or", + "courtiers, or three of her own children.", + "‘How should I know?’ said Alice, surprised at her own courage. ‘It’s no", + "business of MINE.’", + "The Queen turned crimson with fury, and, after glaring at her for a", + "moment like a wild beast, screamed ‘Off with her head! Off--’", + "‘Nonsense!’ said Alice, very loudly and decidedly, and the Queen was", + "silent.", + "The King laid his hand upon her arm, and timidly said ‘Consider, my", + "dear: she is only a child!’", + "The Queen turned angrily away from him, and said to the Knave ‘Turn them", + "over!’", + "The Knave did so, very carefully, with one foot.", + "‘Get up!’ said the Queen, in a shrill, loud voice, and the three", + "gardeners instantly jumped up, and began bowing to the King, the Queen,", + "the royal children, and everybody else.", + "‘Leave off that!’ screamed the Queen. ‘You make me giddy.’ And then,", + "turning to the rose-tree, she went on, ‘What HAVE you been doing here?’", + "‘May it please your Majesty,’ said Two, in a very humble tone, going", + "down on one knee as he spoke, ‘we were trying--’", + "‘I see!’ said the Queen, who had meanwhile been examining the roses.", + "‘Off with their heads!’ and the procession moved on, three of the", + "soldiers remaining behind to execute the unfortunate gardeners, who ran", + "to Alice for protection.", + "‘You shan’t be beheaded!’ said Alice, and she put them into a large", + "flower-pot that stood near. The three soldiers wandered about for a", + "minute or two, looking for them, and then quietly marched off after the", + "others.", + "‘Are their heads off?’ shouted the Queen.", + "‘Their heads are gone, if it please your Majesty!’ the soldiers shouted", + "in reply.", + "‘That’s right!’ shouted the Queen. ‘Can you play croquet?’", + "The soldiers were silent, and looked at Alice, as the question was", + "evidently meant for her.", + "‘Yes!’ shouted Alice.", + "‘Come on, then!’ roared the Queen, and Alice joined the procession,", + "wondering very much what would happen next.", + "‘It’s--it’s a very fine day!’ said a timid voice at her side. She was", + "walking by the White Rabbit, who was peeping anxiously into her face.", + "‘Very,’ said Alice: ‘--where’s the Duchess?’", + "‘Hush! Hush!’ said the Rabbit in a low, hurried tone. He looked", + "anxiously over his shoulder as he spoke, and then raised himself upon", + "tiptoe, put his mouth close to her ear, and whispered ‘She’s under", + "sentence of execution.’", + "‘What for?’ said Alice.", + "‘Did you say “What a pity!”?’ the Rabbit asked.", + "‘No, I didn’t,’ said Alice: ‘I don’t think it’s at all a pity. I said", + "“What for?”’", + "‘She boxed the Queen’s ears--’ the Rabbit began. Alice gave a little", + "scream of laughter. ‘Oh, hush!’ the Rabbit whispered in a frightened", + "tone. ‘The Queen will hear you! You see, she came rather late, and the", + "Queen said--’", + "‘Get to your places!’ shouted the Queen in a voice of thunder, and", + "people began running about in all directions, tumbling up against each", + "other; however, they got settled down in a minute or two, and the game", + "began. Alice thought she had never seen such a curious croquet-ground in", + "her life; it was all ridges and furrows; the balls were live hedgehogs,", + "the mallets live flamingoes, and the soldiers had to double themselves", + "up and to stand on their hands and feet, to make the arches.", + "The chief difficulty Alice found at first was in managing her flamingo:", + "she succeeded in getting its body tucked away, comfortably enough, under", + "her arm, with its legs hanging down, but generally, just as she had got", + "its neck nicely straightened out, and was going to give the hedgehog a", + "blow with its head, it WOULD twist itself round and look up in her face,", + "with such a puzzled expression that she could not help bursting out", + "laughing: and when she had got its head down, and was going to begin", + "again, it was very provoking to find that the hedgehog had unrolled", + "itself, and was in the act of crawling away: besides all this, there was", + "generally a ridge or furrow in the way wherever she wanted to send the", + "hedgehog to, and, as the doubled-up soldiers were always getting up", + "and walking off to other parts of the ground, Alice soon came to the", + "conclusion that it was a very difficult game indeed.", + "The players all played at once without waiting for turns, quarrelling", + "all the while, and fighting for the hedgehogs; and in a very short", + "time the Queen was in a furious passion, and went stamping about, and", + "shouting ‘Off with his head!’ or ‘Off with her head!’ about once in a", + "minute.", + "Alice began to feel very uneasy: to be sure, she had not as yet had any", + "dispute with the Queen, but she knew that it might happen any minute,", + "‘and then,’ thought she, ‘what would become of me? They’re dreadfully", + "fond of beheading people here; the great wonder is, that there’s any one", + "left alive!’", + "She was looking about for some way of escape, and wondering whether she", + "could get away without being seen, when she noticed a curious appearance", + "in the air: it puzzled her very much at first, but, after watching it", + "a minute or two, she made it out to be a grin, and she said to herself", + "‘It’s the Cheshire Cat: now I shall have somebody to talk to.’", + "‘How are you getting on?’ said the Cat, as soon as there was mouth", + "enough for it to speak with.", + "Alice waited till the eyes appeared, and then nodded. ‘It’s no use", + "speaking to it,’ she thought, ‘till its ears have come, or at least one", + "of them.’ In another minute the whole head appeared, and then Alice put", + "down her flamingo, and began an account of the game, feeling very glad", + "she had someone to listen to her. The Cat seemed to think that there was", + "enough of it now in sight, and no more of it appeared.", + "‘I don’t think they play at all fairly,’ Alice began, in rather a", + "complaining tone, ‘and they all quarrel so dreadfully one can’t hear", + "oneself speak--and they don’t seem to have any rules in particular;", + "at least, if there are, nobody attends to them--and you’ve no idea how", + "confusing it is all the things being alive; for instance, there’s the", + "arch I’ve got to go through next walking about at the other end of the", + "ground--and I should have croqueted the Queen’s hedgehog just now, only", + "it ran away when it saw mine coming!’", + "‘How do you like the Queen?’ said the Cat in a low voice.", + "‘Not at all,’ said Alice: ‘she’s so extremely--’ Just then she noticed", + "that the Queen was close behind her, listening: so she went on,", + "‘--likely to win, that it’s hardly worth while finishing the game.’", + "The Queen smiled and passed on.", + "‘Who ARE you talking to?’ said the King, going up to Alice, and looking", + "at the Cat’s head with great curiosity.", + "‘It’s a friend of mine--a Cheshire Cat,’ said Alice: ‘allow me to", + "introduce it.’", + "‘I don’t like the look of it at all,’ said the King: ‘however, it may", + "kiss my hand if it likes.’", + "‘I’d rather not,’ the Cat remarked.", + "‘Don’t be impertinent,’ said the King, ‘and don’t look at me like that!’", + "He got behind Alice as he spoke.", + "‘A cat may look at a king,’ said Alice. ‘I’ve read that in some book,", + "but I don’t remember where.’", + "‘Well, it must be removed,’ said the King very decidedly, and he called", + "the Queen, who was passing at the moment, ‘My dear! I wish you would", + "have this cat removed!’", + "The Queen had only one way of settling all difficulties, great or small.", + "‘Off with his head!’ she said, without even looking round.", + "‘I’ll fetch the executioner myself,’ said the King eagerly, and he", + "hurried off.", + "Alice thought she might as well go back, and see how the game was going", + "on, as she heard the Queen’s voice in the distance, screaming with", + "passion. She had already heard her sentence three of the players to be", + "executed for having missed their turns, and she did not like the look", + "of things at all, as the game was in such confusion that she never knew", + "whether it was her turn or not. So she went in search of her hedgehog.", + "The hedgehog was engaged in a fight with another hedgehog, which seemed", + "to Alice an excellent opportunity for croqueting one of them with the", + "other: the only difficulty was, that her flamingo was gone across to the", + "other side of the garden, where Alice could see it trying in a helpless", + "sort of way to fly up into a tree.", + "By the time she had caught the flamingo and brought it back, the fight", + "was over, and both the hedgehogs were out of sight: ‘but it doesn’t", + "matter much,’ thought Alice, ‘as all the arches are gone from this side", + "of the ground.’ So she tucked it away under her arm, that it might not", + "escape again, and went back for a little more conversation with her", + "friend.", + "When she got back to the Cheshire Cat, she was surprised to find quite a", + "large crowd collected round it: there was a dispute going on between", + "the executioner, the King, and the Queen, who were all talking at once,", + "while all the rest were quite silent, and looked very uncomfortable.", + "The moment Alice appeared, she was appealed to by all three to settle", + "the question, and they repeated their arguments to her, though, as they", + "all spoke at once, she found it very hard indeed to make out exactly", + "what they said.", + "The executioner’s argument was, that you couldn’t cut off a head unless", + "there was a body to cut it off from: that he had never had to do such a", + "thing before, and he wasn’t going to begin at HIS time of life.", + "The King’s argument was, that anything that had a head could be", + "beheaded, and that you weren’t to talk nonsense.", + "The Queen’s argument was, that if something wasn’t done about it in less", + "than no time she’d have everybody executed, all round. (It was this last", + "remark that had made the whole party look so grave and anxious.)", + "Alice could think of nothing else to say but ‘It belongs to the Duchess:", + "you’d better ask HER about it.’", + "‘She’s in prison,’ the Queen said to the executioner: ‘fetch her here.’", + "And the executioner went off like an arrow.", + " The Cat’s head began fading away the moment he was gone, and,", + "by the time he had come back with the Duchess, it had entirely", + "disappeared; so the King and the executioner ran wildly up and down", + "looking for it, while the rest of the party went back to the game.", + "CHAPTER IX. The Mock Turtle’s Story", + "‘You can’t think how glad I am to see you again, you dear old thing!’", + "said the Duchess, as she tucked her arm affectionately into Alice’s, and", + "they walked off together.", + "Alice was very glad to find her in such a pleasant temper, and thought", + "to herself that perhaps it was only the pepper that had made her so", + "savage when they met in the kitchen.", + "‘When I’M a Duchess,’ she said to herself, (not in a very hopeful tone", + "though), ‘I won’t have any pepper in my kitchen AT ALL. Soup does very", + "well without--Maybe it’s always pepper that makes people hot-tempered,’", + "she went on, very much pleased at having found out a new kind of", + "rule, ‘and vinegar that makes them sour--and camomile that makes", + "them bitter--and--and barley-sugar and such things that make children", + "sweet-tempered. I only wish people knew that: then they wouldn’t be so", + "stingy about it, you know--’", + "She had quite forgotten the Duchess by this time, and was a little", + "startled when she heard her voice close to her ear. ‘You’re thinking", + "about something, my dear, and that makes you forget to talk. I can’t", + "tell you just now what the moral of that is, but I shall remember it in", + "a bit.’", + "‘Perhaps it hasn’t one,’ Alice ventured to remark.", + "‘Tut, tut, child!’ said the Duchess. ‘Everything’s got a moral, if only", + "you can find it.’ And she squeezed herself up closer to Alice’s side as", + "she spoke.", + "Alice did not much like keeping so close to her: first, because the", + "Duchess was VERY ugly; and secondly, because she was exactly the", + "right height to rest her chin upon Alice’s shoulder, and it was an", + "uncomfortably sharp chin. However, she did not like to be rude, so she", + "bore it as well as she could.", + "‘The game’s going on rather better now,’ she said, by way of keeping up", + "the conversation a little.", + "‘’Tis so,’ said the Duchess: ‘and the moral of that is--“Oh, ‘tis love,", + "‘tis love, that makes the world go round!”’", + "‘Somebody said,’ Alice whispered, ‘that it’s done by everybody minding", + "their own business!’", + "‘Ah, well! It means much the same thing,’ said the Duchess, digging her", + "sharp little chin into Alice’s shoulder as she added, ‘and the moral", + "of THAT is--“Take care of the sense, and the sounds will take care of", + "themselves.”’", + "‘How fond she is of finding morals in things!’ Alice thought to herself.", + "‘I dare say you’re wondering why I don’t put my arm round your waist,’", + "the Duchess said after a pause: ‘the reason is, that I’m doubtful about", + "the temper of your flamingo. Shall I try the experiment?’", + "‘HE might bite,’ Alice cautiously replied, not feeling at all anxious to", + "have the experiment tried.", + "‘Very true,’ said the Duchess: ‘flamingoes and mustard both bite. And", + "the moral of that is--“Birds of a feather flock together.”’", + "‘Only mustard isn’t a bird,’ Alice remarked.", + "‘Right, as usual,’ said the Duchess: ‘what a clear way you have of", + "putting things!’", + "‘It’s a mineral, I THINK,’ said Alice.", + "‘Of course it is,’ said the Duchess, who seemed ready to agree to", + "everything that Alice said; ‘there’s a large mustard-mine near here. And", + "the moral of that is--“The more there is of mine, the less there is of", + "yours.”’", + "‘Oh, I know!’ exclaimed Alice, who had not attended to this last remark,", + "‘it’s a vegetable. It doesn’t look like one, but it is.’", + "‘I quite agree with you,’ said the Duchess; ‘and the moral of that", + "is--“Be what you would seem to be”--or if you’d like it put more", + "simply--“Never imagine yourself not to be otherwise than what it might", + "appear to others that what you were or might have been was not otherwise", + "than what you had been would have appeared to them to be otherwise.”’", + "‘I think I should understand that better,’ Alice said very politely, ‘if", + "I had it written down: but I can’t quite follow it as you say it.’", + "‘That’s nothing to what I could say if I chose,’ the Duchess replied, in", + "a pleased tone.", + "‘Pray don’t trouble yourself to say it any longer than that,’ said", + "Alice.", + "‘Oh, don’t talk about trouble!’ said the Duchess. ‘I make you a present", + "of everything I’ve said as yet.’", + "‘A cheap sort of present!’ thought Alice. ‘I’m glad they don’t give", + "birthday presents like that!’ But she did not venture to say it out", + "loud.", + "‘Thinking again?’ the Duchess asked, with another dig of her sharp", + "little chin.", + "‘I’ve a right to think,’ said Alice sharply, for she was beginning to", + "feel a little worried.", + "‘Just about as much right,’ said the Duchess, ‘as pigs have to fly; and", + "the m--’", + "But here, to Alice’s great surprise, the Duchess’s voice died away, even", + "in the middle of her favourite word ‘moral,’ and the arm that was linked", + "into hers began to tremble. Alice looked up, and there stood the Queen", + "in front of them, with her arms folded, frowning like a thunderstorm.", + "‘A fine day, your Majesty!’ the Duchess began in a low, weak voice.", + "‘Now, I give you fair warning,’ shouted the Queen, stamping on the", + "ground as she spoke; ‘either you or your head must be off, and that in", + "about half no time! Take your choice!’", + "The Duchess took her choice, and was gone in a moment.", + "‘Let’s go on with the game,’ the Queen said to Alice; and Alice was", + "too much frightened to say a word, but slowly followed her back to the", + "croquet-ground.", + "The other guests had taken advantage of the Queen’s absence, and were", + "resting in the shade: however, the moment they saw her, they hurried", + "back to the game, the Queen merely remarking that a moment’s delay would", + "cost them their lives.", + "All the time they were playing the Queen never left off quarrelling with", + "the other players, and shouting ‘Off with his head!’ or ‘Off with her", + "head!’ Those whom she sentenced were taken into custody by the soldiers,", + "who of course had to leave off being arches to do this, so that by", + "the end of half an hour or so there were no arches left, and all the", + "players, except the King, the Queen, and Alice, were in custody and", + "under sentence of execution.", + "Then the Queen left off, quite out of breath, and said to Alice, ‘Have", + "you seen the Mock Turtle yet?’", + "‘No,’ said Alice. ‘I don’t even know what a Mock Turtle is.’", + "‘It’s the thing Mock Turtle Soup is made from,’ said the Queen.", + "‘I never saw one, or heard of one,’ said Alice.", + "‘Come on, then,’ said the Queen, ‘and he shall tell you his history,’", + "As they walked off together, Alice heard the King say in a low voice,", + "to the company generally, ‘You are all pardoned.’ ‘Come, THAT’S a good", + "thing!’ she said to herself, for she had felt quite unhappy at the", + "number of executions the Queen had ordered.", + "They very soon came upon a Gryphon, lying fast asleep in the sun.", + "(IF you don’t know what a Gryphon is, look at the picture.) ‘Up, lazy", + "thing!’ said the Queen, ‘and take this young lady to see the Mock", + "Turtle, and to hear his history. I must go back and see after some", + "executions I have ordered’; and she walked off, leaving Alice alone with", + "the Gryphon. Alice did not quite like the look of the creature, but on", + "the whole she thought it would be quite as safe to stay with it as to go", + "after that savage Queen: so she waited.", + "The Gryphon sat up and rubbed its eyes: then it watched the Queen till", + "she was out of sight: then it chuckled. ‘What fun!’ said the Gryphon,", + "half to itself, half to Alice.", + "‘What IS the fun?’ said Alice.", + "‘Why, SHE,’ said the Gryphon. ‘It’s all her fancy, that: they never", + "executes nobody, you know. Come on!’", + "‘Everybody says “come on!” here,’ thought Alice, as she went slowly", + "after it: ‘I never was so ordered about in all my life, never!’", + "They had not gone far before they saw the Mock Turtle in the distance,", + "sitting sad and lonely on a little ledge of rock, and, as they came", + "nearer, Alice could hear him sighing as if his heart would break. She", + "pitied him deeply. ‘What is his sorrow?’ she asked the Gryphon, and the", + "Gryphon answered, very nearly in the same words as before, ‘It’s all his", + "fancy, that: he hasn’t got no sorrow, you know. Come on!’", + "So they went up to the Mock Turtle, who looked at them with large eyes", + "full of tears, but said nothing.", + "‘This here young lady,’ said the Gryphon, ‘she wants for to know your", + "history, she do.’", + "‘I’ll tell it her,’ said the Mock Turtle in a deep, hollow tone: ‘sit", + "down, both of you, and don’t speak a word till I’ve finished.’", + "So they sat down, and nobody spoke for some minutes. Alice thought to", + "herself, ‘I don’t see how he can EVEN finish, if he doesn’t begin.’ But", + "she waited patiently.", + "‘Once,’ said the Mock Turtle at last, with a deep sigh, ‘I was a real", + "Turtle.’", + "These words were followed by a very long silence, broken only by an", + "occasional exclamation of ‘Hjckrrh!’ from the Gryphon, and the constant", + "heavy sobbing of the Mock Turtle. Alice was very nearly getting up and", + "saying, ‘Thank you, sir, for your interesting story,’ but she could", + "not help thinking there MUST be more to come, so she sat still and said", + "nothing.", + "‘When we were little,’ the Mock Turtle went on at last, more calmly,", + "though still sobbing a little now and then, ‘we went to school in the", + "sea. The master was an old Turtle--we used to call him Tortoise--’", + "‘Why did you call him Tortoise, if he wasn’t one?’ Alice asked.", + "‘We called him Tortoise because he taught us,’ said the Mock Turtle", + "angrily: ‘really you are very dull!’", + "‘You ought to be ashamed of yourself for asking such a simple question,’", + "added the Gryphon; and then they both sat silent and looked at poor", + "Alice, who felt ready to sink into the earth. At last the Gryphon said", + "to the Mock Turtle, ‘Drive on, old fellow! Don’t be all day about it!’", + "and he went on in these words:", + "‘Yes, we went to school in the sea, though you mayn’t believe it--’", + "‘I never said I didn’t!’ interrupted Alice.", + "‘You did,’ said the Mock Turtle.", + "‘Hold your tongue!’ added the Gryphon, before Alice could speak again.", + "The Mock Turtle went on.", + "‘We had the best of educations--in fact, we went to school every day--’", + "‘I’VE been to a day-school, too,’ said Alice; ‘you needn’t be so proud", + "as all that.’", + "‘With extras?’ asked the Mock Turtle a little anxiously.", + "‘Yes,’ said Alice, ‘we learned French and music.’", + "‘And washing?’ said the Mock Turtle.", + "‘Certainly not!’ said Alice indignantly.", + "‘Ah! then yours wasn’t a really good school,’ said the Mock Turtle in", + "a tone of great relief. ‘Now at OURS they had at the end of the bill,", + "“French, music, AND WASHING--extra.”’", + "‘You couldn’t have wanted it much,’ said Alice; ‘living at the bottom of", + "the sea.’", + "‘I couldn’t afford to learn it.’ said the Mock Turtle with a sigh. ‘I", + "only took the regular course.’", + "‘What was that?’ inquired Alice.", + "‘Reeling and Writhing, of course, to begin with,’ the Mock Turtle", + "replied; ‘and then the different branches of Arithmetic--Ambition,", + "Distraction, Uglification, and Derision.’", + "‘I never heard of “Uglification,”’ Alice ventured to say. ‘What is it?’", + "The Gryphon lifted up both its paws in surprise. ‘What! Never heard of", + "uglifying!’ it exclaimed. ‘You know what to beautify is, I suppose?’", + "‘Yes,’ said Alice doubtfully: ‘it means--to--make--anything--prettier.’", + "‘Well, then,’ the Gryphon went on, ‘if you don’t know what to uglify is,", + "you ARE a simpleton.’", + "Alice did not feel encouraged to ask any more questions about it, so she", + "turned to the Mock Turtle, and said ‘What else had you to learn?’", + "‘Well, there was Mystery,’ the Mock Turtle replied, counting off", + "the subjects on his flappers, ‘--Mystery, ancient and modern, with", + "Seaography: then Drawling--the Drawling-master was an old conger-eel,", + "that used to come once a week: HE taught us Drawling, Stretching, and", + "Fainting in Coils.’", + "‘What was THAT like?’ said Alice.", + "‘Well, I can’t show it you myself,’ the Mock Turtle said: ‘I’m too", + "stiff. And the Gryphon never learnt it.’", + "‘Hadn’t time,’ said the Gryphon: ‘I went to the Classics master, though.", + "He was an old crab, HE was.’", + "‘I never went to him,’ the Mock Turtle said with a sigh: ‘he taught", + "Laughing and Grief, they used to say.’", + "‘So he did, so he did,’ said the Gryphon, sighing in his turn; and both", + "creatures hid their faces in their paws.", + "‘And how many hours a day did you do lessons?’ said Alice, in a hurry to", + "change the subject.", + "‘Ten hours the first day,’ said the Mock Turtle: ‘nine the next, and so", + "on.’", + "‘What a curious plan!’ exclaimed Alice.", + "‘That’s the reason they’re called lessons,’ the Gryphon remarked:", + "‘because they lessen from day to day.’", + "This was quite a new idea to Alice, and she thought it over a little", + "before she made her next remark. ‘Then the eleventh day must have been a", + "holiday?’", + "‘Of course it was,’ said the Mock Turtle.", + "‘And how did you manage on the twelfth?’ Alice went on eagerly.", + "‘That’s enough about lessons,’ the Gryphon interrupted in a very decided", + "tone: ‘tell her something about the games now.’", + "CHAPTER X. The Lobster Quadrille", + "The Mock Turtle sighed deeply, and drew the back of one flapper across", + "his eyes. He looked at Alice, and tried to speak, but for a minute or", + "two sobs choked his voice. ‘Same as if he had a bone in his throat,’", + "said the Gryphon: and it set to work shaking him and punching him in", + "the back. At last the Mock Turtle recovered his voice, and, with tears", + "running down his cheeks, he went on again:--", + "‘You may not have lived much under the sea--’ [‘I haven’t,’ said", + "Alice)--‘and perhaps you were never even introduced to a lobster--’", + "(Alice began to say ‘I once tasted--’ but checked herself hastily, and", + "said ‘No, never’) ‘--so you can have no idea what a delightful thing a", + "Lobster Quadrille is!’", + "‘No, indeed,’ said Alice. ‘What sort of a dance is it?’", + "‘Why,’ said the Gryphon, ‘you first form into a line along the", + "sea-shore--’", + "‘Two lines!’ cried the Mock Turtle. ‘Seals, turtles, salmon, and so on;", + "then, when you’ve cleared all the jelly-fish out of the way--’", + "‘THAT generally takes some time,’ interrupted the Gryphon.", + "‘--you advance twice--’", + "‘Each with a lobster as a partner!’ cried the Gryphon.", + "‘Of course,’ the Mock Turtle said: ‘advance twice, set to partners--’", + "‘--change lobsters, and retire in same order,’ continued the Gryphon.", + "‘Then, you know,’ the Mock Turtle went on, ‘you throw the--’", + "‘The lobsters!’ shouted the Gryphon, with a bound into the air.", + "‘--as far out to sea as you can--’", + "‘Swim after them!’ screamed the Gryphon.", + "‘Turn a somersault in the sea!’ cried the Mock Turtle, capering wildly", + "about.", + "‘Change lobsters again!’ yelled the Gryphon at the top of its voice.", + "‘Back to land again, and that’s all the first figure,’ said the Mock", + "Turtle, suddenly dropping his voice; and the two creatures, who had been", + "jumping about like mad things all this time, sat down again very sadly", + "and quietly, and looked at Alice.", + "‘It must be a very pretty dance,’ said Alice timidly.", + "‘Would you like to see a little of it?’ said the Mock Turtle.", + "‘Very much indeed,’ said Alice.", + "‘Come, let’s try the first figure!’ said the Mock Turtle to the Gryphon.", + "‘We can do without lobsters, you know. Which shall sing?’", + "‘Oh, YOU sing,’ said the Gryphon. ‘I’ve forgotten the words.’", + "So they began solemnly dancing round and round Alice, every now and", + "then treading on her toes when they passed too close, and waving their", + "forepaws to mark the time, while the Mock Turtle sang this, very slowly", + "and sadly:--", + " ‘“Will you walk a little faster?” said a whiting to a snail.", + " “There’s a porpoise close behind us, and he’s treading on my tail.", + " See how eagerly the lobsters and the turtles all advance!", + " They are waiting on the shingle--will you come and join the dance?", + " Will you, won’t you, will you, won’t you, will you join the dance?", + " Will you, won’t you, will you, won’t you, won’t you join the dance?", + " “You can really have no notion how delightful it will be", + " When they take us up and throw us, with the lobsters, out to sea!”", + " But the snail replied “Too far, too far!” and gave a look askance--", + " Said he thanked the whiting kindly, but he would not join the dance.", + " Would not, could not, would not, could not, would not join the dance.", + " Would not, could not, would not, could not, could not join the dance.", + " ‘“What matters it how far we go?” his scaly friend replied.", + " “There is another shore, you know, upon the other side.", + " The further off from England the nearer is to France--", + " Then turn not pale, beloved snail, but come and join the dance.", + " Will you, won’t you, will you, won’t you, will you join the dance?", + " Will you, won’t you, will you, won’t you, won’t you join the dance?”’", + "‘Thank you, it’s a very interesting dance to watch,’ said Alice, feeling", + "very glad that it was over at last: ‘and I do so like that curious song", + "about the whiting!’", + "‘Oh, as to the whiting,’ said the Mock Turtle, ‘they--you’ve seen them,", + "of course?’", + "‘Yes,’ said Alice, ‘I’ve often seen them at dinn--’ she checked herself", + "hastily.", + "‘I don’t know where Dinn may be,’ said the Mock Turtle, ‘but if you’ve", + "seen them so often, of course you know what they’re like.’", + "‘I believe so,’ Alice replied thoughtfully. ‘They have their tails in", + "their mouths--and they’re all over crumbs.’", + "‘You’re wrong about the crumbs,’ said the Mock Turtle: ‘crumbs would all", + "wash off in the sea. But they HAVE their tails in their mouths; and the", + "reason is--’ here the Mock Turtle yawned and shut his eyes.--‘Tell her", + "about the reason and all that,’ he said to the Gryphon.", + "‘The reason is,’ said the Gryphon, ‘that they WOULD go with the lobsters", + "to the dance. So they got thrown out to sea. So they had to fall a long", + "way. So they got their tails fast in their mouths. So they couldn’t get", + "them out again. That’s all.’", + "‘Thank you,’ said Alice, ‘it’s very interesting. I never knew so much", + "about a whiting before.’", + "‘I can tell you more than that, if you like,’ said the Gryphon. ‘Do you", + "know why it’s called a whiting?’", + "‘I never thought about it,’ said Alice. ‘Why?’", + "‘IT DOES THE BOOTS AND SHOES.’ the Gryphon replied very solemnly.", + "Alice was thoroughly puzzled. ‘Does the boots and shoes!’ she repeated", + "in a wondering tone.", + "‘Why, what are YOUR shoes done with?’ said the Gryphon. ‘I mean, what", + "makes them so shiny?’", + "Alice looked down at them, and considered a little before she gave her", + "answer. ‘They’re done with blacking, I believe.’", + "‘Boots and shoes under the sea,’ the Gryphon went on in a deep voice,", + "‘are done with a whiting. Now you know.’", + "‘And what are they made of?’ Alice asked in a tone of great curiosity.", + "‘Soles and eels, of course,’ the Gryphon replied rather impatiently:", + "‘any shrimp could have told you that.’", + "‘If I’d been the whiting,’ said Alice, whose thoughts were still running", + "on the song, ‘I’d have said to the porpoise, “Keep back, please: we", + "don’t want YOU with us!”’", + "‘They were obliged to have him with them,’ the Mock Turtle said: ‘no", + "wise fish would go anywhere without a porpoise.’", + "‘Wouldn’t it really?’ said Alice in a tone of great surprise.", + "‘Of course not,’ said the Mock Turtle: ‘why, if a fish came to ME, and", + "told me he was going a journey, I should say “With what porpoise?”’", + "‘Don’t you mean “purpose”?’ said Alice.", + "‘I mean what I say,’ the Mock Turtle replied in an offended tone. And", + "the Gryphon added ‘Come, let’s hear some of YOUR adventures.’", + "‘I could tell you my adventures--beginning from this morning,’ said", + "Alice a little timidly: ‘but it’s no use going back to yesterday,", + "because I was a different person then.’", + "‘Explain all that,’ said the Mock Turtle.", + "‘No, no! The adventures first,’ said the Gryphon in an impatient tone:", + "‘explanations take such a dreadful time.’", + "So Alice began telling them her adventures from the time when she first", + "saw the White Rabbit. She was a little nervous about it just at first,", + "the two creatures got so close to her, one on each side, and opened", + "their eyes and mouths so VERY wide, but she gained courage as she went", + "on. Her listeners were perfectly quiet till she got to the part about", + "her repeating ‘YOU ARE OLD, FATHER WILLIAM,’ to the Caterpillar, and the", + "words all coming different, and then the Mock Turtle drew a long breath,", + "and said ‘That’s very curious.’", + "‘It’s all about as curious as it can be,’ said the Gryphon.", + "‘It all came different!’ the Mock Turtle repeated thoughtfully. ‘I", + "should like to hear her try and repeat something now. Tell her to", + "begin.’ He looked at the Gryphon as if he thought it had some kind of", + "authority over Alice.", + "‘Stand up and repeat “‘TIS THE VOICE OF THE SLUGGARD,”’ said the", + "Gryphon.", + "‘How the creatures order one about, and make one repeat lessons!’", + "thought Alice; ‘I might as well be at school at once.’ However, she", + "got up, and began to repeat it, but her head was so full of the Lobster", + "Quadrille, that she hardly knew what she was saying, and the words came", + "very queer indeed:--", + " ‘’Tis the voice of the Lobster; I heard him declare,", + " “You have baked me too brown, I must sugar my hair.”", + " As a duck with its eyelids, so he with his nose", + " Trims his belt and his buttons, and turns out his toes.’", + " [later editions continued as follows", + " When the sands are all dry, he is gay as a lark,", + " And will talk in contemptuous tones of the Shark,", + " But, when the tide rises and sharks are around,", + " His voice has a timid and tremulous sound.]", + "‘That’s different from what I used to say when I was a child,’ said the", + "Gryphon.", + "‘Well, I never heard it before,’ said the Mock Turtle; ‘but it sounds", + "uncommon nonsense.’", + "Alice said nothing; she had sat down with her face in her hands,", + "wondering if anything would EVER happen in a natural way again.", + "‘I should like to have it explained,’ said the Mock Turtle.", + "‘She can’t explain it,’ said the Gryphon hastily. ‘Go on with the next", + "verse.’", + "‘But about his toes?’ the Mock Turtle persisted. ‘How COULD he turn them", + "out with his nose, you know?’", + "‘It’s the first position in dancing.’ Alice said; but was dreadfully", + "puzzled by the whole thing, and longed to change the subject.", + "‘Go on with the next verse,’ the Gryphon repeated impatiently: ‘it", + "begins “I passed by his garden.”’", + "Alice did not dare to disobey, though she felt sure it would all come", + "wrong, and she went on in a trembling voice:--", + " ‘I passed by his garden, and marked, with one eye,", + " How the Owl and the Panther were sharing a pie--’", + " [later editions continued as follows", + " The Panther took pie-crust, and gravy, and meat,", + " While the Owl had the dish as its share of the treat.", + " When the pie was all finished, the Owl, as a boon,", + " Was kindly permitted to pocket the spoon:", + " While the Panther received knife and fork with a growl,", + " And concluded the banquet--]", + "‘What IS the use of repeating all that stuff,’ the Mock Turtle", + "interrupted, ‘if you don’t explain it as you go on? It’s by far the most", + "confusing thing I ever heard!’", + "‘Yes, I think you’d better leave off,’ said the Gryphon: and Alice was", + "only too glad to do so.", + "‘Shall we try another figure of the Lobster Quadrille?’ the Gryphon went", + "on. ‘Or would you like the Mock Turtle to sing you a song?’", + "‘Oh, a song, please, if the Mock Turtle would be so kind,’ Alice", + "replied, so eagerly that the Gryphon said, in a rather offended tone,", + "‘Hm! No accounting for tastes! Sing her “Turtle Soup,” will you, old", + "fellow?’", + "The Mock Turtle sighed deeply, and began, in a voice sometimes choked", + "with sobs, to sing this:--", + " ‘Beautiful Soup, so rich and green,", + " Waiting in a hot tureen!", + " Who for such dainties would not stoop?", + " Soup of the evening, beautiful Soup!", + " Soup of the evening, beautiful Soup!", + " Beau--ootiful Soo--oop!", + " Beau--ootiful Soo--oop!", + " Soo--oop of the e--e--evening,", + " Beautiful, beautiful Soup!", + " ‘Beautiful Soup! Who cares for fish,", + " Game, or any other dish?", + " Who would not give all else for two", + " Pennyworth only of beautiful Soup?", + " Pennyworth only of beautiful Soup?", + " Beau--ootiful Soo--oop!", + " Beau--ootiful Soo--oop!", + " Soo--oop of the e--e--evening,", + " Beautiful, beauti--FUL SOUP!’", + "‘Chorus again!’ cried the Gryphon, and the Mock Turtle had just begun", + "to repeat it, when a cry of ‘The trial’s beginning!’ was heard in the", + "distance.", + "‘Come on!’ cried the Gryphon, and, taking Alice by the hand, it hurried", + "off, without waiting for the end of the song.", + "‘What trial is it?’ Alice panted as she ran; but the Gryphon only", + "answered ‘Come on!’ and ran the faster, while more and more faintly", + "came, carried on the breeze that followed them, the melancholy words:--", + " ‘Soo--oop of the e--e--evening,", + " Beautiful, beautiful Soup!’", + "CHAPTER XI. Who Stole the Tarts?", + "The King and Queen of Hearts were seated on their throne when they", + "arrived, with a great crowd assembled about them--all sorts of little", + "birds and beasts, as well as the whole pack of cards: the Knave was", + "standing before them, in chains, with a soldier on each side to guard", + "him; and near the King was the White Rabbit, with a trumpet in one hand,", + "and a scroll of parchment in the other. In the very middle of the court", + "was a table, with a large dish of tarts upon it: they looked so good,", + "that it made Alice quite hungry to look at them--‘I wish they’d get the", + "trial done,’ she thought, ‘and hand round the refreshments!’ But there", + "seemed to be no chance of this, so she began looking at everything about", + "her, to pass away the time.", + "Alice had never been in a court of justice before, but she had read", + "about them in books, and she was quite pleased to find that she knew", + "the name of nearly everything there. ‘That’s the judge,’ she said to", + "herself, ‘because of his great wig.’", + "The judge, by the way, was the King; and as he wore his crown over the", + "wig, (look at the frontispiece if you want to see how he did it,) he did", + "not look at all comfortable, and it was certainly not becoming.", + "‘And that’s the jury-box,’ thought Alice, ‘and those twelve creatures,’", + "(she was obliged to say ‘creatures,’ you see, because some of them were", + "animals, and some were birds,) ‘I suppose they are the jurors.’ She said", + "this last word two or three times over to herself, being rather proud of", + "it: for she thought, and rightly too, that very few little girls of her", + "age knew the meaning of it at all. However, ‘jury-men’ would have done", + "just as well.", + "The twelve jurors were all writing very busily on slates. ‘What are they", + "doing?’ Alice whispered to the Gryphon. ‘They can’t have anything to put", + "down yet, before the trial’s begun.’", + "‘They’re putting down their names,’ the Gryphon whispered in reply, ‘for", + "fear they should forget them before the end of the trial.’", + "‘Stupid things!’ Alice began in a loud, indignant voice, but she stopped", + "hastily, for the White Rabbit cried out, ‘Silence in the court!’ and the", + "King put on his spectacles and looked anxiously round, to make out who", + "was talking.", + "Alice could see, as well as if she were looking over their shoulders,", + "that all the jurors were writing down ‘stupid things!’ on their slates,", + "and she could even make out that one of them didn’t know how to spell", + "‘stupid,’ and that he had to ask his neighbour to tell him. ‘A nice", + "muddle their slates’ll be in before the trial’s over!’ thought Alice.", + "One of the jurors had a pencil that squeaked. This of course, Alice", + "could not stand, and she went round the court and got behind him, and", + "very soon found an opportunity of taking it away. She did it so quickly", + "that the poor little juror (it was Bill, the Lizard) could not make out", + "at all what had become of it; so, after hunting all about for it, he was", + "obliged to write with one finger for the rest of the day; and this was", + "of very little use, as it left no mark on the slate.", + "‘Herald, read the accusation!’ said the King.", + "On this the White Rabbit blew three blasts on the trumpet, and then", + "unrolled the parchment scroll, and read as follows:--", + " ‘The Queen of Hearts, she made some tarts,", + " All on a summer day:", + " The Knave of Hearts, he stole those tarts,", + " And took them quite away!’", + "‘Consider your verdict,’ the King said to the jury.", + "‘Not yet, not yet!’ the Rabbit hastily interrupted. ‘There’s a great", + "deal to come before that!’", + "‘Call the first witness,’ said the King; and the White Rabbit blew three", + "blasts on the trumpet, and called out, ‘First witness!’", + "The first witness was the Hatter. He came in with a teacup in one", + "hand and a piece of bread-and-butter in the other. ‘I beg pardon, your", + "Majesty,’ he began, ‘for bringing these in: but I hadn’t quite finished", + "my tea when I was sent for.’", + "‘You ought to have finished,’ said the King. ‘When did you begin?’", + "The Hatter looked at the March Hare, who had followed him into the", + "court, arm-in-arm with the Dormouse. ‘Fourteenth of March, I think it", + "was,’ he said.", + "‘Fifteenth,’ said the March Hare.", + "‘Sixteenth,’ added the Dormouse.", + "‘Write that down,’ the King said to the jury, and the jury eagerly", + "wrote down all three dates on their slates, and then added them up, and", + "reduced the answer to shillings and pence.", + "‘Take off your hat,’ the King said to the Hatter.", + "‘It isn’t mine,’ said the Hatter.", + "‘Stolen!’ the King exclaimed, turning to the jury, who instantly made a", + "memorandum of the fact.", + "‘I keep them to sell,’ the Hatter added as an explanation; ‘I’ve none of", + "my own. I’m a hatter.’", + "Here the Queen put on her spectacles, and began staring at the Hatter,", + "who turned pale and fidgeted.", + "‘Give your evidence,’ said the King; ‘and don’t be nervous, or I’ll have", + "you executed on the spot.’", + "This did not seem to encourage the witness at all: he kept shifting", + "from one foot to the other, looking uneasily at the Queen, and in", + "his confusion he bit a large piece out of his teacup instead of the", + "bread-and-butter.", + "Just at this moment Alice felt a very curious sensation, which puzzled", + "her a good deal until she made out what it was: she was beginning to", + "grow larger again, and she thought at first she would get up and leave", + "the court; but on second thoughts she decided to remain where she was as", + "long as there was room for her.", + "‘I wish you wouldn’t squeeze so.’ said the Dormouse, who was sitting", + "next to her. ‘I can hardly breathe.’", + "‘I can’t help it,’ said Alice very meekly: ‘I’m growing.’", + "‘You’ve no right to grow here,’ said the Dormouse.", + "‘Don’t talk nonsense,’ said Alice more boldly: ‘you know you’re growing", + "too.’", + "‘Yes, but I grow at a reasonable pace,’ said the Dormouse: ‘not in that", + "ridiculous fashion.’ And he got up very sulkily and crossed over to the", + "other side of the court.", + "All this time the Queen had never left off staring at the Hatter, and,", + "just as the Dormouse crossed the court, she said to one of the officers", + "of the court, ‘Bring me the list of the singers in the last concert!’ on", + "which the wretched Hatter trembled so, that he shook both his shoes off.", + "‘Give your evidence,’ the King repeated angrily, ‘or I’ll have you", + "executed, whether you’re nervous or not.’", + "‘I’m a poor man, your Majesty,’ the Hatter began, in a trembling voice,", + "‘--and I hadn’t begun my tea--not above a week or so--and what with the", + "bread-and-butter getting so thin--and the twinkling of the tea--’", + "‘The twinkling of the what?’ said the King.", + "‘It began with the tea,’ the Hatter replied.", + "‘Of course twinkling begins with a T!’ said the King sharply. ‘Do you", + "take me for a dunce? Go on!’", + "‘I’m a poor man,’ the Hatter went on, ‘and most things twinkled after", + "that--only the March Hare said--’", + "‘I didn’t!’ the March Hare interrupted in a great hurry.", + "‘You did!’ said the Hatter.", + "‘I deny it!’ said the March Hare.", + "‘He denies it,’ said the King: ‘leave out that part.’", + "‘Well, at any rate, the Dormouse said--’ the Hatter went on, looking", + "anxiously round to see if he would deny it too: but the Dormouse denied", + "nothing, being fast asleep.", + "‘After that,’ continued the Hatter, ‘I cut some more bread-and-butter--’", + "‘But what did the Dormouse say?’ one of the jury asked.", + "‘That I can’t remember,’ said the Hatter.", + "‘You MUST remember,’ remarked the King, ‘or I’ll have you executed.’", + "The miserable Hatter dropped his teacup and bread-and-butter, and went", + "down on one knee. ‘I’m a poor man, your Majesty,’ he began.", + "‘You’re a very poor speaker,’ said the King.", + "Here one of the guinea-pigs cheered, and was immediately suppressed by", + "the officers of the court. (As that is rather a hard word, I will just", + "explain to you how it was done. They had a large canvas bag, which tied", + "up at the mouth with strings: into this they slipped the guinea-pig,", + "head first, and then sat upon it.)", + "‘I’m glad I’ve seen that done,’ thought Alice. ‘I’ve so often read", + "in the newspapers, at the end of trials, “There was some attempts", + "at applause, which was immediately suppressed by the officers of the", + "court,” and I never understood what it meant till now.’", + "‘If that’s all you know about it, you may stand down,’ continued the", + "King.", + "‘I can’t go no lower,’ said the Hatter: ‘I’m on the floor, as it is.’", + "‘Then you may SIT down,’ the King replied.", + "Here the other guinea-pig cheered, and was suppressed.", + "‘Come, that finished the guinea-pigs!’ thought Alice. ‘Now we shall get", + "on better.’", + "‘I’d rather finish my tea,’ said the Hatter, with an anxious look at the", + "Queen, who was reading the list of singers.", + "‘You may go,’ said the King, and the Hatter hurriedly left the court,", + "without even waiting to put his shoes on.", + "‘--and just take his head off outside,’ the Queen added to one of the", + "officers: but the Hatter was out of sight before the officer could get", + "to the door.", + "‘Call the next witness!’ said the King.", + "The next witness was the Duchess’s cook. She carried the pepper-box in", + "her hand, and Alice guessed who it was, even before she got into the", + "court, by the way the people near the door began sneezing all at once.", + "‘Give your evidence,’ said the King.", + "‘Shan’t,’ said the cook.", + "The King looked anxiously at the White Rabbit, who said in a low voice,", + "‘Your Majesty must cross-examine THIS witness.’", + "‘Well, if I must, I must,’ the King said, with a melancholy air, and,", + "after folding his arms and frowning at the cook till his eyes were", + "nearly out of sight, he said in a deep voice, ‘What are tarts made of?’", + "‘Pepper, mostly,’ said the cook.", + "‘Treacle,’ said a sleepy voice behind her.", + "‘Collar that Dormouse,’ the Queen shrieked out. ‘Behead that Dormouse!", + "Turn that Dormouse out of court! Suppress him! Pinch him! Off with his", + "whiskers!’", + "For some minutes the whole court was in confusion, getting the Dormouse", + "turned out, and, by the time they had settled down again, the cook had", + "disappeared.", + "‘Never mind!’ said the King, with an air of great relief. ‘Call the next", + "witness.’ And he added in an undertone to the Queen, ‘Really, my dear,", + "YOU must cross-examine the next witness. It quite makes my forehead", + "ache!’", + "Alice watched the White Rabbit as he fumbled over the list, feeling very", + "curious to see what the next witness would be like, ‘--for they haven’t", + "got much evidence YET,’ she said to herself. Imagine her surprise, when", + "the White Rabbit read out, at the top of his shrill little voice, the", + "name ‘Alice!’", + "CHAPTER XII. Alice’s Evidence", + "‘Here!’ cried Alice, quite forgetting in the flurry of the moment how", + "large she had grown in the last few minutes, and she jumped up in such", + "a hurry that she tipped over the jury-box with the edge of her skirt,", + "upsetting all the jurymen on to the heads of the crowd below, and there", + "they lay sprawling about, reminding her very much of a globe of goldfish", + "she had accidentally upset the week before.", + "‘Oh, I BEG your pardon!’ she exclaimed in a tone of great dismay, and", + "began picking them up again as quickly as she could, for the accident of", + "the goldfish kept running in her head, and she had a vague sort of idea", + "that they must be collected at once and put back into the jury-box, or", + "they would die.", + "‘The trial cannot proceed,’ said the King in a very grave voice, ‘until", + "all the jurymen are back in their proper places--ALL,’ he repeated with", + "great emphasis, looking hard at Alice as he said do.", + "Alice looked at the jury-box, and saw that, in her haste, she had put", + "the Lizard in head downwards, and the poor little thing was waving its", + "tail about in a melancholy way, being quite unable to move. She soon got", + "it out again, and put it right; ‘not that it signifies much,’ she said", + "to herself; ‘I should think it would be QUITE as much use in the trial", + "one way up as the other.’", + "As soon as the jury had a little recovered from the shock of being", + "upset, and their slates and pencils had been found and handed back to", + "them, they set to work very diligently to write out a history of the", + "accident, all except the Lizard, who seemed too much overcome to do", + "anything but sit with its mouth open, gazing up into the roof of the", + "court.", + "‘What do you know about this business?’ the King said to Alice.", + "‘Nothing,’ said Alice.", + "‘Nothing WHATEVER?’ persisted the King.", + "‘Nothing whatever,’ said Alice.", + "‘That’s very important,’ the King said, turning to the jury. They were", + "just beginning to write this down on their slates, when the White Rabbit", + "interrupted: ‘UNimportant, your Majesty means, of course,’ he said in a", + "very respectful tone, but frowning and making faces at him as he spoke.", + "‘UNimportant, of course, I meant,’ the King hastily said, and went on", + "to himself in an undertone,", + "‘important--unimportant--unimportant--important--’ as if he were trying", + "which word sounded best.", + "Some of the jury wrote it down ‘important,’ and some ‘unimportant.’", + "Alice could see this, as she was near enough to look over their slates;", + "‘but it doesn’t matter a bit,’ she thought to herself.", + "At this moment the King, who had been for some time busily writing in", + "his note-book, cackled out ‘Silence!’ and read out from his book, ‘Rule", + "Forty-two. ALL PERSONS MORE THAN A MILE HIGH TO LEAVE THE COURT.’", + "Everybody looked at Alice.", + "‘I’M not a mile high,’ said Alice.", + "‘You are,’ said the King.", + "‘Nearly two miles high,’ added the Queen.", + "‘Well, I shan’t go, at any rate,’ said Alice: ‘besides, that’s not a", + "regular rule: you invented it just now.’", + "‘It’s the oldest rule in the book,’ said the King.", + "‘Then it ought to be Number One,’ said Alice.", + "The King turned pale, and shut his note-book hastily. ‘Consider your", + "verdict,’ he said to the jury, in a low, trembling voice.", + "‘There’s more evidence to come yet, please your Majesty,’ said the White", + "Rabbit, jumping up in a great hurry; ‘this paper has just been picked", + "up.’", + "‘What’s in it?’ said the Queen.", + "‘I haven’t opened it yet,’ said the White Rabbit, ‘but it seems to be a", + "letter, written by the prisoner to--to somebody.’", + "‘It must have been that,’ said the King, ‘unless it was written to", + "nobody, which isn’t usual, you know.’", + "‘Who is it directed to?’ said one of the jurymen.", + "‘It isn’t directed at all,’ said the White Rabbit; ‘in fact, there’s", + "nothing written on the OUTSIDE.’ He unfolded the paper as he spoke, and", + "added ‘It isn’t a letter, after all: it’s a set of verses.’", + "‘Are they in the prisoner’s handwriting?’ asked another of the jurymen.", + "‘No, they’re not,’ said the White Rabbit, ‘and that’s the queerest thing", + "about it.’ (The jury all looked puzzled.)", + "‘He must have imitated somebody else’s hand,’ said the King. (The jury", + "all brightened up again.)", + "‘Please your Majesty,’ said the Knave, ‘I didn’t write it, and they", + "can’t prove I did: there’s no name signed at the end.’", + "‘If you didn’t sign it,’ said the King, ‘that only makes the matter", + "worse. You MUST have meant some mischief, or else you’d have signed your", + "name like an honest man.’", + "There was a general clapping of hands at this: it was the first really", + "clever thing the King had said that day.", + "‘That PROVES his guilt,’ said the Queen.", + "‘It proves nothing of the sort!’ said Alice. ‘Why, you don’t even know", + "what they’re about!’", + "‘Read them,’ said the King.", + "The White Rabbit put on his spectacles. ‘Where shall I begin, please", + "your Majesty?’ he asked.", + "‘Begin at the beginning,’ the King said gravely, ‘and go on till you", + "come to the end: then stop.’", + "These were the verses the White Rabbit read:--", + " ‘They told me you had been to her,", + " And mentioned me to him:", + " She gave me a good character,", + " But said I could not swim.", + " He sent them word I had not gone", + " (We know it to be true):", + " If she should push the matter on,", + " What would become of you?", + " I gave her one, they gave him two,", + " You gave us three or more;", + " They all returned from him to you,", + " Though they were mine before.", + " If I or she should chance to be", + " Involved in this affair,", + " He trusts to you to set them free,", + " Exactly as we were.", + " My notion was that you had been", + " (Before she had this fit)", + " An obstacle that came between", + " Him, and ourselves, and it.", + " Don’t let him know she liked them best,", + " For this must ever be", + " A secret, kept from all the rest,", + " Between yourself and me.’", + "‘That’s the most important piece of evidence we’ve heard yet,’ said the", + "King, rubbing his hands; ‘so now let the jury--’", + "‘If any one of them can explain it,’ said Alice, (she had grown so large", + "in the last few minutes that she wasn’t a bit afraid of interrupting", + "him,) ‘I’ll give him sixpence. _I_ don’t believe there’s an atom of", + "meaning in it.’", + "The jury all wrote down on their slates, ‘SHE doesn’t believe there’s an", + "atom of meaning in it,’ but none of them attempted to explain the paper.", + "‘If there’s no meaning in it,’ said the King, ‘that saves a world of", + "trouble, you know, as we needn’t try to find any. And yet I don’t know,’", + "he went on, spreading out the verses on his knee, and looking at them", + "with one eye; ‘I seem to see some meaning in them, after all. “--SAID", + "I COULD NOT SWIM--” you can’t swim, can you?’ he added, turning to the", + "Knave.", + "The Knave shook his head sadly. ‘Do I look like it?’ he said. (Which he", + "certainly did NOT, being made entirely of cardboard.)", + "‘All right, so far,’ said the King, and he went on muttering over", + "the verses to himself: ‘“WE KNOW IT TO BE TRUE--” that’s the jury, of", + "course--“I GAVE HER ONE, THEY GAVE HIM TWO--” why, that must be what he", + "did with the tarts, you know--’", + "‘But, it goes on “THEY ALL RETURNED FROM HIM TO YOU,”’ said Alice.", + "‘Why, there they are!’ said the King triumphantly, pointing to the tarts", + "on the table. ‘Nothing can be clearer than THAT. Then again--“BEFORE SHE", + "HAD THIS FIT--” you never had fits, my dear, I think?’ he said to the", + "Queen.", + "‘Never!’ said the Queen furiously, throwing an inkstand at the Lizard", + "as she spoke. (The unfortunate little Bill had left off writing on his", + "slate with one finger, as he found it made no mark; but he now hastily", + "began again, using the ink, that was trickling down his face, as long as", + "it lasted.)", + "‘Then the words don’t FIT you,’ said the King, looking round the court", + "with a smile. There was a dead silence.", + "‘It’s a pun!’ the King added in an offended tone, and everybody laughed,", + "‘Let the jury consider their verdict,’ the King said, for about the", + "twentieth time that day.", + "‘No, no!’ said the Queen. ‘Sentence first--verdict afterwards.’", + "‘Stuff and nonsense!’ said Alice loudly. ‘The idea of having the", + "sentence first!’", + "‘Hold your tongue!’ said the Queen, turning purple.", + "‘I won’t!’ said Alice.", + "‘Off with her head!’ the Queen shouted at the top of her voice. Nobody", + "moved.", + "‘Who cares for you?’ said Alice, (she had grown to her full size by this", + "time.) ‘You’re nothing but a pack of cards!’", + "At this the whole pack rose up into the air, and came flying down upon", + "her: she gave a little scream, half of fright and half of anger, and", + "tried to beat them off, and found herself lying on the bank, with her", + "head in the lap of her sister, who was gently brushing away some dead", + "leaves that had fluttered down from the trees upon her face.", + "‘Wake up, Alice dear!’ said her sister; ‘Why, what a long sleep you’ve", + "had!’", + "‘Oh, I’ve had such a curious dream!’ said Alice, and she told her", + "sister, as well as she could remember them, all these strange Adventures", + "of hers that you have just been reading about; and when she had", + "finished, her sister kissed her, and said, ‘It WAS a curious dream,", + "dear, certainly: but now run in to your tea; it’s getting late.’ So", + "Alice got up and ran off, thinking while she ran, as well she might,", + "what a wonderful dream it had been.", + "But her sister sat still just as she left her, leaning her head on her", + "hand, watching the setting sun, and thinking of little Alice and all her", + "wonderful Adventures, till she too began dreaming after a fashion, and", + "this was her dream:--", + "First, she dreamed of little Alice herself, and once again the tiny", + "hands were clasped upon her knee, and the bright eager eyes were looking", + "up into hers--she could hear the very tones of her voice, and see that", + "queer little toss of her head to keep back the wandering hair that", + "WOULD always get into her eyes--and still as she listened, or seemed to", + "listen, the whole place around her became alive with the strange creatures", + "of her little sister’s dream.", + "The long grass rustled at her feet as the White Rabbit hurried by--the", + "frightened Mouse splashed his way through the neighbouring pool--she", + "could hear the rattle of the teacups as the March Hare and his friends", + "shared their never-ending meal, and the shrill voice of the Queen", + "ordering off her unfortunate guests to execution--once more the pig-baby", + "was sneezing on the Duchess’s knee, while plates and dishes crashed", + "around it--once more the shriek of the Gryphon, the squeaking of the", + "Lizard’s slate-pencil, and the choking of the suppressed guinea-pigs,", + "filled the air, mixed up with the distant sobs of the miserable Mock", + "Turtle.", + "So she sat on, with closed eyes, and half believed herself in", + "Wonderland, though she knew she had but to open them again, and all", + "would change to dull reality--the grass would be only rustling in the", + "wind, and the pool rippling to the waving of the reeds--the rattling", + "teacups would change to tinkling sheep-bells, and the Queen’s shrill", + "cries to the voice of the shepherd boy--and the sneeze of the baby, the", + "shriek of the Gryphon, and all the other queer noises, would change (she", + "knew) to the confused clamour of the busy farm-yard--while the lowing", + "of the cattle in the distance would take the place of the Mock Turtle’s", + "heavy sobs.", + "Lastly, she pictured to herself how this same little sister of hers", + "would, in the after-time, be herself a grown woman; and how she would", + "keep, through all her riper years, the simple and loving heart of her", + "childhood: and how she would gather about her other little children, and", + "make THEIR eyes bright and eager with many a strange tale, perhaps even", + "with the dream of Wonderland of long ago: and how she would feel with", + "all their simple sorrows, and find a pleasure in all their simple joys,", + "remembering her own child-life, and the happy summer days.", + " THE END", + "End of Project Gutenberg’s Alice’s Adventures in Wonderland, by Lewis Carroll", + "*** END OF THIS PROJECT GUTENBERG EBOOK ALICE’S ADVENTURES IN WONDERLAND ***", + "***** This file should be named 11-0.txt or 11-0.zip *****", + "This and all associated files of various formats will be found in:", + " http://www.gutenberg.org/1/11/", + "Updated editions will replace the previous one--the old editions", + "will be renamed.", + "Creating the works from public domain print editions means that no", + "one owns a United States copyright in these works, so the Foundation", + "(and you!) can copy and distribute it in the United States without", + "permission and without paying copyright royalties. Special rules,", + "set forth in the General Terms of Use part of this license, apply to", + "copying and distributing Project Gutenberg-tm electronic works to", + "protect the PROJECT GUTENBERG-tm concept and trademark. Project", + "Gutenberg is a registered trademark, and may not be used if you", + "charge for the eBooks, unless you receive specific permission. If you", + "do not charge anything for copies of this eBook, complying with the", + "rules is very easy. You may use this eBook for nearly any purpose", + "such as creation of derivative works, reports, performances and", + "research. They may be modified and printed and given away--you may do", + "practically ANYTHING with public domain eBooks. Redistribution is", + "subject to the trademark license, especially commercial", + "redistribution.", + "*** START: FULL LICENSE ***", + "THE FULL PROJECT GUTENBERG LICENSE", + "PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK", + "To protect the Project Gutenberg-tm mission of promoting the free", + "distribution of electronic works, by using or distributing this work", + "(or any other work associated in any way with the phrase “Project", + "Gutenberg”), you agree to comply with all the terms of the Full Project", + "Gutenberg-tm License (available with this file or online at", + "http://gutenberg.org/license).", + "Section 1. General Terms of Use and Redistributing Project Gutenberg-tm", + "electronic works", + "1.A. By reading or using any part of this Project Gutenberg-tm", + "electronic work, you indicate that you have read, understand, agree to", + "and accept all the terms of this license and intellectual property", + "(trademark/copyright) agreement. If you do not agree to abide by all", + "the terms of this agreement, you must cease using and return or destroy", + "all copies of Project Gutenberg-tm electronic works in your possession.", + "If you paid a fee for obtaining a copy of or access to a Project", + "Gutenberg-tm electronic work and you do not agree to be bound by the", + "terms of this agreement, you may obtain a refund from the person or", + "entity to whom you paid the fee as set forth in paragraph 1.E.8.", + "1.B. “Project Gutenberg” is a registered trademark. It may only be", + "used on or associated in any way with an electronic work by people who", + "agree to be bound by the terms of this agreement. There are a few", + "things that you can do with most Project Gutenberg-tm electronic works", + "even without complying with the full terms of this agreement. See", + "paragraph 1.C below. There are a lot of things you can do with Project", + "Gutenberg-tm electronic works if you follow the terms of this agreement", + "and help preserve free future access to Project Gutenberg-tm electronic", + "works. See paragraph 1.E below.", + "1.C. The Project Gutenberg Literary Archive Foundation (“the Foundation”", + " or PGLAF), owns a compilation copyright in the collection of Project", + "Gutenberg-tm electronic works. Nearly all the individual works in the", + "collection are in the public domain in the United States. If an", + "individual work is in the public domain in the United States and you are", + "located in the United States, we do not claim a right to prevent you from", + "copying, distributing, performing, displaying or creating derivative", + "works based on the work as long as all references to Project Gutenberg", + "are removed. Of course, we hope that you will support the Project", + "Gutenberg-tm mission of promoting free access to electronic works by", + "freely sharing Project Gutenberg-tm works in compliance with the terms of", + "this agreement for keeping the Project Gutenberg-tm name associated with", + "the work. You can easily comply with the terms of this agreement by", + "keeping this work in the same format with its attached full Project", + "Gutenberg-tm License when you share it without charge with others.", + "1.D. The copyright laws of the place where you are located also govern", + "what you can do with this work. Copyright laws in most countries are in", + "a constant state of change. If you are outside the United States, check", + "the laws of your country in addition to the terms of this agreement", + "before downloading, copying, displaying, performing, distributing or", + "creating derivative works based on this work or any other Project", + "Gutenberg-tm work. The Foundation makes no representations concerning", + "the copyright status of any work in any country outside the United", + "States.", + "1.E. Unless you have removed all references to Project Gutenberg:", + "1.E.1. The following sentence, with active links to, or other immediate", + "access to, the full Project Gutenberg-tm License must appear prominently", + "whenever any copy of a Project Gutenberg-tm work (any work on which the", + "phrase “Project Gutenberg” appears, or with which the phrase “Project", + "Gutenberg” is associated) is accessed, displayed, performed, viewed,", + "copied or distributed:", + "This eBook is for the use of anyone anywhere at no cost and with", + "almost no restrictions whatsoever. You may copy it, give it away or", + "re-use it under the terms of the Project Gutenberg License included", + "with this eBook or online at www.gutenberg.org", + "1.E.2. If an individual Project Gutenberg-tm electronic work is derived", + "from the public domain (does not contain a notice indicating that it is", + "posted with permission of the copyright holder), the work can be copied", + "and distributed to anyone in the United States without paying any fees", + "or charges. If you are redistributing or providing access to a work", + "with the phrase “Project Gutenberg” associated with or appearing on the", + "work, you must comply either with the requirements of paragraphs 1.E.1", + "through 1.E.7 or obtain permission for the use of the work and the", + "Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or", + "1.E.9.", + "1.E.3. If an individual Project Gutenberg-tm electronic work is posted", + "with the permission of the copyright holder, your use and distribution", + "must comply with both paragraphs 1.E.1 through 1.E.7 and any additional", + "terms imposed by the copyright holder. Additional terms will be linked", + "to the Project Gutenberg-tm License for all works posted with the", + "permission of the copyright holder found at the beginning of this work.", + "1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm", + "License terms from this work, or any files containing a part of this", + "work or any other work associated with Project Gutenberg-tm.", + "1.E.5. Do not copy, display, perform, distribute or redistribute this", + "electronic work, or any part of this electronic work, without", + "prominently displaying the sentence set forth in paragraph 1.E.1 with", + "active links or immediate access to the full terms of the Project", + "Gutenberg-tm License.", + "1.E.6. You may convert to and distribute this work in any binary,", + "compressed, marked up, nonproprietary or proprietary form, including any", + "word processing or hypertext form. However, if you provide access to or", + "distribute copies of a Project Gutenberg-tm work in a format other than", + "“Plain Vanilla ASCII” or other format used in the official version", + "posted on the official Project Gutenberg-tm web site (www.gutenberg.org),", + "you must, at no additional cost, fee or expense to the user, provide a", + "copy, a means of exporting a copy, or a means of obtaining a copy upon", + "request, of the work in its original “Plain Vanilla ASCII” or other", + "form. Any alternate format must include the full Project Gutenberg-tm", + "License as specified in paragraph 1.E.1.", + "1.E.7. Do not charge a fee for access to, viewing, displaying,", + "performing, copying or distributing any Project Gutenberg-tm works", + "unless you comply with paragraph 1.E.8 or 1.E.9.", + "1.E.8. You may charge a reasonable fee for copies of or providing", + "access to or distributing Project Gutenberg-tm electronic works provided", + "that", + "- You pay a royalty fee of 20% of the gross profits you derive from", + " the use of Project Gutenberg-tm works calculated using the method", + " you already use to calculate your applicable taxes. The fee is", + " owed to the owner of the Project Gutenberg-tm trademark, but he", + " has agreed to donate royalties under this paragraph to the", + " Project Gutenberg Literary Archive Foundation. Royalty payments", + " must be paid within 60 days following each date on which you", + " prepare (or are legally required to prepare) your periodic tax", + " returns. Royalty payments should be clearly marked as such and", + " sent to the Project Gutenberg Literary Archive Foundation at the", + " address specified in Section 4, “Information about donations to", + " the Project Gutenberg Literary Archive Foundation.”", + "- You provide a full refund of any money paid by a user who notifies", + " you in writing (or by e-mail) within 30 days of receipt that s/he", + " does not agree to the terms of the full Project Gutenberg-tm", + " License. You must require such a user to return or", + " destroy all copies of the works possessed in a physical medium", + " and discontinue all use of and all access to other copies of", + " Project Gutenberg-tm works.", + "- You provide, in accordance with paragraph 1.F.3, a full refund of any", + " money paid for a work or a replacement copy, if a defect in the", + " electronic work is discovered and reported to you within 90 days", + " of receipt of the work.", + "- You comply with all other terms of this agreement for free", + " distribution of Project Gutenberg-tm works.", + "1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm", + "electronic work or group of works on different terms than are set", + "forth in this agreement, you must obtain permission in writing from", + "both the Project Gutenberg Literary Archive Foundation and Michael", + "Hart, the owner of the Project Gutenberg-tm trademark. Contact the", + "Foundation as set forth in Section 3 below.", + "1.F.", + "1.F.1. Project Gutenberg volunteers and employees expend considerable", + "effort to identify, do copyright research on, transcribe and proofread", + "public domain works in creating the Project Gutenberg-tm", + "collection. Despite these efforts, Project Gutenberg-tm electronic", + "works, and the medium on which they may be stored, may contain", + "“Defects,” such as, but not limited to, incomplete, inaccurate or", + "corrupt data, transcription errors, a copyright or other intellectual", + "property infringement, a defective or damaged disk or other medium, a", + "computer virus, or computer codes that damage or cannot be read by", + "your equipment.", + "1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the “Right", + "of Replacement or Refund” described in paragraph 1.F.3, the Project", + "Gutenberg Literary Archive Foundation, the owner of the Project", + "Gutenberg-tm trademark, and any other party distributing a Project", + "Gutenberg-tm electronic work under this agreement, disclaim all", + "liability to you for damages, costs and expenses, including legal", + "fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT", + "LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE", + "PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE", + "TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE", + "LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR", + "INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH", + "DAMAGE.", + "1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a", + "defect in this electronic work within 90 days of receiving it, you can", + "receive a refund of the money (if any) you paid for it by sending a", + "written explanation to the person you received the work from. If you", + "received the work on a physical medium, you must return the medium with", + "your written explanation. The person or entity that provided you with", + "the defective work may elect to provide a replacement copy in lieu of a", + "refund. If you received the work electronically, the person or entity", + "providing it to you may choose to give you a second opportunity to", + "receive the work electronically in lieu of a refund. If the second copy", + "is also defective, you may demand a refund in writing without further", + "opportunities to fix the problem.", + "1.F.4. Except for the limited right of replacement or refund set forth", + "in paragraph 1.F.3, this work is provided to you ‘AS-IS’ WITH NO OTHER", + "WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO", + "WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE.", + "1.F.5. Some states do not allow disclaimers of certain implied", + "warranties or the exclusion or limitation of certain types of damages.", + "If any disclaimer or limitation set forth in this agreement violates the", + "law of the state applicable to this agreement, the agreement shall be", + "interpreted to make the maximum disclaimer or limitation permitted by", + "the applicable state law. The invalidity or unenforceability of any", + "provision of this agreement shall not void the remaining provisions.", + "1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the", + "trademark owner, any agent or employee of the Foundation, anyone", + "providing copies of Project Gutenberg-tm electronic works in accordance", + "with this agreement, and any volunteers associated with the production,", + "promotion and distribution of Project Gutenberg-tm electronic works,", + "harmless from all liability, costs and expenses, including legal fees,", + "that arise directly or indirectly from any of the following which you do", + "or cause to occur: (a) distribution of this or any Project Gutenberg-tm", + "work, (b) alteration, modification, or additions or deletions to any", + "Project Gutenberg-tm work, and (c) any Defect you cause.", + "Section 2. Information about the Mission of Project Gutenberg-tm", + "Project Gutenberg-tm is synonymous with the free distribution of", + "electronic works in formats readable by the widest variety of computers", + "including obsolete, old, middle-aged and new computers. It exists", + "because of the efforts of hundreds of volunteers and donations from", + "people in all walks of life.", + "Volunteers and financial support to provide volunteers with the", + "assistance they need, is critical to reaching Project Gutenberg-tm’s", + "goals and ensuring that the Project Gutenberg-tm collection will", + "remain freely available for generations to come. In 2001, the Project", + "Gutenberg Literary Archive Foundation was created to provide a secure", + "and permanent future for Project Gutenberg-tm and future generations.", + "To learn more about the Project Gutenberg Literary Archive Foundation", + "and how your efforts and donations can help, see Sections 3 and 4", + "and the Foundation web page at http://www.pglaf.org.", + "Section 3. Information about the Project Gutenberg Literary Archive", + "Foundation", + "The Project Gutenberg Literary Archive Foundation is a non profit", + "501(c)(3) educational corporation organized under the laws of the", + "state of Mississippi and granted tax exempt status by the Internal", + "Revenue Service. The Foundation’s EIN or federal tax identification", + "number is 64-6221541. Its 501(c)(3) letter is posted at", + "http://pglaf.org/fundraising. Contributions to the Project Gutenberg", + "Literary Archive Foundation are tax deductible to the full extent", + "permitted by U.S. federal laws and your state’s laws.", + "The Foundation’s principal office is located at 4557 Melan Dr. S.", + "Fairbanks, AK, 99712., but its volunteers and employees are scattered", + "throughout numerous locations. Its business office is located at", + "809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email", + "business@pglaf.org. Email contact links and up to date contact", + "information can be found at the Foundation’s web site and official", + "page at http://pglaf.org", + "For additional contact information:", + " Dr. Gregory B. Newby", + " Chief Executive and Director", + " gbnewby@pglaf.org", + "Section 4. Information about Donations to the Project Gutenberg", + "Literary Archive Foundation", + "Project Gutenberg-tm depends upon and cannot survive without wide", + "spread public support and donations to carry out its mission of", + "increasing the number of public domain and licensed works that can be", + "freely distributed in machine readable form accessible by the widest", + "array of equipment including outdated equipment. Many small donations", + "($1 to $5,000) are particularly important to maintaining tax exempt", + "status with the IRS.", + "The Foundation is committed to complying with the laws regulating", + "charities and charitable donations in all 50 states of the United", + "States. Compliance requirements are not uniform and it takes a", + "considerable effort, much paperwork and many fees to meet and keep up", + "with these requirements. We do not solicit donations in locations", + "where we have not received written confirmation of compliance. To", + "SEND DONATIONS or determine the status of compliance for any", + "particular state visit http://pglaf.org", + "While we cannot and do not solicit contributions from states where we", + "have not met the solicitation requirements, we know of no prohibition", + "against accepting unsolicited donations from donors in such states who", + "approach us with offers to donate.", + "International donations are gratefully accepted, but we cannot make", + "any statements concerning tax treatment of donations received from", + "outside the United States. U.S. laws alone swamp our small staff.", + "Please check the Project Gutenberg Web pages for current donation", + "methods and addresses. Donations are accepted in a number of other", + "ways including checks, online payments and credit card donations.", + "To donate, please visit: http://pglaf.org/donate", + "Section 5. General Information About Project Gutenberg-tm electronic", + "works.", + "Professor Michael S. Hart is the originator of the Project Gutenberg-tm", + "concept of a library of electronic works that could be freely shared", + "with anyone. For thirty years, he produced and distributed Project", + "Gutenberg-tm eBooks with only a loose network of volunteer support.", + "Project Gutenberg-tm eBooks are often created from several printed", + "editions, all of which are confirmed as Public Domain in the U.S.", + "unless a copyright notice is included. Thus, we do not necessarily", + "keep eBooks in compliance with any particular paper edition.", + "Most people start at our Web site which has the main PG search facility:", + " http://www.gutenberg.org", + "This Web site includes information about Project Gutenberg-tm,", + "including how to make donations to the Project Gutenberg Literary", + "Archive Foundation, how to help produce our new eBooks, and how to", + "subscribe to our email newsletter to hear about new eBooks.", + "" +};
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/format.sh
Added
@@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" +find . \( -name '*.cpp' -o -name '*.c' -o -name '*.h' -o -name '*.hpp' -o -name '*.re2c' \) -exec astyle --style=stroustrup --attach-extern-c --break-blocks --pad-header --pad-paren-out --unpad-paren --add-brackets --keep-one-line-blocks --keep-one-line-statements --convert-tabs --align-pointer=type --align-reference=type --suffix=none --lineend=linux --max-code-length=180 {} \;
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src
Added
+(directory)
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/avc.c
Added
@@ -0,0 +1,595 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ + +#include "avc.h" +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +//////////////////////////////////////////////////////////////////////////////// +// AVC RBSP Methods +// TODO move the to a avcutils file +static size_t _find_emulation_prevention_byte (const uint8_t* data, size_t size) +{ + size_t offset = 2; + + while (offset < size) { + if (0 == data[offset]) { + // 0 0 X 3 //; we know X is zero + offset += 1; + } else if (3 != data[offset]) { + // 0 0 X 0 0 3; we know X is not 0 and not 3 + offset += 3; + } else if (0 != data[offset-1]) { + // 0 X 0 0 3 + offset += 2; + } else if (0 != data[offset-2]) { + // X 0 0 3 + offset += 1; + } else { + // 0 0 3 + return offset; + } + } + + return size; +} + +static size_t _copy_to_rbsp (uint8_t* destData, size_t destSize, const uint8_t* sorcData, size_t sorcSize) +{ + size_t toCopy, totlSize = 0; + + for (;;) { + if (destSize >= sorcSize) { + return 0; + } + + // The following line IS correct! We want to look in sorcData up to destSize bytes + // We know destSize is smaller than sorcSize because of the previous line + toCopy = _find_emulation_prevention_byte (sorcData,destSize); + memcpy (destData, sorcData, toCopy); + totlSize += toCopy; + destData += toCopy; + destSize -= toCopy; + + if (0 == destSize) { + return totlSize; + } + + // skip the emulation prevention byte + totlSize += 1; + sorcData += toCopy + 1; + sorcSize -= toCopy + 1; + } + + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +static inline size_t _find_emulated (uint8_t* data, size_t size) +{ + size_t offset = 2; + + while (offset < size) { + if (3 < data[offset]) { + // 0 0 X; we know X is not 0, 1, 2 or 3 + offset += 3; + } else if (0 != data[offset-1]) { + // 0 X 0 0 1 + offset += 2; + } else if (0 != data[offset-2]) { + // X 0 0 1 + offset += 1; + } else { + // 0 0 0, 0 0 1 + return offset; + } + } + + return size; +} + +size_t _copy_from_rbsp (uint8_t* data, uint8_t* payloadData, size_t payloadSize) +{ + size_t total = 0; + + while (payloadSize) { + size_t bytes = _find_emulated (payloadData,payloadSize); + + if (bytes > payloadSize) { + return 0; + } + + memcpy (data, payloadData, bytes); + + if (bytes == payloadSize) { + return total + bytes; + } + + data[bytes] = 3; // insert emulation prevention byte + data += bytes + 1; total += bytes + 1; + payloadData += bytes; payloadSize -= bytes; + } + + return total; +} +//////////////////////////////////////////////////////////////////////////////// +struct _sei_message_t { + size_t size; + sei_msgtype_t type; + struct _sei_message_t* next; +}; + +sei_message_t* sei_message_next (sei_message_t* msg) { return ( (struct _sei_message_t*) msg)->next; } +sei_msgtype_t sei_message_type (sei_message_t* msg) { return ( (struct _sei_message_t*) msg)->type; } +size_t sei_message_size (sei_message_t* msg) { return ( (struct _sei_message_t*) msg)->size; } +uint8_t* sei_message_data (sei_message_t* msg) { return ( (uint8_t*) msg) + sizeof (struct _sei_message_t); } +void sei_message_free (sei_message_t* msg) { if (msg) { free (msg); } } + +sei_message_t* sei_message_new (sei_msgtype_t type, uint8_t* data, size_t size) +{ + struct _sei_message_t* msg = (struct _sei_message_t*) malloc (sizeof (struct _sei_message_t) + size); + msg->next = 0; msg->type = type; msg->size = size; + + if (data) { + memcpy (sei_message_data (msg), data, size); + } else { + memset (sei_message_data (msg), 0, size); + } + + return (sei_message_t*) msg; +} +//////////////////////////////////////////////////////////////////////////////// +void sei_init (sei_t* sei) +{ + sei->dts = -1; + sei->cts = -1; + sei->head = 0; + sei->tail = 0; +} + +void sei_message_append (sei_t* sei, sei_message_t* msg) +{ + if (0 == sei->head) { + sei->head = msg; + sei->tail = msg; + } else { + sei->tail->next = msg; + sei->tail = msg; + } +} + +void sei_free (sei_t* sei) +{ + sei_message_t* tail; + + while (sei->head) { + tail = sei->head->next; + free (sei->head); + sei->head = tail; + } + + sei_init (sei); +} + +void sei_dump (sei_t* sei) +{ + fprintf (stderr,"SEI %p\n", sei); + sei_dump_messages (sei->head); +} + +void sei_dump_messages (sei_message_t* head) +{ + cea708_t cea708; + sei_message_t* msg; + cea708_init (&cea708); + + for (msg = head ; msg ; msg = sei_message_next (msg)) { + uint8_t* data = sei_message_data (msg); + size_t size = sei_message_size (msg); + fprintf (stderr,"-- Message %p\n-- Message Type: %d\n-- Message Size: %d\n", data, sei_message_type (msg), (int) size); + + while (size) { + fprintf (stderr,"%02X ", *data); + ++data; --size; + } + + fprintf (stderr,"\n"); + + if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) { + cea708_parse (sei_message_data (msg), sei_message_size (msg), &cea708); + cea708_dump (&cea708); + } + + + } +} + +//////////////////////////////////////////////////////////////////////////////// +size_t sei_render_size (sei_t* sei) +{ + size_t size = 2; // nalu_type + stop bit + sei_message_t* msg; + + for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) { + size += 1 + (msg->type / 255); + size += 1 + (msg->size / 255); + size += 1 + (msg->size * 4/3); + } + + return size; +} + +// we can safely assume sei_render_size() bytes have been allocated for data +size_t sei_render (sei_t* sei, uint8_t* data) +{ + size_t escaped_size, size = 2; // nalu_type + stop bit + sei_message_t* msg; + (*data) = 6; ++data; + + for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) { + int payloadType = sei_message_type (msg); + int payloadSize = (int) sei_message_size (msg); + uint8_t* payloadData = sei_message_data (msg); + + while (255 <= payloadType) { + (*data) = 255; + ++data; ++size; + payloadType -= 255; + } + + (*data) = payloadType; + ++data; ++size; + + while (255 <= payloadSize) { + (*data) = 255; + ++data; ++size; + payloadSize -= 255; + } + + (*data) = payloadSize; + ++data; ++size; + + if (0 >= (escaped_size = _copy_from_rbsp (data,payloadData,payloadSize))) { + return 0; + } + + data += escaped_size; + size += escaped_size; + } + + // write stop bit and return + (*data) = 0x80; + return size; +} + +uint8_t* sei_render_alloc (sei_t* sei, size_t* size) +{ + size_t aloc = sei_render_size (sei); + uint8_t* data = malloc (aloc); + (*size) = sei_render (sei, data); + return data; +} + +//////////////////////////////////////////////////////////////////////////////// +int sei_parse_nalu (sei_t* sei, const uint8_t* data, size_t size, double dts, double cts) +{ + assert (0<=cts); // cant present before decode + sei->dts = dts; + sei->cts = cts; + int ret = 0; + + if (0 == data || 0 == size) { + return 0; + } + + uint8_t nal_unit_type = (*data) & 0x1F; + ++data; --size; + + if (6 != nal_unit_type) { + return 0; + } + + // SEI may contain more than one payload + while (1<size) { + int payloadType = 0; + int payloadSize = 0; + + while (0 < size && 255 == (*data)) { + payloadType += 255; + ++data; --size; + } + + if (0 == size) { + goto error; + } + + payloadType += (*data); + ++data; --size; + + while (0 < size && 255 == (*data)) { + payloadSize += 255; + ++data; --size; + } + + if (0 == size) { + goto error; + } + + payloadSize += (*data); + ++data; --size; + + if (payloadSize) { + sei_message_t* msg = sei_message_new ( (sei_msgtype_t) payloadType, 0, payloadSize); + uint8_t* payloadData = sei_message_data (msg); + size_t bytes = _copy_to_rbsp (payloadData, payloadSize, data, size); + sei_message_append (sei, msg); + + if ( (int) bytes < payloadSize) { + goto error; + } + + data += bytes; size -= bytes; + ++ret; + } + } + + // There should be one trailing byte, 0x80. But really, we can just ignore that fact. + return ret; +error: + sei_init (sei); + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +libcaption_stauts_t sei_to_caption_frame (sei_t* sei, caption_frame_t* frame) +{ + cea708_t cea708; + sei_message_t* msg; + libcaption_stauts_t status = LIBCAPTION_OK; + + cea708_init (&cea708); + + for (msg = sei_message_head (sei) ; msg ; msg = sei_message_next (msg)) { + if (sei_type_user_data_registered_itu_t_t35 == sei_message_type (msg)) { + cea708_parse (sei_message_data (msg), sei_message_size (msg), &cea708); + status = libcaption_status_update (status, cea708_to_caption_frame (frame, &cea708, sei_pts (sei))); + } + } + + if (LIBCAPTION_READY == status) { + frame->timestamp = sei->dts + sei->cts; + frame->duration = 0; + } + + return status; +} + +//////////////////////////////////////////////////////////////////////////////// +#define DEFAULT_CHANNEL 0 + +void sei_append_708 (sei_t* sei, cea708_t* cea708) +{ + sei_message_t* msg = sei_message_new (sei_type_user_data_registered_itu_t_t35, 0, CEA608_MAX_SIZE); + msg->size = cea708_render (cea708, sei_message_data (msg), sei_message_size (msg)); + sei_message_append (sei,msg); + // cea708_dump (cea708); + cea708_init (cea708); // will confgure using HLS compatiable defaults +} + +// This should be moved to 708.c +// This works for popon, but bad for paint on and roll up +// Please understand this function before you try to use it, setting null values have different effects than you may assume +void sei_encode_eia608 (sei_t* sei, cea708_t* cea708, uint16_t cc_data) +{ + // This one is full, flush and init a new one + // shoudl this be 32? I cant remember + if (31 == cea708->user_data.cc_count) { + sei_append_708 (sei,cea708); + } + + if (0 == cea708->user_data.cc_count) { // This is a new 708 header, but a continuation of a 608 stream + cea708_add_cc_data (cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command (eia608_control_resume_caption_loading, DEFAULT_CHANNEL)); + } + + if (0 == cc_data) { // Finished + sei_encode_eia608 (sei,cea708,eia608_control_command (eia608_control_end_of_caption, DEFAULT_CHANNEL)); + sei_append_708 (sei,cea708); + return; + } + + cea708_add_cc_data (cea708, 1, cc_type_ntsc_cc_field_1, cc_data); +} +//////////////////////////////////////////////////////////////////////////////// +// TODO use alternate charcters instead of always using space before extended charcters +// TODO rewrite this function with better logic +int sei_from_caption_frame (sei_t* sei, caption_frame_t* frame) +{ + int r,c; + cea708_t cea708; + const char* data; + uint16_t prev_cc_data; + + cea708_init (&cea708); // set up a new popon frame + cea708_add_cc_data (&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command (eia608_control_erase_non_displayed_memory, DEFAULT_CHANNEL)); + cea708_add_cc_data (&cea708, 1, cc_type_ntsc_cc_field_1, eia608_control_command (eia608_control_resume_caption_loading, DEFAULT_CHANNEL)); + + for (r=0; r<SCREEN_ROWS; ++r) { + // Calculate preamble + for (c=0; c<SCREEN_COLS && 0 == *caption_frame_read_char (frame,r,c,0,0) ; ++c) {} + + // This row is blank + if (SCREEN_COLS == c) { + continue; + } + + // Write preamble + sei_encode_eia608 (sei, &cea708, eia608_row_column_pramble (r,c,DEFAULT_CHANNEL,0)); + int tab = c % 4; + + if (tab) { + sei_encode_eia608 (sei, &cea708, eia608_tab (tab,DEFAULT_CHANNEL)); + } + + // Write the row + for (prev_cc_data = 0, data = caption_frame_read_char (frame,r,c,0,0) ; + (*data) && c < SCREEN_COLS ; ++c, data = caption_frame_read_char (frame,r,c,0,0)) { + uint16_t cc_data = eia608_from_utf8_1 (data,DEFAULT_CHANNEL); + + if (!cc_data) { + // We do't want to write bad data, so just ignore it. + } else if (eia608_is_basicna (prev_cc_data)) { + if (eia608_is_basicna (cc_data)) { + // previous and current chars are both basicna, combine them into current + sei_encode_eia608 (sei, &cea708, eia608_from_basicna (prev_cc_data,cc_data)); + } else if (eia608_is_westeu (cc_data)) { + // extended charcters overwrite the previous charcter, so insert a dummy char thren write the extended char + sei_encode_eia608 (sei, &cea708, eia608_from_basicna (prev_cc_data,eia608_from_utf8_1 (EIA608_CHAR_SPACE,DEFAULT_CHANNEL))); + sei_encode_eia608 (sei, &cea708, cc_data); + } else { + // previous was basic na, but current isnt; write previous and current + sei_encode_eia608 (sei, &cea708, prev_cc_data); + sei_encode_eia608 (sei, &cea708, cc_data); + } + + prev_cc_data = 0; // previous is handled, we can forget it now + } else if (eia608_is_westeu (cc_data)) { + // extended chars overwrite the previous chars, so insert a dummy char + sei_encode_eia608 (sei, &cea708, eia608_from_utf8_1 (EIA608_CHAR_SPACE,DEFAULT_CHANNEL)); + sei_encode_eia608 (sei, &cea708, cc_data); + } else if (eia608_is_basicna (cc_data)) { + prev_cc_data = cc_data; + } else { + sei_encode_eia608 (sei, &cea708, cc_data); + } + + if (eia608_is_specialna (cc_data)) { + // specialna are treated as controll charcters. Duplicated controll charcters are discarded + // So we for a resume after a specialna as a noop to break repetition detection + // TODO only do this if the same charcter is repeated + sei_encode_eia608 (sei, &cea708, eia608_control_command (eia608_control_resume_caption_loading, DEFAULT_CHANNEL)); + } + } + + if (0 != prev_cc_data) { + sei_encode_eia608 (sei, &cea708, prev_cc_data); + } + } + + sei_encode_eia608 (sei, &cea708, 0); // flush + sei->dts = frame->timestamp; // assumes in order frames + // sei_dump (sei); + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +static int avc_is_start_code (const uint8_t* data, int size, int* len) +{ + if (3 > size) { + return -1; + } + + if (1 < data[2]) { + return 3; + } + + if (0 != data[1]) { + return 2; + } + + if (0 == data[0]) { + if (1 == data[2]) { + *len = 3; + return 0; + } + + if (4 <= size && 1 == data[3]) { + *len = 4; + return 0; + } + } + + return 1; +} + + +static int avc_find_start_code (const uint8_t* data, int size, int* len) +{ + int pos = 0; + + for (;;) { + // is pos pointing to a start code? + int isc = avc_is_start_code (data + pos, size - pos, len); + + if (0 < isc) { + pos += isc; + } else if (0 > isc) { + // No start code found + return isc; + } else { + // Start code found at pos + return pos; + } + } +} + + +static int avc_find_start_code_increnental (const uint8_t* data, int size, int prev_size, int* len) +{ + int offset = (3 <= prev_size) ? (prev_size - 3) : 0; + int pos = avc_find_start_code (data + offset, size - offset, len); + + if (0 <= pos) { + return pos + offset; + } + + return pos; +} + +void avcnalu_init (avcnalu_t* nalu) +{ + memset (nalu,0,sizeof (avcnalu_t)); +} + +int avcnalu_parse_annexb (avcnalu_t* nalu, const uint8_t** data, size_t* size) +{ + int scpos, sclen; + int new_size = (int) (nalu->size + (*size)); + + if (new_size > MAX_NALU_SIZE) { + (*size) = nalu->size = 0; + return LIBCAPTION_ERROR; + } + + memcpy (&nalu->data[nalu->size], (*data), (*size)); + scpos = avc_find_start_code_increnental (&nalu->data[0], new_size, (int) nalu->size, &sclen); + + if (0<=scpos) { + (*data) += (scpos - nalu->size) + sclen; + (*size) -= (scpos - nalu->size) + sclen; + nalu->size = scpos; + return 0 < nalu->size ? LIBCAPTION_READY : LIBCAPTION_OK; + } else { + (*size) = 0; + nalu->size = new_size; + return LIBCAPTION_OK; + } +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/caption.c
Added
@@ -0,0 +1,491 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "utf8.h" +#include "xds.h" +#include "eia608.h" +#include "caption.h" +#include <stdio.h> +#include <string.h> +//////////////////////////////////////////////////////////////////////////////// +void caption_frame_buffer_clear (caption_frame_buffer_t* buff) +{ + memset (buff,0,sizeof (caption_frame_buffer_t)); +} + +void caption_frame_state_clear (caption_frame_t* frame) +{ + frame->timestamp = -1; + frame->duration = 0; + frame->state = (caption_frame_state_t) {0,0,0,0,0,0,0}; // clear global state +} + +void caption_frame_init (caption_frame_t* frame) +{ + caption_frame_state_clear (frame); + xds_init (&frame->xds); + caption_frame_buffer_clear (&frame->back); + caption_frame_buffer_clear (&frame->front); +} +//////////////////////////////////////////////////////////////////////////////// +#define CAPTION_CLEAR 0 +#define CAPTION_POP_ON 2 +#define CAPTION_PAINT_ON 3 +#define CAPTION_ROLL_UP 4 +//////////////////////////////////////////////////////////////////////////////// +// Helpers +static caption_frame_cell_t* frame_buffer_cell (caption_frame_buffer_t* buff, int row, int col) +{ + return &buff->cell[row][col]; +} + +static caption_frame_buffer_t* frame_write_buffer (caption_frame_t* frame) +{ + if (CAPTION_POP_ON == frame->state.mod) { + return &frame->back; + } else if (CAPTION_PAINT_ON == frame->state.mod || CAPTION_ROLL_UP == frame->state.mod) { + return &frame->front; + } else { + return 0; + } +} + +static caption_frame_cell_t* frame_cell (caption_frame_t* frame, int row, int col) +{ + return frame_buffer_cell (&frame->front,row,col); +} + +static caption_frame_cell_t* frame_cell_get (caption_frame_t* frame) +{ + return frame_cell (frame, frame->state.row, frame->state.col); +} + +//////////////////////////////////////////////////////////////////////////////// +uint16_t _eia608_from_utf8 (const char* s); // function is in eia608.c.re2c +int caption_frame_write_char (caption_frame_t* frame, int row, int col, eia608_style_t style, int underline, const char* c) +{ + caption_frame_buffer_t* buff = frame_write_buffer (frame); + + if (!buff || ! _eia608_from_utf8 (c)) { + return 0; + } + + caption_frame_cell_t* cell = frame_buffer_cell (buff,row,col); + + if (utf8_char_copy (&cell->data[0],c)) { + cell->uln = underline; + cell->sty = style; + return 1; + } + + return 0; +} + +const utf8_char_t* caption_frame_read_char (caption_frame_t* frame, int row, int col, eia608_style_t* style, int* underline) +{ + caption_frame_cell_t* cell = frame_cell (frame, row, col); + + if (!cell) { + if (style) { + (*style) = eia608_style_white; + } + + if (underline) { + (*underline) = 0; + } + + return EIA608_CHAR_NULL; + } + + if (style) { + (*style) = cell->sty; + } + + if (underline) { + (*underline) = cell->uln; + } + + return &cell->data[0]; +} + +//////////////////////////////////////////////////////////////////////////////// +// Parsing +libcaption_stauts_t caption_frame_carriage_return (caption_frame_t* frame) +{ + caption_frame_buffer_t* buff = frame_write_buffer (frame); + + if (!buff) { + return LIBCAPTION_OK; + } + + int r = frame->state.row - (frame->state.rup-1); + + if (0 >= r || CAPTION_ROLL_UP != frame->state.mod) { + return LIBCAPTION_OK; + } + + for (; r < SCREEN_ROWS; ++r) { + uint8_t* dst = (uint8_t*) frame_buffer_cell (buff,r-1,0); + uint8_t* src = (uint8_t*) frame_buffer_cell (buff,r-0,0); + memcpy (dst,src,sizeof (caption_frame_cell_t) * SCREEN_COLS); + } + + memset (frame_buffer_cell (buff,SCREEN_ROWS-1,0), 0,sizeof (caption_frame_cell_t) * SCREEN_COLS); + return LIBCAPTION_OK; +} +//////////////////////////////////////////////////////////////////////////////// +libcaption_stauts_t eia608_write_char (caption_frame_t* frame, char* c) +{ + if (0 == c || 0 == c[0] || + SCREEN_ROWS <= frame->state.row || 0 > frame->state.row || + SCREEN_COLS <= frame->state.col || 0 > frame->state.col) { + // NO-OP + } else if (caption_frame_write_char (frame,frame->state.row,frame->state.col,frame->state.sty,frame->state.uln, c)) { + frame->state.col += 1; + } + + return LIBCAPTION_OK; +} + +libcaption_stauts_t caption_frame_end (caption_frame_t* frame) +{ + memcpy (&frame->front,&frame->back,sizeof (caption_frame_buffer_t)); + caption_frame_state_clear (frame); + caption_frame_buffer_clear (&frame->back); + return LIBCAPTION_READY; +} + +libcaption_stauts_t caption_frame_decode_preamble (caption_frame_t* frame, uint16_t cc_data) +{ + eia608_style_t sty; + int row, col, chn, uln; + + if (eia608_parse_preamble (cc_data, &row, &col, &sty, &chn, &uln)) { + frame->state.row = row; + frame->state.col = col; + frame->state.sty = sty; + frame->state.uln = uln; + } + + return LIBCAPTION_OK; +} + +libcaption_stauts_t caption_frame_decode_midrowchange (caption_frame_t* frame, uint16_t cc_data) +{ + eia608_style_t sty; + int chn, unl; + + if (eia608_parse_midrowchange (cc_data,&chn,&sty,&unl)) { + frame->state.sty = sty; + frame->state.uln = unl; + } + + return LIBCAPTION_OK; +} + +libcaption_stauts_t caption_frame_backspace (caption_frame_t* frame) +{ + // do not reverse wrap (tw 28:20) + frame->state.col = (0 < frame->state.col) ? (frame->state.col - 1) : 0; + caption_frame_write_char (frame,frame->state.row,frame->state.col,eia608_style_white,0,EIA608_CHAR_NULL); + return LIBCAPTION_READY; +} + +libcaption_stauts_t caption_frame_decode_control (caption_frame_t* frame, uint16_t cc_data) +{ + int cc; + eia608_control_t cmd = eia608_parse_control (cc_data,&cc); + + switch (cmd) { + // PAINT ON + case eia608_control_resume_direct_captioning: + frame->state.rup = 0; + frame->state.mod = CAPTION_PAINT_ON; + return LIBCAPTION_OK; + + case eia608_control_erase_display_memory: + caption_frame_buffer_clear (&frame->front); + return LIBCAPTION_OK; + + // ROLL-UP + case eia608_control_roll_up_2: + frame->state.rup = 1; + frame->state.mod = CAPTION_ROLL_UP; + return LIBCAPTION_OK; + + case eia608_control_roll_up_3: + frame->state.rup = 2; + frame->state.mod = CAPTION_ROLL_UP; + return LIBCAPTION_OK; + + case eia608_control_roll_up_4: + frame->state.rup = 3; + frame->state.mod = CAPTION_ROLL_UP; + return LIBCAPTION_OK; + + case eia608_control_carriage_return: + return caption_frame_carriage_return (frame); + + // Corrections (Is this only valid as part of paint on?) + case eia608_control_backspace: + return caption_frame_backspace (frame); + + case eia608_control_delete_to_end_of_row: { + int c; + + for (c = frame->state.col ; c < SCREEN_COLS ; ++c) { + caption_frame_write_char (frame,frame->state.row,c,eia608_style_white,0,EIA608_CHAR_NULL); + } + } + + return LIBCAPTION_READY; + + // POP ON + case eia608_control_resume_caption_loading: + frame->state.rup = 0; + frame->state.mod = CAPTION_POP_ON; + return LIBCAPTION_OK; + + case eia608_control_erase_non_displayed_memory: + caption_frame_buffer_clear (&frame->back); + return LIBCAPTION_OK; + + case eia608_control_end_of_caption: + return caption_frame_end (frame); + + // cursor positioning + case eia608_tab_offset_0: + case eia608_tab_offset_1: + case eia608_tab_offset_2: + case eia608_tab_offset_3: + frame->state.col += (cmd - eia608_tab_offset_0); + return LIBCAPTION_OK; + + // Unhandled + default: + case eia608_control_alarm_off: + case eia608_control_alarm_on: + case eia608_control_text_restart: + case eia608_control_text_resume_text_display: + return LIBCAPTION_OK; + } +} + +libcaption_stauts_t caption_frame_decode_text (caption_frame_t* frame, uint16_t cc_data) +{ + int chan; + char char1[5], char2[5]; + size_t chars = eia608_to_utf8 (cc_data, &chan, &char1[0], &char2[0]); + + if (eia608_is_westeu (cc_data)) { + // Extended charcters replace the previous charcter for back compatibility + caption_frame_backspace (frame); + } + + if (0 < chars) { + eia608_write_char (frame,char1); + } + + if (1 < chars) { + eia608_write_char (frame,char2); + } + + return LIBCAPTION_OK; +} + +libcaption_stauts_t caption_frame_decode (caption_frame_t* frame, uint16_t cc_data, double timestamp) +{ + libcaption_stauts_t status = LIBCAPTION_OK; + + if (!eia608_parity_varify (cc_data)) { + return LIBCAPTION_ERROR; + } + + if (eia608_is_padding (cc_data)) { + return LIBCAPTION_OK; + } + + // skip duplicate controll commands. We also skip duplicate specialna to match the behaviour of iOS/vlc + if ( (eia608_is_specialna (cc_data) || eia608_is_control (cc_data)) && cc_data == frame->state.cc_data) { + return LIBCAPTION_OK; + } + + if (0 > frame->timestamp && 0 < timestamp) { + frame->timestamp = timestamp; + } + + frame->state.cc_data = cc_data; + + if (frame->xds.state) { + status = xds_decode (&frame->xds,cc_data); + } else if (eia608_is_xds (cc_data)) { + status = xds_decode (&frame->xds,cc_data); + } else if (eia608_is_control (cc_data)) { + status = caption_frame_decode_control (frame,cc_data); + } else if (eia608_is_basicna (cc_data) || + eia608_is_specialna (cc_data) || + eia608_is_westeu (cc_data)) { + + // Don't decode text if we dont know what mode we are in. + if (CAPTION_CLEAR == frame->state.mod) { + return LIBCAPTION_OK; + } + + status = caption_frame_decode_text (frame,cc_data); + + // If we are in paint on mode, display immiditally + if (1 == status && (CAPTION_PAINT_ON == frame->state.mod || CAPTION_ROLL_UP == frame->state.mod)) { + status = LIBCAPTION_READY; + } + } else if (eia608_is_preamble (cc_data)) { + status = caption_frame_decode_preamble (frame,cc_data); + } else if (eia608_is_midrowchange (cc_data)) { + status = caption_frame_decode_midrowchange (frame,cc_data); + } + + return status; +} + +//////////////////////////////////////////////////////////////////////////////// +int caption_frame_from_text (caption_frame_t* frame, const utf8_char_t* data) +{ + int r, c, chan = 0; + ssize_t size = (ssize_t) strlen (data); + size_t char_count, char_length, line_length = 0, trimmed_length = 0; + caption_frame_init (frame); + frame->state.mod = CAPTION_POP_ON; + + for (r = 0 ; 0 < size && SCREEN_ROWS > r ; ++r) { + const utf8_char_t* cap_data = data; + line_length = utf8_line_length (cap_data); + trimmed_length = utf8_trimmed_length (cap_data,line_length); + char_count = utf8_char_count (cap_data,trimmed_length); + + // If char_count is greater than one line can display, split it. + if (SCREEN_COLS < char_count) { + char_count = utf8_wrap_length (cap_data,SCREEN_COLS); + line_length = utf8_string_length (cap_data,char_count+1); + } + + // Write the line + for (c = 0 ; c < (int) char_count ; ++c) { + caption_frame_write_char (frame,r,c,eia608_style_white,0,&cap_data[0]); + char_length = utf8_char_length (cap_data); + cap_data += char_length; + } + + data += line_length; + size -= (ssize_t) line_length; + } + + caption_frame_end (frame); + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +void caption_frame_to_text (caption_frame_t* frame, utf8_char_t* data) +{ + int r, c, x, s, uln; + eia608_style_t sty; + + data[0] = 0; + + for (r = 0 ; r < SCREEN_ROWS ; ++r) { + for (c = 0, x = 0 ; c < SCREEN_COLS ; ++c) { + const char* chr = caption_frame_read_char (frame, r, c, &sty, &uln); + + if (0 < (s = (int) utf8_char_copy (data,chr))) { + ++x; data += s; + } + } + + if (x) { + strcpy ( (char*) data,"\r\n"); + data += 2; + } + } +} +//////////////////////////////////////////////////////////////////////////////// +size_t caption_frame_dump_buffer (caption_frame_t* frame, utf8_char_t* buf) +{ + int r, c; + size_t bytes, total = 0; + bytes = sprintf (buf, " row: %d\tcol: %d\n mode: %s\troll-up: %d\n", + frame->state.row, frame->state.col, + eia608_mode_map[frame->state.mod],frame->state.rup?1+frame->state.rup:0); + total += bytes; buf += bytes; + bytes = sprintf (buf, " 00000000001111111111222222222233\n 01234567890123456789012345678901\n %s--------------------------------%s\n", + EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT); + total += bytes; buf += bytes; + + for (r = 0 ; r < SCREEN_ROWS ; ++r) { + bytes = sprintf (buf, "%02d%s", r, EIA608_CHAR_VERTICAL_LINE); + total += bytes; buf += bytes; + + for (c = 0 ; c < SCREEN_COLS ; ++c) { + caption_frame_cell_t* cell = frame_cell (frame,r,c); + bytes = utf8_char_copy (buf, (0==cell->data[0]) ?EIA608_CHAR_SPACE:&cell->data[0]); + total += bytes; buf += bytes; + } + + bytes = sprintf (buf, "%s\n", EIA608_CHAR_VERTICAL_LINE); + total += bytes; buf += bytes; + } + + bytes = sprintf (buf, " %s--------------------------------%s\n", + EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT); + total += bytes; buf += bytes; + return total; +} + +void caption_frame_dump (caption_frame_t* frame) +{ + utf8_char_t buff[CAPTION_FRAME_DUMP_BUF_SIZE]; + size_t size = caption_frame_dump_buffer (frame, buff); + fprintf (stderr,"%s\n", buff); +} + +size_t caption_frame_json (caption_frame_t* frame, utf8_char_t* buf) +{ + size_t bytes, total = 0; + int r,c,count = 0; + bytes = sprintf (buf, "{\"format\":\"eia608\",\"mode\":\"%s\",\"rollUp\":%d,\"data\":[", + eia608_mode_map[frame->state.mod],frame->state.rup?1+frame->state.rup:0); + total += bytes; buf += bytes; + + for (r = 0 ; r < SCREEN_ROWS ; ++r) { + for (c = 0 ; c < SCREEN_COLS ; ++c) { + caption_frame_cell_t* cell = frame_cell (frame,r,c); + + if (0 != cell->data[0]) { + const char* data = ('"' == cell->data[0]) ?"\\\"": (const char*) &cell->data[0]; //escape quote + bytes = sprintf (buf, "%s\n{\"row\":%d,\"col\":%d,\"char\":\"%s\",\"style\":\"%s\"}", + (0<count?",":""),r,c,data,eia608_style_map[cell->sty]); + total += bytes; buf += bytes; ++count; + } + } + } + + bytes = sprintf (buf, "\n]}\n"); + total += bytes; buf += bytes; + return total; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/cea708.c
Added
@@ -0,0 +1,207 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "cea708.h" +#include <memory.h> + +int cea708_cc_count (user_data_t* data) +{ + return data->cc_count; +} + +uint16_t cea708_cc_data (user_data_t* data, int index, int* valid, cea708_cc_type_t* type) +{ + (*valid) = data->cc_data[index].cc_valid; + (*type) = data->cc_data[index].cc_type; + return data->cc_data[index].cc_data; +} + + +int cea708_init (cea708_t* cea708) +{ + memset (cea708,0,sizeof (cea708_t)); + cea708->country = country_united_states; + cea708->provider = t35_provider_atsc; + cea708->user_identifier = ('G'<<24) | ('A'<<16) | ('9'<<8) | ('4'); + cea708->atsc1_data_user_data_type_code = 3; //what does 3 mean here? + cea708->directv_user_data_length = 0; + /////////// + cea708->user_data.process_em_data_flag = 0; + cea708->user_data.process_cc_data_flag = 1; + cea708->user_data.additional_data_flag = 0; + cea708->user_data.cc_count = 0; + return 1; +} + +// 00 00 00 06 C1 FF FC 34 B9 FF : onCaptionInfo. +int cea708_parse (uint8_t* data, size_t size, cea708_t* cea708) +{ + int i; + cea708->country = (itu_t_t35_country_code_t) (data[0]); + cea708->provider = (itu_t_t35_provider_code_t) ( (data[1] <<8) | data[2]); + cea708->atsc1_data_user_data_type_code = 0; + cea708->user_identifier = 0; + data += 3; size -= 3; + + if (t35_provider_atsc == cea708->provider) { + // GA94 + cea708->user_identifier = (data[0] <<24) | (data[1] <<16) | (data[2] <<8) | data[3]; + data += 4; size -= 4; + } + + // Im not sure what this extra byt is. It sonly seesm to come up in onCaptionInfo + // where country and provider are zero + if (0 == cea708->provider) { + data += 1; size -= 1; + } else if (t35_provider_atsc == cea708->provider || t35_provider_direct_tv == cea708->provider) { + cea708->atsc1_data_user_data_type_code = data[0]; + data += 1; size -= 1; + } + + if (t35_provider_direct_tv == cea708->provider) { + cea708->directv_user_data_length = data[0]; + data += 1; size -= 1; + } + + // TODO I believe this is condational on the above. + cea708->user_data.process_em_data_flag = !! (data[0]&0x80); + cea708->user_data.process_cc_data_flag = !! (data[0]&0x40); + cea708->user_data.additional_data_flag = !! (data[0]&0x20); + cea708->user_data.cc_count = (data[0]&0x1F); + cea708->user_data.em_data = data[1]; + data += 2; size -= 2; + + if (size < 3 * cea708->user_data.cc_count) { + cea708_init (cea708); + return 0; + } + + for (i = 0 ; i < (int) cea708->user_data.cc_count ; ++i) { + cea708->user_data.cc_data[i].marker_bits = data[0]>>3; + cea708->user_data.cc_data[i].cc_valid = data[0]>>2; + cea708->user_data.cc_data[i].cc_type = data[0]>>0; + cea708->user_data.cc_data[i].cc_data = data[1]<<8|data[2]; + data += 3; size -= 3; + } + + return 1; +} + +int cea708_add_cc_data (cea708_t* cea708, int valid, cea708_cc_type_t type, uint16_t cc_data) +{ + if (31 <= cea708->user_data.cc_count) { + return 0; + } + + cea708->user_data.cc_data[cea708->user_data.cc_count].marker_bits = 0x1F; + cea708->user_data.cc_data[cea708->user_data.cc_count].cc_valid = valid; + cea708->user_data.cc_data[cea708->user_data.cc_count].cc_type = type; + cea708->user_data.cc_data[cea708->user_data.cc_count].cc_data = cc_data; + ++cea708->user_data.cc_count; + return 1; +} + +int cea708_render (cea708_t* cea708, uint8_t* data, size_t size) +{ + int i; size_t total = 0; + data[0] = cea708->country; + data[1] = cea708->provider>>8; + data[2] = cea708->provider>>0; + total += 3; data += 3; size -= 3; + + if (t35_provider_atsc == cea708->provider) { + + data[0] = cea708->user_identifier >> 24; + data[1] = cea708->user_identifier >> 16; + data[2] = cea708->user_identifier >> 8; + data[3] = cea708->user_identifier >> 0; + total += 4; data += 4; size -= 4; + } + + if (t35_provider_atsc == cea708->provider || t35_provider_direct_tv == cea708->provider) { + data[0] = cea708->atsc1_data_user_data_type_code; + total += 1; data += 1; size -= 1; + } + + if (t35_provider_direct_tv == cea708->provider) { + data[0] = cea708->directv_user_data_length; + total += 1; data += 1; size -= 1; + } + + data[1] = cea708->user_data.em_data; + data[0] = (cea708->user_data.process_em_data_flag?0x80:0x00) + | (cea708->user_data.process_cc_data_flag?0x40:0x00) + | (cea708->user_data.additional_data_flag?0x20:0x00) + | (cea708->user_data.cc_count & 0x1F); + + total += 2; data += 2; size -= 2; + + for (i = 0 ; i < (int) cea708->user_data.cc_count ; ++i) { + data[0] = (cea708->user_data.cc_data[i].marker_bits<<3) + | (data[0] = cea708->user_data.cc_data[i].cc_valid<<2) + | (data[0] = cea708->user_data.cc_data[i].cc_type); + data[1] = cea708->user_data.cc_data[i].cc_data>>8; + data[2] = cea708->user_data.cc_data[i].cc_data>>0; + total += 3; data += 3; size -= 3; + } + + data[0] = 0xFF; + return (int) (total + 1); +} + +cc_data_t cea708_encode_cc_data (int cc_valid, cea708_cc_type_t type, uint16_t cc_data) +{ + cc_data_t data = { 0x1F, cc_valid,type,cc_data}; + return data; +} + +void cea708_dump (cea708_t* cea708) +{ + int i; + + for (i = 0 ; i < (int) cea708->user_data.cc_count ; ++i) { + cea708_cc_type_t type; int valid; + uint16_t cc_data = cea708_cc_data (&cea708->user_data, i, &valid, &type); + + if (valid && cc_type_ntsc_cc_field_1 == type) { + eia608_dump (cc_data); + } + } +} + +libcaption_stauts_t cea708_to_caption_frame (caption_frame_t* frame, cea708_t* cea708, double pts) +{ + int i, count = cea708_cc_count (&cea708->user_data); + libcaption_stauts_t status = LIBCAPTION_OK; + + for (i = 0 ; i < count ; ++i) { + cea708_cc_type_t type; int valid; + uint16_t cc_data = cea708_cc_data (&cea708->user_data, i, &valid, &type); + + if (valid && cc_type_ntsc_cc_field_1 == type) { + status = libcaption_status_update (status,caption_frame_decode (frame,cc_data, pts)); + } + } + + return status; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/eia608.c
Added
@@ -0,0 +1,754 @@ +/* Generated by re2c 0.15.3 on Tue Nov 22 15:42:35 2016 */ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "eia608.h" +#include <string.h> +#include <stdio.h> + +//////////////////////////////////////////////////////////////////////////////// +int eia608_row_map[] = {10, -1, 0, 1, 2, 3, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9}; +int eia608_reverse_row_map[] = {2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 0, 6, 7, 8, 9, 1}; + +const char* eia608_mode_map[] = { + "clear", + "loading", + "popOn", + "paintOn", + "rollUp", +}; + +const char* eia608_style_map[] = { + "white", + "green", + "blue", + "cyan", + "red", + "yellow", + "magenta", + "italics", +}; + +static inline uint16_t eia608_row_pramble (int row, int chan, int x, int underline) +{ + row = eia608_reverse_row_map[row&0x0F]; + return eia608_parity (0x1040 | (chan?0x0800:0x0000) | ( (row<<7) &0x0700) | ( (row<<5) &0x0020)) | ( (x<<1) &0x001E) | (underline?0x0001:0x0000); +} + +uint16_t eia608_row_column_pramble (int row, int col, int chan, int underline) { return eia608_row_pramble (row,chan,0x10| (col/4),underline); } +uint16_t eia608_row_style_pramble (int row, eia608_style_t style, int chan, int underline) { return eia608_row_pramble (row,chan,style,underline); } + +int eia608_parse_preamble (uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline) +{ + (*row) = eia608_row_map[ ( (0x0700 & cc_data) >> 7) | ( (0x0020 & cc_data) >> 5)]; + (*chan) = !! (0x0800 & cc_data); + (*underline) = 0x0001 & cc_data; + + if (0x0010 & cc_data) { + (*style) = eia608_style_white; + (*col) = 4* ( (0x000E & cc_data) >> 1); + } else { + (*style) = (0x000E & cc_data) >> 1; + (*col) = 0; + } + + return 1; +} + +int eia608_parse_midrowchange (uint16_t cc_data, int* chan, eia608_style_t* style, int* underline) +{ + (*chan) = !! (0x0800 & cc_data); + + if (0x1120 == (0x7770 & cc_data)) { + (*style) = (0x000E & cc_data) >> 1; + (*underline) = 0x0001 & cc_data; + } + + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +// control command +eia608_control_t eia608_parse_control (uint16_t cc_data, int* cc) +{ + if (0x0200&cc_data) { + (*cc) = (cc_data&0x0800?0x01:0x00); + return (eia608_control_t) (0x177F & cc_data); + } else { + (*cc) = (cc_data&0x0800?0x01:0x00) | (cc_data&0x0100?0x02:0x00); + return (eia608_control_t) (0x167F & cc_data); + } +} + +uint16_t eia608_control_command (eia608_control_t cmd, int cc) +{ + uint16_t c = (cc&0x01) ?0x0800:0x0000; + uint16_t f = (cc&0x02) ?0x0100:0x0000; + + if (eia608_tab_offset_0 == (eia608_control_t) (cmd&0xFFC0)) { + return (eia608_control_t) eia608_parity (cmd|c); + } else { + return (eia608_control_t) eia608_parity (cmd|c|f); + } +} +//////////////////////////////////////////////////////////////////////////////// +// text +static const char* utf8_from_index (int idx) { return (0<=idx && EIA608_CHAR_COUNT>idx) ? eia608_char_map[idx] : ""; } +static int eia608_to_index (uint16_t cc_data, int* chan, int* c1, int* c2) +{ + (*c1) = (*c2) = -1; (*chan) = 0; + cc_data &= 0x7F7F; // strip off parity bits + + // Handle Basic NA BEFORE we strip the channel bit + if (eia608_is_basicna (cc_data)) { + // we got first char, yes. But what about second char? + (*c1) = (cc_data>>8) - 0x20; + cc_data &= 0x00FF; + + if (0x0020<=cc_data && 0x0080>cc_data) { + (*c2) = cc_data - 0x20; + return 2; + } + + return 1; + } + + // Check then strip second channel toggle + (*chan) = cc_data & 0x0800; + cc_data = cc_data & 0xF7FF; + + if (eia608_is_specialna (cc_data)) { + // Special North American character + (*c1) = cc_data - 0x1130 + 0x60; + return 1; + } + + if (0x1220<=cc_data && 0x1240>cc_data) { + // Extended Western European character set, Spanish/Miscellaneous/French + (*c1) = cc_data - 0x1220 + 0x70; + return 1; + } + + if (0x1320<=cc_data && 0x1340>cc_data) { + // Extended Western European character set, Portuguese/German/Danish + (*c1) = cc_data - 0x1320 + 0x90; + return 1; + } + + return 0; +} + + +int eia608_to_utf8 (uint16_t c, int* chan, char* str1, char* str2) +{ + int c1, c2; + size_t size = eia608_to_index (c,chan,&c1,&c2); + strncpy (str1, utf8_from_index (c1),5); + strncpy (str2, utf8_from_index (c2),5); + return (int)size; +} + +uint16_t eia608_from_basicna (uint16_t bna1, uint16_t bna2) +{ + if (! eia608_is_basicna (bna1) || ! eia608_is_basicna (bna2)) { + return 0; + } + + return eia608_parity ( ( (0xFF00&bna1) >>0) | ( (0xFF00&bna2) >>8)); +} + +// prototype for re2c generated function +uint16_t _eia608_from_utf8 (const utf8_char_t* s); +uint16_t eia608_from_utf8_1 (const utf8_char_t* c, int chan) +{ + uint16_t cc_data = _eia608_from_utf8 (c); + + if (0 == cc_data) { + return cc_data; + } + + if (chan && ! eia608_is_basicna (cc_data)) { + cc_data |= 0x0800; + } + + return eia608_parity (cc_data); +} + +uint16_t eia608_from_utf8_2 (const utf8_char_t* c1, const utf8_char_t* c2) +{ + uint16_t cc1 = _eia608_from_utf8 (c1); + uint16_t cc2 = _eia608_from_utf8 (c2); + return eia608_from_basicna (cc1,cc2); +} +//////////////////////////////////////////////////////////////////////////////// +void eia608_dump (uint16_t cc_data) +{ + eia608_style_t style; + const char* text = 0; + char char1[5], char2[5]; + char1[0] = char2[0] = 0; + int row, col, chan, underline; + + if (!eia608_parity_varify (cc_data)) { + text = "parity failed"; + } else if (0 == eia608_parity_strip (cc_data)) { + text = "pad"; + } else if (eia608_is_basicna (cc_data)) { + text = "basicna"; + eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]); + } else if (eia608_is_specialna (cc_data)) { + text = "specialna"; + eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]); + } else if (eia608_is_westeu (cc_data)) { + text = "westeu"; + eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]); + } else if (eia608_is_xds (cc_data)) { + text = "xds"; + } else if (eia608_is_midrowchange (cc_data)) { + text = "midrowchange"; + } else if (eia608_is_norpak (cc_data)) { + text = "norpak"; + } else if (eia608_is_preamble (cc_data)) { + text = "preamble"; + eia608_parse_preamble (cc_data, &row, &col, &style, &chan, &underline); + fprintf (stderr,"preamble %d %d %d %d %d\n", row, col, style, chan, underline); + + } else if (eia608_is_control (cc_data)) { + switch (eia608_parse_control (cc_data,&chan)) { + + default: text = "unknown_control"; break; + + case eia608_tab_offset_0: text = "eia608_tab_offset_0"; break; + + case eia608_tab_offset_1: text = "eia608_tab_offset_1"; break; + + case eia608_tab_offset_2:text = "eia608_tab_offset_2"; break; + + case eia608_tab_offset_3: text = "eia608_tab_offset_3"; break; + + case eia608_control_resume_caption_loading: text = "eia608_control_resume_caption_loading"; break; + + case eia608_control_backspace: text = "eia608_control_backspace"; break; + + case eia608_control_alarm_off: text = "eia608_control_alarm_off"; break; + + case eia608_control_alarm_on: text = "eia608_control_alarm_on"; break; + + case eia608_control_delete_to_end_of_row: text = "eia608_control_delete_to_end_of_row"; break; + + case eia608_control_roll_up_2: text = "eia608_control_roll_up_2"; break; + + case eia608_control_roll_up_3: text = "eia608_control_roll_up_3"; break; + + case eia608_control_roll_up_4: text = "eia608_control_roll_up_4"; break; + + case eia608_control_resume_direct_captioning: text = "eia608_control_resume_direct_captioning"; break; + + case eia608_control_text_restart: text = "eia608_control_text_restart"; break; + + case eia608_control_text_resume_text_display: text = "eia608_control_text_resume_text_display"; break; + + case eia608_control_erase_display_memory: text = "eia608_control_erase_display_memory"; break; + + case eia608_control_carriage_return: text = "eia608_control_carriage_return"; break; + + case eia608_control_erase_non_displayed_memory:text = "eia608_control_erase_non_displayed_memory"; break; + + case eia608_control_end_of_caption: text = "eia608_control_end_of_caption"; break; + } + } else { + text = "unhandled"; + } + + fprintf (stderr,"cc %04X (%04X) '%s' '%s' (%s)\n", cc_data, eia608_parity_strip (cc_data), char1, char2, text); +} +//////////////////////////////////////////////////////////////////////////////// +// below this line is re2c +uint16_t _eia608_from_utf8 (const utf8_char_t* s) +{ + const unsigned char* YYMARKER; // needed by default rule + const unsigned char* YYCURSOR = (const unsigned char*) s; + + if (0==s) { return 0x0000;} + + +{ + unsigned char yych; + yych = *YYCURSOR; + if (yych <= '`') { + if (yych <= '*') { + if (yych <= '&') { + if (yych <= 0x00) goto yy2; + if (yych <= 0x1F) goto yy32; + goto yy26; + } else { + if (yych <= '\'') goto yy4; + if (yych <= ')') goto yy26; + goto yy6; + } + } else { + if (yych <= ']') { + if (yych == '\\') goto yy8; + goto yy26; + } else { + if (yych <= '^') goto yy10; + if (yych <= '_') goto yy12; + goto yy14; + } + } + } else { + if (yych <= 0x7F) { + if (yych <= '|') { + if (yych <= 'z') goto yy26; + if (yych <= '{') goto yy16; + goto yy18; + } else { + if (yych <= '}') goto yy20; + if (yych <= '~') goto yy22; + goto yy24; + } + } else { + if (yych <= 0xC3) { + if (yych <= 0xC1) goto yy32; + if (yych <= 0xC2) goto yy31; + goto yy28; + } else { + if (yych == 0xE2) goto yy30; + goto yy32; + } + } + } +yy2: + ++YYCURSOR; + { /*NULL*/ return 0x0000; } +yy4: + ++YYCURSOR; + { /*APOSTROPHE -> RIGHT_SINGLE_QUOTATION_MARK*/ return 0x1229; } +yy6: + ++YYCURSOR; + { /*ASTERISK*/ return 0x1228; } +yy8: + ++YYCURSOR; + { /*REVERSE_SOLIDUS*/ return 0x132B; } +yy10: + ++YYCURSOR; + { /*CIRCUMFLEX_ACCENT*/ return 0x132C; } +yy12: + ++YYCURSOR; + { /*LOW_LINE*/ return 0x132D; } +yy14: + ++YYCURSOR; + { /*GRAVE_ACCENT, No equivalent return 0x0000; return 1;*/ /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; } +yy16: + ++YYCURSOR; + { /*LEFT_CURLY_BRACKET*/ return 0x1329; } +yy18: + ++YYCURSOR; + { /*VERTICAL_LINE*/ return 0x132E; } +yy20: + ++YYCURSOR; + { /*RIGHT_CURLY_BRACKET*/ return 0x132A; } +yy22: + ++YYCURSOR; + { /*TILDE*/ return 0x132F; } +yy24: + ++YYCURSOR; + { /*DEL/BACKSPACE. Need to set bits 9 and 12! return 0x1421;*/ return 0x0000; } +yy26: + ++YYCURSOR; + { /*ASCII range*/ return (s[0]<<8) &0xFF00; } +yy28: + ++YYCURSOR; + switch ((yych = *YYCURSOR)) { + case 0x80: goto yy157; + case 0x81: goto yy169; + case 0x82: goto yy155; + case 0x83: goto yy129; + case 0x84: goto yy111; + case 0x85: goto yy101; + case 0x87: goto yy153; + case 0x88: goto yy151; + case 0x89: goto yy167; + case 0x8A: goto yy149; + case 0x8B: goto yy147; + case 0x8C: goto yy123; + case 0x8D: goto yy125; + case 0x8E: goto yy143; + case 0x8F: goto yy141; + case 0x91: goto yy187; + case 0x92: goto yy119; + case 0x93: goto yy165; + case 0x94: goto yy137; + case 0x95: goto yy115; + case 0x96: goto yy107; + case 0x98: goto yy97; + case 0x99: goto yy135; + case 0x9A: goto yy163; + case 0x9B: goto yy131; + case 0x9C: goto yy161; + case 0x9F: goto yy103; + case 0xA0: goto yy183; + case 0xA1: goto yy201; + case 0xA2: goto yy179; + case 0xA3: goto yy127; + case 0xA4: goto yy109; + case 0xA5: goto yy99; + case 0xA7: goto yy191; + case 0xA8: goto yy181; + case 0xA9: goto yy199; + case 0xAA: goto yy177; + case 0xAB: goto yy145; + case 0xAC: goto yy121; + case 0xAD: goto yy197; + case 0xAE: goto yy175; + case 0xAF: goto yy139; + case 0xB1: goto yy185; + case 0xB2: goto yy117; + case 0xB3: goto yy195; + case 0xB4: goto yy173; + case 0xB5: goto yy113; + case 0xB6: goto yy105; + case 0xB7: goto yy189; + case 0xB8: goto yy95; + case 0xB9: goto yy133; + case 0xBA: goto yy193; + case 0xBB: goto yy171; + case 0xBC: goto yy159; + default: goto yy29; + } +yy29: + { /*DEFAULT_RULE*/ return 0x0000; } +yy30: + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 0x80: goto yy63; + case 0x84: goto yy64; + case 0x94: goto yy61; + case 0x96: goto yy66; + case 0x99: goto yy65; + default: goto yy29; + } +yy31: + yych = *++YYCURSOR; + switch (yych) { + case 0xA0: goto yy47; + case 0xA1: goto yy45; + case 0xA2: goto yy51; + case 0xA3: goto yy49; + case 0xA4: goto yy35; + case 0xA5: goto yy37; + case 0xA6: goto yy33; + case 0xA9: goto yy43; + case 0xAB: goto yy41; + case 0xAE: goto yy59; + case 0xB0: goto yy57; + case 0xBB: goto yy39; + case 0xBD: goto yy55; + case 0xBF: goto yy53; + default: goto yy29; + } +yy32: + yych = *++YYCURSOR; + goto yy29; +yy33: + ++YYCURSOR; + { /*BROKEN_BAR*/ return 0x1337; } +yy35: + ++YYCURSOR; + { /*CURRENCY_SIGN*/ return 0x1336; } +yy37: + ++YYCURSOR; + { /*YEN_SIGN*/ return 0x1335; } +yy39: + ++YYCURSOR; + { /*RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123F; } +yy41: + ++YYCURSOR; + { /*LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123E; } +yy43: + ++YYCURSOR; + { /*COPYRIGHT_SIGN*/ return 0x122B; } +yy45: + ++YYCURSOR; + { /*INVERTED_EXCLAMATION_MARK*/ return 0x1227; } +yy47: + ++YYCURSOR; + { /*NO_BREAK_SPACE*/ return 0x1139; } +yy49: + ++YYCURSOR; + { /*POUND_SIGN*/ return 0x1136; } +yy51: + ++YYCURSOR; + { /*CENT_SIGN*/ return 0x1135; } +yy53: + ++YYCURSOR; + { /*INVERTED_QUESTION_MARK*/ return 0x1133; } +yy55: + ++YYCURSOR; + { /*VULGAR_FRACTION_ONE_HALF*/ return 0x1132; } +yy57: + ++YYCURSOR; + { /*DEGREE_SIGN*/ return 0x1131; } +yy59: + ++YYCURSOR; + { /*REGISTERED_SIGN*/ return 0x1130; } +yy61: + yych = *++YYCURSOR; + switch (yych) { + case 0x8C: goto yy87; + case 0x90: goto yy89; + case 0x94: goto yy91; + case 0x98: goto yy93; + default: goto yy62; + } +yy62: + YYCURSOR = YYMARKER; + goto yy29; +yy63: + yych = *++YYCURSOR; + switch (yych) { + case 0x94: goto yy79; + case 0x98: goto yy75; + case 0x99: goto yy77; + case 0x9C: goto yy83; + case 0x9D: goto yy85; + case 0xA2: goto yy81; + default: goto yy62; + } +yy64: + yych = *++YYCURSOR; + if (yych == 0xA0) goto yy73; + if (yych == 0xA2) goto yy71; + goto yy62; +yy65: + yych = *++YYCURSOR; + if (yych == 0xAA) goto yy69; + goto yy62; +yy66: + yych = *++YYCURSOR; + if (yych != 0x88) goto yy62; + ++YYCURSOR; + { /*FULL_BLOCK*/ return 0x7F00; } +yy69: + ++YYCURSOR; + { /*EIGHTH_NOTE*/ return 0x1137; } +yy71: + ++YYCURSOR; + { /*TRADE_MARK_SIGN*/ return 0x1134; } +yy73: + ++YYCURSOR; + { /*SERVICE_MARK*/ return 0x122C; } +yy75: + ++YYCURSOR; + { /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; } +yy77: + ++YYCURSOR; + { /*RIGHT_SINGLE_QUOTATION_MARK -> APOSTROPHE*/ return 0x2700; } +yy79: + ++YYCURSOR; + { /*EM_DASH*/ return 0x122A; } +yy81: + ++YYCURSOR; + { /*BULLET*/ return 0x122D; } +yy83: + ++YYCURSOR; + { /*LEFT_DOUBLE_QUOTATION_MARK*/ return 0x122E; } +yy85: + ++YYCURSOR; + { /*RIGHT_DOUBLE_QUOTATION_MARK*/ return 0x122F; } +yy87: + ++YYCURSOR; + { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT*/ return 0x133C; } +yy89: + ++YYCURSOR; + { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT*/ return 0x133D; } +yy91: + ++YYCURSOR; + { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT*/ return 0x133E; } +yy93: + ++YYCURSOR; + { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT*/ return 0x133F; } +yy95: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_O_WITH_STROKE*/ return 0x133B; } +yy97: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_O_WITH_STROKE*/ return 0x133A; } +yy99: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_A_WITH_RING_ABOVE*/ return 0x1339; } +yy101: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE*/ return 0x1338; } +yy103: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_SHARP_S*/ return 0x1334; } +yy105: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_O_WITH_DIAERESIS*/ return 0x1333; } +yy107: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS*/ return 0x1332; } +yy109: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_A_WITH_DIAERESIS*/ return 0x1331; } +yy111: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS*/ return 0x1330; } +yy113: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_O_WITH_TILDE*/ return 0x1328; } +yy115: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_O_WITH_TILDE*/ return 0x1327; } +yy117: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_O_WITH_GRAVE*/ return 0x1326; } +yy119: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_O_WITH_GRAVE*/ return 0x1325; } +yy121: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_I_WITH_GRAVE*/ return 0x1324; } +yy123: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_I_WITH_GRAVE*/ return 0x1323; } +yy125: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_I_WITH_ACUTE*/ return 0x1322; } +yy127: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_A_WITH_TILDE*/ return 0x1321; } +yy129: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_A_WITH_TILDE*/ return 0x1320; } +yy131: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x123D; } +yy133: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_U_WITH_GRAVE*/ return 0x123C; } +yy135: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_U_WITH_GRAVE*/ return 0x123B; } +yy137: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x123A; } +yy139: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_I_WITH_DIAERESIS*/ return 0x1239; } +yy141: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS*/ return 0x1238; } +yy143: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x1237; } +yy145: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_E_WITH_DIAERESIS*/ return 0x1236; } +yy147: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS*/ return 0x1235; } +yy149: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x1234; } +yy151: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_E_WITH_GRAVE*/ return 0x1233; } +yy153: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_C_WITH_CEDILLA*/ return 0x1232; } +yy155: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x1231; } +yy157: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_A_WITH_GRAVE*/ return 0x1230; } +yy159: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_U_WITH_DIAERESIS*/ return 0x1225; } +yy161: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS*/ return 0x1224; } +yy163: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_U_WITH_ACUTE*/ return 0x1223; } +yy165: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_O_WITH_ACUTE*/ return 0x1222; } +yy167: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_E_WITH_ACUTE*/ return 0x1221; } +yy169: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_A_WITH_ACUTE*/ return 0x1220; } +yy171: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x113F; } +yy173: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x113E; } +yy175: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x113D; } +yy177: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x113C; } +yy179: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x113B; } +yy181: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_E_WITH_GRAVE*/ return 0x113A; } +yy183: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_A_WITH_GRAVE*/ return 0x1138; } +yy185: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_N_WITH_TILDE*/ return 0x7E00; } +yy187: + ++YYCURSOR; + { /*LATIN_CAPITAL_LETTER_N_WITH_TILDE*/ return 0x7D00; } +yy189: + ++YYCURSOR; + { /*DIVISION_SIGN*/ return 0x7C00; } +yy191: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_C_WITH_CEDILLA*/ return 0x7B00; } +yy193: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_U_WITH_ACUTE*/ return 0x6000; } +yy195: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_O_WITH_ACUTE*/ return 0x5F00; } +yy197: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_I_WITH_ACUTE*/ return 0x5E00; } +yy199: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_E_WITH_ACUTE*/ return 0x5C00; } +yy201: + ++YYCURSOR; + { /*LATIN_SMALL_LETTER_A_WITH_ACUTE*/ return 0x2A00; } +} + +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/eia608.c.re2c
Added
@@ -0,0 +1,421 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "eia608.h" +#include <string.h> +#include <stdio.h> + +//////////////////////////////////////////////////////////////////////////////// +int eia608_row_map[] = {10, -1, 0, 1, 2, 3, 11, 12, 13, 14, 4, 5, 6, 7, 8, 9}; +int eia608_reverse_row_map[] = {2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 0, 6, 7, 8, 9, 1}; + +const char* eia608_mode_map[] = { + "clear", + "loading", + "popOn", + "paintOn", + "rollUp", +}; + +const char* eia608_style_map[] = { + "white", + "green", + "blue", + "cyan", + "red", + "yellow", + "magenta", + "italics", +}; + +static inline uint16_t eia608_row_pramble (int row, int chan, int x, int underline) +{ + row = eia608_reverse_row_map[row&0x0F]; + return eia608_parity (0x1040 | (chan?0x0800:0x0000) | ( (row<<7) &0x0700) | ( (row<<5) &0x0020)) | ( (x<<1) &0x001E) | (underline?0x0001:0x0000); +} + +uint16_t eia608_row_column_pramble (int row, int col, int chan, int underline) { return eia608_row_pramble (row,chan,0x10| (col/4),underline); } +uint16_t eia608_row_style_pramble (int row, eia608_style_t style, int chan, int underline) { return eia608_row_pramble (row,chan,style,underline); } + +int eia608_parse_preamble (uint16_t cc_data, int* row, int* col, eia608_style_t* style, int* chan, int* underline) +{ + (*row) = eia608_row_map[ ( (0x0700 & cc_data) >> 7) | ( (0x0020 & cc_data) >> 5)]; + (*chan) = !! (0x0800 & cc_data); + (*underline) = 0x0001 & cc_data; + + if (0x0010 & cc_data) { + (*style) = eia608_style_white; + (*col) = 4* ( (0x000E & cc_data) >> 1); + } else { + (*style) = (0x000E & cc_data) >> 1; + (*col) = 0; + } + + return 1; +} + +int eia608_parse_midrowchange (uint16_t cc_data, int* chan, eia608_style_t* style, int* underline) +{ + (*chan) = !! (0x0800 & cc_data); + + if (0x1120 == (0x7770 & cc_data)) { + (*style) = (0x000E & cc_data) >> 1; + (*underline) = 0x0001 & cc_data; + } + + return 1; +} +//////////////////////////////////////////////////////////////////////////////// +// control command +eia608_control_t eia608_parse_control (uint16_t cc_data, int* cc) +{ + if (0x0200&cc_data) { + (*cc) = (cc_data&0x0800?0x01:0x00); + return (eia608_control_t) (0x177F & cc_data); + } else { + (*cc) = (cc_data&0x0800?0x01:0x00) | (cc_data&0x0100?0x02:0x00); + return (eia608_control_t) (0x167F & cc_data); + } +} + +uint16_t eia608_control_command (eia608_control_t cmd, int cc) +{ + uint16_t c = (cc&0x01) ?0x0800:0x0000; + uint16_t f = (cc&0x02) ?0x0100:0x0000; + + if (eia608_tab_offset_0 == (eia608_control_t) (cmd&0xFFC0)) { + return (eia608_control_t) eia608_parity (cmd|c); + } else { + return (eia608_control_t) eia608_parity (cmd|c|f); + } +} +//////////////////////////////////////////////////////////////////////////////// +// text +static const char* utf8_from_index (int idx) { return (0<=idx && EIA608_CHAR_COUNT>idx) ? eia608_char_map[idx] : ""; } +static int eia608_to_index (uint16_t cc_data, int* chan, int* c1, int* c2) +{ + (*c1) = (*c2) = -1; (*chan) = 0; + cc_data &= 0x7F7F; // strip off parity bits + + // Handle Basic NA BEFORE we strip the channel bit + if (eia608_is_basicna (cc_data)) { + // we got first char, yes. But what about second char? + (*c1) = (cc_data>>8) - 0x20; + cc_data &= 0x00FF; + + if (0x0020<=cc_data && 0x0080>cc_data) { + (*c2) = cc_data - 0x20; + return 2; + } + + return 1; + } + + // Check then strip second channel toggle + (*chan) = cc_data & 0x0800; + cc_data = cc_data & 0xF7FF; + + if (eia608_is_specialna (cc_data)) { + // Special North American character + (*c1) = cc_data - 0x1130 + 0x60; + return 1; + } + + if (0x1220<=cc_data && 0x1240>cc_data) { + // Extended Western European character set, Spanish/Miscellaneous/French + (*c1) = cc_data - 0x1220 + 0x70; + return 1; + } + + if (0x1320<=cc_data && 0x1340>cc_data) { + // Extended Western European character set, Portuguese/German/Danish + (*c1) = cc_data - 0x1320 + 0x90; + return 1; + } + + return 0; +} + + +int eia608_to_utf8 (uint16_t c, int* chan, char* str1, char* str2) +{ + int c1, c2; + int size = (int) eia608_to_index (c,chan,&c1,&c2); + strncpy (str1, utf8_from_index (c1),5); + strncpy (str2, utf8_from_index (c2),5); + return size; +} + +uint16_t eia608_from_basicna (uint16_t bna1, uint16_t bna2) +{ + if (! eia608_is_basicna (bna1) || ! eia608_is_basicna (bna2)) { + return 0; + } + + return eia608_parity ( ( (0xFF00&bna1) >>0) | ( (0xFF00&bna2) >>8)); +} + +// prototype for re2c generated function +uint16_t _eia608_from_utf8 (const utf8_char_t* s); +uint16_t eia608_from_utf8_1 (const utf8_char_t* c, int chan) +{ + uint16_t cc_data = _eia608_from_utf8 (c); + + if (0 == cc_data) { + return cc_data; + } + + if (chan && ! eia608_is_basicna (cc_data)) { + cc_data |= 0x0800; + } + + return eia608_parity (cc_data); +} + +uint16_t eia608_from_utf8_2 (const utf8_char_t* c1, const utf8_char_t* c2) +{ + uint16_t cc1 = _eia608_from_utf8 (c1); + uint16_t cc2 = _eia608_from_utf8 (c2); + return eia608_from_basicna (cc1,cc2); +} +//////////////////////////////////////////////////////////////////////////////// +void eia608_dump (uint16_t cc_data) +{ + eia608_style_t style; + const char* text = 0; + char char1[5], char2[5]; + char1[0] = char2[0] = 0; + int row, col, chan, underline; + + if (!eia608_parity_varify (cc_data)) { + text = "parity failed"; + } else if (0 == eia608_parity_strip (cc_data)) { + text = "pad"; + } else if (eia608_is_basicna (cc_data)) { + text = "basicna"; + eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]); + } else if (eia608_is_specialna (cc_data)) { + text = "specialna"; + eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]); + } else if (eia608_is_westeu (cc_data)) { + text = "westeu"; + eia608_to_utf8 (cc_data,&chan,&char1[0],&char2[0]); + } else if (eia608_is_xds (cc_data)) { + text = "xds"; + } else if (eia608_is_midrowchange (cc_data)) { + text = "midrowchange"; + } else if (eia608_is_norpak (cc_data)) { + text = "norpak"; + } else if (eia608_is_preamble (cc_data)) { + text = "preamble"; + eia608_parse_preamble (cc_data, &row, &col, &style, &chan, &underline); + fprintf (stderr,"preamble %d %d %d %d %d\n", row, col, style, chan, underline); + + } else if (eia608_is_control (cc_data)) { + switch (eia608_parse_control (cc_data,&chan)) { + + default: text = "unknown_control"; break; + + case eia608_tab_offset_0: text = "eia608_tab_offset_0"; break; + + case eia608_tab_offset_1: text = "eia608_tab_offset_1"; break; + + case eia608_tab_offset_2:text = "eia608_tab_offset_2"; break; + + case eia608_tab_offset_3: text = "eia608_tab_offset_3"; break; + + case eia608_control_resume_caption_loading: text = "eia608_control_resume_caption_loading"; break; + + case eia608_control_backspace: text = "eia608_control_backspace"; break; + + case eia608_control_alarm_off: text = "eia608_control_alarm_off"; break; + + case eia608_control_alarm_on: text = "eia608_control_alarm_on"; break; + + case eia608_control_delete_to_end_of_row: text = "eia608_control_delete_to_end_of_row"; break; + + case eia608_control_roll_up_2: text = "eia608_control_roll_up_2"; break; + + case eia608_control_roll_up_3: text = "eia608_control_roll_up_3"; break; + + case eia608_control_roll_up_4: text = "eia608_control_roll_up_4"; break; + + case eia608_control_resume_direct_captioning: text = "eia608_control_resume_direct_captioning"; break; + + case eia608_control_text_restart: text = "eia608_control_text_restart"; break; + + case eia608_control_text_resume_text_display: text = "eia608_control_text_resume_text_display"; break; + + case eia608_control_erase_display_memory: text = "eia608_control_erase_display_memory"; break; + + case eia608_control_carriage_return: text = "eia608_control_carriage_return"; break; + + case eia608_control_erase_non_displayed_memory:text = "eia608_control_erase_non_displayed_memory"; break; + + case eia608_control_end_of_caption: text = "eia608_control_end_of_caption"; break; + } + } else { + text = "unhandled"; + } + + fprintf (stderr,"cc %04X (%04X) '%s' '%s' (%s)\n", cc_data, eia608_parity_strip (cc_data), char1, char2, text); +} +//////////////////////////////////////////////////////////////////////////////// +// below this line is re2c +uint16_t _eia608_from_utf8 (const utf8_char_t* s) +{ + const unsigned char* YYMARKER; // needed by default rule + const unsigned char* YYCURSOR = (const unsigned char*) s; + + if (0==s) { return 0x0000;} + + /*!re2c + re2c:yyfill:enable = 0; + re2c:indent:string = " "; + re2c:define:YYCTYPE = "unsigned char"; + + /*Ascii Exceptions*/ + "\x00" { /*NULL*/ return 0x0000; } + "\x27" { /*APOSTROPHE -> RIGHT_SINGLE_QUOTATION_MARK*/ return 0x1229; } + "\x2A" { /*ASTERISK*/ return 0x1228; } + "\x5C" { /*REVERSE_SOLIDUS*/ return 0x132B; } + "\x5E" { /*CIRCUMFLEX_ACCENT*/ return 0x132C; } + "\x5F" { /*LOW_LINE*/ return 0x132D; } + /*Lets Map this to a LEFT_SINGLE_QUOTATION_MARK, just so we have a cc_data for every printable ASCII value*/ + "\x60" { /*GRAVE_ACCENT, No equivalent return 0x0000; return 1;*/ /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; } + "\x7B" { /*LEFT_CURLY_BRACKET*/ return 0x1329; } + "\x7C" { /*VERTICAL_LINE*/ return 0x132E; } + "\x7D" { /*RIGHT_CURLY_BRACKET*/ return 0x132A; } + "\x7E" { /*TILDE*/ return 0x132F; } + /*There is a controll equivilant. Havnt decided if we want to habcle that here, or not*/ + "\x7F" { /*DEL/BACKSPACE. Need to set bits 9 and 12! return 0x1421;*/ return 0x0000; } + + /* Rules are processed top to bottom. So All single byte chars MUST be above this line!*/ + [\x20-\x7F] { /*ASCII range*/ return (s[0]<<8) &0xFF00; } /* Should we use yych instead of s[0]?*/ + + /*This is the second half of the ascii exceptions*/ + "\xC3\xA1" { /*LATIN_SMALL_LETTER_A_WITH_ACUTE*/ return 0x2A00; } + "\xC3\xA9" { /*LATIN_SMALL_LETTER_E_WITH_ACUTE*/ return 0x5C00; } + "\xC3\xAD" { /*LATIN_SMALL_LETTER_I_WITH_ACUTE*/ return 0x5E00; } + "\xC3\xB3" { /*LATIN_SMALL_LETTER_O_WITH_ACUTE*/ return 0x5F00; } + "\xC3\xBA" { /*LATIN_SMALL_LETTER_U_WITH_ACUTE*/ return 0x6000; } + "\xC3\xA7" { /*LATIN_SMALL_LETTER_C_WITH_CEDILLA*/ return 0x7B00; } + "\xC3\xB7" { /*DIVISION_SIGN*/ return 0x7C00; } + "\xC3\x91" { /*LATIN_CAPITAL_LETTER_N_WITH_TILDE*/ return 0x7D00; } + "\xC3\xB1" { /*LATIN_SMALL_LETTER_N_WITH_TILDE*/ return 0x7E00; } + "\xE2\x96\x88" { /*FULL_BLOCK*/ return 0x7F00; } + + /*Special North American character set*/ + "\xC2\xAE" { /*REGISTERED_SIGN*/ return 0x1130; } + "\xC2\xB0" { /*DEGREE_SIGN*/ return 0x1131; } + "\xC2\xBD" { /*VULGAR_FRACTION_ONE_HALF*/ return 0x1132; } + "\xC2\xBF" { /*INVERTED_QUESTION_MARK*/ return 0x1133; } + "\xE2\x84\xA2" { /*TRADE_MARK_SIGN*/ return 0x1134; } + "\xC2\xA2" { /*CENT_SIGN*/ return 0x1135; } + "\xC2\xA3" { /*POUND_SIGN*/ return 0x1136; } + "\xE2\x99\xAA" { /*EIGHTH_NOTE*/ return 0x1137; } + "\xC3\xA0" { /*LATIN_SMALL_LETTER_A_WITH_GRAVE*/ return 0x1138; } + "\xC2\xA0" { /*NO_BREAK_SPACE*/ return 0x1139; } + "\xC3\xA8" { /*LATIN_SMALL_LETTER_E_WITH_GRAVE*/ return 0x113A; } + "\xC3\xA2" { /*LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x113B; } + "\xC3\xAA" { /*LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x113C; } + "\xC3\xAE" { /*LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x113D; } + "\xC3\xB4" { /*LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x113E; } + "\xC3\xBB" { /*LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x113F; } + + /*Extended Spanish/Miscellaneous*/ + "\xC3\x81" { /*LATIN_CAPITAL_LETTER_A_WITH_ACUTE*/ return 0x1220; } + "\xC3\x89" { /*LATIN_CAPITAL_LETTER_E_WITH_ACUTE*/ return 0x1221; } + "\xC3\x93" { /*LATIN_CAPITAL_LETTER_O_WITH_ACUTE*/ return 0x1222; } + "\xC3\x9A" { /*LATIN_CAPITAL_LETTER_U_WITH_ACUTE*/ return 0x1223; } + "\xC3\x9C" { /*LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS*/ return 0x1224; } + "\xC3\xBC" { /*LATIN_SMALL_LETTER_U_WITH_DIAERESIS*/ return 0x1225; } + "\xE2\x80\x98" { /*LEFT_SINGLE_QUOTATION_MARK*/ return 0x1226; } + "\xC2\xA1" { /*INVERTED_EXCLAMATION_MARK*/ return 0x1227; } + /*ASTERISK handled in ASCII mapping*/ + "\xE2\x80\x99" { /*RIGHT_SINGLE_QUOTATION_MARK -> APOSTROPHE*/ return 0x2700; } + "\xE2\x80\x94" { /*EM_DASH*/ return 0x122A; } + "\xC2\xA9" { /*COPYRIGHT_SIGN*/ return 0x122B; } + "\xE2\x84\xA0" { /*SERVICE_MARK*/ return 0x122C; } + "\xE2\x80\xA2" { /*BULLET*/ return 0x122D; } + "\xE2\x80\x9C" { /*LEFT_DOUBLE_QUOTATION_MARK*/ return 0x122E; } + "\xE2\x80\x9D" { /*RIGHT_DOUBLE_QUOTATION_MARK*/ return 0x122F; } + + /*Extended French*/ + "\xC3\x80" { /*LATIN_CAPITAL_LETTER_A_WITH_GRAVE*/ return 0x1230; } + "\xC3\x82" { /*LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX*/ return 0x1231; } + "\xC3\x87" { /*LATIN_CAPITAL_LETTER_C_WITH_CEDILLA*/ return 0x1232; } + "\xC3\x88" { /*LATIN_CAPITAL_LETTER_E_WITH_GRAVE*/ return 0x1233; } + "\xC3\x8A" { /*LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX*/ return 0x1234; } + "\xC3\x8B" { /*LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS*/ return 0x1235; } + "\xC3\xAB" { /*LATIN_SMALL_LETTER_E_WITH_DIAERESIS*/ return 0x1236; } + "\xC3\x8E" { /*LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX*/ return 0x1237; } + "\xC3\x8F" { /*LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS*/ return 0x1238; } + "\xC3\xAF" { /*LATIN_SMALL_LETTER_I_WITH_DIAERESIS*/ return 0x1239; } + "\xC3\x94" { /*LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX*/ return 0x123A; } + "\xC3\x99" { /*LATIN_CAPITAL_LETTER_U_WITH_GRAVE*/ return 0x123B; } + "\xC3\xB9" { /*LATIN_SMALL_LETTER_U_WITH_GRAVE*/ return 0x123C; } + "\xC3\x9B" { /*LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX*/ return 0x123D; } + "\xC2\xAB" { /*LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123E; } + "\xC2\xBB" { /*RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK*/ return 0x123F; } + + /*Portuguese*/ + "\xC3\x83" { /*LATIN_CAPITAL_LETTER_A_WITH_TILDE*/ return 0x1320; } + "\xC3\xA3" { /*LATIN_SMALL_LETTER_A_WITH_TILDE*/ return 0x1321; } + "\xC3\x8D" { /*LATIN_CAPITAL_LETTER_I_WITH_ACUTE*/ return 0x1322; } + "\xC3\x8C" { /*LATIN_CAPITAL_LETTER_I_WITH_GRAVE*/ return 0x1323; } + "\xC3\xAC" { /*LATIN_SMALL_LETTER_I_WITH_GRAVE*/ return 0x1324; } + "\xC3\x92" { /*LATIN_CAPITAL_LETTER_O_WITH_GRAVE*/ return 0x1325; } + "\xC3\xB2" { /*LATIN_SMALL_LETTER_O_WITH_GRAVE*/ return 0x1326; } + "\xC3\x95" { /*LATIN_CAPITAL_LETTER_O_WITH_TILDE*/ return 0x1327; } + "\xC3\xB5" { /*LATIN_SMALL_LETTER_O_WITH_TILDE*/ return 0x1328; } + /*LEFT_CURLY_BRACKET handled in ASCII mapping*/ + /*RIGHT_CURLY_BRACKET handled in ASCII mapping*/ + /*REVERSE_SOLIDUS handled in ASCII mapping*/ + /*CIRCUMFLEX_ACCENT handled in ASCII mapping*/ + /*LOW_LINE handled in ASCII mapping*/ + /*VERTICAL_LINE handled in ASCII mapping*/ + /*TILDE handled in ASCII mapping*/ + + /*German/Danish*/ + "\xC3\x84" { /*LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS*/ return 0x1330; } + "\xC3\xA4" { /*LATIN_SMALL_LETTER_A_WITH_DIAERESIS*/ return 0x1331; } + "\xC3\x96" { /*LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS*/ return 0x1332; } + "\xC3\xB6" { /*LATIN_SMALL_LETTER_O_WITH_DIAERESIS*/ return 0x1333; } + "\xC3\x9F" { /*LATIN_SMALL_LETTER_SHARP_S*/ return 0x1334; } + "\xC2\xA5" { /*YEN_SIGN*/ return 0x1335; } + "\xC2\xA4" { /*CURRENCY_SIGN*/ return 0x1336; } + "\xC2\xA6" { /*BROKEN_BAR*/ return 0x1337; } + "\xC3\x85" { /*LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE*/ return 0x1338; } + "\xC3\xA5" { /*LATIN_SMALL_LETTER_A_WITH_RING_ABOVE*/ return 0x1339; } + "\xC3\x98" { /*LATIN_CAPITAL_LETTER_O_WITH_STROKE*/ return 0x133A; } + "\xC3\xB8" { /*LATIN_SMALL_LETTER_O_WITH_STROKE*/ return 0x133B; } + "\xE2\x94\x8C" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT*/ return 0x133C; } + "\xE2\x94\x90" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT*/ return 0x133D; } + "\xE2\x94\x94" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT*/ return 0x133E; } + "\xE2\x94\x98" { /*EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT*/ return 0x133F; } + + /*Default rule*/ + [^] { /*DEFAULT_RULE*/ return 0x0000; } + */ +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/eia608_charmap.c
Added
@@ -0,0 +1,54 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "eia608_charmap.h" +// 0 - 95: Basic North American character set +// 96 - 111: Special North American character +// 112 - 127: Extended Western European character set : Extended Spanish/Miscellaneous +// 128 - 143: Extended Western European character set : Extended French +// 144 - 159: Extended Western European character set : Portuguese +// 160 - 175: Extended Western European character set : German/Danish +const char* eia608_char_map[] = { + EIA608_CHAR_SPACE, EIA608_CHAR_EXCLAMATION_MARK, EIA608_CHAR_QUOTATION_MARK, EIA608_CHAR_NUMBER_SIGN, EIA608_CHAR_DOLLAR_SIGN, EIA608_CHAR_PERCENT_SIGN, EIA608_CHAR_AMPERSAND, EIA608_CHAR_RIGHT_SINGLE_QUOTATION_MARK, + EIA608_CHAR_LEFT_PARENTHESIS, EIA608_CHAR_RIGHT_PARENTHESIS, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_ACUTE, EIA608_CHAR_PLUS_SIGN, EIA608_CHAR_COMMA, EIA608_CHAR_HYPHEN_MINUS, EIA608_CHAR_FULL_STOP, EIA608_CHAR_SOLIDUS, + EIA608_CHAR_DIGIT_ZERO, EIA608_CHAR_DIGIT_ONE, EIA608_CHAR_DIGIT_TWO, EIA608_CHAR_DIGIT_THREE, EIA608_CHAR_DIGIT_FOUR, EIA608_CHAR_DIGIT_FIVE, EIA608_CHAR_DIGIT_SIX, EIA608_CHAR_DIGIT_SEVEN, EIA608_CHAR_DIGIT_EIGHT, + EIA608_CHAR_DIGIT_NINE, EIA608_CHAR_COLON, EIA608_CHAR_SEMICOLON, EIA608_CHAR_LESS_THAN_SIGN, EIA608_CHAR_EQUALS_SIGN, EIA608_CHAR_GREATER_THAN_SIGN, EIA608_CHAR_QUESTION_MARK, EIA608_CHAR_COMMERCIAL_AT, + EIA608_CHAR_LATIN_CAPITAL_LETTER_A, EIA608_CHAR_LATIN_CAPITAL_LETTER_B, EIA608_CHAR_LATIN_CAPITAL_LETTER_C, EIA608_CHAR_LATIN_CAPITAL_LETTER_D, EIA608_CHAR_LATIN_CAPITAL_LETTER_E, EIA608_CHAR_LATIN_CAPITAL_LETTER_F, EIA608_CHAR_LATIN_CAPITAL_LETTER_G, EIA608_CHAR_LATIN_CAPITAL_LETTER_H, + EIA608_CHAR_LATIN_CAPITAL_LETTER_I, EIA608_CHAR_LATIN_CAPITAL_LETTER_J, EIA608_CHAR_LATIN_CAPITAL_LETTER_K, EIA608_CHAR_LATIN_CAPITAL_LETTER_L, EIA608_CHAR_LATIN_CAPITAL_LETTER_M, EIA608_CHAR_LATIN_CAPITAL_LETTER_N, EIA608_CHAR_LATIN_CAPITAL_LETTER_O, EIA608_CHAR_LATIN_CAPITAL_LETTER_P, + EIA608_CHAR_LATIN_CAPITAL_LETTER_Q, EIA608_CHAR_LATIN_CAPITAL_LETTER_R, EIA608_CHAR_LATIN_CAPITAL_LETTER_S, EIA608_CHAR_LATIN_CAPITAL_LETTER_T, EIA608_CHAR_LATIN_CAPITAL_LETTER_U, EIA608_CHAR_LATIN_CAPITAL_LETTER_V, EIA608_CHAR_LATIN_CAPITAL_LETTER_W, EIA608_CHAR_LATIN_CAPITAL_LETTER_X, + EIA608_CHAR_LATIN_CAPITAL_LETTER_Y, EIA608_CHAR_LATIN_CAPITAL_LETTER_Z, EIA608_CHAR_LEFT_SQUARE_BRACKET, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_ACUTE, EIA608_CHAR_RIGHT_SQUARE_BRACKET, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_ACUTE, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_ACUTE, + EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_ACUTE, EIA608_CHAR_LATIN_SMALL_LETTER_A, EIA608_CHAR_LATIN_SMALL_LETTER_B, EIA608_CHAR_LATIN_SMALL_LETTER_C, EIA608_CHAR_LATIN_SMALL_LETTER_D, EIA608_CHAR_LATIN_SMALL_LETTER_E, EIA608_CHAR_LATIN_SMALL_LETTER_F, EIA608_CHAR_LATIN_SMALL_LETTER_G, EIA608_CHAR_LATIN_SMALL_LETTER_H, + EIA608_CHAR_LATIN_SMALL_LETTER_I, EIA608_CHAR_LATIN_SMALL_LETTER_J, EIA608_CHAR_LATIN_SMALL_LETTER_K, EIA608_CHAR_LATIN_SMALL_LETTER_L, EIA608_CHAR_LATIN_SMALL_LETTER_M, EIA608_CHAR_LATIN_SMALL_LETTER_N, EIA608_CHAR_LATIN_SMALL_LETTER_O, EIA608_CHAR_LATIN_SMALL_LETTER_P, + EIA608_CHAR_LATIN_SMALL_LETTER_Q, EIA608_CHAR_LATIN_SMALL_LETTER_R, EIA608_CHAR_LATIN_SMALL_LETTER_S, EIA608_CHAR_LATIN_SMALL_LETTER_T, EIA608_CHAR_LATIN_SMALL_LETTER_U, EIA608_CHAR_LATIN_SMALL_LETTER_V, EIA608_CHAR_LATIN_SMALL_LETTER_W, EIA608_CHAR_LATIN_SMALL_LETTER_X, + EIA608_CHAR_LATIN_SMALL_LETTER_Y, EIA608_CHAR_LATIN_SMALL_LETTER_Z, EIA608_CHAR_LATIN_SMALL_LETTER_C_WITH_CEDILLA, EIA608_CHAR_DIVISION_SIGN, EIA608_CHAR_LATIN_CAPITAL_LETTER_N_WITH_TILDE, EIA608_CHAR_LATIN_SMALL_LETTER_N_WITH_TILDE, EIA608_CHAR_FULL_BLOCK, + EIA608_CHAR_REGISTERED_SIGN, EIA608_CHAR_DEGREE_SIGN, EIA608_CHAR_VULGAR_FRACTION_ONE_HALF, EIA608_CHAR_INVERTED_QUESTION_MARK, EIA608_CHAR_TRADE_MARK_SIGN, EIA608_CHAR_CENT_SIGN, EIA608_CHAR_POUND_SIGN, EIA608_CHAR_EIGHTH_NOTE, + EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_GRAVE, EIA608_CHAR_NO_BREAK_SPACE, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX, + EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_DIAERESIS, EIA608_CHAR_LEFT_SINGLE_QUOTATION_MARK, EIA608_CHAR_INVERTED_EXCLAMATION_MARK, + EIA608_CHAR_ASTERISK, EIA608_CHAR_APOSTROPHE, EIA608_CHAR_EM_DASH, EIA608_CHAR_COPYRIGHT_SIGN, EIA608_CHAR_SERVICE_MARK, EIA608_CHAR_BULLET, EIA608_CHAR_LEFT_DOUBLE_QUOTATION_MARK, EIA608_CHAR_RIGHT_DOUBLE_QUOTATION_MARK, + EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_CAPITAL_LETTER_E_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_E_WITH_DIAERESIS, EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX, + EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_DIAERESIS, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_U_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX, EIA608_CHAR_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, EIA608_CHAR_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, + EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_TILDE, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_TILDE, EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_ACUTE, EIA608_CHAR_LATIN_CAPITAL_LETTER_I_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_I_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_GRAVE, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_GRAVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_TILDE, + EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_TILDE, EIA608_CHAR_LEFT_CURLY_BRACKET, EIA608_CHAR_RIGHT_CURLY_BRACKET, EIA608_CHAR_REVERSE_SOLIDUS, EIA608_CHAR_CIRCUMFLEX_ACCENT, EIA608_CHAR_LOW_LINE, EIA608_CHAR_VERTICAL_LINE, EIA608_CHAR_TILDE, + EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_DIAERESIS, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_DIAERESIS, EIA608_CHAR_LATIN_SMALL_LETTER_SHARP_S, EIA608_CHAR_YEN_SIGN, EIA608_CHAR_CURRENCY_SIGN, EIA608_CHAR_BROKEN_BAR, + EIA608_CHAR_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE, EIA608_CHAR_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE, EIA608_CHAR_LATIN_CAPITAL_LETTER_O_WITH_STROKE, EIA608_CHAR_LATIN_SMALL_LETTER_O_WITH_STROKE, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, +};
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/scc.c
Added
@@ -0,0 +1,54 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "scc.h" +#include "utf8.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#define FRAME_RATE (1000.0/30) +#define SCCTIME2MS(HH,MM,SS,FF) (((HH*3600.0 + MM*60.0 + SS) * 1000.0) + ( FF * FRAME_RATE )) + +// 00:00:25:16 9420 9440 aeae ae79 ef75 2068 6176 e520 79ef 75f2 20f2 ef62 eff4 e9e3 732c 2061 6e64 2049 94fe 9723 ea75 73f4 20f7 616e f420 f4ef 2062 e520 61f7 e573 ef6d e520 e96e 2073 7061 e3e5 ae80 942c 8080 8080 942f + +int scc_to_608 (const char* line, double* pts, uint16_t* cc, int cc_max) +{ + int cc_count = 0, cc_data = 0, hh = 0, mm = 0, ss = 0, ff = 0; + + // TODO if ';' use 29.79 fps, if ':' use 30 fls + if (4 == sscanf (line, "%2d:%2d:%2d%*1[:;]%2d", &hh, &mm, &ss, &ff)) { + (*pts) = SCCTIME2MS (hh,mm,ss,ff); // scc files start at one hour for some reason + line += 12; + + while (1 == sscanf (line, "%04x ", &cc_data)) { + line += 5; cc[cc_count] = cc_data; ++cc_count; + + if (cc_count >= cc_max) { + break; + } + } + } + + return cc_count; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/srt.c
Added
@@ -0,0 +1,194 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ +#include "srt.h" +#include "utf8.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + + + +srt_t* srt_new (const utf8_char_t* data, size_t size, double timestamp, srt_t* prev, srt_t** head) +{ + srt_t* srt = malloc (sizeof (srt_t)+size+1); + srt->next = 0; + srt->duration = 0; + srt->aloc = size; + srt->timestamp = timestamp; + utf8_char_t* dest = (utf8_char_t*) srt_data (srt); + + if (prev) { + prev->next = srt; + prev->duration = timestamp - prev->timestamp; + } + + if (head && 0 == (*head)) { + (*head) = srt; + } + + if (data) { + memcpy (dest, data, size); + } else { + memset (dest, 0, size); + } + + dest[size] = '\0'; + return srt; +} + +srt_t* srt_free_head (srt_t* head) +{ + srt_t* next = head->next; + free (head); + return next; +} + +void srt_free (srt_t* srt) +{ + while (srt) { + srt = srt_free_head (srt); + } +} + +#define SRTTIME2SECONDS(HH,MM,SS,MS) ((HH*3600.0) + (MM*60.0) + SS + (MS/1000.0)) +srt_t* srt_parse (const utf8_char_t* data, size_t size) +{ + int counter; + srt_t* head = 0, *prev = 0; + double str_pts = 0, end_pts = 0; + size_t line_length = 0, trimmed_length = 0; + int hh1, hh2, mm1, mm2, ss1, ss2, ms1, ms2; + + for (;;) { + line_length = 0; + + do { + data += line_length; + size -= line_length; + line_length = utf8_line_length (data); + trimmed_length = utf8_trimmed_length (data,line_length); + // Skip empty lines + } while (0 < line_length && 0 == trimmed_length); + + // linelength cant be zero before EOF + if (0 == line_length) { + break; + } + + counter = atoi (data); + // printf ("counter (%d): '%.*s'\n", line_length, (int) line_length, data); + data += line_length; + size -= line_length; + + line_length = utf8_line_length (data); + // printf ("time (%d): '%.*s'\n", line_length, (int) line_length, data); + + { + if (8 == sscanf (data, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d", &hh1, &mm1, &ss1, &ms1, &hh2, &mm2, &ss2, &ms2)) { + str_pts = SRTTIME2SECONDS (hh1, mm1, ss1, ms1); + end_pts = SRTTIME2SECONDS (hh2, mm2, ss2, ms2); + } + + data += line_length; + size -= line_length; + } + + // Caption text starts here + const utf8_char_t* text = data; + size_t text_size = 0; + // printf ("time: '(%f --> %f)\n",srt.srt_time, srt.end_time); + + do { + line_length = utf8_line_length (data); + trimmed_length = utf8_trimmed_length (data,line_length); + // printf ("cap (%d): '%.*s'\n", line_length, (int) trimmed_length, data); + data += line_length; + size -= line_length; + text_size += line_length; + } while (trimmed_length); + + // should we trim here? + srt_t* srt = srt_new (text,text_size,str_pts,prev,&head); + srt->duration = end_pts - str_pts; + prev = srt; + } + + return head; +} + +int srt_to_caption_frame (srt_t* srt, caption_frame_t* frame) +{ + const char* data = srt_data (srt); + return caption_frame_from_text (frame,data); +} + +srt_t* srt_from_caption_frame (caption_frame_t* frame, srt_t* prev, srt_t** head) +{ + // CRLF per row, plus an extra at the end + srt_t* srt = srt_new (0, 2+CAPTION_FRAME_TEXT_BYTES, frame->timestamp, prev, head); + utf8_char_t* data = srt_data (srt); + + caption_frame_to_text (frame,data); + // srt requires an extra new line + strcat ( (char*) data,"\r\n"); + + return srt; +} + +static inline void _crack_time (double tt, int* hh, int* mm, int* ss, int* ms) +{ + (*ms) = (int) ((int64_t) (tt * 1000.0) % 1000); + (*ss) = (int) ((int64_t) (tt) % 60); + (*mm) = (int) ((int64_t) (tt / (60.0)) % 60); + (*hh) = (int) ((int64_t) (tt / (60.0*60.0))); +} + +static void _dump (srt_t* head, char type) +{ + int i; + srt_t* srt; + + if ('v' == type) { + printf ("WEBVTT\r\n"); + } + + for (srt = head, i = 1; srt; srt=srt_next (srt), ++i) { + int hh1, hh2, mm1, mm2, ss1, ss2, ms1, ms2; + _crack_time (srt->timestamp, &hh1, &mm1, &ss1, &ms1); + _crack_time (srt->timestamp + srt->duration, &hh2, &mm2, &ss2, &ms2); + + if ('s' == type) { + printf ("%02d\r\n%d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n%s\r\n", i, + hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, srt_data (srt)); + } + + else if ('v' == type) { + printf ("%d:%02d:%02d.%03d --> %02d:%02d:%02d.%03d\r\n%s\r\n", + hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, srt_data (srt)); + } + } +} + +void srt_dump (srt_t* head) { _dump (head,'s'); } +void vtt_dump (srt_t* head) { _dump (head,'v'); }
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/utf8.c
Added
@@ -0,0 +1,170 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ + + + +#include "utf8.h" +#include <string.h> + +const utf8_char_t* utf8_char_next (const char* s) +{ + if (0x80 == (s[0]&0xC0)) { ++s; } + + return s; +} + +// returnes the length of the char in bytes +size_t utf8_char_length (const utf8_char_t* c) +{ + // count null term as zero size + if (0x00 == c[0]) { return 0; } + + if (0x00 == (c[0]&0x80)) { return 1; } + + if (0xC0 == (c[0]&0xE0) && 0x80 == (c[1]&0xC0)) { return 2; } + + if (0xE0 == (c[0]&0xF0) && 0x80 == (c[1]&0xC0) && 0x80 == (c[2]&0xC0)) { return 3; } + + if (0xF0 == (c[0]&0xF8) && 0x80 == (c[1]&0xC0) && 0x80 == (c[2]&0xC0) && 0x80 == (c[3]&0xC0)) { return 4; } + + return 0; +} + +// returns length of the string in bytes +// size is number of charcter to count (0 to count until NULL term) +size_t utf8_string_length (const utf8_char_t* data, utf8_size_t size) +{ + size_t char_length, byts = 0; + + if (0 == size) { + size = utf8_char_count (data,0); + } + + for (; 0 < size ; --size) { + if (0 == (char_length = utf8_char_length (data))) { + break; + } + + data += char_length; + byts += char_length; + } + + return byts; +} + +size_t utf8_char_copy (utf8_char_t* dst, const utf8_char_t* src) +{ + size_t bytes = utf8_char_length (src); + + if (bytes&&dst) { + memcpy (dst,src,bytes); + dst[bytes] = '\0'; + } + + return bytes; +} + +// returnes the number of utf8 charcters in a string given the number of bytes +// to count until the a null terminator, pass 0 for size +utf8_size_t utf8_char_count (const char* data, size_t size) +{ + size_t i, bytes = 0; + utf8_size_t count = 0; + + if (0 == size) { + size = strlen (data); + } + + for (i = 0 ; i < size ; ++count, i += bytes) { + if (0 == (bytes = utf8_char_length (&data[i]))) { + break; + } + } + + return count; +} + +// returnes the length of the line in bytes triming not printable charcters at the end +size_t utf8_trimmed_length (const char* data, size_t size) +{ + for (; 0 < size && ' ' >= (uint8_t) data[size-1] ; --size) { } + + return size; +} + +// returns the length in bytes of the line including the new line charcter(s) +// auto detects between windows(CRLF), unix(LF), mac(CR) and riscos (LFCR) line endings +size_t utf8_line_length (const char* data) +{ + size_t len = 0; + + for (len = 0; 0 != data[len]; ++len) { + if ('\r' == data[len]) { + if ('\n' == data[len+1]) { + return len + 2; // windows + } else { + return len + 1; // unix + } + } else if ('\n' == data[len]) { + if ('\r' == data[len+1]) { + return len + 2; // riscos + } else { + return len + 1; // macos + } + } + } + + return len; +} + +// returns number of chars to include before split +utf8_size_t utf8_wrap_length (const utf8_char_t* data, utf8_size_t size) +{ + // Set split_at to size, so if a split point cna not be found, retuns the size passed in + size_t char_length, char_count, split_at = size; + + for (char_count = 0 ; char_count <= size ; ++char_count) { + if (' ' >= (*data)) { + split_at = char_count; + } + + char_length = utf8_char_length (data); + data += char_length; + } + + return split_at; +} + +int utf8_line_count (const utf8_char_t* data) +{ + size_t len = 0; + int count = 0; + + do { + len = utf8_line_length (data); + data += len; ++count; + } while (0<len); + + return count-1; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/src/xds.c
Added
@@ -0,0 +1,51 @@ +/**********************************************************************************************/ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file */ +/* except in compliance with the License. A copy of the License is located at */ +/* */ +/* http://aws.amazon.com/apache2.0/ */ +/* */ +/* or in the "license" file accompanying this file. This file is distributed on an "AS IS" */ +/* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the */ +/* License for the specific language governing permissions and limitations under the License. */ +/**********************************************************************************************/ +// http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/CC_XDS.HTML#PR +#include "xds.h" +#include "caption.h" +#include <string.h> + +void xds_init (xds_t* xds) +{ + memset (xds,0,sizeof (xds_t)); +} + +int xds_decode (xds_t* xds, uint16_t cc) +{ + switch (xds->state) { + default: + case 0: + xds_init (xds); + xds->class = (cc&0x0F00) >>8; + xds->type = (cc&0x000F); + xds->state = 1; + return LIBCAPTION_OK; + + case 1: + if (0x8F00 == (cc&0xFF00)) { + xds->checksum = (cc&0x007F); + xds->state = 0; + return LIBCAPTION_READY; + } + + if (xds->size < 32) { + xds->content[xds->size+0] = (cc&0x7F00) >>8; + xds->content[xds->size+1] = (cc&0x007F); + xds->size += 2; + return LIBCAPTION_OK; + } + } + + xds->state = 0; + return LIBCAPTION_ERROR; +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/unit_tests
Added
+(directory)
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/unit_tests/eia608_test.c
Added
@@ -0,0 +1,280 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ + +#include "eia608.h" +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +// all possible utf8 valies, including invalid ones +void encode_utf8ish (int32_t in, char out[7]) +{ + if (0 > in) { + out[0] = 0; + return; + } + + // 0xxxxxxx, 7 bits + if (0x80 > in) { + out[0] = in; + out[1] = 0; + return; + } + + // 110xxxxx 10xxxxxx, 11 bits + if (0x800 > in) { + out[0] = 0xC0 | ( (in >> (6*1)) & 0x1F); + out[1] = 0x80 | ( (in >> (6*0)) & 0x3F); + out[2] = 0; + return; + } + + // 1110xxxx 10xxxxxx 10xxxxxx, 16 bits + if (0x10000 > in) { + out[0] = 0xE0 | ( (in >> (6*2)) & 0x0F); + out[1] = 0x80 | ( (in >> (6*1)) & 0x3F); + out[2] = 0x80 | ( (in >> (6*0)) & 0x3F); + out[3] = 0; + return; + } + + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx, 21 bits + if (0x200000 > in) { + out[0] = 0xF0 | ( (in >> (6*3)) & 0x07); + out[1] = 0x80 | ( (in >> (6*2)) & 0x3F); + out[2] = 0x80 | ( (in >> (6*1)) & 0x3F); + out[3] = 0x80 | ( (in >> (6*0)) & 0x3F); + out[4] = 0; + return; + } + + // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx, 26 bits + if (0x4000000 > in) { + out[0] = 0xF8 | ( (in >> (6*4)) & 0x03); + out[1] = 0x80 | ( (in >> (6*3)) & 0x3F); + out[2] = 0x80 | ( (in >> (6*2)) & 0x3F); + out[3] = 0x80 | ( (in >> (6*1)) & 0x3F); + out[4] = 0x80 | ( (in >> (6*0)) & 0x3F); + out[5] = 0; + return; + } + + // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx, 31 bits + if (0x80000000 > in) { + out[0] = 0xFC | ( (in >> (6*5)) & 0x01); + out[1] = 0x80 | ( (in >> (6*4)) & 0x3F); + out[2] = 0x80 | ( (in >> (6*3)) & 0x3F); + out[3] = 0x80 | ( (in >> (6*2)) & 0x3F); + out[4] = 0x80 | ( (in >> (6*1)) & 0x3F); + out[5] = 0x80 | ( (in >> (6*0)) & 0x3F); + out[6] = 0; + return; + } +} + +void test_all_utf8() +{ + char s[7]; size_t size, count = 0; uint16_t code1, code2; + + for (int i = 0 ; i < 0x80000000 ; ++i) { + encode_utf8ish (i, &s[0]); + code1 = eia608_from_utf8 ( (const char*) &s[0], 0, &size); + + // code2 = eia608_from_utf8 ( (const char*) &s[0], 1, &size); + if (code1) { + ++count; + printf ("%d: string: '%s' code: %04X\n",count, &s[0],code1); + } + } + + // Count must be 177 + // 176 charcters, pile we have two mapping for left quote mark +} + +#define BIN "%d%d%d%d%d%d%d%d %d%d%d%d%d%d%d%d" +#define BIND(D) ((D)>>15)&0x01, ((D)>>14)&0x01,((D)>>13)&0x01,((D)>>12)&0x01,((D)>>11)&0x01,((D)>>10)&0x01,((D)>>9)&0x01,((D)>>8)&0x01,((D)>>7)&0x01,((D)>>6)&0x01,((D)>>5)&0x01,((D)>>4)&0x01,((D)>>3)&0x01,((D)>>2)&0x01,((D)>>1)&0x01,((D)>>0)&0x01 + + +void print_bin (int n) +{ + int mask = 0x80; + + for (int mask = 0x80 ; mask ; mask >>= 1) { + printf ("%s", n & mask ? "1" : "0"); + } + + printf ("\n"); +} + +void void_test_all_possible_code_words() +{ + for (int i = 0 ; i <= 0x3FFF ; ++i) { + int16_t code = eia608_parity ( ( (i<<1) &0x7F00) | (i&0x7F)); + + int count =eia608_cc_data_is_extended_data_service (code)+ + eia608_cc_data_is_basic_north_american_character (code) + + eia608_cc_data_is_special_north_american_character (code) + + eia608_cc_data_is_extended_western_european_character (code) + + eia608_cc_data_is_nonwestern_norpak_character (code) + + eia608_cc_data_is_row_preamble (code) + + eia608_cc_data_is_control_command (code); + + if (1 < count) { + printf ("code 0x%04X matched >1\n",code&0x7F7F); + } + + // if (0 == count) { + // printf ("code 0x%04X not matched %d\n",eia608_strip_parity_bits (code), i); + // } + } +} + +void print_charmap() +{ + for (int i = 0 ; i < EIA608_CHAR_COUNT ; ++i) { + printf ("%s", eia608_char_map[i]); + } + + printf ("\n"); +} + +void dance() +{ + for (int i = 0 ; i < 100 ; ++i) { + const char* l = 0 == rand() % 2 ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT; + const char* r = 0 == rand() % 2 ? EIA608_CHAR_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT : EIA608_CHAR_BOX_DRAWINGS_LIGHT_UP_AND_LEFT; + printf ("%s %s%s%s%s%s%s%s %s ", EIA608_CHAR_EIGHTH_NOTE, l, EIA608_CHAR_LEFT_PARENTHESIS, EIA608_CHAR_EM_DASH, EIA608_CHAR_LOW_LINE, EIA608_CHAR_EM_DASH, + EIA608_CHAR_RIGHT_PARENTHESIS, r, EIA608_CHAR_EIGHTH_NOTE); + } + +} + + +int main (int argc, const char** arg) +{ + // print_charmap(); + // // return 0; + // srand (time (0)); + // // test_all_utf8(); + // // void_test_all_possible_code_words(); + // // return 0; + // // print_charmap(); + // dance(); + // return 0; + for (int i = 0 ; i <= 0x3FFF ; ++i) { + uint16_t code1 = eia608_parity ( ( (i<<1) &0x7F00) | (i&0x7F)); + + switch (eia608_cc_data_type (code1)) { + default: + case EIA608_CC_DATA_UNKNOWN: + // printf ("Unknown code %04X\n",code); + break; + + case EIA608_CC_DATA_CONTROL_COMMAND: { + int cc; + eia608_control_t cmd = eia608_parse_control (code1, &cc); + uint16_t code2 = eia608_control_command (cmd,cc); + + if (code1 != code2) { + printf (BIN " != " BIN " (0x%04x != 0x%04x) cc: %d\n", BIND (code1), BIND (code2),code1,code2,cc); + } + } break; + + + case EIA608_CC_DATA_BASIC_NORTH_AMERICAN_CHARACTER: { + char char1[5], char2[5]; int chan; size_t size; + + if (eia608_to_utf8 (code1, &chan, &char1[0], &char2[0])) { + uint16_t code2 = eia608_from_utf8_2 (&char1[0], &char2[0]); + + // if the second char is invalid, mask it off, we will accept the first + if (0x80 < (code1 &0x007F) || 0x20 > (code1 &0x007F)) { + code1 = (code1&0xFF00) |0x0080; + } + + if (code1 == code2) { + // printf ("%s " BIN " == " BIN " (0x%04x == 0x%04x)\n", &char1[0], BIND (code1), BIND (code2),code1,code2); + } else { + printf ("%s %s " BIN " != " BIN " (0x%04x != 0x%04x)\n", &char1[0], &char2[0], BIND (code1), BIND (code2),code1,code2); + } + } + + } break; + + case EIA608_CC_DATA_SPECIAL_NORTH_AMERICAN_CHARACTER: + case EIA608_CC_DATA_EXTENDED_WESTERN_EUROPEAN_CHARACTER: { + char char1[5], char2[5]; int chan; size_t size; + + if (eia608_to_utf8 (code1, &chan, &char1[0], &char2[0])) { + uint16_t code2 = eia608_from_utf8 (&char1[0], chan, &size); + + if (code1 == code2) { + // printf ("%s " BIN " == " BIN " (0x%04x == 0x%04x)\n", &char1[0], BIND (code1), BIND (code2),code1,code2); + } else { + printf ("%s " BIN " != " BIN " (0x%04x != 0x%04x)\n", &char1[0], BIND (code1), BIND (code2),code1,code2); + } + } + } break; + + // #define EIA608_CODE_ROW_PREAMBLE 4 + // #define EIA608_CODE_EXTENDED_DATA_SERVICE 5 + // #define EIA608_CODE_CONTROL_COMMAND 6 + } + } + + return 0; +} + + + + +// for (uint16_t i = 0 ; i < 0x4000; ++i) { +// int chan; +// char str[7]; +// uint16_t code = ( (i<<1) &0x7F00) | (i & 0x007F); +// +// if (eia608_to_utf8 (code,&chan,str)) { +// printf ("code: 0x%04X str: '%s'\n", code,str); +// } +// } +// +// // for(int i = 0 ; i < cie608_char_count ; ++i) +// // { +// // cie608_char_map[i] +// // +// // } +// +// +// for (int i = 0 ; i < 128 ; ++i) { +// // print_bin( B7( i ) ); +// // print_bin( eia608_parity_table[i] ); +// printf ("%d %d %d\n", i, 0x7F & eia608_parity_table[i], eia608_parity_table[i]); +// // if ( i != eia608_parity_table[i] ) +// // { +// // printf( "ERROR\n" ); +// // +// // } +// } +// +// }
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/unit_tests/test_sei.c
Added
@@ -0,0 +1,148 @@ +/**********************************************************************************************/ +/* The MIT License */ +/* */ +/* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in */ +/* all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */ +/* THE SOFTWARE. */ +/**********************************************************************************************/ + +#include "avcsei.h" +#include <stdio.h> +#include <stdlib.h> + +uint8_t sei1[] = { 0x06, 0x04, 0x68, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xDF, 0xFF, 0xFC, 0xEC, 0xE5, + 0xFC, 0xAE, 0x80, 0xFC, 0x94, 0x52, 0xFC, 0x97, 0xA1, 0xFC, 0x2A, 0x20, 0xFC, 0xDC, 0x20, 0xFC, + 0x5E, 0x20, 0xFC, 0xDF, 0x20, 0xFC, 0xE0, 0x20, 0xFC, 0x91, 0x38, 0xFC, 0x20, 0x80, 0xFC, 0x91, + 0xBA, 0xFC, 0x20, 0xE9, 0xFC, 0x13, 0xA4, 0xFC, 0x20, 0xEF, 0xFC, 0x13, 0x26, 0xFC, 0x20, 0x75, + 0xFC, 0x92, 0xBC, 0xFC, 0x94, 0xF2, 0xFC, 0x97, 0xA1, 0xFC, 0x61, 0x80, 0xFC, 0x13, 0x31, 0xFC, + 0x20, 0xE5, 0xFC, 0x92, 0xB6, 0xFC, 0x20, 0xE9, 0xFC, 0x92, 0xB9, 0xFC, 0x20, 0xEF, 0xFC, 0x13, + 0xB3, 0xFC, 0x20, 0x75, 0xFC, 0x92, 0x25, 0xFC, 0x20, 0x80, 0xFF, 0x80, + }; + +uint8_t sei2[] = { 0x06, 0x04, 0x35, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xCE, 0xFF, 0xFC, 0x94, 0x26, + 0xFC, 0x94, 0xAD, 0xFC, 0x94, 0xF2, 0xFC, 0x43, 0xC1, 0xFC, 0xD0, 0x54, 0xFC, 0x49, 0x4F, 0xFC, + 0xCE, 0x20, 0xFC, 0x4C, 0x49, 0xFC, 0xCE, 0x45, 0xFC, 0xD3, 0x20, 0xFC, 0x52, 0x4F, 0xFC, 0x4C, + 0x4C, 0xFC, 0x20, 0xD5, 0xFC, 0xD0, 0x80, 0xFF, 0x80, + }; + + +uint8_t sei3[] = { 0x06, + 0x04, 0x68, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xDF, 0xFF, 0xFC, 0xEC, 0xE5, 0xFC, + 0xAE, 0x80, 0xFC, 0x94, 0x52, 0xFC, 0x97, 0xA1, 0x00, 0x00, 0x03, 0x00, 0xFC, 0xDC, 0x20, 0xFC, + 0x5E, 0x20, 0xFC, 0xDF, 0x20, 0xFC, 0xE0, 0x20, 0xFC, 0x91, 0x38, 0xFC, 0x20, 0x80, 0xFC, 0x91, + 0xBA, 0xFC, 0x20, 0xE9, 0xFC, 0x13, 0xA4, 0xFC, 0x20, 0xEF, 0xFC, 0x13, 0x26, 0xFC, 0x20, 0x75, + 0xFC, 0x92, 0xBC, 0xFC, 0x94, 0xF2, 0xFC, 0x97, 0xA1, 0xFC, 0x61, 0x80, 0xFC, 0x13, 0x31, 0xFC, + 0x20, 0xE5, 0xFC, 0x92, 0xB6, 0xFC, 0x20, 0xE9, 0xFC, 0x92, 0xB9, 0xFC, 0x20, 0xEF, 0xFC, 0x13, + 0xB3, 0xFC, 0x20, 0x75, 0xFC, 0x92, 0x25, 0xFC, 0x20, 0x80, 0xFF, + + 0x04, 0x68, 0xB5, 0x00, 0x31, 0x47, 0x41, 0x39, 0x34, 0x03, 0xDF, 0xFF, 0xFC, 0xEC, 0xE5, + 0xFC, 0xAE, 0x80, 0xFC, 0x94, 0x52, 0xFC, 0x97, 0xA1, 0x00, 0x00, 0x03, 0x00, 0xFC, 0xDC, 0x20, + 0xFC, 0x5E, 0x20, 0xFC, 0xDF, 0x20, 0xFC, 0xE0, 0x20, 0xFC, 0x91, 0x38, 0xFC, 0x20, 0x80, 0xFC, + 0x91, 0xBA, 0xFC, 0x20, 0xE9, 0xFC, 0x13, 0xA4, 0xFC, 0x20, 0xEF, 0xFC, 0x13, 0x26, 0xFC, 0x20, + 0x75, 0xFC, 0x92, 0xBC, 0xFC, 0x94, 0xF2, 0xFC, 0x97, 0xA1, 0xFC, 0x61, 0x80, 0xFC, 0x13, 0x31, + 0xFC, 0x20, 0xE5, 0xFC, 0x92, 0xB6, 0xFC, 0x20, 0xE9, 0xFC, 0x92, 0xB9, 0xFC, 0x20, 0xEF, 0xFC, + 0x13, 0xB3, 0xFC, 0x20, 0x75, 0xFC, 0x92, 0x25, 0xFC, 0x20, 0x80, 0xFF, + 0x80, + }; + + +// TODO make SEI with multiple messages +// TODO make SEI with emupation prevention + + +uint8_t* read_file (const char* file, size_t* size) +{ + FILE* f = fopen (file, "rb"); + + if (! f) { + return 0; + } + + fseek (f,0,SEEK_END); + (*size) = ftell (f); + fseek (f,0,SEEK_SET); + uint8_t* data = (uint8_t*) malloc (*size); + + for (int i = 0 ; i < (*size) ;) { + i += fread (&data[i], 1, *size, f); + } + + fclose (f); + return data; +} + +int test_emulation_byte() +{ + avcsei_t sei; + avcsei_init (&sei); + avcsei_parse (&sei,sei3,sizeof (sei3)); + avcsei_dump (&sei); + avcsei_free (&sei); +} + + +int main (int argc, const char** argv) +{ + // test_emulation_byte(); + // return 0; + + size_t size; + avcsei_t sei; + cea708_t cea708; + eia608_screen_t screen; + char screen_buf[EIA608_SCREEN_DUMP_BUF_SIZE]; + char json_buf[EIA608_SCREEN_JSON_BUF_SIZE]; + + // uint8_t* data = + for (int i = 1 ; i < argc ; ++i) { + avcsei_init (&sei); + eia608_screen_init (&screen); + uint8_t* data = read_file (argv[i],&size); + avcsei_parse (&sei,data,size); + free (data); + + // avcsei_parse (&sei,sei1,sizeof (sei1)); + + for (avcsei_message_t* msg = avcsei_message_head (&sei) ; msg ; msg = avcsei_message_next (msg)) { + if (sei_type_user_data_registered_itu_t_t35 == avcsei_message_type (msg)) { + // avcsei_dump (&sei); + avcsei_decode_cea708 (msg,&cea708); + int count = cea708_cc_count (&cea708.user_data); + + for (int i = 0 ; i < count ; ++i) { + cea708_cc_type_t type; int valid; + uint16_t cc_data = cea708_cc_data (&cea708.user_data, i, &valid, &type); + + if (valid && (cc_type_ntsc_cc_field_1 == type || cc_type_ntsc_cc_field_2 == type)) { + eia608_screen_decode (&screen,cc_data); + } + } + + // eia608_screen_dump (&screen, &screen_buf[0]); + // printf ("screen:\n%s\n",&screen_buf[0]); + + eia608_screen_json (&screen, &json_buf[0]); + printf ("json:\n%s\n",&json_buf[0]); + + } + } + + avcsei_free (&sei); + } +}
View file
obs-studio-0.17.0.tar.xz/deps/libcaption/unit_tests/tos.scc
Added
@@ -0,0 +1,154 @@ +Scenarist_SCC V1.0 + +00:00:22:10 9420 94f2 97a2 d9ef 75a7 f2e5 2061 20ea e5f2 6b2c 2054 68ef 6dae 942c 8080 8080 942f + +00:00:23:28 9420 947c 97a2 4cef ef6b 2043 e5ec e961 2c20 f7e5 2068 6176 e520 f4ef 20e6 efec ecef f720 ef75 f220 7061 7373 e9ef 6e73 3b80 942c 8080 8080 942f + +00:00:25:16 9420 9440 aeae ae79 ef75 2068 6176 e520 79ef 75f2 20f2 ef62 eff4 e9e3 732c 2061 6e64 2049 94fe 9723 ea75 73f4 20f7 616e f420 f4ef 2062 e520 61f7 e573 ef6d e520 e96e 2073 7061 e3e5 ae80 942c 8080 8080 942f + +00:00:29:09 9420 9440 97a1 5768 7920 64ef 6ea7 f420 79ef 7520 ea75 73f4 2061 646d e9f4 20f4 6861 f480 94fe 97a2 79ef 75a7 f2e5 20e6 f2e5 616b e564 20ef 75f4 2062 7920 6d79 20f2 ef62 eff4 2068 616e 64bf 942c 8080 8080 942f + +00:00:33:19 9420 94e0 49a7 6d20 6eef f420 e6f2 e561 6be5 6420 ef75 f420 6279 ad20 e9f4 a773 aeae ae80 942c 8080 8080 942f + +00:00:36:10 9420 94f2 9723 aeae ae61 ecf2 e967 68f4 a120 46e9 6ee5 a180 942c 8080 8080 942f + +00:00:36:29 9420 945e 9723 49a7 6d20 e6f2 e561 6be5 6420 ef75 f4a1 2049 2068 6176 e520 6ee9 6768 f46d 61f2 e573 94f2 f468 61f4 2049 a76d 2062 e5e9 6e67 20e3 6861 73e5 64ae aeae 942c 8080 8080 942f + +00:00:39:27 9420 947c 97a2 aeae ae62 7920 f468 e573 e520 67e9 616e f420 f2ef 62ef f4e9 e320 e3ec 61f7 7320 efe6 2064 e561 f468 aeae ae80 942c 8080 8080 942f + +00:00:40:29 9420 9452 97a2 a246 ef75 f2f4 7920 79e5 61f2 7320 ec61 f4e5 f2a2 94e0 97a2 5768 61f4 e576 e5f2 2c20 5468 ef6d ae20 57e5 a7f2 e520 64ef 6ee5 ae80 942c 8080 8080 942f + +00:00:49:02 9420 94fe 9723 52ef 62ef f4a7 7320 6de5 6def f279 2073 796e e3e5 6420 616e 6420 ecef e36b e564 a180 942c 8080 8080 942f + +00:01:00:08 9420 94f2 97a1 5468 e973 20e9 7320 70f2 e5f4 f479 20e6 f2e5 616b 79ae 942c 8080 8080 942f + +00:01:56:03 9420 94e0 97a2 d368 ef75 ec64 6ea7 f420 79ef 7520 62e5 2064 eff7 6e20 f468 e5f2 e5bf 942c 8080 8080 942f + +00:02:09:29 9420 94fe 97a2 4920 68e5 61f2 6420 79ef 7520 6775 7973 20f4 61ec 6be9 6e67 20ec 6173 f420 6ee9 6768 f4ae 942c 8080 8080 942f + +00:02:15:02 9420 94e0 97a2 49f4 a773 206e eff4 206d 7920 e661 75ec f42c 2079 ef75 206b 6eef f7ae 942c 8080 8080 942f + +00:03:10:08 9420 94f4 97a1 c1f2 e520 79ef 7520 f2e5 6164 79bf 942c 8080 8080 942f + +00:03:11:24 9420 947c 9723 4fe6 20e3 ef75 f273 e520 79ef 75a7 f2e5 20f2 e561 6479 2c20 79ef 75a7 f2e5 2061 20f2 efe3 6b73 f461 f2ae 942c 8080 8080 942f + +00:03:16:02 9420 94e0 9723 c8ef f7a7 7320 e9f4 20ec efef 6be9 6e67 2c20 c261 f2ec e579 bf80 942c 8080 8080 942f + +00:03:17:27 9420 94fe 97a2 57e5 2073 68ef 75ec 6420 6861 76e5 2061 62ef 75f4 20f4 e56e 206d e96e 75f4 e573 aeae ae80 942c 8080 8080 942f + +00:03:20:19 9420 94f2 97a2 57e5 ecec 20f4 6861 f4a7 7320 70e5 f2e6 e5e3 f4ae 942c 8080 8080 942f + +00:03:22:05 9420 9440 57e5 a7f2 e520 ef6e 20e9 6e20 ef6e e5a1 20c1 ecec 2073 7973 f4e5 6d73 2067 efa1 94f4 97a1 d9e5 6168 2079 ef75 2c20 67ef a180 942c 8080 8080 942f + +00:03:26:29 9420 94e0 97a1 c7ef a120 cdef 76e5 2079 ef75 f220 6173 73e5 73a1 20c7 ef20 67ef 2067 efa1 942c 8080 8080 942f + +00:03:32:03 9420 94f2 4920 ecef 76e5 20e9 f4a1 2043 ef6d e520 ef6e 2c20 67ef a180 942c 8080 8080 942f + +00:03:42:08 9420 94f4 97a2 5468 61f4 a773 206e e9e3 e5ae 942c 8080 8080 942f + +00:03:43:18 9420 94f2 ceef f468 e96e 6720 f4ef 20f7 eff2 f279 2061 62ef 75f4 ae80 942c 8080 8080 942f + +00:03:45:11 9420 9476 97a1 5468 ef6d ae80 942c 8080 8080 942f + +00:03:50:07 9420 94f4 97a1 5468 e5f2 e520 7368 e520 e973 ae80 942c 8080 8080 942f + +00:03:52:27 9420 9476 97a2 ceef f7ae 942c 8080 8080 942f + +00:03:54:06 9420 94f4 97a1 d9ef 7520 ecef 76e5 2068 e5f2 ae80 942c 8080 8080 942f + +00:03:56:03 9420 94f2 97a2 d368 e520 e973 2079 ef75 f220 7061 7373 e9ef 6ea1 942c 8080 8080 942f + +00:03:59:04 9420 94f2 9723 c2e5 20f4 e56e 64e5 f220 f4ef 2068 e5f2 ae80 942c 8080 8080 942f + +00:04:00:15 9420 94e0 9723 c2e5 2068 ef6e e573 f4a1 2045 68ad 2062 e520 f4e5 6e64 e5f2 ae80 942c 8080 8080 942f + +00:04:04:02 9420 94f2 52e5 6de9 6e64 2068 e5f2 20f7 6861 f420 ecef 76e5 20e9 73ae 942c 8080 8080 942f + +00:04:51:05 9420 94f4 aeae ae61 6e64 2c20 61e3 f4e9 ef6e a180 942c 8080 8080 942f + +00:04:55:12 9420 94e0 97a1 cde5 6def f279 20ef 76e5 f2f7 f2e9 f4e5 20e9 6e20 70f2 ef67 f2e5 7373 a180 942c 8080 8080 942f + +00:04:58:02 9420 94f2 97a2 d9ef 75a7 f2e5 2061 20ea e5f2 6b2c 2054 68ef 6da1 942c 8080 8080 942f + +00:05:01:17 9420 94f2 9723 4f68 70ad 20d3 eff2 f279 a120 d3ef f2f2 79ae 942c 8080 8080 942f + +00:05:15:05 9420 94f4 97a2 4cef ef6b 2043 e5ec e961 ae80 942c 8080 8080 942f + +00:05:16:26 9420 94e0 57e5 2068 6176 e520 f4ef 20e6 efec ecef f720 ef75 f220 7061 7373 e9ef 6e73 ae80 942c 8080 8080 942f + +00:05:19:28 9420 94e0 9723 d9ef 7520 6861 76e5 2079 ef75 f220 f2ef 62ef f4e9 e373 aeae ae80 942c 8080 8080 942f + +00:05:23:20 9420 947c 9723 aeae ae61 6e64 2049 20ea 7573 f420 f761 6ef4 20f4 ef20 62e5 2061 f7e5 73ef 6de5 20e9 6e20 7370 61e3 e5ae 942c 8080 8080 942f + +00:05:37:21 9420 94fe 4f6b 6179 2c20 f468 e579 a7f2 e520 e3ef 6de9 6e67 ae20 54f7 ef20 6de9 6e75 f4e5 7320 ece5 e6f4 a180 942c 8080 8080 942f + +00:05:42:01 9420 94f2 9723 d370 e5e5 6420 e9f4 2075 702c 2054 68ef 6da1 942c 8080 8080 942f + +00:05:44:04 9420 94f4 97a2 d6e9 7661 e3e9 7373 e96d efa1 942c 8080 8080 942f + +00:05:45:05 9420 945e 97a2 5768 7920 64ef 6ea7 f420 79ef 7520 ea75 73f4 2061 646d e9f4 20f4 6861 f420 79ef 75a7 f2e5 94e0 97a1 e6f2 e561 6be5 6420 ef75 f420 6279 206d 7920 f2ef 62ef f420 6861 6e64 bf80 942c 8080 8080 942f + +00:05:54:26 9420 94e0 97a2 4ce9 73f4 e56e 2043 e5ec e961 2c20 4920 f761 7320 79ef 756e 67ae aeae 942c 8080 8080 942f + +00:05:58:18 9420 94f4 97a1 aeae ae61 6e64 2061 2064 e9e3 6bae 942c 8080 8080 942f + +00:05:59:18 9420 9452 c275 f420 f468 61f4 a773 206e ef20 f2e5 6173 ef6e 20f4 ef80 94f2 9723 64e5 73f4 f2ef 7920 f468 e520 f7ef f2ec 64ae 942c 8080 8080 942f + +00:06:04:00 9420 94f2 97a2 5768 7920 64ef e573 2068 e520 64ef 20f4 68e9 73bf 942c 8080 8080 942f + +00:06:05:12 9420 94e0 9723 57e5 2061 ecf2 e561 6479 20f4 f2e9 e564 20f4 6861 f420 ef6e e5a1 942c 8080 8080 942f + +00:06:10:21 9420 9476 97a1 c162 eff2 f4a1 942c 8080 8080 942f + +00:06:12:07 9420 9476 97a2 4375 f4a1 942c 8080 8080 942f + +00:06:13:06 9420 9476 5768 ef61 6161 a180 942c 8080 8080 942f + +00:06:18:06 9420 9476 5768 ef61 6161 a180 942c 8080 8080 942f + +00:06:20:06 9420 9476 ceef efef efef a180 942c 8080 8080 942f + +00:06:21:29 9420 94f2 97a2 d9ef 7520 62f2 ef6b e520 6d79 2068 e561 f2f4 ae80 942c 8080 8080 942f + +00:06:25:06 9420 9476 4920 6b6e eff7 ae80 942c 8080 8080 942f + +00:06:25:28 9420 94f2 d9ef 7520 e6ef f267 eff4 206d e520 ef6e 20e5 61f2 f468 ae80 942c 8080 8080 942f + +00:06:28:06 9420 9476 4920 6b6e eff7 ae80 942c 8080 8080 942f + +00:06:29:13 9420 94f2 4920 7368 ef75 ec64 20ea 7573 f420 e3f2 7573 6820 79ef 75ae 942c 8080 8080 942f + +00:06:35:07 9420 9476 97a2 49a7 6dad 942c 8080 8080 942f + +00:06:46:03 9420 94f4 9723 49a7 6d20 73ef f2f2 79ae 942c 8080 8080 942f + +00:06:49:02 9420 94f4 97a2 c7ef ef64 2061 64ad ece9 62ae 942c 8080 8080 942f + +00:06:58:01 9420 94f4 97a1 ceef f420 6d79 20e6 6175 ecf4 a180 942c 8080 8080 942f + +00:07:01:03 9420 94f4 9723 5468 e973 20f4 e96d e5ae 942c 8080 8080 942f + +00:07:07:01 9420 94f4 97a1 5175 e9e5 f420 ef6e 2073 e5f4 a180 942c 8080 8080 942f + +00:07:08:29 9420 94f2 9723 57e5 a7f2 e520 ef75 f420 efe6 20f4 e96d e5a1 942c 8080 8080 942f + +00:08:12:03 9420 9476 43ef 6de5 20ef 6ea1 942c 8080 8080 942f + +00:08:20:29 9420 94f4 97a2 52c1 c1c1 c1c1 c1c1 c1c8 a180 942c 8080 8080 942f + +00:08:22:24 9420 94f2 97a1 cde5 6def f279 20ef 76e5 f2f7 f2e9 f4e5 2c20 b9b0 25ae 942c 8080 8080 942f + +00:08:24:22 9420 94e0 9723 4361 70f4 61e9 6ea1 2057 e520 6861 76e5 20f4 ef20 6162 eff2 f4a1 942c 8080 8080 942f + +00:08:36:20 9420 94e0 97a1 5468 e520 f7ef f2ec 64a7 7320 e368 616e 67e5 642c 2043 e5ec e961 aeae ae80 942c 8080 8080 942f + +00:08:52:24 9420 94f2 97a2 aeae ae6d 6179 62e5 20f7 e520 e361 6e20 f4ef efae 942c 8080 8080 942f + +00:08:56:21 9420 94e0 9723 cde5 6def f279 20ef 76e5 f2f7 f2e9 f4e5 20e3 ef6d 70ec e5f4 e5a1 942c 8080 8080 942f + +00:09:17:29 9420 94f4 9723 d9ef 7520 6b6e eff7 ae80 942c 8080 8080 942f + +00:09:20:13 9420 947c 9723 5468 e5f2 e5a7 7320 6120 ece5 7373 ef6e 20f4 ef20 62e5 20ec e561 f26e e564 20e6 f2ef 6d20 f468 e973 ae80 942c 8080 8080 942f + +00:09:24:24 9420 94f2 97a2 43ef 75ec 64a7 6120 67ef 6ee5 20f7 eff2 73e5 ae80 942c 8080 8080 942f +
View file
obs-studio-0.16.6.tar.xz/deps/libff/libff/ff-demuxer.c -> obs-studio-0.17.0.tar.xz/deps/libff/libff/ff-demuxer.c
Changed
@@ -377,7 +377,7 @@ } if (avformat_open_input(format_context, demuxer->input, - input_format, NULL) != 0) + input_format, &demuxer->options.custom_options) != 0) return false; return avformat_find_stream_info(*format_context, NULL) >= 0;
View file
obs-studio-0.16.6.tar.xz/deps/libff/libff/ff-demuxer.h -> obs-studio-0.17.0.tar.xz/deps/libff/libff/ff-demuxer.h
Changed
@@ -40,6 +40,7 @@ bool is_hw_decoding; bool is_looping; enum AVDiscard frame_drop; + AVDictionary *custom_options; }; typedef struct ff_demuxer_options ff_demuxer_options_t;
View file
obs-studio-0.16.6.tar.xz/libobs-d3d11/d3d11-rebuild.cpp -> obs-studio-0.17.0.tar.xz/libobs-d3d11/d3d11-rebuild.cpp
Changed
@@ -31,15 +31,43 @@ throw HRError("Failed to create buffer", hr); } +void gs_texture_2d::RebuildSharedTextureFallback() +{ + td = {}; + td.Width = 2; + td.Height = 2; + td.MipLevels = 1; + td.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + td.ArraySize = 1; + td.SampleDesc.Count = 1; + + width = td.Width; + height = td.Height; + dxgiFormat = td.Format; + levels = 1; + + resourceDesc = {}; + resourceDesc.Format = td.Format; + resourceDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceDesc.Texture2D.MipLevels = 1; + + isShared = false; +} + inline void gs_texture_2d::Rebuild(ID3D11Device *dev) { HRESULT hr; if (isShared) { hr = dev->OpenSharedResource((HANDLE)(uintptr_t)sharedHandle, __uuidof(ID3D11Texture2D), (void**)&texture); - if (FAILED(hr)) - throw HRError("Failed to open shared 2D texture", hr); - } else { + if (FAILED(hr)) { + blog(LOG_WARNING, "Failed to rebuild shared texture: ", + "0x%08lX", hr); + RebuildSharedTextureFallback(); + } + } + + if (!isShared) { hr = dev->CreateTexture2D(&td, data.size() ? srd.data() : nullptr, &texture);
View file
obs-studio-0.16.6.tar.xz/libobs-d3d11/d3d11-shader.cpp -> obs-studio-0.17.0.tar.xz/libobs-d3d11/d3d11-shader.cpp
Changed
@@ -201,6 +201,22 @@ else throw HRError("Failed to compile shader", hr); } + +#ifdef DISASSEMBLE_SHADERS + ComPtr<ID3D10Blob> asmBlob; + + if (!device->d3dDisassemble) + return; + + hr = device->d3dDisassemble((*shader)->GetBufferPointer(), + (*shader)->GetBufferSize(), 0, nullptr, &asmBlob); + + if (SUCCEEDED(hr) && !!asmBlob && asmBlob->GetBufferSize()) { + blog(LOG_INFO, "============================================="); + blog(LOG_INFO, "Disassembly output for shader '%s':\n%s", + file, asmBlob->GetBufferPointer()); + } +#endif } inline void gs_shader::UpdateParam(vector<uint8_t> &constData,
View file
obs-studio-0.16.6.tar.xz/libobs-d3d11/d3d11-subsystem.cpp -> obs-studio-0.17.0.tar.xz/libobs-d3d11/d3d11-subsystem.cpp
Changed
@@ -181,6 +181,11 @@ if (module) { d3dCompile = (pD3DCompile)GetProcAddress(module, "D3DCompile"); + +#ifdef DISASSEMBLE_SHADERS + d3dDisassemble = (pD3DDisassemble)GetProcAddress( + module, "D3DDisassemble"); +#endif if (d3dCompile) { return; }
View file
obs-studio-0.16.6.tar.xz/libobs-d3d11/d3d11-subsystem.hpp -> obs-studio-0.17.0.tar.xz/libobs-d3d11/d3d11-subsystem.hpp
Changed
@@ -37,6 +37,8 @@ #include <util/windows/ComPtr.hpp> #include <util/windows/HRError.hpp> +// #define DISASSEMBLE_SHADERS + struct shader_var; struct shader_sampler; struct gs_vertex_shader; @@ -360,6 +362,7 @@ void InitRenderTargets(); void BackupTexture(const uint8_t **data); + void RebuildSharedTextureFallback(); inline void Rebuild(ID3D11Device *dev); inline void Release() @@ -801,6 +804,9 @@ D3D11_PRIMITIVE_TOPOLOGY curToplogy; pD3DCompile d3dCompile = nullptr; +#ifdef DISASSEMBLE_SHADERS + pD3DDisassemble d3dDisassemble = nullptr; +#endif gs_rect viewport;
View file
obs-studio-0.16.6.tar.xz/libobs-opengl/gl-x11.c -> obs-studio-0.17.0.tar.xz/libobs-opengl/gl-x11.c
Changed
@@ -587,7 +587,12 @@ initialized = true; } - /* TODO: Handle XCB events. */ + xcb_connection_t *xcb_conn = XGetXCBConnection(display); + xcb_generic_event_t *xcb_event; + while((xcb_event = xcb_poll_for_event(xcb_conn))) { + /* TODO: Handle XCB events. */ + free(xcb_event); + } switch (swap_type) { case SWAP_TYPE_EXT: glXSwapIntervalEXT(display, window, 0); break;
View file
obs-studio-0.16.6.tar.xz/libobs/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/libobs/CMakeLists.txt
Changed
@@ -347,6 +347,12 @@ source_group("util\\Source Files" FILES ${libobs_util_SOURCES}) source_group("util\\Header Files" FILES ${libobs_util_HEADERS}) +if(BUILD_CAPTIONS) + include_directories(${CMAKE_SOURCE_DIR}/deps/libcaption) + set(libobs_PLATFORM_DEPS + ${libobs_PLATFORM_DEPS} + caption) +endif() add_library(libobs SHARED ${libobs_SOURCES} ${libobs_HEADERS})
View file
obs-studio-0.16.6.tar.xz/libobs/graphics/vec2.h -> obs-studio-0.17.0.tar.xz/libobs/graphics/vec2.h
Changed
@@ -106,7 +106,7 @@ static inline float vec2_dot(const struct vec2 *v1, const struct vec2 *v2) { - return (v1->x+v2->x) * (v1->y+v2->y); + return v1->x*v2->x + v1->y*v2->y; } static inline float vec2_len(const struct vec2 *v)
View file
obs-studio-0.16.6.tar.xz/libobs/media-io/audio-io.h -> obs-studio-0.17.0.tar.xz/libobs/media-io/audio-io.h
Changed
@@ -25,7 +25,7 @@ extern "C" { #endif -#define MAX_AUDIO_MIXES 4 +#define MAX_AUDIO_MIXES 6 #define MAX_AUDIO_CHANNELS 2 #define AUDIO_OUTPUT_FRAMES 1024
View file
obs-studio-0.16.6.tar.xz/libobs/obs-avc.c -> obs-studio-0.17.0.tar.xz/libobs/obs-avc.c
Changed
@@ -132,15 +132,17 @@ { struct array_output_data output; struct serializer s; + long ref = 1; array_output_serializer_init(&s, &output); *avc_packet = *src; + serialize(&s, &ref, sizeof(ref)); serialize_avc_data(&s, src->data, src->size, &avc_packet->keyframe, &avc_packet->priority); - avc_packet->data = output.bytes.array; - avc_packet->size = output.bytes.num; + avc_packet->data = output.bytes.array + sizeof(ref); + avc_packet->size = output.bytes.num - sizeof(ref); avc_packet->drop_priority = get_drop_priority(avc_packet->priority); }
View file
obs-studio-0.16.6.tar.xz/libobs/obs-config.h -> obs-studio-0.17.0.tar.xz/libobs/obs-config.h
Changed
@@ -27,21 +27,21 @@ /* * Increment if major breaking API changes */ -#define LIBOBS_API_MAJOR_VER 0 /* 0 means development, anything can break */ +#define LIBOBS_API_MAJOR_VER 17 /* * Increment if backward-compatible additions * * Reset to zero each major version */ -#define LIBOBS_API_MINOR_VER 16 +#define LIBOBS_API_MINOR_VER 0 /* * Increment if backward-compatible bug fix * * Reset to zero each major or minor version */ -#define LIBOBS_API_PATCH_VER 6 +#define LIBOBS_API_PATCH_VER 0 #define MAKE_SEMANTIC_VERSION(major, minor, patch) \ ((major << 24) | \
View file
obs-studio-0.16.6.tar.xz/libobs/obs-display.c -> obs-studio-0.17.0.tar.xz/libobs/obs-display.c
Changed
@@ -23,6 +23,7 @@ const struct gs_init_data *graphics_data) { pthread_mutex_init_value(&display->draw_callbacks_mutex); + pthread_mutex_init_value(&display->draw_info_mutex); if (graphics_data) { display->swap = gs_swapchain_create(graphics_data); @@ -40,6 +41,10 @@ blog(LOG_ERROR, "obs_display_init: Failed to create mutex"); return false; } + if (pthread_mutex_init(&display->draw_info_mutex, NULL) != 0) { + blog(LOG_ERROR, "obs_display_init: Failed to create mutex"); + return false; + } display->background_color = 0x4C4C4C; display->enabled = true; @@ -73,6 +78,7 @@ void obs_display_free(obs_display_t *display) { pthread_mutex_destroy(&display->draw_callbacks_mutex); + pthread_mutex_destroy(&display->draw_info_mutex); da_free(display->draw_callbacks); if (display->swap) { @@ -103,13 +109,13 @@ { if (!display) return; - pthread_mutex_lock(&display->draw_callbacks_mutex); + pthread_mutex_lock(&display->draw_info_mutex); display->cx = cx; display->cy = cy; display->size_changed = true; - pthread_mutex_unlock(&display->draw_callbacks_mutex); + pthread_mutex_unlock(&display->draw_info_mutex); } void obs_display_add_draw_callback(obs_display_t *display, @@ -138,16 +144,15 @@ pthread_mutex_unlock(&display->draw_callbacks_mutex); } -static inline void render_display_begin(struct obs_display *display) +static inline void render_display_begin(struct obs_display *display, + uint32_t cx, uint32_t cy, bool size_changed) { struct vec4 clear_color; gs_load_swapchain(display ? display->swap : NULL); - if (display->size_changed) { - gs_resize(display->cx, display->cy); - display->size_changed = false; - } + if (size_changed) + gs_resize(cx, cy); gs_begin_scene(); @@ -161,9 +166,8 @@ /* gs_enable_blending(false); */ gs_set_cull_mode(GS_NEITHER); - gs_ortho(0.0f, (float)display->cx, - 0.0f, (float)display->cy, -100.0f, 100.0f); - gs_set_viewport(0, 0, display->cx, display->cy); + gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f); + gs_set_viewport(0, 0, cx, cy); } static inline void render_display_end() @@ -174,9 +178,27 @@ void render_display(struct obs_display *display) { + uint32_t cx, cy; + bool size_changed; + if (!display || !display->enabled) return; - render_display_begin(display); + /* -------------------------------------------- */ + + pthread_mutex_lock(&display->draw_info_mutex); + + cx = display->cx; + cy = display->cy; + size_changed = display->size_changed; + + if (size_changed) + display->size_changed = false; + + pthread_mutex_unlock(&display->draw_info_mutex); + + /* -------------------------------------------- */ + + render_display_begin(display, cx, cy, size_changed); pthread_mutex_lock(&display->draw_callbacks_mutex); @@ -184,7 +206,7 @@ struct draw_callback *callback; callback = display->draw_callbacks.array+i; - callback->draw(callback->param, display->cx, display->cy); + callback->draw(callback->param, cx, cy); } pthread_mutex_unlock(&display->draw_callbacks_mutex);
View file
obs-studio-0.16.6.tar.xz/libobs/obs-encoder.c -> obs-studio-0.17.0.tar.xz/libobs/obs-encoder.c
Changed
@@ -1035,17 +1035,55 @@ pthread_mutex_unlock(&encoder->outputs_mutex); } -void obs_duplicate_encoder_packet(struct encoder_packet *dst, +void obs_encoder_packet_create_instance(struct encoder_packet *dst, const struct encoder_packet *src) { + long *p_refs; + *dst = *src; - dst->data = bmemdup(src->data, src->size); + p_refs = bmalloc(src->size + sizeof(long)); + dst->data = (void*)(p_refs + 1); + *p_refs = 1; + memcpy(dst->data, src->data, src->size); +} + +void obs_duplicate_encoder_packet(struct encoder_packet *dst, + const struct encoder_packet *src) +{ + obs_encoder_packet_create_instance(dst, src); } void obs_free_encoder_packet(struct encoder_packet *packet) { - bfree(packet->data); - memset(packet, 0, sizeof(struct encoder_packet)); + obs_encoder_packet_release(packet); +} + +void obs_encoder_packet_ref(struct encoder_packet *dst, + struct encoder_packet *src) +{ + if (!src) + return; + + if (src->data) { + long *p_refs = ((long*)src->data) - 1; + os_atomic_inc_long(p_refs); + } + + *dst = *src; +} + +void obs_encoder_packet_release(struct encoder_packet *pkt) +{ + if (!pkt) + return; + + if (pkt->data) { + long *p_refs = ((long*)pkt->data) - 1; + if (os_atomic_dec_long(p_refs) == 0) + bfree(p_refs); + } + + memset(pkt, 0, sizeof(struct encoder_packet)); } void obs_encoder_set_preferred_video_format(obs_encoder_t *encoder,
View file
obs-studio-0.16.6.tar.xz/libobs/obs-internal.h -> obs-studio-0.17.0.tar.xz/libobs/obs-internal.h
Changed
@@ -199,6 +199,7 @@ uint32_t background_color; gs_swapchain_t *swap; pthread_mutex_t draw_callbacks_mutex; + pthread_mutex_t draw_info_mutex; DARRAY(struct draw_callback) draw_callbacks; struct obs_display *next; @@ -718,8 +719,6 @@ return GS_RGBA; else if (format == VIDEO_FORMAT_BGRA) return GS_BGRA; - else if (format == VIDEO_FORMAT_Y800) - return GS_R8; return GS_BGRX; } @@ -774,6 +773,13 @@ struct obs_output *output; }; +#define CAPTION_LINE_CHARS (32) +#define CAPTION_LINE_BYTES (4*CAPTION_LINE_CHARS) +struct caption_text { + char text[CAPTION_LINE_BYTES+1]; + struct caption_text *next; +}; + struct obs_output { struct obs_context_data context; struct obs_output_info info; @@ -828,6 +834,11 @@ struct video_scale_info video_conversion; struct audio_convert_info audio_conversion; + pthread_mutex_t caption_mutex; + double caption_timestamp; + struct caption_text *caption_head; + struct caption_text *caption_tail; + bool valid; uint64_t active_delay_ns; @@ -864,6 +875,8 @@ extern void obs_output_remove_encoder(struct obs_output *output, struct obs_encoder *encoder); +extern void obs_encoder_packet_create_instance(struct encoder_packet *dst, + const struct encoder_packet *src); void obs_output_destroy(obs_output_t *output);
View file
obs-studio-0.16.6.tar.xz/libobs/obs-output-delay.c -> obs-studio-0.17.0.tar.xz/libobs/obs-output-delay.c
Changed
@@ -35,7 +35,7 @@ dd.msg = DELAY_MSG_PACKET; dd.ts = t; - obs_duplicate_encoder_packet(&dd.packet, packet); + obs_encoder_packet_create_instance(&dd.packet, packet); pthread_mutex_lock(&output->delay_mutex); circlebuf_push_back(&output->delay_data, &dd, sizeof(dd)); @@ -48,7 +48,7 @@ switch (dd->msg) { case DELAY_MSG_PACKET: if (!delay_active(output) || !delay_capturing(output)) - obs_free_encoder_packet(&dd->packet); + obs_encoder_packet_release(&dd->packet); else output->delay_callback(output, &dd->packet); break; @@ -68,7 +68,7 @@ while (output->delay_data.size) { circlebuf_pop_front(&output->delay_data, &dd, sizeof(dd)); if (dd.msg == DELAY_MSG_PACKET) { - obs_free_encoder_packet(&dd.packet); + obs_encoder_packet_release(&dd.packet); } }
View file
obs-studio-0.16.6.tar.xz/libobs/obs-output.c -> obs-studio-0.17.0.tar.xz/libobs/obs-output.c
Changed
@@ -20,6 +20,11 @@ #include "obs.h" #include "obs-internal.h" +#if BUILD_CAPTIONS +#include <caption/caption.h> +#include <caption/avc.h> +#endif + static inline bool active(const struct obs_output *output) { return os_atomic_load_bool(&output->active); @@ -99,11 +104,14 @@ output = bzalloc(sizeof(struct obs_output)); pthread_mutex_init_value(&output->interleaved_mutex); pthread_mutex_init_value(&output->delay_mutex); + pthread_mutex_init_value(&output->caption_mutex); if (pthread_mutex_init(&output->interleaved_mutex, NULL) != 0) goto fail; if (pthread_mutex_init(&output->delay_mutex, NULL) != 0) goto fail; + if (pthread_mutex_init(&output->caption_mutex, NULL) != 0) + goto fail; if (os_event_init(&output->stopping_event, OS_EVENT_TYPE_MANUAL) != 0) goto fail; if (!init_output_handlers(output, name, settings, hotkey_data)) @@ -129,12 +137,6 @@ if (ret < 0) goto fail; - if (info) - output->context.data = info->create(output->context.settings, - output); - if (!output->context.data) - blog(LOG_ERROR, "Failed to create output '%s'!", name); - output->reconnect_retry_sec = 2; output->reconnect_retry_max = 20; output->valid = true; @@ -146,6 +148,12 @@ &obs->data.outputs_mutex, &obs->data.first_output); + if (info) + output->context.data = info->create(output->context.settings, + output); + if (!output->context.data) + blog(LOG_ERROR, "Failed to create output '%s'!", name); + blog(LOG_DEBUG, "output '%s' (%s) created", name, id); return output; @@ -157,7 +165,7 @@ static inline void free_packets(struct obs_output *output) { for (size_t i = 0; i < output->interleaved_packets.num; i++) - obs_free_encoder_packet(output->interleaved_packets.array+i); + obs_encoder_packet_release(output->interleaved_packets.array+i); da_free(output->interleaved_packets); } @@ -196,6 +204,7 @@ } os_event_destroy(output->stopping_event); + pthread_mutex_destroy(&output->caption_mutex); pthread_mutex_destroy(&output->interleaved_mutex); pthread_mutex_destroy(&output->delay_mutex); os_event_destroy(output->reconnect_stop_event); @@ -235,6 +244,7 @@ if (os_atomic_load_long(&output->delay_restart_refs)) os_atomic_dec_long(&output->delay_restart_refs); + output->caption_timestamp = 0; return success; } @@ -356,6 +366,12 @@ signal_stop(output); os_event_signal(output->stopping_event); } + + while (output->caption_head) { + output->caption_tail = output->caption_head->next; + bfree(output->caption_head); + output->caption_head = output->caption_tail; + } } void obs_output_stop(obs_output_t *output) @@ -942,6 +958,56 @@ return output->highest_video_ts > packet->dts_usec; } +#if BUILD_CAPTIONS +static const uint8_t nal_start[4] = {0, 0, 0, 1}; + +static bool add_caption(struct obs_output *output, struct encoder_packet *out) +{ + struct encoder_packet backup = *out; + caption_frame_t cf; + sei_t sei; + uint8_t *data; + size_t size; + long ref = 1; + + DARRAY(uint8_t) out_data; + + if (out->priority > 1) + return false; + + sei_init(&sei); + + da_init(out_data); + da_push_back_array(out_data, &ref, sizeof(ref)); + da_push_back_array(out_data, out->data, out->size); + + caption_frame_init(&cf); + caption_frame_from_text(&cf, &output->caption_head->text[0]); + + sei_from_caption_frame(&sei, &cf); + + data = malloc(sei_render_size(&sei)); + size = sei_render(&sei, data); + /* TODO SEI should come after AUD/SPS/PPS, but before any VCL */ + da_push_back_array(out_data, nal_start, 4); + da_push_back_array(out_data, data, size); + free(data); + + obs_encoder_packet_release(out); + + *out = backup; + out->data = (uint8_t*)out_data.array + sizeof(ref); + out->size = out_data.num - sizeof(ref); + + sei_free(&sei); + + struct caption_text *next = output->caption_head->next; + bfree(output->caption_head); + output->caption_head = next; + return true; +} +#endif + static inline void send_interleaved(struct obs_output *output) { struct encoder_packet out = output->interleaved_packets.array[0]; @@ -952,12 +1018,37 @@ if (!has_higher_opposing_ts(output, &out)) return; - if (out.type == OBS_ENCODER_VIDEO) + da_erase(output->interleaved_packets, 0); + + if (out.type == OBS_ENCODER_VIDEO) { output->total_frames++; - da_erase(output->interleaved_packets, 0); +#if BUILD_CAPTIONS + pthread_mutex_lock(&output->caption_mutex); + + double frame_timestamp = (out.pts * out.timebase_num) / + (double)out.timebase_den; + + /* TODO if output->caption_timestamp is more than 5 seconds + * old, send empty frame */ + if (output->caption_head && + output->caption_timestamp <= frame_timestamp) { + blog(LOG_INFO,"Sending caption: %f \"%s\"", + frame_timestamp, + &output->caption_head->text[0]); + + if (add_caption(output, &out)) { + output->caption_timestamp = + frame_timestamp + 2.0; + } + } + + pthread_mutex_unlock(&output->caption_mutex); +#endif + } + output->info.encoded_packet(output->context.data, &out); - obs_free_encoder_packet(&out); + obs_encoder_packet_release(&out); } static inline void set_higher_ts(struct obs_output *output, @@ -1056,7 +1147,7 @@ for (size_t i = 0; i < idx; i++) { struct encoder_packet *packet = &output->interleaved_packets.array[i]; - obs_free_encoder_packet(packet); + obs_encoder_packet_release(packet); } da_erase_range(output->interleaved_packets, 0, idx); @@ -1304,7 +1395,7 @@ pthread_mutex_unlock(&output->interleaved_mutex); if (output->active_delay_ns) - obs_free_encoder_packet(packet); + obs_encoder_packet_release(packet); return; } @@ -1313,7 +1404,7 @@ if (output->active_delay_ns) out = *packet; else - obs_duplicate_encoder_packet(&out, packet); + obs_encoder_packet_create_instance(&out, packet); if (was_started) apply_interleaved_packet_offset(output, &out); @@ -1356,7 +1447,7 @@ } if (output->active_delay_ns) - obs_free_encoder_packet(packet); + obs_encoder_packet_release(packet); } static void default_raw_video_callback(void *param, struct video_data *frame) @@ -1954,3 +2045,61 @@ return obs_output_valid(output, "obs_output_get_id") ? output->info.id : NULL; } + +#if BUILD_CAPTIONS +static struct caption_text *caption_text_new(const char *text, size_t bytes, + struct caption_text *tail, struct caption_text **head) +{ + struct caption_text *next = bzalloc(sizeof(struct caption_text)); + snprintf(&next->text[0], CAPTION_LINE_BYTES + 1, "%.*s", bytes, text); + + if (!*head) { + *head = next; + } else { + tail->next = next; + } + + return next; +} + +void obs_output_output_caption_text1(obs_output_t *output, const char *text) +{ + if (!obs_output_valid(output, "obs_output_output_caption_text1")) + return; + if (!active(output)) + return; + + // split text into 32 charcter strings + int size = (int)strlen(text); + int r; + size_t char_count; + size_t line_length = 0; + size_t trimmed_length = 0; + + blog(LOG_DEBUG, "Caption text: %s", text); + + pthread_mutex_lock(&output->caption_mutex); + + for (r = 0 ; 0 < size && CAPTION_LINE_CHARS > r; ++r) { + line_length = utf8_line_length(text); + trimmed_length = utf8_trimmed_length(text, line_length); + char_count = utf8_char_count(text, trimmed_length); + + if (SCREEN_COLS < char_count) { + char_count = utf8_wrap_length(text, CAPTION_LINE_CHARS); + line_length = utf8_string_length(text, char_count + 1); + } + + output->caption_tail = caption_text_new( + text, + line_length, + output->caption_tail, + &output->caption_head); + + text += line_length; + size -= (int)line_length; + } + + pthread_mutex_unlock(&output->caption_mutex); +} +#endif
View file
obs-studio-0.16.6.tar.xz/libobs/obs-scene.c -> obs-studio-0.17.0.tar.xz/libobs/obs-scene.c
Changed
@@ -741,11 +741,13 @@ bool cur_visible = item->visible; uint64_t frame_num = 0; size_t deref_count = 0; - float *buf; + float *buf = NULL; - if (!*p_buf) - *p_buf = malloc(AUDIO_OUTPUT_FRAMES * sizeof(float)); - buf = *p_buf; + if (p_buf) { + if (!*p_buf) + *p_buf = malloc(AUDIO_OUTPUT_FRAMES * sizeof(float)); + buf = *p_buf; + } pthread_mutex_lock(&item->actions_mutex); @@ -760,7 +762,7 @@ new_frame_num = (timestamp - ts) * (uint64_t)sample_rate / 1000000000ULL; - if (new_frame_num >= AUDIO_OUTPUT_FRAMES) + if (ts && new_frame_num >= AUDIO_OUTPUT_FRAMES) break; da_erase(item->audio_actions, i--); @@ -769,7 +771,7 @@ if (!item->visible) deref_count++; - if (new_frame_num > frame_num) { + if (buf && new_frame_num > frame_num) { for (; frame_num < new_frame_num; frame_num++) buf[frame_num] = cur_visible ? 1.0f : 0.0f; } @@ -777,8 +779,10 @@ cur_visible = item->visible; } - for (; frame_num < AUDIO_OUTPUT_FRAMES; frame_num++) - buf[frame_num] = cur_visible ? 1.0f : 0.0f; + if (buf) { + for (; frame_num < AUDIO_OUTPUT_FRAMES; frame_num++) + buf[frame_num] = cur_visible ? 1.0f : 0.0f; + } pthread_mutex_unlock(&item->actions_mutex); @@ -790,7 +794,7 @@ } } -static inline bool apply_scene_item_volume(struct obs_scene_item *item, +static bool apply_scene_item_volume(struct obs_scene_item *item, float **buf, uint64_t ts, size_t sample_rate) { bool actions_pending; @@ -808,7 +812,7 @@ uint64_t duration = (uint64_t)AUDIO_OUTPUT_FRAMES * 1000000000ULL / (uint64_t)sample_rate; - if (action.timestamp < (ts + duration)) { + if (!ts || action.timestamp < (ts + duration)) { apply_scene_item_audio_actions(item, buf, ts, sample_rate); return true; @@ -818,6 +822,12 @@ return false; } +static void process_all_audio_actions(struct obs_scene_item *item, + size_t sample_rate) +{ + while (apply_scene_item_volume(item, NULL, 0, sample_rate)); +} + static void mix_audio_with_buf(float *p_out, float *p_in, float *buf_in, size_t pos, size_t count) { @@ -867,6 +877,14 @@ } if (!timestamp) { + /* just process all pending audio actions if no audio playing, + * otherwise audio actions will just never be processed */ + item = scene->first_item; + while (item) { + process_all_audio_actions(item, sample_rate); + item = item->next; + } + audio_unlock(scene); return false; }
View file
obs-studio-0.16.6.tar.xz/libobs/obs-source.c -> obs-studio-0.17.0.tar.xz/libobs/obs-source.c
Changed
@@ -174,7 +174,7 @@ source->control = bzalloc(sizeof(obs_weak_source_t)); source->deinterlace_top_first = true; source->control->source = source; - source->audio_mixers = 0xF; + source->audio_mixers = 0xFF; if (is_audio_source(source)) { pthread_mutex_lock(&obs->data.audio_sources_mutex); @@ -2098,6 +2098,41 @@ dst->linesize[plane] * lines); } +static void copy_frame_data_line_y800(uint32_t *dst, uint8_t *src, uint8_t *end) +{ + while (src < end) { + register uint32_t val = *(src++); + val |= (val << 8); + val |= (val << 16); + *(dst++) = val; + } +} + +static inline void copy_frame_data_y800(struct obs_source_frame *dst, + const struct obs_source_frame *src) +{ + uint32_t *ptr_dst; + uint8_t *ptr_src; + uint8_t *src_end; + + if ((src->linesize[0] * 4) != dst->linesize[0]) { + for (uint32_t cy = 0; cy < src->height; cy++) { + ptr_dst = (uint32_t*) + (dst->data[0] + cy * dst->linesize[0]); + ptr_src = (src->data[0] + cy * src->linesize[0]); + src_end = ptr_src + src->width; + + copy_frame_data_line_y800(ptr_dst, ptr_src, src_end); + } + } else { + ptr_dst = (uint32_t*)dst->data[0]; + ptr_src = (uint8_t *)src->data[0]; + src_end = ptr_src + src->height * src->linesize[0]; + + copy_frame_data_line_y800(ptr_dst, ptr_src, src_end); + } +} + static void copy_frame_data(struct obs_source_frame *dst, const struct obs_source_frame *src) { @@ -2111,7 +2146,7 @@ memcpy(dst->color_range_max, src->color_range_max, size); } - switch (dst->format) { + switch (src->format) { case VIDEO_FORMAT_I420: copy_frame_data_plane(dst, src, 0, dst->height); copy_frame_data_plane(dst, src, 1, dst->height/2); @@ -2132,12 +2167,16 @@ case VIDEO_FORMAT_YVYU: case VIDEO_FORMAT_YUY2: case VIDEO_FORMAT_UYVY: - case VIDEO_FORMAT_Y800: case VIDEO_FORMAT_NONE: case VIDEO_FORMAT_RGBA: case VIDEO_FORMAT_BGRA: case VIDEO_FORMAT_BGRX: copy_frame_data_plane(dst, src, 0, dst->height); + break; + + case VIDEO_FORMAT_Y800: + copy_frame_data_y800(dst, src); + break; } } @@ -2218,8 +2257,12 @@ if (!new_frame) { struct async_frame new_af; + enum video_format format = frame->format; + + if (format == VIDEO_FORMAT_Y800) + format = VIDEO_FORMAT_BGRX; - new_frame = obs_source_frame_create(frame->format, + new_frame = obs_source_frame_create(format, frame->width, frame->height); new_af.frame = new_frame; new_af.used = true;
View file
obs-studio-0.16.6.tar.xz/libobs/obs.h -> obs-studio-0.17.0.tar.xz/libobs/obs.h
Changed
@@ -533,8 +533,8 @@ EXPORT gs_effect_t *obs_get_base_effect(enum obs_base_effect effect); /* DEPRECATED: gets texture_rect default effect */ -DEPRECATED_START EXPORT gs_effect_t *obs_get_default_rect_effect(void) - DEPRECATED_END; +DEPRECATED +EXPORT gs_effect_t *obs_get_default_rect_effect(void); /** Returns the primary obs signal handler */ EXPORT signal_handler_t *obs_get_signal_handler(void); @@ -1460,6 +1460,11 @@ EXPORT const char *obs_output_get_id(const obs_output_t *output); +#if BUILD_CAPTIONS +EXPORT void obs_output_output_caption_text1(obs_output_t *output, + const char *text); +#endif + /* ------------------------------------------------------------------------- */ /* Functions used by outputs */ @@ -1651,11 +1656,17 @@ EXPORT uint32_t obs_get_encoder_caps(const char *encoder_id); /** Duplicates an encoder packet */ +DEPRECATED EXPORT void obs_duplicate_encoder_packet(struct encoder_packet *dst, const struct encoder_packet *src); +DEPRECATED EXPORT void obs_free_encoder_packet(struct encoder_packet *packet); +EXPORT void obs_encoder_packet_ref(struct encoder_packet *dst, + struct encoder_packet *src); +EXPORT void obs_encoder_packet_release(struct encoder_packet *packet); + /* ------------------------------------------------------------------------- */ /* Stream Services */
View file
obs-studio-0.16.6.tar.xz/libobs/obsconfig.h.in -> obs-studio-0.17.0.tar.xz/libobs/obsconfig.h.in
Changed
@@ -1,10 +1,19 @@ #pragma once +#ifndef ON +#define ON 1 +#endif + +#ifndef OFF +#define OFF 0 +#endif + #define OBS_VERSION "@OBS_VERSION@" #define OBS_DATA_PATH "@OBS_DATA_PATH@" #define OBS_INSTALL_PREFIX "@OBS_INSTALL_PREFIX@" #define OBS_PLUGIN_DESTINATION "@OBS_PLUGIN_DESTINATION@" #define OBS_RELATIVE_PREFIX "@OBS_RELATIVE_PREFIX@" #define OBS_UNIX_STRUCTURE @OBS_UNIX_STRUCTURE@ +#define BUILD_CAPTIONS @BUILD_CAPTIONS@ #define HAVE_DBUS @HAVE_DBUS@
View file
obs-studio-0.16.6.tar.xz/libobs/util/c99defs.h -> obs-studio-0.17.0.tar.xz/libobs/util/c99defs.h
Changed
@@ -24,19 +24,15 @@ #define UNUSED_PARAMETER(param) (void)param #ifdef _MSC_VER -#define DEPRECATED_START __declspec(deprecated) -#define DEPRECATED_END +#define DEPRECATED __declspec(deprecated) #define FORCE_INLINE __forceinline #else -#define DEPRECATED_START -#define DEPRECATED_END __attribute__ ((deprecated)) +#define DEPRECATED __attribute__ ((deprecated)) #define FORCE_INLINE inline __attribute__((always_inline)) #endif #ifdef _MSC_VER -#pragma warning (disable : 4996) - /* Microsoft is one of the most inept companies on the face of the planet. * The fact that even visual studio 2013 doesn't support the standard 'inline' * keyword is so incredibly stupid that I just can't imagine what sort of
View file
obs-studio-0.16.6.tar.xz/libobs/util/circlebuf.h -> obs-studio-0.17.0.tar.xz/libobs/util/circlebuf.h
Changed
@@ -254,6 +254,20 @@ cb->end_pos -= size; } +static inline void *circlebuf_data(struct circlebuf *cb, size_t idx) +{ + uint8_t *ptr = (uint8_t*)cb->data; + size_t offset = cb->start_pos + idx; + + if (idx > cb->size) + return NULL; + + if (offset >= cb->capacity) + offset -= cb->capacity; + + return ptr + offset; +} + #ifdef __cplusplus } #endif
View file
obs-studio-0.16.6.tar.xz/libobs/util/platform.c -> obs-studio-0.17.0.tar.xz/libobs/util/platform.c
Changed
@@ -16,6 +16,7 @@ #define _FILE_OFFSET_BITS 64 +#include <time.h> #include <errno.h> #include <stdlib.h> #include <locale.h> @@ -657,3 +658,123 @@ return path + pos; } + +static inline bool valid_string(const char *str) +{ + while (str && *str) { + if (*(str++) != ' ') + return true; + } + + return false; +} + +static void replace_text(struct dstr *str, size_t pos, size_t len, + const char *new_text) +{ + struct dstr front = {0}; + struct dstr back = {0}; + + dstr_left(&front, str, pos); + dstr_right(&back, str, pos + len); + dstr_copy_dstr(str, &front); + dstr_cat(str, new_text); + dstr_cat_dstr(str, &back); + dstr_free(&front); + dstr_free(&back); +} + +static void erase_ch(struct dstr *str, size_t pos) +{ + struct dstr new_str = {0}; + dstr_left(&new_str, str, pos); + dstr_cat(&new_str, str->array + pos + 1); + dstr_free(str); + *str = new_str; +} + +char *os_generate_formatted_filename(const char *extension, bool space, + const char *format) +{ + time_t now = time(0); + struct tm *cur_time; + cur_time = localtime(&now); + + const size_t spec_count = 23; + static const char *spec[][2] = { + {"%CCYY", "%Y"}, + {"%YY", "%y"}, + {"%MM", "%m"}, + {"%DD", "%d"}, + {"%hh", "%H"}, + {"%mm", "%M"}, + {"%ss", "%S"}, + {"%%", "%%"}, + + {"%a", ""}, + {"%A", ""}, + {"%b", ""}, + {"%B", ""}, + {"%d", ""}, + {"%H", ""}, + {"%I", ""}, + {"%m", ""}, + {"%M", ""}, + {"%p", ""}, + {"%S", ""}, + {"%y", ""}, + {"%Y", ""}, + {"%z", ""}, + {"%Z", ""}, + }; + + char convert[128] = {0}; + struct dstr sf; + struct dstr c = {0}; + size_t pos = 0; + + dstr_init_copy(&sf, format); + + while (pos < sf.len) { + for (size_t i = 0; i < spec_count && !convert[0]; i++) { + size_t len = strlen(spec[i][0]); + + const char *cmp = sf.array + pos; + + if (astrcmp_n(cmp, spec[i][0], len) == 0) { + if (strlen(spec[i][1])) + strftime(convert, sizeof(convert), + spec[i][1], cur_time); + else + strftime(convert, sizeof(convert), + spec[i][0], cur_time); + + + dstr_copy(&c, convert); + if (c.len && valid_string(c.array)) + replace_text(&sf, pos, len, convert); + } + } + + if (convert[0]) { + pos += strlen(convert); + convert[0] = 0; + } else if (!convert[0] && sf.array[pos] == '%') { + erase_ch(&sf, pos); + } else { + pos++; + } + } + + if (!space) + dstr_replace(&sf, " ", "_"); + + dstr_cat_ch(&sf, '.'); + dstr_cat(&sf, extension); + dstr_free(&c); + + if (sf.len > 255) + dstr_mid(&sf, &sf, 0, 255); + + return sf.array; +}
View file
obs-studio-0.16.6.tar.xz/libobs/util/platform.h -> obs-studio-0.17.0.tar.xz/libobs/util/platform.h
Changed
@@ -162,6 +162,9 @@ EXPORT int os_rename(const char *old_path, const char *new_path); EXPORT int os_copyfile(const char *file_in, const char *file_out); +EXPORT char *os_generate_formatted_filename(const char *extension, bool space, + const char *format); + struct os_inhibit_info; typedef struct os_inhibit_info os_inhibit_t;
View file
obs-studio-0.16.6.tar.xz/plugins/decklink/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/decklink/data/locale/tr-TR.ini
Changed
@@ -2,4 +2,5 @@ Device="Aygıt" Mode="Mod" Buffering="Arabelleği Kullan" +PixelFormat="Piksel Biçimi"
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/#Resources/PATCH_NOTES.md -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/#Resources/PATCH_NOTES.md
Changed
@@ -1,29 +1,11 @@ -# Multi-GPU Support And Filler Data Fix (Hotfix 2) -With this update the encoder plugin now supports multi-GPU setups, such as RX 480 + R9 390, R9 285 + R9 290, and others. You can select which GPU to use with the Advanced View Mode. The UI will also now update according to the supported features of the selected GPU and by default uses the primary GPU. Unsupported features will be hidden, just like unused features. +# 1.4.3.4 - Crimson ReLive Compatibility Update (Hotfix 1) +Crimson ReLive changed how the Full Range flag is applied, which caused the plugin to break since it expected another property there. This has been fixed and some log messages have been changed to also result in better readability for users and support. -The 'Filler Data' property has now been fixed, Delta QP for B-Pictures is now visible when not using Constant QP, 'Memory Type' and 'Surface Format' have been removed and 'CABAC' has been replaced with 'Coding Type'. 'Memory Type' is now automatically using the best available and 'Surface Format' is taken from OBS settings. - -Additionally a crash with AMD Hybrid/Switchable GPU setups was fixed and these systems should now be able to use the encoder. It will now default to using the best available AMD GPU in the system if it can detect it. - -Hotfix 2: Fixed a potential crash when opening settings. -Hotfix 1: Fixed Presets not being applied properly - -## Notes - -Due to the nature of changes since 1.3 users might experience that their settings have vanished or are incorrect. Please revalidate your settings or even create a clean profile to work off of. +Hotfix 1: The Driver update also broke VBAQ, but it caused less issues than the Full Range flag. This has been fixed. ## Changelog - -* (Hotfix 2) Fixed: Potential crash when opening the settings. -* (Hotfix 1) Fixed: Presets were not being applied properly. -* Added: Full multi-GPU encoding support. -* Added: 'Coding Type' property which replaces 'CABAC'. -* Fixed: Filler Data was always being forced on for CBR. -* Fixed: Users should now be able to modify Delta QP for B-Pictures even when not using Constant QP. -* Fixed: Crash on OBS start on AMD Hybrid/Switchable GPU systems. -* Changed: Default device is always the primary/best available AMD GPU in the system. -* Changed: B-Picture properties will be properly hidden now if not in use. -* Changed: B-Pictures defaults to 0 and B-Picture Reference defaults to Disabled. -* Removed: 'Memory Type' property as the plugin will now always use the best available API. -* Removed: 'Surface Format' property as the plugin will now use the OBS settings for this. -* Removed: Deprecated encoder entry has been fully removed now. \ No newline at end of file +* Hotfix 1: Experimental Property VBAQ would not be properly set. +* Hotfix 1: Runtime and Compiled Against version numbers were switched around. +* Fixed: Experimental Full Range Color mode no longer causes encoding to fail. (Fixes #175) +* Changed: Queue status log messages have been reduced to once per second instead of once per frame. +* Changed: First submission log message now show the time in seconds instead of nanoseconds.
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/#Resources/package.in.bat -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/#Resources/package.in.bat
Changed
@@ -16,4 +16,3 @@ "%InnoSetup%" /cc "Installer.iss" POPD -PAUSE
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/CMakeLists.txt
Changed
@@ -3,26 +3,30 @@ # Shared (OBS Studio & Standalone) PROJECT(enc-amf) SET(enc-amf_HEADERS - "Include/amd-amf.h" - "Include/amd-amf-vce.h" - "Include/amd-amf-vce-capabilities.h" + "Include/amf.h" + "Include/amf-capabilities.h" + "Include/amf-h264.h" "Include/api-base.h" "Include/api-d3d9.h" "Include/api-d3d11.h" + "Include/api-host.h" + "Include/api-opengl.h" "Include/enc-h264.h" "Include/plugin.h" "${PROJECT_BINARY_DIR}/Include/Version.h" ) SET(enc-amf_SOURCES - "Source/amd-amf.cpp" - "Source/amd-amf-vce.cpp" - "Source/amd-amf-vce-capabilities.cpp" + "Source/amf.cpp" + "Source/amf-capabilities.cpp" + "Source/amf-h264.cpp" "Source/api-base.cpp" + "Source/api-host.cpp" "Source/api-d3d9.cpp" "Source/api-d3d11.cpp" + "Source/api-opengl.cpp" "Source/enc-h264.cpp" - "Source/plugin.cpp" "Source/misc-util.cpp" + "Source/plugin.cpp" ) SET(enc-amf_LIBRARIES version @@ -32,8 +36,8 @@ # Version SET(enc-amf_VERSION_MAJOR 1) SET(enc-amf_VERSION_MINOR 4) -SET(enc-amf_VERSION_PATCH 2) -SET(enc-amf_VERSION_BUILD 3) +SET(enc-amf_VERSION_PATCH 3) +SET(enc-amf_VERSION_BUILD 4) configure_file( "${PROJECT_SOURCE_DIR}/#Resources/package.in.bat" "${PROJECT_SOURCE_DIR}/#Resources/package.bat"
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/CONTRIBUTING.md -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/CONTRIBUTING.md
Changed
@@ -1,83 +1,89 @@ -# Reporting Issues - -Before you report an issue, please read the [Troubleshooting Guide](https://github.com/Xaymar/obs-studio_amf-encoder-plugin/wiki/Troubleshooting-Guide). -It contains a step-by-step guide on how to solve your issue and even includes a FAQ for you to read through. - -# Git and the Project - -## Committing Changes - -Read [this wiki page for information](https://github.com/Xaymar/obs-studio_amf-encoder-plugin/wiki/Contributing) and please follow it. Rebasing a bunch of pushed commits is terrible for anyone involved. - -## Pull Requests +# Contributing +It's great to hear that you want to contribute to the project! So let's get you started. + +## Reporting Issues, Requesting Features, etc. +Before you report an issue, please read the [Troubleshooting Guide](https://github.com/Xaymar/obs-studio_amf-encoder-plugin/wiki/Troubleshooting-Guide). It contains a step-by-step guide on how to solve your issue and even includes a FAQ for you to read through. If you request a certain feature, make sure that it is actually possible to implement this feature. + +## Changing the Project +The first step to starting off is to get the project building so that you can actually test your changes yourself. + +### Prerequisites +* [CMake Build Tool](https://cmake.org/) +* [Visual Studio® 2013](http://visualstudio.com/), [Visual Studio® 2015](http://visualstudio.com/) or newer +* [Open Broadcaster Software Studio](https://github.com/jp9000/obs-studio) +* [AMDs Advanced Media Framework SDK](https://github.com/GPUOpen-LibrariesAndSDKs/AMF) +* Windows 10 SDK (Version 10586 or better) *[Windows Only]* +* Optional: [InnoSetup](http://www.jrsoftware.org/isinfo.php) for building a Standalone Installer + +### Step 1: Build Open Broadcaster Studio +This is necessary so the plugin itself has something to link against. Simply build OBS Studio with the same configuration (or do a Batch Build for all configurations) and you are good to go. + +### Step 2: Configure the Project +1. Point CMake at the Source Code and tell it to put binaries in /build32 (32-Bit) or /build64 (64-bit). +2. Configure the Project +3. Set PATH_AMDAMFSDK to where you cloned the AMD Advanced Media Framework SDK to. +4. Set PATH_OBSStudio to where you cloned Open Broadcaster Software Studio to. +5. Generate the Project files +6. You should now have a Solution file in the /build32 or /build64 folder. + +### Step 3: Building the Project +To verify that everything worked right you should now attempt to build the project with the generated solution file. If something did not work right, make sure that you have all prerequisites and start again from step 1. +Once the building is complete you will notice a new folder called /#Build. This folder will always contain the latest files from a build, no matter the configuration. + +### Step 4: Test the built Project +Copy the files from /#Build to a OBS Studio installation (Portable or Static) and try to use your changes. + +## Git and the Project +Version Control plays a large role in managing things and keeping in touch with changes. + +### Modules +The plugin itself is made up of several sub-modules: + +* AMF: amf.cpp, amf.h, amf-capabilities.cpp, amf-capabilities.h +* H264: amf-h264.cpp, amf-h264.h, enc-h264.cpp, enc-h264.h +* H265: amf-h265.cpp, amf-h265.h, enc-h265.cpp, enc-h265.h +* API: api-base.cpp, api-base.h +* API-OGL: api-opengl.cpp, api-opengl.h +* API-D3D9: api-d3d9.cpp, api-d3d9.h +* API-D3D11: api-d3d11.cpp, api-d3d11.h +* API-Host: api-host.cpp, api-host.h +* Utilities: misc-util.cpp +* Locale: Any locale files +* Resources: Any resource files + +### Commits +Commits should ideally only contain one group of changes. For example if you change how the H264 Color Format is called, that change would be prefixed by H264 and contain all the files this changes. + +#### Messages +The first line of a message should not be longer than 80 characters and be prefixed by the module it changes. If it changes more than one separate them by comma. If it changes all of them use the prefix 'project'. + +### Pull Requests Pull Request titles should follow the guidelines for committing changes and also have a short description of what the change does. -# Building - -## Step 1: Get the pre-requisites -This plugin is included in the Open Broadcaster Studio project itself. This is only necessary if you wish to verify functionality with a standalone build. - -### Pre-Requisites -* [Visual Studio® 2013 or Visual Studio® 2015 (Community or better)](http://visualstudio.com/) -* Windows 10 SDK (Version 10586 or better, bundled with Visual Studio) -* [OBS Studio](https://github.com/jp9000/obs-studio) -* [AMF SDK](https://github.com/GPUOpen-LibrariesAndSDKs/AMF) -* [InnoSetup](http://www.jrsoftware.org/isinfo.php) -* CMake - -## Step 2: Configure with CMake -Point CMake at the source code and use either /build32 for 32-bit or /build64 for 64-bit as the binaries path. - -The following variables are needed to be set for a successful build: - -* PATH_AMDAMFSDK - Path to the cloned AMF SDK repository. -* PATH_OBSStudio - Path to the cloned OBS Studio repository. - -Once you have set these, you can generate the project files. - -## Step 3: Build with CMake -1. Open the project file -2. Build - -Binaries will be located in /#Build and in the chosen binary path. An Installer can be created using the package.bat in /#Resources. - -## Step 3: Verify Functionality - -*[You can only do this with an AMD APU or GPU installed](https://github.com/Xaymar/obs-studio_amf-encoder-plugin/wiki/Hardware,-GCN-and-VCE-Limits)*. -Install the plugin into your OBS Studio installation or test environment and select it in either Simple Output Mode or Advanced Output Mode. It should encode fine without crashing at any point. - -# Coding Standard - +## Coding Standard The entire Project is written in C++ and as such follows common C++ writing practices. -## Namespaces - +### Namespaces Namespaces should be named in *Pascal Case*. You may create a nested namespace that is 3 levels deep, not more. -## Enumerations +### Structures and Classes +Structures and Classes should be named using *Pascal Case* and should be inside a namespace. A structure or class not in a namespace must have relevance to the entire code. + +#### Methods +Methods should be named in *Pascal Case* and always reside in the class it belongs to. + +#### Members +Members should be prefixed by 'm_' and then use a *Pascal Case* name. There is no special prefix per-type, per-usage or per-source. +### Enumerations Enumerations should be named in *Pascal Case* and be inside a namespace or class. Enumeration Constants should always be prefixed by the enumeration name so no ambiguity exists. -## Functions - +### Functions Functions should be named in *Pascal Case* and should always be inside a namespace or class. Ideally your function should be either inlinable or have parameters passed by reference for optimization. -## Classes - -Classes should be named in *Pascal Case* and should always be inside a namespace - a class not in a namespace must be really important to everything. - -### Methods (Class-specific Functions) - -Methods should be named in *Pascal Case* and always reside in the class it belongs to. - -### Members (Class-specific Variables) - -Members should be prefixed by 'm_' and then use a *Pascal Case* name. There is no special prefix per-type, per-usage or per-source. - -## Variables - -Variables should be named in *camel Case* +### Variables +Variables should be named in *camel Case*.
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/amf-capabilities.h
Added
@@ -0,0 +1,111 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include <stdint.h> +#include <inttypes.h> +#include <vector> +#include <list> +#include <map> +#include <tuple> + +// Plugin +#include "plugin.h" +#include "amf.h" +#include "amf-h264.h" +#include "api-base.h" + +// AMF +#include "components\ComponentCaps.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// + +namespace Plugin { + namespace AMD { + volatile struct VCEDeviceCapabilities { + amf::AMF_ACCELERATION_TYPE acceleration_type; + uint32_t maxProfile; + uint32_t maxProfileLevel; + uint32_t maxBitrate; + uint32_t minReferenceFrames; + uint32_t maxReferenceFrames; + bool supportsBFrames; + bool supportsFixedSliceMode; + uint32_t maxTemporalLayers; + uint32_t maxNumOfStreams; + uint32_t maxNumOfHwInstances; + + struct IOCaps { + int32_t minWidth, maxWidth; + int32_t minHeight, maxHeight; + bool supportsInterlaced; + uint32_t verticalAlignment; + + std::vector<std::pair<amf::AMF_SURFACE_FORMAT, bool>> formats; + std::vector<std::pair<amf::AMF_MEMORY_TYPE, bool>> memoryTypes; + } input, output; + + Plugin::AMD::VCEDeviceCapabilities::VCEDeviceCapabilities(); + }; + + class VCECapabilities { + ////////////////////////////////////////////////////////////////////////// + // Singleton + ////////////////////////////////////////////////////////////////////////// + public: + static std::shared_ptr<Plugin::AMD::VCECapabilities> GetInstance(); + static void ReportCapabilities(std::shared_ptr<Plugin::API::Base> api); + static void ReportAdapterCapabilities(std::shared_ptr<Plugin::API::Base> api, + Plugin::API::Adapter adapter); + static void ReportAdapterTypeCapabilities(std::shared_ptr<Plugin::API::Base> api, + Plugin::API::Adapter adapter, + VCEEncoderType type); + static void ReportAdapterTypeIOCapabilities(std::shared_ptr<Plugin::API::Base> api, + Plugin::API::Adapter adapter, + VCEEncoderType type, + bool output); + + ////////////////////////////////////////////////////////////////////////// + // Class + ////////////////////////////////////////////////////////////////////////// + public: + VCECapabilities(); + ~VCECapabilities(); + + bool Refresh(); + std::vector<std::pair<VCEEncoderType, VCEDeviceCapabilities>> + GetAllAdapterCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter); + VCEDeviceCapabilities + GetAdapterCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter, VCEEncoderType type); + + private: + std::map<std::tuple<std::string, Plugin::API::Adapter, Plugin::AMD::VCEEncoderType>, VCEDeviceCapabilities> capabilityMap; + }; + } +} \ No newline at end of file
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/amf-h264.h
Added
@@ -0,0 +1,506 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include <condition_variable> +#include <algorithm> +#include <mutex> +#include <queue> +#include <thread> +#include <vector> +#include <chrono> + +// Plugin +#include "plugin.h" +#include "amf.h" +#include "api-base.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// + +namespace Plugin { + namespace AMD { + // Internal Properties + enum VCEEncoderType { + VCEEncoderType_AVC, // Advanced Video Coding + VCEEncoderType_SVC, // Scalable Video Coding + VCEEncoderType_HEVC, // High-Efficiency Video Coding (Discovered in amfrt64.dll) + }; + enum VCEMemoryType { + VCEMemoryType_Host, // Host-Managed Memory + VCEMemoryType_DirectX9, // DirectX9 + VCEMemoryType_DirectX11, // DirectX11 + VCEMemoryType_OpenGL, // OpenGL + }; + enum VCEColorFormat { + // 4:2:0 Formats + VCEColorFormat_NV12, // NV12 + VCEColorFormat_I420, // YUV 4:2:0 + // 4:2:2 Formats + VCEColorFormat_YUY2, + // Uncompressed + VCEColorFormat_BGRA, // ARGB + VCEColorFormat_RGBA, // RGBA + // Other + VCEColorFormat_GRAY, + }; + enum VCEColorProfile { + VCEColorProfile_601, + VCEColorProfile_709, + VCEColorProfile_2020, // HDR + }; + + // Static Properties + enum VCEUsage { + VCEUsage_Transcoding, + VCEUsage_UltraLowLatency, + VCEUsage_LowLatency, + VCEUsage_Webcam, // For SVC + }; + enum VCEQualityPreset { + VCEQualityPreset_Speed, + VCEQualityPreset_Balanced, + VCEQualityPreset_Quality, + }; + enum VCEProfile { + VCEProfile_Baseline = 66, + VCEProfile_Main = 77, + VCEProfile_High = 100, + VCEProfile_ConstrainedBaseline = 256, + VCEProfile_ConstrainedHigh = 257 + }; + enum VCEProfileLevel { + VCEProfileLevel_Automatic = 0, + VCEProfileLevel_10 = 10, + VCEProfileLevel_11, + VCEProfileLevel_12, + VCEProfileLevel_13, + VCEProfileLevel_20 = 20, + VCEProfileLevel_21, + VCEProfileLevel_22, + VCEProfileLevel_30 = 30, + VCEProfileLevel_31, + VCEProfileLevel_32, + VCEProfileLevel_40 = 40, + VCEProfileLevel_41, + VCEProfileLevel_42, + VCEProfileLevel_50 = 50, + VCEProfileLevel_51, + VCEProfileLevel_52, + VCEProfileLevel_60 = 60, + VCEProfileLevel_61, + VCEProfileLevel_62, + }; + enum VCEScanType { + VCEScanType_Progressive, + VCEScanType_Interlaced, + }; + enum VCECodingType { + VCECodingType_Default = 0, + VCECodingType_CABAC = 1, + VCECodingType_CALVC = 2, + }; + + // Dynamic Properties + enum VCERateControlMethod { + VCERateControlMethod_ConstantQP, + VCERateControlMethod_ConstantBitrate, + VCERateControlMethod_VariableBitrate_PeakConstrained, + VCERateControlMethod_VariableBitrate_LatencyConstrained, + }; + enum VCEBFramePattern { + VCEBFramePattern_None, + VCEBFramePattern_One, + VCEBFramePattern_Two, + VCEBFramePattern_Three, + }; + + // Experimental + enum VCESliceMode { + VCESliceMode_Horizontal = 1, + VCESliceMode_Vertical = 2 + }; + enum VCESliceControlMode { + VCESliceControlMode_Off, + VCESliceControlMode_Macroblock = 1, // AMF_VIDEO_ENCODER_SLICE_CTRL_MODE_MB + VCESliceControlMode_Invalid, + VCESliceControlMode_Macroblock_Row = 3 // AMF_VIDEO_ENCODER_SLICE_CTRL_MODE_MB_ROW + }; + + + + class VCEEncoder { + #pragma region Initializer & Finalizer + public: + VCEEncoder( + VCEEncoderType p_Type, + std::string p_VideoAPI, + uint64_t p_VideoAdapterId, + bool p_OpenCL, + VCEColorFormat p_SurfaceFormat = VCEColorFormat_NV12 + ); + ~VCEEncoder(); + #pragma endregion Initializer & Finalizer + + public: + void Start(); + void Restart(); + void Stop(); + bool IsStarted(); + + bool SendInput(struct encoder_frame* frame); + bool GetOutput(struct encoder_packet* packet, bool* received_packet); + bool GetExtraData(uint8_t**& data, size_t*& size); + void GetVideoInfo(struct video_scale_info*& vsi); + + #pragma region Properties + public: + void LogProperties(); + + // Static + + #pragma region Startup Properties + // Set which Usage preset to use. + // Changing this will also change a lot of other properties. + void SetUsage(VCEUsage usage); + VCEUsage GetUsage(); + + // Set which Quality Preset AMF should use. + // Affects the quality of the output. + void SetQualityPreset(VCEQualityPreset preset); + VCEQualityPreset GetQualityPreset(); + + // Set the Profile the output should have. + void SetProfile(VCEProfile profile); + VCEProfile GetProfile(); + + // Set the Profile Level the output should have. + void SetProfileLevel(VCEProfileLevel level); + VCEProfileLevel GetProfileLevel(); + #pragma endregion Startup Properties + + #pragma region Frame Properties + // Set which Color Profile the input frame is. + void SetColorProfile(VCEColorProfile profile); + VCEColorProfile GetColorProfile(); + + // Set if the input frame is in full color range. + void SetFullRangeColorEnabled(bool enabled); + bool IsFullRangeColorEnabled(); + + // Resolution for the input and output. + void SetResolution(uint32_t width, uint32_t height); + std::pair<uint32_t, uint32_t> GetResolution(); + + // Framerate of the input and output. + void SetFrameRate(uint32_t num, uint32_t den); + std::pair<uint32_t, uint32_t> GetFrameRate(); + + // Scanning method for input (and output?). + void SetScanType(VCEScanType scanType); + VCEScanType GetScanType(); + #pragma endregion Frame Properties + + // Dynamic + + #pragma region Rate Control + /* Selects the rate control method: + * - CQP - Constrained QP, + * - CBR - Constant Bitrate, + * - VBR - Peak Constrained VBR, + * - VBR_LAT - Latency Constrained VBR + * + * Remarks: + * - When SVC encoding is enabled, all Rate-control parameters (with some restrictions) can be configured differently for a particular SVC-layer. An SVC-layer is denoted by an index pair [SVC-Temporal Layer index][SVC-Quality Layer index]. E.g. The bitrate may be configured differently for SVC-layers [0][0] and [1][0]. + * - We restrict all SVC layers to have the same Rate Control method. Some RC parameters are not enabled with SVC encoding (e.g. all parameters related to B-Frames). + **/ + void SetRateControlMethod(VCERateControlMethod method); + VCERateControlMethod GetRateControlMethod(); + + /* Sets the target bitrate */ + void SetTargetBitrate(uint32_t bitrate); + uint32_t GetTargetBitrate(); + + /* Sets the peak bitrate */ + void SetPeakBitrate(uint32_t bitrate); + uint32_t GetPeakBitrate(); + + /* Sets the minimum QP */ + void SetMinimumQP(uint8_t qp); + uint8_t GetMinimumQP(); + + /* Sets the maximum QP */ + void SetMaximumQP(uint8_t qp); + uint8_t GetMaximumQP(); + + // Set the fixed QP value for I-Frames. + void SetIFrameQP(uint8_t qp); + uint8_t GetIFrameQP(); + + // Set the fixed QP value for P-Frames. + void SetPFrameQP(uint8_t qp); + uint8_t GetPFrameQP(); + + // Set the fixed QP value for B-Frames. + void SetBFrameQP(uint8_t qp); + uint8_t GetBFrameQP(); + + // Set the Video Buffer Verifier (VBV) size in bits per second (bps). + void SetVBVBufferSize(uint32_t size); + // Set the Video Buffer Verifier (VBV) size using a strictness constraint. + void SetVBVBufferAutomatic(double_t strictness); + uint32_t GetVBVBufferSize(); + + /* Sets the initial VBV Buffer Fullness */ + void SetInitialVBVBufferFullness(double_t fullness); + double_t GetInitialVBVBufferFullness(); + + /* Enables/Disables filler data */ + void SetFillerDataEnabled(bool enabled); + bool IsFillerDataEnabled(); + + /* Enables skip frame for rate control */ + void SetFrameSkippingEnabled(bool enabled); + bool IsFrameSkippingEnabled(); + + /* Enables/Disables constraints on QP variation within a picture to meet HRD requirement(s) */ + void SetEnforceHRDRestrictionsEnabled(bool enforce); + bool IsEnforceHRDRestrictionsEnabled(); + #pragma endregion Rate Control + + #pragma region Picture Control + // Set the Instantaneous-Decoder-Refresh (IDR) Period in frames. + void SetIDRPeriod(uint32_t period); + uint32_t GetIDRPeriod(); + + #pragma region B-Frames + /* Sets the number of consecutive B-Frames. BFramesPattern = 0 indicates that B-Frames are not used */ + void SetBFramePattern(VCEBFramePattern pattern); + VCEBFramePattern GetBFramePattern(); + + /* Selects the delta QP of non-reference B-Frames with respect to the last non-B-Frame */ + void SetBFrameDeltaQP(int8_t qp); + int8_t GetBFrameDeltaQP(); + + /* Enables or disables using B-Frames as references */ + void SetBFrameReferenceEnabled(bool enabled); + bool IsBFrameReferenceEnabled(); + + /* Selects delta QP of reference B-Frames with respect to the last non-B-Frame */ + void SetBFrameReferenceDeltaQP(int8_t qp); + int8_t GetBFrameReferenceDeltaQP(); + #pragma endregion B-Frames + #pragma endregion Picture Control + + #pragma region Miscellaneous + /* Turns on/off the Deblocking Filter */ + void SetDeblockingFilterEnabled(bool enabled); + bool IsDeblockingFilterEnabled(); + + #pragma region Motion Estimation + /* Turns on/off half-pixel motion estimation */ + void SetHalfPixelMotionEstimationEnabled(bool enabled); + bool IsHalfPixelMotionEstimationEnabled(); + + /* Turns on/off quarter-pixel motion estimation */ + void SetQuarterPixelMotionEstimationEnabled(bool enabled); + bool IsQuarterPixelMotionEstimationEnabled(); + #pragma endregion Motion Estimation + #pragma endregion Miscellaneous + + #pragma region Experimental Properties + // Get the maximum amount of MBps the encoder can output. + uint32_t GetMaxMBPerSec(); + + /* Coding Type */ + void SetCodingType(VCECodingType type); + VCECodingType GetCodingType(); + + void SetWaitForTaskEnabled(bool enabled); + bool IsWaitForTaskEnabled(); + + // Preanalysis Pass is AMDs version of Two-Pass hardware encoding. + void SetPreAnalysisPassEnabled(bool enabled); + bool IsPreAnalysisPassEnabled(); + + // VBAQ = Variable Bitrate Average Quality? + // - EanbleVBAQ (bool) + void SetVBAQEnabled(bool enabled); + bool IsVBAQEnabled(); + + /* Sets the headers insertion spacing */ + void SetHeaderInsertionSpacing(uint32_t spacing); // Similar to IDR Period, spacing (in frames) between headers. + uint32_t GetHeaderInsertionSpacing(); + + /* The number of long-term references controlled by the user. + * + * Remarks: + * - When == 0, the encoder may or may not use LTRs during encoding. + * - When >0, the user has control over all LTR. + * - With user control of LTR, B-Frames and Intra-refresh features are not supported. + * - The actual maximum number of LTRs allowed depends on H.264 Annex A Table A-1 Level limits, which defines dependencies between the H.264 Level number, encoding resolution, and DPB size. The DPB size limit impacts the maximum number of LTR allowed. + **/ + void SetMaximumLongTermReferenceFrames(uint32_t maximumLTRFrames); // Long-Term Reference Frames. If 0, Encoder decides, if non-0 B-Frames and Intra-Refresh are not supported. + uint32_t GetMaximumLongTermReferenceFrames(); + + /* Sets Maximum AU Size in bits */ + void SetMaximumAccessUnitSize(uint32_t size); + uint32_t GetMaximumAccessUnitSize(); + + void SetMaximumReferenceFrames(uint32_t frameCount); + uint32_t GetMaximumReferenceFrames(); + + void SetAspectRatio(uint32_t x, uint32_t y); + std::pair<uint32_t, uint32_t> GetAspectRatio(); + + #pragma region Group of Pictures + void SetGOPSize(uint32_t gopSize); + uint32_t GetGOPSize(); + + void SetGOPAlignmentEnabled(bool enabled); + bool IsGOPAlignementEnabled(); + #pragma endregion Group of Pictures + + #pragma region Intra Refresh + // Macroblocks per Intra-Refresh Slot + // Intra-Refresh Coding + void SetIntraRefreshMacroblocksPerSlot(uint32_t macroblocks); + uint32_t GetIntraRefreshMacroblocksPerSlot(); + + // - IntraRefreshNumOfStripes (0 - INT_MAX) + // Intra-Refresh Coding + void SetIntraRefreshNumberOfStripes(uint32_t stripes); + uint32_t GetIntraRefreshNumberOfStripes(); + #pragma endregion Intra Refresh + + #pragma region Slicing + /* Sets the number of slices per frame */ + void SetSlicesPerFrame(uint32_t slices); + uint32_t GetSlicesPerFrame(); + + // - SliceMode (1 - 2, Default is 1) + void SetSliceMode(VCESliceMode mode); + VCESliceMode GetSliceMode(); + + // - MaxSliceSize (1 - INT_MAX) + void SetMaximumSliceSize(uint32_t size); + uint32_t GetMaximumSliceSize(); + + // - SliceControlMode (0 - 3) + void SetSliceControlMode(VCESliceControlMode mode); + VCESliceControlMode GetSliceControlMode(); + + // - SliceControlSize (0 - INT_MAX) + void SetSliceControlSize(uint32_t size); + uint32_t GetSliceControlSize(); + #pragma endregion Slicing + + // More: + // - CodecId (H264 = 5, H264SVC = 8, 2xUNKNOWN) + // - EngineType (Auto = 0, DX9 = 1, DX11 = 2, XVBA = 3) + // - ConstraintSetFlags (0 - 255, 1 byte bitset?) + // - LowLatencyInternal (bool) + // - CommonLowLatencyInternal (bool) + // - UniqueInstance (0 - INT_MAX) + // - MultiInstanceMode (bool) + // - MultiInstanceCurrentQueue (0 - 1) + // - InstanceId (-1 - [# of Streams - 1]) + // - EncoderMaxInstances (1 - [# of Instances]) + #pragma endregion Experimental Properties + + #pragma endregion Properties + + // Threading + private: + static void InputThreadMain(Plugin::AMD::VCEEncoder* p_this); + void InputThreadLogic(); + static void OutputThreadMain(Plugin::AMD::VCEEncoder* p_this); + void OutputThreadLogic(); + inline amf::AMFSurfacePtr CreateSurfaceFromFrame(struct encoder_frame*& frame); + + #pragma region Members + private: + // AMF Data References + std::shared_ptr<Plugin::AMD::AMF> m_AMF; + amf::AMFFactory* m_AMFFactory; + amf::AMFContextPtr m_AMFContext; + amf::AMFComponentPtr m_AMFConverter; + amf::AMFComponentPtr m_AMFEncoder; + amf::AMFComputePtr m_AMFCompute; + + // API References + std::shared_ptr<Plugin::API::Base> m_API; + Plugin::API::Adapter m_APIAdapter; + void* m_APIInstance; + + // Static Buffers + std::vector<uint8_t> m_PacketDataBuffer; + std::vector<uint8_t> m_ExtraDataBuffer; + + // Structured Queue + struct { + std::queue<amf::AMFSurfacePtr> queue; + + // Threading + std::thread thread; + std::mutex mutex; + std::condition_variable condvar; + std::mutex queuemutex; + } m_Input; + struct { + std::queue<amf::AMFDataPtr> queue; + + // Threading + std::thread thread; + std::mutex mutex; + std::condition_variable condvar; + std::mutex queuemutex; + } m_Output; + + // Internal Properties + VCEEncoderType m_EncoderType; + VCEMemoryType m_MemoryType; + bool m_OpenCL; + VCEColorFormat m_ColorFormat; + bool m_Flag_IsStarted, + m_Flag_FirstFrameSubmitted, + m_Flag_FirstFrameReceived; + std::pair<uint32_t, uint32_t> m_FrameSize, + m_FrameRate; + double_t m_FrameRateDivisor, + m_FrameRateReverseDivisor; + size_t m_InputQueueLimit, + m_InputQueueLastSize; + uint32_t m_TimerPeriod; + VCEColorProfile m_ColorProfile; + std::chrono::time_point<std::chrono::high_resolution_clock> m_LastQueueWarnMessageTime; + + #pragma endregion Members + }; + } +} \ No newline at end of file
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/amf.h
Changed
(renamed from plugins/enc-amf/Include/amd-amf.h)
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/api-base.h -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/api-base.h
Changed
@@ -27,61 +27,67 @@ // Includes ////////////////////////////////////////////////////////////////////////// #include "plugin.h" + #include <vector> +#include <map> ////////////////////////////////////////////////////////////////////////// // Code ////////////////////////////////////////////////////////////////////////// namespace Plugin { namespace API { - struct Device { - std::string Name; - std::string UniqueId; - - Device(); - Device(std::string Name, std::string UniqueId); - ~Device(); - - - friend bool operator<(const Plugin::API::Device& left, const Plugin::API::Device& right); - friend bool operator>(const Plugin::API::Device& left, const Plugin::API::Device& right); - friend bool operator<=(const Plugin::API::Device& left, const Plugin::API::Device& right); - friend bool operator>=(const Plugin::API::Device& left, const Plugin::API::Device& right); - - friend bool operator==(const Plugin::API::Device& left, const Plugin::API::Device& right); - friend bool operator!=(const Plugin::API::Device& left, const Plugin::API::Device& right); - }; - enum APIType { - APIType_Base, + APIType_Host, APIType_Direct3D9, APIType_Direct3D11, APIType_OpenGL, }; - class APIBase { - public: - static std::vector<Plugin::API::Device> EnumerateDevices(); - static Plugin::API::Device GetDeviceForUniqueId(std::string uniqueId); + struct Adapter { + int32_t idLow, idHigh; + std::string Name; - static Plugin::API::APIType GetBestAvailableAPI(); - static std::unique_ptr<Plugin::API::APIBase> - CreateBestAvailableAPI(Plugin::API::Device device); + Adapter() : idLow(0), idHigh(0), Name("Invalid Device") {} + Adapter(int32_t idLow, int32_t idHigh, std::string Name) : idLow(idLow), idHigh(idHigh), Name(Name) {} - APIBase(); - APIBase(Device device); - virtual ~APIBase(); + friend bool operator<(const Plugin::API::Adapter& left, const Plugin::API::Adapter& right); + friend bool operator>(const Plugin::API::Adapter& left, const Plugin::API::Adapter& right); + friend bool operator<=(const Plugin::API::Adapter& left, const Plugin::API::Adapter& right); + friend bool operator>=(const Plugin::API::Adapter& left, const Plugin::API::Adapter& right); - Plugin::API::Device GetDevice(); + friend bool operator==(const Plugin::API::Adapter& left, const Plugin::API::Adapter& right); + friend bool operator!=(const Plugin::API::Adapter& left, const Plugin::API::Adapter& right); + }; + + class Base { + ////////////////////////////////////////////////////////////////////////// + // API Index + ////////////////////////////////////////////////////////////////////////// + public: + static void Initialize(); + + static size_t GetAPICount(); + static std::shared_ptr<Base> GetAPIInstance(size_t index); + static std::string GetAPIName(size_t index); + static std::shared_ptr<Base> GetAPIByName(std::string name); + static std::vector<std::shared_ptr<Base>> EnumerateAPIs(); + static std::vector<std::string> EnumerateAPINames(); + + ////////////////////////////////////////////////////////////////////////// + // API + ////////////////////////////////////////////////////////////////////////// + public: + virtual std::string GetName() = 0; + virtual APIType GetType() = 0; - virtual Plugin::API::APIType GetType(); - virtual void* GetContext(); - - protected: - Plugin::API::APIType myType; + virtual std::vector<Adapter> EnumerateAdapters() = 0; + virtual Adapter GetAdapterById(uint32_t idLow, uint32_t idHigh) = 0; + virtual Adapter GetAdapterByName(std::string name) = 0; - private: - Plugin::API::Device myDevice; + virtual void* CreateInstanceOnAdapter(Adapter adapter) = 0; + virtual Adapter GetAdapterForInstance(void* instance) = 0; + virtual void* GetContextFromInstance(void* instance) = 0; + virtual void DestroyInstance(void* instance) = 0; }; } } \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/api-d3d11.h -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/api-d3d11.h
Changed
@@ -23,33 +23,30 @@ */ #pragma once -#ifdef _WIN32 + ////////////////////////////////////////////////////////////////////////// // Includes ////////////////////////////////////////////////////////////////////////// #include "api-base.h" -#include <d3d11.h> - ////////////////////////////////////////////////////////////////////////// // Code ////////////////////////////////////////////////////////////////////////// + namespace Plugin { namespace API { - class Direct3D11 : public APIBase { - public: - static std::vector<Plugin::API::Device> EnumerateDevices(); - static Plugin::API::Device GetDeviceForUniqueId(std::string uniqueId); - - Direct3D11(Device device); - ~Direct3D11(); - - virtual void* GetContext() override; - - private: - ID3D11Device* pDevice; - ID3D11DeviceContext* pDeviceContext; + class Direct3D11 : public Base { + virtual std::string GetName() override; + virtual APIType GetType() override; + + virtual std::vector<Adapter> EnumerateAdapters() override; + virtual Adapter GetAdapterById(uint32_t idLow, uint32_t idHigh) override; + virtual Adapter GetAdapterByName(std::string name) override; + + virtual void* CreateInstanceOnAdapter(Adapter adapter) override; + virtual Adapter GetAdapterForInstance(void* pInstance) override; + virtual void* GetContextFromInstance(void* pInstance) override; + virtual void DestroyInstance(void* pInstance) override; }; } } -#endif
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/api-d3d9.h -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/api-d3d9.h
Changed
@@ -23,35 +23,30 @@ */ #pragma once -#ifdef _WIN32 + ////////////////////////////////////////////////////////////////////////// // Includes ////////////////////////////////////////////////////////////////////////// #include "api-base.h" -#define D3D_DEBUG_INFO -#include <d3d9.h> -#pragma comment(lib, "d3d9.lib") - ////////////////////////////////////////////////////////////////////////// // Code ////////////////////////////////////////////////////////////////////////// + namespace Plugin { namespace API { - class Direct3D9 : public APIBase { - public: - static std::vector<Plugin::API::Device> EnumerateDevices(); - static Plugin::API::Device GetDeviceForUniqueId(std::string uniqueId); - - Direct3D9(Device device); - ~Direct3D9(); - - virtual void* GetContext() override; - - private: - IDirect3D9* pDirect3D; - IDirect3DDevice9* pDirect3DDevice; + class Direct3D9 : public Base { + virtual std::string GetName() override; + virtual APIType GetType() override; + + virtual std::vector<Adapter> EnumerateAdapters() override; + virtual Adapter GetAdapterById(uint32_t idLow, uint32_t idHigh); + virtual Adapter GetAdapterByName(std::string name); + + virtual void* CreateInstanceOnAdapter(Adapter adapter) override; + virtual Adapter GetAdapterForInstance(void* pInstance) override; + virtual void* GetContextFromInstance(void* pInstance) override; + virtual void DestroyInstance(void* pInstance) override; }; } } -#endif
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/api-host.h
Added
@@ -0,0 +1,52 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include "api-base.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// + +namespace Plugin { + namespace API { + class Host : public Base { + virtual std::string GetName() override; + virtual APIType GetType() override; + + virtual std::vector<Adapter> EnumerateAdapters() override; + virtual Adapter GetAdapterById(uint32_t idLow, uint32_t idHigh); + virtual Adapter GetAdapterByName(std::string name); + + virtual void* CreateInstanceOnAdapter(Adapter adapter) override; + virtual Adapter GetAdapterForInstance(void* pInstance) override; + virtual void* GetContextFromInstance(void* pInstance) override; + virtual void DestroyInstance(void* pInstance) override; + }; + } +}
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/api-opengl.h
Added
@@ -0,0 +1,52 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include "api-base.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// + +namespace Plugin { + namespace API { + class OpenGL : public Base { + virtual std::string GetName() override; + virtual APIType GetType() override; + + virtual std::vector<Adapter> EnumerateAdapters() override; + virtual Adapter GetAdapterById(uint32_t idLow, uint32_t idHigh); + virtual Adapter GetAdapterByName(std::string name); + + virtual void* CreateInstanceOnAdapter(Adapter adapter) override; + virtual Adapter GetAdapterForInstance(void* instance) override; + virtual void* GetContextFromInstance(void* instance) override; + virtual void DestroyInstance(void* instance) override; + }; + } +}
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/enc-h264.h -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/enc-h264.h
Changed
@@ -28,8 +28,155 @@ ////////////////////////////////////////////////////////////////////////// // Plugin #include "plugin.h" -#include "amd-amf-vce.h" -#include "amd-amf-vce-capabilities.h" +#include "amf-capabilities.h" +#include "amf-h264.h" + +////////////////////////////////////////////////////////////////////////// +// Defines - Translation Strings +////////////////////////////////////////////////////////////////////////// + +// Presets +#define AMF_H264_PRESET TEXT_AMF_H264("Preset") +#define AMF_H264_PRESET_RESETTODEFAULTS TEXT_AMF_H264("Preset.ResetToDefaults") +#define AMF_H264_PRESET_RECORDING TEXT_AMF_H264("Preset.Recording") +#define AMF_H264_PRESET_HIGHQUALITY TEXT_AMF_H264("Preset.HighQuality") +#define AMF_H264_PRESET_INDISTINGUISHABLE TEXT_AMF_H264("Preset.Indistinguishable") +#define AMF_H264_PRESET_LOSSLESS TEXT_AMF_H264("Preset.Lossless") +#define AMF_H264_PRESET_TWITCH TEXT_AMF_H264("Preset.Twitch") +#define AMF_H264_PRESET_YOUTUBE TEXT_AMF_H264("Preset.YouTube") + +// Startup Properties +#define AMF_H264_USAGE TEXT_AMF_H264("Usage") +#define AMF_H264_USAGE_DESCRIPTION TEXT_AMF_H264("Usage.Description") +#define AMF_H264_USAGE_TRANSCODING TEXT_AMF_H264("Usage.Transcoding") +#define AMF_H264_USAGE_ULTRALOWLATENCY TEXT_AMF_H264("Usage.UltraLowLatency") +#define AMF_H264_USAGE_LOWLATENCY TEXT_AMF_H264("Usage.LowLatency") +#define AMF_H264_USAGE_WEBCAM TEXT_AMF_H264("Usage.Webcam") +#define AMF_H264_QUALITY_PRESET TEXT_AMF_H264("QualityPreset") +#define AMF_H264_QUALITY_PRESET_DESCRIPTION TEXT_AMF_H264("QualityPreset.Description") +#define AMF_H264_QUALITY_PRESET_SPEED TEXT_AMF_H264("QualityPreset.Speed") +#define AMF_H264_QUALITY_PRESET_BALANCED TEXT_AMF_H264("QualityPreset.Balanced") +#define AMF_H264_QUALITY_PRESET_QUALITY TEXT_AMF_H264("QualityPreset.Quality") +#define AMF_H264_PROFILE TEXT_AMF_H264("Profile") +#define AMF_H264_PROFILE_DESCRIPTION TEXT_AMF_H264("Profile.Description") +#define AMF_H264_PROFILELEVEL TEXT_AMF_H264("ProfileLevel") +#define AMF_H264_PROFILELEVEL_DESCRIPTION TEXT_AMF_H264("ProfileLevel.Description") + +// Rate Control Properties +#define AMF_H264_RATECONTROLMETHOD TEXT_AMF_H264("RateControlMethod") +#define AMF_H264_RATECONTROLMETHOD_DESCRIPTION TEXT_AMF_H264("RateControlMethod.Description") +#define AMF_H264_RATECONTROLMETHOD_CQP TEXT_AMF_H264("RateControlMethod.CQP") +#define AMF_H264_RATECONTROLMETHOD_CBR TEXT_AMF_H264("RateControlMethod.CBR") +#define AMF_H264_RATECONTROLMETHOD_VBR TEXT_AMF_H264("RateControlMethod.VBR.Peak") +#define AMF_H264_RATECONTROLMETHOD_VBR_LAT TEXT_AMF_H264("RateControlMethod.VBR.Latency") +#define AMF_H264_BITRATE_TARGET TEXT_AMF_H264("Bitrate.Target") +#define AMF_H264_BITRATE_TARGET_DESCRIPTION TEXT_AMF_H264("Bitrate.Target.Description") +#define AMF_H264_BITRATE_PEAK TEXT_AMF_H264("Bitrate.Peak") +#define AMF_H264_BITRATE_PEAK_DESCRIPTION TEXT_AMF_H264("Bitrate.Peak.Description") +#define AMF_H264_QP_MINIMUM TEXT_AMF_H264("QP.Minimum") +#define AMF_H264_QP_MINIMUM_DESCRIPTION TEXT_AMF_H264("QP.Minimum.Description") +#define AMF_H264_QP_MAXIMUM TEXT_AMF_H264("QP.Maximum") +#define AMF_H264_QP_MAXIMUM_DESCRIPTION TEXT_AMF_H264("QP.Maximum.Description") +#define AMF_H264_QP_IFRAME TEXT_AMF_H264("QP.IFrame") +#define AMF_H264_QP_IFRAME_DESCRIPTION TEXT_AMF_H264("QP.IFrame.Description") +#define AMF_H264_QP_PFRAME TEXT_AMF_H264("QP.PFrame") +#define AMF_H264_QP_PFRAME_DESCRIPTION TEXT_AMF_H264("QP.PFrame.Description") +#define AMF_H264_QP_BFRAME TEXT_AMF_H264("QP.BFrame") +#define AMF_H264_QP_BFRAME_DESCRIPTION TEXT_AMF_H264("QP.BFrame.Description") +#define AMF_H264_VBVBUFFER TEXT_AMF_H264("VBVBuffer") +#define AMF_H264_VBVBUFFER_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Description") +#define AMF_H264_VBVBUFFER_STRICTNESS TEXT_AMF_H264("VBVBuffer.Strictness") +#define AMF_H264_VBVBUFFER_STRICTNESS_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Strictness.Description") +#define AMF_H264_VBVBUFFER_SIZE TEXT_AMF_H264("VBVBuffer.Size") +#define AMF_H264_VBVBUFFER_SIZE_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Size.Description") +#define AMF_H264_VBVBUFFER_FULLNESS TEXT_AMF_H264("VBVBuffer.Fullness") +#define AMF_H264_VBVBUFFER_FULLNESS_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Fullness.Description") +#define AMF_H264_FILLERDATA TEXT_AMF_H264("FillerData") +#define AMF_H264_FILLERDATA_DESCRIPTION TEXT_AMF_H264("FillerData.Description") +#define AMF_H264_FRAMESKIPPING TEXT_AMF_H264("FrameSkipping") +#define AMF_H264_FRAMESKIPPING_DESCRIPTION TEXT_AMF_H264("FrameSkipping.Description") +#define AMF_H264_ENFORCEHRDCOMPATIBILITY TEXT_AMF_H264("EnforceHRDCompatibility") +#define AMF_H264_ENFORCEHRDCOMPATIBILITY_DESCRIPTION TEXT_AMF_H264("EnforceHRDCompatibility.Description") + +// Picture Control Properties +#define AMF_H264_KEYFRAME_INTERVAL TEXT_AMF_H264("KeyframeInterval") +#define AMF_H264_KEYFRAME_INTERVAL_DESCRIPTION TEXT_AMF_H264("KeyframeInterval.Description") +#define AMF_H264_IDR_PERIOD TEXT_AMF_H264("IDRPeriod") +#define AMF_H264_IDR_PERIOD_DESCRIPTION TEXT_AMF_H264("IDRPeriod.Description") +#define AMF_H264_BFRAME_PATTERN TEXT_AMF_H264("BFrame.Pattern") +#define AMF_H264_BFRAME_PATTERN_DESCRIPTION TEXT_AMF_H264("BFrame.Pattern.Description") +#define AMF_H264_BFRAME_DELTAQP TEXT_AMF_H264("BFrame.DeltaQP") +#define AMF_H264_BFRAME_DELTAQP_DESCRIPTION TEXT_AMF_H264("BFrame.DeltaQP.Description") +#define AMF_H264_BFRAME_REFERENCE TEXT_AMF_H264("BFrame.Reference") +#define AMF_H264_BFRAME_REFERENCE_DESCRIPTION TEXT_AMF_H264("BFrame.Reference.Description") +#define AMF_H264_BFRAME_REFERENCEDELTAQP TEXT_AMF_H264("BFrame.ReferenceDeltaQP") +#define AMF_H264_BFRAME_REFERENCEDELTAQP_DESCRIPTION TEXT_AMF_H264("BFrame.ReferenceDeltaQP.Description") +#define AMF_H264_DEBLOCKINGFILTER TEXT_AMF_H264("DeblockingFilter") +#define AMF_H264_DEBLOCKINGFILTER_DESCRIPTION TEXT_AMF_H264("DeblockingFilter.Description") + +// Miscellaneous Properties +#define AMF_H264_SCANTYPE TEXT_AMF_H264("ScanType") +#define AMF_H264_SCANTYPE_DESCRIPTION TEXT_AMF_H264("ScanType.Description") +#define AMF_H264_SCANTYPE_PROGRESSIVE TEXT_AMF_H264("ScanType.Progressive") +#define AMF_H264_SCANTYPE_INTERLACED TEXT_AMF_H264("ScanType.Interlaced") +#define AMF_H264_MOTIONESTIMATION TEXT_AMF_H264("MotionEstimation") +#define AMF_H264_MOTIONESTIMATION_DESCRIPTION TEXT_AMF_H264("MotionEstimation.Description") +#define AMF_H264_MOTIONESTIMATION_NONE TEXT_AMF_H264("MotionEstimation.None") +#define AMF_H264_MOTIONESTIMATION_HALF TEXT_AMF_H264("MotionEstimation.Half") +#define AMF_H264_MOTIONESTIMATION_QUARTER TEXT_AMF_H264("MotionEstimation.Quarter") +#define AMF_H264_MOTIONESTIMATION_BOTH TEXT_AMF_H264("MotionEstimation.Both") + +// Experimental Properties +#define AMF_H264_CODINGTYPE TEXT_AMF_H264("CodingType") +#define AMF_H264_CODINGTYPE_DESCRIPTION TEXT_AMF_H264("CodingType.Description") +#define AMF_H264_MAXIMUMLTRFRAMES TEXT_AMF_H264("MaximumLTRFrames") +#define AMF_H264_MAXIMUMLTRFRAMES_DESCRIPTION TEXT_AMF_H264("MaximumLTRFrames.Description") +#define AMF_H264_MAXIMUMACCESSUNITSIZE TEXT_AMF_H264("MaximumAccessUnitSize") +#define AMF_H264_MAXIMUMACCESSUNITSIZE_DESCRIPTION TEXT_AMF_H264("MaximumAccessUnitSize.Description") +#define AMF_H264_HEADER_INSERTION_SPACING TEXT_AMF_H264("HeaderInsertionSpacing") +#define AMF_H264_HEADER_INSERTION_SPACING_DESCRIPTION TEXT_AMF_H264("HeaderInsertionSpacing.Description") +#define AMF_H264_WAITFORTASK TEXT_AMF_H264("WaitForTask") +#define AMF_H264_WAITFORTASK_DESCRIPTION TEXT_AMF_H264("WaitForTask.Description") +#define AMF_H264_PREANALYSISPASS TEXT_AMF_H264("PreanalysisPass") +#define AMF_H264_PREANALYSISPASS_DESCRIPTION TEXT_AMF_H264("PreanalysisPass.Description") +#define AMF_H264_VBAQ TEXT_AMF_H264("VBAQ") +#define AMF_H264_VBAQ_DESCRIPTION TEXT_AMF_H264("VBAQ.Description") +#define AMF_H264_GOPSIZE TEXT_AMF_H264("GOPSize") +#define AMF_H264_GOPSIZE_DESCRIPTION TEXT_AMF_H264("GOPSize.Description") +#define AMF_H264_GOPALIGNMENT TEXT_AMF_H264("GOPAlignment") +#define AMF_H264_GOPALIGNMENT_DESCRIPTION TEXT_AMF_H264("GOPAlignment.Description") +#define AMF_H264_MAXIMUMREFERENCEFRAMES TEXT_AMF_H264("MaximumReferenceFrames") +#define AMF_H264_MAXIMUMREFERENCEFRAMES_DESCRIPTION TEXT_AMF_H264("MaximumReferenceFrames.Description") +#define AMF_H264_SLICESPERFRAME TEXT_AMF_H264("SlicesPerFrame") +#define AMF_H264_SLICESPERFRAME_DESCRIPTION TEXT_AMF_H264("SlicesPerFrame.Description") +#define AMF_H264_SLICEMODE TEXT_AMF_H264("SliceMode") +#define AMF_H264_SLICEMODE_DESCRIPTION TEXT_AMF_H264("SliceMode.Description") +#define AMF_H264_MAXIMUMSLICESIZE TEXT_AMF_H264("MaximumSliceSize") +#define AMF_H264_MAXIMUMSLICESIZE_DESCRIPTION TEXT_AMF_H264("MaximumSliceSize.Description") +#define AMF_H264_SLICECONTROLMODE TEXT_AMF_H264("SliceControlMode") +#define AMF_H264_SLICECONTROLMODE_DESCRIPTION TEXT_AMF_H264("SliceControlMode.Description") +#define AMF_H264_SLICECONTROLSIZE TEXT_AMF_H264("SliceControlSize") +#define AMF_H264_SLICECONTROLSIZE_DESCRIPTION TEXT_AMF_H264("SliceControlSize.Description") +#define AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES TEXT_AMF_H264("IntraRefresh.NumberOfStripes") +#define AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES_DESCRIPTION TEXT_AMF_H264("IntraRefresh.NumberOfStripes.Description") +#define AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT TEXT_AMF_H264("IntraRefresh.MacroblocksPerSlot") +#define AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT_DESCRIPTION TEXT_AMF_H264("IntraRefresh.MacroblocksPerSlot.Description") + +// System Properties +#define AMF_H264_VIDEOAPI TEXT_AMF_H264("VideoAPI") +#define AMF_H264_VIDEOAPI_DESCRIPTION TEXT_AMF_H264("VideoAPI.Description") +#define AMF_H264_VIDEOADAPTER TEXT_AMF_H264("VideoAdapter") +#define AMF_H264_VIDEOADAPTER_DESCRIPTION TEXT_AMF_H264("VideoAdapter.Description") +#define AMF_H264_OPENCL TEXT_AMF_H264("OpenCL") +#define AMF_H264_OPENCL_DESCRIPTION TEXT_AMF_H264("OpenCL.Description") +#define AMF_H264_VIEW TEXT_AMF_H264("View") +#define AMF_H264_VIEW_DESCRIPTION TEXT_AMF_H264("View.Description") +#define AMF_H264_VIEW_BASIC TEXT_AMF_H264("View.Basic") +#define AMF_H264_VIEW_ADVANCED TEXT_AMF_H264("View.Advanced") +#define AMF_H264_VIEW_EXPERT TEXT_AMF_H264("View.Expert") +#define AMF_H264_VIEW_MASTER TEXT_AMF_H264("View.Master") +#define AMF_H264_DEBUG TEXT_AMF_H264("Debug") +#define AMF_H264_DEBUG_DESCRIPTION TEXT_AMF_H264("Debug.Description") ////////////////////////////////////////////////////////////////////////// // Code @@ -40,7 +187,6 @@ public: static void encoder_register(); static const char* get_name(void* type_data); - static const char* get_name_simple(void* type_data); static void get_defaults(obs_data_t *settings); static obs_properties_t* get_properties(void* data);
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Include/plugin.h -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Include/plugin.h
Changed
@@ -46,8 +46,7 @@ #define vstr(s) dstr(s) #define dstr(s) #s - -#define clamp(a,b,c) (a > c ? c : (a < b ? b : a)) +#define clamp(val,low,high) (val > high ? high : (val < low ? low : val)) #include "Version.h" #define PLUGIN_VERSION_FULL (((uint64_t)PLUGIN_VERSION_MAJOR << 48ull) | ((uint64_t)PLUGIN_VERSION_MINOR << 32ull) | ((uint64_t)PLUGIN_VERSION_PATCH) | ((uint64_t)PLUGIN_VERSION_BUILD)) @@ -60,11 +59,6 @@ #define AMF_LOG_CONFIG(format, ...) AMF_LOG(350, format, ##__VA_ARGS__) #define AMF_LOG_DEBUG(format, ...) AMF_LOG(LOG_DEBUG, format, ##__VA_ARGS__) -#define TEXT_T(x) obs_module_text_multi(x) -#define TEXT_AMF(x) ("AMF." ## x) -#define TEXT_AMF_H264(x) (TEXT_AMF("H264." ## x)) -#define TEXT_AMF_UTIL(x) (TEXT_AMF("Util." ## x)) - #define ThrowExceptionWithAMFError(format, res, ...) {\ std::vector<char> _throwexceptionwithamferror_buf(8192);\ sprintf_s(_throwexceptionwithamferror_buf.data(), _throwexceptionwithamferror_buf.size(), format, ##__VA_ARGS__, Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res);\ @@ -73,142 +67,28 @@ } #ifndef __FUNCTION_NAME__ - #if defined(_WIN32) || defined(_WIN64) //WINDOWS - #define __FUNCTION_NAME__ __FUNCTION__ - #else //*NIX - #define __FUNCTION_NAME__ __func__ - #endif +#if defined(_WIN32) || defined(_WIN64) //WINDOWS +#define __FUNCTION_NAME__ __FUNCTION__ +#else //*NIX +#define __FUNCTION_NAME__ __func__ +#endif #endif ////////////////////////////////////////////////////////////////////////// // Defines - Translation Strings ////////////////////////////////////////////////////////////////////////// -// Presets -#define AMF_H264_PRESET TEXT_AMF_H264("Preset") -#define AMF_H264_PRESET_RESETTODEFAULTS TEXT_AMF_H264("Preset.ResetToDefaults") -#define AMF_H264_PRESET_RECORDING TEXT_AMF_H264("Preset.Recording") -#define AMF_H264_PRESET_HIGHQUALITY TEXT_AMF_H264("Preset.HighQuality") -#define AMF_H264_PRESET_INDISTINGUISHABLE TEXT_AMF_H264("Preset.Indistinguishable") -#define AMF_H264_PRESET_LOSSLESS TEXT_AMF_H264("Preset.Lossless") -#define AMF_H264_PRESET_TWITCH TEXT_AMF_H264("Preset.Twitch") -#define AMF_H264_PRESET_YOUTUBE TEXT_AMF_H264("Preset.YouTube") - -// Static Properties -#define AMF_H264_USAGE TEXT_AMF_H264("Usage") -#define AMF_H264_USAGE_DESCRIPTION TEXT_AMF_H264("Usage.Description") -#define AMF_H264_USAGE_TRANSCODING TEXT_AMF_H264("Usage.Transcoding") -#define AMF_H264_USAGE_ULTRALOWLATENCY TEXT_AMF_H264("Usage.UltraLowLatency") -#define AMF_H264_USAGE_LOWLATENCY TEXT_AMF_H264("Usage.LowLatency") -#define AMF_H264_USAGE_WEBCAM TEXT_AMF_H264("Usage.Webcam") -#define AMF_H264_QUALITY_PRESET TEXT_AMF_H264("QualityPreset") -#define AMF_H264_QUALITY_PRESET_DESCRIPTION TEXT_AMF_H264("QualityPreset.Description") -#define AMF_H264_QUALITY_PRESET_SPEED TEXT_AMF_H264("QualityPreset.Speed") -#define AMF_H264_QUALITY_PRESET_BALANCED TEXT_AMF_H264("QualityPreset.Balanced") -#define AMF_H264_QUALITY_PRESET_QUALITY TEXT_AMF_H264("QualityPreset.Quality") -#define AMF_H264_PROFILE TEXT_AMF_H264("Profile") -#define AMF_H264_PROFILE_DESCRIPTION TEXT_AMF_H264("Profile.Description") -#define AMF_H264_PROFILELEVEL TEXT_AMF_H264("ProfileLevel") -#define AMF_H264_PROFILELEVEL_DESCRIPTION TEXT_AMF_H264("ProfileLevel.Description") -#define AMF_H264_MAXIMUMLTRFRAMES TEXT_AMF_H264("MaximumLTRFrames") -#define AMF_H264_MAXIMUMLTRFRAMES_DESCRIPTION TEXT_AMF_H264("MaximumLTRFrames.Description") -#define AMF_H264_CODINGTYPE TEXT_AMF_H264("CodingType") -#define AMF_H264_CODINGTYPE_DESCRIPTION TEXT_AMF_H264("CodingType.Description") - -// Rate Control Properties -#define AMF_H264_RATECONTROLMETHOD TEXT_AMF_H264("RateControlMethod") -#define AMF_H264_RATECONTROLMETHOD_DESCRIPTION TEXT_AMF_H264("RateControlMethod.Description") -#define AMF_H264_RATECONTROLMETHOD_CQP TEXT_AMF_H264("RateControlMethod.CQP") -#define AMF_H264_RATECONTROLMETHOD_CBR TEXT_AMF_H264("RateControlMethod.CBR") -#define AMF_H264_RATECONTROLMETHOD_VBR TEXT_AMF_H264("RateControlMethod.VBR.Peak") -#define AMF_H264_RATECONTROLMETHOD_VBR_LAT TEXT_AMF_H264("RateControlMethod.VBR.Latency") -#define AMF_H264_BITRATE_TARGET TEXT_AMF_H264("Bitrate.Target") -#define AMF_H264_BITRATE_TARGET_DESCRIPTION TEXT_AMF_H264("Bitrate.Target.Description") -#define AMF_H264_BITRATE_PEAK TEXT_AMF_H264("Bitrate.Peak") -#define AMF_H264_BITRATE_PEAK_DESCRIPTION TEXT_AMF_H264("Bitrate.Peak.Description") -#define AMF_H264_QP_MINIMUM TEXT_AMF_H264("QP.Minimum") -#define AMF_H264_QP_MINIMUM_DESCRIPTION TEXT_AMF_H264("QP.Minimum.Description") -#define AMF_H264_QP_MAXIMUM TEXT_AMF_H264("QP.Maximum") -#define AMF_H264_QP_MAXIMUM_DESCRIPTION TEXT_AMF_H264("QP.Maximum.Description") -#define AMF_H264_QP_IFRAME TEXT_AMF_H264("QP.IFrame") -#define AMF_H264_QP_IFRAME_DESCRIPTION TEXT_AMF_H264("QP.IFrame.Description") -#define AMF_H264_QP_PFRAME TEXT_AMF_H264("QP.PFrame") -#define AMF_H264_QP_PFRAME_DESCRIPTION TEXT_AMF_H264("QP.PFrame.Description") -#define AMF_H264_QP_BFRAME TEXT_AMF_H264("QP.BFrame") -#define AMF_H264_QP_BFRAME_DESCRIPTION TEXT_AMF_H264("QP.BFrame.Description") -#define AMF_H264_QP_BPICTURE_DELTA TEXT_AMF_H264("QP.BPictureDelta") -#define AMF_H264_QP_BPICTURE_DELTA_DESCRIPTION TEXT_AMF_H264("QP.BPictureDelta.Description") -#define AMF_H264_QP_REFERENCE_BPICTURE_DELTA TEXT_AMF_H264("QP.ReferenceBPictureDelta") -#define AMF_H264_QP_REFERENCE_BPICTURE_DELTA_DESCRIPTION TEXT_AMF_H264("QP.ReferenceBPictureDelta.Description") -#define AMF_H264_VBVBUFFER TEXT_AMF_H264("VBVBuffer") -#define AMF_H264_VBVBUFFER_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Description") -#define AMF_H264_VBVBUFFER_STRICTNESS TEXT_AMF_H264("VBVBuffer.Strictness") -#define AMF_H264_VBVBUFFER_STRICTNESS_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Strictness.Description") -#define AMF_H264_VBVBUFFER_SIZE TEXT_AMF_H264("VBVBuffer.Size") -#define AMF_H264_VBVBUFFER_SIZE_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Size.Description") -#define AMF_H264_VBVBUFFER_FULLNESS TEXT_AMF_H264("VBVBuffer.Fullness") -#define AMF_H264_VBVBUFFER_FULLNESS_DESCRIPTION TEXT_AMF_H264("VBVBuffer.Fullness.Description") -#define AMF_H264_FILLERDATA TEXT_AMF_H264("FillerData") -#define AMF_H264_FILLERDATA_DESCRIPTION TEXT_AMF_H264("FillerData.Description") -#define AMF_H264_FRAMESKIPPING TEXT_AMF_H264("FrameSkipping") -#define AMF_H264_FRAMESKIPPING_DESCRIPTION TEXT_AMF_H264("FrameSkipping.Description") -#define AMF_H264_ENFORCEHRDCOMPATIBILITY TEXT_AMF_H264("EnforceHRDCompatibility") -#define AMF_H264_ENFORCEHRDCOMPATIBILITY_DESCRIPTION TEXT_AMF_H264("EnforceHRDCompatibility.Description") -#define AMF_H264_MAXIMUMACCESSUNITSIZE TEXT_AMF_H264("MaximumAccessUnitSize") -#define AMF_H264_MAXIMUMACCESSUNITSIZE_DESCRIPTION TEXT_AMF_H264("MaximumAccessUnitSize.Description") - -// Picture Control Properties -#define AMF_H264_KEYFRAME_INTERVAL TEXT_AMF_H264("KeyframeInterval") -#define AMF_H264_KEYFRAME_INTERVAL_DESCRIPTION TEXT_AMF_H264("KeyframeInterval.Description") -#define AMF_H264_IDR_PERIOD TEXT_AMF_H264("IDRPeriod") -#define AMF_H264_IDR_PERIOD_DESCRIPTION TEXT_AMF_H264("IDRPeriod.Description") -#define AMF_H264_HEADER_INSERTION_SPACING TEXT_AMF_H264("HeaderInsertionSpacing") -#define AMF_H264_HEADER_INSERTION_SPACING_DESCRIPTION TEXT_AMF_H264("HeaderInsertionSpacing.Description") -#define AMF_H264_BPICTURE_PATTERN TEXT_AMF_H264("BPicture.Pattern") -#define AMF_H264_BPICTURE_PATTERN_DESCRIPTION TEXT_AMF_H264("BPicture.Pattern.Description") -#define AMF_H264_BPICTURE_REFERENCE TEXT_AMF_H264("BPicture.Reference") -#define AMF_H264_BPICTURE_REFERENCE_DESCRIPTION TEXT_AMF_H264("BPicture.Reference.Description") -#define AMF_H264_DEBLOCKINGFILTER TEXT_AMF_H264("DeblockingFilter") -#define AMF_H264_DEBLOCKINGFILTER_DESCRIPTION TEXT_AMF_H264("DeblockingFilter.Description") -#define AMF_H264_SLICESPERFRAME TEXT_AMF_H264("SlicesPerFrame") -#define AMF_H264_SLICESPERFRAME_DESCRIPTION TEXT_AMF_H264("SlicesPerFrame.Description") -#define AMF_H264_INTRAREFRESHNUMMBSPERSLOT TEXT_AMF_H264("IntraRefreshNumMBsPerSlot") -#define AMF_H264_INTRAREFRESHNUMMBSPERSLOT_DESCRIPTION TEXT_AMF_H264("IntraRefreshNumMBsPerSlot.Description") - -// Miscellaneous Properties -#define AMF_H264_SCANTYPE TEXT_AMF_H264("ScanType") -#define AMF_H264_SCANTYPE_DESCRIPTION TEXT_AMF_H264("ScanType.Description") -#define AMF_H264_SCANTYPE_PROGRESSIVE TEXT_AMF_H264("ScanType.Progressive") -#define AMF_H264_SCANTYPE_INTERLACED TEXT_AMF_H264("ScanType.Interlaced") -#define AMF_H264_MOTIONESTIMATION TEXT_AMF_H264("MotionEstimation") -#define AMF_H264_MOTIONESTIMATION_DESCRIPTION TEXT_AMF_H264("MotionEstimation.Description") -#define AMF_H264_MOTIONESTIMATION_NONE TEXT_AMF_H264("MotionEstimation.None") -#define AMF_H264_MOTIONESTIMATION_HALF TEXT_AMF_H264("MotionEstimation.Half") -#define AMF_H264_MOTIONESTIMATION_QUARTER TEXT_AMF_H264("MotionEstimation.Quarter") -#define AMF_H264_MOTIONESTIMATION_BOTH TEXT_AMF_H264("MotionEstimation.Both") - -// System Properties -#define AMF_H264_DEVICE TEXT_AMF_H264("Device") -#define AMF_H264_DEVICE_DESCRIPTION TEXT_AMF_H264("Device.Description") -#define AMF_H264_USE_OPENCL TEXT_AMF_H264("UseOpenCL") -#define AMF_H264_USE_OPENCL_DESCRIPTION TEXT_AMF_H264("UseOpenCL.Description") -#define AMF_H264_VIEW TEXT_AMF_H264("View") -#define AMF_H264_VIEW_DESCRIPTION TEXT_AMF_H264("View.Description") -#define AMF_H264_VIEW_BASIC TEXT_AMF_H264("View.Basic") -#define AMF_H264_VIEW_ADVANCED TEXT_AMF_H264("View.Advanced") -#define AMF_H264_VIEW_EXPERT TEXT_AMF_H264("View.Expert") -#define AMF_H264_VIEW_MASTER TEXT_AMF_H264("View.Master") -#define AMF_H264_UNLOCK_PROPERTIES TEXT_AMF_H264("UnlockProperties") -#define AMF_H264_UNLOCK_PROPERTIES_DESCRIPTION TEXT_AMF_H264("UnlockProperties.Description") -#define AMF_H264_DEBUG TEXT_AMF_H264("Debug") -#define AMF_H264_DEBUG_DESCRIPTION TEXT_AMF_H264("Debug.Description") +#define TEXT_T(x) obs_module_text_multi(x) +#define TEXT_AMF(x) ("AMF." ## x) +#define TEXT_AMF_H264(x) (TEXT_AMF("H264." ## x)) +#define TEXT_AMF_UTIL(x) (TEXT_AMF("Util." ## x)) // Utility -#define AMF_UTIL_DEFAULT TEXT_AMF_UTIL("Default") -#define AMF_UTIL_AUTOMATIC TEXT_AMF_UTIL("Automatic") -#define AMF_UTIL_MANUAL TEXT_AMF_UTIL("Manual") -#define AMF_UTIL_TOGGLE_DISABLED TEXT_AMF_UTIL("Toggle.Disabled") -#define AMF_UTIL_TOGGLE_ENABLED TEXT_AMF_UTIL("Toggle.Enabled") +#define AMF_UTIL_DEFAULT TEXT_AMF_UTIL("Default") +#define AMF_UTIL_AUTOMATIC TEXT_AMF_UTIL("Automatic") +#define AMF_UTIL_MANUAL TEXT_AMF_UTIL("Manual") +#define AMF_UTIL_TOGGLE_DISABLED TEXT_AMF_UTIL("Toggle.Disabled") +#define AMF_UTIL_TOGGLE_ENABLED TEXT_AMF_UTIL("Toggle.Enabled") ////////////////////////////////////////////////////////////////////////// // Threading Specific @@ -223,4 +103,4 @@ void SetThreadName(std::thread* thread, const char* threadName); void SetThreadName(const char* threadName); -#endif \ No newline at end of file +#endif
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/README.md -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/README.md
Changed
@@ -6,7 +6,90 @@ Read [CONTRIBUTING.md](https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/CONTRIBUTING.md) for a guide on how to start. -## MIT License +# Contributors +These people have helped (in one way or another) making this project possible. Without them, this project would have most likely not been where it is. + +| Who | What | +| --- | ---- | +| [Jim](https://github.com/jp9000) | Origin of the Open Broadcaster Software, provided support for development questions. | +| [jackun](http://github.com/jackun) | The awesome person that started it all with his own Classic and Studio fork.<br>Thanks to him this project even exists today. | +| [Xaymar](http://github.com/Xaymar) | Just the guy who spent a week staring at his monitors, trying to figure out how to make it work. | +| GolDAce | CrowdIn integration. | +| [leporel](https://github.com/leporel) | Provided ru-RU language files (Russian) | +| [max20091](https://github.com/max20091) | Provided vi-VN language files (Vietnamese) | +| [M4RK22](https://github.com/M4RK22) | Provided es-ES language files (Spanish) | +| [niteforce](https://github.com/niteforce) | Provided hu-HU language files (Hungarian) | +| [nwgat](https://github.com/nwgat) | Provided nb-NO language files (Norwegian) | +| [wazerstar](https://github.com/wazerstar) | Provided da-DK language files (Danish) | +| AMD | Providing Media SDK and later providing the AMF SDK. Also for incredibly fast fixing of bugs. | + +## The Amazing Supporters +Special thanks go out to those that have either donated to the project directly or have decided to put some of their spare money into [my Patreon](https://patreon.com/xaymar). You guys rock! + +**[Jim](https://github.com/jp9000)** +Basically created the entire OBS project, without him it wouldn't even be here. + +**Kytos/M4RK22** <!-- https://www.patreon.com/user?u=3762404 --> +Im happy to support a nice recording plugin for AMD users. +Patron: 2016 August-November +[Website](https://markitos.ovh), [Steam](http://steamcommunity.com/id/markitos22/) + +**nwgat.ninja** <!-- https://www.patreon.com/user?u=2885495 --> +nwgat.ninja is proud to support Xaymars Technology Projects. +Patron: 2016 August-November +[Website](https://nwgat.ninja) + +**Mattheus Wiegand** +Patron: 2016 August, September +[Twitter](https://twitter.com/Morphy2k/), [GitHub](https://github.com/Morphy2k) + +**Jeremy "razorlikes" Nieth** <!-- https://www.patreon.com/user?u=2463662 --> +I like to support this project because it gives me a way to stream without having to sacrifice immense amounts of cpu resources for encoding. +Patron: 2016 August-November +[Twitch](https://twitch.tv/razorlikes), [GitHub](https://github.com/razorlikes) + +**Kristian Kirkesæther** <!-- https://www.patreon.com/user?u=3963961 --> +Patron: 2016 September-November + +**vektorDex** <!-- https://www.patreon.com/vDex --> +Patron: 2016 September-November +[Website](http://blog-of-dex.de/), [Twitter](https://twitter.com/vektordex), [Studio](http://digitaldawnstudios.com) + +**AJ** <!-- https://www.patreon.com/user?u=3931856 --> +Patron: 2016 September-November + +**SneakyJoe** <!-- https://www.patreon.com/sneaky4oe --> +Russian streamer and stream teacher, AMD fanboy. Wants to make AMD great again. +Patron: 2016 September-November +[Website](http://sneakyjoe.ru/), [YouTube](https://www.youtube.com/channel/UCUmRv5GwQcsnxXRzuPCGr-Q) + +**Nicholas Kreimeyer** <!-- https://www.patreon.com/user?u=280867 --> +Patron: 2016 October, November + +**noext** <!-- https://www.patreon.com/user?u=3209509 --> +Patron: 2016 October + +**John Difool** <!-- https://www.patreon.com/user?u=3972864 --> +John Difool der alte Sack +Patron: 2016 October, November +[YouTube](https://www.youtube.com/channel/UC5FPsFLQh4ah0-vz-eoZlOA) + +**DaOrgest** <!-- https://www.patreon.com/daorgest --> +Currently studying computer and I do YouTube for a hobby +Patron: 2016 September-November +[Website](http://daorgest.me), [YouTube](http://youtube.com/daorgest) + +**Nucu** <!-- https://www.patreon.com/user?u=187366 --> +Thanks AMD and Xaymar to make hardware encoding possible. +Patron: 2016 August-November + +**Daniel Bagge** <!-- https://www.patreon.com/user?u=2457937 --> +Patron: 2016 September-November + +**Cihangir Ceviren** <!-- https://www.patreon.com/user?u=4509018 --> +Patron: 2016 November + +# MIT License Copyright (c) 2016 Michael Fabian Dirks
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/bg-BG.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/bg-BG.ini
Changed
@@ -1,5 +1,6 @@ +AMF.Util.Default="По подразбиране" +AMF.Util.Manual="Ръчно" AMF.H264.Profile="Профил" AMF.H264.View.Advanced="Разширения" AMF.H264.Debug="Дебъг" -AMF.Util.Default="По подразбиране" -AMF.Util.Manual="Ръчно" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/ca-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/ca-ES.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Per defecte" +AMF.Util.Automatic="Automàtic" +AMF.Util.Manual="Manual" +AMF.Util.Toggle.Disabled="Desactivat" +AMF.Util.Toggle.Enabled="Activat" AMF.H264.Preset="Configuració preestablerta" AMF.H264.Preset.Recording="S'està enregistrant" AMF.H264.Preset.HighQuality="Alta qualitat" @@ -16,10 +21,6 @@ AMF.H264.QualityPreset.Quality="Qualitat" AMF.H264.Profile="Perfil" AMF.H264.ProfileLevel="Nivell de perfil" -AMF.H264.MaximumLTRFrames="Fotogrames màxims LTR" -AMF.H264.ScanType="Tipus d'exploració" -AMF.H264.ScanType.Progressive="Progressiu" -AMF.H264.ScanType.Interlaced="Entrellaçat" AMF.H264.RateControlMethod="Mètode de control del flux" AMF.H264.RateControlMethod.CQP="QP constant (CQP)" AMF.H264.RateControlMethod.CBR="Flux constant (CBR)" @@ -32,30 +33,23 @@ AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta="QP Delta en B-Pictures de referencia" AMF.H264.FillerData="Dades a omplir" AMF.H264.FrameSkipping="Omissió de fotogrames" AMF.H264.EnforceHRDCompatibility="Força la compatibilitat amb HRD" -AMF.H264.BPicture.Pattern="Patró B-Picture" -AMF.H264.BPicture.Reference="Referència B-Picture" AMF.H264.DeblockingFilter="Filtre d'eliminació de blocs" +AMF.H264.ScanType="Tipus d'exploració" +AMF.H264.ScanType.Progressive="Progressiu" +AMF.H264.ScanType.Interlaced="Entrellaçat" AMF.H264.MotionEstimation.None="Cap" AMF.H264.MotionEstimation.Half="Meitat de píxel" AMF.H264.MotionEstimation.Quarter="Quart de Píxel" -AMF.H264.Device="Dispositiu" +AMF.H264.MaximumLTRFrames="Fotogrames màxims LTR" AMF.H264.View="Mode de visualització" AMF.H264.View.Description="Quines propietats han de ser visibles. No rebreu suport si feu servir el mode de vista 'Expert' o 'Màster'." AMF.H264.View.Basic="Bàsic" AMF.H264.View.Advanced="Avançat" AMF.H264.View.Expert="Expert" AMF.H264.View.Master="Màster" -AMF.H264.UnlockProperties="Desbloqueja les propietats" -AMF.H264.UnlockProperties.Description="Desbloqueja algunes propietats a la seva màxima capacitat en lloc de limitar-les de forma parcial." AMF.H264.Debug="Depuració" AMF.H264.Debug.Description="Habilita el registre d'informació de depuració addicional, ha de ser activat quan necessiteu ajuda amb aquest codificador." -AMF.Util.Default="Per defecte" -AMF.Util.Automatic="Automàtic" -AMF.Util.Manual="Manual" -AMF.Util.Toggle.Disabled="Desactivat" -AMF.Util.Toggle.Enabled="Activat" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/cs-CZ.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/cs-CZ.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Výchozí" +AMF.Util.Automatic="Automatické" +AMF.Util.Manual="Manuální" +AMF.Util.Toggle.Disabled="Zakázáno" +AMF.Util.Toggle.Enabled="Povoleno" AMF.H264.Preset="Profil" AMF.H264.Preset.ResetToDefaults="Obnovit výchozí" AMF.H264.Preset.Recording="Nahrávání" @@ -16,11 +21,6 @@ AMF.H264.QualityPreset.Quality="Kvalita" AMF.H264.Profile="Profil" AMF.H264.ProfileLevel="Úroveň profilu" -AMF.H264.MaximumLTRFrames="Maximální počet LTR snímků" -AMF.H264.ScanType="Typ skenování" -AMF.H264.ScanType.Description="Určuje použitou metodu skenování, vždy ponechejte na 'Progresivní'." -AMF.H264.ScanType.Progressive="Progresivní" -AMF.H264.ScanType.Interlaced="Prokládané" AMF.H264.RateControlMethod="Metoda řízení" AMF.H264.RateControlMethod.CQP="Konstantní QP (CQP)" AMF.H264.RateControlMethod.CBR="Konstantní bitrate (CBR)" @@ -32,32 +32,41 @@ AMF.H264.Bitrate.Peak.Description="Bitrate, kterého se máme snažit nepřekročit v celé sekvenci." AMF.H264.QP.Minimum="Minimální QP" AMF.H264.QP.Maximum="Maximální QP" +AMF.H264.QP.IFrame="I-Frame QP" +AMF.H264.QP.IFrame.Description="Pevná hodnota QP používaná pro I-Frames." +AMF.H264.QP.PFrame="P-Frame QP" +AMF.H264.QP.PFrame.Description="Pevná hodnota QP používaná pro P-Frames." +AMF.H264.QP.BFrame="B-Frame QP" +AMF.H264.QP.BFrame.Description="Pevná hodnota QP používaná pro B-Frames." +AMF.H264.VBVBuffer="VBV Buffer" AMF.H264.FillerData="Filtrovat data" AMF.H264.FrameSkipping="Přeskakování snímků" AMF.H264.EnforceHRDCompatibility="Vynutit kompatibilitu s HRD" AMF.H264.KeyframeInterval="Interval klíčový snímků" AMF.H264.KeyframeInterval.Description="Kolik vteřin by mělo být mezi ne-zahazovatelnými snímky.\nTaké ovládá velikost sekvence(GOP)." +AMF.H264.ScanType="Typ skenování" +AMF.H264.ScanType.Description="Určuje použitou metodu skenování, vždy ponechejte na 'Progresivní'." +AMF.H264.ScanType.Progressive="Progresivní" +AMF.H264.ScanType.Interlaced="Prokládané" AMF.H264.MotionEstimation="Odhad pohybu" AMF.H264.MotionEstimation.Description="Odhad pohybu umožňuje enkodéru snížit požadovaný bitrate předpovídáním, kam se určitý pixel posunul." AMF.H264.MotionEstimation.None="Žádný" AMF.H264.MotionEstimation.Half="Polovina pixelu" AMF.H264.MotionEstimation.Quarter="Čtvrtina pixelu" AMF.H264.MotionEstimation.Both="Polovina & čtvrtina pixelu" -AMF.H264.Device="Zařízení" -AMF.H264.UseOpenCL="Použít OpenCL" -AMF.H264.UseOpenCL.Description="Měl by enkodér použít OpenCL pro potvrzování samostatných snímků?" +AMF.H264.MaximumLTRFrames="Maximální počet LTR snímků" +AMF.H264.VideoAPI="Grafické rozhraní (API)" +AMF.H264.VideoAPI.Description="Které rozhraní má být použito pro kódování." +AMF.H264.VideoAdapter="Grafický adaptér" +AMF.H264.VideoAdapter.Description="Adaptér, který má být použit pro kódování." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="Má být použit OpenCL pro vkládání jednotlivých snímků?" AMF.H264.View="Režim zobrazení" AMF.H264.View.Description="Které možnosti mají být zobrazeny. Nezískáte žádnou pomoc při použití módu 'Expert' či 'Master'." AMF.H264.View.Basic="Základní" AMF.H264.View.Advanced="Pokročilý" AMF.H264.View.Expert="Expert" AMF.H264.View.Master="Master" -AMF.H264.UnlockProperties="Odblokovat vlastnosti" -AMF.H264.UnlockProperties.Description="Odblokuje určité vlastnosti do jejich plného rozsahu místo omezování do určitého." AMF.H264.Debug="Ladění" AMF.H264.Debug.Description="Zapne rozšířené protokolování, mělo by být zapnuto, pokud pořebujete pomoci s tmto enkodérem." -AMF.Util.Default="Výchozí" -AMF.Util.Automatic="Automatické" -AMF.Util.Manual="Manuální" -AMF.Util.Toggle.Disabled="Zakázáno" -AMF.Util.Toggle.Enabled="Povoleno" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/da-DK.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/da-DK.ini
Changed
@@ -1,3 +1,6 @@ +AMF.Util.Default="Standard" +AMF.Util.Toggle.Disabled="Deaktiveret" +AMF.Util.Toggle.Enabled="Aktiveret" AMF.H264.Usage.Transcoding="Transcoding" AMF.H264.Usage.UltraLowLatency="Ekstrem Lav Ventetid" AMF.H264.Usage.LowLatency="Lav Ventetid" @@ -7,9 +10,6 @@ AMF.H264.QualityPreset.Quality="Kvalitet (Bedste Kvalitet)" AMF.H264.Profile="Profil" AMF.H264.ProfileLevel="Profil Niveau" -AMF.H264.ScanType="Scan Type" -AMF.H264.ScanType.Progressive="Progressive" -AMF.H264.ScanType.Interlaced="Interlaced" AMF.H264.RateControlMethod="Rate Control Method" AMF.H264.RateControlMethod.CQP="Constant QP (CQP)" AMF.H264.RateControlMethod.CBR="Constant Bitrate (CBR)" @@ -22,13 +22,11 @@ AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" AMF.H264.FillerData="Filler Data" AMF.H264.FrameSkipping="Billede skip" AMF.H264.EnforceHRDCompatibility="Tving HRD Kompatibilitet" -AMF.H264.BPicture.Pattern="B-Picture Pattern" -AMF.H264.BPicture.Reference="B-Picture Reference" AMF.H264.DeblockingFilter="Deblocking Filter" -AMF.Util.Default="Standard" -AMF.Util.Toggle.Disabled="Deaktiveret" -AMF.Util.Toggle.Enabled="Aktiveret" +AMF.H264.ScanType="Scan Type" +AMF.H264.ScanType.Progressive="Progressive" +AMF.H264.ScanType.Interlaced="Interlaced" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/de-DE.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/de-DE.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Standard" +AMF.Util.Automatic="Automatisch" +AMF.Util.Manual="Manuell" +AMF.Util.Toggle.Disabled="Deaktiviert" +AMF.Util.Toggle.Enabled="Aktiviert" AMF.H264.Preset="Voreinstellungen" AMF.H264.Preset.ResetToDefaults="Standardeinstellungen wiederherstellen" AMF.H264.Preset.Recording="Aufnahme" @@ -17,17 +22,9 @@ AMF.H264.QualityPreset.Balanced="Ausgeglichen" AMF.H264.QualityPreset.Quality="Qualität" AMF.H264.Profile="Profil" -AMF.H264.Profile.Description="Welches H.264 Profil soll für das codieren verwendet werden:\n- 'Baseline' hat die größte Betriebssystemunterstützung,\n- 'Main' wird von älteren Geräten unterstützt (empfohlen sofern das Ziel mobile Geräte sind),\n- 'High' wird von neueren Geräten unterstützt (empfohlen)." +AMF.H264.Profile.Description="Welches H.264 Profil soll für die Kodierung verwendet werden, sortiert von höchster Qualität bis am weitesten verbeiteten Unterstützung." AMF.H264.ProfileLevel="Profillevel" AMF.H264.ProfileLevel.Description="Welches H.264 Profil Level für das verarbeiten verwendet werden soll:\n- '\@AMF.Util.Automatic\@' errechnet das beste Profil Level für die gegebene Frame Rate und Frame Größe,\n- '4.1' unterstützt 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' unterstützt 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' unterstützt 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' unterstützt 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' unterstützt 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Maximale Langzeitreferenz-Bilder" -AMF.H264.MaximumLTRFrames.Description="Langzeitreferenz (LTR) Bilder ist ein Feature das dem Codierer erlaubt, einige Bilder innerhalb einer Sequenz als referenzierbar zu markieren.\nDies kann einen positiven Effekt auf die Qualität haben sofern B-Bilder nicht unterstützt oder gewollt sind.\nLTR Bilder können nicht zusammen mit B-Bildern verwendet werden und der Codierer wird B-Bilder deaktivieren sofern diese verwendet werden." -AMF.H264.CodingType="Codierungstyp" -AMF.H264.CodingType.Description="Welcher Codierungstyp verwendet werden soll:\n* \@AMF.Util.Default\@ lässt AMF entscheiden (empfohlen).\n* CALVC (Context-Adaptive Variable-Length Coding) ist schneller aber größer.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) ist langsamer aber kleiner." -AMF.H264.ScanType="Abtastverfahren" -AMF.H264.ScanType.Description="Welches Abtastverfahren verwendet werden soll. Sollte immer '\@AMF.H264.ScanType.Progressive\@' sein." -AMF.H264.ScanType.Progressive="Progressiv" -AMF.H264.ScanType.Interlaced="Zeilensprung" AMF.H264.RateControlMethod="Ratenkontrollmethode" AMF.H264.RateControlMethod.Description="Welche Ratenkontrollmethode verwendet werden soll:\n- '\@AMF.H264.RateControlMethod.CQP\@' setzt feste QP (Quantifizierungsparameter) Werte für I-/P-/B- Bilder,\n- '\@AMF.H264.RateControlMethod.CBR\@' bleibt auf der Zielbitrate (mithilfe von Füllungsdaten) (empfohlen für das Streamen),\n- '\@AMF.H264.RateControlMethod.VBR\@' bleibt unter der Spitzenbitrate,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' bleibt nahe der Zielbitrate sofern GPU-Latenz und GPU-Benutzung dies erlauben, ansonsten wird eine höhere Bitrate verwendet (empfohlen für Aufnahmen)." AMF.H264.RateControlMethod.CQP="Konstante QP (CQP)" @@ -43,22 +40,18 @@ AMF.H264.QP.Maximum="Maximale QP" AMF.H264.QP.Maximum.Description="Höchster QP (Quantifizierungsparameter) wert der in einem Bild verwendet wird." AMF.H264.QP.IFrame="I-Einzelbild QP" -AMF.H264.QP.IFrame.Description="Fester QP (Quantifizierungsparameter) wert der für I-Bilder genutzt wird.\nI-Bild QP sollte höher oder gleich wie der von P- und B-Bildern sein." +AMF.H264.QP.IFrame.Description="Fester QP wert der für I-Bilder verwendet wird." AMF.H264.QP.PFrame="P-Einzelbild QP" -AMF.H264.QP.PFrame.Description="Fester QP (Quantifizierungsparameter) wert der für P-Bilder genutzt wird.\nI-Bild QP sollte höher oder gleich wie der von B-Bildern sein." +AMF.H264.QP.PFrame.Description="Fester QP wert der für P-Bilder verwendet wird." AMF.H264.QP.BFrame="B-Einzelbild QP" -AMF.H264.QP.BFrame.Description="Fester QP (Quantifizierungsparameter) wert der für B-Bilder genutzt wird." -AMF.H264.QP.BPictureDelta="B-Bild Delta QP" -AMF.H264.QP.BPictureDelta.Description="Delta QP wert zum letzten nicht-Referenz B-Bild." -AMF.H264.QP.ReferenceBPictureDelta="Referenz B-Bild Delta QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="Delta QP wert zum letzten Referenz B-Bild." +AMF.H264.QP.BFrame.Description="Fester QP wert der für B-Bilder verwendet wird." AMF.H264.VBVBuffer="VBV Buffer" AMF.H264.VBVBuffer.Description="Welche Methode genutzt werden soll um die VBV-Puffergröße zu bestimmen:\n- '\@AMF.Util.Automatic\@' errechnet diese mithilfe einer Strengeneinschränkung,\n- '\@AMF.Util.Manual\@' erlaubt es dem Nutzer die Größe zu kontrollieren.\n VBV (Videopufferungsverifizierer) Puffer wird von verschiedenen Ratenkontrollmethoden genutzt um die gesamte Bitrate innerhalb der Begrenzungen zu halten." AMF.H264.VBVBuffer.Strictness="VBV Buffer Genauigkeit" -AMF.H264.VBVBuffer.Strictness.Description="Wie streng der VBV Buffer sein soll, wobei 100% fast exakt die Zielbitrate und 0% komplett unbeschränkt ist." +AMF.H264.VBVBuffer.Strictness.Description="Legt die Einschränkungsstärke des VBV Buffers fest, wobei 100% so eingeschränkt wie möglich ist und 0% komplett uneingeschränkt." AMF.H264.VBVBuffer.Size="VBV Buffer Größe" -AMF.H264.VBVBuffer.Size.Description="Die Größe des VBV Buffers der für die Bitratenkontrollen in einer Sequenz verwendet wird.\nEine kleine Größe ergibt eine fast perfekte Übereinstimmung mit der Bitrate aber hat einen größeren Performanzeinfluss." +AMF.H264.VBVBuffer.Size.Description="Die Größe des VBV Buffers, welcher für die Bitratenkontrolle in einer Sequenz verwendet wird." AMF.H264.VBVBuffer.Fullness="VBV Buffer Füllung" AMF.H264.VBVBuffer.Fullness.Description="Wie voll der VBV Buffer anfangs ist, hat nur einen Effekt auf die erste Sequenz beim codieren." AMF.H264.FillerData="Füllungsdaten" @@ -66,47 +59,77 @@ AMF.H264.FrameSkipping="Bildüberspringung" AMF.H264.FrameSkipping.Description="Bildüberspringung erlaubt es dem Codierer, Bilder zu überspringen um die Zielbitrate einzuhalten.\nWenn der Codierer ein Bild überspringt, fügt dieser stattdessen ein repeat-last-frame NAL in den Stream ein.\nKann bei sehr niedrigen Zielbitraten helfen." AMF.H264.EnforceHRDCompatibility="Erzwinge HRD Kompatiblität" -AMF.H264.EnforceHRDCompatibility.Description="Erzwinge Hypothetischer-Referenz-Decodierer Limitierungen welches die maximale Änderung des QP werts innerhalb eines Bildes begrenzt.\nNicht empfohlen für Aufname oder Streamen und sollte nur verwendet werden sofern das Ziel sehr alte Geräte mit einem Softwarereferenz Decodierer sind." -AMF.H264.MaximumAccessUnitSize="Maximale Zugriffseinheitsgröße" -AMF.H264.MaximumAccessUnitSize.Description="Größte Größe einer Zugriffseinheit für einen NAL. Ein Wert von 0 erlaubt es dem Codierer die beste Größte zu wählen." +AMF.H264.EnforceHRDCompatibility.Description="Erzwinge Hypothetischer-Referenz-Decodierer Limitierungen welches die maximale Änderung des QP werts innerhalb eines Bildes begrenzt." AMF.H264.KeyframeInterval="Keyframeintervall" AMF.H264.KeyframeInterval.Description="Definiert die Distanz zwischen Keyframes in Sekunden. Setzt auch die Größe einer GOP-Sequenz fest." AMF.H264.IDRPeriod="IDR Zeitraum" AMF.H264.IDRPeriod.Description="Definiert die Distanz zwischen Sofortigen-Decodierer-Aktualisierungen (IDR) in Frames. Setzt auch die Größe einer GOP-Sequenz fest." -AMF.H264.HeaderInsertionSpacing="Dateikopfeinfügungsabstand" -AMF.H264.HeaderInsertionSpacing.Description="Wie viele Bilder zwischen NAL-Kopfzeilen sein sollen. Es wird nicht empfohlen dies von 0 (automatisch) zu ändern." -AMF.H264.BPicture.Pattern="B-Bild Muster" -AMF.H264.BPicture.Pattern.Description="Wie viele B-Bilder sollen erlaubt sein für das codieren. Dies hat einen positiven Einfluss auf Qualität und einen negativen Einfluss auf Performanz.\nWird nur von der 2. und 3. Generation an VCE-Karten unterstützt." -AMF.H264.BPicture.Reference="B-Bild Referenz" -AMF.H264.BPicture.Reference.Description="Erlaube B-Bilder andere B-Bilder zu verwenden.\nSehr großer Einfluss auf Performanz, wenig Einfluss auf Qualität." +AMF.H264.BFrame.Pattern="B-Bilder" +AMF.H264.BFrame.Pattern.Description="Wie viele B-Bilder beim codieren verwendet werden sollen.\nWird von der 2ten und 3ten generation an VCE-Karten unterstützt. Negativer Einfluss auf Codierungsperformanz." +AMF.H264.BFrame.DeltaQP="Delta QP für B-Bilder" +AMF.H264.BFrame.DeltaQP.Description="Delta QP wert zum letzten I- or P-Bild für nicht referenzierbare B-Bilder." +AMF.H264.BFrame.Reference="Referenzierbare B-Bilder" +AMF.H264.BFrame.Reference.Description="Erlaube einem B-Bild andere B-Bilder als referenz zu verwenden, anstatt nur P- und I-Bilder." +AMF.H264.BFrame.ReferenceDeltaQP="Delta QP für referenzierbare B-Bilder" +AMF.H264.BFrame.ReferenceDeltaQP.Description="Delta QP wert zum letzten I- or P-Bild für referenzierbare B-Bilder." AMF.H264.DeblockingFilter="Entblockungsfilter" AMF.H264.DeblockingFilter.Description="Setze die Markierung dass der Decodierer einen Entblockungsfilter verwenden darf." -AMF.H264.SlicesPerFrame="Slices pro Frame" -AMF.H264.SlicesPerFrame.Description="Wie viele I-Bild-Schnitte sollen mit jedem Bild gespeichert werden?\nEin Wert von Null erlaubt es dem Codierer während dem codieren die Entscheidung zu treffen.\nIntra-Erneuerungs-Codieren wird genutzt für schnelleres abspielen und suchen." -AMF.H264.IntraRefreshNumMBsPerSlot="Intra-Refresh Anzahl der Makroblöcke pro Slot" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="Wie viele Makroblöcke sollen pro Slot gespeichert werden?\nEin Wert von Null erlaubt es dem Codierer während dem codieren die Entscheidung zu treffen.\nIntra-Erneuerungs-Codieren wird genutzt für schnelleres abspielen und suchen." +AMF.H264.ScanType="Abtastverfahren" +AMF.H264.ScanType.Description="Welches Abtastverfahren verwendet werden soll. Sollte immer '\@AMF.H264.ScanType.Progressive\@' sein." +AMF.H264.ScanType.Progressive="Progressiv" +AMF.H264.ScanType.Interlaced="Zeilensprung" AMF.H264.MotionEstimation="Bewegungsschätzung" AMF.H264.MotionEstimation.Description="Bewegungsschätzung erlaubt des dem Codierer die benötigte Bitrate zu reduzieren durch das herausfinden, wo ein Pixel hinbewegt wurde." AMF.H264.MotionEstimation.None="Keine" AMF.H264.MotionEstimation.Half="Halb-Pixel" AMF.H264.MotionEstimation.Quarter="Viertel-Pixel" AMF.H264.MotionEstimation.Both="Halb- & Viertel-Pixel" -AMF.H264.Device="Gerät" -AMF.H264.Device.Description="Welches Gerät für das codieren verwendet werden soll.\nBenötigt einen anderen Speichertyp als 'Host'." -AMF.H264.UseOpenCL="Benutze OpenCL" -AMF.H264.UseOpenCL.Description="Soll OpenCL verwendet werden, um Einzelbilder zum Codierer zu senden?" +AMF.H264.CodingType="Codierungstyp" +AMF.H264.CodingType.Description="Welcher Codierungstyp verwendet werden soll:\n* \@AMF.Util.Default\@ lässt AMF entscheiden (empfohlen).\n* CALVC (Context-Adaptive Variable-Length Coding) ist schneller aber größer.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) ist langsamer aber kleiner." +AMF.H264.MaximumLTRFrames="Maximale Langzeitreferenz-Bilder" +AMF.H264.MaximumLTRFrames.Description="Langzeitreferenz (LTR) Bilder ist ein Feature das dem Codierer erlaubt, einige Bilder innerhalb einer Sequenz als referenzierbar zu markieren.\nLTR Bilder können nicht zusammen mit B-Bildern verwendet werden und der Codierer wird B-Bilder deaktivieren sofern diese verwendet werden." +AMF.H264.MaximumAccessUnitSize="Maximale Zugriffseinheitsgröße" +AMF.H264.MaximumAccessUnitSize.Description="Größte Größe einer Zugriffseinheit für einen NAL." +AMF.H264.HeaderInsertionSpacing="Dateikopfeinfügungsabstand" +AMF.H264.HeaderInsertionSpacing.Description="Wie viele Bilder zwischen NAL-Kopfzeilen sein sollen." +AMF.H264.WaitForTask="Warte auf Arbeit" +AMF.H264.WaitForTask.Description="Unbekannt, Experimentell" +AMF.H264.PreAnalysisPass="Voranalyse Durchlauf" +AMF.H264.PreAnalysisPass.Description="Unbekannt, Experimentell" +AMF.H264.VBAQ="VBAQ" +AMF.H264.VBAQ.Description="Unbekannt, Experimentell" +AMF.H264.GOPSize="GOP Größe" +AMF.H264.GOPSize.Description="Unbekannt, Experimentell" +AMF.H264.GOPAlignment="GOP Angleichung" +AMF.H264.GOPAlignment.Description="Unbekannt, Experimentell" +AMF.H264.MaximumReferenceFrames="Maximale Referenzbilder" +AMF.H264.MaximumReferenceFrames.Description="Unbekannt, Experimentell" +AMF.H264.SlicesPerFrame="Slices pro Frame" +AMF.H264.SlicesPerFrame.Description="Wie viele I-Bild-Schnitte sollen mit jedem Bild gespeichert werden?\nEin Wert von Null erlaubt es dem Codierer während dem codieren die Entscheidung zu treffen.\nIntra-Erneuerungs-Codieren wird genutzt für schnelleres abspielen und suchen." +AMF.H264.SliceMode="Schnittmodus" +AMF.H264.SliceMode.Description="Unbekannt, Experimentell" +AMF.H264.MaximumSliceSize="Maximale Schnittgröße" +AMF.H264.MaximumSliceSize.Description="Unbekannt, Experimentell" +AMF.H264.SliceControlMode="Schnittkontrollmodus" +AMF.H264.SliceControlMode.Description="Unbekannt, Experimentell" +AMF.H264.SliceControlSize="Schnittkontrollgröße" +AMF.H264.SliceControlSize.Description="Unbekannt, Experimentell" +AMF.H264.IntraRefresh.NumberOfStripes="Intra-Refresh Anzahl an Streifen" +AMF.H264.IntraRefresh.NumberOfStripes.Description="Unbekannt, Experimentell" +AMF.H264.IntraRefresh.MacroblocksPerSlot="Intra-Refresh Makroblöcke pro Slot" +AMF.H264.IntraRefresh.MacroblocksPerSlot.Description="Wie viele Makroblöcke sollen pro Slot gespeichert werden?\nEin Wert von Null schaltet diese Feature ab.\nIntra-Erneuerungs-Codieren wird genutzt für schnelleres abspielen und suchen." +AMF.H264.VideoAPI="Video API" +AMF.H264.VideoAPI.Description="Welche API für das codieren verwendet werden soll." +AMF.H264.VideoAdapter="Video Adapter" +AMF.H264.VideoAdapter.Description="Welcher Adapter für das codieren verwendet werden soll." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="Soll der Codierer OpenCL zum übertragen der Bilder verwenden?" AMF.H264.View="Ansichtsmodus" AMF.H264.View.Description="Welche Eigenschaften sollen sichtbar sein?\nDas benutzen von '\@AMF.H264.View.Master\@' disqualifiziert dich von jeglichen Support." AMF.H264.View.Basic="Grundlegend" AMF.H264.View.Advanced="Erweitert" AMF.H264.View.Expert="Experte" AMF.H264.View.Master="Meister" -AMF.H264.UnlockProperties="Entsperre Einstellungen" -AMF.H264.UnlockProperties.Description="Entsperre einige Einstellungen, sodass diese die volle Reichweite haben, anstatt nur eine begrenzte." AMF.H264.Debug="Debug" AMF.H264.Debug.Description="Aktiviere erweiterte Debug-Nachrichten, sollte aktiv sein wenn man Hilfe erwartet mit diesem Codierer." -AMF.Util.Default="Standard" -AMF.Util.Automatic="Automatisch" -AMF.Util.Manual="Manuell" -AMF.Util.Toggle.Disabled="Deaktiviert" -AMF.Util.Toggle.Enabled="Aktiviert" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/el-GR.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/el-GR.ini
Changed
@@ -1,1 +1,2 @@ AMF.H264.Profile="Προφίλ" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/en-US.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/en-US.ini
Changed
@@ -1,4 +1,11 @@ -# Presets +# Shared +AMF.Util.Default="Default" +AMF.Util.Automatic="Automatic" +AMF.Util.Manual="Manual" +AMF.Util.Toggle.Disabled="Disabled" +AMF.Util.Toggle.Enabled="Enabled" +# H264 +# - Preset AMF.H264.Preset="Preset" AMF.H264.Preset.ResetToDefaults="Reset to Defaults" AMF.H264.Preset.Recording="Recording" @@ -7,7 +14,7 @@ AMF.H264.Preset.Lossless="Lossless" AMF.H264.Preset.Twitch="Twitch" AMF.H264.Preset.YouTube="YouTube" -# Static Properties +# - Startup Properties AMF.H264.Usage="Usage" AMF.H264.Usage.Description="What usage AMF should be tuned for:\n- '\@AMF.H264.Usage.Transcoding\@' is general purpose transcoding (recommended),\n- '\@AMF.H264.Usage.UltraLowLatency\@' is for really low latency encoding,\n- '\@AMF.H264.Usage.LowLatency\@' is similar to above with a slightly higher latency.\nStreaming only supports '\@AMF.H264.Usage.Transcoding\@', all other values can be used for recording." AMF.H264.Usage.Transcoding="Transcoding" @@ -19,20 +26,12 @@ AMF.H264.QualityPreset.Balanced="Balanced" AMF.H264.QualityPreset.Quality="Quality" AMF.H264.Profile="Profile" -AMF.H264.Profile.Description="Which H.264 Profile to use for encoding:\n- 'Baseline' has the biggest platform support,\n- 'Main' is supported by older devices (recommended if targeting mobile devices),\n- 'High' is supported by current devices (recommended)." +AMF.H264.Profile.Description="Which H.264 Profile to use for encoding, sorted from highest quality to most widespread support." AMF.H264.ProfileLevel="Profile Level" AMF.H264.ProfileLevel.Description="Which H.264 Profile Level to use for encoding:\n- '\@AMF.Util.Automatic\@' calculates the best profile level for the given Frame Rate and Frame Size,\n- '4.1' supports 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' supports 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' supports 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' supports 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' supports 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Maximum LTR Frames" -AMF.H264.MaximumLTRFrames.Description="Long Term Reference (LTR) Frames are a feature that allows the encoder to flag certain frames in a sequence as referencable.\nThis can have a positive effect on quality when B-Pictures are not supported or wanted.\nLTR Frames can't be used with B-Pictures and the encoder will disable B-Pictures if these are used." -AMF.H264.CodingType="Coding Type" -AMF.H264.CodingType.Description="Which type of coding to use:\n* \@AMF.Util.Default\@ lets AMF decide (recommended).\n* CALVC (Context-Adaptive Variable-Length Coding) is faster, but larger.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) is slower, but smaller." -AMF.H264.ScanType="Scan Type" -AMF.H264.ScanType.Description="Which scanning method to use, always leave this on '\@AMF.H264.ScanType.Progressive\@'." -AMF.H264.ScanType.Progressive="Progressive" -AMF.H264.ScanType.Interlaced="Interlaced" -# Rate Control Properties +# - Rate Control Properties AMF.H264.RateControlMethod="Rate Control Method" -AMF.H264.RateControlMethod.Description="What rate control method should be used:\n- '\@AMF.H264.RateControlMethod.CQP\@' assigns fixed I-/P-/B-Frame QP (Quantization Parameter) values,\n- '\@AMF.H264.RateControlMethod.CBR\@' stays at the given Target Bitrate (using Filler Data) (recommended for streaming),\n- '\@AMF.H264.RateControlMethod.VBR\@' stays below the given Peak Bitrate,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' stays close to the Target Bitrate if GPU latency and load allow for it, otherwise will use higher bitrate (recommended for recording)." +AMF.H264.RateControlMethod.Description="What rate control method should be used:\n- '\@AMF.H264.RateControlMethod.CQP\@' assigns fixed I-/P-/B-Frame QP values,\n- '\@AMF.H264.RateControlMethod.CBR\@' stays at the given Target Bitrate (using Filler Data) (recommended for streaming),\n- '\@AMF.H264.RateControlMethod.VBR\@' stays below the given Peak Bitrate,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' stays close to the Target Bitrate if GPU latency and load allow for it, otherwise will use higher bitrate (recommended for recording)." AMF.H264.RateControlMethod.CQP="Constant QP (CQP)" AMF.H264.RateControlMethod.CBR="Constant Bitrate (CBR)" AMF.H264.RateControlMethod.VBR.Peak="Variable Bitrate (Peak Constrained) (VBR)" @@ -42,25 +41,21 @@ AMF.H264.Bitrate.Peak="Peak Bitrate" AMF.H264.Bitrate.Peak.Description="Bitrate to attempt to maximally peak to in the overall sequence." AMF.H264.QP.Minimum="Minimum QP" -AMF.H264.QP.Minimum.Description="Lowest QP (Quantization Parameter) value to use in a frame." +AMF.H264.QP.Minimum.Description="Lowest QP value to use in a Frame." AMF.H264.QP.Maximum="Maximum QP" -AMF.H264.QP.Maximum.Description="Highest QP (Quantization Parameter) value to use in a frame." +AMF.H264.QP.Maximum.Description="Highest QP value to use in a Frame." AMF.H264.QP.IFrame="I-Frame QP" -AMF.H264.QP.IFrame.Description="Fixed QP (Quantization Parameter) value to use for I-Frames.\nI-Frame QP should be at or higher than P- and B-Frame QP." +AMF.H264.QP.IFrame.Description="Fixed QP value to use for I-Frames." AMF.H264.QP.PFrame="P-Frame QP" -AMF.H264.QP.PFrame.Description="Fixed QP (Quantization Parameter) value to use for P-Frames.\nP-Frame QP should be at or higher than B-Frame QP." +AMF.H264.QP.PFrame.Description="Fixed QP value to use for P-Frames." AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BFrame.Description="Fixed QP (Quantization Parameter) value to use for B-Frames." -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.BPictureDelta.Description="Delta QP (Quantization Parameter) value to the last non-reference B-Picture." -AMF.H264.QP.ReferenceBPictureDelta="Reference B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="Delta QP (Quantization Parameter) value to the last reference B-Picture." +AMF.H264.QP.BFrame.Description="Fixed QP value to use for B-Frames." AMF.H264.VBVBuffer="VBV Buffer" AMF.H264.VBVBuffer.Description="What method should be used to determine the VBV Buffer Size:\n- '\@AMF.Util.Automatic\@' calculates the size using a strictness constraint,\n- '\@AMF.Util.Manual\@' allows the user to control the size.\nVBV (Video Buffering Verifier) Buffer is used by certain Rate Control Methods to keep the overall bitrate within the given constraints." AMF.H264.VBVBuffer.Strictness="VBV Buffer Strictness" -AMF.H264.VBVBuffer.Strictness.Description="How strict the VBV Buffer is, with 100% being almost exactly the targetted Bitrate and 0% being unrestricted." +AMF.H264.VBVBuffer.Strictness.Description="Determines the strictness of the VBV Buffer, with 100% being as strict as possible and 0% being unrestricted." AMF.H264.VBVBuffer.Size="VBV Buffer Size" -AMF.H264.VBVBuffer.Size.Description="The size of the VBV Buffer which is used for Bitrate control in a sequence.\nA small size results in an almost perfect bitrate match but has a larger performance impact." +AMF.H264.VBVBuffer.Size.Description="The size of the VBV Buffer which is used for Bitrate control in a sequence." AMF.H264.VBVBuffer.Fullness="VBV Buffer Fullness" AMF.H264.VBVBuffer.Fullness.Description="How full the VBV Buffer initially is, will only affect the initial sequence of encoding." AMF.H264.FillerData="Filler Data" @@ -68,51 +63,80 @@ AMF.H264.FrameSkipping="Frame Skipping" AMF.H264.FrameSkipping.Description="Frame Skipping allows the encoder to drop frames in order to meet Target Bitrate requirements.\nWhen the encoder drops a frame it instead insert a repeat-last-frame NAL into the stream.\nCan help with very low Target Bitrates." AMF.H264.EnforceHRDCompatibility="Enforce HRD Compatibility" -AMF.H264.EnforceHRDCompatibility.Description="Enforce Hypothetical Reference Decoder restrictions which limit the maximum QP value change within a frame.\nNot recommended for recording or streaming and should only be used for targeting very old devices that only have reference software decoders." -AMF.H264.MaximumAccessUnitSize="Maximum Access Unit Size" -AMF.H264.MaximumAccessUnitSize.Description="Largest Size of an Access Unit for a NAL. A value of 0 allows the encoder to pick the best one." -# Picture Control Properties +AMF.H264.EnforceHRDCompatibility.Description="Enforce Hypothetical Reference Decoder restrictions which limit the maximum QP value change within a frame." +# - Picture Control Properties AMF.H264.KeyframeInterval="Keyframe Interval" AMF.H264.KeyframeInterval.Description="Defines the distance between Keyframes in seconds. Also controls GOP-sequence size." AMF.H264.IDRPeriod="IDR Period" AMF.H264.IDRPeriod.Description="Defines the distance between Instantaneous Decoding Refreshes (IDR) in frames. Also controls GOP-sequence size." -AMF.H264.HeaderInsertionSpacing="Header Insertion Spacing" -AMF.H264.HeaderInsertionSpacing.Description="How many frames should be between NAL headers. It is not recommended to change this from 0 (automatic)." -AMF.H264.BPicture.Pattern="B-Picture Pattern" -AMF.H264.BPicture.Pattern.Description="How many B-Pictures should be allowed for encoding, has a positive impact on quality and negative impact on performance.\nSupported by 2nd and 3rd Generation VCE cards." -AMF.H264.BPicture.Reference="B-Picture Reference" -AMF.H264.BPicture.Reference.Description="Allow B-Pictures to reference other B-Pictures additionally to P- and I-Frames.\nImproves quality slightly but lowers encoding performance." +AMF.H264.BFrame.Pattern="B-Frames" +AMF.H264.BFrame.Pattern.Description="The amount of B-Frames to use while encoding.\nSupported by 2nd and 3rd Generation VCE cards. Negative impact on encoding performance." +AMF.H264.BFrame.DeltaQP="Delta QP for B-Frames" +AMF.H264.BFrame.DeltaQP.Description="Delta QP value to the last I- or P-Frame for non-referenceable B-Frames." +AMF.H264.BFrame.Reference="Referenceable B-Frames" +AMF.H264.BFrame.Reference.Description="Allow a B-Frame to also use B-Frames as reference, instead of just P- and I-Frames." +AMF.H264.BFrame.ReferenceDeltaQP="Delta QP for referenceable B-Frames" +AMF.H264.BFrame.ReferenceDeltaQP.Description="Delta QP value to the last I- or P-Frame for referenceable B-Frames." AMF.H264.DeblockingFilter="Deblocking Filter" AMF.H264.DeblockingFilter.Description="Sets the flag that the decoder is allowed to use a Deblocking Filter for the encoded stream." -AMF.H264.SlicesPerFrame="Slices Per Frame" -AMF.H264.SlicesPerFrame.Description="How many I-Frame slices should be stored with each frame?\nA value of zero lets the encoder decide on the fly.\nIntra-Refresh encoding is used for faster playback and seeking." -AMF.H264.IntraRefreshNumMBsPerSlot="Intra-Refresh Number of Macroblocks Per Slot" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="How many Macroblocks should be stored in each slot?\nA value of zero lets the encoder decide on the fly.\nIntra-Refresh encoding is used for faster playback and seeking." -# Miscellaneous Properties +# - Miscellaneous Properties +AMF.H264.ScanType="Scan Type" +AMF.H264.ScanType.Description="Which scanning method to use, always leave this on '\@AMF.H264.ScanType.Progressive\@'." +AMF.H264.ScanType.Progressive="Progressive" +AMF.H264.ScanType.Interlaced="Interlaced" AMF.H264.MotionEstimation="Motion Estimation" AMF.H264.MotionEstimation.Description="Motion Estimation allows the encoder to reduce needed bitrate by estimating where a pixel went." AMF.H264.MotionEstimation.None="None" AMF.H264.MotionEstimation.Half="Half-Pixel" AMF.H264.MotionEstimation.Quarter="Quarter-Pixel" AMF.H264.MotionEstimation.Both="Half- & Quarter-Pixel" -# System Properties -AMF.H264.Device="Device" -AMF.H264.Device.Description="Which Device to use for encoding.\nRequires Memory Type to not be set to 'Host'." -AMF.H264.UseOpenCL="Use OpenCL" -AMF.H264.UseOpenCL.Description="Should the Encoder use OpenCL to submit the individual frames?" +# - Experimental Properties +AMF.H264.CodingType="Coding Type" +AMF.H264.CodingType.Description="Which type of coding to use:\n* \@AMF.Util.Default\@ lets AMF decide (recommended).\n* CALVC (Context-Adaptive Variable-Length Coding) is faster, but larger.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) is slower, but smaller." +AMF.H264.MaximumLTRFrames="Maximum LTR Frames" +AMF.H264.MaximumLTRFrames.Description="Long Term Reference (LTR) Frames are a feature that allows the encoder to flag certain frames in a sequence as referencable for a long time.\nLTR Frames can't be used with B-Frames and the encoder will disable B-Frames if these are used." +AMF.H264.MaximumAccessUnitSize="Maximum Access Unit Size" +AMF.H264.MaximumAccessUnitSize.Description="Largest Size of an Access Unit for a NAL." +AMF.H264.HeaderInsertionSpacing="Header Insertion Spacing" +AMF.H264.HeaderInsertionSpacing.Description="How many frames should be between NAL headers." +AMF.H264.WaitForTask="Wait For Task" +AMF.H264.WaitForTask.Description="Unknown, Experimental" +AMF.H264.PreAnalysisPass="Pre Analysis Pass" +AMF.H264.PreAnalysisPass.Description="Unknown, Experimental" +AMF.H264.VBAQ="VBAQ" +AMF.H264.VBAQ.Description="Unknown, Experimental" +AMF.H264.GOPSize="GOP Size" +AMF.H264.GOPSize.Description="Unknown, Experimental" +AMF.H264.GOPAlignment="GOP Alignment" +AMF.H264.GOPAlignment.Description="Unknown, Experimental" +AMF.H264.MaximumReferenceFrames="Maximum Reference Frames" +AMF.H264.MaximumReferenceFrames.Description="Unknown, Experimental" +AMF.H264.SlicesPerFrame="Slices Per Frame" +AMF.H264.SlicesPerFrame.Description="How many I-Frame slices should be stored with each frame?\nA value of zero lets the encoder decide on the fly.\nIntra-Refresh encoding is used for faster playback and seeking." +AMF.H264.SliceMode="Slice Mode" +AMF.H264.SliceMode.Description="Unknown, Experimental" +AMF.H264.MaximumSliceSize="Maximum Slice Size" +AMF.H264.MaximumSliceSize.Description="Unknown, Experimental" +AMF.H264.SliceControlMode="Slice Control Mode" +AMF.H264.SliceControlMode.Description="Unknown, Experimental" +AMF.H264.SliceControlSize="Slice Control Size" +AMF.H264.SliceControlSize.Description="Unknown, Experimental" +AMF.H264.IntraRefresh.NumberOfStripes="Intra-Refresh Number of Stripes" +AMF.H264.IntraRefresh.NumberOfStripes.Description="Unknown, Experimental" +AMF.H264.IntraRefresh.MacroblocksPerSlot="Intra-Refresh Macroblocks per Slot" +AMF.H264.IntraRefresh.MacroblocksPerSlot.Description="How many Macroblocks should be stored in each slot?\nA value of 0 disables this feature.\nIntra-Refresh encoding is used for faster playback and seeking." +# - System Properties +AMF.H264.VideoAPI="Video API" +AMF.H264.VideoAPI.Description="Which API to use for encoding." +AMF.H264.VideoAdapter="Video Adapter" +AMF.H264.VideoAdapter.Description="Which Adapter to use for encoding." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="Should the Encoder use OpenCL to submit the individual frames?" AMF.H264.View="View Mode" AMF.H264.View.Description="What properties should be shown?\nUsing '\@AMF.H264.View.Master\@' will disqualify you from receiving support." AMF.H264.View.Basic="Basic" AMF.H264.View.Advanced="Advanced" AMF.H264.View.Expert="Expert" AMF.H264.View.Master="Master" -AMF.H264.UnlockProperties="Unlock Properties" -AMF.H264.UnlockProperties.Description="Unlock certain properties to their full range instead of limiting them to a partial range." AMF.H264.Debug="Debug" AMF.H264.Debug.Description="Enable additional debug logging, should be active whenever you need support with this encoder." -# Utility -AMF.Util.Default="Default" -AMF.Util.Automatic="Automatic" -AMF.Util.Manual="Manual" -AMF.Util.Toggle.Disabled="Disabled" -AMF.Util.Toggle.Enabled="Enabled" \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/es-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/es-ES.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Por defecto" +AMF.Util.Automatic="Automático" +AMF.Util.Manual="Manual" +AMF.Util.Toggle.Disabled="Deshabilitado" +AMF.Util.Toggle.Enabled="Habilitado" AMF.H264.Preset="Preajuste" AMF.H264.Preset.ResetToDefaults="Restablecer por defecto" AMF.H264.Preset.Recording="Grabación" @@ -20,12 +25,6 @@ AMF.H264.Profile.Description="Que perfil H.264 a utilizar para la codificación:\n- 'Baseline' tiene el mayor soporte en las plataformas,\n- 'Main' es compatible con dispositivos algo mas anticuados (recomendado si la emisión va dirigida a dispositivos móviles),\n- 'High' es compatible con los dispositivos actuales (recomendado)." AMF.H264.ProfileLevel="Nivel del Perfil" AMF.H264.ProfileLevel.Description="Nivel de perfil H.264 a utilizar para la codificación:\n- 'Automático' calcula el mejor nivel de perfil para cierta velocidad y tamaño de fotogramas,\n- '4.1' soporta 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' soporta 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' soporta 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' soporta 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' soporta 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Fotogramas LTR máximos" -AMF.H264.MaximumLTRFrames.Description="Fotogramas de referencia a largo plazo (LTR) son una caracteristica que permite al codificador marcar ciertos frames en una secuencia como referentes.\nEsto puede tener un efecto positivo en la calidad cuando los B-Pictures no estan soportados.\nLos fotogramas LTR no pueden ser usados con B-Pictures y el codificador deshabilitará B-Pictures si se usa." -AMF.H264.ScanType="Tipo de escaneo" -AMF.H264.ScanType.Description="Que método de escaneo usar, dejar siempre en 'Progresivo'." -AMF.H264.ScanType.Progressive="Progresivo" -AMF.H264.ScanType.Interlaced="Entrelazado" AMF.H264.RateControlMethod="Método de control del flujo" AMF.H264.RateControlMethod.Description="Qué método de control de flujo debe ser usado:\n- '\@AMF.H264.RateControlMethod.CQP\@' asigna valores fijos de QP en I-/P-/B-Frames (Parámetro de cuantización),\n- '\@AMF.H264.RateControlMethod.CBR\@' se mantiene en la tasa de bits objetivo (usando Datos de relleno) (recomendado para emisiones en directo),\n- '\@AMF.H264.RateControlMethod.VBR\@' se mantiene por debajo de un pico de tasa de bits,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' se mantiene cerca de la tasa de bits deseada si la latencia y carga de la GPU lo permite, si no se aumentará la tasa de bits (recomendado para grabaciones)." AMF.H264.RateControlMethod.CQP="QP constante (CQP)" @@ -41,21 +40,17 @@ AMF.H264.QP.Maximum="QP Máximo" AMF.H264.QP.Maximum.Description="Valor máximo de QP (parámetro de cuantización) a utilizar en un fotograma." AMF.H264.QP.IFrame="I-Frame QP" -AMF.H264.QP.IFrame.Description="Valor de QP Fijo (parámetro de cuantización) a usar por I-Frames.\n-El valor QP de un I-Frame debe ser igual o superior al valor QP de P- y B-Frames." +AMF.H264.QP.IFrame.Description="Valor fijo de QP para I-Frames." AMF.H264.QP.PFrame="P-Frame QP" -AMF.H264.QP.PFrame.Description="Valor de QP Fijo (parámetro de cuantización) a usar por P-Frames.\n-El valor QP de un P-Frame debe ser igual o superior al valor QP de un B-Frame." +AMF.H264.QP.PFrame.Description="Valor fijo de QP para P-Frames." AMF.H264.QP.BFrame="B-Frame QP" AMF.H264.QP.BFrame.Description="Valor de QP Fijo (parámetro de cuantización) a usar por B-Frames." -AMF.H264.QP.BPictureDelta="QP Delta en B-Pictures" -AMF.H264.QP.BPictureDelta.Description="QP Delta del último B-Picture que no es de referencia." -AMF.H264.QP.ReferenceBPictureDelta="QP Delta en B-Pictures de referencia" -AMF.H264.QP.ReferenceBPictureDelta.Description="QP Delta del último B-Picture de referencia." AMF.H264.VBVBuffer="Buffer VBV" AMF.H264.VBVBuffer.Description="Que método se debe usar para determinar el tamaño del buffer VBV:\n- 'Automático' calcula el tamaño usando una restricción estricta,\n- 'Manual' permite al usuario controlar el tamaño.\nEl buffer VBV (Verificador de Buffering de Video) es usado por ciertos métodos de control del flujo para mantener la tasa de bits dentro de los parámetros establecidos." AMF.H264.VBVBuffer.Strictness="Estricticidad del Buffer VBV" -AMF.H264.VBVBuffer.Strictness.Description="Como de estricto es el buffer VBV, con 100% siendo casi exactamente la tasa de bits deseada y 0% siendo sin restricción." +AMF.H264.VBVBuffer.Strictness.Description="Determina la rigidez del Buffer VBV, con 100% siendo tan estricto como sea posible y 0% sin restricción." AMF.H264.VBVBuffer.Size="Tamaño de buffer VBV" -AMF.H264.VBVBuffer.Size.Description="El tamaño del Buffer VBV que es usado para el control de la tasa de bits en una secuencia.\nUn tamaño pequeño ofrece una tasa de bits con una coincidencia casi perfecta pero tiene un gran impacto en el rendimiento." +AMF.H264.VBVBuffer.Size.Description="Tamaño del Buffer VBV que se utiliza para el control de Bitrate en una secuencia." AMF.H264.VBVBuffer.Fullness="Amplitud del Buffer VBV" AMF.H264.VBVBuffer.Fullness.Description="Como de lleno es el buffer VMV inicialmente, solo afectará a la secuencia inicial de la codificación." AMF.H264.FillerData="Datos de relleno" @@ -64,46 +59,76 @@ AMF.H264.FrameSkipping.Description="Omisión de fotogramas permite al codificador saltar fotogramas para cumplir con el requerimiento de la tasa de bits objetivo.\nCuando el codificador salta un fotograma insertará un NAL que repetirá el ultimo fotograma codificado en el stream.\nPuede ayudar con tasa de bits objetivo muy bajas." AMF.H264.EnforceHRDCompatibility="Forzar compatibilidad con HRD" AMF.H264.EnforceHRDCompatibility.Description="Forzar las restricciones del decodificador hipotético de referencia que limitan el cambio de valor máximo de QP dentro de un fotograma.\nNo recomendado para grabación o emisión en directo y solo se debe usar cuando el objetivo son dispositivos antiguos que solo tienen decodificadores de referencia por software." -AMF.H264.MaximumAccessUnitSize="Tamaño máximo de la unidad de acceso" -AMF.H264.MaximumAccessUnitSize.Description="Mayor tamaño de una unidad de acceso para una NAL. Un valor de 0 permite al codificador elegir el mejor." AMF.H264.KeyframeInterval="Intervalo de fotogramas clave" AMF.H264.KeyframeInterval.Description="Cuantos segundos deben haber entre fotogramas que no se pueden descartar.\nTambién controla el tamaño de la secuencia (GOP)." AMF.H264.IDRPeriod="Periodo IDR" AMF.H264.IDRPeriod.Description="Define la distancia entre Instantaneous Decoding Refreshes (IDR) en Fotogramas. También controla el tamaño de la secuencia del GOP." -AMF.H264.HeaderInsertionSpacing="Espaciado de inserción de cabeceras (Frames)" -AMF.H264.HeaderInsertionSpacing.Description="Cuantos fotogramas deben haber entre cabeceras NAL. No se recomienda cambiar de 0 (automatico)." -AMF.H264.BPicture.Pattern="Patron de B-Pictures" -AMF.H264.BPicture.Pattern.Description="Cuantas B-Pictures deben ser permitidos en la codificación, tiene un impacto positivo en la calidad y negativo en rendimiento.\nSoportado por la segunda y tercera generación de VCE." -AMF.H264.BPicture.Reference="B-Pictures de referencia" -AMF.H264.BPicture.Reference.Description="Permitir B-Pictures referenciar otras B-Pictures adicionalmente a P- y I-Frames.\nGran impacto en el rendimiento, poca mejora de calidad." +AMF.H264.BFrame.Pattern="B-Frames" +AMF.H264.BFrame.Pattern.Description="La cantidad de B-Frames a usar mientras se codifica.\nSoportado con tarjetas de 2 º y 3 º generación VCE. Impacto negativo en el rendimiento de codificación." +AMF.H264.BFrame.DeltaQP="Delta QP para B-Frames" +AMF.H264.BFrame.DeltaQP.Description="Valor Delta QP para el ultimo I- o P-Frame para B-Frames no referenciables." +AMF.H264.BFrame.Reference="B-Frames referenciables" +AMF.H264.BFrame.Reference.Description="Permitir a un B-Frame utilizar también B-Frames como referencia, en lugar de P - y I-Frames." +AMF.H264.BFrame.ReferenceDeltaQP="Delta QP para los fotogramas referenciables" +AMF.H264.BFrame.ReferenceDeltaQP.Description="Valor Delta QP para el ultimo I- o P-Frame para B-Frames referenciables." AMF.H264.DeblockingFilter="Filtro de eliminación de bloques" AMF.H264.DeblockingFilter.Description="Establece el indicador de que el decodificador está permitido a usar el Filtro de eliminación de bloques para el stream codificado." -AMF.H264.SlicesPerFrame="Porciones por fotograma" -AMF.H264.SlicesPerFrame.Description="Cuantas porciones I-Frame deben ser almacenados en cada fotograma?\nUn valor de 0 permite al codificador decidir al vuelo.\nLa codificación Intra-Refresh es usada para una reproducción y exploración mas fluida." -AMF.H264.IntraRefreshNumMBsPerSlot="Numero de macrobloques intra-refresh por Slot" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="Cuantos macrobloques deben ser almacenados en cada slot?\nUn valor de 0 permite al codificador decidir al vuelo.\nLa codificación Intra-Refresh es usada para una reproducción y exploración mas fluida." +AMF.H264.ScanType="Tipo de escaneo" +AMF.H264.ScanType.Description="Que método de escaneo usar, dejar siempre en 'Progresivo'." +AMF.H264.ScanType.Progressive="Progresivo" +AMF.H264.ScanType.Interlaced="Entrelazado" AMF.H264.MotionEstimation="Estimación de movimiento" AMF.H264.MotionEstimation.Description="Estimación de movimiento permite al codificador reducir el flujo de datos necesario estimando de donde vienen los pixeles." AMF.H264.MotionEstimation.None="Ninguno" AMF.H264.MotionEstimation.Half="Mitad de Pixel" AMF.H264.MotionEstimation.Quarter="Cuarto de Pixel" AMF.H264.MotionEstimation.Both="Mitad y cuarto de Pixel" -AMF.H264.Device="Dispositivo" -AMF.H264.Device.Description="Que dispositivo usar para codificar.\nRequiere que el tipo de memoria seleccionado no sea 'Host'." -AMF.H264.UseOpenCL="Usar OpenCL" -AMF.H264.UseOpenCL.Description="Debe el codificador usar OpenCL para entregar los fotogramas individuales?" +AMF.H264.CodingType="Tipo de codificación" +AMF.H264.CodingType.Description="Qué tipo de codificación utilizar:\n* \@AMF.Util.Default\@ deja que AMF lo decida (recomendado).\n* CALVC (Context-Adaptive Variable-Length Coding) es más rápido, pero más grande.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) es más lento, pero más pequeño." +AMF.H264.MaximumLTRFrames="Fotogramas LTR máximos" +AMF.H264.MaximumLTRFrames.Description="Fotogramas de referencia a largo plazo (LTR) son una característica que permite al codificador marcar ciertos frames en una secuencia como referentes por un largo tiempo.\nLos fotogramas LTR no pueden ser usados con B-Pictures y el codificador deshabilitará B-Pictures si se usa." +AMF.H264.MaximumAccessUnitSize="Tamaño máximo de la unidad de acceso" +AMF.H264.MaximumAccessUnitSize.Description="Mayor tamaño de una unidad de acceso para una NAL. Un valor de 0 permite al codificador elegir el mejor." +AMF.H264.HeaderInsertionSpacing="Espaciado de inserción de cabeceras (Frames)" +AMF.H264.HeaderInsertionSpacing.Description="Cuantos fotogramas deben haber entre cabeceras NAL. No se recomienda cambiar de 0 (automatico)." +AMF.H264.WaitForTask="Esperar para la tarea" +AMF.H264.WaitForTask.Description="Desconocido, Experimental" +AMF.H264.PreAnalysisPass="Pase de pre-análisis" +AMF.H264.PreAnalysisPass.Description="Desconocido, Experimental" +AMF.H264.VBAQ="VBAQ" +AMF.H264.VBAQ.Description="Desconocido, Experimental" +AMF.H264.GOPSize="Tamaño del GOP" +AMF.H264.GOPSize.Description="Desconocido, Experimental" +AMF.H264.GOPAlignment="Alineación del GOP" +AMF.H264.GOPAlignment.Description="Desconocido, Experimental" +AMF.H264.MaximumReferenceFrames="Fotogramas de referencia máximos" +AMF.H264.MaximumReferenceFrames.Description="Desconocido, Experimental" +AMF.H264.SlicesPerFrame="Porciones por fotograma" +AMF.H264.SlicesPerFrame.Description="Cuantas porciones I-Frame deben ser almacenados en cada fotograma?\nUn valor de 0 permite al codificador decidir al vuelo.\nLa codificación Intra-Refresh es usada para una reproducción y exploración mas fluida." +AMF.H264.SliceMode="Modo de porciones" +AMF.H264.SliceMode.Description="Desconocido, Experimental" +AMF.H264.MaximumSliceSize="Tamaño máximo de la porción" +AMF.H264.MaximumSliceSize.Description="Desconocido, Experimental" +AMF.H264.SliceControlMode="Modo de control de la porción" +AMF.H264.SliceControlMode.Description="Desconocido, Experimental" +AMF.H264.SliceControlSize="Control de tamaño de la porción" +AMF.H264.SliceControlSize.Description="Desconocido, Experimental" +AMF.H264.IntraRefresh.NumberOfStripes="Numero de lineas Intra-Refresh" +AMF.H264.IntraRefresh.NumberOfStripes.Description="Desconocido, Experimental" +AMF.H264.IntraRefresh.MacroblocksPerSlot="Numero de macrobloques intra-refresh por Slot" +AMF.H264.IntraRefresh.MacroblocksPerSlot.Description="Cuantos macrobloques deben ser almacenados en cada slot?\nUn valor de 0 deshabilita esta función.\nLa codificación Intra-Refresh es usada para una reproducción y exploración mas fluida." +AMF.H264.VideoAPI="API de vídeo" +AMF.H264.VideoAPI.Description="Que API usar para la codificación." +AMF.H264.VideoAdapter="Adaptador de video" +AMF.H264.VideoAdapter.Description="Que adaptador usar para la codificación." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="¿Debe el Codificador usar OpenCL para presentar los fotogramas individuales?" AMF.H264.View="Modo de Vista" AMF.H264.View.Description="Que propiedades deben ser visibles. No recibirás soporte si usas el modo de vista 'Experto' o 'Maestro'." AMF.H264.View.Basic="Básico" AMF.H264.View.Advanced="Avanzado" AMF.H264.View.Expert="Experto" AMF.H264.View.Master="Maestro" -AMF.H264.UnlockProperties="Desbloquear propiedades" -AMF.H264.UnlockProperties.Description="Desbloquea ciertas propiedades a su maxima capacidad en lugar de limitarlas de forma parcial." AMF.H264.Debug="Depurar" AMF.H264.Debug.Description="Habilita el registro de información de depuración adicional, debe ser activado cuando necesites ayuda con este codificador." -AMF.Util.Default="Por defecto" -AMF.Util.Automatic="Automático" -AMF.Util.Manual="Manual" -AMF.Util.Toggle.Disabled="Deshabilitado" -AMF.Util.Toggle.Enabled="Habilitado" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/eu-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/eu-ES.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Lehenetsia" +AMF.Util.Automatic="Automatikoa" +AMF.Util.Manual="Eskuz" +AMF.Util.Toggle.Disabled="Ezgaituta" +AMF.Util.Toggle.Enabled="Gaituta" AMF.H264.Preset="Aurrezarrita" AMF.H264.Preset.ResetToDefaults="Berrezarri balio lehenetsiak" AMF.H264.Preset.Recording="Grabatzen" @@ -18,11 +23,6 @@ AMF.H264.Profile="Profila" AMF.H264.ProfileLevel="Profilaren maila" AMF.H264.ProfileLevel.Description="H.264 profilaren zein maila erabili behar da kodetzeko:\n- 'Automatic' automatikoki kalkulatzen du emandako abiadura eta fotogramen tamainarako egokiena,\n- '4.1'-ek onartzen du 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2'-k onartzen du 1920x1080 60FPS, 1280x720 120FPS\n- '5.0'-k onartzen du 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1'-k onartzen du 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2'-k onartzen du 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Gehienezko LTR fotogramak" -AMF.H264.MaximumLTRFrames.Description="Long Term Reference (LTR) Fotogramak aukera ematen dio kodegailuari sekuentzia baten hainbat fotograma erreferente moduan markatzeko.\nHonek kalitatean eragin positiboa izan dezake B-Pictures onartzen ez direnean.\nLTR Fotogramak ezin dira B-Pictures-ekin erabili eta kodegailuak B-Pictures-ak desgaituko ditu hauek erabiltzean." -AMF.H264.ScanType="Eskaneatze mota" -AMF.H264.ScanType.Progressive="Progresiboa" -AMF.H264.ScanType.Interlaced="Gurutzelarkatua" AMF.H264.RateControlMethod="Emaria kontrolatzeko metodoa" AMF.H264.RateControlMethod.CQP="Konstantea QP (CQP)" AMF.H264.RateControlMethod.CBR="Bit emari konstantea (CBR)" @@ -35,8 +35,6 @@ AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta="B-Picture Delta QP erreferentzia" AMF.H264.VBVBuffer="VBV bufferra" AMF.H264.VBVBuffer.Strictness="VBV bufferraren zorroztasuna" AMF.H264.VBVBuffer.Size="VBV bufferraren tamaina" @@ -44,34 +42,40 @@ AMF.H264.FillerData="Datu betegarria" AMF.H264.FrameSkipping="Fotogramen saltoa" AMF.H264.EnforceHRDCompatibility="Behartu HRD bateragarritasuna" -AMF.H264.MaximumAccessUnitSize="Sarbide unitatearen gehienezko tamaina" AMF.H264.KeyframeInterval="Gako fotogramen tartea" AMF.H264.IDRPeriod="IDR periodoa" -AMF.H264.HeaderInsertionSpacing="Goiburuak txertatzeko tartea" -AMF.H264.BPicture.Pattern="B-Picture eredua" -AMF.H264.BPicture.Reference="B-Picture erreferentzia" AMF.H264.DeblockingFilter="Desblokeoko iragazkia" -AMF.H264.SlicesPerFrame="Zatiak fotogramako" -AMF.H264.IntraRefreshNumMBsPerSlot="Makroblokeen barne freskatze kopura erreteneko" +AMF.H264.ScanType="Eskaneatze mota" +AMF.H264.ScanType.Description="Erabili behar den eskaneatze metodoa, utzi beti '\@AMF.H264.ScanType.Progressive\@'." +AMF.H264.ScanType.Progressive="Progresiboa" +AMF.H264.ScanType.Interlaced="Gurutzelarkatua" AMF.H264.MotionEstimation="Mugimenduaren estimazioa" AMF.H264.MotionEstimation.None="Ezer ez" AMF.H264.MotionEstimation.Half="Pixel erdia" AMF.H264.MotionEstimation.Quarter="Pixel laurdena" AMF.H264.MotionEstimation.Both="Pixel erdia eta laurdena" -AMF.H264.Device="Gailua" -AMF.H264.Device.Description="Zein gailu erabili kodeketarako.\nHautatutako memoria mota ez du 'Host' izan behar." -AMF.H264.UseOpenCL="Erabili OpenCL" -AMF.H264.UseOpenCL.Description="Kodifikagailuak OpenCL erabili behar du banakako fotogramak bidaltzeko?" +AMF.H264.CodingType="Kodetze mota" +AMF.H264.MaximumLTRFrames="Gehienezko LTR fotogramak" +AMF.H264.MaximumAccessUnitSize="Sarbide unitatearen gehienezko tamaina" +AMF.H264.HeaderInsertionSpacing="Goiburuak txertatzeko tartea" +AMF.H264.WaitForTask.Description="Ezezaguna, esperimentala" +AMF.H264.PreAnalysisPass.Description="Ezezaguna, esperimentala" +AMF.H264.VBAQ.Description="Ezezaguna, esperimentala" +AMF.H264.GOPSize.Description="Ezezaguna, esperimentala" +AMF.H264.GOPAlignment.Description="Ezezaguna, esperimentala" +AMF.H264.MaximumReferenceFrames.Description="Ezezaguna, esperimentala" +AMF.H264.SlicesPerFrame="Zatiak fotogramako" +AMF.H264.SliceMode.Description="Ezezaguna, esperimentala" +AMF.H264.MaximumSliceSize.Description="Ezezaguna, esperimentala" +AMF.H264.SliceControlMode.Description="Ezezaguna, esperimentala" +AMF.H264.SliceControlSize.Description="Ezezaguna, esperimentala" +AMF.H264.IntraRefresh.NumberOfStripes.Description="Ezezaguna, esperimentala" +AMF.H264.OpenCL="OpenCL" AMF.H264.View="Ikuspegia" AMF.H264.View.Description="Zein propietate ikusi behar dira. Ez duzu laguntzarik jasoko 'Aditu' edo 'Maisu' ikuspegian." AMF.H264.View.Basic="Oinarrizkoa" AMF.H264.View.Advanced="Aurreratua" AMF.H264.View.Expert="Aditu" AMF.H264.View.Master="Maixu" -AMF.H264.UnlockProperties="Desblokeatu propietateak" AMF.H264.Debug="Garbiketa" -AMF.Util.Default="Lehenetsia" -AMF.Util.Automatic="Automatikoa" -AMF.Util.Manual="Eskuz" -AMF.Util.Toggle.Disabled="Ezgaituta" -AMF.Util.Toggle.Enabled="Gaituta" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/fi-FI.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/fi-FI.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Oletusarvo" +AMF.Util.Automatic="Automaattinen" +AMF.Util.Manual="Manuaalinen" +AMF.Util.Toggle.Disabled="Pois käytöstä" +AMF.Util.Toggle.Enabled="Käytössä" AMF.H264.Preset="Esiasetus" AMF.H264.Preset.ResetToDefaults="Palauta oletukset" AMF.H264.Preset.Recording="Tallennus" @@ -16,9 +21,6 @@ AMF.H264.QualityPreset.Quality="Laatu" AMF.H264.Profile="Profiili" AMF.H264.ProfileLevel="Profiilin taso" -AMF.H264.ScanType="Skannaustyyppi" -AMF.H264.ScanType.Progressive="Progressiivinen" -AMF.H264.ScanType.Interlaced="Lomitettu" AMF.H264.RateControlMethod="Rate Control -tapa" AMF.H264.RateControlMethod.CQP="Pysyvä QP (CQP)" AMF.H264.RateControlMethod.CBR="Jatkuva bitrate (CBR)" @@ -31,16 +33,15 @@ AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta="Reference B-Picture Delta QP" AMF.H264.VBVBuffer="VBV-puskuri" AMF.H264.VBVBuffer.Size="VBV-puskurin koko" AMF.H264.FillerData="Täyttödata" AMF.H264.FrameSkipping="Ruudun ohitus" AMF.H264.EnforceHRDCompatibility="Pakota HRD-yhteensopivuus" -AMF.H264.BPicture.Pattern="B-Picture Pattern" -AMF.H264.BPicture.Reference="B-Picture Reference" AMF.H264.DeblockingFilter="Deblocking filtteri" +AMF.H264.ScanType="Skannaustyyppi" +AMF.H264.ScanType.Progressive="Progressiivinen" +AMF.H264.ScanType.Interlaced="Lomitettu" AMF.H264.MotionEstimation="Liikkeen ennakointi" AMF.H264.MotionEstimation.None="Ei mitään" AMF.H264.View="Näyttötila" @@ -48,10 +49,5 @@ AMF.H264.View.Advanced="Kehittynyt" AMF.H264.View.Expert="Expertti" AMF.H264.View.Master="Jumalallinen" -AMF.H264.UnlockProperties="Avaa ominaisuudet" AMF.H264.Debug="Debug" -AMF.Util.Default="Oletusarvo" -AMF.Util.Automatic="Automaattinen" -AMF.Util.Manual="Manuaalinen" -AMF.Util.Toggle.Disabled="Pois käytöstä" -AMF.Util.Toggle.Enabled="Käytössä" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/fr-FR.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/fr-FR.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Défaut" +AMF.Util.Automatic="Automatique" +AMF.Util.Manual="Manuel" +AMF.Util.Toggle.Disabled="Désactivé" +AMF.Util.Toggle.Enabled="Activé" AMF.H264.Preset="Préréglage" AMF.H264.Preset.ResetToDefaults="Valeurs par défaut" AMF.H264.Preset.Recording="Enregistrement" @@ -20,63 +25,57 @@ AMF.H264.Profile.Description="Le profil H.264 utilisé pour l'encodage :\n- 'Baseline' est compatible avec la majorité des lecteurs,\n-'Main' est compatible avec les lecteurs d'ancienne génération (recommandé pour les lecteurs mobiles),\n- 'High' est compatible avec la plupart des lecteurs récents (réglage recommandé pour la plupart des cas)." AMF.H264.ProfileLevel="Niveau de profil" AMF.H264.ProfileLevel.Description="Quel niveau de profil H.264 utiliser pour l'encodage :\n- \"Automatique\" laisse l'encodeur déterminer le meilleur profil en fonction de la résolution d'image et du nombre d'images par seconde.\n- \"4.1\" supporte les formats suivants : 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- \"4.2\" supporte les formats suivants : 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- \"5.0\" supporte les formats suivants : 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- \"5.1\" supporte les formats suivants : 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- \"5.2\" supporte les formats suivants : 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Maximum de trames LTR" -AMF.H264.MaximumLTRFrames.Description="Les trames LTR (Long Term Reference) sont une fonctionnalité de l'encodeur qui l'autorise à marquer certaines trames comme étant des trames de référence au sein d'une séquence d'images.\nUtiliser cette fonctionnalité peut apporter un gain de qualité dans le cas où les images B (B-Pictures) ne sont pas supportées ou activées.\nLes trames LTR ne sont pas utilisables en conjonction des images B, et l'encodeur désactivera les images B si cette fonctionnalité (trames LTR) est activée." -AMF.H264.ScanType="Balayage" -AMF.H264.ScanType.Description="La méthode de balayage à utiliser (laissez cette valeur sur \"\@AMF.H264.ScanType.Progressive\@\")." -AMF.H264.ScanType.Progressive="Progressif" -AMF.H264.ScanType.Interlaced="Entrelacé" AMF.H264.RateControlMethod="Méthode de contrôle du débit" AMF.H264.RateControlMethod.CQP="QP constant (CQP)" AMF.H264.RateControlMethod.CBR="Débit constant (CBR)" AMF.H264.RateControlMethod.VBR.Peak="Débit Variable (maximum) (VBR)" AMF.H264.RateControlMethod.VBR.Latency="Débit Variable (latence limitée) (VBR_LAT)" AMF.H264.Bitrate.Target="Débit cible" +AMF.H264.Bitrate.Target.Description="Le débit de données sortantes que l'encodeur va essayer de respecter pendant l'encodage." AMF.H264.Bitrate.Peak="Débit maximal" +AMF.H264.Bitrate.Peak.Description="Le débit de données sortantes que l'encodeur va essayer de respecter pendant l'encodage." AMF.H264.QP.Minimum="QP minimal" AMF.H264.QP.Maximum="QP maximal" AMF.H264.QP.IFrame="QP I-Frame" AMF.H264.QP.PFrame="QP P-Frame" AMF.H264.QP.BFrame="QP B-Frame" -AMF.H264.QP.BPictureDelta="QP B-Image Delta" -AMF.H264.QP.ReferenceBPictureDelta="Delta QP de l'image B de référence" AMF.H264.VBVBuffer="Tampon VBV" +AMF.H264.VBVBuffer.Description="Quelle méthode utiliser pour déterminer la taille du tampon VBV :\n- \"\@AMF.Util.Automatic\@\" calcule la taille en fonction de la valeur de respect du tampon,\n- \"\@AMF.Util.Manual\@\" laisse le choix de la taille à l'utilisateur.\nLe tampon VBV (Video Buffering Verifier) est utilisé par certaines méthodes de contrôle du débit pour assurer au mieux le respect des contraintes données." AMF.H264.VBVBuffer.Strictness="Respect du tampon VBV" AMF.H264.VBVBuffer.Size="Taille du tampon VBV" AMF.H264.VBVBuffer.Fullness="Remplissage du tampon VBV" AMF.H264.FillerData="Données de remplissage" AMF.H264.FrameSkipping="Saut d'images" AMF.H264.EnforceHRDCompatibility="Appliquer la compatibilité avec l'HRD" -AMF.H264.MaximumAccessUnitSize="Taille max. d'une Access Unit" AMF.H264.KeyframeInterval="Intervalle d'images-clé" AMF.H264.IDRPeriod="Périodicité des trames IDR" -AMF.H264.HeaderInsertionSpacing="Intervalle d'insertion de l'en-tête de stream" -AMF.H264.BPicture.Pattern="Modèle d'image B" -AMF.H264.BPicture.Reference="Référence d'image B" AMF.H264.DeblockingFilter="Filtre de dégroupage" -AMF.H264.SlicesPerFrame="Tranches par image" +AMF.H264.ScanType="Balayage" +AMF.H264.ScanType.Description="La méthode de balayage à utiliser (laissez cette valeur sur \"\@AMF.H264.ScanType.Progressive\@\")." +AMF.H264.ScanType.Progressive="Progressif" +AMF.H264.ScanType.Interlaced="Entrelacé" AMF.H264.MotionEstimation="Estimation de mouvement" AMF.H264.MotionEstimation.Description="L'estimation du mouvement permet à l'encodeur de réduire le débit en calculant le déplacement des pixels." AMF.H264.MotionEstimation.None="Aucun" AMF.H264.MotionEstimation.Half="Demi-pixel" AMF.H264.MotionEstimation.Quarter="Quart de pixel" AMF.H264.MotionEstimation.Both="Demi-pixel & quart de pixel" -AMF.H264.Device="Périphérique" -AMF.H264.Device.Description="Quel périphérique utiliser pour l'encodage.\n<Seulement dans le cas où \"Type de mémoire\" n'est pas réglé sur \"Hôte\"." -AMF.H264.UseOpenCL="OpenCL" -AMF.H264.UseOpenCL.Description="L'encodeur doit-il utiliser OpenCL pour transmettre chaque image ?" +AMF.H264.CodingType="Type de codage" +AMF.H264.CodingType.Description="Le type de codage à utiliser:\n* \"\@AMF.Util.Default\@\" : laisser AMF décider (recommandé).\n* CALVC (Context-Adaptive Variable-Length Coding) est rapide mais lourd.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) est lent mais léger." +AMF.H264.MaximumLTRFrames="Maximum de trames LTR" +AMF.H264.MaximumAccessUnitSize="Taille max. d'une Access Unit" +AMF.H264.MaximumAccessUnitSize.Description="Taille maximale d’une unité d’accès pour un NAL. Une valeur de 0 permet à l’encodeur de choisir le meilleur." +AMF.H264.HeaderInsertionSpacing="Intervalle d'insertion de l'en-tête de stream" +AMF.H264.SlicesPerFrame="Tranches par image" +AMF.H264.VideoAPI="API vidéo" +AMF.H264.VideoAdapter="Périphérique vidéo" +AMF.H264.OpenCL="OpenCL" AMF.H264.View="Mode de visualisation" AMF.H264.View.Description="Quels paramètres afficher ?\nChoisir '\@AMF.H264.View.Master\@' est réservé aux utilisateurs avancés, et vous exclus d'office de toute possibilité d'assistance de la part du développeur." AMF.H264.View.Basic="Basique" AMF.H264.View.Advanced="Avancé" AMF.H264.View.Expert="Expert" AMF.H264.View.Master="Maître" -AMF.H264.UnlockProperties="Débloquer les propriétés" -AMF.H264.UnlockProperties.Description="Sur certains paramètres, débloque au maximum la plage des valeurs possibles plutôt que de la limiter à une plage partielle." AMF.H264.Debug="Débogage" AMF.H264.Debug.Description="Activer le débogage avancé dans le fichier journal (dans le cas où vous souhaitez solliciter une assistance auprès du développeur de l'encodeur)." -AMF.Util.Default="Défaut" -AMF.Util.Automatic="Automatique" -AMF.Util.Manual="Manuel" -AMF.Util.Toggle.Disabled="Désactivé" -AMF.Util.Toggle.Enabled="Activé" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/hr-HR.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/hr-HR.ini
Changed
@@ -1,3 +1,7 @@ +AMF.Util.Default="Podrazumevano" +AMF.Util.Automatic="Automatski" +AMF.Util.Toggle.Disabled="Onemogućeno" +AMF.Util.Toggle.Enabled="Omogućeno" AMF.H264.Usage.Transcoding="Transkodiranje" AMF.H264.Usage.UltraLowLatency="Ultra nisko kašnjenje" AMF.H264.Usage.LowLatency="Nisko kašnjenje" @@ -7,9 +11,6 @@ AMF.H264.QualityPreset.Quality="Kvalitet" AMF.H264.Profile="Profil" AMF.H264.ProfileLevel="Nivo profila" -AMF.H264.ScanType="Vrsta skeniranja" -AMF.H264.ScanType.Progressive="Progresivno" -AMF.H264.ScanType.Interlaced="Isprekidano" AMF.H264.RateControlMethod="Metoda kontrole protoka" AMF.H264.RateControlMethod.CQP="Konstantan kvalitet (CQP)" AMF.H264.RateControlMethod.CBR="Konstantan protok (CBR)" @@ -22,15 +23,11 @@ AMF.H264.QP.IFrame="I-Frejm QP" AMF.H264.QP.PFrame="P-Frejm QP" AMF.H264.QP.BFrame="B-Frejm QP" -AMF.H264.QP.BPictureDelta="B-Promena slike QP" -AMF.H264.QP.ReferenceBPictureDelta="Referenca B-Promena slike QP" AMF.H264.FillerData="Data za popunjavanje" AMF.H264.FrameSkipping="Preskakanje frejmova" AMF.H264.EnforceHRDCompatibility="Prisilna HRD kompatibilnost" -AMF.H264.BPicture.Pattern="B-Šablonska slika" -AMF.H264.BPicture.Reference="B-Referentna slika" AMF.H264.DeblockingFilter="Odblokirajući filter" -AMF.Util.Default="Podrazumevano" -AMF.Util.Automatic="Automatski" -AMF.Util.Toggle.Disabled="Onemogućeno" -AMF.Util.Toggle.Enabled="Omogućeno" +AMF.H264.ScanType="Vrsta skeniranja" +AMF.H264.ScanType.Progressive="Progresivno" +AMF.H264.ScanType.Interlaced="Isprekidano" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/hu-HU.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/hu-HU.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Alapértelmezett" +AMF.Util.Automatic="Automatikus" +AMF.Util.Manual="Manuális" +AMF.Util.Toggle.Disabled="Letiltva" +AMF.Util.Toggle.Enabled="Engedélyezve" AMF.H264.Preset="Készlet" AMF.H264.Preset.ResetToDefaults="Alapértelmezett beállítások visszaállítása" AMF.H264.Preset.Recording="Felvétel" @@ -17,10 +22,6 @@ AMF.H264.Profile="Enkóder profil" AMF.H264.Profile.Description="Mely H.264 Profilt használja kódoláshoz:\n- 'Baseline' a legnagyobb platform támogatottsággal,\n- 'Main' a régebbi eszközök támogatják (ajánlott ha mobil eszköz tulajdonosokat céloz meg),\n- 'High' a jelenlegi eszközök támogatják (ajánlott)." AMF.H264.ProfileLevel="Profil szint" -AMF.H264.MaximumLTRFrames="Maximális LTR képkocka" -AMF.H264.ScanType="Rögzítés módja" -AMF.H264.ScanType.Progressive="Progreszív" -AMF.H264.ScanType.Interlaced="Interlaced (Kísérleti)" AMF.H264.RateControlMethod="Bitráta vezérlés" AMF.H264.RateControlMethod.CQP="Erőltetett QP (CQP)" AMF.H264.RateControlMethod.CBR="Konstans bitráta (CBR)" @@ -35,46 +36,57 @@ AMF.H264.QP.Maximum="Maximum QP" AMF.H264.QP.Maximum.Description="Legmagasabb QP (Quantization Parameter) képkockában használható érték." AMF.H264.QP.IFrame="I-Képkocka QP" -AMF.H264.QP.IFrame.Description="Rögzített QP (Quantization Parameter) érték használata az I-Képkockákhoz.\nI-Képkocka QP értéknek nagyobbnak kell lennie a P- és B-Képkocka QP értéknél." +AMF.H264.QP.IFrame.Description="Rögzített QP érték az I képkockák használatához." AMF.H264.QP.PFrame="P-Képkocka QP" -AMF.H264.QP.PFrame.Description="Rögzített QP (Quantization Parameter) érték használata a P-Képkockákhoz.\nIPKépkocka QP értéknek nagyobbnak kell lennie a B-Képkocka QP értéknél." +AMF.H264.QP.PFrame.Description="Rögzített QP érték a P képkockák használatához." AMF.H264.QP.BFrame="B-Képkocka QP" AMF.H264.QP.BFrame.Description="Rögzített QP (Quantization Parameter) érték a B-Képkockák használatához." -AMF.H264.QP.BPictureDelta="B-Képkocka Delta QP" -AMF.H264.QP.BPictureDelta.Description="Delta QP (Quantization Parameter) érték az utolsó nem referencia a B-Képhez." -AMF.H264.QP.ReferenceBPictureDelta="Referencia B-képkocka Delta QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="Delta QP (Quantization Parameter) érték az utolsó referencia a B-Képhez." AMF.H264.VBVBuffer="VBV puffer" AMF.H264.VBVBuffer.Strictness="VBV Puffer kötöttség" +AMF.H264.VBVBuffer.Strictness.Description="Meghatározza a VBV puffer szigorúságát, 100% esetén teljesen pontos és 0% esetén kötetlen." AMF.H264.VBVBuffer.Size="VBV pufferméret" AMF.H264.VBVBuffer.Fullness="VBV puffer telítettség" AMF.H264.FillerData="Filler adat" AMF.H264.FrameSkipping="Képkocka kihagyás" AMF.H264.EnforceHRDCompatibility="HRD Kompatibilitás kényszerítése" -AMF.H264.MaximumAccessUnitSize="Hozzáférési egység maximális mérete" AMF.H264.KeyframeInterval="Kulcsképkocka időköze" AMF.H264.IDRPeriod="IDR időköz" -AMF.H264.BPicture.Pattern="B-képkockák száma" -AMF.H264.BPicture.Reference="B-képkocka referencia" +AMF.H264.BFrame.Pattern="B képkocka" +AMF.H264.BFrame.DeltaQP="B képkocka Delta QP" +AMF.H264.BFrame.Reference="Referenciálható B képkockák" +AMF.H264.BFrame.Reference.Description="Lehetővé teszi a B képkockák számára, hogy B képkockát referenciaként használjon, P és I képkockák helyett." +AMF.H264.BFrame.ReferenceDeltaQP="Delta QP a referenciálható B kockákhoz" +AMF.H264.BFrame.ReferenceDeltaQP.Description="Delta QP érték az utolsó I vagy P képkockának a referenciálható B képkockákhoz." AMF.H264.DeblockingFilter="Deblocking Filter" -AMF.H264.SlicesPerFrame="Szeletelés képkockánként" +AMF.H264.ScanType="Rögzítés módja" +AMF.H264.ScanType.Progressive="Progresszív" +AMF.H264.ScanType.Interlaced="Váltottsoros (Kísérleti)" AMF.H264.MotionEstimation="Mozgásbecslés" AMF.H264.MotionEstimation.None="Semmi" AMF.H264.MotionEstimation.Half="Fél-pixel" AMF.H264.MotionEstimation.Quarter="Negyed-pixel" AMF.H264.MotionEstimation.Both="Fél-&negyed-pixel" -AMF.H264.Device="Eszköz" -AMF.H264.UseOpenCL="OpenCL Használata" +AMF.H264.CodingType="Kódolás típusa" +AMF.H264.MaximumLTRFrames="Maximális LTR képkocka" +AMF.H264.MaximumAccessUnitSize="Hozzáférési egység maximális mérete" +AMF.H264.PreAnalysisPass="Elemzés előtti fázis" +AMF.H264.VBAQ="VBAQ" +AMF.H264.GOPSize="GOP méret" +AMF.H264.GOPAlignment="GOP igazítás" +AMF.H264.MaximumReferenceFrames="Maximális referencia képkockák" +AMF.H264.SlicesPerFrame="Szeletelés képkockánként" +AMF.H264.SliceMode="Szelet mód" +AMF.H264.MaximumSliceSize="Maximális szeletméret" +AMF.H264.VideoAPI="Videó API" +AMF.H264.VideoAPI.Description="Melyik API használható kódoláshoz." +AMF.H264.VideoAdapter="Videó adapter" +AMF.H264.VideoAdapter.Description="Melyik adapter használható kódoláshoz." +AMF.H264.OpenCL="OpenCL" AMF.H264.View="Nézet mód" AMF.H264.View.Basic="Alap" AMF.H264.View.Advanced="Haladó" AMF.H264.View.Expert="Szakértő" AMF.H264.View.Master="Mester" -AMF.H264.UnlockProperties="Tulajdonságok feloldása" AMF.H264.Debug="Hibakeresés" AMF.H264.Debug.Description="További hibakeresési naplózás engedélyezése, aktiválja amennyiben tanácsadásra van szüksége a kódolóval kapcsolatban." -AMF.Util.Default="Alapértelmezett" -AMF.Util.Automatic="Automatikus" -AMF.Util.Manual="Manuális" -AMF.Util.Toggle.Disabled="Letiltva" -AMF.Util.Toggle.Enabled="Engedélyezve" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/it-IT.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/it-IT.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="Predefinito" +AMF.Util.Automatic="Automatico" +AMF.Util.Manual="Manuale" +AMF.Util.Toggle.Disabled="Disabilitato" +AMF.Util.Toggle.Enabled="Attivo" AMF.H264.Preset="Preset" AMF.H264.Preset.ResetToDefaults="Ripristina a Predefiniti" AMF.H264.Preset.Recording="Registrazione" @@ -17,10 +22,6 @@ AMF.H264.Profile="Profilo" AMF.H264.ProfileLevel="Livello profilo" AMF.H264.ProfileLevel.Description="Quale livello di profilo H.264 usare per l'encoding:\n- 'Automatico' calcola il miglior livello per il dato Frame Rate e Frame Size,\n- '4.1' supporta 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' supporta 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' supporta 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' supporta 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' supporta 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Fotogrammi LTR Massimi" -AMF.H264.ScanType="Tipo di scansione" -AMF.H264.ScanType.Progressive="Progressivo" -AMF.H264.ScanType.Interlaced="Interlacciato" AMF.H264.RateControlMethod="Metodo di controllo della frequenza" AMF.H264.RateControlMethod.CQP="QP Costante (QPC)" AMF.H264.RateControlMethod.CBR="Bitrate costante (CBR)" @@ -29,12 +30,12 @@ AMF.H264.Bitrate.Target="Bitrate di destinazione" AMF.H264.Bitrate.Peak="Picco Bitrate" AMF.H264.QP.Minimum="QP Minimo" +AMF.H264.QP.Minimum.Description="Valore QP più basso da utilizzare in un Frame." AMF.H264.QP.Maximum="QP Massimo" +AMF.H264.QP.Maximum.Description="Valore QP più alto da utilizzare in un Frame." AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta="Riferimento B-Picture Delta QP" AMF.H264.VBVBuffer="Buffer VBV" AMF.H264.VBVBuffer.Strictness="Strettezza Buffer VBV" AMF.H264.VBVBuffer.Size="Dimensione Buffer VBV" @@ -42,31 +43,27 @@ AMF.H264.FillerData="Dati di riempimento" AMF.H264.FrameSkipping="Frame Skipping" AMF.H264.EnforceHRDCompatibility="Forza compatibilità HRD" -AMF.H264.MaximumAccessUnitSize="Massima dimensione di unità d'accesso" AMF.H264.KeyframeInterval="Intervallo Keyframe" AMF.H264.IDRPeriod="Periodo IDR" -AMF.H264.HeaderInsertionSpacing="Spaziatura di inserimento di intestazione" -AMF.H264.BPicture.Pattern="Modello B-Picture" -AMF.H264.BPicture.Reference="Riferimento B-Picture" AMF.H264.DeblockingFilter="Filtro di deblock" -AMF.H264.SlicesPerFrame="Slices Per Frame" -AMF.H264.IntraRefreshNumMBsPerSlot="Intra-Refresh Number of Macroblocks Per Slot" +AMF.H264.ScanType="Tipo di scansione" +AMF.H264.ScanType.Progressive="Progressivo" +AMF.H264.ScanType.Interlaced="Interlacciato" AMF.H264.MotionEstimation="Stima Movimento" AMF.H264.MotionEstimation.None="Nessuno" AMF.H264.MotionEstimation.Half="Metà-Pixel" AMF.H264.MotionEstimation.Quarter="Quarto-Pixel" AMF.H264.MotionEstimation.Both="Meta- & Quarto-Pixel" -AMF.H264.Device="Dispositivo" -AMF.H264.UseOpenCL="OpenCL" +AMF.H264.CodingType="Tipo di codifica" +AMF.H264.MaximumLTRFrames="Fotogrammi LTR Massimi" +AMF.H264.MaximumAccessUnitSize="Massima dimensione di unità d'accesso" +AMF.H264.HeaderInsertionSpacing="Spaziatura di inserimento di intestazione" +AMF.H264.WaitForTask="Attendere per attività" +AMF.H264.SlicesPerFrame="Slices Per Frame" AMF.H264.View="Modalità di visualizzazione" AMF.H264.View.Basic="Basico" AMF.H264.View.Advanced="Avanzate" AMF.H264.View.Expert="Esperto" AMF.H264.View.Master="Master" -AMF.H264.UnlockProperties="Sblocca proprietà" AMF.H264.Debug="Debug" -AMF.Util.Default="Predefinito" -AMF.Util.Automatic="Automatico" -AMF.Util.Manual="Manuale" -AMF.Util.Toggle.Disabled="Disabilitato" -AMF.Util.Toggle.Enabled="Attivo" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/ja-JP.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/ja-JP.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="既定値" +AMF.Util.Automatic="自動" +AMF.Util.Manual="手動" +AMF.Util.Toggle.Disabled="無効" +AMF.Util.Toggle.Enabled="有効" AMF.H264.Preset="プリセット" AMF.H264.Preset.ResetToDefaults="既定値に戻す" AMF.H264.Preset.Recording="録画中" @@ -7,27 +12,27 @@ AMF.H264.Preset.Twitch="Twitch" AMF.H264.Preset.YouTube="YouTube" AMF.H264.Usage="用途" +AMF.H264.Usage.Description="AMFの使用方法:\n- '\@AMF.H264.Usage.Transcoding\@' は汎用のトランスコード (推奨) で、\n- '\@AMF.H264.Usage.UltraLowLatency\@' は超低遅延エンコード用で、\n- '\@AMF.H264.Usage.LowLatency\@' は上記と似ていますが少し遅延があります。\n配信は '\@AMF.H264.Usage.Transcoding\@' のみをサポートし、他のすべての値は録画で使用できます。" AMF.H264.Usage.Transcoding="変換" AMF.H264.Usage.UltraLowLatency="超低遅延" AMF.H264.Usage.LowLatency="低遅延" AMF.H264.QualityPreset="品質プリセット" +AMF.H264.QualityPreset.Description="どの品質プリセットをAMFが目標とするか:\n- '\@AMF.H264.QualityPreset.Speed\@' は最速ですが品質は最悪で、\n- '\@AMF.H264.QualityPreset.Balanced\@' は両方のバランスの取れた組み合わせで、\n- '\@AMF.H264.QualityPreset.Quality\@' は指定されたビットレートに対して最高の品質を提供します。" AMF.H264.QualityPreset.Speed="速度" AMF.H264.QualityPreset.Balanced="バランス" AMF.H264.QualityPreset.Quality="品質" AMF.H264.Profile="プロファイル" +AMF.H264.Profile.Description="エンコードに使用するH.264プロファイル:\n- 'Baseline' はプラットフォームごとのサポートが最も大きく、\n- 'Main' は古いデバイスでもサポートされ、(モバイルデバイスがターゲットなら推奨)\n- 'High' は現在主流のデバイスでサポートされています。(推奨)" AMF.H264.ProfileLevel="プロファイルレベル" AMF.H264.ProfileLevel.Description="エンコードに使用する H.264 プロファイルレベル:\n- '自動' は与えられたフレームレートと解像度に対して最適なプロファイルレベルを計算し、\n- '4.1' は 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS をサポートし、\n- '4.2' は 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS をサポートし、\n- '5.0' は 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS をサポートし、\n- '5.1' は 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS をサポートし、\n- '5.2' は 3840x2160 60FPS、1920 x 1080 172FPS, 1280 x 720 172FPS, 960 x 540 172FPS をサポートします。" -AMF.H264.MaximumLTRFrames="最大 LTR フレーム" -AMF.H264.ScanType="スキャンの種類" -AMF.H264.ScanType.Description="どのスキャン方法が使用されるか、'プログレッシブ'を常にこのままにしておきます。" -AMF.H264.ScanType.Progressive="プログレッシブ" -AMF.H264.ScanType.Interlaced="インターレース" AMF.H264.RateControlMethod="レート制御方式" +AMF.H264.RateControlMethod.Description="どのレート制御方法を使用すべきか:\n- '\@AMF.H264.RateControlMethod.CQP\@' は固定I-/P-/B-フレームQP (量子化パラメータ) の値を割り当て、\n- '\@AMF.H264.RateControlMethod.CBR\@' は指定された目標ビットレート (フィラーデータを使用) に留まり (配信に推奨)、\n- '\@AMF.H264.RateControlMethod.VBR\@' は指定されたピークビットレート以下にとどまり、\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' はGPU遅延と負荷が許可されている場合は目標ビットレートに近く、それ以外の場合はより高いビットレートを使用します (録画に推奨)。" AMF.H264.RateControlMethod.CQP="固定QP (CQP)" AMF.H264.RateControlMethod.CBR="固定ビットレート (CBR)" AMF.H264.RateControlMethod.VBR.Peak="可変ビットレート (ピーク制約) (VBR)" AMF.H264.RateControlMethod.VBR.Latency="可変ビットレート (遅延制約) (VBR_LAT)" AMF.H264.Bitrate.Target="目標ビットレート" +AMF.H264.Bitrate.Target.Description="全体的なシーケンスで達成しようとするビットレート。" AMF.H264.Bitrate.Peak="最大ビットレート" AMF.H264.Bitrate.Peak.Description="全体的なシーケンスでピークを最大にしようとするビットレート。" AMF.H264.QP.Minimum="最小QP" @@ -35,49 +40,95 @@ AMF.H264.QP.Maximum="最大QP" AMF.H264.QP.Maximum.Description="フレームで使用する最高 QP (量子化パラメーター) の値です。" AMF.H264.QP.IFrame="I-フレーム QP" +AMF.H264.QP.IFrame.Description="I-フレームに使用する固定 QP の値。" AMF.H264.QP.PFrame="P-フレーム QP" +AMF.H264.QP.PFrame.Description="P-フレームに使用する固定 QP の値。" AMF.H264.QP.BFrame="B-フレーム QP" -AMF.H264.QP.BPictureDelta="B-画像デルタ QP" -AMF.H264.QP.BPictureDelta.Description="最後の非参照B-画像のデルタQPです。" -AMF.H264.QP.ReferenceBPictureDelta="B-画像参照のデルタQP" -AMF.H264.QP.ReferenceBPictureDelta.Description="最後の参照B-画像のデルタQPです。" +AMF.H264.QP.BFrame.Description="B-フレームに対して使用する固定 QP (量子化パラメーター) の値です。" AMF.H264.VBVBuffer="VBV バッファ" +AMF.H264.VBVBuffer.Description="どの方法を使用してVBVバッファーサイズを決定する必要があるか:\n- '\@AMF.Util.Automatic\@' は厳密性制約を使用してサイズを計算し、\n- '\@AMF.Util.Manual\@' はユーザーがサイズを制御できるようにします。\nVBV (ビデオバッファリングベリファイア) バッファは特定のレート制御方法により指定された制約内で全体のビットレートを保持するために使用されます。" AMF.H264.VBVBuffer.Strictness="VBV バッファ厳密性" +AMF.H264.VBVBuffer.Strictness.Description="VBV バッファーの厳密さを決定し、100%は可能な限り厳密で0%は制限されません。" AMF.H264.VBVBuffer.Size="VBV バッファサイズ" +AMF.H264.VBVBuffer.Size.Description="シーケンスにおけるビットレート制御のために使用されている VBV バッファーのサイズ。" AMF.H264.VBVBuffer.Fullness="VBV バッファ充満" +AMF.H264.VBVBuffer.Fullness.Description="VBVバッファーの初期状態は、エンコーディングの初期シーケンスにのみ影響します。" AMF.H264.FillerData="フィラーデータ" +AMF.H264.FillerData.Description="フィラーデータを有効にするとエンコーダは空の情報でシーケンスの残りのスペースを埋めることによって少なくともターゲットビットレートを維持することができます。" AMF.H264.FrameSkipping="フレームスキップ" +AMF.H264.FrameSkipping.Description="フレームスキッピングはエンコーダが目標ビットレート要件を満たすためにフレームをドロップすることを可能にする。\nエンコーダがフレームを落とすときに代わりにリピートラストフレームNALをストリームに挿入する。\n目標ビットレートが非常に低い場合に役立ちます。" AMF.H264.EnforceHRDCompatibility="HRD 互換性を強制" -AMF.H264.MaximumAccessUnitSize="最大アクセスユニットサイズ" +AMF.H264.EnforceHRDCompatibility.Description="フレーム内の最大QP値の変化を制限する仮説的参照デコーダの制限を強制します。\n録画や配信には非推奨で参照ソフトウェアデコーダのみを持つ非常に古いデバイスをターゲットにする場合にのみ使用してください。" AMF.H264.KeyframeInterval="キーフレーム間隔" AMF.H264.KeyframeInterval.Description="ドロップ不可能なフレーム間の秒数。\nGOPのサイズも制御します。" AMF.H264.IDRPeriod="IDR 周期" -AMF.H264.HeaderInsertionSpacing="ヘッダー挿入間隔" -AMF.H264.BPicture.Pattern="B-画像パターン" -AMF.H264.BPicture.Reference="B-画像参照" +AMF.H264.IDRPeriod.Description="フレーム内の瞬時デコードリフレッシュ (IDR) 間の距離を定義します。 GOP-シーケンスのサイズも制御します。" +AMF.H264.BFrame.Pattern="B-フレーム" +AMF.H264.BFrame.Pattern.Description="エンコードに使用するBフレームの数。\n第2世代および第3世代のVCEカードでサポートされています。 エンコーディングのパフォーマンスに悪影響を与えます。" +AMF.H264.BFrame.DeltaQP="B-フレーム デルタ QP" +AMF.H264.BFrame.DeltaQP.Description="参照不可能なB-フレームに対する最後のI-フレームまたはP-フレームまでのデルタ QP の値。" +AMF.H264.BFrame.Reference="参照可能 B-フレーム" +AMF.H264.BFrame.Reference.Description="B-フレームはP-フレームとI-フレームだけでなく、B-フレームも参照として使用できます。" +AMF.H264.BFrame.ReferenceDeltaQP="参照可能 B-フレーム デルタ QP" +AMF.H264.BFrame.ReferenceDeltaQP.Description="参照可能なB-フレームに対する最後のI-フレームまたはP-フレームまでのデルタ QP の値。" AMF.H264.DeblockingFilter="デブロックフィルタ" AMF.H264.DeblockingFilter.Description="デコーダがエンコードされたストリームに対してデブロックフィルタの使用を許可されているかのフラグを設定します。" -AMF.H264.SlicesPerFrame="フレームあたりのスライス" -AMF.H264.IntraRefreshNumMBsPerSlot="スロットごとのマクロブロックのイントラリフレッシュ数" +AMF.H264.ScanType="スキャンの種類" +AMF.H264.ScanType.Description="どのスキャン方法が使用されるか、'プログレッシブ'を常にこのままにしておきます。" +AMF.H264.ScanType.Progressive="プログレッシブ" +AMF.H264.ScanType.Interlaced="インターレース" AMF.H264.MotionEstimation="動き推定" AMF.H264.MotionEstimation.Description="動き推定はピクセルがどこに移動したかを推定することによってエンコーダが必要とするビットレートを削減します。" AMF.H264.MotionEstimation.None="未設定" AMF.H264.MotionEstimation.Half="1/2ピクセル" AMF.H264.MotionEstimation.Quarter="1/4ピクセル" AMF.H264.MotionEstimation.Both="ハーフ & クォーターピクセル" -AMF.H264.Device="デバイス" -AMF.H264.UseOpenCL="OpenCL を使用する" +AMF.H264.CodingType="コーディングの種類" +AMF.H264.CodingType.Description="使用するコーディングの種類:\n* \@AMF.Util.Default\@ AMFが決定します。(推奨)\n* CALVC (Context-Adaptive Variable-Length Coding) は高速ですが、容量は大きいです。\n* CABAC (Context-Adaptive Binary Arithmetic Coding) は低速ですが、容量は小さくなります。" +AMF.H264.MaximumLTRFrames="最大 LTR フレーム" +AMF.H264.MaximumLTRFrames.Description="長期間参照 (LTR) フレームはエンコーダがシーケンス内の特定のフレームに長期間参照可能なフラグを立てる機能です。\nLTRフレームはB-ピクチャとの併用は不可でエンコーダはB-ピクチャが使用されている場合は無効にします。" +AMF.H264.MaximumAccessUnitSize="最大アクセスユニットサイズ" +AMF.H264.MaximumAccessUnitSize.Description="NALに対するアクセス単位の最大サイズ。 値が0の場合エンコーダは最良のものを選択できます。" +AMF.H264.HeaderInsertionSpacing="ヘッダー挿入間隔" +AMF.H264.HeaderInsertionSpacing.Description="NALヘッダーの間にあるフレーム数。 これを0 (自動) から変更することはお勧めしません。" +AMF.H264.WaitForTask="タスクの待機" +AMF.H264.WaitForTask.Description="不明、実験的" +AMF.H264.PreAnalysisPass="事前解析パス" +AMF.H264.PreAnalysisPass.Description="不明、実験的" +AMF.H264.VBAQ="VBAQ" +AMF.H264.VBAQ.Description="不明、実験的" +AMF.H264.GOPSize="GOP サイズ" +AMF.H264.GOPSize.Description="不明、実験的" +AMF.H264.GOPAlignment="GOP 配置" +AMF.H264.GOPAlignment.Description="不明、実験的" +AMF.H264.MaximumReferenceFrames="最大参照フレーム" +AMF.H264.MaximumReferenceFrames.Description="不明、実験的" +AMF.H264.SlicesPerFrame="フレームあたりのスライス" +AMF.H264.SlicesPerFrame.Description="各スロットにいくつのI-フレームスライスを格納する必要があるか?\nゼロの値を指定するとエンコーダは高速で決定します。\nイントラ-リフレッシュのエンコードは高速再生とシークに使用されます。" +AMF.H264.SliceMode="スライスモード" +AMF.H264.SliceMode.Description="不明、実験的" +AMF.H264.MaximumSliceSize="最大スライスサイズ" +AMF.H264.MaximumSliceSize.Description="不明、実験的" +AMF.H264.SliceControlMode="スライスコントロールモード" +AMF.H264.SliceControlMode.Description="不明、実験的" +AMF.H264.SliceControlSize="スライスコントロールサイズ" +AMF.H264.SliceControlSize.Description="不明、実験的" +AMF.H264.IntraRefresh.NumberOfStripes="イントラ-リフレッシュストライプ数" +AMF.H264.IntraRefresh.NumberOfStripes.Description="不明、実験的" +AMF.H264.IntraRefresh.MacroblocksPerSlot="スロットごとのマクロブロックのイントラ-リフレッシュ数" +AMF.H264.IntraRefresh.MacroblocksPerSlot.Description="各スロットにいくつのマクロブロックを格納する必要があるか?\nゼロの値を指定するとこの機能は無効になります。\nイントラ-リフレッシュのエンコードは高速再生とシークに使用されます。" +AMF.H264.VideoAPI="映像 API" +AMF.H264.VideoAPI.Description="エンコードに使用する API。" +AMF.H264.VideoAdapter="ビデオアダプター" +AMF.H264.VideoAdapter.Description="エンコードに使用するアダプター。" +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="エンコーダはOpenCLを使用して個々のフレームを送信する必要がありますか?" AMF.H264.View="表示モード" AMF.H264.View.Description="どのプロパティが表示されるか。 'エキスパート' または 'マスター' の表示モードを使用する場合はサポートを受けられません。" AMF.H264.View.Basic="基本" AMF.H264.View.Advanced="詳細設定" AMF.H264.View.Expert="エキスパート" AMF.H264.View.Master="マスター" -AMF.H264.UnlockProperties="プロパティのロック解除" AMF.H264.Debug="デバッグ" AMF.H264.Debug.Description="追加のデバッグログ出力を有効にし、これはこのエンコーダでサポートが必要なときにアクティブにする必要があります。" -AMF.Util.Default="既定値" -AMF.Util.Automatic="自動" -AMF.Util.Manual="手動" -AMF.Util.Toggle.Disabled="無効" -AMF.Util.Toggle.Enabled="有効" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/ko-KR.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/ko-KR.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="기본값" +AMF.Util.Automatic="자동" +AMF.Util.Manual="수동" +AMF.Util.Toggle.Disabled="비활성화" +AMF.Util.Toggle.Enabled="활성화" AMF.H264.Preset="사전 설정" AMF.H264.Preset.ResetToDefaults="기본값으로 복구" AMF.H264.Preset.Recording="녹화" @@ -20,12 +25,6 @@ AMF.H264.Profile.Description="인코딩에 사용할 H.264 프로파일을 선택합니다:\n- 'Baseline'은 지원하는 플랫폼이 가장 많습니다,\n- 'Main'은 비교적 오래된 장치에서 지원합니다. (모바일 장치를 대상으로 한다면 추천하는 설정입니다),\n- 'High'는 현재 장치에서 지원하는 설정입니다 (추천)." AMF.H264.ProfileLevel="프로필 수준" AMF.H264.ProfileLevel.Description="인코딩으로 사용할 H.264 프로파일 수준을 지정합니다:\n-'자동'은 설정된 프레임과 그 크기에 맞춰 가장 좋은 수준을 계산합니다,\n-'4.1'은 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS을 지원합니다,\n-'4.2'는 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS을 지원합니다,\n- '5.0'은 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS을 지원합니다,\n- '5.1'은 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS을 지원합니다,\n- '5.2'은 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS을 지원합니다." -AMF.H264.MaximumLTRFrames="최대 장기참조 프레임" -AMF.H264.MaximumLTRFrames.Description="장기참조 프레임(LTR)은 인코더가 특정 프레임을 참조 가능하게 만들어 줍니다.\n이 설정은 B-화면 기능이 지원되지 않거나 필요한 경우 품질을 올리는데 도움이 될 수 있습니다.\n장기참조 프레임은 B-화면과 동시에 사용할 수 없습니다." -AMF.H264.ScanType="스캔 형식" -AMF.H264.ScanType.Description="주사 방식을 설정합니다. 항상 '프로그레시브'로 두십시오." -AMF.H264.ScanType.Progressive="프로그레시브" -AMF.H264.ScanType.Interlaced="인터레이스" AMF.H264.RateControlMethod="속도 제어 방식" AMF.H264.RateControlMethod.Description="속도 제어 동작 방식을 설정합니다:\n- '\@AMF.H264.RateControlMethod.CQP\@'는 고정된 I-/P-/B- 프레임 QP (양자화 매개변수) 값을 할당합니다, \n- '\@AMF.H264.RateControlMethod.CBR\@'은 주어진 목표 비트레이트를 유지합니다. (채우기 정보를 사용)(방송에 추천함),\n- '\@AMF.H264.RateControlMethod.VBR\@'은 주어진 최대 비트레이트보다 낮은 수준을 유지합니다,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@'는 GPU의 지연시간과 부하가 허용한다면 목표 비트레이트에 가까운 수준을 유지하며, 그렇지 않은 상황에서는 그보다 높은 비트레이트를 사용합니다. (녹화에 추천)." AMF.H264.RateControlMethod.CQP="고정 QP (CQP)" @@ -41,21 +40,17 @@ AMF.H264.QP.Maximum="최대 QP" AMF.H264.QP.Maximum.Description="하나의 프레임에 사용하는 최고 QP (양자화 매개변수) 값" AMF.H264.QP.IFrame="I-프레임 QP" -AMF.H264.QP.IFrame.Description="I-화면에 사용하는 고정 QP (양자화 매개변수) 값.\nI-화면 QP는 P-와 B-화면 QP값과 같거나 커야 함." +AMF.H264.QP.IFrame.Description="I-화면에 사용할 고정 QP 값입니다." AMF.H264.QP.PFrame="P-프레임 QP" -AMF.H264.QP.PFrame.Description="P-화면에 사용하는 고정 QP (양자화 매개변수) 값.\nP-화면 QP는 B-화면 QP값과 같거나 혹은 커야 함." +AMF.H264.QP.PFrame.Description="P-화면에 사용할 고정 QP 값입니다." AMF.H264.QP.BFrame="BP-프레임 QP" AMF.H264.QP.BFrame.Description="B-화면에 사용하는 고정 QP (양자화 매개변수) 값." -AMF.H264.QP.BPictureDelta="B-화면 델타 QP" -AMF.H264.QP.BPictureDelta.Description="마지막 비참조 B-화면의 델타 QP." -AMF.H264.QP.ReferenceBPictureDelta="참조 B-화면 델타 QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="마지막 참조 B-화면의 델타 QP." AMF.H264.VBVBuffer="VBV 버퍼" AMF.H264.VBVBuffer.Description="VBV 버퍼 크기를 결정하는 방식을 설정합니다:\n-'자동'은 엄격도의 제약하에 크기를 계산합니다.\n-'수동'은 사용자가 크기를 조절할 수 있도록 허용합니다.\n일부 특정 속도제어 방식이 사용하는 VBV (Video Buffering Verifier) 버퍼는 제공된 제약 안에서 전반적인 비트레이트를 유지합니다." AMF.H264.VBVBuffer.Strictness="VBV 버퍼 엄격도" -AMF.H264.VBVBuffer.Strictness.Description="VBV 버퍼가 어떤 수준으로 제어될지 결정합니다. 100%에는 목표로 정한 비트레이트와 거의 일치하도록 조절하며 0%에서는 제약이 사라집니다." +AMF.H264.VBVBuffer.Strictness.Description="VBV 버퍼의 엄격도를 설정합니다. 0%는 제약이 사라지고 100%는 최대한 제한을 합니다." AMF.H264.VBVBuffer.Size="VBV 버퍼 크기" -AMF.H264.VBVBuffer.Size.Description="한 장면의 비트레이트 제어에 사용하는 VBV 버퍼의 크기를 설정합니다.\n크기를 작게 설정하면 거의 완벽하게 비트레이트 수준에 일치하는 결과를 얻지만, 작업을 하는데 더 많은 자원을 요구합니다." +AMF.H264.VBVBuffer.Size.Description="VBV의 크기는 한 장면의 비트레이트 제어에 사용하는 단위입니다." AMF.H264.VBVBuffer.Fullness="VBV 버퍼 충만도" AMF.H264.VBVBuffer.Fullness.Description="초기 VBV버퍼가 얼마나 충만한지는 오로지 인코딩의 초반에만 영향을 미칩니다." AMF.H264.FillerData="채우기 정보" @@ -64,46 +59,73 @@ AMF.H264.FrameSkipping.Description="프레임 생략은 인코더가 목표로 하는 비트레이트 요건을 맞추기 위해 프레임을 떨어뜨릴 수 있습니다.\n인코더가 프레임 하나를 떨어뜨리면 마지막 프레임 NAL을 대신 전송합니다.\n목표 비트레이트가 아주 낮을 때 도움이 될 수 있습니다." AMF.H264.EnforceHRDCompatibility="HDR 호환모드 적용" AMF.H264.EnforceHRDCompatibility.Description="이론적 기본 디코더 강제는 프레임 하나의 최대 QP값 변화를 제한하는 설정입니다.\n녹화나 방송에는 적합하지 않고 기본 소프트웨어 디코더만 사용 가능한 매우 낡은 장치에서 영상을 재생할 때 사용합니다." -AMF.H264.MaximumAccessUnitSize="최대 접근 유닛 크기" -AMF.H264.MaximumAccessUnitSize.Description="NAL 장치에서 단일 접근 유닛의 가장 큰 크기를 결정합니다. 0 값은 인코더가 최적화된 수치를 결정하도록 허용합니다." AMF.H264.KeyframeInterval="키프레임 간격" AMF.H264.KeyframeInterval.Description="손실이 불가능한 프레임 사이에 얼마나 많은 시간(초)이 필요한지 설정합니다.\n또한 영상(GOP) 크기도 제어합니다." AMF.H264.IDRPeriod="IDR 주기" AMF.H264.IDRPeriod.Description="프레임 내에서 순간 복호 갱신(nstantaneous Decoding Refreshes) 사이의 거리를 설정합니다. 또한, GOP-장면 크기를 제어합니다." -AMF.H264.HeaderInsertionSpacing="헤더 삽입 간격" -AMF.H264.HeaderInsertionSpacing.Description="NAL 헤더 사이에 얼마나 많은 프레임이 필요한지 설정합니다. 0(자동)에서 바꾸는 것은 추천하지 않습니다." -AMF.H264.BPicture.Pattern="B-화면 양식" -AMF.H264.BPicture.Pattern.Description="인코딩에서 얼마나 많은 B-화면이 필요한지 결정합니다. 수치가 늘어날수록 품질은 올라가고 필요한 성능은 높아집니다.\n2세대와 3 세대 VCE 카드에서만 지원이 됩니다." -AMF.H264.BPicture.Reference="B-화면 참조" -AMF.H264.BPicture.Reference.Description="다른 B-화면뿐만 아니라 P-/I-화면에도 B-화면을 참조할 수 있도록 허용합니다.\n높은 성능이 요구되지만 품질 개선에는 그리 큰 효과가 없습니다." +AMF.H264.BFrame.Pattern.Description="인코딩에 얼마나 많은 B-화면을 사용할지 설정합니다.\n2, 3세대 VCE카드에서 지원합니다. 인코딩 성능에 부정적인 영향을 줍니다." +AMF.H264.BFrame.DeltaQP="B-화면 델타 QP" +AMF.H264.BFrame.DeltaQP.Description="비참조 B-화면에 쓰이는 마지막 I- 혹은P-화면의 델타 QP 값" +AMF.H264.BFrame.Reference="참조가능한 B-화면" +AMF.H264.BFrame.Reference.Description="P-와 I-화면뿐만 아니라 B-화면도 참조할 수 있도록 허용합니다." +AMF.H264.BFrame.ReferenceDeltaQP="참조가능한 B-화면 델타 QP" +AMF.H264.BFrame.ReferenceDeltaQP.Description="비참조 B-화면에 쓰이는 마지막 I- 혹은P-화면의 델타 QP 값." AMF.H264.DeblockingFilter="디블록 필터" AMF.H264.DeblockingFilter.Description="디코더가 인코딩된 작업에 디블록 필터를 사용할 수 있도록 허용합니다." -AMF.H264.SlicesPerFrame="조각 당 프레임" -AMF.H264.SlicesPerFrame.Description="프레임마다 얼마나 많은 I-화면 조각을 저장할지 결정합니다.\n0값은 인코더가 상태에 따라 맞춰 조절합니다.\n인트라-리프레시 인코딩은 더 빠른 재생과 탐색을 위해 사용합니다." -AMF.H264.IntraRefreshNumMBsPerSlot="슬롯 당 매크로블록의 인트라-리프레시 수" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="슬롯마다 얼마나 많은 매크로 블록을 저장할지 결정합니다.\n\0값은 인코더가 상태에 따라 맞춰 조절합니다.\n인인트라-리프레시 인코딩은 더 빠른 재생과 탐색을 위해 사용합니다." +AMF.H264.ScanType="스캔 형식" +AMF.H264.ScanType.Description="주사 방식을 설정합니다. 항상 '프로그레시브'로 두십시오." +AMF.H264.ScanType.Progressive="프로그레시브" +AMF.H264.ScanType.Interlaced="인터레이스" AMF.H264.MotionEstimation="동작 예측" AMF.H264.MotionEstimation.Description="동작 추정은 픽셀의 움직임을 추정하여 필요한 비트레이트를 줄일 수 있게 합니다." AMF.H264.MotionEstimation.None="없음" AMF.H264.MotionEstimation.Half="1/2 화소" AMF.H264.MotionEstimation.Quarter="1/4 화소" AMF.H264.MotionEstimation.Both="1/2 & 1/4 화소" -AMF.H264.Device="장치" -AMF.H264.Device.Description="인코덩에 사용할 장치를 설정합니다.\n메모리 형식에서 'Host'를 선택하면 안됩니다." -AMF.H264.UseOpenCL="OpenCL 사용" -AMF.H264.UseOpenCL.Description="해당 인코더가 개별 프레임을 제출할 때 OpenCL을 사용하겠습니까?" +AMF.H264.CodingType="부호화 형식" +AMF.H264.CodingType.Description="부호화 형식을 결정합니다:\n* \@AMF.Util.Default\@ 은 AMF가 자동으로 선택합니다 (추천).\n* CALVC (문맥기반 적응적 가변길이 부호화) 는 빠르지만, 더 큽니다.\n* CABAC (문맥기반 적응적 이진산술 부호화) 는 느리지만, 더 작습니다." +AMF.H264.MaximumLTRFrames="최대 장기참조 프레임" +AMF.H264.MaximumLTRFrames.Description="장기참조 프레임(LTR)은 인코더가 긴 시계에서 특정 프레임을 참조 가능하게 만들어 줍니다.\n장기참조 프레임은 B-화면과 동시에 사용할 수 없습니다." +AMF.H264.MaximumAccessUnitSize="최대 접근 유닛 크기" +AMF.H264.MaximumAccessUnitSize.Description="NAL 장치에서 단일 접근 유닛의 가장 큰 크기를 결정합니다. 0 값은 인코더가 최적화된 수치를 결정하도록 허용합니다." +AMF.H264.HeaderInsertionSpacing="헤더 삽입 간격" +AMF.H264.HeaderInsertionSpacing.Description="NAL 헤더 사이에 얼마나 많은 프레임이 필요한지 설정합니다. 0(자동)에서 바꾸는 것은 추천하지 않습니다." +AMF.H264.WaitForTask="작업을 대기" +AMF.H264.WaitForTask.Description="알수 없음, 실험적인 기능" +AMF.H264.VBAQ="VBAQ" +AMF.H264.VBAQ.Description="알수 없음, 실험적인 기능" +AMF.H264.GOPSize="GOP 크기" +AMF.H264.GOPSize.Description="알수 없음, 실험적인 기능" +AMF.H264.GOPAlignment="GOP 조정" +AMF.H264.GOPAlignment.Description="알수 없음, 실험적인 기능" +AMF.H264.MaximumReferenceFrames="최대 참조 프레임" +AMF.H264.MaximumReferenceFrames.Description="알수 없음, 실험적인 기능" +AMF.H264.SlicesPerFrame="조각 당 프레임" +AMF.H264.SlicesPerFrame.Description="프레임마다 얼마나 많은 I-화면 조각을 저장할지 결정합니다.\n0값은 인코더가 상태에 따라 맞춰 조절합니다.\n인트라-리프레시 인코딩은 더 빠른 재생과 탐색을 위해 사용합니다." +AMF.H264.SliceMode="분할 모드" +AMF.H264.SliceMode.Description="알수 없음, 실험적인 기능" +AMF.H264.MaximumSliceSize="최대 분할 크기" +AMF.H264.MaximumSliceSize.Description="알수 없음, 실험적인 기능" +AMF.H264.SliceControlMode="분할 제어 모드" +AMF.H264.SliceControlMode.Description="알수 없음, 실험적인 기능" +AMF.H264.SliceControlSize="분할 제어 크기" +AMF.H264.SliceControlSize.Description="알수 없음, 실험적인 기능" +AMF.H264.IntraRefresh.NumberOfStripes="인트라-리프레시 줄무늬 개수" +AMF.H264.IntraRefresh.NumberOfStripes.Description="알수 없음, 실험적인 기능" +AMF.H264.IntraRefresh.MacroblocksPerSlot="슬롯 당 매크로블록의 인트라-리프레시 수" +AMF.H264.IntraRefresh.MacroblocksPerSlot.Description="슬롯마다 얼마나 많은 매크로 블록을 저장할지 결정합니다.\n\0값은 인코더가 상태에 따라 맞춰 조절합니다.\n인트라-리프레시 인코딩은 더 빠른 재생과 탐색을 위해 사용합니다." +AMF.H264.VideoAPI="비디오 API" +AMF.H264.VideoAPI.Description="인코딩에 어떤 API를 사용할지 설정합니다." +AMF.H264.VideoAdapter="비디오 어댑터:" +AMF.H264.VideoAdapter.Description="인코딩에 어떤 어댑터를 사용할지 설정합니다." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="해당 인코더가 개별 프레임을 제출할 때 OpenCL을 사용하겠습니까?" AMF.H264.View="보기 모드" AMF.H264.View.Description="어떤 설정을 표시할지 결정합니다. '숙련' 혹은 '달인' 표시 모드에서는 지원을 받을 수 없습니다." AMF.H264.View.Basic="기본" AMF.H264.View.Advanced="고급" AMF.H264.View.Expert="숙련" AMF.H264.View.Master="달인" -AMF.H264.UnlockProperties="속성 잠금해제" -AMF.H264.UnlockProperties.Description="특정 설정을 부분적이 아닌 전체 범위를 다룰 수 있도록 잠금을 해제합니다." AMF.H264.Debug="디버그" AMF.H264.Debug.Description="추가적인 디버그 기록을 활성화하여 이 인코더에 대한 지원이 필요할 때 제출하십시오." -AMF.Util.Default="기본값" -AMF.Util.Automatic="자동" -AMF.Util.Manual="수동" -AMF.Util.Toggle.Disabled="비활성화" -AMF.Util.Toggle.Enabled="활성화" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/nb-NO.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/nb-NO.ini
Changed
@@ -1,3 +1,7 @@ +AMF.Util.Default="Standard" +AMF.Util.Automatic="Automatisk" +AMF.Util.Toggle.Disabled="Deaktivert" +AMF.Util.Toggle.Enabled="Aktivert" AMF.H264.Usage.Transcoding="Transkoding" AMF.H264.Usage.UltraLowLatency="Ultra-lav latens" AMF.H264.Usage.LowLatency="Lav latens" @@ -7,13 +11,10 @@ AMF.H264.QualityPreset.Quality="Kvalitet" AMF.H264.Profile="Profil" AMF.H264.ProfileLevel="Profilnivå" -AMF.H264.ScanType="Skanne Type" AMF.H264.Bitrate.Target="Mål Bitrate" AMF.H264.Bitrate.Peak="Maks bitrate" AMF.H264.QP.Minimum="Minste QP" AMF.H264.QP.Maximum="Maksimal QP" AMF.H264.EnforceHRDCompatibility="Håndheve HRD kompatibilitet" -AMF.Util.Default="Standard" -AMF.Util.Automatic="Automatisk" -AMF.Util.Toggle.Disabled="Deaktivert" -AMF.Util.Toggle.Enabled="Aktivert" +AMF.H264.ScanType="Skanne Type" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/nl-NL.ini
Changed
@@ -1,3 +1,7 @@ +AMF.Util.Default="Standaard" +AMF.Util.Automatic="Automatisch" +AMF.Util.Toggle.Disabled="Uitgeschakeld" +AMF.Util.Toggle.Enabled="Ingeschakeld" AMF.H264.Preset="Voorkeursinstelling" AMF.H264.Preset.Recording="Opname" AMF.H264.Preset.HighQuality="Hoge kwaliteit" @@ -17,11 +21,6 @@ AMF.H264.Profile="Profiel" AMF.H264.ProfileLevel="Profielniveau" AMF.H264.ProfileLevel.Description="Welk H.264 profielniveau moet worden gebruikt voor encoden:\n- 'Automatisch' berekent het beste profielniveau voor de gebruikte framerate en framegrootte.\n- '4.1' ondersteunt 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' ondersteunt 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' ondersteunt1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' ondersteunt3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' ondersteunt 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Maximale LTR Frames" -AMF.H264.MaximumLTRFrames.Description="Long Term Reference (LTR) Frames zijn een functie waarmee de encoder bepaalde frames achter elkaar als refereerbaar kan markern.\nDit kan een positief effect hebben op de kwaliteit wanneer B-Pictures niet ondersteund of gewild zijn.\nLTR Frames kunnen niet samen met B-Pictures gebruikt worden en deencoder zal B-Pictures uitschakelen als deze worden gebruikt." -AMF.H264.ScanType="Scantype" -AMF.H264.ScanType.Progressive="Progressive" -AMF.H264.ScanType.Interlaced="Interlaced" AMF.H264.RateControlMethod="Rate control methode" AMF.H264.RateControlMethod.CQP="Constant QP (CQP)" AMF.H264.RateControlMethod.CBR="Constant Bitrate (CBR)" @@ -34,18 +33,13 @@ AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.BPictureDelta.Description="Delta QP (Quantization Parameter) waarde tot de laatste niet-reference B-Picture." -AMF.H264.QP.ReferenceBPictureDelta="Referentie B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="Delta QP (Quantization Parameter) waarde tot de laatste referentie B-Picture,." AMF.H264.VBVBuffer="VBV Buffer" AMF.H264.FillerData="Opvuldata" AMF.H264.FrameSkipping="Frames overslaan" AMF.H264.EnforceHRDCompatibility="Forceer HDR compatibiliteit" -AMF.H264.BPicture.Pattern="B-Picture patroon" -AMF.H264.BPicture.Reference="B-Picture referentie" AMF.H264.DeblockingFilter="Deblocking Filter" -AMF.Util.Default="Standaard" -AMF.Util.Automatic="Automatisch" -AMF.Util.Toggle.Disabled="Uitgeschakeld" -AMF.Util.Toggle.Enabled="Ingeschakeld" +AMF.H264.ScanType="Scantype" +AMF.H264.ScanType.Progressive="Progressive" +AMF.H264.ScanType.Interlaced="Interlaced" +AMF.H264.MaximumLTRFrames="Maximale LTR Frames" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/pl-PL.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/pl-PL.ini
Changed
@@ -1,4 +1,10 @@ +AMF.Util.Default="Domyślne" +AMF.Util.Automatic="Automatycznie" +AMF.Util.Manual="Ustawienia własne" +AMF.Util.Toggle.Disabled="Wyłączone" +AMF.Util.Toggle.Enabled="Włączone" AMF.H264.Preset="Profil" +AMF.H264.Preset.ResetToDefaults="Przywróć ustawienia domyślne" AMF.H264.Preset.Recording="Nagrywanie" AMF.H264.Preset.HighQuality="Wysoka jakość" AMF.H264.Preset.Indistinguishable="Nie do odróżnienia" @@ -15,30 +21,61 @@ AMF.H264.QualityPreset.Quality="Jakość" AMF.H264.Profile="Profil" AMF.H264.ProfileLevel="Profil" -AMF.H264.ScanType="Metoda skanowania" -AMF.H264.ScanType.Progressive="Progresywne" -AMF.H264.ScanType.Interlaced="Z przeplotem" AMF.H264.RateControlMethod="Metoda kontroli przepływności" AMF.H264.RateControlMethod.CQP="Stała QP (CQP)" AMF.H264.RateControlMethod.CBR="Stała przepływność (CBR)" AMF.H264.RateControlMethod.VBR.Peak="Zmienna przepływność (z ograniczeniem górnym) (VBR)" AMF.H264.RateControlMethod.VBR.Latency="Zmienna przepływność (z ograniczeniem opóźnieniem) (VBR_LAT)" AMF.H264.Bitrate.Target="Przepływność docelowa" +AMF.H264.Bitrate.Target.Description="Średni bitrate do uzyskania w sekwencji." AMF.H264.Bitrate.Peak="Przepływność szczytowa" +AMF.H264.Bitrate.Peak.Description="Maksymalny bitrate do uzyskania w sekwencji." AMF.H264.QP.Minimum="Minimalna QP" +AMF.H264.QP.Minimum.Description="Najniższa wartość QP (parametr kwantyzacji) do użycia w ramce." AMF.H264.QP.Maximum="Maksymalna QP" +AMF.H264.QP.Maximum.Description="Najwyższa wartość QP (parametr kwantyzacji) do użycia w ramce." AMF.H264.QP.IFrame="I-Frame QP" +AMF.H264.QP.IFrame.Description="Stała wartość QP dla ramek I-Frame." AMF.H264.QP.PFrame="P-Frame QP" +AMF.H264.QP.PFrame.Description="Stała wartość QP dla ramek P-Frame." AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta="Referencyjne B-Picture Delta QP" +AMF.H264.QP.BFrame.Description="Stała wartość QP (parametr kwantyzacji) do użycia w ramce B-Frame." +AMF.H264.VBVBuffer="Bufor VBV" +AMF.H264.VBVBuffer.Strictness="Odchylenie bufora VBV" +AMF.H264.VBVBuffer.Strictness.Description="Określa rygor wykorzystania bufora VBV, gdzie 100% oznacza pełne podporządkowanie wartości a 0% - dowolne." +AMF.H264.VBVBuffer.Size="Rozmiar bufora VBV" +AMF.H264.VBVBuffer.Size.Description="Rozmiar bufora VBV używanego w kontroli przepływności sekwencji kodowania." +AMF.H264.VBVBuffer.Fullness="Zapełnienie bufora VBV" +AMF.H264.VBVBuffer.Fullness.Description="Jak bardzo zapełniony na starcie powinien być bufor VBV. Wpływa jedynie na początkową sekwencję kodowania." AMF.H264.FillerData="Filler Data" AMF.H264.FrameSkipping="Pomijanie klatek" AMF.H264.EnforceHRDCompatibility="Wymuszanie zgodności HRD" -AMF.H264.BPicture.Pattern="Schemat B-Picture" -AMF.H264.BPicture.Reference="Referencyjny B-Picture" +AMF.H264.KeyframeInterval="Interwał klatki kluczowej" +AMF.H264.KeyframeInterval.Description="Określa odległość (w sekundach) między klatkami kluczowymi oraz kontroluje rozmiar GOP." +AMF.H264.IDRPeriod="Okres IDR" +AMF.H264.IDRPeriod.Description="Określa (w klatkach) odległość między natychmiastowymi odświeżeniami dekodera. Kontroluje również rozmiar sekwencji GOP. +" AMF.H264.DeblockingFilter="Filtr niwelujacy bloki obrazu" -AMF.Util.Default="Domyślne" -AMF.Util.Automatic="Automatycznie" -AMF.Util.Toggle.Disabled="Wyłączone" -AMF.Util.Toggle.Enabled="Włączone" +AMF.H264.ScanType="Metoda skanowania" +AMF.H264.ScanType.Progressive="Progresywne" +AMF.H264.ScanType.Interlaced="Z przeplotem" +AMF.H264.CodingType="Typ kodowania" +AMF.H264.MaximumAccessUnitSize="Maksymalny rozmiar Access Unit" +AMF.H264.MaximumAccessUnitSize.Description="Maksymalny rozmiar Access Unit. Wartość 0 umożliwia enkoderowi wybranie najlepszej wartości." +AMF.H264.HeaderInsertionSpacing="Rozmiar nagłówka (w klatkach)" +AMF.H264.HeaderInsertionSpacing.Description="Ile klatek powinno być między nagłówkami. Nie zaleca się zmieniać wartości na inną niż 0 (automatycznie)." +AMF.H264.VideoAPI="Typ API" +AMF.H264.VideoAPI.Description="Rodzaj API wykorzystywanego do enkodowania." +AMF.H264.VideoAdapter="Karta graficzna" +AMF.H264.VideoAdapter.Description="Karta graficzna wykorzystywana do enkodowania." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="Czy enkoder ma użyć OpenCL do wysyłania poszczególnych klatek?" +AMF.H264.View="Tryb ustawień" +AMF.H264.View.Description="Którego typu ustawień używać.\nWłączenie '\@AMF.H264.View.Master\@' oznacza rezygnację ze wsparcia technicznego." +AMF.H264.View.Basic="Podstawowy" +AMF.H264.View.Advanced="Zaawansowany" +AMF.H264.View.Expert="Ekspercki" +AMF.H264.View.Master="Pełny" +AMF.H264.Debug="Debugowanie" +AMF.H264.Debug.Description="Włącza dodatkowe opcje logowania w trybie debug. Przydatne w przypadku poszukiwania wsparcia technicznego dla tego enkodera." +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/ru-RU.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/ru-RU.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="По умолчанию" +AMF.Util.Automatic="Автоматически" +AMF.Util.Manual="Руководство" +AMF.Util.Toggle.Disabled="Выключено" +AMF.Util.Toggle.Enabled="Включено" AMF.H264.Preset="Предустановка" AMF.H264.Preset.ResetToDefaults="Сброс по умолчанию" AMF.H264.Preset.Recording="Запись" @@ -19,12 +24,6 @@ AMF.H264.Profile="Профиль кодирования" AMF.H264.ProfileLevel="Уровень профиля" AMF.H264.ProfileLevel.Description="Какой уровень профиля H.264 использовать для кодирования:\n- 'Автоматически' выбирает наиболее подходящий уровень под выбранную частоту и размер кадра,\n- '4.1' поддерживает 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' поддерживает 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' поддерживает 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' поддерживает 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' поддерживает 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="Максимум LTR-кадров" -AMF.H264.MaximumLTRFrames.Description="Long Term Reference (LTR) Frames - функция позволяющая кодировщику помечать определенные кадры в последовательности как ссылаемые.\nЭта функция может поднять качество, если функция B-Pictrues не поддерживается или не желательна.\nФункция LTR Frames не может использоваться вместе с функцией B-Pictrues и кодировщик отключит функцию B-Pictrues если таковая используется." -AMF.H264.ScanType="Развертка" -AMF.H264.ScanType.Description="Какой режим сканирования использовать; всегда оставляется этот параметр на 'прогрессивном'." -AMF.H264.ScanType.Progressive="Прогрессивная" -AMF.H264.ScanType.Interlaced="Чересстрочная" AMF.H264.RateControlMethod="Метод кодирования" AMF.H264.RateControlMethod.CQP="CQP: постоянное качество" AMF.H264.RateControlMethod.CBR="CBR: постоянный битрейт" @@ -39,65 +38,47 @@ AMF.H264.QP.Maximum="Максимальное QP" AMF.H264.QP.Maximum.Description="Наибольшее значение QP (Параметр квантования) для использования в кадре." AMF.H264.QP.IFrame="I-кадр QP" -AMF.H264.QP.IFrame.Description="Фиксированное значение QP (Параметр квантования) для использования в I-Кадрах.\nQP I-Кадров должен быть равен или больше чем QP P- и B-Кадров." AMF.H264.QP.PFrame="P-кадр QP" -AMF.H264.QP.PFrame.Description="Фиксированное значение QP (Параметр квантования) для использования в P-Кадрах.\nQP P-Кадров должен быть равен или больше чем QP B-Кадров." AMF.H264.QP.BFrame="B-кадр QP" AMF.H264.QP.BFrame.Description="Фиксированное значение QP (Параметр квантования) для использования в B-Кадрах." -AMF.H264.QP.BPictureDelta="B-кадры дельта QP" -AMF.H264.QP.BPictureDelta.Description="Дельта QP до последнего не референсного B-кадра." -AMF.H264.QP.ReferenceBPictureDelta="Референсные B-кадры дельта QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="Дельта QP до последнего референсного B-кадра." AMF.H264.VBVBuffer="Буфер VBV" AMF.H264.VBVBuffer.Description="Какой метод следует использовать для определения Размера буфера VBV:\n- '\@AMF.Util.Automatic\@' рассчитывает размер ограничивающийся строгостью,\n- '\@AMF.Util.Manual\@' позволяет пользователю контролировать размер буфера.\nVBV (Верификатор буферизации видео) буфер используется некоторыми Методами управления скоростью, чтобы сохранить общий битрейт в пределах заданных ограничений." AMF.H264.VBVBuffer.Strictness="Строгость буфера VBV" -AMF.H264.VBVBuffer.Strictness.Description="Насколько строго должен быть ограничен буфер VBV: 100% — почти полное соответствие целевому битрейту, 0% — без ограничений." AMF.H264.VBVBuffer.Size="Размер буфера VBV" AMF.H264.VBVBuffer.Fullness="Заполнение буфера VBV" AMF.H264.VBVBuffer.Fullness.Description="Изначальная степень заполнения VBV буфера, будет влиять только на первоначальную последовательность кодирования." AMF.H264.FillerData="Данные наполнителя" AMF.H264.FrameSkipping="Пропуск кадров" AMF.H264.EnforceHRDCompatibility="Принудительная HRD совместимость" -AMF.H264.MaximumAccessUnitSize="Максимальный Размер Блока Доступа" -AMF.H264.MaximumAccessUnitSize.Description="Большой размер блока доступа для NAL. Значение 0 позволяет регулировать, чтобы выбрать лучший." AMF.H264.KeyframeInterval="Интервал ключевых кадров" AMF.H264.KeyframeInterval.Description="Сколько секунд должен быть просадок кадров.\nТакже контролирует GOP Size." AMF.H264.IDRPeriod="Период IDR" AMF.H264.IDRPeriod.Description="Определяет расстояние между Мгновенными обновлениями декодирования (IDR) в кадрах. Так же контролирует размер последовательности GOP." -AMF.H264.HeaderInsertionSpacing="Расстояние вставки заголовка" -AMF.H264.HeaderInsertionSpacing.Description="Сколько кадров должно быть между заголовками NAL. Не рекомендуется менять значение с 0 (автоматически)." -AMF.H264.BPicture.Pattern="Патерн B-кадра" -AMF.H264.BPicture.Pattern.Description="Сколько кадров B-Pictures должно быть разрешено для кодирования. Имеет положительный эффект на качестве и негативный на производительности.\nПоддерживает только второе поколение VCE. Значение функции LTR Frames должно быть равно нулю." -AMF.H264.BPicture.Reference="Референс B-кадра" -AMF.H264.BPicture.Reference.Description="Разрешает B-Кадрам ссылаться на другие B-Кадры как и на P- и I-Кадры.\nОгромный урон производительности, исправление низкого качества." AMF.H264.DeblockingFilter="Фильтр деблокинга" AMF.H264.DeblockingFilter.Description="Устанавливает флаг, что декодер может использовать фильтр удаления блочности для прямой трансляции." -AMF.H264.SlicesPerFrame="Количество частей на кадр" -AMF.H264.SlicesPerFrame.Description="Сколько кусков I-Кадров должно быть сохранено в каждом кадре?\nЗначение 0 позволяет кодировщику выбирать \"на лету\".\nКодирование Intra-Refresh используется для быстрого воспроизведения и поиска при перемотке." -AMF.H264.IntraRefreshNumMBsPerSlot="Интра-обновить Количество Макроблоков в слот" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="Сколько Макроблоков должно быть сохранено в каждом слоте?\nЗначение 0 позволяет кодировщику выбирать \"на лету\".\nКодирование Intra-Refresh используется для быстрого воспроизведения и поиска при перемотке." +AMF.H264.ScanType="Развертка" +AMF.H264.ScanType.Description="Какой режим сканирования использовать; всегда оставляется этот параметр на 'прогрессивном'." +AMF.H264.ScanType.Progressive="Прогрессивная" +AMF.H264.ScanType.Interlaced="Чересстрочная" AMF.H264.MotionEstimation="Оценка движения" AMF.H264.MotionEstimation.Description="Оценки движения позволяет кодировщику необходимость уменьшить Битрейт, оценивая, где пиксель прошел." AMF.H264.MotionEstimation.None="Нет" AMF.H264.MotionEstimation.Half="Пол-пиксельная" AMF.H264.MotionEstimation.Quarter="Четверть-пиксельная" AMF.H264.MotionEstimation.Both="Пол- & Четверть-пиксельная" -AMF.H264.Device="Устройство" -AMF.H264.Device.Description="Которое из устройств использовать для кодирования.\nТип памяти должен быть не 'Host'." -AMF.H264.UseOpenCL="Использовать OpenCL" -AMF.H264.UseOpenCL.Description="Должен ли кодировщик использовать OpenCL для подтверждения индивидуальных кадров?" +AMF.H264.MaximumLTRFrames="Максимум LTR-кадров" +AMF.H264.MaximumAccessUnitSize="Максимальный Размер Блока Доступа" +AMF.H264.MaximumAccessUnitSize.Description="Большой размер блока доступа для NAL. Значение 0 позволяет регулировать, чтобы выбрать лучший." +AMF.H264.HeaderInsertionSpacing="Расстояние вставки заголовка" +AMF.H264.HeaderInsertionSpacing.Description="Сколько кадров должно быть между заголовками NAL. Не рекомендуется менять значение с 0 (автоматически)." +AMF.H264.SlicesPerFrame="Количество частей на кадр" +AMF.H264.SlicesPerFrame.Description="Сколько кусков I-Кадров должно быть сохранено в каждом кадре?\nЗначение 0 позволяет кодировщику выбирать \"на лету\".\nКодирование Intra-Refresh используется для быстрого воспроизведения и поиска при перемотке." AMF.H264.View="Режим просмотра" AMF.H264.View.Description="Какие параметры должны быть видны. Вы не будете получать поддержку при использовании режимов 'Эксперт' и 'Мастер'." AMF.H264.View.Basic="Обычный" AMF.H264.View.Advanced="Расширенный" AMF.H264.View.Expert="Эксперт" AMF.H264.View.Master="Мастер" -AMF.H264.UnlockProperties="Разблокировать параметры" -AMF.H264.UnlockProperties.Description="Разблокировать определённые параметры до их полного, неограниченного диапазона." AMF.H264.Debug="Отладка" AMF.H264.Debug.Description="Включить дополнительные логи для отладки; следует включить, если вам нужна поддержка с этим кодировщиком." -AMF.Util.Default="По умолчанию" -AMF.Util.Automatic="Автоматически" -AMF.Util.Manual="Руководство" -AMF.Util.Toggle.Disabled="Выключено" -AMF.Util.Toggle.Enabled="Включено" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/sk-SK.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/sk-SK.ini
Changed
@@ -4,3 +4,4 @@ AMF.H264.Preset.Twitch="Twitch" AMF.H264.Preset.YouTube="YouTube" AMF.H264.Profile="Profil" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/sr-CS.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/sr-CS.ini
Changed
@@ -1,23 +1,29 @@ +AMF.Util.Default="Podrazumevano" +AMF.Util.Automatic="Automatski" +AMF.Util.Manual="Ručno" +AMF.Util.Toggle.Disabled="Onemogućeno" +AMF.Util.Toggle.Enabled="Omogućeno" AMF.H264.Preset="Šablon" +AMF.H264.Preset.ResetToDefaults="Vrati na podrazumevane vrednosti" AMF.H264.Preset.Recording="Snimanje" AMF.H264.Preset.HighQuality="Visoki kvalitet" AMF.H264.Preset.Indistinguishable="Istovetno" AMF.H264.Preset.Lossless="Bez gubitaka" AMF.H264.Preset.Twitch="Twitch" AMF.H264.Preset.YouTube="YouTube" +AMF.H264.Usage="Upotreba" +AMF.H264.Usage.Description="Za koju upotrebu bi AMF trebao biti podešen:\n- '\@AMF.H264.Usage.Transcoding\@' je transkoding opšte namene (preporučeno),\n- '\@AMF.H264.Usage.UltraLowLatency\@' je za enkoding veoma niskog kašnjenja,\n- '\@AMF.H264.Usage.LowLatency\@' je slično prethodnom sa malo višim kašnjenjem.\nEmitovanje podržava samo '\@AMF.H264.Usage.Transcoding\@', sve ostale vrednosti se mogu koristiti za snimanje." AMF.H264.Usage.Transcoding="Transkodiranje" AMF.H264.Usage.UltraLowLatency="Ultra nisko kašnjenje" AMF.H264.Usage.LowLatency="Nisko kašnjenje" AMF.H264.QualityPreset="Šablon kvaliteta" +AMF.H264.QualityPreset.Description="Koji šablon za kvalitet bi AMF trebao da cilja:\n- '\@AMF.H264.QualityPreset.Speed\@' je najbrži sa najlošijim kvalitetom,\n- '\@AMF.H264.QualityPreset.Balanced\@' je balansiran spoj oba,\n- '\@AMF.H264.QualityPreset.Quality\@' daje najbolji kvalitet za zadati bitrejt." AMF.H264.QualityPreset.Speed="Brzina" AMF.H264.QualityPreset.Balanced="Izbalansirano" AMF.H264.QualityPreset.Quality="Kvalitet" AMF.H264.Profile="Profil" +AMF.H264.Profile.Description="Koji H.264 profil koristiti za enkodiranje:\n- 'Baseline' ima najveću podršku platformi,\n- 'Main' je podržan na starijim uređajima (preporučeno ako se ide ka mobilnim uređajima),\n- 'High' je podržan na aktuelnim uređajima (preporučeno)." AMF.H264.ProfileLevel="Nivo profila" -AMF.H264.MaximumLTRFrames="Maksimalan broj LTR frejmova" -AMF.H264.ScanType="Vrsta skeniranja" -AMF.H264.ScanType.Progressive="Progresivno" -AMF.H264.ScanType.Interlaced="Isprekidano" AMF.H264.RateControlMethod="Metoda kontrole protoka" AMF.H264.RateControlMethod.CQP="Konstantan kvalitet (CQP)" AMF.H264.RateControlMethod.CBR="Konstantan protok (CBR)" @@ -30,15 +36,12 @@ AMF.H264.QP.IFrame="I-Frejm QP" AMF.H264.QP.PFrame="P-Frejm QP" AMF.H264.QP.BFrame="B-Frejm QP" -AMF.H264.QP.BPictureDelta="B-Promena slike QP" -AMF.H264.QP.ReferenceBPictureDelta="Referenca B-Promena slike QP" AMF.H264.FillerData="Podaci za popunjavanje" AMF.H264.FrameSkipping="Preskakanje frejmova" AMF.H264.EnforceHRDCompatibility="Prisilna HRD kompatibilnost" -AMF.H264.BPicture.Pattern="B-Šablonska slika" -AMF.H264.BPicture.Reference="B-Referentna slika" AMF.H264.DeblockingFilter="Odblokirajući filter" -AMF.Util.Default="Podrazumevano" -AMF.Util.Automatic="Automatski" -AMF.Util.Toggle.Disabled="Onemogućeno" -AMF.Util.Toggle.Enabled="Omogućeno" +AMF.H264.ScanType="Vrsta skeniranja" +AMF.H264.ScanType.Progressive="Progresivno" +AMF.H264.ScanType.Interlaced="Isprekidano" +AMF.H264.MaximumLTRFrames="Maksimalan broj LTR frejmova" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/sr-SP.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/sr-SP.ini
Changed
@@ -1,3 +1,7 @@ +AMF.Util.Default="Подразумевано" +AMF.Util.Automatic="Аутоматски" +AMF.Util.Toggle.Disabled="Онемогућено" +AMF.Util.Toggle.Enabled="Омогућено" AMF.H264.Usage.Transcoding="Транскодирање" AMF.H264.Usage.UltraLowLatency="Ултра ниско кашњење" AMF.H264.Usage.LowLatency="Ниско кашњење" @@ -7,9 +11,6 @@ AMF.H264.QualityPreset.Quality="Квалитет" AMF.H264.Profile="Профил" AMF.H264.ProfileLevel="Ниво профила" -AMF.H264.ScanType="Врста скенирања" -AMF.H264.ScanType.Progressive="Прогресивно" -AMF.H264.ScanType.Interlaced="Испрекидано" AMF.H264.RateControlMethod="Метода контроле протока" AMF.H264.RateControlMethod.CQP="Константан квалитет (CQP)" AMF.H264.RateControlMethod.CBR="Константан проток (CBR)" @@ -22,15 +23,11 @@ AMF.H264.QP.IFrame="I-Фрејм QP" AMF.H264.QP.PFrame="P-Фрејм QP" AMF.H264.QP.BFrame="B-Фрејм QP" -AMF.H264.QP.BPictureDelta="B-Промена слике QP" -AMF.H264.QP.ReferenceBPictureDelta="Референца B-Промена слике QP" AMF.H264.FillerData="Подаци за попуњавање" AMF.H264.FrameSkipping="Прескакање фрејмова" AMF.H264.EnforceHRDCompatibility="Присилна HRD компатибилност" -AMF.H264.BPicture.Pattern="B-Шаблонска слика" -AMF.H264.BPicture.Reference="B-Референтна слика" AMF.H264.DeblockingFilter="Одблокирајући филтер" -AMF.Util.Default="Подразумевано" -AMF.Util.Automatic="Аутоматски" -AMF.Util.Toggle.Disabled="Онемогућено" -AMF.Util.Toggle.Enabled="Омогућено" +AMF.H264.ScanType="Врста скенирања" +AMF.H264.ScanType.Progressive="Прогресивно" +AMF.H264.ScanType.Interlaced="Испрекидано" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/sv-SE.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/sv-SE.ini
Changed
@@ -1,40 +1,63 @@ +AMF.Util.Default="Standard" +AMF.Util.Automatic="Automatisk" +AMF.Util.Manual="Manuell" +AMF.Util.Toggle.Disabled="Inaktiverad" +AMF.Util.Toggle.Enabled="Aktiverad" AMF.H264.Preset="Förinställning" +AMF.H264.Preset.ResetToDefaults="Återställ till standardvärden" +AMF.H264.Preset.Recording="Spelar in" AMF.H264.Preset.HighQuality="Hög kvalitet" AMF.H264.Preset.Indistinguishable="Oskiljbar" AMF.H264.Preset.Lossless="Förlustfri" AMF.H264.Preset.Twitch="Twitch" AMF.H264.Preset.YouTube="YouTube" AMF.H264.Usage="Användning" +AMF.H264.Usage.Description="Vilken användning AMF borde vara inställd på:\n- '\@AMF.H264.Usage.Transcoding\@' är för allmän omkodning (rekommenderas),\n- '\@AMF.H264.Usage.UltraLowLatency\@' är för omkodning med riktigt låg latens,\n- '\@AMF.H264.Usage.LowLatency\@' liknar ovanstående men med lite högre latens.\nStrömning stöder endast '\@AMF.H264.Usage.Transcoding\@', alla andra värden kan användas för inspelning." AMF.H264.Usage.Transcoding="Omkodning" AMF.H264.Usage.UltraLowLatency="Ultralåg latens" AMF.H264.Usage.LowLatency="Låg latens" AMF.H264.QualityPreset="Kvalitetsförinställning" +AMF.H264.QualityPreset.Description="Vilken kvalitetsmall AMF bör försöka att uppnå:\n- '\@AMF.H264.QualityPreset.Speed\@' är den snabbaste men har den sämsta kvaliteten,\n- '\@AMF.H264.QualityPreset.Balanced\@' är en balanserad mix av båda,\n- '\@AMF.H264.QualityPreset.Quality\@' ger den bästa kvaliteten för en angiven bithastighet." AMF.H264.QualityPreset.Speed="Hastighet" AMF.H264.QualityPreset.Balanced="Balanserad" AMF.H264.QualityPreset.Quality="Kvalitet" AMF.H264.Profile="Profil" +AMF.H264.Profile.Description="Vilken H.264-profil att använda för kodning:\n- 'Baseline' stödjer flest plattformar,\n- 'Main' stöds av äldre enheter (rekommenderas för mobila enheter),\n- 'High' stöds av aktuella enheter (rekommenderas)." AMF.H264.ProfileLevel="Profilnivå" -AMF.H264.ScanType="Typ av skanning" -AMF.H264.ScanType.Progressive="Progressiv" -AMF.H264.ScanType.Interlaced="Sammanflätad" +AMF.H264.ProfileLevel.Description="Vilken H.264-profilnivå att använda för kodning:\n- '\@AMF.Util.Automatic\@' beräknar den bästa profilnivån för den angivna bildfrekvensen och bildstorleken,\n- '4.1' stöder 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2' stöder 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0' stöder 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1' stöder 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2' stöder 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" AMF.H264.RateControlMethod.CQP="Konstant QP (CQP)" AMF.H264.RateControlMethod.CBR="Konstant bithastighet (CBR)" AMF.H264.Bitrate.Target="Målets bithastighet" +AMF.H264.Bitrate.Target.Description="Bithastighet att försöka uppnå i den övergripande sekvensen." AMF.H264.Bitrate.Peak="Maximal bithastighet" AMF.H264.QP.Minimum="Minimal QP" AMF.H264.QP.Maximum="Maximal QP" +AMF.H264.VBVBuffer="VBV-buffert" +AMF.H264.VBVBuffer.Description="Vilken metod som ska användas för att bestämma VBV-buffertens storlek:\n- '\@AMF.Util.Automatic\@' beräknar storleken med hjälp av en strikt begränsning,\n- '\@AMF.Util.Manual\@' låter användaren kontrollera storleken.\nVBV-buffertern (Video Buffering Verifier) används av vissa Rate Control Methods för att hålla den övergripande bithastigheten inom de angivna begränsningarna." +AMF.H264.VBVBuffer.Strictness="Strikthet för VBV-buffert" +AMF.H264.VBVBuffer.Size="VBV-buffertstorlek" AMF.H264.FrameSkipping="Hoppa över bildrutor" AMF.H264.EnforceHRDCompatibility="Tvinga HRD-kompatibilitet" +AMF.H264.IDRPeriod="IDR-period" +AMF.H264.IDRPeriod.Description="Definierar avståndet mellan Instantaneous Decoding Refreshes (IDR) i bildrutor. Kontrollerar även GOP-sekvensens storlek." AMF.H264.DeblockingFilter="Avblockningsfilter" +AMF.H264.ScanType="Typ av skanning" +AMF.H264.ScanType.Description="Vilken skanningsmetod att använda, lämna alltid detta på '\@AMF.H264.ScanType.Progressive\@'." +AMF.H264.ScanType.Progressive="Progressiv" +AMF.H264.ScanType.Interlaced="Sammanflätad" +AMF.H264.MotionEstimation="Rörelseuppskattning" +AMF.H264.MotionEstimation.Description="Rörelseuppskattning låter kodaren reducera nödvändig bithastighet genom att uppskatta var en bildpunkt förflyttas." AMF.H264.MotionEstimation.None="Ingen" +AMF.H264.MotionEstimation.Half="Halv bildpunkt" +AMF.H264.MotionEstimation.Quarter="Fjärdedels bildpunkt" +AMF.H264.MotionEstimation.Both="Halv och fjärdedels bildpunkt" +AMF.H264.CodingType="Kodningstyp" +AMF.H264.CodingType.Description="Vilken typ av kodning som ska användas:\n* \@AMF.Util.Default\@ låter AMF bestämma (rekommenderas).\n* CALVC (Context-Adaptive Variable-Length Coding) är snabbare, men större.\n* CABAC (Context-Adaptive Binary Arithmetic Coding) är långsammare, men mindre." +AMF.H264.MaximumLTRFrames="Maximalt antal LTR-bildrutor" AMF.H264.View="Visningsläge" AMF.H264.View.Basic="Grundläggande" AMF.H264.View.Advanced="Avancerad" AMF.H264.View.Expert="Expert" AMF.H264.View.Master="Master" AMF.H264.Debug="Felsök" -AMF.Util.Default="Standard" -AMF.Util.Automatic="Automatisk" -AMF.Util.Manual="Manuell" -AMF.Util.Toggle.Disabled="Inaktiverad" -AMF.Util.Toggle.Enabled="Aktiverad" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/uk-UA.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/uk-UA.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="За замовчанням" +AMF.Util.Automatic="Автоматично" +AMF.Util.Manual="Вручну" +AMF.Util.Toggle.Disabled="Вимкнено" +AMF.Util.Toggle.Enabled="Увімкнено" AMF.H264.Preset="Шаблон" AMF.H264.Preset.ResetToDefaults="Відновити параметри за замовчанням" AMF.H264.Preset.Recording="Звичайний запис" @@ -20,12 +25,6 @@ AMF.H264.Profile.Description="Зазначений профіль H.264 буде використано енкодером:\n 'Baseline' - найпоширеніший серед пристроїв відтворення\n 'Main' - майже всі пристрої відтворення мають підтримку цього профілю\n 'High' - профіль підтримується найсучаснішими пристроями (рекомендується)." AMF.H264.ProfileLevel="Рівень профілю" AMF.H264.ProfileLevel.Description="Визначає рівень профілю H.264 який буде використано під час кодування:\n 'Автоматично' - програма сама встановить найкращій рівень профілю згідно розміру та частоти кадрів,\n '4.1' - підтримує 1920x1080 30 кадрів/с, 1280x720 60 кадрів/с, 960x540 90 кадрів/с\n '4.2' - підтримує 1920x1080 60 кадрів/с, 1280x720 120 кадрів/с, 960x540 172 кадрів/с\n '5.0' - підтримує 1920x1080 60 кадрів/с, 1280x720 144 кадрів/с, 960x540 172 кадрів/с\n '5.1' - підтримує 3840x2160 30 кадрів/с, 1920x1080 120 кадрів/с, 1280x720 172 кадрів/с, 960x540 172 кадрів/с\n '5.2' - підтримує 3840x2160 60 кадрів/с, 1920x1080 172 кадрів/с, 1280x720 172 кадрів/с, 960x540 172 кадрів/с" -AMF.H264.MaximumLTRFrames="Кількість LTR-кадрів контрольованих користувачем" -AMF.H264.MaximumLTRFrames.Description="Long-Term Reference (LTR) кадри дозволяють при кодуванні маркувати декілька кадрів як опорні для інших.\nЦе може поліпшити якість у разі відсутності підтримки B-кадрів або небажаності їх використання.\nЯкщо 'Кількість LTR-кадрів контрольованих користувачем' вказано, то енкодер не підтримуватиме B-кадри у відео." -AMF.H264.ScanType="Вид розгортки" -AMF.H264.ScanType.Description="Визначає вид розгортки який треба використовувати у кодуванні,\nзавжди користуйтеся значенням 'Прогресивна'." -AMF.H264.ScanType.Progressive="Прогресивна" -AMF.H264.ScanType.Interlaced="Черезрядкова" AMF.H264.RateControlMethod="Метод керування потоком" AMF.H264.RateControlMethod.Description="Визначає метод керування потоком:\n 'Фіксований QP (CQP)' - встановлює фіксовані QP для I-/P-/B-кадрів,\n 'Постійний бітрейт (CBR)' - дотримується значення Бажаний бітрейт потоку (використовуючи\nопцію Заповнювати пустоти у бітрейту) (рекомендується для трансляцій),\n 'Змінний бітрейт (максимальний бітрейт обмежено) (VBR)' - потік завжди залишається нижче значення Максимальний бітрейт,\n 'Змінний бітрейт (затримку обмежено) (VBR_LAT)' - потік буде збережено близько до значення Бажаний бітрейт,\nдопоки затримка графічного адаптеру та навантаження на нього дозволятимуть це,\nв іншому випадку бітрейт буде збільшено (рекомендується для запису).\n\nQP - Quantization Parameter (параметр квантування)." AMF.H264.RateControlMethod.CQP="Фіксований QP (CQP)" @@ -41,21 +40,17 @@ AMF.H264.QP.Maximum="Максимальний QP" AMF.H264.QP.Maximum.Description="Найвищий QP (параметр квантування) в кадрі." AMF.H264.QP.IFrame="QP для I-кадрів" -AMF.H264.QP.IFrame.Description="Фіксоване значення QP (параметр квантування) для I-кадрів.\nQP для I-кадрів повинно бути на рівні або вище за QP для P- та B-кадрів." +AMF.H264.QP.IFrame.Description="Фіксоване значення QP (параметр квантування) для I-кадрів." AMF.H264.QP.PFrame="QP для P-кадрів" -AMF.H264.QP.PFrame.Description="Фіксоване значення QP (параметр квантування) для P-кадрів.\nQP для P-кадрів повинно бути на рівні або вище за QP для B-кадрів." +AMF.H264.QP.PFrame.Description="Фіксоване значення QP (параметр квантування) для P-кадрів." AMF.H264.QP.BFrame="QP для B-кадрів" AMF.H264.QP.BFrame.Description="Фіксоване значення QP (параметр квантування) для B-кадрів." -AMF.H264.QP.BPictureDelta="B-кадри, відхил QP" -AMF.H264.QP.BPictureDelta.Description="Відхил QP (параметра квантування) для не опорних B-кадрів, по відношенню до I-кадрів." -AMF.H264.QP.ReferenceBPictureDelta="Опорні B-кадри, відхил QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="Відхил QP (параметра квантування) для порних B-кадрів, по відношенню до I-кадрів." AMF.H264.VBVBuffer="Буфер VBV" AMF.H264.VBVBuffer.Description="Метод, що використовується для визначення параметру Розмір VBV буфера:\n 'Автоматично' - енкодер вираховує розмір враховуючи параметр Буфер VBV, кореляція.\n 'Вручну' - дозволяє користувачеві контролювати цей розмір.\nVBV (Video Buffering Verifier) Буфер використовується різними Методами керування потоком для збереження бітрейту у зазначених межах." AMF.H264.VBVBuffer.Strictness="Буфер VBV, кореляція" -AMF.H264.VBVBuffer.Strictness.Description="Визначає як близько значення Буфер VBV дорівнюють значенню Бажаний бітрейт, у відсотках." +AMF.H264.VBVBuffer.Strictness.Description="Визначає як близько значення Буфер VBV дорівнює заданому, у відсотках." AMF.H264.VBVBuffer.Size="Розмір VBV буфера" -AMF.H264.VBVBuffer.Size.Description="Розмір VBV буфера (Video Buffering Verifier) використовується під час контролю бітрейта відео.\nМалі значення дозволяють цілком збігатися зі встановленим бітрейтом але здійснюють додаткове навантаження." +AMF.H264.VBVBuffer.Size.Description="Розмір VBV буфера (Video Buffering Verifier) використовується під час контролю бітрейта відео." AMF.H264.VBVBuffer.Fullness="Початкова повнота буферу VBV" AMF.H264.VBVBuffer.Fullness.Description="Визначає початкову заповнюваність Буферу VBV, діє лише на початку кодування." AMF.H264.FillerData="Заповнювати пустоти у бітрейту" @@ -64,46 +59,49 @@ AMF.H264.FrameSkipping.Description="Пропускати кадри - дозволяє енкодеру відкидати кадри, якщо керування потоком не може досягти встановленого значення Бажаний бітрейт.\nКоли енкодер пропускає кадр, він додає дублювати-останній-кадр NAL до потоку.\nМоже допомогти при встановленні дуже низьких значень Бажаний бітрейт." AMF.H264.EnforceHRDCompatibility="Застосувати примусову сумісність з HRD" AMF.H264.EnforceHRDCompatibility.Description="Застосувати примусову сумісність з HRD (Hypothetical Reference Decoder) - накладає обмеження на максимальне значення QP (параметра квантування) у кадрі задля досягнення сумісності з HRD.\nНе рекомендується для записів або трансляцій. Використовувати лише для сумісності з найстарішими пристроями які мають лише базовий декодер." -AMF.H264.MaximumAccessUnitSize="Максимальний розмір Access Unit" -AMF.H264.MaximumAccessUnitSize.Description="Визначає максимальний розмір Access Unit для NAL. Значення 0 дозволяє енкодеру обирати найкращий розмір самостійно." AMF.H264.KeyframeInterval="Інтервал ключових кадрів" AMF.H264.KeyframeInterval.Description="Визначає кількість секунд між двома повними кадрами (ключовими кадрами).\nТакож контролює довжину послідовності кадрів у групі зображень (GOP)." AMF.H264.IDRPeriod="IDR, період (кадрів)" AMF.H264.IDRPeriod.Description="Визначає відстань між Instantaneous Decoding Refreshes (IDR) (ключовими кадрами), в кадрах.\nТакож контролює довжину послідовності кадрів у групі зображень (GOP)." -AMF.H264.HeaderInsertionSpacing="Заголовки потоку, період (кадрів)" -AMF.H264.HeaderInsertionSpacing.Description="Визначає скільки кадрів повинно бути між NAL заголовками. Не рекомендується змінювати цей параметр від значення 0 (автоматично)." -AMF.H264.BPicture.Pattern="Послідовні B-кадри" -AMF.H264.BPicture.Pattern.Description="Визначає кількість дозволених B-кадрів у кодуванні. Має позитивний вплив на якість зображення та негативний на продуктивність.\nПідтримується принаймні 2-м та 3-м поколінням VCE карт." -AMF.H264.BPicture.Reference="B-кадри як опорні" -AMF.H264.BPicture.Reference.Description="Дозволяє робити B-кадри опорними для інших B-кадрів в додаток до вже існуючих P- та I-кадрів.\nЗдійснює величезне навантаження, при незначному поліпшенні якості." +AMF.H264.BFrame.Pattern="B-кадри" +AMF.H264.BFrame.Pattern.Description="Визначає кількість послідовних B-кадрів у кодуванні.\nПідтримується принаймні 2-м та 3-м поколінням VCE карт. Маєнегативний вплив на продуктивність." +AMF.H264.BFrame.DeltaQP="B-кадри, відхил QP" AMF.H264.DeblockingFilter="Деблокінг-фільтр" AMF.H264.DeblockingFilter.Description="Встановлює позначку, що дозволяє декодеру використовувати Деблокінг-фільтр для цього відео." -AMF.H264.SlicesPerFrame="Фрагментів на кадр" -AMF.H264.SlicesPerFrame.Description="Скільки фрагментів I-кадрів буде у кожному кадру?\nНульове значення дозволяє енкодеру визначати цю кількість під час кодування самостійно.\nIntra-Refresh кодування використовується для більш швидкого відтворення та навігації." -AMF.H264.IntraRefreshNumMBsPerSlot="Кількість Intra-Refresh макроблоків на слот" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="Скільки Intra-Refresh макроблоків буде у кожному слоті?\nНульове значення дозволяє енкодеру визначати цю кількість під час кодування самостійно.\nIntra-Refresh кодування використовується для більш швидкого відтворення та навігації." +AMF.H264.ScanType="Вид розгортки" +AMF.H264.ScanType.Description="Визначає вид розгортки який треба використовувати у кодуванні,\nзавжди користуйтеся значенням 'Прогресивна'." +AMF.H264.ScanType.Progressive="Прогресивна" +AMF.H264.ScanType.Interlaced="Черезрядкова" AMF.H264.MotionEstimation="Оцінка руху" AMF.H264.MotionEstimation.Description="Оцінка руху дозволяє енкодеру зменшити вимоги до бітрейту завдяки розрахункам з переміщення пікселів." AMF.H264.MotionEstimation.None="Немає" AMF.H264.MotionEstimation.Half="Пів-пікселя" AMF.H264.MotionEstimation.Quarter="Чверть-пікселя" AMF.H264.MotionEstimation.Both="Пів-пікселя та Чверть-пікселя" -AMF.H264.Device="Пристрій" -AMF.H264.Device.Description="Визначає Пристрій що буде використано у кодуванні.\nПотребує встановити параметр Пам'ять адресується у значення відмінне від 'Host'." -AMF.H264.UseOpenCL="Використовувати OpenCL" -AMF.H264.UseOpenCL.Description="Чи буде енкодер використовувати OpenCL щоб надсилати кожен окремий кадр?" +AMF.H264.CodingType="Схема кодування" +AMF.H264.CodingType.Description="Визначає яку схему кодування використовувати:\n 'За замовчанням' - програма вирішує самостійно (рекомендується).\n 'CABAC' - контекстно-залежне адаптивне бінарне арифметичне кодування, схема має кращу компресію даних, але здійснює більше навантаження.\n 'CAVLC' - контекстно-залежне адаптивне кодування із змінною довжиною кодового слова, схема має дещо меншу компресію даних, але й здійснює менше навантаження." +AMF.H264.MaximumLTRFrames="Кількість LTR-кадрів контрольованих користувачем" +AMF.H264.MaximumLTRFrames.Description="Long-Term Reference (LTR) кадри дозволяють при кодуванні маркувати декілька кадрів як опорні для інших.\nЯкщо 'Кількість LTR-кадрів контрольованих користувачем' вказано, то енкодер не підтримуватиме B-кадри у відео." +AMF.H264.MaximumAccessUnitSize="Максимальний розмір Access Unit" +AMF.H264.MaximumAccessUnitSize.Description="Визначає максимальний розмір Access Unit для NAL. Значення 0 дозволяє енкодеру обирати найкращий розмір самостійно." +AMF.H264.HeaderInsertionSpacing="Заголовки потоку, період (кадрів)" +AMF.H264.HeaderInsertionSpacing.Description="Визначає скільки кадрів повинно бути між NAL заголовками. Не рекомендується змінювати цей параметр від значення 0 (автоматично)." +AMF.H264.GOPSize="Розмір GOP" +AMF.H264.MaximumReferenceFrames="Максимальна кількість опорних кадрів" +AMF.H264.SlicesPerFrame="Фрагментів на кадр" +AMF.H264.SlicesPerFrame.Description="Скільки фрагментів I-кадрів буде у кожному кадру?\nНульове значення дозволяє енкодеру визначати цю кількість під час кодування самостійно.\nIntra-Refresh кодування використовується для більш швидкого відтворення та навігації." +AMF.H264.IntraRefresh.NumberOfStripes="Кількість рядків Intra-Refresh" +AMF.H264.IntraRefresh.MacroblocksPerSlot="Кількість Intra-Refresh макроблоків на слот" +AMF.H264.VideoAdapter="Відеоадаптер" +AMF.H264.VideoAdapter.Description="Визначає який відеоадаптер використовувати для кодування." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="Чи буде енкодер використовувати OpenCL щоб надсилати кожен окремий кадр?" AMF.H264.View="Вид для налаштувань" AMF.H264.View.Description="Визначає кількість наявних опцій для налаштування. Навряд чи розробник вам допомагатиме, якщо ви оберете рівень 'Експерт' або 'Бог енкодерів'." AMF.H264.View.Basic="Базовий" AMF.H264.View.Advanced="Розширений" AMF.H264.View.Expert="Експерт" AMF.H264.View.Master="Бог енкодерів" -AMF.H264.UnlockProperties="Розширити ввод параметрів" -AMF.H264.UnlockProperties.Description="Дозволяє вводити деякі параметри у їх необробленому виді, тобто без\nперерахунків на Кбайтність/Кбітність та без деяких обмежень." AMF.H264.Debug="Відладка" AMF.H264.Debug.Description="Вмикає занесення до лог-файлу додаткової інформації про процес кодування. Корисно у випадку коли ви бажаєте звернутися за допомогою до розробника енкодера." -AMF.Util.Default="За замовчанням" -AMF.Util.Automatic="Автоматично" -AMF.Util.Manual="Вручну" -AMF.Util.Toggle.Disabled="Вимкнено" -AMF.Util.Toggle.Enabled="Увімкнено" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/vi-VN.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/vi-VN.ini
Changed
@@ -1,10 +1,17 @@ +AMF.Util.Default="Mặc định" +AMF.Util.Automatic="Tự động" +AMF.Util.Manual="Thủ công" +AMF.Util.Toggle.Disabled="Tắt" +AMF.Util.Toggle.Enabled="Bật" AMF.H264.Preset="Mẫu thiết lập" +AMF.H264.Preset.ResetToDefaults="Thiết lập về mặc định" AMF.H264.Preset.Recording="Quay video" AMF.H264.Preset.HighQuality="Chất lượng cao" AMF.H264.Preset.Indistinguishable="Không thể phân biệt" AMF.H264.Preset.Lossless="Lossless" AMF.H264.Preset.Twitch="Twitch" AMF.H264.Preset.YouTube="YouTube" +AMF.H264.Usage="Sử dụng" AMF.H264.Usage.Transcoding="Chuyển mã" AMF.H264.Usage.UltraLowLatency="Độ trễ cực thấp" AMF.H264.Usage.LowLatency="Độ trễ thấp" @@ -14,10 +21,6 @@ AMF.H264.QualityPreset.Quality="Chất lượng" AMF.H264.Profile="Profile" AMF.H264.ProfileLevel="Profile Level" -AMF.H264.MaximumLTRFrames="LTR Frames tối đa" -AMF.H264.ScanType="Quét hình loại" -AMF.H264.ScanType.Progressive="Quét nguyên ảnh (Progressive)" -AMF.H264.ScanType.Interlaced="Quét 1/2 ảnh (Interlaced)" AMF.H264.RateControlMethod="Cách kiểm soát Bitrate" AMF.H264.RateControlMethod.CQP="QP Không thay đổi (CQP)" AMF.H264.RateControlMethod.CBR="Bitrate Không thay đổi (CBR)" @@ -30,31 +33,27 @@ AMF.H264.QP.IFrame="I-Frame QP" AMF.H264.QP.PFrame="P-Frame QP" AMF.H264.QP.BFrame="B-Frame QP" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta="Reference B-Picture Delta QP" AMF.H264.FillerData="Filler Data (Thêm data cho đủ bitrate)" AMF.H264.FrameSkipping="Frame Skipping" AMF.H264.EnforceHRDCompatibility="Enforce HRD Compatibility" AMF.H264.KeyframeInterval="Thời gian đặt keyframe" -AMF.H264.BPicture.Pattern="B-Picture Pattern" -AMF.H264.BPicture.Reference="B-Picture Reference" AMF.H264.DeblockingFilter="De-blocking Filter (Lọc chống nhiễu ảnh)" -AMF.H264.SlicesPerFrame="Lát cho mỗi khung hình" +AMF.H264.ScanType="Quét hình loại" +AMF.H264.ScanType.Progressive="Quét nguyên ảnh (Progressive)" +AMF.H264.ScanType.Interlaced="Quét 1/2 ảnh (Interlaced)" AMF.H264.MotionEstimation="Dự đoán bù trừ chuyển động" AMF.H264.MotionEstimation.Description="Dự toán chuyển động cho phép bộ mã hóa giảm bitrate cần thiết bằng cách ước tính một pixel sẽ đi đâu." AMF.H264.MotionEstimation.None="Không" AMF.H264.MotionEstimation.Half="1/2 Pixel" AMF.H264.MotionEstimation.Quarter="1/4 Pixel" AMF.H264.MotionEstimation.Both="1/2 và 1/4 Pixel" +AMF.H264.CodingType="Coding Type" +AMF.H264.MaximumLTRFrames="LTR Frames tối đa" +AMF.H264.SlicesPerFrame="Lát cho mỗi khung hình" AMF.H264.View="Chế độ xem" AMF.H264.View.Basic="Cơ bản" AMF.H264.View.Advanced="Nâng cao" AMF.H264.View.Expert="Chuyên gia" AMF.H264.View.Master="Bật cả tính năng ẩn" -AMF.H264.UnlockProperties="Mở khóa Properties" AMF.H264.Debug="Gỡ lỗi" -AMF.Util.Default="Mặc định" -AMF.Util.Automatic="Tự động" -AMF.Util.Manual="Thủ công" -AMF.Util.Toggle.Disabled="Tắt" -AMF.Util.Toggle.Enabled="Bật" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/zh-CN.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/zh-CN.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="默认" +AMF.Util.Automatic="自动" +AMF.Util.Manual="手动" +AMF.Util.Toggle.Disabled="禁用" +AMF.Util.Toggle.Enabled="启用" AMF.H264.Preset="预设" AMF.H264.Preset.ResetToDefaults="重置为默认值" AMF.H264.Preset.Recording="录像" @@ -20,12 +25,6 @@ AMF.H264.Profile.Description="H.264的编码选项有:\n-'Baseline' 支持的平台最广,\n-'Main' 支持较老的设备(如果使用的平台是手机,推荐使用),\n-'High' 被当下的设备支持(推荐使用)。" AMF.H264.ProfileLevel="配置等级" AMF.H264.ProfileLevel.Description="对于编码使用哪种 H.264 Profile Level:\n-'Automatic' 根据给定的帧率和帧大小计算最优的 profile level,\n-'4.1' 支持 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n-'4.2' 支持 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n-'5.0' 支持 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n-'5.1' 支持 3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n-'5.2' 支持 3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="最大的 LTR 帧" -AMF.H264.MaximumLTRFrames.Description="长期参考帧(LTR) 是一个特性允许编码器来标记在一个序列的一些帧作为参考帧.\n这会使当 B 帧不支持或者不需要时提高质量.\nLTR真不能和 B 帧一起使用, 并且当使用LTR时, 编码器会禁用 B 帧." -AMF.H264.ScanType="扫描类型" -AMF.H264.ScanType.Description="使用哪种扫描方法, 通常设置为'Progressive'." -AMF.H264.ScanType.Progressive="渐进" -AMF.H264.ScanType.Interlaced="交错" AMF.H264.RateControlMethod="速率控制方法" AMF.H264.RateControlMethod.Description="该使用什么调节码率的方法:\n- '\@AMF.H264.RateControlMethod.CQP\@' assigns fixed I-/P-/B-Frame QP (Quantization Parameter) values,\n- '\@AMF.H264.RateControlMethod.CBR\@' stays at the given Target Bitrate (using Filler Data) (推荐推流使用),\n- '\@AMF.H264.RateControlMethod.VBR\@' stays below the given Peak Bitrate,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' stays close to the Target Bitrate if GPU latency and load allow for it, otherwise will use higher bitrate (推荐录像使用)." AMF.H264.RateControlMethod.CQP="恒定 QP (CQP)" @@ -41,21 +40,17 @@ AMF.H264.QP.Maximum="最高 QP" AMF.H264.QP.Maximum.Description="一帧中最高 QP (量化参数) 值" AMF.H264.QP.IFrame="I 帧 QP" -AMF.H264.QP.IFrame.Description="用于 I 帧的固定 QP (量化参数) 值.\nI帧 QP值应该大于等于 P B 帧的 QP 值." +AMF.H264.QP.IFrame.Description="用于 I 帧的固定的 QP 值." AMF.H264.QP.PFrame="P 帧 QP" -AMF.H264.QP.PFrame.Description="用于 P 帧的固定 QP (量化参数) 值.\nP帧 QP值应该大于等于 B 帧的 QP 值." +AMF.H264.QP.PFrame.Description="用于 P 帧的固定 QP 值." AMF.H264.QP.BFrame="B 帧 QP" AMF.H264.QP.BFrame.Description="用于 B 帧的固定 QP (量化参数) 值." -AMF.H264.QP.BPictureDelta="B 图片 差值 QP" -AMF.H264.QP.BPictureDelta.Description="相对于上一个非参考 B 帧的差值 QP 值." -AMF.H264.QP.ReferenceBPictureDelta="参考 B 图片 差值 QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="相对于上一个参考 B 帧的差值 QP 值." AMF.H264.VBVBuffer="VBV 缓存" AMF.H264.VBVBuffer.Description="应使用什么方法来确定 VBV 缓冲区大小:\n-'自动' 计算使用严格约束的大小,\n- '手册' 允许用户控制大小.\nVBV缓存 (视频缓冲程序验证程序) 用于某些率控制方法来保持整体的比特率在给定的约束内." AMF.H264.VBVBuffer.Strictness="VBV 缓存规范性" -AMF.H264.VBVBuffer.Strictness.Description="VBV 缓存应该怎样严格, 100% 几乎完全和目标比特率一致和 0% 不受限制的." +AMF.H264.VBVBuffer.Strictness.Description="决定 VBV 缓存的严格性, 100% 表示尽可能严格, 0% 表示无限制." AMF.H264.VBVBuffer.Size="VBV 缓存大小" -AMF.H264.VBVBuffer.Size.Description="VBV 缓存大小用于在一个序列中的比特率控制.\n小缓存会导致几乎完美的比特率控制但有较大的性能影响." +AMF.H264.VBVBuffer.Size.Description="用于在一个序列中的控制比特率的 VBV 缓存的大小." AMF.H264.VBVBuffer.Fullness="VBV 缓冲满" AMF.H264.VBVBuffer.Fullness.Description="VBV 缓存最初应该多满, 将只会影响最初的序列的编码." AMF.H264.FillerData="填充数据" @@ -64,46 +59,76 @@ AMF.H264.FrameSkipping.Description="跳过的帧允许编码器下丢帧, 以满足目标比特率要求.\n当编码器丢帧时, 它反而插入一个重复最后一帧的 NAL 到流中.\n可以帮助非常低的目标比特率." AMF.H264.EnforceHRDCompatibility="强制 HRD 兼容" AMF.H264.EnforceHRDCompatibility.Description="强制假设的参考解码器限制在一个帧内的最大的 QP 值更改.\n不推荐用于录制或推流, 并且应仅用于面向只有参考软件解码器的很老的设备." -AMF.H264.MaximumAccessUnitSize="最大访问单元大小" -AMF.H264.MaximumAccessUnitSize.Description="一个 NAL 的访问单元的最大大小. 值 0 允许编码器挑选最好的一个." AMF.H264.KeyframeInterval="关键帧间隔" AMF.H264.KeyframeInterval.Description="非丢弃帧之间应该多少秒.\n也控制序列(GOP) 的大小." AMF.H264.IDRPeriod="IDR 周期" AMF.H264.IDRPeriod.Description="定义的帧内瞬时解码刷新 (IDR) 的距离. 也控制 GOP 序列长度." -AMF.H264.HeaderInsertionSpacing="头部插入空白" -AMF.H264.HeaderInsertionSpacing.Description="NAL 头之间应该多少帧. 不推荐改为非零(自动) 值." -AMF.H264.BPicture.Pattern="B 图片模式" -AMF.H264.BPicture.Pattern.Description="应该允许编码多少 B 帧, 对质量有好处和对性能有坏处.\n第二代和第三代 VCE 卡支持." -AMF.H264.BPicture.Reference="B 图片参考" -AMF.H264.BPicture.Reference.Description="允许 B 帧参考 P 帧和 I 帧之外的其他 B 帧.\n 巨大的性能影响, 较小的质量提高." +AMF.H264.BFrame.Pattern="B 帧" +AMF.H264.BFrame.Pattern.Description="多少 B 帧应该用于编码.\n2 代和 3 代 VCE 卡支持. 对编码性能有负面影响." +AMF.H264.BFrame.DeltaQP="B 帧差值 QP" +AMF.H264.BFrame.DeltaQP.Description="对于非参考 B 帧, 相对于上一个 I 或者 P 帧的差值 QP 值." +AMF.H264.BFrame.Reference="参考 B 帧" +AMF.H264.BFrame.Reference.Description="允许 B 帧也使用 B 帧作为参考, 而不是只是 P 和 I 帧." +AMF.H264.BFrame.ReferenceDeltaQP="参考 B 帧差值 QP" +AMF.H264.BFrame.ReferenceDeltaQP.Description="对于参考 B 帧, 相对于上一个 I 或者 P 帧的差值 QP 值." AMF.H264.DeblockingFilter="去块滤波" AMF.H264.DeblockingFilter.Description="设置解码器允许使用的标记, 用于编码流去块滤波器." -AMF.H264.SlicesPerFrame="每帧的切片数" -AMF.H264.SlicesPerFrame.Description="每个帧应该和多少 I 帧切片一起存储?\n0 值让编码器运行时决定.\n内部刷新编码用于更快的回放和定位." -AMF.H264.IntraRefreshNumMBsPerSlot="每个槽的内部宏块刷新数量" -AMF.H264.IntraRefreshNumMBsPerSlot.Description="每个槽应该和多少宏块一起存储?\n0 值让编码器在运行时决定.\n帧内刷新编码用于更快的回放和定位." +AMF.H264.ScanType="扫描类型" +AMF.H264.ScanType.Description="使用哪种扫描方法, 通常设置为'Progressive'." +AMF.H264.ScanType.Progressive="渐进" +AMF.H264.ScanType.Interlaced="交错" AMF.H264.MotionEstimation="移动侦测" AMF.H264.MotionEstimation.Description="运动侦测允许编码器通过估计一个像素去了哪里来降低比特率." AMF.H264.MotionEstimation.None="无" AMF.H264.MotionEstimation.Half="半像素" AMF.H264.MotionEstimation.Quarter="四分之一像素" AMF.H264.MotionEstimation.Both="半&四分之一像素" -AMF.H264.Device="设备" -AMF.H264.Device.Description="哪个设备用来编码.\n需要内存类型不能设置为'主机'." -AMF.H264.UseOpenCL="使用 OpenCL" -AMF.H264.UseOpenCL.Description="编码器应该使用 OpenCL 提交单独的帧吗?" +AMF.H264.CodingType="编码类型" +AMF.H264.CodingType.Description="使用哪种编码类型:\n* \@AMF.Util.Default\@ 让 AMF 决定(推荐).\n* CALVC(上下文自适应可变长度编码) 速度更快但是更大.\n* CABAC(上下文自适应二进制算术编码)速度更慢, 但是更小." +AMF.H264.MaximumLTRFrames="最大的 LTR 帧" +AMF.H264.MaximumLTRFrames.Description="长期参考帧(LTR) 是一个特性允许编码器来标记在一个序列的一些帧作为参考帧一段时间.\nLTR 帧不能和 B 帧一起使用并且如果使用 LTR 帧, 编码器会禁用 B 帧." +AMF.H264.MaximumAccessUnitSize="最大访问单元大小" +AMF.H264.MaximumAccessUnitSize.Description="一个 NAL 的访问单元的最大大小. 值 0 允许编码器挑选最好的一个." +AMF.H264.HeaderInsertionSpacing="头部插入空白" +AMF.H264.HeaderInsertionSpacing.Description="NAL 头之间应该多少帧. 不推荐改为非零(自动) 值." +AMF.H264.WaitForTask="等待任务" +AMF.H264.WaitForTask.Description="未知, 实验" +AMF.H264.PreAnalysisPass="预分析通过" +AMF.H264.PreAnalysisPass.Description="未知, 实验" +AMF.H264.VBAQ="VBAQ" +AMF.H264.VBAQ.Description="未知, 实验" +AMF.H264.GOPSize="GOP 大小" +AMF.H264.GOPSize.Description="未知, 实验" +AMF.H264.GOPAlignment="GOP 对齐" +AMF.H264.GOPAlignment.Description="未知, 实验" +AMF.H264.MaximumReferenceFrames="最大参考帧" +AMF.H264.MaximumReferenceFrames.Description="未知, 实验" +AMF.H264.SlicesPerFrame="每帧的切片数" +AMF.H264.SlicesPerFrame.Description="每个帧应该和多少 I 帧切片一起存储?\n0 值让编码器运行时决定.\n内部刷新编码用于更快的回放和定位." +AMF.H264.SliceMode="切片模式" +AMF.H264.SliceMode.Description="未知, 实验" +AMF.H264.MaximumSliceSize="最大切片大小" +AMF.H264.MaximumSliceSize.Description="未知, 实验" +AMF.H264.SliceControlMode="切片控制模式" +AMF.H264.SliceControlMode.Description="未知, 实验" +AMF.H264.SliceControlSize="切片控制大小" +AMF.H264.SliceControlSize.Description="未知, 实验" +AMF.H264.IntraRefresh.NumberOfStripes="帧内刷新的条纹的数目" +AMF.H264.IntraRefresh.NumberOfStripes.Description="未知, 实验" +AMF.H264.IntraRefresh.MacroblocksPerSlot="每个插槽的帧内刷新宏" +AMF.H264.IntraRefresh.MacroblocksPerSlot.Description="每个槽应该和多少宏块一起存储?\n0 值让编码器在运行时决定.\n帧内刷新编码用于更快的回放和定位." +AMF.H264.VideoAPI="视频的 API" +AMF.H264.VideoAPI.Description="要用于编码的 API。" +AMF.H264.VideoAdapter="视频适配器" +AMF.H264.VideoAdapter.Description="哪种适配器用来编码." +AMF.H264.OpenCL="OpenCL" +AMF.H264.OpenCL.Description="编码器应该使用 OpenCL 提交单独的帧吗>" AMF.H264.View="查看模式" AMF.H264.View.Description="哪些属性应该是可见的. 当使用 '专家' 或者 '大师' 模式时, 您将不会得到支持." AMF.H264.View.Basic="基本" AMF.H264.View.Advanced="高级" AMF.H264.View.Expert="专家" AMF.H264.View.Master="主" -AMF.H264.UnlockProperties="解锁属性" -AMF.H264.UnlockProperties.Description="解锁给他们完整范围的某些属性, 而不是将他们局限到一定范围内." AMF.H264.Debug="调试" AMF.H264.Debug.Description="启用附加调试日志记录, 应该是启用的, 无论何时您需要此编码器的支持." -AMF.Util.Default="默认" -AMF.Util.Automatic="自动" -AMF.Util.Manual="手动" -AMF.Util.Toggle.Disabled="禁用" -AMF.Util.Toggle.Enabled="启用" +
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Resources/locale/zh-TW.ini -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Resources/locale/zh-TW.ini
Changed
@@ -1,3 +1,8 @@ +AMF.Util.Default="預設" +AMF.Util.Automatic="自動" +AMF.Util.Manual="手動" +AMF.Util.Toggle.Disabled="停用" +AMF.Util.Toggle.Enabled="啟用" AMF.H264.Preset="預設" AMF.H264.Preset.ResetToDefaults="重設為預設值" AMF.H264.Preset.Recording="錄影" @@ -19,11 +24,6 @@ AMF.H264.Profile.Description="用於編碼的 H.264 設定:\n- 'Baseline' 有最廣泛的平台支援度,\n- 'Main' 較舊的裝置也支援 (如果目標是行動裝置,建議選此),\n- 'High' 當前主流裝置支援 (建議選此)。" AMF.H264.ProfileLevel="設定檔級別" AMF.H264.ProfileLevel.Description="用於編碼的 H.264 設定等級:\n- '\@AMF.Util.Automatic\@'根據給定的畫面播放速率以及尺寸計算最佳的設定等級,\n- '4.1'支援 1920x1080 30FPS, 1280x720 60FPS, 960x540 90FPS\n- '4.2'支援 1920x1080 60FPS, 1280x720 120FPS, 960x540 172FPS\n- '5.0'支援 1920x1080 60FPS, 1280x720 144FPS, 960x540 172FPS\n- '5.1'支援3840x2160 30FPS, 1920x1080 120FPS, 1280x720 172FPS, 960x540 172FPS\n- '5.2'支援3840x2160 60FPS, 1920x1080 172FPS, 1280x720 172FPS, 960x540 172FPS" -AMF.H264.MaximumLTRFrames="長期參照訊框(LTR)最大數量" -AMF.H264.MaximumLTRFrames.Description="當指定了長期參照訊框(LTR)最大數量時,編碼器將會停用 B-Picture。" -AMF.H264.ScanType="掃描類型" -AMF.H264.ScanType.Progressive="漸進式" -AMF.H264.ScanType.Interlaced="交错式" AMF.H264.RateControlMethod="速率控制方法" AMF.H264.RateControlMethod.Description="該使用什麼位元速率控制方法:\n- '\@AMF.H264.RateControlMethod.CQP\@' 指定固定的 I-/P-/B-訊框 QP (量化參數)值,\n- '\@AMF.H264.RateControlMethod.CBR\@' 固定在給定的目標位元速率 (藉由填塞空白資料)(建議用於串流),\n- '\@AMF.H264.RateControlMethod.VBR\@' 保持低於給定的位元速率最大值,\n- '\@AMF.H264.RateControlMethod.VBR_LAT\@' 在 GPU 延遲跟負載允許的情況下盡量接近目標位元速率,不足時使用較高的位元速率(建議用於錄影)。" AMF.H264.RateControlMethod.CQP="固定 QP (CQP)" @@ -39,48 +39,36 @@ AMF.H264.QP.Maximum="最大 QP 值" AMF.H264.QP.Maximum.Description="一個訊框中使用的最高 QP (量化參數) 值。" AMF.H264.QP.IFrame="I-訊框 QP" -AMF.H264.QP.IFrame.Description="I-訊框使用的固定 QP (量化參數) 值。\nI-訊框 QP 應該要跟 P/B-訊框 QP 一樣或更高。" AMF.H264.QP.PFrame="P-訊框 QP" -AMF.H264.QP.PFrame.Description="P-訊框使用的固定 QP (量化參數) 值。\nP-訊框 QP 應該要跟 B-訊框 QP 一樣或更高。" AMF.H264.QP.BFrame="B-訊框 QP" AMF.H264.QP.BFrame.Description="B-訊框使用的固定 QP (量化參數) 值。" -AMF.H264.QP.BPictureDelta="B-Picture Delta QP" -AMF.H264.QP.BPictureDelta.Description="最後一個非參考 B-Picture 所使用的 Delta QP。" -AMF.H264.QP.ReferenceBPictureDelta="Reference B-Picture Delta QP" -AMF.H264.QP.ReferenceBPictureDelta.Description="最後一個參考 B-Picture 所使用的 Delta QP。" AMF.H264.VBVBuffer="VBV(Video Buffering Verifier) 緩衝區" AMF.H264.VBVBuffer.Description="決定 VBV 緩衝區大小的方法:\n- '\@AMF.Util.Automatic\@' 根據嚴格性計算大小,\n- '\@AMF.Util.Manual\@' 允許使用者調整大小。\n 某些速率控制方法會使用 VBV (Video Buffering Verifier) 緩衝區讓整體的位元速率保持在給定的條件之內。" AMF.H264.VBVBuffer.Strictness="VBV 緩衝區嚴格性" -AMF.H264.VBVBuffer.Strictness.Description="VBV 緩衝區嚴格程度,100% 表示幾乎跟目標位元速率一樣,0% 則不受限制。" AMF.H264.VBVBuffer.Size="VBV 緩衝區大小" -AMF.H264.VBVBuffer.Size.Description="用於位元流量控制的 VBV 緩衝區大小。\n一個極小值將會得到近乎完美的位元速率結果,但是會有較大的效能消耗。" AMF.H264.VBVBuffer.Fullness="初始 VBV 緩衝區填充度" AMF.H264.VBVBuffer.Fullness.Description="VBV 緩衝區起始該多滿,將只影響編碼的起始。" AMF.H264.FillerData="填塞空白資料" AMF.H264.FillerData.Description="啟用填塞空白資料允許編碼器保持位元速率至少有目標位元速率,編碼器將會將不足的位元用空白訊息填滿" AMF.H264.FrameSkipping="省略訊框" AMF.H264.EnforceHRDCompatibility="與 HRD 相容" -AMF.H264.BPicture.Pattern="B-Picture 模式" -AMF.H264.BPicture.Reference="B-Picture 參照" AMF.H264.DeblockingFilter="去塊狀色斑濾鏡" +AMF.H264.ScanType="掃描類型" +AMF.H264.ScanType.Progressive="漸進式" +AMF.H264.ScanType.Interlaced="交错式" AMF.H264.MotionEstimation="動態估算" AMF.H264.MotionEstimation.Description="動態估算讓編碼器藉由估算像素移動來減少位元速率。" AMF.H264.MotionEstimation.None="無" AMF.H264.MotionEstimation.Half="半像素" AMF.H264.MotionEstimation.Quarter="四分之一像素" AMF.H264.MotionEstimation.Both="半 & 四分之一像素" +AMF.H264.MaximumLTRFrames="長期參照訊框(LTR)最大數量" AMF.H264.View="檢視模式" AMF.H264.View.Description="該顯示哪些屬性?\n使用'\@AMF.H264.View.Master\@'時將不提供任何的支援。" AMF.H264.View.Basic="基本" AMF.H264.View.Advanced="進階" AMF.H264.View.Expert="專家" AMF.H264.View.Master="上帝模式" -AMF.H264.UnlockProperties="解除屬性值限制" -AMF.H264.UnlockProperties.Description="允許一些屬性的數值範圍為全部可行的範圍,而非限定在一定的範圍內。" AMF.H264.Debug="除錯模式" AMF.H264.Debug.Description="啟用額外的除錯紀錄,當需要任何關於此編碼器的支援時皆應啟用。" -AMF.Util.Default="預設" -AMF.Util.Automatic="自動" -AMF.Util.Manual="手動" -AMF.Util.Toggle.Disabled="停用" -AMF.Util.Toggle.Enabled="啟用" +
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/amf-capabilities.cpp
Added
@@ -0,0 +1,381 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include <string> +#include <sstream> + +#ifdef _WIN32 +#include <windows.h> +#include <VersionHelpers.h> +#endif + +#include "amf-capabilities.h" +#include "api-d3d11.h" +#include "api-d3d9.h" +#include "misc-util.cpp" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// + +Plugin::AMD::VCEDeviceCapabilities::VCEDeviceCapabilities() { + acceleration_type = amf::AMF_ACCEL_NOT_SUPPORTED; + maxProfile = + maxProfileLevel = + maxBitrate = + minReferenceFrames = + maxReferenceFrames = + maxTemporalLayers = + maxNumOfStreams = + maxNumOfHwInstances = + input.minWidth = + input.maxWidth = + input.minHeight = + input.maxHeight = + input.verticalAlignment = + output.minWidth = + output.maxWidth = + output.minHeight = + output.maxHeight = + output.verticalAlignment = 0; + supportsBFrames = + supportsFixedSliceMode = + input.supportsInterlaced = + output.supportsInterlaced = false; + input.formats.clear(); + input.memoryTypes.clear(); + output.formats.clear(); + output.memoryTypes.clear(); +} + +std::shared_ptr<Plugin::AMD::VCECapabilities> Plugin::AMD::VCECapabilities::GetInstance() { + static std::shared_ptr<VCECapabilities> __instance = std::make_shared<VCECapabilities>(); + static std::mutex __mutex; + + const std::lock_guard<std::mutex> lock(__mutex); + return __instance; +} + +void Plugin::AMD::VCECapabilities::ReportCapabilities(std::shared_ptr<Plugin::API::Base> api) { + auto inst = GetInstance(); + auto adapters = api->EnumerateAdapters(); + for (auto adapter : adapters) { + ReportAdapterCapabilities(api, adapter); + } +} + +void Plugin::AMD::VCECapabilities::ReportAdapterCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter) { + auto inst = GetInstance(); + VCEEncoderType types[] = { + VCEEncoderType_AVC, + VCEEncoderType_SVC, + }; + + AMF_LOG_INFO("Capabilities for Device '%s' on API %s:", + adapter.Name.c_str(), + api->GetName().c_str()); + + for (auto type : types) { + ReportAdapterTypeCapabilities(api, adapter, type); + } +} + +void Plugin::AMD::VCECapabilities::ReportAdapterTypeCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter, VCEEncoderType type) { + auto inst = GetInstance(); + auto caps = inst->GetAdapterCapabilities(api, adapter, type); + + AMF_LOG_INFO(" %s (Acceleration: %s)", + (type == VCEEncoderType_AVC ? "AVC" : (type == VCEEncoderType_SVC ? "SVC" : (type == VCEEncoderType_HEVC ? "HEVC" : "Unknown"))), + (caps.acceleration_type == amf::AMF_ACCEL_SOFTWARE ? "Software" : (caps.acceleration_type == amf::AMF_ACCEL_GPU ? "GPU" : (caps.acceleration_type == amf::AMF_ACCEL_HARDWARE ? "Hardware" : "None"))) + ); + + if (caps.acceleration_type == amf::AMF_ACCEL_NOT_SUPPORTED) + return; + + AMF_LOG_INFO(" Limits"); + AMF_LOG_INFO(" Profile: %s", Plugin::Utility::ProfileAsString((VCEProfile)caps.maxProfile)); + AMF_LOG_INFO(" Profile Level: %ld.%ld", caps.maxProfileLevel / 10, caps.maxProfileLevel % 10); + AMF_LOG_INFO(" Bitrate: %ld", caps.maxBitrate); + AMF_LOG_INFO(" Reference Frames: %ld (min) - %ld (max)", caps.minReferenceFrames, caps.maxReferenceFrames); + if (type == VCEEncoderType_SVC) + AMF_LOG_INFO(" Temporal Layers: %ld", caps.maxTemporalLayers); + AMF_LOG_INFO(" Features"); + AMF_LOG_INFO(" B-Frames: %s", caps.supportsBFrames ? "Supported" : "Not Supported"); + AMF_LOG_INFO(" Fixed Slice Mode: %s", caps.supportsFixedSliceMode ? "Supported" : "Not Supported"); + AMF_LOG_INFO(" Instancing"); + AMF_LOG_INFO(" # of Streams: %ld", caps.maxNumOfStreams); + AMF_LOG_INFO(" # of Instances: %ld", caps.maxNumOfHwInstances); + AMF_LOG_INFO(" Input"); + ReportAdapterTypeIOCapabilities(api, adapter, type, false); + AMF_LOG_INFO(" Output"); + ReportAdapterTypeIOCapabilities(api, adapter, type, true); +} + +void Plugin::AMD::VCECapabilities::ReportAdapterTypeIOCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter, VCEEncoderType type, bool output) { + auto amf = Plugin::AMD::AMF::GetInstance(); + + auto inst = GetInstance(); + VCEDeviceCapabilities::IOCaps ioCaps = output + ? inst->GetAdapterCapabilities(api, adapter, type).output + : inst->GetAdapterCapabilities(api, adapter, type).input; + AMF_LOG_INFO(" Resolution: %ldx%ld - %ldx%ld", + ioCaps.minWidth, ioCaps.minHeight, + ioCaps.maxWidth, ioCaps.maxHeight); + AMF_LOG_INFO(" Vertical Alignment: %ld", ioCaps.verticalAlignment); + AMF_LOG_INFO(" Interlaced: %s", ioCaps.supportsInterlaced ? "Supported" : "Not Supported"); + std::stringstream formatstr; + for (auto format : ioCaps.formats) { + std::vector<char> buf(1024); + wcstombs(buf.data(), amf->GetTrace()->SurfaceGetFormatName(format.first), 1024); + formatstr + << buf.data() + << (format.second ? " (Native)" : "") + << ", "; + } + AMF_LOG_INFO(" Formats: %s", formatstr.str().c_str()); + std::stringstream memorystr; + for (auto memory : ioCaps.memoryTypes) { + std::vector<char> buf(1024); + wcstombs(buf.data(), amf->GetTrace()->GetMemoryTypeName(memory.first), 1024); + memorystr + << buf.data() + << (memory.second ? " (Native)" : "") + << ", "; + } + AMF_LOG_INFO(" Memory Types: %s", memorystr.str().c_str()); +} + +Plugin::AMD::VCECapabilities::VCECapabilities() { + this->Refresh(); +} + +Plugin::AMD::VCECapabilities::~VCECapabilities() {} + +static AMF_RESULT GetIOCapability(bool output, amf::AMFCapsPtr amfCaps, Plugin::AMD::VCEDeviceCapabilities::IOCaps* caps) { + AMF_RESULT res = AMF_OK; + amf::AMFIOCapsPtr amfIOCaps; + if (output) + res = amfCaps->GetOutputCaps(&amfIOCaps); + else + res = amfCaps->GetInputCaps(&amfIOCaps); + if (res != AMF_OK) + return res; + + amfIOCaps->GetWidthRange(&(caps->minWidth), &(caps->maxWidth)); + amfIOCaps->GetHeightRange(&(caps->minHeight), &(caps->maxHeight)); + caps->supportsInterlaced = amfIOCaps->IsInterlacedSupported(); + caps->verticalAlignment = amfIOCaps->GetVertAlign(); + + int32_t numFormats = amfIOCaps->GetNumOfFormats(); + caps->formats.resize(numFormats); + for (int32_t formatIndex = 0; formatIndex < numFormats; formatIndex++) { + amf::AMF_SURFACE_FORMAT format = amf::AMF_SURFACE_UNKNOWN; + bool isNative = false; + + amfIOCaps->GetFormatAt(formatIndex, &format, &isNative); + caps->formats[formatIndex].first = format; + caps->formats[formatIndex].second = isNative; + } + + int32_t numMemoryTypes = amfIOCaps->GetNumOfMemoryTypes(); + caps->memoryTypes.resize(numMemoryTypes); + for (int32_t memoryTypeIndex = 0; memoryTypeIndex < numMemoryTypes; memoryTypeIndex++) { + amf::AMF_MEMORY_TYPE type = amf::AMF_MEMORY_UNKNOWN; + bool isNative = false; + + amfIOCaps->GetMemoryTypeAt(memoryTypeIndex, &type, &isNative); + caps->memoryTypes[memoryTypeIndex].first = type; + caps->memoryTypes[memoryTypeIndex].second = isNative; + } + + return AMF_OK; +} + +bool Plugin::AMD::VCECapabilities::Refresh() { + AMF_RESULT res; + + auto amfInstance = AMD::AMF::GetInstance(); + auto amfFactory = amfInstance->GetFactory(); + + auto APIs = Plugin::API::Base::EnumerateAPIs(); + for (auto api : APIs) { + std::vector<Plugin::API::Adapter> adapters; + try { + adapters = api->EnumerateAdapters(); + } catch (std::exception e) { + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Unexpected exception while enumerating adapters for API '%s':", api->GetName()); + AMF_LOG_ERROR("%s", e.what()); + continue; + } catch (...) { + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Unexpected critical exception while enumerating adapters for API '%s'.", api->GetName()); + throw; + } + + for (auto adapter : adapters) { + // Create AMF Instance + amf::AMFContextPtr amfContext; + if (amfFactory->CreateContext(&amfContext) != AMF_OK) { + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> CreateContext failed for device '%s', error %ls (code %d).", + adapter.Name.c_str(), + amfInstance->GetTrace()->GetResultText(res), + res); + continue; + } + + void* apiInst = nullptr; + try { + apiInst = api->CreateInstanceOnAdapter(adapter); + } catch (std::exception e) { + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Unexpected exception while testing adapter '%s' on API '%s':", adapter.Name, api->GetName()); + AMF_LOG_ERROR("%s", e.what()); + continue; + } catch (...) { + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Unexpected critical exceptionwhile testing adapter '%s' on API '%s'.", adapter.Name, api->GetName()); + throw; + } + switch (api->GetType()) { + case Plugin::API::APIType_Direct3D11: + res = amfContext->InitDX11(api->GetContextFromInstance(apiInst)); + break; + case Plugin::API::APIType_Direct3D9: + res = amfContext->InitDX9(api->GetContextFromInstance(apiInst)); + break; + case Plugin::API::APIType_OpenGL: + res = amfContext->InitOpenGL(api->GetContextFromInstance(apiInst), nullptr, nullptr); + break; + default: + res = AMF_OK; + break; + } + if (res != AMF_OK) { + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> Init failed for device '%s', error %ls (code %d).", + adapter.Name.c_str(), + amfInstance->GetTrace()->GetResultText(res), + res); + continue; + } + + VCEEncoderType types[] = { + VCEEncoderType_AVC, + VCEEncoderType_SVC + }; + for (auto type : types) { + VCEDeviceCapabilities devCaps = VCEDeviceCapabilities(); + + amf::AMFComponentPtr amfComponent; + if (amfFactory->CreateComponent(amfContext, + Plugin::Utility::VCEEncoderTypeAsAMF(type), + &amfComponent) != AMF_OK) { + AMF_LOG_ERROR("CreateComponent failed for device '%s' with codec '%s', error %ls (code %d).", + adapter.Name.c_str(), + Plugin::Utility::VCEEncoderTypeAsString(type), + amfInstance->GetTrace()->GetResultText(res), + res); + continue; + } + + amf::AMFCapsPtr amfCaps; + res = amfComponent->GetCaps(&amfCaps); + if (res != AMF_OK) { + AMF_LOG_ERROR("GetCaps failed for device '%s' with codec '%s', error %ls (code %d).", + adapter.Name.c_str(), + Plugin::Utility::VCEEncoderTypeAsString(type), + amfInstance->GetTrace()->GetResultText(res), + res); + amfComponent->Terminate(); + continue; + } + + devCaps.acceleration_type = amfCaps->GetAccelerationType(); + if (devCaps.acceleration_type != amf::AMF_ACCEL_NOT_SUPPORTED) { + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_BITRATE, &(devCaps.maxBitrate)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_NUM_OF_STREAMS, &(devCaps.maxNumOfStreams)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_PROFILE, &(devCaps.maxProfile)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_LEVEL, &(devCaps.maxProfileLevel)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_BFRAMES, &(devCaps.supportsBFrames)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MIN_REFERENCE_FRAMES, &(devCaps.minReferenceFrames)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_REFERENCE_FRAMES, &(devCaps.maxReferenceFrames)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_MAX_TEMPORAL_LAYERS, &(devCaps.maxTemporalLayers)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_FIXED_SLICE_MODE, &(devCaps.supportsFixedSliceMode)); + amfCaps->GetProperty(AMF_VIDEO_ENCODER_CAP_NUM_OF_HW_INSTANCES, &(devCaps.maxNumOfHwInstances)); + + if (GetIOCapability(false, amfCaps, &(devCaps.input)) != AMF_OK) + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> GetInputCaps failed for device '%s' with codec '%ls', error %ls (code %d).", + adapter.Name.c_str(), + Plugin::Utility::VCEEncoderTypeAsString(type), + amfInstance->GetTrace()->GetResultText(res), res); + + if (GetIOCapability(true, amfCaps, &(devCaps.output)) != AMF_OK) + AMF_LOG_ERROR("<" __FUNCTION_NAME__ "> GetOutputCaps failed capabilities for device '%s' with codec '%ls', error %ls (code %d).", + adapter.Name.c_str(), + Plugin::Utility::VCEEncoderTypeAsString(type), + amfInstance->GetTrace()->GetResultText(res), res); + } + + amfComponent->Terminate(); + + // Insert + capabilityMap.insert(std::make_pair( + std::make_tuple(api->GetName(), adapter, type), + devCaps) + ); + } + api->DestroyInstance(apiInst); + amfContext->Terminate(); + } + } + return true; +} + +std::vector<std::pair<VCEEncoderType, VCEDeviceCapabilities>> Plugin::AMD::VCECapabilities::GetAllAdapterCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter) { + std::vector<std::pair<VCEEncoderType, VCEDeviceCapabilities>> caps; + for (auto kv : capabilityMap) { + auto apiName = std::get<0>(kv.first); + auto adapter = std::get<1>(kv.first); + + if (apiName != api->GetName()) + continue; + if (adapter != adapter) + continue; + + auto type = std::get<2>(kv.first); + caps.push_back(std::make_pair(type, kv.second)); + } + return caps; +} + +Plugin::AMD::VCEDeviceCapabilities Plugin::AMD::VCECapabilities::GetAdapterCapabilities(std::shared_ptr<Plugin::API::Base> api, Plugin::API::Adapter adapter, VCEEncoderType type) { + auto key = std::make_tuple(api->GetName(), adapter, type); + + if (capabilityMap.count(key) == 0) + return VCEDeviceCapabilities(); + + return capabilityMap.find(key)->second; +} +
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/amf-h264.cpp
Added
@@ -0,0 +1,2091 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include <chrono> + +#include "amf-capabilities.h" +#include "amf-h264.h" +#include "misc-util.cpp" +#include "api-base.h" + +// AMF +#include "components/VideoEncoderVCE.h" +#include "components/VideoConverter.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// + +// Logging and Exception Helpers +static void FormatTextWithAMFError(std::vector<char>* buffer, const char* format, AMF_RESULT res) { + sprintf(buffer->data(), format, Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res); +} + +template<typename _T> +static void FormatTextWithAMFError(std::vector<char>* buffer, const char* format, _T other, AMF_RESULT res) { + sprintf(buffer->data(), format, other, Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res); +} + +// Class +#ifdef _DEBUG +static void fastPrintVariant(const char* text, amf::AMFVariantStruct variant) { + std::vector<char> buf(1024); + switch (variant.type) { + case amf::AMF_VARIANT_EMPTY: + sprintf(buf.data(), "%s%s", text, "Empty"); + break; + case amf::AMF_VARIANT_BOOL: + sprintf(buf.data(), "%s%s", text, variant.boolValue ? "true" : "false"); + break; + case amf::AMF_VARIANT_INT64: + sprintf(buf.data(), "%s%lld", text, variant.int64Value); + break; + case amf::AMF_VARIANT_DOUBLE: + sprintf(buf.data(), "%s%f", text, variant.doubleValue); + break; + case amf::AMF_VARIANT_RECT: + sprintf(buf.data(), "%s[%ld,%ld,%ld,%ld]", text, + variant.rectValue.top, variant.rectValue.left, + variant.rectValue.bottom, variant.rectValue.right); + break; + case amf::AMF_VARIANT_SIZE: + sprintf(buf.data(), "%s%ldx%ld", text, + variant.sizeValue.width, variant.sizeValue.height); + break; + case amf::AMF_VARIANT_POINT: + sprintf(buf.data(), "%s[%ld,%ld]", text, + variant.pointValue.x, variant.pointValue.y); + break; + case amf::AMF_VARIANT_RATE: + sprintf(buf.data(), "%s%ld/%ld", text, + variant.rateValue.num, variant.rateValue.den); + break; + case amf::AMF_VARIANT_RATIO: + sprintf(buf.data(), "%s%ld:%ld", text, + variant.ratioValue.num, variant.ratioValue.den); + break; + case amf::AMF_VARIANT_COLOR: + sprintf(buf.data(), "%s(%d,%d,%d,%d)", text, + variant.colorValue.r, + variant.colorValue.g, + variant.colorValue.b, + variant.colorValue.a); + break; + case amf::AMF_VARIANT_STRING: + sprintf(buf.data(), "%s'%s'", text, + variant.stringValue); + break; + case amf::AMF_VARIANT_WSTRING: + sprintf(buf.data(), "%s'%ls'", text, + variant.wstringValue); + break; + } + AMF_LOG_INFO("%s", buf.data()); +}; + +static void printDebugInfo(amf::AMFComponentPtr m_AMFEncoder) { + amf::AMFPropertyInfo* pInfo; + size_t propCount = m_AMFEncoder->GetPropertyCount(); + AMF_LOG_INFO("-- Internal AMF Encoder Properties --"); + for (size_t propIndex = 0; propIndex < propCount; propIndex++) { + static const char* typeToString[] = { + "Empty", + "Boolean", + "Int64", + "Double", + "Rect", + "Size", + "Point", + "Rate", + "Ratio", + "Color", + "String", + "WString", + "Interface" + }; + + AMF_RESULT res = m_AMFEncoder->GetPropertyInfo(propIndex, (const amf::AMFPropertyInfo**) &pInfo); + if (res != AMF_OK) + continue; + AMF_LOG_INFO(" [%ls] %ls (Type: %s, Index %d)", + pInfo->name, pInfo->desc, typeToString[pInfo->type], propIndex); + AMF_LOG_INFO(" Content Type: %d", + pInfo->contentType); + AMF_LOG_INFO(" Access: %s%s%s", + (pInfo->accessType & amf::AMF_PROPERTY_ACCESS_READ) ? "R" : "", + (pInfo->accessType & amf::AMF_PROPERTY_ACCESS_WRITE) ? "W" : "", + (pInfo->accessType & amf::AMF_PROPERTY_ACCESS_WRITE_RUNTIME) ? "X" : ""); + + AMF_LOG_INFO(" Values:"); + amf::AMFVariantStruct curStruct = amf::AMFVariantStruct(); + m_AMFEncoder->GetProperty(pInfo->name, &curStruct); + fastPrintVariant(" Current: ", curStruct); + fastPrintVariant(" Default: ", pInfo->defaultValue); + fastPrintVariant(" Minimum: ", pInfo->minValue); + fastPrintVariant(" Maximum: ", pInfo->maxValue); + if (pInfo->pEnumDescription) { + AMF_LOG_INFO(" Enumeration: "); + const amf::AMFEnumDescriptionEntry* pEnumEntry = pInfo->pEnumDescription; + while (pEnumEntry->name != nullptr) { + AMF_LOG_INFO(" %ls (%ld)", + pEnumEntry->name, + pEnumEntry->value); + pEnumEntry++; + } + } + } +} +#endif + +Plugin::AMD::VCEEncoder::VCEEncoder( + VCEEncoderType p_Type, + std::string p_VideoAPI, + uint64_t p_VideoAdapterId, + bool p_OpenCL, + VCEColorFormat p_SurfaceFormat/* = VCESurfaceFormat_NV12*/ +) { + #pragma region Assign Default Values + m_EncoderType = p_Type; + m_ColorFormat = p_SurfaceFormat; + m_OpenCL = p_OpenCL; + m_Flag_IsStarted = false; + m_Flag_FirstFrameReceived = false; + m_Flag_FirstFrameSubmitted = false; + m_FrameSize.first = 64; m_FrameSize.second = 64; + m_FrameRate.first = 30; m_FrameRate.second = 1; + m_FrameRateDivisor = ((double_t)m_FrameRate.first / (double_t)m_FrameRate.second); + m_FrameRateReverseDivisor = ((double_t)m_FrameRate.second / (double_t)m_FrameRate.first); + m_InputQueueLimit = (uint32_t)(m_FrameRateDivisor); + m_InputQueueLastSize = 0; + m_TimerPeriod = 1; + m_LastQueueWarnMessageTime = std::chrono::high_resolution_clock::time_point(std::chrono::high_resolution_clock::duration(0)); + #pragma endregion Assign Default Values + + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Initializing..."); + + AMF_RESULT res = AMF_OK; + // AMF + m_AMF = AMF::GetInstance(); + m_AMFFactory = m_AMF->GetFactory(); + /// Create an AMF context. + if (m_AMFFactory->CreateContext(&m_AMFContext) != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> CreateContext failed with error %ls (code %ld).", res); + /// Initialize to a specific API. + m_API = Plugin::API::Base::GetAPIByName(p_VideoAPI); + m_APIAdapter = m_API->GetAdapterById(p_VideoAdapterId & UINT_MAX, (p_VideoAdapterId >> 32) & UINT_MAX); + m_APIInstance = m_API->CreateInstanceOnAdapter(m_APIAdapter); + switch (m_API->GetType()) { + case Plugin::API::APIType_Direct3D11: + m_MemoryType = VCEMemoryType_DirectX11; + res = m_AMFContext->InitDX11(m_API->GetContextFromInstance(m_APIInstance)); + break; + case Plugin::API::APIType_Direct3D9: + m_MemoryType = VCEMemoryType_DirectX9; + res = m_AMFContext->InitDX9(m_API->GetContextFromInstance(m_APIInstance)); + break; + case Plugin::API::APIType_OpenGL: + m_MemoryType = VCEMemoryType_OpenGL; + res = m_AMFContext->InitOpenGL(m_API->GetContextFromInstance(m_APIInstance), GetDesktopWindow(), nullptr); + break; + case Plugin::API::APIType_Host: + m_MemoryType = VCEMemoryType_Host; + m_OpenCL = false; + break; + } + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Initializing Video API failed with error %ls (code %ld).", res); + + /// Initialize OpenCL if user selected it. + if (m_OpenCL) { + res = m_AMFContext->InitOpenCL(nullptr); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> InitOpenCL failed with error %ls (code %ld).", res); + m_AMFContext->GetCompute(amf::AMF_MEMORY_OPENCL, &m_AMFCompute); + } + + /// Create the AMF Encoder component. + if (m_AMFFactory->CreateComponent(m_AMFContext, Plugin::Utility::VCEEncoderTypeAsAMF(p_Type), &m_AMFEncoder) != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Creating a component object failed with error %ls (code %ld).", res); + + /// Create the AMF Converter component. + if (m_AMFFactory->CreateComponent(m_AMFContext, AMFVideoConverter, &m_AMFConverter) != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to create VideoConverter component, error %ls (code %ld).", res); + if (m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_MEMORY_TYPE, Utility::MemoryTypeAsAMF(m_MemoryType)) != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Memory Type not supported by VideoConverter component, error %ls (code %ld).", res); + if (m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_OUTPUT_FORMAT, Utility::SurfaceFormatAsAMF(m_ColorFormat))) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Color Format not supported by VideoConverter component, error %ls (code %ld).", res); + + #ifdef _DEBUG + printDebugInfo(m_AMFEncoder); + #endif + + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Initialized."); +} + +Plugin::AMD::VCEEncoder::~VCEEncoder() { + if (m_Flag_IsStarted) + Stop(); + + // AMF + if (m_AMFConverter) + m_AMFConverter->Terminate(); + if (m_AMFEncoder) + m_AMFEncoder->Terminate(); + if (m_AMFContext) + m_AMFContext->Terminate(); + m_AMFConverter = nullptr; + m_AMFEncoder = nullptr; + m_AMFContext = nullptr; + + // API + if (m_APIInstance) + m_API->DestroyInstance(m_APIInstance); + m_APIInstance = nullptr; + m_API = nullptr; +} + +void Plugin::AMD::VCEEncoder::Start() { + // Set proper Timer resolution. + m_TimerPeriod = 1; + while (timeBeginPeriod(m_TimerPeriod) == TIMERR_NOCANDO) { + ++m_TimerPeriod; + } + + // Create Encoder + AMF_RESULT res = m_AMFEncoder->Init(Utility::SurfaceFormatAsAMF(m_ColorFormat), + m_FrameSize.first, m_FrameSize.second); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Encoder initialization failed with error %ls (code %ld).", res); + + // Create Converter + m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_COLOR_PROFILE, this->GetColorProfile()); + if (m_AMFConverter->SetProperty(L"FullRangeColor", this->IsFullRangeColorEnabled()) != AMF_OK) + m_AMFConverter->SetProperty(L"NominalRange", this->IsFullRangeColorEnabled()); + + res = m_AMFConverter->Init(Utility::SurfaceFormatAsAMF(m_ColorFormat), m_FrameSize.first, m_FrameSize.second); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Converter initialization failed with error %ls (code %ld).", res); + + m_Flag_IsStarted = true; + + // Threading + m_Input.thread = std::thread(&(Plugin::AMD::VCEEncoder::InputThreadMain), this); + m_Output.thread = std::thread(&(Plugin::AMD::VCEEncoder::OutputThreadMain), this); + + #ifdef _DEBUG + printDebugInfo(m_AMFEncoder); + #endif +} + +void Plugin::AMD::VCEEncoder::Restart() { + if (!m_Flag_IsStarted) + return; + + std::unique_lock<std::mutex> ilock(m_Input.mutex); + std::unique_lock<std::mutex> olock(m_Output.mutex); + + // Create Encoder + AMF_RESULT res = m_AMFEncoder->ReInit(m_FrameSize.first, m_FrameSize.second); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Initialization failed with error %ls (code %ld).", res); +} + +void Plugin::AMD::VCEEncoder::Stop() { + // Restore Timer precision. + if (m_TimerPeriod != 0) { + timeEndPeriod(m_TimerPeriod); + } + + m_Flag_IsStarted = false; + + // Threading + m_Output.condvar.notify_all(); + #if defined _WIN32 || defined _WIN64 + { // Windows: Force terminate Thread after 1 second of waiting. + std::thread::native_handle_type hnd = m_Output.thread.native_handle(); + + uint32_t res = WaitForSingleObject((HANDLE)hnd, 1000); + switch (res) { + case WAIT_OBJECT_0: + m_Output.thread.join(); + break; + default: + m_Output.thread.detach(); + TerminateThread((HANDLE)hnd, 0); + break; + } + } + #else + m_Output.thread.join(); + #endif + + m_Input.condvar.notify_all(); + #if defined _WIN32 || defined _WIN64 + { // Windows: Force terminate Thread after 1 second of waiting. + std::thread::native_handle_type hnd = m_Input.thread.native_handle(); + + uint32_t res = WaitForSingleObject((HANDLE)hnd, 1000); + switch (res) { + case WAIT_OBJECT_0: + m_Input.thread.join(); + break; + default: + m_Input.thread.detach(); + TerminateThread((HANDLE)hnd, 0); + break; + } + } + #else + m_Input.thread.join(); + #endif + + // Stop AMF Encoder + if (m_AMFEncoder) { + m_AMFEncoder->Drain(); + m_AMFEncoder->Flush(); + } + + // Clear Queues, Data + std::queue<amf::AMFSurfacePtr>().swap(m_Input.queue); + std::queue<amf::AMFDataPtr>().swap(m_Output.queue); + m_PacketDataBuffer.clear(); + m_ExtraDataBuffer.clear(); + } + +bool Plugin::AMD::VCEEncoder::IsStarted() { + return m_Flag_IsStarted; +} + +bool Plugin::AMD::VCEEncoder::SendInput(struct encoder_frame* frame) { + // Early-Exception if not encoding. + if (!m_Flag_IsStarted) { + const char* error = "<" __FUNCTION_NAME__ "> Attempted to send input while not running."; + AMF_LOG_ERROR("%s", error); + throw std::exception(error); + } + + // Attempt to queue for 1 second (forces "Encoding overloaded" message to appear). + bool queueSuccessful = false; + auto queueStart = std::chrono::high_resolution_clock::now(); + auto queueDuration = std::chrono::nanoseconds((uint64_t)floor(m_FrameRateReverseDivisor * 1000000)); + size_t queueSize = m_InputQueueLimit; + do { + // Wake up submission thread. + m_Input.condvar.notify_all(); + + { + std::unique_lock<std::mutex> qlock(m_Input.queuemutex); + queueSize = m_Input.queue.size(); + } + + // Push into queue if it has room. + if (queueSize < m_InputQueueLimit) { + amf::AMFSurfacePtr pAMFSurface = CreateSurfaceFromFrame(frame); + if (!pAMFSurface) { + AMF_LOG_ERROR("Unable copy frame for submission, terminating..."); + return false; + } else { + pAMFSurface->SetPts(frame->pts / m_FrameRate.second); + pAMFSurface->SetProperty(L"Frame", frame->pts); + pAMFSurface->SetDuration((uint64_t)ceil(m_FrameRateReverseDivisor * AMF_SECOND)); + } + + { + std::unique_lock<std::mutex> qlock(m_Input.queuemutex); + m_Input.queue.push(pAMFSurface); + queueSize++; + } + queueSuccessful = true; + break; + } + + // Sleep + std::this_thread::sleep_for(queueDuration / 4); + } while ((queueSuccessful == false) && (std::chrono::high_resolution_clock::now() - queueStart <= queueDuration)); + + // Report status. + auto timedelta = std::chrono::high_resolution_clock::now() - m_LastQueueWarnMessageTime; + if (timedelta >= std::chrono::seconds(1)) { // Only show these messages once per second. + if (queueSuccessful) { + int32_t queueSizeDelta = ((int32_t)m_InputQueueLastSize - (int32_t)queueSize); + + if (queueSizeDelta >= 5) { + AMF_LOG_INFO("GPU Encoder is catching up, queue is shrinking... (%ld,%+ld,%ld)", + m_InputQueueLastSize, + queueSizeDelta, + queueSize); + m_InputQueueLastSize = queueSize; + } else if (queueSizeDelta <= -5) { + AMF_LOG_WARNING("GPU Encoder overloaded, queue is growing... (%ld,%+ld,%ld)", + m_InputQueueLastSize, queueSizeDelta, queueSize); + m_InputQueueLastSize = queueSize; + } + } else { + AMF_LOG_ERROR("GPU Encoder overloaded, dropping frame instead..."); + } + m_LastQueueWarnMessageTime = std::chrono::high_resolution_clock::now(); + } + + /// Signal Thread Wakeup + m_Input.condvar.notify_all(); + + // WORKAROUND: Block for at most 5 seconds until the first frame has been submitted. + if (!m_Flag_FirstFrameSubmitted) { + auto startsubmit = std::chrono::high_resolution_clock::now(); + auto diff = std::chrono::high_resolution_clock::now() - startsubmit; + do { + diff = std::chrono::high_resolution_clock::now() - startsubmit; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } while ((diff <= std::chrono::seconds(5)) && !m_Flag_FirstFrameSubmitted); + if (!m_Flag_FirstFrameSubmitted) + throw std::exception("Unable to submit first frame, terminating..."); + else { + uint64_t dtime = (uint64_t)diff.count(); + AMF_LOG_INFO("First submission took %ld.%ld seconds.", dtime / 1000000000, dtime % 1000000000); + } + } + + return true; +} + +bool Plugin::AMD::VCEEncoder::GetOutput(struct encoder_packet* packet, bool* received_packet) { + // Early-Exception if not encoding. + if (!m_Flag_IsStarted) { + const char* error = "<" __FUNCTION_NAME__ "> Attempted to send input while not running."; + AMF_LOG_ERROR("%s", error); + throw std::exception(error); + } + + // Signal Output Thread to wake up. + m_Output.condvar.notify_all(); + + // Dequeue a Packet + bool queueSuccessful = false; + auto queueStart = std::chrono::high_resolution_clock::now(); + auto queueDuration = std::chrono::nanoseconds((uint64_t)floor(m_FrameRateReverseDivisor * 1000000)); + do { + std::unique_lock<std::mutex> qlock(m_Output.queuemutex); + if (m_Output.queue.size() != 0) + queueSuccessful = true; + + // Sleep + std::this_thread::sleep_for(queueDuration / 4); + } while ((queueSuccessful == false) && (std::chrono::high_resolution_clock::now() - queueStart <= queueDuration)); + if (!queueSuccessful) + return true; + + // We've got a DataPtr, let's use it. + { + amf::AMFDataPtr pAMFData; + { + std::unique_lock<std::mutex> qlock(m_Output.queuemutex); + pAMFData = m_Output.queue.front(); + m_Output.queue.pop(); + } + amf::AMFBufferPtr pAMFBuffer = amf::AMFBufferPtr(pAMFData); + + // Assemble Packet + packet->type = OBS_ENCODER_VIDEO; + /// Data + packet->size = pAMFBuffer->GetSize(); + if (m_PacketDataBuffer.size() < packet->size) { + size_t newBufferSize = (size_t)exp2(ceil(log2(packet->size))); + AMF_LOG_DEBUG("Packet Buffer was resized to %d byte from %d byte.", newBufferSize, m_PacketDataBuffer.size()); + m_PacketDataBuffer.resize(newBufferSize); + } + packet->data = m_PacketDataBuffer.data(); + std::memcpy(packet->data, pAMFBuffer->GetNative(), packet->size); + /// Timestamps + packet->dts = (pAMFData->GetPts() - 2) * m_FrameRate.second; // Offset by 2 to support B-Frames + pAMFBuffer->GetProperty(L"Frame", &packet->pts); + { /// Packet Priority & Keyframe + uint64_t pktType; + pAMFData->GetProperty(AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &pktType); + + switch ((AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_ENUM)pktType) { + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR:// + packet->keyframe = true; // IDR-Frames are Key-Frames that contain a lot of information. + packet->priority = 3; // Highest priority, always continue streaming with these. + //packet->drop_priority = 3; // Dropped IDR-Frames can only be replaced by the next IDR-Frame. + break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_I: // I-Frames need only a previous I- or IDR-Frame. + packet->priority = 2; // I- and IDR-Frames will most likely be present. + // packet->drop_priority = 2; // So we can continue with a I-Frame when streaming. + // break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_P: // P-Frames need either a previous P-, I- or IDR-Frame. + packet->priority = 1; // We can safely assume that at least one of these is present. + // packet->drop_priority = 1; // So we can continue with a P-Frame when streaming. + // break; + case AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_B: // B-Frames need either a parent B-, P-, I- or IDR-Frame. + packet->priority = 0; // We don't know if the last non-dropped frame was a B-Frame. + // packet->drop_priority = 1; // So require a P-Frame or better to continue streaming. + // break; + } + } + *received_packet = true; + + // Debug: Packet Information + std::vector<wchar_t> fileName(128); + mbstowcs(fileName.data(), __FILE__, fileName.size()); + std::vector<wchar_t> functionName(128); + mbstowcs(functionName.data(), __FUNCTION__, functionName.size()); + m_AMF->GetTrace()->TraceW(fileName.data(), __LINE__, AMF_TRACE_TRACE, L"Plugin::GetOutput", 4, L"Packet: Type(%lld), PTS(%4lld), DTS(%4lld), Size(%8lld)", (int64_t)packet->priority, (int64_t)packet->pts, (int64_t)packet->dts, (int64_t)packet->size); + } + + return true; +} + +bool Plugin::AMD::VCEEncoder::GetExtraData(uint8_t**& extra_data, size_t*& extra_data_size) { + if (!m_AMFContext || !m_AMFEncoder) + throw std::exception("<" __FUNCTION_NAME__ "> Called while not initialized."); + + if (!m_Flag_IsStarted) + throw std::exception("<" __FUNCTION_NAME__ "> Called while not encoding."); + + amf::AMFVariant var; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_EXTRADATA, &var); + if (res == AMF_OK && var.type == amf::AMF_VARIANT_INTERFACE) { + amf::AMFBufferPtr buf(var.pInterface); + + *extra_data_size = buf->GetSize(); + m_ExtraDataBuffer.resize(*extra_data_size); + std::memcpy(m_ExtraDataBuffer.data(), buf->GetNative(), *extra_data_size); + *extra_data = m_ExtraDataBuffer.data(); + + return true; + } + return false; +} + +void Plugin::AMD::VCEEncoder::GetVideoInfo(struct video_scale_info*& vsi) { + if (!m_AMFContext || !m_AMFEncoder) + throw std::exception("<" __FUNCTION_NAME__ "> Called while not initialized."); + + if (!m_Flag_IsStarted) + throw std::exception("<" __FUNCTION_NAME__ "> Called while not encoding."); + + switch (m_ColorFormat) { + // 4:2:0 Formats + case VCEColorFormat_NV12: + vsi->format = VIDEO_FORMAT_NV12; + break; + case VCEColorFormat_I420: + vsi->format = VIDEO_FORMAT_I420; + break; + // 4:2:2 Formats + case VCEColorFormat_YUY2: + vsi->format = VIDEO_FORMAT_YUY2; + break; + // Uncompressed + case VCEColorFormat_RGBA: + vsi->format = VIDEO_FORMAT_RGBA; + break; + case VCEColorFormat_BGRA: + vsi->format = VIDEO_FORMAT_BGRA; + break; + // Other + case VCEColorFormat_GRAY: + vsi->format = VIDEO_FORMAT_Y800; + break; + } + + // AMF requires Partial Range for some reason. + if (this->IsFullRangeColorEnabled()) { // Only use Full range if actually enabled. + vsi->range = VIDEO_RANGE_FULL; + } else { + vsi->range = VIDEO_RANGE_PARTIAL; + } +} + +void Plugin::AMD::VCEEncoder::InputThreadMain(Plugin::AMD::VCEEncoder* p_this) { + p_this->InputThreadLogic(); +} + +void Plugin::AMD::VCEEncoder::OutputThreadMain(Plugin::AMD::VCEEncoder* p_this) { + p_this->OutputThreadLogic(); +} + +void Plugin::AMD::VCEEncoder::InputThreadLogic() { // Thread Loop that handles Surface Submission + // Assign Thread Name + static const char* __threadName = "enc-amf Input Thread"; + SetThreadName(__threadName); + + // Core Loop + std::unique_lock<std::mutex> lock(m_Input.mutex); + uint32_t repeatSurfaceSubmission = 0; + do { + m_Input.condvar.wait(lock); + + // Assign Thread Name + static const char* __threadName = "enc-amf Input Thread"; + SetThreadName(__threadName); + + // Skip to check if isStarted is false. + if (!m_Flag_IsStarted) + continue; + + // Dequeue Surface + amf::AMFSurfacePtr surface; + { + std::unique_lock<std::mutex> qlock(m_Input.queuemutex); + if (m_Input.queue.size() == 0) + continue; // Queue is empty, + surface = m_Input.queue.front(); + } + + /// Convert Frame + AMF_RESULT res; + amf::AMFDataPtr outbuf; + + res = m_AMFConverter->SubmitInput(surface); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to submit Frame to Converter, error %ls (code %ld).", res); + res = m_AMFConverter->QueryOutput(&outbuf); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to retrieve Frame from Converter, error %ls (code %ld).", res); + + /// Submit to AMF + res = m_AMFEncoder->SubmitInput(outbuf); + if (res == AMF_OK) { + m_Flag_FirstFrameSubmitted = true; + + { // Remove Surface from Queue + std::unique_lock<std::mutex> qlock(m_Input.queuemutex); + m_Input.queue.pop(); + } + + // Reset AMF_INPUT_FULL retries. + repeatSurfaceSubmission = 0; + + // Continue with next Surface. + m_Input.condvar.notify_all(); + } else if (res == AMF_INPUT_FULL) { + m_Output.condvar.notify_all(); + if (repeatSurfaceSubmission < 5) { + repeatSurfaceSubmission++; + m_Input.condvar.notify_all(); + } + } else if (res == AMF_EOF) { + // This should never happen, but on the off-chance that it does, just straight up leave the loop. + break; + } else { + // Unknown, unexpected return code. + std::vector<char> msgBuf(128); + FormatTextWithAMFError(&msgBuf, "%ls (code %d)", Plugin::AMD::AMF::GetInstance()->GetTrace()->GetResultText(res), res); + AMF_LOG_WARNING("<" __FUNCTION_NAME__ "> SubmitInput failed with error %s.", msgBuf.data()); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(m_TimerPeriod)); + } while (m_Flag_IsStarted); +} + +void Plugin::AMD::VCEEncoder::OutputThreadLogic() { // Thread Loop that handles Querying + // Assign Thread Name + static const char* __threadName = "enc-amf Output Thread"; + SetThreadName(__threadName); + + // Core Loop + std::unique_lock<std::mutex> lock(m_Output.mutex); + do { + m_Output.condvar.wait(lock); + + // Assign Thread Name + static const char* __threadName = "enc-amf Output Thread"; + SetThreadName(__threadName); + + // Skip to check if isStarted is false. + if (!m_Flag_IsStarted) + continue; + + amf::AMFDataPtr pData = amf::AMFDataPtr(); + AMF_RESULT res = m_AMFEncoder->QueryOutput(&pData); + if (res == AMF_OK) { + m_Flag_FirstFrameReceived = true; + + { // Queue + std::unique_lock<std::mutex> qlock(m_Output.queuemutex); + m_Output.queue.push(pData); + } + + // Continue querying until nothing is left. + m_Output.condvar.notify_all(); + } else if (res == AMF_REPEAT) { + m_Input.condvar.notify_all(); + } else if (res == AMF_EOF) { + // This should never happen, but on the off-chance that it does, just straight up leave the loop. + break; + } else { + // Unknown, unexpected return code. + std::vector<char> msgBuf(128); + FormatTextWithAMFError(&msgBuf, "%s (code %d)", res); + AMF_LOG_WARNING("<" __FUNCTION_NAME__ "> QueryOutput failed with error %s.", msgBuf.data()); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(m_TimerPeriod)); + } while (m_Flag_IsStarted); +} + +inline amf::AMFSurfacePtr Plugin::AMD::VCEEncoder::CreateSurfaceFromFrame(struct encoder_frame*& frame) { + AMF_RESULT res = AMF_UNEXPECTED; + amf::AMFSurfacePtr pSurface = nullptr; + if (m_OpenCL) { + amf_size l_origin[] = { 0, 0, 0 }; + amf_size l_size0[] = { m_FrameSize.first, m_FrameSize.second, 1 }; + amf_size l_size1[] = { m_FrameSize.first >> 1, m_FrameSize.second >> 1, 1 }; + + res = m_AMFContext->AllocSurface(Utility::MemoryTypeAsAMF(m_MemoryType), + Utility::SurfaceFormatAsAMF(m_ColorFormat), + m_FrameSize.first, m_FrameSize.second, &pSurface); + if (res != AMF_OK) // Unable to create Surface + ThrowExceptionWithAMFError("AllocSurface failed with error %ls (code %d).", res); + + amf::AMFComputeSyncPointPtr pSyncPoint; + m_AMFCompute->PutSyncPoint(&pSyncPoint); + pSurface->Convert(amf::AMF_MEMORY_OPENCL); + m_AMFCompute->CopyPlaneFromHost(frame->data[0], l_origin, l_size0, frame->linesize[0], pSurface->GetPlaneAt(0), false); + m_AMFCompute->CopyPlaneFromHost(frame->data[1], l_origin, l_size1, frame->linesize[1], pSurface->GetPlaneAt(1), false); + m_AMFCompute->FinishQueue(); + pSurface->Convert(Utility::MemoryTypeAsAMF(m_MemoryType)); + pSyncPoint->Wait(); + } else { + res = m_AMFContext->AllocSurface(amf::AMF_MEMORY_HOST, Utility::SurfaceFormatAsAMF(m_ColorFormat), + m_FrameSize.first, m_FrameSize.second, &pSurface); + if (res != AMF_OK) // Unable to create Surface + ThrowExceptionWithAMFError("AllocSurface failed with error %ls (code %d).", res); + + size_t planeCount = pSurface->GetPlanesCount(); + #pragma loop(hint_parallel(2)) + for (uint8_t i = 0; i < planeCount; i++) { + amf::AMFPlanePtr plane = pSurface->GetPlaneAt(i); + void* plane_nat = plane->GetNative(); + int32_t height = plane->GetHeight(); + int32_t hpitch = plane->GetHPitch(); + + for (int32_t py = 0; py < height; py++) { + int32_t plane_off = py * hpitch; + int32_t frame_off = py * frame->linesize[i]; + std::memcpy( + static_cast<void*>(static_cast<uint8_t*>(plane_nat) + plane_off), + static_cast<void*>(frame->data[i] + frame_off), frame->linesize[i]); + } + } + + // Convert to AMF native type. + pSurface->Convert(Utility::MemoryTypeAsAMF(m_MemoryType)); + } + + return pSurface; +} + +////////////////////////////////////////////////////////////////////////// +// AMF Properties +////////////////////////////////////////////////////////////////////////// + +void Plugin::AMD::VCEEncoder::LogProperties() { + AMF_LOG_INFO("-- AMD Advanced Media Framework Encoder --"); + + // Initialization Properties + AMF_LOG_INFO("Initialization Properties: "); + AMF_LOG_INFO(" Type: %s", Utility::VCEEncoderTypeAsString(m_EncoderType)); + AMF_LOG_INFO(" Video API: %s", Utility::MemoryTypeAsString(m_MemoryType)); + if (m_MemoryType != VCEMemoryType_Host) { + AMF_LOG_INFO(" Video Adapter: %s", m_APIAdapter.Name.c_str()); + AMF_LOG_INFO(" OpenCL: %s", m_OpenCL ? "Enabled" : "Disabled"); + } + AMF_LOG_INFO(" Color Format: %s", Utility::SurfaceFormatAsString(m_ColorFormat)); + + // Startup Properties + AMF_LOG_INFO("Startup Properties: "); + AMF_LOG_INFO(" Usage: %s", Utility::UsageAsString(GetUsage())); + AMF_LOG_INFO(" Quality Preset: %s", Utility::QualityPresetAsString(GetQualityPreset())); + AMF_LOG_INFO(" Profile: %s %d.%d", Utility::ProfileAsString(GetProfile()), GetProfileLevel() / 10, this->GetProfileLevel() % 10); + + // Frame Properties + AMF_LOG_INFO("Frame Properties: "); + try { + AMF_LOG_INFO(" Color Profile: %s", GetColorProfile() == VCEColorProfile_709 ? "709" : "601"); + } catch (...) { + AMF_LOG_INFO(" Color Profile: N/A"); + } + try { + AMF_LOG_INFO(" Color Range: %s", IsFullRangeColorEnabled() ? "Full" : "Partial"); + } catch (...) { + AMF_LOG_INFO(" Color Range: N/A"); + } + AMF_LOG_INFO(" Resolution: %dx%d", GetResolution().first, GetResolution().second); + AMF_LOG_INFO(" Frame Rate: %d/%d", GetFrameRate().first, GetFrameRate().second); + AMF_LOG_INFO(" Scan Type: %s", GetScanType() == VCEScanType_Progressive ? "Progressive" : "Interlaced"); + + // Rate Control Properties + AMF_LOG_INFO("Rate Control Properties: "); + AMF_LOG_INFO(" Method: %s", Utility::RateControlMethodAsString(GetRateControlMethod())); + AMF_LOG_INFO(" Bitrate: "); + AMF_LOG_INFO(" Target: %d bits", GetTargetBitrate()); + AMF_LOG_INFO(" Peak: %d bits", GetPeakBitrate()); + AMF_LOG_INFO(" Quantization Parameter: "); + AMF_LOG_INFO(" Minimum: %d", GetMinimumQP()); + AMF_LOG_INFO(" Maximum: %d", GetMaximumQP()); + AMF_LOG_INFO(" I-Frame: %d", GetIFrameQP()); + AMF_LOG_INFO(" P-Frame: %d", GetPFrameQP()); + if (VCECapabilities::GetInstance()->GetAdapterCapabilities(m_API, m_APIAdapter, VCEEncoderType_AVC).supportsBFrames) { + try { AMF_LOG_INFO(" B-Frame: %d", GetBFrameQP()); } catch (...) {} + } else { + AMF_LOG_INFO(" B-Frame: N/A"); + } + AMF_LOG_INFO(" VBV Buffer: "); + AMF_LOG_INFO(" Size: %d bits", GetVBVBufferSize()); + AMF_LOG_INFO(" Initial Fullness: %f%%", GetInitialVBVBufferFullness() * 100.0); + AMF_LOG_INFO(" Flags: "); + AMF_LOG_INFO(" Filler Data: %s", IsFillerDataEnabled() ? "Enabled" : "Disabled"); + AMF_LOG_INFO(" Frame Skipping: %s", IsFrameSkippingEnabled() ? "Enabled" : "Disabled"); + AMF_LOG_INFO(" Enforce HRD Restrictions: %s", IsEnforceHRDRestrictionsEnabled() ? "Enabled" : "Disabled"); + + // Picture Control Properties + AMF_LOG_INFO("Picture Control Properties: "); + AMF_LOG_INFO(" IDR Period: %d frames", GetIDRPeriod()); + if (VCECapabilities::GetInstance()->GetAdapterCapabilities(m_API, m_APIAdapter, VCEEncoderType_AVC).supportsBFrames) { + AMF_LOG_INFO(" B-Frame Pattern: %d", GetBFramePattern()); + try { + AMF_LOG_INFO(" B-Frame Delta QP: %d", GetBFrameDeltaQP()); + } catch (...) { + AMF_LOG_INFO(" B-Frame Delta QP: N/A"); + } + AMF_LOG_INFO(" B-Frame Reference: %s", IsBFrameReferenceEnabled() ? "Enabled" : "Disabled"); + try { + AMF_LOG_INFO(" B-Frame Reference Delta QP: %d", GetBFrameReferenceDeltaQP()); + } catch (...) { + AMF_LOG_INFO(" B-Frame Reference Delta QP: N/A"); + } + } else { + AMF_LOG_INFO(" B-Frame Pattern: N/A"); + AMF_LOG_INFO(" B-Frame Delta QP: N/A"); + AMF_LOG_INFO(" B-Frame Reference: N/A"); + AMF_LOG_INFO(" B-Frame Reference Delta QP: N/A"); + } + + AMF_LOG_INFO("Miscellaneous Properties: "); + AMF_LOG_INFO(" Deblocking Filter: %s", IsDeblockingFilterEnabled() ? "Enabled" : "Disabled"); + AMF_LOG_INFO(" Motion Estimation: %s", + (this->IsHalfPixelMotionEstimationEnabled() + ? (this->IsQuarterPixelMotionEstimationEnabled() + ? "Half & Quarter Pixel" + : "Half Pixel") + : (this->IsQuarterPixelMotionEstimationEnabled() + ? "Quarter Pixel" + : "None") + ) + ); + + AMF_LOG_INFO("Experimental Properties: "); + try { AMF_LOG_INFO(" Maximum MB/s: %d", GetMaxMBPerSec()); } catch (...) {} + try { AMF_LOG_INFO(" Coding Type: %s", Utility::CodingTypeAsString(GetCodingType())); } catch (...) {} + try { AMF_LOG_INFO(" Wait For Task: %s", IsWaitForTaskEnabled() ? "Enabled" : "Disabled"); } catch (...) {} + try { AMF_LOG_INFO(" Pre-Analyiss Pass: %s", IsPreAnalysisPassEnabled() ? "Enabled" : "Disabled"); } catch (...) {} + try { AMF_LOG_INFO(" VBAQ: %s", IsVBAQEnabled() ? "Enabled" : "Disabled"); } catch (...) {} + try { AMF_LOG_INFO(" Header Insertion Spacing: %d frames", GetHeaderInsertionSpacing()); } catch (...) {} + try { AMF_LOG_INFO(" Maximum Long-Term Reference Frames: %d", GetMaximumLongTermReferenceFrames()); } catch (...) {} + try { AMF_LOG_INFO(" Maximum Access Unit Size: %d bits", GetMaximumAccessUnitSize()); } catch (...) {} + try { AMF_LOG_INFO(" Maximum Reference Frames: %d", GetMaximumReferenceFrames()); } catch (...) {} + try { AMF_LOG_INFO(" Aspect Ratio: %d:%d", GetAspectRatio().first, this->GetAspectRatio().second); } catch (...) {} + try { AMF_LOG_INFO(" GOP Size: %d", GetGOPSize()) } catch (...) {} + try { AMF_LOG_INFO(" GOP Alignment: %s", IsGOPAlignementEnabled() ? "Enabled" : "Disabled") } catch (...) {} + try { AMF_LOG_INFO(" Intra-Refresh Macroblocks Pro Slot: %d", GetIntraRefreshMacroblocksPerSlot()) } catch (...) {} + try { AMF_LOG_INFO(" Intra-Refresh Number Of Stripes: %d", GetIntraRefreshNumberOfStripes()) } catch (...) {} + try { AMF_LOG_INFO(" Slices Per Frame: %d", GetSlicesPerFrame()); } catch (...) {} + try { AMF_LOG_INFO(" Slice Mode: %s", Utility::SliceModeAsString(GetSliceMode())); } catch (...) {} + try { AMF_LOG_INFO(" Maximum Slice Size: %d", GetMaximumSliceSize()); } catch (...) {} + try { AMF_LOG_INFO(" Slice Control Mode: %s", Utility::SliceControlModeAsString(GetSliceControlMode())); } catch (...) {} + try { AMF_LOG_INFO(" Slice Control Size: %d", GetSliceControlSize()); } catch (...) {} + + Plugin::AMD::VCECapabilities::ReportAdapterCapabilities(m_API, m_APIAdapter); + + #ifdef _DEBUG + printDebugInfo(m_AMFEncoder); + #endif + + AMF_LOG_INFO("-- AMD Advanced Media Framework VCE Encoder --"); +} + +void Plugin::AMD::VCEEncoder::SetUsage(VCEUsage usage) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_USAGE, + (uint32_t)Utility::UsageAsAMF(usage)); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", + res, Utility::UsageAsString(usage)); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::UsageAsString(usage)); +} + +Plugin::AMD::VCEUsage Plugin::AMD::VCEEncoder::GetUsage() { + uint32_t usage; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_USAGE, &usage); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", + Utility::UsageAsString(Utility::UsageFromAMF(usage))); + return Utility::UsageFromAMF(usage); +} + +void Plugin::AMD::VCEEncoder::SetQualityPreset(VCEQualityPreset preset) { + static AMF_VIDEO_ENCODER_QUALITY_PRESET_ENUM CustomToAMF[] = { + AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED, + AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, + AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, + }; + static char* CustomToName[] = { + "Speed", + "Balanced", + "Quality", + }; + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QUALITY_PRESET, (uint32_t)CustomToAMF[preset]); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, CustomToName[preset]); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", CustomToName[preset]); +} + +Plugin::AMD::VCEQualityPreset Plugin::AMD::VCEEncoder::GetQualityPreset() { + static VCEQualityPreset AMFToCustom[] = { + VCEQualityPreset_Balanced, + VCEQualityPreset_Speed, + VCEQualityPreset_Quality, + }; + static char* CustomToName[] = { + "Speed", + "Balanced", + "Quality", + }; + + uint32_t preset; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QUALITY_PRESET, &preset); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", CustomToName[AMFToCustom[preset]]); + return AMFToCustom[preset]; +} + +void Plugin::AMD::VCEEncoder::SetProfile(VCEProfile profile) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE, (uint32_t)profile); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, Utility::ProfileAsString(profile)); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::ProfileAsString(profile)); +} + +Plugin::AMD::VCEProfile Plugin::AMD::VCEEncoder::GetProfile() { + uint32_t profile; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_PROFILE, &profile); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", Utility::ProfileAsString((VCEProfile)profile)); + return (VCEProfile)profile; +} + +void Plugin::AMD::VCEEncoder::SetProfileLevel(VCEProfileLevel level) { + // Automatic Detection + if (level == VCEProfileLevel_Automatic) { + auto frameSize = this->GetResolution(); + auto frameRate = this->GetFrameRate(); + level = Plugin::Utility::GetMinimumProfileLevel(frameSize, frameRate); + } + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_PROFILE_LEVEL, (uint32_t)level); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, level); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", level); +} + +Plugin::AMD::VCEProfileLevel Plugin::AMD::VCEEncoder::GetProfileLevel() { + uint32_t profileLevel; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_PROFILE_LEVEL, &profileLevel); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", profileLevel); + return (VCEProfileLevel)(profileLevel); +} + +void Plugin::AMD::VCEEncoder::SetColorProfile(VCEColorProfile profile) { + AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM pluginToAMF[] = { + AMF_VIDEO_CONVERTER_COLOR_PROFILE_601, + AMF_VIDEO_CONVERTER_COLOR_PROFILE_709, + AMF_VIDEO_CONVERTER_COLOR_PROFILE_2020, + }; + const char* pluginToString[] = { + "601", + "709", + "2020", + }; + + AMF_RESULT res = m_AMFConverter->SetProperty(AMF_VIDEO_CONVERTER_COLOR_PROFILE, + pluginToAMF[profile]); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Unable to set Color Profile, error %ls (code %ld).", res); + m_ColorProfile = profile; + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", pluginToString[profile]); +} + +Plugin::AMD::VCEColorProfile Plugin::AMD::VCEEncoder::GetColorProfile() { + return m_ColorProfile; +} + +void Plugin::AMD::VCEEncoder::SetFullRangeColorEnabled(bool enabled) { + // Info from Mikhail: + // - Name may change in the future + // - Use GetProperty or GetPropertyDescription to test for older or newer drivers. + const wchar_t* names[] = { + L"FullRangeColor", // 16.12.1 + L"NominalRange", // 16.11.5 and below. + }; + + bool enabledTest; + AMF_RESULT res = AMF_INVALID_ARG; + for (size_t i = 0; i < _countof(names); i++) { + if (m_AMFEncoder->GetProperty(names[i], &enabledTest) == AMF_OK) { + m_AMFConverter->SetProperty(names[i], enabled); + res = m_AMFEncoder->SetProperty(names[i], enabled); + break; + } + } + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsFullRangeColorEnabled() { + // Info from Mikhail: + // - Name may change in the future + // - Use GetProperty or GetPropertyDescription to test for older or newer drivers. + const wchar_t* names[] = { + L"FullRangeColor", // 16.12.1 + L"NominalRange", // 16.11.5 and below. + }; + + bool enabled; + AMF_RESULT res = AMF_INVALID_ARG; + for (size_t i = 0; i < _countof(names); i++) { + res = m_AMFEncoder->GetProperty(names[i], &enabled); + if (res == AMF_OK) { + break; + } + } + if (res != AMF_OK) + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetResolution(uint32_t width, uint32_t height) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_FRAMESIZE, ::AMFConstructSize(width, height)); + if (res != AMF_OK) { + std::vector<char> msgBuf(128); + sprintf(msgBuf.data(), "%dx%d", width, height); + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, msgBuf.data()); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %dx%d.", width, height); + m_FrameSize.first = width; + m_FrameSize.second = height; + + if (this->GetProfileLevel() == VCEProfileLevel_Automatic) + this->SetProfileLevel(VCEProfileLevel_Automatic); +} + +std::pair<uint32_t, uint32_t> Plugin::AMD::VCEEncoder::GetResolution() { + AMFSize frameSize; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_FRAMESIZE, &frameSize); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %dx%d.", frameSize.width, frameSize.height); + m_FrameSize.first = frameSize.width; + m_FrameSize.second = frameSize.height; + + if (this->GetProfileLevel() == VCEProfileLevel_Automatic) + this->SetProfileLevel(VCEProfileLevel_Automatic); + + return std::pair<uint32_t, uint32_t>(m_FrameSize); +} + +void Plugin::AMD::VCEEncoder::SetFrameRate(uint32_t num, uint32_t den) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_FRAMERATE, ::AMFConstructRate(num, den)); + if (res != AMF_OK) { + std::vector<char> msgBuf; + sprintf(msgBuf.data(), "%d/%d", num, den); + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, msgBuf.data()); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d/%d.", num, den); + m_FrameRate.first = num; + m_FrameRate.second = den; + m_FrameRateDivisor = (double_t)m_FrameRate.first / (double_t)m_FrameRate.second; + m_FrameRateReverseDivisor = ((double_t)m_FrameRate.second / (double_t)m_FrameRate.first); + m_InputQueueLimit = (uint32_t)ceil(m_FrameRateDivisor); + + if (this->GetProfileLevel() == VCEProfileLevel_Automatic) + this->SetProfileLevel(VCEProfileLevel_Automatic); +} + +std::pair<uint32_t, uint32_t> Plugin::AMD::VCEEncoder::GetFrameRate() { + AMFRate frameRate; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_FRAMERATE, &frameRate); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d/%d.", frameRate.num, frameRate.den); + m_FrameRate.first = frameRate.num; + m_FrameRate.second = frameRate.den; + m_FrameRateDivisor = (double_t)frameRate.num / (double_t)frameRate.den; + m_InputQueueLimit = (uint32_t)ceil(m_FrameRateDivisor); + + if (this->GetProfileLevel() == VCEProfileLevel_Automatic) + this->SetProfileLevel(VCEProfileLevel_Automatic); + + return std::pair<uint32_t, uint32_t>(m_FrameRate); +} + +void Plugin::AMD::VCEEncoder::SetScanType(VCEScanType scanType) { + static AMF_VIDEO_ENCODER_SCANTYPE_ENUM CustomToAMF[] = { + AMF_VIDEO_ENCODER_SCANTYPE_PROGRESSIVE, + AMF_VIDEO_ENCODER_SCANTYPE_INTERLACED, + }; + static char* CustomToName[] = { + "Progressive", + "Interlaced", + }; + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_SCANTYPE, (uint32_t)CustomToAMF[scanType]); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, CustomToName[scanType]); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", CustomToName[scanType]); +} + +Plugin::AMD::VCEScanType Plugin::AMD::VCEEncoder::GetScanType() { + static char* CustomToName[] = { + "Progressive", + "Interlaced", + }; + + uint32_t scanType; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_SCANTYPE, &scanType); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", CustomToName[scanType]); + return (Plugin::AMD::VCEScanType)scanType; +} + +void Plugin::AMD::VCEEncoder::SetRateControlMethod(VCERateControlMethod method) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, + (uint64_t)Utility::RateControlMethodAsAMF(method)); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", + res, Utility::RateControlMethodAsString(method)); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", + Utility::RateControlMethodAsString(method)); +} + +Plugin::AMD::VCERateControlMethod Plugin::AMD::VCEEncoder::GetRateControlMethod() { + uint32_t method; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, &method); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", + Utility::RateControlMethodAsString(Utility::RateControlMethodFromAMF(method))); + return Utility::RateControlMethodFromAMF(method); +} + +void Plugin::AMD::VCEEncoder::SetTargetBitrate(uint32_t bitrate) { + // Clamp Value + bitrate = clamp(bitrate, 10000, + Plugin::AMD::VCECapabilities::GetInstance()->GetAdapterCapabilities(m_API, m_APIAdapter, VCEEncoderType_AVC).maxBitrate); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_TARGET_BITRATE, bitrate); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, bitrate); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", bitrate); +} + +uint32_t Plugin::AMD::VCEEncoder::GetTargetBitrate() { + uint32_t bitrate; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_TARGET_BITRATE, &bitrate); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d bits.", bitrate); + return bitrate; +} + +void Plugin::AMD::VCEEncoder::SetPeakBitrate(uint32_t bitrate) { + // Clamp Value + bitrate = clamp(bitrate, 10000, + Plugin::AMD::VCECapabilities::GetInstance()->GetAdapterCapabilities(m_API, m_APIAdapter, VCEEncoderType_AVC).maxBitrate); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_PEAK_BITRATE, (uint32_t)bitrate); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, bitrate); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", bitrate); +} + +uint32_t Plugin::AMD::VCEEncoder::GetPeakBitrate() { + uint32_t bitrate; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_PEAK_BITRATE, &bitrate); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d bits.", bitrate); + return bitrate; +} + +void Plugin::AMD::VCEEncoder::SetMinimumQP(uint8_t qp) { + // Clamp Value + qp = clamp(qp, 0, 51); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MIN_QP, (uint32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +uint8_t Plugin::AMD::VCEEncoder::GetMinimumQP() { + uint32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MIN_QP, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (uint8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetMaximumQP(uint8_t qp) { + // Clamp Value + qp = clamp(qp, 0, 51); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MAX_QP, (uint32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +uint8_t Plugin::AMD::VCEEncoder::GetMaximumQP() { + uint32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MAX_QP, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (uint8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetIFrameQP(uint8_t qp) { + // Clamp Value + qp = clamp(qp, 0, 51); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QP_I, (uint32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +uint8_t Plugin::AMD::VCEEncoder::GetIFrameQP() { + uint32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QP_I, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (uint8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetPFrameQP(uint8_t qp) { + // Clamp Value + qp = clamp(qp, 0, 51); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QP_P, (uint32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +uint8_t Plugin::AMD::VCEEncoder::GetPFrameQP() { + uint32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QP_P, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (uint8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetBFrameQP(uint8_t qp) { + // Clamp Value + qp = clamp(qp, 0, 51); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_QP_B, (uint32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +uint8_t Plugin::AMD::VCEEncoder::GetBFrameQP() { + uint32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_QP_B, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (uint8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetVBVBufferSize(uint32_t size) { + // Clamp Value + size = clamp(size, 1000, 100000000); // 1kbit to 100mbit. + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, (uint32_t)size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, size); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", size); +} + +void Plugin::AMD::VCEEncoder::SetVBVBufferAutomatic(double_t strictness) { + uint32_t strictBitrate = 1000, looseBitrate = 100000000; + + // Strict VBV Buffer Size = Bitrate / FPS + // Loose VBV Buffer Size = Bitrate + + switch (this->GetRateControlMethod()) { + case VCERateControlMethod_ConstantBitrate: + case VCERateControlMethod_VariableBitrate_LatencyConstrained: + looseBitrate = this->GetTargetBitrate(); + break; + case VCERateControlMethod_VariableBitrate_PeakConstrained: + looseBitrate = max(this->GetTargetBitrate(), this->GetPeakBitrate()); + break; + case VCERateControlMethod_ConstantQP: + // When using Constant QP, one will have to pick a QP that is decent + // in both quality and bitrate. We can easily calculate both the QP + // required for an average bitrate and the average bitrate itself + // with these formulas: + // BITRATE = ((1 - (QP / 51)) ^ 2) * ((Width * Height) * 1.5 * (FPSNumerator / FPSDenumerator)) + // QP = (1 - sqrt(BITRATE / ((Width * Height) * 1.5 * (FPSNumerator / FPSDenumerator)))) * 51 + + auto frameSize = this->GetResolution(); + auto frameRate = this->GetFrameRate(); + + double_t bitrate = frameSize.first * frameSize.second; + switch (this->m_ColorFormat) { + case VCEColorFormat_NV12: + case VCEColorFormat_I420: + bitrate *= 1.5; + break; + case VCEColorFormat_YUY2: + bitrate *= 4; + break; + case VCEColorFormat_BGRA: + case VCEColorFormat_RGBA: + bitrate *= 3; + break; + case VCEColorFormat_GRAY: + bitrate *= 1; + break; + } + bitrate *= frameRate.first / frameRate.second; + + uint8_t qp_i, qp_p, qp_b; + qp_i = this->GetIFrameQP(); + qp_p = this->GetPFrameQP(); + try { qp_b = this->GetBFrameQP(); } catch (...) { qp_b = 51; } + double_t qp = 1 - ((double_t)(min(min(qp_i, qp_p), qp_b)) / 51.0); + qp = max(qp * qp, 0.001); // Needs to be at least 0.001. + + looseBitrate = static_cast<uint32_t>(bitrate * qp); + break; + } + strictBitrate = static_cast<uint32_t>(looseBitrate * m_FrameRateReverseDivisor); + + #define PI 3.14159265 + double_t interpVal = (sin(max(min(strictness, 1.0), 0.0) * 90 * (PI / 180))); // sin curve? + uint32_t realBitrate = static_cast<uint32_t>(ceil((strictBitrate * interpVal) + (looseBitrate * (1.0 - interpVal)))); + this->SetVBVBufferSize(realBitrate); +} + +uint32_t Plugin::AMD::VCEEncoder::GetVBVBufferSize() { + uint32_t size; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, &size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); + return size; +} + +void Plugin::AMD::VCEEncoder::SetInitialVBVBufferFullness(double_t fullness) { + // Clamp Value + fullness = max(min(fullness, 1), 0); // 0 to 100 % + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, (uint32_t)(fullness * 64)); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %f%% failed with error %ls (code %d).", res, fullness * 100); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %f%%.", fullness * 100); +} + +double_t Plugin::AMD::VCEEncoder::GetInitialVBVBufferFullness() { + uint32_t vbvBufferFullness; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, &vbvBufferFullness); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %f%%.", vbvBufferFullness / 64.0 * 100.0); + return ((double_t)vbvBufferFullness / 64.0); +} + +void Plugin::AMD::VCEEncoder::SetFillerDataEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsFillerDataEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetFrameSkippingEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsFrameSkippingEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetEnforceHRDRestrictionsEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_ENFORCE_HRD, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsEnforceHRDRestrictionsEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_ENFORCE_HRD, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetIDRPeriod(uint32_t period) { + // Clamp Value + period = max(min(period, 1000), 1); // 1-1000 so that OBS can actually quit. + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_IDR_PERIOD, (uint32_t)period); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, period); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", period); +} + +uint32_t Plugin::AMD::VCEEncoder::GetIDRPeriod() { + int32_t period; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_IDR_PERIOD, &period); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", period); + return period; +} + +void Plugin::AMD::VCEEncoder::SetBFramePattern(VCEBFramePattern pattern) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_B_PIC_PATTERN, (uint32_t)pattern); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, pattern); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", pattern); +} + +Plugin::AMD::VCEBFramePattern Plugin::AMD::VCEEncoder::GetBFramePattern() { + uint32_t pattern; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_B_PIC_PATTERN, &pattern); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", pattern); + return (Plugin::AMD::VCEBFramePattern)pattern; +} + +void Plugin::AMD::VCEEncoder::SetBFrameDeltaQP(int8_t qp) { + // Clamp Value + qp = clamp(qp, -10, 10); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, (int32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +int8_t Plugin::AMD::VCEEncoder::GetBFrameDeltaQP() { + int32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (int8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetBFrameReferenceEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_B_REFERENCE_ENABLE, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsBFrameReferenceEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_B_REFERENCE_ENABLE, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetBFrameReferenceDeltaQP(int8_t qp) { + // Clamp Value + qp = clamp(qp, -10, 10); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, (int32_t)qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, qp); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", qp); +} + +int8_t Plugin::AMD::VCEEncoder::GetBFrameReferenceDeltaQP() { + int32_t qp; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, &qp); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", qp); + return (int8_t)qp; +} + +void Plugin::AMD::VCEEncoder::SetDeblockingFilterEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsDeblockingFilterEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetHalfPixelMotionEstimationEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsHalfPixelMotionEstimationEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetQuarterPixelMotionEstimationEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsQuarterPixelMotionEstimationEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +////////////////////////////////////////////////////////////////////////// +// EXPERIMENTAL PROPERTIES - MAY BREAK AT ANY POINT IN TIME! +////////////////////////////////////////////////////////////////////////// +// Their effect may vary from driver to driver, card to card. + +uint32_t Plugin::AMD::VCEEncoder::GetMaxMBPerSec() { + uint32_t maxMBPerSec; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"MaxMBPerSec", &maxMBPerSec); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", maxMBPerSec); + return maxMBPerSec; +} + +void Plugin::AMD::VCEEncoder::SetHeaderInsertionSpacing(uint32_t spacing) { + // Clamp Value + spacing = max(min(spacing, m_FrameRate.second * 1000), 0); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, (uint32_t)spacing); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, spacing); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", spacing); +} + +uint32_t Plugin::AMD::VCEEncoder::GetHeaderInsertionSpacing() { + int32_t headerInsertionSpacing; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, &headerInsertionSpacing); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", headerInsertionSpacing); + return headerInsertionSpacing; +} + +void Plugin::AMD::VCEEncoder::SetMaximumLongTermReferenceFrames(uint32_t maximumLTRFrames) { + // Clamp Parameter Value + maximumLTRFrames = max(min(maximumLTRFrames, 2), 0); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MAX_LTR_FRAMES, (uint32_t)maximumLTRFrames); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, maximumLTRFrames); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", maximumLTRFrames); +} + +uint32_t Plugin::AMD::VCEEncoder::GetMaximumLongTermReferenceFrames() { + uint32_t maximumLTRFrames; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MAX_LTR_FRAMES, &maximumLTRFrames); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", maximumLTRFrames); + return maximumLTRFrames; +} + +void Plugin::AMD::VCEEncoder::SetCodingType(VCECodingType type) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"CABACEnable", type); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, Utility::CodingTypeAsString(type)); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::CodingTypeAsString(type)); +} + +VCECodingType Plugin::AMD::VCEEncoder::GetCodingType() { + uint64_t type; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"CABACEnable", &type); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", Utility::CodingTypeAsString((VCECodingType)type)); + return (VCECodingType)type; +} + +void Plugin::AMD::VCEEncoder::SetMaximumAccessUnitSize(uint32_t size) { + // Clamp Value + size = max(min(size, 100000000), 0); // 1kbit to 100mbit. + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_MAX_AU_SIZE, (uint32_t)size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d bits failed with error %ls (code %d).", res, size); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d bits.", size); +} + +uint32_t Plugin::AMD::VCEEncoder::GetMaximumAccessUnitSize() { + uint32_t size; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_MAX_AU_SIZE, &size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); + return size; +} + +void Plugin::AMD::VCEEncoder::SetWaitForTaskEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"WaitForTask", enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsWaitForTaskEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"WaitForTask", &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetPreAnalysisPassEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"RateControlPreanalysisEnable", enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsPreAnalysisPassEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"RateControlPreanalysisEnable", &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetVBAQEnabled(bool enabled) { + const wchar_t* names[] = { + L"EnableVBAQ", // 16.12.1 + L"EanbleVBAQ", // 16.11.5 and below. + }; + + bool enabledTest; + AMF_RESULT res = AMF_INVALID_ARG; + for (size_t i = 0; i < _countof(names); i++) { + if (m_AMFEncoder->GetProperty(names[i], &enabledTest) == AMF_OK) { + m_AMFConverter->SetProperty(names[i], enabled); + res = m_AMFEncoder->SetProperty(names[i], enabled); + break; + } + } + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsVBAQEnabled() { + const wchar_t* names[] = { + L"EnableVBAQ", // 16.12.1 + L"EanbleVBAQ", // 16.11.5 and below. + }; + + bool enabled; + AMF_RESULT res = AMF_INVALID_ARG; + for (size_t i = 0; i < _countof(names); i++) { + res = m_AMFEncoder->GetProperty(names[i], &enabled); + if (res == AMF_OK) { + break; + } + } + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetGOPSize(uint32_t size) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"GOPSize", (uint32_t)size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, size); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", size); +} + +uint32_t Plugin::AMD::VCEEncoder::GetGOPSize() { + uint32_t size; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"GOPSize", &size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); + return size; +} + +void Plugin::AMD::VCEEncoder::SetGOPAlignmentEnabled(bool enabled) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"EnableGOPAlignment", enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, enabled ? "Enabled" : "Disabled"); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", enabled ? "Enabled" : "Disabled"); +} + +bool Plugin::AMD::VCEEncoder::IsGOPAlignementEnabled() { + bool enabled; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"EnableGOPAlignment", &enabled); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", enabled ? "Enabled" : "Disabled"); + return enabled; +} + +void Plugin::AMD::VCEEncoder::SetMaximumReferenceFrames(uint32_t numFrames) { + auto caps = VCECapabilities::GetInstance()->GetAdapterCapabilities(m_API, m_APIAdapter, VCEEncoderType_AVC); + numFrames = clamp(numFrames, + caps.minReferenceFrames, + caps.maxReferenceFrames); + + AMF_RESULT res = m_AMFEncoder->SetProperty(L"MaxNumRefFrames", (uint32_t)numFrames); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, numFrames); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", numFrames); +} + +uint32_t Plugin::AMD::VCEEncoder::GetMaximumReferenceFrames() { + uint32_t numFrames; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"MaxNumRefFrames", &numFrames); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", numFrames); + return numFrames; +} + +void Plugin::AMD::VCEEncoder::SetAspectRatio(uint32_t num, uint32_t den) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"AspectRatio", ::AMFConstructRate(num, den)); + if (res != AMF_OK) { + std::vector<char> msgBuf; + sprintf(msgBuf.data(), "%d:%d", num, den); + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, msgBuf.data()); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d:%d.", num, den); +} + +std::pair<uint32_t, uint32_t> Plugin::AMD::VCEEncoder::GetAspectRatio() { + AMFRate aspectRatio; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"AspectRatio", &aspectRatio); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d:%d.", aspectRatio.num, aspectRatio.den); + return std::pair<uint32_t, uint32_t>(aspectRatio.num, aspectRatio.den); +} + +void Plugin::AMD::VCEEncoder::SetIntraRefreshMacroblocksPerSlot(uint32_t mbs) { + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, (uint32_t)mbs); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, mbs); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", mbs); +} + +uint32_t Plugin::AMD::VCEEncoder::GetIntraRefreshMacroblocksPerSlot() { + int32_t mbs; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, &mbs); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", mbs); + return mbs; +} + +void Plugin::AMD::VCEEncoder::SetIntraRefreshNumberOfStripes(uint32_t stripes) { + stripes = clamp(stripes, 0, INT_MAX); + + AMF_RESULT res = m_AMFEncoder->SetProperty(L"IntraRefreshNumOfStripes", (uint32_t)stripes); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, stripes); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", stripes); + +} + +uint32_t Plugin::AMD::VCEEncoder::GetIntraRefreshNumberOfStripes() { + uint32_t stripes; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"IntraRefreshNumOfStripes", &stripes); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", stripes); + return stripes; +} + +void Plugin::AMD::VCEEncoder::SetSlicesPerFrame(uint32_t slices) { + slices = max(slices, 1); + + AMF_RESULT res = m_AMFEncoder->SetProperty(AMF_VIDEO_ENCODER_SLICES_PER_FRAME, (uint32_t)slices); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, slices); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", slices); +} + +uint32_t Plugin::AMD::VCEEncoder::GetSlicesPerFrame() { + uint32_t slices; + AMF_RESULT res = m_AMFEncoder->GetProperty(AMF_VIDEO_ENCODER_SLICES_PER_FRAME, &slices); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", slices); + return slices; +} + +void Plugin::AMD::VCEEncoder::SetSliceMode(VCESliceMode mode) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"SliceMode", (uint32_t)mode); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, Utility::SliceModeAsString(mode)); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::SliceModeAsString(mode)); +} + +Plugin::AMD::VCESliceMode Plugin::AMD::VCEEncoder::GetSliceMode() { + uint32_t mode; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"SliceMode", &mode); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", Utility::SliceModeAsString((VCESliceMode)mode)); + return (VCESliceMode)mode; +} + +void Plugin::AMD::VCEEncoder::SetMaximumSliceSize(uint32_t size) { + size = clamp(size, 1, INT_MAX); + + AMF_RESULT res = m_AMFEncoder->SetProperty(L"MaxSliceSize", (uint32_t)size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, size); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", size); +} + +uint32_t Plugin::AMD::VCEEncoder::GetMaximumSliceSize() { + uint32_t size; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"MaxSliceSize", &size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); + return size; +} + +void Plugin::AMD::VCEEncoder::SetSliceControlMode(VCESliceControlMode mode) { + AMF_RESULT res = m_AMFEncoder->SetProperty(L"SliceControlMode", (uint32_t)mode); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %s failed with error %ls (code %d).", res, Utility::SliceControlModeAsString(mode)); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %s.", Utility::SliceControlModeAsString(mode)); +} + +Plugin::AMD::VCESliceControlMode Plugin::AMD::VCEEncoder::GetSliceControlMode() { + uint32_t mode; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"SliceControlMode", &mode); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %s.", Utility::SliceControlModeAsString((VCESliceControlMode)mode)); + return (VCESliceControlMode)mode; +} + +void Plugin::AMD::VCEEncoder::SetSliceControlSize(uint32_t size) { + // If GetSliceMode() is VCESliceMode_Vertical, then it outputs nothing with the following settings: + // - SliceControlMode: VCESliceControlMode_Macroblock + // - SliceControlSize: < 3600 + // If GetSliceMode() is VCESliceMode_Horizontal, then it outputs nothing with the following settings: + // - SliceControlMode: VCESliceControlMode_Macroblock + // - SliceControlSize: < 32 + + // H264 Macroblock = 16*16 = 256 + switch (GetSliceControlMode()) { + case VCESliceControlMode_Off: + return; + case VCESliceControlMode_Macroblock: + size = clamp(size, 0, (uint32_t)(ceil(m_FrameSize.first / 16) * ceil(m_FrameSize.second / 16))); + break; + case VCESliceControlMode_Macroblock_Row: + size = clamp(size, 0, (uint32_t)ceil(m_FrameSize.second / 16)); + break; + } + + AMF_RESULT res = m_AMFEncoder->SetProperty(L"SliceControlSize", (uint32_t)size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Setting to %d failed with error %ls (code %d).", res, size); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Set to %d.", size); +} + +uint32_t Plugin::AMD::VCEEncoder::GetSliceControlSize() { + uint32_t size; + AMF_RESULT res = m_AMFEncoder->GetProperty(L"SliceControlSize", &size); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<" __FUNCTION_NAME__ "> Failed with error %ls (code %d).", res); + } + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Value is %d.", size); + return size; +}
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/amf.cpp
Added
@@ -0,0 +1,268 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include <vector> +#include <mutex> + +#include "amf.h" +#include "windows.h" + +// AMD AMF SDK +#include "components\Component.h" +#include "components\ComponentCaps.h" +#include "components\VideoEncoderVCE.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// +using namespace Plugin::AMD; + +class CustomWriter : public amf::AMFTraceWriter { + public: + virtual void Write(const wchar_t* scope, const wchar_t* message) override { + const wchar_t* realmsg = &(message[(33 + wcslen(scope) + 2)]); // Skip Time & Scope + size_t msgLen = wcslen(realmsg) - (sizeof(wchar_t)); + + blog(LOG_INFO, "[AMF Encoder] [%.*ls][%ls] %.*ls", + 12, &(message[11]), + scope, + msgLen, realmsg); + } + + virtual void Flush() override {} + + static std::shared_ptr<CustomWriter> GetInstance() { + static std::shared_ptr<CustomWriter> __instance = std::make_shared<CustomWriter>(); + static std::mutex __mutex; + + const std::lock_guard<std::mutex> lock(__mutex); + return __instance; + } +}; + +std::shared_ptr<Plugin::AMD::AMF> Plugin::AMD::AMF::GetInstance() { + static std::shared_ptr<AMF> __instance = std::make_shared<AMF>(); + static std::mutex __mutex; + + const std::lock_guard<std::mutex> lock(__mutex); + return __instance; +} + +Plugin::AMD::AMF::AMF() { + AMF_RESULT res = AMF_OK; + + // Initialize AMF Library + AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Initializing..."); + + #pragma region Null Class Members + m_TimerPeriod = 0; + m_AMFVersion_Compiler = 0; + m_AMFVersion_Runtime = 0; + m_AMFModule = 0; + + m_AMFFactory = nullptr; + m_AMFTrace = nullptr; + m_AMFDebug = nullptr; + AMFQueryVersion = nullptr; + AMFInit = nullptr; + #pragma endregion Null Class Members + + /// Load AMF Runtime into Memory. + m_AMFModule = LoadLibraryW(AMF_DLL_NAME); + if (!m_AMFModule) { + DWORD error = GetLastError(); + std::vector<char> buf(1024); + sprintf(buf.data(), "Unable to load '%ls', error code %ld.", AMF_DLL_NAME, error); + AMF_LOG_ERROR("%s", buf.data()); + throw std::exception(buf.data(), error); + } + AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Loaded '%ls'.", AMF_DLL_NAME); + #ifdef _WIN32 // Windows: Get Product Version + std::vector<char> verbuf(GetFileVersionInfoSizeW(AMF_DLL_NAME, nullptr)); + GetFileVersionInfoW(AMF_DLL_NAME, 0, (DWORD)verbuf.size(), verbuf.data()); + + void* pBlock = verbuf.data(); + + // Read the list of languages and code pages. + struct LANGANDCODEPAGE { + WORD wLanguage; + WORD wCodePage; + } *lpTranslate; + UINT cbTranslate = sizeof(LANGANDCODEPAGE); + + VerQueryValueA(pBlock, "\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate); + + std::vector<char> buf(1024); + sprintf(buf.data(), "%s%04x%04x%s", + "\\StringFileInfo\\", + lpTranslate[0].wLanguage, + lpTranslate[0].wCodePage, + "\\ProductVersion"); + + // Retrieve file description for language and code page "i". + void* pProductVersion; + uint32_t lProductVersionSize; + VerQueryValueA(pBlock, buf.data(), &pProductVersion, &lProductVersionSize); + #endif _WIN32 // Windows: Get Product Version + + /// Find Function for Querying AMF Version. + #pragma region Query AMF Runtime Version + AMFQueryVersion = (AMFQueryVersion_Fn)GetProcAddress(m_AMFModule, AMF_QUERY_VERSION_FUNCTION_NAME); + if (!AMFQueryVersion) { + DWORD error = GetLastError(); + std::vector<char> buf(1024); + sprintf(buf.data(), "<Plugin::AMD::AMF::AMF> Finding Address of Function '%s' failed with error code %ld.", AMF_QUERY_VERSION_FUNCTION_NAME, error); + AMF_LOG_ERROR("%s", buf.data()); + throw std::exception(buf.data(), error); + } + /// Query Runtime Version + m_AMFVersion_Compiler = AMF_FULL_VERSION; + res = AMFQueryVersion(&m_AMFVersion_Runtime); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<Plugin::AMD::AMF::AMF> Querying Version failed with error %ls (code %ld).", res); + #pragma endregion Query AMF Runtime Version + + /// Find Function for Initializing AMF. + AMFInit = (AMFInit_Fn)GetProcAddress(m_AMFModule, AMF_INIT_FUNCTION_NAME); + if (!AMFInit) { + DWORD error = GetLastError(); + std::vector<char> buf(1024); + sprintf(buf.data(), "<Plugin::AMD::AMF::AMF> Finding Address of Function '%s' failed with error code %ld.", AMF_INIT_FUNCTION_NAME, error); + AMF_LOG_ERROR("%s", buf.data()); + throw std::exception(buf.data(), error); + } else { + res = AMFInit(m_AMFVersion_Runtime, &m_AMFFactory); + if (res != AMF_OK) + ThrowExceptionWithAMFError("<Plugin::AMD::AMF::AMF> Initializing AMF Library failed with error %ls (code %ld).", res); + } + AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> AMF Library initialized."); + + /// Retrieve Trace Object. + res = m_AMFFactory->GetTrace(&m_AMFTrace); + if (res != AMF_OK) { + ThrowExceptionWithAMFError("<Plugin::AMD::AMF::AMF> Retrieving Trace object failed with error %ls (code %ld).", res); + } + + /// Retrieve Debug Object. + res = m_AMFFactory->GetDebug(&m_AMFDebug); + if (res != AMF_OK) { + AMF_LOG_ERROR("<Plugin::AMD::AMF::AMF> Retrieving Debug object failed with error code %ls (code %ld).", res); + throw std::exception("", res); + } + + /// Register Custom Trace Writer and disable Debug Tracing. + m_AMFTrace->RegisterWriter(L"OBSWriter", CustomWriter::GetInstance().get(), true); + this->EnableDebugTrace(false); + + // Log success + AMF_LOG_INFO("Version " PLUGIN_VERSION_TEXT " loaded (Compiled: %d.%d.%d.%d, Runtime: %d.%d.%d.%d, Library: %.*s).", + (uint16_t)((m_AMFVersion_Compiler >> 48ull) & 0xFFFF), + (uint16_t)((m_AMFVersion_Compiler >> 32ull) & 0xFFFF), + (uint16_t)((m_AMFVersion_Compiler >> 16ull) & 0xFFFF), + (uint16_t)((m_AMFVersion_Compiler & 0xFFFF)), + (uint16_t)((m_AMFVersion_Runtime >> 48ull) & 0xFFFF), + (uint16_t)((m_AMFVersion_Runtime >> 32ull) & 0xFFFF), + (uint16_t)((m_AMFVersion_Runtime >> 16ull) & 0xFFFF), + (uint16_t)((m_AMFVersion_Runtime & 0xFFFF)), + lProductVersionSize, pProductVersion + ); + + AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Initialized."); +} + +Plugin::AMD::AMF::~AMF() { + AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Finalizing."); + + /// Unregister Writer + if (m_AMFTrace) + m_AMFTrace->UnregisterWriter(L"OBSWriter"); + + // Free Library again + if (m_AMFModule) + FreeLibrary(m_AMFModule); + + #pragma region Null Class Members + m_TimerPeriod = 0; + m_AMFVersion_Compiler = 0; + m_AMFVersion_Runtime = 0; + m_AMFModule = 0; + + m_AMFFactory = nullptr; + m_AMFTrace = nullptr; + m_AMFDebug = nullptr; + AMFQueryVersion = nullptr; + AMFInit = nullptr; + #pragma endregion Null Class Members + + AMF_LOG_DEBUG("<Plugin::AMD::AMF::AMF> Finalized."); +} + +amf::AMFFactory* Plugin::AMD::AMF::GetFactory() { + return m_AMFFactory; +} + +amf::AMFTrace* Plugin::AMD::AMF::GetTrace() { + return m_AMFTrace; +} + +amf::AMFDebug* Plugin::AMD::AMF::GetDebug() { + return m_AMFDebug; +} + +void Plugin::AMD::AMF::EnableDebugTrace(bool enable) { + if (!m_AMFTrace) + throw std::exception(__FUNCTION_NAME__ " called without a AMFTrace object!"); + if (!m_AMFDebug) + throw std::exception(__FUNCTION_NAME__ " called without a AMFDebug object!"); + + m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_CONSOLE, false); + m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_CONSOLE, AMF_TRACE_ERROR); + #ifdef _DEBUG + m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_DEBUG_OUTPUT, true); + m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TEST); + m_AMFTrace->SetPath(L"C:/AMFTrace.log"); + #else + m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_DEBUG_OUTPUT, false); + m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_ERROR); + #endif + m_AMFTrace->EnableWriter(AMF_TRACE_WRITER_FILE, false); + m_AMFTrace->SetWriterLevel(AMF_TRACE_WRITER_FILE, AMF_TRACE_ERROR); + + if (enable) { + m_AMFDebug->AssertsEnable(true); + m_AMFDebug->EnablePerformanceMonitor(true); + m_AMFTrace->TraceEnableAsync(true); + m_AMFTrace->SetGlobalLevel(AMF_TRACE_TEST); + m_AMFTrace->SetWriterLevel(L"OBSWriter", AMF_TRACE_TEST); + } else { + m_AMFDebug->AssertsEnable(false); + m_AMFDebug->EnablePerformanceMonitor(false); + m_AMFTrace->TraceEnableAsync(true); + m_AMFTrace->SetGlobalLevel(AMF_TRACE_WARNING); + m_AMFTrace->SetWriterLevel(L"OBSWriter", AMF_TRACE_WARNING); + } +}
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/api-base.cpp -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/api-base.cpp
Changed
@@ -30,6 +30,8 @@ #include "api-d3d9.h" #include "api-d3d11.h" +#include "api-host.h" +#include "api-opengl.h" #if defined(_WIN32) || defined(_WIN64) #include <windows.h> @@ -39,116 +41,110 @@ ////////////////////////////////////////////////////////////////////////// // Code ////////////////////////////////////////////////////////////////////////// +using namespace Plugin::API; -Plugin::API::Device::Device() { - this->Name = "Default"; - this->UniqueId = ""; +bool Plugin::API::operator<(const Plugin::API::Adapter & left, const Plugin::API::Adapter & right) { + if (left == right) + return left.Name < right.Name; + else + return (((uint64_t)left.idLow + ((uint64_t)left.idHigh << 32)) < ((uint64_t)right.idLow + ((uint64_t)right.idHigh << 32))); } -Plugin::API::Device::Device(std::string Name, std::string UniqueId) { - this->Name = Name; - this->UniqueId = UniqueId; -} - -Plugin::API::Device::~Device() { -} - -bool Plugin::API::operator<(const Plugin::API::Device & left, const Plugin::API::Device& right) { - return left.UniqueId < right.UniqueId; -} - -bool Plugin::API::operator>(const Plugin::API::Device & left, const Plugin::API::Device& right) { +bool Plugin::API::operator>(const Plugin::API::Adapter & left, const Plugin::API::Adapter & right) { return right < left; } -bool Plugin::API::operator<=(const Plugin::API::Device & left, const Plugin::API::Device& right) { +bool Plugin::API::operator<=(const Plugin::API::Adapter & left, const Plugin::API::Adapter & right) { return !(right < left); } -bool Plugin::API::operator>=(const Plugin::API::Device & left, const Plugin::API::Device& right) { +bool Plugin::API::operator>=(const Plugin::API::Adapter & left, const Plugin::API::Adapter & right) { return !(left < right); } -bool Plugin::API::operator==(const Plugin::API::Device & left, const Plugin::API::Device& right) { - return left.UniqueId == right.UniqueId; +bool Plugin::API::operator==(const Plugin::API::Adapter & left, const Plugin::API::Adapter & right) { + return ((left.idLow == right.idLow) && (right.idHigh == right.idHigh)); } -bool Plugin::API::operator!=(const Plugin::API::Device & left, const Plugin::API::Device& right) { +bool Plugin::API::operator!=(const Plugin::API::Adapter & left, const Plugin::API::Adapter & right) { return !(left == right); } -std::vector<Plugin::API::Device> Plugin::API::APIBase::EnumerateDevices() { - // Build a list of Devices - #if defined(_WIN32) || defined(_WIN64) +////////////////////////////////////////////////////////////////////////// +// API Index +////////////////////////////////////////////////////////////////////////// +static std::vector<std::shared_ptr<Base>> s_APIInstances; + +void Plugin::API::Base::Initialize() { + // DirectX 11 + #ifdef _WIN32 if (IsWindows8OrGreater()) { - return Plugin::API::Direct3D11::EnumerateDevices(); - } else if (IsWindowsXPOrGreater()) { - //return Plugin::API::Direct3D9::EnumerateDevices(); - } else - #endif - { // OpenGL - //return Plugin::API::OpenGL::EnumerateDevices(); + s_APIInstances.insert(s_APIInstances.end(), std::make_shared<Direct3D11>()); } - return std::vector<Plugin::API::Device>(); -} + #endif -Plugin::API::Device Plugin::API::APIBase::GetDeviceForUniqueId(std::string uniqueId) { - auto devices = EnumerateDevices(); - for (auto device : devices) { - if (device.UniqueId == uniqueId) - return device; + // DirectX 9 + #ifdef _WIN32 + if (IsWindowsXPOrGreater()) { + s_APIInstances.insert(s_APIInstances.end(), std::make_shared<Direct3D9>()); } - return Plugin::API::Device(); -} + #endif -std::unique_ptr<Plugin::API::APIBase> Plugin::API::APIBase::CreateBestAvailableAPI(Plugin::API::Device device) { - std::unique_ptr<Plugin::API::APIBase> retVal = std::make_unique<Plugin::API::APIBase>(); - #if defined(_WIN32) || defined(_WIN64) - if (IsWindows8OrGreater()) { - retVal = std::make_unique<Plugin::API::Direct3D11>(device); - } else if (IsWindowsXPOrGreater()) { - //retVal = std::make_unique<Plugin::API::Direct3D9>(device); - } else - #endif - { // OpenGL - //return Plugin::API::OpenGL::OpenGL(device); + // OpenGL + { + s_APIInstances.insert(s_APIInstances.end(), std::make_shared<OpenGL>()); } - return retVal; -} -Plugin::API::APIType Plugin::API::APIBase::GetBestAvailableAPI() { - #if defined(_WIN32) || defined(_WIN64) - if (IsWindows8OrGreater()) { - return APIType_Direct3D11; - } else if (IsWindowsXPOrGreater()) { - return APIType_Direct3D9; - } else - #endif - { // OpenGL - return APIType_OpenGL; + // Host + { + s_APIInstances.insert(s_APIInstances.end(), std::make_shared<Host>()); } - return APIType_Base; } -Plugin::API::APIBase::APIBase() { - myDevice = Plugin::API::Device(); +size_t Plugin::API::Base::GetAPICount() { + return s_APIInstances.size(); } -Plugin::API::APIBase::APIBase(Device device) { - myDevice = device; +std::shared_ptr<Base> Plugin::API::Base::GetAPIInstance(size_t index) { + auto indAPI = s_APIInstances.begin(); + for (size_t n = 0; n < index; n++) + indAPI++; + + if (indAPI == s_APIInstances.end()) + throw std::exception("Invalid API Index"); + + return *indAPI; } -Plugin::API::APIBase::~APIBase() { +std::string Plugin::API::Base::GetAPIName(size_t index) { + auto indAPI = s_APIInstances.begin(); + indAPI + index; // Advanced by x elements. + + if (indAPI == s_APIInstances.end()) + throw std::exception("Invalid API Index"); + + return indAPI->get()->GetName(); } -Plugin::API::APIType Plugin::API::APIBase::GetType() { - return myType; + +std::shared_ptr<Base> Plugin::API::Base::GetAPIByName(std::string name) { + for (auto api : s_APIInstances) { + if (name == api->GetName()) { + return api; + } + } + // If none was found, return the first one. + return *s_APIInstances.begin(); } -void* Plugin::API::APIBase::GetContext() { - return nullptr; +std::vector<std::shared_ptr<Base>> Plugin::API::Base::EnumerateAPIs() { + return std::vector<std::shared_ptr<Base>>(s_APIInstances); } -Plugin::API::Device Plugin::API::APIBase::GetDevice() { - return myDevice; +std::vector<std::string> Plugin::API::Base::EnumerateAPINames() { + std::vector<std::string> names; + for (auto api : s_APIInstances) { + names.push_back(api->GetName()); + } + return names; }
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/api-d3d11.cpp -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/api-d3d11.cpp
Changed
@@ -22,7 +22,6 @@ SOFTWARE. */ -#ifdef _WIN32 ////////////////////////////////////////////////////////////////////////// // Includes ////////////////////////////////////////////////////////////////////////// @@ -32,11 +31,11 @@ #include <string> #include <sstream> #include <stdlib.h> +#include <mutex> #include <dxgi.h> #include <d3d11.h> - -#include <mutex> +#include <atlutil.h> ////////////////////////////////////////////////////////////////////////// // Code @@ -67,6 +66,18 @@ FreeLibrary(hModule); } + HRESULT CreateDXGIFactory(REFIID riid, _Out_ void **ppFactory) { + if (hModule == 0) + return S_FALSE; + + typedef HRESULT(__stdcall *t_CreateDXGIFactory)(REFIID, void**); + t_CreateDXGIFactory pCreateDXGIFactory = (t_CreateDXGIFactory)GetProcAddress(hModule, "CreateDXGIFactory"); + + if (pCreateDXGIFactory) { + return pCreateDXGIFactory(riid, ppFactory); + } + return S_FALSE; + } HRESULT CreateDXGIFactory1(REFIID riid, _Out_ void **ppFactory) { if (hModule == 0) return S_FALSE; @@ -83,6 +94,7 @@ private: HMODULE hModule; }; + class SingletonD3D11 { public: @@ -138,174 +150,208 @@ HMODULE hModule; }; -Plugin::API::Device BuildDeviceFromAdapter(DXGI_ADAPTER_DESC1* pAdapter) { - if (pAdapter == nullptr) - return Device("INVALID DEVICE", ""); - - std::vector<char> uidBuf(1024); - sprintf(uidBuf.data(), "%ld:%ld", - pAdapter->AdapterLuid.LowPart, - pAdapter->AdapterLuid.HighPart); - - std::vector<char> nameBuf(1024); - wcstombs(nameBuf.data(), pAdapter->Description, 1024); - - return Device(std::string(nameBuf.data()), std::string(uidBuf.data())); +std::string Plugin::API::Direct3D11::GetName() { + return std::string("Direct3D 11"); } -std::vector<Plugin::API::Device> Plugin::API::Direct3D11::EnumerateDevices() { - std::vector<Plugin::API::Device> devices = std::vector<Plugin::API::Device>(); - - IDXGIFactory1* pFactory = NULL; - auto singletonDXGI = SingletonDXGI::GetInstance(); - HRESULT hr = singletonDXGI->CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory)); - if (FAILED(hr)) { - return devices; +std::vector<Adapter> Plugin::API::Direct3D11::EnumerateAdapters() { + auto dxgiInst = SingletonDXGI::GetInstance(); + + ATL::CComPtr<IDXGIFactory1> dxgiFactory; + HRESULT hr = dxgiInst->CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&dxgiFactory); + if (FAILED(hr)) + throw std::exception("<" __FUNCTION_NAME__ "> Failed to enumerate adapters, error code %X.", hr); + + std::vector<Adapter> adapters; + IDXGIAdapter1* dxgiAdapter = nullptr; + for (size_t adapterIndex = 0; + !FAILED(dxgiFactory->EnumAdapters1((UINT)adapterIndex, &dxgiAdapter)); + adapterIndex++) { + DXGI_ADAPTER_DESC1 desc = DXGI_ADAPTER_DESC1(); + dxgiAdapter->GetDesc1(&desc); + + if (desc.VendorId != 0x1002 /* AMD */) + continue; + + std::vector<char> descBuf(256); + wcstombs(descBuf.data(), desc.Description, descBuf.size()); + adapters.push_back(Adapter( + desc.AdapterLuid.LowPart, + desc.AdapterLuid.HighPart, + std::string(descBuf.data()) + )); } - IDXGIAdapter1* pAdapter = NULL; - for (uint32_t iAdapterIndex = 0; pFactory->EnumAdapters1(iAdapterIndex, &pAdapter) != DXGI_ERROR_NOT_FOUND; iAdapterIndex++) { - DXGI_ADAPTER_DESC1 adapterDesc = DXGI_ADAPTER_DESC1(); - std::memset(&adapterDesc, 0, sizeof(DXGI_ADAPTER_DESC1)); + return adapters; +} - if (pAdapter->GetDesc1(&adapterDesc) == S_OK) { - // Only allow AMD devices to be listed here. - if (adapterDesc.VendorId != 0x1002) - continue; +Plugin::API::Adapter Plugin::API::Direct3D11::GetAdapterById(uint32_t idLow, uint32_t idHigh) { + for (auto adapter : EnumerateAdapters()) { + if ((adapter.idLow == idLow) && (adapter.idHigh == idHigh)) + return adapter; + } + return *(EnumerateAdapters().begin()); +} - devices.push_back(BuildDeviceFromAdapter(&adapterDesc)); - } +Plugin::API::Adapter Plugin::API::Direct3D11::GetAdapterByName(std::string name) { + for (auto adapter : EnumerateAdapters()) { + if (adapter.Name == name) + return adapter; } + return *(EnumerateAdapters().begin()); +} - pFactory->Release(); +struct Direct3D11Instance { + ATL::CComPtr<IDXGIFactory1> factory; + ATL::CComPtr<ID3D11Device> device; + ATL::CComPtr<ID3D11DeviceContext> context; +}; - return devices; -} +void* Plugin::API::Direct3D11::CreateInstanceOnAdapter(Adapter adapter) { + HRESULT hr; -Plugin::API::Device Plugin::API::Direct3D11::GetDeviceForUniqueId(std::string uniqueId) { - Plugin::API::Device device = Device("", ""); + auto dxgiInst = SingletonDXGI::GetInstance(); - IDXGIFactory1* pFactory = NULL; - auto singletonDXGI = SingletonDXGI::GetInstance(); - HRESULT hr = singletonDXGI->CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory)); + ATL::CComPtr<IDXGIFactory1> dxgiFactory; + hr = dxgiInst->CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&dxgiFactory); if (FAILED(hr)) { - return device; + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Failed to enumerate adapters, error code %X.", hr); + throw std::exception(buf.data()); } - IDXGIAdapter1* pAdapter = NULL; - for (uint32_t iAdapterIndex = 0; pFactory->EnumAdapters1(iAdapterIndex, &pAdapter) != DXGI_ERROR_NOT_FOUND; iAdapterIndex++) { - DXGI_ADAPTER_DESC1 adapterDesc = DXGI_ADAPTER_DESC1(); - std::memset(&adapterDesc, 0, sizeof(DXGI_ADAPTER_DESC1)); - - if (pAdapter->GetDesc1(&adapterDesc) == S_OK) { - // Only allow AMD devices to be listed here. - if (adapterDesc.VendorId != 0x1002) - continue; - - Plugin::API::Device device2 = BuildDeviceFromAdapter(&adapterDesc); - - if (uniqueId == device2.UniqueId) { - device = device2; + LUID adapterLUID; + adapterLUID.LowPart = adapter.idLow; + adapterLUID.HighPart = adapter.idHigh; + + ATL::CComPtr<IDXGIAdapter> dxgiAdapter; + for (size_t adapterIndex = 0; + !FAILED(dxgiFactory->EnumAdapters((UINT)adapterIndex, &dxgiAdapter)); + adapterIndex++) { + DXGI_ADAPTER_DESC desc = DXGI_ADAPTER_DESC(); + dxgiAdapter->GetDesc(&desc); + + if (desc.VendorId != 0x1002 /* AMD */) + continue; + + if ((desc.AdapterLuid.HighPart == adapterLUID.HighPart) + && (desc.AdapterLuid.LowPart == adapterLUID.LowPart)) { + hr = NOERROR; + break; + } else { + hr = E_INVALIDARG; + } + } + if (FAILED(hr)) + throw std::invalid_argument("adapter"); + + // Create D3D Stuff + auto d3dInst = SingletonD3D11::GetInstance(); + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; + ID3D11Device* d3dDevice; + ID3D11DeviceContext* d3dContext; + for (size_t c = 0; c < 3; c++) { + uint32_t flags = 0; + + switch (c) { + case 0: + flags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT; + case 1: + flags |= D3D11_CREATE_DEVICE_BGRA_SUPPORT; + case 2: break; - } } + + hr = d3dInst->D3D11CreateDevice( + dxgiAdapter, + dxgiAdapter == NULL ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN, + NULL, + flags, + featureLevels + 1, _countof(featureLevels) - 1, + D3D11_SDK_VERSION, + &d3dDevice, + NULL, + &d3dContext); + if (SUCCEEDED(hr)) { + break; + } else { + AMF_LOG_WARNING("<" __FUNCTION_NAME__ "> Unable to create D3D11 device, error code %X (mode %d).", hr, c); + } + } + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Unable to create D3D11 device, error code %X.", hr); + throw std::exception(buf.data()); } - pFactory->Release(); - return device; + Direct3D11Instance* instance = new Direct3D11Instance(); + instance->factory = dxgiFactory; + instance->device = d3dDevice; + instance->context = d3dContext; + return instance; } -Plugin::API::Direct3D11::Direct3D11(Device device) : APIBase(device) { - IDXGIFactory1 *pFactory; +Plugin::API::Adapter Plugin::API::Direct3D11::GetAdapterForInstance(void* pInstance) { + HRESULT hr; - this->myType = APIType_Direct3D11; + if (pInstance == nullptr) + throw std::invalid_argument("instance"); - auto singletonDXGI = SingletonDXGI::GetInstance(); - if (FAILED(singletonDXGI->CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory)))) - throw new std::exception("Unable to create D3D11 driver."); + Direct3D11Instance* instance = static_cast<Direct3D11Instance*>(pInstance); + if (instance == nullptr) + throw std::invalid_argument("instance"); + + ATL::CComPtr<IDXGIAdapter> dxgiAdapter; + hr = instance->device->QueryInterface(&dxgiAdapter); + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Failed to query Adapter from D3D11 device, error code %X.", hr); + throw std::exception(buf.data()); + } - try { - IDXGIAdapter1 *pAdapter = NULL; - if (device.UniqueId != "") { - IDXGIAdapter1 *pAdapter2 = NULL; - for (uint32_t iAdapterIndex = 0; pFactory->EnumAdapters1(iAdapterIndex, &pAdapter2) != DXGI_ERROR_NOT_FOUND; iAdapterIndex++) { - DXGI_ADAPTER_DESC1 adapterDesc = DXGI_ADAPTER_DESC1(); - std::memset(&adapterDesc, 0, sizeof(DXGI_ADAPTER_DESC1)); + DXGI_ADAPTER_DESC adapterDesc; + hr = dxgiAdapter->GetDesc(&adapterDesc); + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Failed to get description from DXGI adapter, error code %X.", hr); + throw std::exception(buf.data()); + } - if (pAdapter2->GetDesc1(&adapterDesc) == S_OK) { - // Only allow AMD devices to be listed here. - if (adapterDesc.VendorId != 0x1002) - continue; + std::vector<char> descBuf(256); + wcstombs(descBuf.data(), adapterDesc.Description, descBuf.size()); - Plugin::API::Device device2 = BuildDeviceFromAdapter(&adapterDesc); + return Adapter( + adapterDesc.AdapterLuid.LowPart, + adapterDesc.AdapterLuid.HighPart, + std::string(descBuf.data()) + ); +} - if (device.UniqueId == device2.UniqueId) { - pAdapter = pAdapter2; - break; - } - } - } - } +void* Plugin::API::Direct3D11::GetContextFromInstance(void* pInstance) { + if (pInstance == nullptr) + throw std::invalid_argument("instance"); - try { - D3D_FEATURE_LEVEL featureLevels[] = { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0 - }; - D3D_FEATURE_LEVEL featureLevel; - uint32_t flags = - D3D11_CREATE_DEVICE_BGRA_SUPPORT | - D3D11_CREATE_DEVICE_DISABLE_GPU_TIMEOUT | - D3D11_CREATE_DEVICE_VIDEO_SUPPORT; - - DXGI_ADAPTER_DESC desc; - if (pAdapter != NULL) { - pAdapter->GetDesc(&desc); - } - - auto singletonD3D11 = SingletonD3D11::GetInstance(); - HRESULT hr = singletonD3D11->D3D11CreateDevice( - pAdapter, pAdapter == NULL ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN, - NULL, flags, - featureLevels, _countof(featureLevels), - D3D11_SDK_VERSION, - &pDevice, &featureLevel, &pDeviceContext); - if (FAILED(hr)) { - AMF_LOG_ERROR("Unable to create D3D11.1 device."); - hr = singletonD3D11->D3D11CreateDevice( - pAdapter, pAdapter == NULL ? D3D_DRIVER_TYPE_HARDWARE : D3D_DRIVER_TYPE_UNKNOWN, - NULL, flags, - featureLevels + 1, _countof(featureLevels) - 1, - D3D11_SDK_VERSION, - &pDevice, &featureLevel, &pDeviceContext); - if (FAILED(hr)) { - throw std::exception("Unable to create D3D11 device."); - } - } - } catch (...) { - if (pAdapter) - pAdapter->Release(); - - throw; - } - } catch (...) { - if (pFactory) - pFactory->Release(); + Direct3D11Instance* instance = static_cast<Direct3D11Instance*>(pInstance); + if (instance == nullptr) + throw std::invalid_argument("instance"); - throw; - } + return instance->device; } -Plugin::API::Direct3D11::~Direct3D11() { - if (pDeviceContext) - pDeviceContext->Release(); - if (pDevice) - pDevice->Release(); -} +void Plugin::API::Direct3D11::DestroyInstance(void* pInstance) { + if (pInstance == nullptr) + throw std::invalid_argument("instance"); -void* Plugin::API::Direct3D11::GetContext() { - return pDevice; -} + Direct3D11Instance* instance = static_cast<Direct3D11Instance*>(pInstance); + if (instance == nullptr) + throw std::invalid_argument("instance"); + delete instance; +} -#endif +Plugin::API::APIType Plugin::API::Direct3D11::GetType() { + return APIType_Direct3D11; +}
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/api-d3d9.cpp -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/api-d3d9.cpp
Changed
@@ -22,179 +22,220 @@ SOFTWARE. */ -#ifdef _WIN32 ////////////////////////////////////////////////////////////////////////// // Includes ////////////////////////////////////////////////////////////////////////// #include "api-d3d9.h" +#include <mutex> +#include <list> + +#ifdef _DEBUG +#define D3D_DEBUG_INFO +#endif +#pragma comment(lib, "d3d9.lib") +#include <d3d9.h> +#include <atlutil.h> + ////////////////////////////////////////////////////////////////////////// // Code ////////////////////////////////////////////////////////////////////////// using namespace Plugin::API; -Plugin::API::Device BuildDeviceFromAdapter(D3DADAPTER_IDENTIFIER9* pAdapter) { - if (pAdapter == nullptr) - return Device("INVALID DEVICE", ""); - - std::vector<char> uidBuf(1024); - sprintf(uidBuf.data(), "%ld:%ld:%ld:%ld", - pAdapter->VendorId, - pAdapter->DeviceId, - pAdapter->SubSysId, - pAdapter->Revision); - - std::vector<char> nameBuf(1024); - sprintf(nameBuf.data(), "%s (%s)", - pAdapter->DeviceName, - pAdapter->Description); - - return Device(std::string(nameBuf.data()), std::string(uidBuf.data())); +std::string Plugin::API::Direct3D9::GetName() { + return std::string("Direct3D 9"); } +std::vector<Adapter> Plugin::API::Direct3D9::EnumerateAdapters() { + ATL::CComPtr<IDirect3D9Ex> pD3DEx; + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3DEx); + if (FAILED(hr)) + throw std::exception("<" __FUNCTION_NAME__ "> Failed to enumerate adapters, error code %X.", hr); -std::vector<Plugin::API::Device> Plugin::API::Direct3D9::EnumerateDevices() { - std::vector<Plugin::API::Device> devices = std::vector<Plugin::API::Device>(); + std::vector<Adapter> adapters; + std::list<LUID> enumeratedLUIDs; + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + for (size_t adapterIndex = 0; + !FAILED(pD3DEx->GetAdapterIdentifier((UINT)adapterIndex, 0, &adapterIdentifier)); + adapterIndex++) { - IDirect3D9* pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); + if (adapterIdentifier.VendorId != 0x1002 /* AMD */) + continue; - uint32_t adapterCount = pDirect3D->GetAdapterCount(); - for (uint32_t adapterIndex = 0; adapterIndex < adapterCount; adapterIndex++) { - D3DADAPTER_IDENTIFIER9 adapterDesc = D3DADAPTER_IDENTIFIER9(); - pDirect3D->GetAdapterIdentifier(adapterIndex, 0, &adapterDesc); + LUID adapterLUID; + if (FAILED(pD3DEx->GetAdapterLUID((UINT)adapterIndex, &adapterLUID))) + continue; - if (adapterDesc.VendorId != 0x1002) + bool enumerated = false; + for (LUID enumeratedLUID : enumeratedLUIDs) { + if ((enumeratedLUID.LowPart == adapterLUID.LowPart) + && (enumeratedLUID.HighPart == adapterLUID.HighPart)) { + enumerated = true; + break; + } + } + if (enumerated) continue; + else + enumeratedLUIDs.push_back(adapterLUID); - Device device = BuildDeviceFromAdapter(&adapterDesc); - devices.push_back(device); + adapters.emplace_back( + Adapter(adapterLUID.LowPart, adapterLUID.HighPart, + std::string(adapterIdentifier.Description))); } - pDirect3D->Release(); - - return devices; + return adapters; } -Plugin::API::Device Plugin::API::Direct3D9::GetDeviceForUniqueId(std::string uniqueId) { - Plugin::API::Device device = Device("", ""); - - IDirect3D9* pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); - - uint32_t adapterCount = pDirect3D->GetAdapterCount(); - for (uint32_t adapterIndex = 0; adapterIndex <= adapterCount; adapterIndex++) { - D3DADAPTER_IDENTIFIER9 adapterDesc = D3DADAPTER_IDENTIFIER9(); - pDirect3D->GetAdapterIdentifier(adapterIndex, 0, &adapterDesc); - - if (adapterDesc.VendorId != 0x1002) - continue; - - Device device2 = BuildDeviceFromAdapter(&adapterDesc); - if (device2.UniqueId == uniqueId) - device = device2; +Plugin::API::Adapter Plugin::API::Direct3D9::GetAdapterById(uint32_t idLow, uint32_t idHigh) { + for (auto adapter : EnumerateAdapters()) { + if ((adapter.idLow == idLow) && (adapter.idHigh == idHigh)) + return adapter; } + return *(EnumerateAdapters().begin()); +} - pDirect3D->Release(); - - return device; +Plugin::API::Adapter Plugin::API::Direct3D9::GetAdapterByName(std::string name) { + for (auto adapter : EnumerateAdapters()) { + if (adapter.Name == name) + return adapter; + } + return *(EnumerateAdapters().begin()); } -struct EnumWindowsData { - DWORD processId; - HWND bestWindowId; +struct Direct3D9Instance { + ATL::CComPtr<IDirect3D9Ex> d3d; + ATL::CComPtr<IDirect3DDevice9Ex> device; }; -BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) { - EnumWindowsData* data = (EnumWindowsData*)lParam; - - DWORD processId; - GetWindowThreadProcessId(handle, &processId); - if ((processId == data->processId) - && (GetWindow(handle, GW_OWNER) == (HWND)0) - && (IsWindowVisible(handle))) { - return TRUE; +void* Plugin::API::Direct3D9::CreateInstanceOnAdapter(Adapter adapter) { + ATL::CComPtr<IDirect3D9Ex> pD3DEx; + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3DEx); + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Unable to create Direct3D 9 instance, error code %X.", hr); + throw std::exception(buf.data()); } - data->bestWindowId = handle; - return FALSE; -} - -Plugin::API::Direct3D9::Direct3D9(Device device) : APIBase(device) { - this->myType = APIType_Direct3D9; - pDirect3D = Direct3DCreate9(D3D_SDK_VERSION); - if (!pDirect3D) - throw std::exception("Unable to create D3D9 driver."); + size_t adapterNum = (size_t)-1; + D3DADAPTER_IDENTIFIER9 adapterIdentifier; + for (size_t adapterIndex = 0; + !FAILED(pD3DEx->GetAdapterIdentifier((UINT)adapterIndex, 0, &adapterIdentifier)); + adapterIndex++) { - // Find Adapter Index - uint32_t usedAdapter = 0; - uint32_t adapterCount = pDirect3D->GetAdapterCount(); - for (uint32_t adapterIndex = 0; adapterIndex <= adapterCount; adapterIndex++) { - D3DADAPTER_IDENTIFIER9 adapterDesc = D3DADAPTER_IDENTIFIER9(); - pDirect3D->GetAdapterIdentifier(adapterIndex, 0, &adapterDesc); + if (adapterIdentifier.VendorId != 0x1002 /* AMD */) + continue; - if (adapterDesc.VendorId != 0x1002) + LUID adapterLUID; + if (FAILED(pD3DEx->GetAdapterLUID((UINT)adapterIndex, &adapterLUID))) continue; - Device device2 = BuildDeviceFromAdapter(&adapterDesc); - if (device2.UniqueId == device.UniqueId) { - usedAdapter = adapterIndex++; + if ((adapterLUID.LowPart == adapter.idLow) + && (adapterLUID.HighPart == adapter.idHigh)) { + adapterNum = adapterIndex; break; } } + if (adapterNum == -1) + throw std::invalid_argument("adapter"); + + D3DPRESENT_PARAMETERS presentParameters; + std::memset(&presentParameters, 0, sizeof(D3DPRESENT_PARAMETERS)); + presentParameters.BackBufferWidth = 0; + presentParameters.BackBufferHeight = 0; + presentParameters.BackBufferFormat = D3DFMT_UNKNOWN; + presentParameters.Windowed = TRUE; + presentParameters.SwapEffect = D3DSWAPEFFECT_COPY; + presentParameters.hDeviceWindow = GetDesktopWindow(); + presentParameters.Flags = D3DPRESENTFLAG_VIDEO; + presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + + D3DCAPS9 ddCaps; + std::memset(&ddCaps, 0, sizeof(ddCaps)); + hr = pD3DEx->GetDeviceCaps((UINT)adapterNum, D3DDEVTYPE_HAL, &ddCaps); + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Unable to query capabilities for D3D9 adapter, error code %X.", hr); + throw std::exception(buf.data()); + } + + DWORD vp = 0; + if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { + vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; + } else { + vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } - EnumWindowsData data = EnumWindowsData(); - data.processId = GetCurrentProcessId(); - EnumWindows(EnumWindowsCallback, (LPARAM)&data); - - D3DPRESENT_PARAMETERS pPresentParameter = D3DPRESENT_PARAMETERS(); - pPresentParameter.BackBufferWidth = 1280; - pPresentParameter.BackBufferHeight = 720; - pPresentParameter.BackBufferFormat = D3DFORMAT::D3DFMT_X8R8G8B8; - pPresentParameter.BackBufferCount = 2; - pPresentParameter.MultiSampleType = D3DMULTISAMPLE_TYPE::D3DMULTISAMPLE_NONE; - pPresentParameter.MultiSampleQuality = 0; - pPresentParameter.SwapEffect = D3DSWAPEFFECT::D3DSWAPEFFECT_DISCARD; - pPresentParameter.hDeviceWindow = data.bestWindowId; - pPresentParameter.Windowed = TRUE; - pPresentParameter.EnableAutoDepthStencil = FALSE; - pPresentParameter.AutoDepthStencilFormat = D3DFORMAT::D3DFMT_A1; - pPresentParameter.Flags = D3DPRESENTFLAG_VIDEO; - pPresentParameter.FullScreen_RefreshRateInHz = 0; - pPresentParameter.PresentationInterval = 60; - - HRESULT hr = pDirect3D->CreateDevice(usedAdapter, + ATL::CComPtr<IDirect3DDevice9Ex> pD3DDeviceEx; + hr = pD3DEx->CreateDeviceEx( + (UINT)adapterNum, D3DDEVTYPE_HAL, - data.bestWindowId, - 0, //D3DCREATE_DISABLE_DRIVER_MANAGEMENT_EX | D3DCREATE_MULTITHREADED | D3DCREATE_PUREDEVICE | D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_NOWINDOWCHANGES, - &pPresentParameter, - &pDirect3DDevice); - switch (hr) { - case D3DERR_DEVICELOST: - throw std::exception("D3DERR_DEVICELOST"); - break; - case D3DERR_INVALIDCALL: - throw std::exception("D3DERR_INVALIDCALL"); - break; - case D3DERR_NOTAVAILABLE: - throw std::exception("D3DERR_NOTAVAILABLE"); - break; - case D3DERR_OUTOFVIDEOMEMORY: - throw std::exception("D3DERR_OUTOFVIDEOMEMORY"); - break; + presentParameters.hDeviceWindow, + vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED, + &presentParameters, + NULL, + &pD3DDeviceEx + ); + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Unable to create D3D9 device, error code %X.", hr); + throw std::exception(buf.data()); } - if (FAILED(hr)) - throw std::exception("Unable to create D3D9 device."); + + Direct3D9Instance* instance = new Direct3D9Instance(); + instance->d3d = pD3DEx; + instance->device = pD3DDeviceEx; + return instance; } -Plugin::API::Direct3D9::~Direct3D9() { - if (pDirect3DDevice) - pDirect3DDevice->Release(); +Plugin::API::Adapter Plugin::API::Direct3D9::GetAdapterForInstance(void* pInstance) { + if (pInstance == nullptr) + throw std::invalid_argument("instance"); + + Direct3D9Instance* instance = static_cast<Direct3D9Instance*>(pInstance); + if (instance == nullptr) + throw std::invalid_argument("instance"); - if (pDirect3D) - pDirect3D->Release(); + D3DDEVICE_CREATION_PARAMETERS par; + HRESULT hr = instance->device->GetCreationParameters(&par); + if (FAILED(hr)) { + std::vector<char> buf(1024); + std::sprintf(buf.data(), "<" __FUNCTION_NAME__ "> Unable to get adapter from D3D9 device, error code %X.", hr); + throw std::exception(buf.data()); + } + + auto adapters = Direct3D9::EnumerateAdapters(); + if (par.AdapterOrdinal > adapters.size()) + return *adapters.begin(); + + auto adapter = adapters.begin(); + for (size_t n = 0; n < par.AdapterOrdinal; n++) + adapter++; + return *adapter; } -void* Plugin::API::Direct3D9::GetContext() { - return pDirect3DDevice; +void* Plugin::API::Direct3D9::GetContextFromInstance(void* pInstance) { + if (pInstance == nullptr) + throw std::invalid_argument("instance"); + + Direct3D9Instance* instance = static_cast<Direct3D9Instance*>(pInstance); + if (instance == nullptr) + throw std::invalid_argument("instance"); + + return instance->device; } -#endif +void Plugin::API::Direct3D9::DestroyInstance(void* pInstance) { + if (pInstance == nullptr) + throw std::invalid_argument("instance"); + + Direct3D9Instance* instance = static_cast<Direct3D9Instance*>(pInstance); + if (instance == nullptr) + throw std::invalid_argument("instance"); + + delete instance; +} + +Plugin::API::APIType Plugin::API::Direct3D9::GetType() { + return APIType_Direct3D9; +}
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/api-host.cpp
Added
@@ -0,0 +1,69 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include "api-host.h" + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// +using namespace Plugin::API; + +std::string Plugin::API::Host::GetName() { + return "Host"; +} + +Plugin::API::APIType Plugin::API::Host::GetType() { + return APIType_Host; +} + +std::vector<Adapter> Plugin::API::Host::EnumerateAdapters() { + std::vector<Adapter> list; + list.push_back(Adapter(0, 0, TEXT_T(AMF_UTIL_DEFAULT))); + return list; +} + +Plugin::API::Adapter Plugin::API::Host::GetAdapterById(uint32_t idLow, uint32_t idHigh) { + return Adapter(0, 0, TEXT_T(AMF_UTIL_DEFAULT)); +} + +Plugin::API::Adapter Plugin::API::Host::GetAdapterByName(std::string name) { + return Adapter(0, 0, TEXT_T(AMF_UTIL_DEFAULT)); +} + +void* Plugin::API::Host::CreateInstanceOnAdapter(Adapter adapter) { + return nullptr; +} + +Plugin::API::Adapter Plugin::API::Host::GetAdapterForInstance(void* pInstance) { + return Adapter(0, 0, TEXT_T(AMF_UTIL_DEFAULT)); +} + +void* Plugin::API::Host::GetContextFromInstance(void* pInstance) { + throw std::exception("Host API does not have a Context."); +} + +void Plugin::API::Host::DestroyInstance(void* pInstance) {}
View file
obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/api-opengl.cpp
Added
@@ -0,0 +1,86 @@ +/* +MIT License + +Copyright (c) 2016 Michael Fabian Dirks + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +////////////////////////////////////////////////////////////////////////// +// Includes +////////////////////////////////////////////////////////////////////////// +#include "api-opengl.h" + +#include <vector> + +#ifdef _WIN32 +#include <windows.h> +#endif +#include <gl/GL.h> + +////////////////////////////////////////////////////////////////////////// +// Code +////////////////////////////////////////////////////////////////////////// +using namespace Plugin::API; + +std::string Plugin::API::OpenGL::GetName() { + return std::string("OpenGL"); +} + +std::vector<Adapter> Plugin::API::OpenGL::EnumerateAdapters() { + std::vector<Adapter> adapters; + adapters.push_back(Adapter(0, 0, "Default")); + return adapters; +} + +Plugin::API::Adapter Plugin::API::OpenGL::GetAdapterById(uint32_t idLow, uint32_t idHigh) { + for (auto adapter : EnumerateAdapters()) { + if ((adapter.idLow == idLow) && (adapter.idHigh == idHigh)) + return adapter; + } + return *(EnumerateAdapters().begin()); +} + +Plugin::API::Adapter Plugin::API::OpenGL::GetAdapterByName(std::string name) { + for (auto adapter : EnumerateAdapters()) { + if (adapter.Name == name) + return adapter; + } + return *(EnumerateAdapters().begin()); +} + +void* Plugin::API::OpenGL::CreateInstanceOnAdapter(Adapter adapter) { + return nullptr; +} + +void Plugin::API::OpenGL::DestroyInstance(void* instance) { + return; +} + +Plugin::API::Adapter Plugin::API::OpenGL::GetAdapterForInstance(void* instance) { + return *(EnumerateAdapters().begin()); +} + +void* Plugin::API::OpenGL::GetContextFromInstance(void* instance) { + return nullptr; +} + +Plugin::API::APIType Plugin::API::OpenGL::GetType() { + return APIType_OpenGL; +}
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/enc-h264.cpp -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/enc-h264.cpp
Changed
@@ -30,7 +30,7 @@ #include "enc-h264.h" #include "misc-util.cpp" -#if (defined _WIN32) || (defined _WIN64) +#ifdef _WIN32 #include <VersionHelpers.h> #include "api-d3d9.h" @@ -62,15 +62,29 @@ }; void Plugin::Interface::H264Interface::encoder_register() { - static obs_encoder_info* encoder_info = new obs_encoder_info(); - static const char* encoder_name = "amd_amf_h264"; - static const char* encoder_codec = "h264"; + // Ensure that there is a supported AMD GPU. + bool haveAVCsupport = false; + for (auto api : Plugin::API::Base::EnumerateAPIs()) { + for (auto adapter : api->EnumerateAdapters()) { + auto caps = VCECapabilities::GetInstance()->GetAdapterCapabilities(api, adapter, VCEEncoderType_AVC); + if (caps.acceleration_type != amf::AMF_ACCEL_NOT_SUPPORTED) + haveAVCsupport = true; + } + } + if (!haveAVCsupport) { + AMF_LOG_WARNING("No detected GPU supports H264 encoding."); + return; + } - std::memset(encoder_info, 0, sizeof(obs_encoder_info)); + // Create structure + static std::unique_ptr<obs_encoder_info> encoder_info = std::make_unique<obs_encoder_info>(); + std::memset(encoder_info.get(), 0, sizeof(obs_encoder_info)); // Initialize Structure - encoder_info->id = encoder_name; encoder_info->type = obs_encoder_type::OBS_ENCODER_VIDEO; + static const char* encoder_name = "amd_amf_h264"; + encoder_info->id = encoder_name; + static const char* encoder_codec = "h264"; encoder_info->codec = encoder_codec; // Functions @@ -84,7 +98,7 @@ encoder_info->get_video_info = &get_video_info; encoder_info->get_extra_data = &get_extra_data; - obs_register_encoder(encoder_info); + obs_register_encoder(encoder_info.get()); } const char* Plugin::Interface::H264Interface::get_name(void*) { @@ -92,13 +106,6 @@ return name; } -////////////////////////////////////////////////////////////////////////// -// Deprecated old Encoder -const char* Plugin::Interface::H264Interface::get_name_simple(void*) { - static const char* name = "[DEPRECATED] H264 Encoder (AMD Advanced Media Framework)"; - return name; -} -////////////////////////////////////////////////////////////////////////// void* Plugin::Interface::H264Interface::create(obs_data_t* settings, obs_encoder_t* encoder) { Plugin::Interface::H264Interface* enc = nullptr; try { @@ -106,35 +113,33 @@ enc = new Plugin::Interface::H264Interface(settings, encoder); return enc; } catch (std::exception e) { - AMF_LOG_ERROR("Exception: %s", e.what()); - AMF_LOG_ERROR("Unable to create Encoder, see log for more information."); - if (enc) - delete enc; - return NULL; + AMF_LOG_ERROR("%s", e.what()); + } catch (std::exception* e) { + AMF_LOG_ERROR("%s", e->what()); + delete e; } catch (...) { - AMF_LOG_ERROR("Unhandled Exception during start up."); - if (enc) - delete enc; - return NULL; + AMF_LOG_ERROR("Unknown Exception during start up."); } + if (enc) + delete enc; + return NULL; } -#pragma warning( push ) -#pragma warning( disable: 4702 ) void Plugin::Interface::H264Interface::destroy(void* data) { try { AMF_LOG_INFO("Shutting down..."); Plugin::Interface::H264Interface* enc = static_cast<Plugin::Interface::H264Interface*>(data); delete enc; } catch (std::exception e) { - AMF_LOG_ERROR("Exception: %s", e.what()); - AMF_LOG_ERROR("Unable to destroy Encoder, see log for more information."); + AMF_LOG_ERROR("%s", e.what()); + } catch (std::exception* e) { + AMF_LOG_ERROR("%s", e->what()); + delete e; } catch (...) { - AMF_LOG_ERROR("Unhandled Exception during shut down."); + AMF_LOG_ERROR("Unknown Exception during shut down."); } data = nullptr; } -#pragma warning( pop ) bool Plugin::Interface::H264Interface::encode(void *data, struct encoder_frame *frame, struct encoder_packet *packet, bool *received_packet) { try { @@ -150,7 +155,6 @@ void Plugin::Interface::H264Interface::get_defaults(obs_data_t *data) { #pragma region OBS - Enforce Streaming Service Restrictions - // OBS - Enforce Streaming Service Restrictions obs_data_set_default_int(data, "bitrate", -1); obs_data_set_default_int(data, "keyint_sec", -1); obs_data_set_default_string(data, "rate_control", ""); @@ -163,14 +167,6 @@ obs_data_set_string(data, "preset", ""); #pragma endregion OBS - Enforce Streaming Service Restrictions - // Cached Data - obs_data_set_string(data, "last" vstr(AMF_H264_DEVICE), "InvalidUniqueDeviceId"); - obs_data_set_int(data, "last" vstr(AMF_H264_VIEW), -1); - obs_data_set_int(data, "last" vstr(AMF_H264_RATECONTROLMETHOD), -1); - obs_data_set_int(data, "last" vstr(AMF_H264_VBVBUFFER), -1); - obs_data_set_int(data, "last" vstr(AMF_H264_BPICTURE_PATTERN), -1); - obs_data_set_int(data, "last" vstr(AMF_H264_BPICTURE_REFERENCE), -1); - // Preset obs_data_set_default_int(data, AMF_H264_PRESET, -1); @@ -179,10 +175,9 @@ obs_data_set_default_int(data, AMF_H264_QUALITY_PRESET, VCEQualityPreset_Balanced); obs_data_set_default_int(data, AMF_H264_PROFILE, VCEProfile_Main); obs_data_set_default_int(data, AMF_H264_PROFILELEVEL, VCEProfileLevel_Automatic); - obs_data_set_default_int(data, AMF_H264_MAXIMUMLTRFRAMES, 0); - obs_data_set_default_int(data, AMF_H264_CODINGTYPE, 0); // Rate Control Properties + obs_data_set_int(data, "last" vstr(AMF_H264_RATECONTROLMETHOD), -1); obs_data_set_default_int(data, AMF_H264_RATECONTROLMETHOD, VCERateControlMethod_ConstantBitrate); obs_data_set_default_int(data, AMF_H264_BITRATE_TARGET, 3500); obs_data_set_default_int(data, AMF_H264_BITRATE_PEAK, 9000); @@ -191,8 +186,7 @@ obs_data_set_default_int(data, AMF_H264_QP_IFRAME, 22); obs_data_set_default_int(data, AMF_H264_QP_PFRAME, 22); obs_data_set_default_int(data, AMF_H264_QP_BFRAME, 22); - obs_data_set_default_int(data, AMF_H264_QP_BPICTURE_DELTA, 4); - obs_data_set_default_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, 2); + obs_data_set_int(data, "last" vstr(AMF_H264_VBVBUFFER), -1); obs_data_set_default_int(data, AMF_H264_VBVBUFFER, 0); obs_data_set_default_int(data, AMF_H264_VBVBUFFER_SIZE, 3500); obs_data_set_default_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 0); @@ -200,38 +194,64 @@ obs_data_set_default_int(data, AMF_H264_MAXIMUMACCESSUNITSIZE, 0); obs_data_set_default_int(data, AMF_H264_FILLERDATA, 1); obs_data_set_default_int(data, AMF_H264_FRAMESKIPPING, 0); - obs_data_set_default_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); + obs_data_set_default_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 1); - // Picture Control Properties + // Frame Control Properties obs_data_set_default_double(data, AMF_H264_KEYFRAME_INTERVAL, 2); obs_data_set_default_int(data, AMF_H264_IDR_PERIOD, 60); - obs_data_set_default_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - obs_data_set_default_int(data, AMF_H264_BPICTURE_PATTERN, VCEBPicturePattern_None); - obs_data_set_default_int(data, AMF_H264_BPICTURE_REFERENCE, 0); + obs_data_set_int(data, "last" vstr(AMF_H264_BFRAME_PATTERN), -1); + obs_data_set_default_int(data, AMF_H264_BFRAME_PATTERN, VCEBFramePattern_None); + obs_data_set_int(data, "last" vstr(AMF_H264_BFRAME_REFERENCE), -1); + obs_data_set_default_int(data, AMF_H264_BFRAME_REFERENCE, 0); + obs_data_set_default_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, 2); + obs_data_set_default_int(data, AMF_H264_BFRAME_DELTAQP, 4); obs_data_set_default_int(data, AMF_H264_DEBLOCKINGFILTER, 1); - obs_data_set_default_int(data, AMF_H264_SLICESPERFRAME, 0); - obs_data_set_default_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); // Miscellaneous Control Properties obs_data_set_default_int(data, AMF_H264_SCANTYPE, VCEScanType_Progressive); obs_data_set_default_int(data, AMF_H264_MOTIONESTIMATION, 3); - // System Properties - obs_data_set_default_string(data, AMF_H264_DEVICE, ""); - obs_data_set_default_int(data, AMF_H264_USE_OPENCL, 0); + // Experimental Properties + obs_data_set_default_int(data, AMF_H264_MAXIMUMLTRFRAMES, 0); + obs_data_set_default_int(data, AMF_H264_CODINGTYPE, VCECodingType_Default); + obs_data_set_default_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); + obs_data_set_default_int(data, AMF_H264_SLICESPERFRAME, 1); + obs_data_set_default_int(data, AMF_H264_SLICEMODE, VCESliceMode_Horizontal); + obs_data_set_default_int(data, AMF_H264_MAXIMUMSLICESIZE, INT_MAX); + obs_data_set_default_int(data, AMF_H264_SLICECONTROLMODE, VCESliceControlMode_Off); + obs_data_set_default_int(data, AMF_H264_SLICECONTROLSIZE, 0); + obs_data_set_default_int(data, AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES, 0); + obs_data_set_default_int(data, AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT, 0); + obs_data_set_default_int(data, AMF_H264_WAITFORTASK, 0); + obs_data_set_default_int(data, AMF_H264_PREANALYSISPASS, 0); + obs_data_set_default_int(data, AMF_H264_VBAQ, 0); + obs_data_set_default_int(data, AMF_H264_GOPSIZE, 0); + obs_data_set_default_int(data, AMF_H264_GOPALIGNMENT, 1); + obs_data_set_default_int(data, AMF_H264_MAXIMUMREFERENCEFRAMES, 4); + // System Properties + obs_data_set_string(data, "last" vstr(AMF_H264_VIDEOAPI), ""); + obs_data_set_default_string(data, AMF_H264_VIDEOAPI, ""); + obs_data_set_int(data, "last" vstr(AMF_H264_VIDEOADAPTER), 0); + obs_data_set_default_int(data, AMF_H264_VIDEOADAPTER, 0); + obs_data_set_default_int(data, AMF_H264_OPENCL, 0); + obs_data_set_int(data, "last" vstr(AMF_H264_VIEW), -1); obs_data_set_default_int(data, AMF_H264_VIEW, ViewMode::Basic); - obs_data_set_default_bool(data, AMF_H264_UNLOCK_PROPERTIES, false); obs_data_set_default_bool(data, AMF_H264_DEBUG, false); } -static void fill_device_list(obs_property_t* p) { - std::vector<Plugin::API::Device> devices = Plugin::API::APIBase::EnumerateDevices(); +static void fill_api_list(obs_property_t* p) { + obs_property_list_clear(p); + for (auto api : Plugin::API::Base::EnumerateAPIs()) { + obs_property_list_add_string(p, api->GetName().c_str(), api->GetName().c_str()); + } +} +static void fill_device_list(obs_property_t* p, const char* apiname) { obs_property_list_clear(p); - obs_property_list_add_string(p, TEXT_T(AMF_UTIL_DEFAULT), ""); - for (Plugin::API::Device device : devices) { - obs_property_list_add_string(p, device.Name.c_str(), device.UniqueId.c_str()); + auto api = Plugin::API::Base::GetAPIByName(std::string(apiname)); + for (auto adapter : api->EnumerateAdapters()) { + obs_property_list_add_int(p, adapter.Name.c_str(), ((int64_t)adapter.idHigh << 32) + (int64_t)adapter.idLow); } } @@ -259,8 +279,10 @@ obs_property_list_add_int(p, TEXT_T(AMF_H264_USAGE_TRANSCODING), VCEUsage_Transcoding); obs_property_list_add_int(p, TEXT_T(AMF_H264_USAGE_ULTRALOWLATENCY), VCEUsage_UltraLowLatency); obs_property_list_add_int(p, TEXT_T(AMF_H264_USAGE_LOWLATENCY), VCEUsage_LowLatency); - //obs_property_list_add_int(list, TEXT_T(AMF_H264_USAGE_WEBCAM), VCEUsage_Webcam); // Requires SVC? SVC is not implemented by default. + // Webcam requires SVC, which is not something OBSs properties API makes easy to support. Nor would it look like anything usable. + //obs_property_list_add_int(list, TEXT_T(AMF_H264_USAGE_WEBCAM), VCEUsage_Webcam); #pragma endregion Usage + #pragma region Quality Preset p = obs_properties_add_list(props, AMF_H264_QUALITY_PRESET, TEXT_T(AMF_H264_QUALITY_PRESET), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_QUALITY_PRESET_DESCRIPTION)); @@ -268,32 +290,19 @@ obs_property_list_add_int(p, TEXT_T(AMF_H264_QUALITY_PRESET_BALANCED), VCEQualityPreset_Balanced); obs_property_list_add_int(p, TEXT_T(AMF_H264_QUALITY_PRESET_QUALITY), VCEQualityPreset_Quality); #pragma endregion Quality Preset + #pragma region Profile p = obs_properties_add_list(props, AMF_H264_PROFILE, TEXT_T(AMF_H264_PROFILE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_PROFILE_DESCRIPTION)); - obs_property_list_add_int(p, "NOT INITIALIZED", 0xFFFFFFFFFFFFFFFFull); #pragma endregion Profile + #pragma region Profile Level p = obs_properties_add_list(props, AMF_H264_PROFILELEVEL, TEXT_T(AMF_H264_PROFILELEVEL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_PROFILELEVEL_DESCRIPTION)); - obs_property_list_add_int(p, "NOT INITIALIZED", 0xFFFFFFFFFFFFFFFFull); #pragma endregion Profile Levels - #pragma region Long Term Reference Frames - p = obs_properties_add_int_slider(props, AMF_H264_MAXIMUMLTRFRAMES, TEXT_T(AMF_H264_MAXIMUMLTRFRAMES), 0, 2, 1); - obs_property_set_long_description(p, TEXT_T(AMF_H264_MAXIMUMLTRFRAMES_DESCRIPTION)); - obs_property_set_modified_callback(p, properties_modified); - #pragma endregion Long Term Reference Frames - #pragma region Coding Type - p = obs_properties_add_list(props, AMF_H264_CODINGTYPE, TEXT_T(AMF_H264_CODINGTYPE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_set_long_description(p, TEXT_T(AMF_H264_CODINGTYPE_DESCRIPTION)); - obs_property_list_add_int(p, TEXT_T(AMF_UTIL_DEFAULT), VCECodingType_Default); - obs_property_list_add_int(p, "CALVC", VCECodingType_CALV); - obs_property_list_add_int(p, "CABAC", VCECodingType_CABAC); - #pragma endregion Coding Type #pragma endregion Static Properties #pragma region Rate Control Properties - //p = obs_properties_add_bool(props, "rcp_delimiter", "------ Rate Control Properties ------"); #pragma region Method p = obs_properties_add_list(props, AMF_H264_RATECONTROLMETHOD, TEXT_T(AMF_H264_RATECONTROLMETHOD), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_RATECONTROLMETHOD_DESCRIPTION)); @@ -303,6 +312,7 @@ obs_property_list_add_int(p, TEXT_T(AMF_H264_RATECONTROLMETHOD_VBR_LAT), VCERateControlMethod_VariableBitrate_LatencyConstrained); obs_property_set_modified_callback(p, properties_modified); #pragma endregion Method + #pragma region Method Parameters /// Bitrate Constraints p = obs_properties_add_int(props, AMF_H264_BITRATE_TARGET, TEXT_T(AMF_H264_BITRATE_TARGET), 0, @@ -311,11 +321,13 @@ p = obs_properties_add_int(props, AMF_H264_BITRATE_PEAK, TEXT_T(AMF_H264_BITRATE_PEAK), 0, 1, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_BITRATE_PEAK_DESCRIPTION)); + /// Minimum QP, Maximum QP p = obs_properties_add_int_slider(props, AMF_H264_QP_MINIMUM, TEXT_T(AMF_H264_QP_MINIMUM), 0, 51, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_QP_MINIMUM_DESCRIPTION)); p = obs_properties_add_int_slider(props, AMF_H264_QP_MAXIMUM, TEXT_T(AMF_H264_QP_MAXIMUM), 0, 51, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_QP_MAXIMUM_DESCRIPTION)); + /// Method: Constant QP p = obs_properties_add_int_slider(props, AMF_H264_QP_IFRAME, TEXT_T(AMF_H264_QP_IFRAME), 0, 51, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_QP_IFRAME_DESCRIPTION)); @@ -324,6 +336,7 @@ p = obs_properties_add_int_slider(props, AMF_H264_QP_BFRAME, TEXT_T(AMF_H264_QP_BFRAME), 0, 51, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_QP_BFRAME_DESCRIPTION)); #pragma endregion Method Parameters + #pragma region VBV Buffer p = obs_properties_add_list(props, AMF_H264_VBVBUFFER, TEXT_T(AMF_H264_VBVBUFFER), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_VBVBUFFER_DESCRIPTION)); @@ -337,20 +350,24 @@ p = obs_properties_add_float_slider(props, AMF_H264_VBVBUFFER_FULLNESS, TEXT_T(AMF_H264_VBVBUFFER_FULLNESS), 0.0, 100.0, 100.0 / 64.0); obs_property_set_long_description(p, TEXT_T(AMF_H264_VBVBUFFER_FULLNESS_DESCRIPTION)); #pragma endregion VBV Buffer + /// Max Access Unit Size p = obs_properties_add_int_slider(props, AMF_H264_MAXIMUMACCESSUNITSIZE, TEXT_T(AMF_H264_MAXIMUMACCESSUNITSIZE), 0, 100000000, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_MAXIMUMACCESSUNITSIZE_DESCRIPTION)); + #pragma region Flags /// Filler Data (Only supported by CBR so far) p = obs_properties_add_list(props, AMF_H264_FILLERDATA, TEXT_T(AMF_H264_FILLERDATA), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_FILLERDATA_DESCRIPTION)); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); + /// Frame Skipping p = obs_properties_add_list(props, AMF_H264_FRAMESKIPPING, TEXT_T(AMF_H264_FRAMESKIPPING), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_FRAMESKIPPING_DESCRIPTION)); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); + /// Enforce Hypothetical Reference Decoder Compatibility p = obs_properties_add_list(props, AMF_H264_ENFORCEHRDCOMPATIBILITY, TEXT_T(AMF_H264_ENFORCEHRDCOMPATIBILITY), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_ENFORCEHRDCOMPATIBILITY_DESCRIPTION)); @@ -359,53 +376,47 @@ #pragma endregion Flags #pragma endregion Rate Control Properties - #pragma region Picture Control Properties - //p = obs_properties_add_bool(props, "pcp_delimiter", "------ Picture Control Properties ------"); - #pragma region IDR Period / Keyframe Interval / Header Insertion Spacing + #pragma region Frame Control Properties + #pragma region IDR Period / Keyframe Interval p = obs_properties_add_float(props, AMF_H264_KEYFRAME_INTERVAL, TEXT_T(AMF_H264_KEYFRAME_INTERVAL), 0, 100, 0.001); obs_property_set_long_description(p, TEXT_T(AMF_H264_KEYFRAME_INTERVAL_DESCRIPTION)); p = obs_properties_add_int(props, AMF_H264_IDR_PERIOD, TEXT_T(AMF_H264_IDR_PERIOD), 1, 1000, 1); obs_property_set_long_description(p, TEXT_T(AMF_H264_IDR_PERIOD_DESCRIPTION)); - p = obs_properties_add_int(props, AMF_H264_HEADER_INSERTION_SPACING, TEXT_T(AMF_H264_HEADER_INSERTION_SPACING), 0, 1000, 1); - obs_property_set_long_description(p, TEXT_T(AMF_H264_HEADER_INSERTION_SPACING_DESCRIPTION)); - #pragma endregion IDR Period / Keyframe Interval / Header Insertion Spacing - #pragma region B-Pictures - /// B-Pictures Pattern - p = obs_properties_add_int_slider(props, AMF_H264_BPICTURE_PATTERN, TEXT_T(AMF_H264_BPICTURE_PATTERN), - VCEBPicturePattern_None, VCEBPicturePattern_Three, 1); - obs_property_set_long_description(p, TEXT_T(AMF_H264_BPICTURE_PATTERN_DESCRIPTION)); + #pragma endregion IDR Period / Keyframe Interval + + #pragma region B-Frames + /// B-Frames Pattern + p = obs_properties_add_int_slider(props, AMF_H264_BFRAME_PATTERN, TEXT_T(AMF_H264_BFRAME_PATTERN), + VCEBFramePattern_None, VCEBFramePattern_Three, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_BFRAME_PATTERN_DESCRIPTION)); obs_property_set_modified_callback(p, properties_modified); /// Enable Reference to B-Frames (2nd Generation GCN and newer) - p = obs_properties_add_list(props, AMF_H264_BPICTURE_REFERENCE, TEXT_T(AMF_H264_BPICTURE_REFERENCE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_set_long_description(p, TEXT_T(AMF_H264_BPICTURE_REFERENCE_DESCRIPTION)); + p = obs_properties_add_list(props, AMF_H264_BFRAME_REFERENCE, TEXT_T(AMF_H264_BFRAME_REFERENCE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_BFRAME_REFERENCE_DESCRIPTION)); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); obs_property_set_modified_callback(p, properties_modified); - /// B-Picture Delta QP - p = obs_properties_add_int_slider(props, AMF_H264_QP_BPICTURE_DELTA, TEXT_T(AMF_H264_QP_BPICTURE_DELTA), -10, 10, 1); - obs_property_set_long_description(p, TEXT_T(AMF_H264_QP_BPICTURE_DELTA_DESCRIPTION)); - p = obs_properties_add_int_slider(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, TEXT_T(AMF_H264_QP_REFERENCE_BPICTURE_DELTA), -10, 10, 1); - obs_property_set_long_description(p, TEXT_T(AMF_H264_QP_REFERENCE_BPICTURE_DELTA_DESCRIPTION)); - #pragma endregion B-Pictures + /// B-Frame Delta QP + p = obs_properties_add_int_slider(props, AMF_H264_BFRAME_REFERENCEDELTAQP, TEXT_T(AMF_H264_BFRAME_REFERENCEDELTAQP), -10, 10, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_BFRAME_REFERENCEDELTAQP_DESCRIPTION)); + p = obs_properties_add_int_slider(props, AMF_H264_BFRAME_DELTAQP, TEXT_T(AMF_H264_BFRAME_DELTAQP), -10, 10, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_BFRAME_DELTAQP_DESCRIPTION)); + #pragma endregion B-Frames + /// De-Blocking Filter p = obs_properties_add_list(props, AMF_H264_DEBLOCKINGFILTER, TEXT_T(AMF_H264_DEBLOCKINGFILTER), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_DEBLOCKINGFILTER_DESCRIPTION)); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); - /// Number of Slices Per Frame - p = obs_properties_add_int_slider(props, AMF_H264_SLICESPERFRAME, TEXT_T(AMF_H264_SLICESPERFRAME), 0, 8160, 1); - obs_property_set_long_description(p, TEXT_T(AMF_H264_SLICESPERFRAME_DESCRIPTION)); - /// Intra Refresh Number of Macro Blocks per Slot - obs_properties_add_int_slider(props, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, TEXT_T(AMF_H264_INTRAREFRESHNUMMBSPERSLOT), 0, 8160, 1); - #pragma endregion Picture Control Properties + #pragma endregion Frame Control Properties #pragma region Miscellaneous Control Properties - //p = obs_properties_add_bool(props, "msc_delimiter", "------ Miscellaneous Properties ------"); /// Scan Type p = obs_properties_add_list(props, AMF_H264_SCANTYPE, TEXT_T(AMF_H264_SCANTYPE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_SCANTYPE_DESCRIPTION)); obs_property_list_add_int(p, TEXT_T(AMF_H264_SCANTYPE_PROGRESSIVE), VCEScanType_Progressive); obs_property_list_add_int(p, TEXT_T(AMF_H264_SCANTYPE_INTERLACED), VCEScanType_Interlaced); + /// Motion Estimation p = obs_properties_add_list(props, AMF_H264_MOTIONESTIMATION, TEXT_T(AMF_H264_MOTIONESTIMATION), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); obs_property_set_long_description(p, TEXT_T(AMF_H264_MOTIONESTIMATION_DESCRIPTION)); @@ -415,18 +426,111 @@ obs_property_list_add_int(p, TEXT_T(AMF_H264_MOTIONESTIMATION_BOTH), 3); #pragma endregion Miscellaneous Control Properties + #pragma region Experimental Properties + #pragma region Coding Type + p = obs_properties_add_list(props, AMF_H264_CODINGTYPE, TEXT_T(AMF_H264_CODINGTYPE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_CODINGTYPE_DESCRIPTION)); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_DEFAULT), VCECodingType_Default); + obs_property_list_add_int(p, "CABAC", VCECodingType_CABAC); + obs_property_list_add_int(p, "CALVC", VCECodingType_CALVC); + #pragma endregion Coding Type + + #pragma region Long Term Reference Frames + p = obs_properties_add_int_slider(props, AMF_H264_MAXIMUMLTRFRAMES, TEXT_T(AMF_H264_MAXIMUMLTRFRAMES), 0, 2, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_MAXIMUMLTRFRAMES_DESCRIPTION)); + obs_property_set_modified_callback(p, properties_modified); + #pragma endregion Long Term Reference Frames + + /// Header Insertion Spacing + p = obs_properties_add_int(props, AMF_H264_HEADER_INSERTION_SPACING, TEXT_T(AMF_H264_HEADER_INSERTION_SPACING), 0, 1000, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_HEADER_INSERTION_SPACING_DESCRIPTION)); + + #pragma region Slicing + /// Number of Slices Per Frame + p = obs_properties_add_int_slider(props, AMF_H264_SLICESPERFRAME, TEXT_T(AMF_H264_SLICESPERFRAME), 1, 8160, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_SLICESPERFRAME_DESCRIPTION)); + + /// Slice Mode + p = obs_properties_add_list(props, AMF_H264_SLICEMODE, TEXT_T(AMF_H264_SLICEMODE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_SLICEMODE_DESCRIPTION)); + obs_property_list_add_int(p, "Horizontal", VCESliceMode_Horizontal); + obs_property_list_add_int(p, "Vertical", VCESliceMode_Vertical); + + /// Maximum Slice Size + p = obs_properties_add_int_slider(props, AMF_H264_MAXIMUMSLICESIZE, TEXT_T(AMF_H264_MAXIMUMSLICESIZE), 1, INT_MAX, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_MAXIMUMSLICESIZE_DESCRIPTION)); + + /// Slice Control Mode + p = obs_properties_add_list(props, AMF_H264_SLICECONTROLMODE, TEXT_T(AMF_H264_SLICECONTROLMODE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_SLICECONTROLMODE_DESCRIPTION)); + obs_property_list_add_int(p, Utility::SliceControlModeAsString(VCESliceControlMode_Off), VCESliceControlMode_Off); + obs_property_list_add_int(p, Utility::SliceControlModeAsString(VCESliceControlMode_Macroblock), VCESliceControlMode_Macroblock); + obs_property_list_add_int(p, Utility::SliceControlModeAsString(VCESliceControlMode_Macroblock_Row), VCESliceControlMode_Macroblock_Row); + + /// Slice Control Size + p = obs_properties_add_int_slider(props, AMF_H264_SLICECONTROLSIZE, TEXT_T(AMF_H264_SLICECONTROLSIZE), 0, 34560, 1); // 4096x2160 / 16x16 + obs_property_set_long_description(p, TEXT_T(AMF_H264_SLICECONTROLSIZE_DESCRIPTION)); + #pragma endregion Slicing + + #pragma region Intra Refresh + /// Intra Refresh: Number of Stripes + p = obs_properties_add_int_slider(props, AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES, TEXT_T(AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES), 0, INT_MAX, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES_DESCRIPTION)); + + /// Intra Refresh: Macroblocks Per Slot + p = obs_properties_add_int_slider(props, AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT, TEXT_T(AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT), 0, 34560, 1); // 4096x2160 / 16x16 + obs_property_set_long_description(p, TEXT_T(AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT_DESCRIPTION)); + #pragma endregion Intra Refresh + + /// Wait For Task + p = obs_properties_add_list(props, AMF_H264_WAITFORTASK, TEXT_T(AMF_H264_WAITFORTASK), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_WAITFORTASK_DESCRIPTION)); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); + + /// Preanalysis Pass + p = obs_properties_add_list(props, AMF_H264_PREANALYSISPASS, TEXT_T(AMF_H264_PREANALYSISPASS), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_PREANALYSISPASS_DESCRIPTION)); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); + + /// VBAQ + p = obs_properties_add_list(props, AMF_H264_VBAQ, TEXT_T(AMF_H264_VBAQ), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_VBAQ_DESCRIPTION)); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); + + /// GOP Size + p = obs_properties_add_int(props, AMF_H264_GOPSIZE, TEXT_T(AMF_H264_GOPSIZE), 0, INT_MAX, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_GOPSIZE_DESCRIPTION)); + + /// GOP Alignment + p = obs_properties_add_list(props, AMF_H264_GOPALIGNMENT, TEXT_T(AMF_H264_GOPALIGNMENT), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_GOPALIGNMENT_DESCRIPTION)); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); + obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); + + /// GOP Size + p = obs_properties_add_int_slider(props, AMF_H264_MAXIMUMREFERENCEFRAMES, TEXT_T(AMF_H264_MAXIMUMREFERENCEFRAMES), 1, 1, 1); + obs_property_set_long_description(p, TEXT_T(AMF_H264_MAXIMUMREFERENCEFRAMES_DESCRIPTION)); + + #pragma endregion Experimental Properties + #pragma region System Properties - //p = obs_properties_add_bool(props, "sys_delimiter", "------ System Properties ------"); - #pragma region Device Selection - p = obs_properties_add_list(props, AMF_H264_DEVICE, TEXT_T(AMF_H264_DEVICE), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); - fill_device_list(p); - obs_property_set_long_description(p, TEXT_T(AMF_H264_DEVICE_DESCRIPTION)); + /// Video API + p = obs_properties_add_list(props, AMF_H264_VIDEOAPI, TEXT_T(AMF_H264_VIDEOAPI), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); + obs_property_set_long_description(p, TEXT_T(AMF_H264_VIDEOAPI_DESCRIPTION)); + obs_property_set_modified_callback(p, properties_modified); + fill_api_list(p); + + /// Video Adapter + p = obs_properties_add_list(props, AMF_H264_VIDEOADAPTER, TEXT_T(AMF_H264_VIDEOADAPTER), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_VIDEOADAPTER_DESCRIPTION)); obs_property_set_modified_callback(p, properties_modified); - #pragma endregion Device Selection - /// Compute Type - p = obs_properties_add_list(props, AMF_H264_USE_OPENCL, TEXT_T(AMF_H264_USE_OPENCL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); - obs_property_set_long_description(p, TEXT_T(AMF_H264_USE_OPENCL_DESCRIPTION)); + /// OpenCL + p = obs_properties_add_list(props, AMF_H264_OPENCL, TEXT_T(AMF_H264_OPENCL), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, TEXT_T(AMF_H264_OPENCL_DESCRIPTION)); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_DISABLED), 0); obs_property_list_add_int(p, TEXT_T(AMF_UTIL_TOGGLE_ENABLED), 1); @@ -438,10 +542,6 @@ obs_property_list_add_int(p, TEXT_T(AMF_H264_VIEW_EXPERT), ViewMode::Expert); obs_property_list_add_int(p, TEXT_T(AMF_H264_VIEW_MASTER), ViewMode::Master); obs_property_set_modified_callback(p, properties_modified); - /// Unlock Properties to full range. - p = obs_properties_add_bool(props, AMF_H264_UNLOCK_PROPERTIES, TEXT_T(AMF_H264_UNLOCK_PROPERTIES)); - obs_property_set_long_description(p, TEXT_T(AMF_H264_UNLOCK_PROPERTIES_DESCRIPTION)); - obs_property_set_modified_callback(p, properties_modified); /// Debug p = obs_properties_add_bool(props, AMF_H264_DEBUG, TEXT_T(AMF_H264_DEBUG)); @@ -499,20 +599,18 @@ obs_property_t* p; #pragma region Presets - Presets preset = (Presets)obs_data_get_int(data, AMF_H264_PRESET); - { // Reset State + Presets lastPreset = (Presets)obs_data_get_int(data, "last" vstr(AMF_H264_PRESET)), + preset = (Presets)obs_data_get_int(data, AMF_H264_PRESET); + if (lastPreset != preset) { // Reset State obs_property_t* pn = obs_properties_first(props); do { obs_property_set_enabled(pn, true); } while (obs_property_next(&pn)); - if (preset != Presets::None) { - // System Properties - obs_data_set_bool(data, AMF_H264_UNLOCK_PROPERTIES, false); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_UNLOCK_PROPERTIES), false); - result = true; - } + result = true; } + if (preset != Presets::None) + result = true; switch (preset) { case ResetToDefaults: @@ -521,6 +619,11 @@ obs_property_t* pn = obs_properties_first(props); do { const char* name = obs_property_name(pn); + + // Do not reset Video Adapter or API. + if ((strcmp(name, AMF_H264_VIDEOAPI) == 0) || (strcmp(name, AMF_H264_VIDEOADAPTER) == 0)) + continue; + switch (obs_property_get_type(pn)) { case obs_property_type::OBS_PROPERTY_BOOL: obs_data_set_bool(data, name, obs_data_get_default_bool(data, name)); @@ -577,10 +680,10 @@ /*obs_data_set_int(data, AMF_H264_QP_IFRAME, 0); obs_data_set_int(data, AMF_H264_QP_PFRAME, 0); obs_data_set_int(data, AMF_H264_QP_BFRAME, 0);*/ - obs_data_set_int(data, AMF_H264_QP_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), false); - obs_data_set_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), false); + obs_data_set_int(data, AMF_H264_BFRAME_DELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), false); //obs_data_set_int(data, AMF_H264_VBVBUFFER, 0); //obs_property_set_enabled(obs_properties_get(props, AMF_H264_VBVBUFFER), false); //obs_data_set_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 0); @@ -593,13 +696,13 @@ //obs_data_set_int(data, AMF_H264_FRAMESKIPPING, 0); //obs_data_set_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); - // Picture Control Properties + // Frame Control Properties obs_data_set_double(data, AMF_H264_KEYFRAME_INTERVAL, 1); obs_property_set_enabled(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), false); //obs_data_set_int(data, AMF_H264_IDR_PERIOD, 60); //obs_data_set_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_PATTERN, obs_data_get_default_int(data, AMF_H264_BPICTURE_PATTERN)); - //obs_data_set_int(data, AMF_H264_BPICTURE_REFERENCE, obs_data_get_default_int(data, AMF_H264_BPICTURE_REFERENCE)); + //obs_data_set_int(data, AMF_H264_BFrame_PATTERN, obs_data_get_default_int(data, AMF_H264_BFrame_PATTERN)); + //obs_data_set_int(data, AMF_H264_BFrame_REFERENCE, obs_data_get_default_int(data, AMF_H264_BFrame_REFERENCE)); //obs_data_set_int(data, AMF_H264_SLICESPERFRAME, 0); //obs_data_set_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); @@ -635,10 +738,10 @@ obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_PFRAME), false); obs_data_set_int(data, AMF_H264_QP_BFRAME, 22); obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BFRAME), false); - obs_data_set_int(data, AMF_H264_QP_BPICTURE_DELTA, -2); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), false); - obs_data_set_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, -2); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), false); + obs_data_set_int(data, AMF_H264_BFRAME_DELTAQP, -2); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, -2); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), false); //obs_data_set_int(data, AMF_H264_VBVBUFFER, 0); //obs_property_set_enabled(obs_properties_get(props, AMF_H264_VBVBUFFER), false); //obs_data_set_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 0); @@ -650,13 +753,13 @@ //obs_data_set_int(data, AMF_H264_FRAMESKIPPING, 0); //obs_data_set_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); - // Picture Control Properties + // Frame Control Properties obs_data_set_double(data, AMF_H264_KEYFRAME_INTERVAL, 1); obs_property_set_enabled(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), false); //obs_data_set_int(data, AMF_H264_IDR_PERIOD, 60); //obs_data_set_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_PATTERN, obs_data_get_default_int(data, AMF_H264_BPICTURE_PATTERN)); - //obs_data_set_int(data, AMF_H264_BPICTURE_REFERENCE, obs_data_get_default_int(data, AMF_H264_BPICTURE_REFERENCE)); + //obs_data_set_int(data, AMF_H264_BFrame_PATTERN, obs_data_get_default_int(data, AMF_H264_BFrame_PATTERN)); + //obs_data_set_int(data, AMF_H264_BFrame_REFERENCE, obs_data_get_default_int(data, AMF_H264_BFrame_REFERENCE)); //obs_data_set_int(data, AMF_H264_SLICESPERFRAME, 0); //obs_data_set_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); @@ -692,10 +795,10 @@ obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_PFRAME), false); obs_data_set_int(data, AMF_H264_QP_BFRAME, 17); obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BFRAME), false); - obs_data_set_int(data, AMF_H264_QP_BPICTURE_DELTA, -2); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), false); - obs_data_set_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, -2); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), false); + obs_data_set_int(data, AMF_H264_BFRAME_DELTAQP, -2); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, -2); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), false); //obs_data_set_int(data, AMF_H264_VBVBUFFER, 0); //obs_property_set_enabled(obs_properties_get(props, AMF_H264_VBVBUFFER), false); //obs_data_set_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 0); @@ -707,13 +810,13 @@ //obs_data_set_int(data, AMF_H264_FRAMESKIPPING, 0); //obs_data_set_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); - // Picture Control Properties + // Frame Control Properties obs_data_set_double(data, AMF_H264_KEYFRAME_INTERVAL, 1); obs_property_set_enabled(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), false); //obs_data_set_int(data, AMF_H264_IDR_PERIOD, 60); //obs_data_set_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_PATTERN, obs_data_get_default_int(data, AMF_H264_BPICTURE_PATTERN)); - //obs_data_set_int(data, AMF_H264_BPICTURE_REFERENCE, obs_data_get_default_int(data, AMF_H264_BPICTURE_REFERENCE)); + //obs_data_set_int(data, AMF_H264_BFRAME_PATTERN, obs_data_get_default_int(data, AMF_H264_BFRAME_PATTERN)); + //obs_data_set_int(data, AMF_H264_BFRAME_REFERENCE, obs_data_get_default_int(data, AMF_H264_BFRAME_REFERENCE)); //obs_data_set_int(data, AMF_H264_SLICESPERFRAME, 0); //obs_data_set_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); @@ -749,10 +852,10 @@ obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_PFRAME), false); obs_data_set_int(data, AMF_H264_QP_BFRAME, 0); obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BFRAME), false); - obs_data_set_int(data, AMF_H264_QP_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), false); - obs_data_set_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), false); + obs_data_set_int(data, AMF_H264_BFRAME_DELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), false); //obs_data_set_int(data, AMF_H264_VBVBUFFER, 0); //obs_property_set_enabled(obs_properties_get(props, AMF_H264_VBVBUFFER), false); //obs_data_set_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 0); @@ -764,16 +867,16 @@ //obs_data_set_int(data, AMF_H264_FRAMESKIPPING, 0); //obs_data_set_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); - // Picture Control Properties + // Frame Control Properties obs_data_set_double(data, AMF_H264_KEYFRAME_INTERVAL, 1); obs_property_set_enabled(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), false); obs_data_set_int(data, AMF_H264_IDR_PERIOD, 30); obs_property_set_enabled(obs_properties_get(props, AMF_H264_IDR_PERIOD), false); //obs_data_set_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - obs_data_set_int(data, AMF_H264_BPICTURE_PATTERN, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_BPICTURE_PATTERN), false); - obs_data_set_int(data, AMF_H264_BPICTURE_REFERENCE, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_BPICTURE_REFERENCE), false); + obs_data_set_int(data, AMF_H264_BFRAME_PATTERN, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_PATTERN), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCE, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCE), false); //obs_data_set_int(data, AMF_H264_SLICESPERFRAME, 0); //obs_data_set_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); @@ -813,10 +916,10 @@ /*obs_data_set_int(data, AMF_H264_QP_IFRAME, 0); obs_data_set_int(data, AMF_H264_QP_PFRAME, 0); obs_data_set_int(data, AMF_H264_QP_BFRAME, 0);*/ - obs_data_set_int(data, AMF_H264_QP_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), false); - obs_data_set_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), false); + obs_data_set_int(data, AMF_H264_BFRAME_DELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), false); //obs_data_set_int(data, AMF_H264_VBVBUFFER, 0); //obs_property_set_enabled(obs_properties_get(props, AMF_H264_VBVBUFFER), false); //obs_data_set_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 80); @@ -829,13 +932,13 @@ //obs_data_set_int(data, AMF_H264_FRAMESKIPPING, 0); //obs_data_set_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); - // Picture Control Properties + // Frame Control Properties obs_data_set_double(data, AMF_H264_KEYFRAME_INTERVAL, 2); obs_property_set_enabled(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), false); //obs_data_set_int(data, AMF_H264_IDR_PERIOD, 120); //obs_data_set_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_PATTERN, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_REFERENCE, 0); + //obs_data_set_int(data, AMF_H264_BFRAME_PATTERN, 0); + //obs_data_set_int(data, AMF_H264_BFRAME_REFERENCE, 0); //obs_data_set_int(data, AMF_H264_SLICESPERFRAME, 0); //obs_data_set_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); @@ -874,10 +977,10 @@ /*obs_data_set_int(data, AMF_H264_QP_IFRAME, 0); obs_data_set_int(data, AMF_H264_QP_PFRAME, 0); obs_data_set_int(data, AMF_H264_QP_BFRAME, 0);*/ - obs_data_set_int(data, AMF_H264_QP_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), false); - obs_data_set_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA, 0); - obs_property_set_enabled(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), false); + obs_data_set_int(data, AMF_H264_BFRAME_DELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), false); + obs_data_set_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP, 0); + obs_property_set_enabled(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), false); //obs_data_set_int(data, AMF_H264_VBVBUFFER, 0); //obs_property_set_enabled(obs_properties_get(props, AMF_H264_VBVBUFFER), false); //obs_data_set_double(data, AMF_H264_VBVBUFFER_STRICTNESS, 80); @@ -890,13 +993,13 @@ //obs_data_set_int(data, AMF_H264_FRAMESKIPPING, 0); //obs_data_set_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY, 0); - // Picture Control Properties + // Frame Control Properties obs_data_set_double(data, AMF_H264_KEYFRAME_INTERVAL, 2); obs_property_set_enabled(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), false); //obs_data_set_int(data, AMF_H264_IDR_PERIOD, 120); //obs_data_set_int(data, AMF_H264_HEADER_INSERTION_SPACING, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_PATTERN, 0); - //obs_data_set_int(data, AMF_H264_BPICTURE_REFERENCE, 0); + //obs_data_set_int(data, AMF_H264_BFRAME_PATTERN, 0); + //obs_data_set_int(data, AMF_H264_BFRAME_REFERENCE, 0); //obs_data_set_int(data, AMF_H264_SLICESPERFRAME, 0); //obs_data_set_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT, 0); @@ -912,19 +1015,40 @@ } #pragma endregion Presets - #pragma region Device Capabilities - const char* deviceId = obs_data_get_string(data, AMF_H264_DEVICE); - auto device = Plugin::API::APIBase::GetDeviceForUniqueId(deviceId); - auto caps = Plugin::AMD::VCECapabilities::GetInstance(); - auto devCaps = caps->GetDeviceCaps(device, VCEEncoderType_AVC); - #pragma endregion Device Capabilities + #pragma region Video API + const char *lastVideoAPI = obs_data_get_string(data, "last" vstr(AMF_H264_VIDEOAPI)), + *curVideoAPI = obs_data_get_string(data, AMF_H264_VIDEOAPI); + if (strcmp(curVideoAPI, "") == 0) { + p = obs_properties_get(props, AMF_H264_VIDEOAPI); + //fill_api_list(p); + + obs_data_set_string(data, AMF_H264_VIDEOAPI, + obs_property_list_item_string(p, 0)); + curVideoAPI = obs_data_get_string(data, AMF_H264_VIDEOAPI); + } + if ((strcmp(lastVideoAPI, curVideoAPI) != 0) + || (strcmp(curVideoAPI, "") == 0)) { + obs_data_set_string(data, "last" vstr(AMF_H264_VIDEOAPI), curVideoAPI); + fill_device_list(obs_properties_get(props, AMF_H264_VIDEOADAPTER), curVideoAPI); + + // Reset Video Adapter to first in list. + obs_data_set_int(data, AMF_H264_VIDEOADAPTER, + obs_property_list_item_int(obs_properties_get(props, AMF_H264_VIDEOADAPTER), 0)); + } + #pragma endregion Video API + + #pragma region Video Adapter & Capabilities + VCEDeviceCapabilities devCaps; + int64_t lastAdapterId = obs_data_get_int(data, "last" vstr(AMF_H264_VIDEOADAPTER)), + curAdapterId = obs_data_get_int(data, AMF_H264_VIDEOADAPTER); + { + auto api = Plugin::API::Base::GetAPIByName(obs_data_get_string(data, AMF_H264_VIDEOAPI)); + auto adapter = api->GetAdapterById(curAdapterId & UINT_MAX, (curAdapterId >> 32) & UINT_MAX); + devCaps = Plugin::AMD::VCECapabilities::GetInstance()->GetAdapterCapabilities(api, adapter, VCEEncoderType_AVC); + } + if (lastAdapterId != curAdapterId) { + obs_data_set_int(data, "last" vstr(AMF_H264_VIDEOADAPTER), curAdapterId); - #pragma region Rebuild UI - bool unlocked = obs_data_get_bool(data, AMF_H264_UNLOCK_PROPERTIES); - bool lastUnlocked = obs_data_get_bool(data, "last" vstr(AMF_H264_UNLOCK_PROPERTIES)); - const char* lastDeviceId = obs_data_get_string(data, "last" vstr(AMF_H264_DEVICE)); - if (strcmp(lastDeviceId, deviceId) != 0 || (unlocked != lastUnlocked)) { - #pragma region Static Properties #pragma region Profile p = obs_properties_get(props, AMF_H264_PROFILE); obs_property_list_clear(p); @@ -940,6 +1064,7 @@ break; } #pragma endregion Profile + #pragma region Profile Level p = obs_properties_get(props, AMF_H264_PROFILELEVEL); obs_property_list_clear(p); @@ -986,70 +1111,44 @@ obs_property_list_add_int(p, "1.0", VCEProfileLevel_10); } #pragma endregion Profile Level - #pragma endregion Static Properties - - #pragma region Unlockable Stuff - // Store values. - uint64_t bitrateTarget = obs_data_get_int(data, AMF_H264_BITRATE_TARGET), - bitratePeak = obs_data_get_int(data, AMF_H264_BITRATE_PEAK), - vbvBufferSize = obs_data_get_int(data, AMF_H264_VBVBUFFER_SIZE); - // Set proper limits - uint32_t limitDivisor = unlocked ? 1 : 1000; obs_property_int_set_limits(obs_properties_get(props, AMF_H264_BITRATE_TARGET), - 10000 / limitDivisor, - devCaps.maxBitrate / limitDivisor, - 1); + 10, devCaps.maxBitrate / 1000, 1); obs_property_int_set_limits(obs_properties_get(props, AMF_H264_BITRATE_PEAK), - 10000 / limitDivisor, - devCaps.maxBitrate / limitDivisor, - 1); + 10, devCaps.maxBitrate / 1000, 1); obs_property_int_set_limits(obs_properties_get(props, AMF_H264_VBVBUFFER_SIZE), - 1000 / limitDivisor, - 100000000 / limitDivisor, - 1); + 1, 100000, 1); obs_property_float_set_limits(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), - unlocked ? 0 : 1, - 100, - 1); + 1.0 / 144.0, 30, 1.0 / 144.0); obs_property_int_set_limits(obs_properties_get(props, AMF_H264_IDR_PERIOD), - unlocked ? 0 : 1, - 1000, - 1); - - // Restore values. - uint64_t valDivisor = (lastUnlocked && !unlocked ? 1000 : 1); - uint64_t valMultiplier = (unlocked && !lastUnlocked ? 1000 : 1); + 1, 1000, 1); - obs_data_set_int(data, AMF_H264_BITRATE_TARGET, (bitrateTarget * valMultiplier) / valDivisor); - obs_data_set_int(data, AMF_H264_BITRATE_PEAK, (bitratePeak * valMultiplier) / valDivisor); - obs_data_set_int(data, AMF_H264_VBVBUFFER_SIZE, (vbvBufferSize * valMultiplier) / valDivisor); - #pragma endregion Unlockable Stuff - - obs_data_set_bool(data, "last" vstr(AMF_H264_UNLOCK_PROPERTIES), unlocked); - obs_data_set_string(data, "last" vstr(AMF_H264_DEVICE), deviceId); - result = true; + // Experimental + obs_property_int_set_limits(obs_properties_get(props, AMF_H264_MAXIMUMREFERENCEFRAMES), + devCaps.minReferenceFrames, devCaps.maxReferenceFrames, 1); } - #pragma endregion Rebuild UI + #pragma endregion Video Adapter #pragma region View Mode - uint32_t view = (uint32_t)obs_data_get_int(data, AMF_H264_VIEW); - bool vis_basic = view >= ViewMode::Basic, - vis_advanced = view >= ViewMode::Advanced, - vis_expert = view >= ViewMode::Expert, - vis_master = view >= ViewMode::Master; - - uint32_t lastView = (uint32_t)obs_data_get_int(data, "last" vstr(AMF_H264_VIEW)); - if (lastView != view) { - obs_data_set_int(data, "last" vstr(AMF_H264_VIEW), view); + uint32_t lastView = (uint32_t)obs_data_get_int(data, "last" vstr(AMF_H264_VIEW)), + curView = (uint32_t)obs_data_get_int(data, AMF_H264_VIEW); + if (lastView != curView) { + obs_data_set_int(data, "last" vstr(AMF_H264_VIEW), curView); result = true; } + bool vis_basic = curView >= ViewMode::Basic, + vis_advanced = curView >= ViewMode::Advanced, + vis_expert = curView >= ViewMode::Expert, + vis_master = curView >= ViewMode::Master; + #pragma region Basic const char* basicProps[] = { + AMF_H264_PRESET, AMF_H264_QUALITY_PRESET, AMF_H264_PROFILE, AMF_H264_RATECONTROLMETHOD, + AMF_H264_VIEW, AMF_H264_DEBUG, }; for (auto prop : basicProps) { @@ -1063,8 +1162,9 @@ const char* advancedProps[] = { AMF_H264_VBVBUFFER, AMF_H264_FRAMESKIPPING, + AMF_H264_ENFORCEHRDCOMPATIBILITY, AMF_H264_DEBLOCKINGFILTER, - AMF_H264_DEVICE, + AMF_H264_VIDEOAPI, }; for (auto prop : advancedProps) { obs_property_set_visible(obs_properties_get(props, prop), vis_advanced); @@ -1076,11 +1176,8 @@ #pragma region Expert const char* expertProps[] = { AMF_H264_PROFILELEVEL, - AMF_H264_CODINGTYPE, AMF_H264_VBVBUFFER_FULLNESS, - AMF_H264_ENFORCEHRDCOMPATIBILITY, AMF_H264_MOTIONESTIMATION, - AMF_H264_USE_OPENCL, }; for (auto prop : expertProps) { obs_property_set_visible(obs_properties_get(props, prop), vis_expert); @@ -1092,14 +1189,25 @@ #pragma region Master const char* masterProps[] = { AMF_H264_USAGE, - AMF_H264_MAXIMUMLTRFRAMES, AMF_H264_MAXIMUMACCESSUNITSIZE, AMF_H264_IDR_PERIOD, AMF_H264_HEADER_INSERTION_SPACING, - AMF_H264_SLICESPERFRAME, - AMF_H264_INTRAREFRESHNUMMBSPERSLOT, AMF_H264_SCANTYPE, - AMF_H264_UNLOCK_PROPERTIES, + AMF_H264_MAXIMUMLTRFRAMES, + AMF_H264_CODINGTYPE, + AMF_H264_SLICESPERFRAME, + AMF_H264_SLICEMODE, + AMF_H264_MAXIMUMSLICESIZE, + AMF_H264_SLICECONTROLMODE, + AMF_H264_SLICECONTROLSIZE, + AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES, + AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT, + AMF_H264_WAITFORTASK, + AMF_H264_PREANALYSISPASS, + AMF_H264_VBAQ, + AMF_H264_GOPSIZE, + AMF_H264_GOPALIGNMENT, + AMF_H264_MAXIMUMREFERENCEFRAMES, }; for (auto prop : masterProps) { obs_property_set_visible(obs_properties_get(props, prop), vis_master); @@ -1112,11 +1220,43 @@ uint32_t ltrFrames = (uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMLTRFRAMES); bool usingLTRFrames = ltrFrames > 0; - // Keyframe Interval + // Key-frame Interval obs_property_set_visible(obs_properties_get(props, AMF_H264_KEYFRAME_INTERVAL), !vis_master); if (vis_master) obs_data_default_single(props, data, AMF_H264_KEYFRAME_INTERVAL); + #pragma region B-Frames + /// Pattern + obs_property_set_visible(obs_properties_get(props, AMF_H264_BFRAME_PATTERN), vis_advanced && !usingLTRFrames && devCaps.supportsBFrames); + if (!vis_advanced || usingLTRFrames || !devCaps.supportsBFrames) + obs_data_default_single(props, data, AMF_H264_BFRAME_PATTERN); + bool lastUsingBFrames = obs_data_get_int(data, "last" vstr(AMF_H264_BFRAME_PATTERN)) != 0, + usingBFrames = obs_data_get_int(data, AMF_H264_BFRAME_PATTERN) != 0; + if (usingBFrames != lastUsingBFrames) { + obs_data_set_int(data, "last" vstr(AMF_H264_BFRAME_PATTERN), obs_data_get_int(data, AMF_H264_BFRAME_PATTERN)); + result = true; + } + + /// Reference + obs_property_set_visible(obs_properties_get(props, AMF_H264_BFRAME_REFERENCE), vis_advanced && !usingLTRFrames && usingBFrames && devCaps.supportsBFrames); + if (!vis_advanced || usingLTRFrames || !usingBFrames || !devCaps.supportsBFrames) + obs_data_default_single(props, data, AMF_H264_BFRAME_REFERENCE); + bool lastUsingBFrameReference = obs_data_get_int(data, "last" vstr(AMF_H264_BFRAME_REFERENCE)) != 0, + usingBFrameReference = obs_data_get_int(data, AMF_H264_BFRAME_REFERENCE) == 1; + if (usingBFrameReference != lastUsingBFrameReference) { + obs_data_set_int(data, "last" vstr(AMF_H264_BFRAME_REFERENCE), obs_data_get_int(data, AMF_H264_BFRAME_REFERENCE)); + result = true; + } + + /// QP Delta + obs_property_set_visible(obs_properties_get(props, AMF_H264_BFRAME_DELTAQP), vis_advanced && usingBFrames && devCaps.supportsBFrames); + if (!vis_advanced || !usingBFrames || !devCaps.supportsBFrames) + obs_data_default_single(props, data, AMF_H264_BFRAME_DELTAQP); + obs_property_set_visible(obs_properties_get(props, AMF_H264_BFRAME_REFERENCEDELTAQP), vis_advanced && usingBFrames && usingBFrameReference && devCaps.supportsBFrames); + if (!vis_advanced || !usingBFrames || !usingBFrameReference || !devCaps.supportsBFrames) + obs_data_default_single(props, data, AMF_H264_BFRAME_REFERENCEDELTAQP); + #pragma endregion B-Frames + #pragma region Rate Control bool vis_rcm_bitrate_target = false, vis_rcm_bitrate_peak = false, @@ -1124,8 +1264,13 @@ vis_rcm_qp_b = false, vis_rcm_fillerdata = false; - VCERateControlMethod rcm = (VCERateControlMethod)obs_data_get_int(data, AMF_H264_RATECONTROLMETHOD); - switch (rcm) { + VCERateControlMethod lastRCM = (VCERateControlMethod)obs_data_get_int(data, "last" vstr(AMF_H264_RATECONTROLMETHOD)), + curRCM = (VCERateControlMethod)obs_data_get_int(data, AMF_H264_RATECONTROLMETHOD); + if (lastRCM != curRCM) { + obs_data_set_int(data, "last" vstr(AMF_H264_RATECONTROLMETHOD), curRCM); + result = true; + } + switch (curRCM) { case VCERateControlMethod_ConstantBitrate: vis_rcm_bitrate_target = true; vis_rcm_fillerdata = true; @@ -1140,16 +1285,10 @@ break; case VCERateControlMethod_ConstantQP: vis_rcm_qp = true; - vis_rcm_qp_b = (!usingLTRFrames) && devCaps.supportsBFrames; + vis_rcm_qp_b = (!usingLTRFrames) && devCaps.supportsBFrames && usingBFrames; break; } - VCERateControlMethod lastRCM = (VCERateControlMethod)obs_data_get_int(data, "last" vstr(AMF_H264_RATECONTROLMETHOD)); - if (lastRCM != rcm) { - obs_data_set_int(data, "last" vstr(AMF_H264_RATECONTROLMETHOD), rcm); - result = true; - } - /// Bitrate obs_property_set_visible(obs_properties_get(props, AMF_H264_BITRATE_TARGET), vis_rcm_bitrate_target); if (!vis_rcm_bitrate_target) @@ -1182,6 +1321,7 @@ if (!vis_rcm_fillerdata) obs_data_default_single(props, data, AMF_H264_FILLERDATA); #pragma endregion Rate Control + #pragma region VBV Buffer uint32_t vbvBufferMode = (uint32_t)obs_data_get_int(data, AMF_H264_VBVBUFFER); bool vbvBufferVisible = vis_advanced; @@ -1194,47 +1334,22 @@ obs_property_set_visible(obs_properties_get(props, AMF_H264_VBVBUFFER_STRICTNESS), vbvBufferVisible && (vbvBufferMode == 0)); obs_property_set_visible(obs_properties_get(props, AMF_H264_VBVBUFFER_SIZE), vbvBufferVisible && (vbvBufferMode == 1)); - if (!vbvBufferVisible) { - if (vbvBufferMode == 0) { - obs_data_default_single(props, data, AMF_H264_VBVBUFFER_SIZE); - } else if (vbvBufferMode == 1) { - obs_data_default_single(props, data, AMF_H264_VBVBUFFER_STRICTNESS); - } - } + if (!vbvBufferVisible || vbvBufferMode == 0) + obs_data_default_single(props, data, AMF_H264_VBVBUFFER_SIZE); + if (!vbvBufferVisible || vbvBufferMode == 1) + obs_data_default_single(props, data, AMF_H264_VBVBUFFER_STRICTNESS); #pragma endregion VBV Buffer - #pragma region B-Frames - /// Pattern - obs_property_set_visible(obs_properties_get(props, AMF_H264_BPICTURE_PATTERN), vis_advanced && !usingLTRFrames && devCaps.supportsBFrames); - if (!vis_advanced || usingLTRFrames || !devCaps.supportsBFrames) - obs_data_default_single(props, data, AMF_H264_BPICTURE_PATTERN); - bool usingBPictures = obs_data_get_int(data, AMF_H264_BPICTURE_PATTERN) != 0; - bool lastUsingBPictures = obs_data_get_int(data, "last" vstr(AMF_H264_BPICTURE_PATTERN)) != 0; - if (usingBPictures != lastUsingBPictures) { - obs_data_set_int(data, "last" vstr(AMF_H264_BPICTURE_PATTERN), obs_data_get_int(data, AMF_H264_BPICTURE_PATTERN)); - result = true; - } + bool isnothostmode = strcmp(obs_data_get_string(data, AMF_H264_VIDEOAPI), "Host") != 0; + /// Video Adapter + obs_property_set_visible(obs_properties_get(props, AMF_H264_VIDEOADAPTER), vis_advanced && isnothostmode); + if (!vis_advanced || !isnothostmode) + obs_data_default_single(props, data, AMF_H264_VIDEOADAPTER); + /// OpenCL + obs_property_set_visible(obs_properties_get(props, AMF_H264_OPENCL), vis_advanced && isnothostmode); + if (!vis_advanced || !isnothostmode) + obs_data_default_single(props, data, AMF_H264_OPENCL); - /// Reference - obs_property_set_visible(obs_properties_get(props, AMF_H264_BPICTURE_REFERENCE), vis_advanced && !usingLTRFrames && usingBPictures && devCaps.supportsBFrames); - if (!vis_advanced || usingLTRFrames || !usingBPictures || !devCaps.supportsBFrames) - obs_data_default_single(props, data, AMF_H264_BPICTURE_REFERENCE); - bool usingBPictureReference = obs_data_get_int(data, AMF_H264_BPICTURE_REFERENCE) == 1; - - bool lastUsingBPictureReference = obs_data_get_int(data, "last" vstr(AMF_H264_BPICTURE_REFERENCE)) != 0; - if (usingBPictureReference != lastUsingBPictureReference) { - obs_data_set_int(data, "last" vstr(AMF_H264_BPICTURE_REFERENCE), obs_data_get_int(data, AMF_H264_BPICTURE_REFERENCE)); - result = true; - } - - /// QP Delta - obs_property_set_visible(obs_properties_get(props, AMF_H264_QP_BPICTURE_DELTA), vis_advanced && usingBPictures && devCaps.supportsBFrames); - if (!vis_advanced || !usingBPictures || !devCaps.supportsBFrames) - obs_data_default_single(props, data, AMF_H264_QP_BPICTURE_DELTA); - obs_property_set_visible(obs_properties_get(props, AMF_H264_QP_REFERENCE_BPICTURE_DELTA), vis_advanced && usingBPictures && usingBPictureReference && devCaps.supportsBFrames); - if (!vis_advanced || !usingBPictures || !usingBPictureReference || !devCaps.supportsBFrames) - obs_data_default_single(props, data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA); - #pragma endregion B-Frames #pragma endregion Special Logic #pragma endregion View Mode @@ -1307,36 +1422,31 @@ surfFormat = VCEColorFormat_GRAY; break; } - m_VideoEncoder = new VCEEncoder(VCEEncoderType_AVC, - std::string(obs_data_get_string(data, AMF_H264_DEVICE)), - !!obs_data_get_int(data, AMF_H264_USE_OPENCL), - surfFormat); - m_VideoEncoder->SetColorProfile(voi->colorspace == VIDEO_CS_709 ? VCEColorProfile_709 : VCEColorProfile_601); - m_VideoEncoder->SetFullColorRangeEnabled(voi->range == VIDEO_RANGE_FULL); + m_VideoEncoder = new VCEEncoder(VCEEncoderType_AVC, obs_data_get_string(data, AMF_H264_VIDEOAPI), + obs_data_get_int(data, AMF_H264_VIDEOADAPTER), !!obs_data_get_int(data, AMF_H264_OPENCL), surfFormat); /// Static Properties m_VideoEncoder->SetUsage((VCEUsage)obs_data_get_int(data, AMF_H264_USAGE)); m_VideoEncoder->SetQualityPreset((VCEQualityPreset)obs_data_get_int(data, AMF_H264_QUALITY_PRESET)); - /// Framesize & Framerate - m_VideoEncoder->SetFrameSize(m_cfgWidth, m_cfgHeight); + /// Frame + m_VideoEncoder->SetColorProfile(voi->colorspace == VIDEO_CS_709 ? VCEColorProfile_709 : VCEColorProfile_601); + try { m_VideoEncoder->SetFullRangeColorEnabled(voi->range == VIDEO_RANGE_FULL); } catch (...) {} + m_VideoEncoder->SetResolution(m_cfgWidth, m_cfgHeight); m_VideoEncoder->SetFrameRate(m_cfgFPSnum, m_cfgFPSden); + m_VideoEncoder->SetScanType((VCEScanType)obs_data_get_int(data, AMF_H264_SCANTYPE)); /// Progressive or Interlaced /// Profile & Level m_VideoEncoder->SetProfile((VCEProfile)obs_data_get_int(data, AMF_H264_PROFILE)); m_VideoEncoder->SetProfileLevel((VCEProfileLevel)obs_data_get_int(data, AMF_H264_PROFILELEVEL)); - /// LTR Stuff + #pragma region Experimental + /// Long Term Reference if ((uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMLTRFRAMES) > 0) - m_VideoEncoder->SetBPicturePattern(VCEBPicturePattern_None); + m_VideoEncoder->SetBFramePattern(VCEBFramePattern_None); m_VideoEncoder->SetMaximumLongTermReferenceFrames((uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMLTRFRAMES)); - /// Miscellaneous Properties - m_VideoEncoder->SetScanType((VCEScanType)obs_data_get_int(data, AMF_H264_SCANTYPE)); - m_VideoEncoder->SetCodingType((VCECodingType)obs_data_get_int(data, AMF_H264_CODINGTYPE)); - //m_VideoEncoder->SetRateControlPreanalysisEnabled(true); - //m_VideoEncoder->SetWaitForTaskEnabled(true); - //m_VideoEncoder->SetMaximumNumberOfReferenceFrames(VCECapabilities::GetInstance()->GetEncoderCaps(VCEEncoderType_AVC)->maxReferenceFrames); + #pragma endregion Experimental // OBS - Enforce Streaming Service Restrictions #pragma region OBS - Enforce Streaming Service Restrictions @@ -1344,21 +1454,31 @@ // Profile const char* p_str = obs_data_get_string(data, "profile"); if (strcmp(p_str, "") != 0) { - if (strcmp(p_str, "baseline")) { + if (strcmp(p_str, "constrained_baseline")) { + m_VideoEncoder->SetProfile(VCEProfile_ConstrainedBaseline); + } else if (strcmp(p_str, "baseline")) { m_VideoEncoder->SetProfile(VCEProfile_Baseline); } else if (strcmp(p_str, "main")) { m_VideoEncoder->SetProfile(VCEProfile_Main); + } else if (strcmp(p_str, "constrained_high")) { + m_VideoEncoder->SetProfile(VCEProfile_ConstrainedHigh); } else if (strcmp(p_str, "high")) { m_VideoEncoder->SetProfile(VCEProfile_High); } } else { switch (m_VideoEncoder->GetProfile()) { + case VCEProfile_ConstrainedBaseline: + obs_data_set_string(data, "profile", "constrained_baseline"); + break; case VCEProfile_Baseline: obs_data_set_string(data, "profile", "baseline"); break; case VCEProfile_Main: obs_data_set_string(data, "profile", "main"); break; + case VCEProfile_ConstrainedHigh: + obs_data_set_string(data, "profile", "constrained_high"); + break; case VCEProfile_High: obs_data_set_string(data, "profile", "high"); break; @@ -1419,81 +1539,101 @@ bool Plugin::Interface::H264Interface::update(obs_data_t* data) { #pragma region Device Capabilities - const char* deviceId = obs_data_get_string(data, AMF_H264_DEVICE); - auto device = Plugin::API::APIBase::GetDeviceForUniqueId(deviceId); - auto caps = Plugin::AMD::VCECapabilities::GetInstance(); - auto devCaps = caps->GetDeviceCaps(device, VCEEncoderType_AVC); + auto api = Plugin::API::Base::GetAPIByName(obs_data_get_string(data, AMF_H264_VIDEOAPI)); + int64_t adapterId = obs_data_get_int(data, AMF_H264_VIDEOADAPTER); + auto adapter = api->GetAdapterById(adapterId & UINT_MAX, (adapterId >> 32) & UINT_MAX); + auto devCaps = Plugin::AMD::VCECapabilities::GetInstance()->GetAdapterCapabilities(api, adapter, VCEEncoderType_AVC); #pragma endregion Device Capabilities - double_t framerate = (double_t)m_VideoEncoder->GetFrameRate().first / (double_t)m_VideoEncoder->GetFrameRate().second; - int32_t bitrateMultiplier = obs_data_get_bool(data, AMF_H264_UNLOCK_PROPERTIES) ? 1 : 1000; - + #pragma region Rate Control // Rate Control Properties m_VideoEncoder->SetRateControlMethod((VCERateControlMethod)obs_data_get_int(data, AMF_H264_RATECONTROLMETHOD)); m_VideoEncoder->SetMinimumQP((uint8_t)obs_data_get_int(data, AMF_H264_QP_MINIMUM)); m_VideoEncoder->SetMaximumQP((uint8_t)obs_data_get_int(data, AMF_H264_QP_MAXIMUM)); switch ((VCERateControlMethod)obs_data_get_int(data, AMF_H264_RATECONTROLMETHOD)) { case VCERateControlMethod_ConstantBitrate: - m_VideoEncoder->SetTargetBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_TARGET) * bitrateMultiplier); + m_VideoEncoder->SetTargetBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_TARGET) * 1000); m_VideoEncoder->SetPeakBitrate(m_VideoEncoder->GetTargetBitrate()); break; case VCERateControlMethod_VariableBitrate_PeakConstrained: - m_VideoEncoder->SetTargetBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_TARGET) * bitrateMultiplier); - m_VideoEncoder->SetPeakBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_PEAK) * bitrateMultiplier); + m_VideoEncoder->SetTargetBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_TARGET) * 1000); + m_VideoEncoder->SetPeakBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_PEAK) * 1000); break; case VCERateControlMethod_VariableBitrate_LatencyConstrained: - m_VideoEncoder->SetTargetBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_TARGET) * bitrateMultiplier); - m_VideoEncoder->SetPeakBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_PEAK) * bitrateMultiplier); + m_VideoEncoder->SetTargetBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_TARGET) * 1000); + m_VideoEncoder->SetPeakBitrate((uint32_t)obs_data_get_int(data, AMF_H264_BITRATE_PEAK) * 1000); break; case VCERateControlMethod_ConstantQP: m_VideoEncoder->SetIFrameQP((uint8_t)obs_data_get_int(data, AMF_H264_QP_IFRAME)); m_VideoEncoder->SetPFrameQP((uint8_t)obs_data_get_int(data, AMF_H264_QP_PFRAME)); try { m_VideoEncoder->SetBFrameQP((uint8_t)obs_data_get_int(data, AMF_H264_QP_BFRAME)); - } catch (...) {} + } catch (std::exception e) {} catch (...) {} break; } if (obs_data_get_int(data, AMF_H264_VBVBUFFER) == 0) { m_VideoEncoder->SetVBVBufferAutomatic(obs_data_get_double(data, AMF_H264_VBVBUFFER_STRICTNESS) / 100.0); } else { - m_VideoEncoder->SetVBVBufferSize((uint32_t)obs_data_get_int(data, AMF_H264_VBVBUFFER_SIZE) * bitrateMultiplier); + m_VideoEncoder->SetVBVBufferSize((uint32_t)obs_data_get_int(data, AMF_H264_VBVBUFFER_SIZE) * 1000); } m_VideoEncoder->SetInitialVBVBufferFullness(obs_data_get_double(data, AMF_H264_VBVBUFFER_FULLNESS) / 100.0); - m_VideoEncoder->SetEnforceHRDRestrictionsEnabled(obs_data_get_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY) == 1); m_VideoEncoder->SetFillerDataEnabled(obs_data_get_int(data, AMF_H264_FILLERDATA) == 1); m_VideoEncoder->SetFrameSkippingEnabled(obs_data_get_int(data, AMF_H264_FRAMESKIPPING) == 1); - if (obs_data_get_int(data, AMF_H264_MAXIMUMACCESSUNITSIZE) != 0) - m_VideoEncoder->SetMaximumAccessUnitSize((uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMACCESSUNITSIZE)); + m_VideoEncoder->SetEnforceHRDRestrictionsEnabled(obs_data_get_int(data, AMF_H264_ENFORCEHRDCOMPATIBILITY) == 1); + #pragma endregion Rate Control - // Picture Control Properties + // Key-frame Interval + double_t framerate = (double_t)m_VideoEncoder->GetFrameRate().first / (double_t)m_VideoEncoder->GetFrameRate().second; if (obs_data_get_int(data, AMF_H264_VIEW) == ViewMode::Master) m_VideoEncoder->SetIDRPeriod((uint32_t)obs_data_get_int(data, AMF_H264_IDR_PERIOD)); else m_VideoEncoder->SetIDRPeriod(max((uint32_t)(obs_data_get_double(data, AMF_H264_KEYFRAME_INTERVAL) * framerate), 1)); - if (obs_data_get_int(data, AMF_H264_HEADER_INSERTION_SPACING) != 0) - m_VideoEncoder->SetHeaderInsertionSpacing((uint32_t)obs_data_get_int(data, AMF_H264_HEADER_INSERTION_SPACING)); - m_VideoEncoder->SetDeblockingFilterEnabled(!!obs_data_get_int(data, AMF_H264_DEBLOCKINGFILTER)); + + #pragma region B-Frames if (devCaps.supportsBFrames) { try { - m_VideoEncoder->SetBPicturePattern((VCEBPicturePattern)obs_data_get_int(data, AMF_H264_BPICTURE_PATTERN)); - m_VideoEncoder->SetBPictureReferenceEnabled(!!obs_data_get_int(data, AMF_H264_BPICTURE_REFERENCE)); - } catch (...) {} + m_VideoEncoder->SetBFramePattern((VCEBFramePattern)obs_data_get_int(data, AMF_H264_BFRAME_PATTERN)); + m_VideoEncoder->SetBFrameReferenceEnabled(!!obs_data_get_int(data, AMF_H264_BFRAME_REFERENCE)); + } catch (std::exception e) {} catch (...) {} try { - if (m_VideoEncoder->GetBPicturePattern() != VCEBPicturePattern_None) { - m_VideoEncoder->SetBPictureDeltaQP((int8_t)obs_data_get_int(data, AMF_H264_QP_BPICTURE_DELTA)); - if (m_VideoEncoder->IsBPictureReferenceEnabled()) - m_VideoEncoder->SetReferenceBPictureDeltaQP((int8_t)obs_data_get_int(data, AMF_H264_QP_REFERENCE_BPICTURE_DELTA)); + if (m_VideoEncoder->GetBFramePattern() != VCEBFramePattern_None) { + m_VideoEncoder->SetBFrameDeltaQP((int8_t)obs_data_get_int(data, AMF_H264_BFRAME_DELTAQP)); + if (m_VideoEncoder->IsBFrameReferenceEnabled()) + m_VideoEncoder->SetBFrameReferenceDeltaQP((int8_t)obs_data_get_int(data, AMF_H264_BFRAME_REFERENCEDELTAQP)); } - } catch (...) {} + } catch (std::exception e) {} catch (...) {} } - if (obs_data_get_int(data, AMF_H264_SLICESPERFRAME) != 0) - m_VideoEncoder->SetSlicesPerFrame((uint32_t)obs_data_get_int(data, AMF_H264_SLICESPERFRAME)); - if (obs_data_get_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT) != 0) - m_VideoEncoder->SetIntraRefreshMBsNumberPerSlot((uint32_t)obs_data_get_int(data, AMF_H264_INTRAREFRESHNUMMBSPERSLOT)); + #pragma endregion B-Frames + + m_VideoEncoder->SetDeblockingFilterEnabled(!!obs_data_get_int(data, AMF_H264_DEBLOCKINGFILTER)); - // Miscellaneous Properties + #pragma region Motion Estimation m_VideoEncoder->SetHalfPixelMotionEstimationEnabled(!!(obs_data_get_int(data, AMF_H264_MOTIONESTIMATION) & 1)); m_VideoEncoder->SetQuarterPixelMotionEstimationEnabled(!!(obs_data_get_int(data, AMF_H264_MOTIONESTIMATION) & 2)); + #pragma endregion Motion Estimation + + #pragma region Experimental + try { m_VideoEncoder->SetCodingType((VCECodingType)obs_data_get_int(data, AMF_H264_CODINGTYPE)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetWaitForTaskEnabled(!!obs_data_get_int(data, AMF_H264_WAITFORTASK)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetPreAnalysisPassEnabled(!!obs_data_get_int(data, AMF_H264_PREANALYSISPASS)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetVBAQEnabled(!!obs_data_get_int(data, AMF_H264_VBAQ)); } catch (std::exception e) {} catch (...) {} + + try { m_VideoEncoder->SetHeaderInsertionSpacing((uint32_t)obs_data_get_int(data, AMF_H264_HEADER_INSERTION_SPACING)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetMaximumAccessUnitSize((uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMACCESSUNITSIZE)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetMaximumReferenceFrames((uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMREFERENCEFRAMES)); } catch (std::exception e) {} catch (...) {} + + try { m_VideoEncoder->SetGOPSize((uint32_t)obs_data_get_int(data, AMF_H264_GOPSIZE)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetGOPAlignmentEnabled(!!obs_data_get_int(data, AMF_H264_GOPALIGNMENT)); } catch (std::exception e) {} catch (...) {} + + try { m_VideoEncoder->SetIntraRefreshNumberOfStripes((uint32_t)obs_data_get_int(data, AMF_H264_INTRAREFRESH_NUMBEROFSTRIPES)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetIntraRefreshMacroblocksPerSlot((uint32_t)obs_data_get_int(data, AMF_H264_INTRAREFRESH_MACROBLOCKSPERSLOT)); } catch (std::exception e) {} catch (...) {} + + try { m_VideoEncoder->SetSlicesPerFrame((uint32_t)obs_data_get_int(data, AMF_H264_SLICESPERFRAME)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetSliceMode((VCESliceMode)obs_data_get_int(data, AMF_H264_SLICEMODE)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetMaximumSliceSize((uint32_t)obs_data_get_int(data, AMF_H264_MAXIMUMSLICESIZE)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetSliceControlMode((VCESliceControlMode)obs_data_get_int(data, AMF_H264_SLICECONTROLMODE)); } catch (std::exception e) {} catch (...) {} + try { m_VideoEncoder->SetSliceControlSize((uint32_t)obs_data_get_int(data, AMF_H264_SLICECONTROLSIZE)); } catch (std::exception e) {} catch (...) {} + #pragma endregion Experimental if (m_VideoEncoder->IsStarted()) { // OBS - Enforce Streaming Service Stuff @@ -1542,8 +1682,8 @@ obs_data_set_int(data, "bitrate", m_VideoEncoder->GetTargetBitrate() / 1000); - obs_data_set_int(data, AMF_H264_BITRATE_TARGET, m_VideoEncoder->GetTargetBitrate() / bitrateMultiplier); - obs_data_set_int(data, AMF_H264_BITRATE_PEAK, m_VideoEncoder->GetPeakBitrate() / bitrateMultiplier); + obs_data_set_int(data, AMF_H264_BITRATE_TARGET, m_VideoEncoder->GetTargetBitrate() / 1000); + obs_data_set_int(data, AMF_H264_BITRATE_PEAK, m_VideoEncoder->GetPeakBitrate() / 1000); } else { obs_data_set_int(data, "bitrate", m_VideoEncoder->GetTargetBitrate() / 1000); }
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/misc-util.cpp -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/misc-util.cpp
Changed
@@ -29,9 +29,9 @@ // Plugin #include "plugin.h" -#include "amd-amf.h" -#include "amd-amf-vce.h" -#include "amd-amf-vce-capabilities.h" +#include "amf.h" +#include "amf-capabilities.h" +#include "amf-h264.h" ////////////////////////////////////////////////////////////////////////// // Code @@ -82,6 +82,24 @@ return VCEProfileLevel_52; } + #pragma region VCEEncoderType + inline const char* VCEEncoderTypeAsString(VCEEncoderType type) { + const char* types[] = { + "AVC", + "SVC", + "HEVC" + }; + return types[type]; + } + inline const wchar_t* VCEEncoderTypeAsAMF(VCEEncoderType type) { + const wchar_t* types[] = { + AMFVideoEncoderVCE_AVC, + AMFVideoEncoderVCE_SVC, + L"AMFVideoEncoderHW_HEVC" + }; + return types[type]; + } + #pragma endregion VCEEncoderType #pragma region VCEMemoryType inline const char* MemoryTypeAsString(VCEMemoryType memoryType) { static const char* memoryTypeToString[] = { @@ -218,12 +236,35 @@ #pragma endregion VCERateControlMethod inline const char* CodingTypeAsString(VCECodingType type) { - const char* TypeToString[] = { - "Default", - "CABAC", - "CALV", - }; - return TypeToString[type]; + switch (type) { + case VCECodingType_CABAC: + return "CABAC"; + case VCECodingType_CALVC: + return "CALVC"; + case VCECodingType_Default: + return "Default"; + } + return "MEMORY CORRUPTION"; + } + inline const char* SliceModeAsString(VCESliceMode mode) { + switch (mode) { + case VCESliceMode_Horizontal: + return "Horizontal"; + case VCESliceMode_Vertical: + return "Vertical"; + } + return "MEMORY CORRUPTION"; + } + inline const char* SliceControlModeAsString(VCESliceControlMode mode) { + switch (mode) { + case VCESliceControlMode_Off: + return "Off"; + case VCESliceControlMode_Macroblock: + return "Macroblock"; + case VCESliceControlMode_Macroblock_Row: + return "Macroblock Row"; + } + return "MEMORY CORRUPTION"; } } } \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/enc-amf/Source/plugin.cpp -> obs-studio-0.17.0.tar.xz/plugins/enc-amf/Source/plugin.cpp
Changed
@@ -32,8 +32,9 @@ // Plugin #include "plugin.h" -#include "amd-amf.h" -#include "amd-amf-vce-capabilities.h" +#include "api-base.h" +#include "amf.h" +#include "amf-capabilities.h" #include "enc-h264.h" ////////////////////////////////////////////////////////////////////////// @@ -56,25 +57,54 @@ * false to indicate failure and unload the module */ MODULE_EXPORT bool obs_module_load(void) { - try { - AMF_LOG_INFO("Version " PLUGIN_VERSION_TEXT); + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Loading..."); - // Load AMF Runtime - auto instance = Plugin::AMD::AMF::GetInstance(); + // Attempt to load AMF Runtime + try { + Plugin::AMD::AMF::GetInstance(); + } catch (std::exception& e) { + AMF_LOG_ERROR("%s", e.what()); + return true; + } catch (std::exception* e) { + AMF_LOG_ERROR("%s", e->what()); + delete e; + return true; + } catch (...) { + AMF_LOG_ERROR("Unknown Exception."); + return true; + } - // Report AMF Capabilities - //Plugin::AMD::VCECapabilities::ReportCapabilities(); + // Initialize Graphics APIs + try { + Plugin::API::Base::Initialize(); + } catch (std::exception& e) { + AMF_LOG_ERROR("%s", e.what()); + return true; + } catch (std::exception* e) { + AMF_LOG_ERROR("%s", e->what()); + delete e; + return true; + } catch (...) { + AMF_LOG_ERROR("Unknown Exception."); + return true; + } - // Register Encoders + // Register Encoder + try { Plugin::Interface::H264Interface::encoder_register(); } catch (std::exception& e) { - AMF_LOG_ERROR("Uncaught Exception: %s", e.what()); + AMF_LOG_ERROR("%s", e.what()); + return true; } catch (std::exception* e) { - AMF_LOG_ERROR("Uncaught Exception: %s", e->what()); + AMF_LOG_ERROR("%s", e->what()); delete e; + return true; } catch (...) { - AMF_LOG_ERROR("Uncaught Unknown Exception."); + AMF_LOG_ERROR("Unknown Exception."); + return true; } + + AMF_LOG_DEBUG("<" __FUNCTION_NAME__ "> Complete."); return true; }
View file
obs-studio-0.16.6.tar.xz/plugins/image-source/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/image-source/data/locale/tr-TR.ini
Changed
@@ -1,5 +1,14 @@ ImageInput="Görüntü" File="Görüntü Dosyası" -UnloadWhenNotShowing="Resim gösterilmediğinde bellekten kaldır" +UnloadWhenNotShowing="Görüntü gösterilmediğinde bellekten kaldır" +SlideShow="Resim Slayt Gösterisi" +SlideShow.TransitionSpeed="Geçiş Hızı (milisaniye)" +SlideShow.SlideTime="Slaytlar Arası Süre (milisaniye)" +SlideShow.Files="Görüntü Dosyaları" +SlideShow.Transition="Geçiş" +SlideShow.Transition.Cut="Cut" +SlideShow.Transition.Fade="Fade" +SlideShow.Transition.Swipe="Swipe" +SlideShow.Transition.Slide="Slide"
View file
obs-studio-0.16.6.tar.xz/plugins/image-source/image-source.c -> obs-studio-0.17.0.tar.xz/plugins/image-source/image-source.c
Changed
@@ -151,7 +151,6 @@ if (!context->image.texture) return; - gs_reset_blend_state(); gs_effect_set_texture(gs_effect_get_param_by_name(effect, "image"), context->image.texture); gs_draw_sprite(context->image.texture, 0,
View file
obs-studio-0.17.0.tar.xz/plugins/linux-alsa/data/locale/vi-VN.ini
Added
@@ -0,0 +1,3 @@ +AlsaInput="Thiết bị thu âm thanh (ALSA)" +Device="Thiết bị" +
View file
obs-studio-0.17.0.tar.xz/plugins/linux-capture/data/locale/vi-VN.ini
Added
@@ -0,0 +1,16 @@ +X11SharedMemoryScreenInput="Quay màn hỉnh (XSHM)" +Screen="Màn hình" +CaptureCursor="Quay cả con trỏ" +AdvancedSettings="Cài đặt nâng cao" +XServer="X Server" +XCCapture="Quay cửa sổ (Xcomposite)" +Window="Cửa sổ" +CropTop="Cắt bên trên (pixels)" +CropLeft="Cắt bên trái (pixels)" +CropRight="Cắt bên phải (pixels)" +CropBottom="Cắt bên dưới (pixels)" +SwapRedBlue="Đổi đỏ và xanh" +LockX="Khóa X server khi quay" +IncludeXBorder="Bao gồm X Border" +ExcludeAlpha="Dùng texture format không có Alpha (Cách giải quyết với Mesa driver)" +
View file
obs-studio-0.16.6.tar.xz/plugins/mac-avcapture/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/mac-avcapture/data/locale/tr-TR.ini
Changed
@@ -4,6 +4,7 @@ Preset="Ön Tanımlı" Buffering="Arabelleğe Almayı Kullan" FrameRate="Kare hızı" +InputFormat="Giriş biçimi" ColorSpace="Renk alanı" VideoRange="Video aralığı" VideoRange.Partial="Kısmi"
View file
obs-studio-0.16.6.tar.xz/plugins/mac-capture/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/mac-capture/data/locale/nl-NL.ini
Changed
@@ -1,5 +1,5 @@ -CoreAudio.InputCapture="Audioinvoer Capture" -CoreAudio.OutputCapture="Audiouitvoer Capture" +CoreAudio.InputCapture="Audioinvoer Opname" +CoreAudio.OutputCapture="Audiouitvoer Opname" CoreAudio.Device="Apparaat" CoreAudio.Device.Default="Standaardinstellingen" DisplayCapture="Beeldschermcapture"
View file
obs-studio-0.16.6.tar.xz/plugins/mac-vth264/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/mac-vth264/data/locale/tr-TR.ini
Changed
@@ -1,3 +1,6 @@ +VTH264EncHW="Apple VT H264 Donanım Kodlayıcı" +VTH264EncSW="Apple VT H264 Yazılım Kodlayıcı" +VTEncoder="VideoToolbox Kodlayıcı" Bitrate="Bithızı" MaxBitrate="Maks bit hızı" KeyframeIntervalSec="Anahtarkare Aralığı (saniye, 0=otomatik)"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/ar-SA.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/ar-SA.ini
Changed
@@ -3,6 +3,7 @@ Bitrate="معدل النقل" Preset="الإعداد المسبق" + NVENC.Preset.default="الإفتراضي" NVENC.Preset.hq="جودة عالية" NVENC.Preset.hp="أداء عالي" @@ -25,3 +26,4 @@ MediaFileFilter.AudioFiles="ملفات الصوت" MediaFileFilter.AllFiles="كل الملفات" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/bg-BG.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/bg-BG.ini
Changed
@@ -5,3 +5,5 @@ + +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/ca-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/ca-ES.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Interval de fotograma clau (en segons, 0 = automàtic)" Lossless="Sense pèrdues" + NVENC.Use2Pass="Utilitza codificació en dues passades" NVENC.Preset.default="Per defecte" NVENC.Preset.hq="Alta Qualitat" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Arxius d'àudio" MediaFileFilter.AllFiles="Tots els fitxers" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/cs-CZ.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/cs-CZ.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Interval klíč. snímků (vteřiny, 0=auto)" Lossless="Lossless" + NVENC.Use2Pass="Použít dvoustupňové enkódování" NVENC.Preset.default="Výchozí" NVENC.Preset.hq="Vysoká kvalita" @@ -47,3 +48,6 @@ MediaFileFilter.AudioFiles="Zvukové soubory" MediaFileFilter.AllFiles="Všechny soubory" +ReplayBuffer="Záznam do paměti" +ReplayBuffer.Save="Uložit záznam" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/da-DK.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/da-DK.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Keyframe-interval (sekunder, 0= auto)" Lossless="Tabsfri" +BFrames="B-rammer" + NVENC.Use2Pass="Benyt to-trins kodning" NVENC.Preset.default="Standard" NVENC.Preset.hq="Høj kvalitet" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Lydfiler" MediaFileFilter.AllFiles="Alle filer" +ReplayBuffer="Genafspilningsbuffer" +ReplayBuffer.Save="Gem Genafspilning" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/de-DE.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/de-DE.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Keyframeintervall (Sekunden, 0=auto)" Lossless="Verlustfrei" +BFrames="B-frames" + NVENC.Use2Pass="Benutze Two-Pass Encoding" NVENC.Preset.default="Standard" NVENC.Preset.hq="Hohe Qualität" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Audio-Dateien" MediaFileFilter.AllFiles="Alle Dateien" +ReplayBuffer="Replaypuffer" +ReplayBuffer.Save="Replay speichern" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/el-GR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/el-GR.ini
Changed
@@ -2,6 +2,7 @@ FFmpegAAC="FFmpeg προεπιλεγμένος κωδικοποιητής AAC" Bitrate="Ρυθμός μετάδοσης bit" + NVENC.Preset.default="Προεπιλογή" LocalFile="Τοπικό αρχείο" @@ -19,3 +20,4 @@ +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/en-US.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/en-US.ini
Changed
@@ -48,3 +48,6 @@ MediaFileFilter.VideoFiles="Video Files" MediaFileFilter.AudioFiles="Audio Files" MediaFileFilter.AllFiles="All Files" + +ReplayBuffer="Replay Buffer" +ReplayBuffer.Save="Save Replay"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/es-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/es-ES.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Intervalo de keyframes (segundos, 0=auto)" Lossless="Sin pérdidas" +BFrames="B-Frames" + NVENC.Use2Pass="Usar codificación en dos pasadas" NVENC.Preset.default="Por defecto" NVENC.Preset.hq="Alta Calidad" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Archivos de audio" MediaFileFilter.AllFiles="Todos los Archivos" +ReplayBuffer="Búfer de reproducción" +ReplayBuffer.Save="Guardar repetición" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/eu-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/eu-ES.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Gako-fotogramen tartea (segundoak, 0=auto)" Lossless="Galerarik gabe" +BFrames="B-fotogramak" + NVENC.Use2Pass="Erabili bi urratseko kodeketa" NVENC.Preset.default="Lehenetsia" NVENC.Preset.hq="Kalitate handia" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Audio-fitxategiak" MediaFileFilter.AllFiles="Fitxategi guztiak" +ReplayBuffer="Erreprodukzio bufferra" +ReplayBuffer.Save="Gorde erreprodukzioa" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/fi-FI.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/fi-FI.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Keyframe-väli (sekunteina, 0=automaattinen)" Lossless="Häviötön" +BFrames="B-kehykset" + NVENC.Use2Pass="Käytä Two-Pass enkoodausta" NVENC.Preset.default="Oletusarvo" NVENC.Preset.hq="Korkea laatu" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Äänitiedostot" MediaFileFilter.AllFiles="Kaikki tiedostot" +ReplayBuffer="Toistopuskuri" +ReplayBuffer.Save="Tallenna uusinta" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/fr-FR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/fr-FR.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Intervalle d'image-clé (en secondes, 0 = auto)" Lossless="Sans perte" +BFrames="B-frames" + NVENC.Use2Pass="Utiliser l'encodage double passe" NVENC.Preset.default="Défaut" NVENC.Preset.hq="Haute qualité" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Fichiers audio" MediaFileFilter.AllFiles="Tous les fichiers" +ReplayBuffer="Tampon de relecture" +ReplayBuffer.Save="Sauvegarder la relecture" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/gl-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/gl-ES.ini
Changed
@@ -2,6 +2,7 @@ FFmpegAAC="Codificador AAC FFmpeg predefinido" Bitrate="Velocidade de bits" + NVENC.Level="Nivel" FFmpegSource="Fonte multimedia" @@ -24,3 +25,4 @@ +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/he-IL.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/he-IL.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="מרווח ערך ה keyframe בשניות (0=אוטומטי)" Lossless="ללא אובדן נתונים" + NVENC.Use2Pass="השתמש בקידוד שני מעברים" NVENC.Preset.default="ברירת מחדל" NVENC.Preset.hq="איכות גבוהה" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="קבצי אודיו" MediaFileFilter.AllFiles="כל הקבצים" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/hr-HR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/hr-HR.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Interval ključnih frejmova (sekunde, 0=automatski)" Lossless="Bez gubitka" + NVENC.Use2Pass="Koristi enkoding duplog prolaza" NVENC.Preset.default="Podrazumevani" NVENC.Preset.hq="Visoki kvalitet" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Zvučne datoteke" MediaFileFilter.AllFiles="Sve datoteke" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/hu-HU.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/hu-HU.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Kulcsképkocka időköze (másodperc, 0=auto)" Lossless="Veszteségmentes" +BFrames="B képkocka" + NVENC.Use2Pass="Kétmenetes kódolás" NVENC.Preset.default="Alapértelmezett" NVENC.Preset.hq="Kiváló minőség" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Hangfájlok" MediaFileFilter.AllFiles="Minden fájl" +ReplayBuffer="Visszajátszás puffer" +ReplayBuffer.Save="Visszajátszás mentése" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/it-IT.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/it-IT.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Intervallo Keyframe (secondi, 0=automatico)" Lossless="Lossless" + NVENC.Use2Pass="Usa codifica in due passaggi" NVENC.Preset.default="Predefinito" NVENC.Preset.hq="Alta Qualità" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="File audio" MediaFileFilter.AllFiles="Tutti i file" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/ja-JP.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/ja-JP.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="キーフレーム間隔 (秒, 0=自動)" Lossless="無損失" +BFrames="B-フレーム" + NVENC.Use2Pass="2パスエンコードを使用" NVENC.Preset.default="既定" NVENC.Preset.hq="高品質" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="オーディオファイル" MediaFileFilter.AllFiles="すべてのファイル" +ReplayBuffer="リプレイバッファー" +ReplayBuffer.Save="リプレイ保存" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/ko-KR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/ko-KR.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="키프레임 간격 (초 단위, 0=자동)" Lossless="무손실" +BFrames="B-화면" + NVENC.Use2Pass="2 패스 인코딩 사용" NVENC.Preset.default="기본" NVENC.Preset.hq="우수한 품질" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="오디오 파일" MediaFileFilter.AllFiles="모든 파일" +ReplayBuffer="리플레이 버퍼" +ReplayBuffer.Save="리플레이 저장" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/nb-NO.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/nb-NO.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Nøkkelbildeintervall (sekunder, 0 = automatisk)" Lossless="Tapsfri" + NVENC.Use2Pass="Bruk tostegskoding" NVENC.Preset.default="Standard" NVENC.Preset.hq="Høy kvalitet" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Lydfiler" MediaFileFilter.AllFiles="Alle filer" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/nl-NL.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Tijd tussen keyframes (seconden, 0=auto)" Lossless="Lossless" +BFrames="B-frames" + NVENC.Use2Pass="Gebruik two-pass encoding" NVENC.Preset.default="Standaard" NVENC.Preset.hq="Hoge kwaliteit" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Audiobestanden" MediaFileFilter.AllFiles="Alle bestanden" +ReplayBuffer="Replay Buffer" +ReplayBuffer.Save="Replay Opslaan" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/pl-PL.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/pl-PL.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Odstęp między klatkami kluczowymi (sekundy, 0=automatyczny)" Lossless="Bezstratny" +BFrames="B-ramki" + NVENC.Use2Pass="Użyj enkodowania dwuprzebiegowego" NVENC.Preset.default="Domyślny" NVENC.Preset.hq="Wysoka jakość" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Pliki audio" MediaFileFilter.AllFiles="Wszystkie pliki" +ReplayBuffer="Bufor replay" +ReplayBuffer.Save="Zapisz replay" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/pt-BR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/pt-BR.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Intervalo de Keyframe (segundos, 0=auto)" Lossless="Sem perdas" + NVENC.Use2Pass="Utilizar a codificação em dois passos" NVENC.Preset.default="Padrão" NVENC.Preset.hq="Alta Qualidade" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Arquivos de Áudio" MediaFileFilter.AllFiles="Todos os Arquivos" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/pt-PT.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/pt-PT.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Intervalo do keyframe (segundos, 0=automático)" Lossless="Sem perdas" + NVENC.Preset.default="Predefinido" NVENC.Preset.hq="Alta Qualidade" NVENC.Preset.hp="Alto Desempenho" @@ -46,3 +47,4 @@ MediaFileFilter.AudioFiles="Arquivos de Áudio" MediaFileFilter.AllFiles="Todos os ficheiros" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/ro-RO.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/ro-RO.ini
Changed
@@ -3,6 +3,7 @@ Bitrate="Rată de biți" Preset="Presetare" + NVENC.Preset.default="Implicită" NVENC.Preset.bd="Bluray" NVENC.Level="Nivel" @@ -38,3 +39,4 @@ MediaFileFilter.AudioFiles="Fișiere audio" MediaFileFilter.AllFiles="Toate fișierele" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/ru-RU.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/ru-RU.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Интервал ключевых кадров (сек, 0=авто)" Lossless="Без потерь" + NVENC.Use2Pass="Использовать двухпроходное кодирование" NVENC.Preset.default="По умолчанию" NVENC.Preset.hq="Высокое качество" @@ -47,3 +48,5 @@ MediaFileFilter.AudioFiles="Аудиофайлы" MediaFileFilter.AllFiles="Все файлы" +ReplayBuffer.Save="Сохранить повтор" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/sk-SK.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/sk-SK.ini
Changed
@@ -3,9 +3,11 @@ Bitrate="Bitrate" + Looping="Slučka" Advanced="Rozšírené" DiscardNone="Žiadny" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/sl-SI.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/sl-SI.ini
Changed
@@ -3,6 +3,7 @@ Bitrate="Bitrate" + FFmpegSource="Medijski Vir" LocalFile="Lokalna Datoteka" Looping="Ponavljaj" @@ -25,3 +26,4 @@ +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/sr-CS.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/sr-CS.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Interval ključnih frejmova (sekunde, 0=automatski)" Lossless="Bez gubitka" + NVENC.Use2Pass="Koristi enkoding duplog prolaza" NVENC.Preset.default="Podrazumevani" NVENC.Preset.hq="Visoki kvalitet" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Zvučne datoteke" MediaFileFilter.AllFiles="Sve datoteke" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/sr-SP.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/sr-SP.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Интервал кључних фрејмова (секунде, 0=аутоматски)" Lossless="Без губитка" + NVENC.Use2Pass="Користи енкодинг дуплог пролаза" NVENC.Preset.default="Подразумевани" NVENC.Preset.hq="Високи квалитет" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Звучне датотеке" MediaFileFilter.AllFiles="Све датотеке" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/sv-SE.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/sv-SE.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Intervall för keyframes (sekunder, 0=automatisk)" Lossless="Förlustfri" + NVENC.Use2Pass="Använd tvåpassavkodning" NVENC.Preset.default="Standard" NVENC.Preset.hq="Hög kvalitet" @@ -47,3 +48,4 @@ MediaFileFilter.AudioFiles="Ljudfiler" MediaFileFilter.AllFiles="Alla filer" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/th-TH.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/th-TH.ini
Changed
@@ -4,3 +4,5 @@ + +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/tr-TR.ini
Changed
@@ -3,10 +3,17 @@ Bitrate="Bit hızı" Preset="Ön Tanımlı" KeyframeIntervalSec="Anahtarkare Aralığı (saniye, 0=otomatik)" +Lossless="Kayıpsız" + NVENC.Preset.default="Varsayılan" NVENC.Preset.hq="Yüksek Kalite" NVENC.Preset.hp="Yüksek Performans" +NVENC.Preset.bd="Bluray" +NVENC.Preset.ll="Düşük Gecikme" +NVENC.Preset.llhq="Düşük Gecikme Yüksek Kalite" +NVENC.Preset.llhp="Düşük Gecikme Yüksek Performans" +NVENC.Level="Seviye" FFmpegSource="Ortam Kaynağı" LocalFile="Yerel Dosya" @@ -27,6 +34,10 @@ DiscardNonIntra="Intra Olmayan Kareler" DiscardNonKey="Anahtar Olmayan Kareler" DiscardAll="Tüm Kareler (Dikkatli Olun!)" +ColorRange="YUV Renk Aralığı" +ColorRange.Auto="Otomatik" +ColorRange.Partial="Kısmi" +ColorRange.Full="Tam" MediaFileFilter.AllMediaFiles="Tüm Medya Dosyaları" @@ -34,3 +45,5 @@ MediaFileFilter.AudioFiles="Ses Dosyaları" MediaFileFilter.AllFiles="Tüm Dosyalar" +ReplayBuffer="Tekrar Oynatma Arabelleği" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/uk-UA.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/uk-UA.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="Інтервал ключових кадрів (секунд, 0 = авто)" Lossless="Без втрат" +BFrames="B-кадри" + NVENC.Use2Pass="Використовувати двопрохідне кодування" NVENC.Preset.default="Стандартний" NVENC.Preset.hq="Висока якість" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="Аудіо" MediaFileFilter.AllFiles="Всі файли" +ReplayBuffer="Запис Повторів" +ReplayBuffer.Save="Зберегти Повтор" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/vi-VN.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/vi-VN.ini
Changed
@@ -6,6 +6,7 @@ KeyframeIntervalSec="Thời gian đặt Keyframe (giây, 0=tự động)" Lossless="Lossless" + NVENC.Use2Pass="Sử dụng 2-Pass Encoding" NVENC.Preset.default="Mặc định" NVENC.Preset.hq="Chất lượng cao" @@ -23,3 +24,4 @@ +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/zh-CN.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/zh-CN.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="关键帧间隔(秒, 0=自动)" Lossless="无损" +BFrames="B 帧" + NVENC.Use2Pass="使用 Two-Pass 编码" NVENC.Preset.default="默认" NVENC.Preset.hq="高质量" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="音频文件" MediaFileFilter.AllFiles="所有文件" +ReplayBuffer="回放缓存" +ReplayBuffer.Save="保存回放" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/data/locale/zh-TW.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/data/locale/zh-TW.ini
Changed
@@ -6,6 +6,8 @@ KeyframeIntervalSec="關鍵訊框間隔 (秒,0 = 自動)" Lossless="無損" +BFrames="B 訊框" + NVENC.Use2Pass="使用 Two-Pass 編碼" NVENC.Preset.default="預設" NVENC.Preset.hq="高品質" @@ -47,3 +49,6 @@ MediaFileFilter.AudioFiles="音效檔" MediaFileFilter.AllFiles="所有檔案" +ReplayBuffer="重播緩衝" +ReplayBuffer.Save="儲存重播" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-aac.c -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-aac.c
Changed
@@ -259,7 +259,7 @@ obs_properties_t *props = obs_properties_create(); obs_properties_add_int(props, "bitrate", - obs_module_text("Bitrate"), 32, 320, 32); + obs_module_text("Bitrate"), 64, 320, 32); return props; }
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mux.c -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-mux.c
Changed
@@ -16,9 +16,13 @@ ******************************************************************************/ #include <obs-module.h> +#include <obs-hotkey.h> #include <obs-avc.h> #include <util/dstr.h> #include <util/pipe.h> +#include <util/darray.h> +#include <util/platform.h> +#include <util/circlebuf.h> #include <util/threading.h> #include "ffmpeg-mux/ffmpeg-mux.h" @@ -40,17 +44,55 @@ volatile bool active; volatile bool stopping; volatile bool capturing; + + /* replay buffer */ + struct circlebuf packets; + int64_t cur_size; + int64_t cur_time; + int64_t max_size; + int64_t max_time; + int64_t save_ts; + int keyframes; + obs_hotkey_id hotkey; + + DARRAY(struct encoder_packet) mux_packets; + pthread_t mux_thread; + bool mux_thread_joinable; + volatile bool muxing; }; -static const char *ffmpeg_mux_getname(void *unused) +static const char *ffmpeg_mux_getname(void *type) { - UNUSED_PARAMETER(unused); + UNUSED_PARAMETER(type); return obs_module_text("FFmpegMuxer"); } +static inline void replay_buffer_clear(struct ffmpeg_muxer *stream) +{ + while (stream->packets.size > 0) { + struct encoder_packet pkt; + circlebuf_pop_front(&stream->packets, &pkt, sizeof(pkt)); + obs_encoder_packet_release(&pkt); + } + + circlebuf_free(&stream->packets); + stream->cur_size = 0; + stream->cur_time = 0; + stream->max_size = 0; + stream->max_time = 0; + stream->save_ts = 0; + stream->keyframes = 0; +} + static void ffmpeg_mux_destroy(void *data) { struct ffmpeg_muxer *stream = data; + + replay_buffer_clear(stream); + if (stream->mux_thread_joinable) + pthread_join(stream->mux_thread, NULL); + da_free(stream->mux_packets); + os_process_pipe_destroy(stream->pipe); dstr_free(&stream->path); bfree(stream); @@ -177,7 +219,8 @@ dstr_free(&mux); } -static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd) +static void build_command_line(struct ffmpeg_muxer *stream, struct dstr *cmd, + const char *path) { obs_encoder_t *vencoder = obs_output_get_video_encoder(stream->output); obs_encoder_t *aencoders[MAX_AUDIO_MIXES]; @@ -196,7 +239,11 @@ dstr_init_move_array(cmd, obs_module_file(FFMPEG_MUX)); dstr_insert_ch(cmd, 0, '\"'); dstr_cat(cmd, "\" \""); + + dstr_copy(&stream->path, path); + dstr_replace(&stream->path, "\"", "\"\""); dstr_cat_dstr(cmd, &stream->path); + dstr_catf(cmd, "\" %d %d ", vencoder ? 1 : 0, num_tracks); if (vencoder) @@ -213,11 +260,18 @@ add_muxer_params(cmd, stream); } +static inline void start_pipe(struct ffmpeg_muxer *stream, const char *path) +{ + struct dstr cmd; + build_command_line(stream, &cmd, path); + stream->pipe = os_process_pipe_create(cmd.array, "w"); + dstr_free(&cmd); +} + static bool ffmpeg_mux_start(void *data) { struct ffmpeg_muxer *stream = data; obs_data_t *settings; - struct dstr cmd; const char *path; if (!obs_output_can_begin_data_capture(stream->output, 0)) @@ -227,14 +281,9 @@ settings = obs_output_get_settings(stream->output); path = obs_data_get_string(settings, "path"); - dstr_copy(&stream->path, path); - dstr_replace(&stream->path, "\"", "\"\""); + start_pipe(stream, path); obs_data_release(settings); - build_command_line(stream, &cmd); - stream->pipe = os_process_pipe_create(cmd.array, "w"); - dstr_free(&cmd); - if (!stream->pipe) { warn("Failed to create process pipe"); return false; @@ -424,3 +473,330 @@ .encoded_packet = ffmpeg_mux_data, .get_properties = ffmpeg_mux_properties }; + +/* ------------------------------------------------------------------------ */ + +static const char *replay_buffer_getname(void *type) +{ + UNUSED_PARAMETER(type); + return obs_module_text("ReplayBuffer"); +} + +static bool replay_buffer_hotkey(void *data, obs_hotkey_id id, + obs_hotkey_t *hotkey, bool pressed) +{ + struct ffmpeg_muxer *stream = data; + if (os_atomic_load_bool(&stream->active)) + stream->save_ts = os_gettime_ns() / 1000LL; + return true; +} + +static void *replay_buffer_create(obs_data_t *settings, obs_output_t *output) +{ + struct ffmpeg_muxer *stream = bzalloc(sizeof(*stream)); + stream->output = output; + + stream->hotkey = obs_hotkey_register_output(output, + "ReplayBuffer.Save", + obs_module_text("ReplayBuffer.Save"), + replay_buffer_hotkey, stream); + + UNUSED_PARAMETER(settings); + return stream; +} + +static void replay_buffer_destroy(void *data) +{ + struct ffmpeg_muxer *stream = data; + if (stream->hotkey) + obs_hotkey_unregister(stream->hotkey); + ffmpeg_mux_destroy(data); +} + +static bool replay_buffer_start(void *data) +{ + struct ffmpeg_muxer *stream = data; + + if (!obs_output_can_begin_data_capture(stream->output, 0)) + return false; + if (!obs_output_initialize_encoders(stream->output, 0)) + return false; + + obs_data_t *s = obs_output_get_settings(stream->output); + stream->max_time = obs_data_get_int(s, "max_time_sec") * 1000000LL; + stream->max_size = obs_data_get_int(s, "max_size_mb") * (1024 * 1024); + obs_data_release(s); + + os_atomic_set_bool(&stream->active, true); + os_atomic_set_bool(&stream->capturing, true); + obs_output_begin_data_capture(stream->output, 0); + + return true; +} + +static bool purge_front(struct ffmpeg_muxer *stream) +{ + struct encoder_packet pkt; + bool keyframe; + + circlebuf_pop_front(&stream->packets, &pkt, sizeof(pkt)); + + keyframe = pkt.type == OBS_ENCODER_VIDEO && pkt.keyframe; + + if (keyframe) + stream->keyframes--; + + if (!stream->packets.size) { + stream->cur_size = 0; + stream->cur_time = 0; + } else { + struct encoder_packet first; + circlebuf_peek_front(&stream->packets, &first, sizeof(first)); + stream->cur_time = first.dts_usec; + stream->cur_size -= (int64_t)pkt.size; + } + + obs_encoder_packet_release(&pkt); + return keyframe; +} + +static inline void purge(struct ffmpeg_muxer *stream) +{ + if (purge_front(stream)) { + struct encoder_packet pkt; + + for (;;) { + circlebuf_peek_front(&stream->packets, &pkt, + sizeof(pkt)); + if (pkt.type == OBS_ENCODER_VIDEO && pkt.keyframe) + return; + + purge_front(stream); + } + } +} + +static inline void replay_buffer_purge(struct ffmpeg_muxer *stream, + struct encoder_packet *pkt) +{ + if (stream->max_size) { + if (!stream->packets.size || stream->keyframes <= 2) + return; + + while ((stream->cur_size + (int64_t)pkt->size) > + stream->max_size) + purge(stream); + } + + if (!stream->packets.size || stream->keyframes <= 2) + return; + + while ((pkt->dts_usec - stream->cur_time) > stream->max_time) + purge(stream); +} + +static void insert_packet(struct darray *array, struct encoder_packet *packet, + int64_t video_offset, int64_t *audio_offsets, + int64_t video_dts_offset, int64_t *audio_dts_offsets) +{ + struct encoder_packet pkt; + DARRAY(struct encoder_packet) packets; + packets.da = *array; + size_t idx; + + obs_encoder_packet_ref(&pkt, packet); + + if (pkt.type == OBS_ENCODER_VIDEO) { + pkt.dts_usec -= video_offset; + pkt.dts -= video_dts_offset; + pkt.pts -= video_dts_offset; + } else { + pkt.dts_usec -= audio_offsets[pkt.track_idx]; + pkt.dts -= audio_dts_offsets[pkt.track_idx]; + pkt.pts -= audio_dts_offsets[pkt.track_idx]; + } + + for (idx = packets.num; idx > 0; idx--) { + struct encoder_packet *p = packets.array + (idx - 1); + if (p->dts_usec < pkt.dts_usec) + break; + } + + da_insert(packets, idx, &pkt); + *array = packets.da; +} + +static void *replay_buffer_mux_thread(void *data) +{ + struct ffmpeg_muxer *stream = data; + + start_pipe(stream, stream->path.array); + + if (!stream->pipe) { + warn("Failed to create process pipe"); + goto error; + } + + if (!send_headers(stream)) { + warn("Could not write headers for file '%s'", + stream->path.array); + goto error; + } + + for (size_t i = 0; i < stream->mux_packets.num; i++) { + struct encoder_packet *pkt = &stream->mux_packets.array[i]; + write_packet(stream, pkt); + obs_encoder_packet_release(pkt); + } + + info("Wrote replay buffer to '%s'", stream->path.array); + +error: + os_process_pipe_destroy(stream->pipe); + stream->pipe = NULL; + da_free(stream->mux_packets); + os_atomic_set_bool(&stream->muxing, false); + return NULL; +} + +static void replay_buffer_save(struct ffmpeg_muxer *stream) +{ + const size_t size = sizeof(struct encoder_packet); + size_t num_packets = stream->packets.size / size; + + da_reserve(stream->mux_packets, num_packets); + + /* ---------------------------- */ + /* reorder packets */ + + bool found_video = false; + bool found_audio[MAX_AUDIO_MIXES] = {0}; + int64_t video_offset = 0; + int64_t video_dts_offset = 0; + int64_t audio_offsets[MAX_AUDIO_MIXES] = {0}; + int64_t audio_dts_offsets[MAX_AUDIO_MIXES] = {0}; + + for (size_t i = 0; i < num_packets; i++) { + struct encoder_packet *pkt; + pkt = circlebuf_data(&stream->packets, i * size); + + if (pkt->type == OBS_ENCODER_VIDEO) { + if (!found_video) { + video_offset = pkt->dts_usec; + video_dts_offset = pkt->dts; + found_video = true; + } + } else { + if (!found_audio[pkt->track_idx]) { + found_audio[pkt->track_idx] = true; + audio_offsets[pkt->track_idx] = pkt->dts_usec; + audio_dts_offsets[pkt->track_idx] = pkt->dts; + } + } + + insert_packet(&stream->mux_packets.da, pkt, + video_offset, audio_offsets, + video_dts_offset, audio_dts_offsets); + } + + /* ---------------------------- */ + /* generate filename */ + + obs_data_t *settings = obs_output_get_settings(stream->output); + const char *dir = obs_data_get_string(settings, "directory"); + const char *fmt = obs_data_get_string(settings, "format"); + const char *ext = obs_data_get_string(settings, "extension"); + bool space = obs_data_get_bool(settings, "allow_spaces"); + + char *filename = os_generate_formatted_filename(ext, space, fmt); + + dstr_copy(&stream->path, dir); + dstr_replace(&stream->path, "\\", "/"); + if (dstr_end(&stream->path) != '/') + dstr_cat_ch(&stream->path, '/'); + dstr_cat(&stream->path, filename); + + bfree(filename); + obs_data_release(settings); + + /* ---------------------------- */ + + os_atomic_set_bool(&stream->muxing, true); + stream->mux_thread_joinable = pthread_create(&stream->mux_thread, NULL, + replay_buffer_mux_thread, stream) == 0; +} + +static void deactivate_replay_buffer(struct ffmpeg_muxer *stream) +{ + if (stopping(stream)) + obs_output_end_data_capture(stream->output); + + os_atomic_set_bool(&stream->active, false); + os_atomic_set_bool(&stream->sent_headers, false); + os_atomic_set_bool(&stream->stopping, false); + replay_buffer_clear(stream); +} + +static void replay_buffer_data(void *data, struct encoder_packet *packet) +{ + struct ffmpeg_muxer *stream = data; + struct encoder_packet pkt; + + if (!active(stream)) + return; + + if (stopping(stream)) { + if (packet->sys_dts_usec >= stream->stop_ts) { + deactivate_replay_buffer(stream); + return; + } + } + + obs_encoder_packet_ref(&pkt, packet); + replay_buffer_purge(stream, &pkt); + + if (!stream->packets.size) + stream->cur_time = pkt.dts_usec; + stream->cur_size += pkt.size; + + circlebuf_push_back(&stream->packets, packet, sizeof(*packet)); + + if (packet->type == OBS_ENCODER_VIDEO && packet->keyframe) + stream->keyframes++; + + if (stream->save_ts && packet->sys_dts_usec >= stream->save_ts) { + if (os_atomic_load_bool(&stream->muxing)) + return; + + if (stream->mux_thread_joinable) { + pthread_join(stream->mux_thread, NULL); + stream->mux_thread_joinable = false; + } + + stream->save_ts = 0; + replay_buffer_save(stream); + } +} + +static void replay_buffer_defaults(obs_data_t *s) +{ + obs_data_set_default_int(s, "max_time_sec", 15); + obs_data_set_default_int(s, "max_size_mb", 500); + obs_data_set_default_string(s, "format", "%CCYY-%MM-%DD %hh-%mm-%ss"); + obs_data_set_default_string(s, "extension", "mp4"); + obs_data_set_default_bool(s, "allow_spaces", true); +} + +struct obs_output_info replay_buffer = { + .id = "replay_buffer", + .flags = OBS_OUTPUT_AV | + OBS_OUTPUT_ENCODED | + OBS_OUTPUT_MULTI_TRACK, + .get_name = replay_buffer_getname, + .create = replay_buffer_create, + .destroy = replay_buffer_destroy, + .start = replay_buffer_start, + .stop = ffmpeg_mux_stop, + .encoded_packet = replay_buffer_data, + .get_defaults = replay_buffer_defaults +};
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c
Changed
@@ -272,7 +272,9 @@ enc = bzalloc(sizeof(*enc)); enc->encoder = encoder; - enc->nvenc = avcodec_find_encoder_by_name("nvenc_h264"); + enc->nvenc = avcodec_find_encoder_by_name("h264_nvenc"); + if (!enc->nvenc) + enc->nvenc = avcodec_find_encoder_by_name("nvenc_h264"); enc->first_packet = true; blog(LOG_INFO, "---------------------------------");
View file
obs-studio-0.16.6.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg.c -> obs-studio-0.17.0.tar.xz/plugins/obs-ffmpeg/obs-ffmpeg.c
Changed
@@ -11,6 +11,7 @@ extern struct obs_source_info ffmpeg_source; extern struct obs_output_info ffmpeg_output; extern struct obs_output_info ffmpeg_muxer; +extern struct obs_output_info replay_buffer; extern struct obs_encoder_info aac_encoder_info; extern struct obs_encoder_info nvenc_encoder_info; @@ -145,6 +146,7 @@ obs_register_source(&ffmpeg_source); obs_register_output(&ffmpeg_output); obs_register_output(&ffmpeg_muxer); + obs_register_output(&replay_buffer); obs_register_encoder(&aac_encoder_info); if (nvenc_supported()) { blog(LOG_INFO, "NVENC supported");
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/CMakeLists.txt
Changed
@@ -20,7 +20,7 @@ set(obs-filters_SOURCES obs-filters.c - color-filter.c + color-correction-filter.c async-delay-filter.c crop-filter.c scale-filter.c
View file
obs-studio-0.17.0.tar.xz/plugins/obs-filters/color-correction-filter.c
Added
@@ -0,0 +1,406 @@ +/***************************************************************************** +Copyright (C) 2016 by c3r1c3 <c3r1c3@nevermindonline.com> + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ +#include <obs-module.h> +#include <graphics/matrix4.h> +#include <graphics/quat.h> + + +#define SETTING_GAMMA "gamma" +#define SETTING_CONTRAST "contrast" +#define SETTING_BRIGHTNESS "brightness" +#define SETTING_SATURATION "saturation" +#define SETTING_HUESHIFT "hue_shift" +#define SETTING_OPACITY "opacity" +#define SETTING_COLOR "color" + +#define TEXT_GAMMA obs_module_text("Gamma") +#define TEXT_CONTRAST obs_module_text("Contrast") +#define TEXT_BRIGHTNESS obs_module_text("Brightness") +#define TEXT_SATURATION obs_module_text("Saturation") +#define TEXT_HUESHIFT obs_module_text("HueShift") +#define TEXT_OPACITY obs_module_text("Opacity") +#define TEXT_COLOR obs_module_text("Color") + +struct color_correction_filter_data { + obs_source_t *context; + + gs_effect_t *effect; + + gs_eparam_t *gamma_param; + gs_eparam_t *final_matrix_param; + + struct vec3 gamma; + float contrast; + float brightness; + float saturation; + float hue_shift; + float opacity; + struct vec4 color; + + /* Pre-Computes */ + struct matrix4 con_matrix; + struct matrix4 bright_matrix; + struct matrix4 sat_matrix; + struct matrix4 hue_op_matrix; + struct matrix4 color_matrix; + struct matrix4 final_matrix; + + struct vec3 rot_quaternion; + float rot_quaternion_w; + struct vec3 cross; + struct vec3 square; + struct vec3 wimag; + struct vec3 diag; + struct vec3 a_line; + struct vec3 b_line; + struct vec3 half_unit; +}; + +const static float root3 = 0.57735f; + +/* + * As the functions' namesake, this provides the internal name of your Filter, + * which is then translated/referenced in the "data/locale" files. + */ +static const char *color_correction_filter_name(void *unused) +{ + UNUSED_PARAMETER(unused); + return obs_module_text("ColorFilter"); +} + +/* + * This function is called (see bottom of this file for more details) + * whenever the OBS filter interface changes. So when the user is messing + * with a slider this function is called to update the internal settings + * in OBS, and hence the settings being passed to the CPU/GPU. + */ +static void color_correction_filter_update(void *data, obs_data_t *settings) +{ + struct color_correction_filter_data *filter = data; + + /* Build our Gamma numbers. */ + double gamma = obs_data_get_double(settings, SETTING_GAMMA); + gamma = (gamma < 0.0) ? (-gamma + 1.0) : (1.0 / (gamma + 1.0)); + vec3_set(&filter->gamma, (float)gamma, (float)gamma, (float)gamma); + + /* Build our contrast number. */ + filter->contrast = (float)obs_data_get_double(settings, + SETTING_CONTRAST) + 1.0f; + float one_minus_con = (1.0f - filter->contrast) / 2.0f; + + /* Now let's build our Contrast matrix. */ + filter->con_matrix = (struct matrix4) + { + filter->contrast, 0.0f, 0.0f, 0.0f, + 0.0f, filter->contrast, 0.0f, 0.0f, + 0.0f, 0.0f, filter->contrast, 0.0f, + one_minus_con, one_minus_con, one_minus_con, 1.0f + }; + + /* Build our brightness number. */ + filter->brightness = (float)obs_data_get_double(settings, + SETTING_BRIGHTNESS); + + /* + * Now let's build our Brightness matrix. + * Earlier (in the function color_correction_filter_create) we set + * this matrix to the identity matrix, so now we only need + * to set the 3 variables that have changed. + */ + filter->bright_matrix.t.x = filter->brightness; + filter->bright_matrix.t.y = filter->brightness; + filter->bright_matrix.t.z = filter->brightness; + + /* Build our Saturation number. */ + filter->saturation = (float)obs_data_get_double(settings, + SETTING_SATURATION) + 1.0f; + + /* Factor in the selected color weights. */ + float one_minus_sat = (1.0f - filter->saturation) / 3.0f; + float sat_val = one_minus_sat + filter->saturation; + + /* Now we build our Saturation matrix. */ + filter->sat_matrix = (struct matrix4) + { + sat_val, one_minus_sat, one_minus_sat, 0.0f, + one_minus_sat, sat_val, one_minus_sat, 0.0f, + one_minus_sat, one_minus_sat, sat_val, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + /* Build our Hue number. */ + filter->hue_shift = (float)obs_data_get_double(settings, + SETTING_HUESHIFT); + + /* Build our Transparency number. */ + filter->opacity = (float)obs_data_get_int(settings, + SETTING_OPACITY) * 0.01f; + + /* Hue is the radian of 0 to 360 degrees. */ + float half_angle = 0.5f * (float)(filter->hue_shift / (180.0f / M_PI)); + + /* Pseudo-Quaternion To Matrix. */ + float rot_quad1 = root3 * (float)sin(half_angle); + vec3_set(&filter->rot_quaternion, rot_quad1, rot_quad1, + rot_quad1); + filter->rot_quaternion_w = (float)cos(half_angle); + + vec3_mul(&filter->cross, &filter->rot_quaternion, + &filter->rot_quaternion); + vec3_mul(&filter->square, &filter->rot_quaternion, + &filter->rot_quaternion); + vec3_mulf(&filter->wimag, &filter->rot_quaternion, + filter->rot_quaternion_w); + + vec3_mulf(&filter->square, &filter->square, 2.0f); + vec3_sub(&filter->diag, &filter->half_unit, &filter->square); + vec3_add(&filter->a_line, &filter->cross, &filter->wimag); + vec3_sub(&filter->b_line, &filter->cross, &filter->wimag); + + /* Now we build our Hue and Opacity matrix. */ + filter->hue_op_matrix = (struct matrix4) + { + filter->diag.x * 2.0f, + filter->b_line.z * 2.0f, + filter->a_line.y * 2.0f, + 0.0f, + + filter->a_line.z * 2.0f, + filter->diag.y * 2.0f, + filter->b_line.x * 2.0f, + 0.0f, + + filter->b_line.y * 2.0f, + filter->a_line.x * 2.0f, + filter->diag.z * 2.0f, + 0.0f, + + 0.0f, 0.0f, 0.0f, filter->opacity + }; + + /* Now get the overlay color data. */ + uint32_t color = (uint32_t)obs_data_get_int(settings, + SETTING_COLOR); + vec4_from_rgba(&filter->color, color); + + /* + * Now let's build our Color 'overlay' matrix. + * Earlier (in the function color_correction_filter_create) we set + * this matrix to the identity matrix, so now we only need + * to set the 6 variables that have changed. + */ + filter->color_matrix.x.x = filter->color.x; + filter->color_matrix.y.y = filter->color.y; + filter->color_matrix.z.z = filter->color.z; + + filter->color_matrix.t.x = filter->color.w * + filter->color.x; + filter->color_matrix.t.y = filter->color.w * + filter->color.y; + filter->color_matrix.t.z = filter->color.w * + filter->color.z; + + + /* First we apply the Contrast & Brightness matrix. */ + matrix4_mul(&filter->final_matrix, &filter->bright_matrix, + &filter->con_matrix); + /* Now we apply the Saturation matrix. */ + matrix4_mul(&filter->final_matrix, &filter->final_matrix, + &filter->sat_matrix); + /* Next we apply the Hue+Opacity matrix. */ + matrix4_mul(&filter->final_matrix, &filter->final_matrix, + &filter->hue_op_matrix); + /* Lastly we apply the Color Wash matrix. */ + matrix4_mul(&filter->final_matrix, &filter->final_matrix, + &filter->color_matrix); +} + +/* + * Since this is C we have to be careful when destroying/removing items from + * OBS. Jim has added several useful functions to help keep memory leaks to + * a minimum, and handle the destruction and construction of these filters. + */ +static void color_correction_filter_destroy(void *data) +{ + struct color_correction_filter_data *filter = data; + + if (filter->effect) { + obs_enter_graphics(); + gs_effect_destroy(filter->effect); + obs_leave_graphics(); + } + + bfree(data); +} + +/* + * When you apply a filter OBS creates it, and adds it to the source. OBS also + * starts rendering it immediately. This function doesn't just 'create' the + * filter, it also calls the render function (farther below) that contains the + * actual rendering code. + */ +static void *color_correction_filter_create(obs_data_t *settings, + obs_source_t *context) +{ + /* + * Because of limitations of pre-c99 compilers, you can't create an + * array that doesn't have a known size at compile time. The below + * function calculates the size needed and allocates memory to + * handle the source. + */ + struct color_correction_filter_data *filter = + bzalloc(sizeof(struct color_correction_filter_data)); + + /* + * By default the effect file is stored in the ./data directory that + * your filter resides in. + */ + char *effect_path = obs_module_file("color_correction_filter.effect"); + + filter->context = context; + + /* Set/clear/assign for all necessary vectors. */ + vec3_set(&filter->half_unit, 0.5f, 0.5f, 0.5f); + matrix4_identity(&filter->bright_matrix); + matrix4_identity(&filter->color_matrix); + + /* Here we enter the GPU drawing/shader portion of our code. */ + obs_enter_graphics(); + + /* Load the shader on the GPU. */ + filter->effect = gs_effect_create_from_file(effect_path, NULL); + + /* If the filter is active pass the parameters to the filter. */ + if (filter->effect) { + filter->gamma_param = gs_effect_get_param_by_name( + filter->effect, SETTING_GAMMA); + filter->final_matrix_param = gs_effect_get_param_by_name( + filter->effect, "color_matrix"); + } + + obs_leave_graphics(); + + bfree(effect_path); + + /* + * If the filter has been removed/deactivated, destroy the filter + * and exit out so we don't crash OBS by telling it to update + * values that don't exist anymore. + */ + if (!filter->effect) { + color_correction_filter_destroy(filter); + return NULL; + } + + /* + * It's important to call the update function here. If we don't + * we could end up with the user controlled sliders and values + * updating, but the visuals not updating to match. + */ + color_correction_filter_update(filter, settings); + return filter; +} + +/* This is where the actual rendering of the filter takes place. */ +static void color_correction_filter_render(void *data, gs_effect_t *effect) +{ + struct color_correction_filter_data *filter = data; + + if (!obs_source_process_filter_begin(filter->context, GS_RGBA, + OBS_ALLOW_DIRECT_RENDERING)) + return; + + /* Now pass the interface variables to the .effect file. */ + gs_effect_set_vec3(filter->gamma_param, &filter->gamma); + gs_effect_set_matrix4(filter->final_matrix_param, &filter->final_matrix); + + obs_source_process_filter_end(filter->context, filter->effect, 0, 0); + + UNUSED_PARAMETER(effect); +} + +/* + * This function sets the interface. the types (add_*_Slider), the type of + * data collected (int), the internal name, user-facing name, minimum, + * maximum and step values. While a custom interface can be built, for a + * simple filter like this it's better to use the supplied functions. + */ +static obs_properties_t *color_correction_filter_properties(void *data) +{ + obs_properties_t *props = obs_properties_create(); + + obs_properties_add_float_slider(props, SETTING_GAMMA, + TEXT_GAMMA, -3.0f, 3.0f, 0.01f); + + obs_properties_add_float_slider(props, SETTING_CONTRAST, + TEXT_CONTRAST, -2.0f, 2.0f, 0.01f); + obs_properties_add_float_slider(props, SETTING_BRIGHTNESS, + TEXT_BRIGHTNESS, -1.0f, 1.0f, 0.01f); + obs_properties_add_float_slider(props, SETTING_SATURATION, + TEXT_SATURATION, -1.0f, 5.0f, 0.01f); + obs_properties_add_float_slider(props, SETTING_HUESHIFT, + TEXT_HUESHIFT, -180.0f, 180.0f, 0.01f); + obs_properties_add_int_slider(props, SETTING_OPACITY, + TEXT_OPACITY, 0, 100, 1); + + obs_properties_add_color(props, SETTING_COLOR, TEXT_COLOR); + + UNUSED_PARAMETER(data); + return props; +} + +/* + * As the functions' namesake, this provides the default settings for any + * options you wish to provide a default for. Try to select defaults that + * make sense to the end user, or that don't effect the data. + * *NOTE* this function is completely optional, as is providing a default + * for any particular setting. + */ +static void color_correction_filter_defaults(obs_data_t *settings) +{ + obs_data_set_default_double(settings, SETTING_GAMMA, 0.0); + obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0); + obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0); + obs_data_set_default_double(settings, + SETTING_SATURATION, 0.0); + obs_data_set_default_double(settings, SETTING_HUESHIFT, 0.0); + obs_data_set_default_double(settings, SETTING_OPACITY, 100.0); + obs_data_set_default_int(settings, SETTING_COLOR, 0xFFFFFF); +} + +/* + * So how does OBS keep track of all these plug-ins/filters? How does OBS know + * which function to call when it needs to update a setting? Or a source? Or + * what type of source this is? + * + * OBS does it through the obs_source_info_struct. Notice how variables are + * assigned the name of a function? Notice how the function name has the + * variable name in it? While not mandatory, it helps a ton for you (and those + * reading your code) to follow this convention. + */ +struct obs_source_info color_filter = { + .id = "color_filter", + .type = OBS_SOURCE_TYPE_FILTER, + .output_flags = OBS_SOURCE_VIDEO, + .get_name = color_correction_filter_name, + .create = color_correction_filter_create, + .destroy = color_correction_filter_destroy, + .video_render = color_correction_filter_render, + .update = color_correction_filter_update, + .get_properties = color_correction_filter_properties, + .get_defaults = color_correction_filter_defaults +};
View file
obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/color_correction_filter.effect
Added
@@ -0,0 +1,78 @@ +/***************************************************************************** +Copyright (C) 2016 by c3r1c3 <c3r1c3@nevermindonline.com> + +This program 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 2 of the License, or +(at your option) any later version. + +This program 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 this program. If not, see <http://www.gnu.org/licenses/>. +*****************************************************************************/ + +uniform float4x4 ViewProj; +uniform texture2d image; + +uniform float3 gamma; + +/* Pre-Compute variables. */ +uniform float4x4 color_matrix; + + +sampler_state textureSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +struct CurrentPixel { + float4 current_pixel; +}; + +VertData VSDefault(VertData vert_in) +{ + VertData vert_out; + vert_out.pos = mul(float4(vert_in.pos.xyz, 1.0), ViewProj); + vert_out.uv = vert_in.uv; + return vert_out; +} + +float4 PSColorFilterRGBA(VertData vert_in) : TARGET +{ + /* Realize the struct. */ + CurrentPixel pixel = (CurrentPixel) 0; + + /* Grab the current pixel to perform operations on. */ + pixel.current_pixel = image.Sample(textureSampler, vert_in.uv); + + /* Always address the gamma first. */ + pixel.current_pixel.rgb = pow(pixel.current_pixel.rgb, gamma); + + /* Much easier to manipulate pixels for these types of operations + * when in a matrix such as the below. See + * http://www.graficaobscura.com/matrix/index.html and + * https://docs.rainmeter.net/tips/colormatrix-guide/for more info. + */ + pixel.current_pixel = mul(color_matrix, pixel.current_pixel); + + return pixel.current_pixel; +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(vert_in); + pixel_shader = PSColorFilterRGBA(vert_in); + } +}
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/da-DK.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/da-DK.ini
Changed
@@ -1,11 +1,14 @@ ColorFilter="Farvekorrektion" MaskFilter="Billede maske/blanding" AsyncDelayFilter="Video forsinkelse (asynkron)" +CropFilter="Beskæring/Polstring" ScrollFilter="Rul" ChromaKeyFilter="Chroma nøgle" ColorKeyFilter="Farvenøgle" SharpnessFilter="Skarphed" +ScaleFilter="Skalering/Formatforhold" NoiseGate="Noise Gate" +NoiseSuppress="Støjundertrykkelse" Gain="Forstærkning" DelayMs="Forsinkelse (millisekunder)" Type="Type" @@ -43,6 +46,21 @@ Green="Grøn" Blue="Blå" Magenta="Magenta" +NoiseGate.OpenThreshold="Åbne-tærskel (dB)" +NoiseGate.CloseThreshold="Lukke-tærskel (dB)" +NoiseGate.AttackTime="Effektueringstid (millisek.)" +NoiseGate.HoldTime="Holdetid (millisek.)" +NoiseGate.ReleaseTime="Frigivelsestid (millisek.)" Gain.GainDB="Forstærkning (dB)" StretchImage="Stræk billedet (ignorer størrelsesforhold)" +Resolution="Opløsning" +None="Ingen" +ScaleFiltering="Skaleringsfilter" +ScaleFiltering.Point="Punkt" +ScaleFiltering.Bilinear="Bilineær" +ScaleFiltering.Bicubic="Bikubisk" +ScaleFiltering.Lanczos="Lanczos" +NoiseSuppress.SuppressLevel="Undertrykkelsesniveau (dB)" +Saturation="Mætning" +HueShift="Nuanceskift"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/de-DE.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/de-DE.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="Bicubic" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Unterdrückungspegel (dB)" +Saturation="Sättigung" +HueShift="Farbtonverschiebung"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/en-US.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/en-US.ini
Changed
@@ -61,3 +61,5 @@ ScaleFiltering.Bicubic="Bicubic" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Suppression Level (dB)" +Saturation="Saturation" +HueShift="Hue Shift"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/es-ES.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/es-ES.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="Bicúbico" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Nivel de eliminación de ruido (dB)" +Saturation="Saturación" +HueShift="Cambio de tonalidad"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/fr-FR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/fr-FR.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="Bicubique" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Seuil de suppression (en dB)" +Saturation="Saturation" +HueShift="Décalage de teinte"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/hu-HU.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/hu-HU.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="Kettős köbös" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Csökkentési szint (dB)" +Saturation="Telítettség" +HueShift="Színezet váltása"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/ja-JP.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/ja-JP.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="バイキュービック" ScaleFiltering.Lanczos="ランチョス" NoiseSuppress.SuppressLevel="抑制レベル (dB)" +Saturation="彩度" +HueShift="色相シフト"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/ko-KR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/ko-KR.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="쌍삼차" ScaleFiltering.Lanczos="란초스" NoiseSuppress.SuppressLevel="억제 세기 (dB)" +Saturation="채도" +HueShift="색조 변화"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/nl-NL.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="Bicubic" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Onderdrukkingsniveau (dB)" +Saturation="Verzadiging" +HueShift="Tintverschuiving"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/pl-PL.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/pl-PL.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="Dwusześcienne" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="Poziom tłumienia (dB)" +Saturation="Nasycenie" +HueShift="Przesunięcie barwy"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/tr-TR.ini
Changed
@@ -6,6 +6,7 @@ ColorKeyFilter="Renk Anahtarı" SharpnessFilter="Keskinleştirme" NoiseGate="Gürültü Filtresi" +NoiseSuppress="Gürültü Bastırma" Gain="Kazanç" DelayMs="Gecikme (milisaniye)" Type="Türü" @@ -20,7 +21,7 @@ Contrast="Karşıtlık" Brightness="Parlaklık" Gamma="Gama" -BrowsePath.Images="Tüm Resim Dosyaları" +BrowsePath.Images="Tüm Görüntü Dosyaları" BrowsePath.AllFiles="Tüm Dosyalar" KeyColorType="Anahtar Renk Türü" KeyColor="Anahtar Renk" @@ -49,4 +50,11 @@ NoiseGate.HoldTime="Kavrama Süresi (milisaniye)" NoiseGate.ReleaseTime="Bırakma Süresi (milisaniye)" Gain.GainDB="Kazanç (dB)" +Resolution="Çözünürlük" +None="Hiçbiri" +ScaleFiltering="Ölçek Filtreleme" +ScaleFiltering.Point="Nokta" +ScaleFiltering.Bilinear="Bilinear" +ScaleFiltering.Bicubic="Bicubic" +ScaleFiltering.Lanczos="Lanczos"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/zh-CN.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/zh-CN.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="双立方算法" ScaleFiltering.Lanczos="兰索斯算法" NoiseSuppress.SuppressLevel="抑制程度 (dB)" +Saturation="饱和度" +HueShift="色调偏移"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-filters/data/locale/zh-TW.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-filters/data/locale/zh-TW.ini
Changed
@@ -61,4 +61,6 @@ ScaleFiltering.Bicubic="雙三次插值" ScaleFiltering.Lanczos="Lanczos" NoiseSuppress.SuppressLevel="抑制標準 (dB)" +Saturation="飽合度" +HueShift="色調偏移"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-outputs/data/locale/da-DK.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-outputs/data/locale/da-DK.ini
Changed
@@ -2,4 +2,5 @@ RTMPStream.DropThreshold="Drop Tærskel (millisekunder)" FLVOutput="FLV File Output" FLVOutput.FilePath="Filsti" +Default="Standard"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-outputs/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-outputs/data/locale/tr-TR.ini
Changed
@@ -2,4 +2,5 @@ RTMPStream.DropThreshold="Düşürme Eşiği (milisaniye)" FLVOutput="FLV Dosyası Çıkışı" FLVOutput.FilePath="Dosya Yolu" +Default="Varsayılan"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-outputs/flv-output.c -> obs-studio-0.17.0.tar.xz/plugins/obs-outputs/flv-output.c
Changed
@@ -100,7 +100,7 @@ flv_packet_mux(packet, &data, &size, is_header); fwrite(data, 1, size, stream->file); bfree(data); - obs_free_encoder_packet(packet); + obs_encoder_packet_release(packet); return ret; } @@ -200,7 +200,7 @@ if (packet->type == OBS_ENCODER_VIDEO) { obs_parse_avc_packet(&parsed_packet, packet); write_packet(stream, &parsed_packet, false); - obs_free_encoder_packet(&parsed_packet); + obs_encoder_packet_release(&parsed_packet); } else { write_packet(stream, packet, false); }
View file
obs-studio-0.16.6.tar.xz/plugins/obs-outputs/librtmp/rtmp.c -> obs-studio-0.17.0.tar.xz/plugins/obs-outputs/librtmp/rtmp.c
Changed
@@ -650,7 +650,7 @@ } static int -add_addr_info(struct sockaddr_storage *service, socklen_t *addrlen, AVal *host, int port) +add_addr_info(struct sockaddr_storage *service, socklen_t *addrlen, AVal *host, int port, socklen_t addrlen_hint) { char *hostname; int ret = TRUE; @@ -698,7 +698,7 @@ // prefer ipv4 results, since lots of ISPs have broken ipv6 connectivity for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { - if (ptr->ai_family == AF_INET) + if (ptr->ai_family == AF_INET && (!addrlen_hint || ptr->ai_addrlen == addrlen_hint)) { memcpy(service, ptr->ai_addr, ptr->ai_addrlen); *addrlen = (socklen_t)ptr->ai_addrlen; @@ -710,7 +710,7 @@ { for (ptr = result; ptr != NULL; ptr = ptr->ai_next) { - if (ptr->ai_family == AF_INET6) + if (ptr->ai_family == AF_INET6 && (!addrlen_hint || ptr->ai_addrlen == addrlen_hint)) { memcpy(service, ptr->ai_addr, ptr->ai_addrlen); *addrlen = (socklen_t)ptr->ai_addrlen; @@ -905,6 +905,7 @@ #endif struct sockaddr_storage service; socklen_t addrlen = 0; + socklen_t addrlen_hint = 0; if (!r->Link.hostname.av_len) return FALSE; @@ -920,16 +921,19 @@ memset(&service, 0, sizeof(service)); + if (r->m_bindIP.addrLen) + addrlen_hint = r->m_bindIP.addrLen; + if (r->Link.socksport) { /* Connect via SOCKS */ - if (!add_addr_info(&service, &addrlen, &r->Link.sockshost, r->Link.socksport)) + if (!add_addr_info(&service, &addrlen, &r->Link.sockshost, r->Link.socksport, addrlen_hint)) return FALSE; } else { /* Connect directly */ - if (!add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port)) + if (!add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port, addrlen_hint)) return FALSE; } @@ -949,7 +953,7 @@ socklen_t addrlen = 0; memset(&service, 0, sizeof(service)); - add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port); + add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port, 0); // not doing IPv6 socks if (service.ss_family == AF_INET6)
View file
obs-studio-0.16.6.tar.xz/plugins/obs-outputs/rtmp-stream.c -> obs-studio-0.17.0.tar.xz/plugins/obs-outputs/rtmp-stream.c
Changed
@@ -134,7 +134,7 @@ while (stream->packets.size) { struct encoder_packet packet; circlebuf_pop_front(&stream->packets, &packet, sizeof(packet)); - obs_free_encoder_packet(&packet); + obs_encoder_packet_release(&packet); } pthread_mutex_unlock(&stream->packets_mutex); } @@ -375,7 +375,10 @@ ret = RTMP_Write(&stream->rtmp, (char*)data, (int)size, (int)idx); bfree(data); - obs_free_encoder_packet(packet); + if (is_header) + bfree(packet->data); + else + obs_encoder_packet_release(packet); stream->total_bytes_sent += size; return ret; @@ -414,7 +417,7 @@ if (stopping(stream)) { if (can_shutdown_stream(stream, &packet)) { - obs_free_encoder_packet(&packet); + obs_encoder_packet_release(&packet); break; } } @@ -676,8 +679,10 @@ bool success = netif_str_to_addr(&stream->rtmp.m_bindIP.addr, &stream->rtmp.m_bindIP.addrLen, stream->bind_ip.array); - if (success) - info("Binding to IP"); + if (success) { + info("Binding to IPv%d", (stream->rtmp.m_bindIP.addrLen == + sizeof(struct sockaddr_in6) ? 6 : 4)); + } } RTMP_AddStream(&stream->rtmp, stream->key.array); @@ -842,7 +847,7 @@ } else { num_frames_dropped++; - obs_free_encoder_packet(&packet); + obs_encoder_packet_release(&packet); } } @@ -927,7 +932,7 @@ if (packet->type == OBS_ENCODER_VIDEO) obs_parse_avc_packet(&new_packet, packet); else - obs_duplicate_encoder_packet(&new_packet, packet); + obs_encoder_packet_ref(&new_packet, packet); pthread_mutex_lock(&stream->packets_mutex); @@ -942,7 +947,7 @@ if (added_packet) os_sem_post(stream->send_sem); else - obs_free_encoder_packet(&new_packet); + obs_encoder_packet_release(&new_packet); } static void rtmp_stream_defaults(obs_data_t *defaults)
View file
obs-studio-0.16.6.tar.xz/plugins/obs-qsv11/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/CMakeLists.txt
Changed
@@ -48,9 +48,11 @@ ) set(obs-qsv11_SOURCES + common_directx9.cpp common_directx11.cpp common_utils.cpp common_utils_windows.cpp + device_directx9.cpp QSV_Encoder.cpp QSV_Encoder_Internal.cpp obs-qsv11.c @@ -59,7 +61,9 @@ set(obs-qsv11_HEADERS bits/linux_defs.h bits/windows_defs.h + common_directx9.h common_directx11.h + device_directx9.h common_utils.h QSV_Encoder.h QSV_Encoder_Internal.h) @@ -72,7 +76,9 @@ ) target_link_libraries(obs-qsv11 libobs + d3d9 d3d11 + dxva2 dxgi )
View file
obs-studio-0.16.6.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.cpp -> obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.cpp
Changed
@@ -83,6 +83,7 @@ m_bIsWindows8OrGreater = IsWindows8OrGreater(); m_bUseD3D11 = false; + m_bD3D9HACK = true; if (m_bIsWindows8OrGreater) { tempImpl = impl | MFX_IMPL_VIA_D3D11; @@ -107,6 +108,21 @@ return; } } + else if (m_bD3D9HACK) { + tempImpl = impl | MFX_IMPL_VIA_D3D9; + sts = m_session.Init(tempImpl, &version); + if (sts == MFX_ERR_NONE) { + m_session.QueryVersion(&version); + m_session.Close(); + + blog(LOG_INFO, "\timpl: D3D09\n" + "\tsurf: Hack"); + + m_impl = tempImpl; + m_ver = version; + return; + } + } // Either windows 7 or D3D11 failed at this point. tempImpl = impl | MFX_IMPL_VIA_D3D9; @@ -136,11 +152,14 @@ if (m_bUseD3D11) // Use D3D11 surface - sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator); + sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, false, false); + else if (m_bD3D9HACK) + // Use hack + sts = Initialize(m_impl, m_ver, &m_session, &m_mfxAllocator, false, true); else - // Use system memory sts = Initialize(m_impl, m_ver, &m_session, NULL); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); m_pmfxENC = new MFXVideoENCODE(m_session); @@ -260,7 +279,7 @@ m_mfxEncParams.mfx.FrameInfo.Width = MSDK_ALIGN16(pParams->nWidth); m_mfxEncParams.mfx.FrameInfo.Height = MSDK_ALIGN16(pParams->nHeight); - if (m_bUseD3D11) + if (m_bUseD3D11 || m_bD3D9HACK) m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY; else m_mfxEncParams.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; @@ -282,7 +301,7 @@ EncRequest.NumFrameSuggested += m_mfxEncParams.AsyncDepth; // Allocate required surfaces - if (m_bUseD3D11) { + if (m_bUseD3D11 || m_bD3D9HACK) { sts = m_mfxAllocator.Alloc(m_mfxAllocator.pthis, &EncRequest, &m_mfxResponse); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); @@ -498,14 +517,14 @@ } mfxFrameSurface1 *pSurface = m_pmfxSurfaces[nSurfIdx]; - if (m_bUseD3D11) + if (m_bUseD3D11 || m_bD3D9HACK) sts = m_mfxAllocator.Lock(m_mfxAllocator.pthis, pSurface->Data.MemId, &(pSurface->Data)); sts = LoadNV12(pSurface, pDataY, pDataUV, strideY, strideUV); pSurface->Data.TimeStamp = ts; - if (m_bUseD3D11) + if (m_bUseD3D11 || m_bD3D9HACK) sts = m_mfxAllocator.Unlock(m_mfxAllocator.pthis, pSurface->Data.MemId, &(pSurface->Data)); @@ -538,7 +557,7 @@ { mfxStatus sts = MFX_ERR_NONE; - while (m_pTaskPool[m_nFirstSyncTask].syncp) { + while (m_pTaskPool && m_pTaskPool[m_nFirstSyncTask].syncp) { sts = m_session.SyncOperation(m_pTaskPool[m_nFirstSyncTask].syncp, 60000); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); @@ -556,11 +575,11 @@ sts = m_pmfxENC->Close(); - if (m_bUseD3D11) + if (m_bUseD3D11 || m_bD3D9HACK) m_mfxAllocator.Free(m_mfxAllocator.pthis, &m_mfxResponse); for (int i = 0; i < m_nSurfNum; i++) { - if (!m_bUseD3D11) + if (!m_bUseD3D11 && !m_bD3D9HACK) delete m_pmfxSurfaces[i]->Data.Y; delete m_pmfxSurfaces[i]; @@ -578,7 +597,7 @@ m_pmfxENC = NULL; } - if (m_bUseD3D11) + if (m_bUseD3D11 || m_bD3D9HACK) Release(); m_session.Close();
View file
obs-studio-0.16.6.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.h -> obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/QSV_Encoder_Internal.h
Changed
@@ -108,5 +108,6 @@ mfxBitstream m_outBitstream; bool m_bIsWindows8OrGreater; bool m_bUseD3D11; + bool m_bD3D9HACK; };
View file
obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/common_directx9.cpp
Added
@@ -0,0 +1,457 @@ +#include "common_directx9.h" +#include "device_directx9.h" + +#include <objbase.h> +#include <initguid.h> +#include <d3d9.h> +#include <map> +#include <atlbase.h> + + +#define D3DFMT_NV12 (D3DFORMAT)MAKEFOURCC('N','V','1','2') +#define D3DFMT_YV12 (D3DFORMAT)MAKEFOURCC('Y','V','1','2') +#define D3DFMT_P010 (D3DFORMAT)MAKEFOURCC('P','0','1','0') +#define MSDK_SAFE_FREE(X) {if (X) { free(X); X = NULL; }} + +std::map<mfxMemId*, mfxHDL> dx9_allocResponses; +std::map<mfxHDL, mfxFrameAllocResponse> dx9_allocDecodeResponses; +std::map<mfxHDL, int> dx9_allocDecodeRefCount; + +CComPtr<IDirect3DDeviceManager9> m_manager; +CComPtr<IDirectXVideoDecoderService> m_decoderService; +CComPtr<IDirectXVideoProcessorService> m_processorService; +HANDLE m_hDecoder; +HANDLE m_hProcessor; +DWORD m_surfaceUsage; + +CD3D9Device* g_hwdevice; + +const struct { + mfxIMPL impl; // actual implementation + mfxU32 adapterID; // device adapter number +} implTypes[] = { + { MFX_IMPL_HARDWARE, 0 }, + { MFX_IMPL_HARDWARE2, 1 }, + { MFX_IMPL_HARDWARE3, 2 }, + { MFX_IMPL_HARDWARE4, 3 } +}; + +struct mfxAllocatorParams +{ + virtual ~mfxAllocatorParams(){}; +}; + +struct D3DAllocatorParams : mfxAllocatorParams +{ + IDirect3DDeviceManager9 *pManager; + DWORD surfaceUsage; + + D3DAllocatorParams() + : pManager() + , surfaceUsage() + { + } +}; + +mfxStatus DX9_Alloc_Init(D3DAllocatorParams *pParams) +{ + D3DAllocatorParams *pd3dParams = 0; + pd3dParams = dynamic_cast<D3DAllocatorParams *>(pParams); + if (!pd3dParams) + return MFX_ERR_NOT_INITIALIZED; + + m_manager = pd3dParams->pManager; + m_surfaceUsage = pd3dParams->surfaceUsage; + + return MFX_ERR_NONE; +} + +mfxStatus DX9_CreateHWDevice(mfxSession session, mfxHDL* deviceHandle, HWND, bool) +{ + mfxStatus result; + + g_hwdevice = new CD3D9Device; + mfxU32 adapterNum = 0; + mfxIMPL impl; + + MFXQueryIMPL(session, &impl); + + mfxIMPL baseImpl = MFX_IMPL_BASETYPE(impl); // Extract Media SDK base implementation type + + // get corresponding adapter number + for (mfxU8 i = 0; i < sizeof(implTypes) / sizeof(implTypes[0]); i++) { + if (implTypes[i].impl == baseImpl) { + adapterNum = implTypes[i].adapterID; + break; + } + } + + POINT point = { 0, 0 }; + HWND window = WindowFromPoint(point); + + result = g_hwdevice->Init(window, 0, adapterNum); + if (result != MFX_ERR_NONE) { + return result; + } + + g_hwdevice->GetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, deviceHandle); + + + D3DAllocatorParams dx9_allocParam; + dx9_allocParam.pManager = reinterpret_cast<IDirect3DDeviceManager9 *>(*deviceHandle); + DX9_Alloc_Init(&dx9_allocParam); + return MFX_ERR_NONE; +} + +void DX9_CleanupHWDevice() +{ + if (g_hwdevice) { + // g_hwdevice->Close(); + delete g_hwdevice; + g_hwdevice = NULL; + } + if (m_manager && m_hDecoder) { + m_manager->CloseDeviceHandle(m_hDecoder); + m_manager = NULL; + m_hDecoder = NULL; + } + + if (m_manager && m_hProcessor) { + m_manager->CloseDeviceHandle(m_hProcessor); + m_manager = NULL; + m_hProcessor = NULL; + } + + if (m_decoderService) { + // delete m_decoderService; + m_decoderService = NULL; + } + + if (m_processorService) { + // delete m_processorService; + m_processorService = NULL; + } +} + +D3DFORMAT ConvertMfxFourccToD3dFormat(mfxU32 fourcc) +{ + switch (fourcc) + { + case MFX_FOURCC_NV12: + return D3DFMT_NV12; + case MFX_FOURCC_YV12: + return D3DFMT_YV12; + case MFX_FOURCC_YUY2: + return D3DFMT_YUY2; + case MFX_FOURCC_RGB3: + return D3DFMT_R8G8B8; + case MFX_FOURCC_RGB4: + return D3DFMT_A8R8G8B8; + case MFX_FOURCC_P8: + return D3DFMT_P8; + case MFX_FOURCC_P010: + return D3DFMT_P010; + case MFX_FOURCC_A2RGB10: + return D3DFMT_A2R10G10B10; + default: + return D3DFMT_UNKNOWN; + } +} + +mfxStatus dx9_simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr) +{ + pthis; // To suppress warning for this unused parameter + + if (!ptr || !mid) + return MFX_ERR_NULL_PTR; + + mfxHDLPair *dxmid = (mfxHDLPair*)mid; + IDirect3DSurface9 *pSurface = static_cast<IDirect3DSurface9*>(dxmid->first); + if (pSurface == 0) + return MFX_ERR_INVALID_HANDLE; + + D3DSURFACE_DESC desc; + HRESULT hr = pSurface->GetDesc(&desc); + if (FAILED(hr)) + return MFX_ERR_LOCK_MEMORY; + + if (desc.Format != D3DFMT_NV12 && + desc.Format != D3DFMT_YV12 && + desc.Format != D3DFMT_YUY2 && + desc.Format != D3DFMT_R8G8B8 && + desc.Format != D3DFMT_A8R8G8B8 && + desc.Format != D3DFMT_P8 && + desc.Format != D3DFMT_P010 && + desc.Format != D3DFMT_A2R10G10B10) + return MFX_ERR_LOCK_MEMORY; + + D3DLOCKED_RECT locked; + + hr = pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK); + if (FAILED(hr)) + return MFX_ERR_LOCK_MEMORY; + + switch ((DWORD)desc.Format) + { + case D3DFMT_NV12: + ptr->Pitch = (mfxU16)locked.Pitch; + ptr->Y = (mfxU8 *)locked.pBits; + ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch; + ptr->V = ptr->U + 1; + break; + case D3DFMT_YV12: + ptr->Pitch = (mfxU16)locked.Pitch; + ptr->Y = (mfxU8 *)locked.pBits; + ptr->V = ptr->Y + desc.Height * locked.Pitch; + ptr->U = ptr->V + (desc.Height * locked.Pitch) / 4; + break; + case D3DFMT_YUY2: + ptr->Pitch = (mfxU16)locked.Pitch; + ptr->Y = (mfxU8 *)locked.pBits; + ptr->U = ptr->Y + 1; + ptr->V = ptr->Y + 3; + break; + case D3DFMT_R8G8B8: + ptr->Pitch = (mfxU16)locked.Pitch; + ptr->B = (mfxU8 *)locked.pBits; + ptr->G = ptr->B + 1; + ptr->R = ptr->B + 2; + break; + case D3DFMT_A8R8G8B8: + case D3DFMT_A2R10G10B10: + ptr->Pitch = (mfxU16)locked.Pitch; + ptr->B = (mfxU8 *)locked.pBits; + ptr->G = ptr->B + 1; + ptr->R = ptr->B + 2; + ptr->A = ptr->B + 3; + break; + case D3DFMT_P8: + ptr->Pitch = (mfxU16)locked.Pitch; + ptr->Y = (mfxU8 *)locked.pBits; + ptr->U = 0; + ptr->V = 0; + break; + case D3DFMT_P010: + ptr->PitchHigh = (mfxU16)(locked.Pitch / (1 << 16)); + ptr->PitchLow = (mfxU16)(locked.Pitch % (1 << 16)); + ptr->Y = (mfxU8 *)locked.pBits; + ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch; + ptr->V = ptr->U + 1; + break; + } + + return MFX_ERR_NONE; +} + +mfxStatus dx9_simple_unlock(mfxHDL, mfxMemId mid, mfxFrameData* ptr) +{ + if (!mid) + return MFX_ERR_NULL_PTR; + + mfxHDLPair *dxmid = (mfxHDLPair*)mid; + IDirect3DSurface9 *pSurface = static_cast<IDirect3DSurface9*>(dxmid->first); + if (pSurface == 0) + return MFX_ERR_INVALID_HANDLE; + + pSurface->UnlockRect(); + + if (NULL != ptr) + { + ptr->Pitch = 0; + ptr->Y = 0; + ptr->U = 0; + ptr->V = 0; + } + + return MFX_ERR_NONE; +} + +mfxStatus dx9_simple_gethdl(mfxHDL, mfxMemId mid, mfxHDL* handle) +{ + if (!mid || !handle) + return MFX_ERR_NULL_PTR; + + mfxHDLPair *dxMid = (mfxHDLPair*)mid; + *handle = dxMid->first; + return MFX_ERR_NONE; +} + +mfxStatus _dx9_simple_free(mfxFrameAllocResponse* response) +{ + if (!response) + return MFX_ERR_NULL_PTR; + + mfxStatus sts = MFX_ERR_NONE; + + if (response->mids) { + for (mfxU32 i = 0; i < response->NumFrameActual; i++) { + if (response->mids[i]) { + mfxHDLPair *dxMids = (mfxHDLPair*)response->mids[i]; + static_cast<IDirect3DSurface9*>(dxMids->first)->Release(); + } + } + MSDK_SAFE_FREE(response->mids[0]); + } + MSDK_SAFE_FREE(response->mids); + + return sts; +} + +mfxStatus dx9_simple_free(mfxHDL pthis, mfxFrameAllocResponse* response) +{ + if (NULL == response) + return MFX_ERR_NULL_PTR; + + if (dx9_allocResponses.find(response->mids) == dx9_allocResponses.end()) { + // Decode free response handling + if (--dx9_allocDecodeRefCount[pthis] == 0) { + _dx9_simple_free(response); + dx9_allocDecodeResponses.erase(pthis); + dx9_allocDecodeRefCount.erase(pthis); + } + } else { + // Encode and VPP free response handling + dx9_allocResponses.erase(response->mids); + _dx9_simple_free(response); + } + + return MFX_ERR_NONE; +} + +mfxStatus _dx9_simple_alloc(mfxFrameAllocRequest* request, mfxFrameAllocResponse* response) +{ + HRESULT hr; + + MSDK_CHECK_POINTER(request, MFX_ERR_NULL_PTR); + if (request->NumFrameSuggested == 0) + return MFX_ERR_UNKNOWN; + + D3DFORMAT format = ConvertMfxFourccToD3dFormat(request->Info.FourCC); + + if (format == D3DFMT_UNKNOWN) + return MFX_ERR_UNSUPPORTED; + + DWORD target; + + if (MFX_MEMTYPE_DXVA2_DECODER_TARGET & request->Type) + { + target = DXVA2_VideoDecoderRenderTarget; + } + else if (MFX_MEMTYPE_DXVA2_PROCESSOR_TARGET & request->Type) + { + target = DXVA2_VideoProcessorRenderTarget; + } + else + return MFX_ERR_UNSUPPORTED; + + IDirectXVideoAccelerationService* videoService = NULL; + + if (target == DXVA2_VideoProcessorRenderTarget) { + if (!m_hProcessor) { + hr = m_manager->OpenDeviceHandle(&m_hProcessor); + if (FAILED(hr)) + return MFX_ERR_MEMORY_ALLOC; + + hr = m_manager->GetVideoService(m_hProcessor, IID_IDirectXVideoProcessorService, (void**)&m_processorService); + if (FAILED(hr)) + return MFX_ERR_MEMORY_ALLOC; + } + videoService = m_processorService; + } + else { + if (!m_hDecoder) + { + hr = m_manager->OpenDeviceHandle(&m_hDecoder); + if (FAILED(hr)) + return MFX_ERR_MEMORY_ALLOC; + + hr = m_manager->GetVideoService(m_hDecoder, IID_IDirectXVideoDecoderService, (void**)&m_decoderService); + if (FAILED(hr)) + return MFX_ERR_MEMORY_ALLOC; + } + videoService = m_decoderService; + } + + mfxHDLPair *dxMids = NULL, **dxMidPtrs = NULL; + dxMids = (mfxHDLPair*)calloc(request->NumFrameSuggested, sizeof(mfxHDLPair)); + dxMidPtrs = (mfxHDLPair**)calloc(request->NumFrameSuggested, sizeof(mfxHDLPair*)); + + if (!dxMids || !dxMidPtrs) { + MSDK_SAFE_FREE(dxMids); + MSDK_SAFE_FREE(dxMidPtrs); + return MFX_ERR_MEMORY_ALLOC; + } + + response->mids = (mfxMemId*)dxMidPtrs; + response->NumFrameActual = request->NumFrameSuggested; + + if (request->Type & MFX_MEMTYPE_EXTERNAL_FRAME) { + for (int i = 0; i < request->NumFrameSuggested; i++) { + hr = videoService->CreateSurface(request->Info.Width, request->Info.Height, 0, format, + D3DPOOL_DEFAULT, m_surfaceUsage, target, (IDirect3DSurface9**)&dxMids[i].first, &dxMids[i].second); + if (FAILED(hr)) { + _dx9_simple_free(response); + MSDK_SAFE_FREE(dxMids); + return MFX_ERR_MEMORY_ALLOC; + } + dxMidPtrs[i] = &dxMids[i]; + } + } + else { + safe_array<IDirect3DSurface9*> dxSrf(new IDirect3DSurface9*[request->NumFrameSuggested]); + if (!dxSrf.get()) + { + MSDK_SAFE_FREE(dxMids); + return MFX_ERR_MEMORY_ALLOC; + } + hr = videoService->CreateSurface(request->Info.Width, request->Info.Height, request->NumFrameSuggested - 1, format, + D3DPOOL_DEFAULT, m_surfaceUsage, target, dxSrf.get(), NULL); + if (FAILED(hr)) + { + MSDK_SAFE_FREE(dxMids); + return MFX_ERR_MEMORY_ALLOC; + } + + + for (int i = 0; i < request->NumFrameSuggested; i++) { + dxMids[i].first = dxSrf.get()[i]; + dxMidPtrs[i] = &dxMids[i]; + } + } + return MFX_ERR_NONE; +} + +mfxStatus dx9_simple_alloc(mfxHDL pthis, mfxFrameAllocRequest* request, mfxFrameAllocResponse* response) +{ + mfxStatus sts = MFX_ERR_NONE; + + if (request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) + return MFX_ERR_UNSUPPORTED; + + if (dx9_allocDecodeResponses.find(pthis) != dx9_allocDecodeResponses.end() && + MFX_MEMTYPE_EXTERNAL_FRAME & request->Type && + MFX_MEMTYPE_FROM_DECODE & request->Type) { + // Memory for this request was already allocated during manual allocation stage. Return saved response + // When decode acceleration device (DXVA) is created it requires a list of d3d surfaces to be passed. + // Therefore Media SDK will ask for the surface info/mids again at Init() stage, thus requiring us to return the saved response + // (No such restriction applies to Encode or VPP) + *response = dx9_allocDecodeResponses[pthis]; + dx9_allocDecodeRefCount[pthis]++; + } else { + sts = _dx9_simple_alloc(request, response); + + if (MFX_ERR_NONE == sts) { + if ( MFX_MEMTYPE_EXTERNAL_FRAME & request->Type && + MFX_MEMTYPE_FROM_DECODE & request->Type) { + // Decode alloc response handling + dx9_allocDecodeResponses[pthis] = *response; + dx9_allocDecodeRefCount[pthis]++; + } else { + // Encode and VPP alloc response handling + dx9_allocResponses[response->mids] = pthis; + } + } + } + + return sts; +}
View file
obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/common_directx9.h
Added
@@ -0,0 +1,70 @@ +/********************************************************************************* + +INTEL CORPORATION PROPRIETARY INFORMATION +This software is supplied under the terms of a license agreement or nondisclosure +agreement with Intel Corporation and may not be copied or disclosed except in +accordance with the terms of that agreement +Copyright(c) 2011-2014 Intel Corporation. All Rights Reserved. + +**********************************************************************************/ + +#pragma once + +#include "common_utils.h" +#include <initguid.h> +#include <d3d9.h> +#include <dxva2api.h> +#include <dxva.h> +#include <windows.h> + +#define VIDEO_MAIN_FORMAT D3DFMT_YUY2 + +class IGFXS3DControl; + +/** Direct3D 9 device implementation. +@note Can be initilized for only 1 or two 2 views. Handle to +MFX_HANDLE_GFXS3DCONTROL must be set prior if initializing for 2 views. + +@note Device always set D3DPRESENT_PARAMETERS::Windowed to TRUE. +*/ + template <class T> + class safe_array + { + public: + safe_array(T *ptr = 0):m_ptr(ptr) + { // construct from object pointer + }; + ~safe_array() + { + reset(0); + } + T* get() + { // return wrapped pointer + return m_ptr; + } + T* release() + { // return wrapped pointer and give up ownership + T* ptr = m_ptr; + m_ptr = 0; + return ptr; + } + void reset(T* ptr) + { // destroy designated object and store new pointer + if (m_ptr) + { + delete[] m_ptr; + } + m_ptr = ptr; + } + protected: + T* m_ptr; // the wrapped object pointer + }; + +mfxStatus dx9_simple_alloc(mfxHDL pthis, mfxFrameAllocRequest* request, mfxFrameAllocResponse* response); +mfxStatus dx9_simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr); +mfxStatus dx9_simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr); +mfxStatus dx9_simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL* handle); +mfxStatus dx9_simple_free(mfxHDL pthis, mfxFrameAllocResponse* response); + +mfxStatus DX9_CreateHWDevice(mfxSession session, mfxHDL* deviceHandle, HWND hWnd, bool bCreateSharedHandles); +void DX9_CleanupHWDevice();
View file
obs-studio-0.16.6.tar.xz/plugins/obs-qsv11/common_utils.h -> obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/common_utils.h
Changed
@@ -95,7 +95,7 @@ int GetFreeTaskIndex(Task* pTaskPool, mfxU16 nPoolSize); // Initialize Intel Media SDK Session, device/display and memory manager -mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles = false); +mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles = false, bool dx9hack = false); // Release resources (device/display) void Release();
View file
obs-studio-0.16.6.tar.xz/plugins/obs-qsv11/common_utils_windows.cpp -> obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/common_utils_windows.cpp
Changed
@@ -16,13 +16,14 @@ #include "common_directx.h" #elif DX11_D3D #include "common_directx11.h" +#include "common_directx9.h" #endif /* ======================================================= * Windows implementation of OS-specific utility functions */ -mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles) +mfxStatus Initialize(mfxIMPL impl, mfxVersion ver, MFXVideoSession* pSession, mfxFrameAllocator* pmfxAllocator, bool bCreateSharedHandles, bool dx9hack) { bCreateSharedHandles; // (Hugh) Currently unused pmfxAllocator; // (Hugh) Currently unused @@ -30,10 +31,10 @@ mfxStatus sts = MFX_ERR_NONE; // If mfxFrameAllocator is provided it means we need to setup DirectX device and memory allocator - if (pmfxAllocator) { - // Initialize Intel Media SDK Session - sts = pSession->Init(impl, &ver); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + if (pmfxAllocator && !dx9hack) { + // Initialize Intel Media SDK Session + sts = pSession->Init(impl, &ver); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); // Create DirectX device context mfxHDL deviceHandle; @@ -54,13 +55,37 @@ // Since we are using video memory we must provide Media SDK with an external allocator sts = pSession->SetFrameAllocator(pmfxAllocator); MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + } else if (pmfxAllocator && dx9hack) { + // Initialize Intel Media SDK Session + sts = pSession->Init(impl, &ver); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Create DirectX device context + mfxHDL deviceHandle; + sts = DX9_CreateHWDevice(*pSession, &deviceHandle, NULL, bCreateSharedHandles); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // Provide device manager to Media SDK + sts = pSession->SetHandle(MFX_HANDLE_D3D9_DEVICE_MANAGER, deviceHandle); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + pmfxAllocator->pthis = *pSession; // We use Media SDK session ID as the allocation identifier + pmfxAllocator->Alloc = dx9_simple_alloc; + pmfxAllocator->Free = dx9_simple_free; + pmfxAllocator->Lock = dx9_simple_lock; + pmfxAllocator->Unlock = dx9_simple_unlock; + pmfxAllocator->GetHDL = dx9_simple_gethdl; + + // Since we are using video memory we must provide Media SDK with an external allocator + sts = pSession->SetFrameAllocator(pmfxAllocator); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + } else { + // Initialize Intel Media SDK Session + sts = pSession->Init(impl, &ver); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); } - else - { - // Initialize Intel Media SDK Session - sts = pSession->Init(impl, &ver); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - } return sts; } @@ -68,6 +93,7 @@ { #if defined(DX9_D3D) || defined(DX11_D3D) CleanupHWDevice(); + DX9_CleanupHWDevice(); #endif }
View file
obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/data/locale/da-DK.ini
Added
@@ -0,0 +1,12 @@ +TargetUsage="TargetUsage" +Bitrate="Bithastighed" +MaxBitrate="Maks. bithastighed" +RateControl="Hastighedskontrol" +KeyframeIntervalSec="Keyframe-interval (sek., 0= auto)" +Profile="Profil" +AsyncDepth="Asynk. dybde" +Accuracy="Nøjagtighed" +Convergence="Konvergens" +ICQQuality="ICQ-kvalitet" +LookAheadDepth="Lookahead-dybde" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-qsv11/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/data/locale/tr-TR.ini
Changed
@@ -1,6 +1,8 @@ +TargetUsage="Hedef Kullanımı" Bitrate="Bit hızı" MaxBitrate="Maks Bit hızı" KeyframeIntervalSec="Anahtarkare Aralığı (saniye, 0=otomatik)" Profile="Profil" Accuracy="Doğruluk" +ICQQuality="ICQ Kalitesi"
View file
obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/device_directx9.cpp
Added
@@ -0,0 +1,451 @@ +/********************************************************************************* + +INTEL CORPORATION PROPRIETARY INFORMATION +This software is supplied under the terms of a license agreement or nondisclosure +agreement with Intel Corporation and may not be copied or disclosed except in +accordance with the terms of that agreement +Copyright(c) 2011-2015 Intel Corporation. All Rights Reserved. + +**********************************************************************************/ + +// #include "mfx_samples_config.h" + +#if defined(WIN32) || defined(WIN64) + +//prefast singnature used in combaseapi.h +#ifndef _PREFAST_ + #pragma warning(disable:4068) +#endif + +#include "device_directx9.h" +// #include "igfx_s3dcontrol.h" + +#include "atlbase.h" + +// Macros +#define MSDK_ZERO_MEMORY(VAR) {memset(&VAR, 0, sizeof(VAR));} +#define MSDK_MEMCPY_VAR(dstVarName, src, count) memcpy_s(&(dstVarName), sizeof(dstVarName), (src), (count)) + +CD3D9Device::CD3D9Device() +{ + m_pD3D9 = NULL; + m_pD3DD9 = NULL; + m_pDeviceManager9 = NULL; + MSDK_ZERO_MEMORY(m_D3DPP); + m_resetToken = 0; + + m_nViews = 0; + m_pS3DControl = NULL; + + MSDK_ZERO_MEMORY(m_backBufferDesc); + m_pDXVAVPS = NULL; + m_pDXVAVP_Left = NULL; + m_pDXVAVP_Right = NULL; + + MSDK_ZERO_MEMORY(m_targetRect); + + MSDK_ZERO_MEMORY(m_VideoDesc); + MSDK_ZERO_MEMORY(m_BltParams); + MSDK_ZERO_MEMORY(m_Sample); + + // Initialize DXVA structures + + DXVA2_AYUVSample16 color = { + 0x8000, // Cr + 0x8000, // Cb + 0x1000, // Y + 0xffff // Alpha + }; + + DXVA2_ExtendedFormat format = { // DestFormat + DXVA2_SampleProgressiveFrame, // SampleFormat + DXVA2_VideoChromaSubsampling_MPEG2, // VideoChromaSubsampling + DXVA_NominalRange_0_255, // NominalRange + DXVA2_VideoTransferMatrix_BT709, // VideoTransferMatrix + DXVA2_VideoLighting_bright, // VideoLighting + DXVA2_VideoPrimaries_BT709, // VideoPrimaries + DXVA2_VideoTransFunc_709 // VideoTransferFunction + }; + + // init m_VideoDesc structure + MSDK_MEMCPY_VAR(m_VideoDesc.SampleFormat, &format, sizeof(DXVA2_ExtendedFormat)); + m_VideoDesc.SampleWidth = 0; + m_VideoDesc.SampleHeight = 0; + m_VideoDesc.InputSampleFreq.Numerator = 60; + m_VideoDesc.InputSampleFreq.Denominator = 1; + m_VideoDesc.OutputFrameFreq.Numerator = 60; + m_VideoDesc.OutputFrameFreq.Denominator = 1; + + // init m_BltParams structure + MSDK_MEMCPY_VAR(m_BltParams.DestFormat, &format, sizeof(DXVA2_ExtendedFormat)); + MSDK_MEMCPY_VAR(m_BltParams.BackgroundColor, &color, sizeof(DXVA2_AYUVSample16)); + + // init m_Sample structure + m_Sample.Start = 0; + m_Sample.End = 1; + m_Sample.SampleFormat = format; + m_Sample.PlanarAlpha.Fraction = 0; + m_Sample.PlanarAlpha.Value = 1; + + m_bIsA2rgb10 = FALSE; +} + +bool CD3D9Device::CheckOverlaySupport() +{ + D3DCAPS9 d3d9caps; + D3DOVERLAYCAPS d3doverlaycaps = {0}; + IDirect3D9ExOverlayExtension *d3d9overlay = NULL; + bool overlaySupported = false; + + memset(&d3d9caps, 0, sizeof(d3d9caps)); + HRESULT hr = m_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3d9caps); + if (FAILED(hr) || !(d3d9caps.Caps & D3DCAPS_OVERLAY)) + { + overlaySupported = false; + } + else + { + hr = m_pD3D9->QueryInterface(IID_PPV_ARGS(&d3d9overlay)); + if (FAILED(hr) || (d3d9overlay == NULL)) + { + overlaySupported = false; + } + else + { + hr = d3d9overlay->CheckDeviceOverlayType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + m_D3DPP.BackBufferWidth, + m_D3DPP.BackBufferHeight, + m_D3DPP.BackBufferFormat, NULL, + D3DDISPLAYROTATION_IDENTITY, &d3doverlaycaps); + MSDK_SAFE_RELEASE(d3d9overlay); + + if (FAILED(hr)) + { + overlaySupported = false; + } + else + { + overlaySupported = true; + } + } + } + + return overlaySupported; +} + +mfxStatus CD3D9Device::FillD3DPP(mfxHDL hWindow, mfxU16 nViews, D3DPRESENT_PARAMETERS &D3DPP) +{ + mfxStatus sts = MFX_ERR_NONE; + + D3DPP.Windowed = true; + D3DPP.hDeviceWindow = (HWND)hWindow; + + D3DPP.Flags = D3DPRESENTFLAG_VIDEO; + D3DPP.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + D3DPP.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // note that this setting leads to an implicit timeBeginPeriod call + D3DPP.BackBufferCount = 1; + D3DPP.BackBufferFormat = (m_bIsA2rgb10) ? D3DFMT_A2R10G10B10 : D3DFMT_X8R8G8B8; + + if (hWindow) + { + RECT r; + GetClientRect((HWND)hWindow, &r); + int x = GetSystemMetrics(SM_CXSCREEN); + int y = GetSystemMetrics(SM_CYSCREEN); + D3DPP.BackBufferWidth = min(r.right - r.left, x); + D3DPP.BackBufferHeight = min(r.bottom - r.top, y); + } + else + { + D3DPP.BackBufferWidth = GetSystemMetrics(SM_CYSCREEN); + D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN); + } + // + // Mark the back buffer lockable if software DXVA2 could be used. + // This is because software DXVA2 device requires a lockable render target + // for the optimal performance. + // + { + D3DPP.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + } + + bool isOverlaySupported = CheckOverlaySupport(); + if (2 == nViews && !isOverlaySupported) + return MFX_ERR_UNSUPPORTED; + + bool needOverlay = (2 == nViews) ? true : false; + + D3DPP.SwapEffect = needOverlay ? D3DSWAPEFFECT_OVERLAY : D3DSWAPEFFECT_DISCARD; + + return sts; +} + +mfxStatus CD3D9Device::Init( + mfxHDL hWindow, + mfxU16 nViews, + mfxU32 nAdapterNum) +{ + mfxStatus sts = MFX_ERR_NONE; + + if (2 < nViews) + return MFX_ERR_UNSUPPORTED; + + m_nViews = nViews; + + HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &m_pD3D9); + if (!m_pD3D9 || FAILED(hr)) + return MFX_ERR_DEVICE_FAILED; + + ZeroMemory(&m_D3DPP, sizeof(m_D3DPP)); + sts = FillD3DPP(hWindow, nViews, m_D3DPP); + MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + hr = m_pD3D9->CreateDeviceEx( + nAdapterNum, + D3DDEVTYPE_HAL, + (HWND)hWindow, + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE, + &m_D3DPP, + NULL, + &m_pD3DD9); + if (FAILED(hr)) + return MFX_ERR_NULL_PTR; + + if(hWindow) + { + hr = m_pD3DD9->ResetEx(&m_D3DPP, NULL); + if (FAILED(hr)) + return MFX_ERR_UNDEFINED_BEHAVIOR; + hr = m_pD3DD9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); + if (FAILED(hr)) + return MFX_ERR_UNDEFINED_BEHAVIOR; + } + UINT resetToken = 0; + + hr = DXVA2CreateDirect3DDeviceManager9(&resetToken, &m_pDeviceManager9); + if (FAILED(hr)) + return MFX_ERR_NULL_PTR; + + hr = m_pDeviceManager9->ResetDevice(m_pD3DD9, resetToken); + if (FAILED(hr)) + return MFX_ERR_UNDEFINED_BEHAVIOR; + + m_resetToken = resetToken; + + return sts; +} + +mfxStatus CD3D9Device::Reset() +{ + HRESULT hr = NO_ERROR; + MSDK_CHECK_POINTER(m_pD3DD9, MFX_ERR_NULL_PTR); + + if (m_D3DPP.Windowed) + { + RECT r; + GetClientRect((HWND)m_D3DPP.hDeviceWindow, &r); + int x = GetSystemMetrics(SM_CXSCREEN); + int y = GetSystemMetrics(SM_CYSCREEN); + m_D3DPP.BackBufferWidth = min(r.right - r.left, x); + m_D3DPP.BackBufferHeight = min(r.bottom - r.top, y); + } + else + { + m_D3DPP.BackBufferWidth = GetSystemMetrics(SM_CXSCREEN); + m_D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN); + } + + // Reset will change the parameters, so use a copy instead. + D3DPRESENT_PARAMETERS d3dpp = m_D3DPP; + hr = m_pD3DD9->ResetEx(&d3dpp, NULL); + + if (FAILED(hr)) + return MFX_ERR_UNDEFINED_BEHAVIOR; + + hr = m_pDeviceManager9->ResetDevice(m_pD3DD9, m_resetToken); + if (FAILED(hr)) + return MFX_ERR_UNDEFINED_BEHAVIOR; + + return MFX_ERR_NONE; +} + +void CD3D9Device::Close() +{ + MSDK_SAFE_RELEASE(m_pDXVAVP_Left); + MSDK_SAFE_RELEASE(m_pDXVAVP_Right); + MSDK_SAFE_RELEASE(m_pDXVAVPS); + + MSDK_SAFE_RELEASE(m_pDeviceManager9); + MSDK_SAFE_RELEASE(m_pD3DD9); + MSDK_SAFE_RELEASE(m_pD3D9); + m_pS3DControl = NULL; +} + +CD3D9Device::~CD3D9Device() +{ + Close(); +} + +mfxStatus CD3D9Device::GetHandle(mfxHandleType type, mfxHDL *pHdl) +{ + if (MFX_HANDLE_DIRECT3D_DEVICE_MANAGER9 == type && pHdl != NULL) + { + *pHdl = m_pDeviceManager9; + + return MFX_ERR_NONE; + } + else if (MFX_HANDLE_GFXS3DCONTROL == type && pHdl != NULL) + { + *pHdl = m_pS3DControl; + + return MFX_ERR_NONE; + } + return MFX_ERR_UNSUPPORTED; +} + +mfxStatus CD3D9Device::SetHandle(mfxHandleType type, mfxHDL hdl) +{ + if (MFX_HANDLE_GFXS3DCONTROL == type && hdl != NULL) + { + m_pS3DControl = (IGFXS3DControl*)hdl; + return MFX_ERR_NONE; + } + else if (MFX_HANDLE_DEVICEWINDOW == type && hdl != NULL) //for render window handle + { + m_D3DPP.hDeviceWindow = (HWND)hdl; + return MFX_ERR_NONE; + } + return MFX_ERR_UNSUPPORTED; +} + +mfxStatus CD3D9Device::RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc) +{ + HRESULT hr = S_OK; + + if (!(1 == m_nViews || (2 == m_nViews && NULL != m_pS3DControl))) + return MFX_ERR_UNDEFINED_BEHAVIOR; + + MSDK_CHECK_POINTER(pSurface, MFX_ERR_NULL_PTR); + MSDK_CHECK_POINTER(m_pDeviceManager9, MFX_ERR_NOT_INITIALIZED); + MSDK_CHECK_POINTER(pmfxAlloc, MFX_ERR_NULL_PTR); + + // don't try to render second view if output rect changed since first view + if (2 == m_nViews && (0 != pSurface->Info.FrameId.ViewId)) + return MFX_ERR_NONE; + + hr = m_pD3DD9->TestCooperativeLevel(); + + switch (hr) + { + case D3D_OK : + break; + + case D3DERR_DEVICELOST : + { + return MFX_ERR_DEVICE_LOST; + } + + case D3DERR_DEVICENOTRESET : + { + return MFX_ERR_UNKNOWN; + } + + default : + { + return MFX_ERR_UNKNOWN; + } + } + + CComPtr<IDirect3DSurface9> pBackBuffer; + hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); + + mfxHDLPair* dxMemId = (mfxHDLPair*)pSurface->Data.MemId; + + hr = m_pD3DD9->StretchRect((IDirect3DSurface9*)dxMemId->first, NULL, pBackBuffer, NULL, D3DTEXF_LINEAR); + if (FAILED(hr)) + { + return MFX_ERR_UNKNOWN; + } + + if (SUCCEEDED(hr)&& (1 == m_nViews || pSurface->Info.FrameId.ViewId == 1)) + { + hr = m_pD3DD9->Present(NULL, NULL, NULL, NULL); + } + + return SUCCEEDED(hr) ? MFX_ERR_NONE : MFX_ERR_DEVICE_FAILED; +} + +/* +mfxStatus CD3D9Device::CreateVideoProcessors() +{ + if (!(1 == m_nViews || (2 == m_nViews && NULL != m_pS3DControl))) + return MFX_ERR_UNDEFINED_BEHAVIOR; + + MSDK_SAFE_RELEASE(m_pDXVAVP_Left); + MSDK_SAFE_RELEASE(m_pDXVAVP_Right); + + HRESULT hr ; + + if (2 == m_nViews && NULL != m_pS3DControl) + { + hr = m_pS3DControl->SetDevice(m_pDeviceManager9); + if (FAILED(hr)) + { + return MFX_ERR_DEVICE_FAILED; + } + } + + ZeroMemory(&m_backBufferDesc, sizeof(m_backBufferDesc)); + IDirect3DSurface9 *backBufferTmp = NULL; + hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBufferTmp); + if (NULL != backBufferTmp) + backBufferTmp->GetDesc(&m_backBufferDesc); + MSDK_SAFE_RELEASE(backBufferTmp); + + if (SUCCEEDED(hr)) + { + // Create DXVA2 Video Processor Service. + hr = DXVA2CreateVideoService(m_pD3DD9, + IID_IDirectXVideoProcessorService, + (void**)&m_pDXVAVPS); + } + + if (2 == m_nViews) + { + // Activate L channel + if (SUCCEEDED(hr)) + { + hr = m_pS3DControl->SelectLeftView(); + } + + if (SUCCEEDED(hr)) + { + // Create VPP device for the L channel + hr = m_pDXVAVPS->CreateVideoProcessor(DXVA2_VideoProcProgressiveDevice, + &m_VideoDesc, + m_D3DPP.BackBufferFormat, + 1, + &m_pDXVAVP_Left); + } + + // Activate R channel + if (SUCCEEDED(hr)) + { + hr = m_pS3DControl->SelectRightView(); + } + + } + if (SUCCEEDED(hr)) + { + hr = m_pDXVAVPS->CreateVideoProcessor(DXVA2_VideoProcProgressiveDevice, + &m_VideoDesc, + m_D3DPP.BackBufferFormat, + 1, + &m_pDXVAVP_Right); + } + + return SUCCEEDED(hr) ? MFX_ERR_NONE : MFX_ERR_DEVICE_FAILED; +} +*/ + +#endif // #if defined(WIN32) || defined(WIN64) \ No newline at end of file
View file
obs-studio-0.17.0.tar.xz/plugins/obs-qsv11/device_directx9.h
Added
@@ -0,0 +1,118 @@ +/********************************************************************************* + +INTEL CORPORATION PROPRIETARY INFORMATION +This software is supplied under the terms of a license agreement or nondisclosure +agreement with Intel Corporation and may not be copied or disclosed except in +accordance with the terms of that agreement +Copyright(c) 2011-2014 Intel Corporation. All Rights Reserved. + +**********************************************************************************/ + +#pragma once + +#if defined( _WIN32 ) || defined ( _WIN64 ) + +#include "common_utils.h" + +#pragma warning(disable : 4201) +#include <initguid.h> +#include <d3d9.h> +#include <dxva2api.h> +#include <dxva.h> +#include <windows.h> + +#define VIDEO_MAIN_FORMAT D3DFMT_YUY2 + +class IGFXS3DControl; + + +/// Base class for hw device +class CHWDevice +{ +public: + virtual ~CHWDevice(){} + /** Initializes device for requested processing. + @param[in] hWindow Window handle to bundle device to. + @param[in] nViews Number of views to process. + @param[in] nAdapterNum Number of adapter to use + */ + virtual mfxStatus Init( + mfxHDL hWindow, + mfxU16 nViews, + mfxU32 nAdapterNum) = 0; + /// Reset device. + virtual mfxStatus Reset() = 0; + /// Get handle can be used for MFX session SetHandle calls + virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL *pHdl) = 0; + /** Set handle. + Particular device implementation may require other objects to operate. + */ + virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl) = 0; + virtual mfxStatus RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc) = 0; + virtual void Close() = 0; +}; + +enum { + MFX_HANDLE_GFXS3DCONTROL = 0x100, /* A handle to the IGFXS3DControl instance */ + MFX_HANDLE_DEVICEWINDOW = 0x101 /* A handle to the render window */ +}; //mfxHandleType + +/** Direct3D 9 device implementation. +@note Can be initilized for only 1 or two 2 views. Handle to +MFX_HANDLE_GFXS3DCONTROL must be set prior if initializing for 2 views. + +@note Device always set D3DPRESENT_PARAMETERS::Windowed to TRUE. +*/ +class CD3D9Device : public CHWDevice +{ +public: + CD3D9Device(); + virtual ~CD3D9Device(); + + virtual mfxStatus Init( + mfxHDL hWindow, + mfxU16 nViews, + mfxU32 nAdapterNum); + virtual mfxStatus Reset(); + virtual mfxStatus GetHandle(mfxHandleType type, mfxHDL *pHdl); + virtual mfxStatus SetHandle(mfxHandleType type, mfxHDL hdl); + virtual mfxStatus RenderFrame(mfxFrameSurface1 * pSurface, mfxFrameAllocator * pmfxAlloc); + virtual void UpdateTitle(double /*fps*/) { } + virtual void Close() ; + void DefineFormat(bool isA2rgb10) { m_bIsA2rgb10 = (isA2rgb10) ? TRUE : FALSE; } +protected: + mfxStatus CreateVideoProcessors(); + bool CheckOverlaySupport(); + virtual mfxStatus FillD3DPP(mfxHDL hWindow, mfxU16 nViews, D3DPRESENT_PARAMETERS &D3DPP); +private: + IDirect3D9Ex* m_pD3D9; + IDirect3DDevice9Ex* m_pD3DD9; + IDirect3DDeviceManager9* m_pDeviceManager9; + D3DPRESENT_PARAMETERS m_D3DPP; + UINT m_resetToken; + + mfxU16 m_nViews; + IGFXS3DControl* m_pS3DControl; + + + D3DSURFACE_DESC m_backBufferDesc; + + // service required to create video processors + IDirectXVideoProcessorService* m_pDXVAVPS; + //left channel processor + IDirectXVideoProcessor* m_pDXVAVP_Left; + // right channel processor + IDirectXVideoProcessor* m_pDXVAVP_Right; + + // target rectangle + RECT m_targetRect; + + // various structures for DXVA2 calls + DXVA2_VideoDesc m_VideoDesc; + DXVA2_VideoProcessBltParams m_BltParams; + DXVA2_VideoSample m_Sample; + + BOOL m_bIsA2rgb10; +}; + +#endif // #if defined( _WIN32 ) || defined ( _WIN64 ) \ No newline at end of file
View file
obs-studio-0.16.6.tar.xz/plugins/obs-text/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-text/data/locale/nl-NL.ini
Changed
@@ -9,6 +9,10 @@ Opacity="Dekking" Gradient="Kleurovergang" Gradient.Color="Overgangskleur" +Gradient.Opacity="Kleurovergang Dekking" +Gradient.Direction="Kleurovergang Richting" +BkColor="Achtergrondkleur" +BkOpacity="Achtergronddekking" Alignment="Uitlijning" Alignment.Left="Links" Alignment.Center="Midden"
View file
obs-studio-0.17.0.tar.xz/plugins/obs-text/data/locale/tr-TR.ini
Added
@@ -0,0 +1,31 @@ +TextGDIPlus="Metin (GDI+)" +Font="Yazı Tipi" +Text="Metin" +ReadFromFile="Dosyadan oku" +TextFile="Metin Dosyası (UTF-8)" +Filter.TextFiles="Metin Dosyaları" +Filter.AllFiles="Tüm Dosyalar" +Color="Renk" +Opacity="Opaklık" +Gradient="Eğim" +Gradient.Color="Eğim Rengi" +Gradient.Opacity="Eğim Saydamlığı" +Gradient.Direction="Eğim Yönü" +BkColor="Arka Plan Rengi" +BkOpacity="Arkaplan Saydamlığı" +Alignment="Hizalama" +Alignment.Left="Sol" +Alignment.Center="Ortala" +Alignment.Right="Sağ" +Vertical="Dikey" +VerticalAlignment="Dikey Hizalama" +VerticalAlignment.Top="Üst" +VerticalAlignment.Bottom="Alt" +Outline="Anahat" +Outline.Size="Anahat Boyutu" +Outline.Color="Anahat Rengi" +Outline.Opacity="Anahat Saydamlığı" +UseCustomExtents="İsteğe Bağlı Metin Boyutu Kullan" +Width="Genişlik" +Height="Yükseklik" +
View file
obs-studio-0.16.6.tar.xz/plugins/obs-text/gdiplus/obs-text.cpp -> obs-studio-0.17.0.tar.xz/plugins/obs-text/gdiplus/obs-text.cpp
Changed
@@ -787,7 +787,6 @@ if (!tex) return; - gs_reset_blend_state(); gs_effect_set_texture(gs_effect_get_param_by_name(effect, "image"), tex); gs_draw_sprite(tex, 0, cx, cy); }
View file
obs-studio-0.16.6.tar.xz/plugins/obs-transitions/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/obs-transitions/data/locale/tr-TR.ini
Changed
@@ -2,10 +2,49 @@ CutTransition="Kes" SwipeTransition="Kaydır" SlideTransition="Kaydır" +FadeToColorTransition="Fade to Color" Direction="Yönlendir" Direction.Left="Sol" Direction.Right="Sağ" Direction.Up="Yukarı" Direction.Down="Aşağı" +SwipeIn="İçeri Kaydır" Color="Renk" +LumaWipe.Image="Görüntü" +LumaWipe.Invert="Ters Çevir" +LumaWipe.Softness="Yumuşaklık" +LumaWipe.Type.BarndoorBottomLeft="Barndoor Bottom Left" +LumaWipe.Type.BarndoorHorizontal="Barndoor Horizontal" +LumaWipe.Type.BarndoorTopLeft="Barndoor Top Left" +LumaWipe.Type.BarndoorVertical="Barndoor Vertical" +LumaWipe.Type.BlindsHorizontal="Blinds Horizontal" +LumaWipe.Type.BoxBottomLeft="Box Bottom Left" +LumaWipe.Type.BoxBottomRight="Box Bottom Right" +LumaWipe.Type.BoxTopLeft="Box Top Left" +LumaWipe.Type.BoxTopRight="Box Top Right" +LumaWipe.Type.Burst="Burst" +LumaWipe.Type.CheckerboardSmall="Checkerboard Small" +LumaWipe.Type.Circles="Circles" +LumaWipe.Type.Clock="Clock" +LumaWipe.Type.Cloud="Cloud" +LumaWipe.Type.Curtain="Curtain" +LumaWipe.Type.Fan="Fan" +LumaWipe.Type.Fractal="Fractal" +LumaWipe.Type.Iris="Iris" +LumaWipe.Type.LinearHorizontal="Linear Horizontal" +LumaWipe.Type.LinearTopLeft="Linear Top Left" +LumaWipe.Type.LinearTopRight="Linear Top Right" +LumaWipe.Type.LinearVertical="Linear Vertical" +LumaWipe.Type.ParallelZigzagHorizontal="Parallel Zigzag Horizontal" +LumaWipe.Type.ParallelZigzagVertical="Parallel Zigzag Vertical" +LumaWipe.Type.Sinus9="Sinus 9" +LumaWipe.Type.Spiral="Spiral" +LumaWipe.Type.Square="Square" +LumaWipe.Type.Squares="Squares" +LumaWipe.Type.Stripes="Stripes" +LumaWipe.Type.StripsHorizontal="Strips Horizontal" +LumaWipe.Type.StripsVertical="Strips Vertical" +LumaWipe.Type.Watercolor="Watercolor" +LumaWipe.Type.ZigzagHorizontal="Zigzag Horizontal" +LumaWipe.Type.ZigzagVertical="Zigzag Vertical"
View file
obs-studio-0.16.6.tar.xz/plugins/obs-transitions/data/slide_transition.effect -> obs-studio-0.17.0.tar.xz/plugins/obs-transitions/data/slide_transition.effect
Changed
@@ -28,12 +28,11 @@ { float2 tex_a_uv = v_in.uv + tex_a_dir; float2 tex_b_uv = v_in.uv - tex_b_dir; - - float4 tex_a_sample = tex_a.Sample(textureSampler, tex_a_uv); - float4 tex_b_sample = tex_b.Sample(textureSampler, tex_b_uv); - - float val = saturate(abs((tex_a_uv.x - saturate(tex_a_uv.x)) + (tex_a_uv.y - saturate(tex_a_uv.y))) * 65535); - return lerp(tex_a_sample, tex_b_sample, val); + + return (tex_a_uv.x - saturate(tex_a_uv.x) != 0.0) || + (tex_a_uv.y - saturate(tex_a_uv.y) != 0.0) + ? tex_b.Sample(textureSampler, tex_b_uv) + : tex_a.Sample(textureSampler, tex_a_uv); } technique Slide
View file
obs-studio-0.16.6.tar.xz/plugins/rtmp-services/data/package.json -> obs-studio-0.17.0.tar.xz/plugins/rtmp-services/data/package.json
Changed
@@ -1,10 +1,10 @@ { "url": "https://obsproject.com/obs2_update/rtmp-services", - "version": 41, + "version": 43, "files": [ { "name": "services.json", - "version": 41 + "version": 43 } ] }
View file
obs-studio-0.16.6.tar.xz/plugins/rtmp-services/data/services.json -> obs-studio-0.17.0.tar.xz/plugins/rtmp-services/data/services.json
Changed
@@ -346,15 +346,6 @@ ] }, { - "name": "mSportz", - "servers": [ - { - "name": "Primary", - "url": "rtmp://52.21.78.175/mSports" - } - ] - }, - { "name": "Switchboard Live (Joicaster)", "servers": [ { @@ -439,15 +430,6 @@ ] }, { - "name": "Streamup", - "servers": [ - { - "name": "Worldwide", - "url": "rtmp://origin.streamuplive.com/app" - } - ] - }, - { "name": "connectcast.tv", "servers": [ { @@ -557,60 +539,56 @@ "common": true, "servers": [ { - "name": "US-West (San Jose, California)", - "url": "rtmp://us-west.restream.io/live" - }, - { - "name": "US-West (Los Angeles, California)", - "url": "rtmp://us-la.restream.io/live" - }, - { - "name": "US-West (Seattle, Washington)", - "url": "rtmp://us-seattle.restream.io/live" + "name": "EU-West (London, GB)", + "url": "rtmp://eu-london.restream.io/live" }, { - "name": "US-Central (Dallas, Texas)", - "url": "rtmp://us-central.restream.io/live" + "name": "EU-West (Amsterdam, NL)", + "url": "rtmp://eu-ams.restream.io/live" }, { - "name": "US-East (Washington, D.C.)", - "url": "rtmp://us-east.restream.io/live" + "name": "EU-Central (Frankfurt, DE)", + "url": "rtmp://eu-central.restream.io/live" }, { - "name": "NA-East (Toronto, Canada)", - "url": "rtmp://na-toronto.restream.io/live" + "name": "EU-East (Falkenstein, DE)", + "url": "rtmp://eu-east.restream.io/live" }, { - "name": "EU-Central (Frankfurt, Germany)", - "url": "rtmp://eu-central.restream.io/live" + "name": "Russia (Moscow)", + "url": "rtmp://ru.restream.io/live" }, { - "name": "EU-Central 2 (Frankfurt, Germany)", - "url": "rtmp://eu.restream.io/live" + "name": "US-West (Seattle, WA)", + "url": "rtmp://us-seattle.restream.io/live" }, { - "name": "EU-West (Amsterdam, Netherlands)", - "url": "rtmp://eu-ams.restream.io/live" + "name": "US-West (San Jose, CA)", + "url": "rtmp://us-west.restream.io/live" }, { - "name": "EU-West (London, Great Britain)", - "url": "rtmp://eu-london.restream.io/live" + "name": "US-Central (Dallas, TX)", + "url": "rtmp://us-central.restream.io/live" }, { - "name": "Australia (Sydney)", - "url": "rtmp://au.restream.io/live" + "name": "US-East (Washington, DC)", + "url": "rtmp://us-east.restream.io/live" }, { - "name": "Australia Secondary (Sydney)", - "url": "rtmp://au-secondary.restream.io/live" + "name": "NA-East (Toronto, Canada)", + "url": "rtmp://na-toronto.restream.io/live" }, { - "name": "South America (Sao Paulo, Brazil)", + "name": "SA (Saint Paul, Brazil)", "url": "rtmp://sa.restream.io/live" }, { "name": "Asia (Singapore)", "url": "rtmp://singapore.restream.io/live" + }, + { + "name": "Australia (Sydney)", + "url": "rtmp://au.restream.io/live" } ], "recommended": {
View file
obs-studio-0.17.0.tar.xz/plugins/vlc-video/data/locale/tr-TR.ini
Added
@@ -0,0 +1,3 @@ +VLCSource="VLC Video Kaynağı" +Playlist="Oynatma Listesi" +
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/win-capture/CMakeLists.txt
Changed
@@ -1,7 +1,9 @@ project(win-capture) set(win-capture_HEADERS + nt-stuff.h obfuscate.h + app-helpers.h hook-helpers.h inject-library.h cursor-capture.h @@ -12,6 +14,7 @@ set(win-capture_SOURCES dc-capture.c obfuscate.c + app-helpers.c inject-library.c cursor-capture.c game-capture.c
View file
obs-studio-0.17.0.tar.xz/plugins/win-capture/app-helpers.c
Added
@@ -0,0 +1,77 @@ +#include <windows.h> +#include <stdio.h> +#include "app-helpers.h" +#include "nt-stuff.h" + +WINADVAPI WINAPI ConvertSidToStringSidW(PSID sid, LPWSTR *str); + +bool is_app(HANDLE process) +{ + DWORD size_ret; + DWORD ret = 0; + HANDLE token; + + if (OpenProcessToken(process, TOKEN_QUERY, &token)) { + BOOL success = GetTokenInformation(token, TokenIsAppContainer, + &ret, sizeof(ret), &size_ret); + if (!success) { + DWORD error = GetLastError(); + int test = 0; + } + + CloseHandle(token); + } + return !!ret; +} + +wchar_t *get_app_sid(HANDLE process) +{ + wchar_t *ret = NULL; + DWORD size_ret; + BOOL success; + HANDLE token; + + if (OpenProcessToken(process, TOKEN_QUERY, &token)) { + DWORD info_len = GetSidLengthRequired(12) + + sizeof(TOKEN_APPCONTAINER_INFORMATION); + + PTOKEN_APPCONTAINER_INFORMATION info = malloc(info_len); + + success = GetTokenInformation(token, TokenAppContainerSid, + info, info_len, &size_ret); + if (success) + ConvertSidToStringSidW(info->TokenAppContainer, &ret); + + free(info); + CloseHandle(token); + } + + return ret; +} + +static const wchar_t *path_format = + L"\\Sessions\\%lu\\AppContainerNamedObjects\\%s\\%s"; + +HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name) +{ + wchar_t path[MAX_PATH]; + DWORD session_id = WTSGetActiveConsoleSessionId(); + _snwprintf(path, MAX_PATH, path_format, session_id, sid, name); + return nt_open_mutex(path); +} + +HANDLE open_app_event(const wchar_t *sid, const wchar_t *name) +{ + wchar_t path[MAX_PATH]; + DWORD session_id = WTSGetActiveConsoleSessionId(); + _snwprintf(path, MAX_PATH, path_format, session_id, sid, name); + return nt_open_event(path); +} + +HANDLE open_app_map(const wchar_t *sid, const wchar_t *name) +{ + wchar_t path[MAX_PATH]; + DWORD session_id = WTSGetActiveConsoleSessionId(); + _snwprintf(path, MAX_PATH, path_format, session_id, sid, name); + return nt_open_map(path); +}
View file
obs-studio-0.17.0.tar.xz/plugins/win-capture/app-helpers.h
Added
@@ -0,0 +1,9 @@ +#pragma once + +#include <stdbool.h> + +extern bool is_app(HANDLE process); +extern wchar_t *get_app_sid(HANDLE process); +extern HANDLE open_app_mutex(const wchar_t *sid, const wchar_t *name); +extern HANDLE open_app_event(const wchar_t *sid, const wchar_t *name); +extern HANDLE open_app_map(const wchar_t *sid, const wchar_t *name);
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/win-capture/data/locale/nl-NL.ini
Changed
@@ -13,7 +13,7 @@ GameCapture="Gamecapture" GameCapture.AnyFullscreen="Capture elke full-screen applicatie" GameCapture.CaptureWindow="Specifiek venster opnemen" -GameCapture.UseHotkey="Venster op voorgrond opnemen met hotkey" +GameCapture.UseHotkey="Venster op voorgrond opnemen met sneltoets" GameCapture.ForceScaling="Forceer Schalen" GameCapture.ScaleRes="Geschaalde resolutie" GameCapture.LimitFramerate="Begrens frame rate van de opname"
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/win-capture/data/locale/tr-TR.ini
Changed
@@ -17,4 +17,5 @@ GameCapture.LimitFramerate="Yakalama kare hızını sınırlandır" GameCapture.CaptureOverlays="Üçüncü taraf katmanları yakala (steam vb.)" GameCapture.AntiCheatHook="Anti-hile uyumluluğunu kullan" +Mode="Mod"
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/game-capture.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/game-capture.c
Changed
@@ -12,6 +12,8 @@ #include "graphics-hook-info.h" #include "window-helpers.h" #include "cursor-capture.h" +#include "app-helpers.h" +#include "nt-stuff.h" #define do_log(level, format, ...) \ blog(level, "[game-capture: '%s'] " format, \ @@ -127,13 +129,16 @@ bool dwm_capture : 1; bool initial_config : 1; bool convert_16bit : 1; + bool is_app : 1; struct game_capture_config config; ipc_pipe_server_t pipe; gs_texture_t *texture; struct hook_info *global_hook_info; - HANDLE keep_alive; + HANDLE keepalive_thread; + DWORD keepalive_thread_id; + HANDLE hook_init; HANDLE hook_restart; HANDLE hook_stop; HANDLE hook_ready; @@ -142,6 +147,8 @@ HANDLE global_hook_info_map; HANDLE target_process; HANDLE texture_mutexes[2]; + wchar_t *app_sid; + int retrying; union { struct { @@ -159,6 +166,61 @@ struct graphics_offsets offsets32 = {0}; struct graphics_offsets offsets64 = {0}; +static inline bool use_anticheat(struct game_capture *gc) +{ + return gc->config.anticheat_hook && !gc->is_app; +} + +static inline HANDLE open_mutex_plus_id(struct game_capture *gc, + const wchar_t *name, DWORD id) +{ + wchar_t new_name[64]; + _snwprintf(new_name, 64, L"%s%lu", name, id); + return gc->is_app + ? open_app_mutex(gc->app_sid, new_name) + : open_mutex(new_name); +} + +static inline HANDLE open_mutex_gc(struct game_capture *gc, + const wchar_t *name) +{ + return open_mutex_plus_id(gc, name, gc->process_id); +} + +static inline HANDLE open_event_plus_id(struct game_capture *gc, + const wchar_t *name, DWORD id) +{ + wchar_t new_name[64]; + _snwprintf(new_name, 64, L"%s%lu", name, id); + return gc->is_app + ? open_app_event(gc->app_sid, new_name) + : open_event(new_name); +} + +static inline HANDLE open_event_gc(struct game_capture *gc, + const wchar_t *name) +{ + return open_event_plus_id(gc, name, gc->process_id); +} + +static inline HANDLE open_map_plus_id(struct game_capture *gc, + const wchar_t *name, DWORD id) +{ + wchar_t new_name[64]; + _snwprintf(new_name, 64, L"%s%lu", name, id); + + debug("map id: %S", new_name); + + return gc->is_app + ? open_app_map(gc->app_sid, new_name) + : OpenFileMappingW(GC_MAPPING_FLAGS, false, new_name); +} + +static inline HANDLE open_hook_info(struct game_capture *gc) +{ + return open_map_plus_id(gc, SHMEM_HOOK_INFO, gc->process_id); +} + static inline enum gs_color_format convert_format(uint32_t format) { switch (format) { @@ -219,11 +281,22 @@ gc->data = NULL; } - close_handle(&gc->keep_alive); + if (gc->keepalive_thread) { + PostThreadMessage(gc->keepalive_thread_id, WM_QUIT, 0, 0); + WaitForSingleObject(gc->keepalive_thread, 300); + close_handle(&gc->keepalive_thread); + } + + if (gc->app_sid) { + LocalFree(gc->app_sid); + gc->app_sid = NULL; + } + close_handle(&gc->hook_restart); close_handle(&gc->hook_stop); close_handle(&gc->hook_ready); close_handle(&gc->hook_exit); + close_handle(&gc->hook_init); close_handle(&gc->hook_data_map); close_handle(&gc->global_hook_info_map); close_handle(&gc->target_process); @@ -237,10 +310,16 @@ gc->texture = NULL; } + if (gc->active) + info("capture stopped"); + gc->copy_texture = NULL; gc->wait_for_target_startup = false; gc->active = false; gc->capturing = false; + + if (gc->retrying) + gc->retrying--; } static inline void free_config(struct game_capture_config *config) @@ -473,21 +552,6 @@ return gc; } -static inline HANDLE create_event_id(bool manual_reset, bool initial_state, - const char *name, DWORD process_id) -{ - char new_name[128]; - sprintf(new_name, "%s%lu", name, process_id); - return CreateEventA(NULL, manual_reset, initial_state, new_name); -} - -static inline HANDLE open_event_id(const char *name, DWORD process_id) -{ - char new_name[128]; - sprintf(new_name, "%s%lu", name, process_id); - return OpenEventA(EVENT_ALL_ACCESS, false, new_name); -} - #define STOP_BEING_BAD \ " This is most likely due to security software. Please make sure " \ "that the OBS installation folder is excluded/ignored in the " \ @@ -570,30 +634,104 @@ } gc->process_is_64bit = is_64bit_process(gc->target_process); + gc->is_app = is_app(gc->target_process); + if (gc->is_app) { + gc->app_sid = get_app_sid(gc->target_process); + } return true; } +struct keepalive_data { + struct game_capture *gc; + HANDLE initialized; +}; + +#define DEF_FLAGS (WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS) + +static DWORD WINAPI keepalive_window_thread(struct keepalive_data *data) +{ + HANDLE initialized = data->initialized; + struct game_capture *gc = data->gc; + wchar_t new_name[64]; + WNDCLASSW wc; + HWND window; + MSG msg; + + _snwprintf(new_name, sizeof(new_name), L"%s%lu", + WINDOW_HOOK_KEEPALIVE, gc->process_id); + + memset(&wc, 0, sizeof(wc)); + wc.style = CS_OWNDC; + wc.hInstance = GetModuleHandleW(NULL); + wc.lpfnWndProc = (WNDPROC)DefWindowProc; + wc.lpszClassName = new_name; + + if (!RegisterClass(&wc)) { + warn("Failed to create keepalive window class: %lu", + GetLastError()); + return 0; + } + + window = CreateWindowExW(0, new_name, NULL, DEF_FLAGS, 0, 0, 1, 1, + NULL, NULL, wc.hInstance, NULL); + if (!window) { + warn("Failed to create keepalive window: %lu", + GetLastError()); + return 0; + } + + SetEvent(initialized); + + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + DestroyWindow(window); + UnregisterClassW(new_name, wc.hInstance); + + return 0; +} + static inline bool init_keepalive(struct game_capture *gc) { - gc->keep_alive = create_event_id(false, false, EVENT_HOOK_KEEPALIVE, - gc->process_id); - if (!gc->keep_alive) { - warn("failed to create keepalive event"); + struct keepalive_data data; + HANDLE initialized = CreateEvent(NULL, false, false, NULL); + + data.gc = gc; + data.initialized = initialized; + + gc->keepalive_thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE)keepalive_window_thread, + &data, 0, &gc->keepalive_thread_id); + if (!gc->keepalive_thread) { + warn("Failed to create keepalive window thread: %lu", + GetLastError()); return false; } + WaitForSingleObject(initialized, INFINITE); + CloseHandle(initialized); + return true; } static inline bool init_texture_mutexes(struct game_capture *gc) { - gc->texture_mutexes[0] = get_mutex_plus_id(MUTEX_TEXTURE1, - gc->process_id); - gc->texture_mutexes[1] = get_mutex_plus_id(MUTEX_TEXTURE2, - gc->process_id); + gc->texture_mutexes[0] = open_mutex_gc(gc, MUTEX_TEXTURE1); + gc->texture_mutexes[1] = open_mutex_gc(gc, MUTEX_TEXTURE2); if (!gc->texture_mutexes[0] || !gc->texture_mutexes[1]) { - warn("failed to create texture mutexes: %lu", GetLastError()); + DWORD error = GetLastError(); + if (error == 2) { + if (!gc->retrying) { + gc->retrying = 2; + info("hook not loaded yet, retrying.."); + } + } else { + warn("failed to open texture mutexes: %lu", + GetLastError()); + } return false; } @@ -603,7 +741,7 @@ /* if there's already a hook in the process, then signal and start */ static inline bool attempt_existing_hook(struct game_capture *gc) { - gc->hook_restart = open_event_id(EVENT_CAPTURE_RESTART, gc->process_id); + gc->hook_restart = open_event_gc(gc, EVENT_CAPTURE_RESTART); if (gc->hook_restart) { debug("existing hook found, signaling process: %s", gc->config.executable); @@ -635,7 +773,7 @@ static inline bool init_hook_info(struct game_capture *gc) { - gc->global_hook_info_map = get_hook_info(gc->process_id); + gc->global_hook_info_map = open_hook_info(gc); if (!gc->global_hook_info_map) { warn("init_hook_info: get_hook_info failed: %lu", GetLastError()); @@ -750,7 +888,7 @@ wchar_t *command_line_w = malloc(4096 * sizeof(wchar_t)); wchar_t *inject_path_w; wchar_t *hook_dll_w; - bool anti_cheat = gc->config.anticheat_hook; + bool anti_cheat = use_anticheat(gc); PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; bool success = false; @@ -812,11 +950,11 @@ matching_architecture = !gc->process_is_64bit; #endif - if (matching_architecture && !gc->config.anticheat_hook) { + if (matching_architecture && !use_anticheat(gc)) { info("using direct hook"); success = hook_direct(gc, hook_path); } else { - info("using helper (%s hook)", gc->config.anticheat_hook ? + info("using helper (%s hook)", use_anticheat(gc) ? "compatibility" : "direct"); success = create_inject_process(gc, inject_path, hook_dll); } @@ -838,7 +976,11 @@ "devenv", "taskmgr", "systemsettings", + "applicationframehost", "cmd", + "shellexperiencehost", + "winstore.app", + "searchui", NULL }; @@ -860,6 +1002,13 @@ return false; } +static bool target_suspended(struct game_capture *gc) +{ + return thread_is_suspended(gc->process_id, gc->thread_id); +} + +static bool init_events(struct game_capture *gc); + static bool init_hook(struct game_capture *gc) { struct dstr exe = {0}; @@ -871,8 +1020,9 @@ exe.array); } } else { - info("attempting to hook process: %s", gc->executable.array); - dstr_copy_dstr(&exe, &gc->executable); + if (get_window_exe(&exe, gc->next_window)) { + info("attempting to hook process: %s", exe.array); + } } blacklisted_process = is_blacklisted_exe(exe.array); @@ -883,16 +1033,13 @@ if (blacklisted_process) { return false; } - if (!open_target_process(gc)) { + if (target_suspended(gc)) { return false; } - if (!init_keepalive(gc)) { - return false; - } - if (!init_texture_mutexes(gc)) { + if (!open_target_process(gc)) { return false; } - if (!init_hook_info(gc)) { + if (!init_keepalive(gc)) { return false; } if (!init_pipe(gc)) { @@ -903,22 +1050,45 @@ return false; } } + if (!init_texture_mutexes(gc)) { + return false; + } + if (!init_hook_info(gc)) { + return false; + } + if (!init_events(gc)) { + return false; + } + + SetEvent(gc->hook_init); gc->window = gc->next_window; gc->next_window = NULL; gc->active = true; + gc->retrying = 0; return true; } static void setup_window(struct game_capture *gc, HWND window) { - DWORD process_id = 0; HANDLE hook_restart; + HANDLE process; - GetWindowThreadProcessId(window, &process_id); + GetWindowThreadProcessId(window, &gc->process_id); + if (gc->process_id) { + process = open_process(PROCESS_QUERY_INFORMATION, + false, gc->process_id); + if (process) { + gc->is_app = is_app(process); + if (gc->is_app) { + gc->app_sid = get_app_sid(process); + } + CloseHandle(process); + } + } /* do not wait if we're re-hooking a process */ - hook_restart = open_event_id(EVENT_CAPTURE_RESTART, process_id); + hook_restart = open_event_gc(gc, EVENT_CAPTURE_RESTART); if (hook_restart) { gc->wait_for_target_startup = false; CloseHandle(hook_restart); @@ -1019,7 +1189,9 @@ if (gc->process_id == GetCurrentProcessId()) return; - if (!gc->thread_id || !gc->process_id) { + if (!gc->thread_id && gc->process_id) + return; + if (!gc->process_id) { warn("error acquiring, failed to get window " "thread/process ids: %lu", GetLastError()); @@ -1038,8 +1210,7 @@ static inline bool init_events(struct game_capture *gc) { if (!gc->hook_restart) { - gc->hook_restart = get_event_plus_id(EVENT_CAPTURE_RESTART, - gc->process_id); + gc->hook_restart = open_event_gc(gc, EVENT_CAPTURE_RESTART); if (!gc->hook_restart) { warn("init_events: failed to get hook_restart " "event: %lu", GetLastError()); @@ -1048,8 +1219,7 @@ } if (!gc->hook_stop) { - gc->hook_stop = get_event_plus_id(EVENT_CAPTURE_STOP, - gc->process_id); + gc->hook_stop = open_event_gc(gc, EVENT_CAPTURE_STOP); if (!gc->hook_stop) { warn("init_events: failed to get hook_stop event: %lu", GetLastError()); @@ -1057,9 +1227,17 @@ } } + if (!gc->hook_init) { + gc->hook_init = open_event_gc(gc, EVENT_HOOK_INIT); + if (!gc->hook_init) { + warn("init_events: failed to get hook_init event: %lu", + GetLastError()); + return false; + } + } + if (!gc->hook_ready) { - gc->hook_ready = get_event_plus_id(EVENT_HOOK_READY, - gc->process_id); + gc->hook_ready = open_event_gc(gc, EVENT_HOOK_READY); if (!gc->hook_ready) { warn("init_events: failed to get hook_ready event: %lu", GetLastError()); @@ -1068,8 +1246,7 @@ } if (!gc->hook_exit) { - gc->hook_exit = get_event_plus_id(EVENT_HOOK_EXIT, - gc->process_id); + gc->hook_exit = open_event_gc(gc, EVENT_HOOK_EXIT); if (!gc->hook_exit) { warn("init_events: failed to get hook_exit event: %lu", GetLastError()); @@ -1088,9 +1265,6 @@ static inline enum capture_result init_capture_data(struct game_capture *gc) { - char name[64]; - sprintf(name, "%s%u", SHMEM_TEXTURE, gc->global_hook_info->map_id); - gc->cx = gc->global_hook_info->cx; gc->cy = gc->global_hook_info->cy; gc->pitch = gc->global_hook_info->pitch; @@ -1102,7 +1276,8 @@ CloseHandle(gc->hook_data_map); - gc->hook_data_map = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, name); + gc->hook_data_map = open_map_plus_id(gc, SHMEM_TEXTURE, + gc->global_hook_info->map_id); if (!gc->hook_data_map) { DWORD error = GetLastError(); if (error == 2) { @@ -1410,17 +1585,20 @@ static bool start_capture(struct game_capture *gc) { - if (!init_events(gc)) { - return false; - } + debug("Starting capture"); + if (gc->global_hook_info->type == CAPTURE_TYPE_MEMORY) { if (!init_shmem_capture(gc)) { return false; } + + info("memory capture successful"); } else { if (!init_shtex_capture(gc)) { return false; } + + info("shared texture capture successful"); } return true; @@ -1443,6 +1621,9 @@ if (activate_now) { HWND hwnd = (HWND)os_atomic_load_long(&gc->hotkey_window); + if (is_uwp_window(hwnd)) + hwnd = get_uwp_actual_window(hwnd); + if (get_window_exe(&gc->executable, hwnd)) { get_window_title(&gc->title, hwnd); get_window_class(&gc->class, hwnd); @@ -1471,6 +1652,7 @@ } if (gc->hook_stop && object_signalled(gc->hook_stop)) { + debug("hook stop signal received"); stop_capture(gc); } if (gc->active && deactivate) { @@ -1478,8 +1660,7 @@ } if (gc->active && !gc->hook_ready && gc->process_id) { - gc->hook_ready = get_event_plus_id(EVENT_HOOK_READY, - gc->process_id); + gc->hook_ready = open_event_gc(gc, EVENT_HOOK_READY); } if (gc->injector_process && object_signalled(gc->injector_process)) { @@ -1499,10 +1680,13 @@ } if (gc->hook_ready && object_signalled(gc->hook_ready)) { + debug("capture initializing!"); enum capture_result result = init_capture_data(gc); if (result == CAPTURE_SUCCESS) gc->capturing = start_capture(gc); + else + debug("init_capture_data failed"); if (result != CAPTURE_RETRY && !gc->capturing) { gc->retry_interval = ERROR_RETRY_INTERVAL; @@ -1554,13 +1738,17 @@ static inline void game_capture_render_cursor(struct game_capture *gc) { POINT p = {0}; + HWND window; - if (!gc->global_hook_info->window || - !gc->global_hook_info->base_cx || + if (!gc->global_hook_info->base_cx || !gc->global_hook_info->base_cy) return; - ClientToScreen((HWND)(uintptr_t)gc->global_hook_info->window, &p); + window = !!gc->global_hook_info->window + ? (HWND)(uintptr_t)gc->global_hook_info->window + : gc->window; + + ClientToScreen(window, &p); float x_scale = (float)gc->global_hook_info->cx / (float)gc->global_hook_info->base_cx;
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/get-graphics-offsets/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/win-capture/get-graphics-offsets/CMakeLists.txt
Changed
@@ -11,6 +11,10 @@ d3d8-offsets.cpp d3d9-offsets.cpp) +if(MSVC) + add_compile_options("$<$<CONFIG:RelWithDebInfo>:/MT>") +endif() + add_executable(get-graphics-offsets ${get-graphics-offsets_SOURCES} ${get-graphics-offsets_HEADERS})
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/get-graphics-offsets/d3d8-offsets.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/get-graphics-offsets/d3d8-offsets.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <windows.h> #include "../d3d8-api/d3d8.h"
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/get-graphics-offsets/d3d9-offsets.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/get-graphics-offsets/d3d9-offsets.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <windows.h> #include <d3d9.h>
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/get-graphics-offsets/dxgi-offsets.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <windows.h> #include <d3d10.h> #include <dxgi.h>
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/get-graphics-offsets/get-graphics-offsets.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/get-graphics-offsets/get-graphics-offsets.c
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <inttypes.h> #include <stdio.h> #include <windows.h>
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook-info.h -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook-info.h
Changed
@@ -7,19 +7,21 @@ #include "hook-helpers.h" -#define EVENT_CAPTURE_RESTART "CaptureHook_Restart" -#define EVENT_CAPTURE_STOP "CaptureHook_Stop" +#define EVENT_CAPTURE_RESTART L"CaptureHook_Restart" +#define EVENT_CAPTURE_STOP L"CaptureHook_Stop" -#define EVENT_HOOK_READY "CaptureHook_HookReady" -#define EVENT_HOOK_EXIT "CaptureHook_Exit" +#define EVENT_HOOK_READY L"CaptureHook_HookReady" +#define EVENT_HOOK_EXIT L"CaptureHook_Exit" -#define EVENT_HOOK_KEEPALIVE "CaptureHook_KeepAlive" +#define EVENT_HOOK_INIT L"CaptureHook_Initialize" -#define MUTEX_TEXTURE1 "CaptureHook_TextureMutex1" -#define MUTEX_TEXTURE2 "CaptureHook_TextureMutex2" +#define WINDOW_HOOK_KEEPALIVE L"CaptureHook_KeepAlive" -#define SHMEM_HOOK_INFO "Local\\CaptureHook_HookInfo" -#define SHMEM_TEXTURE "Local\\CaptureHook_Texture" +#define MUTEX_TEXTURE1 L"CaptureHook_TextureMutex1" +#define MUTEX_TEXTURE2 L"CaptureHook_TextureMutex2" + +#define SHMEM_HOOK_INFO L"CaptureHook_HookInfo" +#define SHMEM_TEXTURE L"CaptureHook_Texture" #define PIPE_NAME "CaptureHook_Pipe" @@ -101,19 +103,13 @@ #pragma pack(pop) -static inline HANDLE get_hook_info(DWORD id) -{ - HANDLE handle; - char new_name[64]; - sprintf(new_name, "%s%lu", SHMEM_HOOK_INFO, id); - - handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, - PAGE_READWRITE, 0, sizeof(struct hook_info), new_name); +#define GC_MAPPING_FLAGS (FILE_MAP_READ | FILE_MAP_WRITE) - if (!handle && GetLastError() == ERROR_ALREADY_EXISTS) { - handle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, - new_name); - } +static inline HANDLE create_hook_info(DWORD id) +{ + wchar_t new_name[64]; + _snwprintf(new_name, 64, L"%s%lu", SHMEM_HOOK_INFO, id); - return handle; + return CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, sizeof(struct hook_info), new_name); }
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/CMakeLists.txt
Changed
@@ -29,6 +29,10 @@ d3d11-capture.cpp d3d12-capture.cpp) +if(MSVC) + add_compile_options("$<$<CONFIG:RelWithDebInfo>:/MT>") +endif() + add_library(graphics-hook MODULE ${graphics-hook_SOURCES} ${graphics-hook_HEADERS})
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/d3d10-capture.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/d3d10-capture.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <d3d10.h> #include <dxgi.h> @@ -772,7 +771,7 @@ data.cur_tex = next_tex; } -void d3d10_capture(void *swap_ptr, void *backbuffer_ptr) +void d3d10_capture(void *swap_ptr, void *backbuffer_ptr, bool) { IDXGIResource *dxgi_backbuffer = (IDXGIResource*)backbuffer_ptr; IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr;
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/d3d11-capture.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/d3d11-capture.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <d3d11.h> #include <dxgi.h> @@ -814,7 +813,7 @@ data.cur_tex = next_tex; } -void d3d11_capture(void *swap_ptr, void *backbuffer_ptr) +void d3d11_capture(void *swap_ptr, void *backbuffer_ptr, bool) { IDXGIResource *dxgi_backbuffer = (IDXGIResource*)backbuffer_ptr; IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr;
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/d3d12-capture.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/d3d12-capture.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <windows.h> #include "graphics-hook.h" @@ -6,11 +5,13 @@ #include <d3d11on12.h> #include <d3d12.h> -#include <dxgi1_2.h> +#include <dxgi1_4.h> #include "dxgi-helpers.hpp" #include "../funchook.h" +#define MAX_BACKBUFFERS 8 + struct d3d12_data { ID3D12Device *device; /* do not release */ uint32_t base_cx; @@ -21,6 +22,7 @@ bool using_shtex : 1; bool using_scale : 1; bool multisampled : 1; + bool dxgi_1_4 : 1; ID3D11Device *device11; ID3D11DeviceContext *context11; @@ -29,7 +31,9 @@ union { struct { struct shtex_data *shtex_info; - ID3D11Resource *backbuffer11; + ID3D11Resource *backbuffer11[MAX_BACKBUFFERS]; + UINT backbuffer_count; + UINT cur_backbuffer; ID3D11Texture2D *copy_tex; HANDLE handle; }; @@ -42,8 +46,10 @@ { if (data.copy_tex) data.copy_tex->Release(); - if (data.backbuffer11) - data.backbuffer11->Release(); + for (size_t i = 0; i < data.backbuffer_count; i++) { + if (data.backbuffer11[i]) + data.backbuffer11[i]->Release(); + } if (data.device11) data.device11->Release(); if (data.context11) @@ -58,20 +64,34 @@ hlog("----------------- d3d12 capture freed ----------------"); } -static bool create_d3d12_tex(ID3D12Resource *backbuffer) +struct bb_info { + ID3D12Resource *backbuffer[MAX_BACKBUFFERS]; + UINT count; +}; + +static bool create_d3d12_tex(bb_info &bb) { D3D11_RESOURCE_FLAGS rf11 = {}; HRESULT hr; - hr = data.device11on12->CreateWrappedResource(backbuffer, &rf11, - D3D12_RESOURCE_STATE_COPY_SOURCE, - D3D12_RESOURCE_STATE_PRESENT, - __uuidof(ID3D11Resource), - (void**)&data.backbuffer11); - if (FAILED(hr)) { - hlog_hr("create_d3d12_tex: failed to create backbuffer11", - hr); + if (!bb.count) return false; + + data.backbuffer_count = bb.count; + + for (UINT i = 0; i < bb.count; i++) { + hr = data.device11on12->CreateWrappedResource( + bb.backbuffer[i], + &rf11, + D3D12_RESOURCE_STATE_COPY_SOURCE, + D3D12_RESOURCE_STATE_PRESENT, + __uuidof(ID3D11Resource), + (void**)&data.backbuffer11[i]); + if (FAILED(hr)) { + hlog_hr("create_d3d12_tex: failed to create " + "backbuffer11", hr); + return false; + } } D3D11_TEXTURE2D_DESC desc11 = {}; @@ -91,7 +111,10 @@ return false; } - data.device11on12->ReleaseWrappedResources(&data.backbuffer11, 1); + for (UINT i = 0; i < bb.count; i++) { + data.device11on12->ReleaseWrappedResources( + &data.backbuffer11[i], 1); + } IDXGIResource *dxgi_res; hr = data.copy_tex->QueryInterface(__uuidof(IDXGIResource), @@ -175,12 +198,12 @@ return true; } -static bool d3d12_shtex_init(HWND window, ID3D12Resource *backbuffer) +static bool d3d12_shtex_init(HWND window, bb_info &bb) { if (!d3d12_init_11on12()) { return false; } - if (!create_d3d12_tex(backbuffer)) { + if (!create_d3d12_tex(bb)) { return false; } if (!capture_init_shtex(&data.shtex_info, window, @@ -193,9 +216,11 @@ return true; } -static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window) +static inline bool d3d12_init_format(IDXGISwapChain *swap, HWND &window, + bb_info &bb) { DXGI_SWAP_CHAIN_DESC desc; + IDXGISwapChain3 *swap3; HRESULT hr; hr = swap->GetDesc(&desc); @@ -210,6 +235,39 @@ data.base_cx = desc.BufferDesc.Width; data.base_cy = desc.BufferDesc.Height; + hr = swap->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&swap3); + if (SUCCEEDED(hr)) { + data.dxgi_1_4 = true; + hlog("We're DXGI1.4 boys!"); + swap3->Release(); + } + + hlog("Buffer count: %d, swap effect: %d", (int)desc.BufferCount, + (int)desc.SwapEffect); + + bb.count = desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD + ? 1 : desc.BufferCount; + + if (bb.count == 1) + data.dxgi_1_4 = false; + + if (bb.count > MAX_BACKBUFFERS) { + hlog("Somehow it's using more than the max backbuffers. " + "Not sure why anyone would do that."); + bb.count = 1; + data.dxgi_1_4 = false; + } + + for (UINT i = 0; i < bb.count; i++) { + hr = swap->GetBuffer(i, __uuidof(ID3D12Resource), + (void**)&bb.backbuffer[i]); + if (SUCCEEDED(hr)) { + bb.backbuffer[i]->Release(); + } else { + return false; + } + } + if (data.using_scale) { data.cx = global_hook_info->cx; data.cy = global_hook_info->cy; @@ -220,9 +278,10 @@ return true; } -static void d3d12_init(IDXGISwapChain *swap, ID3D12Resource *backbuffer) +static void d3d12_init(IDXGISwapChain *swap) { bool success = true; + bb_info bb = {}; HWND window; HRESULT hr; @@ -236,7 +295,7 @@ data.device->Release(); - if (!d3d12_init_format(swap, window)) { + if (!d3d12_init_format(swap, window, bb)) { return; } if (data.using_scale) { @@ -248,7 +307,7 @@ "unsupported; ignoring"); } - success = d3d12_shtex_init(window, backbuffer); + success = d3d12_shtex_init(window, bb); } if (!success) @@ -264,37 +323,49 @@ } } -static inline void d3d12_shtex_capture() +static inline void d3d12_shtex_capture(IDXGISwapChain *swap, + bool capture_overlay) { - data.device11on12->AcquireWrappedResources(&data.backbuffer11, 1); - d3d12_copy_texture(data.copy_tex, data.backbuffer11); - data.device11on12->ReleaseWrappedResources(&data.backbuffer11, 1); + bool dxgi_1_4 = data.dxgi_1_4; + UINT cur_idx; + + if (dxgi_1_4) { + IDXGISwapChain3 *swap3 = + reinterpret_cast<IDXGISwapChain3*>(swap); + cur_idx = swap3->GetCurrentBackBufferIndex(); + if (!capture_overlay) { + if (++cur_idx >= data.backbuffer_count) + cur_idx = 0; + } + } else { + cur_idx = data.cur_backbuffer; + } + + ID3D11Resource *backbuffer = data.backbuffer11[cur_idx]; + + data.device11on12->AcquireWrappedResources(&backbuffer, 1); + d3d12_copy_texture(data.copy_tex, backbuffer); + data.device11on12->ReleaseWrappedResources(&backbuffer, 1); data.context11->Flush(); + + if (!dxgi_1_4) { + if (++data.cur_backbuffer >= data.backbuffer_count) + data.cur_backbuffer = 0; + } } -void d3d12_capture(void *swap_ptr, void *backbuffer_ptr) +void d3d12_capture(void *swap_ptr, void*, bool capture_overlay) { - IUnknown *unk_backbuffer = (IUnknown*)backbuffer_ptr; IDXGISwapChain *swap = (IDXGISwapChain*)swap_ptr; - ID3D12Resource *backbuffer; - HRESULT hr; if (capture_should_stop()) { d3d12_free(); } if (capture_should_init()) { - hr = unk_backbuffer->QueryInterface(__uuidof(ID3D12Resource), - (void**)&backbuffer); - if (FAILED(hr)) { - hlog_hr("d3d12_capture: failed to get backbuffer", hr); - return; - } - - d3d12_init(swap, backbuffer); - backbuffer->Release(); + d3d12_init(swap); } if (capture_ready()) { - d3d12_shtex_capture(); + d3d12_shtex_capture(swap, capture_overlay); } }
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/d3d8-capture.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/d3d8-capture.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <dxgi.h> #include "../d3d8-api/d3d8.h"
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/d3d9-capture.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/d3d9-capture.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <d3d9.h> #include <d3d11.h> #include <dxgi.h>
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/dxgi-capture.cpp -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/dxgi-capture.cpp
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <d3d10_1.h> #include <d3d11.h> #include <dxgi.h> @@ -21,7 +20,7 @@ struct dxgi_swap_data { IDXGISwapChain *swap; - void (*capture)(void*, void*); + void (*capture)(void*, void*, bool); void (*free)(void); }; @@ -132,7 +131,7 @@ backbuffer = get_dxgi_backbuffer(swap); if (!!backbuffer) { - data.capture(swap, backbuffer); + data.capture(swap, backbuffer, capture_overlay); backbuffer->Release(); } } @@ -156,7 +155,7 @@ backbuffer = get_dxgi_backbuffer(swap); if (!!backbuffer) { - data.capture(swap, backbuffer); + data.capture(swap, backbuffer, capture_overlay); backbuffer->Release(); } }
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/gl-capture.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/gl-capture.c
Changed
@@ -1,5 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS - #ifdef _MSC_VER #pragma warning(disable : 4214) /* nonstandard extension, non-int bitfield */ #pragma warning(disable : 4054) /* function pointer to data pointer */
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/graphics-hook.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/graphics-hook.c
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <windows.h> #include <psapi.h> #include "graphics-hook.h" @@ -32,6 +31,7 @@ HANDLE signal_stop = NULL; HANDLE signal_ready = NULL; HANDLE signal_exit = NULL; +static HANDLE signal_init = NULL; HANDLE tex_mutexes[2] = {NULL, NULL}; static HANDLE filemap_hook_info = NULL; @@ -40,7 +40,7 @@ static HANDLE capture_thread = NULL; char system_path[MAX_PATH] = {0}; char process_name[MAX_PATH] = {0}; -char keepalive_name[64] = {0}; +wchar_t keepalive_name[64] = {0}; HWND dummy_window = NULL; static unsigned int shmem_id_counter = 0; @@ -74,22 +74,17 @@ return true; } -static HANDLE init_event(const char *name, DWORD pid) +static HANDLE init_event(const wchar_t *name, DWORD pid) { - HANDLE handle = get_event_plus_id(name, pid); + HANDLE handle = create_event_plus_id(name, pid); if (!handle) hlog("Failed to get event '%s': %lu", name, GetLastError()); return handle; } -static HANDLE init_mutex(const char *name, DWORD pid) +static HANDLE init_mutex(const wchar_t *name, DWORD pid) { - char new_name[64]; - HANDLE handle; - - sprintf(new_name, "%s%lu", name, pid); - - handle = OpenMutexA(MUTEX_ALL_ACCESS, false, new_name); + HANDLE handle = create_mutex_plus_id(name, pid); if (!handle) hlog("Failed to open mutex '%s': %lu", name, GetLastError()); return handle; @@ -119,6 +114,11 @@ return false; } + signal_init = init_event(EVENT_HOOK_INIT, pid); + if (!signal_init) { + return false; + } + return true; } @@ -164,7 +164,7 @@ static inline bool init_hook_info(void) { - filemap_hook_info = get_hook_info(GetCurrentProcessId()); + filemap_hook_info = create_hook_info(GetCurrentProcessId()); if (!filemap_hook_info) { hlog("Failed to create hook info file mapping: %lu", GetLastError()); @@ -235,24 +235,10 @@ { wait_for_dll_main_finish(thread_handle); - sprintf(keepalive_name, "%s%lu", EVENT_HOOK_KEEPALIVE, - GetCurrentProcessId()); + _snwprintf(keepalive_name, sizeof(keepalive_name), L"%s%lu", + WINDOW_HOOK_KEEPALIVE, GetCurrentProcessId()); - if (!init_pipe()) { - return false; - } - if (!init_signals()) { - return false; - } - if (!init_mutexes()) { - return false; - } - if (!init_system_path()) { - return false; - } - if (!init_hook_info()) { - return false; - } + init_pipe(); init_dummy_window_thread(); log_current_process(); @@ -329,6 +315,7 @@ if (!d3d9_hooked) { if (!d3d9_hookable()) { + DbgOut("no D3D9 hook address found!\n"); d3d9_hooked = true; } else { d3d9_hooked = hook_d3d9(); @@ -340,6 +327,7 @@ if (!dxgi_hooked) { if (!dxgi_hookable()) { + DbgOut("no DXGI hook address found!\n"); dxgi_hooked = true; } else { dxgi_hooked = hook_dxgi(); @@ -385,6 +373,8 @@ static inline void capture_loop(void) { + WaitForSingleObject(signal_init, INFINITE); + while (!attempt_hook()) Sleep(40); @@ -496,10 +486,10 @@ static inline bool init_shared_info(size_t size) { - char name[64]; - sprintf_s(name, 64, "%s%u", SHMEM_TEXTURE, ++shmem_id_counter); + wchar_t name[64]; + _snwprintf(name, 64, L"%s%ld", SHMEM_TEXTURE, ++shmem_id_counter); - shmem_file_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, + shmem_file_handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)size, name); if (!shmem_file_handle) { hlog("init_shared_info: Failed to create shared memory: %d", @@ -792,8 +782,27 @@ dll_inst = hinst; - HANDLE cur_thread = OpenThread(THREAD_ALL_ACCESS, false, - GetCurrentThreadId()); + HANDLE cur_thread; + bool success = DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), &cur_thread, + SYNCHRONIZE, false, 0); + + if (!success) + DbgOut("Failed to get current thread handle"); + + if (!init_signals()) { + return false; + } + if (!init_system_path()) { + return false; + } + if (!init_hook_info()) { + return false; + } + if (!init_mutexes()) { + return false; + } /* this prevents the library from being automatically unloaded * by the next FreeLibrary call */
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/graphics-hook/graphics-hook.h -> obs-studio-0.17.0.tar.xz/plugins/win-capture/graphics-hook/graphics-hook.h
Changed
@@ -43,13 +43,13 @@ extern bool hook_dxgi(void); extern bool hook_gl(void); -extern void d3d10_capture(void *swap, void *backbuffer); +extern void d3d10_capture(void *swap, void *backbuffer, bool capture_overlay); extern void d3d10_free(void); -extern void d3d11_capture(void *swap, void *backbuffer); +extern void d3d11_capture(void *swap, void *backbuffer, bool capture_overlay); extern void d3d11_free(void); #if COMPILE_D3D12_HOOK -extern void d3d12_capture(void *swap, void *backbuffer); +extern void d3d12_capture(void *swap, void *backbuffer, bool capture_overlay); extern void d3d12_free(void); #endif @@ -98,7 +98,7 @@ extern HANDLE tex_mutexes[2]; extern char system_path[MAX_PATH]; extern char process_name[MAX_PATH]; -extern char keepalive_name[64]; +extern wchar_t keepalive_name[64]; extern HWND dummy_window; extern volatile bool active; @@ -143,13 +143,7 @@ static inline bool capture_alive(void) { - HANDLE event = OpenEventA(EVENT_ALL_ACCESS, false, keepalive_name); - if (event) { - CloseHandle(event); - return true; - } - - return false; + return !!FindWindowW(keepalive_name, NULL); } static inline bool capture_active(void) @@ -198,8 +192,18 @@ { bool stop_requested = false; - if (capture_active()) - stop_requested = capture_stopped() || !capture_alive(); + if (capture_active()) { + static uint64_t last_keepalive_check = 0; + uint64_t cur_time = os_gettime_ns(); + bool alive = true; + + if (cur_time - last_keepalive_check > 5000000000) { + alive = capture_alive(); + last_keepalive_check = cur_time; + } + + stop_requested = capture_stopped() || !alive; + } return stop_requested; }
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/hook-helpers.h -> obs-studio-0.17.0.tar.xz/plugins/win-capture/hook-helpers.h
Changed
@@ -4,36 +4,41 @@ #define inline __inline #endif -static inline HANDLE get_event(const char *name) +#define GC_EVENT_FLAGS (EVENT_MODIFY_STATE | SYNCHRONIZE) +#define GC_MUTEX_FLAGS (SYNCHRONIZE) + +static inline HANDLE create_event(const wchar_t *name) { - HANDLE event = CreateEventA(NULL, false, false, name); - if (!event) - event = OpenEventA(EVENT_ALL_ACCESS, false, name); + return CreateEventW(NULL, false, false, name); +} - return event; +static inline HANDLE open_event(const wchar_t *name) +{ + return OpenEventW(GC_EVENT_FLAGS, false, name); } -static inline HANDLE get_mutex(const char *name) +static inline HANDLE create_mutex(const wchar_t *name) { - HANDLE event = CreateMutexA(NULL, false, name); - if (!event) - event = OpenMutexA(MUTEX_ALL_ACCESS, false, name); + return CreateMutexW(NULL, false, name); +} - return event; +static inline HANDLE open_mutex(const wchar_t *name) +{ + return OpenMutexW(GC_MUTEX_FLAGS, false, name); } -static inline HANDLE get_event_plus_id(const char *name, DWORD id) +static inline HANDLE create_event_plus_id(const wchar_t *name, DWORD id) { - char new_name[64]; - sprintf(new_name, "%s%lu", name, id); - return get_event(new_name); + wchar_t new_name[64]; + _snwprintf(new_name, 64, L"%s%lu", name, id); + return create_event(new_name); } -static inline HANDLE get_mutex_plus_id(const char *name, DWORD id) +static inline HANDLE create_mutex_plus_id(const wchar_t *name, DWORD id) { - char new_name[64]; - sprintf(new_name, "%s%lu", name, id); - return get_mutex(new_name); + wchar_t new_name[64]; + _snwprintf(new_name, 64, L"%s%lu", name, id); + return create_mutex(new_name); } static inline bool object_signalled(HANDLE event)
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/inject-helper/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/win-capture/inject-helper/CMakeLists.txt
Changed
@@ -9,6 +9,10 @@ ../obfuscate.c inject-helper.c) +if(MSVC) + add_compile_options("$<$<CONFIG:RelWithDebInfo>:/MT>") +endif() + add_executable(inject-helper ${inject-helper_SOURCES})
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/inject-helper/inject-helper.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/inject-helper/inject-helper.c
Changed
@@ -1,5 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS - #include <stdio.h> #include <stdlib.h> #include <wchar.h>
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/load-graphics-offsets.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/load-graphics-offsets.c
Changed
@@ -1,4 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS #include <obs-module.h> #include <util/windows/win-version.h> #include <util/platform.h>
View file
obs-studio-0.17.0.tar.xz/plugins/win-capture/nt-stuff.h
Added
@@ -0,0 +1,205 @@ +#pragma once + +#include <winternl.h> + +#define THREAD_STATE_WAITING 5 +#define THREAD_WAIT_REASON_SUSPENDED 5 + +typedef struct _SYSTEM_PROCESS_INFORMATION2 { + ULONG NextEntryOffset; + ULONG ThreadCount; + BYTE Reserved1[48]; + PVOID Reserved2[3]; + HANDLE UniqueProcessId; + PVOID Reserved3; + ULONG HandleCount; + BYTE Reserved4[4]; + PVOID Reserved5[11]; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER Reserved6[6]; +} SYSTEM_PROCESS_INFORMATION2; + +typedef struct _SYSTEM_THREAD_INFORMATION { + FILETIME KernelTime; + FILETIME UserTime; + FILETIME CreateTime; + DWORD WaitTime; + PVOID Address; + HANDLE UniqueProcessId; + HANDLE UniqueThreadId; + DWORD Priority; + DWORD BasePriority; + DWORD ContextSwitches; + DWORD ThreadState; + DWORD WaitReason; + DWORD Reserved1; +} SYSTEM_THREAD_INFORMATION; + +#ifndef NT_SUCCESS +#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0) +#endif + +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) + +#define init_named_attribs(o, name) \ + do { \ + (o)->Length = sizeof(*(o)); \ + (o)->ObjectName = name; \ + (o)->RootDirectory = NULL; \ + (o)->Attributes = 0; \ + (o)->SecurityDescriptor = NULL; \ + (o)->SecurityQualityOfService = NULL; \ + } while (false) + +typedef void (WINAPI *RTLINITUNICODESTRINGFUNC)(PCUNICODE_STRING pstr, const wchar_t *lpstrName); +typedef NTSTATUS (WINAPI *NTOPENFUNC)(PHANDLE phandle, ACCESS_MASK access, POBJECT_ATTRIBUTES objattr); +typedef ULONG (WINAPI *RTLNTSTATUSTODOSERRORFUNC)(NTSTATUS status); +typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATIONFUNC)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG); + +static FARPROC get_nt_func(const char *name) +{ + static bool initialized = false; + static HANDLE ntdll = NULL; + if (!initialized) { + ntdll = GetModuleHandleW(L"ntdll"); + initialized = true; + } + + return GetProcAddress(ntdll, name); +} + +static void nt_set_last_error(NTSTATUS status) +{ + static bool initialized = false; + static RTLNTSTATUSTODOSERRORFUNC func = NULL; + + if (!initialized) { + func = (RTLNTSTATUSTODOSERRORFUNC)get_nt_func( + "RtlNtStatusToDosError"); + initialized = true; + } + + if (func) + SetLastError(func(status)); +} + +static void rtl_init_str(UNICODE_STRING *unistr, const wchar_t *str) +{ + static bool initialized = false; + static RTLINITUNICODESTRINGFUNC func = NULL; + + if (!initialized) { + func = (RTLINITUNICODESTRINGFUNC)get_nt_func( + "RtlInitUnicodeString"); + initialized = true; + } + + if (func) + func(unistr, str); +} + +static NTSTATUS nt_query_information(SYSTEM_INFORMATION_CLASS info_class, + PVOID info, ULONG info_len, PULONG ret_len) +{ + static bool initialized = false; + static NTQUERYSYSTEMINFORMATIONFUNC func = NULL; + + if (!initialized) { + func = (NTQUERYSYSTEMINFORMATIONFUNC)get_nt_func( + "NtQuerySystemInformation"); + initialized = true; + } + + if (func) + return func(info_class, info, info_len, ret_len); + return (NTSTATUS)-1; +} + +static bool thread_is_suspended(DWORD process_id, DWORD thread_id) +{ + ULONG size = 4096; + bool suspended = false; + void *data = malloc(size); + + for (;;) { + NTSTATUS stat = nt_query_information(SystemProcessInformation, + data, size, &size); + if (NT_SUCCESS(stat)) + break; + + if (stat != STATUS_INFO_LENGTH_MISMATCH) { + goto fail; + } + + free(data); + size += 1024; + data = malloc(size); + } + + SYSTEM_PROCESS_INFORMATION2 *spi = data; + + for (;;) { + if (spi->UniqueProcessId == (HANDLE)process_id) { + break; + } + + ULONG offset = spi->NextEntryOffset; + if (!offset) + goto fail; + + spi = (SYSTEM_PROCESS_INFORMATION2*)((BYTE*)spi + offset); + } + + SYSTEM_THREAD_INFORMATION *sti; + SYSTEM_THREAD_INFORMATION *info = NULL; + sti = (SYSTEM_THREAD_INFORMATION*)((BYTE*)spi + sizeof(*spi)); + + for (ULONG i = 0; i < spi->ThreadCount; i++) { + if (sti[i].UniqueThreadId == (HANDLE)thread_id) { + info = &sti[i]; + break; + } + } + + if (info) { + suspended = info->ThreadState == THREAD_STATE_WAITING && + info->WaitReason == THREAD_WAIT_REASON_SUSPENDED; + } + +fail: + free(data); + return suspended; +} + +#define MAKE_NT_OPEN_FUNC(func_name, nt_name, access) \ +static HANDLE func_name(const wchar_t *name) \ +{ \ + static bool initialized = false; \ + static NTOPENFUNC open = NULL; \ + HANDLE handle; \ + NTSTATUS status; \ + UNICODE_STRING unistr; \ + OBJECT_ATTRIBUTES attr; \ +\ + if (!initialized) { \ + open = (NTOPENFUNC)get_nt_func(#nt_name); \ + initialized = true; \ + } \ +\ + if (!open) \ + return NULL; \ +\ + rtl_init_str(&unistr, name); \ + init_named_attribs(&attr, &unistr); \ +\ + status = open(&handle, access, &attr); \ + if (NT_SUCCESS(status)) \ + return handle; \ + nt_set_last_error(status); \ + return NULL; \ +} + +MAKE_NT_OPEN_FUNC(nt_open_mutex, NtOpenMutant, SYNCHRONIZE) +MAKE_NT_OPEN_FUNC(nt_open_event, NtOpenEvent, EVENT_MODIFY_STATE | SYNCHRONIZE) +MAKE_NT_OPEN_FUNC(nt_open_map, NtOpenSection, FILE_MAP_READ | FILE_MAP_WRITE)
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/obfuscate.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/obfuscate.c
Changed
@@ -1,5 +1,3 @@ -#define _CRT_SECURE_NO_WARNINGS - #ifdef _MSC_VER #pragma warning(disable : 4152) /* casting func ptr to void */ #endif
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/window-helpers.c -> obs-studio-0.17.0.tar.xz/plugins/win-capture/window-helpers.c
Changed
@@ -128,6 +128,33 @@ dstr_from_wcs(class, temp); } +/* not capturable or internal windows */ +static const char *internal_microsoft_exes[] = { + "applicationframehost", + "shellexperiencehost", + "winstore.app", + "searchui", + NULL +}; + +static bool is_microsoft_internal_window_exe(const char *exe) +{ + char cur_exe[MAX_PATH]; + + if (!exe) + return false; + + for (const char **vals = internal_microsoft_exes; *vals; vals++) { + strcpy(cur_exe, *vals); + strcat(cur_exe, ".exe"); + + if (strcmpi(cur_exe, exe) == 0) + return true; + } + + return false; +} + static void add_window(obs_property_t *p, HWND hwnd, add_window_cb callback) { struct dstr class = {0}; @@ -138,6 +165,10 @@ if (!get_window_exe(&exe, hwnd)) return; + if (is_microsoft_internal_window_exe(exe.array)) { + dstr_free(&exe); + return; + } get_window_title(&title, hwnd); get_window_class(&class, hwnd); @@ -192,33 +223,92 @@ return true; } -static inline HWND next_window(HWND window, enum window_search_mode mode) +bool is_uwp_window(HWND hwnd) +{ + wchar_t name[256]; + + name[0] = 0; + if (!GetClassNameW(hwnd, name, sizeof(name) / sizeof(wchar_t))) + return false; + + return wcscmp(name, L"ApplicationFrameWindow") == 0; +} + +HWND get_uwp_actual_window(HWND parent) +{ + DWORD parent_id = 0; + HWND child; + + GetWindowThreadProcessId(parent, &parent_id); + child = FindWindowEx(parent, NULL, NULL, NULL); + + while (child) { + DWORD child_id = 0; + GetWindowThreadProcessId(child, &child_id); + + if (child_id != parent_id) + return child; + + child = FindWindowEx(parent, child, NULL, NULL); + } + + return NULL; +} + +static inline HWND next_window(HWND window, enum window_search_mode mode, + HWND *parent) { + if (*parent) { + window = *parent; + *parent = NULL; + } + while (true) { - window = GetNextWindow(window, GW_HWNDNEXT); + window = FindWindowEx(GetDesktopWindow(), window, NULL, NULL); if (!window || check_window_valid(window, mode)) break; } + if (is_uwp_window(window)) { + HWND child = get_uwp_actual_window(window); + if (child) { + *parent = window; + return child; + } + } + return window; } -static inline HWND first_window(enum window_search_mode mode) +static inline HWND first_window(enum window_search_mode mode, HWND *parent) { - HWND window = GetWindow(GetDesktopWindow(), GW_CHILD); + HWND window = FindWindowEx(GetDesktopWindow(), NULL, NULL, NULL); + + *parent = NULL; + if (!check_window_valid(window, mode)) - window = next_window(window, mode); + window = next_window(window, mode, parent); + + if (is_uwp_window(window)) { + HWND child = get_uwp_actual_window(window); + if (child) { + *parent = window; + return child; + } + } + return window; } void fill_window_list(obs_property_t *p, enum window_search_mode mode, add_window_cb callback) { - HWND window = first_window(mode); + HWND parent; + HWND window = first_window(mode, &parent); while (window) { add_window(p, window, callback); - window = next_window(window, mode); + window = next_window(window, mode, &parent); } } @@ -226,7 +316,8 @@ enum window_priority priority, const char *class, const char *title, - const char *exe) + const char *exe, + bool uwp_window) { struct dstr cur_class = {0}; struct dstr cur_title = {0}; @@ -248,12 +339,18 @@ else exe_val += 3; - if (dstr_cmpi(&cur_class, class) == 0) - total += class_val; - if (dstr_cmpi(&cur_title, title) == 0) - total += title_val; - if (dstr_cmpi(&cur_exe, exe) == 0) - total += exe_val; + if (uwp_window) { + if (dstr_cmpi(&cur_title, title) == 0 && + dstr_cmpi(&cur_exe, exe) == 0) + total += exe_val + title_val + class_val; + } else { + if (dstr_cmpi(&cur_class, class) == 0) + total += class_val; + if (dstr_cmpi(&cur_title, title) == 0) + total += title_val; + if (dstr_cmpi(&cur_exe, exe) == 0) + total += exe_val; + } dstr_free(&cur_class); dstr_free(&cur_title); @@ -268,18 +365,25 @@ const char *title, const char *exe) { - HWND window = first_window(mode); + HWND parent; + HWND window = first_window(mode, &parent); HWND best_window = NULL; int best_rating = 0; + if (!class) + return NULL; + + bool uwp_window = strcmp(class, "Windows.UI.Core.CoreWindow") == 0; + while (window) { - int rating = window_rating(window, priority, class, title, exe); + int rating = window_rating(window, priority, class, title, exe, + uwp_window); if (rating > best_rating) { best_rating = rating; best_window = window; } - window = next_window(window, mode); + window = next_window(window, mode, &parent); } return best_window;
View file
obs-studio-0.16.6.tar.xz/plugins/win-capture/window-helpers.h -> obs-studio-0.17.0.tar.xz/plugins/win-capture/window-helpers.h
Changed
@@ -16,6 +16,8 @@ extern bool get_window_exe(struct dstr *name, HWND window); extern void get_window_title(struct dstr *name, HWND hwnd); extern void get_window_class(struct dstr *class, HWND hwnd); +extern bool is_uwp_window(HWND hwnd); +extern HWND get_uwp_actual_window(HWND parent); typedef bool (*add_window_cb)(const char *title, const char *class, const char *exe);
View file
obs-studio-0.16.6.tar.xz/plugins/win-dshow/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/win-dshow/data/locale/tr-TR.ini
Changed
@@ -24,6 +24,9 @@ UseCustomAudioDevice="Özel ses aygıtını kullan" AudioDevice="Ses Aygıtı" Buffering="Arabelleğe Alma" +Buffering.AutoDetect="Otomatik Algıla" +Buffering.Enable="Etkinleştir" +Buffering.Disable="Devre Dışı Bırak" Activate="Etkinleştir" Deactivate="Devredışı Bırak" FlipVertically="Dikey Çevir"
View file
obs-studio-0.16.6.tar.xz/plugins/win-ivcam/seg_service/CMakeLists.txt -> obs-studio-0.17.0.tar.xz/plugins/win-ivcam/seg_service/CMakeLists.txt
Changed
@@ -33,6 +33,10 @@ ${seg_service_GENERATED_FILES} ) +if(MSVC) + add_compile_options("$<$<CONFIG:RelWithDebInfo>:/MT>") +endif() + add_executable(seg_service WIN32 ${seg_service_SOURCES} ${seg_service_HEADERS})
View file
obs-studio-0.16.6.tar.xz/plugins/win-mf/data/locale/tr-TR.ini -> obs-studio-0.17.0.tar.xz/plugins/win-mf/data/locale/tr-TR.ini
Changed
@@ -8,6 +8,9 @@ MF.H264.Bitrate="Bithızı" MF.H264.MaxBitrate="Maks Bit hızı" MF.H264.KeyframeIntervalSec="Anahtarkare Aralığı (saniye, 0=otomatik)" +MF.H264.VBR="VBR (Değişken Bit Hızı)" +MF.H264.MinQP="Minimum QP" +MF.H264.MaxQP="Maksimum QP" MF.H264.Profile="Profil" MF.H264.Advanced="Gelişmiş"
View file
obs-studio-0.16.6.tar.xz/plugins/win-wasapi/data/locale/nl-NL.ini -> obs-studio-0.17.0.tar.xz/plugins/win-wasapi/data/locale/nl-NL.ini
Changed
@@ -1,4 +1,4 @@ -AudioInput="Audioinvoer Capture" +AudioInput="Audioinvoer Opname" AudioOutput="Audiouitvoer Opname" Device="Apparaat" Default="Standaardinstellingen"
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.