Direct Play on Apple TV develops recurring micro-stutter that worsens the longer playback runs and clears temporarily on pause/play (issue #1776). Since 2.4 the avfoundation VO has presented frames against a media-time CMTimebase anchored and rate-servoed to follow mpv's audio-slaved schedule; clock skew between the two domains can only be retired by rate slewing or a re-anchor snap that retimes every queued frame at once. The media timebase exists for PiP, which tvOS does not have. Bump MPVKit to 1.0.22 and opt tvOS into its new avfoundation-presentation=host mode: samples carry mpv's scheduled display time against a free-running host-clock timebase, so drift is absorbed per frame inside mpv and no timing state accumulates in the VO. The queue lead returns to 128ms; 500ms only dampened media-mode snaps and quadrupled their blast radius. 1.0.22 also paces the compressed-passthrough feed off the most-advanced playhead reading, fixing the periodic audio dropouts passthrough users reported on 2.14.
87 lines
3.6 KiB
Ruby
Executable File
87 lines
3.6 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
# Adds the Plezy MpvPlayer Swift sources and the MPVKit Swift Package
|
|
# dependency to tvos/Runner.xcodeproj so it matches the iOS project's
|
|
# linkage. Idempotent: re-running skips already-added entries.
|
|
|
|
require 'xcodeproj'
|
|
|
|
PROJECT_PATH = File.expand_path('../Runner.xcodeproj', __dir__)
|
|
project = Xcodeproj::Project.open(PROJECT_PATH)
|
|
runner_target = project.targets.find { |t| t.name == 'Runner' }
|
|
raise "Runner target not found" unless runner_target
|
|
|
|
# Find or create the MpvPlayer group under Runner.
|
|
main_group = project.main_group['Runner']
|
|
raise "Runner group not found" unless main_group
|
|
mpv_group = main_group['MpvPlayer'] || main_group.new_group('MpvPlayer', 'Runner/MpvPlayer')
|
|
|
|
# File references.
|
|
# path is relative to the group's path (Runner/MpvPlayer → ../..).
|
|
# For files elsewhere in the repo, use SOURCE_ROOT with the absolute-ish path.
|
|
sources = [
|
|
{ name: 'MpvPlayerCoreBase.swift', path: '../shared/apple/MpvPlayer/MpvPlayerCoreBase.swift', tree: '<source_root>' },
|
|
{ name: 'MpvPlayerPluginShared.swift', path: '../shared/apple/MpvPlayer/MpvPlayerPluginShared.swift', tree: '<source_root>' },
|
|
{ name: 'MpvPlayerCore.swift', path: '../ios/Runner/MpvPlayer/MpvPlayerCore.swift', tree: '<source_root>' },
|
|
{ name: 'MpvPlayerPlugin.swift', path: '../ios/Runner/MpvPlayer/MpvPlayerPlugin.swift', tree: '<source_root>' },
|
|
{ name: 'MpvPipController.swift', path: '../ios/Runner/MpvPlayer/MpvPipController.swift', tree: '<source_root>' },
|
|
{ name: 'MpvAudioPlayerCore.swift', path: '../shared/apple/MpvPlayer/MpvAudioPlayerCore.swift', tree: '<source_root>' },
|
|
{ name: 'MpvAudioPlayerPlugin.swift', path: '../shared/apple/MpvPlayer/MpvAudioPlayerPlugin.swift', tree: '<source_root>' },
|
|
]
|
|
|
|
sources_phase = runner_target.source_build_phase
|
|
sources.each do |src|
|
|
ref = mpv_group.files.find { |file| file.display_name == src[:name] }
|
|
unless ref
|
|
ref = mpv_group.new_file(src[:path])
|
|
ref.name = src[:name]
|
|
ref.source_tree = src[:tree]
|
|
puts "[add ] #{src[:name]} reference"
|
|
end
|
|
|
|
if sources_phase.files_references.include?(ref)
|
|
puts "[skip] #{src[:name]} source membership already present"
|
|
else
|
|
sources_phase.add_file_reference(ref, true)
|
|
puts "[add ] #{src[:name]} source membership"
|
|
end
|
|
end
|
|
|
|
# Swift Package: MPVKit. Restore each graph edge independently so a project
|
|
# with a surviving package reference cannot silently omit the Runner linkage.
|
|
pkg_url = 'https://github.com/edde746/MPVKit'
|
|
pkg_version = '1.0.22'
|
|
pkg = project.root_object.package_references.find do |candidate|
|
|
candidate.repositoryURL == pkg_url rescue false
|
|
end
|
|
|
|
unless pkg
|
|
pkg = project.new(Xcodeproj::Project::Object::XCRemoteSwiftPackageReference)
|
|
pkg.repositoryURL = pkg_url
|
|
project.root_object.package_references << pkg
|
|
puts "[add ] MPVKit SPM package reference"
|
|
end
|
|
pkg.requirement = { 'kind' => 'exactVersion', 'version' => pkg_version }
|
|
puts "[set ] MPVKit SPM package version"
|
|
|
|
product = runner_target.package_product_dependencies.find do |candidate|
|
|
candidate.product_name == 'MPVKit'
|
|
end
|
|
unless product
|
|
product = project.new(Xcodeproj::Project::Object::XCSwiftPackageProductDependency)
|
|
product.product_name = 'MPVKit'
|
|
runner_target.package_product_dependencies << product
|
|
puts "[add ] MPVKit Runner product dependency"
|
|
end
|
|
product.package = pkg
|
|
|
|
frameworks_phase = runner_target.frameworks_build_phase
|
|
unless frameworks_phase.files.any? { |build_file| build_file.product_ref == product }
|
|
build_file = project.new(Xcodeproj::Project::Object::PBXBuildFile)
|
|
build_file.product_ref = product
|
|
frameworks_phase.files << build_file
|
|
puts "[add ] MPVKit framework linkage"
|
|
end
|
|
|
|
project.save
|
|
puts "Saved #{PROJECT_PATH}"
|