### Development Setup Script
Source: https://github.com/harflabs/swiftvlc/blob/main/README.md
Clone the repository, navigate to the project directory, and run the setup script to prepare the development environment. This script downloads necessary binaries and configures local package references for development.
```bash
git clone https://github.com/harflabs/SwiftVLC.git
cd SwiftVLC
./scripts/setup-dev.sh
```
--------------------------------
### Install Build Dependencies and Build libVLC
Source: https://github.com/harflabs/swiftvlc/blob/main/README.md
Installs required build tools using Homebrew and then executes the script to build all libVLC components for all supported platforms. This process can take a significant amount of time.
```bash
brew install autoconf automake libtool cmake pkg-config gettext
./scripts/build-libvlc.sh --all
```
--------------------------------
### Integration Test Example
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
An example of an integration test using SwiftVLC's Player API. This test requires a `VLCInstance` and uses bundled fixture files.
```swift
@Test(.tags(.integration, .media, .async))
func playAndWaitForState() async throws {
let player = Player()
try player.play(url: TestMedia.videoURL)
// Wait for state change...
}
```
--------------------------------
### Configure Media Playback Options
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md
Add playback options to a media object using colon-prefixed strings. These options affect media that has not yet started playing. Examples include network caching and start time.
```swift
media.addOption(":network-caching=1500")
```
```swift
media.addOption(":start-time=30")
```
--------------------------------
### Instantiate and Use PiPController Directly
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PictureInPicture.md
Demonstrates how to manually instantiate PiPController, add its layer to a container, and start the PiP session. Use this when custom view hierarchies or layout control is needed.
```swift
let controller = PiPController(player: player)
container.layer.addSublayer(controller.layer)
controller.start()
```
--------------------------------
### Prewarm libVLC Instance at App Launch
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/GettingStarted.md
Prewarm the shared libVLC instance during app initialization to perform one-time setup, avoiding delays during the first playback.
```swift
import SwiftUI
import SwiftVLC
@main
struct MyApp: App {
init() {
VLCInstance.prewarmShared()
}
var body: some Scene {
WindowGroup { PlayerView() }
}
}
```
--------------------------------
### SwiftVLC Quick Start Player View
Source: https://github.com/harflabs/swiftvlc/blob/main/README.md
A basic SwiftUI View that uses SwiftVLC to play a video from a URL. Ensure the URL is a direct media stream or file URL.
```swift
import SwiftUI
import SwiftVLC
struct PlayerView: View {
@State private var player = Player()
var body: some View {
VideoView(player)
.onAppear {
try? player.play(url: URL(string: "https://example.com/video.mp4")!)
}
}
}
```
--------------------------------
### VideoView Rendering with libVLC
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
Illustrates the interaction between SwiftUI, VideoView, VideoSurface, and libVLC for video rendering. libVLC handles all rendering internally without requiring CALayer or AVPlayerLayer setup.
```mermaid
sequenceDiagram
participant SwiftUI
participant VideoView
participant VideoSurface as VideoSurface
(UIView / NSView)
participant libVLC
SwiftUI->>VideoView: makeUIView / makeNSView
VideoView->>VideoSurface: create
VideoSurface->>libVLC: set_nsobject(view pointer)
libVLC->>VideoSurface: adds rendering sublayer
loop On resize
VideoSurface->>VideoSurface: layoutSubviews() — sync sublayer frames
end
SwiftUI->>VideoView: dismantleUIView
VideoSurface->>libVLC: set_nsobject(nil)
```
--------------------------------
### Cast Media to a Renderer
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DiscoveryAndCasting.md
Discover renderer devices on the network and cast media to them. This involves starting a RendererDiscoverer and reacting to events for when renderers are added or removed. A new Player instance is recommended for casting.
```swift
let services = RendererDiscoverer.availableServices()
guard let service = services.first else { return }
var player = Player()
let discoverer = try RendererDiscoverer(name: service.name)
try discoverer.start()
for await event in discoverer.events {
switch event {
case .itemAdded(let renderer):
print("Found", renderer.name, renderer.type)
let castPlayer = Player()
do {
try castPlayer.setRenderer(renderer)
try castPlayer.play(url: mediaURL)
player.stop()
player = castPlayer
} catch {
print("Cast failed:", error)
}
case .itemDeleted(let renderer):
print("Lost", renderer.name)
}
}
```
--------------------------------
### Multiple Consumers for Log Streams
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/Logging.md
Demonstrates how multiple tasks can independently subscribe to the log stream with different minimum severity levels. The underlying libVLC callback is installed lazily and removed when all consumers terminate.
```swift
Task { for await e in instance.logStream(minimumLevel: .error) {
diagnostics.record(e)
}}
```
```swift
Task { for await e in instance.logStream(minimumLevel: .debug) {
devConsole.append(e)
}}
```
--------------------------------
### Discover Local Media Sources
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DiscoveryAndCasting.md
Use MediaDiscoverer to find available media services on the local network, such as UPnP or SMB. Start a discoverer for a specific service and retrieve a list of media items.
```swift
let services = MediaDiscoverer.availableServices(category: .lan)
guard let upnp = services.first(where: { $0.name == "upnp" }) else { return }
let discoverer = try MediaDiscoverer(name: upnp.name)
try discoverer.start()
try? await Task.sleep(for: .seconds(2))
if let list = discoverer.mediaList {
for i in 0.. XCF["Vendor/libvlc.xcframework
(unstripped)"]
XCF --> RELEASE["release.sh vX.Y.Z"]
RELEASE --> VERIFY["Verify all required slices present"]
VERIFY --> STRIP["strip -S"]
STRIP --> ZIP["ditto -c -k"]
ZIP --> SUM["swift package compute-checksum"]
SUM --> COMMIT["Commit on main:
Package.swift → url+checksum
Showcase → exactVersion X.Y.Z"]
COMMIT --> TAG["git tag vX.Y.Z"]
TAG --> PUSH_TAG["git push origin vX.Y.Z"]
PUSH_TAG --> GH["gh release create
+ attached .zip"]
GH --> PUSH_MAIN["git push origin HEAD:main"]
PUSH_MAIN --> SPM["main and consumers resolve the same release"]
```
--------------------------------
### Build a Media List
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/MediaPlaylists.md
Create a MediaList and append or insert Media items. MediaList is thread-safe.
```swift
let list = MediaList()
try list.append(Media(url: url1))
try list.append(Media(url: url2))
try list.insert(Media(url: url3), at: 1)
```
--------------------------------
### SwiftVLC Test Directory Structure
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
Illustrates the organization of test files and fixtures within the SwiftVLC project.
```tree
Tests/SwiftVLCTests/
├── Support/
│ ├── TestMedia.swift # Fixture URLs (bundled resources)
│ └── Tag.swift # Test tag definitions
├── Fixtures/
│ ├── test.mp4 # 1s, 64x64, with metadata
│ ├── twosec.mp4 # 2s, for seeking tests
│ ├── silence.wav # Audio-only
│ └── test.srt # Subtitle file
└── … # One test suite per domain area
```
--------------------------------
### Perform a dry run of the release script
Source: https://github.com/harflabs/swiftvlc/blob/main/README.md
Simulates the release process by stripping debug symbols, zipping the framework, and computing checksums, without actually pushing any changes.
```bash
./scripts/release.sh X.Y.Z --dry-run # strip + zip + checksum, no push
```
--------------------------------
### Verification Script for Dynamic Host
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/IntegrationTopology.md
This script builds and audits the dynamic host fixture to verify the single-copy libVLC runtime. It checks the 'nm' output for '_libvlc_new' symbol definition count and optionally launches the iOS app in a simulator.
```sh
Fixtures/DynamicHost/verify.sh # build + single-copy audit
```
```sh
Fixtures/DynamicHost/verify.sh --launch # additionally run the iOS app
# in a simulator (local only)
```
--------------------------------
### Basic Video Playback in SwiftUI
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/SwiftVLC.md
This snippet demonstrates how to initialize a Player and play a video URL within a SwiftUI View. It utilizes the @State property wrapper for player management and the .task modifier for asynchronous playback initiation.
```swift
import SwiftUI
import SwiftVLC
struct ContentView: View {
@State private var player = Player()
var body: some View {
VideoView(player)
.task { try? player.play(url: videoURL) }
}
}
```
--------------------------------
### Initialize Player Instance
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PlaybackEssentials.md
Declare a Player instance using @State for use within SwiftUI views. This initializes the underlying libVLC resources.
```swift
@State private var player = Player()
```
--------------------------------
### Package.swift Local Binary Target
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
Defines the libvlc binary target for local development, pointing to an on-disk xcframework.
```swift
.binaryTarget(name: "libvlc", path: "Vendor/libvlc.xcframework")
```
--------------------------------
### Configure HTTP Request Options
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md
Set HTTP-specific request options for streams, such as user-agent and referrer, using the addOption method. These options are applied to HTTP and HTTPS streams.
```swift
media.addOption(":http-user-agent=CustomApp/1.0")
```
```swift
media.addOption(":http-referrer=https://example.com")
```
--------------------------------
### Best-Effort Seeks
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PlaybackEssentials.md
For live, timeshift, or unknown-duration media, use these best-effort seek methods that do not throw errors.
```swift
player.seek(toPosition: 0.95, fast: true) // raw fractional seek
player.jump(by: .seconds(-10)) // native relative jump
```
--------------------------------
### Exhaustive Error Handling with Pattern Matching
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/HandlingErrors.md
Demonstrates how to use a do-catch block with pattern matching to handle all possible VLCError cases. This ensures that no error goes unhandled.
```swift
do {
try player.play(url: url)
} catch .instanceCreationFailed {
print("libVLC could not be initialized")
} catch .mediaCreationFailed(let source) {
print("Couldn't build media for: \(source)")
} catch .playbackFailed(let reason) {
print("Playback refused: \(reason)")
} catch .parseFailed(let reason) {
print("Parsing failed: \(reason)")
} catch .parseTimeout {
print("Parsing timed out")
} catch .trackNotFound(let id) {
print("No track matched: \(id)")
} catch .invalidState(let message) {
print("Player wasn't ready: \(message)")
} catch .invalidInput(let message) {
print("Bad argument: \(message)")
} catch .operationFailed(let op) {
print("libVLC call failed: \(op)")
}
```
--------------------------------
### Media Parsing Flow
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
Illustrates the asynchronous parsing flow for media, including cancellation, timeout, and success scenarios. This sequence diagram outlines the interaction between the App, Media, and libVLC components.
```mermaid
sequenceDiagram
participant App
participant Media
participant libVLC
App->>Media: parse(timeout:) async throws
Media->>libVLC: libvlc_media_parse_request()
libVLC-->>Media: MediaParsedChanged event
alt Task cancelled
Media->>libVLC: libvlc_media_parse_stop()
else Timeout exceeded
Media-->>App: throws .parseTimeout
else Success
Media-->>App: returns Metadata
end
```
--------------------------------
### Audio Volume Scale Conversion
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Demonstrates the conversion between VLCKit's 0-200 integer volume scale and SwiftVLC's 0.0-2.0 float scale.
```swift
// VLCKit
player.audio.volume = 150
```
```swift
// SwiftVLC
try player.setAudioVolume(Volume(1.5))
```
--------------------------------
### Stop and Wait for Player
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Use `stopAndWait()` to ensure the native stop operation completes before proceeding. This prevents common porting bugs related to deactivating audio sessions too early.
```swift
await player.stopAndWait()
try AVAudioSession.sharedInstance()
.setActive(false, options: .notifyOthersOnDeactivation)
```
--------------------------------
### Configure Audio Session for PiP
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PictureInPicture.md
Sets the audio session category to .playback and mode to .moviePlayback, then activates the session. This is required for PiP functionality on iOS.
```swift
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback)
try? AVAudioSession.sharedInstance().setActive(true)
```
--------------------------------
### Parse Media Metadata Up Front
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Parse media metadata and track information once before playback begins. This operation is asynchronous and honors task cancellation.
```swift
let media = try Media(url: url)
let metadata = try await media.parse()
try player.play(media)
```
--------------------------------
### Playing Media on the Main Actor
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PlaybackEssentials.md
Construct a Media object on any actor and then play it on the main actor. Ownership of the Media object is transferred to the player upon calling play.
```swift
let media = try Media(url: url) // any actor
await MainActor.run {
try? player.play(media) // main actor; ownership transfers
}
```
--------------------------------
### SwiftVLC @Observable and SwiftUI Integration
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/ComparisonWithVLCKit.md
Demonstrates SwiftVLC's integration with SwiftUI using the @Observable macro for state management and a direct Swift API for playback. This approach avoids Objective-C bridging.
```swift
// SwiftVLC: @Observable plus SwiftUI
struct PlayerView: View {
@State var player = Player()
var body: some View {
VideoView(player)
.task { try? player.play(url: url) }
}
}
```
--------------------------------
### Play a Media List
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/MediaPlaylists.md
Attach a MediaListPlayer to an existing Player and set the MediaList. Playback can be looped or default.
```swift
let listPlayer = MediaListPlayer()
listPlayer.mediaPlayer = player
listPlayer.mediaList = list
listPlayer.playbackMode = .loop
listPlayer.play()
```
--------------------------------
### Set Audio Role Hint
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md
Provide a hint to libVLC about the intended role of the audio playback, such as music or communication calls. The actual effect of this hint depends on the platform and the active audio output module.
```swift
player.role = .music // long-form listening
player.role = .communication // voice/video calls
```
--------------------------------
### Configure Video Adjustments Overlay
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md
Enables and adjusts video properties such as contrast, brightness, and saturation in real time. These adjustments are applied to the video feed.
```swift
player.withAdjustments {
$0.isEnabled = true
$0.contrast = 1.1
$0.brightness = 1.05
$0.saturation = 1.2
}
```
--------------------------------
### Project Structure
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
Hierarchical view of the SwiftVLC project directory, detailing the organization of source code, tests, showcase applications, vendor libraries, scripts, and configuration files.
```tree
SwiftVLC/
├── Sources/
│ ├── CLibVLC/ # C bridging layer
│ │ ├── include/vlc/ # libVLC 4.0 C headers
│ │ └── shim.c # va_list formatting shim
│ │
│ └── SwiftVLC/ # Main library
│ ├── Core/ # VLCInstance, VLCError, Logging, Duration
│ ├── Player/ # Player, EventBridge, PlayerState, Events, ABLoop, etc.
│ ├── Media/ # Media, Metadata, Track, Thumbnails, Statistics
│ ├── Audio/ # AudioOutput, Equalizer, ChannelModes
│ ├── Video/ # VideoView, AspectRatio, Adjustments, Marquee, Logo, Viewpoint
│ ├── Playlist/ # MediaList, MediaListPlayer, PlaybackMode
│ ├── Discovery/ # MediaDiscoverer, RendererDiscoverer
│ └── PiP/ # PiPController, PiPVideoView, PixelBufferRenderer
│
├── Tests/SwiftVLCTests/ # Swift Testing suite, one file per domain
│ ├── Support/ # TestMedia fixtures, Tag definitions
│ └── Fixtures/ # Bundled media files (~50 KB)
│
├── Showcase/ # Platform showcase apps
│ ├── Shared/ # Launch-arg/accessibility contracts, app icon, and shared showcase resources
│ ├── iOS/ # Full-featured iOS target/scheme, also enabled for Mac Catalyst
│ ├── macOS/ # Native macOS target/scheme with Mac-tailored showcases
│ ├── tvOS/ # Native tvOS target/scheme with TV-tailored showcases
│ ├── visionOS/ # Native visionOS target/scheme with focused playback coverage
│ └── UITests/
│ ├── iOS/ # UI tests for the iOS/Catalyst showcase
│ ├── macOS/ # Native macOS UI tests
│ └── tvOS/ # Empty tvOS UI-test target shell
│
├── Vendor/ # libvlc.xcframework (multi-GB unstripped; release zip a few hundred MB)
│
├── scripts/
│ ├── build-libvlc.sh # Compile libvlc from source
│ ├── setup-dev.sh # Download xcframework for local dev
│ ├── release.sh # Cut a versioned release and advance main
│ ├── fix-duplicate-symbols.sh # Localize duplicate json symbols
│ ├── ci-use-released-xcframework.sh # CI: point Package.swift at latest release
│ └── ci-run-with-timeouts.py # CI: wall-clock + idle test timeouts
│
├── .github/workflows/
│ ├── test.yml # CI test runner
│ ├── sanitize.yml # Sanitizer test runner
│ └── claude.yml # Claude Code bot integration
│
├── Package.swift # SPM manifest (Swift 6.3+)
├── .swiftlint.yml # Lint configuration
├── .swiftformat # Format: 2-space indent
└── README.md # User guide
```
--------------------------------
### Seeking Media Position in SwiftVLC
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Use `Player/seek(to:)` for precise seeking or `Player/seek(toPosition:fast:)` for a more lenient approach when migrating from VLCKit's `player.position = x`.
```swift
Player/seek(to:)-(PlaybackPosition)
```
```swift
Player/seek(toPosition:fast:)
```
--------------------------------
### Logo (image overlay)
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md
Adds an image logo overlay to the video. Supports static PNGs or animated sequences. Allows configuration of opacity and screen position.
```APIDOC
## Logo (image overlay)
``Logo`` layers a PNG (or a sequence of PNGs for animation) on top of the video:
```swift
player.withLogo { logo in
logo.isEnabled = true
logo.setFile("/tmp/logo.png")
logo.opacity = 200 // 0–255
logo.screenPosition = .topRight
}
```
For an animated sequence, pass "file,delay,transparency;…" to ``Logo/setFile(_:)``.
```
--------------------------------
### Set Stereo Mode and Mix Mode
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md
Configure the stereo transformation mode (e.g., mono, reversed) and the channel count of the final audio mix, including options like stereo, 5.1, 7.1, and binaural rendering for headphones.
```swift
player.stereoMode = .mono // collapse to mono
player.mixMode = .binaural // spatialize for headphones
```
--------------------------------
### Marquee (text overlay)
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md
Configures a text marquee overlay on the video. Supports strftime-style placeholders and allows customization of refresh interval, font size, color, and screen position.
```APIDOC
## Marquee (text overlay)
``Marquee`` displays a text string on top of the video. It supports strftime-style placeholders refreshed at the interval configured by ``Marquee/refresh``:
```swift
player.withMarquee { m in
m.isEnabled = true
m.setText("%H:%M:%S")
m.refresh = 1000 // refresh every second
m.fontSize = 24
m.color = 0xFFFFFF
m.screenPosition = .bottomLeft
}
```
Anchoring uses ``OverlayPosition``, an `OptionSet` whose flags compose into corners (`.topLeft`, `.bottomRight`, …) or an empty set for the center. The raw ``Marquee/position`` `Int` bitmask remains available for libVLC-flavored code.
```
--------------------------------
### Multiplexing Player Events with `AsyncStream`
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/ConcurrencyModel.md
Shows how to subscribe to player events using `AsyncStream`. Multiple independent streams can be created from the same event source, with each stream receiving all events broadcast after its creation. Slow consumers will drop the oldest events due to `bufferingNewest`.
```swift
Task { for await e in player.events { handleA(e) } }
Task { for await e in player.events { handleB(e) } }
```
--------------------------------
### Delegate Thread-Marshaling Comparison
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Compares the old VLCKit delegate pattern requiring manual main-queue hops with SwiftVLC's direct consumption of events on the main actor via AsyncStreams.
```swift
// VLCKit: delegate + manual main-queue hop
func mediaPlayerStateChanged(_ notification: Notification!) {
DispatchQueue.main.async { self.updateUI() }
}
```
```swift
// SwiftVLC: consume on the main actor, no marshaling
for await state in player.stateTransitions {
updateUI(for: state)
}
```
--------------------------------
### Fetching Media Metadata in SwiftVLC
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Replace the `mediaMetaDataDidChange` delegate in VLCKit with an `await` call to `Media/parse(timeout:instance:)` in SwiftVLC for metadata retrieval.
```swift
await Media/parse(timeout:instance:)
```
--------------------------------
### Transferring Media Ownership with `sending`
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/ConcurrencyModel.md
Demonstrates how to use the `sending` keyword to transfer ownership of a `Media` object from a background task to the main actor for playback. This prevents the background task from modifying the `Media` object after it has been passed to the player.
```swift
public func load(_ media: sending Media)
```
```swift
Task.detached {
let media = try Media(url: url) // built off-actor
await MainActor.run {
try? player.play(media) // ownership transfers in
}
}
```
--------------------------------
### SwiftUI Player Screen with PiPVideoView
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/PictureInPicture.md
This SwiftUI view demonstrates how to integrate PiPVideoView for Picture-in-Picture playback. It manages the player and a PiPController, allowing users to toggle PiP mode.
```swift
struct PlayerScreen: View {
@State private var player = Player()
@State private var pip: PiPController?
var body: some View {
VStack {
PiPVideoView(player, controller: $pip)
.aspectRatio(16/9, contentMode: .fit)
Button("Picture in Picture") { pip?.toggle() }
.disabled(pip?.isPossible != true)
}
}
}
```
--------------------------------
### Apply a Built-in Equalizer Preset
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md
Load and apply a predefined equalizer preset by its name, such as 'Rock'. If the preset is not found, the default equalizer is used. Set the player's equalizer to nil to disable equalization.
```swift
if let rock = Equalizer(preset: Equalizer.presetNames.firstIndex(of: "Rock") ?? 0) {
player.equalizer = rock
}
player.equalizer = nil
```
--------------------------------
### Adding a Marquee Overlay
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DisplayingVideo.md
Use `withMarquee` to add text overlays to the video. Configure the marquee's enabled state, text content, and font size.
```swift
player.withMarquee { m in
m.isEnabled = true
m.setText("LIVE")
m.fontSize = 32
}
```
--------------------------------
### Configure Marquee Text Overlay
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VideoOverlays.md
Configures a text marquee overlay with custom text, refresh interval, font size, color, and screen position. Supports strftime-style placeholders.
```swift
player.withMarquee {
$0.isEnabled = true
$0.setText("%H:%M:%S")
$0.refresh = 1000 // refresh every second
$0.fontSize = 24
$0.color = 0xFFFFFF
$0.screenPosition = .bottomLeft
}
```
--------------------------------
### Set Equalizer Band Gains Using Typed Values
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/AudioFeatures.md
Set multiple equalizer band gains at once using typed values, including predefined constants like .flat. Individual band gains and preamp gain are clamped within libVLC's -20.0 to +20.0 dB range.
```swift
eq.preampGain = .flat
try eq.setBandGains([+3.0, +2.0, .flat, -1.0, -2.0, -2.0, -1.0, .flat, +1.0, +2.0])
try eq.setGain(+6.0, forBand: 3)
```
--------------------------------
### Enumerate Media Tracks
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md
Retrieve and print information about the audio tracks of a media object after parsing or loading. This includes track name, language, and channel count.
```swift
let audio = media.tracks().filter { $0.type == .audio }
audio.forEach { print($0.name, $0.language ?? "—", $0.channels ?? 0) }
```
--------------------------------
### Taking a Snapshot of the Video Frame
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DisplayingVideo.md
Capture the current video frame and save it as a PNG image to a specified file path. You can optionally specify the width and height for the snapshot.
```swift
try player.takeSnapshot(
to: "/tmp/frame.png",
width: 1920, // pass 0 to derive from aspect ratio
height: 0
)
```
--------------------------------
### Access Media Statistics
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/WorkingWithMedia.md
Retrieve real-time statistics for input, demux, decoders, and output while a media is loaded. These values are snapshots and can be captured on a timer to display rates over time.
```swift
if let stats = player.statistics {
print("Input bitrate: \(stats.inputBitrate) kbps")
print("Dropped frames: \(stats.lostPictures)")
}
```
--------------------------------
### Controlling Aspect Ratio
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DisplayingVideo.md
Set the `aspectRatio` property on the player to control how the video is displayed. Options include default fitting, forcing a specific ratio, or filling the available space.
```swift
player.aspectRatio = .default // letterbox/pillarbox to fit
```
```swift
player.aspectRatio = .ratio(16, 9) // force 16:9
```
```swift
player.aspectRatio = .fill // cover the display; may crop
```
--------------------------------
### Package.swift Remote Binary Target
Source: https://github.com/harflabs/swiftvlc/blob/main/ARCHITECTURE.md
Defines the libvlc binary target for published states, pointing to a remote URL for the xcframework.
```swift
.binaryTarget(
name: "libvlc",
url: "https://github.com/harflabs/SwiftVLC/releases/download/vX.Y.Z/libvlc.xcframework.zip",
checksum: ""
)
```
--------------------------------
### Check Renderer Capabilities
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/DiscoveryAndCasting.md
Inspect a discovered renderer item to check its capabilities, such as whether it supports video playback and its specific type.
```swift
if renderer.canVideo && renderer.type == "chromecast" {
// OK to cast video
}
```
--------------------------------
### Control Playback UI from State
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/GettingStarted.md
Drive UI elements like text descriptions, progress views, and play/pause buttons by directly reading observable properties from the Player instance.
```swift
Text(player.state.description)
ProgressView(value: player.position)
Button(player.isPlaying ? "Pause" : "Play") {
player.togglePlayPause()
}
```
--------------------------------
### Player/shutdown()
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/VLCKitPortingGuide.md
Performs a full asynchronous teardown of the player. After this method returns, no libVLC threads owned by the player are active, and the player becomes an inert no-op.
```APIDOC
## Player/shutdown()
### Description
An awaitable full teardown. After it returns, no libVLC thread owned by the player is draining, its streams are finished, and the player is an inert no-op. Reach for it when the player's end-of-life must complete *before* something else, rather than on `deinit`'s background schedule.
### Method
`await` (asynchronous function)
### Endpoint
N/A (method call)
### Parameters
None
### Request Example
```swift
await player.shutdown()
// Player is now fully shut down and inert.
```
### Response
#### Success Response
Completes when the player has been fully torn down.
#### Response Example
None (asynchronous completion)
```
--------------------------------
### Optional Result with try?
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/HandlingErrors.md
Use try? to simplify error handling when the specific failure reason is not important. This converts any thrown VLCError into a nil result.
```swift
try? player.play(url: url)
```
--------------------------------
### Add SwiftVLC Package to Project
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/GettingStarted.md
Add the SwiftVLC package to your Xcode project by pasting the repository URL. For Package.swift manifests, pin to the latest release version.
```text
https://github.com/harflabs/SwiftVLC.git
```
```swift
dependencies: [
.package(url: "https://github.com/harflabs/SwiftVLC.git", from: "x.y.z")
],
targets: [
.target(name: "MyApp", dependencies: ["SwiftVLC"])
]
```
--------------------------------
### Access Media List Safely
Source: https://github.com/harflabs/swiftvlc/blob/main/Sources/SwiftVLC/SwiftVLC.docc/MediaPlaylists.md
For consistent reads, use withLocked to acquire the underlying libVLC lock. The view passed to the closure is not storable.
```swift
let mrls = list.withLocked { view in
(0..