From f6e368f1c13c1a050f215b9350a8785ed32cd98d Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 20 Feb 2022 21:07:49 +0800 Subject: [PATCH] add ffmpeg_core.py --- ffmpeg_core.py | 294 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 ffmpeg_core.py diff --git a/ffmpeg_core.py b/ffmpeg_core.py new file mode 100644 index 0000000..dc0d861 --- /dev/null +++ b/ffmpeg_core.py @@ -0,0 +1,294 @@ +from ctypes import ( + CDLL, + POINTER, + c_char_p, + c_float, + c_int, + c_int32, + c_int64, + c_size_t, + c_void_p, + c_wchar_p, + pointer, +) +from ctypes.util import find_library + + +dll = find_library('ffmpeg_core') or find_library('_ffmpeg_core') +dll = CDLL(dll) +free_music_handle = dll.free_music_handle +free_music_handle.restype = None +free_music_handle.argtypes = [c_void_p] +free_music_info_handle = dll.free_music_info_handle +free_music_info_handle.restype = None +free_music_info_handle.argtypes = [c_void_p] +free_ffmpeg_core_settings = dll.free_ffmpeg_core_settings +free_ffmpeg_core_settings.restype = None +free_ffmpeg_core_settings.argtypes = [c_void_p] +free_device_name_list = dll.free_device_name_list +free_device_name_list.restype = None +free_device_name_list.argtypes = [c_void_p] +ffmpeg_core_free = dll.ffmpeg_core_free +ffmpeg_core_free.restype = None +ffmpeg_core_free.argtypes = [c_void_p] +ffmpeg_core_malloc = dll.ffmpeg_core_malloc +ffmpeg_core_malloc.restype = c_void_p +ffmpeg_core_malloc.argtypes = [c_size_t] +ffmpeg_core_realloc = dll.ffmpeg_core_realloc +ffmpeg_core_realloc.restype = c_void_p +ffmpeg_core_realloc.argtypes = [c_void_p, c_size_t] +ffmpeg_core_log_format_line = dll.ffmpeg_core_log_format_line +ffmpeg_core_log_format_line.restype = c_int +ffmpeg_core_log_set_callback = dll.ffmpeg_core_log_set_callback +ffmpeg_core_log_set_callback.restype = None +ffmpeg_core_log_set_flags = dll.ffmpeg_core_log_set_flags +ffmpeg_core_log_set_flags.restype = None +ffmpeg_core_log_set_flags.argtypes = [c_int] +ffmpeg_core_version_str = dll.ffmpeg_core_version_str +ffmpeg_core_version_str.restype = c_char_p +ffmpeg_core_version_str.argtypes = [] +ffmpeg_core_version = dll.ffmpeg_core_version +ffmpeg_core_version.restype = c_int32 +ffmpeg_core_version.argtypes = [] +ffmpeg_core_dump_library_version = dll.ffmpeg_core_dump_library_version +ffmpeg_core_dump_library_version.restype = None +ffmpeg_core_dump_library_version.argtypes = [c_int, c_int] +ffmpeg_core_dump_ffmpeg_configuration = dll.ffmpeg_core_dump_ffmpeg_configuration # noqa: E501 +ffmpeg_core_dump_ffmpeg_configuration.restype = None +ffmpeg_core_dump_ffmpeg_configuration.argtypes = [c_int, c_int] +ffmpeg_core_open = dll.ffmpeg_core_open +ffmpeg_core_open.restype = c_int +ffmpeg_core_open.argtypes = [c_wchar_p, POINTER(c_void_p)] +ffmpeg_core_open2 = dll.ffmpeg_core_open2 +ffmpeg_core_open2.restype = c_int +ffmpeg_core_open2.argtypes = [c_wchar_p, POINTER(c_void_p), c_void_p] +ffmpeg_core_open3 = dll.ffmpeg_core_open3 +ffmpeg_core_open3.restype = c_int +ffmpeg_core_open3.argtypes = [c_wchar_p, POINTER(c_void_p), c_void_p, c_wchar_p] # noqa: E501 +ffmpeg_core_info_open = dll.ffmpeg_core_info_open +ffmpeg_core_info_open.restype = c_int +ffmpeg_core_info_open.argtypes = [c_wchar_p, POINTER(c_void_p)] +ffmpeg_core_play = dll.ffmpeg_core_play +ffmpeg_core_play.restype = c_int +ffmpeg_core_play.argtypes = [c_void_p] +ffmpeg_core_pause = dll.ffmpeg_core_pause +ffmpeg_core_pause.restype = c_int +ffmpeg_core_pause.argtypes = [c_void_p] +ffmpeg_core_seek = dll.ffmpeg_core_seek +ffmpeg_core_seek.restype = c_int +ffmpeg_core_seek.argtypes = [c_void_p, c_int64] +ffmpeg_core_set_volume = dll.ffmpeg_core_set_volume +ffmpeg_core_set_volume.restype = c_int +ffmpeg_core_set_volume.argtypes = [c_void_p, c_int] +ffmpeg_core_set_speed = dll.ffmpeg_core_set_speed +ffmpeg_core_set_speed.restype = c_int +ffmpeg_core_set_speed.argtypes = [c_void_p, c_float] +ffmpeg_core_set_equalizer_channel = dll.ffmpeg_core_set_equalizer_channel +ffmpeg_core_set_equalizer_channel.restype = c_int +ffmpeg_core_set_equalizer_channel.argtypes = [c_void_p, c_int, c_int] +ffmpeg_core_get_error = dll.ffmpeg_core_get_error +ffmpeg_core_get_error.restype = c_int +ffmpeg_core_get_error.argtypes = [c_void_p] +ffmpeg_core_get_err_msg = dll.ffmpeg_core_get_err_msg +ffmpeg_core_get_err_msg.restype = c_void_p +ffmpeg_core_get_err_msg.argtypes = [c_int] +ffmpeg_core_get_err_msg2 = dll.ffmpeg_core_get_err_msg2 +ffmpeg_core_get_err_msg2.restype = c_wchar_p +ffmpeg_core_get_err_msg2.argtypes = [c_int] +ffmpeg_core_get_cur_position = dll.ffmpeg_core_get_cur_position +ffmpeg_core_get_cur_position.restype = c_int64 +ffmpeg_core_get_cur_position.argtypes = [c_void_p] +ffmpeg_core_song_is_over = dll.ffmpeg_core_song_is_over +ffmpeg_core_song_is_over.restype = c_int +ffmpeg_core_song_is_over.argtypes = [c_void_p] +ffmpeg_core_get_song_length = dll.ffmpeg_core_get_song_length +ffmpeg_core_get_song_length.restype = c_int64 +ffmpeg_core_get_song_length.argtypes = [c_void_p] +ffmpeg_core_info_get_song_length = dll.ffmpeg_core_info_get_song_length +ffmpeg_core_info_get_song_length.restype = c_int64 +ffmpeg_core_info_get_song_length.argtypes = [c_void_p] +ffmpeg_core_get_channels = dll.ffmpeg_core_get_channels +ffmpeg_core_get_channels.restype = c_int +ffmpeg_core_get_channels.argtypes = [c_void_p] +ffmpeg_core_info_get_channels = dll.ffmpeg_core_info_get_channels +ffmpeg_core_info_get_channels.restype = c_int +ffmpeg_core_info_get_channels.argtypes = [c_void_p] +ffmpeg_core_get_freq = dll.ffmpeg_core_get_freq +ffmpeg_core_get_freq.restype = c_int +ffmpeg_core_get_freq.argtypes = [c_void_p] +ffmpeg_core_info_get_freq = dll.ffmpeg_core_info_get_freq +ffmpeg_core_info_get_freq.restype = c_int +ffmpeg_core_info_get_freq.argtypes = [c_void_p] +ffmpeg_core_is_playing = dll.ffmpeg_core_is_playing +ffmpeg_core_is_playing.restype = c_int +ffmpeg_core_is_playing.argtypes = [c_void_p] +ffmpeg_core_get_bits = dll.ffmpeg_core_get_bits +ffmpeg_core_get_bits.restype = c_int +ffmpeg_core_get_bits.argtypes = [c_void_p] +ffmpeg_core_info_get_bits = dll.ffmpeg_core_info_get_bits +ffmpeg_core_info_get_bits.restype = c_int +ffmpeg_core_info_get_bits.argtypes = [c_void_p] +ffmpeg_core_get_bitrate = dll.ffmpeg_core_get_bitrate +ffmpeg_core_get_bitrate.restype = c_int +ffmpeg_core_get_bitrate.argtypes = [c_void_p] +ffmpeg_core_info_get_bitrate = dll.ffmpeg_core_info_get_bitrate +ffmpeg_core_info_get_bitrate.restype = c_int +ffmpeg_core_info_get_bitrate.argtypes = [c_void_p] +ffmpeg_core_get_metadata = dll.ffmpeg_core_get_metadata +ffmpeg_core_get_metadata.restype = c_void_p +ffmpeg_core_get_metadata.argtypes = [c_void_p, c_char_p] +ffmpeg_core_info_get_metadata = dll.ffmpeg_core_info_get_metadata +ffmpeg_core_info_get_metadata.restype = c_void_p +ffmpeg_core_info_get_metadata.argtypes = [c_void_p, c_char_p] + + +class FFMPEGCoreError(Exception): + def __init__(self, err: int) -> None: + self.err = err + t = ffmpeg_core_get_err_msg(err) + if t is None: + if err < 0: + self.msg = "OOM When getting error message" + else: + self.msg = ffmpeg_core_get_err_msg2(err) + else: + self.msg = c_wchar_p(t).value + ffmpeg_core_free(t) + Exception.__init__(self, f"{self.err} {self.msg}") + + +class FFMPEGCore: + def __init__(self, fn: str): + self._fn = fn + self._h = c_void_p() + self._opened = False + r = ffmpeg_core_open(fn, pointer(self._h)) + if r == 0: + self._opened = True + else: + raise FFMPEGCoreError(r) + self._volume = 100 + self._speed = 1.0 + + @property + def album(self): + return self['album'] + + @property + def artist(self): + return self['artist'] + + @property + def bits(self) -> int: + if self._opened: + return ffmpeg_core_get_bits(self._h) + + @property + def bitrate(self) -> int: + if self._opened: + return ffmpeg_core_get_bitrate(self._h) + + @property + def channels(self) -> int: + if self._opened: + return ffmpeg_core_get_channels(self._h) + + def close(self): + if self._opened: + free_music_handle(self._h) + self._opened = False + self._h = None + + @property + def freq(self) -> int: + if self._opened: + return ffmpeg_core_get_freq(self._h) + + @property + def is_over(self) -> bool: + if self._opened: + return True if ffmpeg_core_song_is_over(self._h) else False + + @property + def length(self) -> float: + if self._opened: + return ffmpeg_core_get_song_length(self._h) / 1E6 + + def pause(self): + if self._opened: + ffmpeg_core_pause(self._h) + + def play(self): + if self._opened: + ffmpeg_core_play(self._h) + + @property + def playing(self): + if self._opened: + return True if ffmpeg_core_is_playing(self._h) else False + + @property + def position(self) -> float: + if self._opened: + return ffmpeg_core_get_cur_position(self._h) / 1E6 + + @position.setter + def position(self, value: float): + return self.seek(value) + + def seek(self, pos: float): + pos = int(pos * 1E6) + if self._opened: + r = ffmpeg_core_seek(self._h, pos) + if r: + raise FFMPEGCoreError(r) + + @property + def speed(self) -> float: + return self._speed + + @speed.setter + def speed(self, v): + if not isinstance(v, (int, float)): + raise TypeError("speed must be int or float") + v = float(v) + r = ffmpeg_core_set_speed(self._h, v) + if r == 0: + self._speed = v + else: + raise FFMPEGCoreError(r) + + @property + def title(self): + return self['title'] + + @property + def volume(self) -> int: + return self._volume + + @volume.setter + def volume(self, v): + if not isinstance(v, int): + raise TypeError("volume must be an integer") + r = ffmpeg_core_set_volume(self._h, v) + if not r: + self._volume = v + else: + raise FFMPEGCoreError(r) + + def __del__(self): + if self._opened: + free_music_handle(self._h) + self._h = None + + def __getitem__(self, k): + if not isinstance(k, (str, bytes)): + raise TypeError("key must be str or bytes") + if isinstance(k, str): + k = k.encode() + if self._opened: + h = ffmpeg_core_get_metadata(self._h, k) + if h: + t = c_wchar_p(h).value + ffmpeg_core_free(h) + return t