Repository: WolfEngine/Wolf.Engine
Branch: main
Commit: cb407495a743
Files: 500
Total size: 2.4 MB
Directory structure:
gitextract_nyue42gt/
├── .dockerignore
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── codeql.yml
│ └── msvc.yml
├── .gitignore
├── CHANGE_LOG.md
├── CMakeLists.txt
├── CMakePresets.json
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── TODO.md
├── coverage.bat
├── docker/
│ └── Dockerfile
├── docs/
│ ├── GCC.txt
│ ├── ProblemSolutions.txt
│ ├── git-commands.txt
│ ├── glslValidator.txt
│ ├── glslValidator_MoltenVK.txt
│ └── quic.md
├── manifest.manifest
├── wolf/
│ ├── .clang-format
│ ├── .clang-tidy
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── DISABLE_ANALYSIS_BEGIN
│ ├── DISABLE_ANALYSIS_END
│ ├── cmake/
│ │ ├── media.cmake
│ │ ├── ml.cmake
│ │ ├── stream.cmake
│ │ ├── system.cmake
│ │ └── vcpkg.cmake
│ ├── media/
│ │ ├── ffmpeg/
│ │ │ ├── w_av_config.cpp
│ │ │ ├── w_av_config.hpp
│ │ │ ├── w_av_format.cpp
│ │ │ ├── w_av_format.hpp
│ │ │ ├── w_av_frame.cpp
│ │ │ ├── w_av_frame.hpp
│ │ │ ├── w_av_packet.cpp
│ │ │ ├── w_av_packet.hpp
│ │ │ ├── w_decoder.cpp
│ │ │ ├── w_decoder.hpp
│ │ │ ├── w_encoder.cpp
│ │ │ ├── w_encoder.hpp
│ │ │ ├── w_ffmpeg.cpp
│ │ │ ├── w_ffmpeg.hpp
│ │ │ ├── w_ffmpeg_ctx.cpp
│ │ │ └── w_ffmpeg_ctx.hpp
│ │ ├── gst/
│ │ │ ├── audio/
│ │ │ │ ├── w_audio_format.cpp
│ │ │ │ ├── w_audio_format.hpp
│ │ │ │ ├── w_audio_info.cpp
│ │ │ │ └── w_audio_info.hpp
│ │ │ ├── core/
│ │ │ │ ├── w_buffer.cpp
│ │ │ │ ├── w_buffer.hpp
│ │ │ │ ├── w_bus.cpp
│ │ │ │ ├── w_bus.hpp
│ │ │ │ ├── w_caps.cpp
│ │ │ │ ├── w_caps.hpp
│ │ │ │ ├── w_clock.cpp
│ │ │ │ ├── w_clock.hpp
│ │ │ │ ├── w_element.cpp
│ │ │ │ ├── w_element.hpp
│ │ │ │ ├── w_element_factory.cpp
│ │ │ │ ├── w_element_factory.hpp
│ │ │ │ ├── w_format.cpp
│ │ │ │ ├── w_format.hpp
│ │ │ │ ├── w_mainloop.cpp
│ │ │ │ ├── w_mainloop.hpp
│ │ │ │ ├── w_message.cpp
│ │ │ │ ├── w_message.hpp
│ │ │ │ ├── w_nonowning.cpp
│ │ │ │ ├── w_nonowning.hpp
│ │ │ │ ├── w_pad.cpp
│ │ │ │ ├── w_pad.hpp
│ │ │ │ ├── w_pipeline.cpp
│ │ │ │ ├── w_pipeline.hpp
│ │ │ │ ├── w_refptr.cpp
│ │ │ │ ├── w_refptr.hpp
│ │ │ │ ├── w_signal_handler.cpp
│ │ │ │ ├── w_signal_handler.hpp
│ │ │ │ ├── w_structure.cpp
│ │ │ │ └── w_structure.hpp
│ │ │ ├── elements/
│ │ │ │ ├── w_element_aacparse.cpp
│ │ │ │ ├── w_element_aacparse.hpp
│ │ │ │ ├── w_element_appsrc.cpp
│ │ │ │ ├── w_element_appsrc.hpp
│ │ │ │ ├── w_element_audioconvert.cpp
│ │ │ │ ├── w_element_audioconvert.hpp
│ │ │ │ ├── w_element_audioresample.cpp
│ │ │ │ ├── w_element_audioresample.hpp
│ │ │ │ ├── w_element_autovideosink.cpp
│ │ │ │ ├── w_element_autovideosink.hpp
│ │ │ │ ├── w_element_avencflv.cpp
│ │ │ │ ├── w_element_avencflv.hpp
│ │ │ │ ├── w_element_capsfilter.cpp
│ │ │ │ ├── w_element_capsfilter.hpp
│ │ │ │ ├── w_element_filesink.cpp
│ │ │ │ ├── w_element_filesink.hpp
│ │ │ │ ├── w_element_flvmux.cpp
│ │ │ │ ├── w_element_flvmux.hpp
│ │ │ │ ├── w_element_h264parse.cpp
│ │ │ │ ├── w_element_h264parse.hpp
│ │ │ │ ├── w_element_mp4mux.cpp
│ │ │ │ ├── w_element_mp4mux.hpp
│ │ │ │ ├── w_element_openh264enc.cpp
│ │ │ │ ├── w_element_openh264enc.hpp
│ │ │ │ ├── w_element_queue.cpp
│ │ │ │ ├── w_element_queue.hpp
│ │ │ │ ├── w_element_rtmpsink.cpp
│ │ │ │ ├── w_element_rtmpsink.hpp
│ │ │ │ ├── w_element_rtph264pay.cpp
│ │ │ │ ├── w_element_rtph264pay.hpp
│ │ │ │ ├── w_element_udpsink.cpp
│ │ │ │ ├── w_element_udpsink.hpp
│ │ │ │ ├── w_element_videoconvert.cpp
│ │ │ │ ├── w_element_videoconvert.hpp
│ │ │ │ ├── w_element_videoscale.cpp
│ │ │ │ ├── w_element_videoscale.hpp
│ │ │ │ ├── w_element_videotestsrc.cpp
│ │ │ │ ├── w_element_videotestsrc.hpp
│ │ │ │ ├── w_element_voaacenc.cpp
│ │ │ │ ├── w_element_voaacenc.hpp
│ │ │ │ ├── w_element_wasapisrc.cpp
│ │ │ │ ├── w_element_wasapisrc.hpp
│ │ │ │ ├── w_element_x264enc.cpp
│ │ │ │ └── w_element_x264enc.hpp
│ │ │ ├── internal/
│ │ │ │ ├── w_common.cpp
│ │ │ │ ├── w_common.hpp
│ │ │ │ ├── w_utils.cpp
│ │ │ │ ├── w_utils.hpp
│ │ │ │ ├── w_wrapper.cpp
│ │ │ │ └── w_wrapper.hpp
│ │ │ ├── video/
│ │ │ │ ├── w_video_format.cpp
│ │ │ │ ├── w_video_format.hpp
│ │ │ │ ├── w_video_info.cpp
│ │ │ │ └── w_video_info.hpp
│ │ │ ├── w_application.cpp
│ │ │ ├── w_application.hpp
│ │ │ ├── w_flow.cpp
│ │ │ └── w_flow.hpp
│ │ ├── test/
│ │ │ ├── avframe.hpp
│ │ │ ├── ffmpeg.hpp
│ │ │ ├── gstreamer.hpp
│ │ │ ├── image.hpp
│ │ │ └── openal.hpp
│ │ ├── w_image.cpp
│ │ ├── w_image.hpp
│ │ ├── w_image_data.cpp
│ │ ├── w_image_data.hpp
│ │ ├── w_openal.cpp
│ │ └── w_openal.hpp
│ ├── ml/
│ │ ├── nudity_detection/
│ │ │ ├── w_nudity_detection.cpp
│ │ │ └── w_nudity_detection.hpp
│ │ ├── referee_ocr/
│ │ │ ├── salieri.h
│ │ │ ├── w_image_processor.cpp
│ │ │ ├── w_image_processor.hpp
│ │ │ ├── w_ocr_engine.cpp
│ │ │ ├── w_ocr_engine.hpp
│ │ │ ├── w_read_video_frames.cpp
│ │ │ ├── w_read_video_frames.hpp
│ │ │ ├── w_referee.cpp
│ │ │ ├── w_referee.hpp
│ │ │ ├── w_soccer.cpp
│ │ │ ├── w_soccer.hpp
│ │ │ ├── w_utilities.cpp
│ │ │ └── w_utilities.hpp
│ │ ├── test/
│ │ │ ├── common_test_asset/
│ │ │ │ ├── soccer/
│ │ │ │ │ ├── .fill_stat_map
│ │ │ │ │ ├── .initial_match_result_struct
│ │ │ │ │ ├── .replace_team_names_with_most_similar_string
│ │ │ │ │ ├── .replace_team_names_with_most_similar_string_0_9
│ │ │ │ │ ├── .set_config
│ │ │ │ │ ├── .single_image_result_extraction
│ │ │ │ │ ├── .update_match_data
│ │ │ │ │ └── replace_team_names_with_most_similar_string.txt
│ │ │ │ └── utilities/
│ │ │ │ ├── .get_env_boolean
│ │ │ │ ├── .get_env_cv_rect
│ │ │ │ ├── .get_env_float
│ │ │ │ ├── .get_env_int
│ │ │ │ ├── .get_env_string
│ │ │ │ ├── .get_nearest_string_0_5
│ │ │ │ ├── .get_nearest_string_0_9
│ │ │ │ ├── .set_env
│ │ │ │ ├── get_nearest_string.txt
│ │ │ │ └── get_value_from_json_file_by_key.json
│ │ │ ├── w_image_processor_test.hpp
│ │ │ ├── w_ocr_engine_test.hpp
│ │ │ ├── w_referee_test.hpp
│ │ │ ├── w_soccer_test.hpp
│ │ │ └── w_utilities_test.hpp
│ │ ├── w_common.cpp
│ │ └── w_common.hpp
│ ├── protos/
│ │ └── raft.proto
│ ├── stream/
│ │ ├── grpc/
│ │ │ ├── w_grpc_client.cpp
│ │ │ ├── w_grpc_client.hpp
│ │ │ ├── w_grpc_server.cpp
│ │ │ └── w_grpc_server.hpp
│ │ ├── http/
│ │ │ ├── w_http_server.cpp
│ │ │ └── w_http_server.hpp
│ │ ├── janus/
│ │ │ ├── w_janus_api_emc.cpp
│ │ │ └── w_janus_api_emc.hpp
│ │ ├── quic/
│ │ │ ├── datatypes/
│ │ │ │ ├── common_flags.hpp
│ │ │ │ ├── w_address.cpp
│ │ │ │ ├── w_address.hpp
│ │ │ │ ├── w_alpn.hpp
│ │ │ │ ├── w_credential_config.cpp
│ │ │ │ ├── w_credential_config.hpp
│ │ │ │ ├── w_new_connection_info.cpp
│ │ │ │ ├── w_new_connection_info.hpp
│ │ │ │ ├── w_registration_config.cpp
│ │ │ │ ├── w_registration_config.hpp
│ │ │ │ ├── w_settings.cpp
│ │ │ │ ├── w_settings.hpp
│ │ │ │ ├── w_status.cpp
│ │ │ │ └── w_status.hpp
│ │ │ ├── events/
│ │ │ │ ├── w_connection_event.cpp
│ │ │ │ ├── w_connection_event.hpp
│ │ │ │ ├── w_listener_event.cpp
│ │ │ │ ├── w_listener_event.hpp
│ │ │ │ ├── w_stream_event.cpp
│ │ │ │ └── w_stream_event.hpp
│ │ │ ├── handles/
│ │ │ │ ├── w_configuration.cpp
│ │ │ │ ├── w_configuration.hpp
│ │ │ │ ├── w_connection.cpp
│ │ │ │ ├── w_connection.hpp
│ │ │ │ ├── w_listener.cpp
│ │ │ │ ├── w_listener.hpp
│ │ │ │ ├── w_registration.cpp
│ │ │ │ ├── w_registration.hpp
│ │ │ │ ├── w_stream.cpp
│ │ │ │ └── w_stream.hpp
│ │ │ ├── internal/
│ │ │ │ ├── common.cpp
│ │ │ │ ├── common.hpp
│ │ │ │ ├── w_msquic_api.cpp
│ │ │ │ └── w_msquic_api.hpp
│ │ │ ├── w_quic.cpp
│ │ │ ├── w_quic.hpp
│ │ │ ├── w_quic_client.cpp
│ │ │ ├── w_quic_client.hpp
│ │ │ ├── w_quic_server.cpp
│ │ │ └── w_quic_server.hpp
│ │ ├── rist/
│ │ │ ├── w_rist.cpp
│ │ │ ├── w_rist.hpp
│ │ │ ├── w_rist_data_block.cpp
│ │ │ └── w_rist_data_block.hpp
│ │ └── test/
│ │ ├── ffmpeg_stream.hpp
│ │ ├── grpc.hpp
│ │ ├── quic.hpp
│ │ └── rist.hpp
│ ├── system/
│ │ ├── compression/
│ │ │ ├── w_lz4.cpp
│ │ │ ├── w_lz4.hpp
│ │ │ ├── w_lzma.cpp
│ │ │ └── w_lzma.hpp
│ │ ├── db/
│ │ │ ├── w_postgresql.cpp
│ │ │ └── w_postgresql.hpp
│ │ ├── gamepad/
│ │ │ ├── w_gamepad_client.hpp
│ │ │ ├── w_gamepad_client_emc.cpp
│ │ │ ├── w_gamepad_client_keymap.hpp
│ │ │ ├── w_gamepad_client_sdl.cpp
│ │ │ ├── w_gamepad_client_types.hpp
│ │ │ ├── w_gamepad_virtual.cpp
│ │ │ ├── w_gamepad_virtual.hpp
│ │ │ ├── w_gamepad_virtual_bus.hpp
│ │ │ ├── w_gamepad_virtual_pool.cpp
│ │ │ └── w_gamepad_virtual_pool.hpp
│ │ ├── getopt.h
│ │ ├── invocable.h
│ │ ├── log/
│ │ │ ├── w_log.cpp
│ │ │ ├── w_log.hpp
│ │ │ └── w_log_config.hpp
│ │ ├── script/
│ │ │ ├── w_lua.cpp
│ │ │ ├── w_lua.hpp
│ │ │ ├── w_python.cpp
│ │ │ └── w_python.hpp
│ │ ├── socket/
│ │ │ ├── w_socket_options.hpp
│ │ │ ├── w_tcp_client.cpp
│ │ │ ├── w_tcp_client.hpp
│ │ │ ├── w_tcp_server.cpp
│ │ │ ├── w_tcp_server.hpp
│ │ │ ├── w_ws_client.cpp
│ │ │ ├── w_ws_client.hpp
│ │ │ ├── w_ws_client_emc.cpp
│ │ │ ├── w_ws_client_emc.hpp
│ │ │ ├── w_ws_server.cpp
│ │ │ └── w_ws_server.hpp
│ │ ├── test/
│ │ │ ├── compress.hpp
│ │ │ ├── coroutine.hpp
│ │ │ ├── gamepad.hpp
│ │ │ ├── gametime.hpp
│ │ │ ├── index.html
│ │ │ ├── log.hpp
│ │ │ ├── lua.hpp
│ │ │ ├── postgresql.hpp
│ │ │ ├── process.hpp
│ │ │ ├── python.hpp
│ │ │ ├── signal_slot.hpp
│ │ │ ├── tcp.hpp
│ │ │ ├── trace.hpp
│ │ │ ├── ws.hpp
│ │ │ └── ws_server.sh
│ │ ├── w_flags.hpp
│ │ ├── w_gametime.cpp
│ │ ├── w_gametime.hpp
│ │ ├── w_leak_detector.cpp
│ │ ├── w_leak_detector.hpp
│ │ ├── w_overloaded.hpp
│ │ ├── w_process.cpp
│ │ ├── w_process.hpp
│ │ ├── w_time.cpp
│ │ ├── w_time.hpp
│ │ └── w_trace.hpp
│ ├── tests.cpp
│ ├── third_party/
│ │ ├── ffmpeg/
│ │ │ ├── LICENSE
│ │ │ ├── README.txt
│ │ │ ├── include/
│ │ │ │ ├── libavcodec/
│ │ │ │ │ ├── ac3_parser.h
│ │ │ │ │ ├── adts_parser.h
│ │ │ │ │ ├── avcodec.h
│ │ │ │ │ ├── avdct.h
│ │ │ │ │ ├── avfft.h
│ │ │ │ │ ├── bsf.h
│ │ │ │ │ ├── codec.h
│ │ │ │ │ ├── codec_desc.h
│ │ │ │ │ ├── codec_id.h
│ │ │ │ │ ├── codec_par.h
│ │ │ │ │ ├── d3d11va.h
│ │ │ │ │ ├── defs.h
│ │ │ │ │ ├── dirac.h
│ │ │ │ │ ├── dv_profile.h
│ │ │ │ │ ├── dxva2.h
│ │ │ │ │ ├── jni.h
│ │ │ │ │ ├── mediacodec.h
│ │ │ │ │ ├── packet.h
│ │ │ │ │ ├── qsv.h
│ │ │ │ │ ├── vdpau.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ ├── version_major.h
│ │ │ │ │ ├── videotoolbox.h
│ │ │ │ │ ├── vorbis_parser.h
│ │ │ │ │ └── xvmc.h
│ │ │ │ ├── libavdevice/
│ │ │ │ │ ├── avdevice.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ └── version_major.h
│ │ │ │ ├── libavfilter/
│ │ │ │ │ ├── avfilter.h
│ │ │ │ │ ├── buffersink.h
│ │ │ │ │ ├── buffersrc.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ └── version_major.h
│ │ │ │ ├── libavformat/
│ │ │ │ │ ├── avformat.h
│ │ │ │ │ ├── avio.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ └── version_major.h
│ │ │ │ ├── libavutil/
│ │ │ │ │ ├── adler32.h
│ │ │ │ │ ├── aes.h
│ │ │ │ │ ├── aes_ctr.h
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── audio_fifo.h
│ │ │ │ │ ├── avassert.h
│ │ │ │ │ ├── avconfig.h
│ │ │ │ │ ├── avstring.h
│ │ │ │ │ ├── avutil.h
│ │ │ │ │ ├── base64.h
│ │ │ │ │ ├── blowfish.h
│ │ │ │ │ ├── bprint.h
│ │ │ │ │ ├── bswap.h
│ │ │ │ │ ├── buffer.h
│ │ │ │ │ ├── camellia.h
│ │ │ │ │ ├── cast5.h
│ │ │ │ │ ├── channel_layout.h
│ │ │ │ │ ├── common.h
│ │ │ │ │ ├── cpu.h
│ │ │ │ │ ├── crc.h
│ │ │ │ │ ├── csp.h
│ │ │ │ │ ├── des.h
│ │ │ │ │ ├── detection_bbox.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── display.h
│ │ │ │ │ ├── dovi_meta.h
│ │ │ │ │ ├── downmix_info.h
│ │ │ │ │ ├── encryption_info.h
│ │ │ │ │ ├── error.h
│ │ │ │ │ ├── eval.h
│ │ │ │ │ ├── ffversion.h
│ │ │ │ │ ├── fifo.h
│ │ │ │ │ ├── file.h
│ │ │ │ │ ├── film_grain_params.h
│ │ │ │ │ ├── frame.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── hdr_dynamic_metadata.h
│ │ │ │ │ ├── hdr_dynamic_vivid_metadata.h
│ │ │ │ │ ├── hmac.h
│ │ │ │ │ ├── hwcontext.h
│ │ │ │ │ ├── hwcontext_cuda.h
│ │ │ │ │ ├── hwcontext_d3d11va.h
│ │ │ │ │ ├── hwcontext_drm.h
│ │ │ │ │ ├── hwcontext_dxva2.h
│ │ │ │ │ ├── hwcontext_mediacodec.h
│ │ │ │ │ ├── hwcontext_opencl.h
│ │ │ │ │ ├── hwcontext_qsv.h
│ │ │ │ │ ├── hwcontext_vaapi.h
│ │ │ │ │ ├── hwcontext_vdpau.h
│ │ │ │ │ ├── hwcontext_videotoolbox.h
│ │ │ │ │ ├── hwcontext_vulkan.h
│ │ │ │ │ ├── imgutils.h
│ │ │ │ │ ├── intfloat.h
│ │ │ │ │ ├── intreadwrite.h
│ │ │ │ │ ├── lfg.h
│ │ │ │ │ ├── log.h
│ │ │ │ │ ├── lzo.h
│ │ │ │ │ ├── macros.h
│ │ │ │ │ ├── mastering_display_metadata.h
│ │ │ │ │ ├── mathematics.h
│ │ │ │ │ ├── md5.h
│ │ │ │ │ ├── mem.h
│ │ │ │ │ ├── motion_vector.h
│ │ │ │ │ ├── murmur3.h
│ │ │ │ │ ├── opt.h
│ │ │ │ │ ├── parseutils.h
│ │ │ │ │ ├── pixdesc.h
│ │ │ │ │ ├── pixelutils.h
│ │ │ │ │ ├── pixfmt.h
│ │ │ │ │ ├── random_seed.h
│ │ │ │ │ ├── rational.h
│ │ │ │ │ ├── rc4.h
│ │ │ │ │ ├── replaygain.h
│ │ │ │ │ ├── ripemd.h
│ │ │ │ │ ├── samplefmt.h
│ │ │ │ │ ├── sha.h
│ │ │ │ │ ├── sha512.h
│ │ │ │ │ ├── spherical.h
│ │ │ │ │ ├── stereo3d.h
│ │ │ │ │ ├── tea.h
│ │ │ │ │ ├── threadmessage.h
│ │ │ │ │ ├── time.h
│ │ │ │ │ ├── timecode.h
│ │ │ │ │ ├── timestamp.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── twofish.h
│ │ │ │ │ ├── tx.h
│ │ │ │ │ ├── uuid.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ ├── video_enc_params.h
│ │ │ │ │ └── xtea.h
│ │ │ │ ├── libpostproc/
│ │ │ │ │ ├── postprocess.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ └── version_major.h
│ │ │ │ ├── libswresample/
│ │ │ │ │ ├── swresample.h
│ │ │ │ │ ├── version.h
│ │ │ │ │ └── version_major.h
│ │ │ │ └── libswscale/
│ │ │ │ ├── swscale.h
│ │ │ │ ├── version.h
│ │ │ │ └── version_major.h
│ │ │ ├── lib/
│ │ │ │ └── win/
│ │ │ │ ├── avcodec-59.def
│ │ │ │ ├── avcodec.lib
│ │ │ │ ├── avdevice-59.def
│ │ │ │ ├── avdevice.lib
│ │ │ │ ├── avfilter-8.def
│ │ │ │ ├── avfilter.lib
│ │ │ │ ├── avformat-59.def
│ │ │ │ ├── avformat.lib
│ │ │ │ ├── avutil-57.def
│ │ │ │ ├── avutil.lib
│ │ │ │ ├── postproc-56.def
│ │ │ │ ├── postproc.lib
│ │ │ │ ├── swresample-4.def
│ │ │ │ ├── swresample.lib
│ │ │ │ ├── swscale-6.def
│ │ │ │ └── swscale.lib
│ │ │ └── presets/
│ │ │ ├── libvpx-1080p.ffpreset
│ │ │ ├── libvpx-1080p50_60.ffpreset
│ │ │ ├── libvpx-360p.ffpreset
│ │ │ ├── libvpx-720p.ffpreset
│ │ │ └── libvpx-720p50_60.ffpreset
│ │ └── shells/
│ │ ├── ffmpeg/
│ │ │ ├── CMakeLists.txt
│ │ │ ├── FFMPEG/
│ │ │ │ ├── CMakeLists-FFMPEG.txt.in
│ │ │ │ └── CMakeLists.txt
│ │ │ └── third_party/
│ │ │ ├── dav1d/
│ │ │ │ ├── CMakeLists-dav1d.txt.in
│ │ │ │ └── CMakeLists.txt
│ │ │ ├── svt-av1/
│ │ │ │ ├── CMakeLists-svtav1.txt.in
│ │ │ │ └── CMakeLists.txt
│ │ │ └── vpx/
│ │ │ ├── CMakeLists-vpx.txt.in
│ │ │ └── CMakeLists.txt
│ │ ├── janus/
│ │ │ └── setup.sh
│ │ ├── librist/
│ │ │ ├── android-arm.ini
│ │ │ ├── android-armv8.ini
│ │ │ ├── librist-android.sh
│ │ │ ├── librist.bat
│ │ │ └── librist.sh
│ │ └── webRTC/
│ │ ├── webRTC.bat
│ │ └── webRTC.sh
│ ├── wolf.cpp
│ ├── wolf.hpp
│ └── wolf.ruleset
└── wolf_demo/
└── wasm/
├── build.sh
├── run.sh
├── ssl_server.py
├── wolf.cpp
└── www/
├── index.html
├── janus.js
├── janus_env.js
├── wolf.js
└── wolf.wasm
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
build
================================================
FILE: .gitattributes
================================================
#sources
*.c text
*.cc text
*.cxx text
*.cpp text
*.c++ text
*.hpp text
*.h text
*.h++ text
*.hh text
# Compiled Object files
*.slo binary
*.lo binary
*.o binary
*.obj binary
# Precompiled Headers
*.gch binary
*.pch binary
# Compiled Dynamic libraries
*.so binary
*.dylib binary
*.dll binary
# Compiled Static libraries
*.lai binary
*.la binary
*.a binary
*.lib binary
# Executables
*.exe binary
*.out binary
*.app binary
================================================
FILE: .github/workflows/codeql.yml
================================================
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Analysis"
on:
push:
branches: [ "main" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "main" ]
schedule:
- cron: '40 9 * * 0'
env:
# Path to the CMake build directory.
build: '${{ github.workspace }}/build'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup VCPKG
uses: friendlyanon/setup-vcpkg@v1
with: { committish: 63aa65e65b9d2c08772ea15d25fb8fdb0d32e557 }
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
#- name: Autobuild
#uses: github/codeql-action/autobuild@v2
- name: Configure CMake
run: cmake -B ${{ env.build }} --preset linux-x64-release
# Build is not required for MSVC Code Analysis and will be used for Codecov
- name: Build CMake
run: cmake --build ${{ env.build }} --preset linux-x64-release
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"
================================================
FILE: .github/workflows/msvc.yml
================================================
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
#
# Find more information at:
# https://github.com/microsoft/msvc-code-analysis-action
name: Microsoft C++ Code Analysis
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
schedule:
- cron: "41 16 * * 1"
env:
# Path to the CMake build directory.
build: "${{ github.workspace }}/build"
permissions:
contents: read
jobs:
analyze:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
name: Analyze
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup VCPKG
uses: friendlyanon/setup-vcpkg@v1
with: { committish: 63aa65e65b9d2c08772ea15d25fb8fdb0d32e557 }
- name: Get SW
uses: egorpugin/sw-action@master
- name: SW setup and add to PATH
run: |
./sw setup
echo "D:\a\WolfEngine\WolfEngine" >> $env:GITHUB_PATH
- name: Setup OpenCppCoverage and add to PATh
id: setup_opencppcoverage
run: |
choco install OpenCppCoverage -y
echo "C:\Program Files\OpenCppCoverage" >> $env:GITHUB_PATH
- name: Configure CMake
run: cmake -DCMAKE_BUILD_TYPE=Debug -B ${{ env.build }}
# Build is not required for MSVC Code Analysis and will be used for Codecov
- name: Build CMake
run: cmake --build ${{ env.build }}
- name: Run MSVC Code Analysis
uses: microsoft/msvc-code-analysis-action@04825f6d9e00f87422d6bf04e1a38b1f3ed60d99
# Provide a unique ID to access the sarif output path
id: run-analysis
with:
cmakeBuildDirectory: ${{ env.build }}
# Ruleset file that will determine what checks will be run
ruleset: NativeRecommendedRules.ruleset
ignoredTargetPaths: ${{ env.build }}/_deps/boost_chrono-src;${{ env.build }}/_deps/boost_context-src;${{ env.build }}/_deps/boost_coroutine-src;${{ env.build }}/_deps/boost_date_time-src;${{ env.build }}/_deps/boost_exception-src;${{ env.build }}/_deps/fmt-src;${{ env.build }}/_deps/boost_container-src;${{ env.build }}/_deps/opencv-src;${{ env.build }}/_deps/rapidjson-src;${{ env.build }}/_deps/tesseract-src
- name: Generate Codecov Report
id: generate_test_report
shell: cmd
run: OpenCppCoverage.exe --continue_after_cpp_exception --export_type cobertura:WolfCov.xml --sources %CD% --excluded_sources %CD%\build\_deps -- %CD%\build\wolf\Debug\wolf_tests.exe
- name: Upload Report to Codecov
uses: codecov/codecov-action@v2
with:
files: ./WolfCov.xml
fail_ci_if_error: true
functionalities: fix
# Upload SARIF file to GitHub Code Scanning Alerts
#- name: Upload SARIF to GitHub
# uses: github/codeql-action/upload-sarif@v2
# with:
# sarif_file: ${{ steps.run-analysis.outputs.sarif }}
# Upload SARIF file as an Artifact to download and view
- name: Upload SARIF as an Artifact
uses: actions/upload-artifact@v3
with:
name: sarif-file
path: ${{ steps.run-analysis.outputs.sarif }}
================================================
FILE: .gitignore
================================================
*.log
*.tlog
*.wLog
*.idb
*.pdb
*.ipch
*.ilk
*.recipe
*.res
*.enc
*.vscode
*.advixeproj
*.advixeexp
*.dflgadvixe
*.infoadvixe
*.DS_Store
*.db
*.db-shm
*.db-wal
*.opendb
*.DS_Store
*.pem
/bin/*
/build/*
/coverage/*
/install/*
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Fortran module files
*.mod
# Executables
*.exe
*.out
*.app
================================================
FILE: CHANGE_LOG.md
================================================
# ToDos
- Dynamic lod creator for lod sample
- Forward+
- DirectX 12
- Realtime Raytracing
- DEBUG, RELEASE, MinSizeRelease(does not have assimp and just use wscene files)
# 2.1
A major release, rewrite most of wolf.system with pure C
- fixed some bugs
- improved memory pool
- executing python from c has been added
# 2.0.0.0
A major release, rewrite most of wolf.system with pure C
- Build for Win64
- Build for OSX
- Build for iOS
- Build for Android-armv7
- Build for Linux64
# 1.68.0.9 (2018-10-03)
A minor release with many compatibility-breaking changes.
New features:
- CMAKE added for building wolf for linux platform
# 1.65.0.0 (2018-06-04)
A minor release with many compatibility-breaking changes.
New features:
- system::w_logger optimized and integrated with spdlog
- framework::w_media_core optimized for streaming
- gpu occlusion culling has been added
# 1.63.1.0 (2018-04-19)
A minor release with many compatibility-breaking changes.
New features:
- Integrated with Vulkan SDK version 1.1.73.0
- Integrated with VulkanMemoryAllocator for better gpu memory managment
- The new coordinate system is Left handed Y-Up
- The function "contains" have been added to wolf::system::w_bounding_sphere
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.22)
# set the name of the projects
project(wolf)
add_subdirectory(wolf)
================================================
FILE: CMakePresets.json
================================================
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20
},
"configurePresets": [
{
"name": "base",
"hidden": true,
"description": "base project for other configurations.",
"binaryDir": "${sourceDir}/build/${presetName}",
"installDir": "${sourceDir}/install/${presetName}",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"ARCH": "win64"
}
},
{
"name": "wasm32-unknown-emscripten-debug",
"displayName": "wasm32-unknown-emscripten",
"description": "Configure debug mode based on Emscripten",
"inherits": "base",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "wasm32-unknown-emscripten-release",
"displayName": "Win x64 Release",
"description": "Configure release mode based on Emscripten",
"inherits": "wasm32-unknown-emscripten-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "win-x64-debug",
"displayName": "Win x64 Debug",
"description": "Sets windows platform and debug build type for x64 arch",
"inherits": "base",
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "win-x64-release",
"displayName": "Win x64 Release",
"description": "Sets windows platform and release build type for x64 arch",
"inherits": "win-x64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "base-android",
"hidden": true,
"inherits": "base",
"environment": {
"ANDROID_NDK_HOME": "$env{NDK}",
"ANDROID_NDK": "$env{NDK}",
"ANDROID_NATIVE_API_LEVEL": "24",
"ANDROID_PLATFORM": "android-24"
},
"cacheVariables": {
"ANDROID": true,
"CMAKE_TOOLCHAIN_FILE": "$env{ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
"ANDROID_STL": "c++_shared",
"ANDROID_ABI": "arm64-v8a",
"CPU": "armv8",
"CMAKE_ANDROID_ARCH_ABI": "arm64-v8a",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_SYSTEM_NAME": "Android"
}
},
{
"name": "android-arm64-debug",
"inherits": "base-android",
"displayName": "Android ARM64 v8a Debug",
"description": "Sets android platform and debug build type for arm64-v8a arch",
"architecture": {
"value": "arm64-v8a",
"strategy": "external"
},
"environment": {
"ANDROID_ABI": "arm64-v8a",
"CPU": "armv8",
"ARCH": "aarch64",
"CMAKE_ANDROID_ARCH_ABI": "arm64-v8a",
"CMAKE_BUILD_TYPE": "Debug"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "android-arm64-release",
"displayName": "Android ARM64 v8a Release",
"description": "Sets android platform and release build type for arm64-v8a arch",
"inherits": "android-arm64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
},
"environment": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "android-arm-debug",
"inherits": "base-android",
"displayName": "Android ARM eabi v7a Debug",
"description": "Sets android platform and debug build type for armeabi-v7a arch",
"architecture": {
"value": "armeabi-v7a",
"strategy": "external"
},
"environment": {
"ANDROID_ABI": "armeabi-v7a",
"CPU": "arm",
"ARCH": "arm",
"CMAKE_ANDROID_ARCH_ABI": "armeabi-v7a",
"CMAKE_BUILD_TYPE": "Debug"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"ANDROID_ABI": "armeabi-v7a",
"CMAKE_ANDROID_ARCH_ABI": "armeabi-v7a",
"ARCH": "arm",
"CPU": "arm"
}
},
{
"name": "android-arm-release",
"displayName": "Android ARM eabi v7a Release",
"description": "Sets android platform and release build type for armeabi-v7a arch",
"inherits": "android-arm-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
},
"environment": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-x64-debug",
"displayName": "GCC x64 linux gnu debug",
"description": "Using compilers: C = /usr/bin/gcc, CXX = /usr/bin/g++",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install/${presetName}",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "linux-x64-release",
"displayName": "GCC x64 linux gnu release",
"inherits": "linux-x64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{
"name": "wasm32-unknown-emscripten-debug",
"displayName": "wasm32-unknown-emscripten-debug",
"description": "Build WebAssembly with Emscripten",
"configurePreset": "wasm32-unknown-emscripten-debug"
},
{
"name": "wasm32-unknown-emscripten-release",
"displayName": "wasm32-unknown-emscripten-release",
"description": "Build WebAssembly with Emscripten",
"configurePreset": "wasm32-unknown-emscripten-release"
},
{
"name": "win-x64-release",
"displayName": "Win x64 Release",
"description": "Sets windows platform and debug build type for x64 arch in release mode",
"configurePreset": "win-x64-release"
},
{
"name": "win-x64-debug",
"displayName": "Win x64 Debug",
"description": "Sets windows platform and debug build type for x64 arch in debug mode",
"configurePreset": "win-x64-debug"
},
{
"name": "android-arm64-debug",
"displayName": "Android ARM64 v8a Debug",
"description": "Build Android",
"configurePreset": "android-arm64-debug"
},
{
"name": "android-arm64-release",
"displayName": "Android ARM64 v8a Release",
"description": "Build Android",
"configurePreset": "android-arm64-release"
},
{
"name": "android-arm-debug",
"displayName": "Android ARM eabi v7a Debug",
"description": "Build Android",
"configurePreset": "android-arm-debug"
},
{
"name": "android-arm-release",
"displayName": "Android ARM eabi v7a Release",
"description": "Build Android",
"configurePreset": "android-arm-release"
},
{
"name": "linux-x64-debug",
"displayName": "Sets linux platform and debug build type for x64 arch in debug mode",
"description": "linux x64 Debug",
"configurePreset": "linux-x64-debug"
},
{
"name": "linux-x64-release",
"displayName": "Sets linux platform and release build type for x64 arch in release mode",
"description": "linux x64 Release",
"configurePreset": "linux-x64-release"
},
{
"name": "wasm",
"description": "",
"displayName": "",
"configurePreset": "wasm32-unknown-emscripten-debug"
}
],
"testPresets": [
{
"name": "base-tests",
"hidden": true,
"output": {
"outputOnFailure": true
}
},
{
"name": "windows-tests",
"inherits": "base-tests",
"configurePreset": "win-x64-debug"
}
]
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
pooya{dot}eimandar{at}gmail{dot}com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License 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.
================================================
FILE: README.md
================================================
# [Here is the Rust implementation of Wolf](https://github.com/WolfEngine/WolfEngine/tree/wolf-rs)
### Wolf Engine [](https://github.com/WolfEngine/Wolf.Engine/blob/main/LICENSE.md) [](https://codecov.io/github/WolfEngine/WolfEngine) [](https://github.com/WolfEngine/WolfEngine/actions/workflows/codeql.yml) [](https://github.com/WolfEngine/WolfEngine/actions/workflows/msvc.yml)
Welcome to the Wolf Engine source code.
The Wolf Engine is the next
generation of Persian Game Engine which is a
cross-platform open source game engine created by Pooya Eimandar.
The Wolf is a comprehensive set of C++ open source libraries for realtime rendering, realtime streaming and game developing, which is support Lua and WASM as an embedded scripting languages.
# Build
- Prerequisites
- For windows, make sure install the latest Windows 11/10 SDK
- [git](https://git-scm.com/downloads)
- [CMake](https://cmake.org/download/)
- [vcpkg](https://vcpkg.io/)
- [Meson](https://github.com/mesonbuild/meson/releases)
- [Ninja](https://ninja-build.org/). Alternatively, setup [Python3](https://www.python.org/downloads/) and use "pip3 install ninja"
- [QT6](https://www.qt.io/download) for demos and examples
- [NDK](https://developer.android.com/ndk/downloads) for android.
then make sure get the main branch
`git clone https://github.com/WolfEngine/WolfEngine.git --branch main --depth 1`
## CMakePresets
To list configure presets: `cmake . --list-presets`
To list build presets: `cmake --build --list-presets`
To install wolf: `cmake --install --prefix `
For example for building wolf for android:
```
cmake . --preset android-arm64-release
cmake --build --preset android-arm64-release
```
For example for building wolf for windows:
```
cmake . --preset win-x64-release
cmake --build --preset win-x64-release
cmake --install C:/WolfEngine/build/win-x64-release --prefix C:/wolf
```
## Recent Sample
Dynamic LOD Generation using Simplygon
## Supported platforms
| Not Supported | Planned | In Progress | Done |
|:-----------:|:-----------:|:-----------:|:-----------:|
| :x: | :memo: | :construction: | :white_check_mark: |
### Supported platforms and APIs for render module
| API | Windows | Linux | macOS | iOS | Android | Wasm |
|:-----------:|:-----------:|:--------------------------:|:--------------:|:-------------:|:--------------:|:-------------:|
| GPU | Vulkan/OpenGL ES :construction: | Vulkan/OpenGL ES :memo: | MoltenVK :memo: | MoltenVK :memo: | Vulkan/OpenGL ES :memo: | WebGL/WebGPU :memo: |
### Supported platforms and APIs for media module
| API | Windows | Linux | macOS | iOS | Android | Wasm |
|:-----------:|:-----------:|:--------------------------:|:--------------:|:-------------:|:--------------:|:-------------:|
| [Bitmap](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/media/test/ffmpeg.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| [FFmpeg](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/stream/test/ffmpeg_stream.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| [JPEG](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/media/test/ffmpeg.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| [OpenAL](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/media/test/openal.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| [PNG](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/media/test/ffmpeg.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| WebP | :memo: | :memo: | :memo: | :memo: | :memo: | :x: |
### Supported platforms and APIs for stream module
| API | Windows | Linux | macOS | iOS | Android | Wasm |
|:-----------:|:-----------:|:--------------------------:|:--------------:|:-------------:|:--------------:|:-------------:|
| gRPC | :memo: | :x: | :x: | :x: | :x: | :x: |
| [Janus](https://github.com/WolfEngine/WolfEngine/tree/main/wolf_demo/wasm) | :construction: | :x: | :x: | :x: | :x: | :white_check_mark: |
| [QUIC](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/stream/test/quic.hpp) | :white_check_mark: | :memo: | :memo: | :memo: | :memo: | :x: |
| [RIST](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/stream/test/rist.hpp) | :white_check_mark: | :memo: | :memo: | :memo: | :white_check_mark: | :x: |
| RTMP | :memo: | :x: | :x: | :x: | :x: | :x: |
| [RTSP](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/stream/test/ffmpeg_stream.hpp) | :white_check_mark: | :memo: | :memo: | :memo: | :memo: | :x: |
| [SRT](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/stream/test/ffmpeg_stream.hpp) | :white_check_mark: | :memo: | :memo: | :memo: | :memo: | :x: |
| webRTC | :memo: | :memo: | :memo: | :memo: | :memo: | :memo: |
| [WebSocket](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/ws.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :memo: |
### Supported platforms and APIs for system module
| API | Windows | Linux | macOS | iOS | Android | Wasm |
|:-----------:|:-----------:|:--------------------------:|:--------------:|:-------------:|:--------------:|:-------------:|
| [Coroutine](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/coroutine.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :x: | :x: | :x: |
| [GameTime](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/gametime.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :white_check_mark: |
| [Gamepad](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/gamepad.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :white_check_mark: |
| [Virtual Gamepad](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/gamepad.hpp) | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
| [Log](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/log.hpp) | :white_check_mark: | :white_check_mark: | :construction: | :construction: | :construction: | :construction: |
| LuaJit | :memo: | :memo: | :memo: | :memo: | :memo: | :x: |
| [LZ4](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/compress.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| [LZMA](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/compress.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :x: | :x: | :x: |
| OpenTelemetry | :memo: | :memo: | :memo: | :x: | :x: | :x: |
| RAFT | :memo: | :memo: | :memo: | :memo: | :memo: | :memo: |
| Screen Capture | :memo: | :construction: | :construction: | :x: | :x: | :x: |
| [Signal Slot](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/signal_slot.hpp) | :white_check_mark: | :white_check_mark: | :construction: | :x: | :x: | :x: |
| [Stacktrace](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/tests.cpp) | :white_check_mark: | :white_check_mark: | :construction: | :construction: | :construction: | :x: |
| Sycl | :memo: | :memo: | :memo: | :x: | :x: | :x: |
| [TCP](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/tcp.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| [Trace](https://github.com/WolfEngine/WolfEngine/blob/main/wolf/system/test/trace.hpp) | :white_check_mark: | :white_check_mark: | :memo: | :memo: | :memo: | :x: |
| UDP | :construction: | :memo: | :memo: | :memo: | :memo: | :x: |
| Wasm3 | :memo: | :memo: | :memo: | :memo: | :memo: | :memo: |
## Projects using Wolf
* [Wolf.Playout](https://www.youtube.com/watch?v=EZSdEjBvuGY), a playout automation software
* [Falcon](https://youtu.be/ygpz35ddZ_4), a real time 3D monitoring system
* [PlayPod](https://playpod.ir), the first cloud gaming platform launched in Middle East
* [RivalArium](https://rivalarium.com), play and rival other users via our leagues and duels from any device, any location and let your skills generate income
## [Youtube](https://www.youtube.com/c/WolfEngine)
## [Twitter](https://www.twitter.com/Wolf_Engine)
Wolf Engine © 2014-2023 [Pooya Eimandar](https://www.linkedin.com/in/pooyaeimandar/)
================================================
FILE: TODO.md
================================================
- support android
- support windows
- support linux
- support osx
- support ios
================================================
FILE: coverage.bat
================================================
OpenCppCoverage.exe --continue_after_cpp_exception --export_type=html:%CD%\coverage\ --sources %CD% --excluded_sources %CD%\build\_deps -- %CD%\build\wolf\Debug\wolf_tests.exe
================================================
FILE: docker/Dockerfile
================================================
ARG UBUNTU_VERSION="22.04"
FROM ubuntu:${UBUNTU_VERSION}
ENV VCPKG_ROOT=/opt/vcpkg
ARG VCPKG_GITHUB_REPOSITORY=https://github.com/microsoft/vcpkg/archive/master.tar.gz
ARG VCPKG_COMPRESSED_FILE_NAME=vcpkg.tar.gz
RUN set -eux \
&& export DEBIAN_FRONTEND="noninteractive" \
&& apt-get update \
&& apt-get install --yes --no-install-recommends \
build-essential \
ca-certificates \
cmake \
cpp \
curl \
git \
make \ls
pkg-config \
tar \
unzip \
wget \
zip
WORKDIR ${VCPKG_ROOT}
RUN wget -qO ${VCPKG_COMPRESSED_FILE_NAME} ${VCPKG_GITHUB_REPOSITORY} \
&& tar xf ${VCPKG_COMPRESSED_FILE_NAME} --strip-components=1 \
&& rm ${VCPKG_COMPRESSED_FILE_NAME} \
&& /opt/vcpkg/bootstrap-vcpkg.sh \
&& ln -s /opt/vcpkg/vcpkg /usr/local/bin/vcpkg
WORKDIR /workspace
COPY . .
RUN cmake -B build --preset linux-x64-release
RUN rm -rf ./*
================================================
FILE: docs/GCC.txt
================================================
cd /home/build
GCC_VERSION=10.2.0
wget https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VERSION}/gcc-${GCC_VERSION}.tar.gz
tar xzvf gcc-${GCC_VERSION}.tar.gz
mkdir obj.gcc-${GCC_VERSION}
cd gcc-${GCC_VERSION}
./contrib/download_prerequisites
cd ../obj.gcc-${GCC_VERSION}
#RedHat base
sudo yum groupinstall "Development Tools"
#Debian
sudo apt-get install build-essential
../gcc-${GCC_VERSION}/configure --disable-multilib --enable-languages=c,c++
make -j $(nproc)
make install
================================================
FILE: docs/ProblemSolutions.txt
================================================
------------------------------------------------------- -------------------------------------------------------
-------------------- Problem ----------------------- -------------------- Solution -----------------------
------------------------------------------------------- -------------------------------------------------------
initializePlugin function could not be found in Add following command to the Liker->command Line
Maya plug-in "/export:initializePlugin /export:uninitializePlugin"
------------------------------------------------------- -------------------------------------------------------
No target architecture error at compile time use #include instead of #include
------------------------------------------------------- -------------------------------------------------------
Copy relative content to the execution directory $(OutDir)/%(RelativeDir)/%(filename).cso for more info
see following link
http://msdn.microsoft.com/en-us/library/ms164313.aspx
------------------------------------------------------- -------------------------------------------------------
Debug does not active, breakpoint disable Properties->Linker->debugging->GenerateDebugInfo->yes
Properties->Linker->debugging->DebuggingAssembly->yes
Properties->C/C++->Code Generation->Multi-threaded Debug DLL (/MDd)
------------------------------------------------------- -------------------------------------------------------
Could not find entry point First right click on
Solution->Properties->Configuration Manager
set the x64
Then check dllMain or main function
------------------------------------------------------- -------------------------------------------------------
error MSB6006: "icl.exe" exited with code 4 switch from intel c++ to microsoft visual c++ to check other errors,
alsoCheck precompiled headers
------------------------------------------------------- -------------------------------------------------------
error LNK2019: unresolved external symbol __imp___CrtDbgReportW Remove _DEBUG from preprocessor or somwhere in your code
referenced in function, when you add std::map or std::vector
------------------------------------------------------- -------------------------------------------------------
Can link constructor or destructor ot method of a class make sure add API(see W_Object.h) before declaration of method in class
from DLL
------------------------------------------------------- -------------------------------------------------------
eglGetPlatformDisplayEXT does not generate display device make sure copy libGLESv2.dll, libEGL.dll & d3dcompiler_47.dll in bin folder
in Angle project
------------------------------------------------------- -------------------------------------------------------
Error MSB6006 "fxc.exe" exited with code 1. check all *.hlsl codes and shader type in Properties->HLSL Compiler->General in your project
================================================
FILE: docs/git-commands.txt
================================================
//subtrees
git config commit.gpgsign false
git fetch git@github.com:g-truc/glm.git master
git subtree add --prefix=engine/dependencies/glm-master/ --squash git@github.com:g-truc/glm.git master
git subtree pull --prefix=engine/dependencies/glm-master/ --squash git@github.com:g-truc/glm.git master
git fetch git@github.com:dwd/rapidxml.git master
git subtree add --prefix=engine/dependencies/rapidxml-master/ --squash git@github.com:dwd/rapidxml.git master
git subtree pull --prefix=engine/dependencies/rapidxml-master/ --squash git@github.com:dwd/rapidxml.git master
git fetch git@github.com:miloyip/rapidjson.git master
git subtree add --prefix=engine/dependencies/rapidjson-master/ --squash git@github.com:miloyip/rapidjson.git master
git subtree pull --prefix=engine/dependencies/rapidjson-master/ --squash git@github.com:miloyip/rapidjson.git master
================================================
FILE: docs/glslValidator.txt
================================================
./glslangValidator.exe -V -t -o ~path/to/out.spv ~/path/to/in.vert
================================================
FILE: docs/glslValidator_MoltenVK.txt
================================================
cd /Users/pooyaeimandar/Documents/github/WolfSource/Wolf.Engine/engine/dependencies/vulkan/Mac/Molten/MoltenShaderConverter/Tools/
./MoltenShaderConverter -gi /Users/pooyaeimandar/Documents/github/WolfSource/Wolf.Engine/samples/02_basics/02_shader/src/content/shaders/shader.frag -t f -so /Users/pooyaeimandar/Documents/github/WolfSource/Wolf.Engine/samples/02_basics/02_shader/src/content/shaders/shader.frag.spv
./MoltenShaderConverter -gi /Users/pooyaeimandar/Documents/github/WolfSource/Wolf.Engine/samples/02_basics/02_shader/src/content/shaders/shader.vert -t v -so /Users/pooyaeimandar/Documents/github/WolfSource/Wolf.Engine/samples/02_basics/02_shader/src/content/shaders/shader.vert.spv
================================================
FILE: docs/quic.md
================================================
# Wolf QUIC
Wolf provides quic protocol as a submodule under stream module. Current implementation is mostly a C++ wrapper over msquic which is written in C, along with a few helpers to simplify and help with common usages such as client/server.
There are one to one C++ wrapper types for msquic types. including enums and flags, core data types to hold information, and handle types. public methods and member variables are also kind of one to one with similar name, sometimes with a little modification to ease the use.
Handle instances which are async and have callbacks (connection and stream) have internal refcounting, and when running an instance of them will be managed internally and won't be destroyed/closed until stopped or are shut down. this allows, for example, one to start running an instance of connection in a listener callback and not to worry of managing its lifetime. and if an instance wasn't started, once its out of scope, it will automatically be closed.
Due to the way msquic was designed, the parentship of instances like stream by connection and connection/listener by registration must be handled by user of this library. for example: when a connection is closed, the stream will automatically shut down and user must ensure that stream instances held by them will no longer be accessed or avilable.
So make sure dependent handles **DO NOT** outlive their dependencies. hopefully in the future this will be managed internally.
To understand these dependencies please refer to `API` overview documenetation of msquic: https://github.com/microsoft/msquic/blob/main/docs/API.md
## Base Data Types
Msquic enums/flags have an equivalent enum classes to be used. for bit flags, `w_flags` is used to handle bitwise operations.
The header `stream/quic/datatypes/common_flags.hpp` defines common enum flags used throughout the project.
For alpn name, since it is not forced to be a string, there is `w_alpn_view` in `stream/quic/datatypes/w_alpn.hpp` which represents an alpn name and is simply an alias to `std::span`. it comes with `as_alpn_view` helper method to create view from string views and c strings.
Here is a list of C++ wrapper types and their corresponding msquic types:
- `w_address` represents `QUIC_ADDRESS`.
- `w_status` and `w_status_code` represent `QUIC_STATUS`. the first is for holding a status code and checking whether it succeeded or failed, and the latter is an enum representing different status codes defined by msquic.
- `w_settings` represents `QUIC_SETTINGS`, having each field as an `std::optional` so it can be easily aggregate initialized with specific field. e.g. `w_settings { .idle_timeout_ms = 2000 }`.
- `w_credential_config` represents `QUIC_CREDENTIAL_CONFIG`, and for convenience there are `w_certificate_` alongside it to represent `QUIC_CERTIFICATE_` and be used with ease to construct a credential config with any certificate without worrying about value semantics.
- `w_registration_config` represents `QUIC_REGISTRATION_CONFIG`, and its fields are accessible through set/get methods.
- `w_new_connection_info` represents `QUIC_NEW_CONNECTION_INFO`, and its fields are readonly, accessible through const methods with same name.
## Events
Just as msquic uses callbacks with event as a parameter, those event types are wrapped and represented by classes.
Event types are similar to `std::variant`, and to access the underlying event value, it must be visited with an overload set. wolf library provides `system/w_overloaded` to overload lambdas to ease this.
All event types also have a `name` method to get the underlying type's name string.
There are no fields, but wrapper classes for each specific event, named as `w__event_`, e.g. `w_listener_event_new_connection`. these event classes hold the underlying data, and provide getter and helper methods to interact with them.
Events can not be created, copied, or moved. their lifetime is solely in hands of wolf library that passes them to callback/visitor.
- `w_listener_event` represents `QUIC_LISTENER_EVENT`. in `w_listener_event_new_connection` there are accept/reject methods which shouldn't be called more than once or over each other, and if neither is called then the connection will be rejected.
- `w_conection_event` represents `QUIC_CONNEcTION_EVENT`, and just like `w_listener_event_new_connection` there is `w_connection_event_peer_stream_started` that has accept/reject methods and by default rejects if neither is called.
- `w_stream_event` represents `QUIC_STREAM_EVENT`.
## Handles
The handles in msquic all have the type of `HQUIC`. but here are the common concepts and kinds of handles provided by msquic which have their own api, and wolf has wrapper for them:
- Registration: `w_registration` which on destruction waits on its children to be closed.
- Configuration: `w_configuration`.
- Listener: `w_listener` which starts and works async with callback, but it will shutdown when its last instance goes out of scope.
- Connection: `w_connection` which starts and works async with callback, and will be kept alive/running even if there are no instances of it kept by user. thus user can easily accept/open a new connection and not have to worry about its lifetime.
- Stream: `w_stream` which starts and works async with callbacks, and will be kept alive/running even if there are no instances of it kept by user. thus user can easily accept/open a new stream and not have to worry about its lifetime.
Handles can not be constructed and are created by (commonly named `open`) factory static methods, using boost::leaf for error report and handling.
Callbacks passed to create/set_callback of handle can be any callable and its storage will be internally managed.
Wolf doesn't provide the `context` pointer concept of msquic to user of this library, so instead use lambda captures or other C++-based alternatives.
## For Developer/Contributor (Internals)
Msquic's api table is created only once and is provided by singleton-style factory method `internal::w_msquic_api::api`.
As a C wrapper library there are many scenarios which one C function/type requires another C instance, and for this reason `internal::w_raw_access` pattern is used. classes which wrap a raw/C type declare that as `freind` class and provide desired private api so in any other part in the library if raw access is required, it can be gained via `internal::w_raw_access` can be used and these two types/methods need not to know of each other (necessary for generics). saving us tons of forward declarations and maintenance bookkeepings.
Handles are kept lightweight, only have the `HQUIC` pointer as data member, and all of their required shared data is allocated on heap (the type `context_bundle`) and saved in the handle's context. so the context pointer must never change/written and should be always read for concurrency safety.
================================================
FILE: manifest.manifest
================================================
================================================
FILE: wolf/.clang-format
================================================
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Google
# This defaults to 'Auto'. Explicitly set it for a while, so that
# 'vector >' in existing files gets formatted to
# 'vector>'. ('Auto' means that clang-format will only use
# 'int>>' if the file already contains at least one such instance.)
Standard: Cpp11
SortIncludes: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
BreakStringLiterals: false
DerivePointerAlignment: true
PointerAlignment: Left
ColumnLimit: 100
ForEachMacros: ['list_for_every_entry','list_for_every_entry_safe']
IncludeBlocks: Regroup
IncludeCategories:
# This specific header must come last in kernel source files. Its
# matching rule must come first so the lower-priority rules don't match.
- Regex: '^'
Priority: 1000
# C Header: , , etc
- Regex: '^(<((zircon/|lib/|fuchsia/|arpa/|net/|netinet/|sys/|fidl/)[a-zA-Z0-9_/\.-]+\.h|[a-zA-Z0-9_-]+\.h)>)'
Priority: 1
# Cpp Header: and
- Regex: '^(<(experimental/)*[a-zA-Z0-9_-]+>)'
Priority: 2
# Libraries:
- Regex: '^(<[a-zA-Z0-9_/-]+\.h>)'
Priority: 3
# Local headers: "foo/bar.h"
- Regex: '^("[.a-zA-Z0-9_/-]+\.h")'
Priority: 4
================================================
FILE: wolf/.clang-tidy
================================================
---
Checks: >
-*,
bugprone-*,
clang-diagnostic-*,
-clang-diagnostic-unused-command-line-argument,
google-*,
-google-runtime-references,
misc-*,
-misc-noexcept*,
-misc-unused-parameters,
-misc-const-correctness,
modernize-*,
-modernize-avoid-c-arrays,
-modernize-deprecated-headers,
-modernize-raw-string-literal,
-modernize-return-braced-init-list,
-modernize-use-auto,
-modernize-use-equals-delete,
-modernize-use-nodiscard,
-modernize-use-trailing-return-type,
performance-*,
readability-*,
-readability-function-cognitive-complexity,
-readability-identifier-length,
-readability-implicit-bool-conversion,
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-qualified-auto,
-readability-uppercase-literal-suffix,
-readability-identifier-length,
-readability-named-parameter,
WarningsAsErrors: false
AnalyzeTemporaryDtors: false
FormatStyle: file
CheckOptions:
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore
value: 'int8_t'
- key: bugprone-assert-side-effect.AssertMacros
value: 'FXL_DCHECK'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '2'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-use-default-member-init.UseAssignment
value: '1'
- key: modernize-use-emplace.IgnoreImplicitConstructors
value: '1'
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
- key: readability-braces-around-statements.ShortStatementLines
value: '2'
================================================
FILE: wolf/.gitignore
================================================
*.DS_Store
*.suo
/build/*
/shells/ffmpeg/build/*
/rust/target/*
================================================
FILE: wolf/CMakeLists.txt
================================================
#cmake . -B build -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DANDROID_NDK=$ANDROID_NDK_HOME -DANDROID_PLATFORM=android-21 -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a -DCMAKE_ANDROID_NDK=$ANDROID_NDK_HOME -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=21 -DCMAKE_BUILD_TYPE=Debug -GNinja
#cd build
#ninja
cmake_minimum_required(VERSION 3.22...3.23)
# set the name of the projects
project(wolf
DESCRIPTION "Wolf Engine"
LANGUAGES CXX
)
set(TEST_PROJECT_NAME "${PROJECT_NAME}_tests")
message("CXX Compiler ID is ${CMAKE_CXX_COMPILER_ID}")
# set the options and enviroment variables
#set(WEBRTC_SRC $ENV{WEBRTC_ROOT} CACHE STRING "path to the root folder of webrtc folder")
#define includes, libs and srcs
set(INCLUDES)
set(LIBS PARENT_SCOPE)
set(SRCS)
set(TESTS_SRCS)
# check the OS
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
if (WIN32)
set(WIN64 TRUE)
endif()
endif()
if(UNIX AND (NOT APPLE) AND (NOT EMSCRIPTEN))
set(LINUX TRUE)
endif()
if (MSVC AND NOT WIN64)
message( FATAL_ERROR "Only Window 64 bit is supported" )
endif()
# set target os
if (WIN64)
set(TARGET_OS "win")
set(LIB_EXT "lib")
set(SHARED_EXT "dll")
elseif(APPLE)
set(TARGET_OS "mac")
set(LIB_EXT "a")
set(SHARED_EXT "dylib")
elseif(LINUX)
set(TARGET_OS "linux")
set(LIB_EXT "a")
set(SHARED_EXT "so")
elseif (NOT EMSCRIPTEN)
message( FATAL_ERROR "Unsuported OS, please open an issue at https://github.com/WolfEngine/WolfEngine" )
endif()
# required packages
find_package(Git REQUIRED)
if (NOT EMSCRIPTEN)
find_package (Threads)
endif()
# use folders
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# FetchContent for cloning repositories, avaiable since CMAKE 3.11
include(FetchContent)
set(FETCHCONTENT_QUIET OFF)
# set type of library
if (LINUX OR ANDROID_ABI)
set(LIBRARY_TYPE "SHARED")
else()
set(LIBRARY_TYPE "STATIC")
endif()
set(LIBRARY_TYPE "${LIBRARY_TYPE}" CACHE STRING "Library type")
# Build options
set(LIB_INSTALL_DIR lib CACHE STRING "Install location of libraries")
set(BIN_INSTALL_DIR bin CACHE STRING "Install location of executables")
set(INCLUDE_INSTALL_DIR include CACHE STRING "Install location of executables")
# CMAKE GUI Options
set(EMSDK "$ENV{EMSDK}" CACHE STRING "Emscripten SDK path")
set(BOOST_VERSION "1.82.0" CACHE STRING "Boost version tag")
# render module
option(WOLF_RENDER "Enable cross platform render engine based on Vulkan / OpenGL ES" OFF)
# media modules
option(WOLF_MEDIA_FFMPEG "Enable ffmpeg encoding and decoding" OFF)
option(WOLF_MEDIA_OPENAL "Enable OpenAL soft" OFF)
option(WOLF_MEDIA_SCREEN_CAPTURE "Enable screen capture" OFF)
option(WOLF_MEDIA_STB "Enable stb headers" OFF)
option(WOLF_MEDIA_GSTREAMER "Enable gstreamer wrapper" OFF)
# stream modules
option(WOLF_STREAM_GRPC "Enable gRPC connection" ON)
option(WOLF_STREAM_QUIC "Enable QUIC" OFF)
option(WOLF_STREAM_RIST "Enable RIST streaming protocol" OFF)
option(WOLF_STREAM_WEBRTC "Enable webRTC" OFF)
# system modules
option(WOLF_SYSTEM_GAMEPAD_CLIENT "Enable gamepad input handling" OFF)
option(WOLF_SYSTEM_GAMEPAD_VIRTUAL "Enable virtual gamepad simulator" OFF)
option(WOLF_SYSTEM_HTTP_WS "Enable http1.1 and websocket client/server based on boost beast or Emscripten" OFF)
option(WOLF_SYSTEM_LOG "Enable log" OFF)
option(WOLF_SYSTEM_LZ4 "Enable lz4 for compression" OFF)
option(WOLF_SYSTEM_LZMA "Enable lzma for compression" OFF)
option(WOLF_SYSTEM_LUA "Enable lua scripting language" OFF)
option(WOLF_SYSTEM_MIMALLOC "Enable Microsoft's mimalloc memory allocator" OFF)
option(WOLF_SYSTEM_POSTGRESQL "Enable postgresql database client" OFF)
option(WOLF_SYSTEM_PYTHON "Enable embedded Python3 scripting" OFF)
option(WOLF_SYSTEM_SIG_SLOT "Enable signal/slot based on boost signals2" OFF)
option(WOLF_SYSTEM_SOCKET "Enable TCP/UDP protocol over socket" OFF)
option(WOLF_SYSTEM_OPENSSL "Enable openSSL" OFF)
option(WOLF_SYSTEM_STACKTRACE "Enable boost stacktrace" OFF)
option(WOLF_SYSTEM_ZLIB "Enable Zlib compression library" OFF)
# machine learing modules
option(WOLF_ML_NUDITY_DETECTION "Enable machine learning nudity detection" OFF)
option(WOLF_ML_OCR "Enable machine learning referee ocr" OFF)
#option(WOLF_ENABLE_LTO "Enable cross language linking time optimization" OFF)
option(WOLF_TEST "Enable tests" ON)
if (NOT MSVC)
option(WOLF_ENABLE_ASAN "Enable ASAN" OFF)
endif()
if(ENABLE_LTO)
include(CheckIPOSupported)
check_ipo_supported(RESULT supported OUTPUT error)
if(supported)
message(STATUS "IPO / LTO enabled")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
add_link_options(-fuse-ld=lld)
else()
message(STATUS "IPO / LTO not supported: <${error}>")
endif()
endif()
# set C/CXX standards
set(CMAKE_C_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
#set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "Debug")
endif()
# set C++ flags based on compiler
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# using Clang or AppleClang
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2b -fexceptions -fcoroutines-ts")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2b -fexceptions -fcoroutines")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Microsoft Visual C++
# set C++23 as the primary standard
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_FLAGS "/EHsc /W3 /bigobj")
endif()
set(GETOPT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/system)
# include cmakes
include(cmake/vcpkg.cmake)
include(cmake/system.cmake)
include(cmake/stream.cmake)
include(cmake/media.cmake)
include(cmake/ml.cmake)
if (EMSCRIPTEN)
message(WARNING "WOLF_TEST will be disabled for Emscripten")
set(WOLF_TEST OFF)
else()
# currently threads was not supported with WASM
list(APPEND LIBS Threads::Threads)
endif()
# disable build testing
set(BUILD_TESTING OFF CACHE BOOL "BUILD_TESTING")
if (WOLF_ENABLE_ASAN)
set(ENABLE_ASAN TRUE)
endif()
#add_compile_options(-fsanitize=address)
#add_link_options(-fsanitize=address)
# enabling clang-tidy
# can be enabled with .CLANG-TIDY from Visual Studio Code
# https://devblogs.microsoft.com/cppblog/visual-studio-code-c-december-2021-update-clang-tidy/
# can be enabled with .CLANG-TIDY from Visual Studio
# https://devblogs.microsoft.com/cppblog/code-analysis-with-clang-tidy-in-visual-studio/
#set(CMAKE_C_CLANG_TIDY
# clang-tidy;
# -format-style=file;)
#set(CMAKE_CXX_CLANG_TIDY
# clang-tidy;
# -format-style=file;)
# add definitions
add_definitions(
-DBOOST_ASIO_NO_DEPRECATED
-DBOOST_ASIO_HAS_CO_AWAIT
-DBOOST_ASIO_HAS_STD_COROUTINE
)
if (MSVC)
add_definitions(
-EHsc
-DNOMINMAX
-DWIN32_LEAN_AND_MEAN
-DWIN64
-DWIN32
)
elseif (EMSCRIPTEN)
add_definitions(
-DEMSCRIPTEN
)
elseif(APPLE)
add_definitions(-DNEED_XLOCALE_H=1)
endif()
if(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DDEBUG -D_DEBUG)
else()
add_definitions(-DNDEBUG)
endif()
# setup Wolf definitions
get_cmake_property(_vars VARIABLES)
foreach (_var ${_vars})
string(FIND ${_var} "WOLF_" out)
if(("${out}" EQUAL 0) AND ("(${${_var}}" MATCHES ON))
add_definitions("-D${_var}")
endif()
endforeach()
# include sources
file(GLOB_RECURSE WOLF_SRCS
"${CMAKE_CURRENT_SOURCE_DIR}/wolf.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/wolf.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/DISABLE_ANALYSIS_BEGIN"
"${CMAKE_CURRENT_SOURCE_DIR}/DISABLE_ANALYSIS_END"
)
file(GLOB_RECURSE WOLF_PROTOS
"${CMAKE_CURRENT_SOURCE_DIR}/protos/*"
)
file(GLOB_RECURSE WOLF_CMAKES
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/*"
)
# includes
include_directories(
${INCLUDES}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/../
)
# add source codes
add_library(${PROJECT_NAME} ${LIBRARY_TYPE}
${SRCS}
${WOLF_SRCS}
${WOLF_CMAKES}
${WOLF_PROTOS}
)
if (WOLF_STREAM_RIST)
add_dependencies(${PROJECT_NAME} ${RIST_TARGET})
endif()
if (MSVC OR WIN32)
if (LIBRARY_TYPE STREQUAL "STATIC")
set_property(TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>")
else()
set_property(TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL")
endif()
endif()
# link libraries
target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBS})
# create source group
source_group("wolf" FILES ${WOLF_SRCS})
source_group("cmake" FILES ${WOLF_CMAKES})
source_group("protos" FILES ${WOLF_PROTOS})
source_group("stream/grpc" FILES ${WOLF_STREAM_GRPC_SRC})
source_group("stream/janus" FILES ${WOLF_STREAM_JANUS_SRC})
source_group("stream/test" FILES ${WOLF_STREAM_TEST_SRC})
source_group("stream/quic" FILES ${WOLF_STREAM_QUIC_SRC})
source_group("stream/rist" FILES ${WOLF_STREAM_RIST_SRC})
source_group("stream/webrtc/capturer" FILES ${WOLF_STREAM_WEBRTC_CAPTURER_SRC})
source_group("stream/webrtc/data" FILES ${WOLF_STREAM_WEBRTC_DATA_SRC})
source_group("stream/webrtc/interceptor" FILES ${WOLF_STREAM_WEBRTC_INTERCEPTOR_SRC})
source_group("stream/webrtc/media" FILES ${WOLF_STREAM_WEBRTC_MEDIA_SRC})
source_group("stream/webrtc/peer" FILES ${WOLF_STREAM_WEBRTC_PEER_SRC})
source_group("stream/test" FILES ${WOLF_STREAM_QUIC_SRC})
source_group("stream" FILES ${WOLF_STREAM_SRC})
source_group("system/gamepad" FILES ${WOLF_SYSTEM_GAMEPAD_CLIENT_SRC} ${WOLF_SYSTEM_GAMEPAD_VIRTUAL_SRCS})
source_group("system/log" FILES ${WOLF_SYSTEM_LOG_SRC})
source_group("system/compression" FILES ${WOLF_SYSTEM_LZ4_SRCS} ${WOLF_SYSTEM_LZMA_SRCS})
source_group("system/script" FILES ${WOLF_SYSTEM_LUA_SRC})
source_group("system/script" FILES ${WOLF_SYSTEM_PYTHON_SRC})
source_group("system/socket" FILES ${WOLF_SYSTEM_SOCKET_SRC} ${WOLF_SYSTEM_HTTP_WS_SRC})
source_group("system/test" FILES ${WOLF_SYSTEM_TEST_SRC})
source_group("system" FILES ${WOLF_SYSTEM_SRC})
source_group("media/test" FILES ${WOLF_MEDIA_TEST_SRC})
source_group("media/ffmpeg" FILES ${WOLF_MEDIA_FFMPEG_SRC})
source_group("media" FILES ${WOLF_MEDIA_OPENAL_SRC} ${WOLF_MEDIA_STB_SRC})
source_group("ml/referee_ocr" FILES ${WOLF_ML_OCR_SRC})
source_group("ml/nudity_detection" FILES ${WOLF_ML_NUD_DET_SRC})
# add compile options
if (NOT WIN32)
target_compile_options(${PROJECT_NAME} PRIVATE -std=c++2b -fPIC)
endif()
if (WOLF_ENABLE_ASAN)
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
endif()
# build tests
if (WOLF_TEST)
add_executable(${TEST_PROJECT_NAME}
tests.cpp
${TESTS_SRCS}
)
if (MSVC OR WIN32)
if (LIBRARY_TYPE STREQUAL "STATIC")
set_property(TARGET ${TEST_PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>")
else()
set_property(TARGET ${TEST_PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL")
endif()
endif()
if(WOLF_ML_OCR AND LINUX)
target_link_libraries(${TEST_PROJECT_NAME} PRIVATE ${PROJECT_NAME} ${leptonica_BINARY_DIR}/install/lib/libleptonica.so)
else()
target_link_libraries(${TEST_PROJECT_NAME} PRIVATE ${PROJECT_NAME})
endif()
if (NOT WIN32)
target_compile_options(${TEST_PROJECT_NAME} PRIVATE -std=c++2b)
endif()
include(CTest)
add_test(NAME ${TEST_PROJECT_NAME} COMMAND ${TEST_PROJECT_NAME})
endif()
if(WOLF_ML_OCR AND WIN64)
add_custom_command(TARGET ${TEST_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE} ${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}
)
endif()
# install target
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
foreach(ITEM ${INCLUDES})
install(DIRECTORY ${ITEM}/ DESTINATION ${INCLUDE_INSTALL_DIR})
endforeach()
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/wolf.hpp DESTINATION ${INCLUDE_INSTALL_DIR})
if (WOLF_TEST)
install(TARGETS ${TEST_PROJECT_NAME} DESTINATION ${BIN_INSTALL_DIR})
endif()
================================================
FILE: wolf/DISABLE_ANALYSIS_BEGIN
================================================
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning (disable:ALL_CODE_ANALYSIS_WARNINGS)
#endif
// NOLINTBEGIN
================================================
FILE: wolf/DISABLE_ANALYSIS_END
================================================
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// NOLINTEND
================================================
FILE: wolf/cmake/media.cmake
================================================
# link to ffmpeg
if (WOLF_MEDIA_FFMPEG)
file(GLOB_RECURSE WOLF_MEDIA_FFMPEG_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/media/ffmpeg/*"
)
list(APPEND SRCS ${WOLF_MEDIA_FFMPEG_SRC})
list(APPEND INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/third_party/ffmpeg/include)
list(APPEND FFMPEG_LIBS
avcodec
avdevice
avfilter
avformat
avutil
swresample
swscale
)
foreach (lib_name ${FFMPEG_LIBS})
list(APPEND LIBS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/ffmpeg/lib/${TARGET_OS}/${lib_name}.${LIB_EXT})
endforeach()
endif()
# link openAL
if (WOLF_MEDIA_OPENAL)
message("fetching https://github.com/kcat/openal-soft.git")
FetchContent_Declare(
openal
GIT_REPOSITORY https://github.com/kcat/openal-soft.git
GIT_TAG master
)
set(ALSOFT_EXAMPLES OFF CACHE BOOL "ALSOFT_EXAMPLES")
set(ALSOFT_INSTALL_EXAMPLES OFF CACHE BOOL "ALSOFT_INSTALL_EXAMPLES")
set(LIBTYPE "STATIC" CACHE STRING "STATIC")
set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(openal)
file(GLOB_RECURSE WOLF_MEDIA_OPENAL_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/media/w_openal.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/media/w_openal.cpp"
)
list(APPEND SRCS ${WOLF_MEDIA_OPENAL_SRC})
list(APPEND INCLUDES ${openal_SOURCE_DIR}/include)
list(APPEND LIBS OpenAL::OpenAL)
set_target_properties(
build_version
common
ex-common
OpenAL
openal-info
PROPERTIES FOLDER "openAL")
endif()
if (WOLF_MEDIA_STB)
message("fetching https://github.com/nothings/stb.git")
FetchContent_Declare(
stb
GIT_REPOSITORY https://github.com/nothings/stb.git
GIT_TAG master
)
FetchContent_Populate(stb)
file(GLOB_RECURSE WOLF_MEDIA_STB_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/media/w_image.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/media/w_image.hpp"
)
list(APPEND SRCS ${WOLF_MEDIA_STB_SRC})
list(APPEND INCLUDES ${stb_SOURCE_DIR})
endif()
if (WOLF_MEDIA_GSTREAMER)
file(GLOB_RECURSE WOLF_MEDIA_GSTREAMER_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/media/gst/*"
"${CMAKE_CURRENT_SOURCE_DIR}/media/gst/audio/*"
"${CMAKE_CURRENT_SOURCE_DIR}/media/gst/core/*"
"${CMAKE_CURRENT_SOURCE_DIR}/media/gst/elements/*"
"${CMAKE_CURRENT_SOURCE_DIR}/media/gst/video/*"
)
find_package(PkgConfig REQUIRED)
pkg_check_modules(gstreamer REQUIRED IMPORTED_TARGET
gstreamer-1.0
gstreamer-video-1.0
gstreamer-audio-1.0)
add_library(gstreamer-lib INTERFACE)
target_compile_options(gstreamer-lib INTERFACE ${gstreamer_CFLAGS})
target_include_directories(gstreamer-lib INTERFACE ${gstreamer_INCLUDE_DIRS})
target_link_directories(gstreamer-lib BEFORE INTERFACE ${gstreamer_LIBRARY_DIRS})
target_link_libraries(gstreamer-lib INTERFACE ${gstreamer_LIBRARIES})
list(APPEND SRCS ${WOLF_MEDIA_GSTREAMER_SRC})
list(APPEND LIBS gstreamer-lib)
endif()
file(GLOB_RECURSE WOLF_MEDIA_TEST_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/media/test/*"
)
list(APPEND SRCS ${WOLF_MEDIA_TEST_SRC})
================================================
FILE: wolf/cmake/ml.cmake
================================================
if(WOLF_ML_OCR)
if(LINUX)
# fetch leptonica
message("fetching https://github.com/DanBloomberg/leptonica.git")
FetchContent_Declare(
leptonica
GIT_REPOSITORY https://github.com/DanBloomberg/leptonica.git
GIT_TAG 1.80.0
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
FetchContent_Populate(leptonica)
add_custom_command(OUTPUT lept_config.out COMMAND cmake -B ${leptonica_BINARY_DIR} -DBUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_PREFIX:PATH=${leptonica_BINARY_DIR}/install ${leptonica_SOURCE_DIR})
add_custom_target(lept_config ALL DEPENDS lept_config.out)
add_custom_command(OUTPUT lept_build.out COMMAND cmake --build ${leptonica_BINARY_DIR} --target install)
add_custom_target(lept_build ALL DEPENDS lept_build.out)
endif()
# fetch tesseract
message("fetching https://github.com/tesseract-ocr/tesseract.git")
FetchContent_Declare(
tesseract
GIT_REPOSITORY https://github.com/tesseract-ocr/tesseract.git
GIT_TAG main
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
if(WIN64)
set(FETCHCONTENT_QUIET OFF)
set(BUILD_TESTS OFF CACHE BOOL "BUILD_TESTS")
set(BUILD_TRAINING_TOOLS OFF CACHE BOOL "BUILD_TRAINING_TOOLS")
set(DISABLE_ARCHIVE ON CACHE BOOL "DISABLE_ARCHIVE")
set(DISABLE_CURL ON CACHE BOOL "DISABLE_CURL")
set(FAST_FLOAT ON CACHE BOOL "FAST_FLOAT")
set(GRAPHICS_DISABLED ON CACHE BOOL "GRAPHICS_DISABLED")
set(INSTALL_CONFIGS OFF CACHE BOOL "INSTALL_CONFIGS")
set(SW_BUILD ON CACHE BOOL "SW_BUILD")
FetchContent_MakeAvailable(tesseract)
list(APPEND INCLUDES
${tesseract_SOURCE_DIR}/include
${tesseract_BINARY_DIR}/include
)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(DEBUG_LIB_EXTENTION "d")
else()
set(DEBUG_LIB_EXTENTION "")
endif()
list(APPEND LIBS
${tesseract_BINARY_DIR}/${CMAKE_BUILD_TYPE}/tesseract53${DEBUG_LIB_EXTENTION}.lib
)
elseif(LINUX)
FetchContent_Populate(tesseract)
list(APPEND INCLUDES
${tesseract_SOURCE_DIR}/include
${tesseract_BINARY_DIR}/install/include
)
link_directories(${tesseract_BINARY_DIR}/install/lib)
list(APPEND LIBS
tesseract
)
add_custom_command(OUTPUT tess_config.out COMMAND cmake -B ${tesseract_BINARY_DIR} -DBUILD_SHARED_LIBS=1 -DBUILD_TESTS=OFF -DBUILD_TRAINING_TOOLS=OFF -DDISABLE_ARCHIVE=ON -DDISABLE_CURL=ON -DFAST_FLOAT=ON -DGRAPHICS_DISABLED=ON -DINSTALL_CONFIGS=OFF -DLeptonica_DIR=${leptonica_BINARY_DIR} -DCMAKE_INSTALL_PREFIX:PATH=${tesseract_BINARY_DIR}/install ${tesseract_SOURCE_DIR})
add_custom_target(tess_config ALL DEPENDS tess_config.out)
add_custom_command(OUTPUT tess_build.out COMMAND cmake --build ${tesseract_BINARY_DIR} --target install)
add_custom_target(tess_build ALL DEPENDS tess_build.out)
endif()
# fetch opencv
message("fetching https://github.com/opencv/opencv.git")
FetchContent_Declare(
opencv
GIT_REPOSITORY https://github.com/opencv/opencv.git
GIT_TAG 4.5.4
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
if(WIN64)
FetchContent_GetProperties(opencv)
set(BUILD_LIST core,highgui,videoio CACHE STRING "BUILD_LIST")
set(WITH_IPP OFF CACHE BOOL "WITH_IPP")
set(BUILD_EXAMPLES OFF CACHE BOOL "BUILD_EXAMPLES")
set(OPENCV_GENERATE_PKGCONFIG ON CACHE BOOL "OPENCV_GENERATE_PKGCONFIG")
FetchContent_MakeAvailable(opencv)
list(APPEND INCLUDES
${CMAKE_BINARY_DIR}
${opencv_SOURCE_DIR}/include
${opencv_SOURCE_DIR}/modules/core/include
${opencv_SOURCE_DIR}/modules/highgui/include
${opencv_SOURCE_DIR}/modules/imgcodecs/include
${opencv_SOURCE_DIR}/modules/imgproc/include
${opencv_SOURCE_DIR}/modules/videoio/include
)
list(APPEND LIBS
${opencv_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}/opencv_core454${DEBUG_LIB_EXTENTION}.lib
${opencv_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}/opencv_highgui454${DEBUG_LIB_EXTENTION}.lib
${opencv_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}/opencv_imgcodecs454${DEBUG_LIB_EXTENTION}.lib
${opencv_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}/opencv_imgproc454${DEBUG_LIB_EXTENTION}.lib
${opencv_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE}/opencv_videoio454${DEBUG_LIB_EXTENTION}.lib
)
elseif(LINUX)
FetchContent_Populate(opencv)
list(APPEND INCLUDES
${opencv_BINARY_DIR}/install/include/opencv4
)
list(APPEND LIBS
${opencv_BINARY_DIR}/install/lib/libopencv_core.so
${opencv_BINARY_DIR}/install/lib/libopencv_highgui.so
${opencv_BINARY_DIR}/install/lib/libopencv_imgcodecs.so
${opencv_BINARY_DIR}/install/lib/libopencv_imgproc.so
${opencv_BINARY_DIR}/install/lib/libopencv_videoio.so
)
add_custom_command(OUTPUT opencv_config.out COMMAND cmake -B ${opencv_BINARY_DIR} -DBUILD_LIST=core,highgui,videoio -DBUILD_opencv_python3=OFF -DWITH_IPP=OFF -DBUILD_EXAMPLES=OFF -DOPENCV_GENERATE_PKGCONFIG=ON -DCMAKE_INSTALL_PREFIX:PATH=${opencv_BINARY_DIR}/install ${opencv_SOURCE_DIR})
add_custom_target(opencv_config ALL DEPENDS opencv_config.out)
add_custom_command(OUTPUT opencv_build.out COMMAND cmake --build ${opencv_BINARY_DIR} --target install)
add_custom_target(opencv_build ALL DEPENDS opencv_build.out)
endif()
# fetch rapidjson
message("fetching https://github.com/Tencent/rapidjson.git")
FetchContent_Declare(
rapidjson
GIT_REPOSITORY https://github.com/Tencent/rapidjson.git
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
FetchContent_Populate(rapidjson)
list(APPEND INCLUDES
${rapidjson_SOURCE_DIR}/include
)
file(GLOB_RECURSE WOLF_ML_OCR_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/ml/referee_ocr/*"
)
list(APPEND SRCS
${WOLF_ML_OCR_SRC}
)
endif()
if(WOLF_ML_NUDITY_DETECTION)
# Set the C++ standard for the rest of the project
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find Torch package
find_package(Torch REQUIRED)
# Set the C++ standard for the rest of the project
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(OpenCV REQUIRED)
list(APPEND INCLUDES
${OpenCV_INCLUDE_DIRS}
)
list(APPEND LIBS
${TORCH_LIBRARIES}
${OpenCV_LIBS}
)
file(GLOB_RECURSE WOLF_ML_SHARED_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/ml/w_common.*"
)
list(APPEND SRCS
${WOLF_ML_SHARED_SRC}
)
file(GLOB_RECURSE WOLF_ML_NUD_DET_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/ml/nudity_detection/*"
)
list(APPEND SRCS
${WOLF_ML_NUD_DET_SRC}
)
endif()
================================================
FILE: wolf/cmake/stream.cmake
================================================
# fetch gRPC
if (WOLF_STREAM_GRPC)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_STREAM_GRPC")
endif()
vcpkg_install(asio-grpc asio-grpc TRUE)
list(APPEND LIBS asio-grpc::asio-grpc)
file(GLOB_RECURSE WOLF_STREAM_GRPC_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/grpc/*"
)
list(APPEND SRCS
${WOLF_STREAM_GRPC_SRC}
)
if(WOLF_TEST)
add_library(generate-protos OBJECT)
target_link_libraries(generate-protos PUBLIC protobuf::libprotobuf gRPC::grpc++_unsecure)
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/protos")
set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/protos")
asio_grpc_protobuf_generate(
GENERATE_GRPC GENERATE_MOCK_CODE
TARGET generate-protos
USAGE_REQUIREMENT PUBLIC
IMPORT_DIRS ${PROTO_IMPORT_DIRS}
OUT_DIR "${PROTO_BINARY_DIR}"
PROTOS "${CMAKE_CURRENT_SOURCE_DIR}/protos/raft.proto")
list(APPEND INCLUDES "${PROTO_BINARY_DIR}")
list(APPEND TESTS_SRCS
"${PROTO_BINARY_DIR}/raft.grpc.pb.cc"
"${PROTO_BINARY_DIR}/raft.pb.cc"
)
endif()
endif()
if (WOLF_STREAM_JANUS)
file(GLOB_RECURSE WOLF_STREAM_JANUS_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/janus/*"
)
list(APPEND SRCS
${WOLF_STREAM_JANUS_SRC}
)
endif()
# fetch msquic
if (WOLF_STREAM_QUIC)
if (EMSCRIPTEN)
message(FATAL_ERROR "WOLF_STREAM_QUIC is not supported for wasm32 target")
endif()
if (NOT WIN32)
message(FATAL_ERROR "WOLF_STREAM_QUIC feature is not avilable on non-windows yet.")
endif()
file(GLOB_RECURSE WOLF_STREAM_QUIC_SRCS
"${CMAKE_CURRENT_SOURCE_DIR}/stream/quic/*"
)
if (WIN32 OR WIN64)
FetchContent_Declare(
msquic
URL https://github.com/microsoft/msquic/releases/download/v2.2.0/msquic_windows_x64_Release_schannel.zip
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_Populate(msquic)
else()
message(FATAL_ERROR "WOLF_STREAM_QUIC feature is not supported on target platform.")
endif()
add_library(msquic-lib INTERFACE)
add_library(msquic::msquic ALIAS msquic-lib)
target_include_directories(msquic-lib INTERFACE ${msquic_SOURCE_DIR}/include)
target_link_directories(msquic-lib INTERFACE BEFORE ${msquic_SOURCE_DIR}/bin)
target_link_directories(msquic-lib INTERFACE BEFORE ${msquic_SOURCE_DIR}/lib)
target_link_libraries(msquic-lib INTERFACE msquic)
list(APPEND SRCS ${WOLF_STREAM_QUIC_SRCS})
list(APPEND LIBS msquic::msquic)
endif()
if (WOLF_STREAM_RIST)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_STREAM_RIST")
endif()
set(RIST_TARGET "rist")
message("fetching https://code.videolan.org/rist/librist.git")
FetchContent_Declare(
${RIST_TARGET}
GIT_REPOSITORY https://code.videolan.org/rist/librist.git
GIT_TAG master
)
set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(${RIST_TARGET})
if (ANDROID)
add_custom_command(OUTPUT rist_command.out COMMAND
/bin/bash "${CMAKE_CURRENT_SOURCE_DIR}/third_party/shells/librist/librist-android.sh" --build_dir=${rist_BINARY_DIR}
WORKING_DIRECTORY ${rist_SOURCE_DIR})
add_custom_target(rist ALL DEPENDS rist_command.out)
list(APPEND LIBS
${rist_BINARY_DIR}/librist.a)
else ()
STRING(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWER)
add_custom_command(OUTPUT rist_command.out COMMAND cmd /c "meson setup ${rist_BINARY_DIR} --backend vs2022 --default-library static --buildtype ${CMAKE_BUILD_TYPE_LOWER} & meson compile -C ${rist_BINARY_DIR}" WORKING_DIRECTORY ${rist_SOURCE_DIR})
add_custom_target(rist ALL DEPENDS rist_command.out)
list(APPEND LIBS
ws2_32
${rist_BINARY_DIR}/librist.a)
endif()
list(APPEND INCLUDES
${rist_BINARY_DIR}
${rist_BINARY_DIR}/include
${rist_BINARY_DIR}/include/librist
${rist_SOURCE_DIR}/contrib
${rist_SOURCE_DIR}/contrib/mbedtls/include
${rist_SOURCE_DIR}/include
${rist_SOURCE_DIR}/include/librist
${rist_SOURCE_DIR}/src
)
file(GLOB_RECURSE WOLF_STREAM_RIST_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/rist/*"
)
list(APPEND SRCS ${WOLF_STREAM_RIST_SRC})
endif()
if (WOLF_STREAM_WEBRTC)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_STREAM_WEBRTC")
endif()
# we need http & json for webrtc
if (NOT WOLF_SYSTEM_JSON)
message( FATAL_ERROR "'WOLF_STREAM_WEBRTC' needs 'WOLF_SYSTEM_JSON' = ON" )
endif()
if (NOT WOLF_STREAM_HTTP)
message( FATAL_ERROR "'WOLF_STREAM_WEBRTC' needs 'WOLF_STREAM_HTTP' = ON" )
endif()
list(APPEND INCLUDES
${WEBRTC_SRC}
${WEBRTC_SRC}/third_party/abseil-cpp
${WEBRTC_SRC}/third_party/libyuv/include
)
if (WIN32)
# enable/disable debug option
if(CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(
-D_HAS_ITERATOR_DEBUGGING=1
-D_ITERATOR_DEBUG_LEVEL=2
)
else()
add_definitions(
-D_HAS_ITERATOR_DEBUGGING=0
-D_ITERATOR_DEBUG_LEVEL=0
)
endif()
add_definitions(
-DWEBRTC_WIN
-D__PRETTY_FUNCTION__=__FUNCTION__
#-DUSE_X11
#-D_WINSOCKAPI_
-DHAVE_SOUND)
list(APPEND LIBS
d3d11
dmoguids
dwmapi
dxgi
iphlpapi
msdmo
secur32
strmiids
winmm
wmcodecdspuuid
)
elseif (APPLE)
add_definitions(
-DHAVE_SOUND
-DWEBRTC_MAC
-DWEBRTC_POSIX
-fno-rtti)
find_library(APPLICATION_SERVICES ApplicationServices)
find_library(AUDIO_TOOLBOX AudioToolBox)
find_library(CORE_AUDIO CoreAudio)
find_library(CORE_FOUNDATION CoreFoundation)
find_library(CORE_SERVICES CoreServices)
find_library(FOUNDATION Foundation)
list(APPEND LIBS
${APPLICATION_SERVICES}
${AUDIO_TOOLBOX}
${CORE_AUDIO}
${CORE_FOUNDATION}
${CORE_SERVICES}
${FOUNDATION}
)
endif()
add_definitions(-DHAVE_JPEG)
link_directories(${WEBRTC_SRC}/out/${TARGET_OS}/${CMAKE_BUILD_TYPE}/obj/)
list(APPEND LIBS webrtc)
file(GLOB_RECURSE WOLF_STREAM_WEBRTC_CAPTURER_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/webrtc/capturer/*"
)
file(GLOB_RECURSE WOLF_STREAM_WEBRTC_DATA_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/webrtc/data/*"
)
file(GLOB_RECURSE WOLF_STREAM_WEBRTC_INTERCEPTOR_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/webrtc/interceptor/*"
)
file(GLOB_RECURSE WOLF_STREAM_WEBRTC_MEDIA_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/webrtc/media/*"
)
file(GLOB_RECURSE WOLF_STREAM_WEBRTC_PEER_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/webrtc/peer/*"
)
list(APPEND SRCS
${WOLF_STREAM_WEBRTC_CAPTURER_SRC}
${WOLF_STREAM_WEBRTC_DATA_SRC}
${WOLF_STREAM_WEBRTC_INTERCEPTOR_SRC}
${WOLF_STREAM_WEBRTC_MEDIA_SRC}
${WOLF_STREAM_WEBRTC_PEER_SRC}
)
endif()
file(GLOB_RECURSE WOLF_STREAM_TEST_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/stream/test/*"
)
list(APPEND SRCS ${WOLF_STREAM_TEST_SRC})
================================================
FILE: wolf/cmake/system.cmake
================================================
if (WOLF_SYSTEM_STACKTRACE)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_SYSTEM_STACKTRACE")
elseif(NOT MSVC)
message(FATAL_ERROR "WOLF_SYSTEM_STACKTRACE is only supported on Visual C++")
endif()
endif()
# fetch mimalloc
if (WOLF_SYSTEM_MIMALLOC)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_SYSTEM_MIMALLOC")
endif()
vcpkg_install(mimalloc mimalloc TRUE)
list(APPEND LIBS mimalloc)
endif()
# fetch boost components via vcpkg
if (EMSCRIPTEN)
execute_process(COMMAND vcpkg install
boost-leaf
boost-signals2 --triplet=${VCPKG_TARGET_TRIPLET})
elseif(WOLF_SYSTEM_PYTHON)
execute_process(COMMAND vcpkg install
boost-asio
boost-beast
boost-leaf
boost-python
boost-signals2
boost-test --triplet=${VCPKG_TARGET_TRIPLET})
else()
execute_process(COMMAND vcpkg install
boost-asio
boost-beast
boost-leaf
boost-signals2
boost-test --triplet=${VCPKG_TARGET_TRIPLET})
endif()
set(Boost_INCLUDE_DIR $ENV{VCPKG_ROOT}/installed/${VCPKG_TARGET_TRIPLET}/include CACHE STRING "boost include directory" FORCE)
list(APPEND INCLUDES ${Boost_INCLUDE_DIR})
find_package(Boost ${Boost_VERSION} REQUIRED)
# install gsl
vcpkg_install(Microsoft.GSL ms-gsl TRUE)
list(APPEND LIBS Microsoft.GSL::GSL)
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT EMSCRIPTEN)
vcpkg_install(fmt fmt FALSE)
list(APPEND LIBS fmt::fmt-header-only)
endif()
if (WOLF_SYSTEM_GAMEPAD_CLIENT)
file(GLOB_RECURSE WOLF_SYSTEM_GAMEPAD_CLIENT_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_client_emc.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_client_keymap.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_client_sdl.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_client_types.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_client.hpp"
)
list(APPEND SRCS ${WOLF_SYSTEM_GAMEPAD_CLIENT_SRC})
if (NOT EMSCRIPTEN)
message("fetching https://github.com/libsdl-org/SDL")
FetchContent_Declare(
SDL3-static
GIT_REPOSITORY https://github.com/libsdl-org/SDL
GIT_TAG main
)
set(SDL_AUDIO OFF CACHE BOOL "SDL_AUDIO")
set(SDL_DIRECTX OFF CACHE BOOL "SDL_DIRECTX")
set(SDL_DISKAUDIO OFF CACHE BOOL "SDL_DISKAUDIO")
set(SDL_DUMMYAUDIO OFF CACHE BOOL "SDL_DUMMYAUDIO")
set(SDL_DUMMYVIDEO OFF CACHE BOOL "SDL_DUMMYVIDEO")
set(SDL_FILE OFF CACHE BOOL "SDL_FILE")
set(SDL_FILESYSTEM OFF CACHE BOOL "SDL_FILESYSTEM")
set(SDL_METAL OFF CACHE BOOL "SDL_METAL")
set(SDL_OFFSCREEN OFF CACHE BOOL "SDL_OFFSCREEN")
set(SDL_OPENGL OFF CACHE BOOL "SDL_OPENGL")
set(SDL_OPENGLES OFF CACHE BOOL "SDL_OPENGLES")
set(SDL_RENDER OFF CACHE BOOL "SDL_RENDER")
set(SDL_RENDER_D3D OFF CACHE BOOL "SDL_RENDER_D3D")
set(SDL_RENDER_METAL OFF CACHE BOOL "SDL_RENDER_METAL")
set(SDL_SHARED OFF CACHE BOOL "SDL_SHARED")
set(SDL_TEST OFF CACHE BOOL "SDL_TEST")
set(SDL_TESTS OFF CACHE BOOL "SDL_TESTS")
set(SDL_VIDEO OFF CACHE BOOL "SDL_VIDEO")
set(SDL_VULKAN OFF CACHE BOOL "SDL_VULKAN")
set(SDL_WASAPI OFF CACHE BOOL "SDL_WASAPI")
set(SDL_HIGHDAPI_JOYSTICK ON CACHE BOOL "SDL_HIGHDAPI_JOYSTICK")
set(SDL_JOYSTICK ON CACHE BOOL "SDL_JOYSTICK")
set(SDL_STATIC ON CACHE BOOL "SDL_STATIC")
set(SDL_XINPUT ON CACHE BOOL "SDL_XINPUT")
set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(SDL3-static)
list(APPEND INCLUDES
${SDL3-static_SOURCE_DIR}/include
)
list(APPEND LIBS SDL3-static)
set_target_properties(
SDL3-static
uninstall
PROPERTIES FOLDER "SDL")
endif()
endif()
if (WOLF_SYSTEM_GAMEPAD_VIRTUAL)
if (NOT WIN32)
message(SEND_ERROR "WOLF_SYSTEM_GAMEPAD_VIRTUAL can only build for Windows")
else()
message("fetching https://github.com/ViGEm/ViGEmClient.git")
FetchContent_Declare(
ViGEmClient
GIT_REPOSITORY https://github.com/ViGEm/ViGEmClient.git
GIT_TAG master
)
FetchContent_MakeAvailable(ViGEmClient)
file(GLOB_RECURSE WOLF_SYSTEM_GAMEPAD_VIRTUAL_SRCS
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_virtual_pool.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_virtual_pool.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_virtual.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/gamepad/w_gamepad_virtual.hpp"
)
list(APPEND SRCS ${WOLF_SYSTEM_GAMEPAD_VIRTUAL_SRCS})
list(APPEND INCLUDES ${ViGEmClient_SOURCE_DIR}/include)
list(APPEND LIBS
ViGEmClient
Xinput.lib
SetupAPI.lib)
endif()
endif()
if (WOLF_SYSTEM_LOG)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_SYSTEM_LOG")
endif()
vcpkg_install(spdlog spdlog TRUE)
list(APPEND LIBS spdlog::spdlog spdlog::spdlog_header_only)
file(GLOB_RECURSE WOLF_SYSTEM_LOG_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/log/*"
)
list(APPEND SRCS ${WOLF_SYSTEM_LOG_SRC})
endif()
if (WOLF_SYSTEM_LZ4)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_SYSTEM_LZ4")
endif()
vcpkg_install(lz4 lz4 TRUE)
list(APPEND LIBS lz4::lz4)
file(GLOB_RECURSE WOLF_SYSTEM_LZ4_SRCS
"${CMAKE_CURRENT_SOURCE_DIR}/system/compression/w_lz4.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/compression/w_lz4.hpp"
)
list(APPEND SRCS ${WOLF_SYSTEM_LZ4_SRCS})
endif()
if (WOLF_SYSTEM_LZMA)
if (EMSCRIPTEN)
message(FATAL_ERROR "the wasm32 target is not supported for WOLF_SYSTEM_LZMA")
endif()
message("fetching https://github.com/WolfEngine/lzma.git")
FetchContent_Declare(
lzma
GIT_REPOSITORY https://github.com/WolfEngine/lzma.git
GIT_TAG main
)
set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(lzma)
file(GLOB_RECURSE WOLF_SYSTEM_LZMA_SRCS
"${CMAKE_CURRENT_SOURCE_DIR}/system/compression/w_lzma.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/compression/w_lzma.hpp"
)
list(APPEND SRCS ${WOLF_SYSTEM_LZMA_SRCS})
list(APPEND INCLUDES ${lzma_SOURCE_DIR}/src)
list(APPEND LIBS lzma)
endif()
# include openSSL
if (WOLF_SYSTEM_OPENSSL AND NOT EMSCRIPTEN)
vcpkg_install(OpenSSL openssl FALSE)
list(APPEND LIBS OpenSSL::SSL OpenSSL::Crypto)
endif()
# include socket/websocket sources
if (WOLF_SYSTEM_SOCKET AND NOT EMSCRIPTEN)
file(GLOB_RECURSE WOLF_SYSTEM_SOCKET_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_socket_options.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_tcp_client.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_tcp_client.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_tcp_server.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_tcp_server.hpp"
)
list(APPEND SRCS ${WOLF_SYSTEM_SOCKET_SRC})
endif()
if (WOLF_SYSTEM_HTTP_WS)
if (EMSCRIPTEN)
file(GLOB_RECURSE WOLF_SYSTEM_HTTP_WS_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_ws_client_emc.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_ws_client_emc.hpp"
)
else()
file(GLOB_RECURSE WOLF_SYSTEM_HTTP_WS_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_ws_client.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_ws_client.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_ws_server.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/socket/w_ws_server.hpp"
)
endif()
list(APPEND SRCS ${WOLF_SYSTEM_HTTP_WS_SRC})
endif()
if (WOLF_SYSTEM_ZLIB)
vcpkg_install(ZLIB zlib FALSE)
list(APPEND LIBS ZLIB::ZLIB)
endif()
if (WOLF_SYSTEM_POSTGRESQL)
vcpkg_install(libpq libpq TRUE)
list(APPEND LIBS libpq::libpq)
file(GLOB_RECURSE WOLF_SYSTEM_POSTGRESQL_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/db/w_postgresql.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/db/w_postgresql.hpp"
)
list(APPEND LIBS PostgreSQL::PostgreSQL)
endif()
if (WOLF_SYSTEM_LUA)
vcpkg_install(Lua lua FALSE)
vcpkg_install(sol2 sol2 TRUE)
list(APPEND LIBS lua sol2)
file(GLOB_RECURSE WOLF_SYSTEM_LUA_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/script/w_lua.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/script/w_lua.hpp"
)
list(APPEND SRCS
${WOLF_SYSTEM_LUA_SRC}
)
endif()
if (WOLF_SYSTEM_PYTHON)
find_package(Python3 REQUIRED COMPONENTS Development)
find_package(Boost REQUIRED COMPONENTS python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
file(GLOB_RECURSE WOLF_SYSTEM_PYTHON_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/script/w_python.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/script/w_python.hpp"
)
list(APPEND SRCS
${WOLF_SYSTEM_PYTHON_SRC}
)
list(APPEND INCLUDES ${Python3_INCLUDE_DIRS})
list(APPEND LIBS Python3::Python Boost::python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR})
get_filename_component(PYTHON_HOME ${Python3_EXECUTABLE} DIRECTORY)
add_definitions(
-DBOOST_PYTHON_STATIC_LIB
-DPYTHON_HOME="${PYTHON_HOME}"
)
endif()
if (EMSCRIPTEN)
file (GLOB_RECURSE WOLF_SYSTEM_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_gametime.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_gametime.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_trace.hpp"
)
else()
file (GLOB_RECURSE WOLF_SYSTEM_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/getopt.h"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_gametime.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_gametime.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_leak_detector.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_leak_detector.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_process.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_process.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_time.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_time.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/system/w_trace.hpp"
)
endif()
file(GLOB_RECURSE WOLF_SYSTEM_TEST_SRC
"${CMAKE_CURRENT_SOURCE_DIR}/system/test/*"
)
list(APPEND SRCS
${WOLF_SYSTEM_SRC}
${WOLF_SYSTEM_TEST_SRC}
)
================================================
FILE: wolf/cmake/vcpkg.cmake
================================================
if(NOT DEFINED ENV{VCPKG_ROOT})
message(FATAL_ERROR "VCPKG_ROOT environment variable is not set.")
endif()
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
if(CMAKE_TOOLCHAIN_FILE MATCHES "android_x86_64")
set(vcpkg_triplet "x64-android")
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "android_x86")
set(vcpkg_triplet "x86-android")
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "android_arm64_v8a")
set(vcpkg_triplet "arm64-android")
elseif(CMAKE_TOOLCHAIN_FILE MATCHES "android_armv7")
set(vcpkg_triplet "arm-neon-android")
endif()
elseif(ANDROID_ABI)
if(ANDROID_ABI STREQUAL "x86_64")
set(vcpkg_triplet "x64-android")
elseif(ANDROID_ABI STREQUAL "x86")
set(vcpkg_triplet "x86-android")
elseif(ANDROID_ABI STREQUAL "arm64-v8a")
set(vcpkg_triplet "arm64-android")
elseif(ANDROID_ABI STREQUAL "armeabi-v7a")
set(vcpkg_triplet "arm-neon-android")
endif()
elseif(EMSCRIPTEN)
set(vcpkg_triplet "wasm32-emscripten")
else() # desktop
if(WIN32)
set(vcpkg_triplet "x64-windows")
elseif(APPLE)
set(vcpkg_triplet "x64-osx")
elseif(UNIX)
set(vcpkg_triplet "x64-linux")
endif()
endif()
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
if (LIBRARY_TYPE STREQUAL "STATIC" AND NOT EMSCRIPTEN)
set(VCPKG_TARGET_TRIPLET ${vcpkg_triplet}-static CACHE STRING "vcpkg target triplet" FORCE)
else()
set(VCPKG_TARGET_TRIPLET ${vcpkg_triplet} CACHE STRING "vcpkg target triplet" FORCE)
endif()
include("$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
function(vcpkg_install PACKAGE PACKAGE_NAME WITH_CONFIG)
message(STATUS "finding ${PACKAGE}")
if (WITH_CONFIG)
find_package(${PACKAGE} CONFIG)
else()
find_package(${PACKAGE})
endif()
if(NOT ${PACKAGE}_FOUND)
message(STATUS "installing ${PACKAGE} via vcpkg")
execute_process(COMMAND vcpkg install ${PACKAGE_NAME} --triplet=${VCPKG_TARGET_TRIPLET})
if (WITH_CONFIG)
find_package(${PACKAGE} CONFIG REQUIRED)
else()
find_package(${PACKAGE} REQUIRED)
endif()
endif()
endfunction()
================================================
FILE: wolf/media/ffmpeg/w_av_config.cpp
================================================
#include "w_av_config.hpp"
using w_av_config = wolf::media::ffmpeg::w_av_config;
w_av_config::w_av_config(_In_ AVPixelFormat p_format, _In_ int p_width, _In_ int p_height,
_In_ int p_alignment) noexcept
: format(p_format), width(p_width), height(p_height), alignment(p_alignment) {}
w_av_config::w_av_config(_In_ int p_nb_channels, _In_ AVSampleFormat p_sample_fmts,
_In_ int p_sample_rate) noexcept
: sample_rate(p_sample_rate), sample_fmts(p_sample_fmts), nb_channels(p_nb_channels) {}
int w_av_config::get_required_video_buffer_size() const noexcept {
return av_image_get_buffer_size(this->format, this->width, this->height, this->alignment);
}
================================================
FILE: wolf/media/ffmpeg/w_av_config.hpp
================================================
/*
Project: Wolf Engine. Copyright 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include
extern "C" {
#include
#include
}
namespace wolf::media::ffmpeg {
class w_av_config {
public:
#pragma region Constructors /Destructor
// default constructor
W_API w_av_config() noexcept = default;
// constructor for av video format
W_API w_av_config(_In_ AVPixelFormat p_format, _In_ int p_width, _In_ int p_height,
_In_ int p_alignment = 1) noexcept;
// constructor for av audio format
W_API w_av_config(_In_ int p_nb_channels, _In_ AVSampleFormat p_sample_fmts,
_In_ int p_sample_rate) noexcept;
// destructor
W_API virtual ~w_av_config() noexcept = default;
// move constructor.
W_API w_av_config(w_av_config &&p_other) noexcept = default;
// move assignment operator.
W_API w_av_config &operator=(w_av_config &&p_other) noexcept = default;
// copy constructor
w_av_config(const w_av_config &p_other) noexcept = default;
// copy assignment operator
w_av_config &operator=(const w_av_config &p_other) noexcept = default;
#pragma endregion
/**
* @returns the required buffer size for video frame
*/
W_API int get_required_video_buffer_size() const noexcept;
// the format of av frame
AVPixelFormat format = AVPixelFormat::AV_PIX_FMT_NONE;
// the width of av frame
int width = 0;
// the height of av frame
int height = 0;
// data alignment
int alignment = 0;
// the sample rate of the audio
int sample_rate = 0;
// the sample format of the audio
AVSampleFormat sample_fmts = AVSampleFormat::AV_SAMPLE_FMT_NONE;
// number of channels
int nb_channels = 0;
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_av_format.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_av_format.hpp"
#include "w_av_frame.hpp"
using w_av_format = wolf::media::ffmpeg::w_av_format;
w_av_format::w_av_format() noexcept
: _stream_buffer(nullptr), _fmt_ctx(nullptr), _io_ctx(nullptr) {}
void w_av_format::_release() noexcept {
if (this->_stream_buffer != nullptr) {
auto _ptr = this->_stream_buffer.get();
free(_ptr);
this->_stream_buffer = nullptr;
}
if (this->_fmt_ctx != nullptr) {
auto _ptr = this->_fmt_ctx.get();
avformat_close_input(&_ptr);
this->_stream_buffer = nullptr;
}
if (this->_io_ctx != nullptr) {
auto _ptr = this->_io_ctx.get();
av_free(_ptr);
this->_stream_buffer = nullptr;
}
}
static int s_read_packet(void *p_opaque, _Inout_ uint8_t *p_buf, _In_ int p_buf_size) {
auto _av_fmt = gsl::narrow_cast(p_opaque);
if (_av_fmt) {
if (_av_fmt->on_read_callback) {
return _av_fmt->on_read_callback(p_buf, p_buf_size);
}
}
return -1; // failed
}
boost::leaf::result w_av_format::init(_In_ int p_stream_buf_size) noexcept {
_release();
// alloc a buffer for the stream
auto _ptr = gsl::narrow_cast(malloc(p_stream_buf_size));
if (_ptr == nullptr) {
// out of memory
return W_FAILURE(std::errc::not_enough_memory, "could not allocate memory for stream buffer");
}
this->_stream_buffer.reset(_ptr);
// get a AVContext stream
auto _io_ctx_ptr =
avio_alloc_context(this->_stream_buffer.get(), // buffer
p_stream_buf_size, // buffer size
0, // buffer is only readable - set to 1 for read/write
this, // use your specified data
s_read_packet, // function - reading Packets (see example)
nullptr, // function - write Packets
nullptr // function - seek to position in stream (see example)
);
if (_io_ctx_ptr == nullptr) {
// out of memory
return W_FAILURE(std::errc::not_enough_memory, "could not allocate io context");
}
this->_io_ctx.reset(_io_ctx_ptr);
// allocate a AVContext
auto _fmt_ctx_ptr = avformat_alloc_context();
if (_fmt_ctx_ptr == nullptr) {
// out of memory
return W_FAILURE(std::errc::not_enough_memory, "could not allocate avformat context");
}
this->_fmt_ctx.reset(_fmt_ctx_ptr);
// Set up the format context based on custom IO
this->_fmt_ctx->pb = _io_ctx_ptr;
this->_fmt_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
// open "file" (open our custom IO)
// empty string is where filename would go. doesn't matter since we aren't
// reading a file NULL params are format and demuxer settings, respectively
if (avformat_open_input(&_fmt_ctx_ptr, "", nullptr, nullptr) < 0) {
// error on opening input
return W_FAILURE(std::errc::not_enough_memory, "could not allocate io context");
}
// find the stream info
if (avformat_find_stream_info(_fmt_ctx_ptr, nullptr) < 0) {
// Error on finding stream info
return W_FAILURE(std::errc::operation_canceled, "could not get stream info");
}
// find best stream
const auto _ret =
av_find_best_stream(_fmt_ctx_ptr, AVMediaType::AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (_ret < 0) {
// Error on finding stream info
return W_FAILURE(std::errc::operation_canceled, "could not find best stream");
}
return 0;
}
uint8_t *w_av_format::get_io_ctx_buffer() const {
if (this->_io_ctx) {
return this->_io_ctx->buffer;
}
return nullptr;
}
int w_av_format::get_io_ctx_size() const {
if (this->_io_ctx) {
return this->_io_ctx->buffer_size;
}
return -1;
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_av_format.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include
extern "C" {
#include
}
namespace wolf::media::ffmpeg {
class w_av_format {
public:
#pragma region Constructors /Destructor
W_API w_av_format() noexcept;
W_API ~w_av_format() noexcept { _release(); };
// move constructor.
W_API w_av_format(w_av_format &&p_other) noexcept = default;
// move assignment operator.
W_API w_av_format &operator=(w_av_format &&p_other) noexcept = default;
#pragma endregion
boost::leaf::result init(_In_ int p_stream_buf_size = 32'767) noexcept;
uint8_t *get_io_ctx_buffer() const;
int get_io_ctx_size() const;
std::function on_read_callback;
private:
// copy constructor.
w_av_format(const w_av_format &) = delete;
// copy assignment operator.
w_av_format &operator=(const w_av_format &) = delete;
// release
void _release() noexcept;
std::unique_ptr _stream_buffer = nullptr;
std::unique_ptr _fmt_ctx = nullptr;
std::unique_ptr _io_ctx = nullptr;
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_av_frame.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_av_frame.hpp"
#include "w_ffmpeg_ctx.hpp"
extern "C" {
#include
#include
#include
}
#ifdef WOLF_MEDIA_STB
#include
#include
#endif //WOLF_MEDIA_STB
using w_av_frame = wolf::media::ffmpeg::w_av_frame;
using w_av_config = wolf::media::ffmpeg::w_av_config;
w_av_frame::w_av_frame(_In_ w_av_config &&p_config) noexcept : _config(std::move(p_config)) {}
void w_av_frame::_release() noexcept {
if (this->_av_frame != nullptr) {
av_frame_free(&this->_av_frame);
if (this->_config.nb_channels > 0) {
av_channel_layout_uninit(&this->_av_frame->ch_layout);
}
}
}
void w_av_frame::_move(w_av_frame &&p_other) noexcept {
if (this == &p_other) {
return;
}
this->_av_frame = std::exchange(p_other._av_frame, nullptr);
this->_config = std::move(p_other._config);
this->_data = std::move(p_other._data);
}
boost::leaf::result w_av_frame::init() noexcept {
_release();
// allocate memory for AVFrame
this->_av_frame = av_frame_alloc();
if (this->_av_frame == nullptr) {
return W_FAILURE(std::errc::not_enough_memory, "could not allocate memory for AVFrame");
}
// set audio
this->_av_frame->sample_rate = this->_config.sample_rate;
if (this->_config.nb_channels > 0) {
av_channel_layout_default(&this->_av_frame->ch_layout, this->_config.nb_channels);
}
// set video
this->_av_frame->format = gsl::narrow_cast(this->_config.format);
this->_av_frame->width = this->_config.width;
this->_av_frame->height = this->_config.height;
return 0;
}
boost::leaf::result w_av_frame::set_video_frame(
_Inout_ std::vector &&p_data) noexcept {
const auto _width = this->_config.width;
const auto _height = this->_config.height;
const auto _alignment = this->_config.alignment;
// check for width and height
if (_width <= 0 || _height <= 0) {
return W_FAILURE(std::errc::invalid_argument, "width or height of w_av_frame is zero");
}
// move the owenership of data to buffer
this->_data = std::forward &&>(p_data);
const auto _buffer_size = this->_config.get_required_video_buffer_size();
if (this->_data.empty()) {
this->_data.resize(_buffer_size, 0);
}
// if size does not fit
if (this->_data.size() != _buffer_size) {
return W_FAILURE(std::errc::invalid_argument,
wolf::format("w_av_frame video buffer size is expected {} but is {}",
_buffer_size, this->_data.size()));
}
const auto _ret = av_image_fill_arrays(this->_av_frame->data, this->_av_frame->linesize,
gsl::narrow_cast(this->_data.data()),
this->_config.format, this->_av_frame->width,
this->_av_frame->height, _alignment);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled, "av_image_fill_arrays failed");
}
return _ret;
}
void w_av_frame::set_pts(_In_ int64_t p_pts) noexcept { this->_av_frame->pts = p_pts; }
std::tuple w_av_frame::get() const noexcept {
if (this->_av_frame) {
auto _buffer_size =
av_image_get_buffer_size(gsl::narrow_cast(this->_av_frame->format),
this->_av_frame->width, this->_av_frame->height, 4);
return std::make_tuple(this->_av_frame->data, _buffer_size);
}
return std::make_tuple(nullptr, 0);
}
w_av_config w_av_frame::get_config() const noexcept { return this->_config; }
boost::leaf::result w_av_frame::convert_audio(_In_ w_av_config &&p_dst_config) {
auto _ret = 0;
SwrContext *swr = nullptr;
auto _dst_frame = w_av_frame(std::move(p_dst_config));
_dst_frame.init();
DEFER {
if (_ret != S_OK) {
if (swr) {
if (swr_is_initialized(swr)) {
swr_close(swr);
}
swr_free(&swr);
}
}
});
swr_alloc_set_opts2(&swr, &this->_channel_layout, p_dst_config.sample_fmts,
p_dst_config.sample_rate, &this->_av_frame->ch_layout,
gsl::narrow_cast(this->_av_frame->format),
this->_av_frame->sample_rate, 0, nullptr);
if (swr == nullptr) {
_ret = -1;
return W_FAILURE(std::errc::operation_canceled, "could not create audio SwrContext");
}
_ret = swr_init(swr);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled, "could not initialize audio SwrContext");
}
// get number of samples
auto _sample_rate = gsl::narrow_cast(this->_av_frame->sample_rate);
auto _delay = swr_get_delay(swr, _sample_rate);
const auto _rescale_rnd =
av_rescale_rnd(_delay + _sample_rate, gsl::narrow_cast(p_dst_config.sample_rate),
_sample_rate, AV_ROUND_UP);
_dst_frame._av_frame->nb_samples = gsl::narrow_cast(_rescale_rnd);
auto size = av_samples_alloc(gsl::narrow_cast(&_dst_frame._av_frame->data[0]),
&_dst_frame._av_frame->linesize[0],
this->_channel_layout.nb_channels, _dst_frame._config.nb_channels,
gsl::narrow_cast(p_dst_config.sample_fmts), 1);
if (size < 0) {
_ret = -1;
return W_FAILURE(std::errc::operation_canceled,
"could not allocate memory for buffer of audio");
}
/* convert to destination format */
size = swr_convert(swr, gsl::narrow_cast(&_dst_frame._av_frame->data[0]),
_dst_frame._av_frame->nb_samples,
(const uint8_t **)(&this->_av_frame->data[0]), this->_av_frame->nb_samples);
if (size < 0) {
_ret = -1;
return W_FAILURE(std::errc::operation_canceled, "error while audio converting\n");
}
const auto _buffer_size = av_samples_get_buffer_size(&_dst_frame._av_frame->linesize[0],
_dst_frame._av_frame->ch_layout.nb_channels,
size, p_dst_config.sample_fmts, 1);
if (_buffer_size < 0) {
_ret = -1;
return W_FAILURE(std::errc::operation_canceled, "could not get sample buffer size\n");
}
return _dst_frame;
}
boost::leaf::result w_av_frame::convert_video(_In_ w_av_config &&p_dst_config) {
// create a buffer and dst frame
auto _video_buffer = std::vector();
auto _dst_frame = w_av_frame(std::move(p_dst_config));
BOOST_LEAF_CHECK(_dst_frame.init());
BOOST_LEAF_CHECK(_dst_frame.set_video_frame(std::move(_video_buffer)));
auto *_context = sws_getContext(
this->_config.width, this->_config.height, this->_config.format, _dst_frame._config.width,
_dst_frame._config.height, _dst_frame._config.format, SWS_BICUBIC, nullptr, nullptr, nullptr);
if (_context == nullptr) {
return W_FAILURE(std::errc::not_enough_memory, "could not create sws context");
}
auto _dst_frame_nn = gsl::not_null(_dst_frame._av_frame);
const auto _height =
sws_scale(_context, gsl::narrow_cast(this->_av_frame->data),
gsl::narrow_cast(this->_av_frame->linesize), 0, this->_config.height,
gsl::narrow_cast(_dst_frame_nn->data),
gsl::narrow_cast(_dst_frame_nn->linesize));
// free context
sws_freeContext(_context);
if (_height < 0) {
return W_FAILURE(
std::errc::invalid_argument,
"w_av_frame sws_scale failed because: \"" + w_ffmpeg_ctx::get_av_error_str(_height) + "\"");
}
return _dst_frame;
}
boost::leaf::result w_av_frame::load_video_frame_from_img_file(
_In_ const std::filesystem::path &p_path, _In_ AVPixelFormat p_pixel_fmt) {
#ifdef WOLF_MEDIA_STB
// width, height, comp
int _width = 0;
int _height = 0;
int _comp = 0;
const auto _path = p_path.string();
if (!std::filesystem::exists(p_path)) {
return W_FAILURE(std::errc::invalid_argument, " path not exist for av_frame" + _path);
}
auto *_raw_img_data = stbi_load(_path.c_str(), &_width, &_height, &_comp, 0);
if (_raw_img_data == nullptr) {
return W_FAILURE(std::errc::invalid_argument, "could not load image file " + _path);
}
auto _len = gsl::narrow_cast(_width * _height * _comp);
const auto _raw_img_data_span = gsl::span(_raw_img_data, _raw_img_data + _len);
auto _raw_img_data_vec =
std::vector(_raw_img_data_span.begin(), _raw_img_data_span.end());
free(_raw_img_data);
auto _src_config = w_av_config(p_pixel_fmt, _width, _height);
// create an av_frame from image raw data
auto _src_frame = w_av_frame(std::move(_src_config));
BOOST_LEAF_CHECK(_src_frame.init());
BOOST_LEAF_CHECK(_src_frame.set_video_frame(std::move(_raw_img_data_vec)));
return _src_frame;
#else
return W_FAILURE(std::errc::not_supported, "WOLF_MEDIA_STB not defined");
#endif
}
boost::leaf::result w_av_frame::save_video_frame_to_img_file(
_In_ const std::filesystem::path &p_path, int p_quality) noexcept {
try {
#ifdef WOLF_MEDIA_STB
if (this->_av_frame == nullptr || this->_av_frame->width == 0 || this->_av_frame->height == 0) {
return W_FAILURE(std::errc::invalid_argument, "bad parameters for avframe");
}
const auto _path = p_path.string();
auto _ext = p_path.extension().string();
std::transform(_ext.cbegin(), _ext.cend(), _ext.begin(), ::tolower);
const auto _comp = this->_av_frame->linesize[0] / this->_av_frame->width;
if (_ext == ".bmp") {
return stbi_write_bmp(_path.c_str(), this->_config.width, this->_config.height, _comp,
this->_av_frame->data[0]);
}
if (_ext == ".png") {
return stbi_write_png(_path.c_str(), this->_config.width, this->_config.height, _comp,
this->_av_frame->data[0], this->_av_frame->linesize[0]);
}
if (_ext == ".jpg" || _ext == ".jpeg") {
return stbi_write_jpg(_path.c_str(), this->_config.width, this->_config.height, _comp,
this->_av_frame->data[0], p_quality);
}
return W_FAILURE(std::errc::invalid_argument, "image format not supported for " + _path);
} catch (const std::exception &p_exc) {
return W_FAILURE(std::errc::invalid_argument,
"caught an esxception for " + std::string(p_exc.what()));
}
#else
return W_FAILURE(std::errc::not_supported, "WOLF_MEDIA_STB not defined");
#endif
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_av_frame.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include
#include "w_av_config.hpp"
extern "C" {
#include
}
namespace wolf::media::ffmpeg {
class w_decoder;
class w_encoder;
class w_av_frame {
friend w_decoder;
friend w_encoder;
public:
/**
* constructor the av_frame with specific config
* @param p_config, the av audio config
*/
W_API explicit w_av_frame(_In_ w_av_config &&p_config) noexcept;
// destructor
W_API virtual ~w_av_frame() noexcept { _release(); }
// move constructor.
W_API w_av_frame(w_av_frame &&p_other) noexcept { _move(std::forward(p_other)); }
// move assignment operator.
W_API w_av_frame &operator=(w_av_frame &&p_other) noexcept {
_move(std::forward(p_other));
return *this;
}
/**
* initialize the avframe
* @returns zero on success
*/
W_API
boost::leaf::result init() noexcept;
/**
* set the AVFrame data
* @param p_data, the initial data of ffmpeg AVFrame
* @param p_alignment, the alignment
* @returns zero on success
*/
W_API boost::leaf::result set_video_frame(_Inout_ std::vector &&p_data) noexcept;
/**
* set the AVFrame's pts
* @param p_pts, the pts data
* @returns void
*/
W_API void set_pts(_In_ int64_t p_pts) noexcept;
/**
* get data and linesize as a tuple
* @returns tuple
*/
W_API
std::tuple get() const noexcept;
/**
* convert the ffmpeg video AVFrame
* @returns the converted instance of AVFrame
*/
W_API
boost::leaf::result convert_video(_In_ w_av_config &&p_dst_config);
/**
* convert the ffmpeg audio AVFrame
* @returns the converted instance of AVFrame
*/
W_API
boost::leaf::result convert_audio(_In_ w_av_config &&p_dst_config);
/**
* @returns config
*/
W_API w_av_config get_config() const noexcept;
#ifdef WOLF_MEDIA_STB
/**
* create w_av_frame from image file path
* @returns the AVFrame
*/
W_API
static boost::leaf::result load_video_frame_from_img_file(
_In_ const std::filesystem::path &p_path, _In_ AVPixelFormat p_pixel_fmt);
/**
* save to to the image file
* @param p_quality, quality will be used only for jpeg and is between 1 and
* 100
* @returns zero on success
*/
W_API
boost::leaf::result save_video_frame_to_img_file(_In_ const std::filesystem::path &p_path,
int p_quality = 100) noexcept;
#endif
private:
// copy constructor.
w_av_frame(const w_av_frame &) = delete;
// copy assignment operator.
w_av_frame &operator=(const w_av_frame &) = delete;
// release
void _release() noexcept;
// move
void _move(w_av_frame &&p_other) noexcept;
// the channel layout of the audio
AVChannelLayout _channel_layout = {};
// the AVFrame config
w_av_config _config = {};
// the ffmpeg AVFrame
gsl::owner _av_frame = nullptr;
// the ffmpeg AVFrame data
std::vector _data = {};
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_av_packet.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_av_packet.hpp"
using w_av_packet = wolf::media::ffmpeg::w_av_packet;
w_av_packet::w_av_packet(_In_ AVPacket *p_av_packet) noexcept
: _packet(p_av_packet) {}
boost::leaf::result w_av_packet::init() noexcept {
_release();
return init(nullptr, 0);
}
boost::leaf::result w_av_packet::init(_Inout_ std::vector &&p_data) noexcept {
_release();
this->_own_data = std::forward &&>(p_data);
return init(this->_own_data.data(), this->_own_data.size());
}
boost::leaf::result w_av_packet::init(_In_ uint8_t *p_data, _In_ size_t p_data_len) noexcept {
this->_packet = av_packet_alloc();
if (this->_packet == nullptr) {
return W_FAILURE(std::errc::not_enough_memory, "could not allocate memory for av packet");
}
if (p_data && p_data_len) {
this->_packet->data = p_data;
this->_packet->size = gsl::narrow_cast(p_data_len);
}
return 0;
}
void w_av_packet::unref() noexcept { av_packet_unref(this->_packet); }
uint8_t *w_av_packet::get_data() const noexcept {
return this->_packet->data;
}
int w_av_packet::get_size() const noexcept {
return this->_packet->size;
}
int w_av_packet::get_stream_index() const noexcept {
return this->_packet->stream_index;
}
void w_av_packet::_release() noexcept {
if (this->_packet != nullptr) {
av_packet_free(&this->_packet);
this->_packet = nullptr;
}
}
void w_av_packet::_move(_Inout_ w_av_packet &&p_other) noexcept {
if (this == &p_other) {
return;
}
this->_packet = std::exchange(p_other._packet, nullptr);
this->_own_data = std::move(p_other._own_data);
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_av_packet.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include
extern "C" {
#include
}
namespace wolf::media::ffmpeg {
class w_decoder;
class w_encoder;
class w_ffmpeg;
class w_av_packet {
friend w_decoder;
friend w_encoder;
friend w_ffmpeg;
public:
// default construct an av_packet
W_API w_av_packet() noexcept = default;
/**
* construct an av_packet
*/
W_API explicit w_av_packet(_In_ AVPacket *p_av_packet) noexcept;
// move constructor.
W_API w_av_packet(w_av_packet &&p_other) noexcept {
_move(std::forward(p_other));
}
// move assignment operator.
W_API w_av_packet &operator=(w_av_packet &&p_other) noexcept {
_move(std::forward(p_other));
return *this;
}
// destructor
W_API virtual ~w_av_packet() noexcept { _release(); }
/**
* initialize the av_packet
* @returns zero on success
*/
W_API boost::leaf::result init() noexcept;
/**
* initialize the av_packet from data
* @returns zero on success
*/
W_API boost::leaf::result init(_In_ uint8_t *p_data, _In_ size_t p_data_len) noexcept;
/**
* initialize the av_packet
* @returns void
*/
W_API boost::leaf::result init(_Inout_ std::vector &&p_data) noexcept;
/**
* unref av_packet
*/
W_API void unref() noexcept;
// get packet data
W_API uint8_t *get_data() const noexcept;
// get packet size
W_API int get_size() const noexcept;
// get stream index
W_API int get_stream_index() const noexcept;
private:
// copy constructor.
w_av_packet(const w_av_packet &) = delete;
// copy assignment operator.
w_av_packet &operator=(const w_av_packet &) = delete;
// release the resources
void _release() noexcept;
// move the resources
void _move(_Inout_ w_av_packet && p_other) noexcept;
gsl::owner _packet = {};
std::vector _own_data;
};
} // namespace wolf::media::ffmpeg
#endif
================================================
FILE: wolf/media/ffmpeg/w_decoder.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_decoder.hpp"
using w_decoder = wolf::media::ffmpeg::w_decoder;
boost::leaf::result w_decoder::decode_frame_from_packet(_In_ AVPacket *p_packet,
_Inout_ w_av_frame &p_frame) {
// start decoding
auto _ret = avcodec_send_packet(this->ctx.codec_ctx, p_packet);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"could not parse packet for decoding because:\"" +
w_ffmpeg_ctx::get_av_error_str(_ret) + "\"");
}
for (;;) {
_ret = avcodec_receive_frame(this->ctx.codec_ctx, p_frame._av_frame);
if (_ret == 0 || _ret == AVERROR(EAGAIN) || _ret == AVERROR_EOF) {
break;
}
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"error happened during the encoding because:\"" +
w_ffmpeg_ctx::get_av_error_str(_ret) + "\"");
}
}
return 0;
}
boost::leaf::result w_decoder::decode(_In_ const w_av_packet &p_packet,
_Inout_ w_av_frame &p_frame,
_In_ bool p_flush) noexcept {
auto _dst_packet = w_av_packet();
_dst_packet.init();
for (;;) {
const auto _bytes =
av_parser_parse2(this->ctx.parser, this->ctx.codec_ctx, &_dst_packet._packet->data,
&_dst_packet._packet->size, p_packet._packet->data, p_packet._packet->size,
AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
if (_bytes == 0) {
break;
}
if (_dst_packet._packet->size == 0) {
// try decode the inputed packet
BOOST_LEAF_CHECK(decode_frame_from_packet(p_packet._packet, p_frame));
} else {
if (_bytes < 0) {
return W_FAILURE(std::errc::operation_canceled, "could not parse packet for decoding");
}
p_packet._packet->data += _bytes;
p_packet._packet->size -= _bytes;
if (_dst_packet._packet->size > 0) {
BOOST_LEAF_CHECK(decode_frame_from_packet(_dst_packet._packet, p_frame));
}
}
}
if (p_flush) {
// flush the decoder
BOOST_LEAF_CHECK(decode_frame_from_packet(nullptr, p_frame));
}
return 0;
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_decoder.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include "w_av_frame.hpp"
#include "w_av_packet.hpp"
#include "w_ffmpeg_ctx.hpp"
#include
namespace wolf::media::ffmpeg {
class w_decoder {
public:
w_ffmpeg_ctx ctx = {};
// constructor
W_API w_decoder() = default;
// destructor
W_API virtual ~w_decoder() noexcept = default;
// move constructor.
W_API w_decoder(w_decoder &&p_other) noexcept = default;
// move assignment operator.
W_API w_decoder &operator=(w_decoder &&p_other) noexcept = default;
W_API boost::leaf::result decode(_In_ const w_av_packet &p_packet,
_Inout_ w_av_frame &p_frame,
_In_ bool p_flush = false) noexcept;
private:
// copy constructor
w_decoder(const w_decoder &) = delete;
// copy operator
w_decoder &operator=(const w_decoder &) = delete;
boost::leaf::result decode_frame_from_packet(_In_ AVPacket *p_packet,
_Inout_ w_av_frame &p_frame);
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_encoder.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_encoder.hpp"
using w_encoder = wolf::media::ffmpeg::w_encoder;
using w_av_packet = wolf::media::ffmpeg::w_av_packet;
boost::leaf::result w_encoder::_encode_frame_to_packet(
_In_ const AVFrame *p_frame, _Inout_ std::vector &p_packet_data) const noexcept {
auto _packet = w_av_packet();
_packet.init();
for (;;) {
auto _ret = avcodec_send_frame(this->ctx.codec_ctx, p_frame);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"failed to send the avframe for encoding because:\"" +
w_ffmpeg_ctx::get_av_error_str(_ret) + "\"");
}
for (;;) {
_ret = avcodec_receive_packet(this->ctx.codec_ctx, _packet._packet);
if (_ret == 0 || _ret == AVERROR_EOF) {
if (_packet._packet->size) {
std::copy(_packet._packet->data, _packet._packet->data + _packet._packet->size,
std::back_inserter(p_packet_data));
}
return 0;
}
_packet.unref();
if (_ret == AVERROR(EAGAIN)) {
break;
}
return W_FAILURE(std::errc::operation_canceled,
"error happened during the encoding because:\"" +
w_ffmpeg_ctx::get_av_error_str(_ret) + "\"");
}
}
return 0;
}
boost::leaf::result w_encoder::encode(_In_ const w_av_frame &p_frame,
_Inout_ w_av_packet &p_packet,
_In_ bool p_flush) noexcept {
std::vector _packet_data;
// encode frame to packet
BOOST_LEAF_CHECK(_encode_frame_to_packet(p_frame._av_frame, _packet_data));
if (p_flush) {
// flush
BOOST_LEAF_CHECK(_encode_frame_to_packet(nullptr, _packet_data));
}
// init packet
p_packet.init(std::move(_packet_data));
return {};
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_encoder.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include "w_av_frame.hpp"
#include "w_av_packet.hpp"
#include "w_ffmpeg_ctx.hpp"
#include
namespace wolf::media::ffmpeg {
class w_encoder {
public:
// constructor
W_API w_encoder() = default;
// destructor
W_API virtual ~w_encoder() noexcept = default;
// move constructor.
W_API w_encoder(w_encoder &&p_other) noexcept = default;
// move assignment operator.
W_API w_encoder &operator=(w_encoder &&p_other) noexcept = default;
W_API boost::leaf::result encode(_In_ const w_av_frame &p_frame,
_Inout_ w_av_packet &p_packet,
_In_ bool p_flush = true) noexcept;
w_ffmpeg_ctx ctx = {};
private:
// copy constructor
w_encoder(const w_encoder &) = delete;
// copy operator
w_encoder &operator=(const w_encoder &) = delete;
boost::leaf::result
_encode_frame_to_packet(_In_ const AVFrame *p_frame,
_Inout_ std::vector &p_packet_data) const noexcept;
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_ffmpeg.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_ffmpeg.hpp"
extern "C" {
#include
}
using w_av_codec_opt = wolf::media::ffmpeg::w_av_codec_opt;
using w_av_config = wolf::media::ffmpeg::w_av_config;
using w_av_set_opt = wolf::media::ffmpeg::w_av_set_opt;
using w_decoder = wolf::media::ffmpeg::w_decoder;
using w_encoder = wolf::media::ffmpeg::w_encoder;
using w_ffmpeg = wolf::media::ffmpeg::w_ffmpeg;
using w_ffmpeg_ctx = wolf::media::ffmpeg::w_ffmpeg_ctx;
static boost::leaf::result s_set_dict(
_In_ const std::vector &p_opts) noexcept {
AVDictionary *_dict = nullptr;
if (p_opts.empty()) {
return _dict;
}
auto _ret = av_dict_set(&_dict, nullptr, nullptr, 0);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"could not allocate memory for AVDictionary because: " +
w_ffmpeg_ctx::get_av_error_str(_ret));
}
try {
for (const auto &_opt : p_opts) {
if (_opt.name.empty()) {
continue;
}
auto _name_str = _opt.name.c_str();
if (std::holds_alternative(_opt.value)) {
// set an integer value
const auto _value = std::get(_opt.value);
const auto _ret = av_dict_set_int(&_dict, _name_str, _value, 0);
if (_ret < 0) {
return W_FAILURE(std::errc::invalid_argument, "could not set int value for " + _opt.name +
":" + std::to_string(_value) +
" because " +
w_ffmpeg_ctx::get_av_error_str(_ret));
}
} else {
// set string value
const auto _value_str = &std::get(_opt.value);
if (_value_str && !_value_str->empty()) {
const auto _ret = av_dict_set(&_dict, _opt.name.c_str(), _value_str->c_str(), 0);
if (_ret < 0) {
return W_FAILURE(std::errc::invalid_argument,
"could not set string value for " + _opt.name + ":" + *_value_str +
" because " + w_ffmpeg_ctx::get_av_error_str(_ret));
}
}
}
}
} catch (const std::exception &p_exc) {
return W_FAILURE(std::errc::operation_canceled,
"s_set_dict failed because: " + std::string(p_exc.what()));
}
return _dict;
}
static boost::leaf::result s_create(_Inout_ w_ffmpeg_ctx &p_ctx,
_In_ const w_av_config &p_config,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts) noexcept {
p_ctx.codec_ctx = avcodec_alloc_context3(p_ctx.codec);
if (p_ctx.codec_ctx == nullptr) {
return W_FAILURE(std::errc::not_enough_memory,
"could not allocate memory for avcodec context3");
}
bool _has_error = false;
DEFER {
if (_has_error && p_ctx.codec_ctx) {
auto _ptr = p_ctx.codec_ctx;
avcodec_free_context(&_ptr);
p_ctx.codec_ctx = nullptr;
}
});
p_ctx.codec_ctx->width = p_config.width;
p_ctx.codec_ctx->height = p_config.height;
p_ctx.codec_ctx->bit_rate = p_codec_opts.bitrate;
p_ctx.codec_ctx->time_base = AVRational{1, p_codec_opts.fps};
p_ctx.codec_ctx->framerate = AVRational{p_codec_opts.fps, 1};
p_ctx.codec_ctx->pix_fmt = p_config.format;
// set gop
if (p_codec_opts.gop >= 0) {
p_ctx.codec_ctx->gop_size = p_codec_opts.gop;
}
// set refs
if (p_codec_opts.refs >= 0) {
p_ctx.codec_ctx->refs = p_codec_opts.refs;
}
// set frames
if (p_codec_opts.max_b_frames >= 0) {
p_ctx.codec_ctx->max_b_frames = p_codec_opts.max_b_frames;
}
// set thread numbers
if (p_codec_opts.thread_count >= 0) {
p_ctx.codec_ctx->thread_count = p_codec_opts.thread_count;
}
// set level
if (p_codec_opts.level >= 0) {
p_ctx.codec_ctx->level = p_codec_opts.level;
}
// set flags
if (p_ctx.codec_ctx->flags & AVFMT_GLOBALHEADER) {
p_ctx.codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
try {
for (const auto &_opt : p_opts) {
if (_opt.name.empty()) {
continue;
}
auto _name_str = _opt.name.c_str();
if (std::holds_alternative(_opt.value)) {
// set an integer value
const auto _value = std::get(_opt.value);
const auto _ret = av_opt_set_int(p_ctx.codec_ctx->priv_data, _name_str, _value, 0);
if (_ret < 0) {
return W_FAILURE(std::errc::invalid_argument, "could not set int value for " + _opt.name +
":" + std::to_string(_value) +
" because " +
w_ffmpeg_ctx::get_av_error_str(_ret));
}
} else if (std::holds_alternative(_opt.value)) {
// set double value
const auto _value = std::get(_opt.value);
const auto _ret = av_opt_set_double(p_ctx.codec_ctx->priv_data, _name_str, _value, 0);
if (_ret < 0) {
return W_FAILURE(std::errc::invalid_argument, "could not set double value for " +
_opt.name + ":" +
std::to_string(_value) + " because " +
w_ffmpeg_ctx::get_av_error_str(_ret));
}
} else {
// set string value
const auto _value_str = &std::get(_opt.value);
if (_value_str && !_value_str->empty()) {
const auto _ret =
av_opt_set(p_ctx.codec_ctx->priv_data, _opt.name.c_str(), _value_str->c_str(), 0);
if (_ret < 0) {
return W_FAILURE(std::errc::invalid_argument,
"could not set string value for " + _opt.name + ":" + *_value_str +
" because " + w_ffmpeg_ctx::get_av_error_str(_ret));
}
}
}
}
} catch (const std::exception &p_exc) {
return W_FAILURE(std::errc::operation_canceled,
"could not set av option because: " + std::string(p_exc.what()));
}
// open avcodec
const auto _ret = avcodec_open2(p_ctx.codec_ctx, p_ctx.codec_ctx->codec, nullptr);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"could not open avcodec because " + w_ffmpeg_ctx::get_av_error_str(_ret));
}
return 0;
}
boost::leaf::result w_ffmpeg::create_encoder(
_In_ const w_av_config &p_config, _In_ AVCodecID p_id, _In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts) noexcept {
w_encoder _encoder = {};
_encoder.ctx.codec = avcodec_find_encoder(p_id);
if (_encoder.ctx.codec == nullptr) {
return W_FAILURE(std::errc::invalid_argument,
"could not find encoder codec id: " + std::to_string(p_id));
}
BOOST_LEAF_CHECK(s_create(_encoder.ctx, p_config, p_codec_opts, p_opts));
return _encoder;
}
boost::leaf::result w_ffmpeg::create_encoder(
_In_ const w_av_config &p_config, _In_ const std::string &p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts) noexcept {
w_encoder _encoder = {};
_encoder.ctx.codec = avcodec_find_encoder_by_name(p_id.c_str());
if (_encoder.ctx.codec == nullptr) {
return W_FAILURE(std::errc::invalid_argument, "could not find encoder codec id: " + p_id);
};
BOOST_LEAF_CHECK(s_create(_encoder.ctx, p_config, p_codec_opts, p_opts));
return _encoder;
}
boost::leaf::result w_ffmpeg::create_decoder(
_In_ const w_av_config &p_config, _In_ const AVCodecID p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts) noexcept {
w_decoder _decoder = {};
_decoder.ctx.codec = avcodec_find_decoder(p_id);
if (_decoder.ctx.codec == nullptr) {
return W_FAILURE(std::errc::invalid_argument,
"could not find decoder codec id: " + std::to_string(p_id));
}
_decoder.ctx.parser = av_parser_init(_decoder.ctx.codec->id);
if (_decoder.ctx.parser == nullptr) {
return W_FAILURE(std::errc::invalid_argument,
"could not initialize parser for codec id: " + std::to_string(p_id));
}
BOOST_LEAF_CHECK(s_create(_decoder.ctx, p_config, p_codec_opts, p_opts));
return _decoder;
}
boost::leaf::result w_ffmpeg::create_decoder(
_In_ const w_av_config &p_config, _In_ const std::string &p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts) noexcept {
w_decoder _decoder = {};
_decoder.ctx.codec = avcodec_find_decoder_by_name(p_id.c_str());
if (_decoder.ctx.codec == nullptr) {
return W_FAILURE(std::errc::invalid_argument, "could not find decoder codec id: " + p_id);
}
_decoder.ctx.parser = av_parser_init(_decoder.ctx.codec->id);
if (_decoder.ctx.parser == nullptr) {
return W_FAILURE(std::errc::invalid_argument,
"could not initialize parser for codec id: " + p_id);
}
BOOST_LEAF_CHECK(s_create(_decoder.ctx, p_config, p_codec_opts, p_opts));
return _decoder;
}
boost::leaf::result w_ffmpeg::open_stream(
_In_ const std::string &p_url, _In_ const std::vector &p_opts,
_In_ const
std::function &p_on_frame) noexcept {
try {
// url is invalid
if (p_url.empty()) {
return W_FAILURE(std::errc::invalid_argument,
"could not allocate memory for av format context");
}
// allocate memory for avformat context
auto _fmt_ctx = avformat_alloc_context();
if (_fmt_ctx == nullptr) {
return W_FAILURE(std::errc::not_enough_memory,
"could not allocate memory for av format context from the url: " + p_url);
}
DEFER {
if (_fmt_ctx != nullptr) {
// free av format context
avformat_free_context(_fmt_ctx);
_fmt_ctx = nullptr;
}
});
// allocate memory for packet
auto _packet = w_av_packet();
BOOST_LEAF_CHECK(_packet.init());
// set options to av format context
BOOST_LEAF_AUTO(_dict, s_set_dict(p_opts));
// open input url
int _ret = avformat_open_input(&_fmt_ctx, p_url.c_str(), nullptr, &_dict);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"could not open input url: " + p_url +
" because: " + w_ffmpeg_ctx::get_av_error_str(_ret));
}
// find the stream info
_ret = avformat_find_stream_info(_fmt_ctx, nullptr);
if (_ret < 0) {
return W_FAILURE(std::errc::operation_canceled,
"could not find stream info from the url: " + p_url);
}
if (_fmt_ctx->nb_streams == 0) {
return W_FAILURE(std::errc::operation_canceled, "missing stream for the url: " + p_url);
}
// search for audio & video stream
const auto _video_stream_index =
av_find_best_stream(_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
const auto _audio_stream_index =
av_find_best_stream(_fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
if (_audio_stream_index < 0 && _video_stream_index < 0) {
return W_FAILURE(std::errc::operation_canceled,
"could not find any video or audio stream from the url: " + p_url);
}
AVStream *_audio_stream = nullptr;
AVStream *_video_stream = nullptr;
if (_audio_stream_index >= 0) {
_audio_stream = _fmt_ctx->streams[_audio_stream_index];
}
if (_video_stream_index >= 0) {
_video_stream = _fmt_ctx->streams[_video_stream_index];
}
for (;;) {
// unref packet
_packet.unref();
// read packet
_ret = av_read_frame(_fmt_ctx, _packet._packet);
if (_ret < 0) {
break;
}
if (p_on_frame && !p_on_frame(_packet, _audio_stream, _video_stream)) {
break;
}
}
return 0;
} catch (const std::exception &p_exc) {
return W_FAILURE(std::errc::operation_canceled,
"caught an exception: " + std::string(p_exc.what()));
}
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_ffmpeg.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include "w_av_packet.hpp"
#include "w_ffmpeg_ctx.hpp"
#include "w_encoder.hpp"
#include "w_decoder.hpp"
#include
#include
namespace wolf::media::ffmpeg {
struct w_av_codec_opt {
int64_t bitrate;
int fps;
int gop;
int level;
int max_b_frames;
int refs;
int thread_count;
};
struct w_av_set_opt {
// name of option
std::string name;
// value type
std::variant value;
};
class w_ffmpeg {
public:
/*
* create ffmpeg encoder
* @param p_config, the video config
* @param p_id, the avcodec id
* @param p_codec_opts, the codec settings
* @param p_opts, the codec options
* @returns encoder object on success
*/
W_API static boost::leaf::result create_encoder(
_In_ const w_av_config &p_config, _In_ AVCodecID p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts = {}) noexcept;
/*
* create ffmpeg encoder
* @param p_config, the video config
* @param p_id, the avcodec id in string (e.g. "libsvtav1", "libvpx")
* @param p_codec_opts, the codec settings
* @param p_opts, the codec options
* @returns encoder object on success
*/
W_API static boost::leaf::result create_encoder(
_In_ const w_av_config &p_config, _In_ const std::string &p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts = {}) noexcept;
/*
* create ffmpeg decoder
* @param p_config, the avconfig
* @param p_id, the avcodec id in string (e.g. "libsvtav1", "libvpx")
* @param p_codec_opts, the codec options
* @param p_opts, the codec options
* @returns encoder object on success
*/
W_API static boost::leaf::result create_decoder(
_In_ const w_av_config &p_config, _In_ AVCodecID p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts = {}) noexcept;
/*
* create ffmpeg decoder
* @param p_config, the avconfig
* @param p_id, the avcodec id in string (e.g. "libsvtav1", "libvpx")
* @param p_codec_opts, the codec settings
* @param p_opts, the codec options
* @returns encoder object on success
*/
W_API static boost::leaf::result create_decoder(
_In_ const w_av_config &p_config, _In_ const std::string &p_id,
_In_ const w_av_codec_opt &p_codec_opts,
_In_ const std::vector &p_opts = {}) noexcept;
/*
* open and receive stream from file or url
* @param p_url, the url
* @param p_opts, the codec options
* @param p_on_frame, on frame data recieved callback
* @returns encoder object on success
*/
W_API static boost::leaf::result open_stream(
_In_ const std::string &p_url, _In_ const std::vector &p_opts,
_In_ const
std::function &p_on_frame) noexcept;
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_ffmpeg_ctx.cpp
================================================
#ifdef WOLF_MEDIA_FFMPEG
#include "w_ffmpeg_ctx.hpp"
using w_ffmpeg_ctx = wolf::media::ffmpeg::w_ffmpeg_ctx;
void w_ffmpeg_ctx::_release() noexcept {
if (this->parser != nullptr) {
av_parser_close(this->parser);
this->parser = nullptr;
}
if (this->codec_ctx != nullptr) {
if (avcodec_is_open(this->codec_ctx) > 0) {
avcodec_close(this->codec_ctx);
}
avcodec_free_context(&this->codec_ctx);
this->codec_ctx = nullptr;
}
}
void w_ffmpeg_ctx::_move(w_ffmpeg_ctx &&p_other) noexcept {
if (this == &p_other) {
return;
}
this->codec_ctx = std::exchange(p_other.codec_ctx, nullptr);
this->codec = std::exchange(p_other.codec, nullptr);
this->parser = std::exchange(p_other.parser, nullptr);
}
std::string w_ffmpeg_ctx::get_av_error_str(_In_ int p_error_code) noexcept {
std::array _error[] = {'\0'};
try {
std::ignore = av_make_error_string(_error->data(), W_MAX_PATH, p_error_code);
return std::string(_error->data());
} catch (...) {
return std::string();
}
}
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/ffmpeg/w_ffmpeg_ctx.hpp
================================================
/*
Project: Wolf Engine. Copyright © 2014-2023 Pooya Eimandar
https://github.com/WolfEngine/WolfEngine
*/
#ifdef WOLF_MEDIA_FFMPEG
#pragma once
#include
extern "C" {
#include
}
namespace wolf::media::ffmpeg {
class w_ffmpeg_ctx {
public:
// constructor
W_API w_ffmpeg_ctx() = default;
// destructor
W_API virtual ~w_ffmpeg_ctx() noexcept { _release(); }
// move constructor.
W_API w_ffmpeg_ctx(w_ffmpeg_ctx &&p_other) noexcept {
_move(std::forward(p_other));
}
// move assignment operator.
W_API w_ffmpeg_ctx &operator=(w_ffmpeg_ctx &&p_other) noexcept {
_move(std::forward(p_other));
return *this;
}
W_API static std::string get_av_error_str(_In_ int p_error_code) noexcept;
gsl::owner codec_ctx = {};
gsl::owner codec = {};
gsl::owner parser = {};
private:
// copy constructor
w_ffmpeg_ctx(const w_ffmpeg_ctx &) = delete;
// copy operator
w_ffmpeg_ctx &operator=(const w_ffmpeg_ctx &) = delete;
// release all resources
void _release() noexcept;
// move all resources
void _move(w_ffmpeg_ctx &&p_other) noexcept;
};
} // namespace wolf::media::ffmpeg
#endif // WOLF_MEDIA_FFMPEG
================================================
FILE: wolf/media/gst/audio/w_audio_format.cpp
================================================
#include "media/gst/audio/w_audio_format.hpp"
================================================
FILE: wolf/media/gst/audio/w_audio_format.hpp
================================================
#pragma once
#include
namespace wolf::media::gst {
/**
* enum same as GstAudioFormat.
*/
enum class w_audio_format
{
Unknonw = GST_AUDIO_FORMAT_UNKNOWN,
Encoded = GST_AUDIO_FORMAT_ENCODED,
S8 = GST_AUDIO_FORMAT_S8,
S16 = GST_AUDIO_FORMAT_S16,
S16LE = GST_AUDIO_FORMAT_S16LE,
S16BE = GST_AUDIO_FORMAT_S16BE,
S32 = GST_AUDIO_FORMAT_S32,
S32LE = GST_AUDIO_FORMAT_S32LE,
S32BE = GST_AUDIO_FORMAT_S32BE,
U8 = GST_AUDIO_FORMAT_U8,
U16 = GST_AUDIO_FORMAT_U16,
U16LE = GST_AUDIO_FORMAT_U16LE,
U16BE = GST_AUDIO_FORMAT_U16BE,
U32 = GST_AUDIO_FORMAT_U32,
U32LE = GST_AUDIO_FORMAT_U32LE,
U32BE = GST_AUDIO_FORMAT_U32BE,
F32 = GST_AUDIO_FORMAT_F32,
F32LE = GST_AUDIO_FORMAT_F32LE,
F32BE = GST_AUDIO_FORMAT_F32BE,
F64 = GST_AUDIO_FORMAT_F32,
F64LE = GST_AUDIO_FORMAT_F64LE,
F64BE = GST_AUDIO_FORMAT_F64BE
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/audio/w_audio_info.cpp
================================================
#include "media/gst/audio/w_audio_info.hpp"
namespace wolf::media::gst {
auto w_audio_info::make(w_audio_format p_format, size_t p_channels, size_t p_samples)
-> boost::leaf::result
{
auto audioinfo_raw = gst_audio_info_new();
if (!audioinfo_raw) {
return W_FAILURE(std::errc::operation_canceled, "couldn't create audio info.");
}
auto format_raw = static_cast(p_format);
gst_audio_info_set_format(
audioinfo_raw,
format_raw,
gsl::narrow_cast(p_samples),
gsl::narrow_cast(p_channels),
nullptr
);
return w_audio_info(internal::w_raw_tag{}, audioinfo_raw);
}
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/audio/w_audio_info.hpp
================================================
#pragma once
#include "wolf.hpp"
#include "media/gst/internal/w_common.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include "media/gst/core/w_caps.hpp"
#include "media/gst/audio/w_audio_format.hpp"
#include
#include
#include
namespace wolf::media::gst {
/**
* wrapper of GstAudioInfo.
*/
class w_audio_info : public w_wrapper
{
friend class internal::w_raw_access;
public:
/**
* @brief make a w_audio_info instance with given format and other info.
* @return a constructed audio info on success.
*/
[[nodiscard]] static auto make(w_audio_format p_format,
std::size_t p_channels = 2,
std::size_t p_samples = 44100)
-> boost::leaf::result;
/**
* @brief make a w_caps with info values.
*/
[[nodiscard]] w_caps to_caps()
{
auto caps_raw = gst_audio_info_to_caps(raw());
return internal::w_raw_access::from_raw(caps_raw);
}
/**
* @brief set sample rate.
* @param p_rate sample rate.
*/
void set_rate(std::size_t p_rate)
{
raw()->rate = gsl::narrow_cast(p_rate);
}
/**
* @brief set channels.
*/
void set_channels(std::size_t p_channels)
{
raw()->channels = gsl::narrow_cast(p_channels);
}
private:
w_audio_info(internal::w_raw_tag, GstAudioInfo* p_rawptr) noexcept
: w_wrapper(p_rawptr)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_buffer.cpp
================================================
#include "media/gst/core/w_buffer.hpp"
#include "media/gst/internal/w_common.hpp"
namespace wolf::media::gst {
auto w_buffer::make(size_t p_size) -> boost::leaf::result
{
auto buffer_raw = gst_buffer_new_and_alloc(p_size);
if (!buffer_raw) {
return W_FAILURE(std::errc::operation_canceled,
"couldn't create and allocate Buffer.");
}
return w_buffer(internal::w_raw_tag{}, buffer_raw);
}
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_buffer.hpp
================================================
#pragma once
#include "wolf.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include
#include
#include
namespace wolf::media::gst {
/**
* @brief read/write map flags.
*/
enum class w_buffer_map_flags
{
Read = GST_MAP_READ,
Write = GST_MAP_WRITE,
ReadWrite = GST_MAP_READWRITE
};
class w_buffer;
/**
* helper class to map underlying data of w_buffer
* to an accessible memory region and unmap on destruction.
*/
class w_buffer_mapped_data
{
friend class w_buffer;
public:
w_buffer_mapped_data(const w_buffer_mapped_data&) = delete;
w_buffer_mapped_data(w_buffer_mapped_data&& p_other) noexcept
: _buffer(std::exchange(p_other._buffer, nullptr))
, _map(std::exchange(p_other._map, GstMapInfo{}))
{}
w_buffer_mapped_data& operator=(const w_buffer_mapped_data&) = delete;
w_buffer_mapped_data& operator=(w_buffer_mapped_data&& p_other) noexcept
{
std::swap(_buffer, p_other._buffer);
std::swap(_map, p_other._map);
return *this;
}
~w_buffer_mapped_data() noexcept
{
if (_buffer) {
gst_buffer_unmap(_buffer, &_map);
}
}
[[nodiscard]] std::size_t size() const noexcept { return _map.size; }
[[nodiscard]] guint8* begin() noexcept { return _map.data; }
[[nodiscard]] const guint8* begin() const noexcept { return _map.data; }
[[nodiscard]] guint8* end() noexcept { return _map.data + _map.size; }
[[nodiscard]] const guint8* end() const noexcept { return _map.data + _map.size; }
[[nodiscard]] guint8* data() noexcept { return _map.data; }
[[nodiscard]] const guint8* data() const noexcept { return _map.data; }
[[nodiscard]] guint8& operator[](std::size_t p_index) { return _map.data[p_index]; }
[[nodiscard]] const guint8& operator[](std::size_t p_index) const { return _map.data[p_index]; }
private:
w_buffer_mapped_data() noexcept {}
/**
* @brief helper method to map raw buffer to a normal accessible data region.
* @param p_buffer raw gstreamer buffer.
* @param p_flags read/write flags. defaults to read-write.
*/
[[nodiscard]] static auto make(internal::w_raw_tag,
GstBuffer* p_buffer,
w_buffer_map_flags p_flags = w_buffer_map_flags::ReadWrite)
-> boost::leaf::result
{
auto ret = w_buffer_mapped_data();
auto flags_raw = static_cast(p_flags);
if (!p_buffer || !gst_buffer_map(p_buffer, &ret._map, flags_raw)) {
return W_FAILURE(std::errc::operation_canceled, "couldn't map the buffer data.");
}
ret._buffer = p_buffer;
return ret;
}
GstBuffer* _buffer = nullptr;
GstMapInfo _map{};
};
/**
* wrapper of GstBuffer.
*/
class w_buffer : public w_wrapper
{
friend class internal::w_raw_access;
public:
/**
* @brief make a buffer with given size.
* @return buffer on success.
*/
[[nodiscard]] static auto make(std::size_t p_size) -> boost::leaf::result;
/**
* @brief get timestamp in nanoseconds.
*/
[[nodiscard]] auto get_timestamp() const noexcept
{
return GST_BUFFER_TIMESTAMP(raw());
}
/**
* @brief get duration of this buffer's playback in nanoseconds.
*/
[[nodiscard]] auto get_duration() const noexcept
{
return raw()->duration;
}
/**
* @brief set timestamp in nanoseconds.
*/
void set_timestamp(std::size_t p_nanoseconds) noexcept
{
GST_BUFFER_TIMESTAMP(raw()) = static_cast(p_nanoseconds);
}
/**
* @brief set duration of this buffer's playback in nanoseconds.
*/
void set_duration(std::size_t p_nanoseconds) noexcept
{
raw()->duration = static_cast(p_nanoseconds);
}
/**
* @brief map to write-only data region.
*/
[[nodiscard]] auto map_data_write()
{
return w_buffer_mapped_data::make(
internal::w_raw_tag{},
raw(),
w_buffer_map_flags::Write
);
}
/**
* @brief map to read-only data region.
*/
[[nodiscard]] auto map_data_read() const
{
// NOTE unfortunately raw methods need pointer to non-const data, thus const_cast.
return w_buffer_mapped_data::make(
internal::w_raw_tag{},
const_cast(raw()),
w_buffer_map_flags::Read
);
}
/**
* @brief map to readable-writable data region.
*/
[[nodiscard]] auto map_data()
{
return w_buffer_mapped_data::make(internal::w_raw_tag{}, raw());
}
/**
* @brief map to readable data region.
*/
[[nodiscard]] auto map_data() const
{
return map_data_read();
}
private:
explicit w_buffer(internal::w_raw_tag, GstBuffer* p_buffer) noexcept
: w_wrapper(p_buffer)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_bus.cpp
================================================
#include "media/gst/core/w_bus.hpp"
================================================
FILE: wolf/media/gst/core/w_bus.hpp
================================================
#pragma once
#include "media/gst/core/w_signal_handler.hpp"
#include "media/gst/core/w_message.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include
namespace wolf::media::gst {
/**
* @brief wrapper of GstBus. a bus to send messages to and notify listeners.
*/
class w_bus : public w_wrapper
{
friend class internal::w_raw_access;
public:
w_bus() = delete;
w_bus(const w_bus&) = delete;
w_bus(w_bus&&) noexcept = default;
w_bus& operator=(const w_bus&) = delete;
w_bus& operator=(w_bus&&) noexcept = default;
~w_bus() noexcept
{
for (auto i = 0u; i < _watch_count; ++i) {
gst_bus_remove_signal_watch(raw());
}
}
/**
* @brief hook a listener handler on message signal.
* @param p_handler message listener handler. it will be passed `w_nonowning`.
*/
template
void hook_message(F&& p_handler)
{
ensure_watch();
constexpr auto invoker = +[](GstBus* /* p_self */, GstMessage* p_message, gpointer p_callee) {
auto& func = (*static_cast(p_callee));
func(internal::w_raw_access::from_raw>(p_message));
};
_sighandlers.message.hook("message", invoker, std::forward(p_handler));
}
/**
* @brief unhook the message listener handler on message signal.
*/
void unhook_message()
{
if (_sighandlers.message.unhook()) {
gst_bus_remove_signal_watch(raw());
--_watch_count;
}
}
private:
explicit w_bus(internal::w_raw_tag, GstBus* p_bus_raw) noexcept
: w_wrapper(p_bus_raw)
, _sighandlers(G_OBJECT(p_bus_raw))
{}
/**
* @brief make sure there is at least one signal watch.
*/
void ensure_watch() noexcept
{
if (_watch_count == 0) {
watch();
}
}
/**
* @brief add a signal watch so a listener can be added.
*/
void watch() noexcept
{
gst_bus_add_signal_watch(raw());
++_watch_count;
}
// signals
struct signal_handler_set {
w_signal_handler> message;
signal_handler_set(auto* p_rawptr) : message(p_rawptr) {}
} _sighandlers;
std::size_t _watch_count = 0;
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_caps.cpp
================================================
#include "media/gst/core/w_caps.hpp"
================================================
FILE: wolf/media/gst/core/w_caps.hpp
================================================
#pragma once
#include "wolf.hpp"
#include "media/gst/internal/w_common.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include "media/gst/core/w_structure.hpp"
#include
#include
namespace wolf::media::gst {
/**
* @brief wrapper of GstCaps, gstreamer capabilities concept.
*/
class w_caps : public w_wrapper
{
friend class internal::w_raw_access;
public:
/**
* @brief make an empty caps.
* @return an instance of w_caps on success.
*/
[[nodiscard]] static auto make() -> boost::leaf::result
{
auto caps_raw = gst_caps_new_empty();
if (!caps_raw) {
return W_FAILURE(std::errc::operation_canceled,
"couldn't make caps.");
}
return w_caps(internal::w_raw_tag{}, caps_raw);
}
/**
* @brief make a caps that acceps any kind of media.
* @return an instance of w_caps on success.
*/
[[nodiscard]] static auto make_any() -> boost::leaf::result
{
auto caps_raw = gst_caps_new_any();
if (!caps_raw) {
return W_FAILURE(std::errc::operation_canceled,
"couldn't make caps as any.");
}
return w_caps(internal::w_raw_tag{}, caps_raw);
}
/**
* @brief make an empty caps with media name.
* @return an instance of w_caps on success.
*/
[[nodiscard]] static auto make_simple(const char* p_media_name)
-> boost::leaf::result
{
auto caps_raw = gst_caps_new_empty_simple(p_media_name);
if (!caps_raw) {
return W_FAILURE(
std::errc::operation_canceled,
"couldn't make caps with given media name."
);
}
return w_caps(internal::w_raw_tag{}, caps_raw);
}
/**
* @brief add a capability structure.
* @param p_structure a capability structure.
*/
void add(w_structure&& p_structure)
{
gst_caps_append_structure(raw(), internal::w_raw_access::disown_raw(p_structure));
}
private:
w_caps(internal::w_raw_tag, GstCaps* p_caps_raw) noexcept
: w_wrapper(p_caps_raw)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_clock.cpp
================================================
#include "media/gst/core/w_clock.hpp"
================================================
FILE: wolf/media/gst/core/w_clock.hpp
================================================
#pragma once
#include "media/gst/internal/w_wrapper.hpp"
#include
namespace wolf::media::gst {
/**
* @brief wrapper of GstClock.
*
* @note this class is not user constructible. it's nonowning by default.
*/
class w_clock : public w_wrapper
{
friend class internal::w_raw_access;
public:
w_clock() = delete;
/**
* @brief get time in nanoseconds.
* @return time in nanoseconds.
*/
std::size_t get_time() noexcept
{
return gst_clock_get_time(raw());
}
private:
explicit w_clock(internal::w_raw_tag, GstClock* p_clock_raw) noexcept
: w_wrapper(p_clock_raw)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_element.cpp
================================================
#include "media/gst/core/w_element.hpp"
namespace wolf::media::gst {
auto w_element::make(const char *p_factory_name) -> boost::leaf::result
{
auto element_factory_raw = gst_element_factory_find(p_factory_name);
if (!element_factory_raw) {
auto err_msg = wolf::format("couldn't find factory name: {}", p_factory_name);
return W_FAILURE(std::errc::operation_canceled, err_msg);
}
auto element_raw = gst_element_factory_create(element_factory_raw, nullptr);
if (!element_raw) {
auto err_msg = wolf::format(
"couldn't create the element with given factory name: {}",
p_factory_name
);
return W_FAILURE(std::errc::operation_canceled, err_msg);
}
if (G_IS_INITIALLY_UNOWNED(element_raw)) {
gst_object_ref_sink(element_raw);
}
return w_element(internal::w_raw_tag{}, element_raw);
}
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_element.hpp
================================================
#pragma once
#include "wolf.hpp"
#include "media/gst/internal/w_common.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include "media/gst/core/w_pad.hpp"
#include "media/gst/core/w_clock.hpp"
#include
#include
namespace wolf::media::gst {
/**
* @brief wrapper of GstElement, gstreamer elements process stream data.
*
* elements combine to make dataflow pipeline graphs (DAG)
* to process one or more media stream(s).
*/
class w_element : public w_wrapper
{
friend class internal::w_raw_access;
public:
/**
* @brief make an element by given factory name.
* @param p_factory_name element's factory name.
* @return an instance of element of given name on success.
*/
[[nodiscard]] static auto make(const char* p_factory_name)
-> boost::leaf::result;
w_element(const w_element&) = delete;
w_element(w_element&&) noexcept = default;
w_element& operator=(const w_element&) = delete;
w_element& operator=(w_element&&) noexcept = default;
virtual ~w_element() = default;
/**
* @brief get a request=pad with given name.
*/
[[nodiscard]] auto request_pad(const char* p_pad_name)
-> boost::leaf::result
{
auto raw_pad = gst_element_request_pad_simple(raw(), p_pad_name);
if (!raw_pad) {
auto err_msg = wolf::format("request for pad `{}` failed.", p_pad_name);
return W_FAILURE(std::errc::operation_canceled, err_msg);
}
return internal::w_raw_access::from_raw(raw_pad);
}
/**
* @brief get an always=pad with given name.
*/
[[nodiscard]] auto always_pad(const char* p_pad_name)
-> boost::leaf::result
{
auto raw_pad = gst_element_get_static_pad(raw(), p_pad_name);
if (!raw_pad) {
auto err_msg = wolf::format("couldn't find always pad: `{}`", p_pad_name);
return W_FAILURE(std::errc::operation_canceled, err_msg);
}
return internal::w_raw_access::from_raw(raw_pad);
}
/**
* @brief get element's clock.
*/
w_nonowning clock() noexcept
{
return internal::w_raw_access::from_raw>(raw()->clock);
}
private:
explicit w_element(internal::w_raw_tag, GstElement* p_element) noexcept
: w_wrapper(p_element)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_element_factory.cpp
================================================
#include "media/gst/core/w_element_factory.hpp"
================================================
FILE: wolf/media/gst/core/w_element_factory.hpp
================================================
#pragma once
#include "media/gst/internal/w_common.hpp"
#include "media/gst/core/w_element.hpp"
#include
#include
#include
#include
namespace wolf::media::gst {
/**
* @brief gstreamer's element factory to create elements.
*/
class w_element_factory
{
public:
w_element_factory() = delete;
/**
* @brief make an element from given gstreamer launch command.
* @param p_launch_str a gstreamer lauch command.
*/
[[nodiscard]] static auto make_from_launch_str(const char* p_launch_str)
-> boost::leaf::result
{
auto element_raw = gst_parse_launch(p_launch_str, nullptr);
if (!element_raw) {
return W_FAILURE(std::errc::operation_canceled,
"couldn't create element from launch string.");
}
return internal::w_raw_access::from_raw(element_raw);
}
/**
* @brief make a an element of given factory name, with given element name.
* @param p_factory_name name of element module.
* @param p_element_name custom name for element to reference later. (nullable)
* @return an element on success.
*/
[[nodiscard]] static auto make_simple(const char* p_factory_name, const char* p_element_name)
-> boost::leaf::result
{
auto element_raw = gst_element_factory_make(p_factory_name, p_element_name);
if (!element_raw) {
auto err_msg = wolf::format("couldn't create element with factory name: {}", p_factory_name);
return W_FAILURE(std::errc::operation_canceled, err_msg);
}
return internal::w_raw_access::from_raw(element_raw);
}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_format.cpp
================================================
#include "media/gst/core/w_format.hpp"
================================================
FILE: wolf/media/gst/core/w_format.hpp
================================================
#pragma once
#include
namespace wolf::media::gst {
/** wrapper of GstFormat */
enum class w_format
{
Undefined = GST_FORMAT_UNDEFINED,
Default = GST_FORMAT_DEFAULT,
Bytes = GST_FORMAT_BYTES,
Time = GST_FORMAT_TIME,
Buffers = GST_FORMAT_BUFFERS,
Percent = GST_FORMAT_PERCENT
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_mainloop.cpp
================================================
#include "media/gst/core/w_mainloop.hpp"
================================================
FILE: wolf/media/gst/core/w_mainloop.hpp
================================================
#pragma once
#include "wolf.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include
#include
#include
#include
#include
namespace wolf::media::gst {
/**
* @brief wrapper of GMainLoop, GLib's mainloop/eventloop facility.
*/
class w_mainloop : public w_wrapper
{
public:
/**
* @brief create a simple instance of mainloop.
* @return a w_mainloop instance on success.
*/
[[nodiscard]] static auto make() -> boost::leaf::result
{
auto main_loop_raw = g_main_loop_new(nullptr, false);
if (!main_loop_raw) {
return W_FAILURE(std::errc::operation_canceled,
"mainloop construction error.");
}
return w_mainloop(internal::w_raw_tag{}, main_loop_raw);
}
/**
* @brief add a callable to be called on event loop idle times.
* @param p_func callable to be called on idle times.
* @return a sourceid to remove it later.
* @note `p_func` must have a consistent lifetime and address
* until either being removed by `idle_remove` or the instance
* of this class be destructed.
*/
template
std::size_t idle_add(F& p_func)
{
constexpr auto invoker = +[](F* p_funcptr) { (*p_funcptr)(); };
return g_idle_add(GSourceFunc(invoker), std::addressof(p_func));
}
bool idle_remove(std::size_t p_sourceid)
{
if (!p_sourceid) {
return false;
}
return g_source_remove(gsl::narrow_cast(p_sourceid));
}
/**
* @brief run the main/event loop.
*/
void run()
{
g_main_loop_run(raw());
}
/**
* @brief stop the main/event loop.
*/
void stop()
{
g_main_loop_quit(raw());
}
private:
w_mainloop(internal::w_raw_tag, GMainLoop* p_main_loop_raw) noexcept
: w_wrapper(p_main_loop_raw)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_message.cpp
================================================
#include "media/gst/core/w_message.hpp"
================================================
FILE: wolf/media/gst/core/w_message.hpp
================================================
#pragma once
#include "media/gst/internal/w_common.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include
#include
namespace wolf::media::gst {
class w_message;
/** type of GstMessage */
enum class w_message_type : std::size_t
{
Unknown = 0,
EOS,
Error,
Warning,
Info
};
//- message structs
/** the unknown variant of GstMessage */
struct w_message_unknown {};
/** the end-of-stream variant of GstMessage */
struct w_message_eos {};
/** the error message variant of GstMessage */
struct w_message_error
{
friend class w_message;
public:
w_message_error() = delete;
w_message_error(const w_message_error&) = delete;
~w_message_error() noexcept
{
if (_error) {
g_clear_error(&_error);
}
if (_debug_info) {
g_free(_debug_info);
}
}
/**
* @brief print the error message to standard output.
*/
void print() const
{
g_printerr(
"Error received from element %s: %s\n",
GST_OBJECT_NAME(_msg->src),
_error->message
);
g_printerr(
"Debugging information: %s\n",
_debug_info ? _debug_info : "none"
);
}
private:
/**
* @brief parse the message to extract error info.
*/
explicit w_message_error(internal::w_raw_tag, GstMessage* p_msg_raw)
: _msg(p_msg_raw)
{
gst_message_parse_error(p_msg_raw, &_error, &_debug_info);
}
GstMessage* _msg = nullptr; //< non-owning.
GError* _error = nullptr;
gchar* _debug_info = nullptr;
};
/**
* @brief wrapper of GstMessage. gstreamer's ultimate message struct.
*
* there are so many different kinds and variants of message,
* and all are represented by w_message.
*
* for ease of use, there are helper message representative classes,
* which on visit the appropriate one will be created and passed to
* given visitor.
*/
class w_message : public w_wrapper
{
friend class internal::w_raw_access;
public:
// not supported yet.
w_message() = delete;
// w_message_type type() const noexcept
// {
// return convert_message_type(GST_MESSAGE_TYPE(msg_));
// }
/**
* @brief visit the message based on its type as the helper representative type.
* @param p_visitor visitor to visit message variant.
*/
template
auto visit(VisitorF&& p_visitor)
{
return raw_visit(std::forward(p_visitor), raw());
}
private:
explicit w_message(internal::w_raw_tag, GstMessage* p_msg_raw)
: w_wrapper(p_msg_raw)
{}
/**
* @brief create and visit appropriate repr variant by given raw message and visitor.
* @param p_visitor visitor to visit message variant.
* @param p_msg_raw raw message pointer.
*/
template
static auto raw_visit(VisitorF&& p_visitor, GstMessage* p_msg_raw)
{
switch (GST_MESSAGE_TYPE(p_msg_raw)) {
case GST_MESSAGE_EOS:
return std::forward(w_message_eos{});
case GST_MESSAGE_ERROR:
return std::forward(p_visitor)(
w_message_error(internal::w_raw_tag{}, p_msg_raw)
);
default: // GST_MESSAGE_UNKNOWN
return std::forward(p_visitor)(w_message_unknown{});
}
}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_nonowning.cpp
================================================
#include "media/gst/core/w_nonowning.hpp"
================================================
FILE: wolf/media/gst/core/w_nonowning.hpp
================================================
#pragma once
#include "media/gst/internal/w_common.hpp"
#include
namespace wolf::media::gst {
/**
* @brief nonowning view of `T` pointing to same resource
* given to make nonowning view of. similar to std::string_view/std::span.
*
* it's for sharing things like element.clock() returning Clock instance,
* which the instance does not own the clock's lifetime, but
* points to same resource to keep track of.
*
* this class is wrapper acting as a pointer to an instance of `T`
* with shared resource beneath.
*
* @tparam T underlying type of nonowning view.
*
* @note make sure the given object lives longer than this nonowning view of it,
* or any access will be undefined behavior.
* similar to std::string_view or std::span.
*/
template
class w_nonowning
{
friend class internal::w_raw_access;
using value_type = std::remove_cvref_t;
public:
/**
* @brief implicit constructor from a value of wrapping type.
* @param p_value value to make nonowing view of.
*/
w_nonowning(value_type& p_value)
: w_nonowning(internal::w_raw_access::raw(p_value))
{}
w_nonowning(const w_nonowning&) = default;
w_nonowning(w_nonowning&&) noexcept = default;
w_nonowning& operator=(const w_nonowning&) = default;
w_nonowning& operator=(w_nonowning&&) noexcept = default;
~w_nonowning() noexcept
{
// disown raw resource before resource
// be released/free'ed by T's destructor.
internal::w_raw_access::disown_raw(_value);
}
value_type* operator->() noexcept { return std::addressof(_value); }
const value_type* operator->() const noexcept { return std::addressof(_value); }
value_type& operator*() noexcept { return _value; }
const value_type& operator*() const noexcept { return _value; }
private:
template
w_nonowning(internal::w_raw_tag, RawT* p_rawptr) noexcept
: _value(internal::w_raw_access::from_raw(p_rawptr))
{}
value_type _value;
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_pad.cpp
================================================
#include "media/gst/core/w_pad.hpp"
================================================
FILE: wolf/media/gst/core/w_pad.hpp
================================================
#pragma once
#include "media/gst/internal/w_common.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include
#include
namespace wolf::media::gst {
/** gstreamer pad availablity */
enum class w_availability
{
Always,
Request,
Sometimes
};
/**
* @brief wrapper of GstPad.
*
* each gstreamer element has source and/or sink pads,
* which they connect by to each other with.
*/
class w_pad : public w_wrapper
{
friend class internal::w_raw_access;
public:
// so far nothing...
private:
explicit w_pad(internal::w_raw_tag, GstPad* p_pad) noexcept
: w_wrapper(p_pad)
{}
};
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_pipeline.cpp
================================================
#include "media/gst/core/w_pipeline.hpp"
namespace wolf::media::gst {
auto w_pipeline::make(const char *p_name)
-> boost::leaf::result
{
auto pipeline_raw = gst_pipeline_new(p_name);
if (!pipeline_raw) {
return W_FAILURE(std::errc::operation_canceled,
wolf::format("couldn't create pipeline: {}", p_name));
}
return w_pipeline(internal::w_raw_tag{}, pipeline_raw);
}
auto w_pipeline::get_bus() -> boost::leaf::result
{
auto bus_raw = gst_element_get_bus(raw());
if (!bus_raw) {
return W_FAILURE(std::errc::operation_canceled,
"couldn't get pipeline's bus.");
}
return internal::w_raw_access::from_raw(bus_raw);
}
bool w_pipeline::bin(w_flow_path &p_flow)
{
for (auto& element : p_flow) {
if (!bin(*element)) {
return false;
}
}
return true;
}
bool w_pipeline::link(w_flow_path &p_flow)
{
auto* last = p_flow.first().get();
for (int i = 1; i < p_flow.size(); ++i) {
if (!link(*last, *p_flow[i])) {
return false;
}
last = p_flow[i].get();
}
return true;
}
} // namespace wolf::media::gst
================================================
FILE: wolf/media/gst/core/w_pipeline.hpp
================================================
#pragma once
#include "wolf.hpp"
#include "media/gst/w_flow.hpp"
#include "media/gst/core/w_element.hpp"
#include "media/gst/core/w_bus.hpp"
#include "media/gst/internal/w_wrapper.hpp"
#include
#include
#include
namespace wolf::media::gst {
/**
* @brief wrapper of GstElement, providing gstreamer pipeline concept.
*/
class w_pipeline : public w_wrapper
{
public:
/**
* @brief make an instance of pipeline with given name.
* @param p_name pipeline's name.
* @return an instance of pipeline on success.
*/
[[nodiscard]] static auto make(const char* p_name)
-> boost::leaf::result;
/**
* @brief get pipeline's bus.
*/
[[nodiscard]] auto get_bus() -> boost::leaf::result;
/**
* @brief add given elements to pipeline's bin.
* @param p_args pack of elements.
* @return boolean indicating success or failure.
*/
template
requires (sizeof...(Args) > 1)
bool bin(Args&& ...p_args)
{
return (true && ... && bin(std::forward(p_args)));
}
/**
* @brief add elements from given flow path to pipeline's bin.
* @param p_flow elements flow path.
* @return boolean indicating success or failure.
*/
bool bin(w_flow_path& p_flow);
/**
* @brief add given single element to pipeline's bin.
* @param p_element single element.
* @return boolean indicating success or failure.
*/
bool bin(w_element& p_element)
{
auto element_raw = internal::w_raw_access::raw(p_element);
p_element.parented();
return gst_bin_add(GST_BIN(raw()), element_raw);
}
/**
* @brief link a pack of given linkables (element or pad) together after each other.
* @param p_a source linkable to link with `p_b`.
* @param p_b sink linkable to link with `p_a`.
* @param p_rest pack of rest of linkables to be linked after `p_b` as source.
* @return boolean indicating success or failure.
*/
template