piemonte/Player: a small Swift video player you can read in one sitting
▶️ Play and stream media in Swift
At a glance
- What is it?
- An AVFoundation wrapper for iOS and tvOS that fits in a single source file, installs through Swift Package Manager or CocoaPods, and gets out of the way once the view is in your hierarchy.
- Who is it for?
- Player is at its best when you want a plain video surface with a few callbacks and no configuration object to learn. The `url`, `asset` and `playerItem` properties cover the three sources a project actually has, and the rest is AVFoundation that you can drop into the view controller yourself.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 7 months ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three ways to install, one of them a single file
Installation is the easiest part to get wrong in a Swift package, and Player makes it deliberately dull. There are three routes. Swift Package Manager takes a version range in your `Package.swift`:
dependencies: [
.package(url: "https://github.com/piemonte/Player.git", from: "0.15.0")
]CocoaPods gets the same library through a podspec:
pod "Player", "~> 0.15.0"The third route is manual. The README says to copy the `Player.swift` file from the `Sources` directory into your Xcode project, and that is the route that matters most for reading the code, because it means the whole library is something you can open and scroll through rather than debug into.
There is a version story here worth noticing. A badge advertises Swift 5.0 and up, and the README then keeps branches for older compilers: target the `swift4.2` branch for Swift 4.2 and `swift4.0` for Swift 4.0, while the default line assumes the latest release. The repository also carries a `.swift-version` file, which is the mechanism most Swift tooling reads. So the supported surface is wide, and the branch you land on depends on the compiler your project is pinned to.
Putting the player view into a view hierarchy
The usage section is short enough to reproduce from memory, which is a compliment. You allocate the controller, assign two delegates, set the frame, and add the view as a child the way UIKit expects:
self.player = Player()
self.player.playerDelegate = self
self.player.playbackDelegate = self
self.player.view.frame = self.view.bounds
self.addChild(self.player)
self.view.addSubview(self.player.view)
self.player.didMove(toParent: self)Note the child view controller dance. `Player` is a `UIViewController` subclass, so the frame assignment and the `addChild` call are not decoration, they are the difference between a working view and one that gets its own lifecycle and rotation behaviour for free.
There is no configuration object, no storyboard, no required theme file. The feature list calls this a simple API and lists customizable UI and user interaction, orientation change support and no size restrictions alongside it. Those four claims are all verified by the code shown above, since the frame is yours to set and the view is a real controller that participates in rotation. Snapshot support is listed as a feature but is not demonstrated anywhere in the usage section, so if frame capture is why you are here, expect to read the source for it.
Three properties cover the three kinds of video you have
The design decision that makes this library pleasant is that the media source is a property assignment rather than a builder call, and there are exactly three properties for the three sources an app tends to have. A local file or a plain HTTP URL goes on `url`:
let videoUrl: URL = // file or http url
self.player.url = videoUrlA stream that needs request headers needs an AVFoundation asset, and the README spells out the exact dictionary key:
let videoUrl: URL = // http url
let headers = ["Authorization": "Bearer token123"]
let asset = AVURLAsset(url: videoUrl, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
self.player.asset = assetThat second one is the line that matters if you are behind a token-gated CDN, because plain `url` gives you no place to attach headers. And a video from the photo library goes on `playerItem` instead:
let playerItem: AVPlayerItem = // your player item
self.player.playerItem = playerItemReading the three together tells you the library is a thin shell over AVPlayer rather than a replacement for it. Nothing here is database logic or scheduling logic; it is a view, a play button, and three entry points into the framework you would otherwise use directly.
Playback progress arrives as a delegate callback
Progress reporting is a delegate extension with four methods, and only one of them carries anything you have to compute:
extension ViewController: PlayerPlaybackDelegate {
public func playerPlaybackWillStartFromBeginning(_ player: Player) {
}
public func playerPlaybackDidEnd(_ player: Player) {
}
public func playerCurrentTimeDidChange(_ player: Player) {
let fraction = Double(player.currentTime) / Double(player.maximumDuration)
self._playbackViewController?.setProgress(progress: CGFloat(fraction), animated: true)
}
public func playerPlaybackWillLoop(_ player: Player) {
self. _playbackViewController?.reset()
}
}The division is the whole mechanism: divide `currentTime` by `maximumDuration` and you have a fraction you can hand to a progress bar. There is no buffering callback in this list, which means you will not get told when the stream stalls, and there is no rate or volume API shown either. Both are reachable through the underlying `AVPlayer` since the object is exposed, but you are expected to go and find them.
Transport control is one call. `self.player.playFromBeginning()` restarts from zero, and the fill mode is set by assigning one enum:
self.player.fillMode = .resizeAspectFitThe `resizeAspectFit` default behaviour letterboxes rather than crops, and the enum offers the usual alternatives if you need to fill the frame.
The tree describes an older kind of Swift project
The repository root tells you more about the project's history than the README does. Alongside `Package.swift` and `Player.podspec` there is `Player.xcworkspace/`, a `Project/` directory holding the Xcode project, a `docs/` folder with a `build_docs.sh` script, and a `.travis.yml` file. Travis as the continuous integration system is a strong signal about the era this was built in, and it sits next to a `CLAUDE.md` file, which is a much more recent addition to the same root. Both facts are in the tree at once.
The branch naming adds a second wrinkle. The repository's default branch is `main`, while the README's image and license links both point at `master`, and the older-compiler branches are named `swift4.0` and `swift4.2`. Which of those two long-lived names carries current work is not something the README settles, so if you are following the badge links rather than the package manager you may be looking at an older snapshot of the code.
On activity, the honest reading is that the last push was on 2026-03-02, and the repository metadata carries no tagged release at all. Both of those are worth weighing before you adopt it: the code is there and the install instructions name version 0.15.0, but there is no release record here to confirm which tag you would actually be pinning.
Where the README stops and AVFoundation starts
The documentation is a jazzy-generated site hosted on GitHub Pages, and the README's resource list points at the AV Foundation Programming Guide and the Swift Evolution repository as the places where the real API lives. That boundary is the honest description of this library. It is not trying to abstract AVPlayer; it is trying to save you the twenty lines of view controller setup shown earlier.
So the questions it does not answer are the ones AVFoundation answers. Buffering and stall handling, playback rate, audio session configuration, AirPlay routing, picture-in-picture, and background audio all sit outside the demonstrated surface. Each is reachable because `Player` wraps an `AVPlayer` rather than hiding it, but reaching means writing AVFoundation code yourself, and that is where the complexity budget of your app actually goes.
There is also a small stable of sibling libraries by the same author that the README points at for adjacent jobs: PBJVideoPlayer for Objective-C, PBJVision as a camera engine, and Next Level for capture. If you are picking a video stack rather than just a player, those links are the useful part of the page. For a Swift player that stays readable, the single file is the argument, and the README does not undercut it anywhere except in the repository layout.
Editorial conclusion
Player is at its best when you want a plain video surface with a few callbacks and no configuration object to learn. The `url`, `asset` and `playerItem` properties cover the three sources a project actually has, and the rest is AVFoundation that you can drop into the view controller yourself. What the README does not settle is the build story: it documents copying one `Player.swift` file while the repository root also carries `Sources/`, `Project/` and `Player.xcworkspace/`, so check what the release archive actually contains before you plan around a single-file copy. The last push was 2026-03-02 and no tagged release is recorded in the repository metadata, so treat version pinning as something to verify in Xcode rather than assume. Start with the `Player()` allocation and the `playerPlaybackCurrentTimeDidChange` callback, since that pair covers most of what an app needs.
Frequently asked questions
Is Player still being worked on?
The repository's last recorded push is 2026-03-02, and no tagged release appears in the repository metadata even though the install instructions name version 0.15.0. The README itself has not moved on from advertising Swift 5.0 with fallback branches for 4.2 and 4.0, so check the current state in Xcode rather than relying on the version string.
How do I play a video that needs authorization headers?
Assign an AVURLAsset built with the `AVURLAssetHTTPHeaderFieldsKey` option rather than setting the `url` property, since a plain URL gives the library nowhere to attach request headers. The README shows this as the route for HTTP streams with custom headers.
Can Player show videos from the iOS photo library?
Yes, by assigning an AVPlayerItem instead of a URL. The README covers iCloud Photos and PHAsset videos through the `playerItem` property, so anything AVPlayer accepts from the photo library can be handed to Player directly.
What is the difference between Player and PBJVideoPlayer?
They are the same author's player for different languages. Player is the Swift version for iOS and tvOS, and PBJVideoPlayer is the Objective-C one. The README also links PBJVision, a camera engine, and Next Level for media capture, if you need the recording side too.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/piemonte-player)