diff options
Diffstat (limited to '')
-rwxr-xr-x | TOOLS/dylib_unhell.py (renamed from TOOLS/dylib-unhell.py) | 101 | ||||
-rwxr-xr-x | TOOLS/gen-interface-changes.py | 83 | ||||
-rw-r--r-- | TOOLS/lua/autocrop.lua | 2 | ||||
-rw-r--r-- | TOOLS/lua/autodeint.lua | 2 | ||||
-rw-r--r-- | TOOLS/lua/autoload.lua | 30 | ||||
-rw-r--r-- | TOOLS/lua/skip-logo.lua | 2 | ||||
-rwxr-xr-x | TOOLS/matroska.py | 3 | ||||
-rwxr-xr-x | TOOLS/osxbundle.py | 43 | ||||
-rw-r--r-- | TOOLS/osxbundle/mpv.app/Contents/Info.plist | 2 |
9 files changed, 233 insertions, 35 deletions
diff --git a/TOOLS/dylib-unhell.py b/TOOLS/dylib_unhell.py index c41d200..c885969 100755 --- a/TOOLS/dylib-unhell.py +++ b/TOOLS/dylib_unhell.py @@ -5,6 +5,7 @@ import os import sys import shutil import subprocess +import json from functools import partial sys_re = re.compile("^/System") @@ -41,7 +42,7 @@ def otool(objfile, rapths): def get_rapths(objfile): rpaths = [] command = "otool -l '%s' | grep -A2 LC_RPATH | grep path" % objfile - pathRe = re.compile("^\s*path (.*) \(offset \d*\)$") + pathRe = re.compile(r"^\s*path (.*) \(offset \d*\)$") try: result = subprocess.check_output(command, shell = True, universal_newlines=True) @@ -49,14 +50,19 @@ def get_rapths(objfile): return rpaths for line in result.splitlines(): - rpaths.append(pathRe.search(line).group(1).strip()) + line_clean = pathRe.search(line).group(1).strip() + # resolve @loader_path + if line_clean.startswith('@loader_path/'): + line_clean = line_clean[len('@loader_path/'):] + line_clean = os.path.normpath(os.path.join(os.path.dirname(objfile), line_clean)) + rpaths.append(line_clean) return rpaths def get_rpaths_dev_tools(binary): - command = "otool -l '%s' | grep -A2 LC_RPATH | grep path | grep \"Xcode\|CommandLineTools\"" % binary + command = "otool -l '%s' | grep -A2 LC_RPATH | grep path | grep \"Xcode\\|CommandLineTools\"" % binary result = subprocess.check_output(command, shell = True, universal_newlines=True) - pathRe = re.compile("^\s*path (.*) \(offset \d*\)$") + pathRe = re.compile(r"^\s*path (.*) \(offset \d*\)$") output = [] for line in result.splitlines(): @@ -82,6 +88,23 @@ def resolve_lib_path(objfile, lib, rapths): raise Exception('Could not resolve library: ' + lib) +def check_vulkan_max_version(version): + try: + result = subprocess.check_output("pkg-config vulkan --max-version=" + version, shell = True) + return True + except: + return False + +def get_homebrew_prefix(): + # set default to standard ARM path, intel path is already in the vulkan loader search array + result = "/opt/homebrew" + try: + result = subprocess.check_output("brew --prefix", universal_newlines=True, shell=True, stderr=subprocess.DEVNULL).strip() + except: + pass + + return result + def install_name_tool_change(old, new, objfile): subprocess.call(["install_name_tool", "-change", old, new, objfile], stderr=subprocess.DEVNULL) @@ -109,6 +132,9 @@ def libraries(objfile, result = dict(), result_relative = set(), rapths = []): def lib_path(binary): return os.path.join(os.path.dirname(binary), 'lib') +def resources_path(binary): + return os.path.join(os.path.dirname(binary), '../Resources') + def lib_name(lib): return os.path.join("@executable_path", "lib", os.path.basename(lib)) @@ -157,12 +183,68 @@ def process_swift_libraries(binary): print(">> setting additional rpath for swift libraries") install_name_tool_add_rpath("@executable_path/lib", binary) +def process_vulkan_loader(binary, loaderName, loaderRelativeFolder, libraryNode): + # https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderDriverInterface.md#example-macos-driver-search-path + # https://github.com/KhronosGroup/Vulkan-Loader/blob/main/docs/LoaderLayerInterface.md#macos-layer-discovery + loaderSystemSearchFolders = [ + os.path.join(os.path.expanduser("~"), ".config", loaderRelativeFolder), + os.path.join("/etc/xdg", loaderRelativeFolder), + os.path.join("/usr/local/etc", loaderRelativeFolder), + os.path.join("/etc", loaderRelativeFolder), + os.path.join(os.path.expanduser("~"), ".local/share", loaderRelativeFolder), + os.path.join("/usr/local/share", loaderRelativeFolder), + os.path.join("/usr/share/vulkan", loaderRelativeFolder), + os.path.join(get_homebrew_prefix(), 'share', loaderRelativeFolder), + ] + + loaderSystemFolder = "" + for loaderSystemSearchFolder in loaderSystemSearchFolders: + if os.path.exists(loaderSystemSearchFolder): + loaderSystemFolder = loaderSystemSearchFolder + break + + if not loaderSystemFolder: + print(">>> could not find loader folder " + loaderRelativeFolder) + return + + loaderBundleFolder = os.path.join(resources_path(binary), loaderRelativeFolder) + loaderSystemPath = os.path.join(loaderSystemFolder, loaderName) + loaderBundlePath = os.path.join(loaderBundleFolder, loaderName) + libraryRelativeFolder = "../../../Frameworks/" + + if not os.path.exists(loaderSystemPath): + print(">>> could not find loader " + loaderName) + return + + if not os.path.exists(loaderBundleFolder): + os.makedirs(loaderBundleFolder) + + loaderSystemFile = open(loaderSystemPath, 'r') + loaderJsonData = json.load(loaderSystemFile) + librarySystemPath = os.path.join(loaderSystemFolder, loaderJsonData[libraryNode]["library_path"]) + + if not os.path.exists(librarySystemPath): + print(">>> could not find loader library " + librarySystemPath) + return + + print(">>> modifiying and writing loader json " + loaderName) + loaderBundleFile = open(loaderBundlePath, 'w') + loaderLibraryName = os.path.basename(librarySystemPath) + loaderJsonData[libraryNode]["library_path"] = os.path.join(libraryRelativeFolder, loaderLibraryName) + json.dump(loaderJsonData, loaderBundleFile, indent=4) + + print(">>> copying loader library " + loaderLibraryName) + frameworkBundleFolder = os.path.join(loaderBundleFolder, libraryRelativeFolder) + if not os.path.exists(frameworkBundleFolder): + os.makedirs(frameworkBundleFolder) + shutil.copy(librarySystemPath, os.path.join(frameworkBundleFolder, loaderLibraryName)) + def remove_dev_tools_rapths(binary): for path in get_rpaths_dev_tools(binary): install_name_tool_delete_rpath(path, binary) -def main(): - binary = os.path.abspath(sys.argv[1]) +def process(binary): + binary = os.path.abspath(binary) if not os.path.exists(lib_path(binary)): os.makedirs(lib_path(binary)) print(">> gathering all linked libraries") @@ -177,5 +259,10 @@ def main(): print(">> copying and processing swift libraries") process_swift_libraries(binary) + print(">> copying and processing vulkan loader") + process_vulkan_loader(binary, "MoltenVK_icd.json", "vulkan/icd.d", "ICD") + if check_vulkan_max_version("1.3.261.1"): + process_vulkan_loader(binary, "VkLayer_khronos_synchronization2.json", "vulkan/explicit_layer.d", "layer") + if __name__ == "__main__": - main() + process(sys.argv[1]) diff --git a/TOOLS/gen-interface-changes.py b/TOOLS/gen-interface-changes.py new file mode 100755 index 0000000..7f5435e --- /dev/null +++ b/TOOLS/gen-interface-changes.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +# Generate a new interface-changes.rst based on the entries in +# the interface-changes directory. + +# +# This file is part of mpv. +# +# mpv is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# mpv is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with mpv. If not, see <http://www.gnu.org/licenses/>. +# + +import pathlib +import sys +from shutil import which +from subprocess import check_output + +def add_new_entries(docs_dir, out, git): + changes_dir = pathlib.Path(docs_dir) / "interface-changes" + files = [] + for f in pathlib.Path(changes_dir).glob("*.txt"): + if f.is_file() and not f.name == "example.txt": + timestamp = check_output([git, "log", "--format=%ct", "-n", "1", "--", + f], encoding="UTF-8") + if timestamp: + files.append((f, timestamp)) + else: + print(f"Skipping file not tracked by git: {f.name}") + + files.sort(key=lambda x: x[1]) + for file in files: + with open(file[0].resolve(), "r") as f: + for line in f: + line = " - " + line.rstrip() + out.write(line + "\n") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} <version>") + sys.exit(1) + + git = which('git') + if not git: + print("Unable to find git binary") + sys.exit(1) + + # Accept passing only the major version number and the full 0 version. + major_version = -1 + if sys.argv[1].isdigit(): + major_version = sys.argv[1] + else: + ver_split = sys.argv[1].split(".") + if len(ver_split) == 3 and ver_split[1].isdigit(): + major_version = ver_split[1] + + if major_version == -1: + print(f"Invalid version number: {sys.argv[1]}") + sys.exit(1) + + docs_dir = pathlib.Path(sys.argv[0]).resolve().parents[1] / "DOCS" + interface_changes = docs_dir / "interface-changes.rst" + with open(interface_changes, "r") as f: + lines = [line.rstrip() for line in f] + + ver_line = " --- mpv 0." + major_version + ".0 ---" + next_ver_line = " --- mpv 0." + str(int(major_version) + 1) + ".0 ---" + with open(interface_changes, "w", newline="\n") as f: + for line in lines: + if line == ver_line: + f.write(next_ver_line + "\n") + f.write(line + "\n") + if line == ver_line: + add_new_entries(docs_dir, f, git) diff --git a/TOOLS/lua/autocrop.lua b/TOOLS/lua/autocrop.lua index b9e1120..ea57d15 100644 --- a/TOOLS/lua/autocrop.lua +++ b/TOOLS/lua/autocrop.lua @@ -177,7 +177,7 @@ function detect_end() else mp.msg.error("No crop data.") mp.msg.info("Was the cropdetect filter successfully inserted?") - mp.msg.info("Does your version of ffmpeg/libav support AVFrame metadata?") + mp.msg.info("Does your version of FFmpeg support AVFrame metadata?") return end diff --git a/TOOLS/lua/autodeint.lua b/TOOLS/lua/autodeint.lua index b891c9a..4e92960 100644 --- a/TOOLS/lua/autodeint.lua +++ b/TOOLS/lua/autodeint.lua @@ -8,7 +8,7 @@ -- telecined and the interlacing field dominance. -- -- Based on this information, it may set mpv's ``deinterlace`` property (which --- usually inserts the yadif filter), or insert the ``pullup`` filter if the +-- usually inserts the bwdif filter), or insert the ``pullup`` filter if the -- content is telecined. It also sets field dominance with lavfi setfield. -- -- OPTIONS: diff --git a/TOOLS/lua/autoload.lua b/TOOLS/lua/autoload.lua index 4003cbc..e0cfeb2 100644 --- a/TOOLS/lua/autoload.lua +++ b/TOOLS/lua/autoload.lua @@ -73,17 +73,17 @@ function Split (s) return set end -EXTENSIONS_VIDEO = Set { +EXTENSIONS_VIDEO_DEFAULT = Set { '3g2', '3gp', 'avi', 'flv', 'm2ts', 'm4v', 'mj2', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ogv', 'rmvb', 'webm', 'wmv', 'y4m' } -EXTENSIONS_AUDIO = Set { +EXTENSIONS_AUDIO_DEFAULT = Set { 'aiff', 'ape', 'au', 'flac', 'm4a', 'mka', 'mp3', 'oga', 'ogg', 'ogm', 'opus', 'wav', 'wma' } -EXTENSIONS_IMAGES = Set { +EXTENSIONS_IMAGES_DEFAULT = Set { 'avif', 'bmp', 'gif', 'j2k', 'jp2', 'jpeg', 'jpg', 'jxl', 'png', 'svg', 'tga', 'tif', 'tiff', 'webp' } @@ -97,9 +97,21 @@ split_option_exts(true, true, true) function create_extensions() EXTENSIONS = {} - if o.videos then SetUnion(SetUnion(EXTENSIONS, EXTENSIONS_VIDEO), o.additional_video_exts) end - if o.audio then SetUnion(SetUnion(EXTENSIONS, EXTENSIONS_AUDIO), o.additional_audio_exts) end - if o.images then SetUnion(SetUnion(EXTENSIONS, EXTENSIONS_IMAGES), o.additional_image_exts) end + EXTENSIONS_VIDEO = {} + EXTENSIONS_AUDIO = {} + EXTENSIONS_IMAGES = {} + if o.videos then + SetUnion(SetUnion(EXTENSIONS_VIDEO, EXTENSIONS_VIDEO_DEFAULT), o.additional_video_exts) + SetUnion(EXTENSIONS, EXTENSIONS_VIDEO) + end + if o.audio then + SetUnion(SetUnion(EXTENSIONS_AUDIO, EXTENSIONS_AUDIO_DEFAULT), o.additional_audio_exts) + SetUnion(EXTENSIONS, EXTENSIONS_AUDIO) + end + if o.images then + SetUnion(SetUnion(EXTENSIONS_IMAGES, EXTENSIONS_IMAGES_DEFAULT), o.additional_image_exts) + SetUnion(EXTENSIONS, EXTENSIONS_IMAGES) + end end create_extensions() @@ -211,6 +223,12 @@ function scan_dir(path, current_file, dir_mode, separator, dir_depth, total_file end function find_and_add_entries() + local aborted = mp.get_property_native("playback-abort") + if aborted then + msg.debug("stopping: playback aborted") + return + end + local path = mp.get_property("path", "") local dir, filename = utils.split_path(path) msg.trace(("dir: %s, filename: %s"):format(dir, filename)) diff --git a/TOOLS/lua/skip-logo.lua b/TOOLS/lua/skip-logo.lua index 8e1f9da..ae66b22 100644 --- a/TOOLS/lua/skip-logo.lua +++ b/TOOLS/lua/skip-logo.lua @@ -232,7 +232,7 @@ local function read_frames() end end -mp.observe_property(meta_property, "none", function() +mp.observe_property(meta_property, "native", function() -- Ignore frames that are decoded/filtered during seeking. if seeking then return diff --git a/TOOLS/matroska.py b/TOOLS/matroska.py index 52bac48..61a33ff 100755 --- a/TOOLS/matroska.py +++ b/TOOLS/matroska.py @@ -92,6 +92,7 @@ elements_matroska = ( 'MaxBlockAdditionID, 55ee, uint', 'Name, 536e, str', 'Language, 22b59c, str', + 'LanguageBCP47, 22b59d, str', 'CodecID, 86, str', 'CodecPrivate, 63a2, binary', 'CodecName, 258688, str', @@ -206,6 +207,7 @@ elements_matroska = ( 'ChapterDisplay*, 80, sub', ( 'ChapString, 85, str', 'ChapLanguage*, 437c, str', + 'ChapLanguageBCP47*, 437d, str', 'ChapCountry*, 437e, str', ), ), @@ -224,6 +226,7 @@ elements_matroska = ( 'SimpleTag*, 67c8, sub', ( 'TagName, 45a3, str', 'TagLanguage, 447a, str', + 'TagLanguageBCP47, 447b, str', 'TagString, 4487, str', 'TagDefault, 4484, uint', ), diff --git a/TOOLS/osxbundle.py b/TOOLS/osxbundle.py index 98699e4..0e156a0 100755 --- a/TOOLS/osxbundle.py +++ b/TOOLS/osxbundle.py @@ -1,13 +1,11 @@ #!/usr/bin/env python3 import os import shutil -import sys import fileinput +import dylib_unhell +import subprocess from optparse import OptionParser -def sh(command): - return os.popen(command).read().strip() - def bundle_path(binary_name): return "%s.app" % binary_name @@ -24,11 +22,11 @@ def target_binary(binary_name): return os.path.join(target_directory(binary_name), os.path.basename(binary_name)) -def copy_bundle(binary_name): +def copy_bundle(binary_name, src_path): if os.path.isdir(bundle_path(binary_name)): shutil.rmtree(bundle_path(binary_name)) shutil.copytree( - os.path.join('TOOLS', 'osxbundle', bundle_name(binary_name)), + os.path.join(src_path, 'TOOLS', 'osxbundle', bundle_name(binary_name)), bundle_path(binary_name)) def copy_binary(binary_name): @@ -39,20 +37,24 @@ def apply_plist_template(plist_file, version): print(line.rstrip().replace('${VERSION}', version)) def sign_bundle(binary_name): - sh('codesign --force --deep -s - ' + bundle_path(binary_name)) - -def bundle_version(): - if os.path.exists('VERSION'): - x = open('VERSION') + sign_directories = ['Contents/Frameworks', 'Contents/MacOS'] + for dir in sign_directories: + resolved_dir = os.path.join(bundle_path(binary_name), dir) + for root, _dirs, files in os.walk(resolved_dir): + for f in files: + subprocess.run(['codesign', '--force', '-s', '-', os.path.join(root, f)]) + subprocess.run(['codesign', '--force', '-s', '-', bundle_path(binary_name)]) + +def bundle_version(src_path): + version = 'UNKNOWN' + version_path = os.path.join(src_path, 'VERSION') + if os.path.exists(version_path): + x = open(version_path) version = x.read() x.close() - else: - version = sh("./version.sh").strip() return version def main(): - version = bundle_version().rstrip() - usage = "usage: %prog [options] arg" parser = OptionParser(usage) parser.add_option("-s", "--skip-deps", action="store_false", dest="deps", @@ -61,14 +63,17 @@ def main(): (options, args) = parser.parse_args() - if len(args) != 1: + if len(args) < 1 or len(args) > 2: parser.error("incorrect number of arguments") else: binary_name = args[0] + src_path = args[1] if len(args) > 1 else "." + + version = bundle_version(src_path).rstrip() - print("Creating Mac OS X application bundle (version: %s)..." % version) + print("Creating macOS application bundle (version: %s)..." % version) print("> copying bundle skeleton") - copy_bundle(binary_name) + copy_bundle(binary_name, src_path) print("> copying binary") copy_binary(binary_name) print("> generating Info.plist") @@ -76,7 +81,7 @@ def main(): if options.deps: print("> bundling dependencies") - print(sh(" ".join(["TOOLS/dylib-unhell.py", target_binary(binary_name)]))) + dylib_unhell.process(target_binary(binary_name)) print("> signing bundle with ad-hoc pseudo identity") sign_bundle(binary_name) diff --git a/TOOLS/osxbundle/mpv.app/Contents/Info.plist b/TOOLS/osxbundle/mpv.app/Contents/Info.plist index e239dc7..eaa83ad 100644 --- a/TOOLS/osxbundle/mpv.app/Contents/Info.plist +++ b/TOOLS/osxbundle/mpv.app/Contents/Info.plist @@ -188,6 +188,8 @@ <string>${VERSION}</string> <key>NSHighResolutionCapable</key> <true/> + <key>LSApplicationCategoryType</key> + <string>public.app-category.games</string> <key>LSEnvironment</key> <dict> <key>MallocNanoZone</key> |