Compare commits

..
1 Commits
Author SHA1 Message Date
Alessandro Ghedini 2da6c95208 Release 0.7.0 2014-11-25 20:18:53 +01:00
1091 changed files with 113876 additions and 220099 deletions

No files matched your search

-23
View File
@@ -1,23 +0,0 @@
# To use this config on you editor, follow the instructions at:
# http://editorconfig.org
root = true
[*]
charset = utf-8
insert_final_newline = true
indent_style = space
indent_size = 4
max_line_length = 80
trim_trailing_whitespace = true
[.git/COMMIT*]
max_line_length = 72
[{osdep/dirent-win.h,TOOLS/osxbundle/mpv.app/Contents/PkgInfo,TOOLS/osxbundle/mpv.app/Contents/Resources/Assets.car}]
charset = unset
insert_final_newline = unset
indent_style = unset
indent_size = unset
max_line_length = unset
trim_trailing_whitespace = unset
-7
View File
@@ -1,7 +0,0 @@
{
"Format": "github-actions",
"Disable": {
"IndentSize": true,
"MaxLineLength": true
}
}
@@ -1,151 +0,0 @@
name: "Report a Linux Issue"
description: "Create a report for a runtime related Linux Issue"
labels: ["os:linux"]
type: Bug
body:
- type: textarea
attributes:
label: "mpv Information"
placeholder: |
mpv v0.38.0-96-gf776be6af5 Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
built on May 5 2024 18:37:43
libplacebo version: v7.349.0 (v6.338.0-120-g7b294350)
FFmpeg version: 6.1.1
FFmpeg library versions:
libavutil 58.29.100
libavcodec 60.31.102
libavformat 60.16.100
libswscale 7.5.100
libavfilter 9.12.100
libswresample 4.12.100
description: |
Provide the output of `mpv --version`.
render: bash
validations:
required: false
- type: textarea
attributes:
label: "Other Information"
description: >
Provide following information if applicable.
- Linux Version: `cat /etc/os-release | grep "NAME"`
- Kernel Version: `uname -a`
- GPU Model: `lspci -nn | grep VGA` or `lshw -C display -numeric`
- Mesa/GPU Driver Version: `glxinfo -B | grep "OpenGL version string"` or `vulkaninfo | grep driverInfo`
- Window Manager and Version
- Source of the mpv binary
- Latest version of mpv you know without the problem
- The time when the problem started to happen (after updating mpv, system, driver, etc.)
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Packages and builds can be found [here](https://mpv.io/installation/).
value: |-
- Linux version:
- Kernel Version:
- GPU Model:
- Mesa/GPU Driver Version:
- Window Manager and Version:
- Source of mpv:
- Latest known working version:
- Issue started after the following happened:
render: text
validations:
required: true
- type: textarea
attributes:
label: "Reproduction Steps"
description: >
Try to reproduce your issue with `--no-config` first. If it isn't reproducible
with `--no-config` try to find out which option or script causes your issue.
If the issue is render performance-related, try to reproduce it with `--no-config
--profile=fast`, which is designed to work on lower-end mobile devices.
For decoding performance-related issues, additionally try to enable hardware
decoding with `--hwdec=yes` or the `Ctrl+h` shortcut.
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differs from your own.
validations:
required: true
- type: textarea
attributes:
label: "Expected Behavior"
placeholder: "What were you expecting?"
validations:
required: true
- type: textarea
attributes:
label: "Actual Behavior"
placeholder: "What happened instead?"
validations:
required: true
- type: textarea
attributes:
label: "Log File"
placeholder: "Drag and drop log file here (Don't paste content directly)"
description: >
Make a log file with `--gpu-debug --log-file=output.txt`, which is our preferred way, and
attach it to the issue.
If you have trouble producing a log file, you can alternatively use `--gpu-debug --msg-time -v -v`,
save the terminal output to a file, and attach it to the issue.
In the case of a crash, please provide a [backtrace](https://wiki.archlinux.org/title/Debugging/Getting_traces).
Without the log file, this issue will be closed for ignoring the issue template.
Disclaimer: The log file may contain identifiable information, such as your username.
Review the log file before sharing and redact any sensitive data if necessary.
validations:
required: true
- type: textarea
attributes:
label: "Sample Files"
placeholder: "Drag and drop sample files here"
description: >
Please provide sample files for a minimal reproduction case, if the issue can't be
reproduced without it or it is helpful to demonstrate the issue.
Preferably files should be attached directly within the text field below. Due to GitHub's
upload restriction, you may need to archive the sample file first and upload it as `.zip`
file. If the sample file is too big to attach directly, use a solution that is easy to
access with possible long-term retention. Possible services include, but are not limited
to, the following:
- [0x0.st](https://0x0.st/) (no long-term retention)
- [Dropbox](https://www.dropbox.com)
- [Google Drive](https://www.google.com/drive/)
- [iCLoud Drive](https://www.icloud.com/iclouddrive/)
- [MediaFire](https://www.mediafire.com/)
- [OneDrive](https://onedrive.live.com/)
- type: checkboxes
attributes:
label: "I carefully read all instruction and confirm that I did the following:"
options:
- label: "I tested with the latest mpv version to validate that the issue is not already fixed."
required: true
- label: "I provided all required information including system and mpv version."
required: true
- label: >-
I produced the log file with the exact same set of files, parameters, and conditions
used in "Reproduction Steps", with the addition of `--log-file=output.txt`.
required: true
- label: >-
I produced the log file while the behaviors described in "Actual Behavior" were
actively observed.
required: true
- label: "I attached the full, untruncated log file."
required: true
- label: "I attached the backtrace in the case of a crash."
required: true
@@ -1,146 +0,0 @@
name: "Report a macOS Issue"
description: "Create a report for a runtime related macOS Issue"
labels: ["os:mac"]
type: Bug
body:
- type: textarea
attributes:
label: "mpv Information"
placeholder: |
mpv v0.38.0-96-gf776be6af5 Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
built on May 5 2024 18:37:43
libplacebo version: v7.349.0 (v6.338.0-120-g7b294350)
FFmpeg version: 6.1.1
FFmpeg library versions:
libavutil 58.29.100
libavcodec 60.31.102
libavformat 60.16.100
libswscale 7.5.100
libavfilter 9.12.100
libswresample 4.12.100
description: |
Provide the output of `mpv --version`.
render: bash
validations:
required: false
- type: textarea
attributes:
label: "Other Information"
description: >
- macOS Version: `system_profiler SPSoftwareDataType | sed -rn 's/^ *System Version: (.*$)/\1/p'`
- Source of the mpv binary or bundle
- Latest version of mpv you know without the problem
- The time when the problem started to happen (after updating mpv, system, driver, etc.)
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Nightly builds from master can be found [here](https://github.com/mpv-player/mpv/actions/workflows/build.yml?query=branch%3Amaster+event%3Apush),
click on the latest workflow run, scroll down to the Artifacts section and download the
appropriate build. Packages and builds can be found [here](https://mpv.io/installation/).
value: |-
- macOS version:
- Source of mpv:
- Latest known working version:
- Issue started after the following happened:
render: text
validations:
required: true
- type: textarea
attributes:
label: "Reproduction Steps"
description: >
Try to reproduce your issue with `--no-config` first. If it isn't reproducible
with `--no-config` try to find out which option or script causes your issue.
If the issue is render performance-related, try to reproduce it with `--no-config
--profile=fast`, which is designed to work on lower-end mobile devices.
For decoding performance-related issues, additionally try to enable hardware
decoding with `--hwdec=yes` or the `Ctrl+h` shortcut.
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differs from your own.
validations:
required: true
- type: textarea
attributes:
label: "Expected Behavior"
placeholder: "What were you expecting?"
validations:
required: true
- type: textarea
attributes:
label: "Actual Behavior"
placeholder: "What happened instead?"
validations:
required: true
- type: textarea
attributes:
label: "Log File"
placeholder: "Drag and drop log file here (Don't paste content directly)"
description: >
Make a log file with `--gpu-debug --log-file=output.txt`, which is our preferred way, and
attach it to the issue. If you use the Bundle, a default log is created for your last run
at `~/Library/Logs/mpv.log`. You can jump to that file via the `Help > Show log File…` menu.
If you have trouble producing a log file, you can alternatively use `--gpu-debug --msg-time -v -v`,
save the terminal output to a file, and attach it to the issue.
In the case of a crash, please provide the macOS Crash Report or create a [backtrace](https://developer.apple.com/library/archive/documentation/General/Conceptual/lldb-guide/chapters/C5-Examining-The-Call-Stack.html)
yourself.
Without the log file, this issue will be closed for ignoring the issue template.
Disclaimer: The log file may contain identifiable information, such as your username.
Review the log file before sharing and redact any sensitive data if necessary.
validations:
required: true
- type: textarea
attributes:
label: "Sample Files"
placeholder: "Drag and drop sample files here"
description: >
Please provide sample files for a minimal reproduction case, if the issue can't be
reproduced without it or it is helpful to demonstrate the issue.
Preferably files should be attached directly within the text field below. Due to GitHub's
upload restriction, you may need to archive the sample file first and upload it as `.zip`
file. If the sample file is too big to attach directly, use a solution that is easy to
access with possible long-term retention. Possible services include, but are not limited
to, the following:
- [0x0.st](https://0x0.st/) (no long-term retention)
- [Dropbox](https://www.dropbox.com)
- [Google Drive](https://www.google.com/drive/)
- [iCLoud Drive](https://www.icloud.com/iclouddrive/)
- [MediaFire](https://www.mediafire.com/)
- [OneDrive](https://onedrive.live.com/)
- type: checkboxes
attributes:
label: "I carefully read all instruction and confirm that I did the following:"
options:
- label: "I tested with the latest mpv version to validate that the issue is not already fixed."
required: true
- label: "I provided all required information including system and mpv version."
required: true
- label: >-
I produced the log file with the exact same set of files, parameters, and conditions
used in "Reproduction Steps", with the addition of `--log-file=output.txt`.
required: true
- label: >-
I produced the log file while the behaviors described in "Actual Behavior" were
actively observed.
required: true
- label: "I attached the full, untruncated log file."
required: true
- label: "I attached the backtrace in the case of a crash."
required: true
@@ -1,147 +0,0 @@
name: "Report a Windows Issue"
description: "Create a report for a runtime related Windows Issue"
labels: ["os:win"]
type: Bug
body:
- type: textarea
attributes:
label: "mpv Information"
placeholder: |
mpv v0.38.0-96-gf776be6af5 Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
built on May 5 2024 18:37:43
libplacebo version: v7.349.0 (v6.338.0-120-g7b294350)
FFmpeg version: 6.1.1
FFmpeg library versions:
libavutil 58.29.100
libavcodec 60.31.102
libavformat 60.16.100
libswscale 7.5.100
libavfilter 9.12.100
libswresample 4.12.100
description: |
Provide the output of `mpv --version`.
render: bash
validations:
required: false
- type: textarea
attributes:
label: "Other Information"
description: >
- Windows Version: `cmd /c ver`
- GPU model, driver and version
- Source of the mpv binary
- Latest version of mpv you know without the problem
- The time when the problem started to happen (after updating mpv, system, driver, etc.)
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Nightly builds from master can be found [here](https://github.com/mpv-player/mpv/actions/workflows/build.yml?query=branch%3Amaster+event%3Apush),
click on the latest workflow run, scroll down to the Artifacts section and download the
appropriate build. Packages and builds can be found [here](https://mpv.io/installation/).
value: |-
- Windows version:
- GPU model, driver and version:
- Source of mpv:
- Latest known working version:
- Issue started after the following happened:
render: text
validations:
required: true
- type: textarea
attributes:
label: "Reproduction Steps"
description: >
Try to reproduce your issue with `--no-config` first. If it isn't reproducible
with `--no-config` try to find out which option or script causes your issue.
If the issue is render performance-related, try to reproduce it with `--no-config
--profile=fast`, which is designed to work on lower-end mobile devices.
For decoding performance-related issues, additionally try to enable hardware
decoding with `--hwdec=yes` or the `Ctrl+h` shortcut.
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differs from your own.
validations:
required: true
- type: textarea
attributes:
label: "Expected Behavior"
placeholder: "What were you expecting?"
validations:
required: true
- type: textarea
attributes:
label: "Actual Behavior"
placeholder: "What happened instead?"
validations:
required: true
- type: textarea
attributes:
label: "Log File"
placeholder: "Drag and drop log file here (Don't paste content directly)"
description: >
Make a log file with `--gpu-debug --log-file=output.txt`, which is our preferred way, and
attach it to the issue.
If you have trouble producing a log file, you can alternatively use `--gpu-debug --msg-time -v -v`,
save the terminal output to a file, and attach it to the issue.
In the case of a crash, please provide a backtrace, attach the appropriate `.dmp` file
from `%LOCALAPPDATA%\CrashDumps`.
Without the log file, this issue will be closed for ignoring the issue template.
Disclaimer: The log file may contain identifiable information, such as your username.
Review the log file before sharing and redact any sensitive data if necessary.
validations:
required: true
- type: textarea
attributes:
label: "Sample Files"
placeholder: "Drag and drop sample files here"
description: >
Please provide sample files for a minimal reproduction case, if the issue can't be
reproduced without it or it is helpful to demonstrate the issue.
Preferably files should be attached directly within the text field below. Due to GitHub's
upload restriction, you may need to archive the sample file first and upload it as `.zip`
file. If the sample file is too big to attach directly, use a solution that is easy to
access with possible long-term retention. Possible services include, but are not limited
to, the following:
- [0x0.st](https://0x0.st/) (no long-term retention)
- [Dropbox](https://www.dropbox.com)
- [Google Drive](https://www.google.com/drive/)
- [iCLoud Drive](https://www.icloud.com/iclouddrive/)
- [MediaFire](https://www.mediafire.com/)
- [OneDrive](https://onedrive.live.com/)
- type: checkboxes
attributes:
label: "I carefully read all instruction and confirm that I did the following:"
options:
- label: "I tested with the latest mpv version to validate that the issue is not already fixed."
required: true
- label: "I provided all required information including system and mpv version."
required: true
- label: >-
I produced the log file with the exact same set of files, parameters, and conditions
used in "Reproduction Steps", with the addition of `--log-file=output.txt`.
required: true
- label: >-
I produced the log file while the behaviors described in "Actual Behavior" were
actively observed.
required: true
- label: "I attached the full, untruncated log file."
required: true
- label: "I attached the backtrace in the case of a crash."
required: true
-144
View File
@@ -1,144 +0,0 @@
name: "Report an Issue on other platforms"
description: "Create a report for a runtime related Issue on other platforms"
labels: []
type: Bug
body:
- type: textarea
attributes:
label: "mpv Information"
placeholder: |
mpv v0.38.0-96-gf776be6af5 Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
built on May 5 2024 18:37:43
libplacebo version: v7.349.0 (v6.338.0-120-g7b294350)
FFmpeg version: 6.1.1
FFmpeg library versions:
libavutil 58.29.100
libavcodec 60.31.102
libavformat 60.16.100
libswscale 7.5.100
libavfilter 9.12.100
libswresample 4.12.100
description: |
Provide the output of `mpv --version`.
render: bash
validations:
required: false
- type: textarea
attributes:
label: "Important Information"
description: >
- Platform and Version
- GPU model, driver and version
- Source of the mpv binary
- Latest version of mpv you know without the problem
- The time when the problem started to happen (after updating mpv, system, driver, etc.)
- Possible screenshot or video of visual glitches
If you're not using git master or the latest release, update.
Packages and builds can be found [here](https://mpv.io/installation/).
value: |-
- Platform version:
- GPU model, driver and version:
- Source of mpv:
- Latest known working version:
- Issue started after the following happened:
render: text
validations:
required: true
- type: textarea
attributes:
label: "Reproduction Steps"
description: >
Try to reproduce your issue with `--no-config` first. If it isn't reproducible
with `--no-config` try to find out which option or script causes your issue.
If the issue is render performance-related, try to reproduce it with `--no-config
--profile=fast`, which is designed to work on lower-end mobile devices.
For decoding performance-related issues, additionally try to enable hardware
decoding with `--hwdec=yes` or the `Ctrl+h` shortcut.
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differs from your own.
validations:
required: true
- type: textarea
attributes:
label: "Expected Behavior"
placeholder: "What were you expecting?"
validations:
required: true
- type: textarea
attributes:
label: "Actual Behavior"
placeholder: "What happened instead?"
validations:
required: true
- type: textarea
attributes:
label: "Log File"
placeholder: "Drag and drop log file here (Don't paste content directly)"
description: >
Make a log file with `--gpu-debug --log-file=output.txt`, which is our preferred way, and
attach it to the issue.
If you have trouble producing a log file, you can alternatively use `--gpu-debug --msg-time -v -v`,
save the terminal output to a file, and attach it to the issue.
In the case of a crash, please provide a backtrace.
Without the log file, this issue will be closed for ignoring the issue template.
Disclaimer: The log file may contain identifiable information, such as your username.
Review the log file before sharing and redact any sensitive data if necessary.
validations:
required: true
- type: textarea
attributes:
label: "Sample Files"
placeholder: "Drag and drop sample files here"
description: >
Please provide sample files for a minimal reproduction case, if the issue can't be
reproduced without it or it is helpful to demonstrate the issue.
Preferably files should be attached directly within the text field below. Due to GitHub's
upload restriction, you may need to archive the sample file first and upload it as `.zip`
file. If the sample file is too big to attach directly, use a solution that is easy to
access with possible long-term retention. Possible services include, but are not limited
to, the following:
- [0x0.st](https://0x0.st/) (no long-term retention)
- [Dropbox](https://www.dropbox.com)
- [Google Drive](https://www.google.com/drive/)
- [iCLoud Drive](https://www.icloud.com/iclouddrive/)
- [MediaFire](https://www.mediafire.com/)
- [OneDrive](https://onedrive.live.com/)
- type: checkboxes
attributes:
label: "I carefully read all instruction and confirm that I did the following:"
options:
- label: "I tested with the latest mpv version to validate that the issue is not already fixed."
required: true
- label: "I provided all required information including system and mpv version."
required: true
- label: >-
I produced the log file with the exact same set of files, parameters, and conditions
used in "Reproduction Steps", with the addition of `--log-file=output.txt`.
required: true
- label: >-
I produced the log file while the behaviors described in "Actual Behavior" were
actively observed.
required: true
- label: "I attached the full, untruncated log file."
required: true
- label: "I attached the backtrace in the case of a crash."
required: true
@@ -1,71 +0,0 @@
name: "Report a build Problem"
description: "Create a report for a build related Issue"
labels: ["core:meson"]
type: Bug
body:
- type: textarea
attributes:
label: "Important Information"
description: >
- mpv version
- Platform and Version
- Meson version
If you're not using git master or the latest release, update.
Releases are listed [here](https://github.com/mpv-player/mpv/releases).
value: |-
- mpv version:
- Platform version:
- Meson version:
render: text
validations:
required: true
- type: textarea
attributes:
label: "Reproduction Steps"
description: >
Describe the reproduction steps as precise as possible. It's very likely that
the bug you experience wasn't reproduced by the developer because the workflow
differs from your own.
validations:
required: true
- type: textarea
attributes:
label: "Expected Behavior"
placeholder: "What were you expecting?"
validations:
required: true
- type: textarea
attributes:
label: "Actual Behavior"
placeholder: "What happened instead?"
validations:
required: true
- type: textarea
attributes:
label: "Log File"
placeholder: "Drag and drop log file here (Don't paste content directly)"
description: >
Attach meson-logs/meson-log.txt or meson setup build output to the issue.
Without the log file, this issue will be closed for ignoring the issue template.
validations:
required: true
- type: checkboxes
attributes:
label: "I carefully read all instruction and confirm that I did the following:"
options:
- label: "I tested with the latest mpv version to validate that the issue is not already fixed."
required: true
- label: "I provided all required information including system and mpv version."
required: true
- label: >-
I produced the log file with the exact same set of parameters, and conditions used in
"Reproduction Steps".
required: true
- label: >-
I produced the log file while the behaviors described in "Actual Behavior" were
actively observed.
required: true
- label: "I attached the full, untruncated log file."
required: true
@@ -1,56 +0,0 @@
name: "Request a new Feature"
description: "Create a request for a new feature"
labels: ["meta:feature-request"]
type: Feature
body:
- type: textarea
attributes:
label: "Expected behavior of the wanted feature"
description: >
Before requesting a new feature, make sure it hasn't been
[requested yet](https://github.com/mpv-player/mpv/labels/meta%3Afeature-request),
and isn't already supported by [mpv](https://mpv.io/manual/master/),
[ffmpeg](https://ffmpeg.org/documentation.html), or existing
[mpv scripts](https://github.com/mpv-player/mpv/wiki/User-Scripts).
If you are not sure about this, ask on
[mpv Discussions](https://github.com/mpv-player/mpv/discussions) and
[mpv IRC channel](https://mpv.io/community/) first before opening a feature request.
validations:
required: true
- type: textarea
attributes:
label: "Alternative behavior of the wanted feature"
- type: textarea
attributes:
label: "Log File"
description: >
Even if you think it's not necessary at first, it might help us later to find
possible issues. Make a log file with `--log-file=output.txt`, which is our preferred way,
and attach it to the issue.
If you have trouble producing a log file, you can alternatively use `-v -v`, save the
terminal output to a file, and attach it to the issue.
- type: textarea
attributes:
label: "Sample Files"
placeholder: "Drag and drop sample files here"
description: >
Please provide sample files in the case you request a format/codec/container dependent
feature, and it could help us test and implement it.
Preferably files should be attached directly within the text field below. Due to GitHub's
upload restriction, you may need to archive the sample file first and upload it as `.zip`
file. If the sample file is too big to attach directly, use a solution that is easy to
access with possible long-term retention. Possible services include, but are not limited
to, the following:
- [0x0.st](https://0x0.st/) (no long-term retention)
- [Dropbox](https://www.dropbox.com)
- [Google Drive](https://www.google.com/drive/)
- [iCLoud Drive](https://www.icloud.com/iclouddrive/)
- [MediaFire](https://www.mediafire.com/)
- [OneDrive](https://onedrive.live.com/)
-12
View File
@@ -1,12 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: mpv Discussions
url: https://github.com/mpv-player/mpv/discussions
about: If you have questions or want to discuss things use our GitHub Discussions
- name: mpv IRC channel
url: https://mpv.io/community/
about: Feel free to ask questions here irc://irc.libera.chat/mpv
- name: mpv IRC developer channel
url: https://mpv.io/community/
about: Ask questions related to the development of mpv here
irc://irc.libera.chat/mpv-devel
-5
View File
@@ -1,5 +0,0 @@
Read this before you submit this pull request:
https://github.com/mpv-player/mpv/blob/master/DOCS/contribute.md
Reading this link and following the rules will get your pull request reviewed
and merged faster. Nobody wants lazy pull requests.
-601
View File
@@ -1,601 +0,0 @@
name: build
on:
push:
branches:
- master
- ci
- 'release/**'
paths-ignore:
- 'DOCS/**'
- 'TOOLS/lua/**'
- '.editorconfig'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE'
- '.gitignore'
- 'Copyright'
- 'README.md'
- 'RELEASE_NOTES'
pull_request:
branches: [master]
paths-ignore:
- 'DOCS/**'
- 'TOOLS/lua/**'
- '.editorconfig'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE'
- '.gitignore'
- 'Copyright'
- 'README.md'
- 'RELEASE_NOTES'
jobs:
mingw:
runs-on: ubuntu-24.04
env:
CCACHE_BASEDIR: ${{ github.workspace }}
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_MAXSIZE: 500M
TARGET: ${{ matrix.arch }}-w64-mingw32
RUST_TARGET: ${{ matrix.arch }}-pc-windows-gnu
strategy:
fail-fast: false
matrix:
include:
- arch: i686
wine: wine32
- arch: x86_64
wine: wine64
steps:
- uses: actions/checkout@v6
- name: Get time
id: get_time
run: echo "timestamp=`date +%s%N`" >> $GITHUB_OUTPUT
- name: Restore cache
uses: actions/cache/restore@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ env.TARGET }}-${{ steps.get_time.outputs.timestamp }}
restore-keys: ${{ env.TARGET }}-
- name: Install dependencies
run: |
rustup target add ${{ env.RUST_TARGET }}
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install --no-install-recommends -y ccache g++-mingw-w64 gcc-multilib python3-pip nasm ninja-build pkgconf ${{ matrix.wine }} wine
python -m pip install meson
- name: Install Meson Wraps
run: |
mkdir subprojects -p
meson wrap install mujs
meson subprojects download
- name: Build libraries
run: |
./ci/build-mingw64.sh
- name: Build with meson
id: build
run: |
./ci/build-mingw64.sh meson pack
- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./mingw_build/meson-logs/meson-log.txt
- name: Functional test
run: |
cd artifact && wine ./mpv.com -v --no-config
env:
WINEDEBUG: '+loaddll'
- name: Run meson tests
id: tests
run: |
meson test -C mingw_build
- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./mingw_build/meson-logs/testlog.txt
- uses: actions/upload-artifact@v5
with:
name: mpv-${{ env.TARGET }}
path: mpv-git-*.zip
- name: Save Cache
uses: actions/cache/save@v4
if: always()
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ env.TARGET }}-${{ steps.get_time.outputs.timestamp }}
win32:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-pc-windows-msvc
arch: "x64"
os: "windows-latest"
- target: aarch64-pc-windows-msvc
arch: "arm64"
os: "windows-11-arm"
env:
VS: "C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise"
CC: "ccache clang"
CXX: "ccache clang++"
CC_LD: "lld-link"
CXX_LD: "lld-link"
WINDRES: "llvm-rc"
RUST_LD: "lld-link"
RUSTC: "rustc --target ${{ matrix.target }}"
CCACHE_BASEDIR: ${{ github.workspace }}
CCACHE_DIR: "${{ github.workspace }}\\.ccache"
CCACHE_MAXSIZE: 500M
steps:
- name: Disable autocrlf
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v6
- name: Get time
id: get_time
run: |
"timestamp=$((Get-Date).Ticks)" >> $env:GITHUB_OUTPUT
- name: Restore cache
uses: actions/cache/restore@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ matrix.target }}-${{ steps.get_time.outputs.timestamp }}
restore-keys: ${{ matrix.target }}-
- name: Install dependencies
run: |
python -m pip install meson==1.9.2
choco install ccache nasm
./ci/install-cmake.ps1 -arch ${{ matrix.arch }}
- name: Update Meson WrapDB
run: |
meson wrap update-db
# Explicitly download wraps, as nested projects may have older versions of them.
meson wrap install expat
meson wrap install harfbuzz
meson wrap install libpng
meson wrap install zlib
- name: Build
id: build
run: |
$env:PATH = ($env:PATH -split ';' | Where-Object { $_ -ne 'C:\Program Files\LLVM\bin' -and `
$_ -ne 'C:\Program Files\CMake\bin' -and `
$_ -ne 'C:\Strawberry\c\bin' }) -join ';'
$env:PATH = "$pwd\cmake\bin;" + $env:PATH + ';C:\Program Files\NASM'
Import-Module "$env:VS\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
Enter-VsDevShell -VsInstallPath $env:VS -SkipAutomaticLocation -DevCmdArguments "-arch=${{ matrix.arch }} -host_arch=${{ matrix.arch }}"
./ci/build-win32.ps1
- name: Print build log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt
- name: Run meson tests
id: tests
run: |
$env:PATH = ($env:PATH -split ';' | Where-Object { $_ -ne 'C:\Program Files\LLVM\bin' -and `
$_ -ne 'C:\Program Files\CMake\bin' -and `
$_ -ne 'C:\Strawberry\c\bin' }) -join ';'
$env:PATH = "$pwd\cmake\bin;" + $env:PATH + ';C:\Program Files\NASM'
Import-Module "$env:VS\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
Enter-VsDevShell -VsInstallPath $env:VS -SkipAutomaticLocation -DevCmdArguments "-arch=${{ matrix.arch }} -host_arch=${{ matrix.arch }}"
meson test -C build -t 2
- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./build/meson-logs/testlog.txt
- uses: actions/upload-artifact@v5
with:
name: mpv-${{ matrix.target }}
path: |
build/mpv.???
build/mpv-*.bat
build/vulkan-*.dll
!build/mpv.lib
- name: Save Cache
uses: actions/cache/save@v4
if: always()
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ matrix.target }}-${{ steps.get_time.outputs.timestamp }}
macos:
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: "macos-14"
arch: "arm"
xcode: "Xcode_15.0"
- os: "macos-15"
arch: "arm"
- os: "macos-15-intel"
- os: "macos-26"
arch: "arm"
- os: "macos-26"
arch: "test"
swift: "-target arm64-apple-macosx10.15"
target: "10.15"
steps:
- uses: actions/checkout@v6
- name: Remove stray upstream python binary symlinks under /usr/local
run: |
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete -print
brew unlink python && brew link --overwrite python
- name: Unlink pkg-config if the CI runner happens to have it already installed
run: |
find "$(brew config | grep HOMEBREW_PREFIX | cut -f 2- -d ' ')/bin" -lname '*/pkg-config@0*/*' -print -exec brew unlink pkg-config@0.29.2 \; -quit
- name: Change Xcode version
if: ${{ matrix.xcode != '' }}
run: |
sudo xcode-select -s /Applications/${{ matrix.xcode }}.app
- name: Install dependencies
run: |
if [[ -n "${{ matrix.homebrew }}" ]]; then
export HOMEBREW_NO_AUTO_UPDATE=1
cd "$(brew --repo homebrew/core)"
git checkout --force ${{ matrix.homebrew }}
else
brew update
fi
brew install -q autoconf automake pkgconf libtool python freetype fribidi little-cms2 \
luajit libass ffmpeg meson rust uchardet mujs libplacebo molten-vk vulkan-loader vulkan-headers
- name: Build with meson
id: build
run: |
./ci/build-macos.sh
env:
TRAVIS_OS_NAME: "${{ matrix.os }}"
SWIFT_FLAGS: "${{ matrix.swift }}"
MACOSX_DEPLOYMENT_TARGET: "${{ matrix.target }}"
- name: Create App Bundle
if: ${{ matrix.arch != 'test' }}
run: |
meson compile -C build macos-bundle
tar -czvf mpv.tar.gz -C build mpv.app
- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt
- name: Run meson tests
id: tests
run: |
meson test -C build
- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./build/meson-logs/testlog.txt
- uses: actions/upload-artifact@v5
if: ${{ matrix.arch != 'test' }}
with:
name: mpv-${{ matrix.os }}${{ matrix.arch != '' && format('-{0}', matrix.arch) || '' }}
path: mpv.tar.gz
linux:
runs-on: ubuntu-latest
container:
image: "registry.opensuse.org/home/mia/images/images/mpv-ci:stable-deps"
env:
CC: "${{ matrix.config.cc }}"
CXX: "${{ matrix.config.cxx }}"
CC_LD: "${{ matrix.config.ld }}"
CXX_LD: "${{ matrix.config.ld }}"
strategy:
matrix:
config:
- cc: "gcc"
cxx: "g++"
args: "-Db_ndebug=true"
- cc: "clang"
cxx: "clang++"
ld: "lld"
args: "-Db_lto=true -Db_lto_mode=thin"
steps:
- uses: actions/checkout@v6
- name: Build with meson
id: build
run: |
./ci/build-tumbleweed.sh ${{ matrix.config.args }}
- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt
- name: Run meson tests
id: tests
run: |
meson test -C build
- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./build/meson-logs/testlog.txt
linux-fuzz:
runs-on: ubuntu-latest
container:
image: "registry.opensuse.org/home/mia/images/images/mpv-ci:stable-deps"
env:
CC: "clang"
CXX: "clang++"
steps:
- uses: actions/checkout@v6
- name: Build with meson
id: build
run: |
meson setup build \
--werror \
-Dfuzzers=true -Dlibmpv=true -Dcplayer=false
meson compile -C build fuzzers
- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt
linux-ffmpeg-6-1:
runs-on: ubuntu-latest
container:
# We want to test ffmpeg 6.1.1 which alpine 3.19 has exactly.
# Furthermore, this is a very minimal build of mpv without commonly
# used features to test build compatibility. Musl is a nice bonus as well
image: alpine:3.19
steps:
- uses: actions/checkout@v6
- name: Install dependencies
run: |
apk update
apk add \
binutils \
ffmpeg-dev \
gcc \
git \
g++ \
libass-dev \
lua5.2-dev \
pulseaudio-dev \
libx11-dev \
libxfixes-dev \
libxkbcommon-dev \
libxrandr-dev \
libxpresent-dev \
libxscrnsaver-dev \
meson \
musl-dev \
rust \
samurai
- name: Build with meson
id: build
run: |
./ci/build-linux-old.sh
- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt
- name: Run meson tests
id: tests
run: |
meson test -C build
- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./build/meson-logs/testlog.txt
openbsd:
runs-on: ubuntu-latest # until https://github.com/actions/runner/issues/385
timeout-minutes: 15 # avoid any weirdness with the VM
steps:
- uses: actions/checkout@v6
- name: Test in OpenBSD VM
uses: cross-platform-actions/action@v0.30.0
with:
operating_system: openbsd
version: '7.8'
run: |
sudo pkg_add -U \
cmake \
ffmpeg \
git \
libarchive \
libbluray \
libcaca \
libcdio-paranoia \
libdvdnav \
libiconv \
libplacebo \
libv4l \
libxkbcommon \
luajit \
meson \
openal \
pkgconf \
pulseaudio \
python3 \
rubberband \
rust \
sdl2 \
shaderc \
spirv-cross \
spirv-headers \
uchardet \
vulkan-loader \
vulkan-headers \
zimg
./ci/build-openbsd.sh
if ! meson test -C build; then
cat ./build/meson-logs/testlog.txt
exit 1
fi
freebsd:
runs-on: ubuntu-latest # until https://github.com/actions/runner/issues/385
timeout-minutes: 15 # avoid any weirdness with the VM
steps:
- uses: actions/checkout@v6
- name: Test in FreeBSD VM
uses: cross-platform-actions/action@v0.30.0
with:
operating_system: freebsd
version: '14.3'
run: |
sudo pkg update
sudo pkg install -y \
alsa-lib \
cmake \
evdev-proto \
ffmpeg \
git \
iconv \
jackit \
libarchive \
libbluray \
libcaca \
libcdio-paranoia \
libdvdnav \
libdisplay-info \
libplacebo \
libXinerama \
libxkbcommon \
libXpresent \
libXv \
luajit \
meson \
mujs \
openal-soft \
pipewire \
pkgconf \
pulseaudio \
python3 \
rubberband \
rust \
sekrit-twc-zimg \
sdl2 \
sndio \
uchardet \
v4l_compat \
vulkan-headers \
wayland-protocols
./ci/build-freebsd.sh
if ! meson test -C build; then
cat ./build/meson-logs/testlog.txt
exit 1
fi
msys2:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- sys: "clang64"
os: "windows-latest"
- sys: "mingw64"
os: "windows-latest"
- sys: "ucrt64"
os: "windows-latest"
- sys: "clangarm64"
os: "windows-11-arm"
defaults:
run:
shell: msys2 {0}
steps:
- name: Disable autocrlf
shell: pwsh
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- uses: actions/checkout@v6
- uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.sys }}
update: true
install: git
pacboy: >-
angleproject:p
ca-certificates:p
cc:p
cppwinrt:p
ffmpeg:p
lcms2:p
libarchive:p
libass:p
libcdio-paranoia:p
libdvdnav:p
libjpeg-turbo:p
libplacebo:p
lua51:p
meson:p
ninja:p
pkgconf:p
python:p
rst2pdf:p
rubberband:p
rust:p
shaderc:p
spirv-cross:p
uchardet:p
vapoursynth:p
vulkan-devel:p
- name: Build with meson
id: build
run: |
./ci/build-msys2.sh meson
env:
SYS: ${{ matrix.sys }}
- name: Print meson log
if: ${{ failure() && steps.build.outcome == 'failure' }}
run: |
cat ./build/meson-logs/meson-log.txt
- name: Run meson tests
id: tests
run: |
meson test -C build
- name: Print meson test log
if: ${{ failure() && steps.tests.outcome == 'failure' }}
run: |
cat ./build/meson-logs/testlog.txt
-41
View File
@@ -1,41 +0,0 @@
name: Cleanup caches
on:
workflow_run:
workflows: [build]
types: [completed]
jobs:
cache:
runs-on: ubuntu-latest
steps:
- run: |
gh cache list -L 100 --json id,key,ref -S last_accessed_at -O desc --jq '
map(select(.key | startswith("x86_64-w64-mingw32-") or
startswith("i686-w64-mingw32-") or
startswith("aarch64-pc-windows-msvc-") or
startswith("x86_64-pc-windows-msvc-"))) |
group_by(.ref) |
map({
ref: .[0].ref,
caches: map({
key: .key,
prefix: (.key | capture("^(?<prefix>[\\w_-]+-)\\d+$").prefix)
}) | group_by(.prefix) | map({keys: map(.key)})
}) |
.[]
' |
while read -r group; do
pr=$(echo "$group" | jq -r '.ref | capture("refs/pull/(?<num>[0-9]+)/merge").num')
if [[ -n "$pr" ]] && [ "$(gh pr view $pr --json state --jq '.state')" != "OPEN" ]; then
keys=$(echo "$group" | jq -c '.caches | map(.keys) | .[]')
else
keys=$(echo "$group" | jq -c '.caches | map(.keys[1:]) | .[]')
fi
for key in $(echo "$keys" | jq -r '.[]'); do
gh cache delete "$key"
done
done
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-46
View File
@@ -1,46 +0,0 @@
name: comment
on:
workflow_run:
workflows: [build]
types: [completed]
jobs:
pr_comment:
if: github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
pr=$(gh pr list --state open --json headRefOid,number \
--jq '.[] | select(.headRefOid == "${{ github.event.workflow_run.head_sha }}") | .number')
if [ -z "$pr" ]; then
echo "No matching open pull request found"
exit 0
fi
artifacts=$(gh api repos/{owner}/{repo}/actions/runs/${{ github.event.workflow_run.id }}/artifacts --jq '.artifacts')
if [ "$(echo "$artifacts" | jq 'length')" -eq 0 ]; then
echo "No artifacts found"
exit 0
fi
body=$(echo "$artifacts" | jq -r '
def link: "https://nightly.link/${{ github.repository }}/actions/artifacts/\(.id).zip";
def entry: "* [\(.name)](\(link))";
"Download the artifacts for this pull request:\n<details><summary>Windows</summary>\n\n" +
(sort_by(.name) | map(select(.name | test("w64|msvc")) | entry) | join("\n")) +
"\n</details>\n<details><summary>macOS</summary>\n\n" +
(sort_by(.name) | map(select(.name | test("macos")) | entry) | join("\n")) +
"\n</details>"
')
comment_id=$(gh issue view $pr --json comments \
--jq '.comments[] | select(.author.login == "github-actions") | .id')
if [ -n "$comment_id" ]; then
edit=--edit-last
fi
gh pr comment $pr --body "$body" $edit
-26
View File
@@ -1,26 +0,0 @@
name: docs
on:
push:
branches:
- master
- ci
- 'release/**'
paths:
- 'DOCS/**'
pull_request:
branches: [master]
paths:
- 'DOCS/**'
jobs:
check-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Docs
run: |
sudo apt-get install --no-install-recommends -y python3-docutils rst2pdf
./TOOLS/docutils-wrapper.py rst2man --strip-elements-with-class=contents --halt=2 ./DOCS/man/mpv.rst mpv.1
./TOOLS/docutils-wrapper.py rst2html --halt=2 ./DOCS/man/mpv.rst mpv.html
./TOOLS/docutils-wrapper.py rst2pdf -c -b 1 --repeat-table-rows ./DOCS/man/mpv.rst -o mpv.pdf
-54
View File
@@ -1,54 +0,0 @@
name: Pull Request Fuzzing
on:
pull_request:
branches: [master]
paths-ignore:
- 'DOCS/**'
- 'TOOLS/lua/**'
- '.editorconfig'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE'
- '.gitignore'
- 'Copyright'
- 'README.md'
- 'RELEASE_NOTES'
permissions: {}
jobs:
Fuzzing:
runs-on: ubuntu-latest
permissions:
security-events: write
strategy:
fail-fast: false
matrix:
sanitizer: [address, undefined, memory]
steps:
- name: Build Fuzzers (${{ matrix.sanitizer }})
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'mpv'
language: c
sanitizer: ${{ matrix.sanitizer }}
- name: Run Fuzzers (${{ matrix.sanitizer }})
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'mpv'
language: c
fuzz-seconds: 1200
sanitizer: ${{ matrix.sanitizer }}
report-ooms: true
report-timeouts: true
output-sarif: true
- name: Upload Crash
uses: actions/upload-artifact@v5
if: failure() && steps.build.outcome == 'success'
with:
name: ${{ matrix.sanitizer }}-artifacts
path: ./out/artifacts
- name: Upload Sarif
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
-71
View File
@@ -1,71 +0,0 @@
name: lint
on:
push:
branches:
- master
- ci
- 'release/**'
pull_request:
branches: [master]
jobs:
commit-msg:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 50
- name: Lint
run: |
./ci/lint-commit-msg.py
swift:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: norio-nomura/action-swiftlint@3.2.1
lua:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: lunarmodules/luacheck@v1
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Check
id: check
uses: astral-sh/ruff-action@v3
with:
src: ". TOOLS/umpv"
- name: Suggested changes
if: ${{ failure() && steps.check.outcome == 'failure' }}
run: ruff check . TOOLS/umpv --diff
mypy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: python/mypy@master
with:
install_project_dependencies: no
options: '--check-untyped-defs'
paths: ". TOOLS/umpv"
editorconfig:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: editorconfig-checker/action-editorconfig-checker@main
- run: editorconfig-checker -config .editorconfig-checker.json
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: pre-commit/action@v3.0.1
+36 -3
View File
@@ -1,3 +1,36 @@
/subprojects/*
!/subprojects/packagefiles
!/subprojects/*.wrap
*.o
*.a
*.d
*.exe
*.pyc
.depend
/config.h
/config.mak
/config.log
/mpv
/mpv.app
/version.h
/input/input_conf.h
/tags
/TAGS
/video/out/gl_video_shaders.h
/video/out/x11_icon.inc
/demux/ebml_defs.c
/demux/ebml_types.h
/sub/osd_font.h
/player/lua/*.inc
/DOCS/man/mpv.1
/DOCS/man/mpv.aux
/DOCS/man/mpv.log
/DOCS/man/mpv.out
/DOCS/man/mpv.pdf
/DOCS/man/mpv.toc
/waf
/build
/.waf*
/.lock-waf_*
/old_build
/Makefile
-109
View File
@@ -1,109 +0,0 @@
local mp_globals = {
mp = {
fields = {
command = {},
commandv = {},
command_native = {},
command_native_async = {},
add_hook = {},
abort_async_command = {},
del_property = {},
get_property = {},
get_property_osd = {},
get_property_bool = {},
get_property_number = {},
get_property_native = {},
set_property = {},
set_property_bool = {},
set_property_number = {},
set_property_native = {},
get_time = {},
add_key_binding = {},
add_forced_key_binding = {},
remove_key_binding = {},
register_event = {},
unregister_event = {},
observe_property = {},
unobserve_property = {},
add_timeout = {},
add_periodic_timer = {},
get_opt = {},
get_script_name = {},
get_script_directory = {},
osd_message = {},
get_wakeup_pipe = {},
get_next_timeout = {},
dispatch_events = {},
register_idle = {},
unregister_idle = {},
enable_messages = {},
register_script_message = {},
unregister_script_message = {},
create_osd_overlay = {},
get_osd_size = {},
msg = {
fields = {
fatal = {},
error = {},
warn = {},
info = {},
verbose = {},
debug = {},
trace = {},
}
},
-- Not documented
-- TODO: Document or remove them
disable_key_bindings = {},
enable_key_bindings = {},
find_config_file = {},
format_time = {},
get_mouse_pos = {},
set_key_bindings = {},
set_mouse_area = {},
set_osd_ass = {},
}
},
exit = {},
unpack = {},
}
local mp_internal = {
mp = {
fields = {
-- Internal
-- TODO: Move to mp_internal module
ARRAY = { fields = { info = {}, type = {} }},
MAP = { fields = { info = {}, type = {} }},
UNKNOWN_TYPE = { fields = { info = {}, type = {} }},
_legacy_overlay = { fields = { res_x = {}, res_y = {}, data = {}, update = {} }},
cancel_timer = {},
flush_keybindings = {},
get_osd_margins = {},
input_define_section = {},
input_disable_section = {},
input_enable_section = {},
input_set_section_mouse_area = {},
keep_running = {},
log = {},
raw_abort_async_command = {},
raw_command_native_async = {},
raw_hook_add = {},
raw_hook_continue = {},
raw_observe_property = {},
raw_unobserve_property = {},
raw_wait_event = {},
request_event = {},
script_name = {},
use_suspend = {},
wait_event = {},
}
}
}
std = "min+mp"
stds = { mp = { read_globals = mp_globals } }
-- mp_internal seems to be merged with mp for other files too...
files["player/lua/defaults.lua"] = { globals = mp_internal }
files["player/lua/auto_profiles.lua"] = { globals = { "p", "get" } }
max_line_length = 100
-23
View File
@@ -1,23 +0,0 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-illegal-windows-names
- id: check-json
- id: check-shebang-scripts-are-executable
- id: check-xml
exclude: ^TOOLS/mpv-osd-symbols.sfdir/font.props$
- id: check-yaml
- id: end-of-file-fixer
exclude: ^TOOLS/osxbundle/mpv.app/Contents/PkgInfo$
- id: fix-byte-order-marker
- id: mixed-line-ending
- id: trailing-whitespace
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
args: ["--ignore-words-list", "ALS,als,datas,DNE,enew,HDA,numer,ontop,optionA,Paeth,pathc,inout,requestor"]
exclude: ^misc/language.c$
-10
View File
@@ -1,10 +0,0 @@
disabled_rules:
- identifier_name
- line_length
- large_tuple
- void_function_in_ternary
- function_body_length
- cyclomatic_complexity
- file_length
- type_body_length
strict: true
+62
View File
@@ -0,0 +1,62 @@
language: c
os:
- linux
- osx
env:
matrix:
- LIBAV=libav-stable
- LIBAV=libav-git
- LIBAV=ffmpeg-stable
- LIBAV=ffmpeg-git
global:
# Coverity token
- secure: "H21mSRlMhk4BKS0xHZvCFGJxteCP0hRVUxTuNfM2Z9HBsyutuLEYMtViLO86VtM+Tqla3xXPzUdS4ozLwI72Ax/5ZUDXACROj73yW6QhFB5D6rLut12+FjqC7M33Qv2hl0xwgNBmR5dsm1ToP37+Wn+ecJQNvN8fkTXF+HVzOEw="
compiler:
- clang
- gcc
branches:
only:
- master
- ci
- coverity_scan
matrix:
exclude:
- os: osx
env: LIBAV=libav-stable
- os: osx
env: LIBAV=libav-git
- os: osx
env: LIBAV=ffmpeg-git
- os: osx
compiler: gcc
- os: linux
env: LIBAV=ffmpeg-stable
- os: linux
compiler: clang
before_install: ./travis-deps libass-stable $LIBAV
script:
- ./bootstrap.py
- ./waf configure
- ./waf build
notifications:
email: false
irc:
channels:
- "irc.freenode.org#mpv-player-dev"
on_success: change
on_failure: always
addons:
coverity_scan:
project:
name: "mpv-player/mpv"
description: "Build submitted via Travis CI"
notification_email: mpv-team@googlegroups.com
build_command_prepend: "./bootstrap.py && ./waf configure"
build_command: "./waf build"
branch_pattern: coverity_scan
+12 -71
View File
@@ -1,78 +1,19 @@
mpv is a fork of mplayer2, which is a fork of MPlayer.
mpv as a whole is licensed under the GNU General Public License GPL version 2
or later (called GPLv2+ in this document, see LICENSE.GPL for full license
text) by default. The mpv program is licensed the GNU Lesser General Public
License LGPL version 2 or later (LGPLv2.1+ in this document, see LICENSE.LGPL
for full license text) if built without using any GPL only files.
The -Dgpl=false configure switch is provided as a convenience for excluding
the GPL only files listed below from the build process.
However, do note that the build system is provided "as is" and using the
-Dgpl=false configure switch does not in itself create a LGPLv2.1+ license
grant.
Additionally, some non-program parts, such as the documentation and some config
files listed below, are still built and licensed under their respective licenses
even when -Dgpl=false is used. Please consult GPLv2+ and LGPLv2.1+ license texts
for further details on how to distribute these files.
Most source files are LGPLv2.1+ or GPLv2+, but some files are available under
more liberal licenses, such as BSD, MIT, ISC, and possibly others. Look at the
copyright header of each source file, and grep the sources for "Copyright" if
you need to know details. C source files without Copyright notice are usually
licensed as LGPLv2.1+. Also see the list of files with specific licenses below
(not all files can have a standard license header).
All new contributions must be LGPLv2.1+ licensed. Using a more liberal license
compatible to LGPLv2.1+ is also ok.
Changes done to GPL code must come with the implicit/explicit agreement that the
project can relicense the changes to LGPLv2.1+ at a later point without asking
the contributor. This is a safeguard for making potential relicensing of
remaining GPL code to LGPLv2.1+ easier.
See DOCS/contribute.md for binding rules wrt. licensing for contributions.
mpv as a whole is licensed as GPL version 2 or later (see LICENSE). Most source
files are GPLv2+, but some files are available under a more liberal license,
such as LGPLv2+, BSD, MIT, ISC, and possibly others. Look at the copyright
header of each source file, and grep the sources for "Copyright" if you need
to know details. Files without Copyright notice are licensed as LGPLv2+.
For information about authors and contributors, consult the git log, which
contains the complete SVN and CVS history as well.
mpv can be built as LGPLv2.1+ without using any GPL only files. To add a
LGPL mode to mpv, MPlayer code had to be relicensed from GPLv2+ to LGPLv2.1+ by
asking the MPlayer authors for permission. Since permission could not be
obtained from everyone, LGPL mode disables the following features, some of them
quite central:
- Linux X11 video output
- BSD audio output via OSS
- NVIDIA/Linux hardware decoding (vdpau, although nvdec usually works)
- minor features: jack, DVD, CDDA, DVB, CACA, legacy direct3d VO
Some of these will be fixed in the future. The intended use for LGPL mode is
with libmpv, and currently it's not recommended to build mpv CLI in LGPL mode
at all.
Note that mplayer2 as a whole is licensed under GPLv3+. This is because it uses
a copy of talloc (part of Samba), which is LGPLv3+, and the next compatible
license for this mix is GPLv3+.
The following files are still GPL only (-Dgpl=false disables them):
audio/out/ao_jack.c will stay GPL
audio/out/ao_oss.c will stay GPL
stream/dvb* must stay GPL
stream/stream_cdda.c unknown
stream/stream_dvb.* must stay GPL
stream/stream_dvdnav.c unknown
video/out/vo_caca.c unknown
video/out/vo_direct3d.c unknown
video/out/vo_vaapi.c probably impossible (some company's code)
video/out/vo_vdpau.c probably impossible (nVidia's code)
video/out/vo_x11.c probably impossible
video/out/vo_xv.c probably impossible
video/out/x11_common.* probably impossible
video/vdpau.c hard (GPL-only parts must be ifdefed)
video/vdpau.h unknown
video/vdpau_mixer.* actual code must be rewritten
DOCS/man/ GPLv2+
etc/mplayer-input.conf unknown license, probably GPLv2+
etc/mpv.desktop unknown license, probably GPLv2+
etc/restore-old-bindings.conf unknown license, probably GPLv2+
None of the cases listed above affect the final binary if it's built as
LGPL. Linked libraries still can affect the final license (for example if
FFmpeg was built as GPL).
MPlayer as a whole is licensed under GPLv2 (incompatible to GPLv3!), because
some files are licensed to GPLv2 (and _not_ any later version of the license).
In particular, this affects the file libmpdemux/demux_ty_osd.c. It is disabled
under mplayer2, and has been removed from mpv.
+10 -226
View File
@@ -4,7 +4,9 @@ Introduction
This file lists all changes that can cause compatibility issues when using
mpv through the client API (libmpv and ``client.h``). Since the client API
interfaces to input handling (commands, properties) as well as command line
options, you should also look at ``interface-changes.rst``.
options, this list is interesting for other uses of mpv, such as the Lua
scripting interface, key bindings in ``input.rst``, or plain command line
usage.
Normally, changes to the C API that are incompatible to previous iterations
receive a major version bump (i.e. the first version number is increased),
@@ -16,233 +18,14 @@ The version number is the same as used for MPV_CLIENT_API_VERSION (see
``client.h`` how to convert between major/minor version numbers and the flat
32 bit integer).
Also, read the section ``Compatibility`` in ``client.h``, and compatibility.rst.
Options, commands, properties
=============================
Changes to these are not listed here, but in ``interface-changes.rst``. (Before
client API version 1.17, they were listed here partially.)
This listing includes changes to the bare C API and behavior only, not what
you can access with them.
Also, read the section ``Compatibility`` in ``client.h``.
API changes
===========
::
--- mpv 0.40.0 ---
2.5 - Deprecate MPV_RENDER_PARAM_AMBIENT_LIGHT. no replacement.
--- mpv 0.39.0 ---
2.4 - mpv_render_param with the MPV_RENDER_PARAM_ICC_PROFILE argument no
longer has incorrect assumptions about memory allocation and can be
correctly used.
--- mpv 0.38.0 ---
2.3 - partially revert the changes from API version 1.27, remove libmpv as
the default VO and move it to the bottom of the auto-probing order.
This restores the prior behavior on all platforms other than macOS,
but still auto selects libmpv/cocoa-cb on macOS if it was built with
support for cocoa-cb.
--- mpv 0.37.0 ---
2.2 - add mpv_time_ns()
--- mpv 0.36.0 ---
2.1 - add mpv_del_property()
--- mpv 0.35.0 ---
2.0 - remove headers/functions of the obsolete opengl_cb API
- remove mpv_opengl_init_params.extra_exts field
- remove deprecated mpv_detach_destroy. Use mpv_destroy instead.
- remove obsolete mpv_suspend and mpv_resume
- remove deprecated SCRIPT_INPUT_DISPATCH, PAUSE and UNPAUSE, TRACKS_CHANGED
TRACK_SWITCHED, METADATA_UPDATE, CHAPTER_CHANGE events
--- mpv 0.33.0 ---
1.109 - add MPV_RENDER_API_TYPE_SW and related (software rendering API)
- deactivate the opengl_cb API (always fails to initialize now)
The opengl_cb API was deprecated over 2 years ago. Use the render API
instead.
1.108 - Deprecate MPV_EVENT_IDLE
- add mpv_event_start_file
- add the following fields to mpv_event_end_file: playlist_entry_id,
playlist_insert_id, playlist_insert_num_entries
- add mpv_event_to_node()
- add mpv_client_id()
1.107 - Remove the deprecated qthelper.hpp. This was obviously not part of the
libmpv API, only an "additionally" provided helper, thus this is not
considered an API change. If you are maintaining a project that relies
on this header, you can simply download this file and adjust the
include statement to use it instead:
https://raw.githubusercontent.com/mpv-player/mpv/v0.32.0/libmpv/qthelper.hpp
It is a good idea to write better wrappers for your use, though.
--- mpv 0.31.0 ---
1.107 - Deprecate MPV_EVENT_TICK
--- mpv 0.30.0 ---
1.106 - Add cancel_fn to mpv_stream_cb_info
1.105 - Fix deadlock problems with MPV_RENDER_PARAM_ADVANCED_CONTROL and if
the "vd-lavc-dr" option is enabled (which it is by default).
There were no actual API changes.
API users on older API versions and mpv releases should set
"vd-lavc-dr" to "no" to avoid these issues.
API users must still adhere to the tricky rules documented in render.h
to avoid other deadlocks.
1.104 - Deprecate struct mpv_opengl_drm_params. Replaced by mpv_opengl_drm_params_v2
- Deprecate MPV_RENDER_PARAM_DRM_DISPLAY. Replaced by MPV_RENDER_PARAM_DRM_DISPLAY_V2.
1.103 - redo handling of async commands
- add mpv_event_command and make it possible to return values from
commands issued with mpv_command_async() or mpv_command_node_async()
- add mpv_abort_async_command()
1.102 - rename struct mpv_opengl_drm_osd_size to mpv_opengl_drm_draw_surface_size
- rename MPV_RENDER_PARAM_DRM_OSD_SIZE to MPV_RENDER_PARAM_DRM_DRAW_SURFACE_SIZE
--- mpv 0.29.0 ---
1.101 - add MPV_RENDER_PARAM_ADVANCED_CONTROL and related API
- add MPV_RENDER_PARAM_NEXT_FRAME_INFO and related symbols
- add MPV_RENDER_PARAM_BLOCK_FOR_TARGET_TIME
- add MPV_RENDER_PARAM_SKIP_RENDERING
- add mpv_render_context_get_info()
1.100 - bump API number to avoid confusion with mpv release versions
- actually apply the GL_MP_MPGetNativeDisplay change for the new render
API. This also means compatibility for anything but x11 and wayland
through the old opengl-cb GL_MP_MPGetNativeDisplay method is now
unsupported.
- deprecate mpv_get_wakeup_pipe(). It's complex, but easy to replace
using normal API (just set a wakeup callback to a function which
writes to a pipe).
- add a 1st class hook API, which replaces the hacky mpv_command()
based one. The old API is deprecated and will be removed soon. The
old API was never meant to be stable, while the new API is.
1.29 - the behavior of mpv_terminate_destroy() and mpv_detach_destroy()
changes subtly (see documentation in the header file). In particular,
mpv_detach_destroy() will not leave the player running in all
situations anymore (it gets closer to refcounting).
- rename mpv_detach_destroy() to mpv_destroy() (the old function will
remain valid as deprecated alias)
- add mpv_create_weak_client(), which makes use of above changes
- MPV_EVENT_SHUTDOWN is now returned exactly once if a mpv_handle
should terminate, instead of spamming the event queue with this event
1.28 - deprecate the render opengl_cb API, and replace it with render.h
and render_gl.h. The goal is allowing support for APIs other than
OpenGL. The old API is emulated with the new API.
Likewise, the "opengl-cb" VO is renamed to "libmpv".
mpv_get_sub_api() is deprecated along the opengl_cb API.
The new API is relatively similar, but not the same. The rough
equivalents are:
mpv_opengl_cb_init_gl => mpv_render_context_create
mpv_opengl_cb_set_update_callback => mpv_render_context_set_update_callback
mpv_opengl_cb_draw => mpv_render_context_render
mpv_opengl_cb_report_flip => mpv_render_context_report_swap
mpv_opengl_cb_uninit_gl => mpv_render_context_free
The VO opengl-cb is also renamed to "libmpv".
Also, the GL_MP_MPGetNativeDisplay pseudo extension is not used by the
render API anymore, and the old opengl-cb API only handles the "x11"
and "wl" names anymore. Support for everything else has been removed.
The new render API uses proper API parameters, e.g. for X11 you pass
MPV_RENDER_PARAM_X11_DISPLAY directly.
- deprecate the qthelper.hpp header file. This provided some C++ helper
utility functions for Qt with use of libmpv. There is no reason to
keep this in the mpv git repository, nor to make it part of the libmpv
API. If you're using this header, you can safely copy it into your
project - it uses only libmpv public API. Alternatively, it could be
maintained in a separate repository by interested parties.
1.27 - make opengl-cb the default VO. This causes a subtle behavior change
if the API user called mpv_opengl_cb_init_gl(), but does not set
the "vo" option. Before, it would still have used another VO (like
on the CLI, e.g. vo=gpu). Now it'll behave as if vo=opengl-cb was
used.
--- mpv 0.28.0 ---
1.26 - remove glMPGetNativeDisplay("drm") support
- add mpv_opengl_cb_window_pos and mpv_opengl_cb_drm_params and
support via glMPGetNativeDisplay() for using it
- make --stop-playback-on-init-failure=no the default in libmpv (just
like in mpv CLI)
--- mpv 0.27.0 ---
1.25 - remove setting "no-" options via mpv_set_option*(). (See corresponding
deprecation in 0.23.0.)
--- mpv 0.25.0 ---
1.24 - add a MPV_ENABLE_DEPRECATED preprocessor symbol, which can be defined
by the user to exclude deprecated API symbols from the C headers
--- mpv 0.23.0 ---
1.24 - the deprecated mpv_suspend() and mpv_resume() APIs now do nothing.
--- mpv 0.22.0 ---
1.23 - deprecate setting "no-" options via mpv_set_option*(). For example,
instead of "no-video=" you should set "video=no".
- do not override the SIGPIPE signal handler anymore. This was done as
workaround for the FFmpeg TLS code, which has been fixed long ago.
- deprecate mpv_suspend() and mpv_resume(). They will be stubbed out
in mpv 0.23.0.
- make mpv_set_property() work to some degree before mpv_initialize().
It can now be used instead of mpv_set_option().
- semi-deprecate mpv_set_option()/mpv_set_option_string(). You should
use mpv_set_property() instead. There are some deprecated properties
which conflict with some options (see client.h remarks on
mpv_set_option()), for which mpv_set_option() might still be required.
In future mpv releases, the conflicting deprecated options/properties
will be removed, and mpv_set_option() will internally translate API
calls to mpv_set_property().
- qthelper.hpp: deprecate get_property_variant, set_property_variant,
set_option_variant, command_variant, and replace them with
get_property, set_property, command.
--- mpv 0.19.0 ---
1.22 - add stream_cb API for custom protocols
--- mpv 0.18.1 ---
---- - remove "status" log level from mpv_request_log_messages() docs. This
is 100% equivalent to "v". The behavior is still the same, thus no
actual API change.
--- mpv 0.18.0 ---
1.21 - mpv_set_property() changes behavior with MPV_FORMAT_NODE. Before this
change it rejected mpv_nodes with format==MPV_FORMAT_STRING if the
property was not a string or did not have special mechanisms in place
the function failed. Now it always invokes the option string parser,
and mpv_node with a basic data type works exactly as if the function
is invoked with that type directly. This new behavior is equivalent
to mpv_set_option().
This also affects the mp.set_property_native() Lua function.
- generally, setting choice options/properties with "yes"/"no" options
can now be set as MPV_FORMAT_FLAG
- reading a choice property as MPV_FORMAT_NODE will now return a
MPV_FORMAT_FLAG value if the choice is "yes" (true) or "no" (false)
This implicitly affects Lua and JSON IPC interfaces as well.
- big changes to vo-cmdline on vo_opengl and vo_opengl_hq (but not
vo_opengl_cb): options are now normally not reset, but applied on top
of the current options. The special undocumented value "-" still
works, but now resets all options to before any vo-cmdline command
has been called.
--- mpv 0.12.0 ---
1.20 - deprecate "GL_MP_D3D_interfaces"/"glMPGetD3DInterface", and introduce
"GL_MP_MPGetNativeDisplay"/"glMPGetNativeDisplay" (this is a
backwards-compatible rename)
--- mpv 0.11.0 ---
--- mpv 0.10.0 ---
1.19 - add "GL_MP_D3D_interfaces" pseudo extension to make it possible to
use DXVA2 in OpenGL fullscreen mode in some situations
- mpv_request_log_messages() now accepts "terminal-default" as parameter
1.18 - add MPV_END_FILE_REASON_REDIRECT, and change behavior of
MPV_EVENT_END_FILE accordingly
- a bunch of interface-changes.rst changes
1.17 - mpv_initialize() now blocks SIGPIPE (details see client.h)
--- mpv 0.9.0 ---
1.16 - add mpv_opengl_cb_report_flip()
- introduce mpv_opengl_cb_draw() and deprecate mpv_opengl_cb_render()
- add MPV_FORMAT_BYTE_ARRAY
1.15 - mpv_initialize() will now load config files. This requires setting
the "config" and "config-dir" options. In particular, it will load
mpv.conf.
- minor backwards-compatible change to the "seek" and "screenshot"
commands (new flag syntax, old additional args deprecated)
--- mpv 0.8.0 ---
1.14 - add mpv_wait_async_requests()
- the --msg-level option changes its native type from a flat string to
a key-value list (setting/reading the option as string still works)
1.13 - add MPV_EVENT_QUEUE_OVERFLOW
1.12 - add class Handle to qthelper.hpp
- improve opengl_cb.h API uninitialization behavior, and fix the qml
example
- add mpv_create_client() function
1.11 - add OpenGL rendering interop API - allows an application to combine
its own and mpv's OpenGL rendering
Warning: this API is not stable yet - anything in opengl_cb.h might
be changed in completely incompatible ways in minor API bumps
--- mpv 0.7.0 ---
--- mpv 0.7.0 is released ---
1.10 - deprecate/disable everything directly related to script_dispatch
(most likely affects nobody)
1.9 - add enum mpv_end_file_reason for mpv_event_end_file.reason
@@ -265,7 +48,7 @@ API changes
1.6 - modify "core-idle" property behavior
- MPV_EVENT_LOG_MESSAGE now always sends complete lines
- introduce numeric log levels (mpv_log_level)
--- mpv 0.6.0 ---
--- mpv 0.6.0 is released ---
1.5 - change in X11 and "--wid" behavior again. The previous change didn't
work as expected, and now the behavior can be explicitly controlled
with the "input-x11-keyboard" option. This is only a temporary
@@ -274,7 +57,7 @@ API changes
although the old option name still works.
1.4 - subtle change in X11 and "--wid" behavior
(this change was added to 0.5.2, and broke some things, see #1090)
--- mpv 0.5.0 ---
--- mpv 0.5.0 is released ---
1.3 - add MPV_MAKE_VERSION()
1.2 - remove "stream-time-pos" property (no replacement)
1.1 - remap dvdnav:// to dvd://
@@ -285,6 +68,7 @@ API changes
- extend the "--start" option; a leading "+", which was previously
insignificant is now significant
- add "cache-free" and "cache-used" properties
- macOS: the "coreaudio" AO spdif code is split into a separate AO
--- mpv 0.4.0 ---
- OSX: the "coreaudio" AO spdif code is split into a separate AO
--- mpv 0.4.0 is released ---
1.0 - the API is declared stable
+181
View File
@@ -0,0 +1,181 @@
// Plays a video from the command line in a window provided by mpv.
// You likely want to play the video in your own window instead,
// but that's not quite ready yet.
// You may need a basic Info.plist and MainMenu.xib to make this work.
#include "../../libmpv/client.h"
#include "shared.h"
#import <Cocoa/Cocoa.h>
@interface CocoaWindow : NSWindow
@end
@implementation CocoaWindow
- (BOOL)canBecomeMainWindow { return YES; }
- (BOOL)canBecomeKeyWindow { return YES; }
@end
@interface AppDelegate : NSObject <NSApplicationDelegate>
{
mpv_handle *mpv;
dispatch_queue_t queue;
NSWindow *w;
}
@end
static void wakeup(void *);
@implementation AppDelegate
- (void)createWindow {
int mask = NSTitledWindowMask|NSClosableWindowMask|
NSMiniaturizableWindowMask|NSResizableWindowMask;
self->w = [[CocoaWindow alloc]
initWithContentRect:NSMakeRect(0,0, 1280, 720)
styleMask:mask
backing:NSBackingStoreBuffered
defer:NO];
[self->w setTitle:@"cocoabasic example"];
[self->w makeMainWindow];
[self->w makeKeyAndOrderFront:nil];
NSMenu *m = [[NSMenu alloc] initWithTitle:@"AMainMenu"];
NSMenuItem *item = [m addItemWithTitle:@"Apple" action:nil keyEquivalent:@""];
NSMenu *sm = [[NSMenu alloc] initWithTitle:@"Apple"];
[m setSubmenu:sm forItem:item];
[sm addItemWithTitle: @"Shutdown mpv" action:@selector(shutdown) keyEquivalent:@"s"];
[NSApp setMenu:m];
[NSApp activateIgnoringOtherApps:YES];
}
- (void) applicationDidFinishLaunching:(NSNotification *)notification {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
atexit_b(^{
// Because activation policy has just been set to behave like a real
// application, that policy must be reset on exit to prevent, among
// other things, the menubar created here from remaining on screen.
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
});
// Read filename
NSArray *args = [NSProcessInfo processInfo].arguments;
if (args.count < 2) {
NSLog(@"Expected filename on command line");
exit(1);
}
NSString *filename = args[1];
[self createWindow];
// Deal with MPV in the background.
queue = dispatch_queue_create("mpv", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
mpv = mpv_create();
if (!mpv) {
printf("failed creating context\n");
exit(1);
}
int64_t wid = (intptr_t) [self->w contentView];
check_error(mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid));
// Maybe set some options here, like default key bindings.
// NOTE: Interaction with the window seems to be broken for now.
check_error(mpv_set_option_string(mpv, "input-default-bindings", "yes"));
// for testing!
check_error(mpv_set_option_string(mpv, "input-media-keys", "yes"));
check_error(mpv_set_option_string(mpv, "input-cursor", "no"));
check_error(mpv_set_option_string(mpv, "input-vo-keyboard", "yes"));
// request important errors
check_error(mpv_request_log_messages(mpv, "warn"));
check_error(mpv_initialize(mpv));
// Register to be woken up whenever mpv generates new events.
mpv_set_wakeup_callback(mpv, wakeup, (__bridge void *) self);
// Load the indicated file
const char *cmd[] = {"loadfile", filename.UTF8String, NULL};
check_error(mpv_command(mpv, cmd));
});
}
- (void) handleEvent:(mpv_event *)event
{
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN:
// Clean up and shut down.
mpv_terminate_destroy(mpv);
mpv = NULL;
dispatch_async(dispatch_get_main_queue(), ^{
[[NSApplication sharedApplication] terminate:nil];
});
break;
case MPV_EVENT_LOG_MESSAGE: {
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
printf("[%s] %s: %s", msg->prefix, msg->level, msg->text);
}
case MPV_EVENT_VIDEO_RECONFIG:
dispatch_async(dispatch_get_main_queue(), ^{
[self->w selectNextKeyView:nil];
});
default:
printf("event: %s\n", mpv_event_name(event->event_id));
}
}
- (void) readEvents
{
dispatch_async(queue, ^{
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
[self handleEvent:event];
}
});
}
static void wakeup(void *context) {
AppDelegate *a = (__bridge AppDelegate *) context;
[a readEvents];
}
// Ostensibly, mpv's window would be hooked up to this.
- (BOOL) windowShouldClose:(id)sender
{
[self shutdown];
if (self->w)
[self->w release];
return YES;
}
- (void) shutdown
{
if (mpv) {
const char *args[] = {"quit", NULL};
mpv_command(mpv, args);
}
}
@end
// Delete this if you already have a main.m.
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
AppDelegate *delegate = [AppDelegate new];
app.delegate = delegate;
[app run];
}
return EXIT_SUCCESS;
}
+219
View File
@@ -0,0 +1,219 @@
// License: pick one of: public domain, WTFPL, ISC, Ms-PL, AGPLv3
// This example can be built with: qmake && make
#include <clocale>
#include <sstream>
#include <QtGlobal>
#include <QFileDialog>
#include <QStatusBar>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QApplication>
#include <QTextEdit>
#if QT_VERSION >= 0x050000
#include <QJsonDocument>
#endif
#include <mpv/qthelper.hpp>
#include "qtexample.h"
static void wakeup(void *ctx)
{
// This callback is invoked from any mpv thread (but possibly also
// recursively from a thread that is calling the mpv API). Just notify
// the Qt GUI thread to wake up (so that it can process events with
// mpv_wait_event()), and return as quickly as possible.
MainWindow *mainwindow = (MainWindow *)ctx;
QCoreApplication::postEvent(mainwindow, new QEvent(QEvent::User));
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setWindowTitle("Qt embedding demo");
setMinimumSize(640, 480);
QMenu *menu = menuBar()->addMenu(tr("&File"));
QAction *on_open = new QAction(tr("&Open"), this);
on_open->setShortcuts(QKeySequence::Open);
on_open->setStatusTip(tr("Open a file"));
connect(on_open, SIGNAL(triggered()), this, SLOT(on_file_open()));
menu->addAction(on_open);
statusBar();
QMainWindow *log_window = new QMainWindow(this);
log = new QTextEdit(log_window);
log->setReadOnly(true);
log_window->setCentralWidget(log);
log_window->setWindowTitle("mpv log window");
log_window->setMinimumSize(500, 50);
log_window->show();
mpv = mpv_create();
if (!mpv)
throw "can't create mpv instance";
// Create a video child window. Force Qt to create a native window, and
// pass the window ID to the mpv wid option. Works on: X11, win32, Cocoa
mpv_container = new QWidget(this);
setCentralWidget(mpv_container);
mpv_container->setAttribute(Qt::WA_DontCreateNativeAncestors);
mpv_container->setAttribute(Qt::WA_NativeWindow);
// If you have a HWND, use: int64_t wid = (intptr_t)hwnd;
int64_t wid = mpv_container->winId();
mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);
// Enable default bindings, because we're lazy. Normally, a player using
// mpv as backend would implement its own key bindings.
mpv_set_option_string(mpv, "input-default-bindings", "yes");
// Enable keyboard input on the X11 window. For the messy details, see
// --input-vo-keyboard on the manpage.
mpv_set_option_string(mpv, "input-vo-keyboard", "yes");
// Let us receive property change events with MPV_EVENT_PROPERTY_CHANGE if
// this property changes.
mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);
mpv_observe_property(mpv, 0, "track-list", MPV_FORMAT_NODE);
mpv_observe_property(mpv, 0, "chapter-list", MPV_FORMAT_NODE);
// Request log messages with level "info" or higher.
// They are received as MPV_EVENT_LOG_MESSAGE.
mpv_request_log_messages(mpv, "info");
// From this point on, the wakeup function will be called. The callback
// can come from any thread, so we use the Qt QEvent mechanism to relay
// the wakeup in a thread-safe way.
mpv_set_wakeup_callback(mpv, wakeup, this);
if (mpv_initialize(mpv) < 0)
throw "mpv failed to initialize";
}
void MainWindow::handle_mpv_event(mpv_event *event)
{
switch (event->event_id) {
case MPV_EVENT_PROPERTY_CHANGE: {
mpv_event_property *prop = (mpv_event_property *)event->data;
if (strcmp(prop->name, "time-pos") == 0) {
if (prop->format == MPV_FORMAT_DOUBLE) {
double time = *(double *)prop->data;
std::stringstream ss;
ss << "At: " << time;
statusBar()->showMessage(QString::fromStdString(ss.str()));
} else if (prop->format == MPV_FORMAT_NONE) {
// The property is unavailable, which probably means playback
// was stopped.
statusBar()->showMessage("");
}
} else if (strcmp(prop->name, "chapter-list") == 0 ||
strcmp(prop->name, "track-list") == 0)
{
// Dump the properties as JSON for demo purposes.
#if QT_VERSION >= 0x050000
if (prop->format == MPV_FORMAT_NODE) {
QVariant v = mpv::qt::node_to_variant((mpv_node *)prop->data);
// Abuse JSON support for easily printing the mpv_node contents.
QJsonDocument d = QJsonDocument::fromVariant(v);
append_log("Change property " + QString(prop->name) + ":\n");
append_log(d.toJson().data());
}
#endif
}
break;
}
case MPV_EVENT_VIDEO_RECONFIG: {
// Retrieve the new video size.
int64_t w, h;
if (mpv_get_property(mpv, "dwidth", MPV_FORMAT_INT64, &w) >= 0 &&
mpv_get_property(mpv, "dheight", MPV_FORMAT_INT64, &h) >= 0 &&
w > 0 && h > 0)
{
// Note that the MPV_EVENT_VIDEO_RECONFIG event doesn't necessarily
// imply a resize, and you should check yourself if the video
// dimensions really changed.
// mpv itself will scale/letter box the video to the container size
// if the video doesn't fit.
std::stringstream ss;
ss << "Reconfig: " << w << " " << h;
statusBar()->showMessage(QString::fromStdString(ss.str()));
}
break;
}
case MPV_EVENT_LOG_MESSAGE: {
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
std::stringstream ss;
ss << "[" << msg->prefix << "] " << msg->level << ": " << msg->text;
append_log(QString::fromStdString(ss.str()));
break;
}
case MPV_EVENT_SHUTDOWN: {
mpv_terminate_destroy(mpv);
mpv = NULL;
break;
}
default: ;
// Ignore uninteresting or unknown events.
}
}
bool MainWindow::event(QEvent *event)
{
// QEvent::User is sent by wakeup().
if (event->type() == QEvent::User) {
// Process all events, until the event queue is empty.
while (mpv) {
mpv_event *event = mpv_wait_event(mpv, 0);
if (event->event_id == MPV_EVENT_NONE)
break;
handle_mpv_event(event);
}
return true;
}
return QMainWindow::event(event);
}
void MainWindow::on_file_open()
{
QString filename = QFileDialog::getOpenFileName(this, "Open file");
if (mpv) {
const QByteArray c_filename = filename.toUtf8();
const char *args[] = {"loadfile", c_filename.data(), NULL};
mpv_command_async(mpv, 0, args);
}
}
void MainWindow::append_log(const QString &text)
{
QTextCursor cursor = log->textCursor();
cursor.movePosition(QTextCursor::End);
cursor.insertText(text);
log->setTextCursor(cursor);
}
MainWindow::~MainWindow()
{
if (mpv)
mpv_terminate_destroy(mpv);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Qt sets the locale in the QApplication constructor, but libmpv requires
// the LC_NUMERIC category to be set to "C", so change it back.
std::setlocale(LC_NUMERIC, "C");
MainWindow w;
w.show();
return a.exec();
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef QTEXAMPLE_H
#define QTEXAMPLE_H
#include <QMainWindow>
#include <mpv/client.h>
class QTextEdit;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
virtual bool event(QEvent *event);
private slots:
void on_file_open();
private:
QWidget *mpv_container;
mpv_handle *mpv;
QTextEdit *log;
void append_log(const QString &text);
void create_player();
void handle_mpv_event(mpv_event *event);
};
#endif // QTEXAMPLE_H
+12
View File
@@ -0,0 +1,12 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = qtexample
TEMPLATE = app
CONFIG += link_pkgconfig debug
PKGCONFIG = mpv
SOURCES += qtexample.cpp
HEADERS += qtexample.h
+10
View File
@@ -0,0 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
static inline void check_error(int status)
{
if (status < 0) {
printf("mpv API error: %s\n", mpv_error_string(status));
exit(1);
}
}
+45
View File
@@ -0,0 +1,45 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "libmpv/client.h"
#include "shared.h"
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("pass a single media file as argument\n");
return 1;
}
mpv_handle *ctx = mpv_create();
if (!ctx) {
printf("failed creating context\n");
return 1;
}
// Enable default key bindings, so the user can actually interact with
// the player (and e.g. close the window).
check_error(mpv_set_option_string(ctx, "input-default-bindings", "yes"));
mpv_set_option_string(ctx, "input-x11-keyboard", "yes");
int val = 1;
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
// Done setting up options.
check_error(mpv_initialize(ctx));
// Play this file.
const char *cmd[] = {"loadfile", argv[1], NULL};
check_error(mpv_command(ctx, cmd));
// Let it play, and wait until the user quits.
while (1) {
mpv_event *event = mpv_wait_event(ctx, 10000);
printf("event: %s\n", mpv_event_name(event->event_id));
if (event->event_id == MPV_EVENT_SHUTDOWN)
break;
}
mpv_terminate_destroy(ctx);
return 0;
}
-195
View File
@@ -1,195 +0,0 @@
CLI and API compatibility policy
================================
Human users and API users rely on the mpv/libmpv/scripting/IPC interface not
breaking their use case. On the other hand, active development occasionally
requires breaking things, such as removing old options or changing options in
a way that may break.
This document lists rules when, what, and how incompatible changes can be made.
It's interesting both for mpv developers, who want to change user-visible parts,
and mpv users, who want to know what is guaranteed to remain stable.
Any of the rules below may be overridden by statements in more specific
documentation (for example, if the manpage says that a particular option may be
removed any time, it means that, and the option probably won't even go through
deprecation).
Additions
---------
Additions are basically always allowed. API users etc. are supposed to deal with
the possibility that for example new API functions are added. Some parts of the
API may document how they are extended.
Options, commands, properties, events, hooks (command interface)
----------------------------------------------------------------
All of these are important for interfacing both with end users and API users
(which include Lua scripts, libmpv, and the JSON IPC). As such, they constitute
a large part of the user interface and APIs.
Certain options and commands may have documented default values. These default
values are considered a part of the API since scripts may already rely on these
documented behaviors. Changing these defaults are considered incompatible
changes and must be documented. Undocumented default values do not subject to
this requirement, and it is recommended to discourage such usage in the related
documentations if there is a need to frequently change such defaults.
All incompatible changes to this must be declared in interface-changes.rst,
which include the types of changes, the impact of these changes, and suggested
actions to address such impact so that the incompatibility is alleviated.
(This may also list compatible additions, but it's not a requirement.)
Degrees of importance and compatibility preservation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Critical and central parts of the command interface have the strictest
requirements. It may not be reasonable to break them, and other means to achieve
some change have to be found. For example, the "seek" command is a bit of a
mess, but since changing it would likely affect almost every user, it may be
impossible to break at least the commonly used syntax. If changed anyway, there
should be a deprecation period of at least 1 year, during which the command
still works, and possibly a warning should remain even after this.
Important/often used parts must be deprecated for at least 2 releases before
they can be broken. There must be at least 1 release where the deprecated
functionality still works, and a replacement is available (if technically
reasonable). For example, a feature deprecated in mpv 0.30.0 may be removed in
mpv 0.32.0. Minor releases do not count towards this.
Under extraordinary circumstances, such as missed incompatible changes that are
already included in a release, critical security fixes, or a severe shortage of
developer time to address the known incompatible changes, important/often used
parts may be broken immediately, but the change must be extensively documented:
all of the related documentations (including manpage, interface-changes.rst,
etc., retrospectively modified if applicable) must clearly state the following:
the fact that the change is a breaking change; the version when the breaking
change happened; and the reason, impact, and suggested remedy actions.
Less useful parts can be broken immediately, but must come with some sort of
removal warning.
Parts for debugging and testing may be removed any time, potentially even
without any sort of documentation.
Currently, the importance of a part is not documented and not even well-defined,
which is probably a mistake.
Renaming or removing options
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Typically, renaming an option can be done in a compatible way with OPT_REPLACED.
You may need to check whether the corresponding properties still work (including
messy details like observing properties for changes).
OPT_REMOVED can be used to inform the user of alternatives or reasons for the
removal, which is better than an option not found error. Likewise,
m_option.deprecation_message should be set to something helpful.
Both OPT_REPLACED and OPT_REMOVED can remain in the code for a long time, since
they're unintrusive and hopefully make incompatible changes less painful for
users.
Scripting APIs
--------------
This affects internal scripting APIs (currently Lua and JavaScript).
Vaguely the same rules as with the command interface apply. Since there is a
large number of scripts, an effort should be made to provide compatibility
for old scripts, but it does not need to be stronger than that of the command
interface.
Undocumented parts of the scripting APIs are _not_ guaranteed for compatibility.
This applies especially for internals. Languages like Lua do not have strict
access control (nor does the mpv code try to emulate any), so if a script
accesses private parts, and breaks on the next mpv release, it's not mpv's
problem.
JSON IPC
--------
The JSON IPC is a thin protocol wrapping the libmpv API and the command
interface. Compatibility-wise, it's about the same as the scripting APIs.
The JSON protocol commands should remain as compatible as possible, and it
should probably accept the current way commands are delimited (line breaks)
forever.
The protocol may accept non-standard JSON extensions, but only standard JSON
(possibly with restrictions) is guaranteed for compatibility. Clients which want
to remain compatible should not use any extensions.
CLI
---
Things such as default key bindings do not necessarily require compatibility.
However, the release notes should be extremely clear on changes to "important"
key bindings. Bindings which restore the old behavior should be added to
restore-old-bindings.conf and restore-osc-bindings.conf.
Some option parsing is CLI-only and not available from libmpv or scripting. No
compatibility guarantees come with them. However, the rules which mpv uses to
distinguish between options and filenames must remain consistent (if the
non-deprecated options syntax is used).
Terminal and log output
-----------------------
There are no compatibility guarantees for the terminal output, or the text
logged via ``MPV_EVENT_LOG_MESSAGE`` and similar APIs. In particular, scripts
invoking mpv CLI are extremely discouraged from trying to parse text output,
and should use other mechanisms such as the JSON IPC.
Protocols, filters, demuxers, etc.
----------------------------------
Which of these are present is generally not guaranteed, and can even depend
on compile time settings.
The filter list and their sub-options are considered part of the
command-interface.
libmpv C API
------------
The libmpv client API (such as ``<mpv/client.h>``) mostly gives access to
the command interface. The API itself (if looked at as a component separate
from the command interface) is intended to be extremely stable.
All API changes are documented in client-api-changes.rst.
API compatibility
^^^^^^^^^^^^^^^^^
The API is *always* compatible. Incompatible changes are only allowed on major
API version changes (see ``MPV_CLIENT_API_VERSION``). A major version change is
an extremely rare event, which means usually no API symbols are ever removed.
Essentially removing API functions by making them always return an error, or
making it do nothing is allowed in cases where it is unlikely to break most
clients, but requires a deprecation period of 2 releases. (This has happened to
``mpv_suspend()`` for example.)
API symbols can be deprecated. This should be clearly marked in the doxygen
with ``@deprecated``, and if possible, the affected API symbols should not be
visible if the API user defines ``MPV_ENABLE_DEPRECATED`` to 0.
ABI compatibility
^^^^^^^^^^^^^^^^^
The ABI must never be broken, except on major API version changes. For example,
constants don't change their values.
Structs are tricky. If a struct can be allocated by a user (such as ``mpv_node``),
no fields can be added. (Unless it's an union, and the addition does not change
the offset or alignment of any of the fields or the struct itself. This has
happened to ``mpv_node`` in the past.) If a struct is allocated by libmpv only,
new fields can be appended to the end (for example ``mpv_event``).
The ABI is only backward compatible. This means if a host application is linked
to an older libmpv, and libmpv is updated to a newer version, it will still
work (as in not causing any undefined behavior).
Forward compatibility (an application would work with an older libmpv than it
was linked to) is not required.
-262
View File
@@ -1,262 +0,0 @@
# Compiling for Windows
Compiling for Windows is supported using GNU-like compilers (GCC/Clang). Clang
is compatible with both the ``w64-windows-gnu`` [MinGW-w64](https://www.mingw-w64.org/)
and ``pc-windows-msvc`` [Windows SDK](https://developer.microsoft.com/windows/downloads/windows-sdk)
targets. It supports the production of both 32-bit and 64-bit binaries and is
suitable for building on Windows as well as cross-compiling from Linux and Cygwin.
Although it is possible to build a complete MinGW-w64 toolchain yourself, there
are build environments and scripts available to simplify the process, such as
MSYS2 on Windows or a packaged toolchain provided by your favorite Linux
distribution. Note that MinGW-w64 environments included in Linux distributions
can vary in versions. As a general guideline, mpv only supports the MinGW-w64
toolchain version included in the latest Ubuntu LTS release.
mpv employs Meson for building, and the process is the same as any standard Meson
compilation.
For the most up-to-date reference on build scripts, you can refer to
[build.yml](https://github.com/mpv-player/mpv/blob/master/.github/workflows/build.yml),
which builds and tests all supported configurations: ``MinGW-w64``, ``Windows SDK``,
and ``MSYS2`` builds.
## Cross-compilation
When cross-compiling, it is recommended to use a Meson ``--cross-file`` to set up the
cross-compiling environment. For a basic example, please refer to
[Cross-compilation](https://mesonbuild.com/Cross-compilation.html).
Alternatively, consider using [mpv-winbuild-cmake](https://github.com/shinchiro/mpv-winbuild-cmake),
which bootstraps a MinGW-w64 toolchain and builds mpv along with its dependencies.
### Example with Meson
1. Create ``cross-file.txt`` with definitions for your toolchain and target platform.
Refer to [x86_64-w64-mingw32.txt](https://mesonbuild.com/Cross-compilation.html)
as a directly usable example.
- **Important**: Beware of pkg-config usage. By default, it uses build machine
files for dependency detection, even when ``--cross-file`` is used. It must
be configured correctly. Refer to ``pkg_config_libdir`` and ``sys_root``
in the [documentation](https://mesonbuild.com/Cross-compilation.html#defining-the-environment)
for proper setup. **In this example pkg-config is not used/required.**
2. Initialize subprojects. This step is optional; other methods are also
available to provide the necessary dependencies.
``` bash
# Update the subprojects database from Meson's WrapDB.
meson wrap update-db
# Explicitly download wraps as nested projects may have older versions of them.
meson wrap install expat
meson wrap install harfbuzz
meson wrap install libpng
meson wrap install zlib
# Add wraps for mpv's required dependencies
mkdir -p subprojects
cat <<EOF > subprojects/libplacebo.wrap
[wrap-git]
url = https://github.com/haasn/libplacebo
revision = master
depth = 1
clone-recursive = true
EOF
cat <<EOF > subprojects/libass.wrap
[wrap-git]
revision = master
url = https://github.com/libass/libass
depth = 1
EOF
# For FFmpeg, use Meson's build system port; alternatively, you can compile
# the upstream version yourself. See https://trac.ffmpeg.org/wiki/CompilationGuide
cat <<EOF > subprojects/ffmpeg.wrap
[wrap-git]
url = https://gitlab.freedesktop.org/gstreamer/meson-ports/ffmpeg.git
revision = meson-8.0
depth = 1
[provide]
libavcodec = libavcodec_dep
libavdevice = libavdevice_dep
libavfilter = libavfilter_dep
libavformat = libavformat_dep
libavutil = libavutil_dep
libswresample = libswresample_dep
libswscale = libswscale_dep
EOF
```
3. Build
``` bash
meson setup -Ddefault_library=static -Dprefer_static=true \
-Dc_link_args='-static' -Dcpp_link_args='-static' \
--cross-file cross-file.txt build
ninja -C build mpv.exe mpv.com
```
This will produce fully portabiel, statically linked, ``mpv.exe`` and ``mpv.com``
binaries.
#### Building libmpv
- To also build ``libmpv``, execute the following commands:
``` bash
# For a static library
meson configure build -Dlibmpv=true -Ddefault_library=static
ninja -C build libmpv.a
# For a shared library
meson configure build -Dlibmpv=true -Ddefault_library=shared
ninja -C build libmpv-2.dll
```
- Depending on the use case, you might want to use ``-Dgpl=false`` and review
similar options for subprojects.
- If any of Meson's subprojects are not linked statically, you might need to
specify options like the following example for ffmpeg:
``-Dffmpeg:default_library=static``.
#### Enabling more mpv features
The process above produces a basic mpv build. You can enable additional features.
Check the Meson
[WrapDB packages](https://mesonbuild.com/Wrapdb-projects.html) for available
dependencies or by providing them through other means.
Enhancing mpv with more features is as simple as adding more arguments to the
Meson setup command, for example:
``` bash
-Dlua=enabled -Djavascript=enabled -Dlcms2=enabled -Dlibplacebo:lcms=enabled
```
they will be automatically downloaded and built by Meson.
## Native Compilation with Clang (Windows SDK Build)
1. Install [Build Tools for Visual Studio](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022)
or the full [Visual Studio](https://visualstudio.microsoft.com/downloads/#visual-studio-community-2022):
- From the installer, select the necessary components:
- Clang compiler for Windows
- C++ CMake tools for Windows
- Windows SDK
- Activate the developer shell:
```
& "<Visual Studio Path>\Common7\Tools\Launch-VsDevShell.ps1" -Arch amd64 -HostArch amd64 -SkipAutomaticLocation | Out-Null
```
2. Install Meson, as outlined in [Getting Meson](https://mesonbuild.com/Getting-meson.html):
3. The following build script utilizes the Meson subprojects system to build mpv and its dependencies.
To make sure all dependency versions are up-to-date, update the subprojects database from Meson's WrapDB.
Also explicitly download several wraps as some nested projects may pull older versions of them.
```
meson wrap update-db
meson wrap install expat
meson wrap install harfbuzz
meson wrap install libpng
meson wrap install zlib
```
4. Set environment variables or use the `--native-file` option in Meson.
```powershell
$env:CC = 'clang'
$env:CXX = 'clang++'
$env:CC_LD = 'lld'
$env:CXX_LD = 'lld'
$env:WINDRES = 'llvm-rc'
```
Note that some dependencies (e.g. LuaJIT) may require `sed` to configure. Fortunately, it is already bundled in
[Git for Windows](https://www.git-scm.com/download/win):
```powershell
$env:PATH += ';<Git Path>\usr\bin'
```
5. Execute [ci\build-win32.ps1](https://github.com/mpv-player/mpv/blob/master/ci/build-win32.ps1). Refer to the script for more details.
This process will produce a fully static ``mpv.exe`` and ``mpv.com``, as well as
a static ``libmpv.a``.
## Native Compilation with MSYS2
For Windows developers seeking a quick setup, MSYS2 is an effective tool for
compiling mpv natively on a Windows machine. The MSYS2 repositories provide
binary packages for most of mpv's dependencies, simplifying the process to
primarily involve building mpv itself.
### Installing MSYS2
1. Follow the installation steps from [MSYS2](https://www.msys2.org/).
2. Initiate one of the [Environments](https://www.msys2.org/docs/environments/),
with the CLANG64 (``clang64.exe``) being the recommended option.
**Note:** This environment is distinct from the MSYS2 shell that opens
automatically after the final installation dialog. You must close that
initial shell and open a new one for the appropriate environment.
### Updating MSYS2
For guidance on updating MSYS2, please refer to the official documentation:
[Updating MSYS2](https://www.msys2.org/docs/updating/).
### Installing mpv Dependencies
``` bash
# Install pacboy and git
pacman -S pactoys git
# Install MSYS2 build dependencies and a MinGW-w64 compiler
pacboy -S python pkgconf cc meson
# Install key dependencies. libass and lcms2 are also included as dependencies
# of ffmpeg.
pacboy -S ffmpeg libjpeg-turbo libplacebo luajit vulkan-headers
```
### Building mpv
To compile and install mpv, execute the following commands.
The binaries will be installed in the directory ``/$MSYSTEM_PREFIX/bin``.
```bash
# Set up the build directory with the desired configuration
meson setup build -Dlibmpv=true --prefix=$MSYSTEM_PREFIX
# Compile
meson compile -C build
# Optionally, install the compiled binaries
meson install -C build
```
## Running mpv
Depending on your build configuration, ``mpv.exe`` may rely on external
libraries. To create a portable package, you will need to include these
dependencies as well. The quickest way to determine which libraries are needed
is to run ``mpv.exe`` and note any error messages that list the required ``.dll``
files. You can find these libraries in the sysroot used for compilation, such as
``/clang64/bin/`` in MSYS2.
## Linking libmpv with MSVC Programs
Building mpv/libmpv directly with the MSVC compiler (cl.exe) is not supported
due to differences in compiler flags. Our build system is designed specifically
for GNU-like compiler drivers. However, you can still build programs in
Visual Studio and link them with libmpv.
If the toolchain used generates a ``.lib`` file, it will be ready for use.
Otherwise, you will need to create an import library for the mpv DLL with the
following command:
```bash
lib /name:mpv-2.dll /out:mpv.lib /MACHINE:X64
```
Ensure that the string in the ``/name:`` parameter matches the filename of the
DLL, as this is the filename that the MSVC linker will reference.
**Note:** Static linking is only feasible with matching compilers. For instance,
if you build with Clang in Visual Studio, static linking is possible.
+40 -194
View File
@@ -4,80 +4,32 @@ How to contribute
General
-------
The main contact for mpv development is IRC, specifically #mpv
and #mpv-devel on Libera.chat. GitHub is used for code review and
long term discussions.
The main contact for mpv development is IRC, specifically #mpv-player and
#mpv-player-dev on Freenode.
Sending patches
---------------
- Make a GitHub pull request, or send a link to a plaintext patch created with
``git format-patch``.
- Plain diffs posted as pastebins are not acceptable! (Especially if the http
link returns HTML.) They only cause extra work for everyone, because they lack
commit message and authorship information.
- Never send patches to any of the developers email addresses.
- If your changes are not supposed to be merged immediately, mark them as
"[RFC]" in the commit message or the pull request title.
- Be sure to test your changes. If you didn't, please say so in the commit
message and the pull request text.
Copyright of contributions
--------------------------
- The copyright belongs to contributors. The project is a collaborative work. By
sending your changes, you agree to license your contributions according to the
requirements of this project.
- All new code must be LGPLv2.1+ licensed, or come with the implicit agreement
that it will be relicensed to LGPLv2.1+ later (see ``Copyright`` in the
repository root directory).
- 100% compatible licenses are allowed too.
- Changes in files with more liberal licenses (such as BSD, MIT, or ISC) are
assumed to be dual-licensed under LGPLv2.1+ and the license indicated in the
file header.
- You must be either the exclusive author of the patch, or acknowledge all
authors involved in the commit message. If you take 3rd party code, authorship
and copyright must be properly acknowledged. If you're making changes on
behalf of your employer, and the employer owns the copyright, you must mention
this. If the license of the code is not LGPLv2.1+, you must mention this.
- These license statements are legally binding.
- Don't use fake names (something that looks like an actual name, and may be
someone else's name, but is not your legal name). Using a pseudonym is
allowed if it can be used to identify or contact you, even if whatever
account you used to submit the patch dies.
- Do not add your name to the license header. This convention is not used by
this project, and neither copyright law nor any of the used licenses require
it.
Write good commit messages
--------------------------
- Make a github pull request, or send a link to a plaintext patch created with
``git format-patch``. diffs posted as pastebins (especially if the http link
returns HTML) just cause extra work for everyone, because they lack commit
message and authorship information.
- Write informative commit messages. Use present tense to describe the
situation with the patch applied, and past tense for the situation before
the change.
- The subject line (the first line in a commit message) must contain a
- The subject line (the first line in a commit message) should contain a
prefix identifying the sub system, followed by a short description what
impact this commit has. This subject line and the commit message body
must not be longer than 72 characters per line, because it messes up the
output of many git tools otherwise.
impact this commit has. This subject line shouldn't be longer than 72
characters, because it messes up the output of many git tools otherwise.
For example, you fixed a crash in af_volume.c:
- Bad: ``fixed the bug (wtf?)``
- Good: ``af_volume: fix crash due to null pointer access``
Bad: ``fixed the bug (wtf?)``
Good: ``af_volume: fix crash due to null pointer access``
Having a prefix gives context, and is especially useful when trying to find
a specific change by looking at the history, or when running ``git blame``.
Sample prefixes: ``vo_gpu: ...``, ``command: ...``, ``DOCS/input: ...``,
``TOOLS/osxbundle: ...``, ``osc.lua: ...``, etc. You can always check the git
log for commits which modify specific files to see which prefixes are used.
- The first word after the ``:`` is lower case.
- Don't end the subject line with a ``.``.
- Put an empty line between the subject line and the commit message.
If this is missing, it will break display in common git tools.
- The body of the commit message (everything else after the subject line) must
- The body of the commit message (everything else after the subject line) should
be as informative as possible and contain everything that isn't obvious. Don't
hesitate to dump as much information as you can - it doesn't cost you
anything. Put some effort into it. If someone finds a bug months or years
@@ -86,81 +38,29 @@ Write good commit messages
information to test the original bug. The old bug might be reintroduced while
fixing the new bug.
The commit message must be wrapped on 72 characters per line, because git
The commit message should be wrapped on 72 characters per line, because git
tools usually do not break text automatically. On the other hand, you do not
need to break text that would be unnatural to break (like data for test cases,
or long URLs).
- Another summary of good conventions: https://chris.beams.io/posts/git-commit/
Split changes into multiple commits
-----------------------------------
- Follow git good practices, and split independent changes into several commits.
It's usually OK to put them into a single pull request.
Important: put an empty line between the subject line and the commit message.
If this is missing, it will break display in common git tools.
- Try to separate cosmetic and functional changes. It's ok to make a few
additional cosmetic changes in the same file you're working on. But don't do
something like reformatting a whole file, and hiding an actual functional
change in the same commit.
- Splitting changes does _not_ mean that you should make them as fine-grained
as possible. Commits should form logical steps in development. The way you
split changes is important for code review and analyzing bugs.
Always squash fixup commits when making changes to pull requests
----------------------------------------------------------------
- If you make fixup commits to your pull request, you should generally squash
them with "git rebase -i". We prefer to have pull requests in a merge
ready state.
- We don't squash-merge (nor do we use GitHub's feature that does this) because
pull requests with multiple commits are perfectly legitimate, and the only
thing that makes sense in non-trivial cases.
- With complex pull requests, it *may* make sense to keep them separate, but
they should be clearly marked as such. Reviewing commits is generally easier
with fixups squashed.
- Reviewers are encouraged to look at individual commits instead of GitHub's
"changes from all commits" view (which just encourages bad git and review
practices).
Touching user-visible parts may require updating the mpv docs
-------------------------------------------------------------
- Most user-visible things are normally documented in DOCS/man/. If your commit
touches documented behavior, list of sub-options, etc., you need to adjust the
documentation.
- These changes usually go into the same commit that changes the code.
- Changes to command line options (addition/modification/removal) must be
documented in options.rst.
- Changes to input properties or input commands must be documented in input.rst.
- Changes to the libmpv API must be reflected in the libmpv's headers doxygen,
and in client-api-changes.rst.
Interface change policy
-----------------------
- All incompatible changes to the user interface (options, properties, commands)
must be documented by making a new text file with a txt extension containing a
small note in the DOCS/interface-changes directory.
- The name of the file should be brief and related to the commit that makes the
change. The content of the file should begin with the type of the change
(add, remove, deprecate, change, rename, etc.). If the file contains multiple
changes, the change which causes the most serious compatibility issues should
be placed first.
- Grouping multiple related changes in the same file is also OK. Just be sure to
put each separate change on a different line.
- Documenting additions in DOCS/interface-changes is optional but encouraged.
- interface-changes.rst is never directly updated except when making new major
releases.
- See DOCS/interface-changes/example.txt for an example.
- If you add a new command line option, document it in options.rst. If you
add a new input property, document it in input.rst.
Code formatting
---------------
mpv uses C11 with K&R formatting, with some exceptions.
mpv uses C99 with K&R formatting, with some exceptions.
- Use the K&R indent style.
- Use 4 spaces of indentation, never use tabs (except in Makefiles).
- Add a single space between keywords and binary operators. There are some other
cases where spaces must be added. Example:
cases where spaces should be added. Example:
```C
if ((a * b) > c) {
@@ -168,9 +68,9 @@ mpv uses C11 with K&R formatting, with some exceptions.
some_function(a, b, c);
}
```
- Break lines on 80 columns. There is a hard limit of 100 columns. You may ignore
- Break lines on 80 columns. There is a hard limit of 85 columns. You may ignore
this limit if there's a strong case that not breaking the line will increase
readability. Going over 100 columns might provoke endless discussions about
readability. Going over 85 columns might provoke endless discussions about
whether such a limit is needed or not, so avoid it.
- If the body of an if/for/while statement has more than 1 physical lines, then
always add braces, even if they're technically redundant.
@@ -193,16 +93,18 @@ mpv uses C11 with K&R formatting, with some exceptions.
do_something();
}
```
- If the if has an else branch, both branches must use braces, even if they're
technically redundant.
- If the body of an if statement uses braces, the else branch should also
use braces (and reverse).
Example:
```C
if (a) {
one_line();
// do something
something();
something_else();
} else {
one_other_line();
one_line();
}
```
- If an if condition spans multiple physical lines, then put the opening brace
@@ -216,86 +118,30 @@ mpv uses C11 with K&R formatting, with some exceptions.
very_long_condition_b)
{
code();
} else {
...
}
```
(If the if body is simple enough, this rule can be skipped.)
- Remove any trailing whitespace.
- Do not make stray whitespaces changes.
Header #include statement order
-------------------------------
The order of ``#include`` statements in the source code is not very consistent.
New code must follow the following conventions:
- Put standard includes (``#include <stdlib.h>`` etc.) on the top,
- then after a blank line, add library includes (``#include <zlib.h>`` etc.)
- then after a blank line, add internal includes (``#include "player/core.h"``)
- sort them alphabetically within these sections
- If the file you're editing uses formatting different from from what is
described here, it's probably an old file from times when nobody followed a
consistent style. You're free to use the existing style, or the new style, or
to send a patch to reformat the file to the new style before making functional
changes.
General coding
--------------
- Use C11. Also freely make use of C11 features if it's appropriate, but do not
use VLA and complex number types.
- Don't use non-standard language (such as GNU C-only features). In some cases
they may be warranted, if they are optional (such as attributes enabling
printf-like format string checks). "#pragma once" is allowed as an exception.
But in general, standard C11 must be used.
- Use C99. Also freely make use of C99 features if it's appropriate, such as
stdbool.h.
- Don't use GNU-only features. In some cases they may be warranted, if they
are optional (such as attributes enabling printf-like format string checks).
But in general, standard C99 should be used.
- The same applies to libc functions. We have to be Windows-compatible too. Use
functions guaranteed by C11 or POSIX only, unless your use is guarded by a
configure check. Be mindful of MinGW-specifics since C11 support is not always
guaranteed.
functions guaranteed by C99 or POSIX only, unless your use is guarded by a
configure check.
- Prefer fusing declaration and initialization, rather than putting declarations
on the top of a block. Obvious data flow is more important than avoiding
mixing declarations and statements, which is just a C90 artifact.
- tech-overview.txt might help to get an overview how mpv is structured.
- If you add features that require intrusive changes, discuss them on the dev
channel first. There might be a better way to add a feature and it can avoid
wasted work.
- Newly added code for any Apple Platform (macOS, iOS, etc), that uses Cocoa or
any other object-oriented Framework or API, should be written in Swift instead
of Objective-C. This also includes complete rewrites/refactors of existing
code. Plain C API usages may stay as C, but can be written in Swift. Existing
Objective-C code can stay as is, though Swift rewrites are welcome.
Code of Conduct
---------------
Please note that this project is released with a Contributor Code of Conduct.
By participating in this project you agree to abide by its terms.
The Contributor Code of Conduct can be found here:
https://www.contributor-covenant.org/version/2/0/code_of_conduct/
Rules for git push access
-------------------------
Push access to the main git repository is handed out on an arbitrary basis. If
you got access, the following rules must be followed:
- You are expected to follow the general development rules as outlined in this
whole document.
- You must be present on the IRC dev channel when you push something.
- Anyone can push small fixes: typo corrections, small/obvious/uncontroversial
bug fixes, edits to the user documentation or code comments, and so on.
- You can freely make changes to parts of the code which you maintain. For
larger changes, it's recommended to let others review the changes first.
- You automatically maintain code if you wrote or modified most of it before
(e.g. you made larger changes to it before, did partial or full rewrites, did
major bug fixes, or you're the original author of the code). If there is more
than one maintainer, you may need to come to an agreement with the others how
to handle this to avoid conflict.
- If you make a pull requests (especially if it's to code you maintain), and you
want reviews, explicitly ping the people from which you expect reviews.
- As a maintainer, you can approve pull requests by others to "your" code.
- If you approve or merge 3rd party changes, make sure they follow the general
development rules.
- Changes to user interface and public API must always be approved by the
project leader.
- Seasoned project members are allowed to revert commits that broke the build,
or broke basic functionality in a catastrophic way, and the developer who
broke it is unavailable. (Depending on severity.)
- Adhere to the CoC.
- The project leader is not bound by these rules.
+83
View File
@@ -0,0 +1,83 @@
Cross Compiling to Windows
==========================
Cross compiling mpv to Windows is supported with MinGW-w64. This can be used to
produce both 32 bit and 64 bit executables. MinGW-w64 is available from
http://mingw-w64.sourceforge.net.
You have to run mpv's configure with these arguments:
```bash
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
```
While building a complete MinGW-w64 toolchain yourself is possible, people have
created scripts to help ease the process. These are the two recommended methods:
- Using [mingw-w64-cmake](https://github.com/lachs0r/mingw-w64-cmake) to setup
a MinGW-w64 environment. We recommend you to try this first before MXE.
mingw-w64-cmake will also build mpv and its dependencies.
- Alternatively, you can use MXE: http://mxe.cc. With MXE, you have to manually
set the target to MinGW-w64 (even if you compile to 32 bit). A working example
below.
**Warning**: the original MinGW (http://www.mingw.org) is unsupported.
Note that MinGW environments included in Linux distributions are often broken,
outdated and useless, and usually don't use MinGW-w64.
Additional dependencies
-----------------------
You need a pthread wrapper. It must be interoperable with native Windows
threads. pthreads-win32 or MinGW pthreads might work.
If you want ``--input-file=...`` to work, you need libwaio. It's available
from: git://midipix.org/waio
Example with MXE
----------------
```bash
# Download MXE. Note that compiling the required packages requires about 1.4 GB
# or more!
cd /opt
git clone https://github.com/mxe/mxe mingw
cd mingw
# Set build options.
# The JOBS environment variable controls threads to use when building. DO NOT
# use the regular `make -j4` option with MXE as it will slow down the build.
# Alternatively, you can set this in the make command by appending "JOBS=4"
# to the end of command:
echo "JOBS := 4" >> settings.mk
# The MXE_TARGET environment variable builds MinGW-w64 for 32 bit targets.
# Alternatively, you can specify this in the make command by appending
# "MXE_TARGETS=i686-w64-mingw32" to the end of command:
echo "MXE_TARGETS := i686-w64-mingw32" >> settings.mk
# If you want to build 64 bit version, use this:
# echo "MXE_TARGETS := x86_64-w64-mingw32" >> settings.mk
# Build required packages. The following provide a minimum required to build
# mpv.
make gcc ffmpeg libass jpeg pthreads
# Add MXE binaries to $PATH
export PATH=/opt/mingw/usr/bin/:$PATH
# Build mpv. The target will be used to automatically select the name of the
# build tools involved (e.g. it will use i686-w64-mingw32-gcc).
cd ..
git clone https://github.com/mpv-player/mpv.git
cd mpv
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
# Or, if 64 bit version,
# DEST_OS=win32 TARGET=x86_64-w64-mingw32 ./waf configure
./waf build
```
+7 -282
View File
@@ -31,8 +31,9 @@ estimated remaining duration of the source file is used.
Note::
Usage of relative or absolute paths as well as any protocol prefixes may be
prevented for security reasons.
mpv can't use ordered chapter files in EDL entries. Usage of relative or
absolute paths as well as any protocol prefixes is prevented for security
reasons.
Syntax of mpv EDL files
@@ -51,8 +52,7 @@ The rest of the lines belong to one of these classes:
1) An empty or commented line. A comment starts with ``#``, which must be the
first character in the line. The rest of the line (up until the next line
break) is ignored. An empty line has 0 bytes between two line feed bytes.
2) A header entry if the line starts with ``!``.
3) A segment entry in all other cases.
2) A segment entry in all other cases.
Each segment entry consists of a list of named or unnamed parameters.
Parameters are separated with ``,``. Named parameters consist of a name,
@@ -64,8 +64,8 @@ Syntax::
segment_entry ::= <param> ( <param> ',' )*
param ::= [ <name> '=' ] ( <value> | '%' <number> '%' <valuebytes> )
The ``name`` string can consist of any characters, except ``=%,;\n!``. The
``value`` string can consist of any characters except of ``,;\n!``.
The ``name`` string can consist of any characters, except ``=%,;\n``. The
``value`` string can consist of any characters except of ``,;\n``.
The construct starting with ``%`` allows defining any value with arbitrary
contents inline, where ``number`` is an integer giving the number of bytes in
@@ -95,232 +95,6 @@ to ``20``, ``param3`` to ``value,escaped``, ``param4`` to ``value2``.
Instead of line breaks, the character ``;`` can be used. Line feed bytes and
``;`` are treated equally.
Header entries start with ``!`` as first character after a line break. Header
entries affect all other file entries in the EDL file. Their format is highly
implementation specific. They should generally follow the file header, and come
before any file entries.
Disabling chapter generation and copying
========================================
By default, chapters from the source ranges are copied to the virtual file's
chapters. Also, a chapter is inserted after each range. This can be disabled
with the ``no_chapters`` header.
Example::
!no_chapters
MP4 DASH
========
This is a header that helps implementing DASH, although it only provides a low
level mechanism.
If this header is set, the given url designates an mp4 init fragment. It's
downloaded, and every URL in the EDL is prefixed with the init fragment on the
byte stream level. This is mostly for use by mpv's internal ytdl support. The
ytdl script will call youtube-dl, which in turn actually processes DASH
manifests. It may work only for this very specific purpose and fail to be
useful in other scenarios. It can be removed or changed in incompatible ways
at any times.
Example::
!mp4_dash,init=url
The ``url`` is encoded as parameter value as defined in the general EDL syntax.
It's expected to point to an "initialization fragment", which will be prefixed
to every entry in the EDL on the byte stream level.
The current implementation will
- ignore stream start times
- use durations as hint for seeking only
- not adjust source timestamps
- open and close segments (i.e. fragments) as needed
- not add segment boundaries as chapter points
- require full compatibility between all segments (same codec etc.)
Another header part of this mechanism is ``no_clip``. This header is similar
to ``mp4_dash``, but does not include on-demand opening/closing of segments,
and does not support init segments. It also exists solely to support internal
ytdl requirements. Using ``no_clip`` with segments is not recommended and
probably breaks. ``mp4_dash`` already implicitly does a variant of ``no_clip``.
The ``mp4_dash`` and ``no_clip`` headers are not part of the core EDL format.
They may be changed or removed at any time, depending on mpv's internal
requirements.
Separate files for tracks
=========================
The special ``new_stream`` header lets you specify separate parts and time
offsets for separate tracks. This can for example be used to source audio and
video track from separate files.
Example::
# mpv EDL v0
video.mkv
!new_stream
audio.mkv
This adds all tracks from both files to the virtual track list. Upon playback,
the tracks will be played at the same time, instead of appending them. The files
can contain more than 1 stream; the apparent effect is the same as if the second
part after the ``!new_stream`` part were in a separate ``.edl`` file and added
with ``--external-file``.
Note that all metadata between the stream sets created by ``new_stream`` is
disjoint. Global metadata is taken from the first part only.
In context of mpv, this is redundant to the ``--audio-file`` and
``--external-file`` options, but (as of this writing) has the advantage that
this will use a unified cache for all streams.
The ``new_stream`` header is not part of the core EDL format. It may be changed
or removed at any time, depending on mpv's internal requirements.
If the first ``!new_stream`` is redundant, it is ignored. This is the same
example as above::
# mpv EDL v0
!new_stream
video.mkv
!new_stream
audio.mkv
Note that ``!new_stream`` must be the first header. Whether the parser accepts
(i.e. ignores) or rejects other headers before that is implementation specific.
Track metadata
==============
The special ``track_meta`` header can set some specific metadata fields of the
current ``!new_stream`` partition. The tags are applied to all tracks within
the partition. It is not possible to set the metadata for individual tracks (the
feature was needed only for single-track media).
It provides following parameters change track metadata:
``lang``
Set the language tag.
``title``
Set the title tag.
``byterate``
Number of bytes per second this stream uses. (Purely informational.)
``index``
The numeric index of the track this should map to (default: -1). This is
the 0-based index of the virtual stream as seen by the player, enumerating
all audio/video/subtitle streams. If nothing matches, this is silently
discarded. The special index -1 (the default) has two meanings: if there
was a previous meta data entry (either ``!track_meta`` or ``!delay_open``
element since the last ``!new_stream``), then this element manipulates
the previous meta data entry. If there was no previous entry, a new meta
data entry that matches all streams is created.
Example::
# mpv EDL v0
!track_meta,lang=bla,title=blabla
file.mkv
!new_stream
!track_meta,title=ducks
sub.srt
If ``file.mkv`` has an audio and a video stream, both will use ``blabla`` as
title. The subtitle stream will use ``ducks`` as title.
The ``track_meta`` header is not part of the core EDL format. It may be changed
or removed at any time, depending on mpv's internal requirements.
Global metadata
===============
The special ``global_tags`` header can set metadata fields (aka tags) of the EDL
file. This metadata is supposed to be informational, much like for example ID3
tags in audio files. Due to lack of separation of different kinds of metadata it
is unspecified what names are allowed, how they are interpreted, and whether
some of them affect playback functionally. (Much of this is unfortunately
inherited from FFmpeg. Another consequence of this is that FFmpeg "normalized"
tags are recognized, or stuff like replaygain tags.)
Example::
!global_tags,title=bla,something_arbitrary=even_more_arbitrary
Any parameter names are allowed. Repeated use of this adds to the tag list. If
``!new_stream`` is used, the location doesn't matter.
May possibly be ignored in some cases, such as delayed media opening.
Delayed media opening
=====================
The special ``delay_open`` header can be used to open the media URL of the
stream only when the track is selected for the first time. This is supposed to
be an optimization to speed up opening of a remote stream if there are many
tracks for whatever reasons.
This has various tricky restrictions, and also will defer failure to open a
stream to "later". By design, it's supposed to be used for single-track streams.
Using multiple segments requires you to specify all offsets and durations (also
it was never tested whether it works at all). Interaction with ``mp4_dash`` may
be strange.
You can describe multiple sub-tracks by using multiple ``delay_open`` headers
before the same source URL. (If there are multiple sub-tracks of the same media
type, then the mapping to the real stream is probably rather arbitrary.) If the
source contains tracks not described, a warning is logged when the delayed
opening happens, and the track is hidden.
This has the following parameters:
``media_type``
Required. Must be set to ``video``, ``audio``, or ``sub``. (Other tracks in
the opened URL are ignored.)
``codec``
The mpv codec name that is expected. Although mpv tries to initialize a
decoder with it currently (and will fail track selection if it does not
initialize successfully), it is not used for decoding - decoding still uses
the information retrieved from opening the actual media information, and may
be a different codec (you should try to avoid this, of course). Defaults to
``null``.
Above also applies for similar fields such as ``w``. These fields are
mostly to help with user track pre-selection.
``flags``
A ``+`` separated list of boolean flags. Currently defined flags:
``default``
Set the default track flag.
``forced``
Set the forced track flag.
Other values are ignored after triggering a warning.
``w``, ``h``
For video codecs: expected video size. See ``codec`` for details.
``fps``
For video codecs: expected video framerate, as integer. (The rate is usually
only crudely reported, and it makes no sense to expect exact values.)
``samplerate``
For audio codecs: expected sample rate, as integer.
The ``delay_open`` header is not part of the core EDL format. It may be changed
or removed at any time, depending on mpv's internal requirements.
Timestamp format
================
@@ -328,8 +102,7 @@ Currently, time values are floating point values in seconds.
As an extension, you can set the ``timestamps=chapters`` option. If this option
is set, timestamps have to be integers, and refer to chapter numbers, starting
with 0. The default value for this parameter is ``seconds``, which means the
time is as described in the previous paragraph.
with 0.
Example::
@@ -338,54 +111,6 @@ Example::
Plays chapter 3 and ends with the start of chapter 7 (4 chapters later).
Implicit chapters
=================
mpv will add one chapter per segment entry to the virtual timeline.
By default, the chapter's titles will match the entries' filenames.
You can override set the ``title`` option to override the chapter title for
that segment.
Example::
# mpv EDL v0
cap.ts,5,240
OP.mkv,0,90,title=Show Opening
The virtual timeline will have two chapters, one called "cap.ts" from 0-240s
and a second one called "Show Opening" from 240-330s.
Entry which defines the track layout
====================================
Normally, you're supposed to put only files with compatible layouts into an EDL
file. However, at least the mpv implementation accepts entries that use
different codecs, or even have a different number of audio/video/subtitle
tracks. In this case, it's not obvious, which virtual tracks the EDL show should
expose when being played.
Currently, mpv will apply an arbitrary heuristic which tracks the EDL file
should expose. (Before mpv 0.30.0, it always used the first source file in the
segment list.)
You can set the ``layout`` option to ``this`` to make a specific entry define
the track layout.
Example::
# mpv EDL v0
file_with_2_streams.ts,5,240
file_with_5_streams.mkv,0,90,layout=this
The way the different virtual EDL tracks are associated with the per-segment
ones is highly implementation-defined, and uses a heuristic. If a segment is
missing a track, there will be a "hole", and bad behavior may result. Improving
this is subject to further development (due to being fringe cases, they don't
have a high priority).
If future versions of mpv change this again, this option may be ignored.
Syntax of EDL URIs
==================
+50 -54
View File
@@ -3,26 +3,27 @@ General usage
::
mpv infile --o=outfile [--of=outfileformat] [--ofopts=formatoptions] [--orawts] \
mpv infile -o outfile [-of outfileformat] [-ofopts formatoptions] \
[-ofps outfps | -oautofps] [-oharddup] [-ocopyts | -orawts] [-oneverdrop] \
[(any other mpv options)] \
--ovc=outvideocodec [--ovcopts=outvideocodecoptions] \
--oac=outaudiocodec [--oacopts=outaudiocodecoptions]
-ovc outvideocodec [-ovcopts outvideocodecoptions] \
-oac outaudiocodec [-oacopts outaudiocodecoptions]
Help for these options is provided if giving help as parameter, as in::
mpv --ovc=help
mpv -ovc help
The suboptions of these generally are identical to ffmpeg's (as option parsing
is simply delegated to ffmpeg). The option --ocopyts enables copying timestamps
is simply delegated to ffmpeg). The option -ocopyts enables copying timestamps
from the source as-is, instead of fixing them to match audio playback time
(note: this doesn't work with all output container formats); --orawts even turns
(note: this doesn't work with all output container formats); -orawts even turns
off discontinuity fixing.
Note that if neither --ofps nor --oautofps is specified, VFR encoding is assumed
and the time base is 24000fps. --oautofps sets --ofps to a guessed fps number
Note that if neither -ofps nor -oautofps is specified, VFR encoding is assumed
and the time base is 24000fps. -oautofps sets -ofps to a guessed fps number
from the input video. Note that not all codecs and not all formats support VFR
encoding, and some which do have bugs when a target bitrate is specified - use
--ofps or --oautofps to force CFR encoding in these cases.
-ofps or -oautofps to force CFR encoding in these cases.
Of course, the options can be stored in a profile, like this .config/mpv/mpv.conf
section::
@@ -30,13 +31,9 @@ section::
[myencprofile]
vf-add = scale=480:-2
ovc = libx264
ovcopts-add = preset=medium
ovcopts-add = tune=fastdecode
ovcopts-add = preset=medium,tune=fastdecode
ovcopts-add = crf=23
ovcopts-add = maxrate=1500k
ovcopts-add = bufsize=1000k
ovcopts-add = rc_init_occupancy=900k
ovcopts-add = refs=2
ovcopts-add = maxrate=1500k,bufsize=1000k,rc_init_occupancy=900k,refs=2
ovcopts-add = profile=baseline
oac = aac
oacopts-add = b=96k
@@ -48,7 +45,7 @@ to encoding. This is not the case anymore.)
One can then encode using this profile using the command::
mpv infile --o=outfile.mp4 --profile=myencprofile
mpv infile -o outfile.mp4 -profile myencprofile
Some example profiles are provided in a file
etc/encoding-profiles.conf; as for this, see below.
@@ -62,33 +59,33 @@ for.
Typical MPEG-4 Part 2 ("ASP", "DivX") encoding, AVI container::
mpv infile --o=outfile.avi \
--vf=fps=25 \
--ovc=mpeg4 --ovcopts=qscale=4 \
--oac=libmp3lame --oacopts=b=128k
mpv infile -o outfile.avi \
-ofps 25 \
-ovc mpeg4 -ovcopts qscale=4 \
-oac libmp3lame -oacopts ab=128k
Note: AVI does not support variable frame rate, so the fps filter must be used.
The frame rate should ideally match the input (25 for PAL, 24000/1001 or
30000/1001 for NTSC)
Note: AVI does not support variable frame rate, so -ofps must be used. The
frame rate should ideally match the input (25 for PAL, 24000/1001 or 30000/1001
for NTSC)
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container::
mpv infile --o=outfile.mkv \
--ovc=libx264 --ovcopts=preset=medium,crf=23,profile=baseline \
--oac=libopus --oacopts=qscale=3
mpv infile -o outfile.mkv \
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
-oac libvorbis -oacopts qscale=3
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, MPEG-4 (MP4) container::
mpv infile --o=outfile.mp4 \
--ovc=libx264 --ovcopts=preset=medium,crf=23,profile=baseline \
--oac=aac --oacopts=b=128k
mpv infile -o outfile.mp4 \
-ovc libx264 -ovcopts preset=medium,crf=23,profile=baseline \
-oac aac -oacopts ab=128k
Typical VP8 encoding, WebM (restricted Matroska) container::
mpv infile -o outfile.mkv \
--of=webm \
--ovc=libvpx --ovcopts=qmin=6,b=1000000k \
--oac=libopus --oacopts=qscale=3
-of webm \
-ovc libvpx -ovcopts qmin=6,b=1000000k \
-oac libvorbis -oacopts qscale=3
Device targets
@@ -97,29 +94,28 @@ Device targets
As the options for various devices can get complex, profiles can be used.
An example profile file for encoding is provided in
etc/encoding-profiles.conf in the source tree. mpv will read any file
named ``encoding-profiles.conf`` in either the local or system
configuration directories.
etc/encoding-profiles.conf in the source tree. This file is installed and loaded
by default (if libavfilter is enabled at compilation). If you want to modify
it, you can replace and it with your own copy by doing::
Keep in mind that the default profile is the playback one. If you want to add
options that apply only in encoding mode, put them into a ``[encoding]``
section.
mkdir -p ~/.mpv
cp /etc/mpv/encoding-profiles.conf ~/.mpv/encoding-profiles.conf
Refer to the top of that file for more comments - in a nutshell, the following
options are added by it::
--profile=enc-to-dvdpal # DVD-Video PAL, use dvdauthor -v pal+4:3 -a ac3+en
--profile=enc-to-dvdntsc # DVD-Video NTSC, use dvdauthor -v ntsc+4:3 -a ac3+en
--profile=enc-to-bb-9000 # MP4 for Blackberry Bold 9000
--profile=enc-to-nok-6300 # 3GP for Nokia 6300
--profile=enc-to-psp # MP4 for PlayStation Portable
--profile=enc-to-iphone # MP4 for iPhone
--profile=enc-to-iphone-4 # MP4 for iPhone 4 (double res)
--profile=enc-to-iphone-5 # MP4 for iPhone 5 (even larger res)
-profile enc-to-dvdpal DVD-Video PAL, use dvdauthor -v pal+4:3 -a ac3+en
-profile enc-to-dvdntsc DVD-Video NTSC, use dvdauthor -v ntsc+4:3 -a ac3+en
-profile enc-to-bb-9000 MP4 for Blackberry Bold 9000
-profile enc-to-nok-6300 3GP for Nokia 6300
-profile enc-to-psp MP4 for PlayStation Portable
-profile enc-to-iphone MP4 for iPhone
-profile enc-to-iphone-4 MP4 for iPhone 4 (double res)
-profile enc-to-iphone-5 MP4 for iPhone 5 (even larger res)
You can encode using these with a command line like::
mpv infile --o=outfile.mp4 --profile=enc-to-bb-9000
mpv infile -o outfile.mp4 -profile enc-to-bb-9000
Of course, you are free to override options set by these profiles by specifying
them after the -profile option.
@@ -129,20 +125,20 @@ What works
==========
* Encoding at variable frame rate (default)
* Encoding at constant frame rate using --vf=fps=RATE
* 2-pass encoding (specify flags=+pass1 in the first pass's --ovcopts, specify
* Encoding at constant frame rate using -ofps framerate -oharddup
* 2-pass encoding (specify flags=+pass1 in the first pass's -ovcopts, specify
flags=+pass2 in the second pass)
* Hardcoding subtitles using vobsub, ass or srt subtitle rendering (just
configure mpv for the subtitles as usual)
* Hardcoding any other mpv OSD (e.g. time codes, using --osdlevel=3 and
--vf=expand=::::1)
* Hardcoding any other mpv OSD (e.g. time codes, using -osdlevel 3 and -vf
expand=::::1)
* Encoding directly from a DVD, network stream, webcam, or any other source
mpv supports
* Using x264 presets/tunings/profiles (by using profile=, tune=, preset= in the
--ovcopts)
-ovcopts)
* Deinterlacing/Inverse Telecine with any of mpv's filters for that
* Audio file converting: mpv --o=outfile.m4a infile.flac --no-video
--oac=aac --oacopts=b=320k
* Audio file converting: mpv -o outfile.mp3 infile.flac -no-video -oac
libmp3lame -oacopts ab=320k
What does not work yet
======================
File diff suppressed because it is too large. Load diff
-1
View File
@@ -1 +0,0 @@
deprecate `--foo`, instead use `--bar=foo` as a replacement
+478 -127
View File
@@ -4,29 +4,66 @@ AUDIO FILTERS
Audio filters allow you to modify the audio stream and its properties. The
syntax is:
``--af=...``
Setup a chain of audio filters. See ``--vf`` (`VIDEO FILTERS`_) for the
full syntax.
This is an object settings list option. See `List Options`_ for details.
``--af=<filter1[=parameter1:parameter2:...],filter2,...>``
Setup a chain of audio filters.
.. note::
To get a full list of available audio filters, see ``--af=help``.
Also, keep in mind that most actual filters are available via the ``lavfi``
wrapper, which gives you access to most of libavfilter's filters. This
includes all filters that have been ported from MPlayer to libavfilter.
You can also set defaults for each filter. The defaults are applied before the
normal filter parameters.
The ``--vf`` description describes how libavfilter can be used and how to
workaround deprecated mpv filters.
``--af-defaults=<filter1[=parameter1:parameter2:...],filter2,...>``
Set defaults for each filter.
See ``--vf`` group of options for info on how ``--af-add``, ``--af-pre``,
``--af-clr``, and possibly others work.
Audio filters are managed in lists. There are a few commands to manage the
filter list:
``--af-add=<filter1[,filter2,...]>``
Appends the filters given as arguments to the filter list.
``--af-pre=<filter1[,filter2,...]>``
Prepends the filters given as arguments to the filter list.
``--af-del=<index1[,index2,...]>``
Deletes the filters at the given indexes. Index numbers start at 0,
negative numbers address the end of the list (-1 is the last).
``--af-clr``
Completely empties the filter list.
Available filters are:
``lavcac3enc[=options]``
``lavrresample[=option1:option2:...]``
This filter uses libavresample (or libswresample, depending on the build)
to change sample rate, sample format, or channel layout of the audio stream.
This filter is automatically enabled if the audio output does not support
the audio configuration of the file being played.
It supports only the following sample formats: u8, s16, s32, float.
``filter-size=<length>``
Length of the filter with respect to the lower sampling rate. (default:
16)
``phase-shift=<count>``
Log2 of the number of polyphase entries. (..., 10->1024, 11->2048,
12->4096, ...) (default: 10->1024)
``cutoff=<cutoff>``
Cutoff frequency (0.0-1.0), default set depending upon filter length.
``linear``
If set then filters will be linearly interpolated between polyphase
entries. (default: no)
``no-detach``
Do not detach if input and output audio format/rate/channels match.
(If you just want to set defaults for this filter that will be used
even by automatically inserted lavrresample instances, you should
prefer setting them with ``--af-defaults=lavrresample:...``.)
``o=<string>``
Set AVOptions on the SwrContext or AVAudioResampleContext. These should
be documented by FFmpeg or Libav.
``lavcac3enc[=tospdif[:bitrate[:minchn]]]``
Encode multi-channel audio to AC-3 at runtime using libavcodec. Supports
16-bit native-endian input format, maximum 6 channels. The output is
big-endian when outputting a raw AC-3 stream, native-endian when
@@ -55,30 +92,147 @@ Available filters are:
:5ch: 448
:6ch: 448
``minch=<n>``
If the input channel number is less than ``<minch>``, the filter will
``minchn=<n>``
If the input channel number is less than ``<minchn>``, the filter will
detach itself (default: 3).
``encoder=<name>``
Select the libavcodec encoder used. Currently, this should be an AC-3
encoder, and using another codec will fail horribly.
``sweep[=speed]``
Produces a sine sweep.
``format=format:srate:channels:out-srate:out-channels``
Does not do any format conversion itself. Rather, it may cause the
filter system to insert necessary conversion filters before or after this
filter if needed. It is primarily useful for controlling the audio format
going into other filters. To specify the format for audio output, see
``--audio-format``, ``--audio-samplerate``, and ``--audio-channels``. This
filter is able to force a particular format, whereas ``--audio-*``
may be overridden by the ao based on output compatibility.
``<0.0-1.0>``
Sine function delta, use very low values to hear the sweep.
``sinesuppress[=freq:decay]``
Remove a sine at the specified frequency. Useful to get rid of the 50/60 Hz
noise on low quality audio equipment. It only works on mono input.
``<freq>``
The frequency of the sine which should be removed (in Hz) (default:
50)
``<decay>``
Controls the adaptivity (a larger value will make the filter adapt to
amplitude and phase changes quicker, a smaller value will make the
adaptation slower) (default: 0.0001). Reasonable values are around
0.001.
``bs2b[=option1:option2:...]``
Bauer stereophonic to binaural transformation using libbs2b. Improves the
headphone listening experience by making the sound similar to that from
loudspeakers, allowing each ear to hear both channels and taking into
account the distance difference and the head shadowing effect. It is
applicable only to 2-channel audio.
``fcut=<300-1000>``
Set cut frequency in Hz.
``feed=<10-150>``
Set feed level for low frequencies in 0.1*dB.
``profile=<value>``
Several profiles are available for convenience:
:default: will be used if nothing else was specified (fcut=700,
feed=45)
:cmoy: Chu Moy circuit implementation (fcut=700, feed=60)
:jmeier: Jan Meier circuit implementation (fcut=650, feed=95)
If ``fcut`` or ``feed`` options are specified together with a profile, they
will be applied on top of the selected profile.
``hrtf[=flag]``
Head-related transfer function: Converts multichannel audio to 2-channel
output for headphones, preserving the spatiality of the sound.
==== ===================================
Flag Meaning
==== ===================================
m matrix decoding of the rear channel
s 2-channel matrix decoding
0 no matrix decoding (default)
==== ===================================
``equalizer=g1:g2:g3:...:g10``
10 octave band graphic equalizer, implemented using 10 IIR band-pass
filters. This means that it works regardless of what type of audio is
being played back. The center frequencies for the 10 bands are:
=== ==========
No. frequency
=== ==========
0 31.25 Hz
1 62.50 Hz
2 125.00 Hz
3 250.00 Hz
4 500.00 Hz
5 1.00 kHz
6 2.00 kHz
7 4.00 kHz
8 8.00 kHz
9 16.00 kHz
=== ==========
If the sample rate of the sound being played is lower than the center
frequency for a frequency band, then that band will be disabled. A known
bug with this filter is that the characteristics for the uppermost band
are not completely symmetric if the sample rate is close to the center
frequency of that band. This problem can be worked around by upsampling
the sound using a resampling filter before it reaches this filter.
``<g1>:<g2>:<g3>:...:<g10>``
floating point numbers representing the gain in dB for each frequency
band (-12-12)
.. admonition:: Example
``mpv --af=equalizer=11:11:10:5:0:-12:0:5:12:12 media.avi``
Would amplify the sound in the upper and lower frequency region
while canceling it almost completely around 1 kHz.
``channels=nch[:routes]``
Can be used for adding, removing, routing and copying audio channels. If
only ``<nch>`` is given, the default routing is used. It works as follows:
If the number of output channels is greater than the number of input
channels, empty channels are inserted (except when mixing from mono to
stereo; then the mono channel is duplicated). If the number of output
channels is less than the number of input channels, the exceeding
channels are truncated.
``<nch>``
number of output channels (1-8)
``<routes>``
List of ``,`` separated routes, in the form ``from1-to1,from2-to2,...``.
Each pair defines where to route each channel. There can be at most
8 routes. Without this argument, the default routing is used. Since
``,`` is also used to separate filters, you must quote this argument
with ``[...]`` or similar.
.. admonition:: Examples
``mpv --af=channels=4:[0-1,1-0,0-2,1-3] media.avi``
Would change the number of channels to 4 and set up 4 routes that
swap channel 0 and channel 1 and leave channel 2 and 3 intact.
Observe that if media containing two channels were played back,
channels 2 and 3 would contain silence but 0 and 1 would still be
swapped.
``mpv --af=channels=6:[0-0,0-1,0-2,0-3] media.avi``
Would change the number of channels to 6 and set up 4 routes that
copy channel 0 to channels 0 to 3. Channel 4 and 5 will contain
silence.
.. note::
You should probably not use this filter. If you want to change the
output channel layout, try the ``format`` filter, which can make mpv
automatically up- and downmix standard channel layouts.
``format=format:srate:channels:out-format:out-srate:out-channels``
Force a specific audio format/configuration without actually changing the
audio data. Keep in mind that the filter system might auto-insert actual
conversion filters before or after this filter if needed.
All parameters are optional. The first 3 parameters restrict what the filter
accepts as input. They will therefore cause conversion filters to be
inserted before this one. The ``out-`` parameters tell the filters or audio
outputs following this filter how to interpret the data without actually
doing a conversion. Setting these will probably just break things unless you
really know you want this for some reason, such as testing or dealing with
broken media.
accepts as input. The ``out-`` parameters change the audio format, without
actually doing a conversion. The data will be 'reinterpreted' by the
filters or audio outputs following this filter.
``<format>``
Force conversion to this format. Use ``--af=format=format=help`` to get
@@ -92,17 +246,296 @@ Available filters are:
Force mixing to a specific channel layout. See ``--audio-channels`` option
for possible values.
``<out-format>``
``<out-srate>``
``<out-channels>``
*NOTE*: this filter used to be named ``force``. The old ``format`` filter
used to do conversion itself, unlike this one which lets the filter system
handle the conversion.
See also ``--audio-format``, ``--audio-samplerate``, and
``--audio-channels`` for related options. Keep in mind that
``--audio-channels`` does not actually force the number of
channels in most cases, while this filter can do this.
*NOTE*: this filter used to be named ``force``. Also, unlike the old
``format`` filter, this does not do any actual conversion anymore.
Conversion is done by other, automatically inserted filters.
``convert24``
Filter for internal use only. Converts between 24-bit and 32-bit sample
formats.
``convertsign``
Filter for internal use only. Converts between signed/unsigned formats.
``volume[=<volumedb>[:...]]``
Implements software volume control. Use this filter with caution since it
can reduce the signal to noise ratio of the sound. In most cases it is
best to use the *Master* volume control of your sound card or the volume
knob on your amplifier.
*NOTE*: This filter is not reentrant and can therefore only be enabled
once for every audio stream.
``<volumedb>``
Sets the desired gain in dB for all channels in the stream from -200 dB
to +60 dB, where -200 dB mutes the sound completely and +60 dB equals a
gain of 1000 (default: 0).
``replaygain-track``
Adjust volume gain according to the track-gain replaygain value stored
in the file metadata.
``replaygain-album``
Like replaygain-track, but using the album-gain value instead.
``replaygain-preamp``
Pre-amplification gain in dB to apply to the selected replaygain gain
(default: 0).
``replaygain-clip=yes|no``
Prevent clipping caused by replaygain by automatically lowering the
gain (default). Use ``replaygain-clip=no`` to disable this.
``softclip``
Turns soft clipping on. Soft-clipping can make the
sound more smooth if very high volume levels are used. Enable this
option if the dynamic range of the loudspeakers is very low.
*WARNING*: This feature creates distortion and should be considered a
last resort.
``s16``
Force S16 sample format if set. Lower quality, but might be faster
in some situations.
``detach``
Remove the filter if the volume is not changed at audio filter config
time. Useful with replaygain: if the current file has no replaygain
tags, then the filter will be removed if this option is enabled.
(If ``--softvol=yes`` is used and the player volume controls are used
during playback, a different volume filter will be inserted.)
.. admonition:: Example
``mpv --af=volume=10.1 media.avi``
Would amplify the sound by 10.1 dB and hard-clip if the sound level
is too high.
``pan=n:[<matrix>]``
Mixes channels arbitrarily. Basically a combination of the volume and the
channels filter that can be used to down-mix many channels to only a few,
e.g. stereo to mono, or vary the "width" of the center speaker in a
surround sound system. This filter is hard to use, and will require some
tinkering before the desired result is obtained. The number of options for
this filter depends on the number of output channels. An example how to
downmix a six-channel file to two channels with this filter can be found
in the examples section near the end.
``<n>``
Number of output channels (1-8).
``<matrix>``
A list of values ``[L00,L01,L02,...,L10,L11,L12,...,Ln0,Ln1,Ln2,...]``,
where each element ``Lij`` means how much of input channel i is mixed
into output channel j (range 0-1). So in principle you first have n
numbers saying what to do with the first input channel, then n numbers
that act on the second input channel etc. If you do not specify any
numbers for some input channels, 0 is assumed.
Note that the values are separated by ``,``, which is already used
by the option parser to separate filters. This is why you must quote
the value list with ``[...]`` or similar.
.. admonition:: Examples
``mpv --af=pan=1:[0.5,0.5] media.avi``
Would downmix from stereo to mono.
``mpv --af=pan=3:[1,0,0.5,0,1,0.5] media.avi``
Would give 3 channel output leaving channels 0 and 1 intact, and mix
channels 0 and 1 into output channel 2 (which could be sent to a
subwoofer for example).
.. note::
If you just want to force remixing to a certain output channel layout,
it is easier to use the ``format`` filter. For example,
``mpv '--af=format=channels=5.1' '--audio-channels=5.1'`` would always force
remixing audio to 5.1 and output it like this.
``sub[=fc:ch]``
Adds a subwoofer channel to the audio stream. The audio data used for
creating the subwoofer channel is an average of the sound in channel 0 and
channel 1. The resulting sound is then low-pass filtered by a 4th order
Butterworth filter with a default cutoff frequency of 60Hz and added to a
separate channel in the audio stream.
.. warning::
Disable this filter when you are playing media with an LFE channel
(e.g. 5.1 surround sound), otherwise this filter will disrupt the sound
to the subwoofer.
``<fc>``
cutoff frequency in Hz for the low-pass filter (20 Hz to 300 Hz)
(default: 60 Hz) For the best result try setting the cutoff frequency
as low as possible. This will improve the stereo or surround sound
experience.
``<ch>``
Determines the channel number in which to insert the sub-channel
audio. Channel number can be between 0 and 7 (default: 5). Observe
that the number of channels will automatically be increased to <ch> if
necessary.
.. admonition:: Example
``mpv --af=sub=100:4 --audio-channels=5 media.avi``
Would add a subwoofer channel with a cutoff frequency of 100 Hz to
output channel 4.
``center``
Creates a center channel from the front channels. May currently be low
quality as it does not implement a high-pass filter for proper extraction
yet, but averages and halves the channels instead.
``<ch>``
Determines the channel number in which to insert the center channel.
Channel number can be between 0 and 7 (default: 5). Observe that the
number of channels will automatically be increased to ``<ch>`` if
necessary.
``surround[=delay]``
Decoder for matrix encoded surround sound like Dolby Surround. Some files
with 2-channel audio actually contain matrix encoded surround sound.
``<delay>``
delay time in ms for the rear speakers (0 to 1000) (default: 20) This
delay should be set as follows: If d1 is the distance from the
listening position to the front speakers and d2 is the distance from
the listening position to the rear speakers, then the delay should be
set to 15ms if d1 <= d2 and to 15 + 5*(d1-d2) if d1 > d2.
.. admonition:: Example
``mpv --af=surround=15 --audio-channels=4 media.avi``
Would add surround sound decoding with 15 ms delay for the sound to
the rear speakers.
``delay[=[ch1,ch2,...]]``
Delays the sound to the loudspeakers such that the sound from the
different channels arrives at the listening position simultaneously. It is
only useful if you have more than 2 loudspeakers.
``[ch1,ch2,...]``
The delay in ms that should be imposed on each channel (floating point
number between 0 and 1000).
To calculate the required delay for the different channels, do as follows:
1. Measure the distance to the loudspeakers in meters in relation to your
listening position, giving you the distances s1 to s5 (for a 5.1
system). There is no point in compensating for the subwoofer (you will
not hear the difference anyway).
2. Subtract the distances s1 to s5 from the maximum distance, i.e.
``s[i] = max(s) - s[i]; i = 1...5``.
3. Calculate the required delays in ms as ``d[i] = 1000*s[i]/342; i =
1...5``.
.. admonition:: Example
``mpv --af=delay=[10.5,10.5,0,0,7,0] media.avi``
Would delay front left and right by 10.5 ms, the two rear channels
and the subwoofer by 0 ms and the center channel by 7 ms.
``export=mmapped_file:nsamples]``
Exports the incoming signal to other processes using memory mapping
(``mmap()``). Memory mapped areas contain a header::
int nch /* number of channels */
int size /* buffer size */
unsigned long long counter /* Used to keep sync, updated every time
new data is exported. */
The rest is payload (non-interleaved) 16-bit data.
``<mmapped_file>``
File to map data to (required)
``<nsamples>``
number of samples per channel (default: 512).
.. admonition:: Example
``mpv --af=export=/tmp/mpv-af_export:1024 media.avi``
Would export 1024 samples per channel to ``/tmp/mpv-af_export``.
``extrastereo[=mul]``
(Linearly) increases the difference between left and right channels which
adds some sort of "live" effect to playback.
``<mul>``
Sets the difference coefficient (default: 2.5). 0.0 means mono sound
(average of both channels), with 1.0 sound will be unchanged, with
-1.0 left and right channels will be swapped.
``drc[=method:target]``
Applies dynamic range compression. This maximizes the volume by compressing
the audio signal's dynamic range. (Formerly called ``volnorm``.)
``<method>``
Sets the used method.
1
Use a single sample to smooth the variations via the standard
weighted mean over past samples (default).
2
Use several samples to smooth the variations via the standard
weighted mean over past samples.
``<target>``
Sets the target amplitude as a fraction of the maximum for the sample
type (default: 0.25).
.. note::
This filter can cause distortion with audio signals that have a very
large dynamic range.
``ladspa=file:label:[<control0>,<control1>,...]``
Load a LADSPA (Linux Audio Developer's Simple Plugin API) plugin. This
filter is reentrant, so multiple LADSPA plugins can be used at once.
``<file>``
Specifies the LADSPA plugin library file.
.. note::
See also the note about the ``LADSPA_PATH`` variable in the
`ENVIRONMENT VARIABLES`_ section.
``<label>``
Specifies the filter within the library. Some libraries contain only
one filter, but others contain many of them. Entering 'help' here
will list all available filters within the specified library, which
eliminates the use of 'listplugins' from the LADSPA SDK.
``[<control0>,<control1>,...]``
Controls are zero or more ``,`` separated floating point values that
determine the behavior of the loaded plugin (for example delay,
threshold or gain).
In verbose mode (add ``-v`` to the mpv command line), all
available controls and their valid ranges are printed. This eliminates
the use of 'analyseplugin' from the LADSPA SDK.
Note that ``,`` is already used by the option parser to separate
filters, so you must quote the list of values with ``[...]`` or
similar.
.. admonition:: Example
``mpv --af=ladspa='/usr/lib/ladspa/delay.so':delay_5s:[0.5,0.2] media.avi``
Does something.
``karaoke``
Simple voice removal filter exploiting the fact that voice is usually
recorded with mono gear and later 'center' mixed onto the final audio
stream. Beware that this filter will turn your signal into mono. Works
well for 2 channel tracks; do not bother trying it on anything but 2
channel stereo.
``scaletempo[=option1:option2:...]``
Scales audio tempo without altering pitch, optionally synced to playback
speed.
speed (default).
This works by playing 'stride' ms of audio at normal speed then consuming
'stride*scale' ms of input audio. It pieces the strides together by
@@ -118,8 +551,8 @@ Available filters are:
cause noticeable skips at high scale amounts and an echo at low scale
amounts. Very low values will alter pitch. Increasing improves
performance. (default: 60)
``overlap=<factor>``
Factor of stride to overlap. Decreasing improves performance.
``overlap=<percent>``
Percentage of stride to overlap. Decreasing improves performance.
(default: .20)
``search=<amount>``
Length in milliseconds to search for best overlap position. Decreasing
@@ -132,10 +565,9 @@ Available filters are:
Scale tempo in sync with speed (default).
pitch
Reverses effect of filter. Scales pitch without altering tempo.
Add this to your ``input.conf`` to step by musical semi-tones::
[ multiply speed 0.9438743126816935
] multiply speed 1.059463094352953
Add ``[ speed_mult 0.9438743126816935`` and ``] speed_mult
1.059463094352953`` to your ``input.conf`` to step by musical
semi-tones.
.. warning::
@@ -159,77 +591,15 @@ Available filters are:
``mpv --af=scaletempo=stride=30:overlap=.50:search=10 media.ogg``
Would tweak the quality and performance parameters.
``mpv --af=format=float,scaletempo media.ogg``
Would make scaletempo use float code. Maybe faster on some
platforms.
``mpv --af=scaletempo=scale=1.2:speed=pitch audio.ogg``
Would play media at 1.2x normal speed, with audio at normal pitch.
Changing playback speed would change pitch, leaving audio tempo at
1.2x.
``scaletempo2[=option1:option2:...]``
Scales audio tempo without altering pitch.
The algorithm is ported from chromium and uses the
Waveform Similarity Overlap-and-add (WSOLA) method.
It seems to achieves higher audio quality than scaletempo, and rubberband R2
engine, or ``engine=faster``. This filter is inserted automatically if
``audio-pitch-correction`` option is used (on by default) when the playback
speed is changed.
By default, the ``search-interval`` and ``window-size`` parameters
have the same values as in chromium.
``min-speed=<speed>``
Mute audio if the playback speed is below ``<speed>``. (default: 0.25)
``max-speed=<speed>``
Mute audio if the playback speed is above ``<speed>``
and ``<speed> != 0``. (default: 8.0)
``search-interval=<amount>``
Length in milliseconds to search for best overlap position. (default: 40)
``window-size=<amount>``
Length in milliseconds of the overlap-and-add window. (default: 12)
``rubberband``
High quality pitch correction with librubberband. This can be used in place
of ``scaletempo`` and ``scaletempo2``, and will be used to adjust audio pitch
when playing at speed different from normal. It can also be used to adjust
audio pitch without changing playback speed.
``pitch-scale=<amount>``
Sets the pitch scaling factor. Frequencies are multiplied by this value.
(default: 1.0)
``engine=<faster|finer>``
Select the core Rubberband engine to be used. There are two available:
:Faster: This is the Rubberband R2 engine. It uses significantly less
CPU than the Finer (R3) engine.
:Finer: This is the Rubberband R3 engine. This engine is only available
with librubberband version 3 or newer. This produces significantly
higher quality output, at the cost of higher CPU usage. (Default
if available)
This filter has a number of additional sub-options. You can list them with
``mpv --af=rubberband=help``. This will also show the default values
for each option. The options are not documented here, because they are
merely passed to librubberband. Look at the librubberband documentation
to learn what each option does:
https://breakfastquay.com/rubberband/code-doc/classRubberBand_1_1RubberBandStretcher.html
Do note that certain options are only applicable to one of R2 (faster) and
R3 (finer) engines.
(The mapping of the mpv rubberband filter sub-option names and values to
those of librubberband follows a simple pattern: ``"Option" + Name + Value``.)
This filter supports the following ``af-command`` commands:
``set-pitch``
Set the ``<pitch-scale>`` argument dynamically. This can be used to
change the playback pitch at runtime. Note that speed is controlled
using the standard ``speed`` property, not ``af-command``.
``multiply-pitch <factor>``
Multiply the current value of ``<pitch-scale>`` dynamically.
``lavfi=graph``
Filter audio using FFmpeg's libavfilter.
@@ -245,22 +615,3 @@ Available filters are:
``o=<string>``
AVOptions.
``fix-pts=<yes|no>``
Determine PTS based on sample count (default: no). If this is enabled,
the player won't rely on libavfilter passing through PTS accurately.
Instead, it pass a sample count as PTS to libavfilter, and compute the
PTS used by mpv based on that and the input PTS. This helps with filters
which output a recomputed PTS instead of the original PTS (including
filters which require the PTS to start at 0). mpv normally expects
filters to not touch the PTS (or only to the extent of changing frame
boundaries), so this is not the default, but it will be needed to use
broken filters. In practice, these broken filters will either cause slow
A/V desync over time (with some files), or break playback completely if
you seek or start playback from the middle of a file.
``drop``
This filter drops or repeats audio frames to adapt to playback speed. It
always operates on full audio frames, because it was made to handle SPDIF
(compressed audio passthrough). This is used automatically if the
``--video-sync=display-adrop`` option is used. Do not use this filter (or
the given option); they are extremely low quality.
+146 -188
View File
@@ -4,320 +4,278 @@ AUDIO OUTPUT DRIVERS
Audio output drivers are interfaces to different audio output facilities. The
syntax is:
``--ao=<driver1,driver2,...[,]>``
``--ao=<driver1[:suboption1[=value]:...],driver2,...[,]>``
Specify a priority list of audio output drivers to be used.
If the list has a trailing ',', mpv will fall back on drivers not contained
in the list.
in the list. Suboptions are optional and can mostly be omitted.
This is an object settings list option. See `List Options`_ for details.
You can also set defaults for each driver. The defaults are applied before the
normal driver parameters.
``--ao-defaults=<driver1[:parameter1:parameter2:...],driver2,...>``
Set defaults for each driver.
.. note::
See ``--ao=help`` for a list of compiled-in audio output drivers sorted by
autoprobe order.
See ``--ao=help`` for a list of compiled-in audio output drivers. The
driver ``--ao=alsa`` is preferred. ``--ao=pulse`` is preferred on systems
where PulseAudio is used. On Windows, ``--ao=wasapi`` is preferred,
though it might cause trouble sometimes, in which case ``--ao=dsound``
should be used. On BSD systems, ``--ao=oss`` or `--ao=sndio`` may work
(the latter being experimental). On OS X systems, use ``--ao=coreaudio``.
Note that the default audio output driver is subject to change, and must
not be relied upon. If a certain AO needs to be used, it must be
explicitly specified.
.. admonition:: Examples
- ``--ao=alsa,oss,`` Try the ALSA driver, then the OSS driver, then others.
- ``--ao=alsa:no-block:device=[hw:0,3]`` Sets noblock-mode and the
device-name as first card, fourth device.
Available audio output drivers are:
``alsa``
ALSA audio output driver.
``alsa`` (Linux only)
ALSA audio output driver
The following global options are supported by this audio output:
``--alsa-resample=yes``
``device=<device>``
Sets the device name. For ac3 output via S/PDIF, use an "iec958" or
"spdif" device, unless you really know how to set it correctly.
``no-block``
Sets noblock-mode.
``resample=yes``
Enable ALSA resampling plugin. (This is disabled by default, because
some drivers report incorrect audio delay in some cases.)
``--alsa-mixer-device=<device>``
Set the mixer device used with ``ao-volume`` (default: ``default``).
``--alsa-mixer-name=<name>``
``mixer-device=<device>``
Set the mixer device used with ``--no-softvol`` (default: ``default``).
``mixer-name=<name>``
Set the name of the mixer element (default: ``Master``). This is for
example ``PCM`` or ``Master``.
``--alsa-mixer-index=<number>``
``mixer-index=<number>``
Set the index of the mixer channel (default: 0). Consider the output of
"``amixer scontrols``", then the index is the number that follows the
name of the element.
``--alsa-non-interleaved``
``non-interleaved``
Allow output of non-interleaved formats (if the audio decoder uses
this format). Currently disabled by default, because some popular
ALSA plugins are utterly broken with non-interleaved formats.
``--alsa-ignore-chmap``
Don't read or set the channel map of the ALSA device - only request the
required number of channels, and then pass the audio as-is to it. This
option most likely should not be used. It can be useful for debugging,
or for static setups with a specially engineered ALSA configuration (in
this case you should always force the same layout with ``--audio-channels``,
or it will work only for files which use the layout implicit to your
ALSA device).
.. note::
``--alsa-buffer-time=<microseconds>``
Set the requested buffer time in microseconds. A value of 0 skips requesting
anything from the ALSA API. This and the ``--alsa-periods`` option uses the
ALSA ``near`` functions to set the requested parameters. If doing so results
in an empty configuration set, setting these parameters is skipped.
MPlayer and mplayer2 required you to replace any ',' with '.' and
any ':' with '=' in the ALSA device name. mpv does not do this anymore.
Instead, quote the device name:
Both options control the buffer size. A low buffer size can lead to higher
CPU usage and audio dropouts, while a high buffer size can lead to higher
latency in volume changes and other filtering.
``--ao=alsa:device=[plug:surround50]``
``--alsa-periods=<number>``
Number of periods requested from the ALSA API. See ``--alsa-buffer-time``
for further remarks.
.. warning::
To get multichannel/surround audio, use ``--audio-channels=auto``. The
default for this option is ``auto-safe``, which makes this audio output
explicitly reject multichannel output, as there is no way to detect
whether a certain channel layout is actually supported.
You can also try `using the upmix plugin
<https://github.com/mpv-player/mpv/wiki/ALSA-Surround-Sound-and-Upmixing>`_.
This setup enables multichannel audio on the ``default`` device
with automatic upmixing with shared access, so playing stereo
and multichannel audio at the same time will work as expected.
Note that the ``[`` and ``]`` simply quote the device name. With some
shells (like zsh), you have to quote the option string to prevent the
shell from interpreting the brackets instead of passing them to mpv.
``oss``
OSS audio output driver
``<dsp-device>``
Sets the audio output device (default: ``/dev/dsp``).
``<mixer-device>``
Sets the audio mixer device (default: ``/dev/mixer``).
``<mixer-channel>``
Sets the audio mixer channel (default: ``pcm``). Other valid values
include **vol, pcm, line**. For a complete list of options look for
``SOUND_DEVICE_NAMES`` in ``/usr/include/linux/soundcard.h``.
``jack``
JACK (Jack Audio Connection Kit) audio output driver.
JACK (Jack Audio Connection Kit) audio output driver
The following global options are supported by this audio output:
``--jack-port=<name>``
``port=<name>``
Connects to the ports with the given name (default: physical ports).
``--jack-name=<client>``
``name=<client>``
Client name that is passed to JACK (default: ``mpv``). Useful
if you want to have certain connections established automatically.
``--jack-autostart=<yes|no>``
``(no-)autostart``
Automatically start jackd if necessary (default: disabled). Note that
this tends to be unreliable and will flood stdout with server messages.
``--jack-connect=<yes|no>``
``(no-)connect``
Automatically create connections to output ports (default: enabled).
When enabled, the maximum number of output channels will be limited to
the number of available output ports.
``--jack-std-channel-layout=<waveext|any>``
Select the standard channel layout (default: waveext). JACK itself has no
``std-channel-layout=alsa|waveext|any``
Select the standard channel layout (default: alsa). JACK itself has no
notion of channel layouts (i.e. assigning which speaker a given
channel is supposed to map to) - it just takes whatever the application
outputs, and reroutes it to whatever the user defines. This means the
user and the application are in charge of dealing with the channel
layout. ``waveext`` uses WAVE_FORMAT_EXTENSIBLE order, which, even
layout. ``alsa`` uses the old MPlayer layout, which is inspired by
ALSA's standard layouts. In this mode, ao_jack will refuse to play 3
or 7 channels (because these do not really have a defined meaning in
MPlayer). ``waveext`` uses WAVE_FORMAT_EXTENSIBLE order, which, even
though it was defined by Microsoft, is the standard on many systems.
The value ``any`` makes JACK accept whatever comes from the audio
filter chain, regardless of channel layout and without reordering. This
mode is probably not very useful, other than for debugging or when used
with fixed setups.
``coreaudio`` (macOS only)
Native macOS audio output driver using AudioUnits and the CoreAudio
``coreaudio`` (Mac OS X only)
Native Mac OS X audio output driver using AudioUnits and the CoreAudio
sound server.
Automatically redirects to ``coreaudio_exclusive`` when playing compressed
formats.
The following global options are supported by this audio output:
``--coreaudio-change-physical-format=<yes|no>``
Change the physical format to one similar to the requested audio format
(default: no). This has the advantage that multichannel audio output
will actually work. The disadvantage is that it will change the
system-wide audio settings. This is equivalent to changing the ``Format``
setting in the ``Audio Devices`` dialog in the ``Audio MIDI Setup``
utility. Note that this does not affect the selected speaker setup.
``--coreaudio-spdif-hack=<yes|no>``
Try to pass through AC3/DTS data as PCM. This is useful for drivers
which do not report AC3 support. It converts the AC3 data to float,
and assumes the driver will do the inverse conversion, which means
a typical A/V receiver will pick it up as compressed IEC framed AC3
stream, ignoring that it's marked as PCM. This disables normal AC3
passthrough (even if the device reports it as supported). Use with
extreme care.
``coreaudio_exclusive`` (macOS only)
Native macOS audio output driver using direct device access and
``coreaudio_exclusive`` (Mac OS X only)
Native Mac OS X audio output driver using direct device access and
exclusive mode (bypasses the sound server).
``avfoundation`` (macOS only)
Native macOS audio output driver using ``AVSampleBufferAudioRenderer``
in AVFoundation, which supports `spatial audio
<https://support.apple.com/en-us/HT211775>`_.
.. warning::
Turning on spatial audio may hang the playback
if mpv is not started out of the bundle,
though playback with spatial audio off always works.
``audiounit`` (iOS only)
Native iOS audio output driver using ``AudioUnits`` and AudioToolbox.
Supports only compressed formats (AC3 and DTS).
``openal``
OpenAL audio output driver.
Experimental OpenAL audio output driver
``--openal-num-buffers=<2-128>``
Specify the number of audio buffers to use. Lower values are better for
lower CPU usage. Default: 4.
``--openal-num-samples=<256-32768>``
Specify the number of complete samples to use for each buffer. Higher
values are better for lower CPU usage. Default: 8192.
``--openal-direct-channels=<yes|no>``
Enable OpenAL Soft's direct channel extension when available to avoid
tinting the sound with ambisonics or HRTF. Default: yes.
.. note:: This driver is not very useful. Playing multi-channel audio with
it is slow.
``pulse``
PulseAudio audio output driver
The following global options are supported by this audio output:
``[<host>][:<output sink>]``
Specify the host and optionally output sink to use. An empty <host>
string uses a local connection, "localhost" uses network transfer
(most likely not what you want).
``--pulse-host=<host>``
Specify the host to use. An empty <host> string uses a local connection,
"localhost" uses network transfer (most likely not what you want).
``--pulse-buffer=<1-2000|native>``
``buffer=<1-2000|native>``
Set the audio buffer size in milliseconds. A higher value buffers
more data, and has a lower probability of buffer underruns. A smaller
value makes the audio stream react faster, e.g. to playback speed
changes. "native" lets the sound server determine buffers.
changes. Default: 250.
``--pulse-latency-hacks=<yes|no>``
``latency-hacks=<yes|no>``
Enable hacks to workaround PulseAudio timing bugs (default: yes). If
enabled, mpv will do elaborate latency calculations on its own. If
disabled, it will use PulseAudio automatically updated timing
information. Disabling this might help with e.g. networked audio or
some plugins, while enabling it might help in some unknown situations
(it is currently enabled due to known bugs with PulseAudio 16.0).
information. Disabling this might help with e.g. networked audio.
``--pulse-allow-suspended=<yes|no>``
Allow mpv to use PulseAudio even if the sink is suspended (default: no).
Can be useful if PulseAudio is running as a bridge to jack and mpv has its sink-input set to the one jack is using.
``portaudio``
PortAudio audio output driver. This works on all platforms, and has
extensive MS Windows support.
``pipewire``
PipeWire audio output driver
.. note:: This driver is not very useful. It was added in the hope of
providing portable audio API across all platforms, but turned
out semi-broken and underfeatured.
The following global options are supported by this audio output:
``device``
Specify the subdevice to use. Giving ``help`` as device name lists all
devices found by PortAudio. Devices can be given as numeric values,
starting from ``1``.
``--pipewire-buffer=<1-2000|native>``
Set the audio buffer size in milliseconds. A higher value buffers
more data, and has a lower probability of buffer underruns. A smaller
value makes the audio stream react faster, e.g. to playback speed
changes. "native" lets the sound server determine buffers.
``dsound`` (Windows only)
DirectX DirectSound audio output driver
``--pipewire-remote=<remote>``
Specify the PipeWire remote daemon name to connect to via local UNIX
sockets.
An empty <remote> string uses the default remote named ``pipewire-0``.
.. note:: This driver is for compatibility with old systems.
``--pipewire-volume-mode=<channel|global>``
Specify if the ``ao-volume`` property should apply to the channel
volumes or the global volume.
By default the channel volumes are used.
``device=<devicenum>``
Sets the device number to use. Playing a file with ``-v`` will show a
list of available devices.
``buffersize=<ms>``
DirectSound buffer size in milliseconds (default: 200).
``sdl``
SDL 2.0+ audio output driver. Should work on any platform supported by SDL
2.0, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
SDL 1.2+ audio output driver. Should work on any platform supported by SDL
1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
appropriately for your system.
.. note:: This driver is for compatibility with extremely foreign
environments, such as systems where none of the other drivers
are available.
The following global options are supported by this audio output:
``--sdl-buflen=<length>``
``buflen=<length>``
Sets the audio buffer length in seconds. Is used only as a hint by the
sound system. Playing a file with ``-v`` will show the requested and
obtained exact buffer size. A value of 0 selects the sound system
default.
``bufcnt=<count>``
Sets the number of extra audio buffers in mpv. Usually needs not be
changed.
``null``
Produces no audio output but maintains video playback speed. You can use
``--ao=null --ao-null-untimed`` for benchmarking.
Produces no audio output but maintains video playback speed. Use
``--ao=null:untimed`` for benchmarking.
The following global options are supported by this audio output:
``--ao-null-untimed``
``untimed``
Do not simulate timing of a perfect audio device. This means audio
decoding will go as fast as possible, instead of timing it to the
system clock.
``--ao-null-buffer``
``buffer``
Simulated buffer length in seconds.
``--ao-null-outburst``
``outburst``
Simulated chunk size in samples.
``--ao-null-speed``
``speed``
Simulated audio playback speed as a multiplier. Usually, a real audio
device will not go exactly as fast as the system clock. It will deviate
just a little, and this option helps to simulate this.
just a little, and this option helps simulating this.
``--ao-null-latency``
``latency``
Simulated device latency. This is additional to EOF.
``--ao-null-broken-eof``
``broken-eof``
Simulate broken audio drivers, which always add the fixed device
latency to the reported audio playback position.
``--ao-null-broken-delay``
Simulate broken audio drivers, which don't report latency correctly.
``--ao-null-channel-layouts``
If not empty, this is a ``,`` separated list of channel layouts the
AO allows. This can be used to test channel layout selection.
``--ao-null-format``
Force the audio output format the AO will accept. If unset accepts any.
``pcm``
Raw PCM/WAVE file writer audio output
The following global options are supported by this audio output:
``--ao-pcm-waveheader=<yes|no>``
``(no-)waveheader``
Include or do not include the WAVE header (default: included). When
not included, raw PCM will be generated.
``--ao-pcm-file=<filename>``
``file=<filename>``
Write the sound to ``<filename>`` instead of the default
``audiodump.wav``. If ``no-waveheader`` is specified, the default is
``audiodump.pcm``.
``--ao-pcm-append=<yes|no>``
Append to the file, instead of overwriting it. Always use this with the
``no-waveheader`` option - with ``waveheader`` it's broken, because
it will write a WAVE header every time the file is opened.
``rsound``
Audio output to an RSound daemon
.. note:: Completely useless, unless you intend to run RSound. Not to be
confused with RoarAudio, which is something completely
different.
``host=<name/path>``
Set the address of the server (default: localhost). Can be either a
network hostname for TCP connections or a Unix domain socket path
starting with '/'.
``port=<number>``
Set the TCP port used for connecting to the server (default: 12345).
Not used if connecting to a Unix domain socket.
``sndio``
Audio output to the OpenBSD sndio sound system
.. note:: Experimental. There are known bugs and issues.
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
layouts.)
``device=<device>``
sndio device to use (default: ``$AUDIODEVICE``, resp. ``snd0``).
``wasapi``
Audio output to the Windows Audio Session API.
The following global options are supported by this audio output:
``device=<id>``
Uses the requested endpoint instead of the system's default audio
endpoint. Both the number and the ID String are valid; the ID String
is guaranteed to not change unless the driver is uninstalled.
``--wasapi-exclusive-buffer=<default|min|1-2000000>``
Set buffer duration in exclusive mode (i.e., with
``--audio-exclusive=yes``). ``default`` and ``min`` use the default and
minimum device period reported by WASAPI, respectively. You can also
directly specify the buffer duration in microseconds, in which case a
duration shorter than the minimum device period will be rounded up to
the minimum period.
Also supports searching active devices by name. If more than one
device matches the name, refuses loading it.
The default buffer duration should provide robust playback in most
cases, but reportedly on some devices there are glitches following
stream resets under the default setting. In such cases, specifying a
shorter duration might help.
To get a list of the valid devices, give ``help`` as the id. The
list is the same as the ``list`` suboption, but stops the player
initialization.
``exclusive``
Requests exclusive, direct hardware access. By definition prevents
sound playback of any other program until mpv exits.
``list``
Lists all audio endpoints (output devices) present in the system.
+435 -16
View File
@@ -1,19 +1,438 @@
CHANGELOG
=========
CHANGES FROM OTHER VERSIONS OF MPLAYER
======================================
There is no real changelog, but you can look at the following things:
**mpv** is based on mplayer2, which in turn is based on the original MPlayer
(also called mplayer, mplayer-svn, mplayer1). Many changes have been made, a
large part of which is incompatible or completely changes how the player
behaves. Although there are still many similarities to its ancestors, **mpv**
should generally be treated as a completely different program.
* The release changelog, which should contain most user-visible changes,
including new features and bug fixes:
.. note::
These lists are incomplete.
https://github.com/mpv-player/mpv/releases
* The git log, which is the "real" changelog
* The file https://github.com/mpv-player/mpv/blob/master/DOCS/interface-changes.rst
documents changes to the command and user interface, such as options and
properties.
* C API changes are listed in
https://github.com/mpv-player/mpv/blob/master/DOCS/client-api-changes.rst
* The file ``mplayer-changes.rst`` in the ``DOCS`` sub directory on the git
repository, which used to be in place of this section. It documents some
changes that happened since mplayer2 forked off MPlayer. (Not updated
anymore.)
General Changes from MPlayer to mpv
-----------------------------------
This listing is about changes introduced by mplayer2 and mpv relatively to
MPlayer.
Player
~~~~~~
* New name for the binary (``mpv``). New location for config files (either
``~/.config/mpv/mpv.conf``, or if you want, ``~/.mpv/config``).
* Encoding functionality (replacement for MEncoder, see the `ENCODING`_ section).
* Support for Lua scripting (see the `LUA SCRIPTING`_ section).
* Better pause handling (e.g. do not unpause on a command).
* Precise seeking support.
* Improvements in audio/video sync handling.
* Do not lose settings when playing a new file in the same player instance.
* Slave mode compatibility broken (see below).
* Re-enable screensaver while the player is paused.
* Allow resuming playback at a later point with ``Shift+q``, also see the
``quit_watch_later`` input command.
* ``--keep-open`` option to stop the player from closing the window and
exiting after playback ends.
* A client API, that allows embedding **mpv** into applications
(see ``libmpv/client.h`` in the sources).
Input
~~~~~
* Improved default keybindings. MPlayer bindings are also available (see
``etc/mplayer-input.conf`` in the source tree).
* Improved responsiveness on user input.
* Support for modifier keys (alt, shift, ctrl) in input.conf.
* Allow customizing whether a key binding for seeking shows the video time, the
OSD bar, or nothing (see the `Input Command Prefixes`_ section).
* Support mapping multiple commands to one key.
Audio
~~~~~
* Support for gapless audio (see the ``--gapless-audio`` option).
* Support for OSS4 volume control.
* Improved support for PulseAudio.
* Make ``--softvol`` default (**mpv** is not a mixer control panel).
* By default, do pitch correction if playback speed is increased.
* Improved downmixing and output of surround audio:
- Instead of using hardcoded pan filters to do remixing, libavresample is used
- Channel maps are used to identify the channel layout, so e.g. ``3.0`` and
``2.1`` audio can be distinguished.
Video
~~~~~
* Wayland support.
* Native support for VAAPI and VDA. Improved VDPAU video output.
* Improved OpenGL output (see the ``opengl-hq`` video output).
* Make hardware decoding work with the ``opengl`` video output.
* Support for libavfilter (for video->video and audio->audio). This allows
using most of FFmpeg's filters, which improve greatly on the old MPlayer
filters in features, performance, and correctness.
* More correct color reproduction (color matrix generation).
* Better subtitle rendering using libass by default.
* Improvements when playing multiple files (``--fixed-vo`` is default, do not
reset settings by default when playing a new file).
* Replace image video outputs (``--vo=jpeg`` etc.) with ``--vo=image``.
* Removal of ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding
can handle these use cases. For yuv4mpeg, for example, use::
mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop
* Image subtitles (DVDs etc.) are rendered in color and use more correct
positioning (color for image subs can be disabled with ``--sub-gray``).
OSD and terminal
~~~~~~~~~~~~~~~~
* Cleaned up terminal output: nicer status line, less useless noise.
* Improved OSD rendering using libass, with full Unicode support.
* New OSD bar with chapter marks. Not positioned in the middle of the video
(this can be customized with the ``--osd-bar-align-y`` option).
* Display list of chapters and audio/subtitle tracks on OSD (see the
`Properties`_ section).
Screenshots
~~~~~~~~~~~
* Instant screenshots without 1-frame delay.
* Support for taking screenshots even with hardware decoding.
* Support for saving screenshots as JPEG or PNG.
* Support for configurable file names.
* Support for taking screenshots with or without subtitles.
Note that the ``screenshot`` video filter is not needed anymore, and should not
be put into the mpv config file.
Miscellaneous
~~~~~~~~~~~~~
* Better MKV support (e.g. ordered chapters, 3D metadata).
* Matroska edition switching at runtime.
* Support for playing URLs of popular streaming sites directly.
(e.g. ``mpv https://www.youtube.com/watch?v=...``).
Requires a recent version of ``youtube-dl`` to be installed, and
``ytdl=yes`` in the mpv config file.
* Support for precise scrolling which scales the parameter of commands. If the
input doesn't support precise scrolling the scale factor stays 1.
* Allow changing/adjusting video filters at runtime. (This is also used to make
the ``D`` key insert vf_yadif if deinterlacing is not supported otherwise).
* Improved support for .cue files.
Mac OS X
~~~~~~~~
* Native OpenGL backend.
* Cocoa event loop is independent from MPlayer's event loop, so user
actions like accessing menus and live resizing do not block the playback.
* Apple Remote support.
* Media Keys support.
* VDA support using libavcodec hwaccel API instead of FFmpeg's decoder with up
to 2-2.5x reduction in CPU usage.
Windows
~~~~~~~
* Improved support for Unicode file names.
* Improved window handling.
* Do not block playback when moving the window.
* Improved Direct3D video output.
* Added WASAPI audio output.
Internal changes
~~~~~~~~~~~~~~~~
* Switch to GPLv2+ (see ``Copyright`` file for details).
* Removal of lots of cruft:
- Internal GUI (replaced by the OSC, see the `ON SCREEN CONTROLLER`_ section).
- MEncoder (replaced by native encoding, see the `ENCODING`_ section).
- OSD menu.
- Kernel video drivers for Linux 2.4 (including VIDIX).
- Teletext support.
- Support for dead platforms.
- Most built-in demuxers have been replaced by their libavformat counterparts.
- Built-in network support has been replaced by libavformat's (which also
supports https URLs).
- Embedded copies of libraries (such as FFmpeg).
* General code cleanups (including refactoring or rewrites of many parts).
* New build system.
* Many bug fixes and removal of long-standing issues.
* Generally preferring FFmpeg/Libav over internal demuxers, decoders, and
filters.
Detailed Listing of User-visible Changes
----------------------------------------
This listing is about changed command line switches, slave commands, and similar
things. Completely removed features are not listed.
Command Line Switches
~~~~~~~~~~~~~~~~~~~~~
* There is a new command line syntax, which is generally preferred over the old
syntax. ``-optname optvalue`` becomes ``--optname=optvalue``.
The old syntax will not be removed. However, the new syntax is mentioned in
all documentation and so on, and unlike the old syntax is not ambiguous,
so it is a good thing to know about this change.
* In general, negating switches like ``-noopt`` now have to be written as
``-no-opt`` or ``--no-opt``.
* Per-file options are not the default anymore. You can explicitly specify
file-local options. See ``Usage`` section.
* Many options have been renamed, removed or changed semantics. Some options
that are required for a good playback experience with MPlayer are now
superfluous or even worse than the defaults, so make sure to read the manual
before trying to use your existing configuration with **mpv**.
* Table of renamed/replaced switches:
=========================== ========================================
Old New
=========================== ========================================
``-no<opt>`` ``--no-<opt>`` (add a dash)
``-a52drc level`` ``--ad-lavc-ac3drc=level``
``-ac spdifac3`` ``--ad=spdif:ac3`` (see ``--ad=help``)
``-af volnorm`` ``--af=drc`` (renamed)
``-afm hwac3`` ``--ad=spdif:ac3,spdif:dts``
``-ao alsa:device=hw=0.3`` ``--ao=alsa:device=[hw:0,3]``
``-aspect`` ``--video-aspect``
``-ass-bottom-margin`` ``--vf=sub=bottom:top``
``-ass`` ``--sub-ass``
``-audiofile-cache`` (removed; the main cache settings are used)
``-audiofile`` ``--audio-file``
``-benchmark`` ``--untimed`` (no stats)
``-capture`` ``--stream-capture=<filename>``
``-channels`` ``--audio-channels`` (changed semantics)
``-cursor-autohide-delay`` ``--cursor-autohide``
``-delay`` ``--audio-delay``
``-dumpstream`` ``--stream-dump=<filename>``
``-dvdangle`` ``--dvd-angle``
``-endpos`` ``--length``
``-font`` ``--osd-font``
``-forcedsubsonly`` ``--sub-forced-only``
``-forceidx`` ``--index``
``-format`` ``--audio-format``
``-fsmode-dontuse`` (removed)
``-fstype`` ``--x11-netwm`` (changed semantics)
``-hardframedrop`` ``--framedrop=hard``
``-identify`` (removed; use TOOLS/mpv_identify.sh)
``-idx`` ``--index``
``-lavdopts ...`` ``--vd-lavc-...``
``-lavfdopts`` ``--demuxer-lavf-...``
``-lircconf`` ``--input-lirc-conf``
``-loop 0`` ``--loop=inf``
``-mixer-channel`` AO suboptions (``alsa``, ``oss``)
``-mixer`` AO suboptions (``alsa``, ``oss``)
``-mouse-movements`` ``--input-cursor``
``-msgcolor`` ``--msg-color``
``-msglevel`` ``--msg-level`` (changed semantics)
``-msgmodule`` ``--msg-module``
``-name`` ``--x11-name``
``-noar`` ``--no-input-appleremote``
``-noautosub`` ``--no-sub-auto``
``-noconsolecontrols`` ``--no-input-terminal``
``-nojoystick`` ``--no-input-joystick``
``-nosound`` ``--no-audio``
``-osdlevel`` ``--osd-level``
``-panscanrange`` ``--video-zoom``, ``--video-pan-x/y``
``-playing-msg`` ``--term-playing-msg``
``-pp ...`` ``'--vf=pp=[...]'``
``-pphelp`` ``--vf=pp:help``
``-rawaudio ...`` ``--demuxer-rawaudio-...``
``-rawvideo ...`` ``--demuxer-rawvideo-...``
``-spugauss`` ``--sub-gauss``
``-srate`` ``--audio-samplerate``
``-ss`` ``--start``
``-ssf <sub>`` ``--sws-...``
``-stop-xscreensaver`` ``--stop-screensaver``
``-sub-fuzziness`` ``--sub-auto``
``-sub`` ``--sub-file``
``-subcp`` ``--sub-codepage``
``-subdelay`` ``--sub-delay``
``-subfile`` ``--sub-file``
``-subfont-*`` ``--sub-text-*``, ``--osd-*``
``-subfont-text-scale`` ``--sub-scale``
``-subfont`` ``--sub-text-font``
``-subfps`` ``--sub-fps``
``-subpos`` ``--sub-pos``
``-sws`` ``--sws-scaler``
``-tvscan`` ``--tv-scan``
``-use-filename-title`` ``--title='${filename}'``
``-vc ffh264vdpau`` (etc.) ``--hwdec=vdpau``
``-vobsub`` ``--sub-file`` (pass the .idx file)
``-x W``, ``-y H`` ``--geometry=WxH`` + ``--no-keepaspect``
``-xineramascreen`` ``--screen`` (different values)
``-xy W`` ``--autofit=W``
``-zoom`` Inverse available as ``--video-unscaled``
``dvdnav://`` ``dvdnav://menu``
``dvd://1`` ``dvd://0`` (0-based offset)
=========================== ========================================
.. note::
``-opt val`` becomes ``--opt=val``.
.. note::
Quite some video filters, video outputs, audio filters, audio outputs, had
changes in their option parsing. These aren't mentioned in the table above.
Also, some video and audio filters have been removed, and you have to use
libavfilter (using ``--vf=lavfi=[...]`` or ``--af=lavfi=[...]``) to get
them back.
input.conf and Slave Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Table of renamed input commands:
This lists only commands that are not always gracefully handled by the
internal legacy translation layer. If an input.conf contains any legacy
commands, a warning will be printed when starting the player. The warnings
also show the replacement commands.
Properties containing ``_`` to separate words use ``-`` instead.
+--------------------------------+----------------------------------------+
| Old | New |
+================================+========================================+
| ``pt_step 1 [0|1]`` | ``playlist_next [weak|force]`` |
| | (translation layer cannot deal with |
| | whitespace) |
+--------------------------------+----------------------------------------+
| ``pt_step -1 [0|1]`` | ``playlist_prev [weak|force] (same)`` |
+--------------------------------+----------------------------------------+
| ``switch_ratio [<ratio>]`` | ``set video-aspect <ratio>`` |
| | |
| | ``set video-aspect 0`` (reset aspect) |
+--------------------------------+----------------------------------------+
| ``step_property_osd <prop>`` | ``cycle <prop> <step>`` (wraps), |
| ``<step> <dir>`` | ``add <prop> <step>`` (clamps). |
| | ``<dir>`` parameter unsupported. Use |
| | a negative ``<step>`` instead. |
+--------------------------------+----------------------------------------+
| ``step_property <prop>`` | Prefix ``cycle`` or ``add`` with |
| ``<step> <dir>`` | ``no-osd``: ``no-osd cycle <prop>`` |
| | ``<step>`` |
+--------------------------------+----------------------------------------+
| ``osd_show_property_text`` | ``show_text <text>`` |
| ``<text>`` | The property expansion format string |
| | syntax slightly changed. |
+--------------------------------+----------------------------------------+
| ``osd_show_text`` | Now does the same as |
| | ``osd_show_property_text``. Use the |
| | ``raw`` prefix to disable property |
| | expansion. |
+--------------------------------+----------------------------------------+
| ``show_tracks`` | ``show_text ${track-list}`` |
+--------------------------------+----------------------------------------+
| ``show_chapters`` | ``show_text ${chapter-list}`` |
+--------------------------------+----------------------------------------+
| ``af_switch``, ``af_add``, ... | ``af set|add|...`` |
+--------------------------------+----------------------------------------+
| ``tv_start_scan`` | ``set tv-scan yes`` |
+--------------------------------+----------------------------------------+
| ``tv_set_channel <val>`` | ``set tv-channel <val>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_channel`` | ``cycle tv-channel`` |
+--------------------------------+----------------------------------------+
| ``dvb_set_channel <v1> <v2>`` | ``set dvb-channel <v1>-<v2>`` |
+--------------------------------+----------------------------------------+
| ``dvb_step_channel`` | ``cycle dvb-channel`` |
+--------------------------------+----------------------------------------+
| ``tv_set_freq <val>`` | ``set tv-freq <val>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_freq`` | ``cycle tv-freq`` |
+--------------------------------+----------------------------------------+
| ``tv_set_norm <norm>`` | ``set tv-norm <norm>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_norm`` | ``cycle tv-norm`` |
+--------------------------------+----------------------------------------+
.. note::
Due to lack of hardware and users using the TV/DVB/PVR features, and
due to the need to cleanup the related command code, it's possible
that the new commands are buggy or behave worse. This can be improved
if testers are available. Otherwise, some of the TV code will be
removed at some point.
Slave mode
~~~~~~~~~~
* Slave mode was removed. A proper slave mode application needed tons of code
and hacks to get
it right. The main problem is that slave mode is a bad and incomplete
interface, and to get around that, applications parsed output messages
intended for users. It is hard to know which messages exactly are parsed by
slave mode applications. This makes it virtually impossible to improve
terminal output intended for users without possibly breaking something.
This is absolutely insane, and since initial improvements to **mpv** quickly
made slave mode incompatible to most applications, it was removed as useless
cruft. The client API (see below) is provided instead.
``--identify`` was replaced by the ``TOOLS/mpv_identify.sh`` wrapper script.
* For some time (until including release 0.4.x), mpv supported a
``--slave-broken`` option. The following options are equivalent:
::
--input-file=/dev/stdin --input-terminal=no
Assuming the system supports ``/dev/stdin``.
(The option was readded in 0.5.1 and sets exactly these options.)
* A JSON RPC protocol giving access to the client API is also supported. See
`JSON IPC`_ for more information.
* **mpv** also provides a client API, which can be used to embed the player
by loading it as shared library. (See ``libmpv/client.h`` in the sources.)
It might also be possible to implement a custom slave mode-like protocol
using Lua scripting.
Policy for Removed Features
---------------------------
**mpv** is in active development. If something is in the way of more important
development (such as fixing bugs or implementing new features), we sometimes
remove features. Usually this happens only with old features that either seem
to be useless, or are not used by anyone. Often these are obscure, or
"inherited", or were marked experimental, but never received any particular
praise by any users.
Sometimes, features are replaced by something new. The new code will be either
simpler or more powerful, but doesn't necessarily provide everything the old
feature did.
We can not exclude that we accidentally remove features that are actually
popular. Generally, we do not know how much a specific functionality is used.
If you miss a feature and think it should be re-added, please open an issue
on the mpv bug tracker. Hopefully, a solution can be found. Often, it turns
out that re-adding something is not much of a problem, or that there are
better alternatives.
Why this Fork?
--------------
mplayer2 is practically dead, and mpv started out as a branch containing
new/experimental development. (Some of it was merged right *after* the fork
was made public, seemingly as an acknowledgment that development, or at
least merging, should have been more active.)
MPlayer is focused on not breaking anything, but is stuck with a horrible
codebase resistant to cleanup. (Unless you do what mpv did - merciless and
consequent pruning of bad, old code.) Cleanup and keeping broken things
conflict, so the kind of development mpv strives for can't be done within
MPlayer due to clashing development policies.
Additionally, mplayer2 already had lots of changes over MPlayer, which would
have needed to be backported to the MPlayer codebase. This would not only
have been hard (several years of diverging development), but also would have
been impossible due to the aforementioned MPlayer development policy.
-58
View File
@@ -1,58 +0,0 @@
COMMANDS
========
This script allows running and completing input commands in the console
interactively, and also adds mpv's log to the console's log.
Keybindings
-----------
\`
Open the console to enter commands.
Commands
--------
``script-binding commands/open``
Open the console to enter commands.
``script-message-to commands type <text> [<cursor_pos>]``
Show the console and pre-fill it with the provided text, optionally
specifying the initial cursor position as a positive integer starting from
1. The console is automatically closed after running the command.
.. admonition:: Examples for input.conf
``% script-message-to commands type "seek absolute-percent" 6``
Enter a percent position to seek to.
``Ctrl+o script-message-to console type "loadfile ''" 11``
Enter a file or URL to play, with autocompletion of paths in the
filesystem.
Configuration
-------------
This script can be customized through a config file ``script-opts/commands.conf``
placed in mpv's user directory and through the ``--script-opts`` command-line
option. The configuration syntax is described in `mp.options functions`_.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``persist_history``
Default: no
Whether to save the command history to a file and load it.
``history_path``
Default: ``~~state/command_history.txt``
The file path for ``persist_history`` (see `FILES`_).
``remember_input``
Default: yes
Whether to remember the input line and cursor position when closing the
console, and prefill it the next time it is opened.
-231
View File
@@ -1,231 +0,0 @@
CONSOLE
=======
This script provides the ability to process the user's textual input to other
scripts through the ``mp.input`` API. It can be displayed on both the video
window and the terminal. It can be disabled entirely using the
``--load-console=no`` option.
Console can either process free-form text or select from a predefined list of
items.
Free-form text mode keybindings
-------------------------------
ESC and Ctrl+[
Hide the console.
ENTER, Ctrl+j and Ctrl+m
Select the first completion if one wasn't already manually selected, and run
the typed command.
Shift+ENTER
Type a literal newline character.
LEFT and Ctrl+b
Move the cursor to the previous character.
RIGHT and Ctrl+f
Move the cursor to the next character.
Ctrl+LEFT and Alt+b
Move the cursor to the beginning of the current word, or if between words,
to the beginning of the previous word.
Ctrl+RIGHT and Alt+f
Move the cursor to the end of the current word, or if between words, to the
end of the next word.
HOME and Ctrl+a
Move the cursor to the start of the current line.
END and Ctrl+e
Move the cursor to the end of the current line.
BACKSPACE and Ctrl+h
Delete the previous character.
Ctrl+d
Hide the console if the current line is empty, otherwise delete the next
character.
Ctrl+BACKSPACE and Ctrl+w
Delete text from the cursor to the beginning of the current word, or if
between words, to the beginning of the previous word.
Ctrl+DEL and Alt+d
Delete text from the cursor to the end of the current word, or if between
words, to the end of the next word.
Ctrl+u
Delete text from the cursor to the beginning of the current line.
Ctrl+k
Delete text from the cursor to the end of the current line.
Ctrl+c
Clear the current line.
UP and Ctrl+p
Move back in the command history.
DOWN and Ctrl+n
Move forward in the command history.
PGUP
Go to the first command in the history.
PGDN
Stop navigating the command history.
Ctrl+r
Search the command history. See `SELECT`_ for the key bindings in this mode.
INSERT
Toggle insert mode.
Ctrl+v
Paste text (uses the clipboard on X11 and Wayland).
Shift+INSERT
Paste text (uses the primary selection on X11 and Wayland).
Ctrl+y
Copy the current line to the clipboard.
TAB and Ctrl+i
Cycle through completions.
Shift+TAB
Cycle through the completions backwards.
Ctrl+l
Clear all log messages from the console.
MBTN_MID
Paste text (uses the primary selection on X11 and Wayland).
WHEEL_UP
Move back in the command history.
WHEEL_DOWN
Move forward in the command history.
Known issues
------------
- Non-ASCII keyboard input has restrictions
- The cursor keys move between Unicode code-points, not grapheme clusters
Configuration
-------------
This script can be customized through a config file ``script-opts/console.conf``
placed in mpv's user directory and through the ``--script-opts`` command-line
option. The configuration syntax is described in `mp.options functions`_.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``monospace_font``
Default: platform dependent
The monospace font used when there are completions to align in a grid.
When there are no completions, ``--osd-font`` is used.
``font_size``
Default: 24
The font size. This will be multiplied by ``display-hidpi-scale`` when the
console is not scaled with the window.
``border_size``
Default: 1.65
The font border size.
``background_alpha``
Default: 80
The transparency of the menu's background. Ranges from 0 (opaque) to 255
(fully transparent).
``gap``
Default: 0.2
The gap between menu items, specified as a percentage the font size.
``padding``
Default: 10
The padding of the menu.
``menu_outline_size``
Default: 0
The size of the menu's border.
``menu_outline_color``
Default: #FFFFFF
The color of the menu's border.
``corner_radius``
Default: 8
The radius of the menu's corners.
``margin_x``
Default: same as ``--osd-margin-x``
The margin from the left of the window.
``margin_y``
Default: same as ``--osd-margin-y``
The margin from the bottom of the window.
``scale_with_window``
Default: ``auto``
Whether to scale the console with the window height. Can be ``yes``, ``no``,
or ``auto``, which follows the value of ``--osd-scale-by-window``.
``focused_color``
Default: ``#222222``
The color of the focused item.
``focused_back_color``
Default: ``#FFFFFF``
The background color of the focused item.
``match_color``
Default: ``#0088FF``
The color of characters that match the searched string.
``exact_match``
Default: no
Whether to match menu search queries exactly instead of fuzzily. Without
this option, prefixing queries with ``'`` enables exact matching.
``case_sensitive``
Default: no
Whether exact searches are case sensitive. Only works with ASCII characters.
``history_dedup``
Default: true
Remove duplicate entries in history as to only keep the latest one.
``font_hw_ratio``
Default: auto
The ratio of font height to font width.
Adjusts grid width of completions.
Values in the range 1.8..2.5 make sense for common monospace fonts.
-98
View File
@@ -1,98 +0,0 @@
CONTEXT MENU SCRIPT
===================
This script provides a context menu for platforms without integration with a
native context menu. On these platforms, it can be disabled entirely using the
``--load-context-menu=no`` option. On platforms where the integration is
implemented, it is already disabled by default.
Script messages
---------------
``open``
Show the context menu.
``select``
Select the focused item when there is one.
Configuration
-------------
This script can be customized through a config file
``script-opts/context_menu.conf`` placed in mpv's user directory and through
the ``--script-opts`` command-line option. The configuration syntax is
described in `mp.options functions`_.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``font_size``
Default: 14
The font size.
``gap``
Default: 0.2
The gap between menu items, specified as a percentage the font size.
``padding_x``
Default: 8
The horizontal padding of the menu.
``padding_y``
Default: 4
The vertical padding of the menu.
``menu_outline_size``
Default: 0
The size of the menu's border.
``menu_outline_color``
Default: ``#FFFFFF``
The color of the menu's border.
``corner_radius``
Default: 5
The radius of the menu's corners.
``scale_with_window``
Default: auto
Whether to scale sizes with the window height. Can be ``yes``, ``no``, or
``auto``, which follows the value of ``--osd-scale-by-window``.
When sizes aren't scaled with the window, they are scaled by
``display-hidpi-scale``.
``focused_color``
Default: ``#222222``
The color of the focused item.
``focused_back_color``
Default: ``#FFFFFF``
The background color of the focused item.
``disabled_color``
Default: ``#555555``
The color of disabled items.
``seconds_to_open_submenus``
Default: 0.2
The number of seconds to open submenus after the cursor enters items
associated with one.
``seconds_to_close_submenus``
Default: 0.2
The number of seconds to close submenus after the cursor enters a parent
menu.
+100 -51
View File
@@ -8,25 +8,64 @@ You can encode files from one format/codec to another using this facility.
``--of=<format>``
Specifies the output format (overrides autodetection by the file name
extension of the file specified by ``--o``). See ``--of=help`` for a full
list of supported formats.
extension of the file specified by ``-o``). This can be a comma separated
list of possible formats to try. See ``--of=help`` for a full list of
supported formats.
``--ofopts=<options>``
Specifies the output format options for libavformat.
See ``--ofopts=help`` for a full list of supported options.
This is a key/value list option. See `List Options`_ for details.
Options are managed in lists. There are a few commands to manage the
options list.
``--ofopts-add=<option>``
Appends the option given as an argument to the options list. (Passing
multiple options is currently still possible, but deprecated.)
``--ofopts-add=<options1[,options2,...]>``
Appends the options given as arguments to the options list.
``--ofopts=""``
``--ofopts-pre=<options1[,options2,...]>``
Prepends the options given as arguments to the options list.
``--ofopts-del=<index1[,index2,...]>``
Deletes the options at the given indexes. Index numbers start at 0,
negative numbers address the end of the list (-1 is the last).
``--ofopts-clr``
Completely empties the options list.
``--ofps=<float value>``
Specifies the output format time base (default: 24000). Low values like 25
limit video fps by dropping frames.
``--oautofps``
Sets the output format time base to the guessed frame rate of the input
video (simulates MEncoder behavior, useful for AVI; may cause frame drops).
Note that not all codecs and not all formats support VFR encoding, and some
which do have bugs when a target bitrate is specified - use ``--ofps`` or
``--oautofps`` to force CFR encoding in these cases.
``--omaxfps=<float value>``
Specifies the minimum distance of adjacent frames (default: 0, which means
unset). Content of lower frame rate is not readjusted to this frame rate;
content of higher frame rate is decimated to this frame rate.
``--oharddup``
If set, the frame rate given by ``--ofps`` is attained not by skipping time
codes, but by duplicating frames (constant frame rate mode).
``--oneverdrop``
If set, frames are never dropped. Instead, time codes of video are
readjusted to always increase. This may cause AV desync, though; to work
around this, use a high-fps time base using ``--ofps`` and absolutely
avoid ``--oautofps``.
``--oac=<codec>``
Specifies the output audio codec. See ``--oac=help`` for a full list of
supported codecs.
Specifies the output audio codec. This can be a comma separated list of
possible codecs to try. See ``--oac=help`` for a full list of supported
codecs.
``--oaoffset=<value>``
Shifts audio data by the given time (in seconds) by adding/removing
samples at the start.
``--oacopts=<options>``
Specifies the output audio codec options for libavcodec.
@@ -37,70 +76,80 @@ You can encode files from one format/codec to another using this facility.
"``--oac=libmp3lame --oacopts=b=128000``"
selects 128 kbps MP3 encoding.
This is a key/value list option. See `List Options`_ for details.
Options are managed in lists. There are a few commands to manage the
options list.
``--oacopts-add=<option>``
Appends the option given as an argument to the options list. (Passing
multiple options is currently still possible, but deprecated.)
``--oacopts-add=<options1[,options2,...]>``
Appends the options given as arguments to the options list.
``--oacopts=""``
``--oacopts-pre=<options1[,options2,...]>``
Prepends the options given as arguments to the options list.
``--oacopts-del=<index1[,index2,...]>``
Deletes the options at the given indexes. Index numbers start at 0,
negative numbers address the end of the list (-1 is the last).
``--oacopts-clr``
Completely empties the options list.
``--ovc=<codec>``
Specifies the output video codec. See ``--ovc=help`` for a full list of
supported codecs.
``--oafirst``
Force the audio stream to become the first stream in the output. By default
the order is unspecified.
``--ovcopts=<options>``
``--ovc=<codec>``
Specifies the output video codec. This can be a comma separated list of
possible codecs to try. See ``--ovc=help`` for a full list of supported
codecs.
``--ovoffset=<value>``
Shifts video data by the given time (in seconds) by shifting the pts
values.
``--ovcopts <options>``
Specifies the output video codec options for libavcodec.
See --ovcopts=help for a full list of supported options.
.. admonition:: Examples
``"--ovc=mpeg4 --ovcopts=qscale=5"``
``"--ovc=mpeg4 --oacopts=qscale=5"``
selects constant quantizer scale 5 for MPEG-4 encoding.
``"--ovc=libx264 --ovcopts=crf=23"``
selects VBR quality factor 23 for H.264 encoding.
This is a key/value list option. See `List Options`_ for details.
Options are managed in lists. There are a few commands to manage the
options list.
``--ovcopts-add=<option>``
Appends the option given as an argument to the options list. (Passing
multiple options is currently still possible, but deprecated.)
``--ovcopts-add=<options1[,options2,...]>``
Appends the options given as arguments to the options list.
``--ovcopts=""``
``--ovcopts-pre=<options1[,options2,...]>``
Prepends the options given as arguments to the options list.
``--ovcopts-del=<index1[,index2,...]>``
Deletes the options at the given indexes. Index numbers start at 0,
negative numbers address the end of the list (-1 is the last).
``--ovcopts-clr``
Completely empties the options list.
``--ovfirst``
Force the video stream to become the first stream in the output. By default
the order is unspecified.
``--ocopyts``
Copies input pts to the output video (not supported by some output
container formats, e.g. AVI). Discontinuities are still fixed.
By default, audio pts are set to playback time and video pts are
synchronized to match audio pts, as some output formats do not support
anything else.
``--orawts``
Copies input pts to the output video (not supported by some output
container formats, e.g. AVI). In this mode, discontinuities are not fixed
and all pts are passed through as-is. Never seek backwards or use multiple
input files in this mode!
``--ocopy-metadata=<yes|no>``
Copy metadata from input files to output files when encoding (default: yes).
``--oset-metadata=<metadata-tag[,metadata-tag,...]>``
Specifies metadata to include in the output file.
Supported keys vary between output formats. For example, Matroska (MKV) and
FLAC allow almost arbitrary keys, while support in MP4 and MP3 is more
limited.
This is a key/value list option. See `List Options`_ for details.
.. admonition:: Example
"``--oset-metadata=title="Output title",comment="Another tag"``"
adds a title and a comment to the output file.
``--oremove-metadata=<metadata-tag[,metadata-tag,...]>``
Specifies metadata to exclude from the output file when copying from the
input file.
This is a string list option. See `List Options`_ for details.
.. admonition:: Example
"``--oremove-metadata=comment,genre``"
excludes copying of the the comment and genre tags to the output
file.
``--no-ometadata``
Turns off copying of metadata from input files to output files when
encoding (which is enabled by default).
+673 -3350
View File
File diff suppressed because it is too large. Load diff
+26 -232
View File
@@ -1,12 +1,11 @@
JSON IPC
========
mpv can be controlled by external programs using the JSON-based IPC protocol.
It can be enabled by specifying the path to a unix socket or a named pipe using
the option ``--input-ipc-server``, or the file descriptor number of a unix socket
or a named pipe using ``--input-ipc-client``.
Clients can connect to this socket and send commands to the player or receive
events from it.
mpv can be controlled by external programs using the JSON-based IPC protocol. It
can be enabled by specifying the path to a unix socket using the option
``--input-unix-socket``. Clients can connect to this socket and send commands to
the player or receive events from it. You can use the ``socat`` tool to send
commands (and receive reply) from the shell.
.. warning::
@@ -16,75 +15,9 @@ events from it.
which can run arbitrary system commands. The use-case is controlling the
player locally. This is not different from the MPlayer slave protocol.
Socat example
-------------
You can use the ``socat`` tool to send commands (and receive replies) from the
shell. Assuming mpv was started with:
::
mpv file.mkv --input-ipc-server=/tmp/mpvsocket
Then you can control it using socat:
::
> echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpvsocket
{"data":190.482000,"error":"success"}
In this case, socat copies data between stdin/stdout and the mpv socket
connection.
See the ``--idle`` option how to make mpv start without exiting immediately or
playing a file.
It's also possible to send input.conf style text-only commands:
::
> echo 'show-text ${playback-time}' | socat - /tmp/mpvsocket
But you won't get a reply over the socket. (This particular command shows the
playback time on the player's OSD.)
Command Prompt example
----------------------
Unfortunately, it's not as easy to test the IPC protocol on Windows, since
Windows ports of socat (in Cygwin and MSYS2) don't understand named pipes. In
the absence of a simple tool to send and receive from bidirectional pipes, the
``echo`` command can be used to send commands, but not receive replies from the
command prompt.
Assuming mpv was started with:
::
mpv file.mkv --input-ipc-server=\\.\pipe\mpvsocket
You can send commands from a command prompt:
::
echo show-text ${playback-time} >\\.\pipe\mpvsocket
To be able to simultaneously read and write from the IPC pipe, like on Linux,
it's necessary to write an external program that uses overlapped file I/O (or
some wrapper like .NET's NamedPipeClientStream.)
You can open the pipe in PuTTY as "serial" device. This is not very
comfortable, but gives a way to test interactively without having to write code.
Protocol
--------
The protocol uses UTF-8-only JSON as defined by RFC-8259. Unlike standard JSON,
"\u" escape sequences are not allowed to construct surrogate pairs. To avoid
getting conflicts, encode all text characters including and above codepoint
U+0020 as UTF-8. mpv might output broken UTF-8 in corner cases (see "UTF-8"
section below).
Clients can execute commands on the player by sending JSON messages of the
following form:
@@ -115,110 +48,18 @@ mpv will also send events to clients with JSON messages of the following form:
where ``event_name`` is the name of the event. Additional event-specific fields
can also be present. See `List of events`_ for a list of all supported events.
Because events can occur at any time, it may be difficult at times to determine
which response goes with which command. Commands may optionally include a
``request_id`` which, if provided in the command request, will be copied
verbatim into the response. mpv does not interpret the ``request_id`` in any
way; it is solely for the use of the requester. The only requirement is that
the ``request_id`` field must be an integer (a number without fractional parts
in the range ``-2^63..2^63-1``). Using other types is deprecated and will
currently show a warning. In the future, this will raise an error.
For example, this request:
::
{ "command": ["get_property", "time-pos"], "request_id": 100 }
Would generate this response:
::
{ "error": "success", "data": 1.468135, "request_id": 100 }
If you don't specify a ``request_id``, command replies will set it to 0.
All commands, replies, and events are separated from each other with a line
break character (``\n``).
If the first character (after skipping whitespace) is not ``{``, the command
will be interpreted as non-JSON text command, as they are used in input.conf
(or ``mpv_command_string()`` in the client API). Additionally, lines starting
(or ``mpv_command_string()`` in the client API). Additionally, line starting
with ``#`` and empty lines are ignored.
Currently, embedded 0 bytes terminate the current line, but you should not
rely on this.
Data flow
---------
Currently, the mpv-side IPC implementation does not service the socket while a
command is executed and the reply is written. It is for example not possible
that other events, that happened during the execution of the command, are
written to the socket before the reply is written.
This might change in the future. The only guarantee is that replies to IPC
messages are sent in sequence.
Also, since socket I/O is inherently asynchronous, it is possible that you read
unrelated event messages from the socket, before you read the reply to the
previous command you sent. In this case, these events were queued by the mpv
side before it read and started processing your command message.
If the mpv-side IPC implementation switches away from blocking writes and
blocking command execution, it may attempt to send events at any time.
You can also use asynchronous commands, which can return in any order, and
which do not block IPC protocol interaction at all while the command is
executed in the background.
Asynchronous commands
---------------------
Command can be run asynchronously. This behaves exactly as with normal command
execution, except that execution is not blocking. Other commands can be sent
while it's executing, and command completion can be arbitrarily reordered.
The ``async`` field controls this. If present, it must be a boolean. If missing,
``false`` is assumed.
For example, this initiates an asynchronous command:
::
{ "command": ["screenshot"], "request_id": 123, "async": true }
And this is the completion:
::
{"request_id":123,"error":"success","data":null}
By design, you will not get a confirmation that the command was started. If a
command is long running, sending the message will not lead to any reply until
much later when the command finishes.
Some commands execute synchronously, but these will behave like asynchronous
commands that finished execution immediately.
Cancellation of asynchronous commands is available in the libmpv API, but has
not yet been implemented in the IPC protocol.
Commands with named arguments
-----------------------------
If the ``command`` field is a JSON object, named arguments are expected. This
is described in the C API ``mpv_command_node()`` documentation (the
``MPV_FORMAT_NODE_MAP`` case). In some cases, this may make commands more
readable, while some obscure commands basically require using named arguments.
Currently, only "proper" commands (as listed by `List of Input Commands`_)
support named arguments.
Commands
--------
In addition to the commands described in `List of Input Commands`_, a few
Additionally to the commands described in `List of Input Commands`_, a few
extra commands can also be used as part of the protocol:
``client_name``
@@ -262,7 +103,14 @@ extra commands can also be used as part of the protocol:
{ "error": "success" }
``set_property_string``
Alias for ``set_property``. Both commands accept native values and strings.
Like ``set_property``, but the argument value must be passed as string.
Example:
::
{ "command": ["set_property_string", "pause", "yes"] }
{ "error": "success" }
``observe_property``
Watch a property for changes. If the given property is changed, then an
@@ -276,14 +124,6 @@ extra commands can also be used as part of the protocol:
{ "error": "success" }
{ "event": "property-change", "id": 1, "data": 52.0, "name": "volume" }
.. warning::
If the connection is closed, the IPC client is destroyed internally,
and the observed properties are unregistered. This happens for example
when sending commands to a socket with separate ``socat`` invocations.
This can make it seem like property observation does not work. You must
keep the IPC connection open to make it work.
``observe_property_string``
Like ``observe_property``, but the resulting data will always be a string.
@@ -297,7 +137,7 @@ extra commands can also be used as part of the protocol:
``unobserve_property``
Undo ``observe_property`` or ``observe_property_string``. This requires the
numeric id passed to the observed command as argument.
numeric id passed to the observe command as argument.
Example:
@@ -316,19 +156,19 @@ extra commands can also be used as part of the protocol:
lead to breakages with future mpv releases. Instead, make a feature request,
and ask for a proper event that returns the information you need.
``enable_event``, ``disable_event``
Enables or disables the named event. Mirrors the ``mpv_request_event`` C
API function. If the string ``all`` is used instead of an event name, all
events are enabled or disabled.
``suspend``
Suspend the mpv main loop. There is a long-winded explanation of this in
the C API function ``mpv_suspend()``. In short, this prevents the player
from displaying the next video frame, so that you don't get blocked when
trying to access the player.
By default, most events are enabled, and there is not much use for this
command.
``resume``
Undo one ``suspend`` call. ``suspend`` increments an internal counter, and
``resume`` decrements it. When 0 is reached, the player is actually resumed.
``get_version``
Returns the client API version the C API of the remote mpv instance
provides.
See also: ``DOCS/client-api-changes.rst``.
provides. (Also see ``DOCS/client-api-changes.rst``.)
UTF-8
-----
@@ -340,50 +180,4 @@ sometimes sends invalid JSON. If that is a problem for the client application's
parser, it should filter the raw data for invalid UTF-8 sequences and perform
the desired replacement, before feeding the data to its JSON parser.
mpv will not attempt to construct invalid UTF-8 with broken "\u" escape
sequences. This includes surrogate pairs.
JSON extensions
---------------
The following non-standard extensions are supported:
- a list or object item can have a trailing ","
- object syntax accepts "=" in addition of ":"
- object keys can be unquoted, if they start with a character in "A-Za-z\_"
and contain only characters in "A-Za-z0-9\_"
- byte escapes with "\xAB" are allowed (with AB being a 2 digit hex number)
Example:
::
{ objkey = "value\x0A" }
Is equivalent to:
::
{ "objkey": "value\n" }
Alternative ways of starting clients
------------------------------------
You can create an anonymous IPC connection without having to set
``--input-ipc-server``. This is achieved through a mpv pseudo scripting backend
that starts processes.
You can put ``.run`` file extension in the mpv scripts directory in its config
directory (see the `FILES`_ section for details), or load them through other
means (see `Script location`_). These scripts are simply executed with the OS
native mechanism (as if you ran them in the shell). They must have a proper
shebang and have the executable bit set.
When executed, a socket (the IPC connection) is passed to them through file
descriptor inheritance. The file descriptor is indicated as the special command
line argument ``--mpv-ipc-fd=N``, where ``N`` is the numeric file descriptor.
The rest is the same as with a normal ``--input-ipc-server`` IPC connection. mpv
does not attempt to observe or other interact with the started script process.
This does not work in Windows yet.
mpv will not attempt to construct invalid UTF-8 with broken escape sequences.
-409
View File
@@ -1,409 +0,0 @@
JAVASCRIPT
==========
JavaScript support in mpv is near identical to its Lua support. Use this section
as reference on differences and availability of APIs, but otherwise you should
refer to the Lua documentation for API details and general scripting in mpv.
Example
-------
JavaScript code which leaves fullscreen mode when the player is paused:
::
function on_pause_change(name, value) {
if (value == true)
mp.set_property("fullscreen", "no");
}
mp.observe_property("pause", "bool", on_pause_change);
Similarities with Lua
---------------------
mpv tries to load a script file as JavaScript if it has a ``.js`` extension, but
otherwise, the documented Lua options, script directories, loading, etc apply to
JavaScript files too.
Script initialization and lifecycle is the same as with Lua, and most of the Lua
functions in the modules ``mp``, ``mp.utils``, ``mp.msg``, ``mp.options`` and
``mp.input`` are available to JavaScript with identical APIs - including running
commands, getting/setting properties, registering events/key-bindings/hooks,
etc.
Differences from Lua
--------------------
No need to load modules. ``mp``, ``mp.utils``, ``mp.msg``, ``mp.options`` and
``mp.input`` are preloaded, and you can use e.g. ``var cwd =
mp.utils.getcwd();`` without prior setup.
Errors are slightly different. Where the Lua APIs return ``nil`` for error,
the JavaScript ones return ``undefined``. Where Lua returns ``something, error``
JavaScript returns only ``something`` - and makes ``error`` available via
``mp.last_error()``. Note that only some of the functions have this additional
``error`` value - typically the same ones which have it in Lua.
Standard APIs are preferred. For instance ``setTimeout`` and ``JSON.stringify``
are available, but ``mp.add_timeout`` and ``mp.utils.format_json`` are not.
No standard library. This means that interaction with anything outside of mpv is
limited to the available APIs, typically via ``mp.utils``. However, some file
functions were added, and CommonJS ``require`` is available too - where the
loaded modules have the same privileges as normal scripts.
Language features - ECMAScript 5
--------------------------------
The scripting backend which mpv currently uses is MuJS - a compatible minimal
ES5 interpreter. As such, ``String.substring`` is implemented for instance,
while the common but non-standard ``String.substr`` is not. Please consult the
MuJS pages on language features and platform support - https://mujs.com .
Unsupported Lua APIs and their JS alternatives
----------------------------------------------
``mp.add_timeout(seconds, fn)`` JS: ``id = setTimeout(fn, ms)``
``mp.add_periodic_timer(seconds, fn)`` JS: ``id = setInterval(fn, ms)``
``utils.parse_json(str [, trail])`` JS: ``JSON.parse(str)``
``utils.format_json(v)`` JS: ``JSON.stringify(v)``
``utils.to_string(v)`` see ``dump`` below.
``mp.get_next_timeout()`` see event loop below.
``mp.dispatch_events([allow_wait])`` see event loop below.
Scripting APIs - identical to Lua
---------------------------------
(LE) - Last-Error, indicates that ``mp.last_error()`` can be used after the
call to test for success (empty string) or failure (non empty reason string).
Where the Lua APIs use ``nil`` to indicate error, JS APIs use ``undefined``.
``mp.command(string)`` (LE)
``mp.commandv(arg1, arg2, ...)`` (LE)
``mp.command_native(table [,def])`` (LE)
``id = mp.command_native_async(table [,fn])`` (LE) Notes: ``id`` is true-thy on
success, ``error`` is empty string on success.
``mp.abort_async_command(id)``
``mp.del_property(name)`` (LE)
``mp.get_property(name [,def])`` (LE)
``mp.get_property_osd(name [,def])`` (LE)
``mp.get_property_bool(name [,def])`` (LE)
``mp.get_property_number(name [,def])`` (LE)
``mp.get_property_native(name [,def])`` (LE)
``mp.set_property(name, value)`` (LE)
``mp.set_property_bool(name, value)`` (LE)
``mp.set_property_number(name, value)`` (LE)
``mp.set_property_native(name, value)`` (LE)
``mp.get_time()``
``mp.add_key_binding(key, name|fn [,fn [,flags]])``
``mp.add_forced_key_binding(...)``
``mp.remove_key_binding(name)``
``mp.register_event(name, fn)``
``mp.unregister_event(fn)``
``mp.observe_property(name, type, fn)``
``mp.unobserve_property(fn)``
``mp.get_opt(key)``
``mp.get_script_name()``
``mp.get_script_directory()``
``mp.osd_message(text [,duration])``
``mp.get_wakeup_pipe()``
``mp.register_idle(fn)``
``mp.unregister_idle(fn)``
``mp.enable_messages(level)``
``mp.register_script_message(name, fn)``
``mp.unregister_script_message(name)``
``mp.create_osd_overlay(format)``
``mp.get_osd_size()`` (returned object has properties: width, height, aspect)
``mp.msg.log(level, ...)``
``mp.msg.fatal(...)``
``mp.msg.error(...)``
``mp.msg.warn(...)``
``mp.msg.info(...)``
``mp.msg.verbose(...)``
``mp.msg.debug(...)``
``mp.msg.trace(...)``
``mp.utils.getcwd()`` (LE)
``mp.utils.readdir(path [, filter])`` (LE)
``mp.utils.file_info(path)`` (LE) Note: like lua - this does NOT expand
meta-paths like ``~~/foo`` (other JS file functions do expand meta paths).
``mp.utils.split_path(path)``
``mp.utils.join_path(p1, p2)``
``mp.utils.subprocess(t)``
``mp.utils.subprocess_detached(t)``
``mp.utils.get_env_list()``
``mp.utils.getpid()`` (LE)
``mp.add_hook(type, priority, fn(hook))``
``mp.options.read_options(obj [, identifier [, on_update]])`` (types:
string/boolean/number)
``mp.input.get(obj)``
``mp.input.select(obj)``
``mp.input.terminate()``
``mp.input.log(message, style)``
``mp.input.log_error(message)``
``mp.input.set_log(log)``
``exit()`` (global)
Additional utilities
--------------------
``mp.last_error()``
If used after an API call which updates last error, returns an empty string
if the API call succeeded, or a non-empty error reason string otherwise.
``Error.stack`` (string)
When using ``try { ... } catch(e) { ... }``, then ``e.stack`` is the stack
trace of the error - if it was created using the ``Error(...)`` constructor.
``print`` (global)
A convenient alias to ``mp.msg.info``.
``dump`` (global)
Like ``print`` but also expands objects and arrays recursively.
``mp.utils.getenv(name)``
Returns the value of the host environment variable ``name``, or
``undefined`` if the variable is not defined.
``mp.utils.get_user_path(path)``
Trivial wrapper of the ``expand-path`` mpv command, returns a string.
``read_file``, ``write_file``, ``append_file`` and ``require`` already
expand the path internally and accept mpv meta-paths like ``~~desktop/foo``.
``mp.utils.read_file(fname [,max])``
Returns the content of file ``fname`` as string. If ``max`` is provided and
not negative, limit the read to ``max`` bytes.
``mp.utils.write_file(fname, str)``
(Over)write file ``fname`` with text content ``str``. ``fname`` must be
prefixed with ``file://`` as simple protection against accidental arguments
switch, e.g. ``mp.utils.write_file("file://~/abc.txt", "hello world")``.
``mp.utils.append_file(fname, str)``
Same as ``mp.utils.write_file`` if the file ``fname`` does not exist. If it
does exist then append instead of overwrite.
Note: ``read_file``, ``write_file`` and ``append_file`` throw on errors, allow
text content only.
``mp.get_time_ms()``
Same as ``mp.get_time()`` but in ms instead of seconds.
``mp.get_script_file()``
Returns the file name of the current script.
``mp.utils.compile_js(fname, content_str)``
Compiles the JS code ``content_str`` as file name ``fname`` (without loading
anything from the filesystem), and returns it as a function. Very similar
to a ``Function`` constructor, but shows at stack traces as ``fname``.
``mp.module_paths``
Global modules search paths array for the ``require`` function (see below).
Timers (global)
---------------
The standard HTML/node.js timers are available:
``id = setTimeout(fn [,duration [,arg1 [,arg2...]]])``
``id = setTimeout(code_string [,duration])``
``clearTimeout(id)``
``id = setInterval(fn [,duration [,arg1 [,arg2...]]])``
``id = setInterval(code_string [,duration])``
``clearInterval(id)``
``setTimeout`` and ``setInterval`` return id, and later call ``fn`` (or execute
``code_string``) after ``duration`` ms. Interval also repeat every ``duration``.
``duration`` has a minimum and default value of 0, ``code_string`` is
a plain string which is evaluated as JS code, and ``[,arg1 [,arg2..]]`` are used
as arguments (if provided) when calling back ``fn``.
The ``clear...(id)`` functions cancel timer ``id``, and are irreversible.
Note: timers always call back asynchronously, e.g. ``setTimeout(fn)`` will never
call ``fn`` before returning. ``fn`` will be called either at the end of this
event loop iteration or at a later event loop iteration. This is true also for
intervals - which also never call back twice at the same event loop iteration.
Additionally, timers are processed after the event queue is empty, so it's valid
to use ``setTimeout(fn)`` as a one-time idle observer.
CommonJS modules and ``require(id)``
------------------------------------
CommonJS Modules are a standard system where scripts can export common functions
for use by other scripts. Specifically, a module is a script which adds
properties (functions, etc) to its pre-existing ``exports`` object, which
another script can access with ``require(module-id)``. This runs the module and
returns its ``exports`` object. Further calls to ``require`` for the same module
will return its cached ``exports`` object without running the module again.
Modules and ``require`` are supported, standard compliant, and generally similar
to node.js. However, most node.js modules won't run due to missing modules such
as ``fs``, ``process``, etc, but some node.js modules with minimal dependencies
do work. In general, this is for mpv modules and not a node.js replacement.
A ``.js`` file extension is always added to ``id``, e.g. ``require("./foo")``
will load the file ``./foo.js`` and return its ``exports`` object.
An id which starts with ``./`` or ``../`` is relative to the script or module
which ``require`` it. Otherwise it's considered a top-level id (CommonJS term).
Top-level id is evaluated as absolute filesystem path if possible, e.g. ``/x/y``
or ``~/x``. Otherwise it's considered a global module id and searched according
to ``mp.module_paths`` in normal array order, e.g. ``require("x")`` tries to
load ``x.js`` at one of the array paths, and id ``foo/x`` tries to load ``x.js``
inside dir ``foo`` at one of the paths.
The ``mp.module_paths`` array is empty by default except for scripts which are
loaded as a directory where it contains one item - ``<directory>/modules/`` .
The array may be updated from a script (or using custom init - see below) which
will affect future calls to ``require`` for global module id's which are not
already loaded/cached.
No ``global`` variable, but a module's ``this`` at its top lexical scope is the
global object - also in strict mode. If you have a module which needs ``global``
as the global object, you could do ``this.global = this;`` before ``require``.
Functions and variables declared at a module don't pollute the global object.
Custom initialization
---------------------
After mpv initializes the JavaScript environment for a script but before it
loads the script - it tries to run the file ``init.js`` at the root of the mpv
configuration directory. Code at this file can update the environment further
for all scripts. E.g. if it contains ``mp.module_paths.push("/foo")`` then
``require`` at all scripts will search global module id's also at ``/foo``
(do NOT do ``mp.module_paths = ["/foo"];`` because this will remove existing
paths - like ``<script-dir>/modules`` for scripts which load from a directory).
The custom-init file is ignored if mpv is invoked with ``--no-config``.
Before mpv 0.34, the file name was ``.init.js`` (with dot) at the same dir.
The event loop
--------------
The event loop poll/dispatch mpv events as long as the queue is not empty, then
processes the timers, then waits for the next event, and repeats this forever.
You could put this code at your script to replace the built-in event loop, and
also print every event which mpv sends to your script:
::
function mp_event_loop() {
var wait = 0;
do {
var e = mp.wait_event(wait);
dump(e); // there could be a lot of prints...
if (e.event != "none") {
mp.dispatch_event(e);
wait = 0;
} else {
wait = mp.process_timers() / 1000;
if (wait != 0) {
mp.notify_idle_observers();
wait = mp.peek_timers_wait() / 1000;
}
}
} while (mp.keep_running);
}
``mp_event_loop`` is a name which mpv tries to call after the script loads.
The internal implementation is similar to this (without ``dump`` though..).
``e = mp.wait_event(wait)`` returns when the next mpv event arrives, or after
``wait`` seconds if positive and no mpv events arrived. ``wait`` value of 0
returns immediately (with ``e.event == "none"`` if the queue is empty).
``mp.dispatch_event(e)`` calls back the handlers registered for ``e.event``,
if there are such (event handlers, property observers, script messages, etc).
``mp.process_timers()`` calls back the already-added, non-canceled due timers,
and returns the duration in ms till the next due timer (possibly 0), or -1 if
there are no pending timers. Must not be called recursively.
``mp.notify_idle_observers()`` calls back the idle observers, which we do when
we're about to sleep (wait != 0), but the observers may add timers or take
non-negligible duration to complete, so we re-calculate ``wait`` afterwards.
``mp.peek_timers_wait()`` returns the same values as ``mp.process_timers()``
but without doing anything. Invalid result if called from a timer callback.
Note: ``exit()`` is also registered for the ``shutdown`` event, and its
implementation is a simple ``mp.keep_running = false``.
-80
View File
@@ -1,80 +0,0 @@
EMBEDDING INTO OTHER PROGRAMS (LIBMPV)
======================================
mpv can be embedded into other programs as video/audio playback backend. The
recommended way to do so is using libmpv. See ``include/mpv/client.h`` in the mpv
source code repository. This provides a C API. Bindings for other languages
might be available (see wiki).
Since libmpv merely allows access to underlying mechanisms that can control
mpv, further documentation is spread over a few places:
- https://github.com/mpv-player/mpv/blob/master/include/mpv/client.h
- https://mpv.io/manual/master/#options
- https://mpv.io/manual/master/#list-of-input-commands
- https://mpv.io/manual/master/#properties
- https://github.com/mpv-player/mpv-examples/tree/master/libmpv
C PLUGINS
=========
You can write C plugins for mpv. These use the libmpv API, although they do not
use the libmpv library itself.
They are enabled by default if compiler supports linking with the ``-rdynamic``
flag on Linux/BSD platforms. On Windows the are always enabled.
C plugins location
------------------
C plugins are put into the mpv scripts directory in its config directory
(see the `FILES`_ section for details). They must have a ``.so`` or ``.dll``
file extension. They can also be explicitly loaded with the ``--script`` option.
API
---
A C plugin must export the following function::
int mpv_open_cplugin(mpv_handle *handle)
The plugin function will be called on loading time. This function must not
return as long as your plugin is loaded (it runs in its own thread). The
``handle`` will be deallocated as soon as the plugin function returns.
The return value is interpreted as error status. A value of ``0`` is
interpreted as success, while ``-1`` signals an error. In the latter case,
the player prints an uninformative error message that loading failed.
Return values other than ``0`` and ``-1`` are reserved, and trigger undefined
behavior.
Within the plugin function, you can call libmpv API functions. The ``handle``
is created by ``mpv_create_client()`` (or actually an internal equivalent),
and belongs to you. You can call ``mpv_wait_event()`` to wait for things
happening, and so on. However do not call ``mpv_destroy()`` or
``mpv_terminate_destroy()`` on this handle.
Note that the player might block until your plugin calls ``mpv_wait_event()``
for the first time. This gives you a chance to install initial hooks etc.
before playback begins.
The details are quite similar to Lua scripts.
Linkage to libmpv
-----------------
The current implementation requires that your plugins are **not** linked against
libmpv. What your plugins use are not symbols from a libmpv binary, but
symbols from the mpv host binary.
On Windows to make symbols from the host binary available, you have to define
MPV_CPLUGIN_DYNAMIC_SYM when compiling cplugin. This will load symbols
dynamically, before calling ``mpv_open_cplugin()``.
Examples
--------
See:
- https://github.com/mpv-player/mpv-examples/tree/master/cplugins
+229 -566
View File
File diff suppressed because it is too large. Load diff
+207 -1256
View File
File diff suppressed because it is too large. Load diff
+1350 -6507
View File
File diff suppressed because it is too large. Load diff
+145 -540
View File
@@ -5,7 +5,7 @@ The On Screen Controller (short: OSC) is a minimal GUI integrated with mpv to
offer basic mouse-controllability. It is intended to make interaction easier
for new users and to enable precise and direct seeking.
The OSC is enabled by default if mpv was compiled with Lua support. It can be
The OSC is enabled by default if mpv was compiled with lua support. It can be
disabled entirely using the ``--osc=no`` option.
Using the OSC
@@ -20,94 +20,37 @@ The Interface
::
+------+---------+---------+-----------------------------------------------+
| menu | pl prev | pl next | title cache |
+------+------+------+---------+-----------+------+-------+-----+-----+----+
| play | skip | skip | time | seekbar | time | audio | sub | vol | fs |
| | back | frwd | elapsed | | left | | | | |
+------+------+------+---------+-----------+------+-------+-----+-----+----+
+------------------+-----------+--------------------+
| playlist prev | title | playlist next |
+-------+------+---+--+------+-+----+------+--------+
| audio | skip | seek | | seek | skip | full |
+-------+ back | back | play | frwd | frwd | screen |
| sub | | | | | | |
+-------+------+------+------+------+------+--------+
| seekbar |
+----------------+--------------+-------------------+
| time passed | cache status | time remaining |
+----------------+--------------+-------------------+
menu
============= ================================================
left-click open the menu
============= ================================================
pl prev
playlist prev
============= ================================================
left-click play previous file in playlist
shift+L-click show the playlist
middle-click show the playlist
right-click open the playlist menu
============= ================================================
pl next
============= ================================================
left-click play next file in playlist
shift+L-click show the playlist
middle-click show the playlist
right-click open the playlist menu
shift+L-click show playlist
============= ================================================
title
| Displays the current playlist position and media-title, filename or custom
title, or the target chapter name while hovering the seekbar.
| Displays current media-title or filename
============= ================================================
left-click show file and track info
shift+L-click show the path
middle-click show the path
right-click open the history menu
left-click show playlist position and length and full title
right-click show filename
============= ================================================
cache
| Shows current cache fill status
play
playlist next
============= ================================================
left-click toggle play/pause
shift+L-click toggle infinite looping of the playlist
middle-click toggle infinite looping of the playlist
right-click toggle infinite looping of the current file
============= ================================================
skip back
============= ================================================
left-click go to beginning of chapter / previous chapter
shift+L-click show chapters
middle-click show chapters
right-click open the chapter menu
============= ================================================
skip frwd
============= ================================================
left-click go to next chapter
shift+L-click show chapters
middle-click show chapters
right-click open the chapter menu
============= ================================================
time elapsed
| Shows current playback position timestamp
============= ================================================
left-click toggle displaying timecodes with milliseconds
============= ================================================
seekbar
| Indicates current playback position and position of chapters
============= ================================================
left-click seek to position
right-click seek to the nearest chapter
mouse wheel seek forward/backward
============= ================================================
time left
| Shows remaining playback time timestamp
============= ================================================
left-click toggle between total and remaining time
left-click play next file in playlist
shift+L-click show playlist
============= ================================================
audio and sub
@@ -115,47 +58,100 @@ audio and sub
============= ================================================
left-click cycle audio/sub tracks forward
shift+L-click cycle audio/sub tracks backwards
middle-click cycle audio/sub tracks backwards
right-click open the audio/sub track menu
mouse wheel cycle audio/sub tracks forward/backwards
right-click cycle audio/sub tracks backwards
shift+L-click show available audio/sub tracks
============= ================================================
vol
skip back
============= ================================================
left-click toggle mute
right-click open the audio device menu
mouse wheel volume up/down
left-click go to beginning of chapter / previous chapter
shift+L-click show chapters
============= ================================================
fs
seek back
============= ================================================
left-click skip back 5 seconds
right-click skip back 30 seconds
shift-L-click skip back 1 frame
============= ================================================
play
============= ================================================
left-click toggle play/pause
============= ================================================
seek frwd
============= ================================================
left-click skip forward 10 seconds
right-click skip forward 60 seconds
shift-L-click skip forward 1 frame
============= ================================================
skip frwd
============= ================================================
left-click go to next chapter
shift+L-click show chapters
============= ================================================
fullscreen
============= ================================================
left-click toggle fullscreen
right-click toggle whether the window is maximized
============= ================================================
Since mpv 0.40.0, it is possible to configure the commands to run with mouse
actions on some interface elements, and the default behaviors of several
elements were changed. If you miss some older behaviors, look at
``etc/restore-osc-bindings.conf`` in the mpv git repository.
seekbar
| Indicates current playback position and position of chapters
============= ================================================
left-click seek to position
============= ================================================
time passed
| Shows current playback position timestamp
============= ================================================
left-click toggle displaying timecodes with milliseconds
============= ================================================
cache status
| Shows current cache fill status (only visible when below 45%)
time remaining
| Shows remaining playback time timestamp
============= ================================================
left-click toggle between total and remaining time
============= ================================================
Key Bindings
~~~~~~~~~~~~
These key bindings are active by default if nothing else is already bound to
these keys. In case of collision, the function needs to be bound to a
different key. See the `Script Commands`_ section.
different key. See `Script Commands`_ section.
============= ================================================
del Cycles visibility between never / auto (mouse-move) / always
del Hide the OSC permanently until mpv is restarted.
============= ================================================
Configuration
-------------
This script can be customized through a config file ``script-opts/osc.conf``
placed in mpv's user directory and through the ``--script-opts`` command-line
option. The configuration syntax is described in `mp.options functions`_.
The OSC offers limited configuration through a config file
``lua-settings/osc.conf`` placed in mpv's user dir and through the
``--lua-opts`` command-line option. Options provided through the command-line
will override those from the config file.
Config Syntax
~~~~~~~~~~~~~
The config file must exactly follow the following syntax::
# this is a comment
optionA=value1
optionB=value2
``#`` can only be used at the beginning of a line and there may be no
spaces around the ``=`` or anywhere else.
Command-line Syntax
~~~~~~~~~~~~~~~~~~~
@@ -165,460 +161,77 @@ To avoid collisions with other scripts, all options need to be prefixed with
Example::
--script-opts=osc-optionA=value1,osc-optionB=value2
--lua-opts=osc-optionA=value1,osc-optionB=value2
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``layout``
Default: bottombar
The layout for the OSC. Currently available are: box, slimbox,
bottombar, topbar, slimbottombar and slimtopbar. Default pre-0.21.0 was
'box'.
``seekbarstyle``
Default: bar
Sets the style of the playback position marker and overall shape
of the seekbar: ``bar``, ``diamond`` or ``knob``.
``seekbarhandlesize``
Default: 0.6
Size ratio of the seek handle if ``seekbarstyle`` is set to ``diamond``
or ``knob``. This is relative to the full height of the seekbar.
``seekbarkeyframes``
Default: yes
Controls the mode used to seek when dragging the seekbar. If set to ``yes``,
default seeking mode is used (usually keyframes, but player defaults and
heuristics can change it to exact). If set to ``no``, exact seeking on
mouse drags will be used instead. Keyframes are preferred, but exact seeks
may be useful in cases where keyframes cannot be found. Note that using
exact seeks can potentially make mouse dragging much slower.
``seekrangestyle``
Default: inverted
Display seekable ranges on the seekbar. ``bar`` shows them on the full
height of the bar, ``line`` as a thick line and ``inverted`` as a thin
line that is inverted over playback position markers. ``none`` will hide
them. Additionally, ``slider`` will show a permanent handle inside the seekbar
with cached ranges marked inside. Note that these will look differently
based on the seekbarstyle option. Also, ``slider`` does not work with
``seekbarstyle`` set to ``bar``.
``seekrangeseparate``
Default: yes
Controls whether to show line-style seekable ranges on top of the
seekbar or separately if ``seekbarstyle`` is set to ``bar``.
``seekrangealpha``
Default: 20
Alpha of the seekable ranges, 0 (opaque) to 255 (fully transparent).
``scrollcontrols``
Default: yes
By default, going up or down with the mouse wheel can trigger certain
actions (such as seeking) if the mouse is hovering an OSC element.
Set to ``no`` to disable any special mouse wheel behavior.
``deadzonesize``
Default: 0.5
Size of the deadzone. The deadzone is an area that makes the mouse act
like leaving the window. Movement there won't make the OSC show up and
it will hide immediately if the mouse enters it. The deadzone starts
at the window border opposite to the OSC and the size controls how much
of the window it will span. Values between 0.0 and 1.0, where 0 means the
OSC will always popup with mouse movement in the window, and 1 means the
OSC will only show up when the mouse hovers it. Default pre-0.21.0 was 0.
``minmousemove``
Default: 0
Minimum amount of pixels the mouse has to move between ticks to make
the OSC show up. Default pre-0.21.0 was 3.
``showwindowed``
Default: yes
Enable the OSC when windowed
| Default: yes
| Show OSC when windowed?
``showfullscreen``
Default: yes
Enable the OSC when fullscreen
``idlescreen``
Default: yes
Show the mpv logo and message when idle
| Default: yes
| Show OSC when fullscreen?
``scalewindowed``
Default: 1.0
Scale factor of the OSC when windowed.
| Default: 1
| Scaling of the controller when windowed
``scalefullscreen``
Default: 1.0
| Default: 1
| Scaling of the controller when fullscreen
Scale factor of the OSC when fullscreen
``scaleforcedwindow``
| Default: 2
| Scaling of the controller when rendered on a forced (dummy) window
``vidscale``
Default: auto
Scale the OSC with the video.
``no`` tries to keep the OSC size constant as much as the window size allows.
``auto`` scales the OSC with the OSD, which is scaled with the window or kept at a
constant size, depending on the ``--osd-scale-by-window`` option.
| Default: yes
| Scale the controller with the video?
``valign``
Default: 0.8
Vertical alignment in box and slimbox layouts, -1 (top) to 1 (bottom).
| Default: 0.8
| Vertical alignment, -1 (top) to 1 (bottom)
``halign``
Default: 0.0
Horizontal alignment in box and slimbox layouts, -1 (left) to 1 (right).
``barmargin``
Default: 0
Margin from bottom (bottombar, slimbottombar) or top (topbar, slimtopbar),
in pixels.
| Default: 0
| Horizontal alignment, -1 (left) to 1 (right)
``boxalpha``
Default: 80
Alpha of the background box, 0 (opaque) to 255 (fully transparent)
| Default: 80
| Alpha of the background box, 0 (opaque) to 255 (fully transparent)
``hidetimeout``
Default: 500
Duration in ms until the OSC hides if no mouse movement, must not be
negative
| Default: 500
| Duration in ms until the OSC hides if no mouse movement, negative value
disables auto-hide
``fadeduration``
Default: 200
Duration of fade effects in ms, 0 = no fade.
``fadein``
Default: no
Enable fade-in.
``title``
Default: ${!playlist-count==1:[${playlist-pos-1}/${playlist-count}] }${media-title}
String that supports property expansion that will be displayed as
OSC title.
ASS tags are escaped and newlines are converted to spaces.
``tooltipborder``
Default: 1
Size of the tooltip outline when using bottombar or topbar layouts
``timetotal``
Default: no
Show total time instead of time remaining
``remaining_playtime``
Default: yes
Whether the time-remaining display takes speed into account.
``yes`` - how much playback time remains at the current speed.
``no`` - how much video-time remains.
``timems``
Default: no
Display timecodes with milliseconds
``tcspace``
Default: 100 (allowed: 50-200)
Adjust space reserved for timecodes (current time and time remaining) in
the ``bottombar`` and ``topbar`` layouts. The timecode width depends on the
font, and with some fonts the spacing near the timecodes becomes too small.
Use values above 100 to increase that spacing, or below 100 to decrease it.
``visibility``
Default: auto (auto hide/show on mouse move)
Also supports ``never`` and ``always``
``visibility_modes``
Default: never_auto_always
The list of visibility modes to cycle through when calling the
osc-visibility cycle script message. Modes are separated by ``_``.
``boxmaxchars``
Default: 80
Max chars for the osc title at the box layout. mpv does not measure the
text width on screen and so it needs to limit it by number of chars. The
default is conservative to allow wide fonts to be used without overflow.
However, with many common fonts a bigger number can be used. YMMV.
``boxvideo``
Default: no
Whether to overlay the osc over the video (``no``), or to box the video
within the areas not covered by the osc (``yes``). If this option is set,
the osc may overwrite the ``--video-margin-ratio-*`` options, even if the
user has set them. (It will not overwrite them if all of them are set to
default values.) Additionally, ``visibility`` must be set to ``always``.
Otherwise, this option does nothing.
Currently, this is supported for the ``bottombar``, ``slimbottombar``,
``topbar`` and ``slimtopbar`` layouts only. The other layouts do not change
if this option is set. Separately, if window controls are present (see
below), they will be affected regardless of which osc layout is in use.
The border is static and appears even if the OSC is configured to appear
only on mouse interaction. If the OSC is invisible, the border is simply
filled with the background color (black by default).
This currently still makes the OSC overlap with subtitles (if the
``--sub-use-margins`` option is set to ``yes``, the default). This may be
fixed later.
This does not work correctly with video outputs like ``--vo=xv``, which
render OSD into the unscaled video.
``windowcontrols``
Default: auto (Show window controls if there is no window border)
Whether to show window management controls over the video, and if so,
which side of the window to place them. This may be desirable when the
window has no decorations, either because they have been explicitly
disabled (``border=no``) or because the current platform doesn't support
them (eg: gnome-shell with wayland).
The set of window controls is fixed, offering ``minimize``, ``maximize``,
and ``quit``. Not all platforms implement ``minimize`` and ``maximize``,
but ``quit`` will always work.
``windowcontrols_alignment``
Default: right
If window controls are shown, indicates which side should they be aligned
to.
Supports ``left`` and ``right`` which will place the controls on those
respective sides.
``windowcontrols_title``
Default: ${media-title}
String that supports property expansion that will be displayed as the
windowcontrols title.
ASS tags are escaped, and newlines and trailing slashes are stripped.
``greenandgrumpy``
Default: no
Set to ``yes`` to reduce festivity (i.e. disable santa hat in December.)
``livemarkers``
Default: yes
Update chapter markers positions on duration changes, e.g. live streams.
The updates are unoptimized - consider disabling it on very low-end systems.
``chapter_fmt``
Default: ``Chapter: %s``
Template for the chapter-name display when hovering the seekbar.
Use ``no`` to disable chapter display on hover. Otherwise it's a lua
``string.format`` template and ``%s`` is replaced with the actual name.
``unicodeminus``
Default: no
Use a Unicode minus sign instead of an ASCII hyphen when displaying
the remaining playback time.
``background_color``
Default: #000000
Sets the background color of the OSC.
``timecode_color``
Default: #FFFFFF
Sets the color of the timecode and seekbar, of the OSC.
``title_color``
Default: #FFFFFF
Sets the color of the video title. Formatted as #RRGGBB.
``time_pos_color``
Default: #FFFFFF
Sets the color of the timecode at hover position in the seekbar.
``time_pos_outline_color``
Default: #FFFFFF
Sets the color of the timecode's outline at hover position in the seekbar.
Also affects the timecode in the slimbox layout.
``buttons_color``
Default: #FFFFFF
Sets the colors of the big buttons.
``top_buttons_color``
Default: #FFFFFF
Sets the colors of the top buttons.
``small_buttonsL_color``
Default: #FFFFFF
Sets the colors of the small buttons on the left in the box layout.
``small_buttonsR_color``
Default: #FFFFFF
Sets the colors of the small buttons on the right in the box layout.
``held_element_color``
Default: #999999
Sets the colors of the elements that are being pressed or held down.
``tick_delay``
Default: 1/60
Sets the minimum interval between OSC redraws in seconds. This can be
decreased on fast systems to make OSC rendering smoother.
Ignored if ``tick_delay_follow_display_fps`` is set to yes and the VO
supports the ``display-fps`` property.
``tick_delay_follow_display_fps``
Default: no
Use display fps to calculate the interval between OSC redraws.
The following options configure what commands are run when the buttons are
clicked. ``mbtn_mid`` commands are also triggered with ``shift+mbtn_left``.
``menu_mbtn_left_command=script-binding select/menu; script-message-to osc osc-hide``
``menu_mbtn_mid_command=``
``menu_mbtn_right_command=``
``playlist_prev_mbtn_left_command=playlist-prev; show-text ${playlist} 3000``
``playlist_prev_mbtn_mid_command=show-text ${playlist} 3000``
``playlist_prev_mbtn_right_command=script-binding select/select-playlist; script-message-to osc osc-hide``
``playlist_next_mbtn_left_command=playlist-next; show-text ${playlist} 3000``
``playlist_next_mbtn_mid_command=show-text ${playlist} 3000``
``playlist_next_mbtn_right_command=script-binding select/select-playlist; script-message-to osc osc-hide``
``title_mbtn_left_command=script-binding stats/display-page-5``
``title_mbtn_mid_command=show-text ${path}``
``title_mbtn_right_command=script-binding select/select-watch-history; script-message-to osc osc-hide``
``play_pause_mbtn_left_command=cycle pause``
``play_pause_mbtn_mid_command=cycle-values loop-playlist inf no``
``play_pause_mbtn_right_command=cycle-values loop-file inf no``
``chapter_prev_mbtn_left_command=osd-msg add chapter -1``
``chapter_prev_mbtn_mid_command=show-text ${chapter-list} 3000``
``chapter_prev_mbtn_right_command=script-binding select/select-chapter; script-message-to osc osc-hide``
``chapter_next_mbtn_left_command=osd-msg add chapter 1``
``chapter_next_mbtn_mid_command=show-text ${chapter-list} 3000``
``chapter_next_mbtn_right_command=script-binding select/select-chapter; script-message-to osc osc-hide``
``audio_track_mbtn_left_command=cycle audio``
``audio_track_mbtn_mid_command=cycle audio down``
``audio_track_mbtn_right_command=script-binding select/select-aid; script-message-to osc osc-hide``
``audio_track_wheel_down_command=cycle audio``
``audio_track_wheel_up_command=cycle audio down``
``sub_track_mbtn_left_command=cycle sub``
``sub_track_mbtn_mid_command=cycle sub down``
``sub_track_mbtn_right_command=script-binding select/select-sid; script-message-to osc osc-hide``
``sub_track_wheel_down_command=cycle sub``
``sub_track_wheel_up_command=cycle sub down``
``volume_mbtn_left_command=no-osd cycle mute``
``volume_mbtn_mid_command=``
``volume_mbtn_right_command=script-binding select/select-audio-device; script-message-to osc osc-hide``
``volume_wheel_down_command=add volume -5``
``volume_wheel_up_command=add volume 5``
``fullscreen_mbtn_left_command="cycle fullscreen"``
``fullscreen_mbtn_mid_command=``
``fullscreen_mbtn_right_command="cycle window-maximized"``
Custom Buttons
~~~~~~~~~~~~~~
Additional script-opts are available to define custom buttons in ``bottombar``
and ``topbar`` layouts.
.. admonition:: Example to add loop, shuffle and speed buttons
::
custom_button_1_content=🔁
custom_button_1_mbtn_left_command=cycle-values loop-file inf no
custom_button_1_mbtn_right_command=cycle-values loop-playlist inf no
custom_button_2_content=🔀
custom_button_2_mbtn_left_command=playlist-shuffle
custom_button_3_content=⏱
custom_button_3_mbtn_left_command=add speed 1
custom_button_3_mbtn_right_command=set speed 1
custom_button_3_wheel_up_command=add speed 0.25
custom_button_3_wheel_down_command=add speed -0.25
| Default: 200
| Duration of fade out in ms, 0 = no fade
``deadzonesize``
| Default: 0
| Size of the deadzone. The deadzone is an area that makes the mouse act
like leaving the window. Movement there won't make the OSC show up and
it will hide immediately if the mouse enters it. The deadzone starts
at the window border opposite to the OSC and the size controls how much
of the window it will span. Values between 0 and 1.
``minmousemove``
| Default: 3
| Minimum amount of pixels the mouse has to move between ticks to make
the OSC show up
``seektooltip``
| Default: yes
| Display a tooltip over the seekbar indicating time at mouse position.
``seekbarstyle``
| Default: slider
| Sets the style of the seekbar, slider (diamond marker) or bar (fill)
Script Commands
~~~~~~~~~~~~~~~
@@ -626,26 +239,18 @@ Script Commands
The OSC script listens to certain script commands. These commands can bound
in ``input.conf``, or sent by other scripts.
``osc-visibility``
Controls visibility mode ``never`` / ``auto`` (on mouse move) / ``always``
and also ``cycle`` to cycle between the modes. If a second argument is
passed (any value), then the output on the OSD will be silenced.
``enable-osc``
Undoes ``disable-osc`` or the effect of the ``del`` key.
``osc-show``
Triggers the OSC to show up, just as if user moved mouse.
``disable-osc``
Hide the OSC permanently. This is also what the ``del`` key does.
``osc-hide``
Hide the OSC when ``visibility`` is ``auto``.
Example
You could put this into ``input.conf`` to hide the OSC with the ``a`` key and
to set auto mode (the default) with ``b``::
to unhide it with ``b``::
a script-message osc-visibility never
b script-message osc-visibility auto
a script_message disable-osc
b script_message enable-osc
``osc-idlescreen``
Controls the visibility of the mpv logo on idle. Valid arguments are ``yes``,
``no``, and ``cycle`` to toggle between yes and no. If a second argument is
passed (any value), then the output on the OSD will be silenced.
-60
View File
@@ -1,60 +0,0 @@
POSITIONING
===========
This script provides script bindings to pan videos and images. It can be
disabled using the ``--load-positioning=no`` option.
Script bindings
---------------
``pan-x <amount>``
Adjust ``--video-align-x`` relatively to the OSD width, rather than
relatively to the video width like the option. This is useful to pan large
images consistently.
``amount`` is a number such that an amount of 1 scrolls as much as the OSD
width.
``pan-y <amount>``
Adjust ``--video-align-y`` relatively to the OSD height, rather than
relatively to the video height like the option.
``amount`` is a number such that an amount of 1 scrolls as much as the OSD
height.
``drag-to-pan``
Pan the video while holding a mouse button, keeping the clicked part of the
video under the cursor.
``align-to-cursor``
Pan through the whole video while holding a mouse button, or after clicking
once if ``toggle_align_to_cursor`` is ``yes``.
``cursor-centric-zoom <amount>``
Increase ``--video-zoom`` by ``amount`` while keeping the part of the video
hovered by the cursor under it, or the average position of touch points if
known.
Configuration
-------------
This script can be customized through a config file
``script-opts/positioning.conf`` placed in mpv's user directory and through the
``--script-opts`` command-line option. The configuration syntax is described in
`mp.options functions`_.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``toggle_align_to_cursor``
Default: no
Whether ``align-to-cursor`` requires holding down a mouse button to pan. If
``no``, dragging pans. If ``yes``, clicking the first time makes pan follow
the cursor, and clicking a second time disables this.
``suppress_osd``
Default: no
Whether to not print the new value of ``--video-zoom`` when using
``cursor-centric-zoom``.
-163
View File
@@ -1,163 +0,0 @@
SELECT
======
console can present a list of items to browse and select from with the
``mp.input.select`` API. ``select.lua`` is a builtin client of this API
providing script bindings that gather and format the data to be selected in the
console and do operations on the selected item. It can be disabled using the
``--load-select=no`` option.
Key bindings
------------
When using ``mp.input.select``, the key bindings listed in `CONSOLE`_ are
extended with the following:
ENTER, Ctrl+j and Ctrl+m
Select the focused item.
UP and Ctrl+p
Focus the item above, or the last one when the first item is selected.
DOWN and Ctrl+n
Focus the item below, or the first one when the last item is selected.
PGUP and Ctrl+b
Scroll up one page.
PGDN and Ctrl+f
Scroll down one page.
Ctrl+y
Copy the focused item to the clipboard.
MBTN_LEFT
Select the item under the cursor, or close the console if clicking outside
of the menu rectangle.
WHEEL_UP
Scroll up.
WHEEL_DOWN
Scroll down.
Typing printable characters does a fuzzy search of the presented items.
If the query starts with ``'``, only exact matches are filtered. You can also
specify multiple search terms delimited by spaces, and only items matching all
terms are filtered.
Script bindings
---------------
By default select.lua's script bindings are bound to key sequences starting with
``g`` listed in `Keyboard Control`_. The names of the script bindings listed
below can be used to bind them to different keys.
.. admonition:: Example to rebind playlist selection in input.conf
Ctrl+p script-binding select/select-playlist
Available script bindings are:
``select-playlist``
Select a playlist entry. ``--osd-playlist-entry`` determines how playlist
entries are formatted.
``select-sid``
Select a subtitle track, or disable the current one.
``select-secondary-sid``
Select a secondary subtitle track, or disable the current one.
``select-aid``
Select an audio track, or disable the current one.
``select-vid``
Select a video track, or disable the current one.
``select-track``
Select a track of any type, or disable a selected track.
``select-chapter``
Select a chapter.
``select-edition``
Select an MKV edition or DVD/Blu-ray title.
``select-subtitle-line``
Select a subtitle line to seek to. This doesn't work with image subtitles.
This currently requires ``ffmpeg`` in ``PATH``, or in the same folder as mpv
on Windows.
``select-audio-device``
Select an audio device.
``select-watch-history``
Select a file from the watch history. Requires ``--save-watch-history``.
If you don't already use ``--autocreate-playlist``, it is recommended to
enable it with this script binding to populate the playlist with the other
files in the entry's directory.
.. admonition:: Example for input.conf to play files adjacent to the history entry
g-h script-binding select/select-watch-history; no-osd set autocreate-playlist filter
``select-watch-later``
Select a file from watch later config files (see `RESUMING PLAYBACK`_) to
resume playing. Requires ``--write-filename-in-watch-later-config``. This
doesn't work with ``--ignore-path-in-watch-later-config``.
If you don't already use ``--autocreate-playlist``, it is recommended to
enable it with this script binding to populate the playlist with the other
files in the entry's directory.
.. admonition:: Example for input.conf to play files adjacent to the watch later entry
g-w script-binding select/select-watch-later; no-osd set autocreate-playlist filter
``select-binding``
List the defined input bindings. You can also select one to run the
associated command.
``show-properties``
List the names and values of all properties. You can also select one to
print its value on the OSD, which is useful for long values that get
clipped.
``edit-config-file``
Open ``mpv.conf`` in the system text editor, creating it if it doesn't
already exist.
``edit-input-conf``
Open ``input.conf`` in the system text editor, creating it if it doesn't
already exist.
``open-docs``
Open mpv's online documentation in the browser.
``menu``
Show a menu with miscellaneous entries.
Configuration
-------------
This script can be customized through a config file ``script-opts/select.conf``
placed in mpv's user directory and through the ``--script-opts`` command-line
option. The configuration syntax is described in `mp.options functions`_.
Configurable options
~~~~~~~~~~~~~~~~~~~~
``history_date_format``
Default: %Y-%m-%d %H:%M:%S
The format of dates of history entries. This is passed to Lua's ``os.date``,
which uses the same formats as ``strftime(3)``.
``hide_history_duplicates``
Default: yes
Whether to show only the last of history entries with the same path.
-304
View File
@@ -1,304 +0,0 @@
STATS
=====
This builtin script displays information and statistics for the currently
played file. It is enabled by default if mpv was compiled with Lua support.
It can be disabled entirely using the ``--load-stats-overlay=no`` option.
Usage
-----
The following key bindings are active by default unless something else is
already bound to them:
==== ==============================================
i Show stats for a fixed duration
I Toggle stats (shown until toggled again)
? Toggle displaying the key bindings
==== ==============================================
While the stats are visible on screen the following key bindings are active,
regardless of existing bindings. They allow you to switch between *pages* of
stats:
==== ==================
1 Show usual stats
2 Show frame timings (scroll)
3 Input cache stats
4 Active key bindings (scroll)
5 Selected Tracks Info (scroll)
0 Internal stuff (scroll)
==== ==================
If stats were displayed by toggling, these key bindings are also active:
==== ==================
ESC Close the stats
==== ==================
On pages which support scroll, these key bindings are also active:
==== ==================
UP Scroll one line up
DOWN Scroll one line down
==== ==================
On page 4, these key bindings are also active:
==== ==================
/ Search key bindings
==== ==================
Configuration
-------------
This script can be customized through a config file ``script-opts/stats.conf``
placed in mpv's user directory and through the ``--script-opts`` command-line
option. The configuration syntax is described in `mp.options functions`_.
Configurable Options
~~~~~~~~~~~~~~~~~~~~
``key_page_1``
Default: 1
``key_page_2``
Default: 2
``key_page_3``
Default: 3
``key_page_4``
Default: 4
``key_page_5``
Default: 5
``key_page_0``
Default: 0
``key_exit``
Default: ESC
Key bindings for page switching while stats are displayed.
``key_scroll_up``
Default: UP
``key_scroll_down``
Default: DOWN
``key_scroll_search``
Default: /
``scroll_lines``
Default: 1
Scroll key bindings and number of lines to scroll on pages which support it.
``duration``
Default: 4
How long the stats are shown in seconds (oneshot).
``redraw_delay``
Default: 1
How long it takes to refresh the displayed stats in seconds (toggling).
``persistent_overlay``
Default: no
When `no`, other scripts printing text to the screen can overwrite the
displayed stats. When `yes`, displayed stats are persistently shown for the
respective duration. This can result in overlapping text when multiple
scripts decide to print text at the same time.
``file_tag_max_length``
Default: 128
Only show file tags shorter than this length, in bytes.
``file_tag_max_count``
Default: 16
Only show the first specified amount of file tags.
``term_clip``
Default: yes
Whether to clip lines to the terminal width.
``plot_perfdata``
Default: no
Show graphs for performance data (page 2).
``plot_vsync_ratio``
Default: no
``plot_vsync_jitter``
Default: no
Show graphs for vsync and jitter values (page 1). Only when toggled.
``plot_cache``
Default: yes
Show graphs for cache values (page 3). Only when toggled.
``plot_tonemapping_lut``
Default: no
Enable tone-mapping LUT visualization automatically. Only when toggled.
``flush_graph_data``
Default: yes
Clear data buffers used for drawing graphs when toggling.
``font``
Default: same as ``osd-font``
Font name. Should support as many font weights as possible for optimal
visual experience.
``font_mono``
Default: monospace
Font name for parts where monospaced characters are necessary to align
text. Currently, monospaced digits are sufficient.
``font_size``
Default: 20
Font size used to render text.
``font_color``
Default: same as ``osd-color``
Color of the text.
``border_size``
Default: 1.65
Size of border drawn around the font.
``border_color``
Default: same as ``osd-border-color``
Color of the text border.
``shadow_x_offset``
Default: same as ``--osd-shadow-offset``
The horizontal distance from the text to position the shadow at.
``shadow_y_offset``
Default: same as ``--osd-shadow-offset``
The vertical distance from the text to position the shadow at.
``shadow_color``
Default: same as ``osd-shadow-color``
Color of the text shadow.
``alpha``
Default: 11
Transparency of text when ``font_color`` is specified, of text borders when
``border_color`` is specified, and of text shadows when ``shadow_color`` is
specified.
``plot_bg_border_color``
Default: 0000FF
Border color used for drawing graphs.
``plot_bg_border_width``
Default: 1.25
Border width used for drawing graphs.
``plot_bg_color``
Default: 262626
Background color used for drawing graphs.
``plot_color``
Default: FFFFFF
Color used for drawing graphs.
``vidscale``
Default: auto
Scale the text and graphs with the video.
``no`` tries to keep the sizes constant.
``auto`` scales the text and graphs with the OSD, which is scaled with the
window or kept at a constant size, depending on the ``--osd-scale-by-window`` option.
Note: colors are given as hexadecimal values and use ASS tag order: BBGGRR
(blue green red).
Different key bindings
~~~~~~~~~~~~~~~~~~~~~~
Additional keys can be configured in ``input.conf`` to display the stats::
e script-binding stats/display-stats
E script-binding stats/display-stats-toggle
And to display a certain page directly::
i script-binding stats/display-page-1
h script-binding stats/display-page-4-toggle
Active key bindings page
~~~~~~~~~~~~~~~~~~~~~~~~
Lists the active key bindings and the commands they're bound to, excluding the
interactive keys of the stats script itself. See also ``--input-test`` for more
detailed view of each binding.
The keys are grouped automatically using a simple analysis of the command
string, and one should not expect documentation-level grouping accuracy,
however, it should still be reasonably useful.
Using ``--idle --script-opt=stats-bindlist=yes`` will print the list to
the terminal and quit immediately. Long lines are clipped to the terminal width
unless this is disabled with ``--script-opt=stats-term_clip=no``. Escape
sequences can be disabled by adding ``-`` before ``yes``, i.e.
``--script-opt=stats-bindlist=-yes``.
Like with ``--input-test``, the list includes bindings from ``input.conf`` and
from user scripts. Use ``--no-config`` to list only built-in bindings.
Internal stuff page
~~~~~~~~~~~~~~~~~~~
Most entries shown on this page have rather vague meaning. Likely none of this
is useful for you. Don't attempt to use it. Forget its existence.
Selecting this for the first time will start collecting some internal
performance data. That means performance will be slightly lower than normal for
the rest of the time the player is running (even if the stats page is closed).
Note that the stats page itself uses a lot of CPU and even GPU resources, and
may have a heavy impact on performance.
The displayed information is accumulated over the redraw delay (shown as
``poll-time`` field).
This adds entries for each Lua script. If there are too many scripts running,
parts of the list will simply be out of the screen, but it can be scrolled.
If the underlying platform does not support pthread per thread times, the
displayed times will be 0 or something random (I suspect that at time of this
writing, only Linux provides the correct via pthread APIs for per thread times).
Most entries are added lazily and only during data collection, which is why
entries may pop up randomly after some time. It's also why the memory usage
entries for scripts that have been inactive since the start of data collection
are missing.
Memory usage is approximate and does not reflect internal fragmentation.
JS scripts memory reporting is disabled by default because collecting the data
at the JS side has an overhead and will increase memory usage. It can be
enabled by setting the ``--js-memory-report`` option before starting mpv.
If entries have ``/time`` and ``/cpu`` variants, the former gives the real time
(monotonic clock), while the latter the thread CPU time (only if the
corresponding pthread API works and is supported).
+766 -625
View File
File diff suppressed because it is too large. Load diff
+682 -501
View File
File diff suppressed because it is too large. Load diff
-455
View File
@@ -1,455 +0,0 @@
CHANGES FROM OTHER VERSIONS OF MPLAYER
======================================
**mpv** is based on mplayer2, which in turn is based on the original MPlayer
(also called mplayer, mplayer-svn, mplayer1). Many changes have been made, a
large part of which is incompatible or completely changes how the player
behaves. Although there are still many similarities to its ancestors, **mpv**
should generally be treated as a completely different program.
.. admonition:: Warning
This document is **not updated** anymore, and is **incomplete** and
**outdated**. If you look for old option replacements, always check with
the current mpv manpage, as the options could have changed meanwhile.
General Changes from MPlayer to mpv
-----------------------------------
This listing is about changes introduced by mplayer2 and mpv relatively to
MPlayer.
Player
~~~~~~
* New name for the binary (``mpv``). New location for config files (either
``~/.config/mpv/mpv.conf``, or if you want, ``~/.mpv/config``).
* Encoding functionality (replacement for MEncoder, see the `ENCODING`_ section).
* Support for Lua scripting (see the `LUA SCRIPTING`_ section).
* Better pause handling (e.g. do not unpause on a command).
* Precise seeking support.
* Improvements in audio/video sync handling.
* Do not lose settings when playing a new file in the same player instance.
* Slave mode compatibility broken (see below).
* Re-enable screensaver while the player is paused.
* Allow resuming playback at a later point with ``Shift+q``, also see the
``quit-watch-later`` input command.
* ``--keep-open`` option to stop the player from closing the window and
exiting after playback ends.
* A client API, that allows embedding **mpv** into applications
(see ``mpv/client.h`` in the sources).
Input
~~~~~
* Improved default keybindings. MPlayer bindings are also available (see
``etc/mplayer-input.conf`` in the source tree).
* Improved responsiveness on user input.
* Support for modifier keys (alt, shift, ctrl) in input.conf.
* Allow customizing whether a key binding for seeking shows the video time, the
OSD bar, or nothing (see the `Input Command Prefixes`_ section).
* Support mapping multiple commands to one key.
* Classic LIRC support was removed. Install remotes as input devices instead.
This way they will send X11 key events to the mpv window, which can be bound
using the normal ``input.conf``.
Also see: https://github.com/mpv-player/mpv/wiki/IR-remotes
* Joystick support was removed. It was considered useless and was the cause
of some problems (e.g. a laptop's accelerator being recognized as joystick).
* Support for relative seeking by percentage.
Audio
~~~~~
* Support for gapless audio (see the ``--gapless-audio`` option).
* Support for OSS4 volume control.
* Improved support for PulseAudio.
* Make ``--softvol`` default (**mpv** is not a mixer control panel).
* By default, do pitch correction if playback speed is increased.
* Improved downmixing and output of surround audio:
- Instead of using hardcoded pan filters to do remixing, libavresample is used
- Channel maps are used to identify the channel layout, so e.g. ``3.0`` and
``2.1`` audio can be distinguished.
Video
~~~~~
* Wayland support.
* Native support for VAAPI and VDA. Improved VDPAU video output.
* Improved GPU-accelerated video output (see the ``gpu-hq`` preset).
* Make hardware decoding work with the ``gpu`` video output.
* Support for libavfilter (for video->video and audio->audio). This allows
using most of FFmpeg's filters, which improve greatly on the old MPlayer
filters in features, performance, and correctness.
* More correct color reproduction (color matrix generation), including support
for BT.2020 (Ultra HD). linear XYZ (Digital Cinema) and SMPTE ST2084 (HDR)
inputs.
* Support for color managed displays, via ICC profiles.
* High-quality image resamplers (see the ``--scale`` suboption).
* Support for scaling in (sigmoidized) linear light.
* Better subtitle rendering using libass by default.
* Improvements when playing multiple files (``-fixed-vo`` is default, do not
reset settings by default when playing a new file).
* Replace image video outputs (``--vo=jpeg`` etc.) with ``--vo=image``.
* Removal of ``--vo=gif89a``, ``--vo=md5sum``, ``--vo=yuv4mpeg``, as encoding
can handle these use cases. For yuv4mpeg, for example, use::
mpv input.mkv -o output.y4m --no-audio --oautofps --oneverdrop
* Image subtitles (DVDs etc.) are rendered in color and use more correct
positioning (color for image subs can be disabled with ``--sub-gray``).
* Support for the X11 video output is removed, since it was considered
deprecated. SDL video output can still be used as a fallback.
OSD and terminal
~~~~~~~~~~~~~~~~
* Cleaned up terminal output: nicer status line, less useless noise.
* Improved OSD rendering using libass, with full Unicode support.
* New OSD bar with chapter marks. Not positioned in the middle of the video
(this can be customized with the ``--osd-bar-align-y`` option).
* Display list of chapters and audio/subtitle tracks on OSD (see the
`Properties`_ section).
Screenshots
~~~~~~~~~~~
* Instant screenshots without 1-frame delay.
* Support for taking screenshots even with hardware decoding.
* Support for saving screenshots as JPEG or PNG.
* Support for configurable file names.
* Support for taking screenshots with or without subtitles.
Note that the ``screenshot`` video filter is not needed anymore, and should not
be put into the mpv config file.
Miscellaneous
~~~~~~~~~~~~~
* Better MKV support (e.g. ordered chapters, 3D metadata).
* Matroska edition switching at runtime.
* Support for playing URLs of popular streaming sites directly.
(e.g. ``mpv https://www.youtube.com/watch?v=...``).
Requires a recent version of ``youtube-dl`` to be installed. Can be
disabled with ``ytdl=no`` in the mpv config file.
* Support for precise scrolling which scales the parameter of commands. If the
input doesn't support precise scrolling the scale factor stays 1.
* Allow changing/adjusting video filters at runtime. (This is also used to make
the ``D`` key insert vf_bwdif if deinterlacing is not supported otherwise).
* Improved support for .cue files.
macOS
~~~~~~~~
* Native OpenGL backend.
* Cocoa event loop is independent from MPlayer's event loop, so user
actions like accessing menus and live resizing do not block the playback.
* Media Keys support.
* VDA support using libavcodec hwaccel API instead of FFmpeg's decoder with up
to 2-2.5x reduction in CPU usage.
Windows
~~~~~~~
* Improved support for Unicode file names.
* Improved window handling.
* Do not block playback when moving the window.
* Improved Direct3D video output.
* Added WASAPI audio output.
Internal changes
~~~~~~~~~~~~~~~~
* Switch to GPLv2+ (see ``Copyright`` file for details).
* Removal of lots of cruft:
- Internal GUI (replaced by the OSC, see the `ON SCREEN CONTROLLER`_ section).
- MEncoder (replaced by native encoding, see the `ENCODING`_ section).
- OSD menu.
- Kernel video drivers for Linux 2.4 (including VIDIX).
- Teletext support.
- Support for dead platforms.
- Most built-in demuxers have been replaced by their libavformat counterparts.
- Built-in network support has been replaced by libavformat's (which also
supports https URLs).
- Embedded copies of libraries (such as FFmpeg).
* General code cleanups (including refactoring or rewrites of many parts).
* New build system.
* Many bug fixes and removal of long-standing issues.
* Generally preferring FFmpeg over internal demuxers, decoders, and
filters.
Detailed Listing of User-visible Changes
----------------------------------------
This listing is about changed command line switches, slave commands, and similar
things. Completely removed features are not listed.
Command Line Switches
~~~~~~~~~~~~~~~~~~~~~
* There is a new command line syntax, which is generally preferred over the old
syntax. ``-optname optvalue`` becomes ``--optname=optvalue``.
The old syntax will not be removed. However, the new syntax is mentioned in
all documentation and so on, and unlike the old syntax is not ambiguous,
so it is a good thing to know about this change.
* In general, negating switches like ``-noopt`` now have to be written as
``-no-opt`` or ``--no-opt``.
* Per-file options are not the default anymore. You can explicitly specify
file-local options. See ``Usage`` section.
* Many options have been renamed, removed or changed semantics. Some options
that are required for a good playback experience with MPlayer are now
superfluous or even worse than the defaults, so make sure to read the manual
before trying to use your existing configuration with **mpv**.
* Table of renamed/replaced switches:
=========================== ========================================
Old New
=========================== ========================================
``-no<opt>`` ``--no-<opt>`` (add a dash)
``-a52drc level`` ``--ad-lavc-ac3drc=level``
``-ac spdifac3`` ``--ad=spdif:ac3`` (see ``--ad=help``)
``-af volnorm`` (removed; use acompressor ffmpeg filter instead)
``-afm hwac3`` ``--ad=spdif:ac3,spdif:dts``
``-ao alsa:device=hw=0.3`` ``--ao=alsa:device=[hw:0,3]``
``-aspect`` ``--video-aspect-override``
``-ass-bottom-margin`` ``--vf=sub=bottom:top``
``-ass`` ``--sub-ass``
``-audiofile-cache`` (removed; the main cache settings are used)
``-audiofile`` ``--audio-file``
``-benchmark`` ``--untimed`` (no stats)
``-capture`` ``--stream-capture=<filename>``
``-channels`` ``--audio-channels`` (changed semantics)
``-cursor-autohide-delay`` ``--cursor-autohide``
``-delay`` ``--audio-delay``
``-dumpstream`` ``--stream-dump=<filename>``
``-dvdangle`` ``--dvd-angle``
``-endpos`` ``--length``
``-fixed-vo`` (removed; always the default)
``-font`` ``--osd-font``
``-forcedsubsonly`` ``--sub-forced-events-only``
``-forceidx`` ``--index``
``-format`` ``--audio-format``
``-fsmode-dontuse`` (removed)
``-fstype`` ``--x11-netwm`` (changed semantics)
``-hardframedrop`` ``--framedrop=hard``
``-identify`` (removed; use TOOLS/mpv_identify.sh)
``-idx`` ``--index``
``-lavdopts ...`` ``--vd-lavc-...``
``-lavfdopts`` ``--demuxer-lavf-...``
``-loop 0`` ``--loop=inf``
``-mixer-channel`` AO suboptions (``alsa``, ``oss``)
``-mixer`` AO suboptions (``alsa``, ``oss``)
``-mouse-movements`` ``--input-cursor``
``-msgcolor`` ``--msg-color``
``-msglevel`` ``--msg-level`` (changed semantics)
``-msgmodule`` ``--msg-module``
``-name`` ``--x11-name``
``-noar`` ``(removed; replaced by MediaPlayer framework)``
``-noautosub`` ``--no-sub-auto``
``-noconsolecontrols`` ``--no-input-terminal``
``-nosound`` ``--no-audio``
``-osdlevel`` ``--osd-level``
``-panscanrange`` ``--video-zoom``, ``--video-pan-x/y``
``-playing-msg`` ``--term-playing-msg``
``-pp ...`` ``'--vf=lavfi=[pp=...]'``
``-pphelp`` (See FFmpeg libavfilter documentation.)
``-rawaudio ...`` ``--demuxer-rawaudio-...``
``-rawvideo ...`` ``--demuxer-rawvideo-...``
``-spugauss`` ``--sub-gauss``
``-srate`` ``--audio-samplerate``
``-ss`` ``--start``
``-ssf <sub>`` ``--sws-...``
``-stop-xscreensaver`` ``--stop-screensaver``
``-sub-fuzziness`` ``--sub-auto``
``-sub-text-*`` ``--sub-*``
``-sub`` ``--sub-file``
``-subcp`` ``--sub-codepage``
``-subdelay`` ``--sub-delay``
``-subfile`` ``--sub-file``
``-subfont-*`` ``--sub-*``, ``--osd-*``
``-subfont-text-scale`` ``--sub-scale``
``-subfont`` ``--sub-font``
``-subfps`` ``--sub-fps``
``-subpos`` ``--sub-pos``
``-sws`` ``--sws-scaler``
``-tvscan`` ``--tv-scan``
``-use-filename-title`` ``--title='${filename}'``
``-vc ffh264vdpau`` (etc.) ``--hwdec=vdpau``
``-vobsub`` ``--sub-file`` (pass the .idx file)
``-x W``, ``-y H`` ``--geometry=WxH`` + ``--no-keepaspect``
``-xineramascreen`` ``--screen`` (different values)
``-xy W`` ``--autofit=W``
``-zoom`` Inverse available as ``--video-unscaled``
``dvdnav://`` Removed.
``dvd://1`` ``dvd://0`` (0-based offset)
=========================== ========================================
.. note::
``-opt val`` becomes ``--opt=val``.
.. note::
Quite some video filters, video outputs, audio filters, audio outputs, had
changes in their option parsing. These aren't mentioned in the table above.
Also, some video and audio filters have been removed, and you have to use
libavfilter (using ``--vf=lavfi=[...]`` or ``--af=lavfi=[...]``) to get
them back.
input.conf and Slave Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Table of renamed input commands:
This lists only commands that are not always gracefully handled by the
internal legacy translation layer. If an input.conf contains any legacy
commands, a warning will be printed when starting the player. The warnings
also show the replacement commands.
Properties containing ``_`` to separate words use ``-`` instead.
+--------------------------------+----------------------------------------+
| Old | New |
+================================+========================================+
| ``pt_step 1 [0|1]`` | ``playlist-next [weak|force]`` |
| | (translation layer cannot deal with |
| | whitespace) |
+--------------------------------+----------------------------------------+
| ``pt_step -1 [0|1]`` | ``playlist-prev [weak|force] (same)`` |
+--------------------------------+----------------------------------------+
| ``switch_ratio [<ratio>]`` | ``set video-aspect-override <ratio>`` |
| | |
| | ``set video-aspect-override 0`` (reset)|
+--------------------------------+----------------------------------------+
| ``step_property_osd <prop>`` | ``cycle <prop> <step>`` (wraps), |
| ``<step> <dir>`` | ``add <prop> <step>`` (clamps). |
| | ``<dir>`` parameter unsupported. Use |
| | a negative ``<step>`` instead. |
+--------------------------------+----------------------------------------+
| ``step_property <prop>`` | Prefix ``cycle`` or ``add`` with |
| ``<step> <dir>`` | ``no-osd``: ``no-osd cycle <prop>`` |
| | ``<step>`` |
+--------------------------------+----------------------------------------+
| ``osd_show_property_text`` | ``show-text <text>`` |
| ``<text>`` | The property expansion format string |
| | syntax slightly changed. |
+--------------------------------+----------------------------------------+
| ``osd_show_text`` | Now does the same as |
| | ``osd_show_property_text``. Use the |
| | ``raw`` prefix to disable property |
| | expansion. |
+--------------------------------+----------------------------------------+
| ``show_tracks`` | ``show-text ${track-list}`` |
+--------------------------------+----------------------------------------+
| ``show_chapters`` | ``show-text ${chapter-list}`` |
+--------------------------------+----------------------------------------+
| ``af_switch``, ``af_add``, ... | ``af set|add|...`` |
+--------------------------------+----------------------------------------+
| ``tv_start_scan`` | ``set tv-scan yes`` |
+--------------------------------+----------------------------------------+
| ``tv_set_channel <val>`` | ``set tv-channel <val>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_channel`` | ``cycle tv-channel`` |
+--------------------------------+----------------------------------------+
| ``dvb_set_channel <v1> <v2>`` | ``set dvb-channel <v1>-<v2>`` |
+--------------------------------+----------------------------------------+
| ``dvb_step_channel`` | ``cycle dvb-channel`` |
+--------------------------------+----------------------------------------+
| ``tv_set_freq <val>`` | ``set tv-freq <val>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_freq`` | ``cycle tv-freq`` |
+--------------------------------+----------------------------------------+
| ``tv_set_norm <norm>`` | ``set tv-norm <norm>`` |
+--------------------------------+----------------------------------------+
| ``tv_step_norm`` | ``cycle tv-norm`` |
+--------------------------------+----------------------------------------+
.. note::
Due to lack of hardware and users using the TV/DVB/PVR features, and
due to the need to cleanup the related command code, it's possible
that the new commands are buggy or behave worse. This can be improved
if testers are available. Otherwise, some of the TV code will be
removed at some point.
Slave mode
~~~~~~~~~~
* Slave mode was removed. A proper slave mode application needed tons of code
and hacks to get
it right. The main problem is that slave mode is a bad and incomplete
interface, and to get around that, applications parsed output messages
intended for users. It is hard to know which messages exactly are parsed by
slave mode applications. This makes it virtually impossible to improve
terminal output intended for users without possibly breaking something.
This is absolutely insane, and since initial improvements to **mpv** quickly
made slave mode incompatible to most applications, it was removed as useless
cruft. The client API (see below) is provided instead.
``--identify`` was replaced by the ``TOOLS/mpv_identify.sh`` wrapper script.
* For some time (until including release 0.4.x), mpv supported a
``--slave-broken`` option. The following options are equivalent:
::
--input-file=/dev/stdin --input-terminal=no
Assuming the system supports ``/dev/stdin``.
(The option was added back in 0.5.1 and sets exactly these options. It was
removed in 0.10.x again.)
* A JSON RPC protocol giving access to the client API is also supported. See
`JSON IPC`_ for more information.
* **mpv** also provides a client API, which can be used to embed the player
by loading it as shared library. (See ``mpv/client.h`` in the sources.)
It might also be possible to implement a custom slave mode-like protocol
using Lua scripting.
Policy for Removed Features
---------------------------
**mpv** is in active development. If something is in the way of more important
development (such as fixing bugs or implementing new features), we sometimes
remove features. Usually this happens only with old features that either seem
to be useless, or are not used by anyone. Often these are obscure, or
"inherited", or were marked experimental, but never received any particular
praise by any users.
Sometimes, features are replaced by something new. The new code will be either
simpler or more powerful, but doesn't necessarily provide everything the old
feature did.
We can not exclude that we accidentally remove features that are actually
popular. Generally, we do not know how much a specific functionality is used.
If you miss a feature and think it should be re-added, please open an issue
on the mpv bug tracker. Hopefully, a solution can be found. Often, it turns
out that re-adding something is not much of a problem, or that there are
better alternatives.
Why this Fork?
--------------
mplayer2 is practically dead, and mpv started out as a branch containing
new/experimental development. (Some of it was merged right *after* the fork
was made public, seemingly as an acknowledgment that development, or at
least merging, should have been more active.)
MPlayer is focused on not breaking anything, but is stuck with a horrible
codebase resistant to cleanup. (Unless you do what mpv did - merciless and
consequent pruning of bad, old code.) Cleanup and keeping broken things
conflict, so the kind of development mpv strives for can't be done within
MPlayer due to clashing development policies.
Additionally, mplayer2 already had lots of changes over MPlayer, which would
have needed to be backported to the MPlayer codebase. This would not only
have been hard (several years of diverging development), but also would have
been impossible due to the aforementioned MPlayer development policy.
+35 -106
View File
@@ -1,142 +1,71 @@
Release Policy
==============
A few times a year, a new release is cut off of the master branch and
assigned a 0.X.Y version number, where X is incremented each time a release
contains breaking changes, such as changed options or added/removed features,
and Y is incremented if a release contains only bugfixes and other minor
changes.
Every few months, a new release is cut off of the master branch and is assigned
a 0.X.0 version number.
Releases are tagged on the master branch and will not be maintained separately.
Patch releases may be made if the amount or severity of bugs justify it, or in
the event of security issues.
As part of the maintenance process, minor releases are made, which are assigned
0.X.Y version numbers. Minor releases contain bug fixes only. They never merge
the master branch, and no features are added to it. Only the latest release is
maintained.
The goal of releases is to provide Linux distributions with something to
package. If you want the newest features, just use the master branch.
We try our best to keep it deployable at all times.
The goal of releases is to provide stability and an unchanged base for the sake
of Linux distributions. If you want the newest features, just use the master
branch, which is stable most of the time, except sometimes, when it's not.
Releases other than the latest release are unsupported and unmaintained.
Release procedure
-----------------
While on master:
- Create branch release/0.X or cherry-pick commits to the relevant branch.
- Update the `RELEASE_NOTES` file, replacing the previous release notes.
- Create and/or update the ``RELEASE_NOTES`` file.
- Update the `MPV_VERSION` file.
- Create and/or update the ``VERSION`` file.
- Update `DOCS/client-api-changes.rst` (in particular, update the last version
number if necessary)
- Update ``DOCS/client-api-changes.rst`` (on major releases).
- Run `TOOLS/gen-interface-changes.py` to refresh `DOCS/interface-changes.rst`,
and edit manually as necessary.
- Create tag v0.X.Y.
- Delete all `.txt` files in `DOCS/interface-changes/` except for `example.txt`.
- Push branch and tag to GitHub.
- Create signed commit with changes.
- Create signed tag v0.X.Y.
- Push release branch (`release/0.X`) and tag to GitHub.
- Create a new GitHub release using the content of `RELEASE_NOTES` related to
the new version. Check the "Create a discussion for this release" box.
- Re-add -UNKNOWN suffix to version in `MPV_VERSION` file and commit.
If necessary (e.g. to exclude commits already on master), the release can
be done on a branch with different commit history. The release branch **must**
then be merged to master so `git describe` will pick up the tag.
This does not apply to patch releases, which are tagged directly on the
`release/0.X` branch. The master branch always remains at v0.X.0.
- Create a new GitHub release using the content of ``RELEASE_NOTES`` related to
the new version.
Release notes template
----------------------
Here is a template that should be used for writing the `RELEASE_NOTES` file:
Here is a template that can be used for writing the ``RELEASE_NOTES`` file.
```markdown
Release 0.X.Y
=============
We are excited to announce the release of mpv 0.X.Y.
Changes
-------
Key highlights:
- List of changes.
* List of notable stuff
Bug fixes
---------
This release requires FFmpeg <ver> or newer and libplacebo <ver> or newer.
- List of bug fixes.
# Features
New features
------------
## New
- List of new features.
- List of new features
## Changed
- List of changed features
## Removed
- List of removed features
# Options and Commands
## Added
- List of added options and commands
## Changed
- List of changed options and commands
## Deprecated
- List of deprecated options and commands
## Removed
- List of removed options and commands
# Fixes and Minor Enhancements
- List of fixes and minor enhancements
This listing is not complete. Check DOCS/client-api-changes.rst for a history
of changes to the client API, and DOCS/interface-changes.rst for a history
of changes to other user-visible interfaces.
A complete changelog can be seen by running `git log start..end`
in the git repository or by visiting
<https://github.com/mpv-player/mpv/compare/start...end>.
This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log <start>..<end>`` in
the git repository.
```
Note that the "Release 0.X.Y" title should be removed when creating a new GitHub
release.
When creating a new point release its changes should be added on top of the
`RELEASE_NOTES` file (with the appropriate title) so that all the changes in
the current 0.X branch will be included. This way the `RELEASE_NOTES` file
``RELEASE_NOTES`` file (with the appropriate title) so that all the changes in
the current 0.X branch will be included. This way the ``RELEASE_NOTES`` file
can be used by distributors as changelog for point releases too.
The changelog lists all changes since the last release, including those
that have been backported to patch releases already. Except for the
"Key highlights" section they are ordered chronologically with older commits
at the top.
Some additional advice:
- Especially for features, try to reword the messages so that the user-visible
change is clear to the reader. But don't simplify too much or be too verbose.
- It often makes sense to merge multiple related changes into one line
- Changes that have been made and reverted within the same release must not
appear in the changelog
- Limit the "Options and Commands" section to relevant changes
- When filling in the GitHub release, remove the "Release 0.X.Y" heading
+88 -477
View File
@@ -11,11 +11,11 @@ player/*.c:
* main():
* basic initializations (e.g. init_libav() and more)
* pre-parse command line (verbosity level, config file locations)
* load config files (mp_parse_cfgfiles())
* load config files (parse_cfgfiles())
* parse command line, add files from the command line to playlist
(m_config_parse_mp_command_line())
* check help options etc. (call handle_help_options()), possibly exit
* call mp_play_files() function that works down the playlist:
* call play_files() function that works down the playlist:
* run idle loop (idle_loop()), until there are files in the
playlist or an exit command was given (only if --idle it set)
* actually load and play a file in play_current_file():
@@ -30,7 +30,7 @@ player/*.c:
* determine next entry on the playlist to play
* loop, or exit if no next file or quit is requested
(see enum stop_play_reason)
* call mp_destroy()
* call exit_player_with_rc()
* run_playloop():
* calls fill_audio_out_buffers()
This checks whether new audio needs to be decoded, and pushes it
@@ -44,9 +44,11 @@ player/*.c:
Things worth saying about the playback core:
- most state is in MPContext (core.h), which is not available to the
subsystems (and should not be made available)
- the currently played tracks are in mpctx->current_track, and decoder
state in track.dec/d_sub
subsystems
- the currently played tracks are in mpctx->current_tracks, and decoder
state in d_video/d_audio/d_sub
- the timeline stuff is used only with MKV ordered chapters (and some other
minor features: cue, edl)
- the other subsystems rarely call back into the frontend, and the frontend
polls them instead (probably a good thing)
- one exceptions are wakeup callbacks, which notify a "higher" component
@@ -54,18 +56,27 @@ player/*.c:
I like to call the player/*.c files the "frontend".
ta.h & ta.c:
Hierarchical memory manager inspired by talloc from Samba. It's like a
malloc() with more features. Most importantly, each talloc allocation can
have a parent, and if the parent is free'd, all children will be free'd as
well. The parent is an arbitrary talloc allocation. It's either set by the
allocation call by passing a talloc parent, usually as first argument to the
allocation function. It can also be set or reset later by other calls (at
least talloc_steal()). A talloc allocation that is used as parent is often
called a talloc context.
talloc.h & talloc.c:
Hierarchical memory manager copied from Samba. It's like a malloc() with
more features. Most importantly, each talloc allocation can have a parent,
and if the parent is free'd, all children will be free'd as well. The
parent is an arbitrary talloc allocation. It's either set by the allocation
call by passing a talloc parent, usually as first argument to the allocation
function. It can also be set or reset later by other calls (at least
talloc_steal()). A talloc allocation that is used as parent is often called
a talloc context.
Lots of code still uses malloc() proper, and you should be careful what
type of allocation you're dealing with when returning or free'ing an
allocation. (Needless to say, talloc_free() and free() are completely
different things.)
The copy in mpv has been modified to abort on OOM conditions. An
allocation call will never return NULL.
One very useful feature of talloc is fast tracking of memory leaks. ("Fast"
as in it doesn't require valgrind.) You can enable it by setting the
as in it doesn't require valgrind.) You can enable it by passing the option
--leak-report as first parameter, or better, setting the
MPV_LEAK_REPORT environment variable to "1":
export MPV_LEAK_REPORT=1
This will list all unfree'd allocations on exit.
@@ -73,14 +84,16 @@ ta.h & ta.c:
Documentation can be found here:
http://git.samba.org/?p=samba.git;a=blob;f=lib/talloc/talloc.h;hb=HEAD
For some reason, we're still using API-compatible wrappers instead of TA
directly. The talloc wrapper has only a subset of the functionality, and
in particular the wrappers abort() on memory allocation failure.
Note: unlike tcmalloc, jemalloc, etc., talloc() is not actually a malloc
replacement. It works on top of system malloc and provides additional
features that are supposed to make memory management easier.
Warning: actually, we're not using talloc anymore. talloc in mpv has been
replaced by a custom re-implementation (TA in ta/). It provides
some talloc emulation (just the parts needed by mpv). We will get
rid of the talloc emulation later and use TA natively.
(See ta/README for details.)
player/command.c:
This contains the implementation for client API commands and properties.
Properties are essentially dynamic variables changed by certain commands.
@@ -93,7 +106,7 @@ player/core.h:
usually not accessed by other parts of mpv for the sake of modularization.
player/client.c:
This implements the client API (mpv/client.h). For the most part, this
This implements the client API (libmpv/client.h). For the most part, this
just calls into other parts of the player. This also manages a ringbuffer
of events from player to clients.
@@ -103,48 +116,15 @@ options/options.h, options/options.c
options.c. Most default values for options and MPOpts are in
mp_default_opts at the end of options.c.
MPOpts is unfortunately quite monolithic, but is being incrementally broken
up into sub-structs. Many components have their own sub-option structs
separate from MPOpts. New options should be bound to the component that uses
them. Add a new option table/struct if needed.
MPOpts is unfortunately quite monolithic, and virtually accessed by
everything.But some components (like video outputs and video filters) have
their own sub-option tables separate from MPOpts.
The global MPOpts still contains the sub-structs as fields, which serves to
link them to the option parser. For example, an entry like this may be
typical:
{"", OPT_SUBSTRUCT(demux_opts, demux_conf)},
This directs the option access code to include all options in demux_conf
into the global option list, with no prefix (""), and as part of the
MPOpts.demux_opts field. The MPOpts.demux_opts field is actually not
accessed anywhere, and instead demux.c does this:
struct m_config_cache *opts_cache =
m_config_cache_alloc(demuxer, global, &demux_conf);
struct demux_opts *opts = opts_cache->opts;
... to get a copy of its options.
See m_config_core.h (below) how to access options.
The actual option parser is spread over m_option.c, m_config_frontend.c,
and parse_commandline.c, and uses the option table in options.c.
options/m_config_*.h & m_config_*.c:
Code for querying and managing options. m_config_frontend.h contains
declarations for the "legacy-ish" global m_config struct, while
m_config_core.h provides ways to access options in a threads-safe way
anywhere, like m_config_cache_alloc().
m_config_cache_alloc() lets anyone read, observe, and write options in any
thread. The only state it needs is struct mpv_global, which is an opaque
type that can be passed "down" the component hierarchy. For safety reasons,
you should not pass down any pointers to option structs (like MPOpts), but
instead pass down mpv_global, and use m_config_cache_alloc() (or similar)
to get a synchronized copy of the options.
The actual option parser is spread over m_option.c, m_config.c, and
parser-mpcmd.c, and uses the option table in options.c.
input/input.c:
This translates keyboard input coming from VOs and other sources (such
This translates keyboard input comming from VOs and other sources (such
as remote control devices like Apple IR or client API commands) to the
key bindings listed in the user's (or the builtin) input.conf and turns
them into items of type struct mp_cmd. These commands are queued, and read
@@ -165,37 +145,30 @@ stream/*:
E.g. if mpv sees "http://something" on the command line, it will pick
stream_lavf.c based on the prefix, and pass the rest of the filename to it.
Some stream inputs are quite special: stream_dvdnav.c turns DVDs into mpeg
Some stream inputs are quite special: stream_dvd.c turns DVDs into mpeg
streams (DVDs are actually a bunch of vob files etc. on a filesystem),
stream_tv.c provides TV input including channel switching.
Some stream inputs are just there to invoke special demuxers, like
stream_mf.c. (Basically to make the prefix "mf://" do something special.)
cache.c is a caching wrapper around streams implementations, needed for
smooth network playback.
demux/:
Demuxers split data streams into audio/video/sub streams, which in turn
are split in packets. Packets (see packet.h) are mostly byte chunks
are split in packets. Packets (see demux_packet.h) are mostly byte chunks
tagged with a playback time (PTS). These packets are passed to the decoders.
Most demuxers have been removed from this fork, and the only important and
"actual" demuxers left are demux_mkv.c and demux_lavf.c (uses libavformat).
There are some pseudo demuxers like demux_cue.c.
There are some pseudo demuxers like demux_cue.c, which exist only to invoke
other frontend code (tl_cue.c in this case).
The main interface is in demux.h. The stream headers are in stheader.h.
There is a stream header for each audio/video/sub stream, and each of them
holds codec information about the stream and other information.
demux.c is a bit big, the main reason being that it contains the demuxer
cache, which is implemented as a list of packets. The cache is complex
because it support seeking, multiple ranges, prefetching, and so on.
filters/:
Filter related code. filter.c contains the generic filtering framework
which converts input frames to output frames (audio, video, or demux
packet data). f_decoder_wrapper.c is a source filter which connects the
frontend with the actual audio and video decoders. f_output_chain.c handles
VO/AO output conversions. f_autoconvert.c automatically inserts the
appropriate conversion filters if format conversion is needed.
video/:
This contains several things related to audio/video decoding, as well as
video filters.
@@ -204,36 +177,41 @@ video/:
internally.
video/decode/:
vd_*.c are video decoders. (There's only vd_lavc.c left.)
vd_*.c are video decoders. (There's only vd_lavc.c left.) dec_video.c/vd.c
handle most of connecting the frontend with the actual decoder.
video/filter/:
vf_*.c are video filters. They are fed by the video decoder, and output the
filtered images to the VOs. By default, no video filters are used.
vf_*.c and vf.c form the video filter chain. They are fed by the video
decoder, and output the filtered images to the VOs though vf_vo.c. By
default, no video filters (except vf_vo) are used. vf_scale is automatically
inserted if the video output can't handle the video format used by the
decoder.
video/out/:
Video output. They also create GUI windows and handle user input. In most
cases, the windowing code is shared among VOs, like x11_common.c for X11 and
w32_common.c for Windows. The VOs stand between frontend and windowing code.
vo_gpu and vo_gpu_next can pick a windowing system at runtime, e.g. the same
binary can provide both X11 and Cocoa support on macOS.
vo_opengl can pick a windowing system at runtime, e.g. the same binary can
provide both X11 and Cocoa support on OSX.
VOs can be reconfigured at runtime. A vo_reconfig() call can change the video
VOs can be reconfigured at runtime. A vo_config() call can change the video
resolution and format, without destroying the window.
vo_gpu should be taken as reference.
vo_vdpau and vo_opengl should be taken as reference.
audio/:
format.h/format.c define the uncompressed audio formats. (As well as some
compressed formats used for spdif.)
audio/decode/:
ad_*.c handle audio decoding. ad_lavc.c is the decoder using ffmpeg.
ad_spdif.c is not really a decoder, but is used for compressed audio
passthrough.
ad_*.c and dec_audio.c/ad.c handle audio decoding. ad_lavc.c is the
decoder using ffmpeg. ad_spdif.c is not really a decoder, but is used for
compressed audio passthrough.
audio/filter/:
Audio filters. af_scaletempo2 is inserted by default if playback is different
from normal speed.
Audio filter chain. af_lavrresample is inserted if any form of conversion
between audio formats is needed. (af_convert24.c and af_convertsignendian.c
are also used for some formats not directly supported by FFmpeg.)
audio/out/:
Audio outputs.
@@ -241,9 +219,9 @@ audio/out/:
Unlike VOs, AOs can't be reconfigured on a format change. On audio format
changes, the AO will simply be closed and re-opened.
buffer.c is the wrapper to support for two types of audio APIs: push and
pull. ao.c calls into that. It contains generic code to deal with the data
flow these APIs impose.
There are wrappers to support for two types of audio APIs: push.c and
pull.c. ao.c calls into one of these. They contain generic code to deal
with the data flow these APIs impose.
Note that mpv synchronizes the video to the audio. That's the reason
why buggy audio drivers can have a bad influence on playback quality.
@@ -260,397 +238,30 @@ sub/:
in turn asks dec_sub.c for subtitle overlay bitmaps, which relays the
request to one of the sd_*.c subtitle decoders/renderers.
Subtitle loading is in demux/. Normally, subtitles are loaded via demux_lavf.c.
Subtitle loading is in demux/. The MPlayer subreader.c is mostly gone - parts
of it survive in demux_subreader.c. It's used as last fallback, or to handle
some text subtitle types on Libav. It should go away eventually. Normally,
subtitles are loaded via demux_lavf.c.
The subtitles are passed to dec_sub.c and the subtitle decoders in sd_*.c
as they are demuxed. All text subtitles are rendered by sd_ass.c. If text
subtitles are not in the ASS format, the libavcodec subtitle converters are
used (lavc_conv.c).
subtitles are not in the ASS format, subtitle converters are inserted, for
example sd_srt.c, which is used to convert SRT->ASS. sd_srt.c is also used
as general converter for text->ASS (to prevent interpretation of text as
ASS tags).
Text subtitles can be preloaded, in which case they are read fully as soon
as the subtitle is selected. In this case, they are effectively stored in
sd_ass.c's internal state.
as the subtitle is selected, and then effectively stored in an ASS_Track.
It's used for external text subtitles, and required to make codepage
detection as well as timing postprocessing work. (Timing postprocessing
removes tiny gaps or overlaps between subtitle events.)
player/timeline/:
A timeline is the abstraction used by loadfile.c to combine several files
into one seemingly linear video. It's mainly used for ordered chapters
playback. The high level code to find and load other files containing the
segments for playing an ordered chapters file is in tl_matroska.c.
etc/:
The files input.conf and builtin.conf are actually integrated into the mpv
binary by the build system. They contain the default configs and keybindings.
Best practices and Concepts within mpv
======================================
General contribution etc.
-------------------------
See: DOCS/contribute.md
Error checking
--------------
If an error is relevant, it should be handled. If it's interesting, log the
error. However, mpv often keeps errors silent and reports failures somewhat
coarsely by propagating them upwards the caller chain. This is OK, as long as
the errors are not very interesting, or would require a developer to debug it
anyway (in which case using a debugger would be more convenient, and the
developer would need to add temporary debug printfs to get extremely detailed
information which would not be appropriate during normal operation).
Basically, keep a balance on error reporting. But always check them, unless you
have a good argument not to.
Memory allocation errors (OOM) are a special class of errors. Normally such
allocation failures are not handled "properly". Instead, abort() is called.
(New code should use MP_HANDLE_OOM() for this.) This is done out of laziness and
for convenience, and due to the fact that MPlayer/mplayer2 never handled it
correctly. (MPlayer varied between handling it correctly, trying to do so but
failing, and just not caring, while mplayer2 started using abort() for it.)
This is justifiable in a number of ways. Error handling paths are notoriously
untested and buggy, so merely having them won't make your program more reliable.
Having these error handling paths also complicates non-error code, due to the
need to roll back state at any point after a memory allocation.
Take any larger body of code, that is supposed to handle OOM, and test whether
the error paths actually work, for example by overriding malloc with a version
that randomly fails. You will find bugs quickly, and often they will be very
annoying to fix (if you can even reproduce them).
In addition, a clear indication that something went wrong may be missing. On
error your program may exhibit "degraded" behavior by design. Consider a video
encoder dropping frames somewhere in the middle of a video due to temporary
allocation failures, instead of just exiting with an errors. In other cases, it
may open conceptual security holes. Failing fast may be better.
mpv uses GPU APIs, which may be break on allocation errors (because driver
authors will have the same issues as described here), or don't even have a real
concept for dealing with OOM (OpenGL).
libmpv is often used by GUIs, which I predict always break if OOM happens.
Last but not least, OSes like Linux use "overcommit", which basically means that
your program may crash any time OOM happens, even if it doesn't use malloc() at
all!
But still, don't just assume malloc() always succeeds. Use MP_HANDLE_OOM(). The
ta* APIs do this for you. The reason for this is that dereferencing a NULL
pointer can have security relevant consequences if large offsets are involved.
Also, a clear error message is better than a random segfault.
Some big memory allocations are checked anyway. For example, all code must
assume that allocating video frames or packets can fail. (The above example
of dropping video frames during encoding is entirely possible in mpv.)
Undefined behavior
------------------
Undefined behavior (UB) is a concept in the C language. C is famous for being a
language that makes it almost impossible to write working code, because
undefined behavior is so easily triggered, compilers will happily abuse it to
generate "faster" code, debugging tools will shout at you, and sometimes it
even means your code doesn't work.
There is a lot of literature on this topic. Read it.
(In C's defense, UB exists in other languages too, but since they're not used
for low level infrastructure, and/or these languages are at times not rigorously
defined, simply nobody cares. However, the C standard committee is still guilty
for not addressing this. I'll admit that I can't even tell from the standard's
gibberish whether some specific behavior is UB or not. It's written like tax
law.)
In mpv, we generally try to avoid undefined behavior. For one, we want portable
and reliable operation. But more importantly, we want clean output from
debugging tools, in order to find real bugs more quickly and effectively.
Avoid the "works in practice" argument. Once debugging tools come into play, or
simply when "in practice" stops being true, this will all get back to you in a
bad way.
Global state, library safety
----------------------------
Mutable global state is when code uses global variables that are not read-only.
This must be avoided in mpv. Always use context structs that the caller of
your code needs to allocate, and whose pointers are passed to your functions.
Library safety means that your code (or library) can be used by a library
without causing conflicts with other library users in the same process. To any
piece of code, a "safe" library's API can simply be used, without having to
worry about other API users that may be around somewhere.
Libraries are often not library safe, because they use global mutable state
or other "global" resources. Typical examples include use of signals, simple
global variables (like hsearch() in libc), or internal caches not protected by
locks.
A surprisingly high number of libraries are not library safe because they need
global initialization. Typically they provide an API function, which
"initializes" the library, and which must be called before calling any other
API functions. Often, you are to provide global configuration parameters, which
can change the behavior of the library. If two libraries A and B use library C,
but A and B initialize C with different parameters, something "bad" may happen.
In addition, these global initialization functions are often not thread-safe. So
if A and B try to initialize C at the same time (from different threads and
without knowing about each other), it may cause undefined behavior. (libcurl is
a good example of both of these issues. FFmpeg and some TLS libraries used to be
affected, but improved.)
This is so bad because library A and B from the previous example most likely
have no way to cooperate, because they're from different authors and have no
business knowing each others. They'd need a library D, which wraps library C
in a safe way. Unfortunately, typically something worse happens: libraries get
"infected" by the unsafeness of its sub-libraries, and export a global init API
just to initialize the sub-libraries. In the previous example, libraries A and B
would export global init APIs just to init library C, even though the rest of
A/B are clean and library safe. (Again, libcurl is an example of this, if you
subtract other historic anti-features.)
The main problem with library safety is that its lack propagates to all
libraries using the library.
We require libmpv to be library safe. This is not really possible, because some
libraries are not library safe (FFmpeg, Xlib, partially ALSA). However, for
ideological reasons, there is no global init API, and best effort is made to try
to avoid problems.
libmpv has some features that are not library safe, but which are disabled by
default (such as terminal usage aka stdout, or JSON IPC blocking SIGPIPE for
internal convenience).
A notable, very disgustingly library unsafe behavior of libmpv is calling
abort() on some memory allocation failure. See error checking section.
Logging
-------
All logging and terminal output in mpv goes through the functions and macros
provided in common/msg.h. This is in part for library safety, and in part to
make sure users can silence all output, or to redirect the output elsewhere,
like a log file or the internal console.lua script.
Locking
-------
See generally available literature. In mpv, we use mp_thread for this.
Always keep locking clean. Don't skip locking just because it will work "in
practice". (See undefined behavior section.) If your use case is simple, you may
use C11 atomics, but most likely you will only hurt yourself and others.
Always make clear which fields in a struct are protected by which lock. If a
field is immutable, or simply not thread-safe (e.g. state for a single worker
thread), document it as well.
Internal mpv APIs are assumed to be not thread-safe by default. If they have
special guarantees (such as being usable by more than one thread at a time),
these should be explicitly documented.
All internal mpv APIs must be free of global state. Even if a component is not
thread-safe, multiple threads can use _different_ instances of it without any
locking.
On a side note, recursive locks may seem convenient at first, but introduce
additional problems with condition variables and locking hierarchies. They
should be avoided.
Locking hierarchy
-----------------
A simple way to avoid deadlocks with classic locking is to define a locking
hierarchy or lock order. If all threads acquire locks in the same order, no
deadlocks will happen.
For example, a "leaf" lock is a lock that is below all other locks in the
hierarchy. You can acquire it any time, as long as you don't acquire other
locks while holding it.
Unfortunately, C has no way to declare or check the lock order, so you should at
least document it.
In addition, try to avoid exposing locks to the outside. Making the declaration
of a lock private to a specific .c file (and _not_ exporting accessors or
lock/unlock functions that manipulate the lock) is a good idea. Your component's
API may acquire internal locks, but should release them when returning. Keeping
the entire locking in a single file makes it easy to check it.
Avoiding callback hell
----------------------
mpv code is separated in components, like the "frontend" (i.e. MPContext mpctx),
VOs, AOs, demuxers, and more. The frontend usually calls "down" the usage
hierarchy: mpctx almost on top, then things like vo/ao, and utility code on the
very bottom.
"Callback hell" is when components call both up and down the hierarchy,
which for example leads to accidentally recursion, reentrancy problems, or
locking nightmares. This is avoided by (mostly) calling only down the hierarchy.
Basically the call graph forms a DAG. The other direction is handled by event
queues, wakeup callbacks, and similar mechanisms.
Typically, a component provides an API, and does not know anything about its
user. The API user (component higher in the hierarchy) polls the state of the
lower component when needed.
This also enforces some level of modularization, and with some luck the locking
hierarchy. (Basically, locks of lower components automatically become leaf
locks.) Another positive effect is simpler memory management.
(Also see e.g.: http://250bpm.com/blog:24)
Wakeup callbacks
----------------
This is a common concept in mpv. Even the public API uses it. It's used when an
API has internal threads (or otherwise triggers asynchronous events), but the
component call hierarchy needs to be kept. The wakeup callback is the only
exception to the call hierarchy, and always calls up.
For example, vo spawns a thread that the API user (the mpv frontend) does not
need to know about. vo simply provides a single-threaded API (or that looks like
one). This API needs a way to notify the API user of new events. But the vo
event producer is on the vo thread - it can't simply invoke a callback back into
the API user, because then the API user has to deal with locking, despite not
using threads. In addition, this will probably cause problems like mentioned in
the "callback hell" section, especially lock order issues.
The solution is the wakeup callback. It merely unblocks the API user from
waiting, and the API user then uses the normal vo API to examine whether or
which state changed. As a concept, it documents what a wakeup callback is
allowed to do and what not, to avoid the aforementioned problems.
Generally, you are not allowed to call any API from the wakeup callback. You
just do whatever is needed to unblock your thread. For example, if it's waiting
on a mutex/condition variable, acquire the mutex, set a change flag, signal
the condition variable, unlock, return. (This mutex must not be held when
calling the API. It must be a leaf lock.)
Restricting the wakeup callback like this sidesteps any reentrancy issues and
other complexities. The API implementation can simply hold internal (and
non-recursive) locks while invoking the wakeup callback.
The API user still needs to deal with locking (probably), but there's only the
need to implement a single "receiver", that can handle the entire API of the
used component. (Or multiple APIs - MPContext for example has only 1 wakeup
callback that handles all AOs, VOs, input, demuxers, and more. It simple re-runs
the playloop.)
You could get something more advanced by turning this into a message queue. The
API would append a message to the queue, and the API user can read it. But then
you still need a way to "wakeup" the API user (unless you force the API user
to block on your API, which will make things inconvenient for the API user). You
also need to worry about what happens if the message queue overruns (you either
lose messages or have unbounded memory usage). In the mpv public API, the
distinction between message queue and wakeup callback is sort of blurry, because
it does provide a message queue, but an additional wakeup callback, so API
users are not required to call mpv_wait_event() with a high timeout.
mpv itself prefers using wakeup callbacks over a generic event queue, because
most times an event queue is not needed (or complicates things), and it is
better to do it manually.
(You could still abstract the API user side of wakeup callback handling, and
avoid reimplementing it all the time. Although mp_dispatch_queue already
provides mechanisms for this.)
Condition variables
-------------------
They're used whenever a thread needs to wait for something, without nonsense
like sleep calls or busy waiting. mpv uses the mp_thread API for this.
There's a lot of literature on condition variables, threading in general. Read it.
For initial understanding, it may be helpful to know that condition variables
are not variables that signal a condition. mp_cond does not have any
state per-se. Maybe mp_cond would better be named mp_interrupt,
because its sole purpose is to interrupt a thread waiting via mp_cond_wait()
(or similar). The "something" in "waiting for something" can be called
predicate (to avoid confusing it with "condition"). Consult literature for the
proper terms.
The very short version is...
Shared declarations:
mp_mutex lock;
mp_cond cond_var;
struct something state_var; // protected by lock, changes signaled by cond_var
Waiter thread:
mp_mutex_lock(&lock);
// Wait for a change in state_var. We want to wait until predicate_fulfilled()
// returns true.
// Must be a loop for 2 reasons:
// 1. cond_var may be associated with other conditions too
// 2. mp_cond_wait() can have sporadic wakeups
while (!predicate_fulfilled(&state_var)) {
// This unlocks, waits for cond_var to be signaled, and then locks again.
// The _whole_ point of cond_var is that unlocking and waiting for the
// signal happens atomically.
mp_cond_wait(&cond_var, &lock);
}
// Here you may react to the state change. The state cannot change
// asynchronously as long as you still hold the lock (and didn't release
// and reacquire it).
// ...
mp_mutex_unlock(&lock);
Signaler thread:
mp_mutex_lock(&lock);
// Something changed. Update the shared variable with the new state.
update_state(&state_var);
// Notify that something changed. This will wake up the waiter thread if
// it's blocked in mp_cond_wait(). If not, nothing happens.
mp_cond_broadcast(&cond_var);
// Fun fact: good implementations wake up the waiter only when the lock is
// released, to reduce kernel scheduling overhead.
mp_mutex_unlock(&lock);
Some basic rules:
1. Always access your state under proper locking
2. Always check your predicate before every call to mp_cond_wait()
(And don't call mp_cond_wait() if the predicate is fulfilled.)
3. Always call mp_cond_wait() in a loop
(And only if your predicate failed without releasing the lock..)
4. Always call mp_cond_broadcast()/_signal() inside of its associated
lock
mpv sometimes violates rule 3, and leaves "retrying" (i.e. looping) to the
caller.
Common pitfalls:
- Thinking that mp_cond is some kind of semaphore, or holds any
application state or the user predicate (it _only_ wakes up threads
that are at the same time blocking on mp_cond_wait() and friends,
nothing else)
- Changing the predicate, but not updating all mp_cond_broadcast()/
_signal() calls correctly
- Forgetting that mp_cond_wait() unlocks the lock (other threads can
and must acquire the lock)
- Holding multiple nested locks while trying to wait (=> deadlock, violates
the lock order anyway)
- Waiting for a predicate correctly, but unlocking/relocking before acting
on it (unlocking allows arbitrary state changes)
- Confusing which lock/condition var. is used to manage a bit of state
Generally available literature probably has better examples and explanations.
Using condition variables the proper way is generally preferred over using more
messy variants of them. (Just saying because on win32, "SetEvent" exists, and
it's inferior to condition variables. Try to avoid the win32 primitives, even if
you're dealing with Windows-only code.)
Threads
-------
Threading should be conservatively used. Normally, mpv code pretends to be
single-threaded, and provides thread-unsafe APIs. Threads are used coarsely,
and if you can avoid messing with threads, you should. For example, VOs and AOs
do not need to deal with threads normally, even though they run on separate
threads. The glue code "isolates" them from any threading issues.
The file input.conf is actually integrated into the mpv binary by the
build system. It contains the default keybindings.
+156
View File
@@ -0,0 +1,156 @@
waf build system overview
=========================
mpv's new build system is based on waf and it should completly replace the
custom ./configure + Makefile based system inherited from MPlayer.
Goals and the choice of waf
===========================
The new system comes with some goals, which can be summed up as: be as good as
the old one at what it did well (customizability) and fix some of it's major
shortcomings:
1) The build system must be uniform in how it handles any single feature check.
Repetition and boilerplate have to be avoided.
When adding a new feature using the old configure, one had to add a fair
amount of code to the shell script to do option parsing, detection of the
feature and declaration of variables for the Makefile to pickup. The worst
part is this pieces are spread apart in the configure and copy pasted for
any single case. That brings us to..
2) --enable-feature has to override the user and help him understand that he
has libraries missing and should install them for the feature to be enabled.
3) Must be customizable, hackable, pleasant to the developer eyes and to work
with in general.
4) Must have separate configuration and build steps.
Goal 2 comes as a given on pretty much any build system, since autotools made
this behaviour very popular among users (and rightly so).
Goal 1+3 were somewhat harder to accomplish as it looks like all of the build
systems we evaluated (waf included!) had problems with them. For reference we
had proof of concept build systems with waf, CMake and autotools.
What puts waf apart from CMake and autotools, is that projects using it use
Python to program their build system. Also while the Waf Book shows really
simple API usages, you can write your own build system on top of waf that is
tailored to the project's specific needs.
mpv's custom configure step on top of waf
=========================================
To some extents mpv has a custom build system written on top of waf. This
document will not go over the standard waf behaviour as that is documented in
the `Waf book <http://docs.waf.googlecode.com/git/book_17/single.html>`_.
All of the configuration process is handled with a declarative approach. Lists
of dictionaries define the checks, and some custom Python code traverses these
lists and depending on the check definition it calls into the actual waf API.
A simple example using pkg-config would be::
{
'name': '--vdpau',
'desc': 'VDPAU acceleration',
'deps': [ 'x11' ],
'func': check_pkg_config('vdpau', '>= 0.2'),
}
This defines a feature called ``vdpau`` which can be enabled or disabled by
the users with configure flags (that's the meaning of ``--``). This feature
depends on another feature whose name is ``x11``, and the autodetection check
consists of running ``pkg-config`` and looking for ``vdpau`` with version
``>= 0.2``. If the check succeds a ``#define HAVE_VDPAU 1`` will be added to
``config.h``, if not ``#define HAVE_VDPAU 0`` will be added.
The defines names are automatically prepended with ``HAVE_``, capitalized and
special characters are replaced with underscores. This happens in
``waftools/inflectors.py``.
Mandatory fields:
-----------------
``name``: indicates the unique identifier used by the custom dependency code
to refer to a feature. If the unique identifier is prepended with ``--``
the build system will also generate options for ``./waf configure`` so that
the feature can be enabled and disabled.
``desc``: this is the textual representation of the feature used in the
interactions with the users.
``func``: function that will perform the check. These functions are defined in
``waftools/checks``. The reusable checks are all functions that return
functions. The return functions will then be applied using waf's configuration
context.
The source code for the reusable checks is a bit convoluted, but it should be
easy to pick up their usage from the ``wscript``. Their signature mirrors
the semantics of some of the shell functions used in mplayer.
If someone expresses some interest, I will extend this document with official
documentation for each check function.
Optional fields
---------------
``deps``: list of dependencies of this feature. It is a list of names of
other features as defined in the ``name`` field (minus the eventual leading
``--``). All of the dependencies must be satisfied. If they are not the check
will be skipped without even running ``func``.
``deps_any``: like deps but it is satisfied even if only one of the dependencies
is satisfied. You can think of ``deps`` as a 'and' condition and ``deps_any``
as a 'or' condition.
``deps_neg``: like deps but it is satisfied when none of the dependencies is
satisfied.
``req``: defaults to False. If set to True makes this feature a hard
dependency of mpv (configuration will fail if autodetection fails). If set to
True you must also provide ``fmsg``.
``fmsg``: string with the failure message in case a required dependency is not
satisfied.
``os_specific_checks``: this takes a dictionary that has ``os-`` dependencies
as keys (such as ``os-win32``), and by values has another dictionary that is
merged on top of the current feature definition only for that specific OS.
For example::
{
'name': '--pthreads',
'desc': 'POSIX threads',
'func': check_pthreads,
'os_specific_checks': {
'os-win32': {
'func': check_pthreads_w32_static.
}
}
}
will override the value of ``func`` with ``check_pthreads_w32_static`` only
if the target OS of the build is Windows.
``groups``: groups a dependency with another one. This can be used to disabled
all the grouped dependencies with one ``--disable-``. At the moment this is
only used for OpenGL backends, where you want to disable them when
``--disable-gl`` is passed to the configure.
mpv's custom build step on top of waf
=====================================
Build step is pretty much vanilla waf. The only difference being that the list
of source files can contain both strings or tuples. If a tuple is found,
the second element in the tuple will the used to match the features detected
in the configure step (the ``name`` field described above). If this feature
was not enabled during configure, the source file will not be compiled in.
All of the custom Python for this is inside the function ``filtered_sources``
contained in the file ``waftools/dependencies.py``.
Also ``dependencies_use`` and ``dependencies_includes`` collect cflags and
ldflags that were generated from the features checks in the configure step.
+15 -13
View File
@@ -1,8 +1,8 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
<https://fsf.org/>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
@@ -303,8 +303,10 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, see <https://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
@@ -328,11 +330,11 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Moe Ghoul>, 1 April 1989
Moe Ghoul, President of Vice
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
-501
View File
@@ -1,501 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
<https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library 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.
This library 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 this library; if not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Moe Ghoul>, 1 April 1990
Moe Ghoul, President of Vice
That's all there is to it!
-1
View File
@@ -1 +0,0 @@
0.41.0
+92 -173
View File
@@ -1,222 +1,141 @@
![mpv logo](https://raw.githubusercontent.com/mpv-player/mpv.io/master/source/images/mpv-logo-128.png)
mpv
===
# mpv
[![Build Status](https://api.travis-ci.org/mpv-player/mpv.png)](https://travis-ci.org/mpv-player/mpv)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/1232/badge.svg)](https://scan.coverity.com/projects/1232)
* [External links](#external-links)
* [Overview](#overview)
* [System requirements](#system-requirements)
* [Downloads](#downloads)
* [Changelog](#changelog)
* [Compilation](#compilation)
* [Release cycle](#release-cycle)
* [Bug reports](#bug-reports)
* [Contributing](#contributing)
* [License](#license)
* [Contact](#contact)
Overview
--------
**mpv** is a movie player based on MPlayer and mplayer2. It supports a wide
variety of video file formats, audio and video codecs, and subtitle types.
## External links
* [Wiki](https://github.com/mpv-player/mpv/wiki)
* [User Scripts](https://github.com/mpv-player/mpv/wiki/User-Scripts)
* [FAQ][FAQ]
* [Manual](https://mpv.io/manual/master/)
## Overview
**mpv** is a free (as in freedom) media player for the command line. It supports
a wide variety of media file formats, audio and video codecs, and subtitle types.
There is a [FAQ][FAQ].
Releases can be found on the [release list][releases].
## System requirements
- A not too ancient Linux (usually, only the latest releases of distributions
are actively supported), Windows 10 1607 or later, or macOS 10.15 or later.
- A somewhat capable CPU. Hardware decoding might help if the CPU is too slow to
decode video in realtime, but must be explicitly enabled with the `--hwdec`
option.
- A not too crappy GPU. mpv's focus is not on power-efficient playback on
embedded or integrated GPUs (for example, hardware decoding is not even
enabled by default). Low power GPUs may cause issues like tearing, stutter,
etc. On such GPUs, it's recommended to use `--profile=fast` for smooth playback.
The main video output uses shaders for video rendering and scaling,
rather than GPU fixed function hardware. On Windows, you might want to make
sure the graphics drivers are current. In some cases, ancient fallback video
output methods can help (such as `--vo=xv` on Linux), but this use is not
recommended or supported.
mpv does not go out of its way to break on older hardware or old, unsupported
operating systems, but development is not done with them in mind. Keeping
compatibility with such setups is not guaranteed. If things work, consider it
a happy accident.
## Downloads
For semi-official builds and third-party packages please see
[mpv.io/installation](https://mpv.io/installation/).
## Changelog
There is no complete changelog; however, changes to the player core interface
are listed in the [interface changelog][interface-changes].
Changes to the C API are documented in the [client API changelog][api-changes].
The [release list][releases] has a summary of most of the important changes
on every release.
Changes to the default key bindings are indicated in
[restore-old-bindings.conf][restore-old-bindings].
Changes to the default OSC bindings are indicated in
[restore-osc-bindings.conf][restore-osc-bindings].
## Compilation
If you are wondering what's different from mplayer2 and MPlayer you can read
more about the [changes][changes].
Compilation
-----------
Compiling with full features requires development files for several
external libraries. Mpv requires [meson](https://mesonbuild.com/index.html)
to build. Meson can be obtained from your distro or PyPI.
external libraries. Below is a list of some important requirements.
After creating your build directory (e.g. `meson setup build`), you can view a list
of all the build options via `meson configure build`. You could also just simply
look at the `meson_options.txt` file. Logs are stored in `meson-logs` within
your build directory.
The mpv build system uses *waf* but we don't store it in your source tree. The
script './bootstrap.py' will download the latest version of waf that was tested
with the build system.
Example:
For a list of the available build options use `./waf configure --help`. If
you think you have support for some feature installed but configure fails to
detect it, the file `build/config.log` may contain information about the
reasons for the failure.
meson setup build
meson compile -C build
meson install -C build
NOTE: To avoid cluttering the output with unreadable spam, `--help` only shows
one of the two switches for each option. If the option is autodetected by
default, the `--disable-***` switch is printed; if the option is disabled by
default, the `--enable-***` switch is printed. Either way, you can use
`--enable-***` or `--disable-**` regardless of what is printed by `--help`.
For libplacebo, meson can use a git check out as a subproject for a convenient
way to compile mpv if a sufficient libplacebo version is not easily available
in the build environment. It will be statically linked with mpv. Example:
To build the software you can use `./waf build`: the result of the compilation
will be located in `build/mpv`. You can use `./waf install` to install mpv
to the *prefix* after it is compiled.
mkdir -p subprojects
git clone https://code.videolan.org/videolan/libplacebo.git --depth=1 --recursive subprojects/libplacebo
NOTE: Using the old build system (with `./old-configure`) should still work,
but will be removed in a future version of mpv.
Essential dependencies (incomplete list):
- gcc or clang
- X development headers (xlib, xrandr, xext, xscrnsaver, xpresent, libvdpau,
libGL, GLX, EGL, xv, ...)
- Audio output development headers (libasound/ALSA, pulseaudio)
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavfilter
and either libswresample or libavresample)
- libplacebo
- zlib
- iconv (normally provided by the system libc)
- libass (OSD, OSC, text subtitles)
- Lua (optional, required for the OSC pseudo-GUI and youtube-dl integration)
- libjpeg (optional, used for screenshots only)
- uchardet (optional, for subtitle charset detection)
- nvdec and vaapi libraries for hardware decoding on Linux (optional)
- X development headers (xlib, X extensions, libvdpau, libGL, libXv, ...)
- Audio output development headers (libasound, pulseaudio)
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavresample)
At least FFmpeg 2.1.4 or Libav 10 is required.
- libjpeg (for screenshots)
- Lua (strictly speaking optional, but required for the OSC pseudo-GUI)
Libass dependencies (when building libass):
Libass dependencies:
- gcc or clang, nasm on x86 and x86_64
- gcc or clang, yasm on x86 and x86_64
- fribidi, freetype, fontconfig development headers (for libass)
- harfbuzz (required for correct rendering of combining characters, particularly
for correct rendering of non-English text on macOS, and Arabic/Indic scripts on
any platform)
FFmpeg dependencies (when building FFmpeg):
FFmpeg dependencies:
- gcc or clang, nasm on x86 and x86_64
- OpenSSL or GnuTLS (have to be explicitly enabled when compiling FFmpeg)
- libx264/libmp3lame/libfdk-aac if you want to use encoding (have to be
explicitly enabled when compiling FFmpeg)
- For native DASH playback, FFmpeg needs to be built with --enable-libxml2
(although there are security implications, and DASH support has lots of bugs).
- AV1 decoding support requires dav1d.
- For good nvidia support on Linux, make sure nv-codec-headers is installed
and can be found by configure.
- gcc or clang, yasm on x86 and x86_64
- OpenSSL (has to be explicitly enabled when compiling ffmpeg)
- libx264/libmp3lame/libfdk-aac if you want to use encoding (has to be
explicitly enabled when compiling ffmpeg)
- Libav also works, but some features will not work. (See section below.)
Most of the above libraries are available in suitable versions on normal
Linux distributions. For ease of compiling the latest git master of everything,
you may wish to use the separately available build wrapper ([mpv-build][mpv-build])
which first compiles FFmpeg libraries and libass, and then compiles the player
statically linked against those.
Linux distributions. However FFmpeg is an exception (distro versions may be
too old to work at all or work well). For that reason you may want to use
the separately available build wrapper ([mpv-build][mpv-build]) that first compiles FFmpeg
libraries and libass, and then compiles the player statically linked against
those.
If you want to build a Windows binary, see [Windows compilation][windows_compilation].
If you are running Mac OSX and using homebrew we provide [homebrew-mpv][homebrew-mpv], an up
to date formula that compiles mpv with sensible dependencies and defaults for
OSX.
FFmpeg vs. Libav
----------------
Generally, mpv should work with the latest release as well as the git version
of both FFmpeg and Libav. But FFmpeg is preferred, and some mpv features work
with FFmpeg only. See the [wiki article][ffmpeg_vs_libav] about the issue.
## Release cycle
Release cycle
-------------
Once or twice a year, a release is cut off from the current development state
and is assigned a 0.X.0 version number. No further maintenance is done, except
in the event of security issues.
Every few months, a new release is cut off of the master branch and is assigned
a 0.X.0 version number.
The goal of releases is to make Linux distributions happy. Linux distributions
are also expected to apply their own patches in case of bugs.
As part of the maintenance process, minor releases are made, which are assigned
0.X.Y version numbers. Minor releases contain bug fixes only. They never merge
the master branch, and no features are added to it. Only the latest release is
maintained.
The goal of releases is to provide stability and an unchanged base for the sake
of Linux distributions. If you want the newest features, just use the master
branch, which is stable most of the time, except sometimes, when it's not.
Releases other than the latest release are unsupported and unmaintained.
See the [release policy document][release-policy] for more information.
## Bug reports
Bug reports
-----------
Please use the [issue tracker][issue-tracker] provided by GitHub to send us bug
reports or feature requests. Follow the template's instructions or the issue
will likely be ignored or closed as invalid.
reports or feature requests.
Questions can be asked in the [discussions][discussions] or on IRC (see
[Contact](#Contact) below).
## Contributing
Please read [contribute.md][contribute.md].
Contributing
------------
For small changes you can just send us pull requests through GitHub. For bigger
changes come and talk to us on IRC before you start working on them. It will
make code review easier for both parties later on.
You can check [the wiki](https://github.com/mpv-player/mpv/wiki/Stuff-to-do)
or the [issue tracker](https://github.com/mpv-player/mpv/issues?q=is%3Aopen+is%3Aissue+label%3Ameta%3Afeature-request)
for ideas on what you could contribute with.
Contact
-------
## License
Most activity happens on the IRC channel and the github issue tracker. The
mailing lists are mostly unused.
GPLv2 "or later" by default, LGPLv2.1 "or later" with `-Dgpl=false`.
See [details.](https://github.com/mpv-player/mpv/blob/master/Copyright)
- **Github issue tracker**: [issue tracker][issue-tracker] (report bugs here)
- **User IRC Channel**: `#mpv-player` on `irc.freenode.net`
- **Developer IRC Channel**: `#mpv-player-dev` on `irc.freenode.net`
- **Users Mailing List**: `mpv-users@googlegroups.com` ([Archive / Subscribe][mpv-users]).
- **Devel Mailing List**: `mpv-devel@googlegroups.com` ([Archive / Subscribe][mpv-devel])
## History
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`. Use
only if discretion is required.
This software is based on the MPlayer project. Before mpv existed as a project,
the code base was briefly developed under the mplayer2 project. For details,
see the [FAQ][FAQ].
## Contact
Most activity happens on the IRC channel and the GitHub issue tracker.
- **GitHub issue tracker**: [issue tracker][issue-tracker] (report bugs here)
- **Discussions**: [discussions][discussions]
- **User IRC Channel**: `#mpv` on `irc.libera.chat`
- **Developer IRC Channel**: `#mpv-devel` on `irc.libera.chat`
[FAQ]: https://github.com/mpv-player/mpv/wiki/FAQ
[releases]: https://github.com/mpv-player/mpv/releases
[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/changes.rst
[mpv-build]: https://github.com/mpv-player/mpv-build
[homebrew-mpv]: https://github.com/mpv-player/homebrew-mpv
[issue-tracker]: https://github.com/mpv-player/mpv/issues
[discussions]: https://github.com/mpv-player/mpv/discussions
[mpv-users]: https://groups.google.com/forum/?hl=en#!forum/mpv-users
[mpv-devel]: https://groups.google.com/forum/?hl=en#!forum/mpv-devel
[ffmpeg_vs_libav]: https://github.com/mpv-player/mpv/wiki/FFmpeg-versus-Libav
[release-policy]: https://github.com/mpv-player/mpv/blob/master/DOCS/release-policy.md
[windows_compilation]: https://github.com/mpv-player/mpv/blob/master/DOCS/compile-windows.md
[interface-changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/interface-changes.rst
[api-changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/client-api-changes.rst
[restore-old-bindings]: https://github.com/mpv-player/mpv/blob/master/etc/restore-old-bindings.conf
[restore-osc-bindings]: https://github.com/mpv-player/mpv/blob/master/etc/restore-osc-bindings.conf
[contribute.md]: https://github.com/mpv-player/mpv/blob/master/DOCS/contribute.md
+62 -134
View File
@@ -1,139 +1,67 @@
Release 0.41.0
==============
Release 0.7.0
=============
We are excited to announce the release of mpv 0.41.0.
Changes
-------
Key highlights:
- Buffer partial log messages in the client API (the client API will now only
pass full log messages to clients).
- Remove ncurses/terminfo/termcap support (it was disabled by default and
replaced by new code since v0.6.0).
- Enable cdda:// support by default again (it was disabled since v0.6.0).
- Cascade-load input.conf (if there are several input.confs in the set of valid
config paths, load them all).
- Draw the OSD twice in 3D mode (this fixes subtitles display in 3D mode).
- Make wasapi the default AO on Windows again since many of its problems have
been solved.
- Use "site-functions" subdir to install the zsh completion script instead of
the Debian-specific "vendor-completions" (also provide the --zshdir waf
configure option for changing this value).
- Improve synchronization between the Cocoa GUI and the player (this fixes some
long standing deadlock issues on Mac OS X).
- Remove --fs-missioncontrol option (only relevant to Mac OS X).
* The libplacebo based `gpu-next` is now the default, over `gpu`
* Vulkan hardware decoding is preferred over other APIs
* New context_menu.lua script for right-click context menus
* AAudio backend for modern, HNI-free audio output on Android
* Improved default color management for gpu-next, and handling on Wayland
* Color representation protocol support for Wayland
* Tablet input support for Wayland
* Clipboard writing support for Wayland and a clipboard backend for X11
* Ambient light support on Linux (using sysfs ALS)
* Built-in helpers to register mpv as a media app on Windows
New features
------------
This release requires FFmpeg 6.1 or newer and libplacebo 6.338.2 or newer.
- Enable pitch correction by default when playing at higher speeds (this can be
controlled with the --audio-pitch-correction option).
- Open stream and demuxer asynchronously (this should avoid having the player
get blocked on network streams).
- Add cache-buffering-state property for querying the cache fill status until
the player unpauses.
- Add support for listing and selecting the audio device (note that it is not
implemented for all AOs, see the --audio-device option for more information).
- Add support for a JSON-based IPC mechanism (note that this is not currently
supported on Windows, see the JSON IPC section in the manpage for more
information).
- Add Lua utility function for starting processes (see utils.subprocess() in the
manpage).
- Add Lua utility function for parsing JSON (see utils.parse_json() in the
manpage).
- Add field-dominance property (see --field-dominance option).
- Add video-rotate property (see --video-rotate option).
- Add playback-abort property for querying whether playback is stopped or is to
be stopped.
- Add cursor-autohide property (see --cursor-autohide option).
- Add vo-configured property for querying whether a window is created.
- Add support for dxva2 hardware acceleration on Windows.
- Drop libquvi support (this has been replaced by a built-in Lua script that
invokes the youtube-dl tool, which needs to be installed, see the --ytdl
option).
- Add support for loading chapters from an external file (see the
--chapters-file option).
- Add window-minimized property for querying whether the window is minimized
(works for X11 only).
- Make it possible to configure the OSC seekbar style (see the "seekbarstyle"
OSC option).
- Add support for libmpv on Mac OS X (it used to be broken, now it's fully
functional and also provides support for embedding the mpv window inside a
Cocoa/Qt application).
- Try to use the audio channel map reported by ALSA in the alsa AO.
- Add option to disable text OSD rendering completely (useful for working around
certain fontconfig issues, see the --use-text-osd option).
# Features
## New
- clipboard-wayland: support clipboard writing
- wayland: add support for wp-color-representation-v1
- wayland: tablet input support
- vo_gpu_next: add support for blend-subtitles=video
- meson: add mpv-register and mpv-unregister helpers on Windows
- context_menu.lua: add this script
- select.lua: add edit-config-file and edit-input-conf
- osc.lua: add indicator for buffering/loading
- osdep/linux-als: support 'ambient-light' property on Linux
- clipboard-x11: add x11 clipboard backend
- ao/aaudio: implement native AAudio backend for Android
## Changed
- vd_lavc: prefer Vulkan hwdec when available
- vd_lavc: prefer non-copy hwdec before falling back to -copy variant
- vo: move vo_mediacodec_embed to not be the default on Android
- sub/osd_libass: don't rerender OSD if not changed
- vo: prefer vo_gpu_next over vo_gpu by default
- vo_gpu_next: respect ICC profile color space over any metadata
- vo_gpu_next: linearize sRGB as a pure 2.2 power function
- meson: warn if building with SDL2 due to known problems
- osxbundle: make bundle category configurable and default to video
- ao_pipewire: avoid setting any media.role by default
# Options and Commands
## Added
- sub: add control for libass caching options (glyph-limit, bitmap-max-size)
- vo: add options to control background tile appearance (transparency)
- command: add default and forced flags to the track add commands
- vo_gpu_next: add options to control subtitle peak for HDR output
- video/out/d3d11: add d3d11 composition mode support
- vd_lavc: add --hwdec-threads
- stream_bluray: add --bluray-angle
- vo_gpu_next: add options to control output colorspace metadata more precisely
- sub: make --sub-fix-timing configurable
- vo_gpu_next: add --hdr-reference-white
- audio/out: add --audio-set-media-role
## Changed
- options: revert --prefetch-playlist default back to 'no'
- vo_gpu_next: change --target-colorspace-hint to 'auto' by default
- options: handle runtime --wid change
- options: reduce swapchain-depth to 2 by default
- screenshot: add osd and scaled flags to screenshot commands
# Fixes and Minor Enhancements
- vo_kitty: add auto-multiplexer-passthrough option
- vd_lavc: enable FFv1 hwaccel by default
- clipboard-wayland: prevent reading from hung up fd
- demux_mkv: fix compilation after deprecated definitions removal
- filters: handle flipping video if displaymatrix indicates so
- player/scripting: fix race condition when destroying clients
- {osd,msg}: use PU codepoints for escape codes instead of invalid UTF-8
- vo_dmabuf_wayland: only load needed hardware decoding drivers
- video/image_writer: tag accurate bit depth
- demux_lavf: fix unconstrained cache size with wrapped AVFrame packets
- libarchive: fix reading name of certain UTF-8 files
- sub/sd_lavc: fix decoding with libaribb24
- ao_avfoundation: fix memory leak
- osc.lua: fix volume icon not updating while paused
- context_wayland: implement target_csp for wayland
- vo_gpu: fix target colorspace for redrawn frames
- vo_dmabuf_wayland: don't set HDR metadata on SDR transfers
- vo_gpu_next: don't do partial updates on hint luminance
- sub/ass_mp: add missing padding for ass packer
- stream_dvb: allow to enforce DVB-S/T for old zap format channels.conf
- demux_libarchive: fix reading archives with '%' in stream URL path
- vo_gpu_next: allow UINT upload if no other format is supported
- ytdl_hook.lua: fix incorrect default format used with yt-dlp
- vo_gpu_next: allow unsetting LUTs
- stream_bluray: use bd_get_main_title() to get main title
- vo_gpu_next: when tone-mapping, set better maxCLL value
- stream_libarchive: seek source stream to 0 before probing
- path-unix: support ~~desktop path expansion
- ytdl_hook.lua: don't crash if playlist entries don't have an usable URL
- mac/vulkan: fix frame not displayed when paused
- mac/common: render first frame on init if possible
- video/out/w32_common: support --wid=0
- demux_mkv: map and expose hearing/visual impaired flags
- player/misc: show percentage progress for --stream-dump
- command: fix null dereference for invalid command in input-commands
- cplugin: fix missing init of pfn_mpv_get_time_ns
- vo_dmabuf_wayland: actually reuse OSD buffers
- mp_image: add support for AVAlphaMode
- vo_gpu_next: add --border-background=blur and --background-blur-radius
- demux/cue: fix crash when there are no tracks
- vf_format: add some basic HDR10 metadata
- vo/context_android: fix surface tearing on resize
- meson: remove redundant 'sdl2' option
- mac/common: fix window position on multi monitor setups
- vo_gpu_next: limit min_luma to 1000:1 contrast ratio in SDR mode
- ao_pipewire: fix some incorrect channel mappings
- wayland: correct geometry handling for rotated outputs
- demux: clear packet pool when upper memory limit is lowered
- mp_image: add ycgco-{re,ro} support
- wayland: convert luminance values to libplacebo space
- vo: trigger manual redraws at most at slightly over display fps
- osxbundle: add new macOS 26 compatible App icon
- wayland: support color-management-v1 version 2
This listing is not complete. Check DOCS/client-api-changes.rst for a history
of changes to the client API, and DOCS/interface-changes.rst for a history
of changes to other user-visible interfaces.
A complete changelog can be seen by running `git log v0.40.0..v0.41.0`
in the git repository or by visiting
<https://github.com/mpv-player/mpv/compare/v0.40.0...v0.41.0>.
This listing is not complete. There are many more bug fixes and changes. The
complete change log can be viewed by running ``git log 7759c18..9479daa`` in
the git repository.
-67
View File
@@ -1,67 +0,0 @@
#!/usr/bin/env python3
"""
Wrapper around docutils rst2x commands,
converting their dependency files to a format understood by meson/ninja.
"""
#
# 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 os
import subprocess
import sys
def convert_depfile(output, depfile):
with open(depfile) as f:
deps = f.readlines()
with open(depfile, "w") as f:
f.write(os.path.abspath(output))
f.write(": \\\n")
for dep in deps:
dep = dep[:-1]
f.write("\t")
f.write(os.path.abspath(dep))
f.write(" \\\n")
def remove(path):
try:
os.remove(path)
except FileNotFoundError:
pass
argv = sys.argv[1:]
depfile = None
output = argv[-1]
for opt, optarg in zip(argv, argv[1:]):
if opt == "--record-dependencies":
depfile = optarg
try:
proc = subprocess.run(argv, check=True)
if depfile is not None:
convert_depfile(output, depfile)
except Exception:
remove(output)
if depfile is not None:
remove(depfile)
sys.exit(1)
sys.exit(proc.returncode)
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env python
import re
import os
import sys
import shutil
import subprocess
from functools import partial
sys_re = re.compile("^/System")
usr_re = re.compile("^/usr/lib/")
exe_re = re.compile("@executable_path")
def is_user_lib(objfile, libname):
return not sys_re.match(libname) and \
not usr_re.match(libname) and \
not exe_re.match(libname) and \
not "libobjc." in libname and \
not "libSystem." in libname and \
not "libc." in libname and \
not "libgcc." in libname and \
not os.path.basename(objfile) in libname
def otool(objfile):
command = "otool -L %s | grep -e '\t' | awk '{ print $1 }'" % objfile
output = subprocess.check_output(command, shell = True)
return filter(partial(is_user_lib, objfile), output.split())
def install_name_tool_change(old, new, objfile):
subprocess.call(["install_name_tool", "-change", old, new, objfile])
def install_name_tool_id(name, objfile):
subprocess.call(["install_name_tool", "-id", name, objfile])
def libraries(objfile, result = dict()):
libs_list = otool(objfile)
result[objfile] = set(libs_list)
for lib in libs_list:
if lib not in result:
libraries(lib, result)
return result
def leafs(libs_dict, processed = []):
result = []
processed = set(processed)
for objfile, libs in libs_dict.items():
if libs <= processed:
result.append(objfile)
return result
def lib_path(binary):
return os.path.join(os.path.dirname(binary), 'lib')
def lib_name(lib):
return os.path.join("@executable_path", "lib", os.path.basename(lib))
def process_libraries(libs_dict, binary, processed = []):
ls = leafs(libs_dict, processed)
diff = set(ls) - set(processed)
if diff == set([binary]):
return
for src in diff:
name = lib_name(src)
dst = os.path.join(lib_path(binary), os.path.basename(src))
shutil.copy(src, dst)
os.chmod(dst, 0o755)
install_name_tool_id(name, dst)
if src in libs_dict[binary]:
install_name_tool_change(src, name, binary)
for p in processed:
if p in libs_dict[src]:
install_name_tool_change(p, lib_name(p), dst)
process_libraries(libs_dict, binary, ls)
def main():
binary = os.path.abspath(sys.argv[1])
if not os.path.exists(lib_path(binary)):
os.makedirs(lib_path(binary))
libs = libraries(binary)
print(libs)
process_libraries(libs, binary)
if __name__ == "__main__":
main()
-313
View File
@@ -1,313 +0,0 @@
#!/usr/bin/env python3
import json
import os
import re
import shutil
import subprocess
import sys
from functools import partial
sys_re = re.compile("^/System")
usr_re = re.compile("^/usr/lib/")
exe_re = re.compile("@executable_path")
def is_user_lib(objfile, libname):
return not sys_re.match(libname) and \
not usr_re.match(libname) and \
not exe_re.match(libname) and \
"libobjc." not in libname and \
"libSystem." not in libname and \
"libc." not in libname and \
"libgcc." not in libname and \
os.path.basename(libname) != "Python" and \
os.path.basename(objfile) not in libname and \
"libswift" not in libname
def otool(objfile, rapths):
command = f"otool -L '{objfile}' | grep -e '\t' | awk '{{ print $1 }}'"
output = subprocess.check_output(command, shell=True, universal_newlines=True)
libs = set(filter(partial(is_user_lib, objfile), output.split()))
libs_resolved = set()
libs_relative = set()
for lib in libs:
lib_path = resolve_lib_path(objfile, lib, rapths)
libs_resolved.add(lib_path)
if lib_path != lib:
libs_relative.add(lib)
return libs_resolved, libs_relative
def get_rapths(objfile):
rpaths: list[str] = []
command = f"otool -l '{objfile}' | grep -A2 LC_RPATH | grep path"
path_re = re.compile(r"^\s*path (.*) \(offset \d*\)$")
try:
result = subprocess.check_output(command, shell=True, universal_newlines=True)
except Exception:
return rpaths
for line in result.splitlines():
match = path_re.search(line)
if match is None:
continue
line_clean = match.group(1).strip()
# resolve @loader_path
if line_clean.startswith("@loader_path/"):
line_clean = line_clean[len("@loader_path/"):]
line_clean = os.path.join(os.path.dirname(objfile), line_clean)
line_clean = os.path.normpath(line_clean)
rpaths.append(line_clean)
return rpaths
def get_rpaths_dev_tools(binary):
command = (
f"otool -l '{binary}' | grep -A2 LC_RPATH | grep path | "
'grep "Xcode\\|CommandLineTools"'
)
result = subprocess.check_output(command, shell = True, universal_newlines=True)
path_re = re.compile(r"^\s*path (.*) \(offset \d*\)$")
return [
match.group(1).strip()
for line in result.splitlines()
if (match := path_re.search(line)) is not None
]
def resolve_lib_path(objfile, lib, rapths):
if os.path.exists(lib):
return lib
if lib.startswith("@rpath/"):
lib = lib[len("@rpath/"):]
for rpath in rapths:
lib_path = os.path.join(rpath, lib)
if os.path.exists(lib_path):
return lib_path
elif lib.startswith("@loader_path/"):
lib = lib[len("@loader_path/"):]
lib_path = os.path.normpath(os.path.join(objfile, lib))
if os.path.exists(lib_path):
return lib_path
raise Exception("Could not resolve library: " + lib)
def check_vulkan_max_version(version):
try:
subprocess.check_output(
f"pkg-config vulkan --max-version={version}",
shell=True,
)
return True
except Exception:
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,
stderr=subprocess.DEVNULL,
).strip()
except Exception:
pass
return result
def install_name_tool_change(old, new, objfile):
subprocess.call(
["install_name_tool", "-change", old, new, objfile],
stderr=subprocess.DEVNULL,
)
def install_name_tool_id(name, objfile):
subprocess.call(
["install_name_tool", "-id", name, objfile],
stderr=subprocess.DEVNULL,
)
def install_name_tool_add_rpath(rpath, binary):
subprocess.call(["install_name_tool", "-add_rpath", rpath, binary])
def install_name_tool_delete_rpath(rpath, binary):
subprocess.call(["install_name_tool", "-delete_rpath", rpath, binary])
def libraries(objfile, result=None, result_relative=None, rapths=None):
if result is None:
result = {}
if result_relative is None:
result_relative = set()
if rapths is None:
rapths = []
rapths = get_rapths(objfile) + rapths
libs_list, libs_relative = otool(objfile, rapths)
result[objfile] = libs_list
result_relative |= libs_relative
for lib in libs_list:
if lib not in result:
libraries(lib, result, result_relative, rapths)
return result, result_relative
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))
def process_libraries(libs_dict, libs_dyn, binary):
libs_set = set(libs_dict)
# Remove binary from libs_set to prevent a duplicate of the binary being
# added to the libs directory.
libs_set.remove(binary)
for src in libs_set:
name = lib_name(src)
dst = os.path.join(lib_path(binary), os.path.basename(src))
shutil.copy(src, dst)
os.chmod(dst, 0o755)
install_name_tool_id(name, dst)
if src in libs_dict[binary]:
install_name_tool_change(src, name, binary)
for p in libs_set:
if p in libs_dict[src]:
install_name_tool_change(p, lib_name(p), dst)
for lib in libs_dyn:
install_name_tool_change(lib, lib_name(lib), dst)
for lib in libs_dyn:
install_name_tool_change(lib, lib_name(lib), binary)
def process_swift_libraries(binary):
swift_stdlib_tool = subprocess.check_output(
["xcrun", "--find", "swift-stdlib-tool"],
universal_newlines=True,
).strip()
# from xcode11 on the dynamic swift libs reside in a separate directory from
# the std one, might need versioned paths for future swift versions
swift_lib_path = os.path.join(swift_stdlib_tool, "../../lib/swift-5.0/macosx")
swift_lib_path = os.path.abspath(swift_lib_path)
command = [
swift_stdlib_tool, "--copy", "--platform", "macosx",
"--scan-executable", binary, "--destination", lib_path(binary),
]
if os.path.exists(swift_lib_path):
command.extend(["--source-libraries", swift_lib_path])
subprocess.check_output(command, universal_newlines=True)
print(">> setting additional rpath for swift libraries")
install_name_tool_add_rpath("@executable_path/lib", binary)
def process_vulkan_loader(binary, loader_name, loader_relative_folder, library_node):
# 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
loader_system_search_folders = [
os.path.join(os.path.expanduser("~"), ".config", loader_relative_folder),
os.path.join("/etc/xdg", loader_relative_folder),
os.path.join("/usr/local/etc", loader_relative_folder),
os.path.join("/etc", loader_relative_folder),
os.path.join(os.path.expanduser("~"), ".local/share", loader_relative_folder),
os.path.join("/usr/local/share", loader_relative_folder),
os.path.join("/usr/share/vulkan", loader_relative_folder),
os.path.join(get_homebrew_prefix(), "etc", loader_relative_folder),
os.path.join(get_homebrew_prefix(), "share", loader_relative_folder), # old location
]
loader_system_folder = ""
for loader_system_search_folder in loader_system_search_folders:
if os.path.exists(loader_system_search_folder):
loader_system_folder = loader_system_search_folder
break
if not loader_system_folder:
print(">>> could not find loader folder " + loader_relative_folder)
return
loader_bundle_folder = os.path.join(resources_path(binary), loader_relative_folder)
loader_system_path = os.path.join(loader_system_folder, loader_name)
loader_bundle_path = os.path.join(loader_bundle_folder, loader_name)
library_relative_folder = "../../../Frameworks/"
if not os.path.exists(loader_system_path):
print(">>> could not find loader " + loader_name)
return
if not os.path.exists(loader_bundle_folder):
os.makedirs(loader_bundle_folder)
loader_system_file = open(loader_system_path)
loader_json_data = json.load(loader_system_file)
library_path = loader_json_data[library_node]["library_path"]
library_system_path = os.path.join(loader_system_folder, library_path)
if not os.path.exists(library_system_path):
print(">>> could not find loader library " + library_system_path)
return
print(">>> modifying and writing loader json " + loader_name)
loader_bundle_file = open(loader_bundle_path, "w")
loader_library_name = os.path.basename(library_system_path)
library_path = os.path.join(library_relative_folder, loader_library_name)
loader_json_data[library_node]["library_path"] = library_path
json.dump(loader_json_data, loader_bundle_file, indent=4)
print(">>> copying loader library " + loader_library_name)
framework_bundle_folder = os.path.join(
loader_bundle_folder, library_relative_folder,
)
if not os.path.exists(framework_bundle_folder):
os.makedirs(framework_bundle_folder)
library_target_path = os.path.join(framework_bundle_folder, loader_library_name)
shutil.copy(library_system_path, library_target_path)
def remove_dev_tools_rapths(binary):
for path in get_rpaths_dev_tools(binary):
install_name_tool_delete_rpath(path, binary)
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")
libs, libs_rel = libraries(binary)
print(">> copying and processing all linked libraries")
process_libraries(libs, libs_rel, binary)
print(">> removing rpath definitions towards dev tools")
remove_dev_tools_rapths(binary)
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__":
process(sys.argv[1])
+24
View File
@@ -0,0 +1,24 @@
#! /usr/bin/env perl
use strict;
use warnings;
# Convert the contents of a file into a C string constant.
# Note that the compiler will implicitly add an extra 0 byte at the end
# of every string, so code using the string may need to remove that to get
# the exact contents of the original file.
# FIXME: why not a char array?
# treat only alphanumeric and not-" punctuation as safe
my $unsafe_chars = qr{[^][A-Za-z0-9!#%&'()*+,./:;<=>?^_{|}~ -]};
for my $file (@ARGV) {
open my $fh, '<:raw', $file or next;
print "/* Generated from $file */\n";
while (<$fh>) {
# replace unsafe chars with their equivalent octal escapes
s/($unsafe_chars)/\\@{[sprintf '%03o', ord($1)]}/gos;
print "\"$_\"\n"
}
close $fh;
}
-45
View File
@@ -1,45 +0,0 @@
#!/usr/bin/env python3
# Convert the contents of a file into a C string constant.
# Note that the compiler will implicitly add an extra 0 byte at the end
# of every string, so code using the string may need to remove that to get
# the exact contents of the original file.
#
# 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 os
import sys
def file2string(infilename, infile, outfile):
outfile.write(f"// Generated from {infilename}\n\n")
conv = [f"\\{c:03o}" for c in range(256)]
safe_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" \
"0123456789!#%&'()*+,-./:;<=>[]^_{|}~ "
for c in safe_chars:
conv[ord(c)] = c
for c, esc in [("\n", "n"), ("\t", "t"), ("\\", "\\"), ('"', '"')]:
conv[ord(c)] = "\\" + esc
for line in infile:
outfile.write('"' + "".join(conv[c] for c in line) + '"\n')
if __name__ == "__main__":
with open(sys.argv[1], "rb") as infile, open(sys.argv[2], "w") as outfile:
file2string(os.path.relpath(sys.argv[1], sys.argv[3]), infile, outfile)
-92
View File
@@ -1,92 +0,0 @@
#!/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
import textwrap
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 f.name != "example.txt":
timestamp = check_output([git, "log", "--format=%ct", "-n", "1", "--",
f], encoding="UTF-8")
if timestamp:
content = f.read_text()
files.append(content)
else:
print(f"Skipping file not tracked by git: {f.name}")
# Sort the changes by "severity", which roughly corresponds to
# alphabetical order by accident (e.g. remove > deprecate > change > add)
for file in reversed(sorted(files)):
for line in file.splitlines():
line = textwrap.fill(line.rstrip(), width=80,
initial_indent=" - ",
subsequent_indent=" ")
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 = None
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 not major_version:
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) 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 ---"
found = False
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)
found = True
if not found:
print(f"Nothing changed! The following line was not found:\n{ver_line}")
-50
View File
@@ -1,50 +0,0 @@
#!/usr/bin/env python3
# Modify X-KDE-Protocols in the mpv.desktop file based on output from
# mpv --list-protocols.
#
# 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 sys
if __name__ == "__main__":
with open(sys.argv[1], encoding="UTF-8") as f:
next(f)
mpv_desktop = dict([line.split("=", 1) for line in f])
if not mpv_desktop["X-KDE-Protocols"]:
raise ValueError("Missing X-KDE-Protocols entry in mpv.desktop file")
with open(sys.argv[2], encoding="UTF-8") as mpv_protocols_f:
mpv_protocols = {
line.strip(" :/")
for line in mpv_protocols_f.read().splitlines()
if "://" in line
}
if len(mpv_protocols) == 0:
raise ValueError("Unable to parse any protocols from mpv '--list-protocols'")
protocol_list = set(mpv_desktop["X-KDE-Protocols"].strip().split(","))
compatible_protocols = sorted(mpv_protocols & protocol_list)
mpv_desktop["X-KDE-Protocols"] = ",".join(compatible_protocols) + "\n"
with open(sys.argv[3], "w", encoding="UTF-8") as f:
f.write("[Desktop Entry]" + "\n")
for key, value in mpv_desktop.items():
f.write(f"{key}={value}")
-9
View File
@@ -1,9 +0,0 @@
#!/bin/sh
# This script is expected to be called as TOOLS/gen-osd-font.sh (it will access
# TOOLS/mpv-osd-symbols.sfdir), and it will write sub/osd_font.otf.
# Needs fontforge with python scripting
fontforge -lang=py -c 'f=open(argv[1]); f.generate(argv[2])' \
TOOLS/mpv-osd-symbols.sfdir sub/osd_font.otf
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
# This script is expected to be called as TOOLS/gen-x11-icon.sh (it will access
# etc/mpv-icon...), and it will write video/out/x11_icon.bin.
conv() {
echo
identify -format "icon: %w %h" "$1"
convert "$1" -depth 8 rgba:-
}
(echo "# File generated by gen-x11-icon.sh" ;
conv etc/mpv-icon-8bit-16x16.png ;
conv etc/mpv-icon-8bit-32x32.png ;
conv etc/mpv-icon-8bit-64x64.png) | gzip -c > video/out/x11_icon.bin
+8 -8
View File
@@ -22,7 +22,7 @@
testfun()
{
$ILDETECT_MPV "$@" \
--vf-add=lavfi="[idet]" --msg-level=ffmpeg=v \
--vf-add=lavfi="[idet]" --msg-level ffmpeg=v \
--o= --vo=null --no-audio --untimed \
$ILDETECT_MPVFLAGS \
| { if [ -n "$ILDETECT_QUIET" ]; then cat; else tee /dev/stderr; fi } \
@@ -47,7 +47,7 @@ judge()
progressive=$((progressive + progressive1))
undetermined=$((undetermined + undetermined1))
done <<EOF
$(testfun "$@" | sed 's/:/: /g')
$(testfun "$@")
EOF
interlaced=$((bff + tff))
@@ -95,18 +95,18 @@ case "$verdict" in
exit 0
;;
interlaced-tff)
judge "$@" --vf-clr --vf-pre=lavfi=\[setfield=tff\],pullup
judge "$@" --vf-clr --vf-pre=pullup --field-dominance=top
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=tff\],pullup
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=tff\],yadif
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=top
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 2
@@ -114,18 +114,18 @@ case "$verdict" in
esac
;;
interlaced-bff)
judge "$@" --vf-clr --vf-pre=lavfi=\[setfield=bff\],pullup
judge "$@" --vf-clr --vf-pre=pullup --field-dominance=bottom
case "$verdict" in
progressive)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=bff\],pullup
$ILDETECT_MPV "$@" --vf-pre=pullup --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 1
;;
*)
[ -n "$ILDETECT_DRY_RUN" ] || \
$ILDETECT_MPV "$@" --vf-pre=lavfi=\[setfield=bff\],yadif
$ILDETECT_MPV "$@" --vf-pre=yadif --field-dominance=bottom
r=$?
[ $r -eq 0 ] || exit $((r | 16))
exit 2
+30
View File
@@ -0,0 +1,30 @@
use 5.008;
use strict;
use warnings;
# ABSTRACT: Module collection to parse Matroska files.
package Parse::Matroska;
=head1 DESCRIPTION
C<use>s L<Parse::Matroska::Reader>. See the documentation
of the modules mentioned in L</"SEE ALSO"> for more information
in how to use this module.
It's intended for this module to contain high-level interfaces
to the other modules in the distribution.
=head1 SOURCE CODE
L<https://github.com/Kovensky/Parse-Matroska>
=head1 SEE ALSO
L<Parse::Matroska::Reader>, L<Parse::Matroska::Element>,
L<Parse::Matroska::Definitions>.
=cut
use Parse::Matroska::Reader;
1;
+357
View File
@@ -0,0 +1,357 @@
use 5.008;
use strict;
use warnings;
# ABSTRACT: internal EBML grammar definitions
package Parse::Matroska::Definitions;
use Parse::Matroska::Utils qw{uniq uncamelize};
use Exporter;
our @ISA = qw{Exporter};
our @EXPORT_OK = qw{elem_by_hexid %EBML_DEFINITION %MATROSKA_DEFINITION};
=head1 SYNOPSIS
use Parse::Matroska::Definitions qw{elem_by_hexid};
my $ebml_id = elem_by_hexid('1a45dfa3');
print "EBML ID $ebml_id->{elid}'s name: $ebml_id->{name}";
=head1 DESCRIPTION
Contains the definition of the EBML grammar as expected in
Matroska files. This module is meant mostly for internal use.
As this was extended from a script in mpv-player, some data
generated is apparently useless for regular module users
but is still relevant to the mpv-player script. Such data
is annotated as being for mpv compatibility.
=head1 NOTE
The API of this module is not yet considered stable.
=head1 GLOBALS
These global variables are considered B<immutable>.
=head2 @Parse::Matroska::Definitions::global_elem_list
A global list of known matroska elements. Useful for
mpv's matroska script, used for generating C headers
that parse matroska.
=head2 %Parse::Matroska::Definitions::global_elem_dict
A global hash of known matroska elements. Used internally
by L</elem_by_hexid($id)>.
=cut
@Parse::Matroska::Definitions::global_elem_list = ();
%Parse::Matroska::Definitions::global_elem_dict = ();
=head2 %EBML_DEFINITION
Optionally-importable hash of known EBML IDs belonging
to the EBML generic grammar.
=head2 %MATROSKA_DEFINITION
Optionally-importable hash of known EBML IDs belonging
to the Matroska-specific grammar.
=cut
our %EBML_DEFINITION = define_ebml();
our %MATROSKA_DEFINITION = define_matroska();
=method elem_by_hexid($id)
Returns an EBML Element Definition corresponding to the provided
hexadecimal string. Returns C<undef> if the element is unknown.
=cut
sub elem_by_hexid {
my ($elid) = @_;
return $Parse::Matroska::Definitions::global_elem_dict{$elid};
}
################################################
### Helper functions for document definition ###
################################################
# used by elem when setting the 'valname' key
use constant TYPE_MAP => {
uint => 'uint64_t',
str => 'struct bstr',
binary => 'struct bstr',
ebml_id => 'uint32_t',
float => 'double',
sint => 'int64_t',
};
# this will be localized to "MATROSKA" or "EBML" on the elem declarations
our $ELEM_DEFINE_TYPE = undef;
=method elem($name,$elid,$valtype)
NOTE: never call this function yourself; it changes data structures
that are considered immutable outside of this package.
Internal API function that generates the EBML Element Definitions.
This API function returns an array which first element is C<$elid>
and the second is a generated hash. The generated hash is stored
in the @global_elem_list and %global_elem_dict.
The generated hash contains:
=for :list
= name
The EBML Element's name, given through C<$name>.
= elid
The EBML Element's hex id, given through C<$elid>. Used for lookups by L</elem_by_hexid($id)>.
= valtype
The EBML Element's type, given through C<$valtype>, except when C<$valtype> is an arrayref.
= multiple
If C<$name> ends with a C<*>, this is set as true and strips the C<*> from L</name>. Used to
mark elements that may be repeated.
= subelements
An arrayref of elements that may be children of this element, given through C<$valtype> if it
is an arrayref. Sets L</valtype> to C<sub> if there are subelements.
= subids
An arrayref listing all the L</elid>s of subelements, C<uniq>ified.
The following elements are for mpv compatibility:
=for :list
= definename
Name used for generating C #defines.
= fieldname
Name used for generating C struct fields.
= structname
Name used for generating C struct names.
= ebmltype
A pre-#defined constant to describe the element's type.
= valname
Typename used when declaring a struct field referring to this element.
=cut
sub elem {
my %e = (name => shift, elid => shift, valtype => shift);
# strip * from name, set 'multiple' if there was one
$e{multiple} = scalar $e{name} =~ s/\*$//;
# ELEM_DEFINE_TYPE is either MATROSKA or EBML
$e{definename} = "${ELEM_DEFINE_TYPE}_ID_".uc($e{name});
$e{fieldname} = uncamelize $e{name};
$e{structname} = "ebml_$e{fieldname}";
if (ref $e{valtype} eq 'HASH') {
$e{subelements} = $e{valtype};
$e{subids} = uniq map { $_->{elid} } values %{$e{subelements}};
$e{valtype} = 'sub';
$e{ebmltype} = 'EBML_TYPE_SUBELEMENTS';
$e{valname} = "struct $e{structname}";
} else {
$e{ebmltype} = "EBML_TYPE_\U$e{valtype}";
die "Unrecognized value type $e{valtype}" unless
defined ($e{valname} = TYPE_MAP->{$e{valtype}});
}
my $e = \%e;
push @Parse::Matroska::Definitions::global_elem_list, $e;
$Parse::Matroska::Definitions::global_elem_dict{$e{elid}} = $e;
return ($e{elid}, $e);
}
#############################################
### EBML and Matroska document definitons ###
#############################################
=method define_ebml
Internal function that defines the EBML generic grammar.
Must not be called from outside the package.
=cut
sub define_ebml {
local $ELEM_DEFINE_TYPE = 'EBML';
return (
elem('EBML', '1a45dfa3', {
elem('EBMLVersion', '4286', 'uint'),
elem('EBMLReadVersion', '42f7', 'uint'),
elem('EBMLMaxIDLength', '42f2', 'uint'),
elem('EBMLMaxSizeLength', '42f3', 'uint'),
elem('DocType', '4282', 'str'),
elem('DocTypeVersion', '4287', 'uint'),
elem('DocTypeReadVersion', '4285', 'uint'),
}),
elem('CRC32', 'bf', 'binary'),
elem('Void', 'ec', 'binary'),
);
}
=method define_matroska
Internal function that defines the Matroska-specific EBML grammar.
Must not be called from outside the package.
=cut
sub define_matroska {
local $ELEM_DEFINE_TYPE = 'MATROSKA';
return (
elem('Segment', '18538067', {
elem('SeekHead*', '114d9b74', {
elem('Seek*', '4dbb', {
elem('SeekID', '53ab', 'ebml_id'),
elem('SeekPosition', '53ac', 'uint'),
}),
}),
elem('Info*', '1549a966', {
elem('SegmentUID', '73a4', 'binary'),
elem('PrevUID', '3cb923', 'binary'),
elem('NextUID', '3eb923', 'binary'),
elem('TimecodeScale', '2ad7b1', 'uint'),
elem('DateUTC', '4461', 'sint'),
elem('Title', '7ba9', 'str'),
elem('MuxingApp', '4d80', 'str'),
elem('WritingApp', '5741', 'str'),
elem('Duration', '4489', 'float'),
}),
elem('Cluster*', '1f43b675', {
elem('Timecode', 'e7', 'uint'),
elem('BlockGroup*', 'a0', {
elem('Block', 'a1', 'binary'),
elem('BlockDuration', '9b', 'uint'),
elem('ReferenceBlock*', 'fb', 'sint'),
elem('DiscardPadding', '75A2', 'sint'),
}),
elem('SimpleBlock*', 'a3', 'binary'),
}),
elem('Tracks*', '1654ae6b', {
elem('TrackEntry*', 'ae', {
elem('TrackNumber', 'd7', 'uint'),
elem('TrackUID', '73c5', 'uint'),
elem('TrackType', '83', 'uint'),
elem('FlagEnabled', 'b9', 'uint'),
elem('FlagDefault', '88', 'uint'),
elem('FlagForced', '55aa', 'uint'),
elem('FlagLacing', '9c', 'uint'),
elem('MinCache', '6de7', 'uint'),
elem('MaxCache', '6df8', 'uint'),
elem('DefaultDuration', '23e383', 'uint'),
elem('TrackTimecodeScale', '23314f', 'float'),
elem('MaxBlockAdditionID', '55ee', 'uint'),
elem('Name', '536e', 'str'),
elem('Language', '22b59c', 'str'),
elem('CodecID', '86', 'str'),
elem('CodecPrivate', '63a2', 'binary'),
elem('CodecName', '258688', 'str'),
elem('CodecDecodeAll', 'aa', 'uint'),
elem('CodecDelay', '56AA', 'uint'),
elem('SeekPreRoll', '56BB', 'uint'),
elem('Video', 'e0', {
elem('FlagInterlaced', '9a', 'uint'),
elem('PixelWidth', 'b0', 'uint'),
elem('PixelHeight', 'ba', 'uint'),
elem('DisplayWidth', '54b0', 'uint'),
elem('DisplayHeight', '54ba', 'uint'),
elem('DisplayUnit', '54b2', 'uint'),
elem('FrameRate', '2383e3', 'float'),
elem('ColourSpace', '2eb524', 'binary'),
elem('StereoMode', '53b8', 'uint'),
}),
elem('Audio', 'e1', {
elem('SamplingFrequency', 'b5', 'float'),
elem('OutputSamplingFrequency', '78b5', 'float'),
elem('Channels', '9f', 'uint'),
elem('BitDepth', '6264', 'uint'),
}),
elem('ContentEncodings', '6d80', {
elem('ContentEncoding*', '6240', {
elem('ContentEncodingOrder', '5031', 'uint'),
elem('ContentEncodingScope', '5032', 'uint'),
elem('ContentEncodingType', '5033', 'uint'),
elem('ContentCompression', '5034', {
elem('ContentCompAlgo', '4254', 'uint'),
elem('ContentCompSettings', '4255', 'binary'),
}),
}),
}),
}),
}),
elem('Cues', '1c53bb6b', {
elem('CuePoint*', 'bb', {
elem('CueTime', 'b3', 'uint'),
elem('CueTrackPositions*', 'b7', {
elem('CueTrack', 'f7', 'uint'),
elem('CueClusterPosition', 'f1', 'uint'),
elem('CueRelativePosition','f0', 'uint'),
elem('CueDuration', 'b2', 'uint'),
}),
}),
}),
elem('Attachments', '1941a469', {
elem('AttachedFile*', '61a7', {
elem('FileDescription', '467e', 'str'),
elem('FileName', '466e', 'str'),
elem('FileMimeType', '4660', 'str'),
elem('FileData', '465c', 'binary'),
elem('FileUID', '46ae', 'uint'),
}),
}),
elem('Chapters', '1043a770', {
elem('EditionEntry*', '45b9', {
elem('EditionUID', '45bc', 'uint'),
elem('EditionFlagHidden', '45bd', 'uint'),
elem('EditionFlagDefault', '45db', 'uint'),
elem('EditionFlagOrdered', '45dd', 'uint'),
elem('ChapterAtom*', 'b6', {
elem('ChapterUID', '73c4', 'uint'),
elem('ChapterTimeStart', '91', 'uint'),
elem('ChapterTimeEnd', '92', 'uint'),
elem('ChapterFlagHidden', '98', 'uint'),
elem('ChapterFlagEnabled', '4598', 'uint'),
elem('ChapterSegmentUID', '6e67', 'binary'),
elem('ChapterSegmentEditionUID', '6ebc', 'uint'),
elem('ChapterDisplay*', '80', {
elem('ChapString', '85', 'str'),
elem('ChapLanguage*', '437c', 'str'),
elem('ChapCountry*', '437e', 'str'),
}),
}),
}),
}),
elem('Tags*', '1254c367', {
elem('Tag*', '7373', {
elem('Targets', '63c0', {
elem('TargetTypeValue', '68ca', 'uint'),
elem('TargetTrackUID', '63c5', 'uint'),
elem('TargetEditionUID', '63c9', 'uint'),
elem('TargetChapterUID', '63c4', 'uint'),
elem('TargetAttachmentUID', '63c6', 'uint'),
}),
elem('SimpleTag*', '67c8', {
elem('TagName', '45a3', 'str'),
elem('TagLanguage', '447a', 'str'),
elem('TagString', '4487', 'str'),
}),
}),
}),
}),
);
}
1;
+331
View File
@@ -0,0 +1,331 @@
use 5.008;
use strict;
use warnings;
# ABSTRACT: a mid-level representation of an EBML element
package Parse::Matroska::Element;
use Carp;
use List::Util qw{first};
=head1 SYNOPSIS
use Parse::Matroska::Reader;
my $reader = Parse::Matroska::Reader->new($path);
my $elem = $reader->read_element;
print "ID: $elem->{elid}\n";
print "Name: $elem->{name}\n";
print "Length: $elem->{content_len}\n";
print "Type: $elem->{type}\n";
print "Child count: ", scalar(@{$elem->all_children}), "\n";
if ($elem->{type} eq 'sub') {
while (my $chld = $elem->next_child) {
print "Child Name: $chld->{name}\n";
}
} else {
print "Value: ", $elem->get_value, "\n";
}
=head1 DESCRIPTION
Represents a single Matroska element as decoded by
L<Parse::Matroska::Reader>. This is essentially a hash
augmented with functions for delay-loading of binary
values and children elements.
=head1 NOTE
The API of this module is not yet considered stable.
=attr elid
The EBML Element ID, suitable for passing to
L<Parse::Matroska::Definitions/elem_by_hexid>.
=attr name
The EBML Element's name.
=attr type
The EBML Element's type. Can be C<uint>, C<sint>,
C<float>, C<ebml_id>, C<str> or C<binary>. See L</value>
for details.
Equivalent to
C<elem_by_hexid($elem-E<gt>{value})-E<gt>{valtype}>.
=attr value
The EBML Element's value. Should be obtained through
L</get_value>.
Is an unicode string if the L</type> is C<str>, that is,
the string has already been decoded by L<Encode/decode>.
Is C<undef> if the L</type> is C<binary> and the contents
were delay-loaded and not yet read. L</get_value> will
do the delayed load if needed.
Is an arrayref if the L</type> is C<sub>, containing
the children nodes that were already loaded.
Is a hashref if the L</type> is C<ebml_id>, containing
the referred element's information as defined in
L<Parse::Matroska::Definitions>. Calling
C<elem_by_hexid($elem-E<gt>{value}-E<gt>{elid})> will
return the same object as $elem->{value}.
=attr full_len
The entire length of this EBML Element, including
the header's.
=attr size_len
The length of the size marker. Used when calculating
L</full_len> from L</content_len>
=attr content_len
The length of the contents of this EBML Element,
which excludes the header.
=attr reader
A weakened reference to the associated
L<Parse::Matroska::Reader>.
=method new(%hash)
Creates a new Element initialized with the hash
given as argument.
=cut
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
$self->initialize(@_);
return $self;
}
=method initialize(%hash)
Called by L</new> on initialization.
=cut
sub initialize {
my ($self, %args) = @_;
for (keys %args) {
$self->{$_} = $args{$_};
}
$self->{depth} = 0 unless $self->{depth};
}
=method skip
Called by the user to ignore the contents of this EBML node.
Needed when ignoring the children of a node.
=cut
sub skip {
my ($self) = @_;
my $reader = $self->{reader};
return unless $reader; # we don't have to skip if there's no reader
my $pos = $reader->getpos;
croak "Too late to skip, reads were already done"
if $pos ne $self->{data_pos};
$reader->skip($self->{content_len});
}
=method get_value($keep_bin)
Returns the value contained by this EBML element.
If the element has children, returns an arrayref to
the children elements that were already encountered.
If the element's type is C<binary> and the value was
delay-loaded, does the reading now.
If $keep_bin is true, the delay-loaded data is kept
as the L</value>, otherwise, further calls to
C<get_value> will reread the data from the L</reader>.
=cut
sub get_value {
my ($self, $keep_bin) = @_;
return undef if $self->{type} eq 'skip';
return $self->{value} if $self->{value};
my $reader = $self->{reader} or
croak "The associated Reader has been deleted";
# delay-loaded 'binary'
if ($self->{type} eq 'binary') {
croak "Cannot seek in the current Reader" unless $self->{data_pos};
# seek to the data position...
$reader->setpos($self->{data_pos});
# read the data, keeping it in value if requested
if ($keep_bin) {
$self->{value} = $reader->readlen($self->{content_len});
return $self->{value};
} else {
return $reader->readlen($self->{content_len});
}
}
}
=method next_child($read_bin)
Builtin iterator; reads and returns the next child element.
Always returns undef if the type isn't C<sub>.
Returns undef at the end of the iterator and resets itself to
point to the first element; so calling L</next_child($read_bin)>
after the iterator returned C<undef> will return the first child.
The optional C<$read_bin> parameter has the children elements
not delay-load their value if their type is C<binary>.
If all children elements have already been read, return
each element in-order as would be given by
L</all_children($recurse,$read_bin)>.
=cut
sub next_child {
my ($self, $read_bin) = @_;
return unless $self->{type} eq 'sub';
if ($self->{_all_children_read}) {
my $idx = $self->{_last_child} ||= 0;
if ($idx == @{$self->{value}}) {
# reset the iterator, returning undef once
$self->{_last_child} = 0;
return;
}
my $ret = $self->{value}->[$idx];
++$idx;
$self->{_last_child} = $idx;
return $ret;
}
my $len = defined $self->{remaining_len}
? $self->{remaining_len}
: $self->{content_len};
if ($len == 0) {
# we've read all children; switch into $self->{value} iteration mode
$self->{_all_children_read} = 1;
# return undef since the iterator will reset
return;
}
$self->{pos_offset} ||= 0;
my $pos = $self->{data_pos};
my $reader = $self->{reader} or croak "The associated reader has been deleted";
$reader->setpos($pos);
$reader->{fh}->seek($self->{pos_offset}, 1) if $pos;
my $chld = $reader->read_element($read_bin);
return undef unless defined $chld;
$self->{pos_offset} += $chld->{full_len};
$self->{remaining_len} = $len - $chld->{full_len};
if ($self->{remaining_len} < 0) {
croak "Child elements consumed $self->{remaining_len} more bytes than parent $self->{name} contained";
}
$chld->{depth} = $self->{depth} + 1;
$self->{value} ||= [];
push @{$self->{value}}, $chld;
return $chld;
}
=method all_children($recurse,$read_bin)
Calls L</populate_children($recurse,$read_bin)> on self
and returns an arrayref with the children nodes.
Both C<$recurse> and C<$read_bin> are optional and default
to false.
=cut
sub all_children {
my ($self, $recurse, $read_bin) = @_;
$self->populate_children($recurse, $read_bin);
return $self->{value};
}
=method children_by_name($name)
Searches in the already read children elements for all
elements with the EBML name C<$name>. Returns an array
containing all found elements. On scalar context,
returns only the first element found.
Croaks if the element's C<type> isn't C<sub>.
=cut
sub children_by_name {
my ($self, $name) = @_;
return unless defined wantarray; # don't do work if work isn't wanted
croak "Element can't have children" unless $self->{type} eq 'sub';
my @found = grep { $_->{name} eq $name } @{$self->{value}};
return @found if wantarray; # list
return shift @found if defined wantarray; # scalar
}
=method populate_children($recurse,$read_bin)
Populates the internal array of children elements, that is,
requests that the associated L<Matroska::Parser::Reader> reads
all children elements. Returns itself.
Returns false if the element's C<type> isn't C<sub>.
If C<$recurse> is provided and is true, the method will call
itself in the children elements with the same parameters it
received; this will build a full EBML tree.
If C<$read_bin> is provided and is true, disables delay-loading
of the contents of C<binary>-type nodes, reading the contents
to memory.
If both C<$recurse> and C<$read_bin> are true, entire EBML trees
can be loaded without requiring seeks, thus behaving correctly
on unseekable streams. If C<$read_bin> is false, the entire EBML
tree is still loaded, but calling L</get_value> on C<binary>-type
nodes will produce an error on unseekable streams.
=cut
sub populate_children {
my ($self, $recurse, $read_bin) = @_;
return unless $self->{type} eq 'sub';
if (@{$self->{value}} && $recurse) {
# only recurse
foreach (@{$self->{value}}) {
$_->populate_children($recurse, $read_bin);
}
return $self;
}
while (my $chld = $self->next_child($read_bin)) {
$chld->populate_children($recurse, $read_bin) if $recurse;
}
return $self;
}
1;
+426
View File
@@ -0,0 +1,426 @@
use 5.008;
use strict;
use warnings;
# ABSTRACT: a low-level reader for EBML files
package Parse::Matroska::Reader;
use Parse::Matroska::Definitions qw{elem_by_hexid};
use Parse::Matroska::Element;
use Carp;
use Scalar::Util qw{openhandle weaken};
use IO::Handle;
use IO::File;
use List::Util qw{first};
use Encode;
use constant BIGINT_TRY => 'Pari,GMP,FastCalc';
use Math::BigInt try => BIGINT_TRY;
use Math::BigRat try => BIGINT_TRY;
=head1 SYNOPSIS
use Parse::Matroska::Reader;
my $reader = Parse::Matroska::Reader->new($path);
$reader->close;
$reader->open(\$string_with_matroska_data);
my $elem = $reader->read_element;
print "Element ID: $elem->{elid}\n";
print "Element name: $elem->{name}\n";
if ($elem->{type} ne 'sub') {
print "Element value: $elem->get_value\n";
} else {
while (my $child = $elem->next_child) {
print "Child element: $child->{name}\n";
}
}
$reader->close;
=head1 DESCRIPTION
Reads EBML data, which is used in Matroska files.
This is a low-level reader which is meant to be used as a backend
for higher level readers. TODO: write the high level readers :)
=head1 NOTE
The API of this module is not yet considered stable.
=method new
Creates a new reader.
Calls L</open($arg)> with its arguments if provided.
=cut
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
$self->open(@_) if @_;
return $self;
}
=method open($arg)
Creates the internal filehandle. The argument can be:
=for :list
* An open filehandle or L<IO::Handle> object.
The filehandle is not C<dup()>ed, so calling L</close> in this
object will close the given filehandle as well.
* A scalar containing a path to a file.
* On perl v5.14 or newer, a scalarref pointing to EBML data.
For similar functionality in older perls, give an L<IO::String> object
or the handle to an already C<open>ed scalarref.
=cut
sub open {
my ($self, $arg) = @_;
$self->{fh} = openhandle($arg) || IO::File->new($arg, "<:raw")
or croak "Can't open $arg: $!";
}
=method close
Closes the internal filehandle.
=cut
sub close {
my ($self) = @_;
$self->{fh}->close;
delete $self->{fh};
}
# equivalent to $self->readlen(1), possibly faster
sub _getc {
my ($self) = @_;
my $c = $self->{fh}->getc;
croak "Can't do read of length 1: $!" if !defined $c && $!;
return $c;
}
=method readlen($length)
Reads C<$length> bytes from the internal filehandle.
=cut
sub readlen {
my ($self, $len) = @_;
my $data;
my $readlen = $self->{fh}->read($data, $len);
croak "Can't do read of length $len: $!"
unless defined $readlen;
return $data;
}
# converts a byte string into an integer
# we do so by converting the integer into a hex string (big-endian)
# and then reading the hex-string into an integer
sub _bin2int($) {
my ($bin) = @_;
# if the length is larger than 3
# the resulting integer might be larger than INT_MAX
if (length($bin) > 3) {
return Math::BigInt->from_hex(unpack("H*", $bin));
}
return hex(unpack("H*", $bin));
}
# creates a floating-point number with the given mantissa and exponent
sub _ldexp {
my ($mantissa, $exponent) = @_;
my $r = new Math::BigRat($mantissa);
return $r * Math::BigRat->new(2)**$exponent;
}
# NOTE: the read_* functions are hard to read because they're ports
# of even harder to read python functions.
# TODO: make them readable
=method read_id
Reads an EBML ID atom in hexadecimal string format, suitable
for passing to L<Parse::Matroska::Definitions/elem_by_hexid($id)>.
=cut
sub read_id {
my ($self) = @_;
my $t = $self->_getc;
return undef unless defined $t;
my $i = 0;
my $mask = 1<<7;
if (ord($t) == 0) {
croak "Matroska Syntax error: first byte of ID was \\0"
}
until (ord($t) & $mask) {
++$i;
$mask >>= 1;
}
# return hex string of the bytes we just read
return unpack "H*", ($t . $self->readlen($i));
}
=method read_size
Reads an EBML Data Size atom, which immediately follows
an EBML ID atom.
This returns an array consisting of:
=for :list
0. The length of the Data Size atom.
1. The value encoded in the Data Size atom, which is the length of all the data following it.
=cut
sub read_size {
my ($self) = @_;
my $t = $self->_getc;
my $i = 0;
my $mask = 1<<7;
if (ord($t) == 0) {
croak "Matroska Syntax error: first byte of data size was \\0"
}
until (ord($t) & $mask) {
++$i;
$mask >>= 1;
}
$t = $t & chr($mask-1); # strip length bits (keep only significant bits)
return ($i+1, _bin2int $t . $self->readlen($i));
}
=method read_str($length)
Reads a string of length C<$length> bytes from the internal filehandle.
The string is already L<Encode/decode>d from C<UTF-8>, which is the
standard Matroska string encoding.
=cut
{
my $utf8 = find_encoding("UTF-8");
sub read_str {
my ($self, $length) = @_;
return $utf8->decode($self->readlen($length));
}
}
=method read_uint($length)
Reads an unsigned integer of length C<$length> bytes
from the internal filehandle.
Returns a L<Math::BigInt> object if C<$length> is greater
than 4.
=cut
sub read_uint {
my ($self, $length) = @_;
return _bin2int $self->readlen($length);
}
=method read_sint($length)
Reads a signed integer of length C<$length> bytes
from the internal filehandle.
Returns a L<Math::BigInt> object if C<$length> is greater
than 4.
=cut
sub read_sint {
my ($self, $length) = @_;
my $i = $self->read_uint($length);
# Apply 2's complement to the unsigned int
my $mask = int(2 ** ($length * 8 - 1));
# if the most significant bit is set...
if ($i & $mask) {
# subtract the MSB twice
$i -= 2 * $mask;
}
return $i;
}
=method read_float($length)
Reads an IEEE floating point number of length C<$length>
bytes from the internal filehandle.
Only lengths C<4> and C<8> are supported (C C<float> and C<double>).
=cut
{
my $b1 = new Math::BigInt 1;
sub read_float {
my ($self, $length) = @_;
my $i = new Math::BigInt $self->read_uint($length)->bstr;
my $f;
# These evil expressions reinterpret an unsigned int as IEEE binary floats
if ($length == 4) {
$f = _ldexp(($i & ((1<<23) - 1)) + (1<<23), ($i>>23 & ((1<<8) - 1)) - 150);
$f = -$f if $i & ($b1<<31);
} elsif ($length == 8) {
$f = _ldexp(($i & (($b1<<52) - 1)) + ($b1<<52), ($i>>52 & ((1<<12) - 1)) - 1075);
$f = -$f if $i & ($b1<<63);
} else {
croak "Matroska Syntax error: unsupported IEEE float byte size $length";
}
return $f;
}
}
=method read_ebml_id($length)
Reads an EBML ID when it's encoded as the data inside another
EBML element, that is, when the enclosing element's C<type> is
C<ebml_id>.
This returns a hashref with the EBML element description as
defined in L<Parse::Matroska::Definitions>.
=cut
sub read_ebml_id {
my ($self, $length) = @_;
return elem_by_hexid(unpack("H*", $self->readlen($length)));
}
=method skip($length)
Skips C<$length> bytes in the internal filehandle.
=cut
sub skip {
my ($self, $len) = @_;
return if $self->{fh}->can('seek') && $self->{fh}->seek($len, 1);
$self->readlen($len);
return;
}
=method getpos
Wrapper for L<IO::Seekable/$io-E<gt>getpos> in the internal filehandle.
Returns undef if the internal filehandle can't C<getpos>.
=cut
sub getpos {
my ($self) = @_;
return undef unless $self->{fh}->can('getpos');
return $self->{fh}->getpos;
}
=method setpos($pos)
Wrapper for L<IO::Seekable/$io-E<gt>setpos> in the internal filehandle.
Returns C<undef> if the internal filehandle can't C<setpos>.
Croaks if C<setpos> does not seek to the requested position,
that is, if calling C<getpos> does not yield the same object
as the C<$pos> argument.
=cut
sub setpos {
my ($self, $pos) = @_;
return undef unless $pos && $self->{fh}->can('setpos');
my $ret = $self->{fh}->setpos($pos);
croak "Cannot seek to correct position"
unless $self->getpos eq $pos;
return $ret;
}
=method read_element($read_bin)
Reads a full EBML element from the internal filehandle.
Returns a L<Parse::Matroska::Element> object initialized with
the read data. If C<read_bin> is not present or is false, will
delay-load the contents of C<binary> type elements, that is,
they will only be loaded when calling C<get_value> on the
returned L<Parse::Matroska::Element> object.
Does not read the children of the element if its type is
C<sub>. Look into the L<Parse::Matroska::Element> interface
for details in how to read children elements.
Pass a true C<$read_bin> if the stream being read is not
seekable (C<getpos> is undef) and the contents of C<binary>
elements is desired, otherwise seeking errors or internal
filehandle corruption might occur.
=cut
sub read_element {
my ($self, $read_bin) = @_;
return undef if $self->{fh}->eof;
my $elem_pos = $self->getpos;
my $elid = $self->read_id;
my $elem_def = elem_by_hexid($elid);
my ($size_len, $content_len) = $self->read_size;
my $full_len = length($elid)/2 + $size_len + $content_len;
my $elem = Parse::Matroska::Element->new(
elid => $elid,
name => $elem_def && $elem_def->{name},
type => $elem_def && $elem_def->{valtype},
size_len => $size_len,
content_len => $content_len,
full_len => $full_len,
reader => $self,
elem_pos => $elem_pos,
data_pos => $self->getpos,
);
weaken($elem->{reader});
if (defined $elem_def) {
if ($elem->{type} eq 'sub') {
$elem->{value} = [];
} elsif ($elem->{type} eq 'str') {
$elem->{value} = $self->read_str($content_len);
} elsif ($elem->{type} eq 'ebml_id') {
$elem->{value} = $self->read_ebml_id($content_len);
} elsif ($elem->{type} eq 'uint') {
$elem->{value} = $self->read_uint($content_len);
} elsif ($elem->{type} eq 'sint') {
$elem->{value} = $self->read_sint($content_len);
} elsif ($elem->{type} eq 'float') {
$elem->{value} = $self->read_float($content_len);
} elsif ($elem->{type} eq 'skip') {
$self->skip($content_len);
} elsif ($elem->{type} eq 'binary') {
if ($read_bin) {
$elem->{value} = $self->readlen($content_len);
} else {
$self->skip($content_len);
}
} else {
die "Matroska Definition error: type $elem->{valtype} unknown"
}
} else {
$self->skip($content_len);
}
return $elem;
}
1;
=head1 CAVEATS
Children elements have to be processed as soon as an element
with children is found, or their children ignored with
L<Parse::Matroska::Element/skip>. Not doing so doesn't cause
errors but results in an invalid structure, with constant C<0>
depth.
To work correctly in unseekable streams, either the contents
of C<binary>-type elements has to be ignored or the C<read_bin>
flag to C<read_element> has to be true.
+37
View File
@@ -0,0 +1,37 @@
use strict;
use warnings;
# ABSTRACT: internally-used helper functions
package Parse::Matroska::Utils;
use Exporter;
our @ISA = qw{Exporter};
our @EXPORT_OK = qw{uniq uncamelize};
=method uniq(@array)
The same as L<List::MoreUtils/"uniq LIST">.
Included to avoid depending on it since it's
not a core module.
=cut
sub uniq(@) {
my %seen;
return grep { !$seen{$_}++ } @_;
}
=method uncamelize($string)
Converts a "StringLikeTHIS" into a
"string_like_this".
=cut
sub uncamelize($) {
local $_ = shift;
# lc followed by UC: lc_UC
s/(?<=[a-z])([A-Z])/_\L$1/g;
# UC followed by two lc: _UClclc
s/([A-Z])(?=[a-z]{2})/_\L$1/g;
# strip leading _ that the second regexp might add; lowercase all
s/^_//; lc
}
+3 -11
View File
@@ -4,17 +4,9 @@ mpv lua scripts
The lua scripts in this folder can be loaded on a one-time basis by
adding the option
--script=/path/to/script.lua
--lua=/path/to/script.lua
to mpv's command line.
Where appropriate, they may also be placed in ~/.config/mpv/scripts/ from
where they will be automatically loaded when mpv starts.
This is only a small selection of internally maintained scripts. Some of them
are just for testing mpv internals, or serve as examples. An extensive
user-edited list of 3rd party scripts is available here:
https://github.com/mpv-player/mpv/wiki/User-Scripts
(Anyone can add their own scripts to that list.)
Where appropriate, they may also be placed in ~/.config/mpv/lua from where
they will be automatically loaded when mpv starts.
-158
View File
@@ -1,158 +0,0 @@
-- This script adds control to the dynamic range compression ffmpeg
-- filter including key bindings for adjusting parameters.
--
-- See https://ffmpeg.org/ffmpeg-filters.html#acompressor for explanation
-- of the parameters.
local mp = require 'mp'
local options = require 'mp.options'
local o = {
default_enable = false,
show_osd = true,
osd_timeout = 4000,
filter_label = mp.get_script_name(),
key_toggle = 'n',
key_increase_threshold = 'F1',
key_decrease_threshold = 'Shift+F1',
key_increase_ratio = 'F2',
key_decrease_ratio = 'Shift+F2',
key_increase_knee = 'F3',
key_decrease_knee = 'Shift+F3',
key_increase_makeup = 'F4',
key_decrease_makeup = 'Shift+F4',
key_increase_attack = 'F5',
key_decrease_attack = 'Shift+F5',
key_increase_release = 'F6',
key_decrease_release = 'Shift+F6',
default_threshold = -25.0,
default_ratio = 3.0,
default_knee = 2.0,
default_makeup = 8.0,
default_attack = 20.0,
default_release = 250.0,
step_threshold = -2.5,
step_ratio = 1.0,
step_knee = 1.0,
step_makeup = 1.0,
step_attack = 10.0,
step_release = 10.0,
}
options.read_options(o)
local params = {
{ name = 'attack', min=0.01, max=2000, hide_default=true, dB='' },
{ name = 'release', min=0.01, max=9000, hide_default=true, dB='' },
{ name = 'threshold', min= -30, max= 0, hide_default=false, dB='dB' },
{ name = 'ratio', min= 1, max= 20, hide_default=false, dB='' },
{ name = 'knee', min= 1, max= 10, hide_default=true, dB='dB' },
{ name = 'makeup', min= 0, max= 24, hide_default=false, dB='dB' },
}
local function parse_value(value)
-- Using nil here because tonumber differs between lua 5.1 and 5.2 when
-- parsing fractions in combination with explicit base argument set to 10.
-- And we can't omit it because gsub returns 2 values which would get
-- unpacked and cause more problems. Gotta love scripting languages.
return tonumber(value:gsub('dB$', ''), nil)
end
local function format_value(value, dB)
return string.format('%g%s', value, dB)
end
local function show_osd(filter)
if not o.show_osd then
return
end
if not filter.enabled then
mp.commandv('show-text', 'Dynamic range compressor: disabled', o.osd_timeout)
return
end
local pretty = {}
for _,param in ipairs(params) do
local value = parse_value(filter.params[param.name])
if not (param.hide_default and value == o['default_' .. param.name]) then
pretty[#pretty+1] = string.format('%s: %g%s', param.name:gsub("^%l", string.upper),
value, param.dB)
end
end
if #pretty == 0 then
pretty = ''
else
pretty = '\n(' .. table.concat(pretty, ', ') .. ')'
end
mp.commandv('show-text', 'Dynamic range compressor: enabled' .. pretty, o.osd_timeout)
end
local function get_filter()
local af = mp.get_property_native('af', {})
for i = 1, #af do
if af[i].label == o.filter_label then
return af, i
end
end
af[#af+1] = {
name = 'acompressor',
label = o.filter_label,
enabled = false,
params = {},
}
for _,param in pairs(params) do
af[#af].params[param.name] = format_value(o['default_' .. param.name], param.dB)
end
return af, #af
end
local function toggle_acompressor()
local af, i = get_filter()
af[i].enabled = not af[i].enabled
mp.set_property_native('af', af)
show_osd(af[i])
end
local function update_param(name, increment)
for _,param in pairs(params) do
if param.name == string.lower(name) then
local af, i = get_filter()
local value = parse_value(af[i].params[param.name])
value = math.max(param.min, math.min(value + increment, param.max))
af[i].params[param.name] = format_value(value, param.dB)
af[i].enabled = true
mp.set_property_native('af', af)
show_osd(af[i])
return
end
end
mp.msg.error('Unknown parameter "' .. name .. '"')
end
mp.add_key_binding(o.key_toggle, "toggle-acompressor", toggle_acompressor)
mp.register_script_message('update-param', update_param)
for _,param in pairs(params) do
for direction,step in pairs({increase=1, decrease=-1}) do
mp.add_key_binding(o['key_' .. direction .. '_' .. param.name],
'acompressor-' .. direction .. '-' .. param.name,
function() update_param(param.name, step*o['step_' .. param.name]); end,
{ repeatable = true })
end
end
if o.default_enable then
local af, i = get_filter()
af[i].enabled = true
mp.set_property_native('af', af)
end
-22
View File
@@ -1,22 +0,0 @@
-- Handles the edge case where previous attempts to init audio have failed, but
-- might start working due to a newly added device. This is required in
-- particular for ao=wasapi, since the internal IMMNotificationClient code that
-- normally triggers ao-reload will not be running in this case.
local reloading
local function do_reload()
mp.command("ao-reload")
reloading = nil
end
local function on_audio_device_list_change()
if mp.get_property("current-ao") == "null" and not reloading then
mp.msg.verbose("audio-device-list changed: reloading audio")
-- avoid calling ao-reload too often
reloading = mp.add_timeout(0.5, do_reload)
end
end
mp.set_property("options/audio-fallback-to-null", "yes")
mp.observe_property("audio-device-list", "native", on_audio_device_list_change)
-6
View File
@@ -1,6 +0,0 @@
mp.observe_property("audio-device-list", "native", function(_, val)
print("Audio device list changed:")
for _, e in ipairs(val) do
print(" - '" .. e.name .. "' (" .. e.description .. ")")
end
end)
+89 -271
View File
@@ -1,295 +1,113 @@
--[[
This script uses the lavfi cropdetect filter and the video-crop property to
automatically crop the currently playing video with appropriate parameters.
-- This script uses the lavfi cropdetect filter to automatically
-- insert a crop filter with appropriate parameters for the currently
-- playing video.
--
-- It registers the key-binding "C" (shift+c), which when pressed,
-- inserts the filter vf=lavfi=cropdetect. After 1 second, it then
-- inserts the filter vf=crop=w:h:x:y, where w,h,x,y are determined
-- from the vf-metadata gathered by cropdetect. The cropdetect filter
-- is removed immediately after the crop filter is inserted as it is
-- no longer needed.
--
-- If the "C" key is pressed again, the crop filter is removed
-- restoring playback to its original state.
--
-- Since the crop parameters are determined from the 1 second of video
-- between inserting the cropdetect and crop filters, the "C" key
-- should be pressed at a position in the video where the crop region
-- is unambiguous (i.e., not a black frame, black background title
-- card, or dark scene).
--
-- The default delay between insertion of the cropdetect and
-- crop filters may be overridden by adding
--
-- --lua-opts=autocrop.detect_seconds=<number of seconds>
--
-- to mpv's arguments. This may be desirable to allow cropdetect more
-- time to collect data.
require "mp.msg"
It automatically crops the video when playback starts.
script_name = mp.get_script_name()
cropdetect_label = string.format("%s-cropdetect", script_name)
crop_label = string.format("%s-crop", script_name)
You can also manually crop the video by pressing the "C" (shift+c) key.
Pressing it again undoes the crop.
The workflow is as follows: First, it inserts the cropdetect filter. After
<detect_seconds> (default is 1) seconds, it then sets video-crop based on the
vf-metadata values gathered by cropdetect. The cropdetect filter is removed
after video-crop is set as it is no longer needed.
Since the crop parameters are determined from the 1 second of video between
inserting the cropdetect filter and setting video-crop, the "C" key should be
pressed at a position in the video where the crop region is unambiguous (i.e.,
not a black frame, black background title card, or dark scene).
If non-copy-back hardware decoding is in use, hwdec is temporarily disabled for
the duration of cropdetect as the filter would fail otherwise.
These are the default options. They can be overridden by adding
script-opts-append=autocrop-<parameter>=<value> to mpv.conf.
--]]
local options = {
-- Whether to automatically apply crop at the start of playback. If you
-- don't want to crop automatically, add
-- script-opts-append=autocrop-auto=no to mpv.conf.
auto = true,
-- Delay before starting crop in auto mode. You can try to increase this
-- value to avoid dark scenes or fade ins at beginning. Automatic cropping
-- will not occur if the value is larger than the remaining playback time.
auto_delay = 4,
-- Black threshold for cropdetect. Smaller values will generally result in
-- less cropping. See limit of
-- https://ffmpeg.org/ffmpeg-filters.html#cropdetect
detect_limit = "24/255",
-- The value which the width/height should be divisible by. Smaller
-- values have better detection accuracy. If you have problems with
-- other filters, you can try to set it to 4 or 16. See round of
-- https://ffmpeg.org/ffmpeg-filters.html#cropdetect
detect_round = 2,
-- The ratio of the minimum clip size to the original. A number from 0 to
-- 1. If the picture is over cropped, try adjusting this value.
detect_min_ratio = 0.5,
-- How long to gather cropdetect data. Increasing this may be desirable to
-- allow cropdetect more time to collect data.
detect_seconds = 1,
-- Whether the OSD shouldn't be used when cropdetect and video-crop are
-- applied and removed.
suppress_osd = false,
}
require "mp.options".read_options(options)
local cropdetect_label = mp.get_script_name() .. "-cropdetect"
local timers = {
auto_delay = nil,
detect_crop = nil
}
local hwdec_backup
local command_prefix = options.suppress_osd and 'no-osd' or ''
local function is_enough_time(seconds)
-- Plus 1 second for deviation.
local time_needed = seconds + 1
local playtime_remaining = mp.get_property_native("playtime-remaining")
return playtime_remaining and time_needed < playtime_remaining
-- number of seconds to gather cropdetect data
detect_seconds = tonumber(mp.get_opt(string.format("%s.detect_seconds", script_name)))
if not detect_seconds then
detect_seconds = 1
end
local function is_cropable(time_needed)
if mp.get_property_native('current-tracks/video/image') ~= false then
mp.msg.warn("autocrop only works for videos.")
return false
end
if not is_enough_time(time_needed) then
mp.msg.warn("Not enough time to detect crop.")
return false
end
return true
end
local function remove_cropdetect()
for _, filter in pairs(mp.get_property_native("vf")) do
if filter.label == cropdetect_label then
mp.command(
string.format("%s vf remove @%s", command_prefix, filter.label))
return
function del_filter_if_present(label)
-- necessary because mp.command('vf del @label:filter') raises an
-- error if the filter doesn't exist
local vfs = mp.get_property_native("vf")
for i,vf in pairs(vfs) do
if vf["label"] == label then
table.remove(vfs, i)
mp.set_property_native("vf", vfs)
return true
end
end
return false
end
local function restore_hwdec()
if hwdec_backup then
mp.set_property("hwdec", hwdec_backup)
hwdec_backup = nil
end
end
local function cleanup()
remove_cropdetect()
-- Kill all timers.
for index, timer in pairs(timers) do
if timer then
timer:kill()
timers[index] = nil
end
end
restore_hwdec()
end
local function apply_crop(meta)
-- Verify if it is necessary to crop.
local is_effective = meta.w and meta.h and meta.x and meta.y and
(meta.x > 0 or meta.y > 0
or meta.w < meta.max_w or meta.h < meta.max_h)
-- Verify it is not over cropped.
local is_excessive = false
if is_effective and (meta.w < meta.min_w or meta.h < meta.min_h) then
mp.msg.info("The area to be cropped is too large.")
mp.msg.info("You might need to decrease detect_min_ratio.")
is_excessive = true
end
if not is_effective or is_excessive then
-- Clear any existing crop.
mp.command(string.format("%s set file-local-options/video-crop ''", command_prefix))
function autocrop_start()
-- exit if cropdetection is already in progress
if timer then
mp.msg.warn("already cropdetecting!")
return
end
-- Apply crop.
mp.command(string.format("%s set file-local-options/video-crop %sx%s+%s+%s",
command_prefix, meta.w, meta.h, meta.x, meta.y))
end
local function detect_end()
-- Get the metadata and remove the cropdetect filter.
local cropdetect_metadata = mp.get_property_native(
"vf-metadata/" .. cropdetect_label)
remove_cropdetect()
-- Remove the timer of detect crop.
if timers.detect_crop then
timers.detect_crop:kill()
timers.detect_crop = nil
end
restore_hwdec()
local meta
-- Verify the existence of metadata.
if cropdetect_metadata then
meta = {
w = cropdetect_metadata["lavfi.cropdetect.w"],
h = cropdetect_metadata["lavfi.cropdetect.h"],
x = cropdetect_metadata["lavfi.cropdetect.x"],
y = cropdetect_metadata["lavfi.cropdetect.y"],
}
else
mp.msg.error("No crop data.")
mp.msg.info("Was the cropdetect filter successfully inserted?")
mp.msg.info("Does your version of FFmpeg support AVFrame metadata?")
-- if there's a crop filter, remove it and exit
if del_filter_if_present(crop_label) then
return
end
-- Verify that the metadata meets the requirements and convert it.
if meta.w and meta.h and meta.x and meta.y then
local width = mp.get_property_native("width")
local height = mp.get_property_native("height")
meta = {
w = tonumber(meta.w),
h = tonumber(meta.h),
x = tonumber(meta.x),
y = tonumber(meta.y),
min_w = width * options.detect_min_ratio,
min_h = height * options.detect_min_ratio,
max_w = width,
max_h = height
}
else
mp.msg.error("Got empty crop data.")
mp.msg.info("You might need to increase detect_seconds.")
end
apply_crop(meta)
end
local function detect_crop()
local time_needed = options.detect_seconds
if not is_cropable(time_needed) then
return
end
local hwdec_current = mp.get_property("hwdec-current", "no")
if hwdec_current:find("-copy$") == nil and hwdec_current ~= "no" and
hwdec_current ~= "crystalhd" and hwdec_current ~= "rkmpp" then
hwdec_backup = mp.get_property("hwdec")
mp.set_property("hwdec", "no")
end
-- Insert the cropdetect filter.
local limit = options.detect_limit
local round = options.detect_round
mp.command(
-- insert the cropdetect filter
ret=mp.command(
string.format(
'%s vf pre @%s:cropdetect=limit=%s:round=%d:reset=0',
command_prefix, cropdetect_label, limit, round
'vf add @%s:lavfi=graph="cropdetect=limit=24:round=2:reset=0"',
cropdetect_label
)
)
-- Wait to gather data.
timers.detect_crop = mp.add_timeout(time_needed, detect_end)
-- wait to gather data
timer=mp.add_timeout(detect_seconds, do_crop)
end
local function on_start()
-- Clean up at the beginning.
cleanup()
-- If auto is not true, exit.
if not options.auto then
return
end
-- If it is the beginning, wait for detect_crop
-- after auto_delay seconds, otherwise immediately.
local playback_time = mp.get_property_native("playback-time")
local is_delay_needed = playback_time
and options.auto_delay > playback_time
if is_delay_needed then
-- Verify if there is enough time for autocrop.
local time_needed = options.auto_delay + options.detect_seconds
if not is_cropable(time_needed) then
return
function do_crop()
-- get the metadata
local cropdetect_metadata = mp.get_property_native(
string.format("vf-metadata/%s", cropdetect_label)
)
-- use it to crop if its valid
if cropdetect_metadata then
if cropdetect_metadata["lavfi.cropdetect.w"]
and cropdetect_metadata["lavfi.cropdetect.h"]
and cropdetect_metadata["lavfi.cropdetect.x"]
and cropdetect_metadata["lavfi.cropdetect.y"]
then
mp.command(string.format("vf add @%s:crop=%s:%s:%s:%s",
crop_label,
cropdetect_metadata["lavfi.cropdetect.w"],
cropdetect_metadata["lavfi.cropdetect.h"],
cropdetect_metadata["lavfi.cropdetect.x"],
cropdetect_metadata["lavfi.cropdetect.y"]))
else
mp.msg.error(
"Got empty crop data. You might need to increase detect_seconds."
)
end
timers.auto_delay = mp.add_timeout(time_needed,
function()
detect_crop()
-- Remove the timer of auto delay.
timers.auto_delay:kill()
timers.auto_delay = nil
end
)
else
detect_crop()
mp.msg.error(
"No crop data. Was the cropdetect filter successfully inserted?"
)
mp.msg.error(
"Does your version of ffmpeg/libav support AVFrame metadata?"
)
end
-- remove the cropdetect filter
del_filter_if_present(cropdetect_label)
timer=nil
end
local function on_toggle()
-- If it is during auto_delay, kill the timer.
if timers.auto_delay then
timers.auto_delay:kill()
timers.auto_delay = nil
end
-- Cropped => Remove it.
if mp.get_property("video-crop") ~= "" then
mp.command(string.format("%s set file-local-options/video-crop ''", command_prefix))
return
end
-- Detecting => Leave it.
if timers.detect_crop then
mp.msg.warn("Already cropdetecting!")
return
end
-- Neither => Detect crop.
detect_crop()
end
mp.add_key_binding("C", "toggle_crop", on_toggle)
mp.register_event("end-file", cleanup)
mp.register_event("file-loaded", on_start)
mp.add_key_binding("C", "auto_crop", autocrop_start)
+89 -82
View File
@@ -2,19 +2,24 @@
-- appropriate deinterlacing filter based on a short section of the
-- currently playing video.
--
-- It registers the key-binding ctrl+d, which when pressed, inserts the filters
-- ``vf=idet,lavfi-pullup,idet``. After 4 seconds, it removes these
-- filters and decides whether the content is progressive, interlaced, or
-- telecined and the interlacing field dominance.
-- It registers the key-binding ctrl+d, which when pressed, inserts
-- the filter vf=lavfi=idet. After 4 second, it examines the results
-- to determine whether the content progressive or interlaced and the
-- interlacing field dominance. It immediately sets the latter within
-- mpv.
--
-- Based on this information, it may set mpv's ``deinterlace`` property (which
-- usually inserts the bwdif filter), or insert the ``pullup`` filter if the
-- content is telecined. It also sets field dominance with lavfi setfield.
-- If the content is judged not to be progressive, it may be either
-- interlaced or telecined. To determine which one, the video is
-- seeked back to the detection starting point with the "pullup"
-- filter inserted. After another four seconds, if idet thinks that
-- the pulled up viedo is "progressive", then pullup is the correct
-- filter and this script leaves it in places while removing the idet
-- filter. Otherwise, the content plain interlaced and mpv's deinterlace
-- property is set. This will usually insert the yadif deinterlacing filter.
--
-- OPTIONS:
-- The default detection time may be overridden by adding
--
-- --script-opts=autodeint.detect_seconds=<number of seconds>
-- --lua-opts=autodeint.detect_seconds=<number of seconds>
--
-- to mpv's arguments. This may be desirable to allow idet more
-- time to collect data.
@@ -22,25 +27,24 @@
-- To see counts of the various types of frames for each detection phase,
-- the verbosity can be increased with
--
-- --msg-level=autodeint=v
-- --msg-level autodeint=v
--
-- This script requires a recent version of ffmpeg for which the idet
-- filter adds the required metadata.
require "mp.msg"
local script_name = mp.get_script_name()
local detect_label = string.format("%s-detect", script_name)
local pullup_label = string.format("%s", script_name)
local dominance_label = string.format("%s-dominance", script_name)
local ivtc_detect_label = string.format("%s-ivtc-detect", script_name)
local timer
local progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3
script_name = mp.get_script_name()
detect_label = string.format("%s-detect", script_name)
pullup_label = string.format("%s", script_name)
-- number of seconds to gather cropdetect data
local detect_seconds = tonumber(mp.get_opt(string.format("%s.detect_seconds", script_name)))
detect_seconds = tonumber(mp.get_opt(string.format("%s.detect_seconds", script_name)))
if not detect_seconds then
detect_seconds = 4
end
local function del_filter_if_present(label)
function del_filter_if_present(label)
-- necessary because mp.command('vf del @label:filter') raises an
-- error if the filter doesn't exist
local vfs = mp.get_property_native("vf")
@@ -55,30 +59,51 @@ local function del_filter_if_present(label)
return false
end
local function add_vf(label, filter)
return mp.command(('vf add @%s:%s'):format(label, filter))
function start_detect()
-- exit if detection is already in progress
if timer then
mp.msg.warn("already detecting!")
return
end
mp.set_property("deinterlace","no")
del_filter_if_present(pullup_label)
percent_pos = mp.get_property("percent-pos")
-- insert the detection filter
local cmd = string.format('vf add @%s:lavfi=graph="idet"', detect_label)
if not mp.command(cmd) then
mp.msg.error("failed to insert detection filter")
return
end
-- wait to gather data
timer = mp.add_timeout(detect_seconds, judge_field_dominance)
end
local function stop_detect()
function stop_detect()
del_filter_if_present(detect_label)
del_filter_if_present(ivtc_detect_label)
timer = nil
mp.set_property("playback-pos", percent_pos)
end
local function judge(label)
-- get the metadata
local result = mp.get_property_native(string.format("vf-metadata/%s", label))
local num_tff = tonumber(result["lavfi.idet.multiple.tff"])
local num_bff = tonumber(result["lavfi.idet.multiple.bff"])
local num_progressive = tonumber(result["lavfi.idet.multiple.progressive"])
local num_undetermined = tonumber(result["lavfi.idet.multiple.undetermined"])
local num_interlaced = num_tff + num_bff
local num_determined = num_interlaced + num_progressive
progressive, interlaced_tff, interlaced_bff, interlaced = 0, 1, 2, 3, 4
mp.msg.verbose(label.." progressive = "..num_progressive)
mp.msg.verbose(label.." interlaced-tff = "..num_tff)
mp.msg.verbose(label.." interlaced-bff = "..num_bff)
mp.msg.verbose(label.." undetermined = "..num_undetermined)
function judge()
-- get the metadata
local result = mp.get_property_native(string.format("vf-metadata/%s", detect_label))
num_tff = tonumber(result["lavfi.idet.multiple.tff"])
num_bff = tonumber(result["lavfi.idet.multiple.bff"])
num_progressive = tonumber(result["lavfi.idet.multiple.progressive"])
num_undetermined = tonumber(result["lavfi.idet.multiple.undetermined"])
num_interlaced = num_tff + num_bff
num_determined = num_interlaced + num_progressive
mp.msg.verbose("progressive = "..num_progressive)
mp.msg.verbose("interlaced-tff = "..num_tff)
mp.msg.verbose("interlaced-bff = "..num_bff)
mp.msg.verbose("undetermined = "..num_undetermined)
if num_determined < num_undetermined then
mp.msg.warn("majority undetermined frames")
@@ -94,64 +119,46 @@ local function judge(label)
end
end
local function select_filter()
-- handle the first detection filter results
local verdict = judge(detect_label)
local ivtc_verdict = judge(ivtc_detect_label)
local dominance = "auto"
function judge_field_dominance()
verdict = judge()
if verdict == progressive then
mp.msg.info("progressive: doing nothing")
stop_detect()
del_filter_if_present(dominance_label)
del_filter_if_present(pullup_label)
mp.msg.info("progressive: doing nothing")
return
else
if verdict == interlaced_tff then
dominance = "tff"
add_vf(dominance_label, 'setfield=mode='..dominance)
elseif verdict == interlaced_bff then
dominance = "bff"
add_vf(dominance_label, 'setfield=mode='..dominance)
else
del_filter_if_present(dominance_label)
end
elseif verdict == interlaced_tff then
mp.set_property("field-dominance", "top")
elseif verdict == interlaced_bff then
mp.set_property("field-dominance", "bottom")
elseif verdict == interlaced then
mp.set_property("field-dominance", "auto")
end
-- handle the ivtc detection filter results
if ivtc_verdict == progressive then
mp.msg.info(string.format("telecined with %s field dominance: using pullup", dominance))
local cmd = string.format("vf pre @%s:pullup", pullup_label)
if not mp.command(cmd) then
mp.msg.error("failed to insert pullup filter")
stop_detect()
return
end
-- redo the detection with the pullup filter to see if it's telecined
mp.set_property("percent-pos", percent_pos)
timer = mp.add_timeout(detect_seconds, judge_ivtc)
end
function judge_ivtc()
verdict = judge()
if verdict == progressive then
mp.msg.info(string.format("telecinied with %s field dominance: using pullup", mp.get_property("field-dominance")))
stop_detect()
else
mp.msg.info("interlaced with " .. dominance ..
" field dominance: setting deinterlace property")
mp.msg.info(string.format("interlaced with %s field dominance: setting deinterlace property", mp.get_property("field-dominance")))
del_filter_if_present(pullup_label)
mp.set_property("deinterlace","yes")
stop_detect()
end
end
local function start_detect()
-- exit if detection is already in progress
if timer then
mp.msg.warn("already detecting!")
return
end
mp.set_property("deinterlace","no")
del_filter_if_present(pullup_label)
del_filter_if_present(dominance_label)
-- insert the detection filters
if not (add_vf(detect_label, 'idet') and
add_vf(dominance_label, 'setfield=mode=auto') and
add_vf(pullup_label, 'lavfi-pullup') and
add_vf(ivtc_detect_label, 'idet')) then
mp.msg.error("failed to insert detection filters")
return
end
-- wait to gather data
timer = mp.add_timeout(detect_seconds, select_filter)
return
end
mp.add_key_binding("ctrl+d", script_name, start_detect)
+38 -381
View File
@@ -1,418 +1,75 @@
-- This script automatically loads playlist entries before and after the
-- currently played file. It does so by scanning the directory a file is
-- the currently played file. It does so by scanning the directory a file is
-- located in when starting playback. It sorts the directory entries
-- alphabetically, and adds entries before and after the current file to
-- the internal playlist. (It stops if it would add an already existing
-- the internal playlist. (It stops if the it would add an already existing
-- playlist entry at the same position - this makes it "stable".)
-- Add at most 5000 * 2 files when starting a file (before + after).
-- Add at most 5 * 2 files when starting a file (before + after).
MAXENTRIES = 5
--[[
To configure this script use file autoload.conf in directory script-opts (the "script-opts"
directory must be in the mpv configuration directory, typically ~/.config/mpv/).
mputils = require 'mp.utils'
Option `ignore_patterns` is a comma-separated list of patterns (see lua.org/pil/20.2.html).
Additionally to the standard lua patterns, you can also escape commas with `%`,
for example, the option `bak%,x%,,another` will be resolved as patterns `bak,x,` and `another`.
But it does not mean you need to escape all lua patterns twice,
so the option `bak%%,%.mp4,` will be resolved as two patterns `bak%%` and `%.mp4`.
Example configuration would be:
disabled=no
images=no
videos=yes
audio=yes
additional_image_exts=list,of,ext
additional_video_exts=list,of,ext
additional_audio_exts=list,of,ext
ignore_hidden=yes
same_type=yes
directory_mode=recursive
ignore_patterns=^~,^bak-,%.bak$
--]]
local MAX_ENTRIES = 5000
local MAX_DIR_STACK = 20
local msg = require 'mp.msg'
local options = require 'mp.options'
local utils = require 'mp.utils'
local o = {
disabled = false,
images = true,
videos = true,
audio = true,
additional_image_exts = "",
additional_video_exts = "",
additional_audio_exts = "",
ignore_hidden = true,
same_type = false,
directory_mode = "auto",
ignore_patterns = ""
}
local function Set(t)
local set = {}
for _, v in pairs(t) do set[v] = true end
return set
end
local EXTENSIONS_VIDEO_DEFAULT = Set {
'3g2', '3gp', 'avi', 'flv', 'm2ts', 'm4v', 'mj2', 'mkv', 'mov',
'mp4', 'mpeg', 'mpg', 'ogv', 'rmvb', 'webm', 'wmv', 'y4m'
}
local EXTENSIONS_AUDIO_DEFAULT = Set {
'aiff', 'ape', 'au', 'flac', 'm4a', 'mka', 'mp3', 'oga', 'ogg',
'ogm', 'opus', 'wav', 'wma'
}
local EXTENSIONS_IMAGES_DEFAULT = Set {
'avif', 'bmp', 'gif', 'j2k', 'jp2', 'jpeg', 'jpg', 'jxl', 'png',
'svg', 'tga', 'tif', 'tiff', 'webp'
}
local EXTENSIONS, EXTENSIONS_VIDEO, EXTENSIONS_AUDIO, EXTENSIONS_IMAGES
local function SetUnion(a, b)
for k in pairs(b) do a[k] = true end
return a
end
-- Returns first and last positions in string or past-to-end indices
local function FindOrPastTheEnd(string, pattern, start_at)
local pos1, pos2 = string:find(pattern, start_at)
return pos1 or #string + 1,
pos2 or #string + 1
end
local function Split(list)
local set = {}
local item_pos = 1
local item = ""
while item_pos <= #list do
local pos1, pos2 = FindOrPastTheEnd(list, "%%*,", item_pos)
local pattern_length = pos2 - pos1
local is_comma_escaped = pattern_length % 2
local pos_before_escape = pos1 - 1
local item_escape_count = pattern_length - is_comma_escaped
item = item .. string.sub(list, item_pos, pos_before_escape + item_escape_count)
if is_comma_escaped == 1 then
item = item .. ","
else
set[item] = true
item = ""
end
item_pos = pos2 + 1
end
set[item] = true
-- exclude empty items
set[""] = nil
return set
end
local function split_option_exts(video, audio, image)
if video then o.additional_video_exts = Split(o.additional_video_exts) end
if audio then o.additional_audio_exts = Split(o.additional_audio_exts) end
if image then o.additional_image_exts = Split(o.additional_image_exts) end
end
local function split_patterns()
o.ignore_patterns = Split(o.ignore_patterns)
end
local function create_extensions()
EXTENSIONS = {}
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
local function validate_directory_mode()
if o.directory_mode ~= "recursive" and o.directory_mode ~= "lazy"
and o.directory_mode ~= "ignore" then
o.directory_mode = nil
end
end
options.read_options(o, nil, function(list)
split_option_exts(list.additional_video_exts, list.additional_audio_exts,
list.additional_image_exts)
if list.videos or list.additional_video_exts or
list.audio or list.additional_audio_exts or
list.images or list.additional_image_exts then
create_extensions()
end
if list.directory_mode then
validate_directory_mode()
end
if list.ignore_patterns then
split_patterns()
end
end)
split_option_exts(true, true, true)
split_patterns()
create_extensions()
validate_directory_mode()
local function add_files(files)
function add_files_at(index, files)
index = index - 1
local oldcount = mp.get_property_number("playlist-count", 1)
for i = 1, #files do
mp.commandv("loadfile", files[i][1], "append")
mp.commandv("playlist-move", oldcount + i - 1, files[i][2])
mp.commandv("loadfile", files[i], "append")
mp.commandv("playlist_move", oldcount + i - 1, index + i - 1)
end
end
local function get_extension(path)
return path:match("%.([^%.]+)$") or "nomatch"
end
local function is_ignored(file)
for pattern in pairs(o.ignore_patterns) do
if file:match(pattern) then
return true
end
end
return false
end
-- alphanum sorting for humans in Lua
-- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua
local function alphanumsort(filenames)
local function padnum(n, d)
return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d))
or ("%03d%s"):format(#n, n)
end
local tuples = {}
for i, f in ipairs(filenames) do
tuples[i] = {f:lower():gsub("0*(%d+)%.?(%d*)", padnum), f}
end
table.sort(tuples, function(a, b)
return a[1] == b[1] and #b[2] < #a[2] or a[1] < b[1]
end)
for i, tuple in ipairs(tuples) do filenames[i] = tuple[2] end
return filenames
end
local autoloaded
local added_entries = {}
local autoloaded_dir
local function scan_dir(path, current_file, dir_mode, separator, dir_depth, total_files, extensions)
if dir_depth == MAX_DIR_STACK then
return
end
msg.trace("scanning: " .. path)
local files = utils.readdir(path, "files") or {}
local dirs = dir_mode ~= "ignore" and utils.readdir(path, "dirs") or {}
local prefix = path == "." and "" or path
local function filter(t, iter)
for i = #t, 1, -1 do
if not iter(t[i]) then
table.remove(t, i)
end
end
end
filter(files, function(v)
-- Always accept current file
local current = prefix .. v == current_file
if current then
return true
end
if o.ignore_hidden and v:match("^%.") then
return false
end
if is_ignored(v) then
return false
end
local ext = get_extension(v)
return ext and extensions[ext:lower()]
end)
filter(dirs, function(d)
return not (o.ignore_hidden and d:match("^%."))
end)
alphanumsort(files)
alphanumsort(dirs)
for i, file in ipairs(files) do
files[i] = prefix .. file
end
local function append(t1, t2)
local t1_size = #t1
for i = 1, #t2 do
t1[t1_size + i] = t2[i]
end
end
append(total_files, files)
if dir_mode == "recursive" then
for _, dir in ipairs(dirs) do
scan_dir(prefix .. dir .. separator, current_file, dir_mode,
separator, dir_depth + 1, total_files, extensions)
end
else
for i, dir in ipairs(dirs) do
dirs[i] = prefix .. dir
end
append(total_files, dirs)
end
end
local function find_and_add_entries()
local aborted = mp.get_property_native("playback-abort")
if aborted then
msg.debug("stopping: playback aborted")
return
end
function find_and_add_entries()
local path = mp.get_property("path", "")
local dir, filename = utils.split_path(path)
msg.trace(("dir: %s, filename: %s"):format(dir, filename))
if o.disabled then
msg.debug("stopping: autoload disabled")
return
elseif #dir == 0 then
msg.debug("stopping: not a local path")
local dir, filename = mputils.split_path(path)
if #dir == 0 then
return
end
local pl_count = mp.get_property_number("playlist-count", 1)
local this_ext = get_extension(filename)
-- check if this is a manually made playlist
if pl_count > 1 and autoloaded == nil then
msg.debug("stopping: manually made playlist")
return
elseif pl_count == 1 then
autoloaded = true
autoloaded_dir = dir
added_entries = {}
local files = mputils.readdir(dir, "files")
table.sort(files)
if dir == "." then
dir = ""
end
local extensions
if o.same_type then
if EXTENSIONS_VIDEO[this_ext:lower()] then
extensions = EXTENSIONS_VIDEO
elseif EXTENSIONS_AUDIO[this_ext:lower()] then
extensions = EXTENSIONS_AUDIO
elseif EXTENSIONS_IMAGES[this_ext:lower()] then
extensions = EXTENSIONS_IMAGES
end
else
extensions = EXTENSIONS
end
if not extensions then
msg.debug("stopping: no matched extensions list")
return
end
local pl = mp.get_property_native("playlist", {})
local pl_current = mp.get_property_number("playlist-pos-1", 1)
msg.trace(("playlist-pos-1: %s, playlist: %s"):format(pl_current,
utils.to_string(pl)))
local files = {}
scan_dir(autoloaded_dir, path,
o.directory_mode or mp.get_property("directory-mode", "lazy"),
mp.get_property_native("platform") == "windows" and "\\" or "/",
0, files, extensions)
if next(files) == nil then
msg.debug("no other files or directories in directory")
return
end
local pl_current = mp.get_property_number("playlist-pos", 0) + 1
-- Find the current pl entry (dir+"/"+filename) in the sorted dir list
local current
for i = 1, #files do
if files[i] == path then
if files[i] == filename then
current = i
break
end
end
if not current then
msg.debug("current file not found in directory")
if current == nil then
return
end
msg.trace("current file position in files: "..current)
-- treat already existing playlist entries, independent of how they got added
-- as if they got added by autoload
for _, entry in ipairs(pl) do
added_entries[entry.filename] = true
end
-- stop initial file from being added twice
added_entries[path] = true
local append = {[-1] = {}, [1] = {}}
for direction = -1, 1, 2 do -- 2 iterations, with direction = -1 and +1
for i = 1, MAX_ENTRIES do
local pos = current + i * direction
local file = files[pos]
for i = 1, MAXENTRIES do
local file = files[current + i * direction]
local pl_e = pl[pl_current + i * direction]
if file == nil or file[1] == "." then
break
end
-- skip files that are/were already in the playlist
if not added_entries[file] then
if direction == -1 then
msg.verbose("Prepending " .. file)
table.insert(append[-1], 1, {file, pl_current + i * direction + 1})
else
msg.verbose("Adding " .. file)
if pl_count > 1 then
table.insert(append[1], {file, pl_current + i * direction - 1})
else
mp.commandv("loadfile", file, "append")
end
local filepath = dir .. file
if pl_e then
-- If there's a playlist entry, and it's the same file, stop.
if pl_e.filename == filepath then
break
end
added_entries[file] = true
end
if direction == -1 then
if pl_current == 1 then -- never add additional entries in the middle
mp.msg.info("Prepending " .. file)
table.insert(append[-1], 1, filepath)
end
else
mp.msg.info("Adding " .. file)
table.insert(append[1], filepath)
end
end
if pl_count == 1 and direction == -1 and #append[-1] > 0 then
local load = append[-1]
for i = 1, #load do
mp.commandv("loadfile", load[i][1], "append")
end
mp.commandv("playlist-move", 0, current)
end
end
if pl_count > 1 then
add_files(append[1])
add_files(append[-1])
end
add_files_at(pl_current + 1, append[1])
add_files_at(pl_current, append[-1])
end
mp.register_event("start-file", find_and_add_entries)
-129
View File
@@ -1,129 +0,0 @@
-- Test script for some command API details.
local utils = require("mp.utils")
local function join(sep, arr, count)
local r = ""
if count == nil then
count = #arr
end
for i = 1, count do
if i > 1 then
r = r .. sep
end
r = r .. utils.to_string(arr[i])
end
return r
end
mp.observe_property("vo-configured", "bool", function(_, v)
if v ~= true then
return
end
print("async expand-text")
mp.command_native_async({"expand-text", "hello ${path}!"},
function(res, val, err)
print("done async expand-text: " .. join(" ", {res, val, err}))
end)
-- make screenshot writing very slow
mp.set_property("screenshot-format", "png")
mp.set_property("screenshot-png-compression", "9")
local timer = mp.add_periodic_timer(0.1, function() print("I'm alive") end)
timer:resume()
print("Slow screenshot command...")
local result = mp.command_native({"screenshot"})
print("done, res: " .. utils.to_string(result))
print("Slow screenshot async command...")
result = mp.command_native_async({"screenshot"}, function(res)
print("done (async), res: " .. utils.to_string(res))
timer:kill()
end)
print("done (sending), res: " .. utils.to_string(result))
print("Broken screenshot async command...")
mp.command_native_async({"screenshot-to-file", "/nonexistent/bogus.png"},
function(res, val, err)
print("done err scr.: " .. join(" ", {res, val, err}))
end)
mp.command_native_async({
name = "subprocess",
args = {"sh", "-c", "echo hi && sleep 10s"},
capture_stdout = true
},
function(res, val, err)
print("done subprocess: " .. join(" ", {res, val, err}))
end)
local x = mp.command_native_async({name = "subprocess", args = {"sleep", "inf"}},
function(res, val, err)
print("done sleep inf subprocess: " .. join(" ", {res, val, err}))
end)
mp.add_timeout(15, function()
print("aborting sleep inf subprocess after timeout")
mp.abort_async_command(x)
end)
-- (assuming this "freezes")
local y = mp.command_native_async({name = "sub-add", url = "-"},
function(res, val, err)
print("done sub-add stdin: " .. join(" ", {res, val, err}))
end)
mp.add_timeout(20, function()
print("aborting sub-add stdin after timeout")
mp.abort_async_command(y)
end)
mp.command_native_async({name = "subprocess", args = {"wc", "-c"},
stdin_data = "hello", capture_stdout = true},
function(_, val)
print("Should be '5': " .. val.stdout)
end)
-- blocking stdin by default
mp.command_native_async({name = "subprocess", args = {"cat"},
capture_stdout = true},
function(_, val)
print("Should be 0: " .. #val.stdout)
end)
-- stdin + detached
mp.command_native_async({name = "subprocess",
args = {"bash", "-c", "(sleep 5s ; cat)"},
stdin_data = "this should appear after 5s.\n",
detach = true},
function(_, val)
print("5s test: " .. val.status)
end)
-- This should get killed on script exit.
mp.command_native_async({name = "subprocess", playback_only = false,
args = {"sleep", "inf"}}, function()end)
-- Runs detached; should be killed on player exit (forces timeout)
mp.command_native({_flags={"async"}, name = "subprocess",
playback_only = false, args = {"sleep", "inf"}})
end)
local counter
local function freeze_test(playback_only)
-- This "freezes" the script, should be killed via timeout.
counter = counter and counter + 1 or 0
print("freeze! " .. counter)
local x = mp.command_native({name = "subprocess",
playback_only = playback_only,
args = {"sleep", "inf"}})
print("done, killed=" .. utils.to_string(x.killed_by_us))
end
mp.register_event("shutdown", function()
freeze_test(false)
end)
mp.register_event("idle", function()
freeze_test(true)
end)
+7 -7
View File
@@ -15,11 +15,11 @@
-- TODO: It might make sense to use hardware assisted vdpaupp=pullup,
-- if available, but I don't have hardware to test it. Patch welcome.
local script_name = mp.get_script_name()
local pullup_label = string.format("%s-pullup", script_name)
script_name = mp.get_script_name()
pullup_label = string.format("%s-pullup", script_name)
local function pullup_on()
for _, vf in pairs(mp.get_property_native('vf')) do
function pullup_on()
for i,vf in pairs(mp.get_property_native('vf')) do
if vf['label'] == pullup_label then
return "yes"
end
@@ -27,10 +27,10 @@ local function pullup_on()
return "no"
end
local function do_cycle()
function do_cycle()
if pullup_on() == "yes" then
-- if pullup is on remove it
mp.command(string.format("vf remove @%s:pullup", pullup_label))
mp.command(string.format("vf del @%s:pullup", pullup_label))
return
elseif mp.get_property("deinterlace") == "yes" then
-- if deinterlace is on, turn it off and insert pullup filter
@@ -44,7 +44,7 @@ local function do_cycle()
end
end
local function cycle_deinterlace_pullup_handler()
function cycle_deinterlace_pullup_handler()
do_cycle()
-- independently determine current state and give user feedback
mp.osd_message(string.format("deinterlace: %s\n"..
+99
View File
@@ -0,0 +1,99 @@
-- This script enables live control of the dynamic range compression
-- (drc) audio filter while the video is playing back. This can be
-- useful to avoid having to stop and restart mpv to adjust filter
-- parameters. See the entry for "drc" under the "AUDIO FILTERS"
-- section of the man page for a complete description of the filter.
--
-- This script registers the key-binding "\" to toggle the filter between
--
-- * off
-- * method=1 (single-sample smoothing)
-- * method=2 (multi-sample smoothing)
--
-- It registers the keybindings ctrl+9/ctrl+0 to decrease/increase the
-- target ampltiude. These keys will insert the filter at the default
-- target amplitude of 0.25 if it was not previously present.
--
-- OSD feedback of the current filter state is displayed on pressing
-- each bound key.
script_name = mp.get_script_name()
function print_state(params)
if params then
mp.osd_message(script_name..":\n"
.."method = "..params["method"].."\n"
.."target = "..params["target"])
else
mp.osd_message(script_name..":\noff")
end
end
function get_index_of_drc(afs)
for i,af in pairs(afs) do
if af["label"] == script_name then
return i
end
end
end
function append_drc(afs)
afs[#afs+1] = {
name = "drc",
label = script_name,
params = {
method = "1",
target = "0.25"
}
}
print_state(afs[#afs]["params"])
end
function modify_or_create_af(fun)
afs = mp.get_property_native("af")
i = get_index_of_drc(afs)
if not i then
append_drc(afs)
else
fun(afs, i)
end
mp.set_property_native("af", afs)
end
function drc_toggle_method_handler()
modify_or_create_af(
function (afs, i)
new_method=(afs[i]["params"]["method"]+1)%3
if new_method == 0 then
table.remove(afs, i)
print_state(nil)
else
afs[i]["params"]["method"] = tostring((afs[i]["params"]["method"])%2+1)
print_state(afs[i]["params"])
end
end
)
end
function drc_scale_target(factor)
modify_or_create_af(
function (afs)
afs[i]["params"]["target"] = tostring(afs[i]["params"]["target"]*factor)
print_state(afs[i]["params"])
end
)
end
function drc_louder_handler()
drc_scale_target(2.0)
end
function drc_quieter_handler()
drc_scale_target(0.5)
end
-- toggle between off, method 1 and method 2
mp.add_key_binding("\\", "drc_toggle_method", drc_toggle_method_handler)
-- increase or decrease target volume
mp.add_key_binding("ctrl+9", "drc_quieter", drc_quieter_handler)
mp.add_key_binding("ctrl+0", "drc_louder", drc_louder_handler)
-29
View File
@@ -1,29 +0,0 @@
local function lux_to_gamma(lmin, lmax, rmin, rmax, lux)
if lmax <= lmin or lux == 0 then
return 1
end
local num = (rmax - rmin) * (math.log(lux, 10) - math.log(lmin, 10))
local den = math.log(lmax, 10) - math.log(lmin, 10)
local result = num / den + rmin
-- clamp the result
local max = math.max(rmax, rmin)
local min = math.min(rmax, rmin)
return math.max(math.min(result, max), min)
end
local function lux_changed(_, lux)
local gamma = lux_to_gamma(16.0, 256.0, 1.0, 1.2, lux or 0)
mp.set_property_number("gamma-factor", gamma)
end
if mp.get_property("platform") == "linux" then
-- observing ambient-light isn't supported on Linux
mp.add_periodic_timer(1, function()
lux_changed(nil, mp.get_property_number("ambient-light"))
end)
else
mp.observe_property("ambient-light", "number", lux_changed)
end
-37
View File
@@ -1,37 +0,0 @@
-- Test a float property which internally uses NaN.
-- Run with --no-config (or just scale-param1 not set).
local utils = require 'mp.utils'
local prop_name = "scale-param1"
-- internal NaN, return string "default" instead of NaN
local v = mp.get_property_native(prop_name, "fail")
print("Exp:", "string", "\"default\"")
print("Got:", type(v), utils.to_string(v))
v = mp.get_property(prop_name)
print("Exp:", "default")
print("Got:", v)
-- not representable -> return provided fallback value
v = mp.get_property_number(prop_name, -100)
print("Exp:", -100)
print("Got:", v)
mp.set_property_native(prop_name, 123)
v = mp.get_property_number(prop_name, -100)
print("Exp:", "number", 123)
print("Got:", type(v), utils.to_string(v))
-- try to set an actual NaN
local st, msg = mp.set_property_number(prop_name, 0.0/0)
print("Exp:", nil, "<message>")
print("Got:", st, msg)
-- set default
mp.set_property(prop_name, "default")
v = mp.get_property(prop_name)
print("Exp:", "default")
print("Got:", v)
+11 -17
View File
@@ -1,22 +1,16 @@
-- Test script for property change notification mechanism.
-- Note that watching/reading some properties can be very expensive, or
-- require the player to synchronously wait on network (when playing
-- remote files), so you should in general only watch properties you
-- are interested in.
local utils = require("mp.utils")
function format_property_val(v)
if type(v) == "table" then
return mp.format_table(v) -- undocumented function; might be removed
else
return tostring(v)
end
end
local function observe(name)
mp.observe_property(name, "native", function(prop, val)
print("property '" .. prop .. "' changed to '" ..
utils.to_string(val) .. "'")
for i,name in ipairs(mp.get_property_native("property-list")) do
mp.observe_property(name, "native", function(name, val)
print("property '" .. name .. "' changed to '" ..
format_property_val(val) .. "'")
end)
end
for _, name in ipairs(mp.get_property_native("property-list")) do
observe(name)
end
for _, name in ipairs(mp.get_property_native("options")) do
observe("options/" .. name)
end
-19
View File
@@ -1,19 +0,0 @@
--makes mpv disable ontop when pausing and re-enable it again when resuming playback
--please note that this won't do anything if ontop was not enabled before pausing
local was_ontop = false
mp.observe_property("pause", "bool", function(_, value)
local ontop = mp.get_property_native("ontop")
if value then
if ontop then
mp.set_property_native("ontop", false)
was_ontop = true
end
else
if was_ontop and not ontop then
mp.set_property_native("ontop", true)
end
was_ontop = false
end
end)
-35
View File
@@ -1,35 +0,0 @@
local assdraw = require 'mp.assdraw'
local utils = require 'mp.utils'
local things = {}
for i = 1, 2 do
things[i] = {
osd1 = mp.create_osd_overlay("ass-events"),
osd2 = mp.create_osd_overlay("ass-events")
}
end
things[1].text = "{\\an5}hello\\Nworld"
things[2].text = "{\\pos(400, 200)}something something"
mp.add_periodic_timer(2, function()
for i, thing in ipairs(things) do
thing.osd1.data = thing.text
thing.osd1.compute_bounds = true
--thing.osd1.hidden = true
local res = thing.osd1:update()
print("res " .. i .. ": " .. utils.to_string(res))
thing.osd2.hidden = true
if res ~= nil and res.x0 ~= nil then
local draw = assdraw.ass_new()
draw:append("{\\alpha&H80}")
draw:draw_start()
draw:pos(0, 0)
draw:rect_cw(res.x0, res.y0, res.x1, res.y1)
draw:draw_stop()
thing.osd2.hidden = false
thing.osd2.data = draw.text
end
thing.osd2:update()
end
end)
-20
View File
@@ -1,20 +0,0 @@
-- This script pauses playback when minimizing the window, and resumes playback
-- if it's brought back again. If the player was already paused when minimizing,
-- then try not to mess with the pause state.
local did_minimize = false
mp.observe_property("window-minimized", "bool", function(_, value)
local pause = mp.get_property_native("pause")
if value == true then
if pause == false then
mp.set_property_native("pause", true)
did_minimize = true
end
elseif value == false then
if did_minimize and (pause == true) then
mp.set_property_native("pause", false)
end
did_minimize = false
end
end)
-267
View File
@@ -1,267 +0,0 @@
--[[
Automatically skip in files if video frames with pre-supplied fingerprints are
detected. This will skip ahead by a pre-configured amount of time if a matching
video frame is detected.
This requires the vf_fingerprint video filter to be compiled in. Read the
documentation of this filter for caveats (which will automatically apply to
this script as well), such as no support for zero-copy hardware decoding.
You need to manually gather and provide fingerprints for video frames and add
them to a configuration file in script-opts/skip-logo.conf (the "script-opts"
directory must be in the mpv configuration directory, typically ~/.config/mpv/).
Example script-opts/skip-logo.conf:
cases = {
{
-- Skip ahead 10 seconds if a black frame was detected
-- Note: this is dangerous non-sense. It's just for demonstration.
name = "black frame", -- print if matched
skip = 10, -- number of seconds to skip forward
score = 0.3, -- required score
fingerprint = string.rep("0", 512),
},
{
-- Skip ahead 20 seconds if a white frame was detected
-- Note: this is dangerous non-sense. It's just for demonstration.
name = "fun2",
skip = 20,
fingerprint = string.rep("f", 512),
},
}
This is actually a lua file. Lua was chosen because it seemed less of a pain to
parse. Future versions of this script may change the format.
The fingerprint is a video frame, converted to "gray" (8 bit per pixels), full
range, each pixel concatenated into an array, converted to a hex string. You
can produce these fingerprints by running this manually:
mpv --vf=fingerprint:print yourfile.mkv
This will log the fingerprint of each video frame to the console, along with its
timestamp. You find the fingerprint of a unique-enough looking frame, and add
it as entry to skip-logo.conf.
You can provide a score for "fuzziness". If no score is provided, a default
value of 0.3 is used. The score is inverse: 0 means exactly the same, while a
higher score means a higher difference. Currently, the score is computed as
euclidean distance between the video frame and the pre-provided fingerprint,
thus the highest score is 16. You probably want a score lower than 1 at least.
(This algorithm is very primitive, but also simple and fast to compute.)
There's always the danger of false positives, which might be quite annoying.
It's up to you what you hate more, the logo, or random skips if false positives
are detected. Also, it's always active, and might eat too much CPU with files
that have a high resolution or framerate. To temporarily disable the script,
having a keybind like this in your input.conf will be helpful:
ctrl+k vf toggle @skip-logo
This will disable/enable the fingerprint filter, which the script automatically
adds at start.
Another important caveat is that the script currently disables matching during
seeking or playback initialization, which means it cannot match the first few
frames of a video. This could be fixed, but the author was too lazy to do so.
--]]
local msg = require "mp.msg"
local label = "skip-logo"
local meta_property = string.format("vf-metadata/%s", label)
local config = {}
local cases = {}
local cur_bmp
local seeking = false
local playback_start_pts = nil
-- Convert a hex string to an array. Convert each byte to a [0,1] float by
-- interpreting it as normalized uint8_t.
-- The data parameter, if not nil, may be used as storage (avoiding garbage).
local function hex_to_norm8(hex, data)
local size = math.floor(#hex / 2)
if #hex ~= size * 2 then
return nil
end
local res
if (data ~= nil) and (#data == size) then
res = data
else
res = {}
end
for i = 1, size do
local num = tonumber(hex:sub(i * 2, i * 2 + 1), 16)
if num == nil then
return nil
end
res[i] = num / 255.0
end
return res
end
local function compare_bmp(a, b)
if #a ~= #b then
return nil -- can't compare
end
local sum = 0
for i = 1, #a do
local diff = a[i] - b[i]
sum = sum + diff * diff
end
return math.sqrt(sum)
end
local function load_config()
local conf_file = mp.find_config_file("script-opts/skip-logo.conf")
local conf_fn
local err
if conf_file then
-- luacheck: push
-- luacheck: ignore setfenv
if setfenv then
conf_fn, err = loadfile(conf_file)
if conf_fn then
setfenv(conf_fn, config)
end
else
conf_fn, err = loadfile(conf_file, "t", config)
end
-- luacheck: pop
else
err = "config file not found"
end
if conf_fn and (not err) then
local _, err2 = pcall(conf_fn)
err = err2
end
if err then
msg.error("Failed to load config file:", err)
end
if config.cases then
for n, case in ipairs(config.cases) do
err = nil
case.bitmap = hex_to_norm8(case.fingerprint)
if case.bitmap == nil then
err = "invalid or missing fingerprint field"
end
if case.score == nil then
case.score = 0.3
end
if type(case.score) ~= "number" then
err = "score field is not a number"
end
if type(case.skip) ~= "number" then
err = "skip field is not a number or missing"
end
if case.name == nil then
case.name = ("Entry %d"):format(n)
end
if err == nil then
cases[#cases + 1] = case
else
msg.error(("Entry %s: %s, ignoring."):format(case.name, err))
end
end
end
end
load_config()
-- Returns true on match and if something was done.
local function check_fingerprint(hex, pts)
local bmp = hex_to_norm8(hex, cur_bmp)
cur_bmp = bmp
-- If parsing the filter's result failed (well, it shouldn't).
assert(bmp ~= nil, "filter returned nonsense")
for _, case in ipairs(cases) do
local score = compare_bmp(case.bitmap, bmp)
if (score ~= nil) and (score <= case.score) then
msg.warn(("Matching %s: score=%f (required: %f) at %s, skipping %f seconds"):
format(case.name, score, case.score, mp.format_time(pts), case.skip))
mp.commandv("seek", pts + case.skip, "absolute+exact")
return true
end
end
return false
end
local function read_frames()
local result = mp.get_property_native(meta_property)
if result == nil then
return
end
-- Try to get all entries. Out of laziness, assume that there are at most
-- 100 entries. (In fact, vf_fingerprint limits it to 10.)
for i = 0, 99 do
local prefix = string.format("fp%d.", i)
local hex = result[prefix .. "hex"]
local pts = tonumber(result[prefix .. "pts"])
if (hex == nil) or (pts == nil) then
break
end
local skip = false -- blame Lua for not having "continue" or "goto", not me
-- If seeking just stopped, there will be frames before the seek target,
-- ignore them by checking the timestamps.
if playback_start_pts ~= nil then
if pts >= playback_start_pts then
playback_start_pts = nil -- just for robustness
else
skip = true
end
end
if not skip then
if check_fingerprint(hex, pts) then
break
end
end
end
end
mp.observe_property(meta_property, "native", function()
-- Ignore frames that are decoded/filtered during seeking.
if seeking then
return
end
read_frames()
end)
mp.observe_property("seeking", "bool", function(_, val)
seeking = val
if seeking == false then
playback_start_pts = mp.get_property_number("playback-time")
read_frames()
end
end)
local filters = mp.get_property_native("option-info/vf/choices", {})
local found = false
for _, f in ipairs(filters) do
if f == "fingerprint" then
found = true
break
end
end
if found then
mp.command(("no-osd vf add @%s:fingerprint"):format(label))
else
msg.warn("vf_fingerprint not found")
end
+10 -35
View File
@@ -1,16 +1,12 @@
-- Rebuild the terminal status line as a lua script
-- Be aware that this will require more cpu power!
-- Also, this is based on a rather old version of the
-- builtin mpv status line.
local newStatus
-- Add a string to the status line
local function atsl(s)
function atsl(s)
newStatus = newStatus .. s
end
local function update_status_line()
function update_status_line()
-- Reset the status line
newStatus = ""
@@ -20,10 +16,10 @@ local function update_status_line()
atsl("(Buffering) ")
end
if mp.get_property("aid") ~= "no" then
if mp.get_property("vid") ~= "no" then
atsl("A")
end
if mp.get_property("vid") ~= "no" then
if mp.get_property("aid") ~= "no" then
atsl("V")
end
@@ -32,7 +28,7 @@ local function update_status_line()
atsl(mp.get_property_osd("time-pos"))
atsl(" / ");
atsl(mp.get_property_osd("duration"));
atsl(mp.get_property_osd("length"));
atsl(" (")
atsl(mp.get_property_osd("percent-pos", -1))
@@ -43,9 +39,9 @@ local function update_status_line()
atsl(string.format(" x%4.2f", r))
end
r = mp.get_property_number("avsync")
r = mp.get_property_number("avsync", nil)
if r ~= nil then
atsl(string.format(" A-V: %f", r))
atsl(string.format(" A-V: %7.3f", r))
end
r = mp.get_property("total-avsync-change", 0)
@@ -53,24 +49,12 @@ local function update_status_line()
atsl(string.format(" ct:%7.3f", r))
end
r = mp.get_property_number("decoder-drop-frame-count", -1)
r = mp.get_property_number("drop-frame-count", -1)
if r > 0 then
atsl(" Late: ")
atsl(r)
end
r = mp.get_property_osd("video-bitrate")
if r ~= nil and r ~= "" then
atsl(" Vb: ")
atsl(r)
end
r = mp.get_property_osd("audio-bitrate")
if r ~= nil and r ~= "" then
atsl(" Ab: ")
atsl(r)
end
r = mp.get_property_number("cache", 0)
if r > 0 then
atsl(string.format(" Cache: %d%% ", r))
@@ -80,15 +64,6 @@ local function update_status_line()
mp.set_property("options/term-status-msg", newStatus)
end
local timer = mp.add_periodic_timer(1, update_status_line)
-- Register the event
mp.register_event("tick", update_status_line)
local function on_pause_change(_, value)
if value == false then
timer:resume()
else
timer:stop()
end
mp.add_timeout(0.1, update_status_line)
end
mp.observe_property("pause", "bool", on_pause_change)
mp.register_event("seek", update_status_line)
-32
View File
@@ -1,32 +0,0 @@
local utils = require("mp.utils")
local function hardsleep()
os.execute("sleep 1")
end
local hooks = {"on_before_start_file", "on_load", "on_load_fail",
"on_preloaded", "on_unload", "on_after_end_file"}
for _, name in ipairs(hooks) do
mp.add_hook(name, 0, function()
print("--- hook: " .. name)
hardsleep()
print(" ... continue")
end)
end
local events = {"start-file", "end-file", "file-loaded", "seek",
"playback-restart", "idle", "shutdown"}
for _, name in ipairs(events) do
mp.register_event(name, function()
print("--- event: " .. name)
end)
end
local props = {"path", "metadata"}
for _, name in ipairs(props) do
mp.observe_property(name, "native", function(prop, val)
print("property '" .. prop .. "' changed to '" ..
utils.to_string(val) .. "'")
end)
end
Loaded 100 of 1091 files, more files were not shown because too many files have changed in this diff. Show more