#pragma once #include "Utilities/StrUtil.h" #include "Utilities/Thread.h" #include "util/video_provider.h" #include "Emu/Cell/Modules/cellMusic.h" #include #include #include #include namespace utils { std::string av_error_to_string(int error); struct ffmpeg_codec { int codec_id{}; std::string name; std::string long_name; }; std::vector list_ffmpeg_decoders(); std::vector list_ffmpeg_encoders(); struct media_info { std::string path; std::string sub_type; // The sub type if available (png, jpg...) s32 audio_av_codec_id = 0; // 0 = AV_CODEC_ID_NONE s32 video_av_codec_id = 0; // 0 = AV_CODEC_ID_NONE s32 audio_bitrate_bps = 0; // Bit rate in bit/s s32 video_bitrate_bps = 0; // Bit rate in bit/s s32 sample_rate = 0; // Samples per second s64 duration_us = 0; // in AV_TIME_BASE fractional seconds (= microseconds) s32 width = 0; // Width if available s32 height = 0; // Height if available s32 orientation = 0; // Orientation if available (= CellSearchOrientation) std::unordered_map metadata; // Convenience function for metadata template T get_metadata(const std::string& key, const T& def) const; }; std::pair get_media_info(const std::string& path, s32 av_media_type); template void parse_metadata(D& dst, const utils::media_info& mi, const std::string& key, const std::string& def, usz max_length) { std::string value = mi.get_metadata(key, def); if (value.size() > max_length) { value.resize(max_length); } strcpy_trunc(dst, value); }; class audio_decoder { public: audio_decoder(); ~audio_decoder(); void set_context(music_selection_context context); void set_swap_endianness(bool swapped); void clear(); void stop(); void decode(); u32 set_next_index(bool next); shared_mutex m_mtx; static constexpr s32 sample_rate = 48000; std::vector data; atomic_t m_size = 0; atomic_t track_fully_decoded{0}; atomic_t track_fully_consumed{0}; atomic_t has_error{false}; std::deque> timestamps_ms; private: bool m_swap_endianness = false; music_selection_context m_context{}; std::unique_ptr>> m_thread; }; class video_encoder : public utils::video_sink { public: video_encoder(); ~video_encoder(); struct frame_format { s32 av_pixel_format = 0; // NOTE: Make sure this is a valid AVPixelFormat u32 width = 0; u32 height = 0; u32 pitch = 0; std::string to_string() const { return fmt::format("{ av_pixel_format=%d, width=%d, height=%d, pitch=%d }", av_pixel_format, width, height, pitch); } }; std::string path() const; s64 last_video_pts() const; void set_path(const std::string& path); void set_framerate(u32 framerate); void set_video_bitrate(u32 bitrate); void set_output_format(frame_format format); void set_video_codec(s32 codec_id); void set_max_b_frames(s32 max_b_frames); void set_gop_size(s32 gop_size); void set_sample_rate(u32 sample_rate); void set_audio_channels(u32 channels); void set_audio_bitrate(u32 bitrate); void set_audio_codec(s32 codec_id); void pause(bool flush = true) override; void stop(bool flush = true) override; void resume() override; void encode(); private: std::string m_path; s64 m_last_audio_pts = 0; s64 m_last_video_pts = 0; // Thread control std::unique_ptr>> m_thread; atomic_t m_running = false; // Video parameters u32 m_video_bitrate_bps = 0; s32 m_video_codec_id = 12; // AV_CODEC_ID_MPEG4 s32 m_max_b_frames = 2; s32 m_gop_size = 12; frame_format m_out_format{}; // Audio parameters u32 m_channels = 2; u32 m_audio_bitrate_bps = 320000; s32 m_audio_codec_id = 86018; // AV_CODEC_ID_AAC }; }