IINA: an mpv front end for macOS whose build is pinned to dylibs, a script and one Xcode version
GitHub describes it as The modern video player for macOS.. The repository metadata lists Swift as its primary language. The metadata lists the GPL-3.0 license. This article stays within the project description and details documented in the GitHub repository README.
At a glance
- What is it?
- IINA is a macOS video player built on mpv, and most of what a reader needs to know sits in the build and contribution instructions: nightlies are generated per commit and may be unusable, only the latest public Xcode is supported, dylib versions are pinned by hand, and translations arrive through Crowdin rather than git.
- Who is it for?
- IINA fits a macOS user who wants mpv's decoding with a native interface, and it fits a contributor who has the latest public Xcode, a clean checkout and patience with a pinned dependency layout. It is a poor fit if you need a stable build from an untagged commit, if you are not on macOS 11.0 or later, or if you want to contribute a translation through git.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Nightly builds are generated for every commit, and called possibly unusable
There are three ways to get IINA, and the project is explicit about which one is not a distribution. Stable and beta releases come from the GitHub release page or iina.io. Nightly builds come from a separate nightly download page, and an IMPORTANT note says GitHub generates them automatically for every commit, that they might be buggy and unusable, and that a bug found in one should be reported through the contributing section.
That framing has a consequence for anyone evaluating the player. A crash on a nightly tells you almost nothing about the tagged releases, because the binary you ran was never meant to be a supported build. The release list reinforces the split: v1.5.0-beta2 on 2026-09-19 and v1.5.0-beta1 on 2026-09-04 are the two newest tags, both betas, while the newest full version is v1.4.4 from 2026-06-24. So a reader who wants a finished 1.5.0 has to wait, and a reader who wants something released has to decide whether a three month old 1.4.4 is acceptable.
Only the latest public Xcode is supported, and the file says so twice
Both build routes end with the same instruction: open iina.xcodeproj in the latest public version of Xcode, followed by the note that IINA may not build if you use any other version. The sentence appears once under the pre-compiled libraries route and again under the manual mpv route, which tells you it is a deliberate boundary rather than a passing remark.
The consequence for a contributor is that the toolchain is not negotiable. A machine on a beta Xcode, or on a version behind the current public release, has no documented path into the project, and the failure you would see is a build error inside iina.xcodeproj rather than a clear refusal. The default branch is develop, so an unmodified checkout is also a moving target: what compiles today is the tip of develop, and a tagged release is a different starting point. Combine the two and you have a project where the build environment and the source revision both have to be chosen deliberately, which is a real cost before any code is written.
download_libs.sh pins its artifacts, and an old tag needs the path rewritten by hand
The fast route to a build is one script:
./other/download_libs.shIts options tell you how much control you have. By default it downloads universal binaries, and arch specific ones are available with `--arch <ARCH>`, where the values are `universal`, `arm64` or `x86_64`. Files come down in parallel, 5 concurrent downloads by default, changeable with `--parallel <N>`. The important option is not a flag at all: to build an older IINA version you must change `DYLIBS_DOWNLOAD_PATH` inside the script, and the example given is a versioned file list such as `https://iina.io/dylibs/1.2.0/universal/fileList.txt`.
So the dylibs are versioned server side artifacts and the pin lives in a shell variable, not in a lockfile the build tools read. The consequence is that checking out an old tag and running the script as written gives you the current libraries rather than the ones that tag expected, and reproducing an old build means editing the script first. A contributor who wants to fix a bug in 1.4.4 has to do that before anything compiles.
Updating libmpv means running parse_doc.rb and hand replacing three Swift files
The manual route exists for when the pre-built libraries are not what you need, and step two of it is the part with consequences. You run `other/parse_doc.rb`, which fetches the latest mpv documentation and generates `MPVOption.swift`, `MPVCommand.swift` and `MPVProperty.swift`. You then copy them from `other/` into `iina/`, replacing the current files. The instruction is explicit that this is only needed when updating libmpv, and equally explicit about the risk: if the API changes, the player source code may also need to be changed.
That is the sharpest dependency in the repository. The player's entire option and command surface is generated text checked into the source tree, and the generator reads upstream documentation rather than a pinned header. The consequence for a maintainer is that a libmpv bump is not a regeneration step, it is a review of what regenerated, because a token that appears, disappears or changes type compiles cleanly and still breaks behaviour at runtime. For a user, it means the mpv features IINA exposes are whatever the last regeneration captured.
yt-dlp is symlinked by hand, under a name that still says youtube-dl
Step three of the manual route is a two line shell operation, and it is the only place in the build where a dependency is wired by hand:
mkdir -p deps/executable
ln -s $(which yt-dlp) deps/executable/youtube-dl`which yt-dlp` is evaluated at build time, so the tool has to be on your PATH before you run it, and the link is created under the older name `youtube-dl`. Steps four through eight then take place in the Xcode interface rather than the terminal: remove the `.dylib` references from the Frameworks group, add the `.dylib` files in `deps/lib` to that group, add the imported ones to the Copy Dylibs phase, and make sure the needed ones are present in the Link Binary With Libraries phase.
The consequence is that a clean checkout of the manual route does not build until you have installed yt-dlp yourself and made the link, and that the name the build looks for has not been updated to match the tool. The `deps/` directory at the top level is where both this executable and the libraries live, which is convenient for packaging and inconvenient for a build that expects a clean, scriptless setup.
Translations sync from Crowdin, so a translation pull request will not land
The contributing section routes code, bug reports and translations down three different paths. Bugs and features go to the issue tracker, with a request to search first because duplicates are tolerated but not helpful. Code goes through CONTRIBUTING.md, which is where the process for handling contributions and the shape of the codebase are explained.
Translations are different again. The page links IINA's Crowdin instance at translate.iina.io, says you can create a free account, and then says plainly: please do not send a pull request to this repo directly, because Crowdin will automatically sync new translations. A language that is not on the list costs an issue before it costs a translation session.
The consequence is that translation work is reviewed in a web tool rather than in git, and your change reaches the repository only when the sync runs. That is a sensible arrangement for a project with this many locales, and it means a translator who is comfortable with a pull request has to learn a different workflow. The `crowdin.yml` file and the `Configs/` directory at the top level are where that arrangement is configured.
plugins.json is the registry, and only three plugin identifiers are namespaced
The plugin list is split into official and community, and the split is visible in the identifiers. The official three are Online Media at `iina/plugin-online-media` for streaming and downloading, OpenSubtitles at `iina/plugin-opensub` for subtitle search, and User Scripts at `iina/plugin-userscript` for running custom JavaScript snippets. Every community plugin sits under its author's own namespace instead: `ozykhan/iina-airplay` for AirPlay, `yorkyang2333/iina-anime4k` for Anime4K shaders, `pangziqiang/iina-auto-skip` for skipping intros and outros, `glechic/iina-bilingual-audio` for left and right channel separation, `wyattowalsh/iina-plugin-bookmarks` for timestamps, `D0CA/iina-cinemode` for a fullscreen pause overlay, and `kerim/iina-clickable-subtitles`.
So the same install mechanism covers both an organisation owned plugin and a single person's repository, and only the first group is under the project's own name. The consequence for a reader is that installing a community plugin by identifier means trusting that repository name, and that enabling User Scripts means arbitrary JavaScript from that source runs inside the player. The tree backs the model with `iina-plugin/`, `plugins.json`, `iina-cli/` for the command line tool, `browser/` for the browser extensions and `OpenInIINA/`.
macOS 11.0 and a GPL-3.0 LICENSE define who can run it and who can ship it
Two constraints sit outside the code. The first is the platform: IINA describes itself as the modern video player for macOS, designed with modern versions of macOS in mind, 11.0 and later, and it is a Swift project whose build entry point is an Xcode project file. Force Touch, picture-in-picture and the advanced Touch Bar support in the feature list are the hardware and system affordances that come with that floor, and the Standalone Music Mode for audio files sits alongside them.
The second is the licence. The project is distributed under GPL-3.0, and the tree keeps LICENSE at the top level next to iina.xcodeproj and CONTRIBUTING.md. IINA is built on mpv, which the description credits with providing the best decoding capacity on macOS, so the lineage and the licence terms travel together rather than being an add-on.
The consequence is worth stating plainly. A reader on Windows or Linux is not choosing between players, they are looking at the wrong platform, which is why IINA for Windows keeps turning up as a question. And anyone planning to redistribute IINA inside a product has a licence question to answer from the LICENSE file itself, not from a description of the player.
Editorial conclusion
IINA fits a macOS user who wants mpv's decoding with a native interface, and it fits a contributor who has the latest public Xcode, a clean checkout and patience with a pinned dependency layout. It is a poor fit if you need a stable build from an untagged commit, if you are not on macOS 11.0 or later, or if you want to contribute a translation through git. Before you rely on it, check which tag you actually have, because the newest full release in the list is 1.4.4 from 2026-06-24 while 1.5.0 is still at beta, and read the licensing position yourself from the LICENSE file at the top level.
Frequently asked questions
What is IINA?
The modern video player for macOS, written in Swift, based on mpv for decoding and released under GPL-3.0. It supports macOS 11.0 and later, offers subtitles, playlists, chapters, picture-in-picture, an on screen controller and a plugin system, and ships a command line tool with browser extensions.
Is IINA safe to use?
It is based on mpv, and stable and beta releases are published on the GitHub release page and iina.io. The README warns that nightly builds are generated by GitHub for every commit and might be buggy and unusable, and notes that the User Scripts plugin runs custom JavaScript snippets.
Which is better for macOS, IINA or VLC?
The README makes no comparison with VLC. What it states is that IINA is based on mpv, which it credits with providing the best decoding capacity on macOS, and that IINA targets modern versions of macOS, 11.0 and later.
Is IINA only for Mac?
Yes. It is described as a video player for macOS designed with macOS 11.0 and later in mind, and it is a Swift project built from iina.xcodeproj in the latest public version of Xcode.
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/iina-iina)