Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4e4d9cbba | ||
|
|
fa53c3fc7b | ||
|
|
c61f76829f | ||
|
|
30e77e0fc5 | ||
|
|
328a0f9c80 | ||
|
|
4f2104961e | ||
|
|
c2ef2bcb90 | ||
|
|
86229e8714 | ||
|
|
295fdeb086 | ||
|
|
909c4d7711 | ||
|
|
0f83f1e4b3 | ||
|
|
9c83e8483e | ||
|
|
e0e58e18c0 | ||
|
|
6f9eb960c7 | ||
|
|
a4b21b5a13 | ||
|
|
799458a5b1 | ||
|
|
c774f2c3bb | ||
|
|
9e6091a5b1 | ||
|
|
74c2146092 | ||
|
|
7af2cb08e2 | ||
|
|
155ecb2c14 | ||
|
|
2a2dc4d73c | ||
|
|
d855be5ec1 | ||
|
|
141728832b | ||
|
|
a8b364cad3 | ||
|
|
c282cd679c | ||
|
|
1f815558b8 | ||
|
|
a0de98871b | ||
|
|
3711327430 | ||
|
|
7d523cd47a | ||
|
|
224abe9e23 | ||
|
|
c6d54cccb5 | ||
|
|
081368dabf | ||
|
|
3b5b2144c3 | ||
|
|
a80166f22a | ||
|
|
126b7c4739 | ||
|
|
f8b842cdf3 | ||
|
|
ad9ea546d3 | ||
|
|
c63d929261 | ||
|
|
595c4cf872 | ||
|
|
4ebed102f0 | ||
|
|
371b52e377 | ||
|
|
d8152b7003 | ||
|
|
6a9cdfa771 | ||
|
|
399e746275 | ||
|
|
929c4a5529 | ||
|
|
38903486fb | ||
|
|
c56b237b3c | ||
|
|
63e401ccc9 | ||
|
|
35cc1830a3 | ||
|
|
f4a9c9424f | ||
|
|
d9da0c9ce9 | ||
|
|
5f3f36a800 | ||
|
|
12c316d95e | ||
|
|
cf997ff691 | ||
|
|
1560f74dde | ||
|
|
9b9d453748 | ||
|
|
cb9b59858d | ||
|
|
3f85092ffe | ||
|
|
f4634e404f | ||
|
|
dbc00297cc | ||
|
|
1e14d65db8 | ||
|
|
57829ed95a | ||
|
|
2f69e8f93c | ||
|
|
6b063b3767 | ||
|
|
a5191c1479 | ||
|
|
cfc5a65494 | ||
|
|
307b8925ee | ||
|
|
2090a35c57 | ||
|
|
2746910515 | ||
|
|
40dce4048f | ||
|
|
465bd38dc6 | ||
|
|
5992ff785c | ||
|
|
b6d8694062 | ||
|
|
7b8ab2005e | ||
|
|
4912fef753 | ||
|
|
c9c9919b2d | ||
|
|
b1c76e6a59 | ||
|
|
58c91c02e2 | ||
|
|
5c1c8b5fab | ||
|
|
85f54ce5d0 | ||
|
|
c473688c5f | ||
|
|
413bd22527 | ||
|
|
ccf8c42a42 | ||
|
|
4759f61e73 | ||
|
|
1a346ce11b | ||
|
|
891a9727c6 | ||
|
|
2e133e9dde | ||
|
|
f5c19f29af | ||
|
|
ca048e8d6d | ||
|
|
a2f4391ca1 | ||
|
|
4971ad9e17 | ||
|
|
3d94938246 | ||
|
|
d627c579ea | ||
|
|
752dd2ef76 | ||
|
|
562e42f826 | ||
|
|
ad3d8ce5c6 | ||
|
|
777bffd307 | ||
|
|
7f839323cb | ||
|
|
cb4b28e336 | ||
|
|
35be53108e | ||
|
|
9f4d44f8c7 | ||
|
|
d60940a080 | ||
|
|
dab7602a89 | ||
|
|
37210f0cbc | ||
|
|
f24b8cbd47 | ||
|
|
b706198207 | ||
|
|
e213e20c2d | ||
|
|
2ade5c8477 | ||
|
|
15a191f920 | ||
|
|
899822c001 | ||
|
|
a9db58cc3b | ||
|
|
21c4c50ac6 | ||
|
|
86493730b2 | ||
|
|
87e635e843 | ||
|
|
b0759abe9c | ||
|
|
ebd4bf9792 | ||
|
|
ab4c857ff6 | ||
|
|
e3f4491a24 | ||
|
|
12ee2e64be | ||
|
|
ead565afb3 | ||
|
|
9f80936ddc | ||
|
|
6a8dad4c3a | ||
|
|
3d710630a4 | ||
|
|
f83e28d893 | ||
|
|
3f66dd82b1 | ||
|
|
c4c95f0dde | ||
|
|
60c6307a97 | ||
|
|
99f237beb9 | ||
|
|
6cf54d6bc0 | ||
|
|
c6ce2c6b43 | ||
|
|
7f92344138 | ||
|
|
d56a1112d2 | ||
|
|
b1292c044a | ||
|
|
18fb4bff6f | ||
|
|
7e60fb2c97 | ||
|
|
8c8af64820 | ||
|
|
3ee6992656 | ||
|
|
9a7f332571 | ||
|
|
fadf87f2a7 | ||
|
|
62c7a372ec | ||
|
|
0692da3007 | ||
|
|
0fcb96139d | ||
|
|
5f6b5feac6 | ||
|
|
e2a4fde6de | ||
|
|
01401b5f5b | ||
|
|
f794eca255 | ||
|
|
ad2a461a09 | ||
|
|
2e931b34f4 | ||
|
|
ade8b6214d | ||
|
|
78e957a2bd | ||
|
|
9eb75631c7 | ||
|
|
0c8a419775 | ||
|
|
885c6e5b07 | ||
|
|
44a7649e79 | ||
|
|
fded4de8a7 | ||
|
|
f20575f3dd | ||
|
|
1936cfdb09 | ||
|
|
84c2dc882d | ||
|
|
d72718ca65 | ||
|
|
8a73b02952 | ||
|
|
b4174ab4e9 | ||
|
|
ce5f0f1a7a | ||
|
|
e02146b0c0 | ||
|
|
804468b1ac | ||
|
|
d8455f34c1 | ||
|
|
b0877e5454 | ||
|
|
c926927c59 | ||
|
|
9af1ff9817 | ||
|
|
ca34fd569d | ||
|
|
4bb2da8204 | ||
|
|
6d7eb8346a | ||
|
|
cd99121185 | ||
|
|
392159337f | ||
|
|
fffd7e7a3a | ||
|
|
59781d3cb3 | ||
|
|
4a6cb85993 | ||
|
|
74a3d29f21 | ||
|
|
07acf5cb9a | ||
|
|
8e1e814166 | ||
|
|
da21670880 | ||
|
|
2cac69f221 | ||
|
|
99cca56a99 | ||
|
|
676457256a | ||
|
|
7368d8f353 | ||
|
|
2c9e0c0a29 | ||
|
|
8d3259a391 | ||
|
|
faf561c4ec | ||
|
|
8c54b56f43 | ||
|
|
a44ffb729b | ||
|
|
947a791992 | ||
|
|
42f82c5ccf | ||
|
|
1a3a52ea25 | ||
|
|
77d5aa56b3 | ||
|
|
1f795b6172 | ||
|
|
22a06b0e81 | ||
|
|
f551da2cfb | ||
|
|
ac06ba0aec | ||
|
|
99dc774dbb | ||
|
|
83d44a4f6a | ||
|
|
6609f68691 | ||
|
|
e2beeffb92 | ||
|
|
704c24776a | ||
|
|
cc32aa436e | ||
|
|
57f149e26a | ||
|
|
a77fec7547 | ||
|
|
18c8d60b54 | ||
|
|
1eb4e90161 | ||
|
|
f3e515c790 | ||
|
|
0547b2a637 | ||
|
|
906448243c | ||
|
|
1ea7b386a9 | ||
|
|
a82f2e2792 | ||
|
|
e0231926df | ||
|
|
2c20c6f892 | ||
|
|
bde22281f7 | ||
|
|
697a7b7d19 | ||
|
|
422502f524 | ||
|
|
34cbc9057c | ||
|
|
36a2dd5ace | ||
|
|
6cec24e980 | ||
|
|
9b2b95ee52 | ||
|
|
47d972102e | ||
|
|
0cf7316c47 | ||
|
|
3a6572d206 | ||
|
|
8ab8fa8960 | ||
|
|
295622bab1 | ||
|
|
8def7ccb4f | ||
|
|
f88a86a936 | ||
|
|
1783e8cade | ||
|
|
c7d6b21789 | ||
|
|
8d4e6498c3 | ||
|
|
9984f4fffd | ||
|
|
75a62c7a64 | ||
|
|
73eaadf6c3 | ||
|
|
292f6f1904 | ||
|
|
5a2947c9d0 | ||
|
|
fdea35a71b | ||
|
|
8f6eb196cd | ||
|
|
3b6e063599 | ||
|
|
015218f8c8 | ||
|
|
00d1d6d807 | ||
|
|
49c3cbfb4e | ||
|
|
925becfb15 | ||
|
|
2cebc52065 | ||
|
|
34e504bf93 | ||
|
|
f0649ce841 | ||
|
|
65af6a55b7 | ||
|
|
1326d3f0b8 | ||
|
|
b062b54626 | ||
|
|
9bee56cc67 | ||
|
|
9fb0180eb2 | ||
|
|
4f8af1a518 | ||
|
|
62b6048468 | ||
|
|
b6363c8100 | ||
|
|
db4cec8a6c | ||
|
|
4de6f4f616 | ||
|
|
7c53bb4bb1 | ||
|
|
115709e3c1 | ||
|
|
1e8dbf8212 | ||
|
|
1bfaab13ca | ||
|
|
083235d91f | ||
|
|
bc4e115b30 | ||
|
|
807763c85e | ||
|
|
69fa6c4b73 | ||
|
|
3141381c2e | ||
|
|
8f847437a9 | ||
|
|
487fcea6f4 | ||
|
|
63a31db0a3 | ||
|
|
575edecccb | ||
|
|
14adda8f6b | ||
|
|
7cacff6d61 | ||
|
|
4ced125239 | ||
|
|
ac94c81134 | ||
|
|
9501050ddc | ||
|
|
c688880f9e | ||
|
|
47ec404a52 | ||
|
|
18b15a436f | ||
|
|
6583ad6970 | ||
|
|
863701391c | ||
|
|
3803c14279 | ||
|
|
39126c3828 | ||
|
|
b9cfc3622c | ||
|
|
1b0bf6507e | ||
|
|
7ca6aa4ad0 | ||
|
|
b82a98722a | ||
|
|
3d6d7012ff | ||
|
|
3051ff9f25 | ||
|
|
9bf66294f8 | ||
|
|
577378b827 | ||
|
|
1679222e18 | ||
|
|
74270cd1db | ||
|
|
718bf3b39e | ||
|
|
5ecb381d78 | ||
|
|
17f1332955 | ||
|
|
f4a1dfdffb | ||
|
|
d3972125a1 | ||
|
|
71f504a43d | ||
|
|
bc1370041d | ||
|
|
4f74869cd8 | ||
|
|
8d8b36df1b | ||
|
|
2da6c95208 |
No files matched your search
@@ -28,8 +28,6 @@
|
||||
/DOCS/man/mpv.toc
|
||||
|
||||
/waf
|
||||
/waf-*
|
||||
/waf3-*
|
||||
/build
|
||||
/.waf*
|
||||
/.lock-waf_*
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ language: c
|
||||
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
- osx
|
||||
env:
|
||||
matrix:
|
||||
- LIBAV=libav-stable
|
||||
|
||||
@@ -25,19 +25,6 @@ API changes
|
||||
|
||||
::
|
||||
|
||||
--- mpv 0.8.0 is released ---
|
||||
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 is released ---
|
||||
1.10 - deprecate/disable everything directly related to script_dispatch
|
||||
(most likely affects nobody)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
Client API examples
|
||||
===================
|
||||
|
||||
All these examples use the mpv client API through libmpv.
|
||||
|
||||
cocoa
|
||||
-----
|
||||
|
||||
Shows how to embed the mpv video window in Objective-C/Cocoa.
|
||||
|
||||
qt
|
||||
--
|
||||
|
||||
Shows how to embed the mpv video window in Qt (using normal desktop widgets).
|
||||
|
||||
qml
|
||||
---
|
||||
|
||||
Shows how to use mpv's OpenGL video renderer in QtQuick2 with QML.
|
||||
|
||||
qml_direct
|
||||
----------
|
||||
|
||||
Alternative example, which typically avoids a FBO indirection. Might be
|
||||
slightly faster, but is less flexible and harder to use.
|
||||
|
||||
simple
|
||||
------
|
||||
|
||||
Very primitive terminal-only example. Shows some most basic API usage.
|
||||
+2
-14
@@ -3,20 +3,8 @@
|
||||
// but that's not quite ready yet.
|
||||
// You may need a basic Info.plist and MainMenu.xib to make this work.
|
||||
|
||||
// Build with: clang -o cocoabasic cocoabasic.m `pkg-config --libs --cflags mpv`
|
||||
|
||||
#include <mpv/client.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#include "../../libmpv/client.h"
|
||||
#include "shared.h"
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
#include "main.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <clocale>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <QOpenGLContext>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <QtGui/QOpenGLFramebufferObject>
|
||||
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtQuick/QQuickView>
|
||||
|
||||
class MpvRenderer : public QQuickFramebufferObject::Renderer
|
||||
{
|
||||
static void *get_proc_address(void *ctx, const char *name) {
|
||||
(void)ctx;
|
||||
QOpenGLContext *glctx = QOpenGLContext::currentContext();
|
||||
if (!glctx)
|
||||
return NULL;
|
||||
return (void *)glctx->getProcAddress(QByteArray(name));
|
||||
}
|
||||
|
||||
mpv::qt::Handle mpv;
|
||||
QQuickWindow *window;
|
||||
mpv_opengl_cb_context *mpv_gl;
|
||||
public:
|
||||
MpvRenderer(const MpvObject *obj)
|
||||
: mpv(obj->mpv), window(obj->window()), mpv_gl(obj->mpv_gl)
|
||||
{
|
||||
int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL);
|
||||
if (r < 0)
|
||||
throw std::runtime_error("could not initialize OpenGL");
|
||||
}
|
||||
|
||||
virtual ~MpvRenderer()
|
||||
{
|
||||
// Until this call is done, we need to make sure the player remains
|
||||
// alive. This is done implicitly with the mpv::qt::Handle instance
|
||||
// in this class.
|
||||
mpv_opengl_cb_uninit_gl(mpv_gl);
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
QOpenGLFramebufferObject *fbo = framebufferObject();
|
||||
int vp[4] = {0, 0, fbo->width(), fbo->height()};
|
||||
window->resetOpenGLState();
|
||||
mpv_opengl_cb_render(mpv_gl, fbo->handle(), vp);
|
||||
window->resetOpenGLState();
|
||||
}
|
||||
};
|
||||
|
||||
MpvObject::MpvObject(QQuickItem * parent)
|
||||
: QQuickFramebufferObject(parent), mpv_gl(0)
|
||||
{
|
||||
mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
|
||||
if (!mpv)
|
||||
throw std::runtime_error("could not create mpv context");
|
||||
|
||||
mpv_set_option_string(mpv, "terminal", "yes");
|
||||
mpv_set_option_string(mpv, "msg-level", "all=v");
|
||||
|
||||
if (mpv_initialize(mpv) < 0)
|
||||
throw std::runtime_error("could not initialize mpv context");
|
||||
|
||||
// Make use of the MPV_SUB_API_OPENGL_CB API.
|
||||
mpv::qt::set_option_variant(mpv, "vo", "opengl-cb");
|
||||
|
||||
// Request hw decoding, just for testing.
|
||||
mpv::qt::set_option_variant(mpv, "hwdec", "auto");
|
||||
|
||||
// Setup the callback that will make QtQuick update and redraw if there
|
||||
// is a new video frame. Use a queued connection: this makes sure the
|
||||
// doUpdate() function is run on the GUI thread.
|
||||
mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB);
|
||||
if (!mpv_gl)
|
||||
throw std::runtime_error("OpenGL not compiled in");
|
||||
mpv_opengl_cb_set_update_callback(mpv_gl, MpvObject::on_update, (void *)this);
|
||||
connect(this, &MpvObject::onUpdate, this, &MpvObject::doUpdate,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
MpvObject::~MpvObject()
|
||||
{
|
||||
if (mpv_gl)
|
||||
mpv_opengl_cb_set_update_callback(mpv_gl, NULL, NULL);
|
||||
}
|
||||
|
||||
void MpvObject::on_update(void *ctx)
|
||||
{
|
||||
MpvObject *self = (MpvObject *)ctx;
|
||||
emit self->onUpdate();
|
||||
}
|
||||
|
||||
// connected to onUpdate(); signal makes sure it runs on the GUI thread
|
||||
void MpvObject::doUpdate()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void MpvObject::command(const QVariant& params)
|
||||
{
|
||||
mpv::qt::command_variant(mpv, params);
|
||||
}
|
||||
|
||||
void MpvObject::setProperty(const QString& name, const QVariant& value)
|
||||
{
|
||||
mpv::qt::set_property_variant(mpv, name, value);
|
||||
}
|
||||
|
||||
QQuickFramebufferObject::Renderer *MpvObject::createRenderer() const
|
||||
{
|
||||
window()->setPersistentOpenGLContext(true);
|
||||
window()->setPersistentSceneGraph(true);
|
||||
return new MpvRenderer(this);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// Qt sets the locale in the QGuiApplication constructor, but libmpv
|
||||
// requires the LC_NUMERIC category to be set to "C", so change it back.
|
||||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
qmlRegisterType<MpvObject>("mpvtest", 1, 0, "MpvObject");
|
||||
|
||||
QQuickView view;
|
||||
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
view.setSource(QUrl("qrc:///mpvtest/main.qml"));
|
||||
view.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef MPVRENDERER_H_
|
||||
#define MPVRENDERER_H_
|
||||
|
||||
#include <QtQuick/QQuickFramebufferObject>
|
||||
|
||||
#include <mpv/client.h>
|
||||
#include <mpv/opengl_cb.h>
|
||||
#include <mpv/qthelper.hpp>
|
||||
|
||||
class MpvRenderer;
|
||||
|
||||
class MpvObject : public QQuickFramebufferObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
mpv::qt::Handle mpv;
|
||||
mpv_opengl_cb_context *mpv_gl;
|
||||
|
||||
friend class MpvRenderer;
|
||||
|
||||
public:
|
||||
MpvObject(QQuickItem * parent = 0);
|
||||
virtual ~MpvObject();
|
||||
virtual Renderer *createRenderer() const;
|
||||
public slots:
|
||||
void command(const QVariant& params);
|
||||
void setProperty(const QString& name, const QVariant& value);
|
||||
signals:
|
||||
void onUpdate();
|
||||
private slots:
|
||||
void doUpdate();
|
||||
private:
|
||||
static void on_update(void *ctx);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 1.0
|
||||
|
||||
import mpvtest 1.0
|
||||
|
||||
Item {
|
||||
width: 1280
|
||||
height: 720
|
||||
|
||||
MpvObject {
|
||||
id: renderer
|
||||
anchors.fill: parent
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: renderer.command(["loadfile", "../../../test.mkv"])
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: labelFrame
|
||||
anchors.margins: -50
|
||||
radius: 5
|
||||
color: "white"
|
||||
border.color: "black"
|
||||
opacity: 0.8
|
||||
anchors.fill: box
|
||||
}
|
||||
|
||||
Row {
|
||||
id: box
|
||||
anchors.bottom: renderer.bottom
|
||||
anchors.left: renderer.left
|
||||
anchors.right: renderer.right
|
||||
anchors.margins: 100
|
||||
|
||||
Text {
|
||||
anchors.margins: 10
|
||||
wrapMode: Text.WordWrap
|
||||
text: "QtQuick and mpv are both rendering stuff.\n
|
||||
Click to load ../../../test.mkv"
|
||||
}
|
||||
|
||||
// Don't take these controls too seriously. They're for testing.
|
||||
Column {
|
||||
CheckBox {
|
||||
id: checkbox
|
||||
anchors.margins: 10
|
||||
// Heavily filtered means good, right?
|
||||
text: "Make video look like on a Smart TV"
|
||||
onClicked: {
|
||||
if (checkbox.checked) {
|
||||
renderer.command(["vo_cmdline", "scale=sharpen3:scale-param1=5.0"])
|
||||
} else {
|
||||
renderer.command(["vo_cmdline", ""])
|
||||
}
|
||||
}
|
||||
}
|
||||
Slider {
|
||||
id: slider
|
||||
anchors.margins: 10
|
||||
anchors.left: checkbox.left
|
||||
anchors.right: checkbox.right
|
||||
minimumValue: -100
|
||||
maximumValue: 100
|
||||
value: 0
|
||||
onValueChanged: renderer.setProperty("gamma", slider.value | 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
QT += qml quick
|
||||
|
||||
HEADERS += main.h
|
||||
SOURCES += main.cpp
|
||||
|
||||
CONFIG += link_pkgconfig debug
|
||||
PKGCONFIG += mpv
|
||||
|
||||
RESOURCES += mpvtest.qrc
|
||||
|
||||
OTHER_FILES += main.qml
|
||||
@@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/mpvtest">
|
||||
<file>main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -1,154 +0,0 @@
|
||||
#include "main.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <clocale>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtGlobal>
|
||||
#include <QOpenGLContext>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
#include <QtQuick/QQuickView>
|
||||
|
||||
static void *get_proc_address(void *ctx, const char *name) {
|
||||
(void)ctx;
|
||||
QOpenGLContext *glctx = QOpenGLContext::currentContext();
|
||||
if (!glctx)
|
||||
return NULL;
|
||||
return (void *)glctx->getProcAddress(QByteArray(name));
|
||||
}
|
||||
|
||||
MpvRenderer::MpvRenderer(mpv::qt::Handle a_mpv, mpv_opengl_cb_context *a_mpv_gl)
|
||||
: mpv(a_mpv), mpv_gl(a_mpv_gl), window(0), size()
|
||||
{
|
||||
int r = mpv_opengl_cb_init_gl(mpv_gl, NULL, get_proc_address, NULL);
|
||||
if (r < 0)
|
||||
throw std::runtime_error("could not initialize OpenGL");
|
||||
}
|
||||
|
||||
MpvRenderer::~MpvRenderer()
|
||||
{
|
||||
// Until this call is done, we need to make sure the player remains
|
||||
// alive. This is done implicitly with the mpv::qt::Handle instance
|
||||
// in this class.
|
||||
mpv_opengl_cb_uninit_gl(mpv_gl);
|
||||
}
|
||||
|
||||
void MpvRenderer::paint()
|
||||
{
|
||||
window->resetOpenGLState();
|
||||
|
||||
// Render to the whole window.
|
||||
int vp[4] = {0, 0, size.width(), -size.height()};
|
||||
|
||||
// This uses 0 as framebuffer, which indicates that mpv will render directly
|
||||
// to the frontbuffer. Note that mpv will always switch framebuffers
|
||||
// explicitly. Some QWindow setups (such as using QQuickWidget) actually
|
||||
// want you to render into a FBO in the beforeRendering() signal, and this
|
||||
// code won't work there.
|
||||
mpv_opengl_cb_render(mpv_gl, 0, vp);
|
||||
|
||||
window->resetOpenGLState();
|
||||
}
|
||||
|
||||
MpvObject::MpvObject(QQuickItem * parent)
|
||||
: QQuickItem(parent), mpv_gl(0), renderer(0)
|
||||
{
|
||||
mpv = mpv::qt::Handle::FromRawHandle(mpv_create());
|
||||
if (!mpv)
|
||||
throw std::runtime_error("could not create mpv context");
|
||||
|
||||
mpv_set_option_string(mpv, "terminal", "yes");
|
||||
mpv_set_option_string(mpv, "msg-level", "all=v");
|
||||
|
||||
if (mpv_initialize(mpv) < 0)
|
||||
throw std::runtime_error("could not initialize mpv context");
|
||||
|
||||
// Make use of the MPV_SUB_API_OPENGL_CB API.
|
||||
mpv::qt::set_option_variant(mpv, "vo", "opengl-cb");
|
||||
|
||||
// Setup the callback that will make QtQuick update and redraw if there
|
||||
// is a new video frame. Use a queued connection: this makes sure the
|
||||
// doUpdate() function is run on the GUI thread.
|
||||
mpv_gl = (mpv_opengl_cb_context *)mpv_get_sub_api(mpv, MPV_SUB_API_OPENGL_CB);
|
||||
if (!mpv_gl)
|
||||
throw std::runtime_error("OpenGL not compiled in");
|
||||
mpv_opengl_cb_set_update_callback(mpv_gl, MpvObject::on_update, (void *)this);
|
||||
connect(this, &MpvObject::onUpdate, this, &MpvObject::doUpdate,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(this, &QQuickItem::windowChanged,
|
||||
this, &MpvObject::handleWindowChanged);
|
||||
}
|
||||
|
||||
MpvObject::~MpvObject()
|
||||
{
|
||||
if (mpv_gl)
|
||||
mpv_opengl_cb_set_update_callback(mpv_gl, NULL, NULL);
|
||||
}
|
||||
|
||||
void MpvObject::handleWindowChanged(QQuickWindow *win)
|
||||
{
|
||||
if (!win)
|
||||
return;
|
||||
connect(win, &QQuickWindow::beforeSynchronizing,
|
||||
this, &MpvObject::sync, Qt::DirectConnection);
|
||||
connect(win, &QQuickWindow::sceneGraphInvalidated,
|
||||
this, &MpvObject::cleanup, Qt::DirectConnection);
|
||||
win->setClearBeforeRendering(false);
|
||||
}
|
||||
|
||||
void MpvObject::sync()
|
||||
{
|
||||
if (!renderer) {
|
||||
renderer = new MpvRenderer(mpv, mpv_gl);
|
||||
connect(window(), &QQuickWindow::beforeRendering,
|
||||
renderer, &MpvRenderer::paint, Qt::DirectConnection);
|
||||
}
|
||||
renderer->window = window();
|
||||
renderer->size = window()->size() * window()->devicePixelRatio();
|
||||
}
|
||||
|
||||
void MpvObject::cleanup()
|
||||
{
|
||||
if (renderer) {
|
||||
delete renderer;
|
||||
renderer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MpvObject::on_update(void *ctx)
|
||||
{
|
||||
MpvObject *self = (MpvObject *)ctx;
|
||||
emit self->onUpdate();
|
||||
}
|
||||
|
||||
// connected to onUpdate(); signal makes sure it runs on the GUI thread
|
||||
void MpvObject::doUpdate()
|
||||
{
|
||||
window()->update();
|
||||
}
|
||||
|
||||
void MpvObject::command(const QVariant& params)
|
||||
{
|
||||
mpv::qt::command_variant(mpv, params);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// Qt sets the locale in the QGuiApplication constructor, but libmpv
|
||||
// requires the LC_NUMERIC category to be set to "C", so change it back.
|
||||
std::setlocale(LC_NUMERIC, "C");
|
||||
|
||||
qmlRegisterType<MpvObject>("mpvtest", 1, 0, "MpvObject");
|
||||
|
||||
QQuickView view;
|
||||
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
view.setSource(QUrl("qrc:///mpvtest/main.qml"));
|
||||
view.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
#ifndef MPVRENDERER_H_
|
||||
#define MPVRENDERER_H_
|
||||
|
||||
#include <QtQuick/QQuickItem>
|
||||
|
||||
#include <mpv/client.h>
|
||||
#include <mpv/opengl_cb.h>
|
||||
#include <mpv/qthelper.hpp>
|
||||
|
||||
class MpvRenderer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
mpv::qt::Handle mpv;
|
||||
mpv_opengl_cb_context *mpv_gl;
|
||||
QQuickWindow *window;
|
||||
QSize size;
|
||||
|
||||
friend class MpvObject;
|
||||
public:
|
||||
MpvRenderer(mpv::qt::Handle a_mpv, mpv_opengl_cb_context *a_mpv_gl);
|
||||
virtual ~MpvRenderer();
|
||||
public slots:
|
||||
void paint();
|
||||
};
|
||||
|
||||
class MpvObject : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
mpv::qt::Handle mpv;
|
||||
mpv_opengl_cb_context *mpv_gl;
|
||||
MpvRenderer *renderer;
|
||||
|
||||
public:
|
||||
MpvObject(QQuickItem * parent = 0);
|
||||
virtual ~MpvObject();
|
||||
public slots:
|
||||
void command(const QVariant& params);
|
||||
void sync();
|
||||
void cleanup();
|
||||
signals:
|
||||
void onUpdate();
|
||||
private slots:
|
||||
void doUpdate();
|
||||
void handleWindowChanged(QQuickWindow *win);
|
||||
private:
|
||||
static void on_update(void *ctx);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,49 +0,0 @@
|
||||
import QtQuick 2.0
|
||||
import QtQuick.Controls 1.0
|
||||
|
||||
import mpvtest 1.0
|
||||
|
||||
Item {
|
||||
width: 1280
|
||||
height: 720
|
||||
|
||||
MpvObject {
|
||||
id: renderer
|
||||
|
||||
// This object isn't real and not visible; it just renders into the
|
||||
// background of the containing Window.
|
||||
width: 0
|
||||
height: 0
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: renderer.command(["loadfile", "../../../test.mkv"])
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: labelFrame
|
||||
anchors.margins: -50
|
||||
radius: 5
|
||||
color: "white"
|
||||
border.color: "black"
|
||||
opacity: 0.8
|
||||
anchors.fill: box
|
||||
}
|
||||
|
||||
Row {
|
||||
id: box
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 100
|
||||
|
||||
Text {
|
||||
anchors.margins: 10
|
||||
wrapMode: Text.WordWrap
|
||||
text: "QtQuick and mpv are both rendering stuff.\n
|
||||
In this example, mpv is always in the background.\n
|
||||
Click to load ../../../test.mkv"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
QT += qml quick
|
||||
|
||||
HEADERS += main.h
|
||||
SOURCES += main.cpp
|
||||
|
||||
CONFIG += link_pkgconfig debug
|
||||
PKGCONFIG += mpv
|
||||
|
||||
RESOURCES += mpvtest.qrc
|
||||
|
||||
OTHER_FILES += main.qml
|
||||
@@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/mpvtest">
|
||||
<file>main.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
+16
-23
@@ -28,7 +28,7 @@ static void wakeup(void *ctx)
|
||||
// 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;
|
||||
emit mainwindow->mpv_events();
|
||||
QCoreApplication::postEvent(mainwindow, new QEvent(QEvent::User));
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
@@ -41,13 +41,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
QAction *on_open = new QAction(tr("&Open"), this);
|
||||
on_open->setShortcuts(QKeySequence::Open);
|
||||
on_open->setStatusTip(tr("Open a file"));
|
||||
connect(on_open, &QAction::triggered, this, &MainWindow::on_file_open);
|
||||
connect(on_open, SIGNAL(triggered()), this, SLOT(on_file_open()));
|
||||
menu->addAction(on_open);
|
||||
|
||||
QAction *on_new = new QAction(tr("&New window"), this);
|
||||
connect(on_new, &QAction::triggered, this, &MainWindow::on_new_window);
|
||||
menu->addAction(on_new);
|
||||
|
||||
statusBar();
|
||||
|
||||
QMainWindow *log_window = new QMainWindow(this);
|
||||
@@ -92,10 +88,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
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 QueuedConnection mechanism to
|
||||
// relay the wakeup in a thread-safe way.
|
||||
connect(this, &MainWindow::mpv_events, this, &MainWindow::on_mpv_events,
|
||||
Qt::QueuedConnection);
|
||||
// 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)
|
||||
@@ -169,16 +163,20 @@ void MainWindow::handle_mpv_event(mpv_event *event)
|
||||
}
|
||||
}
|
||||
|
||||
// This slot is invoked by wakeup() (through the mpv_events signal).
|
||||
void MainWindow::on_mpv_events()
|
||||
bool MainWindow::event(QEvent *event)
|
||||
{
|
||||
// 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);
|
||||
// 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()
|
||||
@@ -191,11 +189,6 @@ void MainWindow::on_file_open()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_new_window()
|
||||
{
|
||||
(new MainWindow())->show();
|
||||
}
|
||||
|
||||
void MainWindow::append_log(const QString &text)
|
||||
{
|
||||
QTextCursor cursor = log->textCursor();
|
||||
@@ -15,13 +15,11 @@ public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
virtual bool event(QEvent *event);
|
||||
|
||||
private slots:
|
||||
void on_file_open();
|
||||
void on_new_window();
|
||||
void on_mpv_events();
|
||||
|
||||
signals:
|
||||
void mpv_events();
|
||||
|
||||
private:
|
||||
QWidget *mpv_container;
|
||||
@@ -6,7 +6,7 @@ TARGET = qtexample
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += link_pkgconfig debug
|
||||
PKGCONFIG += mpv
|
||||
PKGCONFIG = mpv
|
||||
|
||||
SOURCES += qtexample.cpp
|
||||
HEADERS += qtexample.h
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,9 @@
|
||||
// Build with: gcc -o simple simple.c `pkg-config --libs --cflags mpv`
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <mpv/client.h>
|
||||
|
||||
static inline void check_error(int status)
|
||||
{
|
||||
if (status < 0) {
|
||||
printf("mpv API error: %s\n", mpv_error_string(status));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#include "libmpv/client.h"
|
||||
#include "shared.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -30,7 +21,7 @@ int main(int argc, char *argv[])
|
||||
// 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-vo-keyboard", "yes");
|
||||
mpv_set_option_string(ctx, "input-x11-keyboard", "yes");
|
||||
int val = 1;
|
||||
check_error(mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, &val));
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
Compiling for Windows
|
||||
=====================
|
||||
|
||||
Compiling for Windows is supported with MinGW-w64. This can be used to produce
|
||||
both 32-bit and 64-bit executables, and it works for building on Windows and
|
||||
cross-compiling from Linux and Cygwin. MinGW-w64 is available from:
|
||||
http://mingw-w64.sourceforge.net.
|
||||
|
||||
While building a complete MinGW-w64 toolchain yourself is possible, there are a
|
||||
few build environments and scripts to help ease the process, such as MSYS2 and
|
||||
MXE. Note that MinGW environments included in Linux distributions are often
|
||||
broken, outdated and useless, and usually don't use MinGW-w64.
|
||||
|
||||
**Warning**: the original MinGW (http://www.mingw.org) is unsupported.
|
||||
|
||||
Cross-compilation
|
||||
=================
|
||||
|
||||
When cross-compiling, you have to run mpv's configure with these arguments:
|
||||
|
||||
```bash
|
||||
DEST_OS=win32 TARGET=i686-w64-mingw32 ./waf configure
|
||||
```
|
||||
|
||||
[MXE](http://mxe.cc) makes it very easy to bootstrap a complete MingGW-w64
|
||||
environment from a Linux machine. See a working example below.
|
||||
|
||||
Alternatively, you can try [mingw-w64-cmake](https://github.com/lachs0r/mingw-w64-cmake),
|
||||
which bootstraps a MinGW-w64 environment and builds mpv and dependencies.
|
||||
|
||||
Example with MXE
|
||||
----------------
|
||||
|
||||
```bash
|
||||
# Before starting, make sure you install MXE prerequisites. MXE will download
|
||||
# and build all target dependencies, but no host dependencies. For example,
|
||||
# you need a working compiler, or MXE can't build the crosscompiler.
|
||||
#
|
||||
# Refer to
|
||||
#
|
||||
# http://mxe.cc/#requirements
|
||||
#
|
||||
# Scroll down for disto/OS-specific instructions to install them.
|
||||
|
||||
# Download MXE. Note that compiling the required packages requires about 1.4 GB
|
||||
# or more!
|
||||
|
||||
cd /opt
|
||||
git clone https://github.com/mxe/mxe mxe
|
||||
cd mxe
|
||||
|
||||
# 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.static" >> settings.mk
|
||||
|
||||
# If you want to build 64 bit version, use this:
|
||||
# echo "MXE_TARGETS := x86_64-w64-mingw32.static" >> 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/mxe/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.static-gcc).
|
||||
|
||||
cd ..
|
||||
git clone https://github.com/mpv-player/mpv.git
|
||||
cd mpv
|
||||
DEST_OS=win32 TARGET=i686-w64-mingw32.static ./waf configure
|
||||
# Or, if 64 bit version,
|
||||
# DEST_OS=win32 TARGET=x86_64-w64-mingw32.static ./waf configure
|
||||
./waf build
|
||||
```
|
||||
|
||||
Native compilation with MSYS2
|
||||
=============================
|
||||
|
||||
For Windows developers looking to get started quickly, MSYS2 can be used to
|
||||
compile mpv natively on a Windows machine. The MSYS2 repositories have binary
|
||||
packages for most of mpv's dependencies, so the process should only involve
|
||||
building mpv itself.
|
||||
|
||||
To build 64-bit mpv on Windows:
|
||||
|
||||
Installing MSYS2
|
||||
----------------
|
||||
|
||||
1. Download an installer from https://msys2.github.io/
|
||||
|
||||
It doesn't matter whether the i686 or the x86_64 version is used. Both can
|
||||
build 32-bit and 64-bit binaries when running on a 64-bit version of Windows.
|
||||
|
||||
2. Add ``C:\msys64\mingw64\bin`` to your ``%PATH%``. mpv will depend on several
|
||||
DLLs in this folder.
|
||||
|
||||
3. Start a MinGW-w64 shell (``mingw64_shell.bat``). For a 32-bit build, use
|
||||
``mingw32_shell.bat``.
|
||||
|
||||
Updating MSYS2
|
||||
--------------
|
||||
|
||||
To prevent errors during post-install, ``msys2-runtime`` and ``pacman`` must be
|
||||
updated first.
|
||||
|
||||
```bash
|
||||
# Check for updates to msys2-runtime and pacman. If there were updates, restart
|
||||
# MSYS2 before continuing.
|
||||
pacman -Sy --needed msys2-runtime pacman
|
||||
|
||||
# Update everything else
|
||||
pacman -Su
|
||||
```
|
||||
|
||||
Installing mpv dependencies
|
||||
---------------------------
|
||||
|
||||
```bash
|
||||
# Install MSYS2 build dependencies and a MinGW-w64 compiler
|
||||
pacman -S git pkg-config python3 mingw-w64-x86_64-gcc
|
||||
|
||||
# Install the most important MinGW-w64 dependencies. libass, libbluray and
|
||||
# lcms2 are also pulled in as dependencies of ffmpeg.
|
||||
pacman -S mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-libjpeg-turbo mingw-w64-x86_64-lua
|
||||
|
||||
# Install additional (optional) dependencies
|
||||
pacman -S mingw-w64-x86_64-libdvdnav mingw-w64-x86_64-mpg123 mingw-w64-x86_64-libguess
|
||||
```
|
||||
|
||||
For a 32-bit build, install ``mingw-w64-i686-*`` packages instead.
|
||||
|
||||
Building mpv
|
||||
------------
|
||||
|
||||
Clone the latest mpv from git and install waf:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mpv-player/mpv.git && cd mpv
|
||||
./bootstrap.py
|
||||
```
|
||||
|
||||
Finally, compile and install mpv. Binaries will be installed to
|
||||
``/mingw64/bin``.
|
||||
|
||||
```bash
|
||||
# For a 32-bit build, use --prefix=/mingw32 instead
|
||||
./waf configure CC=gcc --prefix=/mingw64
|
||||
./waf install
|
||||
```
|
||||
|
||||
Or, compile and install both libmpv and mpv:
|
||||
|
||||
```bash
|
||||
./waf configure CC=gcc --enable-libmpv-shared --prefix=/mingw64
|
||||
./waf install
|
||||
|
||||
# waf installs libmpv to the wrong directory, so fix it up
|
||||
mv -f /mingw64/bin/pkgconfig/mpv.pc /mingw64/lib/pkgconfig/
|
||||
mv -f /mingw64/bin/libmpv.dll.a /mingw64/lib/
|
||||
sed -i 's_/mingw64/bin_/mingw64/lib_' /mingw64/lib/pkgconfig/mpv.pc
|
||||
rmdir /mingw64/bin/pkgconfig
|
||||
```
|
||||
|
||||
Additional dependencies
|
||||
=======================
|
||||
|
||||
pthreads
|
||||
--------
|
||||
|
||||
mpv will use a pthreads wrapper by default. Either pthreads-win32 or
|
||||
winpthreads should work. The latter is packaged with most MinGW-w64
|
||||
environments, including MSYS2, so it shouldn't be a problem. If you don't have
|
||||
a pthreads wrapper or you want to build mpv without one, configure with:
|
||||
|
||||
```bash
|
||||
./waf configure --enable-win32-internal-pthreads
|
||||
```
|
||||
|
||||
libwaio
|
||||
-------
|
||||
|
||||
If you want to use ``--input-file``, you need libwaio. It's available from
|
||||
git://midipix.org/waio
|
||||
|
||||
To compile libwaio in MSYS2, run:
|
||||
|
||||
```bash
|
||||
git clone git://midipix.org/waio && cd waio
|
||||
|
||||
# 32-bit build, run from mingw32_shell.bat
|
||||
./build-mingw-nt32 lib-static CC=gcc AR=ar
|
||||
cp -r include/waio /mingw32/include
|
||||
cp lib32/libwaio.a /mingw32/lib
|
||||
|
||||
# 64-bit build, run from mingw64_shell.bat
|
||||
./build-mingw-nt64 lib-static CC=gcc AR=ar
|
||||
cp -r include/waio /mingw64/include
|
||||
cp lib64/libwaio.a /mingw64/lib
|
||||
```
|
||||
+2
-2
@@ -4,8 +4,8 @@ How to contribute
|
||||
General
|
||||
-------
|
||||
|
||||
The main contact for mpv development is IRC, specifically #mpv-player
|
||||
and #mpv-player-dev on Freenode.
|
||||
The main contact for mpv development is IRC, specifically #mpv-player and
|
||||
#mpv-player-dev on Freenode.
|
||||
|
||||
Sending patches
|
||||
---------------
|
||||
|
||||
@@ -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
|
||||
```
|
||||
+3
-3
@@ -565,9 +565,9 @@ Available filters are:
|
||||
Scale tempo in sync with speed (default).
|
||||
pitch
|
||||
Reverses effect of filter. Scales pitch without altering tempo.
|
||||
Add ``[ multiply speed 0.9438743126816935`` and
|
||||
``] multiply speed 1.059463094352953`` to your ``input.conf``
|
||||
to step by musical semi-tones.
|
||||
Add ``[ speed_mult 0.9438743126816935`` and ``] speed_mult
|
||||
1.059463094352953`` to your ``input.conf`` to step by musical
|
||||
semi-tones.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
||||
+15
-41
@@ -39,6 +39,8 @@ Available audio output drivers are:
|
||||
``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.)
|
||||
@@ -68,40 +70,6 @@ Available audio output drivers are:
|
||||
shells (like zsh), you have to quote the option string to prevent the
|
||||
shell from interpreting the brackets instead of passing them to mpv.
|
||||
|
||||
Actually, you should use the ``--audio-device`` option, instead of
|
||||
setting the device directly.
|
||||
|
||||
.. warning::
|
||||
|
||||
Handling of multichannel/surround audio changed in mpv 0.8.0 from the
|
||||
behavior in MPlayer/mplayer2 and older versions of mpv.
|
||||
|
||||
The old behavior is that the player always downmixed to stereo by
|
||||
default. The ``--audio-channels`` (or ``--channels`` before that) option
|
||||
had to be set to get multichannel audio. Then playing stereo would
|
||||
use the ``default`` device (which typically allows multiple programs
|
||||
to play audio at the same time via dmix), while playing anything with
|
||||
more channels would open one of the hardware devices, e.g. via the
|
||||
``surround51`` alias (typically with exclusive access). Whether the
|
||||
player would use exclusive access or not would depend on the file
|
||||
being played.
|
||||
|
||||
The new behavior since mpv 0.8.0 always enables multichannel audio,
|
||||
i.e. ``--audio-channels=auto`` is the default. However, since ALSA
|
||||
provides no good way to play multichannel audio in a non-exclusive
|
||||
way (without blocking other applications from using audio), the player
|
||||
is restricted to the capabilities of the ``default`` device by default,
|
||||
which means it supports only stereo and mono (at least with current
|
||||
typical ALSA configurations). But if a hardware device is selected,
|
||||
then multichannel audio will typically work.
|
||||
|
||||
The short story is: if you want multichannel audio with ALSA, use
|
||||
``--audio-device`` to select the device (use ``--audio-device=help``
|
||||
to get a list of all devices and their mpv name).
|
||||
|
||||
You can also try
|
||||
`Using the upmix plugin <https://github.com/mpv-player/mpv/wiki/ALSA:-Surround-Sound-and-Upmixing>`_.
|
||||
|
||||
``oss``
|
||||
OSS audio output driver
|
||||
|
||||
@@ -189,6 +157,19 @@ Available audio output drivers are:
|
||||
If you have stuttering video when using pulse, try to enable this
|
||||
option. (Or alternatively, try to update PulseAudio.)
|
||||
|
||||
``portaudio``
|
||||
PortAudio audio output driver. This works on all platforms, and has
|
||||
extensive MS Windows support.
|
||||
|
||||
.. 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.
|
||||
|
||||
``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``.
|
||||
|
||||
``dsound`` (Windows only)
|
||||
DirectX DirectSound audio output driver
|
||||
|
||||
@@ -247,9 +228,6 @@ Available audio output drivers are:
|
||||
Simulate broken audio drivers, which always add the fixed device
|
||||
latency to the reported audio playback position.
|
||||
|
||||
``broken-delay``
|
||||
Simulate broken audio drivers, which don't report latency correctly.
|
||||
|
||||
``pcm``
|
||||
Raw PCM/WAVE file writer audio output
|
||||
|
||||
@@ -260,10 +238,6 @@ Available audio output drivers are:
|
||||
Write the sound to ``<filename>`` instead of the default
|
||||
``audiodump.wav``. If ``no-waveheader`` is specified, the default is
|
||||
``audiodump.pcm``.
|
||||
``(no-)append``
|
||||
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
|
||||
|
||||
+435
-10
@@ -1,13 +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 ``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.
|
||||
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. 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_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.
|
||||
+15
-200
@@ -109,20 +109,11 @@ List of Input Commands
|
||||
keyframes
|
||||
Always restart playback at keyframe boundaries (fast).
|
||||
|
||||
``revert_seek [mode]``
|
||||
``revert_seek``
|
||||
Undoes the ``seek`` command, and some other commands that seek (but not
|
||||
necessarily all of them). Calling this command once will jump to the
|
||||
playback position before the seek. Calling it a second time undoes the
|
||||
``revert_seek`` command itself. This only works within a single file.
|
||||
|
||||
The first argument is optional, and can change the behavior:
|
||||
|
||||
mark
|
||||
Mark the current time position. The next normal ``revert_seek`` command
|
||||
will seek back to this point, no matter how many seeks happened since
|
||||
last time.
|
||||
|
||||
Using it without any arguments gives you the default behavior.
|
||||
``revert_seek`` command itself.
|
||||
|
||||
``frame_step``
|
||||
Play one frame, then pause. Does nothing with audio-only playback.
|
||||
@@ -374,32 +365,6 @@ List of Input Commands
|
||||
essentially like ``quit``. Useful for the client API: playback can be
|
||||
stopped without terminating the player.
|
||||
|
||||
``mouse <x> <y> [<button> [single|double]]``
|
||||
Send a mouse event with given coordinate (``<x>``, ``<y>``).
|
||||
|
||||
Second argument:
|
||||
|
||||
<button>
|
||||
The button number of clicked mouse button. This should be one of 0-19.
|
||||
If ``<button>`` is omitted, only the position will be updated.
|
||||
|
||||
Third argument:
|
||||
|
||||
<single> (default)
|
||||
The mouse event represents regular single click.
|
||||
|
||||
<double>
|
||||
The mouse event represents double-click.
|
||||
|
||||
``audio_add "<file>" [<flags> [<title> [<lang>]]]``
|
||||
Load the given audio file. See ``sub_add`` command.
|
||||
|
||||
``audio_remove [<id>]``
|
||||
Remove the given audio track. See ``sub_remove`` command.
|
||||
|
||||
``audio_reload [<id>]``
|
||||
Reload the given audio tracks. See ``sub_reload`` command.
|
||||
|
||||
|
||||
Input Commands that are Possibly Subject to Change
|
||||
--------------------------------------------------
|
||||
@@ -526,15 +491,18 @@ Input Commands that are Possibly Subject to Change
|
||||
|
||||
It is also possible to pass a raw memory address for use as bitmap memory
|
||||
by passing a memory address as integer prefixed with a ``&`` character.
|
||||
Passing the wrong thing here will crash the player. This mode might be
|
||||
useful for use with libmpv. The ``offset`` parameter is simply added to the
|
||||
memory address (since mpv 0.8.0, ignored before).
|
||||
Passing the wrong thing here will crash the player. The ``offset`` parameter
|
||||
is not used and must be 0. This mode might be useful for use with libmpv.
|
||||
|
||||
``offset`` is the byte offset of the first pixel in the source file.
|
||||
(The current implementation always mmap's the whole file from position 0 to
|
||||
the end of the image, so large offsets should be avoided. Before mpv 0.8.0,
|
||||
the offset was actually passed directly to ``mmap``, but it was changed to
|
||||
make using it easier.)
|
||||
On Windows, currently only raw memory addresses work. File mapping is not
|
||||
implemented because a ``mmap`` compatibility layer is missing, and because
|
||||
this kind of shared memory method would perhaps not be overly useful on
|
||||
Windows.
|
||||
|
||||
``offset`` is the offset of the first pixel in the source file. It is
|
||||
passed directly to ``mmap`` and is subject to certain restrictions
|
||||
(see ``man mmap`` for details). In particular, this value has to be a
|
||||
multiple of the system's page size.
|
||||
|
||||
``fmt`` is a string identifying the image format. Currently, only ``bgra``
|
||||
is defined. This format has 4 bytes per pixels, with 8 bits per component.
|
||||
@@ -618,68 +586,8 @@ Input Commands that are Possibly Subject to Change
|
||||
unseekable streams that are going out of sync.
|
||||
This command might be changed or removed in the future.
|
||||
|
||||
Undocumented commands: ``tv_last_channel`` (TV/DVB only),
|
||||
``get_property`` (deprecated), ``ao_reload`` (experimental/internal).
|
||||
|
||||
Hooks
|
||||
~~~~~
|
||||
|
||||
Hooks are synchronous events between player core and a script or similar. This
|
||||
applies to the Lua scripting interface and the client API and only. Normally,
|
||||
events are supposed to be asynchronous, and the hook API provides an awkward
|
||||
and obscure way to handle events that require stricter coordination. There are
|
||||
no API stability guarantees made. Not following the protocol exactly can make
|
||||
the player freeze randomly. Basically, nobody should use this API.
|
||||
|
||||
There are two special commands involved. Also, the client must listen for
|
||||
client messages (``MPV_EVENT_CLIENT_MESSAGE`` in the C API).
|
||||
|
||||
``hook_add <hook-name> <id> <priority>``
|
||||
Subscribe to the hook identified by the first argument (basically, the
|
||||
name of event). The ``id`` argument is an arbitrary integer chosen by the
|
||||
user. ``priority`` is used to sort all hook handlers globally across all
|
||||
clients. Each client can register multiple hook handlers (even for the
|
||||
same hook-name). Once the hook is registered, it cannot be unregistered.
|
||||
|
||||
When a specific event happens, all registered handlers are run serially.
|
||||
This uses a protocol every client has to follow explicitly. When a hook
|
||||
handler is run, a client message (``MPV_EVENT_CLIENT_MESSAGE``) is sent to
|
||||
the client which registered the hook. This message has the following
|
||||
arguments:
|
||||
|
||||
1. the string ``hook_run``
|
||||
2. the ``id`` argument the hook was registered with as string (this can be
|
||||
used to correctly handle multiple hooks registered by the same client,
|
||||
as long as the ``id`` argument is unique in the client)
|
||||
3. something undefined, used by the hook mechanism to track hook execution
|
||||
(currently, it's the hook-name, but this might change without warning)
|
||||
|
||||
Upon receiving this message, the client can handle the event. While doing
|
||||
this, the player core will still react to requests, but playback will
|
||||
typically be stopped.
|
||||
|
||||
When the client is done, it must continue the core's hook execution by
|
||||
running the ``hook_ack`` command.
|
||||
|
||||
``hook_ack <string>``
|
||||
Run the next hook in the global chain of hooks. The argument is the 3rd
|
||||
argument of the client message that starts hook execution for the
|
||||
current client.
|
||||
|
||||
The following hooks are currently defined:
|
||||
|
||||
``on_load``
|
||||
Called when a file is to be opened, before anything is actually done.
|
||||
For example, you could read and write the ``stream-open-filename``
|
||||
property to redirect an URL to something else (consider support for
|
||||
streaming sites which rarely give the user a direct media URL), or
|
||||
you could set per-file options with by setting the property
|
||||
``file-local-options/<option name>``. The player will wait until all
|
||||
hooks are run.
|
||||
|
||||
``on_unload``
|
||||
Run before closing a file, and before actually uninitializing
|
||||
everything. It's not possible to resume playback in this state.
|
||||
Undocumented commands: ``tv_last_channel`` (TV/DVB only), ``get_property`` (?),
|
||||
``ao_reload`` (experimental/internal).
|
||||
|
||||
Input Command Prefixes
|
||||
----------------------
|
||||
@@ -795,11 +703,6 @@ Property list
|
||||
|
||||
Otherwise, return the ``filename`` property.
|
||||
|
||||
``file-format``
|
||||
Symbolic name of the file format. In some cases, this is a comma-separated
|
||||
list of format names, e.g. mp4 is ``mov,mp4,m4a,3gp,3g2,mj2`` (the list
|
||||
may grow in the future for any format).
|
||||
|
||||
``demuxer``
|
||||
Name of the current demuxer. (This is useless.)
|
||||
|
||||
@@ -869,33 +772,6 @@ Property list
|
||||
``disc-titles``
|
||||
Number of BD/DVD titles.
|
||||
|
||||
This has a number of sub-properties. Replace ``N`` with the 0-based edition
|
||||
index.
|
||||
|
||||
``disc-titles/count``
|
||||
Number of titles.
|
||||
|
||||
``disc-titles/id``
|
||||
Title ID as integer. Currently, this is the same as the title index.
|
||||
|
||||
``disc-titles/length``
|
||||
Length in seconds. Can be unavailable in a number of cases (currently
|
||||
it works for libdvdnav only).
|
||||
|
||||
When querying the property with the client API using ``MPV_FORMAT_NODE``,
|
||||
or with Lua ``mp.get_property_native``, this will return a mpv_node with
|
||||
the following contents:
|
||||
|
||||
::
|
||||
|
||||
MPV_FORMAT_NODE_ARRAY
|
||||
MPV_FORMAT_NODE_MAP (for each edition)
|
||||
"id" MPV_FORMAT_INT64
|
||||
"length" MPV_FORMAT_DOUBLE
|
||||
|
||||
``disc-title-list``
|
||||
List of BD/DVD titles.
|
||||
|
||||
``disc-title`` (RW)
|
||||
Current BD/DVD title number. Writing works only for ``dvdnav://`` and
|
||||
``bd://`` (and aliases for these).
|
||||
@@ -993,10 +869,6 @@ Property list
|
||||
MPV_FORMAT_NODE_MAP
|
||||
(key and string value for each metadata entry)
|
||||
|
||||
``filtered-metadata``
|
||||
Like ``metadata``, but includes only fields listed in the ``--display-tags``
|
||||
option. This is the same set of tags that is printed to the terminal.
|
||||
|
||||
``chapter-metadata``
|
||||
Metadata of current chapter. Works similar to ``metadata`` property. It
|
||||
also allows the same access methods (using sub-properties).
|
||||
@@ -1021,10 +893,6 @@ Property list
|
||||
``pause`` (RW)
|
||||
Pause status. This is usually ``yes`` or ``no``. See ``--pause``.
|
||||
|
||||
``idle``
|
||||
Return ``yes`` if no file is loaded, but the player is staying around
|
||||
because of the ``--idle`` option.
|
||||
|
||||
``core-idle``
|
||||
Return ``yes`` if the playback core is paused, otherwise ``no``. This can
|
||||
be different ``pause`` in special situations, such as when the player
|
||||
@@ -1157,9 +1025,6 @@ Property list
|
||||
``border`` (RW)
|
||||
See ``--border``.
|
||||
|
||||
``on-all-workspaces`` (RW)
|
||||
See ``--on-all-workspaces``. Unsetting may not work on all WMs.
|
||||
|
||||
``framedrop`` (RW)
|
||||
See ``--framedrop``.
|
||||
|
||||
@@ -1188,17 +1053,6 @@ Property list
|
||||
Note that you don't know the success of the operation immediately after
|
||||
writing this property. It happens with a delay as video is reinitialized.
|
||||
|
||||
``detected-hwdec``
|
||||
Return the current hardware decoder that was detected and opened. Returns
|
||||
the same values as ``hwdec``.
|
||||
|
||||
This is known only once the VO has opened (and possibly later). With some
|
||||
VOs (like ``opengl``), this is never known in advance, but only when the
|
||||
decoder attempted to create the hw decoder successfully. Also, hw decoders
|
||||
with ``-copy`` suffix are returned only while hw decoding is active (and
|
||||
unset afterwards). All this reflects how detecting hw decoders are
|
||||
detected and used internally in mpv.
|
||||
|
||||
``panscan`` (RW)
|
||||
See ``--panscan``.
|
||||
|
||||
@@ -1224,16 +1078,6 @@ Property list
|
||||
The pixel format as string. This uses the same names as used in other
|
||||
places of mpv.
|
||||
|
||||
``video-params/average-bpp``
|
||||
Average bits-per-pixel as integer. Subsampled planar formats use a
|
||||
different resolution, which is the reason this value can sometimes be
|
||||
odd or confusing. Can be unavailable with some formats.
|
||||
|
||||
``video-params/plane-depth``
|
||||
Bit depth for each color component as integer. This is only exposed
|
||||
for planar or single-component formats, and is unavailable for other
|
||||
formats.
|
||||
|
||||
``video-params/w``, ``video-params/h``
|
||||
Video size as integers, with no aspect correction applied.
|
||||
|
||||
@@ -1560,14 +1404,6 @@ Property list
|
||||
``seekable``
|
||||
Return whether it's generally possible to seek in the current file.
|
||||
|
||||
``partially-seekable``
|
||||
Return ``yes`` if the current file is considered seekable, but only because
|
||||
the cache is active. This means small relative seeks may be fine, but larger
|
||||
seeks may fail anyway. Whether a seek will succeed or not is generally not
|
||||
known in advance.
|
||||
|
||||
If this property returns true, ``seekable`` will also return true.
|
||||
|
||||
``playback-abort``
|
||||
Return whether playback is stopped or is to be stopped. (Useful in obscure
|
||||
situations like during ``on_load`` hook processing, when the user can
|
||||
@@ -1607,17 +1443,6 @@ Property list
|
||||
whether the video window is visible. If the ``--force-window`` option is
|
||||
used, this is usually always returns ``yes``.
|
||||
|
||||
``packet-video-bitrate``, ``packet-audio-bitrate``, ``packet-sub-bitrate``
|
||||
Bitrate values calculated on the packet level. This works by dividing the
|
||||
bit size of all packets between two keyframes by their presentation
|
||||
timestamp distance. (This uses the timestamps are stored in the file, so
|
||||
e.g. playback speed does not influence the returned values.) In particular,
|
||||
the video bitrate will update only per keyframe, and show the "past"
|
||||
bitrate. To make the property more UI friendly, updates to these properties
|
||||
are throttled in a certain way.
|
||||
|
||||
How exactly these values are calculated might change in the future.
|
||||
|
||||
``audio-device-list``
|
||||
Return the list of discovered audio devices. This is mostly for use with
|
||||
the client API, and reflects what ``--audio-device=help`` with the command
|
||||
@@ -1652,16 +1477,6 @@ Property list
|
||||
|
||||
How these details are handled may change in the future.
|
||||
|
||||
``current-vo``
|
||||
Current video output driver (name as used with ``--vo``).
|
||||
|
||||
``current-ao``
|
||||
Current audio output driver (name as used with ``--ao``).
|
||||
|
||||
``audio-out-detected-device``
|
||||
Return the audio device selected by the AO driver (only implemented for
|
||||
some drivers: currently only ``coreaudio``).
|
||||
|
||||
``mpv-version``
|
||||
Return the mpv version/copyright string. Depending on how the binary was
|
||||
built, it might contain either a release version, or just a git hash.
|
||||
|
||||
+2
-41
@@ -4,7 +4,8 @@ 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 using the option
|
||||
``--input-unix-socket``. Clients can connect to this socket and send commands to
|
||||
the player or receive events from it.
|
||||
the player or receive events from it. You can use the ``socat`` tool to send
|
||||
commands (and receive reply) from the shell.
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -14,38 +15,6 @@ the player or receive 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 reply) from the
|
||||
shell. Assuming mpv was started with:
|
||||
|
||||
::
|
||||
|
||||
mpv file.mkv --input-unix-socket=/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.)
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
@@ -187,14 +156,6 @@ 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.
|
||||
|
||||
By default, most events are enabled, and there is not much use for this
|
||||
command.
|
||||
|
||||
``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
|
||||
|
||||
+38
-26
@@ -1,14 +1,14 @@
|
||||
LUA SCRIPTING
|
||||
=============
|
||||
|
||||
mpv can load Lua scripts. Scripts passed to the ``--script`` option, or found in
|
||||
the ``scripts`` subdirectory of the mpv configuration directory (usually
|
||||
``~/.config/mpv/scripts/``) will be loaded on program start. mpv also appends the
|
||||
``scripts`` subdirectory to the end of Lua's path so you can import scripts from
|
||||
mpv can load Lua scripts. Scripts passed to the ``--lua`` option, or found in
|
||||
the ``lua`` subdirectory of the mpv configuration directory (usually
|
||||
``~/.config/mpv/lua/``) will be loaded on program start. mpv also appends the
|
||||
``lua`` subdirectory to the end of Lua's path so you can import scripts from
|
||||
there too. Since it's added to the end, don't name scripts you want to import
|
||||
the same as Lua libraries because they will be overshadowed by them.
|
||||
|
||||
mpv provides the built-in module ``mp``, which contains functions to send
|
||||
mpv provides the built-in module ``mp``, which provides functions to send
|
||||
commands to the mpv core and to retrieve information about playback state, user
|
||||
settings, file information, and so on.
|
||||
|
||||
@@ -29,14 +29,16 @@ A script which leaves fullscreen mode when the player is paused:
|
||||
end
|
||||
mp.observe_property("pause", "bool", on_pause_change)
|
||||
|
||||
This script provides a pretty weird feature, but Lua scripting was made to
|
||||
allow users implement features which are not going to be added to the mpv core.
|
||||
|
||||
Details on the script initialization and lifecycle
|
||||
--------------------------------------------------
|
||||
Mode of operation
|
||||
-----------------
|
||||
|
||||
Your script will be loaded by the player at program start from the ``scripts``
|
||||
configuration subdirectory, or from a path specified with the ``--script``
|
||||
option. Some scripts are loaded internally (like ``--osc``). Each script runs in
|
||||
its own thread. Your script is first run "as is", and once that is done, the event loop
|
||||
Your script will be loaded by the player at program start from the ``lua``
|
||||
configuration subdirectory, from a path specified with the ``--lua`` option, or
|
||||
in some cases, internally (like ``--osc``). Each script runs in its own
|
||||
thread. Your script is first run "as is", and once that is done, the event loop
|
||||
is entered. This event loop will dispatch events received by mpv and call your
|
||||
own event handlers which you have registered with ``mp.register_event``, or
|
||||
timers added with ``mp.add_timeout`` or similar.
|
||||
@@ -359,7 +361,7 @@ The ``mp`` module is preloaded, although it can be loaded manually with
|
||||
|
||||
|
||||
``mp.get_opt(key)``
|
||||
Return a setting from the ``--script-opts`` option. It's up to the user and
|
||||
Return a setting from the ``--lua-opts`` option. It's up to the user and
|
||||
the script how this mechanism is used. Currently, all scripts can access
|
||||
this equally, so you should be careful about collisions.
|
||||
|
||||
@@ -511,12 +513,12 @@ Example config::
|
||||
optionC=no
|
||||
|
||||
|
||||
Command-line options are read from the ``--script-opts`` parameter. To avoid
|
||||
Command-line options are read from the ``--lua-opts`` parameter. To avoid
|
||||
collisions, all keys have to be prefixed with ``identifier-``.
|
||||
|
||||
Example command-line::
|
||||
|
||||
--script-opts=myscript-optionA=TEST,myscript-optionB=0,myscript-optionC=yes
|
||||
--lua-opts=myscript-optionA=TEST:myscript-optionB=0:myscript-optionC=yes
|
||||
|
||||
|
||||
mp.utils options
|
||||
@@ -644,7 +646,7 @@ Example:
|
||||
print("start of playback!")
|
||||
end
|
||||
|
||||
mp.register_event("file-loaded", my_fn)
|
||||
mp.register_event("playback-start", my_fn)
|
||||
|
||||
|
||||
|
||||
@@ -663,9 +665,7 @@ List of events
|
||||
Happens after a file was loaded and begins playback.
|
||||
|
||||
``seek``
|
||||
Happens on seeking. (This might include cases when the player seeks
|
||||
internally, even without user interaction. This includes e.g. segment
|
||||
changes when playing ordered chapters Matroska files.)
|
||||
Happens on seeking (including ordered chapter segment changes).
|
||||
|
||||
``playback-restart``
|
||||
Start of playback after seek or after file was loaded.
|
||||
@@ -682,7 +682,7 @@ List of events
|
||||
|
||||
``shutdown``
|
||||
Sent when the player quits, and the script should terminate. Normally
|
||||
handled automatically. See `Details on the script initialization and lifecycle`_.
|
||||
handled automatically. See `Mode of operation`_.
|
||||
|
||||
``log-message``
|
||||
Receives messages enabled with ``mp.enable_messages``. The message data
|
||||
@@ -701,8 +701,13 @@ List of events
|
||||
(undocumented) existing ones.
|
||||
|
||||
``text``
|
||||
The log message. The text will end with a newline character. Sometimes
|
||||
it can contain multiple lines.
|
||||
The log message. Note that this is the direct output of a printf()
|
||||
style output API. The text will contain embedded newlines, and it's
|
||||
possible that a single message contains multiple lines, or that a
|
||||
message contains a partial line.
|
||||
|
||||
It's safe to display messages only if they end with a newline character,
|
||||
and to buffer them otherwise.
|
||||
|
||||
Keep in mind that these messages are meant to be hints for humans. You
|
||||
should not parse them, and prefix/level/text of messages might change
|
||||
@@ -733,8 +738,8 @@ The following events also happen, but are deprecated: ``tracks-changed``,
|
||||
Extras
|
||||
------
|
||||
|
||||
This documents experimental features, or features that are "too special" to
|
||||
guarantee a stable interface.
|
||||
This documents experimental features, or features that are "too special" and
|
||||
we don't guarantee a stable interface to it.
|
||||
|
||||
``mp.add_hook(type, priority, fn)``
|
||||
Add a hook callback for ``type`` (a string identifying a certain kind of
|
||||
@@ -745,6 +750,13 @@ guarantee a stable interface.
|
||||
recommended as neutral default value. ``fn`` is the function that will be
|
||||
called during execution of the hook.
|
||||
|
||||
See `Hooks`_ for currently existing hooks and what they do - only the hook
|
||||
list is interesting; handling hook execution is done by the Lua script
|
||||
function automatically.
|
||||
Currently existing hooks:
|
||||
|
||||
``on_load``
|
||||
Called when a file is to be opened, before anything is actually done.
|
||||
For example, you could read and write the ``stream-open-filename``
|
||||
property to redirect an URL to something else (consider support for
|
||||
streaming sites which rarely give the user a direct media URL), or
|
||||
you could set per-file options with by setting the property
|
||||
``file-local-options/<option name>``. The player will wait until all
|
||||
hooks are run.
|
||||
+7
-9
@@ -164,9 +164,6 @@ Shift+PGUP and Shift+PGDWN
|
||||
D
|
||||
Activate/deactivate deinterlacer.
|
||||
|
||||
A
|
||||
Cycle aspect ratio override.
|
||||
|
||||
(The following keys are valid only when using a video output that supports the
|
||||
corresponding adjustment, or the software equalizer (``--vf=eq``).)
|
||||
|
||||
@@ -257,9 +254,9 @@ Additionally, there is a special form of quoting with ``%n%`` described below.
|
||||
|
||||
For example, the ``opengl`` VO can take multiple options:
|
||||
|
||||
``mpv test.mkv --vo=opengl:scale=lanczos:icc-profile=file.icc,xv``
|
||||
``mpv test.mkv --vo=opengl:lscale=lanczos2:icc-profile=file.icc,xv``
|
||||
|
||||
This passes ``scale=lanczos`` and ``icc-profile=file.icc`` to ``opengl``,
|
||||
This passed ``lscale=lanczos2`` and ``icc-profile=file.icc`` to ``opengl``,
|
||||
and also specifies ``xv`` as fallback VO. If the icc-profile path contains
|
||||
spaces or characters like ``,`` or ``:``, you need to quote them:
|
||||
|
||||
@@ -441,11 +438,12 @@ profile name ``default`` to continue with normal options.
|
||||
::
|
||||
|
||||
[vo.vdpau]
|
||||
# Use hardware decoding
|
||||
# Use hardware decoding (might break playback of some h264 files)
|
||||
hwdec=vdpau
|
||||
|
||||
[protocol.dvd]
|
||||
profile-desc="profile for dvd:// streams"
|
||||
vf=pp=hb/vb/dr/al/fd
|
||||
alang=en
|
||||
|
||||
[extension.flv]
|
||||
@@ -766,9 +764,9 @@ FILES
|
||||
``~/.config/mpv/input.conf``
|
||||
key bindings (see `INPUT.CONF`_ section)
|
||||
|
||||
``~/.config/mpv/scripts/``
|
||||
All files in this directory are loaded as if they were passed to the
|
||||
``--script`` option. They are loaded in alphabetical order, and sub-directories
|
||||
``~/.config/mpv/lua/``
|
||||
All files in this directly are loaded as if they were passed to the
|
||||
``--lua`` option. They are loaded in alphabetical order, and sub-directories
|
||||
and files with no ``.lua`` extension are ignored. The ``--load-scripts=no``
|
||||
option disables loading these files.
|
||||
|
||||
|
||||
+31
-139
@@ -107,17 +107,12 @@ Playback Control
|
||||
If ``--audio-pitch-correction`` is used, playing with a speed higher than
|
||||
normal automatically inserts the ``scaletempo`` audio filter.
|
||||
|
||||
``--loop=<N|inf|force|no>``
|
||||
``--loop=<N|inf|no>``
|
||||
Loops playback ``N`` times. A value of ``1`` plays it one time (default),
|
||||
``2`` two times, etc. ``inf`` means forever. ``no`` is the same as ``1`` and
|
||||
disables looping. If several files are specified on command line, the
|
||||
entire playlist is looped.
|
||||
|
||||
The ``force`` mode is like ``inf``, but does not skip playlist entries
|
||||
which have been marked as failing. This means the player might waste CPU
|
||||
time trying to loop a file that doesn't exist. But it might be useful for
|
||||
playing webradios under very bad network conditions.
|
||||
|
||||
``--pause``
|
||||
Start the player in paused state.
|
||||
|
||||
@@ -310,11 +305,6 @@ Program Behavior
|
||||
``--list-protocols``
|
||||
Print a list of the supported protocols.
|
||||
|
||||
``--log-file=<path>``
|
||||
Opens the given path for writing, and print log messages to it. Existing
|
||||
files will be truncated. The log level always corresponds to ``-v``,
|
||||
regardless of terminal verbosity levels.
|
||||
|
||||
``--config-dir=<path>``
|
||||
Force a different configuration directory. If this is set, the given
|
||||
directory is used to load configuration files, and all other configuration
|
||||
@@ -343,30 +333,27 @@ Program Behavior
|
||||
|
||||
This option is useful for debugging only.
|
||||
|
||||
``--idle=<no|yes|once>``
|
||||
``--idle``
|
||||
Makes mpv wait idly instead of quitting when there is no file to play.
|
||||
Mostly useful in slave mode, where mpv can be controlled through input
|
||||
commands (see also ``--slave-broken``).
|
||||
|
||||
``once`` will only idle at start and let the player close once the
|
||||
first playlist has finished playing back.
|
||||
|
||||
``--include=<configuration-file>``
|
||||
Specify configuration file to be parsed after the default ones.
|
||||
|
||||
``--load-scripts=<yes|no>``
|
||||
If set to ``no``, don't auto-load scripts from the ``scripts``
|
||||
configuration subdirectory (usually ``~/.config/mpv/scripts/``).
|
||||
If set to ``no``, don't auto-load scripts from the ``lua`` configuration
|
||||
subdirectory (usually ``~/.config/mpv/lua/``).
|
||||
(Default: ``yes``)
|
||||
|
||||
``--script=<filename>``
|
||||
``--lua=<filename>``
|
||||
Load a Lua script. You can load multiple scripts by separating them with
|
||||
commas (``,``).
|
||||
|
||||
``--script-opts=key1=value1,key2=value2,...``
|
||||
Set options for scripts. A script can query an option by key. If an
|
||||
``--lua-opts=key1=value1,key2=value2,...``
|
||||
Set options for scripts. A Lua script can query an option by key. If an
|
||||
option is used and what semantics the option value has depends entirely on
|
||||
the loaded scripts. Values not claimed by any scripts are ignored.
|
||||
the loaded Lua scripts. Values not claimed by any scripts are ignored.
|
||||
|
||||
``--merge-files``
|
||||
Pretend that all files passed to mpv are concatenated into a single, big
|
||||
@@ -420,9 +407,6 @@ Program Behavior
|
||||
This option may expose privacy-sensitive information and is thus
|
||||
disabled by default.
|
||||
|
||||
``--ignore-path-in-watch-later-config``
|
||||
Ignore path (i.e. use filename only) when using watch later feature.
|
||||
|
||||
``--show-profile=<profile>``
|
||||
Show the description and content of a profile.
|
||||
|
||||
@@ -551,8 +535,7 @@ Video
|
||||
|
||||
The ``vaapi-copy`` mode allows you to use vaapi with any VO. Because
|
||||
this copies the decoded video back to system RAM, it's likely less efficient
|
||||
than the ``vaapi`` mode. But there are reports that this is actually faster
|
||||
as well, and avoids many issues with ``vaapi``.
|
||||
than the ``vaapi`` mode.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -938,7 +921,7 @@ Audio
|
||||
``--dtshd`` and ``--no-dtshd`` are deprecated aliases.
|
||||
|
||||
``--audio-channels=<number|layout>``
|
||||
Request a channel layout for audio output (default: auto). This will ask
|
||||
Request a channel layout for audio output (default: stereo). This will ask
|
||||
the AO to open a device with the given channel layout. It's up to the AO
|
||||
to accept this layout, or to pick a fallback or to error out if the
|
||||
requested layout is not supported.
|
||||
@@ -951,9 +934,9 @@ Audio
|
||||
lists speaker names, which can be used to express arbitrary channel
|
||||
layouts (e.g. ``fl-fr-lfe`` is 2.1).
|
||||
|
||||
The default is ``--audio-channels=auto``, which tries to play audio using
|
||||
the input file's channel layout. (Or more precisely, the output of the
|
||||
audio filter chain.) (``empty`` is an accepted obsolete alias for ``auto``.)
|
||||
You can use ``--audio-channels=auto`` to disable this. In this case, the AO
|
||||
use the channel layout as the audio filter chain indicates. (``empty`` is
|
||||
an accepted obsolete for ``auto``.)
|
||||
|
||||
This will also request the channel layout from the decoder. If the decoder
|
||||
does not support the layout, it will fall back to its native channel layout.
|
||||
@@ -1045,16 +1028,6 @@ Audio
|
||||
maximum amplification, i.e. amplify by 200%. The default volume (no
|
||||
change in volume) will be ``50`` in this case.
|
||||
|
||||
``--audio-file-auto=<no|exact|fuzzy|all>``, ``--no-audio-file-auto``
|
||||
Load additional audio files matching the video filename. The parameter
|
||||
specifies how external audio files are matched. ``exact`` is enabled by
|
||||
default.
|
||||
|
||||
:no: Don't automatically load external audio files.
|
||||
:exact: Load the media filename with audio file extension (default).
|
||||
:fuzzy: Load all audio files containing media filename.
|
||||
:all: Load all audio files in the current directory.
|
||||
|
||||
``--audio-client-name=<name>``
|
||||
The application name the player reports to the audio API. Can be useful
|
||||
if you want to force a different audio profile (e.g. with PulseAudio),
|
||||
@@ -1144,23 +1117,12 @@ Subtitles
|
||||
This affects ASS subtitles as well, and may lead to incorrect subtitle
|
||||
rendering. Use with care, or use ``--sub-text-font-size`` instead.
|
||||
|
||||
``--sub-scale-by-window=<yes|no>``
|
||||
Whether to scale subtitles with the window size (default: yes). If this is
|
||||
disabled, changing the window size won't change the subtitle font size.
|
||||
|
||||
Like ``--sub-scale``, this can break ASS subtitles.
|
||||
|
||||
``--sub-scale-with-window=<yes|no>``
|
||||
Make the subtitle font size relative to the window, instead of the video.
|
||||
This is useful if you always want the same font size, even if the video
|
||||
doesn't covert the window fully, e.g. because screen aspect and window
|
||||
aspect mismatch (and the player adds black bars).
|
||||
|
||||
This option is misnamed. The difference to the confusingly similar sounding
|
||||
option ``--sub-scale-by-window`` is that ``--sub-scale-with-window`` still
|
||||
scales with the approximate window size, while the other option disables
|
||||
this scaling.
|
||||
|
||||
Like ``--sub-scale``, this can break ASS subtitles.
|
||||
|
||||
``--embeddedfonts``, ``--no-embeddedfonts``
|
||||
@@ -1512,41 +1474,26 @@ Window
|
||||
|
||||
See also ``--screen``.
|
||||
|
||||
``--fs-black-out-screens``
|
||||
|
||||
OS X only. Black out other displays when going fullscreen.
|
||||
|
||||
``--keep-open=<yes|no|always>``
|
||||
``--keep-open``
|
||||
Do not terminate when playing or seeking beyond the end of the file, and
|
||||
there is not next file to be played (and ``--loop`` is not used).
|
||||
Instead, pause the player. When trying to seek beyond end of the file, the
|
||||
player will attempt to seek to the last frame.
|
||||
|
||||
The following arguments can be given:
|
||||
|
||||
:no: If the current file ends, go to the next file or terminate.
|
||||
(Default.)
|
||||
:yes: Don't terminate if the current file is the last playlist entry.
|
||||
Equivalent to ``--keep-open`` without arguments.
|
||||
:always: Like ``yes``, but also applies to files before the last playlist
|
||||
entry. This means playback will never automatically advance to
|
||||
the next file.
|
||||
player will pause at an arbitrary playback position (or, in corner cases,
|
||||
not redraw the window at all).
|
||||
|
||||
.. note::
|
||||
|
||||
This option is not respected when using ``--frames``. Explicitly
|
||||
skipping to the next file if the binding uses ``force`` will terminate
|
||||
playback as well.
|
||||
|
||||
Also, if errors or unusual circumstances happen, the player can quit
|
||||
anyway.
|
||||
This option is not respected when using ``--frames``, ``--end``,
|
||||
``--length``, or when passing a chapter range to ``--chapter``.
|
||||
Explicitly skipping to the next file or skipping beyond the last
|
||||
chapter will terminate playback as well, even if ``--keep-open`` is
|
||||
given.
|
||||
|
||||
Since mpv 0.6.0, this doesn't pause if there is a next file in the playlist,
|
||||
or the playlist is looped. Approximately, this will pause when the player
|
||||
would normally exit, but in practice there are corner cases in which this
|
||||
is not the case (e.g. ``mpv --keep-open file.mkv /dev/null`` will play
|
||||
file.mkv normally, then fail to open ``/dev/null``, then exit). (In
|
||||
mpv 0.8.0, ``always`` was introduced, which restores the old behavior.)
|
||||
file.mkv normally, then fail to open ``/dev/null``, then exit).
|
||||
|
||||
``--force-window``
|
||||
Create a video output window even if there is no video. This can be useful
|
||||
@@ -1569,10 +1516,6 @@ Window
|
||||
Play video with window border and decorations. Since this is on by
|
||||
default, use ``--no-border`` to disable the standard window decorations.
|
||||
|
||||
``--on-all-workspaces``
|
||||
(X11 only)
|
||||
Show the video window on all virtual desktops.
|
||||
|
||||
``--geometry=<[W[xH]][+-x+-y]>``, ``--geometry=<x:y>``
|
||||
Adjust the initial window position or size. ``W`` and ``H`` set the window
|
||||
size in pixels. ``x`` and ``y`` set the window position, measured in pixels
|
||||
@@ -1675,17 +1618,6 @@ Window
|
||||
screen height, make the window smaller until either its width is 90%
|
||||
of the screen, or its height is 80% of the screen.
|
||||
|
||||
``--autofit-smaller=<[W[xH]]>``
|
||||
This option behaves exactly like ``--autofit``, except that it sets the
|
||||
minimum size of the window (just as ``--autofit-larger`` sets the maximum).
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``500x500``
|
||||
Make the window at least 500 pixels wide and 500 pixels high
|
||||
(depending on the video aspect ratio, the width or height will be
|
||||
larger than 500 in order to keep the aspect ratio the same).
|
||||
|
||||
``--autosync=<factor>``
|
||||
Gradually adjusts the A/V sync based on audio delay measurements.
|
||||
Specifying ``--autosync=0``, the default, will cause frame timing to be
|
||||
@@ -2211,9 +2143,6 @@ Demuxer
|
||||
a timestamp difference higher than the readahead amount relative to the
|
||||
last packet returned to the decoder, the demuxer keeps reading.
|
||||
|
||||
Note that the ``--cache-secs`` option will override this value if a cache
|
||||
is enabled, and the value is larger.
|
||||
|
||||
(This value tends to be fuzzy, because many file formats don't store linear
|
||||
timestamps.)
|
||||
|
||||
@@ -2341,7 +2270,7 @@ Input
|
||||
|
||||
``--input-vo-keyboard=<yes|no>``
|
||||
Disable all keyboard input on for VOs which can't participate in proper
|
||||
keyboard input dispatching. May not affect all VOs. Generally useful for
|
||||
keyboard input dispatching. This currently affects X11. Generally useful for
|
||||
embedding only.
|
||||
|
||||
On X11, a sub-window with input enabled grabs all keyboard input as long
|
||||
@@ -2353,14 +2282,11 @@ Input
|
||||
behavior, but naively embedding foreign windows breaks it.
|
||||
|
||||
The only way to handle this reasonably is using the XEmbed protocol, which
|
||||
was designed to solve these problems. GTK provides ``GtkSocket``, which
|
||||
supports XEmbed. Qt doesn't seem to provide anything working in newer
|
||||
versions.
|
||||
was designed to solve these problems. But Qt has questionable support, and
|
||||
mpv doesn't implement it yet.
|
||||
|
||||
If the embedder supports XEmbed, input should work with default settings
|
||||
and with this option disabled. Note that ``input-default-bindings`` is
|
||||
disabled by default in libmpv as well - it should be enabled if you want
|
||||
the mpv default key bindings.
|
||||
As a workaround, this option is disabled by default in libmpv. (Note that
|
||||
``input-default-bindings`` is disabled by default in libmpv as well.)
|
||||
|
||||
(This option was renamed from ``--input-x11-keyboard``.)
|
||||
|
||||
@@ -2751,7 +2677,7 @@ Terminal
|
||||
``--no-msg-color``
|
||||
Disable colorful console output on terminals.
|
||||
|
||||
``--msg-level=<module1=level1,module2=level2,...>``
|
||||
``--msg-level=<module1=level1:module2=level2:...>``
|
||||
Control verbosity directly for each module. The ``all`` module changes the
|
||||
verbosity of all the modules not explicitly specified on the command line.
|
||||
|
||||
@@ -3090,7 +3016,7 @@ Cache
|
||||
``--cache-secs=<seconds>``
|
||||
How many seconds of audio/video to prefetch if the cache is active. This
|
||||
overrides the ``--demuxer-readahead-secs`` option if and only if the cache
|
||||
is enabled and the value is larger. (Default: 2.)
|
||||
is enabled. (Default: 2.)
|
||||
|
||||
``--cache-pause``, ``--no-cache-pause``
|
||||
Whether the player should automatically pause when the cache runs low,
|
||||
@@ -3141,11 +3067,6 @@ Network
|
||||
``--referrer=<string>``
|
||||
Specify a referrer path or URL for HTTP requests.
|
||||
|
||||
``--network-timeout=<seconds>``
|
||||
Specify the network timeout in seconds. This affects at least HTTP. The
|
||||
special value 0 (default) uses the FFmpeg/Libav defaults. If a protocol
|
||||
is used which does not support timeouts, this option is silently ignored.
|
||||
|
||||
``--rtsp-transport=<lavf|udp|tcp|http>``
|
||||
Select RTSP transport method (default: tcp). This selects the underlying
|
||||
network transport when playing ``rtsp://...`` URLs. The value ``lavf``
|
||||
@@ -3156,9 +3077,9 @@ Network
|
||||
by default. The option allows the following parameters:
|
||||
|
||||
:no: Don't do anything special. Typically, this will simply pick the
|
||||
first audio/video streams it can find.
|
||||
first audio/video streams it can find. (Default.)
|
||||
:min: Pick the streams with the lowest bitrate.
|
||||
:max: Same, but highest bitrate. (Default.)
|
||||
:max: Same, but highest bitrate.
|
||||
|
||||
The bitrate as used is sent by the server, and there's no guarantee it's
|
||||
actually meaningful.
|
||||
@@ -3174,28 +3095,11 @@ DVB
|
||||
in the mpv configuration directory (usually ``~/.config/mpv``) with the
|
||||
filename ``channels.conf.{sat,ter,cbl,atsc}`` (based on your card type) or
|
||||
``channels.conf`` as a last resort.
|
||||
For DVB-S/2 cards, a VDR 1.7.x format channel list is recommended
|
||||
as it allows tuning to DVB-S2 channels, enabling subtitles and
|
||||
decoding the PMT (which largely improves the demuxing).
|
||||
Classic mplayer format channel lists are still supported (without
|
||||
these improvements), and for other card types, only limited VDR
|
||||
format channel list support is implemented (patches welcome).
|
||||
For channels with dynamic PID switching or incomplete
|
||||
``channels.conf``, ``--dvbin-full-transponder`` or the magic PID
|
||||
``8192`` are recommended.
|
||||
|
||||
``--dvbin-timeout=<1-30>``
|
||||
Maximum number of seconds to wait when trying to tune a frequency before
|
||||
giving up (default: 30).
|
||||
|
||||
``--dvbin-full-transponder=<yes|no>``
|
||||
Apply no filters on program PIDs, only tune to frequency and pass full
|
||||
transponder to demuxer. This is useful to record multiple programs
|
||||
on a single transponder, or to work around issues in the ``channels.conf``.
|
||||
It is also recommended to use this for channels which switch PIDs
|
||||
on-the-fly, e.g. for regional news.
|
||||
|
||||
Default: ``no``
|
||||
|
||||
PVR
|
||||
---
|
||||
@@ -3259,15 +3163,6 @@ PVR
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
``--display-tags=tag1,tags2,...``
|
||||
Set the list of tags that should be displayed on the terminal. Tags that
|
||||
are in the list, but are not present in the played file, will not be shown.
|
||||
If a value ends with ``*``, all tags are matched by prefix (though there
|
||||
is no general globbing). Just passing ``*`` essentially filtering.
|
||||
|
||||
The default includes a common list of tags, call mpv with ``--list-options``
|
||||
to see it.
|
||||
|
||||
``--mc=<seconds/frame>``
|
||||
Maximum A-V sync correction per frame (in seconds)
|
||||
|
||||
@@ -3288,9 +3183,6 @@ Miscellaneous
|
||||
interrupted. Note that, due to cache latencies, captured data may begin and
|
||||
end somewhat delayed compared to what you see displayed.
|
||||
|
||||
The destination file is always appended. (Before mpv 0.8.0, the file was
|
||||
overwritten.)
|
||||
|
||||
``--stream-dump=<filename>``
|
||||
Same as ``--stream-capture``, but do not start playback. Instead, the entire
|
||||
file is dumped.
|
||||
|
||||
+6
-11
@@ -127,7 +127,7 @@ 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 Hide the OSC permanently until mpv is restarted.
|
||||
@@ -138,7 +138,7 @@ Configuration
|
||||
|
||||
The OSC offers limited configuration through a config file
|
||||
``lua-settings/osc.conf`` placed in mpv's user dir and through the
|
||||
``--script-opts`` command-line option. Options provided through the command-line
|
||||
``--lua-opts`` command-line option. Options provided through the command-line
|
||||
will override those from the config file.
|
||||
|
||||
Config Syntax
|
||||
@@ -161,7 +161,7 @@ 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
|
||||
@@ -225,10 +225,9 @@ Configurable Options
|
||||
| Minimum amount of pixels the mouse has to move between ticks to make
|
||||
the OSC show up
|
||||
|
||||
``layout``
|
||||
| Default: box
|
||||
| The layout for the OSC. Currently available are: box, slimbox,
|
||||
bottombar and topbar.
|
||||
``seektooltip``
|
||||
| Default: yes
|
||||
| Display a tooltip over the seekbar indicating time at mouse position.
|
||||
|
||||
``seekbarstyle``
|
||||
| Default: slider
|
||||
@@ -246,10 +245,6 @@ in ``input.conf``, or sent by other scripts.
|
||||
``disable-osc``
|
||||
Hide the OSC permanently. This is also what the ``del`` key does.
|
||||
|
||||
``osc-message``
|
||||
Show a message on screen using the OSC. First argument is the message,
|
||||
second the duration in seconds.
|
||||
|
||||
|
||||
Example
|
||||
|
||||
|
||||
+287
-13
@@ -143,8 +143,8 @@ Available filters are:
|
||||
Accurate rounding for the vertical scaler, which may be faster or
|
||||
slower than the default rounding.
|
||||
|
||||
:no: Disable accurate rounding (default).
|
||||
:yes: Enable accurate rounding.
|
||||
:0: Disable accurate rounding (default).
|
||||
:1: Enable accurate rounding.
|
||||
|
||||
``dsize[=w:h:aspect-method:r:aspect]``
|
||||
Changes the intended display size/aspect at an arbitrary point in the
|
||||
@@ -231,6 +231,156 @@ Available filters are:
|
||||
``<fmt>``
|
||||
Format name, e.g. rgb15, bgr24, 420p, etc. (default: 420p).
|
||||
|
||||
``pp=[filter string]``
|
||||
Enables the specified chain of post-processing subfilters. Subfilters must
|
||||
be separated by '/' and can be disabled by prepending a '-'. Each
|
||||
subfilter and some options have a short and a long name that can be used
|
||||
interchangeably, i.e. ``dr``/``dering`` are the same.
|
||||
|
||||
.. note::
|
||||
|
||||
Unlike in MPlayer or in earlier versions, you must quote the pp string
|
||||
if it contains ``:`` characters, e.g. ``'--vf=pp=[...]'``.
|
||||
|
||||
.. admonition:: Warning
|
||||
|
||||
This filter is most likely useless on modern HD video. It might be
|
||||
helpful with old low-resolution files.
|
||||
|
||||
All subfilters share common options to determine their scope:
|
||||
|
||||
``a/autoq``
|
||||
Automatically switch the subfilter off if the CPU is too slow.
|
||||
``c/chrom``
|
||||
Do chrominance filtering, too (default).
|
||||
``y/nochrom``
|
||||
Do luminance filtering only (no chrominance).
|
||||
``n/noluma``
|
||||
Do chrominance filtering only (no luminance).
|
||||
|
||||
.. note::
|
||||
|
||||
``--vf=pp:help`` shows a list of available subfilters.
|
||||
|
||||
Available subfilters are:
|
||||
|
||||
``hb/hdeblock[:difference[:flatness]]``
|
||||
horizontal deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
``vb/vdeblock[:difference[:flatness]]``
|
||||
vertical deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
``ha/hadeblock[:difference[:flatness]]``
|
||||
accurate horizontal deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
``va/vadeblock[:difference[:flatness]]``
|
||||
accurate vertical deblocking filter
|
||||
|
||||
:<difference>: Difference factor where higher values mean more
|
||||
deblocking (default: 32).
|
||||
:<flatness>: Flatness threshold where lower values mean more
|
||||
deblocking (default: 39).
|
||||
|
||||
The horizontal and vertical deblocking filters share the difference and
|
||||
flatness values so you cannot set different horizontal and vertical
|
||||
thresholds.
|
||||
|
||||
``h1/x1hdeblock``
|
||||
experimental horizontal deblocking filter
|
||||
|
||||
``v1/x1vdeblock``
|
||||
experimental vertical deblocking filter
|
||||
|
||||
``dr/dering``
|
||||
deringing filter
|
||||
|
||||
``tn/tmpnoise[:threshold1[:threshold2[:threshold3]]]``
|
||||
temporal noise reducer
|
||||
|
||||
:<threshold1>: larger -> stronger filtering
|
||||
:<threshold2>: larger -> stronger filtering
|
||||
:<threshold3>: larger -> stronger filtering
|
||||
|
||||
``al/autolevels[:f/fullyrange]``
|
||||
automatic brightness / contrast correction
|
||||
|
||||
:f/fullyrange: Stretch luminance to (0-255).
|
||||
|
||||
``lb/linblenddeint``
|
||||
Linear blend deinterlacing filter that deinterlaces the given block by
|
||||
filtering all lines with a (1 2 1) filter.
|
||||
|
||||
``li/linipoldeint``
|
||||
Linear interpolating deinterlacing filter that deinterlaces the given
|
||||
block by linearly interpolating every second line.
|
||||
|
||||
``ci/cubicipoldeint``
|
||||
Cubic interpolating deinterlacing filter deinterlaces the given block
|
||||
by cubically interpolating every second line.
|
||||
|
||||
``md/mediandeint``
|
||||
Median deinterlacing filter that deinterlaces the given block by
|
||||
applying a median filter to every second line.
|
||||
|
||||
``fd/ffmpegdeint``
|
||||
FFmpeg deinterlacing filter that deinterlaces the given block by
|
||||
filtering every second line with a (-1 4 2 4 -1) filter.
|
||||
|
||||
``l5/lowpass5``
|
||||
Vertically applied FIR low-pass deinterlacing filter that deinterlaces
|
||||
the given block by filtering all lines with a (-1 2 6 2 -1) filter.
|
||||
|
||||
``fq/forceQuant[:quantizer]``
|
||||
Overrides the quantizer table from the input with the constant
|
||||
quantizer you specify.
|
||||
|
||||
:<quantizer>: quantizer to use
|
||||
|
||||
``de/default``
|
||||
default pp filter combination (hb:a,vb:a,dr:a)
|
||||
|
||||
``fa/fast``
|
||||
fast pp filter combination (h1:a,v1:a,dr:a)
|
||||
|
||||
``ac``
|
||||
high quality pp filter combination (ha:a:128:7,va:a,dr:a)
|
||||
|
||||
.. note::
|
||||
|
||||
This filter is only available if FFmpeg/Libav has been compiled
|
||||
with libpostproc enabled.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
``--vf=pp=hb/vb/dr/al``
|
||||
horizontal and vertical deblocking, deringing and automatic
|
||||
brightness/contrast
|
||||
|
||||
``--vf=pp=de/-al``
|
||||
default filters without brightness/contrast correction
|
||||
|
||||
``--vf=pp=[default/tmpnoise:1:2:3]``
|
||||
Enable default filters & temporal denoiser.
|
||||
|
||||
``--vf=pp=[hb:y/vb:a]``
|
||||
Horizontal deblocking on luminance only, and switch vertical
|
||||
deblocking on or off automatically depending on available CPU time.
|
||||
|
||||
``lavfi=graph[:sws-flags[:o=opts]]``
|
||||
Filter video using FFmpeg's libavfilter.
|
||||
|
||||
@@ -301,6 +451,10 @@ Available filters are:
|
||||
``uniform``
|
||||
uniform noise (Gaussian otherwise)
|
||||
|
||||
``hq``
|
||||
high quality (slightly better looking, slightly slower) - not available
|
||||
when using libavfilter
|
||||
|
||||
``hqdn3d[=luma_spatial:chroma_spatial:luma_tmp:chroma_tmp]``
|
||||
This filter aims to reduce image noise producing smooth images and making
|
||||
still images really still (This should enhance compressibility.).
|
||||
@@ -341,6 +495,19 @@ Available filters are:
|
||||
and just plain white. A value of 0.0 turns the gamma correction all
|
||||
the way down while 1.0 leaves it at its full strength (default: 1.0).
|
||||
|
||||
``ilpack[=mode]``
|
||||
When interlaced video is stored in YUV 4:2:0 formats, chroma interlacing
|
||||
does not line up properly due to vertical downsampling of the chroma
|
||||
channels. This filter packs the planar 4:2:0 data into YUY2 (4:2:2) format
|
||||
with the chroma lines in their proper locations, so that in any given
|
||||
scanline, the luma and chroma data both come from the same field.
|
||||
|
||||
``<mode>``
|
||||
Select the sampling mode.
|
||||
|
||||
:0: nearest-neighbor sampling, fast but incorrect
|
||||
:1: linear interpolation (default)
|
||||
|
||||
``unsharp[=lx:ly:la:cx:cy:ca]``
|
||||
unsharp mask / Gaussian blur
|
||||
|
||||
@@ -358,6 +525,9 @@ Available filters are:
|
||||
:<0: blur
|
||||
:>0: sharpen
|
||||
|
||||
``swapuv``
|
||||
Swap U & V plane.
|
||||
|
||||
``pullup[=jl:jr:jt:jb:sb:mp]``
|
||||
Pulldown reversal (inverse telecine) filter, capable of handling mixed
|
||||
hard-telecine, 24000/1001 fps progressive, and 30000/1001 fps progressive
|
||||
@@ -389,6 +559,120 @@ Available filters are:
|
||||
video. The main purpose of setting ``mp`` to a chroma plane is to reduce
|
||||
CPU load and make pullup usable in realtime on slow machines.
|
||||
|
||||
``divtc[=options]``
|
||||
Inverse telecine for deinterlaced video. If 3:2-pulldown telecined video
|
||||
has lost one of the fields or is deinterlaced using a method that keeps
|
||||
one field and interpolates the other, the result is a juddering video that
|
||||
has every fourth frame duplicated. This filter is intended to find and
|
||||
drop those duplicates and restore the original film framerate. Two
|
||||
different modes are available: One-pass mode is the default and is
|
||||
straightforward to use, but has the disadvantage that any changes in the
|
||||
telecine phase (lost frames or bad edits) cause momentary judder until the
|
||||
filter can resync again. Two-pass mode avoids this by analyzing the entire
|
||||
video beforehand so it will have forward knowledge about the phase changes
|
||||
and can resync at the exact spot. These passes do *not* correspond to pass
|
||||
one and two of the encoding process. You must run an extra pass using
|
||||
``divtc`` pass one before the actual encoding throwing the resulting video
|
||||
away. Then use ``divtc`` pass two for the actual encoding. If you use
|
||||
multiple encoder passes, use ``divtc`` pass two for all of them.
|
||||
|
||||
The options are:
|
||||
|
||||
``pass=1|2``
|
||||
Use two pass mode.
|
||||
|
||||
``file=<filename>``
|
||||
Set the two pass log filename (default: ``framediff.log``).
|
||||
|
||||
``threshold=<value>``
|
||||
Set the minimum strength the telecine pattern must have for the filter
|
||||
to believe in it (default: 0.5). This is used to avoid recognizing
|
||||
false pattern from the parts of the video that are very dark or very
|
||||
still.
|
||||
|
||||
``window=<numframes>``
|
||||
Set the number of past frames to look at when searching for pattern
|
||||
(default: 30). Longer window improves the reliability of the pattern
|
||||
search, but shorter window improves the reaction time to the changes
|
||||
in the telecine phase. This only affects the one-pass mode. The
|
||||
two-pass mode currently uses fixed window that extends to both future
|
||||
and past.
|
||||
|
||||
``phase=0|1|2|3|4``
|
||||
Sets the initial telecine phase for one pass mode (default: 0). The
|
||||
two-pass mode can see the future, so it is able to use the correct
|
||||
phase from the beginning, but one-pass mode can only guess. It catches
|
||||
the correct phase when it finds it, but this option can be used to fix
|
||||
the possible juddering at the beginning. The first pass of the two
|
||||
pass mode also uses this, so if you save the output from the first
|
||||
pass, you get constant phase result.
|
||||
|
||||
``deghost=<value>``
|
||||
Set the deghosting threshold (0-255 for one-pass mode, -255-255 for
|
||||
two-pass mode, default 0). If nonzero, deghosting mode is used. This
|
||||
is for video that has been deinterlaced by blending the fields
|
||||
together instead of dropping one of the fields. Deghosting amplifies
|
||||
any compression artifacts in the blended frames, so the parameter
|
||||
value is used as a threshold to exclude those pixels from deghosting
|
||||
that differ from the previous frame less than specified value. If two
|
||||
pass mode is used, then negative value can be used to make the filter
|
||||
analyze the whole video in the beginning of pass-2 to determine
|
||||
whether it needs deghosting or not and then select either zero or the
|
||||
absolute value of the parameter. Specify this option for pass 2, it
|
||||
makes no difference on pass 1.
|
||||
|
||||
``phase[=t|b|p|a|u|T|B|A|U][:v]``
|
||||
Delay interlaced video by one field time so that the field order changes.
|
||||
The intended use is to fix PAL videos that have been captured with the
|
||||
opposite field order to the film-to-video transfer. The options are:
|
||||
|
||||
``t``
|
||||
Capture field order top-first, transfer bottom-first. Filter will
|
||||
delay the bottom field.
|
||||
|
||||
``b``
|
||||
Capture bottom-first, transfer top-first. Filter will delay the top
|
||||
field.
|
||||
|
||||
``p``
|
||||
Capture and transfer with the same field order. This mode only exists
|
||||
for the documentation of the other options to refer to, but if you
|
||||
actually select it, the filter will faithfully do nothing ;-)
|
||||
|
||||
``a``
|
||||
Capture field order determined automatically by field flags, transfer
|
||||
opposite. Filter selects among ``t`` and ``b`` modes on a frame by frame
|
||||
basis using field flags. If no field information is available, then this
|
||||
works just like ``u``.
|
||||
|
||||
``u``
|
||||
Capture unknown or varying, transfer opposite. Filter selects among
|
||||
``t`` and ``b`` on a frame by frame basis by analyzing the images and
|
||||
selecting the alternative that produces best match between the fields.
|
||||
|
||||
``T``
|
||||
Capture top-first, transfer unknown or varying. Filter selects among
|
||||
``t`` and ``p`` using image analysis.
|
||||
|
||||
``B``
|
||||
Capture bottom-first, transfer unknown or varying. Filter selects
|
||||
among ``b`` and ``p`` using image analysis.
|
||||
|
||||
``A``
|
||||
Capture determined by field flags, transfer unknown or varying. Filter
|
||||
selects among ``t``, ``b`` and ``p`` using field flags and image
|
||||
analysis. If no field information is available, then this works just
|
||||
like ``U``. This is the default mode.
|
||||
|
||||
``U``
|
||||
Both capture and transfer unknown or varying. Filter selects among
|
||||
``t``, ``b`` and ``p`` using image analysis only.
|
||||
|
||||
``v``
|
||||
Verbose operation. Prints the selected mode for each frame and the
|
||||
average squared difference between fields for ``t``, ``b``, and ``p``
|
||||
alternatives. (Ignored when libavfilter is used.)
|
||||
|
||||
``yadif=[mode[:enabled=yes|no]]``
|
||||
Yet another deinterlacing filter
|
||||
|
||||
@@ -619,16 +903,13 @@ Available filters are:
|
||||
filters work anyway.)
|
||||
|
||||
``concurrent-frames``
|
||||
Number of frames that should be requested in parallel. The
|
||||
Number of frames that should be requested in parallel (default: 2). The
|
||||
level of concurrency depends on the filter and how quickly mpv can
|
||||
decode video to feed the filter. This value should probably be
|
||||
proportional to the number of cores on your machine. Most time,
|
||||
making it higher than the number of cores can actually make it
|
||||
slower.
|
||||
|
||||
By default, this uses the special value ``auto``, which sets the option
|
||||
to the number of detected logical CPU cores.
|
||||
|
||||
The following variables are defined by mpv:
|
||||
|
||||
``video_in``
|
||||
@@ -649,9 +930,6 @@ Available filters are:
|
||||
|
||||
Useful for some filters which insist on having a FPS.
|
||||
|
||||
``display_fps``
|
||||
Refresh rate of the current display. Note that this value can be 0.
|
||||
|
||||
``vapoursynth-lazy``
|
||||
The same as ``vapoursynth``, but doesn't load Python scripts. Instead, a
|
||||
custom backend using Lua and the raw VapourSynth API is used. The syntax
|
||||
@@ -692,10 +970,6 @@ Available filters are:
|
||||
Show only first field (going by ``--field-dominance``).
|
||||
bob
|
||||
bob deinterlacing (default).
|
||||
weave, motion-adaptive, motion-compensated
|
||||
Advanced deinterlacing algorithms. Whether these actually work
|
||||
depends on the GPU hardware, the GPU drivers, driver bugs, and
|
||||
mpv bugs.
|
||||
|
||||
``vdpaupp``
|
||||
VDPAU video post processing. Works with ``--vo=vdpau`` and ``--vo=opengl``
|
||||
|
||||
+300
-175
@@ -278,88 +278,109 @@ Available video output drivers are:
|
||||
``opengl-hq`` to use this driver with defaults set to high quality
|
||||
rendering.
|
||||
|
||||
Requires at least OpenGL 2.1.
|
||||
Requires at least OpenGL 2.1 and the ``GL_ARB_texture_rg`` extension. For
|
||||
older drivers, ``opengl-old`` may work.
|
||||
|
||||
Some features are available with OpenGL 3 capable graphics drivers only
|
||||
(or if the necessary extensions are available).
|
||||
|
||||
OpenGL ES 2.0 and 3.0 are supported as well.
|
||||
|
||||
Hardware decoding over OpenGL-interop is supported to some degree. Note
|
||||
that in this mode, some corner case might not be gracefully handled, and
|
||||
color space conversion and chroma upsampling is generally in the hand of
|
||||
the hardware decoder APIs.
|
||||
|
||||
``scale=<filter>``
|
||||
``lscale=<filter>``
|
||||
|
||||
``bilinear``
|
||||
Bilinear hardware texture filtering (fastest, very low quality).
|
||||
This is the default for compatibility reasons.
|
||||
Bilinear hardware texture filtering (fastest, mid-quality).
|
||||
This is the default.
|
||||
|
||||
``spline36``
|
||||
Mid quality and speed. This is the default when using ``opengl-hq``.
|
||||
``lanczos2``
|
||||
Lanczos scaling with radius=2. Provides good quality and speed.
|
||||
|
||||
``lanczos3``
|
||||
Lanczos with radius=3.
|
||||
|
||||
``lanczos``
|
||||
Lanczos scaling. Provides mid quality and speed. Generally worse
|
||||
than ``spline36``, but it results in a slightly sharper image
|
||||
which is good for some content types. The number of taps can be
|
||||
controlled with ``scale-radius``, but is best left unchanged.
|
||||
Generic Lanczos scaling filter. Set radius with ``lradius``.
|
||||
|
||||
This filter corresponds to the old ``lanczos3`` alias if the default
|
||||
radius is used, while ``lanczos2`` corresponds to a radius of 2.
|
||||
``spline36``
|
||||
This is the default when using ``opengl-hq``.
|
||||
|
||||
``ewa_lanczos``
|
||||
Elliptic weighted average Lanczos scaling. Also known as Jinc.
|
||||
Relatively slow, but very good quality. The number of taps can
|
||||
be controlled with ``scale-radius``. Adding extra taps makes the
|
||||
filter sharper but adds more ringing.
|
||||
``bicubic_fast``
|
||||
Bicubic filter. Has a blurring effect on the image, even if no
|
||||
scaling is done.
|
||||
|
||||
This filter supports antiringing (see ``scale-antiring``).
|
||||
``sharpen3``
|
||||
Unsharp masking (sharpening) with radius=3 and a default strength
|
||||
of 0.5 (see ``lparam1``).
|
||||
|
||||
``sharpen5``
|
||||
Unsharp masking (sharpening) with radius=5 and a default strength
|
||||
of 0.5 (see ``lparam1``).
|
||||
|
||||
``mitchell``
|
||||
Mitchell-Netravali. The ``b`` and ``c`` parameters can be set with
|
||||
``scale-param1`` and ``scale-param2``. Both are set to 1/3 by default.
|
||||
This filter is very good at downscaling (see ``scale-down``).
|
||||
``lparam1`` and ``lparam2``. Both are set to 1/3 by default.
|
||||
|
||||
There are some more filters, but most are not as useful. For a complete
|
||||
list, pass ``help`` as value, e.g.::
|
||||
``gaussian``
|
||||
Gaussian filter with a parameter ``p`` for sharpness control.
|
||||
``p`` can be set to float number between 1(blurry) and 100(sharp)
|
||||
and has a default value of about 28.8 (see ``lparam1``).
|
||||
|
||||
mpv --vo=opengl:scale=help
|
||||
Note that for extremely small value of ``p``, a large filter radius
|
||||
might be required to avoid unintended artifacts (see ``lradius``).
|
||||
|
||||
``scale-param1=<value>``
|
||||
|
||||
There are some more filters. For a complete list, pass ``help`` as
|
||||
value, e.g.::
|
||||
|
||||
mpv --vo=opengl:lscale=help
|
||||
|
||||
``lparam1=<value>``
|
||||
Set filter parameters. Ignored if the filter is not tunable. These are
|
||||
unset by default, and use the filter specific default if applicable.
|
||||
|
||||
``scale-param2=<value>``
|
||||
See ``scale-param1``.
|
||||
``lparam2=<value>``
|
||||
See ``lparam1``.
|
||||
|
||||
``scale-radius=<r>``
|
||||
``lradius=<r>``
|
||||
Set radius for filters listed below, must be a float number between 1.0
|
||||
and 16.0. Defaults to be 3.0 if not specified.
|
||||
and 8.0. Defaults to be 2.0 if not specified.
|
||||
|
||||
``sinc``, ``lanczos``, ``ewa_lanczos``, ``blackman``, ``gaussian``
|
||||
``sinc``, ``lanczos``, ``blackman``, ``gaussian``
|
||||
|
||||
Note that depending on filter implementation details and video scaling
|
||||
ratio, the radius that actually being used might be different
|
||||
(most likely being increased a bit).
|
||||
|
||||
``scale-antiring=<value>``
|
||||
Set the antiringing strength. This tries to eliminate ringing, but can
|
||||
introduce other artifacts in the process. Must be a float number
|
||||
between 0.0 and 1.0. The default value of 0.0 disables antiringing
|
||||
entirely.
|
||||
|
||||
Note that this currently only affects ``ewa_lanczos``.
|
||||
|
||||
``scaler-resizes-only``
|
||||
Disable the scaler if the video image is not resized. In that case,
|
||||
``bilinear`` is used instead whatever is set with ``scale``. Bilinear
|
||||
``bilinear`` is used instead whatever is set with ``lscale``. Bilinear
|
||||
will reproduce the source image perfectly if no scaling is performed.
|
||||
Note that this option never affects ``cscale``.
|
||||
Note that this option never affects ``cscale``, although the different
|
||||
processing chain might do chroma scaling differently if ``lscale`` is
|
||||
disabled.
|
||||
|
||||
``stereo=<value>``
|
||||
Select a method for stereo display. You may have to use
|
||||
``--video-aspect`` to fix the aspect value. Experimental, do not expect
|
||||
too much from it.
|
||||
|
||||
no
|
||||
Normal 2D display
|
||||
red-cyan
|
||||
Convert side by side input to full-color red-cyan stereo.
|
||||
green-magenta
|
||||
Convert side by side input to full-color green-magenta stereo.
|
||||
quadbuffer
|
||||
Convert side by side input to quad buffered stereo. Only supported
|
||||
by very few OpenGL cards.
|
||||
|
||||
``srgb``
|
||||
Convert and color correct the output to sRGB before displaying it on
|
||||
the screen. This option enables ``linear-scaling``.
|
||||
the screen. This option enables linear light scaling. It also forces
|
||||
the options ``indirect`` and ``gamma``.
|
||||
|
||||
This option is equivalent to using ``icc-profile`` with an sRGB ICC
|
||||
profile, but it is implemented without a 3DLUT and does not require
|
||||
@@ -402,8 +423,7 @@ Available video output drivers are:
|
||||
Used in ``dither=fruit`` mode only.
|
||||
|
||||
``dither=<fruit|ordered|no>``
|
||||
Select dithering algorithm (default: fruit). (Normally, the
|
||||
``dither-depth`` option controls whether dithering is enabled.)
|
||||
Select dithering algorithm (default: fruit).
|
||||
|
||||
``temporal-dither``
|
||||
Enable temporal dithering. (Only active if dithering is enabled in
|
||||
@@ -421,48 +441,34 @@ Available video output drivers are:
|
||||
Interval in displayed frames between two buffer swaps.
|
||||
1 is equivalent to enable VSYNC, 0 to disable VSYNC.
|
||||
|
||||
``no-scale-sep``
|
||||
When using a separable scale filter for luma, usually two filter
|
||||
passes are done. This is often faster. However, it forces
|
||||
conversion to RGB in an extra pass, so it can actually be slower
|
||||
if used with fast filters on small screen resolutions. Using
|
||||
this options will make rendering a single operation.
|
||||
Note that chroma scalers are always done as 1-pass filters.
|
||||
|
||||
``cscale=<filter>``
|
||||
As ``scale``, but for interpolating chroma information. If the image
|
||||
is not subsampled, this option is ignored entirely. Note that the
|
||||
implementation is currently always done as a single pass, so using
|
||||
it with separable filters will result in slow performance for very
|
||||
little visible benefit.
|
||||
As ``lscale``, but for chroma (2x slower with little visible effect).
|
||||
Note that with some scaling filters, upscaling is always done in
|
||||
RGB. If chroma is not subsampled, this option is ignored, and the
|
||||
luma scaler is used instead. Setting this option is often useless.
|
||||
|
||||
``scale-down=<filter>``
|
||||
Like ``scale``, but apply these filters on downscaling instead. If this
|
||||
option is unset, the filter implied by ``scale`` will be applied.
|
||||
``lscale-down=<filter>``, ``cscale-down=<filter>``
|
||||
Like ``lscale``, but apply these filters on downscaling
|
||||
instead. If these options are unset, the filter implied by ``lscale``
|
||||
(and ``cscale``, respectively) will be applied.
|
||||
|
||||
``cscale-param1``, ``cscale-param2``, ``cscale-radius``, ``cscale-antiring``
|
||||
``cparam1``, ``cparam2``, ``cradius``
|
||||
Set filter parameters and radius for ``cscale``.
|
||||
|
||||
See ``scale-param1``, ``scale-param2``, ``scale-radius`` and
|
||||
``scale-antiring``.
|
||||
|
||||
``linear-scaling``
|
||||
Scale in linear light. This is automatically enabled if ``srgb``,
|
||||
``icc-profile`` or ``sigmoid-upscaling`` is set. It should only
|
||||
be used with a ``fbo-format`` that has at least 16 bit precision.
|
||||
See ``lparam1``, ``lparam2`` and ``lradius``.
|
||||
|
||||
``fancy-downscaling``
|
||||
When using convolution based filters, extend the filter size
|
||||
when downscaling. Trades quality for reduced downscaling performance.
|
||||
|
||||
This is automatically disabled for anamorphic video, because this
|
||||
feature doesn't work correctly with different scale factors in
|
||||
different directions.
|
||||
|
||||
``sigmoid-upscaling``
|
||||
When upscaling, use a sigmoidal color transform to avoid emphasizing
|
||||
ringing artifacts. This also enables ``linear-scaling``.
|
||||
|
||||
``sigmoid-center``
|
||||
The center of the sigmoid curve used for ``sigmoid-upscaling``, must
|
||||
be a float between 0.0 and 1.0. Defaults to 0.75 if not specified.
|
||||
|
||||
``sigmoid-slope``
|
||||
The slope of the sigmoid curve used for ``sigmoid-upscaling``, must
|
||||
be a float between 1.0 and 20.0. Defaults to 6.5 if not specified.
|
||||
|
||||
``no-npot``
|
||||
Force use of power-of-2 texture sizes. For debugging only.
|
||||
Borders will be distorted due to filtering.
|
||||
@@ -470,15 +476,14 @@ Available video output drivers are:
|
||||
``glfinish``
|
||||
Call ``glFinish()`` before and after swapping buffers (default: disabled).
|
||||
Slower, but might help getting better results when doing framedropping.
|
||||
Can completely ruin performance. The details depend entirely on the
|
||||
OpenGL driver.
|
||||
The details depend entirely on the OpenGL driver.
|
||||
|
||||
``waitvsync``
|
||||
Call ``glXWaitVideoSyncSGI`` after each buffer swap (default: disabled).
|
||||
This may or may not help with video timing accuracy and frame drop. It's
|
||||
possible that this makes video output slower, or has no effect at all.
|
||||
|
||||
X11/GLX only.
|
||||
X11 only.
|
||||
|
||||
``sw``
|
||||
Continue even if a software renderer is detected.
|
||||
@@ -494,12 +499,19 @@ Available video output drivers are:
|
||||
Cocoa/OS X
|
||||
win
|
||||
Win32/WGL
|
||||
x11, x11es
|
||||
X11/GLX (the ``es`` variant forces GLES)
|
||||
x11
|
||||
X11/GLX
|
||||
wayland
|
||||
Wayland/EGL
|
||||
x11egl, x11egles
|
||||
X11/EGL (the ``es`` variant forces GLES)
|
||||
|
||||
``indirect``
|
||||
Do YUV conversion and scaling as separate passes. This will first render
|
||||
the video into a video-sized RGB texture, and draw the result on screen.
|
||||
The luma scaler is used to scale the RGB image when rendering to screen.
|
||||
The chroma scaler is used only on YUV conversion, and only if the video
|
||||
is chroma-subsampled (usually the case).
|
||||
This mechanism is disabled on RGB input.
|
||||
Specifying this option directly is generally useful for debugging only.
|
||||
|
||||
``fbo-format=<fmt>``
|
||||
Selects the internal format of textures used for FBOs. The format can
|
||||
@@ -507,34 +519,28 @@ Available video output drivers are:
|
||||
always used, and typically only when using extended scalers.)
|
||||
``fmt`` can be one of: rgb, rgba, rgb8, rgb10, rgb10_a2, rgb16, rgb16f,
|
||||
rgb32f, rgba12, rgba16, rgba16f, rgba32f.
|
||||
Default: rgba.
|
||||
Default: rgb.
|
||||
|
||||
``gamma=<0.1..2.0>``
|
||||
Set a gamma value (default: 1.0). If gamma is adjusted in other ways
|
||||
(like with the ``--gamma`` option or key bindings and the ``gamma``
|
||||
property), the value is multiplied with the other gamma value.
|
||||
``gamma=<0.0..10.0>``
|
||||
Set a gamma value. If gamma is adjusted in other ways (like with
|
||||
the ``--gamma`` option or key bindings and the ``gamma`` property), the
|
||||
value is multiplied with the other gamma value.
|
||||
|
||||
Recommended values based on the environmental brightness:
|
||||
|
||||
1.0
|
||||
Brightly illuminated (default)
|
||||
0.9
|
||||
Slightly dim
|
||||
0.8
|
||||
Pitch black room
|
||||
Setting this value to 1.0 can be used to always enable gamma control.
|
||||
(Disables delayed enabling.)
|
||||
|
||||
``icc-profile=<file>``
|
||||
Load an ICC profile and use it to transform linear RGB to screen output.
|
||||
Needs LittleCMS 2 support compiled in. This option overrides the ``srgb``
|
||||
property, as using both is somewhat redundant. It also enables
|
||||
``linear-scaling``.
|
||||
property, as using both is somewhat redundant. It also enables linear
|
||||
light scaling.
|
||||
|
||||
|
||||
``icc-profile-auto``
|
||||
Automatically select the ICC display profile currently specified by
|
||||
the display settings of the operating system.
|
||||
|
||||
NOTE: Only implemented on OS X and X11
|
||||
NOTE: Only implemented on OS X with Cocoa.
|
||||
|
||||
``icc-cache=<file>``
|
||||
Store and load the 3D LUT created from the ICC profile in this file.
|
||||
@@ -556,6 +562,16 @@ Available video output drivers are:
|
||||
3
|
||||
absolute colorimetric
|
||||
|
||||
``approx-gamma``
|
||||
Approximate the actual gamma function as a pure power curve of
|
||||
1.95. A number of video editing programs and studios apparently use this
|
||||
for mastering instead of the true curve. Most notably, anything in the
|
||||
Apple ecosystem uses this approximation - including all programs
|
||||
compatible with it. It's a sound idea to try enabling this flag first
|
||||
when watching videos and shows to see if things look better that way.
|
||||
|
||||
This only affects the output when using either ``icc-profile`` or ``srgb``.
|
||||
|
||||
``3dlut-size=<r>x<g>x<b>``
|
||||
Size of the 3D LUT generated from the ICC profile in each dimension.
|
||||
Default is 128x256x64.
|
||||
@@ -571,8 +587,8 @@ Available video output drivers are:
|
||||
if the video contains alpha information (which is extremely rare). May
|
||||
not be supported on all platforms. If alpha framebuffers are
|
||||
unavailable, it silently falls back on a normal framebuffer. Note
|
||||
that if you set the ``fbo-format`` option to a non-default value,
|
||||
a format with alpha must be specified, or this won't work.
|
||||
that when using FBO indirections (such as with ``opengl-hq``), an FBO
|
||||
format with alpha must be specified with the ``fbo-format`` option.
|
||||
no
|
||||
Ignore alpha component.
|
||||
|
||||
@@ -585,58 +601,12 @@ Available video output drivers are:
|
||||
have any advantages over normal textures. Note that hardware decoding
|
||||
overrides this flag.
|
||||
|
||||
``background=<color>``
|
||||
Color used to draw parts of the mpv window not covered by video.
|
||||
See ``--osd-color`` option how colors are defined.
|
||||
|
||||
``smoothmotion``
|
||||
Reduce stuttering caused by mismatches in video fps and display
|
||||
refresh rate (also known as judder).
|
||||
|
||||
Instead of drawing source frames for variable durations, smoothmotion
|
||||
will blend frames that overlap the transition between two frames in
|
||||
the source material.
|
||||
|
||||
For example, a 24 Hz clip played back on a 60 Hz display would normally
|
||||
result in a pattern like this::
|
||||
|
||||
A A A B B C C C D D E E E F F
|
||||
|
||||
which has different lengths, alternating between 3 and 2. This
|
||||
difference in frame duration is what causes judder.
|
||||
|
||||
With smoothmotion enabled, the pattern changes to::
|
||||
|
||||
A A A+B B B C C C+D D D E E E+F F F
|
||||
|
||||
where A+B is a blend of A and B. In this pattern, each frame gets a
|
||||
(consistent) duration of roughly 2.5 - resulting in smooth motion.
|
||||
|
||||
GPU drivers or compositing window managers overriding vsync behavior
|
||||
can lead to bad results. If the framerate is close to or over the
|
||||
display refresh rate, results can be bad as well.
|
||||
|
||||
.. note:: On systems other than Linux or OS X, you currently must set
|
||||
the ``--display-fps`` option, or the results will be bad.
|
||||
|
||||
``smoothmotion-threshold=<0.0-0.5>``
|
||||
Mix threshold at which interpolation is skipped (default: 0.0 – never
|
||||
skip).
|
||||
|
||||
For example, with a ``smoothmotion-threshold`` of 0.1, if the
|
||||
smoothmotion algorithm would try to blend two frames by a ratio of
|
||||
95% A + 5% B, it would simply display A instead. (Since the
|
||||
distance, 0.05, is lower than the threshold)
|
||||
|
||||
Setting this to 0.5 would be similar to disabling smoothmotion
|
||||
completely, since it would always just display the nearest frame.
|
||||
|
||||
``opengl-hq``
|
||||
Same as ``opengl``, but with default settings for high quality rendering.
|
||||
|
||||
This is equivalent to::
|
||||
|
||||
--vo=opengl:scale=spline36:scale-down=mitchell:dither-depth=auto:fbo-format=rgba16:fancy-downscaling:sigmoid-upscaling
|
||||
--vo=opengl:lscale=spline36:dither-depth=auto:fbo-format=rgba16
|
||||
|
||||
Note that some cheaper LCDs do dithering that gravely interferes with
|
||||
``opengl``'s dithering. Disabling dithering with ``dither-depth=no`` helps.
|
||||
@@ -648,6 +618,188 @@ Available video output drivers are:
|
||||
float texture support, and some OS X setups being very slow with ``rgb16``
|
||||
but fast with ``rgb32f``.
|
||||
|
||||
``opengl-old``
|
||||
OpenGL video output driver, old version. Video size must be smaller
|
||||
than the maximum texture size of your OpenGL implementation. Intended to
|
||||
work even with the most basic OpenGL implementations, but also makes use
|
||||
of newer extensions which allow support for more color spaces.
|
||||
|
||||
The code performs very few checks, so if a feature does not work, this
|
||||
might be because it is not supported by your card and/or OpenGL
|
||||
implementation, even if you do not get any error message. Use ``glxinfo``
|
||||
or a similar tool to display the supported OpenGL extensions.
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``(no-)ati-hack``
|
||||
ATI drivers may give a corrupted image when PBOs are used (when using
|
||||
``force-pbo``). This option fixes this, at the expense of using a bit
|
||||
more memory.
|
||||
``(no-)force-pbo``
|
||||
Always uses PBOs to transfer textures even if this involves an extra
|
||||
copy. Currently this gives a little extra speed with NVIDIA drivers
|
||||
and a lot more speed with ATI drivers. May need the ``ati-hack``
|
||||
suboption to work correctly.
|
||||
``(no-)scaled-osd``
|
||||
Scales the OSD and subtitles instead of rendering them at display size
|
||||
(default: disabled).
|
||||
``rectangle=<0,1,2>``
|
||||
Select usage of rectangular textures, which saves video RAM, but often
|
||||
is slower (default: 0).
|
||||
|
||||
0
|
||||
Use power-of-two textures (default).
|
||||
1
|
||||
Use the ``GL_ARB_texture_rectangle`` extension.
|
||||
2
|
||||
Use the ``GL_ARB_texture_non_power_of_two`` extension. In some
|
||||
cases only supported in software and thus very slow.
|
||||
|
||||
``swapinterval=<n>``
|
||||
Minimum interval between two buffer swaps, counted in displayed frames
|
||||
(default: 1). 1 is equivalent to enabling VSYNC, 0 to disabling VSYNC.
|
||||
Values below 0 will leave it at the system default. This limits the
|
||||
framerate to (horizontal refresh rate / n). Requires
|
||||
``GLX_SGI_swap_control`` support to work. With some (most/all?)
|
||||
implementations this only works in fullscreen mode.
|
||||
``ycbcr``
|
||||
Use the ``GL_MESA_ycbcr_texture`` extension to convert YUV to RGB. In
|
||||
most cases this is probably slower than doing software conversion to
|
||||
RGB.
|
||||
``yuv=<n>``
|
||||
Select the type of YUV to RGB conversion. The default is
|
||||
auto-detection deciding between values 0 and 2.
|
||||
|
||||
0
|
||||
Use software conversion. Compatible with all OpenGL versions.
|
||||
Provides brightness, contrast and saturation control.
|
||||
1
|
||||
Same as 2. This used to use NVIDIA-specific extensions, which
|
||||
did not provide any advantages over using fragment programs, except
|
||||
possibly on very ancient graphics cards. It produced a gray-ish
|
||||
output, which is why it has been removed.
|
||||
2
|
||||
Use a fragment program. Needs the ``GL_ARB_fragment_program``
|
||||
extension and at least three texture units. Provides brightness,
|
||||
contrast, saturation and hue control.
|
||||
3
|
||||
Use a fragment program using the ``POW`` instruction. Needs the
|
||||
``GL_ARB_fragment_program`` extension and at least three texture
|
||||
units. Provides brightness, contrast, saturation, hue and gamma
|
||||
control. Gamma can also be set independently for red, green and
|
||||
blue. Method 4 is usually faster.
|
||||
4
|
||||
Use a fragment program with additional lookup. Needs the
|
||||
``GL_ARB_fragment_program`` extension and at least four texture
|
||||
units. Provides brightness, contrast, saturation, hue and gamma
|
||||
control. Gamma can also be set independently for red, green and
|
||||
blue.
|
||||
5
|
||||
Use ATI-specific method (for older cards). This uses an
|
||||
ATI-specific extension (``GL_ATI_fragment_shader`` - not
|
||||
``GL_ARB_fragment_shader``!). At least three texture units are
|
||||
needed. Provides saturation and hue control. This method is fast
|
||||
but inexact.
|
||||
6
|
||||
Use a 3D texture to do conversion via lookup. Needs the
|
||||
``GL_ARB_fragment_program extension`` and at least four texture
|
||||
units. Extremely slow (software emulation) on some (all?) ATI
|
||||
cards since it uses a texture with border pixels. Provides
|
||||
brightness, contrast, saturation, hue and gamma control. Gamma can
|
||||
also be set independently for red, green and blue. Speed depends
|
||||
more on GPU memory bandwidth than other methods.
|
||||
|
||||
``lscale=<n>``
|
||||
Select the scaling function to use for luminance scaling. Only valid
|
||||
for yuv modes 2, 3, 4 and 6.
|
||||
|
||||
0
|
||||
Use simple linear filtering (default).
|
||||
1
|
||||
Use bicubic B-spline filtering (better quality). Needs one
|
||||
additional texture unit. Older cards will not be able to handle
|
||||
this for chroma at least in fullscreen mode.
|
||||
2
|
||||
Use cubic filtering in horizontal, linear filtering in vertical
|
||||
direction. Works on a few more cards than method 1.
|
||||
3
|
||||
Same as 1 but does not use a lookup texture. Might be faster on
|
||||
some cards.
|
||||
4
|
||||
Use experimental unsharp masking with 3x3 support and a default
|
||||
strength of 0.5 (see ``filter-strength``).
|
||||
5
|
||||
Use experimental unsharp masking with 5x5 support and a default
|
||||
strength of 0.5 (see ``filter-strength``).
|
||||
|
||||
``cscale=<n>``
|
||||
Select the scaling function to use for chrominance scaling. For
|
||||
details see ``lscale``.
|
||||
``filter-strength=<value>``
|
||||
Set the effect strength for the ``lscale``/``cscale`` filters that
|
||||
support it.
|
||||
``stereo=<value>``
|
||||
Select a method for stereo display. You may have to use
|
||||
``--video-aspect`` to fix the aspect value. Experimental, do not expect
|
||||
too much from it.
|
||||
|
||||
0
|
||||
Normal 2D display
|
||||
1
|
||||
Convert side by side input to full-color red-cyan stereo.
|
||||
2
|
||||
Convert side by side input to full-color green-magenta stereo.
|
||||
3
|
||||
Convert side by side input to quad buffered stereo. Only supported
|
||||
by very few OpenGL cards.
|
||||
|
||||
The following options are only useful if writing your own fragment programs.
|
||||
|
||||
``customprog=<filename>``
|
||||
Load a custom fragment program from ``<filename>``.
|
||||
``customtex=<filename>``
|
||||
Load a custom "gamma ramp" texture from ``<filename>``. This can be used
|
||||
in combination with ``yuv=4`` or with the ``customprog`` option.
|
||||
``(no-)customtlin``
|
||||
If enabled (default) use ``GL_LINEAR`` interpolation, otherwise use
|
||||
``GL_NEAREST`` for customtex texture.
|
||||
``(no-)customtrect``
|
||||
If enabled, use ``texture_rectangle`` for the ``customtex`` texture.
|
||||
Default is disabled.
|
||||
``(no-)mipmapgen``
|
||||
If enabled, mipmaps for the video are automatically generated. This
|
||||
should be useful together with the ``customprog`` and the ``TXB``
|
||||
instruction to implement blur filters with a large radius. For most
|
||||
OpenGL implementations, this is very slow for any non-RGB formats.
|
||||
Default is disabled.
|
||||
|
||||
Normally there is no reason to use the following options; they mostly
|
||||
exist for testing purposes.
|
||||
|
||||
``(no-)glfinish``
|
||||
Call ``glFinish()`` before swapping buffers. Slower but in some cases
|
||||
more correct output (default: disabled).
|
||||
``(no-)manyfmts``
|
||||
Enables support for more (RGB and BGR) color formats (default: enabled).
|
||||
Needs OpenGL version >= 1.2.
|
||||
``slice-height=<0-...>``
|
||||
Number of lines copied to texture in one piece (default: 0). 0 for
|
||||
whole image.
|
||||
``sw``
|
||||
Continue even if a software renderer is detected.
|
||||
|
||||
``backend=<sys>``
|
||||
auto
|
||||
auto-select (default)
|
||||
cocoa
|
||||
Cocoa/OS X
|
||||
win
|
||||
Win32/WGL
|
||||
x11
|
||||
X11/GLX
|
||||
wayland
|
||||
Wayland/EGL
|
||||
|
||||
``sdl``
|
||||
SDL 2.0+ Render video output driver, depending on system with or without
|
||||
hardware acceleration. Should work on all platforms supported by SDL 2.0.
|
||||
@@ -772,30 +924,3 @@ Available video output drivers are:
|
||||
Use 3 buffers instead of 2. This can lead to more fluid playback, but
|
||||
uses more memory.
|
||||
|
||||
``opengl-cb``
|
||||
For use with libmpv direct OpenGL embedding; useless in any other contexts.
|
||||
(See ``<mpv/opengl_cb.h>``.)
|
||||
Usually, ``opengl-cb`` renders frames asynchronously by client and this
|
||||
can cause some frame drops. In order to provide a way to handle this
|
||||
situation, ``opengl-cb`` has its own frame queue and calls update callback
|
||||
more frequently if the queue is not empty regardless of existence of new frame.
|
||||
Once the queue is filled, ``opengl-cb`` drops frames automatically.
|
||||
|
||||
With default options, ``opengl-cb`` renders only the latest frame and drops
|
||||
all frames handed over while waiting render function after update callback.
|
||||
|
||||
``frame-queue-size=<1..100>``
|
||||
The maximum count of frames which the frame queue can hold (default: 1)
|
||||
|
||||
``frame-drop-mode=<pop|clear>``
|
||||
Select the behavior when the frame queue is full.
|
||||
|
||||
pop
|
||||
Drop the oldest frame in the frame queue. (default)
|
||||
clear
|
||||
Drop all frames in the frame queue.
|
||||
|
||||
This also supports many of the suboptions the ``opengl`` VO has. Runs
|
||||
``mpv --vo=opengl-cb:help`` for a list.
|
||||
|
||||
This also supports the ``vo_cmdline`` command.
|
||||
@@ -1,443 +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.
|
||||
|
||||
.. note::
|
||||
These lists are incomplete.
|
||||
|
||||
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), including support
|
||||
for BT.2020 (Ultra HD) and linear XYZ (Digital Cinema) inputs.
|
||||
* Support for color managed displays, via ICC profiles.
|
||||
* High-quality image resamplers (see the ``opengl`` ``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``).
|
||||
|
||||
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_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``
|
||||
``-fixed-vo`` (removed; always the default)
|
||||
``-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=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`` ``--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.
|
||||
@@ -1,10 +1,14 @@
|
||||
mpv
|
||||
===
|
||||
|
||||
[](https://travis-ci.org/mpv-player/mpv)
|
||||
|
||||
[](https://scan.coverity.com/projects/1232)
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
**mpv** is a media player based on MPlayer and mplayer2. It supports a wide
|
||||
**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.
|
||||
|
||||
If you are wondering what's different from mplayer2 and MPlayer you can read
|
||||
@@ -46,10 +50,8 @@ Essential dependencies (incomplete list):
|
||||
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavfilter
|
||||
and either libswresample or libavresample)
|
||||
At least FFmpeg 2.1.4 or Libav 10 is required.
|
||||
- zlib
|
||||
- iconv (normally provided by the system libc)
|
||||
- libass
|
||||
- Lua (optional, required for the OSC pseudo-GUI and youtube-dl integration)
|
||||
- Lua (optional, required for the OSC pseudo-GUI)
|
||||
- libjpeg (optional, used for screenshots only)
|
||||
- Enca (optional, for subtitle charset detection)
|
||||
- vdpau and vaapi libraries for hardware decoding on Linux (optional)
|
||||
@@ -81,8 +83,6 @@ If you are running Mac OSX and using homebrew we provide [homebrew-mpv][homebrew
|
||||
to date formula that compiles mpv with sensible dependencies and defaults for
|
||||
OSX.
|
||||
|
||||
If you want to build a Windows binary, you either have to use MSYS2 and MinGW,
|
||||
or cross-compile from Linux with MinGW. See [Windows compilation][windows_compilation].
|
||||
|
||||
FFmpeg vs. Libav
|
||||
----------------
|
||||
@@ -147,4 +147,3 @@ only if discretion is required.
|
||||
[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
|
||||
+184
-174
@@ -1,204 +1,214 @@
|
||||
Release 0.8.2
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix OSD placement accidentally messed up in 0.8.1.
|
||||
|
||||
Release 0.8.1
|
||||
Release 0.7.3
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- DOCS/client-api-changes has been correctly updated for the v0.8.0 release
|
||||
series.
|
||||
- Quality and major perfomance improvements to smoothmotion.
|
||||
- Silence the "[ytdl_hook] WARNING: video doesn't have subtitles" warning.
|
||||
- Other documentation updates.
|
||||
- Several documentation updates and typo fixes.
|
||||
- Don't show "0%" position when the stream is infinite / has unknown length.
|
||||
- Fixes the config file loading order so that lower priority `mpv.conf` files
|
||||
don't override higher priority `config` files.
|
||||
- (OSX) Remove coreaudio_exclusive from the "auto" codec list.
|
||||
- Failing to create a GL3 context is now a warning instead of error, to reduce
|
||||
user confusion.
|
||||
- The subtitle decoder now gets reset when cycling subtitles. This makes the
|
||||
currently shown subtitle event disappear even if cycling back to the current
|
||||
subtitle track.
|
||||
- `--shuffle` and `--merge-files` now affects the contents of playlist files,
|
||||
instead of just the list of files given as arguments to mpv.
|
||||
- `./waf install` avoids installing a few additional data/config files if only
|
||||
libmpv was built.
|
||||
- Improved channel mapping when the file's channel map doesn't match the AO's
|
||||
available channel maps.
|
||||
- (OSX) VDA now gracefully refuses to run on non-OpenGL3-capable systems instead
|
||||
of trying and failing to build its shaders.
|
||||
- Add workaround for vf_vapoursynth filters that expect an FPS.
|
||||
- The default value for `--screenshot-template` now shows up in
|
||||
`--list-options`.
|
||||
- `ao_pulse`'s `latency-hacks` suboption is now off by default, as it causes
|
||||
issues with newer pulseaudio releases. If A/V Sync issues happen, either
|
||||
add the `latency-hacks=on` pulse suboption in mpv.conf, or update the
|
||||
pulseaudio daemon (bug #1430).
|
||||
- (Linux) `ao_alsa` now deals better with audio device disconnection.
|
||||
- Client API: timestamp properties that have no value return "no" instead of
|
||||
magic number.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Attempt to fix OpenGL shader compilation on Intel windows drivers. (bug
|
||||
#1536)
|
||||
- Attempt to improve the OpenGL shader's compatibility with GLES2.
|
||||
- (Windows) Fix noise when seeking while using wasapi:exclusive. (bug #1529)
|
||||
- Fix the waf-based build system when used with newer versions of waf with
|
||||
python3.
|
||||
- Documentation fixes. (includes bug #1608)
|
||||
- (Windows, OSX) Many `ao_wasapi` and `ao_coreaudio` fixes.
|
||||
- (OSX) Make the window title update correctly on OS X Yosemite.
|
||||
- Fixes for handling mono audio on various AOs.
|
||||
- (Linux) Fixes resuming from suspend on ao_alsa.
|
||||
- Fixes for playlist file parsing.
|
||||
- Overly long options in the --list-options output now break the column layout
|
||||
instead of getting truncated; fixes shell completion scripts.
|
||||
- Fix rendering resolution of certain DVB subtitles (bug #1425).
|
||||
- Fix EDL or --merge-files breaking timestamps with .avi files.
|
||||
- Workaround for libavcodec bug with the VP9 codec parser (bug #1448),
|
||||
fixes possible crash.
|
||||
- Improve robustness of the matroska parser with broken files (bugs #1457,
|
||||
#1461).
|
||||
- Improve 10bit video compatibility with older GPUs (specially Intel) (bug
|
||||
#1383).
|
||||
- Fixes flashing the VO window when playing a list of files that includes
|
||||
non-media files (bug #1459).
|
||||
- Workaround for window embedding in OpenBox (bug #1235)
|
||||
- Fixes for several crashes and lockups (bugs #838, #1389, #1408, #1463, #1473,
|
||||
#1474).
|
||||
- Fixes for the zsh completion script (bugs #997)
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- mpv now tries to load '.vtt' subtitles.
|
||||
- mpv now prints the contents of its config.h when running in verbose mode, to
|
||||
aid with debugging.
|
||||
- The `include=` option now accepts `~` to refer to the HOME dir (bug #1406).
|
||||
- `af_volume` now prints ReplayGain values in verbose mode.
|
||||
- m3u playlists that don't have the `#EXTM3U` header are now accepted if they
|
||||
"look like" ASCII or UTF-8 text and have the .m3u extension.
|
||||
- Chapter marks in the seek bar now update when switching files.
|
||||
- Supports embedded cover art in MKV files (bug #1374).
|
||||
- (Windows) Video window can now be resized even with --no-border.
|
||||
- (Windows) Client API: the "run" command now works on Windows too.
|
||||
- (Linux) vo_wayland now supports key modifiers (Meta, Alt, Control, Shift)
|
||||
- Client API: "display-names" property is now observable.
|
||||
|
||||
This listing is not complete. A complete changelog can be seen by running
|
||||
`git log v0.8.0..v0.8.1` in the git repository.
|
||||
`git log v0.7.2..v0.7.3` in the git repository.
|
||||
|
||||
Release 0.8.0
|
||||
Release 0.7.2
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
Changes that may break users' config files have been annotated with a `(!)`.
|
||||
|
||||
- `(!)` vo_opengl_old has been removed. OpenGL rendering now requires hardware
|
||||
that can do at least OpenGL 2.1, the oldest version supported by vo_opengl.
|
||||
- `(!)` vf_pp has been removed. A version of it can still be accessed through
|
||||
lavfilter (e.g. --vf=lavfi=[pp...]), but it receives no QP information.
|
||||
Also, vf_dlopen no longer passes QP information to its loaded plugin either
|
||||
(it's always 0).
|
||||
- `(!)` vf_softpulldown, vf_swapuv, vf_phase, vf_divtc and vf_ilpack have all
|
||||
been removed. Ports or alternative versions of these filters are available
|
||||
through libavfilter (vf_lavfi).
|
||||
- vf_pullup and vf_noise now are simply wrappers to their libavfilter
|
||||
equivalents. Both are only currently available on FFmpeg (not Libav).
|
||||
- `(!)` ao_portaudio has been removed. There is good support for the native
|
||||
audio drivers of all major desktop platforms, as well as ao_sdl and
|
||||
ao_openal as fallbacks.
|
||||
- `(!)` vo_opengl's `lscale` suboption has been renamed to `scale`; `lradius`
|
||||
is now `scale-radius`, `lparam1` and `lparam2` are now respectively
|
||||
`scale-param1` and `scale-param2`; `lscale-down` is now `scale-down`.
|
||||
The `cscale` suboption remains as is.
|
||||
- `(!)` Several of the `vo_opengl` radius-preset aliases supported by `scale`
|
||||
have been removed; use `scale-radius` to set if needed. For example, use
|
||||
`--vo=opengl:scale=lanczos:scale-radius=2` instead of `scale=lanczos2`.
|
||||
The default radius is recommended for most filters.
|
||||
- `(!)` vo_opengl no longer supports the `stereo` suboption. The anaglyph
|
||||
effect can be reproduced with the stereo3d filter. The quadbuffer support,
|
||||
which requires expensive specialized hardware to begin with, is removed.
|
||||
- `(!)` The `approx-gamma` suboption to vo_opengl has been removed. The
|
||||
BT.1886 specification says that it's actually how it's supposed to be done
|
||||
so it is now the default when `srgb` or `icc-profile` are enabled. This does
|
||||
not include BT.1886's gamma drop.
|
||||
- `(!)` The `no-scale-sep` and `indirect` suboptions to vo_opengl have been
|
||||
removed. These are now autodetected and enabled whenever they would have
|
||||
benefit.
|
||||
- `(!)` The `--lua` and `--lua-opts` parameters / options are now called
|
||||
`--script` and `--script-opts`, respectively. The `lua` subdir of the mpv
|
||||
config dir is also now expected to be called `scripts` instead.
|
||||
- `(!)` The `--fixed-vo` option has been removed. It has been the default for
|
||||
a long time anyway, and disabling fixed-vo is not useful.
|
||||
- vo_opengl_hq has been updated to take into account new features.
|
||||
`fancy-downscaling` and `sigmoid-upscaling` are enabled,
|
||||
"mitchell" is now the default for `scale-down`.
|
||||
- The `sub-visibility` OSD message is now clearer about whether subtitles
|
||||
are hidden or just not available / selected.
|
||||
- The device IDs given to `--audio-device` for use with ao_coreaudio now use
|
||||
UIDs, so they don't change when devices are added/removed or after reboots.
|
||||
- `--msg-level` now also accepts ',' as separator.
|
||||
- (Client API) The client API now refuses to initialize if the LC_NUMERIC
|
||||
locale is not "C".
|
||||
- (Client API) The native type of the `msg-level` parameter is now a key-value
|
||||
list. Setting or reading it as a string still works.
|
||||
- (Slave API) The `get_property` command is now deprecated.
|
||||
- Documentation updates.
|
||||
- PDF documentation is now disabled by default due to rst2pdf being fickle,
|
||||
causing weird build errors.
|
||||
- Print desync messages with negative A/V sync as well. While rare, it could
|
||||
happen with some uses of `--autosync`.
|
||||
- Give precedence to the DVD menu navigation keyboard bindings so that user
|
||||
defined LEFT/RIGHT/... bindings don't break DVD menu navigation.
|
||||
- Try to fallback to the "default" device if the selected device is busy in the
|
||||
alsa AO.
|
||||
- Don't create Dock icon for audio only files on OS X.
|
||||
- Save screenshots to desktop when using the app bundle on OS X.
|
||||
- Restore ab-loop settings with playback resume.
|
||||
- Bump required youtube-dl version to 2014.11.26 and enable the ytdl_hook Lua
|
||||
script by default (now playing videos from YouTube and the like will work
|
||||
out of the box without any configuration change needed).
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- (Windows) Avoid resizing the video window when player is minimized, might
|
||||
address bug #1547.
|
||||
- (NetBSD) Fix build with v4l2.
|
||||
- (Linux) Attempt to address conflicts with the pulseaudio mixer. (bug #1578)
|
||||
- Multiple cdda:// fixes. (bugs #1555, #1560)
|
||||
- VP9 timestamps no longer cause "missing PTS" warnings with new enough FFmpeg
|
||||
builds.
|
||||
- Fix a crash when using H.264 hardware decoding on new enough libavcodecs.
|
||||
(bug #1587)
|
||||
- Don't signal an error if --stream-dump is used.
|
||||
- Fix removing key bindings from Lua scripts.
|
||||
- Reject channel descriptions with too many channels in the coreaudio AO.
|
||||
- Don't async redraw when waiting for VO redraw on OS X (this fixes the very
|
||||
annoying glitch where the black bars disappear for a single frame when going
|
||||
fullscreen).
|
||||
- Fix mono playback with the also AO.
|
||||
- Don't crash if framebuffers are not available in the opengl VO.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- vo_opengl now supports frame blending to eliminate stuttering when the video
|
||||
framerate does not nicely match the display framerate through the
|
||||
`smoothmotion` suboption. This is not meant to artificially increase the
|
||||
video's FPS, so there is no "soap opera effect" or difficulties with some
|
||||
video types (e.g. anime).
|
||||
- vo_opengl now supports sigmoidal upscaling (e.g. for fullscreen), which
|
||||
reduces ringing induced by upscaling, enabled through the
|
||||
`sigmoid-upscaling` suboption.
|
||||
- vo_opengl now supports ewa_lanczos (Jinc) scaling, which provides higher
|
||||
quality with less aliasing. It supports an experimental `scale-antiringing`
|
||||
parameter, which tries to further reduce video ringing.
|
||||
- vo_opengl now has a `linear-scaling` suboption, that makes the scalers work
|
||||
in linear light. Implied by the `srgb`, `icc-profile` or the new
|
||||
`sigmoid-upscaling` suboption.
|
||||
- vo_opengl has improved downscaling for higher downscale ratios when
|
||||
`fancy-downscaling` is enabled.
|
||||
- Add `--keep-open=always` to make `--keep-open` apply to all files instead of
|
||||
only the last.
|
||||
- mpv now filters the tags that are printed on the console to try to hide
|
||||
useless metadata. The filter works as a whitelist, and can be configured
|
||||
with the `--display-tags` option.
|
||||
- Add a `--sub-scale-by-window` option that, when set to 'no', prevents
|
||||
subtitles from changing their pixel size when the window changes sizes.
|
||||
- vo_opengl now technically has GLES 2 and 3 support (but not GLES 1). GLES 3
|
||||
support is only tested on Mesa's software emulation. GLES 2 has been tested
|
||||
on nvidia drivers. Both GLES modes are feature deficient and inefficient due
|
||||
to GLES limitations, so they should not be preferred over the standard
|
||||
OpenGL mode.
|
||||
- (X11) vo_opengl now supports the `icc-profile-auto` option on X11 hosts.
|
||||
- The 'A' key now by default cycles through a list of preset aspect ratios.
|
||||
Meant to be used to work around broken files.
|
||||
- There is now a "force" mode for `--loop`. Works like "inf", but tries to
|
||||
open files/streams even if there was an error on the previous attempt.
|
||||
- There is now a `--log-file` option to write mpv's log messages to a specifed
|
||||
file.
|
||||
- There is now a `--audio-file-auto` option to automatically load an external
|
||||
audio file with certain constraints. Will only load external audio if the
|
||||
playing file has a video stream. Set to "exact" by default. (bug #967)
|
||||
- There is now a `--network-timeout` option to specify a timeout in seconds
|
||||
for network access. If 0 (default), uses the libavformat default. If a
|
||||
protocol that doesn't support timeouts is used, this option is ignored.
|
||||
- (X11) The XF86 special keys are now all mappable in `input.conf`. All keys
|
||||
documented in `XF86keysym.h` are available, but only as their numeric codes.
|
||||
- (Linux) The DVB implementation now supports DVB-S2 through S2API.
|
||||
- (Linux) The VDR format for `channels.conf` is now supported and preferred.
|
||||
See http://linuxtv.org/vdrwiki/index.php/Syntax_of_channels.conf for the
|
||||
syntax. Tuning to DVB-S2 channels requires the VDR-format `channels.conf`.
|
||||
- (Linux) There is now a `--dvbin-full-transponder` option for handling
|
||||
special broadcast cases where PIDs switch, or just to work around incomplete
|
||||
PID data.
|
||||
- (Client API) There is now an opengl_cb VO, which receives the OpenGL context
|
||||
from the libmpv client. This allows a client to render libmpv video directly
|
||||
to a provided OpenGL context without having to use --wid embedding.
|
||||
- (Client API) The aforementioned --wid parameter can now be set at any time,
|
||||
but has no effect if a file is already loaded.
|
||||
- (Client API) The list of DVD titles can now be queried.
|
||||
- (Client API) There is now a `filtered-metadata` property, containing only
|
||||
the tags allowed by `--display-tags`.
|
||||
- (Client API) There is now support for XEmbed `--wid` targets, such as a
|
||||
`GtkSocket`'s `gtk_socket_get_id()`.
|
||||
- (Client API) There is now a `file-format` property with a symbolic name
|
||||
for the file format. In some cases this might be a comma separated list
|
||||
of various different extensions due to libavformat idiosyncrasies.
|
||||
- (Client API) There is now a `mouse` command for generating mouse events
|
||||
over the video window.
|
||||
- (Client API) There is now a `partially-seekable` property that indicates
|
||||
whether a file is only considered `seekable` because of the stream cache,
|
||||
but would not be seekable otherwise (e.g. realtime stream, or HTTP with
|
||||
no resume support). Small relative seeks may be fine, but larger seeks
|
||||
will likely fail.
|
||||
- (Client API) There is now an MPV_EVENT_QUEUE_OVERFLOW event that is posted
|
||||
whenever events have to be dropped because the queue is full. No further
|
||||
events are posted until the MPV_EVENT_QUEUE_OVERFLOW is consumed to avoid
|
||||
duplicated posting.
|
||||
- (Client API) There is now a helper `mpv_wait_async_requests()` function
|
||||
that blocks until all known async requests have completed. (bug #1542)
|
||||
- (Client API) There is now a `detected-hwdec` property that returns the
|
||||
detected hardware decoder when one is successfully opened. This probably
|
||||
only returns a valid value after playback has started.
|
||||
- (Client API) There are now `audio_add`, `audio_remove` and `audio_reload`
|
||||
counterparts to the equivalent `sub_` commands for handling external audio
|
||||
files.
|
||||
- Try to handle multi-arc videos in the ytdl_hook Lua script.
|
||||
|
||||
This listing is not complete. A complete changelog can be seen by running
|
||||
`git log v0.7.0..v0.8.0` in the git repository.
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log 47ec404..c7d6b21`` in
|
||||
the git repository.
|
||||
|
||||
Release 0.7.1
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Don't show the volume neutral marker on the OSD if softvol is disabled.
|
||||
- Don't select a subtitle track when executing the sub_add input command in
|
||||
"auto" mode.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix busy loop when seeking while paused (this fixes a problem with pulseaudio
|
||||
that caused mpv and the pulseaudio daemon to use 100% CPU).
|
||||
- Fix Lua function utils.subprocess() in Windows versions older than Vista.
|
||||
- Avoid creating a window bigger than the screen on Windows.
|
||||
- Don't ignore the last line in m3u playlists.
|
||||
- Don't crash if a codec could not be opened.
|
||||
- Dynamically allocate audio channel map entries (this should fix a crash in
|
||||
the alsa and coreaudio AOs with audio devices that support more than 20
|
||||
channel maps).
|
||||
- Ignore the "srgb" option in the opengl VO if hardware decoding is enabled.
|
||||
- Linearize non-RGB sRGB files correctly (eg. JPEG).
|
||||
- Fix opening reference URLs (.file/id=) on OS X.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log 8d8b36d..6583ad6`` in
|
||||
the git repository.
|
||||
|
||||
Release 0.7.0
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- 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).
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- 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).
|
||||
|
||||
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.
|
||||
@@ -19,7 +19,6 @@ def is_user_lib(objfile, libname):
|
||||
not "libSystem." in libname and \
|
||||
not "libc." in libname and \
|
||||
not "libgcc." in libname and \
|
||||
not os.path.basename(libname) == 'Python' and \
|
||||
not os.path.basename(objfile) in libname
|
||||
|
||||
def otool(objfile):
|
||||
|
||||
+3
-3
@@ -4,9 +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.
|
||||
Where appropriate, they may also be placed in ~/.config/mpv/lua from where
|
||||
they will be automatically loaded when mpv starts.
|
||||
@@ -21,7 +21,7 @@
|
||||
-- The default delay between insertion of the cropdetect and
|
||||
-- crop filters may be overridden by adding
|
||||
--
|
||||
-- --script-opts=autocrop.detect_seconds=<number of seconds>
|
||||
-- --lua-opts=autocrop.detect_seconds=<number of seconds>
|
||||
--
|
||||
-- to mpv's arguments. This may be desirable to allow cropdetect more
|
||||
-- time to collect data.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
--
|
||||
-- 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.
|
||||
|
||||
@@ -1,22 +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.
|
||||
|
||||
-- Note: currently works with X11 only.
|
||||
|
||||
local did_minimize = false
|
||||
|
||||
mp.observe_property("window-minimized", "bool", function(name, 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)
|
||||
+1
-3
@@ -3,7 +3,6 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import fileinput
|
||||
from optparse import OptionParser
|
||||
|
||||
def sh(command):
|
||||
@@ -36,8 +35,7 @@ def copy_binary(binary_name):
|
||||
shutil.copy(binary_name, target_binary(binary_name))
|
||||
|
||||
def apply_plist_template(plist_file, version):
|
||||
for line in fileinput.input(plist_file, inplace=1):
|
||||
print (line.rstrip().replace('${VERSION}', version))
|
||||
sh("sed -i -e 's/${VERSION}/%s/g' %s" % (version, plist_file))
|
||||
|
||||
def main():
|
||||
version = sh("./version.sh --print").strip()
|
||||
|
||||
@@ -88,7 +88,6 @@
|
||||
<string>VOB</string>
|
||||
<string>WEBM</string>
|
||||
<string>WMV</string>
|
||||
<string>MK3D</string>
|
||||
<string>asf</string>
|
||||
<string>avi</string>
|
||||
<string>cpk</string>
|
||||
@@ -123,7 +122,6 @@
|
||||
<string>vob</string>
|
||||
<string>webm</string>
|
||||
<string>wmv</string>
|
||||
<string>mk3d</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
@@ -210,7 +208,6 @@
|
||||
<string>mms</string>
|
||||
<string>mmst</string>
|
||||
<string>http</string>
|
||||
<string>https</string>
|
||||
<string>httpproxy</string>
|
||||
<string>rtp</string>
|
||||
<string>rtsp</string>
|
||||
@@ -516,47 +513,6 @@
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mkv</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Matroska stereoscopic/3D video</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.mk3d</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://www.matroska.org</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>mk3d</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.movie</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>WebM Video</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>document.icns</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.mpv.webm</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>http://www.webmproject.org</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>webm</string>
|
||||
</array>
|
||||
</dict>
|
||||
|
||||
-2
@@ -1,3 +1 @@
|
||||
screenshot-template=~/Desktop/shot%n
|
||||
quiet
|
||||
idle=once
|
||||
+3
-5
@@ -62,14 +62,12 @@ def get_event(event, evtype):
|
||||
G.events[event] = e
|
||||
return G.events[event]
|
||||
|
||||
SCALE = 1e6 # microseconds to seconds
|
||||
|
||||
for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
ts, event = line.split(" ", 1)
|
||||
ts = int(ts) / SCALE
|
||||
ts = int(ts) / 1000 # milliseconds
|
||||
if G.start is None:
|
||||
G.start = ts
|
||||
ts = ts - G.start
|
||||
@@ -88,12 +86,12 @@ for line in [line.split("#")[0].strip() for line in open(filename, "r")]:
|
||||
e.vals.append((ts, val))
|
||||
elif event.startswith("event-timed "):
|
||||
_, val, name = event.split(" ", 2)
|
||||
val = int(val) / SCALE - G.start
|
||||
val = int(val) / 1000 - G.start
|
||||
e = get_event(name, "event-signal")
|
||||
e.vals.append((val, 1))
|
||||
elif event.startswith("value-timed "):
|
||||
_, tsval, val, name = event.split(" ", 3)
|
||||
tsval = int(tsval) / SCALE - G.start
|
||||
tsval = int(tsval) / 1000 - G.start
|
||||
val = float(val)
|
||||
e = get_event(name, "value")
|
||||
e.vals.append((tsval, val))
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# 02110-1301 USA
|
||||
#
|
||||
|
||||
FILTERS = telecine tile rectangle framestep ildetect
|
||||
FILTERS = showqscale telecine tile rectangle framestep ildetect
|
||||
COMMON = filterutils.o
|
||||
|
||||
OBJECTS = $(patsubst %,%.o,$(FILTERS)) $(COMMON)
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Rudolf Polzer <divVerent@xonotic.org>
|
||||
*
|
||||
* This file is part of mpv's vf_dlopen examples.
|
||||
*
|
||||
* mpv's vf_dlopen examples are free software; you can redistribute them and/or
|
||||
* modify them 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's vf_dlopen examples are distributed in the hope that they 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's vf_dlopen examples; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vf_dlopen.h"
|
||||
|
||||
/*
|
||||
* qscale visualizer
|
||||
*
|
||||
* usage: --vf=dlopen=/path/to/showqscale.so
|
||||
*
|
||||
* uses reddish colors for high QPs, and greenish colors for low QPs
|
||||
*/
|
||||
|
||||
#define PLANE_Y 0
|
||||
#define PLANE_U 1
|
||||
#define PLANE_V 2
|
||||
|
||||
static int qs_put_image(struct vf_dlopen_context *ctx)
|
||||
{
|
||||
unsigned int x, y, p;
|
||||
|
||||
assert(ctx->inpic.planes == ctx->outpic[0].planes);
|
||||
|
||||
for (p = 0; p < ctx->outpic[0].planes; ++p) {
|
||||
assert(ctx->inpic.planewidth[p] == ctx->outpic[0].planewidth[p]);
|
||||
assert(ctx->inpic.planeheight[p] == ctx->outpic[0].planeheight[p]);
|
||||
if ((p == PLANE_U || p == PLANE_V) && ctx->inpic_qscale)
|
||||
continue;
|
||||
#if 0
|
||||
// copy as is
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
memcpy(
|
||||
&ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y],
|
||||
&inpic[ctx->outpic[0].planeofs[p] + ctx->inpic.planestride[p] * y],
|
||||
ctx->outpic[0].planewidth[p]
|
||||
);
|
||||
#else
|
||||
// reduce contrast
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
for (x = 0; x < ctx->outpic[0].planewidth[p]; ++x)
|
||||
ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y + x] =
|
||||
0x20 + ((ctx->inpic.plane[p][ctx->inpic.planestride[p] * y + x] * 3) >> 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ctx->inpic_qscale) {
|
||||
int qmin = 255;
|
||||
int qmax = -255;
|
||||
|
||||
// clear U plane
|
||||
p = PLANE_U;
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
memset(
|
||||
&ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y],
|
||||
0x80,
|
||||
ctx->outpic[0].planewidth[p]
|
||||
);
|
||||
|
||||
// replace V by the qp (0 = green, 12 = red)
|
||||
p = PLANE_V;
|
||||
for (y = 0; y < ctx->outpic[0].planeheight[p]; ++y)
|
||||
for (x = 0; x < ctx->outpic[0].planewidth[p]; ++x) {
|
||||
int q = ctx->inpic_qscale[
|
||||
(x >> (ctx->inpic_qscaleshift - ctx->inpic.planexshift[p])) +
|
||||
(y >> (ctx->inpic_qscaleshift - ctx->inpic.planeyshift[p])) * ctx->inpic_qscalestride];
|
||||
if (q < qmin)
|
||||
qmin = q;
|
||||
if (q > qmax)
|
||||
qmax = q;
|
||||
int v = 128 + 21 * (q - 6); // range: 0 = green, 12 = red
|
||||
if (v < 0)
|
||||
v = 0;
|
||||
if (v > 255)
|
||||
v = 255;
|
||||
ctx->outpic[0].plane[p][ctx->outpic[0].planestride[p] * y + x] = v;
|
||||
}
|
||||
|
||||
// printf("qscale range: %d .. %d\n", qmin, qmax);
|
||||
}
|
||||
|
||||
ctx->outpic[0].pts = ctx->inpic.pts;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vf_dlopen_getcontext(struct vf_dlopen_context *ctx, int argc, const char **argv)
|
||||
{
|
||||
VF_DLOPEN_CHECK_VERSION(ctx);
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
static struct vf_dlopen_formatpair map[] = {
|
||||
{ "yuv420p", "yuv420p" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
ctx->format_mapping = map;
|
||||
ctx->put_image = qs_put_image;
|
||||
return 1;
|
||||
}
|
||||
+11
-60
@@ -227,14 +227,6 @@ void mp_audio_copy(struct mp_audio *dst, int dst_offset,
|
||||
}
|
||||
}
|
||||
|
||||
// Copy fields that describe characteristics of the audio frame, but which are
|
||||
// not part of the core format (format/channels/rate), and not part of the
|
||||
// data (samples).
|
||||
void mp_audio_copy_attributes(struct mp_audio *dst, struct mp_audio *src)
|
||||
{
|
||||
// nothing yet
|
||||
}
|
||||
|
||||
// Set data to the audio after the given number of samples (i.e. slice it).
|
||||
void mp_audio_skip_samples(struct mp_audio *data, int samples)
|
||||
{
|
||||
@@ -246,40 +238,28 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
|
||||
data->samples -= samples;
|
||||
}
|
||||
|
||||
// Return false if the frame data is shared, true otherwise.
|
||||
// Will return true for non-refcounted frames.
|
||||
bool mp_audio_is_writeable(struct mp_audio *data)
|
||||
// Make sure the frame owns the audio data, and if not, copy the data.
|
||||
// Return negative value on failure (which means it can't be made writeable).
|
||||
// Non-refcounted frames are always considered writeable.
|
||||
int mp_audio_make_writeable(struct mp_audio *data)
|
||||
{
|
||||
bool ok = true;
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
if (data->allocated[n])
|
||||
ok &= av_buffer_is_writable(data->allocated[n]);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void mp_audio_steal_data(struct mp_audio *dst, struct mp_audio *src)
|
||||
{
|
||||
talloc_set_destructor(dst, mp_audio_destructor);
|
||||
mp_audio_destructor(dst);
|
||||
*dst = *src;
|
||||
talloc_set_destructor(src, NULL);
|
||||
talloc_free(src);
|
||||
}
|
||||
|
||||
// Make sure the frame owns the audio data, and if not, copy the data.
|
||||
// Return negative value on failure (which means it can't be made writeable).
|
||||
// Non-refcounted frames are always considered writeable.
|
||||
int mp_audio_make_writeable(struct mp_audio *data)
|
||||
{
|
||||
if (!mp_audio_is_writeable(data)) {
|
||||
if (!ok) {
|
||||
struct mp_audio *new = talloc(NULL, struct mp_audio);
|
||||
*new = *data;
|
||||
mp_audio_set_null_data(new); // use format only
|
||||
mp_audio_realloc(new, data->samples);
|
||||
new->samples = data->samples;
|
||||
mp_audio_copy(new, 0, data, 0, data->samples);
|
||||
mp_audio_steal_data(data, new);
|
||||
// "Transfer" the reference.
|
||||
mp_audio_destructor(data);
|
||||
*data = *new;
|
||||
talloc_set_destructor(new, NULL);
|
||||
talloc_free(new);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -370,8 +350,7 @@ struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
|
||||
if (alloc >= INT_MAX)
|
||||
return NULL;
|
||||
av_buffer_pool_uninit(&pool->avpool);
|
||||
pool->element_size = alloc;
|
||||
pool->avpool = av_buffer_pool_init(pool->element_size, NULL);
|
||||
pool->avpool = av_buffer_pool_init(alloc, NULL);
|
||||
if (!pool->avpool)
|
||||
return NULL;
|
||||
talloc_set_destructor(pool, mp_audio_pool_destructor);
|
||||
@@ -391,31 +370,3 @@ struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
// Return a copy of the given frame.
|
||||
// Returns NULL on error.
|
||||
struct mp_audio *mp_audio_pool_new_copy(struct mp_audio_pool *pool,
|
||||
struct mp_audio *frame)
|
||||
{
|
||||
struct mp_audio *new = mp_audio_pool_get(pool, frame, frame->samples);
|
||||
if (new) {
|
||||
mp_audio_copy(new, 0, frame, 0, new->samples);
|
||||
mp_audio_copy_attributes(new, frame);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
// Exactly like mp_audio_make_writeable(), but get the data from the pool.
|
||||
int mp_audio_pool_make_writeable(struct mp_audio_pool *pool,
|
||||
struct mp_audio *data)
|
||||
{
|
||||
if (mp_audio_is_writeable(data))
|
||||
return 0;
|
||||
struct mp_audio *new = mp_audio_pool_get(pool, data, data->samples);
|
||||
if (!new)
|
||||
return -1;
|
||||
mp_audio_copy(new, 0, data, 0, data->samples);
|
||||
mp_audio_copy_attributes(new, data);
|
||||
mp_audio_steal_data(data, new);
|
||||
return 0;
|
||||
}
|
||||
@@ -66,22 +66,15 @@ void mp_audio_fill_silence(struct mp_audio *mpa, int start, int length);
|
||||
|
||||
void mp_audio_copy(struct mp_audio *dst, int dst_offset,
|
||||
struct mp_audio *src, int src_offset, int length);
|
||||
void mp_audio_copy_attributes(struct mp_audio *dst, struct mp_audio *src);
|
||||
void mp_audio_skip_samples(struct mp_audio *data, int samples);
|
||||
|
||||
bool mp_audio_is_writeable(struct mp_audio *data);
|
||||
int mp_audio_make_writeable(struct mp_audio *data);
|
||||
|
||||
struct AVFrame;
|
||||
struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe);
|
||||
|
||||
struct mp_audio_pool;
|
||||
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent);
|
||||
struct mp_audio *mp_audio_pool_get(struct mp_audio_pool *pool,
|
||||
const struct mp_audio *fmt, int samples);
|
||||
struct mp_audio *mp_audio_pool_new_copy(struct mp_audio_pool *pool,
|
||||
struct mp_audio *frame);
|
||||
int mp_audio_pool_make_writeable(struct mp_audio_pool *pool,
|
||||
struct mp_audio *frame);
|
||||
|
||||
#endif
|
||||
+40
-54
@@ -153,48 +153,23 @@ void audio_uninit(struct dec_audio *d_audio)
|
||||
MP_VERBOSE(d_audio, "Uninit audio filters...\n");
|
||||
af_destroy(d_audio->afilter);
|
||||
uninit_decoder(d_audio);
|
||||
talloc_free(d_audio->waiting);
|
||||
talloc_free(d_audio);
|
||||
}
|
||||
|
||||
static int decode_new_frame(struct dec_audio *da)
|
||||
{
|
||||
while (!da->waiting) {
|
||||
int ret = da->ad_driver->decode_packet(da, &da->waiting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (da->waiting) {
|
||||
da->pts_offset += da->waiting->samples;
|
||||
da->decode_format = *da->waiting;
|
||||
mp_audio_set_null_data(&da->decode_format);
|
||||
}
|
||||
}
|
||||
return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR;
|
||||
}
|
||||
|
||||
/* Decode packets until we know the audio format. Then reinit the buffer.
|
||||
* Returns AD_OK on success, negative AD_* code otherwise.
|
||||
* Also returns AD_OK if already initialized (and does nothing).
|
||||
*/
|
||||
int initial_audio_decode(struct dec_audio *da)
|
||||
{
|
||||
return decode_new_frame(da);
|
||||
}
|
||||
|
||||
static bool copy_output(struct af_stream *afs, struct mp_audio_buffer *outbuf,
|
||||
int minsamples, bool eof)
|
||||
{
|
||||
while (mp_audio_buffer_samples(outbuf) < minsamples) {
|
||||
if (af_output_frame(afs, eof) < 0)
|
||||
return true; // error, stop doing stuff
|
||||
struct mp_audio *mpa = af_read_output_frame(afs);
|
||||
if (!mpa)
|
||||
return false; // out of data
|
||||
mp_audio_buffer_append(outbuf, mpa);
|
||||
talloc_free(mpa);
|
||||
while (!da->waiting) {
|
||||
int ret = da->ad_driver->decode_packet(da, &da->waiting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return true;
|
||||
talloc_steal(da, da->waiting);
|
||||
da->decode_format = *da->waiting;
|
||||
return mp_audio_config_valid(da->waiting) ? AD_OK : AD_ERR;
|
||||
}
|
||||
|
||||
/* Try to get at least minsamples decoded+filtered samples in outbuf
|
||||
@@ -211,30 +186,41 @@ int audio_decode(struct dec_audio *da, struct mp_audio_buffer *outbuf,
|
||||
|
||||
MP_STATS(da, "start audio");
|
||||
|
||||
int res;
|
||||
while (1) {
|
||||
int res = 0;
|
||||
while (res >= 0 && minsamples >= 0) {
|
||||
int buffered = mp_audio_buffer_samples(outbuf);
|
||||
if (minsamples < buffered)
|
||||
break;
|
||||
|
||||
res = 0;
|
||||
|
||||
if (copy_output(afs, outbuf, minsamples, false))
|
||||
break;
|
||||
|
||||
res = decode_new_frame(da);
|
||||
if (res < 0) {
|
||||
// drain filters first (especially for true EOF case)
|
||||
copy_output(afs, outbuf, minsamples, true);
|
||||
break;
|
||||
}
|
||||
|
||||
// On format change, make sure to drain the filter chain.
|
||||
if (!mp_audio_config_equals(&afs->input, da->waiting)) {
|
||||
copy_output(afs, outbuf, minsamples, true);
|
||||
res = AD_NEW_FMT;
|
||||
break;
|
||||
}
|
||||
|
||||
struct mp_audio *mpa = da->waiting;
|
||||
da->waiting = NULL;
|
||||
if (af_filter_frame(afs, mpa) < 0)
|
||||
if (!mpa)
|
||||
res = da->ad_driver->decode_packet(da, &mpa);
|
||||
|
||||
if (res != AD_EOF) {
|
||||
if (res < 0)
|
||||
break;
|
||||
if (!mpa )
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mpa) {
|
||||
da->pts_offset += mpa->samples;
|
||||
da->decode_format = *mpa;
|
||||
mp_audio_set_null_data(&da->decode_format);
|
||||
// On format change, make sure to drain the filter chain.
|
||||
if (!mp_audio_config_equals(&afs->input, mpa)) {
|
||||
res = AD_NEW_FMT;
|
||||
da->waiting = talloc_steal(da, mpa);
|
||||
mpa = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (mpa)
|
||||
da->waiting = NULL;
|
||||
|
||||
if (af_filter(afs, mpa, outbuf) < 0)
|
||||
return AD_ERR;
|
||||
}
|
||||
|
||||
@@ -247,7 +233,7 @@ void audio_reset_decoding(struct dec_audio *d_audio)
|
||||
{
|
||||
if (d_audio->ad_driver)
|
||||
d_audio->ad_driver->control(d_audio, ADCTRL_RESET, NULL);
|
||||
af_seek_reset(d_audio->afilter);
|
||||
af_control_all(d_audio->afilter, AF_CONTROL_RESET, NULL);
|
||||
d_audio->pts = MP_NOPTS_VALUE;
|
||||
d_audio->pts_offset = 0;
|
||||
if (d_audio->waiting) {
|
||||
|
||||
+68
-137
@@ -70,7 +70,9 @@ static const struct af_info *const filter_list[] = {
|
||||
&af_info_pan,
|
||||
&af_info_surround,
|
||||
&af_info_sub,
|
||||
#if HAVE_SYS_MMAN_H
|
||||
&af_info_export,
|
||||
#endif
|
||||
&af_info_drc,
|
||||
&af_info_extrastereo,
|
||||
&af_info_lavcac3enc,
|
||||
@@ -122,19 +124,6 @@ const struct m_obj_list af_obj_list = {
|
||||
},
|
||||
};
|
||||
|
||||
static void af_forget_frames(struct af_instance *af)
|
||||
{
|
||||
for (int n = 0; n < af->num_out_queued; n++)
|
||||
talloc_free(af->out_queued[n]);
|
||||
af->num_out_queued = 0;
|
||||
}
|
||||
|
||||
static void af_chain_forget_frames(struct af_stream *s)
|
||||
{
|
||||
for (struct af_instance *cur = s->first; cur; cur = cur->next)
|
||||
af_forget_frames(cur);
|
||||
}
|
||||
|
||||
static void af_copy_unset_fields(struct mp_audio *dst, struct mp_audio *src)
|
||||
{
|
||||
if (dst->format == AF_FORMAT_UNKNOWN)
|
||||
@@ -175,9 +164,8 @@ static int output_control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int dummy_filter(struct af_instance *af, struct mp_audio *frame)
|
||||
static int dummy_filter(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
af_add_output_frame(af, frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -209,10 +197,10 @@ static struct af_instance *af_create(struct af_stream *s, char *name,
|
||||
struct af_instance *af = talloc_zero(NULL, struct af_instance);
|
||||
*af = (struct af_instance) {
|
||||
.info = info,
|
||||
.mul = 1,
|
||||
.data = talloc_zero(af, struct mp_audio),
|
||||
.log = mp_log_new(af, s->log, name),
|
||||
.replaygain_data = s->replaygain_data,
|
||||
.out_pool = mp_audio_pool_create(af),
|
||||
};
|
||||
struct m_config *config = m_config_from_obj_desc(af, s->log, &desc);
|
||||
if (m_config_apply_defaults(config, name, s->opts->af_defs) < 0)
|
||||
@@ -297,7 +285,6 @@ static void af_remove(struct af_stream *s, struct af_instance *af)
|
||||
|
||||
if (af->uninit)
|
||||
af->uninit(af);
|
||||
af_forget_frames(af);
|
||||
talloc_free(af);
|
||||
}
|
||||
|
||||
@@ -512,8 +499,6 @@ static int af_fix_rate(struct af_stream *s, struct af_instance **p_af,
|
||||
static int af_reinit(struct af_stream *s)
|
||||
{
|
||||
remove_auto_inserted_filters(s);
|
||||
af_chain_forget_frames(s);
|
||||
s->first->fmt_in = s->first->fmt_out = s->input;
|
||||
// Start with the second filter, as the first filter is the special input
|
||||
// filter which needs no initialization.
|
||||
struct af_instance *af = s->first->next;
|
||||
@@ -532,7 +517,6 @@ static int af_reinit(struct af_stream *s)
|
||||
if (!mp_audio_config_valid(&in))
|
||||
goto error;
|
||||
|
||||
af->fmt_in = in;
|
||||
int rv = af->control(af, AF_CONTROL_REINIT, &in);
|
||||
if (rv == AF_OK && !mp_audio_config_equals(&in, af->prev->data))
|
||||
rv = AF_FALSE; // conversion filter needed
|
||||
@@ -540,7 +524,6 @@ static int af_reinit(struct af_stream *s)
|
||||
case AF_OK:
|
||||
if (!mp_audio_config_valid(af->data))
|
||||
goto error;
|
||||
af->fmt_out = *af->data;
|
||||
af = af->next;
|
||||
break;
|
||||
case AF_FALSE: { // Configuration filter is needed
|
||||
@@ -601,40 +584,36 @@ void af_uninit(struct af_stream *s)
|
||||
{
|
||||
while (s->first->next && s->first->next != s->last)
|
||||
af_remove(s, s->first->next);
|
||||
af_chain_forget_frames(s);
|
||||
s->initialized = 0;
|
||||
}
|
||||
|
||||
struct af_stream *af_new(struct mpv_global *global)
|
||||
{
|
||||
struct af_stream *s = talloc_zero(NULL, struct af_stream);
|
||||
s->log = mp_log_new(s, global->log, "!af");
|
||||
|
||||
static const struct af_info in = { .name = "in" };
|
||||
s->first = talloc(s, struct af_instance);
|
||||
*s->first = (struct af_instance) {
|
||||
.info = &in,
|
||||
.log = s->log,
|
||||
.control = input_control,
|
||||
.filter_frame = dummy_filter,
|
||||
.filter = dummy_filter,
|
||||
.priv = s,
|
||||
.data = &s->input,
|
||||
.mul = 1.0,
|
||||
};
|
||||
|
||||
static const struct af_info out = { .name = "out" };
|
||||
s->last = talloc(s, struct af_instance);
|
||||
*s->last = (struct af_instance) {
|
||||
.info = &out,
|
||||
.log = s->log,
|
||||
.control = output_control,
|
||||
.filter_frame = dummy_filter,
|
||||
.filter = dummy_filter,
|
||||
.priv = s,
|
||||
.data = &s->filter_output,
|
||||
.mul = 1.0,
|
||||
};
|
||||
|
||||
s->first->next = s->last;
|
||||
s->last->prev = s->first;
|
||||
s->opts = global->opts;
|
||||
s->log = mp_log_new(s, global->log, "!af");
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -736,6 +715,65 @@ int af_remove_by_label(struct af_stream *s, char *label)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Feed "data" to the chain, and write results to output. "data" needs to be
|
||||
* a refcounted frame, although refcounting is not used yet.
|
||||
* data==NULL means EOF.
|
||||
*/
|
||||
int af_filter(struct af_stream *s, struct mp_audio *data,
|
||||
struct mp_audio_buffer *output)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
assert(s->initialized > 0);
|
||||
int flags = 0;
|
||||
int r = 0;
|
||||
struct mp_audio tmp;
|
||||
char dummy[MP_NUM_CHANNELS];
|
||||
if (data) {
|
||||
assert(mp_audio_config_equals(af->data, data));
|
||||
r = mp_audio_make_writeable(data);
|
||||
} else {
|
||||
data = &tmp;
|
||||
*data = *(af->data);
|
||||
mp_audio_set_null_data(data);
|
||||
flags = AF_FILTER_FLAG_EOF;
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
data->planes[n] = &dummy[n];
|
||||
}
|
||||
if (r < 0)
|
||||
goto done;
|
||||
struct mp_audio frame = *data;
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
frame.allocated[n] = NULL;
|
||||
// Iterate through all filters
|
||||
while (af) {
|
||||
r = af->filter(af, &frame, flags);
|
||||
if (r < 0)
|
||||
goto done;
|
||||
assert(mp_audio_config_equals(af->data, &frame));
|
||||
af = af->next;
|
||||
}
|
||||
mp_audio_buffer_append(output, &frame);
|
||||
|
||||
done:
|
||||
if (data != &tmp)
|
||||
talloc_free(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
// Calculate average ratio of filter output samples to input samples.
|
||||
// e.g: num_output_samples = mul * num_input_samples
|
||||
double af_calc_filter_multiplier(struct af_stream *s)
|
||||
{
|
||||
struct af_instance *af = s->first;
|
||||
double mul = 1;
|
||||
do {
|
||||
mul *= af->mul;
|
||||
af = af->next;
|
||||
} while (af);
|
||||
|
||||
return mul;
|
||||
}
|
||||
|
||||
/* Calculate the total delay [seconds of output] caused by the filters */
|
||||
double af_calc_delay(struct af_stream *s)
|
||||
{
|
||||
@@ -743,8 +781,6 @@ double af_calc_delay(struct af_stream *s)
|
||||
double delay = 0.0;
|
||||
while (af) {
|
||||
delay += af->delay;
|
||||
for (int n = 0; n < af->num_out_queued; n++)
|
||||
delay += af->out_queued[n]->samples / (double)af->data->rate;
|
||||
af = af->next;
|
||||
}
|
||||
return delay;
|
||||
@@ -771,108 +807,3 @@ void af_control_all(struct af_stream *s, int cmd, void *arg)
|
||||
for (struct af_instance *af = s->first; af; af = af->next)
|
||||
af->control(af, cmd, arg);
|
||||
}
|
||||
|
||||
// Used by filters to add a filtered frame to the output queue.
|
||||
// Ownership of frame is transferred from caller to the filter chain.
|
||||
void af_add_output_frame(struct af_instance *af, struct mp_audio *frame)
|
||||
{
|
||||
if (frame) {
|
||||
assert(mp_audio_config_equals(&af->fmt_out, frame));
|
||||
MP_TARRAY_APPEND(af, af->out_queued, af->num_out_queued, frame);
|
||||
}
|
||||
}
|
||||
|
||||
static bool af_has_output_frame(struct af_instance *af)
|
||||
{
|
||||
if (!af->num_out_queued && af->filter_out) {
|
||||
if (af->filter_out(af) < 0)
|
||||
MP_ERR(af, "Error filtering frame.\n");
|
||||
}
|
||||
return af->num_out_queued > 0;
|
||||
}
|
||||
|
||||
static struct mp_audio *af_dequeue_output_frame(struct af_instance *af)
|
||||
{
|
||||
struct mp_audio *res = NULL;
|
||||
if (af_has_output_frame(af)) {
|
||||
res = af->out_queued[0];
|
||||
MP_TARRAY_REMOVE_AT(af->out_queued, af->num_out_queued, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int af_do_filter(struct af_instance *af, struct mp_audio *frame)
|
||||
{
|
||||
if (frame)
|
||||
assert(mp_audio_config_equals(&af->fmt_in, frame));
|
||||
int r = af->filter_frame(af, frame);
|
||||
if (r < 0)
|
||||
MP_ERR(af, "Error filtering frame.\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
// Input a frame into the filter chain. Ownership of frame is transferred.
|
||||
// Return >= 0 on success, < 0 on failure (even if output frames were produced)
|
||||
int af_filter_frame(struct af_stream *s, struct mp_audio *frame)
|
||||
{
|
||||
assert(frame);
|
||||
if (s->initialized < 1) {
|
||||
talloc_free(frame);
|
||||
return -1;
|
||||
}
|
||||
return af_do_filter(s->first, frame);
|
||||
}
|
||||
|
||||
// Output the next queued frame (if any) from the full filter chain.
|
||||
// The frame can be retrieved with af_read_output_frame().
|
||||
// eof: if set, assume there's no more input i.e. af_filter_frame() will
|
||||
// not be called (until reset) - flush all internally delayed frames
|
||||
// returns: -1: error, 0: no output, 1: output available
|
||||
int af_output_frame(struct af_stream *s, bool eof)
|
||||
{
|
||||
if (s->last->num_out_queued)
|
||||
return 1;
|
||||
if (s->initialized < 1)
|
||||
return -1;
|
||||
while (1) {
|
||||
struct af_instance *last = NULL;
|
||||
for (struct af_instance * cur = s->first; cur; cur = cur->next) {
|
||||
// Flush remaining frames on EOF, but do that only if the previous
|
||||
// filters have been flushed (i.e. they have no more output).
|
||||
if (eof && !last) {
|
||||
int r = af_do_filter(cur, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (af_has_output_frame(cur))
|
||||
last = cur;
|
||||
}
|
||||
if (!last)
|
||||
return 0;
|
||||
if (!last->next)
|
||||
return 1;
|
||||
int r = af_do_filter(last->next, af_dequeue_output_frame(last));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
struct mp_audio *af_read_output_frame(struct af_stream *s)
|
||||
{
|
||||
if (!s->last->num_out_queued)
|
||||
af_output_frame(s, false);
|
||||
return af_dequeue_output_frame(s->last);
|
||||
}
|
||||
|
||||
// Make sure the caller can change data referenced by the frame.
|
||||
// Return negative error code on failure (i.e. you can't write).
|
||||
int af_make_writeable(struct af_instance *af, struct mp_audio *frame)
|
||||
{
|
||||
return mp_audio_pool_make_writeable(af->out_pool, frame);
|
||||
}
|
||||
|
||||
void af_seek_reset(struct af_stream *s)
|
||||
{
|
||||
af_control_all(s, AF_CONTROL_RESET, NULL);
|
||||
af_chain_forget_frames(s);
|
||||
}
|
||||
+10
-21
@@ -62,29 +62,21 @@ struct af_instance {
|
||||
struct replaygain_data *replaygain_data;
|
||||
int (*control)(struct af_instance *af, int cmd, void *arg);
|
||||
void (*uninit)(struct af_instance *af);
|
||||
/* Feed a frame. The frame is NULL if EOF was reached, and the filter
|
||||
* should drain all remaining buffered data.
|
||||
* Use af_add_output_frame() to output data. The optional filter_out
|
||||
* callback can be set to produce output frames gradually.
|
||||
/* flags is a bit mask of AF_FILTER_FLAG_* values
|
||||
* returns 0 on success, negative value on error
|
||||
*/
|
||||
int (*filter_frame)(struct af_instance *af, struct mp_audio *frame);
|
||||
int (*filter_out)(struct af_instance *af);
|
||||
int (*filter)(struct af_instance *af, struct mp_audio *data, int flags);
|
||||
void *priv;
|
||||
struct mp_audio *data; // configuration and buffer for outgoing data stream
|
||||
|
||||
struct af_instance *next;
|
||||
struct af_instance *prev;
|
||||
double delay; /* Delay caused by the filter, in seconds of audio consumed
|
||||
* without corresponding output */
|
||||
double mul; /* length multiplier: how much does this instance change
|
||||
* the number of samples passed though. (Ratio of input
|
||||
* and output, e.g. mul=4 => 1 sample becomes 4 samples) .*/
|
||||
bool auto_inserted; // inserted by af.c, such as conversion filters
|
||||
char *label;
|
||||
|
||||
struct mp_audio fmt_in, fmt_out;
|
||||
|
||||
struct mp_audio **out_queued;
|
||||
int num_out_queued;
|
||||
|
||||
struct mp_audio_pool *out_pool;
|
||||
};
|
||||
|
||||
// Current audio stream
|
||||
@@ -144,16 +136,13 @@ void af_uninit(struct af_stream *s);
|
||||
struct af_instance *af_add(struct af_stream *s, char *name, char **args);
|
||||
int af_remove_by_label(struct af_stream *s, char *label);
|
||||
struct af_instance *af_find_by_label(struct af_stream *s, char *label);
|
||||
struct mp_audio_buffer;
|
||||
int af_filter(struct af_stream *s, struct mp_audio *data,
|
||||
struct mp_audio_buffer *output);
|
||||
struct af_instance *af_control_any_rev(struct af_stream *s, int cmd, void *arg);
|
||||
void af_control_all(struct af_stream *s, int cmd, void *arg);
|
||||
void af_seek_reset(struct af_stream *s);
|
||||
|
||||
void af_add_output_frame(struct af_instance *af, struct mp_audio *frame);
|
||||
int af_filter_frame(struct af_stream *s, struct mp_audio *frame);
|
||||
int af_output_frame(struct af_stream *s, bool eof);
|
||||
struct mp_audio *af_read_output_frame(struct af_stream *s);
|
||||
int af_make_writeable(struct af_instance *af, struct mp_audio *frame);
|
||||
|
||||
double af_calc_filter_multiplier(struct af_stream *s);
|
||||
double af_calc_delay(struct af_stream *s);
|
||||
|
||||
int af_test_output(struct af_instance *af, struct mp_audio *out);
|
||||
|
||||
+46
-41
@@ -37,49 +37,26 @@ struct af_bs2b {
|
||||
t_bs2bdp filter; ///< instance of a library filter
|
||||
};
|
||||
|
||||
#define DEF_FILTER(fmt, name) \
|
||||
static int filter_##name(struct af_instance *af, struct mp_audio *data) \
|
||||
#define FILTER(name, type) \
|
||||
static int filter_##name(struct af_instance *af, struct mp_audio *data, int f) \
|
||||
{ \
|
||||
if (!data) \
|
||||
return 0; \
|
||||
if (af_make_writeable(af, data) < 0) { \
|
||||
talloc_free(data); \
|
||||
return -1; \
|
||||
} \
|
||||
/* filter is called for all pairs of samples available in the buffer */ \
|
||||
bs2b_cross_feed_##name(((struct af_bs2b*)(af->priv))->filter, \
|
||||
(data->planes[0]), data->samples); \
|
||||
af_add_output_frame(af, data); \
|
||||
(type*)(data->planes[0]), data->samples); \
|
||||
\
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define GET_FILTER(fmt, name) \
|
||||
case AF_FORMAT_##fmt: return filter_##name;
|
||||
FILTER(f, float)
|
||||
FILTER(s32, int32_t)
|
||||
FILTER(u32, uint32_t)
|
||||
FILTER(s24, bs2b_int24_t)
|
||||
FILTER(u24, bs2b_uint24_t)
|
||||
FILTER(s16, int16_t)
|
||||
FILTER(u16, uint16_t)
|
||||
FILTER(s8, int8_t)
|
||||
FILTER(u8, uint8_t)
|
||||
|
||||
#define FILTERS \
|
||||
FILTER(FLOAT, f) \
|
||||
FILTER(S32, s32) \
|
||||
FILTER(U32, u32) \
|
||||
FILTER(S24, s24) \
|
||||
FILTER(U24, u24) \
|
||||
FILTER(S16, s16) \
|
||||
FILTER(U16, u16) \
|
||||
FILTER(S8, s8) \
|
||||
FILTER(U8, u8)
|
||||
|
||||
#define FILTER DEF_FILTER
|
||||
FILTERS
|
||||
#undef FILTER
|
||||
|
||||
typedef int (*filter)(struct af_instance *af, struct mp_audio *d);
|
||||
static filter get_filter(int fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
#define FILTER GET_FILTER
|
||||
FILTERS
|
||||
#undef FILTER
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialization and runtime control
|
||||
static int control(struct af_instance *af, int cmd, void *arg)
|
||||
@@ -99,10 +76,38 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
|
||||
/* check for formats supported by libbs2b
|
||||
and assign corresponding handlers */
|
||||
af->filter_frame = get_filter(format);
|
||||
if (!af->filter_frame) {
|
||||
af->filter_frame = filter_f;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
switch (format) {
|
||||
case AF_FORMAT_FLOAT:
|
||||
af->filter = filter_f;
|
||||
break;
|
||||
case AF_FORMAT_S32:
|
||||
af->filter = filter_s32;
|
||||
break;
|
||||
case AF_FORMAT_U32:
|
||||
af->filter = filter_u32;
|
||||
break;
|
||||
case AF_FORMAT_S24:
|
||||
af->filter = filter_s24;
|
||||
break;
|
||||
case AF_FORMAT_U24:
|
||||
af->filter = filter_u24;
|
||||
break;
|
||||
case AF_FORMAT_S16:
|
||||
af->filter = filter_s16;
|
||||
break;
|
||||
case AF_FORMAT_U16:
|
||||
af->filter = filter_u16;
|
||||
break;
|
||||
case AF_FORMAT_S8:
|
||||
af->filter = filter_s8;
|
||||
break;
|
||||
case AF_FORMAT_U8:
|
||||
af->filter = filter_u8;
|
||||
break;
|
||||
default:
|
||||
af->filter = filter_f;
|
||||
mp_audio_set_format(af->data, AF_FORMAT_FLOAT);
|
||||
break;
|
||||
}
|
||||
|
||||
// bs2b have srate limits, try to resample if needed
|
||||
|
||||
@@ -58,14 +58,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance* af, struct mp_audio* data)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_center_t* s = af->priv; // Setup for this instance
|
||||
float* a = c->planes[0]; // Audio data
|
||||
@@ -80,14 +75,13 @@ static int filter_frame(struct af_instance* af, struct mp_audio* data)
|
||||
a[i+ch] = (a[i]/2) + (a[i+1]/2);
|
||||
}
|
||||
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
+10
-13
@@ -181,20 +181,15 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
struct mp_audio* l = af->data; // Local data
|
||||
af_channels_t* s = af->priv;
|
||||
int i;
|
||||
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
|
||||
if (!l) {
|
||||
talloc_free(c);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(l, c);
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
// Reset unused channels
|
||||
memset(l->planes[0],0,mp_audio_psize(c) / c->nch * l->nch);
|
||||
@@ -204,15 +199,17 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
copy(af, c->planes[0],l->planes[0],c->nch,s->route[i][FR],
|
||||
l->nch,s->route[i][TO],mp_audio_psize(c),c->bps);
|
||||
|
||||
talloc_free(c);
|
||||
af_add_output_frame(af, l);
|
||||
// Set output data
|
||||
c->planes[0] = l->planes[0];
|
||||
mp_audio_set_channels(c, &l->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
af_channels_t *s = af->priv;
|
||||
|
||||
// If router scan commandline for routing pairs
|
||||
|
||||
@@ -71,19 +71,13 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
#define SHIFT(x) (((x)+1)*8)
|
||||
#endif
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
struct mp_audio *out =
|
||||
mp_audio_pool_get(af->out_pool, af->data, data->samples);
|
||||
if (!out) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(out, data);
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
struct mp_audio *out = af->data;
|
||||
size_t len = mp_audio_psize(data) / data->bps;
|
||||
|
||||
if (data->bps == 4) {
|
||||
for (int s = 0; s < len; s++) {
|
||||
uint32_t val = *((uint32_t *)data->planes[0] + s);
|
||||
@@ -92,6 +86,7 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
ptr[1] = val >> SHIFT(1);
|
||||
ptr[2] = val >> SHIFT(2);
|
||||
}
|
||||
mp_audio_set_format(data, af_fmt_change_bits(data->format, 24));
|
||||
} else {
|
||||
for (int s = 0; s < len; s++) {
|
||||
uint8_t *ptr = (uint8_t *)data->planes[0] + s * 3;
|
||||
@@ -100,17 +95,17 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
| ptr[2] << SHIFT(2);
|
||||
*((uint32_t *)out->planes[0] + s) = val;
|
||||
}
|
||||
mp_audio_set_format(data, af_fmt_change_bits(data->format, 32));
|
||||
}
|
||||
|
||||
talloc_free(data);
|
||||
af_add_output_frame(af, out);
|
||||
data->planes[0] = out->planes[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,15 +71,8 @@ static void si2us(void *data, int len, int bps)
|
||||
} while (i += bps);
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int infmt = data->format;
|
||||
int outfmt = af->data->format;
|
||||
size_t len = data->samples * data->nch;
|
||||
@@ -88,14 +81,13 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
si2us(data->planes[0], len, data->bps);
|
||||
|
||||
mp_audio_set_format(data, outfmt);
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,19 +96,15 @@ static void uninit(struct af_instance* af)
|
||||
free(((af_delay_t*)(af->priv))->q[i]);
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
if (!c)
|
||||
return 0;
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_delay_t* s = af->priv; // Setup for this instance
|
||||
int nch = c->nch; // Number of channels
|
||||
int len = mp_audio_psize(c)/c->bps; // Number of sample in data chunk
|
||||
int ri = 0;
|
||||
int ch,i;
|
||||
if (af_make_writeable(af, c) < 0) {
|
||||
talloc_free(c);
|
||||
return -1;
|
||||
}
|
||||
for(ch=0;ch<nch;ch++){
|
||||
switch(c->bps){
|
||||
case 1:{
|
||||
@@ -156,7 +152,6 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
}
|
||||
}
|
||||
s->ri = ri;
|
||||
af_add_output_frame(af, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -164,7 +159,7 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
af_delay_t *s = af->priv;
|
||||
int n = 1;
|
||||
int i = 0;
|
||||
|
||||
+2
-11
@@ -272,18 +272,10 @@ static void method2_float(af_drc_t *s, struct mp_audio *c)
|
||||
s->idx = (s->idx + 1) % NSAMPLES;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
af_drc_t *s = af->priv;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(af->data->format == (AF_FORMAT_S16))
|
||||
{
|
||||
if (s->method == 2)
|
||||
@@ -298,7 +290,6 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
else
|
||||
method1_float(s, data);
|
||||
}
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -306,7 +297,7 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int af_open(struct af_instance* af){
|
||||
int i = 0;
|
||||
af->control=control;
|
||||
af->filter_frame = filter;
|
||||
af->filter=filter;
|
||||
af_drc_t *priv = af->priv;
|
||||
|
||||
priv->mul = MUL_INIT;
|
||||
|
||||
@@ -41,16 +41,15 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data)
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame=filter;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,20 +141,14 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance* af, struct mp_audio* data)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
struct mp_audio* c = data; // Current working data
|
||||
if (!c)
|
||||
return 0;
|
||||
af_equalizer_t* s = (af_equalizer_t*)af->priv; // Setup
|
||||
uint32_t ci = af->data->nch; // Index for channels
|
||||
uint32_t nch = af->data->nch; // Number of channels
|
||||
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(ci--){
|
||||
float* g = s->g[ci]; // Gain factor
|
||||
float* in = ((float*)c->planes[0])+ci;
|
||||
@@ -183,14 +177,13 @@ static int filter(struct af_instance* af, struct mp_audio* data)
|
||||
out+=nch;
|
||||
}
|
||||
}
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter;
|
||||
af->filter=filter;
|
||||
af_equalizer_t *priv = af->priv;
|
||||
for(int i=0;i<AF_NCH;i++){
|
||||
for(int j=0;j<KM;j++){
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -162,10 +163,8 @@ static void uninit( struct af_instance* af )
|
||||
af audio filter instance
|
||||
data audio data
|
||||
*/
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter( struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_export_t* s = af->priv; // Setup for this instance
|
||||
int16_t* a = c->planes[0]; // Incomming sound
|
||||
@@ -201,7 +200,6 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
&(s->count), sizeof(s->count));
|
||||
}
|
||||
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -213,7 +211,7 @@ static int af_open( struct af_instance* af )
|
||||
{
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
af_export_t *priv = af->priv;
|
||||
|
||||
if (!priv->filename || !priv->filename[0]) {
|
||||
|
||||
@@ -35,6 +35,9 @@ typedef struct af_extrastereo_s
|
||||
float mul;
|
||||
}af_extrastereo_t;
|
||||
|
||||
static int play_s16(struct af_instance* af, struct mp_audio* data, int f);
|
||||
static int play_float(struct af_instance* af, struct mp_audio* data, int f);
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
@@ -46,8 +49,14 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
|
||||
mp_audio_force_interleaved_format(af->data);
|
||||
mp_audio_set_num_channels(af->data, 2);
|
||||
if (af->data->format != AF_FORMAT_FLOAT)
|
||||
if (af->data->format == AF_FORMAT_FLOAT)
|
||||
{
|
||||
af->filter = play_float;
|
||||
}// else
|
||||
{
|
||||
mp_audio_set_format(af->data, AF_FORMAT_S16);
|
||||
af->filter = play_s16;
|
||||
}
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
@@ -56,8 +65,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
}
|
||||
|
||||
// Filter data through filter
|
||||
static void play_s16(af_extrastereo_t *s, struct mp_audio* data)
|
||||
static int play_s16(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
af_extrastereo_t *s = af->priv;
|
||||
register int i = 0;
|
||||
int16_t *a = (int16_t*)data->planes[0]; // Audio data
|
||||
int len = data->samples*data->nch; // Number of samples
|
||||
@@ -73,10 +83,13 @@ static void play_s16(af_extrastereo_t *s, struct mp_audio* data)
|
||||
a[i] = MPCLAMP(l, SHRT_MIN, SHRT_MAX);
|
||||
a[i + 1] = MPCLAMP(r, SHRT_MIN, SHRT_MAX);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void play_float(af_extrastereo_t *s, struct mp_audio* data)
|
||||
static int play_float(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
af_extrastereo_t *s = af->priv;
|
||||
register int i = 0;
|
||||
float *a = (float*)data->planes[0]; // Audio data
|
||||
int len = data->samples * data->nch; // Number of samples
|
||||
@@ -92,29 +105,14 @@ static void play_float(af_extrastereo_t *s, struct mp_audio* data)
|
||||
a[i] = af_softclip(l);
|
||||
a[i + 1] = af_softclip(r);
|
||||
}
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
if (data->format == AF_FORMAT_FLOAT) {
|
||||
play_float(af->priv, data);
|
||||
} else {
|
||||
play_s16(af->priv, data);
|
||||
}
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=play_s16;
|
||||
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
@@ -44,11 +44,9 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
if (data)
|
||||
mp_audio_copy_config(data, af->data);
|
||||
af_add_output_frame(af, data);
|
||||
mp_audio_copy_config(data, af->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -56,7 +54,7 @@ static int af_open(struct af_instance *af)
|
||||
{
|
||||
struct priv *priv = af->priv;
|
||||
af->control = control;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
priv->speed = 1.0;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
@@ -95,18 +95,16 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
if (data)
|
||||
mp_audio_copy_config(data, af->data);
|
||||
af_add_output_frame(af, data);
|
||||
mp_audio_copy_config(data, af->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
|
||||
force_in_params(af, af->data);
|
||||
force_out_params(af, af->data);
|
||||
|
||||
+11
-16
@@ -375,26 +375,17 @@ frequencies).
|
||||
2. A bass compensation is introduced to ensure that 0-200 Hz are not
|
||||
damped (without any real 3D acoustical image, however).
|
||||
*/
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
af_hrtf_t *s = af->priv;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
struct mp_audio *outframe =
|
||||
mp_audio_pool_get(af->out_pool, &af->fmt_out, data->samples);
|
||||
if (!outframe) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(outframe, data);
|
||||
|
||||
short *in = data->planes[0]; // Input audio data
|
||||
short *out = outframe->planes[0]; // Output audio data
|
||||
short *out = NULL; // Output audio data
|
||||
short *end = in + data->samples * data->nch; // Loop end
|
||||
float common, left, right, diff, left_b, right_b;
|
||||
const int dblen = s->dlbuflen, hlen = s->hrflen, blen = s->basslen;
|
||||
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
if(s->print_flag) {
|
||||
s->print_flag = 0;
|
||||
switch (s->decode_mode) {
|
||||
@@ -421,6 +412,8 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
"channel\n");
|
||||
}
|
||||
|
||||
out = af->data->planes[0];
|
||||
|
||||
/* MPlayer's 5 channel layout (notation for the variable):
|
||||
*
|
||||
* 0: L (LF), 1: R (RF), 2: Ls (LR), 3: Rs (RR), 4: C (CF), matrix
|
||||
@@ -558,8 +551,10 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
s->cyc_pos += dblen;
|
||||
}
|
||||
|
||||
talloc_free(data);
|
||||
af_add_output_frame(af, outframe);
|
||||
/* Set output data */
|
||||
data->planes[0] = af->data->planes[0];
|
||||
mp_audio_set_num_channels(data, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -593,7 +588,7 @@ static int af_open(struct af_instance* af)
|
||||
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
|
||||
s = af->priv;
|
||||
|
||||
|
||||
@@ -41,15 +41,10 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
// Filter data through filter
|
||||
static int play(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
if (!c)
|
||||
return 0;
|
||||
if (af_make_writeable(af, c) < 0) {
|
||||
talloc_free(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mp_audio* c = data; // Current working data
|
||||
float* a = c->planes[0]; // Audio data
|
||||
int nch = c->nch; // Number of channels
|
||||
int len = c->samples*nch; // Number of samples in current audio block
|
||||
@@ -67,14 +62,13 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
a[i+1]=a[i];
|
||||
}
|
||||
|
||||
af_add_output_frame(af, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control = control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter = play;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -565,10 +565,7 @@ static void uninit(struct af_instance *af) {
|
||||
* \return Either AF_ERROR or AF_OK
|
||||
*/
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags) {
|
||||
af_ladspa_t *setup = af->priv;
|
||||
const LADSPA_Descriptor *pdes = setup->plugin_descriptor;
|
||||
float *audio = (float*)data->planes[0];
|
||||
@@ -577,14 +574,8 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
int rate = data->rate;
|
||||
int i, p;
|
||||
|
||||
if (setup->status !=AF_OK) {
|
||||
talloc_free(data);
|
||||
if (setup->status !=AF_OK)
|
||||
return -1;
|
||||
}
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* See if it's the first call. If so, setup inbufs/outbufs, instantiate
|
||||
* plugin, connect ports and activate plugin
|
||||
@@ -730,7 +721,6 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
|
||||
/* done */
|
||||
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -747,7 +737,7 @@ static int af_open(struct af_instance *af) {
|
||||
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
|
||||
af_ladspa_t *setup = af->priv;
|
||||
|
||||
|
||||
+96
-101
@@ -53,8 +53,7 @@ typedef struct af_ac3enc_s {
|
||||
struct AVCodecContext *lavc_actx;
|
||||
AVPacket pkt;
|
||||
int bit_rate;
|
||||
struct mp_audio *input; // frame passed to libavcodec
|
||||
struct mp_audio *pending; // unconsumed input data
|
||||
struct mp_audio_buffer *pending;
|
||||
int in_samples; // samples of input per AC3 frame
|
||||
int out_samples; // upper bound on encoded output per AC3 frame
|
||||
int in_sampleformat;
|
||||
@@ -101,16 +100,12 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
} else {
|
||||
s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride;
|
||||
}
|
||||
af->mul = s->out_samples / (double)s->in_samples;
|
||||
|
||||
mp_audio_copy_config(s->input, in);
|
||||
mp_audio_realloc(s->input, s->in_samples);
|
||||
s->input->samples = 0;
|
||||
mp_audio_buffer_reinit(s->pending, in);
|
||||
|
||||
talloc_free(s->pending);
|
||||
s->pending = NULL;
|
||||
|
||||
MP_DBG(af, "af_lavcac3enc reinit: %d, %d, %d.\n",
|
||||
in->nch, in->rate, s->in_samples);
|
||||
MP_DBG(af, "af_lavcac3enc reinit: %d, %d, %f, %d.\n",
|
||||
in->nch, in->rate, af->mul, s->in_samples);
|
||||
|
||||
int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];
|
||||
|
||||
@@ -153,110 +148,111 @@ static void uninit(struct af_instance* af)
|
||||
avcodec_close(s->lavc_actx);
|
||||
av_free(s->lavc_actx);
|
||||
}
|
||||
talloc_free(s->pending);
|
||||
}
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *audio)
|
||||
{
|
||||
af_ac3enc_t *s = af->priv;
|
||||
|
||||
// filter_output must have been called until no output was produced.
|
||||
if (s->pending && s->pending->samples)
|
||||
MP_ERR(af, "broken data flow\n");
|
||||
|
||||
talloc_free(s->pending);
|
||||
s->pending = audio;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void swap_16(uint16_t *ptr, size_t size)
|
||||
{
|
||||
for (size_t n = 0; n < size; n++)
|
||||
ptr[n] = av_bswap16(ptr[n]);
|
||||
}
|
||||
|
||||
// Copy data from input frame to encode frame (because libavcodec wants a full
|
||||
// AC3 frame for encoding, while filter input frames can be smaller or larger).
|
||||
// Return true if the
|
||||
static bool fill_buffer(af_ac3enc_t *s)
|
||||
{
|
||||
if (s->pending) {
|
||||
int copy = MPMIN(s->in_samples - s->input->samples, s->pending->samples);
|
||||
s->input->samples += copy;
|
||||
mp_audio_copy(s->input, s->input->samples - copy, s->pending, 0, copy);
|
||||
mp_audio_skip_samples(s->pending, copy);
|
||||
}
|
||||
return s->input->samples >= s->in_samples;
|
||||
}
|
||||
|
||||
static int filter_out(struct af_instance *af)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* audio, int flags)
|
||||
{
|
||||
struct mp_audio *out = af->data;
|
||||
af_ac3enc_t *s = af->priv;
|
||||
if (!fill_buffer(s))
|
||||
return 0; // need more input
|
||||
int num_frames = (audio->samples + mp_audio_buffer_samples(s->pending))
|
||||
/ s->in_samples;
|
||||
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
MP_FATAL(af, "Could not allocate memory \n");
|
||||
return -1;
|
||||
}
|
||||
frame->nb_samples = s->in_samples;
|
||||
frame->format = s->lavc_actx->sample_fmt;
|
||||
frame->channel_layout = s->lavc_actx->channel_layout;
|
||||
assert(s->input->num_planes <= AV_NUM_DATA_POINTERS);
|
||||
frame->extended_data = frame->data;
|
||||
for (int n = 0; n < s->input->num_planes; n++)
|
||||
frame->data[n] = s->input->planes[n];
|
||||
frame->linesize[0] = s->input->samples * s->input->sstride;
|
||||
int max_out_samples = s->out_samples * num_frames;
|
||||
mp_audio_realloc_min(out, max_out_samples);
|
||||
out->samples = 0;
|
||||
|
||||
int ok;
|
||||
int lavc_ret = avcodec_encode_audio2(s->lavc_actx, &s->pkt, frame, &ok);
|
||||
av_frame_free(&frame);
|
||||
s->input->samples = 0;
|
||||
if (lavc_ret < 0 || !ok) {
|
||||
MP_FATAL(af, "Encode failed.\n");
|
||||
return -1;
|
||||
while (audio->samples > 0) {
|
||||
int ret;
|
||||
|
||||
int consumed_pending = 0;
|
||||
struct mp_audio in_frame;
|
||||
int pending = mp_audio_buffer_samples(s->pending);
|
||||
if (pending == 0 && audio->samples >= s->in_samples) {
|
||||
in_frame = *audio;
|
||||
mp_audio_skip_samples(audio, s->in_samples);
|
||||
} else {
|
||||
if (pending > 0 && pending < s->in_samples) {
|
||||
struct mp_audio tmp = *audio;
|
||||
tmp.samples = MPMIN(tmp.samples, s->in_samples);
|
||||
mp_audio_buffer_append(s->pending, &tmp);
|
||||
mp_audio_skip_samples(audio, tmp.samples);
|
||||
}
|
||||
mp_audio_buffer_peek(s->pending, &in_frame);
|
||||
if (in_frame.samples < s->in_samples)
|
||||
break;
|
||||
consumed_pending = s->in_samples;
|
||||
}
|
||||
in_frame.samples = s->in_samples;
|
||||
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
MP_FATAL(af, "Could not allocate memory \n");
|
||||
return -1;
|
||||
}
|
||||
frame->nb_samples = s->in_samples;
|
||||
frame->format = s->lavc_actx->sample_fmt;
|
||||
frame->channel_layout = s->lavc_actx->channel_layout;
|
||||
assert(in_frame.num_planes <= AV_NUM_DATA_POINTERS);
|
||||
frame->extended_data = frame->data;
|
||||
for (int n = 0; n < in_frame.num_planes; n++)
|
||||
frame->data[n] = in_frame.planes[n];
|
||||
frame->linesize[0] = s->in_samples * audio->sstride;
|
||||
|
||||
int ok;
|
||||
ret = avcodec_encode_audio2(s->lavc_actx, &s->pkt, frame, &ok);
|
||||
av_frame_free(&frame);
|
||||
if (ret < 0 || !ok) {
|
||||
MP_FATAL(af, "Encode failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mp_audio_buffer_skip(s->pending, consumed_pending);
|
||||
|
||||
MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n",
|
||||
s->pkt.size, mp_audio_buffer_samples(s->pending));
|
||||
|
||||
int frame_size = s->pkt.size;
|
||||
int header_len = 0;
|
||||
char hdr[8];
|
||||
|
||||
if (s->cfg_add_iec61937_header && s->pkt.size > 5) {
|
||||
int bsmod = s->pkt.data[5] & 0x7;
|
||||
int len = frame_size;
|
||||
|
||||
frame_size = AC3_FRAME_SIZE * 2 * 2;
|
||||
header_len = 8;
|
||||
|
||||
AV_WL16(hdr, 0xF872); // iec 61937 syncword 1
|
||||
AV_WL16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
|
||||
hdr[5] = bsmod; // bsmod
|
||||
hdr[4] = 0x01; // data-type ac3
|
||||
AV_WL16(hdr + 6, len << 3); // number of bits in payload
|
||||
}
|
||||
|
||||
size_t max_size = (max_out_samples - out->samples) * out->sstride;
|
||||
if (frame_size > max_size)
|
||||
abort();
|
||||
|
||||
char *buf = (char *)out->planes[0] + out->samples * out->sstride;
|
||||
memcpy(buf, hdr, header_len);
|
||||
memcpy(buf + header_len, s->pkt.data, s->pkt.size);
|
||||
memset(buf + header_len + s->pkt.size, 0,
|
||||
frame_size - (header_len + s->pkt.size));
|
||||
swap_16((uint16_t *)(buf + header_len), s->pkt.size / 2);
|
||||
out->samples += frame_size / out->sstride;
|
||||
}
|
||||
|
||||
MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n",
|
||||
s->pkt.size, s->pending->samples);
|
||||
mp_audio_buffer_append(s->pending, audio);
|
||||
|
||||
struct mp_audio *out =
|
||||
mp_audio_pool_get(af->out_pool, af->data, s->out_samples);
|
||||
if (!out)
|
||||
return -1;
|
||||
mp_audio_copy_attributes(out, s->pending);
|
||||
|
||||
int frame_size = s->pkt.size;
|
||||
int header_len = 0;
|
||||
char hdr[8];
|
||||
|
||||
if (s->cfg_add_iec61937_header && s->pkt.size > 5) {
|
||||
int bsmod = s->pkt.data[5] & 0x7;
|
||||
int len = frame_size;
|
||||
|
||||
frame_size = AC3_FRAME_SIZE * 2 * 2;
|
||||
header_len = 8;
|
||||
|
||||
AV_WL16(hdr, 0xF872); // iec 61937 syncword 1
|
||||
AV_WL16(hdr + 2, 0x4E1F); // iec 61937 syncword 2
|
||||
hdr[5] = bsmod; // bsmod
|
||||
hdr[4] = 0x01; // data-type ac3
|
||||
AV_WL16(hdr + 6, len << 3); // number of bits in payload
|
||||
}
|
||||
|
||||
if (frame_size > out->samples * out->sstride)
|
||||
abort();
|
||||
|
||||
char *buf = (char *)out->planes[0];
|
||||
memcpy(buf, hdr, header_len);
|
||||
memcpy(buf + header_len, s->pkt.data, s->pkt.size);
|
||||
memset(buf + header_len + s->pkt.size, 0,
|
||||
frame_size - (header_len + s->pkt.size));
|
||||
swap_16((uint16_t *)(buf + header_len), s->pkt.size / 2);
|
||||
out->samples = frame_size / out->sstride;
|
||||
af_add_output_frame(af, out);
|
||||
*audio = *out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -265,8 +261,7 @@ static int af_open(struct af_instance* af){
|
||||
af_ac3enc_t *s = af->priv;
|
||||
af->control=control;
|
||||
af->uninit=uninit;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter_out = filter_out;
|
||||
af->filter=filter;
|
||||
|
||||
s->lavc_acodec = avcodec_find_encoder_by_name("ac3");
|
||||
if (!s->lavc_acodec) {
|
||||
@@ -297,7 +292,7 @@ static int af_open(struct af_instance* af){
|
||||
|
||||
av_init_packet(&s->pkt);
|
||||
|
||||
s->input = talloc_zero(s, struct mp_audio);
|
||||
s->pending = mp_audio_buffer_create(af);
|
||||
|
||||
if (s->cfg_bit_rate) {
|
||||
int i;
|
||||
|
||||
+52
-62
@@ -201,92 +201,83 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
|
||||
p->timebase_out = l_out->time_base;
|
||||
|
||||
// Blatantly incorrect; we don't know what the filters do.
|
||||
af->mul = out->rate / (double)in->rate;
|
||||
|
||||
return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE;
|
||||
}
|
||||
}
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
struct priv *p = af->priv;
|
||||
struct mp_audio *r = af->data;
|
||||
bool eof = data->samples == 0 && (flags & AF_FILTER_FLAG_EOF);
|
||||
AVFilterLink *l_in = p->in->outputs[0];
|
||||
|
||||
AVFrame *frame = NULL;
|
||||
if (data) {
|
||||
frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
goto error;
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
frame->nb_samples = data->samples;
|
||||
frame->format = l_in->format;
|
||||
|
||||
frame->nb_samples = data->samples;
|
||||
frame->format = l_in->format;
|
||||
// Timebase is 1/sample_rate
|
||||
frame->pts = p->samples_in;
|
||||
|
||||
// Timebase is 1/sample_rate
|
||||
frame->pts = p->samples_in;
|
||||
|
||||
frame->channel_layout = l_in->channel_layout;
|
||||
frame->sample_rate = l_in->sample_rate;
|
||||
frame->channel_layout = l_in->channel_layout;
|
||||
frame->sample_rate = l_in->sample_rate;
|
||||
#if LIBAVFILTER_VERSION_MICRO >= 100
|
||||
// FFmpeg being a stupid POS
|
||||
frame->channels = l_in->channels;
|
||||
// FFmpeg being a stupid POS
|
||||
frame->channels = l_in->channels;
|
||||
#endif
|
||||
|
||||
frame->extended_data = frame->data;
|
||||
for (int n = 0; n < data->num_planes; n++)
|
||||
frame->data[n] = data->planes[n];
|
||||
frame->linesize[0] = frame->nb_samples * data->sstride;
|
||||
frame->extended_data = frame->data;
|
||||
for (int n = 0; n < data->num_planes; n++)
|
||||
frame->data[n] = data->planes[n];
|
||||
frame->linesize[0] = frame->nb_samples * data->sstride;
|
||||
|
||||
if (av_buffersrc_add_frame(p->in, eof ? NULL : frame) < 0) {
|
||||
av_frame_free(&frame);
|
||||
return -1;
|
||||
}
|
||||
av_frame_free(&frame);
|
||||
|
||||
int64_t out_pts = AV_NOPTS_VALUE;
|
||||
r->samples = 0;
|
||||
for (;;) {
|
||||
frame = av_frame_alloc();
|
||||
if (av_buffersink_get_frame(p->out, frame) < 0) {
|
||||
// Not an error situation - no more output buffers in queue.
|
||||
av_frame_free(&frame);
|
||||
break;
|
||||
}
|
||||
|
||||
mp_audio_realloc_min(r, r->samples + frame->nb_samples);
|
||||
for (int n = 0; n < r->num_planes; n++) {
|
||||
memcpy((char *)r->planes[n] + r->samples * r->sstride,
|
||||
frame->extended_data[n], frame->nb_samples * r->sstride);
|
||||
}
|
||||
r->samples += frame->nb_samples;
|
||||
|
||||
if (out_pts == AV_NOPTS_VALUE)
|
||||
out_pts = frame->pts;
|
||||
|
||||
p->samples_in += data->samples;
|
||||
}
|
||||
|
||||
if (av_buffersrc_add_frame(p->in, frame) < 0)
|
||||
goto error;
|
||||
|
||||
av_frame_free(&frame);
|
||||
talloc_free(data);
|
||||
return 0;
|
||||
error:
|
||||
av_frame_free(&frame);
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int filter_out(struct af_instance *af)
|
||||
{
|
||||
struct priv *p = af->priv;
|
||||
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
if (!frame)
|
||||
goto error;
|
||||
|
||||
int err = av_buffersink_get_frame(p->out, frame);
|
||||
if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) {
|
||||
// Not an error situation - no more output buffers in queue.
|
||||
av_frame_free(&frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mp_audio *out = mp_audio_from_avframe(frame);
|
||||
if (!out)
|
||||
goto error;
|
||||
p->samples_in += data->samples;
|
||||
|
||||
mp_audio_copy_config(out, af->data);
|
||||
|
||||
if (frame->pts != AV_NOPTS_VALUE) {
|
||||
double in_time = p->samples_in / (double)af->fmt_in.rate;
|
||||
double out_time = frame->pts * av_q2d(p->timebase_out);
|
||||
if (out_pts != AV_NOPTS_VALUE) {
|
||||
double in_time = p->samples_in / (double)data->rate;
|
||||
double out_time = out_pts * av_q2d(p->timebase_out);
|
||||
// Need pts past the last output sample.
|
||||
out_time += out->samples / (double)out->rate;
|
||||
out_time += r->samples / (double)r->rate;
|
||||
|
||||
af->delay = in_time - out_time;
|
||||
}
|
||||
|
||||
af_add_output_frame(af, out);
|
||||
av_frame_free(&frame);
|
||||
*data = *r;
|
||||
return 0;
|
||||
error:
|
||||
av_frame_free(&frame);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void uninit(struct af_instance *af)
|
||||
@@ -298,8 +289,7 @@ static int af_open(struct af_instance *af)
|
||||
{
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter_out = filter_out;
|
||||
af->filter = filter;
|
||||
// Removing this requires fixing AVFrame.data vs. AVFrame.extended_data
|
||||
assert(MP_NUM_CHANNELS <= AV_NUM_DATA_POINTERS);
|
||||
return AF_OK;
|
||||
|
||||
@@ -82,7 +82,7 @@ struct af_resample {
|
||||
// At least libswresample keeps a pointer around for this:
|
||||
int reorder_in[MP_NUM_CHANNELS];
|
||||
int reorder_out[MP_NUM_CHANNELS];
|
||||
struct mp_audio_pool *reorder_buffer;
|
||||
uint8_t *reorder_buffer;
|
||||
};
|
||||
|
||||
#if HAVE_LIBAVRESAMPLE
|
||||
@@ -248,6 +248,8 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
if (af_to_avformat(out->format) == AV_SAMPLE_FMT_NONE)
|
||||
mp_audio_set_format(out, in->format);
|
||||
|
||||
af->mul = out->rate / (double)in->rate;
|
||||
|
||||
int r = ((in->format == orig_in.format) &&
|
||||
mp_chmap_equals(&in->channels, &orig_in.channels))
|
||||
? AF_OK : AF_FALSE;
|
||||
@@ -309,69 +311,47 @@ static void reorder_planes(struct mp_audio *mpa, int *reorder)
|
||||
}
|
||||
}
|
||||
|
||||
static int resample_frame(struct AVAudioResampleContext *r,
|
||||
struct mp_audio *out, struct mp_audio *in)
|
||||
{
|
||||
return avresample_convert(r,
|
||||
out ? (uint8_t **)out->planes : NULL,
|
||||
out ? mp_audio_get_allocated_size(out) : 0,
|
||||
out ? out->samples : 0,
|
||||
in ? (uint8_t **)in->planes : NULL,
|
||||
in ? mp_audio_get_allocated_size(in) : 0,
|
||||
in ? in->samples : 0);
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *in)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
struct af_resample *s = af->priv;
|
||||
struct mp_audio *in = data;
|
||||
struct mp_audio *out = af->data;
|
||||
|
||||
int samples = avresample_available(s->avrctx) +
|
||||
av_rescale_rnd(get_delay(s) + (in ? in->samples : 0),
|
||||
out->samples = avresample_available(s->avrctx) +
|
||||
av_rescale_rnd(get_delay(s) + in->samples,
|
||||
s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP);
|
||||
struct mp_audio *out = mp_audio_pool_get(af->out_pool, af->data, samples);
|
||||
if (!out)
|
||||
goto error;
|
||||
if (in)
|
||||
mp_audio_copy_attributes(out, in);
|
||||
|
||||
mp_audio_realloc_min(out, out->samples);
|
||||
|
||||
af->delay = get_delay(s) / (double)s->ctx.in_rate;
|
||||
|
||||
if (out->samples) {
|
||||
out->samples = resample_frame(s->avrctx, out, in);
|
||||
out->samples = avresample_convert(s->avrctx,
|
||||
(uint8_t **) out->planes, out->samples * out->sstride, out->samples,
|
||||
(uint8_t **) in->planes, in->samples * in->sstride, in->samples);
|
||||
if (out->samples < 0)
|
||||
goto error;
|
||||
return -1; // error
|
||||
}
|
||||
|
||||
*data = *out;
|
||||
|
||||
if (needs_reorder(s->reorder_out, out->nch)) {
|
||||
if (af_fmt_is_planar(out->format)) {
|
||||
reorder_planes(out, s->reorder_out);
|
||||
reorder_planes(data, s->reorder_out);
|
||||
} else if (out->samples) {
|
||||
struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer, out,
|
||||
out->samples);
|
||||
if (!new)
|
||||
goto error;
|
||||
mp_audio_copy_attributes(new, out);
|
||||
int out_samples = resample_frame(s->avrctx_out, new, out);
|
||||
talloc_free(out);
|
||||
out = new;
|
||||
if (out_samples != new->samples)
|
||||
goto error;
|
||||
int out_size = out->samples * out->sstride;
|
||||
if (talloc_get_size(s->reorder_buffer) < out_size)
|
||||
s->reorder_buffer = talloc_realloc_size(s, s->reorder_buffer, out_size);
|
||||
data->planes[0] = s->reorder_buffer;
|
||||
int out_samples = avresample_convert(s->avrctx_out,
|
||||
(uint8_t **) data->planes, out_size, out->samples,
|
||||
(uint8_t **) out->planes, out_size, out->samples);
|
||||
if (out_samples < 0)
|
||||
MP_ERR(af, "Reordering failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(in);
|
||||
if (out->samples) {
|
||||
af_add_output_frame(af, out);
|
||||
} else {
|
||||
talloc_free(out);
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
talloc_free(in);
|
||||
talloc_free(out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance *af)
|
||||
@@ -380,14 +360,13 @@ static int af_open(struct af_instance *af)
|
||||
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
|
||||
if (s->opts.cutoff <= 0.0)
|
||||
s->opts.cutoff = af_resample_default_cutoff(s->opts.filter_size);
|
||||
|
||||
s->avrctx = avresample_alloc_context();
|
||||
s->avrctx_out = avresample_alloc_context();
|
||||
s->reorder_buffer = mp_audio_pool_create(s);
|
||||
|
||||
if (s->avrctx && s->avrctx_out) {
|
||||
return AF_OK;
|
||||
|
||||
+11
-13
@@ -107,17 +107,11 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
if (!c)
|
||||
return 0;
|
||||
struct mp_audio *l = mp_audio_pool_get(af->out_pool, &af->fmt_out, c->samples);
|
||||
if (!l) {
|
||||
talloc_free(c);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(l, c);
|
||||
|
||||
struct mp_audio* c = data; // Current working data
|
||||
struct mp_audio* l = af->data; // Local data
|
||||
af_pan_t* s = af->priv; // Setup for this instance
|
||||
float* in = c->planes[0]; // Input audio data
|
||||
float* out = NULL; // Output audio data
|
||||
@@ -126,6 +120,8 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
int ncho = l->nch; // Number of output channels
|
||||
register int j,k;
|
||||
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
out = l->planes[0];
|
||||
// Execute panning
|
||||
// FIXME: Too slow
|
||||
@@ -141,15 +137,17 @@ static int filter_frame(struct af_instance *af, struct mp_audio *c)
|
||||
in+= nchi;
|
||||
}
|
||||
|
||||
talloc_free(c);
|
||||
af_add_output_frame(af, l);
|
||||
// Set output data
|
||||
c->planes[0] = l->planes[0];
|
||||
set_channels(c, l->nch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
af_pan_t *s = af->priv;
|
||||
int n = 0;
|
||||
int j,k;
|
||||
|
||||
@@ -84,7 +84,7 @@ typedef struct af_scaletempo_s
|
||||
static int fill_queue(struct af_instance *af, struct mp_audio *data, int offset)
|
||||
{
|
||||
af_scaletempo_t *s = af->priv;
|
||||
int bytes_in = (data ? mp_audio_psize(data) : 0) - offset;
|
||||
int bytes_in = mp_audio_psize(data) - offset;
|
||||
int offset_unchanged = offset;
|
||||
|
||||
if (s->bytes_to_slide > 0) {
|
||||
@@ -210,28 +210,21 @@ static void output_overlap_s16(af_scaletempo_t *s, void *buf_out,
|
||||
}
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int flags)
|
||||
{
|
||||
af_scaletempo_t *s = af->priv;
|
||||
|
||||
if (s->scale == 1.0) {
|
||||
af->delay = 0;
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int in_samples = data ? data->samples : 0;
|
||||
struct mp_audio *out = mp_audio_pool_get(af->out_pool, af->data,
|
||||
((int)(in_samples / s->frames_stride_scaled) + 1) * s->frames_stride);
|
||||
if (!out) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
if (data)
|
||||
mp_audio_copy_attributes(out, data);
|
||||
mp_audio_realloc_min(af->data,
|
||||
((int)(data->samples / s->frames_stride_scaled) + 1) * s->frames_stride);
|
||||
|
||||
int offset_in = fill_queue(af, data, 0);
|
||||
int8_t *pout = out->planes[0];
|
||||
int8_t *pout = af->data->planes[0];
|
||||
while (s->bytes_queued >= s->bytes_queue) {
|
||||
int ti;
|
||||
float tf;
|
||||
@@ -264,15 +257,10 @@ static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
// output corresponding to some length of input can be decided and written
|
||||
// after receiving only a part of that input.
|
||||
af->delay = (s->bytes_queued - s->bytes_to_slide) / s->scale
|
||||
/ out->sstride / out->rate;
|
||||
/ af->data->sstride / af->data->rate;
|
||||
|
||||
out->samples = (pout - (int8_t *)out->planes[0]) / out->sstride;
|
||||
talloc_free(data);
|
||||
if (out->samples) {
|
||||
af_add_output_frame(af, out);
|
||||
} else {
|
||||
talloc_free(out);
|
||||
}
|
||||
data->planes[0] = af->data->planes[0];
|
||||
data->samples = (pout - (int8_t *)af->data->planes[0]) / af->data->sstride;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -297,6 +285,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
if (s->speed_tempo && s->speed_pitch)
|
||||
return AF_DETACH;
|
||||
af->delay = 0;
|
||||
af->mul = 1;
|
||||
return af_test_output(af, data);
|
||||
}
|
||||
|
||||
@@ -311,6 +300,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
s->bytes_stride = s->frames_stride * bps * nch;
|
||||
s->frames_stride_scaled = s->scale * s->frames_stride;
|
||||
s->frames_stride_error = 0;
|
||||
af->mul = 1.0 / s->scale;
|
||||
af->delay = 0;
|
||||
|
||||
int frames_overlap = s->frames_stride * s->percent_overlap;
|
||||
@@ -466,7 +456,7 @@ static int af_open(struct af_instance *af)
|
||||
|
||||
af->control = control;
|
||||
af->uninit = uninit;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
|
||||
s->speed_tempo = !!(s->speed_opt & SCALE_TEMPO);
|
||||
s->speed_pitch = !!(s->speed_opt & SCALE_PITCH);
|
||||
|
||||
@@ -41,6 +41,9 @@ typedef struct af_sinesuppress_s
|
||||
double pos;
|
||||
}af_sinesuppress_t;
|
||||
|
||||
static int play_s16(struct af_instance* af, struct mp_audio* data, int f);
|
||||
//static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data);
|
||||
|
||||
// Initialization and runtime control
|
||||
static int control(struct af_instance* af, int cmd, void* arg)
|
||||
{
|
||||
@@ -51,7 +54,18 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
|
||||
mp_audio_copy_config(af->data, (struct mp_audio*)arg);
|
||||
mp_audio_set_num_channels(af->data, 1);
|
||||
mp_audio_set_format(af->data, AF_FORMAT_S16);
|
||||
#if 0
|
||||
if (((struct mp_audio*)arg)->format == AF_FORMAT_FLOAT)
|
||||
{
|
||||
af->data->format = AF_FORMAT_FLOAT;
|
||||
af->data->bps = 4;
|
||||
af->play = play_float;
|
||||
}// else
|
||||
#endif
|
||||
{
|
||||
mp_audio_set_format(af->data, AF_FORMAT_S16);
|
||||
af->filter = play_s16;
|
||||
}
|
||||
|
||||
return af_test_output(af,(struct mp_audio*)arg);
|
||||
}
|
||||
@@ -59,15 +73,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int play_s16(struct af_instance *af, struct mp_audio *data)
|
||||
// Filter data through filter
|
||||
static int play_s16(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
af_sinesuppress_t *s = af->priv;
|
||||
register int i = 0;
|
||||
int16_t *a = (int16_t*)data->planes[0]; // Audio data
|
||||
@@ -93,14 +101,37 @@ static int play_s16(struct af_instance *af, struct mp_audio *data)
|
||||
|
||||
MP_VERBOSE(af, "f:%8.2f: amp:%8.2f\n", s->freq, sqrt(s->real*s->real + s->imag*s->imag) / s->ref);
|
||||
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct mp_audio* play_float(struct af_instance* af, struct mp_audio* data)
|
||||
{
|
||||
af_sinesuppress_t *s = af->setup;
|
||||
register int i = 0;
|
||||
float *a = (float*)data->audio; // Audio data
|
||||
int len = data->len/4; // Number of samples
|
||||
float avg, l, r;
|
||||
|
||||
for (i = 0; i < len; i+=2)
|
||||
{
|
||||
avg = (a[i] + a[i + 1]) / 2;
|
||||
|
||||
/* l = avg + (s->mul * (a[i] - avg));
|
||||
r = avg + (s->mul * (a[i + 1] - avg));*/
|
||||
|
||||
a[i] = af_softclip(l);
|
||||
a[i + 1] = af_softclip(r);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = play_s16;
|
||||
af->filter=play_s16;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
+3
-10
@@ -98,15 +98,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct mp_audio* c = data; // Current working data
|
||||
af_sub_t* s = af->priv; // Setup for this instance
|
||||
float* a = c->planes[0]; // Audio data
|
||||
@@ -123,14 +117,13 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
IIR(x , s->w[1], s->q[1], a[i+ch]);
|
||||
}
|
||||
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate memory and set function pointers
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
+12
-16
@@ -141,27 +141,21 @@ static const float steering_matrix[][12] = {
|
||||
// Experimental moving average dominance
|
||||
//static int amp_L = 0, amp_R = 0, amp_C = 0, amp_S = 0;
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
struct mp_audio *outframe =
|
||||
mp_audio_pool_get(af->out_pool, &af->fmt_out, data->samples);
|
||||
if (!outframe) {
|
||||
talloc_free(data);
|
||||
return -1;
|
||||
}
|
||||
mp_audio_copy_attributes(outframe, data);
|
||||
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int flags){
|
||||
af_surround_t* s = (af_surround_t*)af->priv;
|
||||
const float* m = steering_matrix[0];
|
||||
float* in = data->planes[0]; // Input audio data
|
||||
float* out = outframe->planes[0]; // Output audio data
|
||||
float* out = NULL; // Output audio data
|
||||
float* end = in + data->samples * data->nch;
|
||||
int i = s->i; // Filter queue index
|
||||
int ri = s->ri; // Read index for delay queue
|
||||
int wi = s->wi; // Write index for delay queue
|
||||
|
||||
mp_audio_realloc_min(af->data, data->samples);
|
||||
|
||||
out = af->data->planes[0];
|
||||
|
||||
while(in < end){
|
||||
/* Dominance:
|
||||
abs(in[0]) abs(in[1]);
|
||||
@@ -221,14 +215,16 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
// Save indexes
|
||||
s->i = i; s->ri = ri; s->wi = wi;
|
||||
|
||||
talloc_free(data);
|
||||
af_add_output_frame(af, outframe);
|
||||
// Set output data
|
||||
data->planes[0] = af->data->planes[0];
|
||||
mp_audio_set_channels_old(data, af->data->nch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
+3
-10
@@ -48,15 +48,9 @@ static int control(struct af_instance* af, int cmd, void* arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
// Filter data through filter
|
||||
static int filter(struct af_instance* af, struct mp_audio* data, int f)
|
||||
{
|
||||
if (!data)
|
||||
return 0;
|
||||
if (af_make_writeable(af, data) < 0) {
|
||||
talloc_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
af_sweept *s = af->priv;
|
||||
int i, j;
|
||||
int16_t *in = (int16_t*)data->planes[0];
|
||||
@@ -70,13 +64,12 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
||||
if(2*s->x*s->delta >= 3.141592) s->x=0;
|
||||
}
|
||||
|
||||
af_add_output_frame(af, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af_open(struct af_instance* af){
|
||||
af->control=control;
|
||||
af->filter_frame = filter_frame;
|
||||
af->filter=filter;
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,30 +97,25 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
return AF_UNKNOWN;
|
||||
}
|
||||
|
||||
static void filter_plane(struct af_instance *af, struct mp_audio *data, int p)
|
||||
static void filter_plane(struct af_instance *af, void *ptr, int num_samples)
|
||||
{
|
||||
struct priv *s = af->priv;
|
||||
|
||||
float level = s->level * s->rgain;
|
||||
int num_samples = data->samples * data->spf;
|
||||
|
||||
if (af_fmt_from_planar(af->data->format) == AF_FORMAT_S16) {
|
||||
int16_t *a = ptr;
|
||||
int vol = 256.0 * level;
|
||||
if (vol != 256) {
|
||||
if (af_make_writeable(af, data) < 0)
|
||||
return; // oom
|
||||
int16_t *a = data->planes[p];
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
int x = (a[i] * vol) >> 8;
|
||||
a[i] = MPCLAMP(x, SHRT_MIN, SHRT_MAX);
|
||||
}
|
||||
}
|
||||
} else if (af_fmt_from_planar(af->data->format) == AF_FORMAT_FLOAT) {
|
||||
float *a = ptr;
|
||||
float vol = level;
|
||||
if (vol != 1.0) {
|
||||
if (af_make_writeable(af, data) < 0)
|
||||
return; // oom
|
||||
float *a = data->planes[p];
|
||||
for (int i = 0; i < num_samples; i++) {
|
||||
float x = a[i] * vol;
|
||||
a[i] = s->soft ? af_softclip(x) : MPCLAMP(x, -1.0, 1.0);
|
||||
@@ -129,13 +124,11 @@ static void filter_plane(struct af_instance *af, struct mp_audio *data, int p)
|
||||
}
|
||||
}
|
||||
|
||||
static int filter(struct af_instance *af, struct mp_audio *data)
|
||||
static int filter(struct af_instance *af, struct mp_audio *data, int f)
|
||||
{
|
||||
if (data) {
|
||||
for (int n = 0; n < data->num_planes; n++)
|
||||
filter_plane(af, data, n);
|
||||
af_add_output_frame(af, data);
|
||||
}
|
||||
for (int n = 0; n < data->num_planes; n++)
|
||||
filter_plane(af, data->planes[n], data->samples * data->spf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -143,7 +136,7 @@ static int af_open(struct af_instance *af)
|
||||
{
|
||||
struct priv *s = af->priv;
|
||||
af->control = control;
|
||||
af->filter_frame = filter;
|
||||
af->filter = filter;
|
||||
af_from_dB(1, &s->cfg_volume, &s->level, 20.0, -200.0, 60.0);
|
||||
return AF_OK;
|
||||
}
|
||||
|
||||
+93
-82
@@ -50,6 +50,7 @@ extern const struct ao_driver audio_out_dsound;
|
||||
extern const struct ao_driver audio_out_wasapi;
|
||||
extern const struct ao_driver audio_out_pcm;
|
||||
extern const struct ao_driver audio_out_lavc;
|
||||
extern const struct ao_driver audio_out_portaudio;
|
||||
extern const struct ao_driver audio_out_sdl;
|
||||
|
||||
static const struct ao_driver * const audio_out_drivers[] = {
|
||||
@@ -71,6 +72,9 @@ static const struct ao_driver * const audio_out_drivers[] = {
|
||||
#endif
|
||||
#if HAVE_OSS_AUDIO
|
||||
&audio_out_oss,
|
||||
#endif
|
||||
#if HAVE_PORTAUDIO
|
||||
&audio_out_portaudio,
|
||||
#endif
|
||||
// wrappers:
|
||||
#if HAVE_JACK
|
||||
@@ -86,6 +90,7 @@ static const struct ao_driver * const audio_out_drivers[] = {
|
||||
&audio_out_sndio,
|
||||
#endif
|
||||
&audio_out_null,
|
||||
// should not be auto-selected:
|
||||
#if HAVE_COREAUDIO
|
||||
&audio_out_coreaudio_exclusive,
|
||||
#endif
|
||||
@@ -124,6 +129,30 @@ const struct m_obj_list ao_obj_list = {
|
||||
.allow_trailer = true,
|
||||
};
|
||||
|
||||
// Return true if the ao with the given name matches the opt (--audio-device
|
||||
// contents). If opt is empty, matching always succeeds. If out_device is not
|
||||
// NULL, it will be set to the implied audio device (or NULL).
|
||||
static bool match_ao_driver(const char *ao_name, char *opt, char **out_device)
|
||||
{
|
||||
bstr ao_nameb = bstr0(ao_name);
|
||||
bstr optb = bstr0(opt);
|
||||
|
||||
char *dummy;
|
||||
if (!out_device)
|
||||
out_device = &dummy;
|
||||
*out_device = NULL;
|
||||
|
||||
if (!optb.len || bstr_equals0(optb, "auto"))
|
||||
return true;
|
||||
if (!bstr_startswith(optb, ao_nameb))
|
||||
return false;
|
||||
if (optb.len > ao_nameb.len && optb.start[ao_nameb.len] != '/')
|
||||
return false;
|
||||
char *split = strchr(opt, '/');
|
||||
*out_device = split ? split + 1 : NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx, char *name, char **args)
|
||||
{
|
||||
@@ -143,7 +172,6 @@ static struct ao *ao_alloc(bool probing, struct mpv_global *global,
|
||||
.input_ctx = input_ctx,
|
||||
.log = mp_log_new(ao, log, name),
|
||||
.def_buffer = opts->audio_buffer,
|
||||
.client_name = talloc_strdup(ao, opts->audio_client_name),
|
||||
};
|
||||
struct m_config *config = m_config_from_obj_desc(ao, ao->log, &desc);
|
||||
if (m_config_apply_defaults(config, name, opts->ao_defs) < 0)
|
||||
@@ -157,12 +185,13 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *dev, char *name, char **args)
|
||||
static struct ao *ao_alloc_pb(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *name, char **args)
|
||||
{
|
||||
struct MPOpts *opts = global->opts;
|
||||
struct ao *ao = ao_alloc(probing, global, input_ctx, name, args);
|
||||
if (!ao)
|
||||
return NULL;
|
||||
@@ -170,32 +199,32 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
ao->channels = channels;
|
||||
ao->format = format;
|
||||
ao->encode_lavc_ctx = encode_lavc_ctx;
|
||||
if (ao->driver->encode != !!ao->encode_lavc_ctx)
|
||||
goto fail;
|
||||
if (ao->driver->encode != !!ao->encode_lavc_ctx) {
|
||||
talloc_free(ao);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
match_ao_driver(ao->driver->name, opts->audio_device, &ao->device);
|
||||
ao->device = talloc_strdup(ao, ao->device);
|
||||
|
||||
ao->client_name = talloc_strdup(ao, opts->audio_client_name);
|
||||
|
||||
return ao;
|
||||
}
|
||||
|
||||
static int ao_init(struct ao *ao)
|
||||
{
|
||||
MP_VERBOSE(ao, "requested format: %d Hz, %s channels, %s\n",
|
||||
ao->samplerate, mp_chmap_to_str(&ao->channels),
|
||||
af_fmt_to_str(ao->format));
|
||||
|
||||
ao->device = talloc_strdup(ao, dev);
|
||||
|
||||
ao->api = ao->driver->play ? &ao_api_push : &ao_api_pull;
|
||||
ao->api_priv = talloc_zero_size(ao, ao->api->priv_size);
|
||||
assert(!ao->api->priv_defaults && !ao->api->options);
|
||||
|
||||
int r = ao->driver->init(ao);
|
||||
if (r < 0) {
|
||||
// Silly exception for coreaudio spdif redirection
|
||||
if (ao->redirect) {
|
||||
char redirect[80], rdevice[80];
|
||||
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
|
||||
snprintf(rdevice, sizeof(rdevice), "%s", ao->device ? ao->device : "");
|
||||
talloc_free(ao);
|
||||
return ao_init(probing, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, rdevice, redirect, args);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ao->sstride = af_fmt2bps(ao->format);
|
||||
ao->num_planes = 1;
|
||||
@@ -213,28 +242,35 @@ static struct ao *ao_init(bool probing, struct mpv_global *global,
|
||||
ao->buffer = MPMAX(ao->device_buffer, ao->def_buffer * ao->samplerate);
|
||||
MP_VERBOSE(ao, "using soft-buffer of %d samples.\n", ao->buffer);
|
||||
|
||||
if (ao->api->init(ao) < 0)
|
||||
goto fail;
|
||||
return ao;
|
||||
|
||||
fail:
|
||||
talloc_free(ao);
|
||||
return NULL;
|
||||
return ao->api->init(ao);
|
||||
}
|
||||
|
||||
static void split_ao_device(void *tmp, char *opt, char **out_ao, char **out_dev)
|
||||
static struct ao *ao_create(bool probing, struct mpv_global *global,
|
||||
struct input_ctx *input_ctx,
|
||||
struct encode_lavc_context *encode_lavc_ctx,
|
||||
int samplerate, int format, struct mp_chmap channels,
|
||||
char *name, char **args)
|
||||
{
|
||||
*out_ao = NULL;
|
||||
*out_dev = NULL;
|
||||
if (!opt)
|
||||
return;
|
||||
if (!opt[0] || strcmp(opt, "auto") == 0)
|
||||
return;
|
||||
// Split on "/". If there's no "/", leave out_device NULL.
|
||||
bstr b_dev, b_ao;
|
||||
if (bstr_split_tok(bstr0(opt), "/", &b_ao, &b_dev))
|
||||
*out_dev = bstrto0(tmp, b_dev);
|
||||
*out_ao = bstrto0(tmp, b_ao);
|
||||
struct ao *ao = ao_alloc_pb(probing, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, name, args);
|
||||
if (ao && ao_init(ao) >= 0)
|
||||
return ao;
|
||||
// Silly exception for coreaudio spdif redirection
|
||||
if (ao && ao->redirect) {
|
||||
char redirect[80], device[80];
|
||||
snprintf(redirect, sizeof(redirect), "%s", ao->redirect);
|
||||
snprintf(device, sizeof(device), "%s", ao->device ? ao->device : "");
|
||||
talloc_free(ao);
|
||||
ao = ao_alloc_pb(probing, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, redirect, args);
|
||||
if (ao) {
|
||||
ao->device = talloc_strdup(ao, device);
|
||||
if (ao_init(ao) >= 0)
|
||||
return ao;
|
||||
}
|
||||
}
|
||||
talloc_free(ao);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ao *ao_init_best(struct mpv_global *global,
|
||||
@@ -243,62 +279,42 @@ struct ao *ao_init_best(struct mpv_global *global,
|
||||
int samplerate, int format, struct mp_chmap channels)
|
||||
{
|
||||
struct MPOpts *opts = global->opts;
|
||||
void *tmp = talloc_new(NULL);
|
||||
struct mp_log *log = mp_log_new(tmp, global->log, "ao");
|
||||
struct mp_log *log = mp_log_new(NULL, global->log, "ao");
|
||||
struct ao *ao = NULL;
|
||||
struct m_obj_settings *ao_list = opts->audio_driver_list;
|
||||
|
||||
bool forced_dev = false;
|
||||
char *pref_ao, *pref_dev;
|
||||
split_ao_device(tmp, opts->audio_device, &pref_ao, &pref_dev);
|
||||
if (!(ao_list && ao_list[0].name) && pref_ao) {
|
||||
// Reuse the autoselection code
|
||||
ao_list = talloc_zero_array(tmp, struct m_obj_settings, 2);
|
||||
ao_list[0].name = pref_ao;
|
||||
forced_dev = true;
|
||||
}
|
||||
|
||||
if (ao_list && ao_list[0].name) {
|
||||
for (int n = 0; ao_list[n].name; n++) {
|
||||
if (strlen(ao_list[n].name) == 0)
|
||||
goto autoprobe;
|
||||
mp_verbose(log, "Trying preferred audio driver '%s'\n",
|
||||
ao_list[n].name);
|
||||
char *dev = NULL;
|
||||
if (pref_ao && strcmp(ao_list[n].name, pref_ao) == 0)
|
||||
dev = pref_dev;
|
||||
if (dev)
|
||||
mp_verbose(log, "Using preferred device '%s'\n", dev);
|
||||
ao = ao_init(false, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, dev,
|
||||
ao_list[n].name, ao_list[n].attribs);
|
||||
ao = ao_create(false, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels,
|
||||
ao_list[n].name, ao_list[n].attribs);
|
||||
if (ao)
|
||||
goto done;
|
||||
mp_err(log, "Failed to initialize audio driver '%s'\n",
|
||||
ao_list[n].name);
|
||||
if (forced_dev) {
|
||||
mp_err(log, "This audio driver/device was forced with the "
|
||||
"--audio-device option.\n"
|
||||
"Try unsetting it.\n");
|
||||
}
|
||||
mp_warn(log, "Failed to initialize audio driver '%s'\n",
|
||||
ao_list[n].name);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
autoprobe: ;
|
||||
// now try the rest...
|
||||
bool matched_dev = false;
|
||||
for (int i = 0; audio_out_drivers[i]; i++) {
|
||||
const struct ao_driver *driver = audio_out_drivers[i];
|
||||
if (driver == &audio_out_null)
|
||||
break;
|
||||
ao = ao_init(true, global, input_ctx, encode_lavc_ctx, samplerate,
|
||||
format, channels, NULL, (char *)driver->name, NULL);
|
||||
char *name = (char *)audio_out_drivers[i]->name;
|
||||
if (!match_ao_driver(name, opts->audio_device, NULL))
|
||||
continue;
|
||||
matched_dev = true;
|
||||
ao = ao_create(true, global, input_ctx, encode_lavc_ctx,
|
||||
samplerate, format, channels, name, NULL);
|
||||
if (ao)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!matched_dev)
|
||||
mp_err(log, "--audio-device option refers to missing output driver.\n");
|
||||
done:
|
||||
talloc_free(tmp);
|
||||
talloc_free(log);
|
||||
return ao;
|
||||
}
|
||||
|
||||
@@ -439,11 +455,6 @@ bool ao_untimed(struct ao *ao)
|
||||
return ao->untimed;
|
||||
}
|
||||
|
||||
const char *ao_get_detected_device(struct ao *ao)
|
||||
{
|
||||
return ao->detected_device;
|
||||
}
|
||||
|
||||
struct ao_device_list *ao_get_device_list(struct mpv_global *global)
|
||||
{
|
||||
struct ao_device_list *list = talloc_zero(NULL, struct ao_device_list);
|
||||
|
||||
@@ -79,7 +79,6 @@ void ao_uninit(struct ao *ao);
|
||||
void ao_get_format(struct ao *ao, struct mp_audio *format);
|
||||
const char *ao_get_name(struct ao *ao);
|
||||
const char *ao_get_description(struct ao *ao);
|
||||
const char *ao_get_detected_device(struct ao *ao);
|
||||
bool ao_untimed(struct ao *ao);
|
||||
int ao_play(struct ao *ao, void **data, int samples, int flags);
|
||||
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg);
|
||||
|
||||
+77
-51
@@ -58,6 +58,7 @@ struct priv {
|
||||
int buffersize; // in frames
|
||||
int outburst; // in frames
|
||||
|
||||
int cfg_block;
|
||||
char *cfg_device;
|
||||
char *cfg_mixer_device;
|
||||
char *cfg_mixer_name;
|
||||
@@ -320,6 +321,47 @@ static bool query_chmaps(struct ao *ao, struct mp_chmap *chmap)
|
||||
|
||||
#endif /* else HAVE_CHMAP_API */
|
||||
|
||||
// Lists device names and their implied channel map.
|
||||
// The second item must be resolvable with mp_chmap_from_str().
|
||||
// Source: http://www.alsa-project.org/main/index.php/DeviceNames
|
||||
// (Speaker names are slightly different from mpv's.)
|
||||
static const char *const device_channel_layouts[][2] = {
|
||||
{"default", "fc"},
|
||||
{"default", "fl-fr"},
|
||||
{"rear", "bl-br"},
|
||||
{"center_lfe", "fc-lfe"},
|
||||
{"side", "sl-sr"},
|
||||
{"surround40", "fl-fr-bl-br"},
|
||||
{"surround50", "fl-fr-bl-br-fc"},
|
||||
{"surround41", "fl-fr-bl-br-lfe"},
|
||||
{"surround51", "fl-fr-bl-br-fc-lfe"},
|
||||
{"surround71", "fl-fr-bl-br-fc-lfe-sl-sr"},
|
||||
};
|
||||
|
||||
#define NUM_ALSA_CHMAPS MP_ARRAY_SIZE(device_channel_layouts)
|
||||
|
||||
static const char *select_chmap(struct ao *ao, struct mp_chmap *chmap)
|
||||
{
|
||||
struct mp_chmap_sel sel = {0};
|
||||
struct mp_chmap maps[NUM_ALSA_CHMAPS];
|
||||
for (int n = 0; n < NUM_ALSA_CHMAPS; n++) {
|
||||
mp_chmap_from_str(&maps[n], bstr0(device_channel_layouts[n][1]));
|
||||
mp_chmap_sel_add_map(&sel, &maps[n]);
|
||||
};
|
||||
|
||||
if (!ao_chmap_sel_adjust(ao, &sel, chmap))
|
||||
return "default";
|
||||
|
||||
for (int n = 0; n < NUM_ALSA_CHMAPS; n++) {
|
||||
if (mp_chmap_equals(chmap, &maps[n]))
|
||||
return device_channel_layouts[n][0];
|
||||
}
|
||||
|
||||
MP_ERR(ao, "channel layout %s (%d ch) not supported.\n",
|
||||
mp_chmap_to_str(chmap), chmap->num);
|
||||
return "default";
|
||||
}
|
||||
|
||||
static int map_iec958_srate(int srate)
|
||||
{
|
||||
switch (srate) {
|
||||
@@ -363,7 +405,7 @@ static char *append_params(void *ta_parent, const char *device, const char *p)
|
||||
abort();
|
||||
}
|
||||
|
||||
static int try_open_device(struct ao *ao, const char *device)
|
||||
static int try_open_device(struct ao *ao, const char *device, int open_mode)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
|
||||
@@ -376,13 +418,13 @@ static int try_open_device(struct ao *ao, const char *device)
|
||||
map_iec958_srate(ao->samplerate));
|
||||
const char *ac3_device = append_params(tmp, device, params);
|
||||
int err = snd_pcm_open
|
||||
(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, open_mode);
|
||||
talloc_free(tmp);
|
||||
if (!err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
return snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, open_mode);
|
||||
}
|
||||
|
||||
static void uninit(struct ao *ao)
|
||||
@@ -399,10 +441,7 @@ static void uninit(struct ao *ao)
|
||||
alsa_error: ;
|
||||
}
|
||||
|
||||
#define INIT_OK 0
|
||||
#define INIT_ERROR -1
|
||||
#define INIT_BRAINDEATH -2
|
||||
static int init_device(struct ao *ao)
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *p = ao->priv;
|
||||
int err;
|
||||
@@ -410,25 +449,47 @@ static int init_device(struct ao *ao)
|
||||
if (!p->cfg_ni)
|
||||
ao->format = af_fmt_from_planar(ao->format);
|
||||
|
||||
const char *device = "default";
|
||||
struct mp_chmap implied_chmap = ao->channels;
|
||||
const char *device;
|
||||
if (AF_FORMAT_IS_IEC61937(ao->format)) {
|
||||
device = "iec958";
|
||||
MP_VERBOSE(ao, "playing AC3/iec61937/iec958, %i channels\n",
|
||||
ao->channels.num);
|
||||
} else {
|
||||
device = select_chmap(ao, &implied_chmap);
|
||||
// Not-default likely means a hw device - enable software conversions.
|
||||
if (strcmp(device, "default") != 0)
|
||||
device = talloc_asprintf(ao, "plug:%s", device);
|
||||
}
|
||||
const char *old_dev = device;
|
||||
if (ao->device)
|
||||
device = ao->device;
|
||||
if (p->cfg_device && p->cfg_device[0])
|
||||
device = p->cfg_device;
|
||||
bool user_set_device = device != old_dev; // not strcmp()
|
||||
|
||||
MP_VERBOSE(ao, "using device: %s\n", device);
|
||||
MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version());
|
||||
|
||||
err = try_open_device(ao, device);
|
||||
CHECK_ALSA_ERROR("Playback open error");
|
||||
err = try_open_device(ao, device, p->cfg_block ? 0 : SND_PCM_NONBLOCK);
|
||||
if (err < 0) {
|
||||
if (err == -EBUSY && !user_set_device && strcmp(device, "default") != 0) {
|
||||
MP_WARN(ao, "Device '%s' busy, retrying default.\n", device);
|
||||
err = try_open_device(ao, "default", 0);
|
||||
} else if (err != -EBUSY && !p->cfg_block) {
|
||||
MP_WARN(ao, "Open in nonblock-mode "
|
||||
"failed, trying to open in block-mode.\n");
|
||||
err = try_open_device(ao, device, 0);
|
||||
}
|
||||
CHECK_ALSA_ERROR("Playback open error");
|
||||
}
|
||||
|
||||
err = snd_pcm_nonblock(p->alsa, 0);
|
||||
CHECK_ALSA_WARN("Unable to set blocking mode");
|
||||
if (err < 0) {
|
||||
MP_ERR(ao, "Error setting block-mode: %s.\n", snd_strerror(err));
|
||||
} else {
|
||||
MP_VERBOSE(ao, "pcm opened in blocking mode\n");
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_t *alsa_hwparams;
|
||||
snd_pcm_sw_params_t *alsa_swparams;
|
||||
@@ -483,9 +544,8 @@ static int init_device(struct ao *ao)
|
||||
} else if (query_chmaps(ao, &dev_chmap)) {
|
||||
ao->channels = dev_chmap;
|
||||
} else {
|
||||
// Assume only stereo and mono are supported.
|
||||
mp_chmap_from_channels(&ao->channels, MPMIN(2, dev_chmap.num));
|
||||
dev_chmap.num = 0;
|
||||
ao->channels = implied_chmap;
|
||||
}
|
||||
|
||||
int num_channels = ao->channels.num;
|
||||
@@ -583,34 +643,6 @@ static int init_device(struct ao *ao)
|
||||
MP_WARN(ao, "ALSA channel map conflicts with channel count!\n");
|
||||
}
|
||||
} else {
|
||||
// Is it one that contains NA channels?
|
||||
struct mp_chmap chmap2 = {0};
|
||||
for (int c = 0; c < alsa_chmap->channels; c++) {
|
||||
int alsa_ch = alsa_chmap->pos[c];
|
||||
if (alsa_ch != SND_CHMAP_NA)
|
||||
chmap2.speaker[chmap2.num++] = find_mp_channel(alsa_ch);
|
||||
}
|
||||
|
||||
if (mp_chmap_is_valid(&chmap2)) {
|
||||
// Sometimes, ALSA will advertise certain chmaps, but it's not
|
||||
// possible to set them. This can happen with dmix: as of
|
||||
// alsa 1.0.28, dmix can do stereo only, but advertises the
|
||||
// surround chmaps of the underlying device. In this case,
|
||||
// requesting e.g. 5.1 will fail, but it will still allow
|
||||
// setting 6 channels. Then it will return something like
|
||||
// "FL FR NA NA NA NA" as channel map. This means we would
|
||||
// have to pad stereo output to 6 channels with silence, which
|
||||
// is way too complicated in the general case. You can't change
|
||||
// the number of channels to 2 either, because the hw params
|
||||
// are already set! So just fuck it and reopen the device with
|
||||
// the chmap "cleaned out" of NA entries.
|
||||
err = snd_pcm_close(p->alsa);
|
||||
p->alsa = NULL;
|
||||
CHECK_ALSA_ERROR("pcm close error");
|
||||
ao->channels = chmap2;
|
||||
return INIT_BRAINDEATH;
|
||||
}
|
||||
|
||||
MP_WARN(ao, "Got unknown channel map from ALSA.\n");
|
||||
}
|
||||
|
||||
@@ -666,19 +698,11 @@ static int init_device(struct ao *ao)
|
||||
|
||||
p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
|
||||
|
||||
return INIT_OK;
|
||||
return 0;
|
||||
|
||||
alsa_error:
|
||||
uninit(ao);
|
||||
return INIT_ERROR;
|
||||
}
|
||||
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
int r = init_device(ao);
|
||||
if (r == INIT_BRAINDEATH)
|
||||
r = init_device(ao); // retry with normalized channel layout
|
||||
return r == INIT_OK ? 0 : -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void drain(struct ao *ao)
|
||||
@@ -922,6 +946,7 @@ const struct ao_driver audio_out_alsa = {
|
||||
.list_devs = list_devs,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.priv_defaults = &(const struct priv) {
|
||||
.cfg_block = 1,
|
||||
.cfg_mixer_device = "default",
|
||||
.cfg_mixer_name = "Master",
|
||||
.cfg_mixer_index = 0,
|
||||
@@ -930,6 +955,7 @@ const struct ao_driver audio_out_alsa = {
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("device", cfg_device, 0),
|
||||
OPT_FLAG("resample", cfg_resample, 0),
|
||||
OPT_FLAG("block", cfg_block, 0),
|
||||
OPT_STRING("mixer-device", cfg_mixer_device, 0),
|
||||
OPT_STRING("mixer-name", cfg_mixer_name, 0),
|
||||
OPT_INTRANGE("mixer-index", cfg_mixer_index, 0, 0, 99),
|
||||
|
||||
@@ -156,11 +156,6 @@ static int init(struct ao *ao)
|
||||
OSStatus err = ca_select_device(ao, ao->device, &p->device);
|
||||
CHECK_CA_ERROR("failed to select device");
|
||||
|
||||
char *uid;
|
||||
err = CA_GET_STR(p->device, kAudioDevicePropertyDeviceUID, &uid);
|
||||
CHECK_CA_ERROR("failed to get device UID");
|
||||
ao->detected_device = talloc_steal(ao, uid);
|
||||
|
||||
if (!init_chmap(ao))
|
||||
goto coreaudio_error;
|
||||
|
||||
|
||||
@@ -83,7 +83,12 @@ OSStatus ca_get_str(AudioObjectID id, ca_scope scope, ca_sel selector,
|
||||
ca_get(id, scope, selector, sizeof(CFStringRef), (void **)&string);
|
||||
CHECK_CA_ERROR_SILENT_L(coreaudio_error);
|
||||
|
||||
*data = cfstr_get_cstr(string);
|
||||
CFIndex size =
|
||||
CFStringGetMaximumSizeForEncoding(
|
||||
CFStringGetLength(string), CA_CFSTR_ENCODING) + 1;
|
||||
|
||||
*data = talloc_zero_size(NULL, size);
|
||||
CFStringGetCString(string, *data, size, CA_CFSTR_ENCODING);
|
||||
CFRelease(string);
|
||||
coreaudio_error:
|
||||
return err;
|
||||
|
||||
@@ -28,21 +28,6 @@
|
||||
#include "osdep/endian.h"
|
||||
#include "audio/format.h"
|
||||
|
||||
CFStringRef cfstr_from_cstr(char *str)
|
||||
{
|
||||
return CFStringCreateWithCString(NULL, str, CA_CFSTR_ENCODING);
|
||||
}
|
||||
|
||||
char *cfstr_get_cstr(CFStringRef cfstr)
|
||||
{
|
||||
CFIndex size =
|
||||
CFStringGetMaximumSizeForEncoding(
|
||||
CFStringGetLength(cfstr), CA_CFSTR_ENCODING) + 1;
|
||||
char *buffer = talloc_zero_size(NULL, size);
|
||||
CFStringGetCString(cfstr, buffer, size, CA_CFSTR_ENCODING);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static bool ca_is_output_device(struct ao *ao, AudioDeviceID dev)
|
||||
{
|
||||
size_t n_buffers;
|
||||
@@ -64,17 +49,13 @@ void ca_get_device_list(struct ao *ao, struct ao_device_list *list)
|
||||
for (int i = 0; i < n_devs; i++) {
|
||||
if (!ca_is_output_device(ao, devs[i]))
|
||||
continue;
|
||||
void *ta_ctx = talloc_new(NULL);
|
||||
char *name;
|
||||
char name[32];
|
||||
char *desc;
|
||||
err = CA_GET_STR(devs[i], kAudioDevicePropertyDeviceUID, &name);
|
||||
talloc_steal(ta_ctx, name);
|
||||
sprintf(name, "%d", devs[i]);
|
||||
err = CA_GET_STR(devs[i], kAudioObjectPropertyName, &desc);
|
||||
talloc_steal(ta_ctx, desc);
|
||||
if (err != noErr)
|
||||
desc = "Unknown";
|
||||
ao_device_list_add(list, ao, &(struct ao_device_desc){name, desc});
|
||||
talloc_free(ta_ctx);
|
||||
}
|
||||
talloc_free(devs);
|
||||
coreaudio_error:
|
||||
@@ -84,32 +65,21 @@ coreaudio_error:
|
||||
OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
|
||||
{
|
||||
OSStatus err = noErr;
|
||||
*device = kAudioObjectUnknown;
|
||||
|
||||
if (name) {
|
||||
CFStringRef uid = cfstr_from_cstr(name);
|
||||
AudioValueTranslation v = (AudioValueTranslation) {
|
||||
.mInputData = &uid,
|
||||
.mInputDataSize = sizeof(CFStringRef),
|
||||
.mOutputData = device,
|
||||
.mOutputDataSize = sizeof(*device),
|
||||
};
|
||||
uint32_t size = sizeof(AudioValueTranslation);
|
||||
AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) {
|
||||
.mSelector = kAudioHardwarePropertyDeviceForUID,
|
||||
.mScope = kAudioObjectPropertyScopeGlobal,
|
||||
.mElement = kAudioObjectPropertyElementMaster,
|
||||
};
|
||||
err = AudioObjectGetPropertyData(
|
||||
kAudioObjectSystemObject, &p_addr, 0, 0, &size, &v);
|
||||
CFRelease(uid);
|
||||
CHECK_CA_ERROR("unable to query for device UID");
|
||||
} else {
|
||||
errno = 0;
|
||||
int selection = name && name[0] ? strtol(name, (char **)NULL, 10) : -1;
|
||||
if (errno == EINVAL || errno == ERANGE) {
|
||||
selection = -1;
|
||||
MP_WARN(ao, "device identifier '%s' is invalid\n", name);
|
||||
}
|
||||
*device = 0;
|
||||
if (selection < 0) {
|
||||
// device not set by user, get the default one
|
||||
err = CA_GET(kAudioObjectSystemObject,
|
||||
kAudioHardwarePropertyDefaultOutputDevice,
|
||||
device);
|
||||
CHECK_CA_ERROR("could not get default audio device");
|
||||
} else {
|
||||
*device = selection;
|
||||
}
|
||||
|
||||
if (mp_msg_test(ao->log, MSGL_V)) {
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
|
||||
#define CA_CFSTR_ENCODING kCFStringEncodingASCII
|
||||
|
||||
CFStringRef cfstr_from_cstr(char *str);
|
||||
char *cfstr_get_cstr(CFStringRef cfstr);
|
||||
|
||||
char *fourcc_repr(void *talloc_ctx, uint32_t code);
|
||||
bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message);
|
||||
|
||||
|
||||
+1
-12
@@ -25,7 +25,6 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "talloc.h"
|
||||
|
||||
@@ -51,7 +50,6 @@ struct priv {
|
||||
float latency_sec; // seconds
|
||||
float latency; // samples
|
||||
int broken_eof;
|
||||
int broken_delay;
|
||||
|
||||
// Minimal unit of audio samples that can be written at once. If play() is
|
||||
// called with sizes not aligned to this, a rounded size will be returned.
|
||||
@@ -193,15 +191,7 @@ static double get_delay(struct ao *ao)
|
||||
if (priv->broken_eof && priv->buffered < priv->latency)
|
||||
delay = priv->latency;
|
||||
|
||||
delay /= ao->samplerate;
|
||||
|
||||
if (priv->broken_delay) { // Report only multiples of outburst
|
||||
double q = priv->outburst / (double)ao->samplerate;
|
||||
if (delay > 0)
|
||||
delay = (int)(delay / q) * q;
|
||||
}
|
||||
|
||||
return delay;
|
||||
return delay / (double)ao->samplerate;
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
@@ -231,7 +221,6 @@ const struct ao_driver audio_out_null = {
|
||||
OPT_FLOATRANGE("speed", speed, 0, 0, 10000),
|
||||
OPT_FLOATRANGE("latency", latency_sec, 0, 0, 100),
|
||||
OPT_FLAG("broken-eof", broken_eof, 0),
|
||||
OPT_FLAG("broken-delay", broken_delay, 0),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
+1
-3
@@ -46,7 +46,6 @@
|
||||
struct priv {
|
||||
char *outputfilename;
|
||||
int waveheader;
|
||||
int append;
|
||||
uint64_t data_length;
|
||||
FILE *fp;
|
||||
};
|
||||
@@ -156,7 +155,7 @@ static int init(struct ao *ao)
|
||||
MP_INFO(ao, "Info: Faster dumping is achieved with --no-video\n");
|
||||
MP_INFO(ao, "Info: To write WAVE files use --ao=pcm:waveheader (default).\n");
|
||||
|
||||
priv->fp = fopen(priv->outputfilename, priv->append ? "ab" : "wb");
|
||||
priv->fp = fopen(priv->outputfilename, "wb");
|
||||
if (!priv->fp) {
|
||||
MP_ERR(ao, "Failed to open %s for writing!\n", priv->outputfilename);
|
||||
return -1;
|
||||
@@ -224,7 +223,6 @@ const struct ao_driver audio_out_pcm = {
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING("file", outputfilename, 0),
|
||||
OPT_FLAG("waveheader", waveheader, 0),
|
||||
OPT_FLAG("append", append, 0),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* This file is part of mplayer2.
|
||||
*
|
||||
* mplayer2 is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* mplayer2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mplayer2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include <portaudio.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "options/m_option.h"
|
||||
#include "audio/format.h"
|
||||
#include "common/msg.h"
|
||||
#include "osdep/timer.h"
|
||||
#include "ao.h"
|
||||
#include "internal.h"
|
||||
|
||||
struct priv {
|
||||
PaStream *stream;
|
||||
|
||||
// Options
|
||||
char *cfg_device;
|
||||
};
|
||||
|
||||
struct format_map {
|
||||
int mp_format;
|
||||
PaSampleFormat pa_format;
|
||||
};
|
||||
|
||||
static const struct format_map format_maps[] = {
|
||||
// first entry is the default format
|
||||
{AF_FORMAT_S16, paInt16},
|
||||
{AF_FORMAT_S24, paInt24},
|
||||
{AF_FORMAT_S32, paInt32},
|
||||
{AF_FORMAT_S8, paInt8},
|
||||
{AF_FORMAT_U8, paUInt8},
|
||||
{AF_FORMAT_FLOAT, paFloat32},
|
||||
{AF_FORMAT_UNKNOWN, 0}
|
||||
};
|
||||
|
||||
static bool check_pa_ret(struct mp_log *log, int ret)
|
||||
{
|
||||
if (ret < 0) {
|
||||
mp_err(log, "%s\n", Pa_GetErrorText(ret));
|
||||
if (ret == paUnanticipatedHostError) {
|
||||
const PaHostErrorInfo* hosterr = Pa_GetLastHostErrorInfo();
|
||||
mp_err(log, "Host error: %s\n", hosterr->errorText);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CHECK_PA_RET(ret) check_pa_ret(ao->log, (ret))
|
||||
|
||||
static int to_int(const char *s, int return_on_error)
|
||||
{
|
||||
char *endptr;
|
||||
int res = strtol(s, &endptr, 10);
|
||||
return (s[0] && !endptr[0]) ? res : return_on_error;
|
||||
}
|
||||
|
||||
static int find_device(struct mp_log *log, const char *name)
|
||||
{
|
||||
int found = paNoDevice;
|
||||
if (!name)
|
||||
return found;
|
||||
int help = strcmp(name, "help") == 0;
|
||||
int count = Pa_GetDeviceCount();
|
||||
check_pa_ret(log, count);
|
||||
int index = to_int(name, -1);
|
||||
if (help)
|
||||
mp_info(log, "PortAudio devices:\n");
|
||||
for (int n = 0; n < count; n++) {
|
||||
const PaDeviceInfo* info = Pa_GetDeviceInfo(n);
|
||||
if (help) {
|
||||
if (info->maxOutputChannels < 1)
|
||||
continue;
|
||||
mp_info(log, " %d '%s', %d channels, latency: %.2f "
|
||||
"ms, sample rate: %.0f\n", n, info->name,
|
||||
info->maxOutputChannels,
|
||||
info->defaultHighOutputLatency * 1000,
|
||||
info->defaultSampleRate);
|
||||
}
|
||||
if (strcmp(name, info->name) == 0 || n == index) {
|
||||
found = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == paNoDevice && !help)
|
||||
mp_warn(log, "Device '%s' not found!\n", name);
|
||||
return found;
|
||||
}
|
||||
|
||||
static int validate_device_opt(struct mp_log *log, const m_option_t *opt,
|
||||
struct bstr name, struct bstr param)
|
||||
{
|
||||
// Note: we do not check whether the device actually exist, because this
|
||||
// might break elaborate configs with several AOs trying several
|
||||
// devices. We do it merely for making "help" special.
|
||||
if (bstr_equals0(param, "help")) {
|
||||
if (!check_pa_ret(log, Pa_Initialize()))
|
||||
return M_OPT_EXIT;
|
||||
find_device(log, "help");
|
||||
Pa_Terminate();
|
||||
return M_OPT_EXIT - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void list_devs(struct ao *ao, struct ao_device_list *list)
|
||||
{
|
||||
if (Pa_Initialize() < 0)
|
||||
return;
|
||||
int count = Pa_GetDeviceCount(); // negative on error
|
||||
for (int n = 0; n < count; n++) {
|
||||
const PaDeviceInfo* info = Pa_GetDeviceInfo(n);
|
||||
char desc[1024];
|
||||
snprintf(desc, sizeof(desc), "%s, %d channels, latency: %.2f "
|
||||
"ms, sample rate: %.0f", info->name,
|
||||
info->maxOutputChannels,
|
||||
info->defaultHighOutputLatency * 1000,
|
||||
info->defaultSampleRate);
|
||||
ao_device_list_add(list, ao, &(struct ao_device_desc){info->name, desc});
|
||||
}
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
static int stream_callback(const void *input,
|
||||
void *output_v,
|
||||
unsigned long frameCount,
|
||||
const PaStreamCallbackTimeInfo *timeInfo,
|
||||
PaStreamCallbackFlags statusFlags,
|
||||
void *userData)
|
||||
{
|
||||
struct ao *ao = userData;
|
||||
|
||||
// NOTE: PA + ALSA in dmix mode seems to pretend that there is no latency
|
||||
// (outputBufferDacTime == currentTime)
|
||||
double play_time = timeInfo->outputBufferDacTime
|
||||
+ frameCount / (float)ao->samplerate;
|
||||
double latency = play_time - timeInfo->currentTime;
|
||||
int64_t end = mp_time_us() + MPMAX(0, latency * 1000000.0);
|
||||
|
||||
ao_read_data(ao, &output_v, frameCount, end);
|
||||
|
||||
return paContinue;
|
||||
}
|
||||
|
||||
static void uninit(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (priv->stream) {
|
||||
if (Pa_IsStreamActive(priv->stream) == 1)
|
||||
CHECK_PA_RET(Pa_StopStream(priv->stream));
|
||||
CHECK_PA_RET(Pa_CloseStream(priv->stream));
|
||||
}
|
||||
|
||||
Pa_Terminate();
|
||||
}
|
||||
|
||||
static int init(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (!CHECK_PA_RET(Pa_Initialize()))
|
||||
return -1;
|
||||
|
||||
int pa_device = Pa_GetDefaultOutputDevice();
|
||||
char *dev_name = priv->cfg_device;
|
||||
if (!dev_name || !dev_name[0])
|
||||
dev_name = ao->device;
|
||||
if (dev_name && dev_name[0])
|
||||
pa_device = find_device(ao->log, dev_name);
|
||||
if (pa_device == paNoDevice)
|
||||
goto error_exit;
|
||||
|
||||
// The actual channel order probably depends on the platform.
|
||||
struct mp_chmap_sel sel = {0};
|
||||
mp_chmap_sel_add_waveext_def(&sel);
|
||||
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
|
||||
goto error_exit;
|
||||
|
||||
PaStreamParameters sp = {
|
||||
.device = pa_device,
|
||||
.channelCount = ao->channels.num,
|
||||
.suggestedLatency
|
||||
= Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency,
|
||||
};
|
||||
|
||||
ao->format = af_fmt_from_planar(ao->format);
|
||||
|
||||
const struct format_map *fmt = format_maps;
|
||||
while (fmt->pa_format) {
|
||||
if (fmt->mp_format == ao->format) {
|
||||
PaStreamParameters test = sp;
|
||||
test.sampleFormat = fmt->pa_format;
|
||||
if (Pa_IsFormatSupported(NULL, &test, ao->samplerate) == paNoError)
|
||||
break;
|
||||
}
|
||||
fmt++;
|
||||
}
|
||||
if (!fmt->pa_format) {
|
||||
MP_VERBOSE(ao, "Unsupported format, using default.\n");
|
||||
fmt = format_maps;
|
||||
}
|
||||
|
||||
ao->format = fmt->mp_format;
|
||||
sp.sampleFormat = fmt->pa_format;
|
||||
int framelen = ao->channels.num * af_fmt2bps(ao->format);
|
||||
ao->bps = ao->samplerate * framelen;
|
||||
|
||||
if (!CHECK_PA_RET(Pa_IsFormatSupported(NULL, &sp, ao->samplerate)))
|
||||
goto error_exit;
|
||||
if (!CHECK_PA_RET(Pa_OpenStream(&priv->stream, NULL, &sp, ao->samplerate,
|
||||
paFramesPerBufferUnspecified, paNoFlag,
|
||||
stream_callback, ao)))
|
||||
goto error_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
error_exit:
|
||||
uninit(ao);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void reset(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (Pa_IsStreamStopped(priv->stream) != 1)
|
||||
CHECK_PA_RET(Pa_AbortStream(priv->stream));
|
||||
}
|
||||
|
||||
static void resume(struct ao *ao)
|
||||
{
|
||||
struct priv *priv = ao->priv;
|
||||
|
||||
if (Pa_IsStreamStopped(priv->stream) == 1)
|
||||
CHECK_PA_RET(Pa_StartStream(priv->stream));
|
||||
}
|
||||
|
||||
#define OPT_BASE_STRUCT struct priv
|
||||
|
||||
const struct ao_driver audio_out_portaudio = {
|
||||
.description = "PortAudio",
|
||||
.name = "portaudio",
|
||||
.init = init,
|
||||
.uninit = uninit,
|
||||
.reset = reset,
|
||||
.resume = resume,
|
||||
.list_devs = list_devs,
|
||||
.priv_size = sizeof(struct priv),
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_STRING_VALIDATE("device", cfg_device, 0, validate_device_opt),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
+20
-68
@@ -113,58 +113,6 @@ exit_label:
|
||||
return;
|
||||
}
|
||||
|
||||
static void thread_resume(struct ao *ao)
|
||||
{
|
||||
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
|
||||
HRESULT hr;
|
||||
|
||||
MP_DBG(state, "Thread Resume\n");
|
||||
UINT32 padding = 0;
|
||||
hr = IAudioClient_GetCurrentPadding(state->pAudioClient, &padding);
|
||||
if (hr != S_OK) {
|
||||
MP_ERR(state, "IAudioClient_GetCurrentPadding returned %s (0x%"PRIx32")\n",
|
||||
wasapi_explain_err(hr), (uint32_t) hr);
|
||||
}
|
||||
|
||||
/* Fill the buffer before starting, but only if there is no audio queued to play. */
|
||||
/* This prevents overfilling the buffer, which leads to problems in exclusive mode */
|
||||
if (padding < (UINT32)state->bufferFrameCount)
|
||||
thread_feed(ao);
|
||||
|
||||
hr = IAudioClient_Start(state->pAudioClient);
|
||||
if (hr != S_OK) {
|
||||
MP_ERR(state, "IAudioClient_Start returned %s (0x%"PRIx32")\n",
|
||||
wasapi_explain_err(hr), (uint32_t) hr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void thread_reset(struct ao *ao)
|
||||
{
|
||||
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
|
||||
HRESULT hr;
|
||||
MP_DBG(state, "Thread Reset\n");
|
||||
hr = IAudioClient_Stop(state->pAudioClient);
|
||||
/* we may get S_FALSE if the stream is already stopped */
|
||||
if (hr != S_OK &&
|
||||
hr != S_FALSE) {
|
||||
MP_ERR(state, "IAudioClient_Stop returned: %s (0x%"PRIx32")\n",
|
||||
wasapi_explain_err(hr), (uint32_t) hr);
|
||||
}
|
||||
|
||||
/* we may get S_FALSE if the stream is already reset */
|
||||
hr = IAudioClient_Reset(state->pAudioClient);
|
||||
if (hr != S_OK &&
|
||||
hr != S_FALSE) {
|
||||
MP_ERR(state, "IAudioClient_Reset returned: %s (0x%"PRIx32")\n",
|
||||
wasapi_explain_err(hr), (uint32_t) hr);
|
||||
}
|
||||
|
||||
atomic_store(&state->sample_count, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
static DWORD __stdcall ThreadLoop(void *lpParameter)
|
||||
{
|
||||
struct ao *ao = lpParameter;
|
||||
@@ -178,10 +126,10 @@ static DWORD __stdcall ThreadLoop(void *lpParameter)
|
||||
|
||||
DWORD waitstatus;
|
||||
HANDLE playcontrol[] =
|
||||
{state->hUninit, state->hFeed, state->hReset, state->hResume, NULL};
|
||||
{state->hUninit, state->hFeed, state->hForceFeed, NULL};
|
||||
MP_DBG(ao, "Entering dispatch loop\n");
|
||||
while (true) { /* watch events */
|
||||
waitstatus = MsgWaitForMultipleObjects(4, playcontrol, FALSE, INFINITE,
|
||||
waitstatus = MsgWaitForMultipleObjects(3, playcontrol, FALSE, INFINITE,
|
||||
QS_POSTMESSAGE | QS_SENDMESSAGE);
|
||||
switch (waitstatus) {
|
||||
case WAIT_OBJECT_0: /*shutdown*/
|
||||
@@ -190,18 +138,16 @@ static DWORD __stdcall ThreadLoop(void *lpParameter)
|
||||
case (WAIT_OBJECT_0 + 1): /* feed */
|
||||
thread_feed(ao);
|
||||
break;
|
||||
case (WAIT_OBJECT_0 + 2): /* reset */
|
||||
thread_reset(ao);
|
||||
case (WAIT_OBJECT_0 + 2): /* force feed */
|
||||
thread_feed(ao);
|
||||
SetEvent(state->hFeedDone);
|
||||
break;
|
||||
case (WAIT_OBJECT_0 + 3): /* resume */
|
||||
thread_resume(ao);
|
||||
break;
|
||||
case (WAIT_OBJECT_0 + 4): /* messages to dispatch (COM marshalling) */
|
||||
case (WAIT_OBJECT_0 + 3): /* messages to dispatch (COM marshalling) */
|
||||
MP_DBG(ao, "Dispatch\n");
|
||||
wasapi_dispatch();
|
||||
break;
|
||||
default:
|
||||
MP_ERR(ao, "Unhandled case in thread loop\n");
|
||||
MP_ERR(ao, "Unhandled case in thread loop");
|
||||
goto exit_label;
|
||||
}
|
||||
}
|
||||
@@ -219,8 +165,8 @@ static void closehandles(struct ao *ao)
|
||||
if (state->init_done) CloseHandle(state->init_done);
|
||||
if (state->hUninit) CloseHandle(state->hUninit);
|
||||
if (state->hFeed) CloseHandle(state->hFeed);
|
||||
if (state->hResume) CloseHandle(state->hResume);
|
||||
if (state->hReset) CloseHandle(state->hReset);
|
||||
if (state->hForceFeed) CloseHandle(state->hForceFeed);
|
||||
if (state->hFeedDone) CloseHandle(state->hFeedDone);
|
||||
if (state->threadLoop) CloseHandle(state->threadLoop);
|
||||
}
|
||||
|
||||
@@ -274,10 +220,10 @@ static int init(struct ao *ao)
|
||||
state->init_done = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
state->hUninit = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
state->hFeed = CreateEventW(NULL, FALSE, FALSE, NULL); /* for wasapi event mode */
|
||||
state->hResume = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
state->hReset = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
state->hForceFeed = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
state->hFeedDone = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
if (!state->init_done || !state->hFeed || !state->hUninit ||
|
||||
!state->hResume || !state->hReset)
|
||||
!state->hForceFeed || !state->hFeedDone)
|
||||
{
|
||||
MP_ERR(ao, "Error initing events\n");
|
||||
uninit(ao);
|
||||
@@ -389,13 +335,19 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
|
||||
static void audio_reset(struct ao *ao)
|
||||
{
|
||||
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
|
||||
SetEvent(state->hReset);
|
||||
|
||||
IAudioClient_Stop(state->pAudioClientProxy);
|
||||
IAudioClient_Reset(state->pAudioClientProxy);
|
||||
atomic_store(&state->sample_count, 0);
|
||||
}
|
||||
|
||||
static void audio_resume(struct ao *ao)
|
||||
{
|
||||
struct wasapi_state *state = (struct wasapi_state *)ao->priv;
|
||||
SetEvent(state->hResume);
|
||||
|
||||
SetEvent(state->hForceFeed);
|
||||
WaitForSingleObject(state->hFeedDone, INFINITE);
|
||||
IAudioClient_Start(state->pAudioClientProxy);
|
||||
}
|
||||
|
||||
static void list_devs(struct ao *ao, struct ao_device_list *list)
|
||||
|
||||
@@ -72,14 +72,15 @@ typedef struct wasapi_state {
|
||||
IMMDeviceEnumerator *pEnumerator;
|
||||
|
||||
HANDLE hFeed; /* wasapi event */
|
||||
HANDLE hResume; /* signal audio thread to resume the stream */
|
||||
HANDLE hReset; /* signal audio thread to reset the stream */
|
||||
HANDLE hForceFeed; /* forces writing a buffer (e.g. before audio_resume) */
|
||||
HANDLE hFeedDone; /* set only after a hForceFeed */
|
||||
HANDLE hTask; /* AV thread */
|
||||
DWORD taskIndex; /* AV task ID */
|
||||
WAVEFORMATEXTENSIBLE format;
|
||||
|
||||
/* WASAPI proxy handles, for Single-Threaded Apartment communication.
|
||||
One is needed for each object that's accessed by a different thread. */
|
||||
IAudioClient *pAudioClientProxy;
|
||||
ISimpleAudioVolume *pAudioVolumeProxy;
|
||||
IAudioEndpointVolume *pEndpointVolumeProxy;
|
||||
IAudioSessionControl *pSessionControlProxy;
|
||||
@@ -87,6 +88,7 @@ typedef struct wasapi_state {
|
||||
/* Streams used to marshal the proxy objects. The thread owning the actual objects
|
||||
needs to marshal proxy objects into these streams, and the thread that wants the
|
||||
proxies unmarshals them from here. */
|
||||
IStream *sAudioClient;
|
||||
IStream *sAudioVolume;
|
||||
IStream *sEndpointVolume;
|
||||
IStream *sSessionControl;
|
||||
|
||||
@@ -958,6 +958,7 @@ HRESULT wasapi_setup_proxies(struct wasapi_state *state) {
|
||||
EXIT_ON_ERROR(hr); \
|
||||
} while (0)
|
||||
|
||||
UNMARSHAL(IID_IAudioClient, state->pAudioClientProxy, state->sAudioClient);
|
||||
UNMARSHAL(IID_ISimpleAudioVolume, state->pAudioVolumeProxy, state->sAudioVolume);
|
||||
UNMARSHAL(IID_IAudioEndpointVolume, state->pEndpointVolumeProxy, state->sEndpointVolume);
|
||||
UNMARSHAL(IID_IAudioSessionControl, state->pSessionControlProxy, state->sSessionControl);
|
||||
@@ -972,6 +973,7 @@ exit_label:
|
||||
}
|
||||
|
||||
void wasapi_release_proxies(wasapi_state *state) {
|
||||
SAFE_RELEASE(state->pAudioClientProxy, IUnknown_Release(state->pAudioClientProxy));
|
||||
SAFE_RELEASE(state->pAudioVolumeProxy, IUnknown_Release(state->pAudioVolumeProxy));
|
||||
SAFE_RELEASE(state->pEndpointVolumeProxy, IUnknown_Release(state->pEndpointVolumeProxy));
|
||||
SAFE_RELEASE(state->pSessionControlProxy, IUnknown_Release(state->pSessionControlProxy));
|
||||
@@ -989,6 +991,7 @@ static HRESULT create_proxies(struct wasapi_state *state) {
|
||||
EXIT_ON_ERROR(hr); \
|
||||
} while (0)
|
||||
|
||||
MARSHAL(IID_IAudioClient, state->sAudioClient, state->pAudioClient);
|
||||
MARSHAL(IID_ISimpleAudioVolume, state->sAudioVolume, state->pAudioVolume);
|
||||
MARSHAL(IID_IAudioEndpointVolume, state->sEndpointVolume, state->pEndpointVolume);
|
||||
MARSHAL(IID_IAudioSessionControl, state->sSessionControl, state->pSessionControl);
|
||||
@@ -1001,6 +1004,7 @@ exit_label:
|
||||
}
|
||||
|
||||
static void destroy_proxies(struct wasapi_state *state) {
|
||||
SAFE_RELEASE(state->sAudioClient, IUnknown_Release(state->sAudioClient));
|
||||
SAFE_RELEASE(state->sAudioVolume, IUnknown_Release(state->sAudioVolume));
|
||||
SAFE_RELEASE(state->sEndpointVolume, IUnknown_Release(state->sEndpointVolume));
|
||||
SAFE_RELEASE(state->sSessionControl, IUnknown_Release(state->sSessionControl));
|
||||
|
||||
@@ -50,9 +50,6 @@ struct ao {
|
||||
// default device should be used, this is set to NULL.
|
||||
char *device;
|
||||
|
||||
// Device actually chosen by the AO
|
||||
char *detected_device;
|
||||
|
||||
// Application name to report to the audio API.
|
||||
char *client_name;
|
||||
|
||||
|
||||
+2
-2
@@ -5,9 +5,9 @@
|
||||
from __future__ import print_function
|
||||
import os, sys, stat, hashlib, subprocess
|
||||
|
||||
WAFRELEASE = "waf-1.8.4"
|
||||
WAFRELEASE = "waf-1.8.1"
|
||||
WAFURL = "http://ftp.waf.io/pub/release/" + WAFRELEASE
|
||||
SHA256HASH = "f02035fa5d8814f33f19b2b20d43822ddef6bb39b955ca196c2a247a1f9ffaa8"
|
||||
SHA256HASH = "ec658116ba0b96629d91fde0b32321849e866e0819f1e835c4c2c7f7ffe1a21d"
|
||||
|
||||
if os.path.exists("waf"):
|
||||
wafver = subprocess.check_output(['./waf', '--version']).decode()
|
||||
|
||||
+1
-2
@@ -55,6 +55,7 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st)
|
||||
{
|
||||
mp_lavc_set_extradata(avctx, st->extradata, st->extradata_size);
|
||||
avctx->codec_tag = st->codec_tag;
|
||||
avctx->stream_codec_tag = st->stream_codec_tag;
|
||||
avctx->bit_rate = st->bit_rate;
|
||||
avctx->width = st->width;
|
||||
avctx->height = st->height;
|
||||
@@ -66,8 +67,6 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st)
|
||||
avctx->block_align = st->block_align;
|
||||
avctx->channel_layout = st->channel_layout;
|
||||
avctx->bits_per_coded_sample = st->bits_per_coded_sample;
|
||||
// Required in FFmpeg 2.5.x / Libav 11, deprecated afterwards.
|
||||
avctx->stream_codec_tag = st->stream_codec_tag;
|
||||
}
|
||||
|
||||
// We merely pass-through our PTS/DTS as an int64_t; libavcodec won't use it.
|
||||
|
||||
+2
-2
@@ -224,8 +224,8 @@ void print_libav_versions(struct mp_log *log, int v)
|
||||
if (broken) {
|
||||
mp_fatal(log, "mpv was compiled and linked against a mixture of Libav "
|
||||
"and FFmpeg versions. This won't work and will most likely "
|
||||
"crash at some point. Aborting.\n");
|
||||
abort();
|
||||
"crash at some point. Exiting.\n");
|
||||
exit(42);
|
||||
}
|
||||
// We don't "really" support mismatched libraries, but if you like to
|
||||
// suffer, you're free to enjoy the terrible aspects of dynamic linking.
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "common/global.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/msg_control.h"
|
||||
#include "video/vfcap.h"
|
||||
#include "options/m_option.h"
|
||||
#include "options/options.h"
|
||||
#include "osdep/timer.h"
|
||||
@@ -835,12 +836,12 @@ int encode_lavc_supports_pixfmt(struct encode_lavc_context *ctx,
|
||||
return 0;
|
||||
|
||||
if (!ctx->vc->pix_fmts)
|
||||
return 1;
|
||||
return VFCAP_CSP_SUPPORTED;
|
||||
else {
|
||||
const enum AVPixelFormat *p;
|
||||
for (p = ctx->vc->pix_fmts; *p >= 0; ++p) {
|
||||
if (pix_fmt == *p)
|
||||
return 1;
|
||||
return VFCAP_CSP_SUPPORTED;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
+31
-38
@@ -48,7 +48,7 @@
|
||||
struct mp_log_root {
|
||||
struct mpv_global *global;
|
||||
// --- protected by mp_msg_lock
|
||||
char **msg_levels;
|
||||
char *msglevels;
|
||||
bool use_terminal; // make accesses to stderr/stdout
|
||||
bool module;
|
||||
bool show_time;
|
||||
@@ -60,7 +60,6 @@ struct mp_log_root {
|
||||
bool force_stderr;
|
||||
struct mp_log_buffer **buffers;
|
||||
int num_buffers;
|
||||
FILE *log_file;
|
||||
FILE *stats_file;
|
||||
// --- semi-atomic access
|
||||
bool mute;
|
||||
@@ -96,33 +95,33 @@ static pthread_mutex_t mp_msg_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static const struct mp_log null_log = {0};
|
||||
struct mp_log *const mp_null_log = (struct mp_log *)&null_log;
|
||||
|
||||
static bool match_mod(const char *name, const char *mod)
|
||||
static bool match_mod(const char *name, bstr mod)
|
||||
{
|
||||
if (!strcmp(mod, "all"))
|
||||
if (bstr_equals0(mod, "all"))
|
||||
return true;
|
||||
// Path prefix matches
|
||||
bstr b = bstr0(name);
|
||||
return bstr_eatstart0(&b, mod) && (bstr_eatstart0(&b, "/") || !b.len);
|
||||
return bstr_eatstart(&b, mod) && (bstr_eatstart0(&b, "/") || !b.len);
|
||||
}
|
||||
|
||||
static void update_loglevel(struct mp_log *log)
|
||||
{
|
||||
struct mp_log_root *root = log->root;
|
||||
pthread_mutex_lock(&mp_msg_lock);
|
||||
log->level = -1;
|
||||
log->terminal_level = -1;
|
||||
if (log->root->use_terminal) {
|
||||
log->level = MSGL_STATUS + log->root->verbose; // default log level
|
||||
for (int n = 0; root->msg_levels && root->msg_levels[n * 2 + 0]; n++) {
|
||||
if (match_mod(log->verbose_prefix, root->msg_levels[n * 2 + 0]))
|
||||
log->level = mp_msg_find_level(root->msg_levels[n * 2 + 1]);
|
||||
bstr s = bstr0(log->root->msglevels);
|
||||
bstr mod;
|
||||
int level;
|
||||
while (mp_msg_split_msglevel(&s, &mod, &level) > 0) {
|
||||
if (match_mod(log->verbose_prefix, mod))
|
||||
log->level = level;
|
||||
}
|
||||
log->terminal_level = log->root->use_terminal ? log->level : -1;
|
||||
}
|
||||
for (int n = 0; n < log->root->num_buffers; n++)
|
||||
log->level = MPMAX(log->level, log->root->buffers[n]->level);
|
||||
if (log->root->log_file)
|
||||
log->level = MPMAX(log->level, MSGL_V);
|
||||
if (log->root->stats_file)
|
||||
log->level = MPMAX(log->level, MSGL_STATS);
|
||||
atomic_store(&log->reload_counter, atomic_load(&log->root->reload_counter));
|
||||
@@ -279,19 +278,6 @@ static void print_terminal_line(struct mp_log *log, int lev, char *text)
|
||||
fflush(stream);
|
||||
}
|
||||
|
||||
static void write_log_file(struct mp_log *log, int lev, char *text)
|
||||
{
|
||||
struct mp_log_root *root = log->root;
|
||||
|
||||
if (lev > MSGL_V || !root->log_file)
|
||||
return;
|
||||
|
||||
fprintf(root->log_file, "[%8.3f][%c][%s] %s",
|
||||
(mp_time_us() - MP_START_TIME) / 1e6,
|
||||
mp_log_levels[lev][0],
|
||||
log->verbose_prefix, text);
|
||||
}
|
||||
|
||||
static void write_msg_to_buffers(struct mp_log *log, int lev, char *text)
|
||||
{
|
||||
struct mp_log_root *root = log->root;
|
||||
@@ -370,7 +356,6 @@ void mp_msg_va(struct mp_log *log, int lev, const char *format, va_list va)
|
||||
char saved = next[0];
|
||||
next[0] = '\0';
|
||||
print_terminal_line(log, lev, text);
|
||||
write_log_file(log, lev, text);
|
||||
write_msg_to_buffers(log, lev, text);
|
||||
next[0] = saved;
|
||||
text = next;
|
||||
@@ -473,12 +458,8 @@ void mp_msg_update_msglevels(struct mpv_global *global)
|
||||
root->termosd = isatty(STDERR_FILENO);
|
||||
}
|
||||
|
||||
m_option_type_msglevels.free(&root->msg_levels);
|
||||
m_option_type_msglevels.copy(NULL, &root->msg_levels,
|
||||
&global->opts->msg_levels);
|
||||
|
||||
if (!root->log_file && opts->log_file && opts->log_file[0])
|
||||
root->log_file = fopen(opts->log_file, "wb");
|
||||
talloc_free(root->msglevels);
|
||||
root->msglevels = talloc_strdup(root, global->opts->msglevels);
|
||||
|
||||
atomic_fetch_add(&root->reload_counter, 1);
|
||||
pthread_mutex_unlock(&mp_msg_lock);
|
||||
@@ -503,9 +484,6 @@ void mp_msg_uninit(struct mpv_global *global)
|
||||
struct mp_log_root *root = global->log->root;
|
||||
if (root->stats_file)
|
||||
fclose(root->stats_file);
|
||||
if (root->log_file)
|
||||
fclose(root->log_file);
|
||||
m_option_type_msglevels.free(&root->msg_levels);
|
||||
talloc_free(root);
|
||||
global->log = NULL;
|
||||
}
|
||||
@@ -639,11 +617,26 @@ const int mp_mpv_log_levels[MSGL_MAX + 1] = {
|
||||
[MSGL_STATS] = 0, // never used
|
||||
};
|
||||
|
||||
int mp_msg_find_level(const char *s)
|
||||
int mp_msg_split_msglevel(struct bstr *s, struct bstr *out_mod, int *out_level)
|
||||
{
|
||||
if (s->len == 0)
|
||||
return 0;
|
||||
bstr elem, rest;
|
||||
bstr_split_tok(*s, ":", &elem, &rest);
|
||||
bstr mod, level;
|
||||
if (!bstr_split_tok(elem, "=", &mod, &level) || mod.len == 0)
|
||||
return -1;
|
||||
int ilevel = -1;
|
||||
for (int n = 0; n < MP_ARRAY_SIZE(mp_log_levels); n++) {
|
||||
if (mp_log_levels[n] && mp_log_levels[n] && !strcmp(s, mp_log_levels[n]))
|
||||
return n;
|
||||
if (mp_log_levels[n] && bstr_equals0(level, mp_log_levels[n])) {
|
||||
ilevel = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
if (ilevel < 0 && !bstr_equals0(level, "no"))
|
||||
return -1;
|
||||
*s = rest;
|
||||
*out_mod = mod;
|
||||
*out_level = ilevel;
|
||||
return 1;
|
||||
}
|
||||
@@ -28,7 +28,9 @@ void mp_msg_log_buffer_destroy(struct mp_log_buffer *buffer);
|
||||
struct mp_log_buffer_entry *mp_msg_log_buffer_read(struct mp_log_buffer *buffer);
|
||||
|
||||
int mp_msg_open_stats_file(struct mpv_global *global, const char *path);
|
||||
int mp_msg_find_level(const char *s);
|
||||
|
||||
struct bstr;
|
||||
int mp_msg_split_msglevel(struct bstr *s, struct bstr *out_mod, int *out_level);
|
||||
|
||||
extern const char *const mp_log_levels[MSGL_MAX + 1];
|
||||
extern const int mp_mpv_log_levels[MSGL_MAX + 1];
|
||||
|
||||
Loaded 100 of 322 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user