diff --git a/MusicPlayer2/CommonData.h b/MusicPlayer2/CommonData.h index f7514cbfd..001baac3e 100644 --- a/MusicPlayer2/CommonData.h +++ b/MusicPlayer2/CommonData.h @@ -299,6 +299,14 @@ struct PlaySettingData int fade_time{ 500 }; //淡入淡出时间(毫秒) bool use_mci{ false }; //是否使用MCI内核 + /// 是否使用ffmpeg内核 + bool use_ffmpeg{ false }; + /// ffmpeg内核缓存时长(单位:s) + int ffmpeg_core_cache_length { 15 }; + /// ffmpeg内核最大重试次数 + int ffmpeg_core_max_retry_count { 3 }; + /// ffmpeg内核非本地文件重试间隔时间(单位s) + int ffmpeg_core_url_retry_interval { 5 }; }; struct GlobalHotKeySettingData diff --git a/MusicPlayer2/FfmpegCore.cpp b/MusicPlayer2/FfmpegCore.cpp new file mode 100644 index 000000000..0f05db214 --- /dev/null +++ b/MusicPlayer2/FfmpegCore.cpp @@ -0,0 +1,616 @@ +#include "stdafx.h" +#include "FfmpegCore.h" + +#include "AudioCommon.h" +#include "Common.h" +#include "MusicPlayer2.h" + +#define ft2ts(t) (((size_t)t.dwHighDateTime << 32) | (size_t)t.dwLowDateTime) + +static std::wstring last_ffmpeg_core_error_cache; + +CFfmpegCore::CFfmpegCore() { + handle = nullptr; + err = 0; + Init(L"ffmpeg_core.dll"); + if (!IsSucceed()) { + CString strInfo = CCommon::LoadText(IDS_FFMPEG_INIT_FAILED); + theApp.WriteLog(wstring(strInfo)); + } +} + +CFfmpegCore::~CFfmpegCore() { + if (handle || settings) UnInitCore(); + CDllLib::UnInit(); +} + +void CFfmpegCore::InitCore() { + if (IsSucceed()) { + CAudioCommon::m_surpported_format.clear(); + SupportedFormat format; + format.description = CCommon::LoadText(IDS_BASIC_AUDIO_FORMAT); + format.extensions.push_back(L"mp3"); + format.extensions.push_back(L"wma"); + format.extensions.push_back(L"wav"); + format.extensions.push_back(L"m4a"); + format.extensions.push_back(L"ogg"); + format.extensions.push_back(L"oga"); + format.extensions.push_back(L"flac"); + format.extensions.push_back(L"ape"); + format.extensions.push_back(L"mp2"); + format.extensions.push_back(L"mp1"); + format.extensions.push_back(L"opus"); + format.extensions.push_back(L"ape"); + format.extensions.push_back(L"aif"); + format.extensions.push_back(L"aiff"); + format.extensions.push_back(L"cda"); + format.extensions.push_back(L"cue"); + format.extensions.push_back(L"mp4"); + format.extensions.push_back(L"mkv"); + format.extensions.push_back(L"m2ts"); + format.extensions_list = L"*.mp3;*.wma;*.wav;*.m4a;*.ogg;*.oga;*.flac;*.ape;*.mp2;*.mp1;*.opus;*.ape;*.cda;*.aif;*.aiff;*.cue;*.mp4;*.mkv;*.m2ts"; + CAudioCommon::m_surpported_format.push_back(format); + CAudioCommon::m_all_surpported_extensions = format.extensions; + settings = ffmpeg_core_init_settings(); + ffmpeg_core_log_set_flags(AV_LOG_SKIP_REPEATED | AV_LOG_PRINT_LEVEL); + ffmpeg_core_log_set_callback(LogCallback); + UpdateSettings(); + auto devices = GetAudioDevices(); + DeviceInfo d; + d.index = -1; + d.name = CCommon::LoadText(IDS_SDL_DEFAULT_DEVICE); + d.driver = L""; + d.flags = 0; + theApp.m_output_devices.clear(); + theApp.m_output_devices.push_back(d); + int device_index = 0; + for (auto i = devices.begin(); i != devices.end(); i++) { + DeviceInfo d; + d.index = device_index++; + d.name = *i; + d.driver = L""; + d.flags = 0; + theApp.m_output_devices.push_back(d); + } + std::string ver("ffmpeg core version: "); + ver += ffmpeg_core_version_str(); + ver += "\n"; + OutputDebugStringA(ver.c_str()); + ffmpeg_core_dump_library_version(1, AV_LOG_INFO); + ffmpeg_core_dump_ffmpeg_configuration(1, AV_LOG_INFO); + } +} + +void CFfmpegCore::UnInitCore() { + if (settings && IsSucceed()) { + free_ffmpeg_core_settings(settings); + settings = nullptr; + } + if (handle) { + Close(); + } +} + +unsigned int CFfmpegCore::GetHandle() { + return 0; +} + +std::wstring CFfmpegCore::GetAudioType() { + return L""; +} + +int CFfmpegCore::GetChannels() { + if (IsSucceed() && handle) { + return ffmpeg_core_get_channels(handle); + } else return 0; +} + +int CFfmpegCore::GetFReq() { + if (IsSucceed() && handle) { + return ffmpeg_core_get_freq(handle); + } else return 0; +} + +std::wstring CFfmpegCore::GetSoundFontName() { + return L""; +} + +void CFfmpegCore::Open(const wchar_t* file_path) { + if (!IsSucceed()) return; + if (handle) { + Close(); + } + if (file_path) recent_file = file_path; + const wchar_t* device = nullptr; + if (theApp.m_play_setting_data.device_selected < theApp.m_output_devices.size() && theApp.m_play_setting_data.device_selected) { + device = theApp.m_output_devices[theApp.m_play_setting_data.device_selected].name.c_str(); + } + if (!settings) settings = ffmpeg_core_init_settings(); + int re = ffmpeg_core_open3(file_path, &handle, settings, device); + if (re) { + err = re; + } +} + +void CFfmpegCore::Close() { + if (IsSucceed() && handle) { + free_music_handle(handle); + handle = nullptr; + err = 0; + } +} + +void CFfmpegCore::Play() { + if (!IsSucceed()) return; + if (!handle && !recent_file.empty()) { + Open(recent_file.c_str()); + } + if (handle) { + ffmpeg_core_play(handle); + } +} + +void CFfmpegCore::Pause() { + if (IsSucceed() && handle) { + ffmpeg_core_pause(handle); + } +} + +void CFfmpegCore::Stop() { + Close(); +} + +void CFfmpegCore::SetVolume(int volume) { + if (!IsSucceed()) return; + if (handle) { + int re = ffmpeg_core_set_volume(handle, volume); + if (re) { + err = re; + } + } else { + ffmpeg_core_settings_set_volume(settings, volume); + } +} + +void CFfmpegCore::SetSpeed(float speed) { + if (!IsSucceed()) return; + if (handle) { + int re = ffmpeg_core_set_speed(handle, speed); + if (re) { + err = re; + } + } else { + ffmpeg_core_settings_set_speed(settings, speed); + } +} + +bool CFfmpegCore::SongIsOver() { + if (IsSucceed() && handle) { + return ffmpeg_core_song_is_over(handle); + } else return false; +} + +int CFfmpegCore::GetCurPosition() { + if (IsSucceed() && handle) { + return ffmpeg_core_get_cur_position(handle) / 1000; + } else return 0; +} + +int CFfmpegCore::GetSongLength() { + if (IsSucceed() && handle) { + return ffmpeg_core_get_song_length(handle) / 1000; + } else return 0; +} + +void CFfmpegCore::SetCurPosition(int position) { + if (IsSucceed() && handle) { + int re = ffmpeg_core_seek(handle, (int64_t)position * 1000); + if (re) { + err = re; + } + } +} + +void CFfmpegCore::GetAudioInfo(SongInfo& song_info, int flag) { + if (!handle || !IsSucceed()) return; + if (flag & AF_LENGTH) song_info.lengh = GetSongLength(); + if (flag & AF_CHANNEL_INFO) { + song_info.freq = ffmpeg_core_get_freq(handle); + song_info.bits = ffmpeg_core_get_bits(handle); + song_info.channels = ffmpeg_core_get_channels(handle); + } + if (flag & AF_BITRATE) { + song_info.bitrate = ffmpeg_core_get_bitrate(handle) / 1000; + } + if (flag & AF_TAG_INFO) { + song_info.title = GetTitle(); + song_info.artist = GetArtist(); + song_info.album = GetAlbum(); + song_info.comment = GetComment(); + song_info.genre = GetGenre(); + song_info.year = GetYear(); + song_info.track = GetTrackNum(); + } +} + +void CFfmpegCore::GetAudioInfo(const wchar_t* file_path, SongInfo& song_info, int flag) { + if (!IsSucceed()) return; + MusicInfoHandle* h = nullptr; + int re = ffmpeg_core_info_open(file_path, &h); + if (re || !h) return; + if (flag & AF_LENGTH) song_info.lengh = ffmpeg_core_info_get_song_length(h) / 1000; + if (flag & AF_CHANNEL_INFO) { + song_info.freq = ffmpeg_core_info_get_freq(h); + song_info.bits = ffmpeg_core_info_get_bits(h); + song_info.channels = ffmpeg_core_info_get_channels(h); + } + if (flag & AF_BITRATE) { + song_info.bitrate = ffmpeg_core_info_get_bitrate(h) / 1000; + } + if (flag & AF_TAG_INFO) { + song_info.title = GetTitle(h); + song_info.artist = GetArtist(h); + song_info.album = GetAlbum(h); + song_info.comment = GetComment(h); + song_info.genre = GetGenre(h); + song_info.year = GetYear(h); + song_info.track = GetTrackNum(h); + } + free_music_info_handle(h); +} + +bool CFfmpegCore::IsMidi() { + return false; +} + +bool CFfmpegCore::IsMidiConnotPlay() { + return false; +} + +MidiInfo CFfmpegCore::GetMidiInfo() { + return MidiInfo(); +} + +std::wstring CFfmpegCore::GetMidiInnerLyric() { + return L""; +} + +bool CFfmpegCore::MidiNoLyric() { + return true; +} + +PlayingState CFfmpegCore::GetPlayingState() { + if (IsSucceed() && handle) { + return ffmpeg_core_is_playing(handle) ? PlayingState::PS_PLAYING : PlayingState::PS_PAUSED; + } else return PlayingState::PS_STOPED; +} + +void CFfmpegCore::ApplyEqualizer(int channel, int gain) { + if (!IsSucceed()) return; + channel = GetEqChannelFreq(channel); + if (handle) { + int re = ffmpeg_core_set_equalizer_channel(handle, channel, gain); + if (re) { + err = re; + } + } else { + ffmpeg_core_settings_set_equalizer_channel(settings, channel, gain); + } +} + +void CFfmpegCore::SetReverb(int mix, int time) { +} + +void CFfmpegCore::ClearReverb() { +} + +void CFfmpegCore::GetFFTData(float fft_data[FFT_SAMPLE]) { + if (handle && IsSucceed()) { + memset(fft_data, 0, FFT_SAMPLE); + ffmpeg_core_get_fft_data(handle, fft_data, FFT_SAMPLE); + } else { + memset(fft_data, 0, FFT_SAMPLE); + } +} + +int CFfmpegCore::GetErrorCode() { + if (err) { + int tmp = err; + err = 0; + return tmp; + } + // ²Ĵ⵱²´ļʱʹﷵ0ϲΪд + // if (handle) return ffmpeg_core_get_error(handle); + return 0; +} + +std::wstring CFfmpegCore::GetErrorInfo(int error_code) { + if (error_code == 0 || !IsSucceed()) return L""; + auto tmp = ffmpeg_core_get_err_msg(error_code); + if (tmp) { + std::wstring re(tmp); + ffmpeg_core_free(tmp); + return re; + } + return L""; +} + +std::wstring CFfmpegCore::GetErrorInfo() { + return GetErrorInfo(GetErrorCode()); +} + +PlayerCoreType CFfmpegCore::GetCoreType() { + return PlayerCoreType::PT_FFMPEG; +} + +int CFfmpegCore::GetDeviceCount() { + return 0; +} + +bool CFfmpegCore::GetFunction() { + bool rtn = true; + //ȡ + free_music_handle = (_free_music_handle)::GetProcAddress(m_dll_module, "free_music_handle"); + free_music_info_handle = (_free_music_info_handle)::GetProcAddress(m_dll_module, "free_music_info_handle"); + free_ffmpeg_core_settings = (_free_ffmpeg_core_settings)::GetProcAddress(m_dll_module, "free_ffmpeg_core_settings"); + free_device_name_list = (_free_device_name_list)::GetProcAddress(m_dll_module, "free_device_name_list"); + ffmpeg_core_free = (_ffmpeg_core_free)::GetProcAddress(m_dll_module, "ffmpeg_core_free"); + ffmpeg_core_malloc = (_ffmpeg_core_malloc)::GetProcAddress(m_dll_module, "ffmpeg_core_malloc"); + ffmpeg_core_realloc = (_ffmpeg_core_realloc)::GetProcAddress(m_dll_module, "ffmpeg_core_realloc"); + ffmpeg_core_log_format_line = (_ffmpeg_core_log_format_line)::GetProcAddress(m_dll_module, "ffmpeg_core_log_format_line"); + ffmpeg_core_log_set_callback = (_ffmpeg_core_log_set_callback)::GetProcAddress(m_dll_module, "ffmpeg_core_log_set_callback"); + ffmpeg_core_log_set_flags = (_ffmpeg_core_log_set_flags)::GetProcAddress(m_dll_module, "ffmpeg_core_log_set_flags"); + ffmpeg_core_version_str = (_ffmpeg_core_version_str)::GetProcAddress(m_dll_module, "ffmpeg_core_version_str"); + ffmpeg_core_version = (_ffmpeg_core_version)::GetProcAddress(m_dll_module, "ffmpeg_core_version"); + ffmpeg_core_dump_library_version = (_ffmpeg_core_dump_library_version)::GetProcAddress(m_dll_module, "ffmpeg_core_dump_library_version"); + ffmpeg_core_dump_ffmpeg_configuration = (_ffmpeg_core_dump_ffmpeg_configuration)::GetProcAddress(m_dll_module, "ffmpeg_core_dump_ffmpeg_configuration"); + ffmpeg_core_open = (_ffmpeg_core_open)::GetProcAddress(m_dll_module, "ffmpeg_core_open"); + ffmpeg_core_open2 = (_ffmpeg_core_open2)::GetProcAddress(m_dll_module, "ffmpeg_core_open2"); + ffmpeg_core_open3 = (_ffmpeg_core_open3)::GetProcAddress(m_dll_module, "ffmpeg_core_open3"); + ffmpeg_core_info_open = (_ffmpeg_core_info_open)::GetProcAddress(m_dll_module, "ffmpeg_core_info_open"); + ffmpeg_core_play = (_ffmpeg_core_play)::GetProcAddress(m_dll_module, "ffmpeg_core_play"); + ffmpeg_core_pause = (_ffmpeg_core_pause)::GetProcAddress(m_dll_module, "ffmpeg_core_pause"); + ffmpeg_core_seek = (_ffmpeg_core_seek)::GetProcAddress(m_dll_module, "ffmpeg_core_seek"); + ffmpeg_core_set_volume = (_ffmpeg_core_set_volume)::GetProcAddress(m_dll_module, "ffmpeg_core_set_volume"); + ffmpeg_core_set_speed = (_ffmpeg_core_set_speed)::GetProcAddress(m_dll_module, "ffmpeg_core_set_speed"); + ffmpeg_core_set_equalizer_channel = (_ffmpeg_core_set_equalizer_channel)::GetProcAddress(m_dll_module, "ffmpeg_core_set_equalizer_channel"); + ffmpeg_core_get_error = (_ffmpeg_core_get_error)::GetProcAddress(m_dll_module, "ffmpeg_core_get_error"); + ffmpeg_core_get_err_msg = (_ffmpeg_core_get_err_msg)::GetProcAddress(m_dll_module, "ffmpeg_core_get_err_msg"); + ffmpeg_core_get_err_msg2 = (_ffmpeg_core_get_err_msg2)::GetProcAddress(m_dll_module, "ffmpeg_core_get_err_msg2"); + ffmpeg_core_get_cur_position = (_ffmpeg_core_get_cur_position)::GetProcAddress(m_dll_module, "ffmpeg_core_get_cur_position"); + ffmpeg_core_song_is_over = (_ffmpeg_core_song_is_over)::GetProcAddress(m_dll_module, "ffmpeg_core_song_is_over"); + ffmpeg_core_get_song_length = (_ffmpeg_core_get_song_length)::GetProcAddress(m_dll_module, "ffmpeg_core_get_song_length"); + ffmpeg_core_info_get_song_length = (_ffmpeg_core_info_get_song_length)::GetProcAddress(m_dll_module, "ffmpeg_core_info_get_song_length"); + ffmpeg_core_get_channels = (_ffmpeg_core_get_channels)::GetProcAddress(m_dll_module, "ffmpeg_core_get_channels"); + ffmpeg_core_info_get_channels = (_ffmpeg_core_info_get_channels)::GetProcAddress(m_dll_module, "ffmpeg_core_info_get_channels"); + ffmpeg_core_get_freq = (_ffmpeg_core_get_freq)::GetProcAddress(m_dll_module, "ffmpeg_core_get_freq"); + ffmpeg_core_info_get_freq = (_ffmpeg_core_info_get_freq)::GetProcAddress(m_dll_module, "ffmpeg_core_info_get_freq"); + ffmpeg_core_is_playing = (_ffmpeg_core_is_playing)::GetProcAddress(m_dll_module, "ffmpeg_core_is_playing"); + ffmpeg_core_get_bits = (_ffmpeg_core_get_bits)::GetProcAddress(m_dll_module, "ffmpeg_core_get_bits"); + ffmpeg_core_info_get_bits = (_ffmpeg_core_info_get_bits)::GetProcAddress(m_dll_module, "ffmpeg_core_info_get_bits"); + ffmpeg_core_get_bitrate = (_ffmpeg_core_get_bitrate)::GetProcAddress(m_dll_module, "ffmpeg_core_get_bitrate"); + ffmpeg_core_info_get_bitrate = (_ffmpeg_core_info_get_bitrate)::GetProcAddress(m_dll_module, "ffmpeg_core_info_get_bitrate"); + ffmpeg_core_get_metadata = (_ffmpeg_core_get_metadata)::GetProcAddress(m_dll_module, "ffmpeg_core_get_metadata"); + ffmpeg_core_info_get_metadata = (_ffmpeg_core_info_get_metadata)::GetProcAddress(m_dll_module, "ffmpeg_core_info_get_metadata"); + ffmpeg_core_get_fft_data = (_ffmpeg_core_get_fft_data)::GetProcAddress(m_dll_module, "ffmpeg_core_get_fft_data"); + ffmpeg_core_init_settings = (_ffmpeg_core_init_settings)::GetProcAddress(m_dll_module, "ffmpeg_core_init_settings"); + ffmpeg_core_settings_set_volume = (_ffmpeg_core_settings_set_volume)::GetProcAddress(m_dll_module, "ffmpeg_core_settings_set_volume"); + ffmpeg_core_settings_set_speed = (_ffmpeg_core_settings_set_speed)::GetProcAddress(m_dll_module, "ffmpeg_core_settings_set_speed"); + ffmpeg_core_settings_set_cache_length = (_ffmpeg_core_settings_set_cache_length)::GetProcAddress(m_dll_module, "ffmpeg_core_settings_set_cache_length"); + ffmpeg_core_settings_set_max_retry_count = (_ffmpeg_core_settings_set_max_retry_count)::GetProcAddress(m_dll_module, "ffmpeg_core_settings_set_max_retry_count"); + ffmpeg_core_settings_set_url_retry_interval = (_ffmpeg_core_settings_set_url_retry_interval)::GetProcAddress(m_dll_module, "ffmpeg_core_settings_set_url_retry_interval"); + ffmpeg_core_settings_set_equalizer_channel = (_ffmpeg_core_settings_set_equalizer_channel)::GetProcAddress(m_dll_module, "ffmpeg_core_settings_set_equalizer_channel"); + ffmpeg_core_get_audio_devices = (_ffmpeg_core_get_audio_devices)::GetProcAddress(m_dll_module, "ffmpeg_core_get_audio_devices"); + //жǷɹ + rtn &= (free_device_name_list != NULL); + rtn &= (free_music_handle != NULL); + rtn &= (free_music_info_handle != NULL); + rtn &= (free_ffmpeg_core_settings != NULL); + rtn &= (ffmpeg_core_free != NULL); + rtn &= (ffmpeg_core_malloc != NULL); + rtn &= (ffmpeg_core_realloc != NULL); + rtn &= (ffmpeg_core_log_format_line != NULL); + rtn &= (ffmpeg_core_log_set_callback != NULL); + rtn &= (ffmpeg_core_log_set_flags != NULL); + rtn &= (ffmpeg_core_version_str != NULL); + rtn &= (ffmpeg_core_version != NULL); + rtn &= (ffmpeg_core_dump_library_version != NULL); + rtn &= (ffmpeg_core_dump_ffmpeg_configuration != NULL); + rtn &= (ffmpeg_core_open != NULL); + rtn &= (ffmpeg_core_open2 != NULL); + rtn &= (ffmpeg_core_open3 != NULL); + rtn &= (ffmpeg_core_info_open != NULL); + rtn &= (ffmpeg_core_play != NULL); + rtn &= (ffmpeg_core_pause != NULL); + rtn &= (ffmpeg_core_seek != NULL); + rtn &= (ffmpeg_core_set_volume != NULL); + rtn &= (ffmpeg_core_set_speed != NULL); + rtn &= (ffmpeg_core_set_equalizer_channel != NULL); + rtn &= (ffmpeg_core_get_error != NULL); + rtn &= (ffmpeg_core_get_err_msg != NULL); + rtn &= (ffmpeg_core_get_err_msg2 != NULL); + rtn &= (ffmpeg_core_get_cur_position != NULL); + rtn &= (ffmpeg_core_song_is_over != NULL); + rtn &= (ffmpeg_core_get_song_length != NULL); + rtn &= (ffmpeg_core_info_get_song_length != NULL); + rtn &= (ffmpeg_core_get_channels != NULL); + rtn &= (ffmpeg_core_info_get_channels != NULL); + rtn &= (ffmpeg_core_get_freq != NULL); + rtn &= (ffmpeg_core_info_get_freq != NULL); + rtn &= (ffmpeg_core_is_playing != NULL); + rtn &= (ffmpeg_core_get_bits != NULL); + rtn &= (ffmpeg_core_info_get_bits != NULL); + rtn &= (ffmpeg_core_get_bitrate != NULL); + rtn &= (ffmpeg_core_info_get_bitrate != NULL); + rtn &= (ffmpeg_core_get_metadata != NULL); + rtn &= (ffmpeg_core_info_get_metadata != NULL); + rtn &= (ffmpeg_core_get_fft_data != NULL); + rtn &= (ffmpeg_core_init_settings != NULL); + rtn &= (ffmpeg_core_settings_set_volume != NULL); + rtn &= (ffmpeg_core_settings_set_speed != NULL); + rtn &= (ffmpeg_core_settings_set_cache_length != NULL); + rtn &= (ffmpeg_core_settings_set_max_retry_count != NULL); + rtn &= (ffmpeg_core_settings_set_url_retry_interval != NULL); + rtn &= (ffmpeg_core_settings_set_equalizer_channel != NULL); + rtn &= (ffmpeg_core_get_audio_devices != NULL); + return rtn; +} + +std::wstring CFfmpegCore::GetMetadata(std::string key, MusicInfoHandle* h) { + if (!IsSucceed()) return L""; + if (h) { + auto r = ffmpeg_core_info_get_metadata(h, key.c_str()); + if (!r) return L""; + std::wstring re(r); + ffmpeg_core_free(r); + return re; + } + if (!handle) return L""; + auto r = ffmpeg_core_get_metadata(handle, key.c_str()); + if (!r) return L""; + std::wstring re(r); + ffmpeg_core_free(r); + return re; +} + +std::wstring CFfmpegCore::GetTitle(MusicInfoHandle* h) { + return GetMetadata("title", h); +} + +std::wstring CFfmpegCore::GetArtist(MusicInfoHandle* h) { + return GetMetadata("artist", h); +} + +std::wstring CFfmpegCore::GetAlbum(MusicInfoHandle* h) { + return GetMetadata("album", h); +} + +std::wstring CFfmpegCore::GetComment(MusicInfoHandle* h) { + auto re = GetMetadata("comment", h); + if (!re.empty()) return re; + return GetMetadata("description", h); +} + +std::wstring CFfmpegCore::GetGenre(MusicInfoHandle* h) { + return GetMetadata("genre", h); +} + +std::wstring CFfmpegCore::GetDate(MusicInfoHandle* h) { + return GetMetadata("date", h); +} + +unsigned short CFfmpegCore::GetYear(MusicInfoHandle* h) { + auto r = GetDate(h); + if (r.empty()) return 0; + unsigned short year = 0; + if (swscanf_s(r.c_str(), L"%hu", &year) == 1) return year; + return 0; +} + +std::wstring CFfmpegCore::GetTrack(MusicInfoHandle* h) { + return GetMetadata("track", h); +} + +int CFfmpegCore::GetTrackNum(MusicInfoHandle* h) { + auto r = GetTrack(h); + if (r.empty()) return 0; + int track; + if (swscanf_s(r.c_str(), L"%i", &track) == 1) return track; + return 0; +} + +void CFfmpegCore::LogCallback(void* ptr, int level, const char* fmt, va_list vl) { + if (level > AV_LOG_VERBOSE) return; + auto re = LoadLibraryW(L"ffmpeg_core.dll"); + if (!re) return; + auto ffmpeg_core_log_format_line = (_ffmpeg_core_log_format_line)::GetProcAddress(re, "ffmpeg_core_log_format_line"); + char buf[1024]; + if (ffmpeg_core_log_format_line) { + int print = 1; + int r = ffmpeg_core_log_format_line(ptr, level, fmt, vl, buf, sizeof(buf), &print); + if (r > 0) { + std::wstring s = CCommon::StrToUnicode(std::string(buf, r), CodeType::UTF8); + if (s.find(L"Last message repeated") != -1) { + FreeLibrary(re); + return; + } + OutputDebugStringW(s.c_str()); + if (level <= AV_LOG_ERROR) { + if (s.back() == '\n') { + s.pop_back(); + } + if (last_ffmpeg_core_error_cache.empty() || last_ffmpeg_core_error_cache != s) { + last_ffmpeg_core_error_cache = s; + theApp.WriteLog(s); + } + } + } + } + FreeLibrary(re); +} + +void CFfmpegCore::UpdateSettings() { + SetCacheLength(theApp.m_play_setting_data.ffmpeg_core_cache_length); + SetMaxRetryCount(theApp.m_play_setting_data.ffmpeg_core_max_retry_count); + SetUrlRetryInterval(theApp.m_play_setting_data.ffmpeg_core_url_retry_interval); +} + +void CFfmpegCore::SetCacheLength(int cache_length) { + if (settings && IsSucceed()) { + ffmpeg_core_settings_set_cache_length(settings, cache_length); + } +} + +void CFfmpegCore::SetMaxRetryCount(int max_retry_count) { + if (settings && IsSucceed()) { + ffmpeg_core_settings_set_max_retry_count(settings, max_retry_count); + } +} + +void CFfmpegCore::SetUrlRetryInterval(int url_retry_interval) { + if (settings && IsSucceed()) { + ffmpeg_core_settings_set_url_retry_interval(settings, url_retry_interval); + } +} + +int CFfmpegCore::GetEqChannelFreq(int channel) { + switch (channel) { + case 0: + return 80; + case 1: + return 125; + case 2: + return 250; + case 3: + return 500; + case 4: + return 1000; + case 5: + return 1500; + case 6: + return 2000; + case 7: + return 4000; + case 8: + return 8000; + case 9: + return 16000; + default: + return 0; + } +} + +std::list CFfmpegCore::GetAudioDevices() { + if (!IsSucceed()) return {}; + auto d = ffmpeg_core_get_audio_devices(); + if (!d) return {}; + std::list l; + l.push_back(CCommon::StrToUnicode(d->device, CodeType::UTF8)); + auto t = d; + while (t->next) { + t = t->next; + l.push_back(CCommon::StrToUnicode(t->device, CodeType::UTF8)); + } + free_device_name_list(&d); + return l; +} diff --git a/MusicPlayer2/FfmpegCore.h b/MusicPlayer2/FfmpegCore.h new file mode 100644 index 000000000..b8fcb14a5 --- /dev/null +++ b/MusicPlayer2/FfmpegCore.h @@ -0,0 +1,183 @@ +#pragma once +#include "IPlayerCore.h" +#include "DllLib.h" + +#define AV_LOG_ERROR 16 +#define AV_LOG_INFO 32 +#define AV_LOG_VERBOSE 40 +#define AV_LOG_SKIP_REPEATED 1 +#define AV_LOG_PRINT_LEVEL 2 +typedef struct MusicHandle MusicHandle; +typedef struct MusicInfoHandle MusicInfoHandle; +typedef struct FfmpegCoreSettings FfmpegCoreSettings; +typedef struct DeviceNameList { + char* device; + struct DeviceNameList* prev; + struct DeviceNameList* next; +} DeviceNameList; +typedef void(*_free_music_handle)(MusicHandle*); +typedef void(*_free_music_info_handle)(MusicInfoHandle*); +typedef void(*_free_ffmpeg_core_settings)(FfmpegCoreSettings*); +typedef void(*_free_device_name_list)(DeviceNameList**); +typedef void(*_ffmpeg_core_free)(void*); +typedef void*(*_ffmpeg_core_malloc)(size_t); +typedef void*(*_ffmpeg_core_realloc)(void*, size_t); +typedef int(*_ffmpeg_core_log_format_line)(void* ptr, int level, const char* fmt, va_list vl, char* line, int line_size, int* print_prefix); +typedef void(*_ffmpeg_core_log_set_callback)(void(*callback)(void*, int, const char*, va_list)); +typedef void(*_ffmpeg_core_log_set_flags)(int); +typedef const char*(*_ffmpeg_core_version_str)(); +typedef int32_t(*_ffmpeg_core_version)(); +typedef void(*_ffmpeg_core_dump_library_version)(int, int); +typedef void(*_ffmpeg_core_dump_ffmpeg_configuration)(int, int); +typedef int(*_ffmpeg_core_open)(const wchar_t*, MusicHandle**); +typedef int(*_ffmpeg_core_open2)(const wchar_t*, MusicHandle**, FfmpegCoreSettings*); +typedef int(*_ffmpeg_core_open3)(const wchar_t*, MusicHandle**, FfmpegCoreSettings*, const wchar_t*); +typedef int(*_ffmpeg_core_info_open)(const wchar_t*, MusicInfoHandle**); +typedef int(*_ffmpeg_core_play)(MusicHandle*); +typedef int(*_ffmpeg_core_pause)(MusicHandle*); +typedef int(*_ffmpeg_core_seek)(MusicHandle*, int64_t); +typedef int(*_ffmpeg_core_set_volume)(MusicHandle*, int); +typedef int(*_ffmpeg_core_set_speed)(MusicHandle*, float); +typedef int(*_ffmpeg_core_set_equalizer_channel)(MusicHandle*, int, int); +typedef int(*_ffmpeg_core_get_error)(MusicHandle*); +typedef wchar_t*(*_ffmpeg_core_get_err_msg)(int); +typedef const wchar_t*(*_ffmpeg_core_get_err_msg2)(int); +typedef int64_t(*_ffmpeg_core_get_cur_position)(MusicHandle*); +typedef int(*_ffmpeg_core_song_is_over)(MusicHandle*); +typedef int64_t(*_ffmpeg_core_get_song_length)(MusicHandle*); +typedef int64_t(*_ffmpeg_core_info_get_song_length)(MusicInfoHandle*); +typedef int(*_ffmpeg_core_get_channels)(MusicHandle*); +typedef int(*_ffmpeg_core_info_get_channels)(MusicInfoHandle*); +typedef int(*_ffmpeg_core_get_freq)(MusicHandle*); +typedef int(*_ffmpeg_core_info_get_freq)(MusicInfoHandle*); +typedef int(*_ffmpeg_core_is_playing)(MusicHandle*); +typedef int(*_ffmpeg_core_get_bits)(MusicHandle*); +typedef int(*_ffmpeg_core_info_get_bits)(MusicInfoHandle*); +typedef int64_t(*_ffmpeg_core_get_bitrate)(MusicHandle*); +typedef int64_t(*_ffmpeg_core_info_get_bitrate)(MusicInfoHandle*); +typedef wchar_t*(*_ffmpeg_core_get_metadata)(MusicHandle*, const char* key); +typedef wchar_t*(*_ffmpeg_core_info_get_metadata)(MusicInfoHandle*, const char* key); +typedef int(*_ffmpeg_core_get_fft_data)(MusicHandle*, float*, int); +typedef FfmpegCoreSettings*(*_ffmpeg_core_init_settings)(); +typedef int(*_ffmpeg_core_settings_set_volume)(FfmpegCoreSettings*, int volume); +typedef int(*_ffmpeg_core_settings_set_speed)(FfmpegCoreSettings*, float); +typedef int(*_ffmpeg_core_settings_set_cache_length)(FfmpegCoreSettings*, int); +typedef int(*_ffmpeg_core_settings_set_max_retry_count)(FfmpegCoreSettings*, int); +typedef int(*_ffmpeg_core_settings_set_url_retry_interval)(FfmpegCoreSettings*, int); +typedef int(*_ffmpeg_core_settings_set_equalizer_channel)(FfmpegCoreSettings*, int, int); +typedef DeviceNameList*(*_ffmpeg_core_get_audio_devices)(); + +class CFfmpegCore : public IPlayerCore, public CDllLib { +public: + CFfmpegCore(); + ~CFfmpegCore(); + virtual void InitCore() override; + virtual void UnInitCore() override; + virtual unsigned int GetHandle() override; + virtual std::wstring GetAudioType() override; + virtual int GetChannels() override; + virtual int GetFReq() override; + virtual std::wstring GetSoundFontName() override; + virtual void Open(const wchar_t* file_path) override; + virtual void Close() override; + virtual void Play() override; + virtual void Pause() override; + virtual void Stop() override; + virtual void SetVolume(int volume) override; + virtual void SetSpeed(float speed) override; + virtual bool SongIsOver() override; + virtual int GetCurPosition() override; + virtual int GetSongLength() override; + virtual void SetCurPosition(int position) override; + virtual void GetAudioInfo(SongInfo& song_info, int flag = AF_LENGTH | AF_BITRATE | AF_TAG_INFO) override; + virtual void GetAudioInfo(const wchar_t* file_path, SongInfo& song_info, int flag = AF_LENGTH | AF_BITRATE | AF_TAG_INFO) override; + virtual bool IsMidi() override; + virtual bool IsMidiConnotPlay() override; + virtual MidiInfo GetMidiInfo() override; + virtual std::wstring GetMidiInnerLyric() override; + virtual bool MidiNoLyric() override; + virtual PlayingState GetPlayingState() override; + virtual void ApplyEqualizer(int channel, int gain) override; + virtual void SetReverb(int mix, int time) override; + virtual void ClearReverb() override; + virtual void GetFFTData(float fft_data[FFT_SAMPLE]) override; + virtual int GetErrorCode() override; + virtual std::wstring GetErrorInfo(int error_code) override; + virtual std::wstring GetErrorInfo() override; + virtual PlayerCoreType GetCoreType() override; + virtual int GetDeviceCount() override; + std::wstring GetTitle(MusicInfoHandle* h = nullptr); + std::wstring GetArtist(MusicInfoHandle* h = nullptr); + std::wstring GetAlbum(MusicInfoHandle* h = nullptr); + std::wstring GetComment(MusicInfoHandle* h = nullptr); + std::wstring GetGenre(MusicInfoHandle* h = nullptr); + std::wstring GetDate(MusicInfoHandle* h = nullptr); + unsigned short GetYear(MusicInfoHandle* h = nullptr); + std::wstring GetTrack(MusicInfoHandle* h = nullptr); + int GetTrackNum(MusicInfoHandle* h = nullptr); + void UpdateSettings(); + void SetCacheLength(int cache_length = 15); + void SetMaxRetryCount(int max_retry_count = 3); + void SetUrlRetryInterval(int url_retry_interval = 5); + std::list GetAudioDevices(); +private: + std::wstring GetMetadata(std::string key, MusicInfoHandle* h = nullptr); + virtual bool GetFunction() override; + static void LogCallback(void*, int, const char*, va_list); + _free_music_handle free_music_handle = nullptr; + _free_music_info_handle free_music_info_handle = nullptr; + _free_ffmpeg_core_settings free_ffmpeg_core_settings = nullptr; + _free_device_name_list free_device_name_list = nullptr; + _ffmpeg_core_free ffmpeg_core_free = nullptr; + _ffmpeg_core_malloc ffmpeg_core_malloc = nullptr; + _ffmpeg_core_realloc ffmpeg_core_realloc = nullptr; + _ffmpeg_core_log_format_line ffmpeg_core_log_format_line = nullptr; + _ffmpeg_core_log_set_callback ffmpeg_core_log_set_callback = nullptr; + _ffmpeg_core_log_set_flags ffmpeg_core_log_set_flags = nullptr; + _ffmpeg_core_version_str ffmpeg_core_version_str = nullptr; + _ffmpeg_core_version ffmpeg_core_version = nullptr; + _ffmpeg_core_dump_library_version ffmpeg_core_dump_library_version = nullptr; + _ffmpeg_core_dump_ffmpeg_configuration ffmpeg_core_dump_ffmpeg_configuration = nullptr; + _ffmpeg_core_open ffmpeg_core_open = nullptr; + _ffmpeg_core_open2 ffmpeg_core_open2 = nullptr; + _ffmpeg_core_open3 ffmpeg_core_open3 = nullptr; + _ffmpeg_core_info_open ffmpeg_core_info_open = nullptr; + _ffmpeg_core_play ffmpeg_core_play = nullptr; + _ffmpeg_core_pause ffmpeg_core_pause = nullptr; + _ffmpeg_core_seek ffmpeg_core_seek = nullptr; + _ffmpeg_core_set_volume ffmpeg_core_set_volume = nullptr; + _ffmpeg_core_set_speed ffmpeg_core_set_speed = nullptr; + _ffmpeg_core_set_equalizer_channel ffmpeg_core_set_equalizer_channel = nullptr; + _ffmpeg_core_get_error ffmpeg_core_get_error = nullptr; + _ffmpeg_core_get_err_msg ffmpeg_core_get_err_msg = nullptr; + _ffmpeg_core_get_err_msg2 ffmpeg_core_get_err_msg2 = nullptr; + _ffmpeg_core_get_cur_position ffmpeg_core_get_cur_position = nullptr; + _ffmpeg_core_song_is_over ffmpeg_core_song_is_over = nullptr; + _ffmpeg_core_get_song_length ffmpeg_core_get_song_length = nullptr; + _ffmpeg_core_info_get_song_length ffmpeg_core_info_get_song_length = nullptr; + _ffmpeg_core_get_channels ffmpeg_core_get_channels = nullptr; + _ffmpeg_core_info_get_channels ffmpeg_core_info_get_channels = nullptr; + _ffmpeg_core_get_freq ffmpeg_core_get_freq = nullptr; + _ffmpeg_core_info_get_freq ffmpeg_core_info_get_freq = nullptr; + _ffmpeg_core_is_playing ffmpeg_core_is_playing = nullptr; + _ffmpeg_core_get_bits ffmpeg_core_get_bits = nullptr; + _ffmpeg_core_info_get_bits ffmpeg_core_info_get_bits = nullptr; + _ffmpeg_core_get_bitrate ffmpeg_core_get_bitrate = nullptr; + _ffmpeg_core_info_get_bitrate ffmpeg_core_info_get_bitrate = nullptr; + _ffmpeg_core_get_metadata ffmpeg_core_get_metadata = nullptr; + _ffmpeg_core_info_get_metadata ffmpeg_core_info_get_metadata = nullptr; + _ffmpeg_core_get_fft_data ffmpeg_core_get_fft_data = nullptr; + _ffmpeg_core_init_settings ffmpeg_core_init_settings = nullptr; + _ffmpeg_core_settings_set_volume ffmpeg_core_settings_set_volume = nullptr; + _ffmpeg_core_settings_set_speed ffmpeg_core_settings_set_speed = nullptr; + _ffmpeg_core_settings_set_cache_length ffmpeg_core_settings_set_cache_length = nullptr; + _ffmpeg_core_settings_set_max_retry_count ffmpeg_core_settings_set_max_retry_count = nullptr; + _ffmpeg_core_settings_set_url_retry_interval ffmpeg_core_settings_set_url_retry_interval = nullptr; + _ffmpeg_core_settings_set_equalizer_channel ffmpeg_core_settings_set_equalizer_channel = nullptr; + _ffmpeg_core_get_audio_devices ffmpeg_core_get_audio_devices = nullptr; + int GetEqChannelFreq(int channel); + MusicHandle* handle; + FfmpegCoreSettings* settings = nullptr; + std::wstring recent_file; + int err; +}; diff --git a/MusicPlayer2/IPlayerCore.h b/MusicPlayer2/IPlayerCore.h index 19c576e52..76121ece0 100644 --- a/MusicPlayer2/IPlayerCore.h +++ b/MusicPlayer2/IPlayerCore.h @@ -23,7 +23,8 @@ enum AudioInfoFlag enum PlayerCoreType { PT_BASS, - PT_MCI + PT_MCI, + PT_FFMPEG, }; enum PlayingState //正在播放标志 diff --git a/MusicPlayer2/MusicPlayer2.rc b/MusicPlayer2/MusicPlayer2.rc index 0a40af2d5..354014047 100644 Binary files a/MusicPlayer2/MusicPlayer2.rc and b/MusicPlayer2/MusicPlayer2.rc differ diff --git a/MusicPlayer2/MusicPlayer2.vcxproj b/MusicPlayer2/MusicPlayer2.vcxproj index 8933a2119..2fc690fc3 100644 --- a/MusicPlayer2/MusicPlayer2.vcxproj +++ b/MusicPlayer2/MusicPlayer2.vcxproj @@ -245,6 +245,7 @@ + @@ -397,6 +398,7 @@ + diff --git a/MusicPlayer2/MusicPlayer2.vcxproj.filters b/MusicPlayer2/MusicPlayer2.vcxproj.filters index f220fc471..a267dd37d 100644 --- a/MusicPlayer2/MusicPlayer2.vcxproj.filters +++ b/MusicPlayer2/MusicPlayer2.vcxproj.filters @@ -363,6 +363,9 @@ {bfba0398-39b7-4eb5-97b5-6b1fa8e31ad7} + + {1374b4aa-def4-4b40-8f36-1caf49de536a} + @@ -824,6 +827,9 @@ 公共的类\tinyxml2 + + 功能逻辑类\PlayerCore\FFMPEG + @@ -1249,6 +1255,9 @@ 公共的类\tinyxml2 + + 功能逻辑类\PlayerCore\FFMPEG + diff --git a/MusicPlayer2/MusicPlayerCmdHelper.cpp b/MusicPlayer2/MusicPlayerCmdHelper.cpp index f0daad9ce..dba8775c0 100644 --- a/MusicPlayer2/MusicPlayerCmdHelper.cpp +++ b/MusicPlayer2/MusicPlayerCmdHelper.cpp @@ -59,6 +59,9 @@ void CMusicPlayerCmdHelper::FormatConvert(const std::vector& songs) { GetOwner()->MessageBox(CCommon::LoadText(IDS_MCI_NO_THIS_FUNCTION_WARNING), NULL, MB_ICONWARNING | MB_OK); return; + } else if (CPlayer::GetInstance().IsFfmpegCore()) { + GetOwner()->MessageBox(CCommon::LoadText(IDS_FFMPEG_NO_THIS_FUNCTION), NULL, MB_ICONWARNING | MB_OK); + return; } pPlayerDlg->m_pFormatConvertDlg = new CFormatConvertDlg(songs, GetOwner()); diff --git a/MusicPlayer2/MusicPlayerDlg.cpp b/MusicPlayer2/MusicPlayerDlg.cpp index f1b615ca7..16795ec64 100644 --- a/MusicPlayer2/MusicPlayerDlg.cpp +++ b/MusicPlayer2/MusicPlayerDlg.cpp @@ -34,6 +34,7 @@ #include "TagLibHelper.h" #include "RecentFolderAndPlaylist.h" #include "UserUi.h" +#include "FfmpegCore.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -445,6 +446,10 @@ void CMusicPlayerDlg::SaveConfig() ini.WriteInt(L"config", L"fade_time", theApp.m_play_setting_data.fade_time); ini.WriteString(L"config", L"output_device", theApp.m_play_setting_data.output_device); ini.WriteBool(L"config", L"use_mci", theApp.m_play_setting_data.use_mci); + ini.WriteBool(L"config", L"use_ffmpeg", theApp.m_play_setting_data.use_ffmpeg); + ini.WriteInt(L"config", L"ffmpeg_core_cache_length", theApp.m_play_setting_data.ffmpeg_core_cache_length); + ini.WriteInt(L"config", L"ffmpeg_core_max_retry_count", theApp.m_play_setting_data.ffmpeg_core_max_retry_count); + ini.WriteInt(L"config", L"ffmpeg_core_url_retry_interval", theApp.m_play_setting_data.ffmpeg_core_url_retry_interval); ini.WriteInt(L"config", L"UI_selected", GetUiSelected()); //保存热键设置 @@ -619,6 +624,10 @@ void CMusicPlayerDlg::LoadConfig() theApp.m_play_setting_data.fade_time = 2000; theApp.m_play_setting_data.output_device = ini.GetString(L"config", L"output_device", L""); theApp.m_play_setting_data.use_mci = ini.GetBool(L"config", L"use_mci", false); + theApp.m_play_setting_data.use_ffmpeg = ini.GetBool(L"config", L"use_ffmpeg", false); + theApp.m_play_setting_data.ffmpeg_core_cache_length = ini.GetInt(L"config", L"ffmpeg_core_cache_length", 15); + theApp.m_play_setting_data.ffmpeg_core_max_retry_count = ini.GetInt(L"config", L"ffmpeg_core_max_retry_count", 3); + theApp.m_play_setting_data.ffmpeg_core_url_retry_interval = ini.GetInt(L"config", L"ffmpeg_core_url_retry_interval", 5); int ui_selected = ini.GetInt(L"config", L"UI_selected", 1); SelectUi(ui_selected); @@ -1075,7 +1084,7 @@ void CMusicPlayerDlg::ApplySettings(const COptionsDlg& optionDlg) || theApp.m_app_setting_data.album_cover_as_background != optionDlg.m_tab2_dlg.m_data.album_cover_as_background || theApp.m_app_setting_data.enable_background != optionDlg.m_tab2_dlg.m_data.enable_background }; bool output_device_changed{ theApp.m_play_setting_data.device_selected != optionDlg.m_tab4_dlg.m_data.device_selected }; - bool player_core_changed{ theApp.m_play_setting_data.use_mci != optionDlg.m_tab4_dlg.m_data.use_mci }; + bool player_core_changed{ theApp.m_play_setting_data.use_mci != optionDlg.m_tab4_dlg.m_data.use_mci || theApp.m_play_setting_data.use_ffmpeg != optionDlg.m_tab4_dlg.m_data.use_ffmpeg }; bool media_lib_setting_changed{ theApp.m_media_lib_setting_data.hide_only_one_classification != optionDlg.m_media_lib_dlg.m_data.hide_only_one_classification || theApp.m_media_lib_setting_data.media_folders != optionDlg.m_media_lib_dlg.m_data.media_folders || theApp.m_media_lib_setting_data.recent_played_range != optionDlg.m_media_lib_dlg.m_data.recent_played_range @@ -1201,6 +1210,10 @@ void CMusicPlayerDlg::ApplySettings(const COptionsDlg& optionDlg) SaveConfig(); //将设置写入到ini文件 theApp.SaveConfig(); CPlayer::GetInstance().SaveConfig(); + if (CPlayer::GetInstance().IsFfmpegCore()) { + CFfmpegCore* core = (CFfmpegCore*)CPlayer::GetInstance().GetPlayerCore(); + core->UpdateSettings(); + } DrawInfo(true); } @@ -3826,6 +3839,8 @@ afx_msg LRESULT CMusicPlayerDlg::OnSetTitle(WPARAM wParam, LPARAM lParam) if (CPlayer::GetInstance().IsMciCore()) title_suffix += _T(" (MCI)"); + else if (CPlayer::GetInstance().IsFfmpegCore()) + title_suffix += _T(" (FFMPEG)"); #ifdef _DEBUG title_suffix += _T(' '); diff --git a/MusicPlayer2/OptionsDlg.cpp b/MusicPlayer2/OptionsDlg.cpp index d993adbc9..737b703e8 100644 --- a/MusicPlayer2/OptionsDlg.cpp +++ b/MusicPlayer2/OptionsDlg.cpp @@ -104,6 +104,7 @@ void COptionsDlg::OnOK() m_tab1_dlg.OnOK(); m_tab2_dlg.OnOK(); m_tab3_dlg.OnOK(); + m_tab4_dlg.OnOK(); m_media_lib_dlg.OnOK(); CBaseDialog::OnOK(); diff --git a/MusicPlayer2/PlaySettingsDlg.cpp b/MusicPlayer2/PlaySettingsDlg.cpp index f65e66840..2a9e86c77 100644 --- a/MusicPlayer2/PlaySettingsDlg.cpp +++ b/MusicPlayer2/PlaySettingsDlg.cpp @@ -34,6 +34,10 @@ void CPlaySettingsDlg::DoDataExchange(CDataExchange* pDX) DDX_Control(pDX, IDC_CONTINUE_WHEN_SWITCH_PLAYLIST_CHECK, m_continue_when_switch_playlist_check); DDX_Control(pDX, IDC_BASS_RADIO, m_bass_radio); DDX_Control(pDX, IDC_MCI_RADIO, m_mci_radio); + DDX_Control(pDX, IDC_FFMPEG_RADIO, m_ffmpeg_radio); + DDX_Control(pDX, IDC_FFMPEG_CACHE_LENGTH, m_ffmpeg_cache_length); + DDX_Control(pDX, IDC_FFMPEG_MAX_RETRY_COUNT, m_ffmpeg_max_retry_count); + DDX_Control(pDX, IDC_FFMPEG_URL_RETRY_INTERVAL, m_ffmpeg_url_retry_interval); } void CPlaySettingsDlg::ShowDeviceInfo() @@ -91,9 +95,13 @@ void CPlaySettingsDlg::ShowDeviceInfo() void CPlaySettingsDlg::EnableControl() { bool enable = !CPlayer::GetInstance().IsMciCore(); + bool ffmpeg_enable = CPlayer::GetInstance().IsFfmpegCore(); m_sound_fade_chk.EnableWindow(enable); m_device_info_list.EnableWindow(enable); m_output_device_combo.EnableWindow(enable); + m_ffmpeg_cache_length.EnableWindow(ffmpeg_enable); + m_ffmpeg_max_retry_count.EnableWindow(ffmpeg_enable); + m_ffmpeg_url_retry_interval.EnableWindow(ffmpeg_enable); } @@ -107,6 +115,7 @@ BEGIN_MESSAGE_MAP(CPlaySettingsDlg, CTabDlg) ON_BN_CLICKED(IDC_CONTINUE_WHEN_SWITCH_PLAYLIST_CHECK, &CPlaySettingsDlg::OnBnClickedContinueWhenSwitchPlaylistCheck) ON_BN_CLICKED(IDC_BASS_RADIO, &CPlaySettingsDlg::OnBnClickedBassRadio) ON_BN_CLICKED(IDC_MCI_RADIO, &CPlaySettingsDlg::OnBnClickedMciRadio) + ON_BN_CLICKED(IDC_FFMPEG_RADIO, &CPlaySettingsDlg::OnBnClickedFfmpegRadio) END_MESSAGE_MAP() @@ -122,6 +131,7 @@ BOOL CPlaySettingsDlg::OnInitDialog() m_toolTip.Create(this); m_toolTip.SetMaxTipWidth(theApp.DPI(300)); m_toolTip.AddTool(GetDlgItem(IDC_MCI_RADIO), CCommon::LoadText(IDS_MCI_KERNAL_TIP)); + m_toolTip.AddTool(GetDlgItem(IDC_FFMPEG_RADIO), CCommon::LoadText(IDS_FFMPEG_CORE)); m_toolTip.SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); //初始化各控件的状态 @@ -140,8 +150,22 @@ BOOL CPlaySettingsDlg::OnInitDialog() m_show_play_state_icon_chk.EnableWindow(FALSE); } + bool enable_ffmpeg = false; + if (CPlayer::GetInstance().IsFfmpegCore()) { + enable_ffmpeg = true; + } else { + auto h = LoadLibraryW(L"ffmpeg_core.dll"); + if (h) { + enable_ffmpeg = true; + FreeLibrary(h); + } + } + m_ffmpeg_radio.EnableWindow(enable_ffmpeg); + if (m_data.use_mci) m_mci_radio.SetCheck(TRUE); + else if (m_data.use_ffmpeg) + m_ffmpeg_radio.SetCheck(TRUE); else m_bass_radio.SetCheck(TRUE); @@ -168,8 +192,18 @@ BOOL CPlaySettingsDlg::OnInitDialog() EnableControl(); + m_ffmpeg_cache_length.SetRange(1, 60); + m_ffmpeg_cache_length.SetValue(theApp.m_play_setting_data.ffmpeg_core_cache_length); + m_ffmpeg_max_retry_count.SetRange(-1, SHORT_MAX); + m_ffmpeg_max_retry_count.SetValue(theApp.m_play_setting_data.ffmpeg_core_max_retry_count); + m_ffmpeg_url_retry_interval.SetRange(1, 120); + m_ffmpeg_url_retry_interval.SetValue(theApp.m_play_setting_data.ffmpeg_core_url_retry_interval); + //设置控件不响应鼠标滚轮消息 m_output_device_combo.SetMouseWheelEnable(false); + m_ffmpeg_cache_length.SetMouseWheelEnable(false); + m_ffmpeg_max_retry_count.SetMouseWheelEnable(false); + m_ffmpeg_url_retry_interval.SetMouseWheelEnable(false); return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE @@ -230,6 +264,7 @@ void CPlaySettingsDlg::OnBnClickedBassRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.use_mci = false; + m_data.use_ffmpeg = false; } @@ -237,6 +272,13 @@ void CPlaySettingsDlg::OnBnClickedMciRadio() { // TODO: 在此添加控件通知处理程序代码 m_data.use_mci = true; + m_data.use_ffmpeg = false; +} + + +void CPlaySettingsDlg::OnBnClickedFfmpegRadio() { + m_data.use_mci = false; + m_data.use_ffmpeg = true; } @@ -248,3 +290,9 @@ BOOL CPlaySettingsDlg::PreTranslateMessage(MSG* pMsg) return CTabDlg::PreTranslateMessage(pMsg); } + +void CPlaySettingsDlg::OnOK() { + m_data.ffmpeg_core_cache_length = m_ffmpeg_cache_length.GetValue(); + m_data.ffmpeg_core_max_retry_count = m_ffmpeg_max_retry_count.GetValue(); + m_data.ffmpeg_core_url_retry_interval = m_ffmpeg_url_retry_interval.GetValue(); +} diff --git a/MusicPlayer2/PlaySettingsDlg.h b/MusicPlayer2/PlaySettingsDlg.h index 9614da69d..8644ff451 100644 --- a/MusicPlayer2/PlaySettingsDlg.h +++ b/MusicPlayer2/PlaySettingsDlg.h @@ -2,6 +2,7 @@ #include "ListCtrlEx.h" #include "TabDlg.h" #include "MyComboBox.h" +#include "SpinEdit.h" // CPlaySettingsDlg 对话框 @@ -31,6 +32,10 @@ class CPlaySettingsDlg : public CTabDlg CListCtrlEx m_device_info_list; CButton m_bass_radio; CButton m_mci_radio; + CButton m_ffmpeg_radio; + CSpinEdit m_ffmpeg_cache_length; + CSpinEdit m_ffmpeg_max_retry_count; + CSpinEdit m_ffmpeg_url_retry_interval; CToolTipCtrl m_toolTip; protected: @@ -41,6 +46,7 @@ class CPlaySettingsDlg : public CTabDlg DECLARE_MESSAGE_MAP() public: + virtual void OnOK(); virtual BOOL OnInitDialog(); afx_msg void OnBnClickedStopWhenError(); afx_msg void OnBnClickedShowTaskbarProgress(); @@ -51,5 +57,6 @@ class CPlaySettingsDlg : public CTabDlg afx_msg void OnBnClickedContinueWhenSwitchPlaylistCheck(); afx_msg void OnBnClickedBassRadio(); afx_msg void OnBnClickedMciRadio(); + afx_msg void OnBnClickedFfmpegRadio(); virtual BOOL PreTranslateMessage(MSG* pMsg); }; diff --git a/MusicPlayer2/Player.cpp b/MusicPlayer2/Player.cpp index 6dd2133b0..08e156dfc 100644 --- a/MusicPlayer2/Player.cpp +++ b/MusicPlayer2/Player.cpp @@ -5,6 +5,7 @@ #include "Playlist.h" #include "BassCore.h" #include "MciCore.h" +#include "FfmpegCore.h" #include "MusicPlayerCmdHelper.h" #include "SongDataManager.h" #include "SongInfoHelper.h" @@ -32,6 +33,8 @@ void CPlayer::IniPlayerCore() { if (theApp.m_play_setting_data.use_mci) m_pCore = new CMciCore(); + else if (theApp.m_play_setting_data.use_ffmpeg) + m_pCore = new CFfmpegCore(); else m_pCore = new CBassCore(); @@ -685,6 +688,12 @@ void CPlayer::CalculateSpectralData() CSpectralDataHelper::SpectralDataMapOld(m_fft, m_spectral_data); else m_spectrum_data_helper.SpectralDataMap(m_fft, m_spectral_data); + } else if (m_pCore->GetCoreType() == PT_FFMPEG) { + m_pCore->GetFFTData(m_fft); + if (theApp.m_app_setting_data.use_old_style_specturm) + CSpectralDataHelper::SpectralDataMapOld(m_fft, m_spectral_data); + else + m_spectrum_data_helper.SpectralDataMap(m_fft, m_spectral_data); } else { @@ -2730,7 +2739,11 @@ wstring CPlayer::GetPlaylistPath() const bool CPlayer::IsMciCore() const { - return m_pCore->GetCoreType() == PT_MCI; + return m_pCore ? m_pCore->GetCoreType() == PT_MCI : false; +} + +bool CPlayer::IsFfmpegCore() const { + return m_pCore->GetCoreType() == PT_FFMPEG; } void CPlayer::SetContainSubFolder(bool contain_sub_folder) diff --git a/MusicPlayer2/Player.h b/MusicPlayer2/Player.h index 6906d8e06..0871d9708 100644 --- a/MusicPlayer2/Player.h +++ b/MusicPlayer2/Player.h @@ -363,6 +363,7 @@ class CPlayer wstring GetPlaylistPath() const; IPlayerCore* GetPlayerCore() { return m_pCore; } bool IsMciCore() const; + bool IsFfmpegCore() const; bool IsFileOpened() const { return m_file_opend; } bool IsContainSubFolder() const { return m_contain_sub_folder; } void SetContainSubFolder(bool contain_sub_folder); diff --git a/MusicPlayer2/ReverbDlg.cpp b/MusicPlayer2/ReverbDlg.cpp index c61ce8841..c77a981a4 100644 --- a/MusicPlayer2/ReverbDlg.cpp +++ b/MusicPlayer2/ReverbDlg.cpp @@ -75,8 +75,13 @@ BOOL CReverbDlg::OnInitDialog() //初始化混响开关复选框 m_enable_reverb_chk.SetCheck(CPlayer::GetInstance().GetReverbEnable()); - //初始化控件的启用状态 - EnableControls(CPlayer::GetInstance().GetReverbEnable()); + if (CPlayer::GetInstance().IsFfmpegCore() || CPlayer::GetInstance().IsMciCore()) { + EnableControls(false); + m_enable_reverb_chk.EnableWindow(FALSE); + } else { + //初始化控件的启用状态 + EnableControls(CPlayer::GetInstance().GetReverbEnable()); + } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE diff --git a/MusicPlayer2/resource.h b/MusicPlayer2/resource.h index 22348c868..54a7bae52 100644 --- a/MusicPlayer2/resource.h +++ b/MusicPlayer2/resource.h @@ -704,6 +704,10 @@ #define IDI_ICON23 552 #define IDI_ADD 552 #define IDS_ITALIC 552 +#define IDS_SDL_DEFAULT_DEVICE 553 +#define IDS_FFMPEG_CORE 554 +#define IDS_FFMPEG_INIT_FAILED 555 +#define IDS_FFMPEG_NO_THIS_FUNCTION 556 #define IDC_STATIC_PATH 1001 #define IDC_LIST1 1002 #define IDC_PATH_LIST 1002 @@ -1091,6 +1095,10 @@ #define IDC_ORIGINAL_STATIC 1187 #define IDC_SAVE_TO_APPDATA_RADIO 1188 #define IDC_SAVE_TO_PROGRAM_DIR_RADIO 1189 +#define IDC_FFMPEG_RADIO 1190 +#define IDC_FFMPEG_CACHE_LENGTH 1191 +#define IDC_FFMPEG_MAX_RETRY_COUNT 1192 +#define IDC_FFMPEG_URL_RETRY_INTERVAL 1193 #define ID_32771 32771 #define ID_32772 32772 #define ID_OPEN 32773 @@ -1520,7 +1528,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 552 +#define _APS_NEXT_RESOURCE_VALUE 555 #define _APS_NEXT_COMMAND_VALUE 33387 #define _APS_NEXT_CONTROL_VALUE 1190 #define _APS_NEXT_SYMED_VALUE 101