Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1409ceacf | ||
|
|
44f62ff6f3 | ||
|
|
55c3055784 | ||
|
|
58fbe50d68 | ||
|
|
6a0036ea03 | ||
|
|
2e4fdf01f5 | ||
|
|
a2259b3fd3 | ||
|
|
aeeb7a92f2 | ||
|
|
1e2f3191a7 | ||
|
|
51d030308e | ||
|
|
4cd8aab84f | ||
|
|
3795154155 | ||
|
|
461198e149 | ||
|
|
7b1f12adba | ||
|
|
cf1645aebb | ||
|
|
1b20ec4864 | ||
|
|
ee529da760 | ||
|
|
c9e6e7cc04 | ||
|
|
cb1d1e7a62 | ||
|
|
e6d4ec62ae | ||
|
|
e7e2a6c8f7 | ||
|
|
6643ebaa28 | ||
|
|
98d33db5da | ||
|
|
ca8dc9147b | ||
|
|
df8b99490c | ||
|
|
c78142a973 | ||
|
|
a8e6caf56b | ||
|
|
e6cca1e43b | ||
|
|
d7538d3597 | ||
|
|
f3eb5b143c | ||
|
|
9993fd8888 | ||
|
|
d9c3a51d87 | ||
|
|
619fa761af | ||
|
|
717d729dcb | ||
|
|
4eb5b62e5a | ||
|
|
b9e32d0d3d | ||
|
|
28e2b95f58 | ||
|
|
491f633a20 | ||
|
|
eb5e45855a | ||
|
|
59e55bb0e1 | ||
|
|
9f46be7373 | ||
|
|
3623fb38ee | ||
|
|
1ad9e322e3 | ||
|
|
cad63810c5 | ||
|
|
da17c64c76 | ||
|
|
57f32f7ca8 | ||
|
|
3d85137495 | ||
|
|
4aff0076a0 | ||
|
|
70f8ea228d | ||
|
|
3196f4cdd7 | ||
|
|
4fa0853c34 | ||
|
|
6598b55c35 | ||
|
|
848d7979e5 | ||
|
|
13301daf6a | ||
|
|
763a38f889 | ||
|
|
ed1e4de452 | ||
|
|
0e2fe55fde | ||
|
|
22cfb48b52 | ||
|
|
4a07120f83 | ||
|
|
d06ff691ed | ||
|
|
34cee2a77d | ||
|
|
8f5eb7b780 | ||
|
|
b991c072f6 | ||
|
|
3c2777994b | ||
|
|
80741f27f3 | ||
|
|
3d18ab77b3 | ||
|
|
8d2baaa318 | ||
|
|
2758bc462d | ||
|
|
2687b43dd0 | ||
|
|
bb40daf367 | ||
|
|
cc1f926441 | ||
|
|
67f653324a | ||
|
|
6e2c29b786 | ||
|
|
e565217f22 | ||
|
|
144c67efaf | ||
|
|
96d7e80ddf | ||
|
|
dde72c5c54 | ||
|
|
577d03da0c | ||
|
|
fc510f0da8 | ||
|
|
8d5775a8d2 | ||
|
|
cf8ff2fd87 | ||
|
|
852c924a60 | ||
|
|
1685d198b9 | ||
|
|
1e2d28f567 | ||
|
|
89973ebca1 | ||
|
|
3f4e528f73 | ||
|
|
6f7c9f516e | ||
|
|
33e0074603 | ||
|
|
b6ed94fa7c | ||
|
|
a419703549 | ||
|
|
5171da86e3 | ||
|
|
7bd670949c | ||
|
|
421b2be348 | ||
|
|
b659476ed9 | ||
|
|
689c3f47a8 | ||
|
|
677d4615ba | ||
|
|
5f788a7812 | ||
|
|
dba25e13c0 | ||
|
|
623b97e45a | ||
|
|
7a645ba62f | ||
|
|
63afe3eb98 | ||
|
|
72c70eb05b | ||
|
|
df0ec55499 | ||
|
|
542bcdfc9d | ||
|
|
218667b5a2 | ||
|
|
13a0e34aec | ||
|
|
76b7a1a713 | ||
|
|
6d6eee2e70 | ||
|
|
89f20cd2f3 | ||
|
|
cce2b675ac | ||
|
|
c1ed4dc242 | ||
|
|
712657a894 | ||
|
|
496956de3d | ||
|
|
483e703793 | ||
|
|
717cdeb95d | ||
|
|
315f3a9218 | ||
|
|
d857722618 | ||
|
|
6d9d597b10 | ||
|
|
c4d905b567 | ||
|
|
e4c69376fc | ||
|
|
842689bbf6 | ||
|
|
5ab2aa84e0 | ||
|
|
229d398ba9 | ||
|
|
5f1b155307 | ||
|
|
241cbe5065 | ||
|
|
76d771a6fa | ||
|
|
19caba0794 | ||
|
|
391546c52f | ||
|
|
a8af6a7852 | ||
|
|
960aca3386 | ||
|
|
e72a327d74 | ||
|
|
87f955f3e9 | ||
|
|
5536ebe82f | ||
|
|
ef8b37ca2a | ||
|
|
d4a5513847 | ||
|
|
d42212cd67 | ||
|
|
674cc1d3a9 | ||
|
|
c47bb9ca42 | ||
|
|
938dad0b88 | ||
|
|
82b5361946 | ||
|
|
f99f48684b | ||
|
|
25864a5539 | ||
|
|
524d9585fd | ||
|
|
95a72baf92 | ||
|
|
48112a74ed | ||
|
|
8427cdc717 | ||
|
|
b695ca1e27 | ||
|
|
801feb6420 | ||
|
|
de6a452039 | ||
|
|
4b764b6cc6 | ||
|
|
7b7c31b190 | ||
|
|
70a66b461d | ||
|
|
844e8f2b51 | ||
|
|
3f4ed8920f | ||
|
|
7ad2999b5f | ||
|
|
14fdbe07ac | ||
|
|
61ed9a8747 | ||
|
|
0801345d68 | ||
|
|
5bd0fe5daf | ||
|
|
cab3c5fbb8 | ||
|
|
99ceae8cc3 | ||
|
|
ebe04ab692 | ||
|
|
808aa08cc0 | ||
|
|
2065e0ba36 | ||
|
|
3c43a022af | ||
|
|
02513cd5df | ||
|
|
4d986d2a98 | ||
|
|
ada6f96811 | ||
|
|
321b3952b0 | ||
|
|
d49b49ff96 | ||
|
|
f088abb2bf | ||
|
|
4a3975bf7e | ||
|
|
a064143899 | ||
|
|
f264d52099 | ||
|
|
74a3c169b5 | ||
|
|
34d9787fcf | ||
|
|
1c0b80d518 | ||
|
|
a9bafeb589 | ||
|
|
3a33db3d92 | ||
|
|
d276f753f7 | ||
|
|
c06000eef8 | ||
|
|
1bc1cd2305 | ||
|
|
a735a2abd7 | ||
|
|
112c1abe31 | ||
|
|
362b35b631 | ||
|
|
49cf0af294 | ||
|
|
1b26874710 | ||
|
|
8fe636da7a | ||
|
|
812f149585 | ||
|
|
635424c8f0 | ||
|
|
2319918721 | ||
|
|
9fabf85a44 | ||
|
|
54fd5d0979 | ||
|
|
d141d281ca | ||
|
|
ebc3d74b04 | ||
|
|
a63fab8921 | ||
|
|
4ee8d8d3f9 | ||
|
|
574a2484c1 | ||
|
|
f5b92bee5e | ||
|
|
ca3d7144db | ||
|
|
86e7c3defb | ||
|
|
0fe1385d80 | ||
|
|
f4e9371d0f | ||
|
|
909185d49e | ||
|
|
c18c324c6f | ||
|
|
6b20c24413 | ||
|
|
5c42d1eb92 | ||
|
|
e34132f8d5 | ||
|
|
bd7ff23f96 | ||
|
|
e6c184e2b1 | ||
|
|
33c4920967 | ||
|
|
0c36f655e1 | ||
|
|
cd31697dd8 | ||
|
|
c497b82583 | ||
|
|
6f5dfb5102 | ||
|
|
59f970d492 | ||
|
|
29c74b42b4 | ||
|
|
4b2a3e50e2 | ||
|
|
35b01c9604 | ||
|
|
09b95257fe | ||
|
|
0cf2df38d1 | ||
|
|
4326fdfe2a | ||
|
|
9755850b3d | ||
|
|
96b50e770b | ||
|
|
9f6551160a | ||
|
|
89b854165e | ||
|
|
0beece4397 | ||
|
|
8abdf1f56e | ||
|
|
5a81f7678e | ||
|
|
e26286dfdb | ||
|
|
389232e5a2 | ||
|
|
c5de0b0a6c | ||
|
|
f9bdfc0782 | ||
|
|
5c9a7e24f6 | ||
|
|
b56f61d2ab | ||
|
|
82ab3a8160 | ||
|
|
e371f2ebd3 | ||
|
|
29b68d69c0 | ||
|
|
6c770eb6df | ||
|
|
965f336917 | ||
|
|
47fae324c7 | ||
|
|
6ab0dbf2ed | ||
|
|
c002196ffe | ||
|
|
3c8fc4588d | ||
|
|
416015f059 | ||
|
|
773db053aa | ||
|
|
a8c09d003f | ||
|
|
1284a6b6b0 | ||
|
|
78c35e42ea |
No files matched your search
@@ -0,0 +1,139 @@
|
||||
Coding style
|
||||
============
|
||||
|
||||
mpv uses C99 with K&R formatting, with some exceptions.
|
||||
|
||||
General formatting
|
||||
------------------
|
||||
|
||||
- Use the K&R indent style.
|
||||
- Use 4 spaces of indentation, never use tabs (except in Makefiles).
|
||||
- Add a single space between keywords and binary operators. There are some other
|
||||
cases where spaces should be added. Example:
|
||||
|
||||
```C
|
||||
if ((a * b) > c) {
|
||||
// code
|
||||
some_function(a, b, c);
|
||||
}
|
||||
```
|
||||
- Break lines on 80 columns. There is a hard limit of 85 columns. You may ignore
|
||||
this limit if there's a strong case that not breaking the line will increase
|
||||
readability. Going over 85 columns might provoke endless discussions about
|
||||
whether such a limit is needed or not, so avoid it.
|
||||
- If the body of an if/for/while statement has more than 1 physical lines, then
|
||||
always add braces, even if they're technically redundant.
|
||||
|
||||
Bad:
|
||||
|
||||
```C
|
||||
if (a)
|
||||
// do something if b
|
||||
if (b)
|
||||
do_something();
|
||||
```
|
||||
|
||||
Good:
|
||||
|
||||
```C
|
||||
if (a) {
|
||||
// do something if b
|
||||
if (b)
|
||||
do_something();
|
||||
}
|
||||
```
|
||||
- If the body of an if statement uses braces, the else branch should also
|
||||
use braces (and reverse).
|
||||
|
||||
Example:
|
||||
|
||||
```C
|
||||
if (a) {
|
||||
// do something
|
||||
something();
|
||||
something_else();
|
||||
} else {
|
||||
one_line();
|
||||
}
|
||||
```
|
||||
- If an if condition spans multiple physical lines, then put the opening brace
|
||||
for the if body on the next physical line. (Also, preferably always add a
|
||||
brace, even if technically none is needed.)
|
||||
|
||||
Example:
|
||||
|
||||
```C
|
||||
if (very_long_condition_a &&
|
||||
very_long_condition_b)
|
||||
{
|
||||
code();
|
||||
}
|
||||
```
|
||||
- Remove any trailing whitespace.
|
||||
- If the file you're editing uses formatting different from from what is
|
||||
described here, it's probably an old file from times when nobody followed a
|
||||
consistent style. You're free to use the existing style, or the new style, or
|
||||
to send a patch to reformat the file to the new style before making functional
|
||||
changes.
|
||||
|
||||
General coding
|
||||
--------------
|
||||
|
||||
- Use C99. Also freely make use of C99 features if it's appropriate, such as
|
||||
stdbool.h.
|
||||
- Don't use GNU-only features. In some cases they may be warranted, if they
|
||||
are optional (such as attributes enabling printf-like format string checks).
|
||||
But in general, standard C99 should be used.
|
||||
- The same applies to libc functions. We have to be Windows-compatible too. Use
|
||||
functions guaranteed by C99 or POSIX only, unless your use is guarded by a
|
||||
configure check.
|
||||
- Prefer fusing declaration and initialization, rather than putting declarations
|
||||
on the top of a block. Obvious data flow is more important than avoiding
|
||||
mixing declarations and statements, which is just a C90 artifact.
|
||||
- tech-overview.txt might help to get an overview how mpv is structured.
|
||||
- If you add features that require intrusive changes, discuss them on the dev
|
||||
channel first. There might be a better way to add a feature and it can avoid
|
||||
wasted work.
|
||||
|
||||
Sending patches
|
||||
---------------
|
||||
|
||||
- Make a github pull request, or send a link to a plaintext patch created with
|
||||
``git format-patch``. diffs posted as pastebins (especially if the http link
|
||||
returns HTML) just cause extra work for everyone, because they lack commit
|
||||
message and authorship information.
|
||||
- Write informative commit messages. Use present tense to describe the
|
||||
situation with the patch applied, and past tense for the situation before
|
||||
the change.
|
||||
- The subject line (the first line in a commit message) should contain a
|
||||
prefix identifying the sub system, followed by a short description what
|
||||
impact this commit has. This subject line shouldn't be longer than 72
|
||||
characters, because it messes up the output of many git tools otherwise.
|
||||
|
||||
For example, you fixed a crash in af_volume.c:
|
||||
|
||||
Bad: ``fixed the bug (wtf?)``
|
||||
Good: ``af_volume: fix crash due to null pointer access``
|
||||
|
||||
Having a prefix gives context, and is especially useful when trying to find
|
||||
a specific change by looking at the history, or when running ``git blame``.
|
||||
- The body of the commit message (everything else after the subject line) should
|
||||
be as informative as possible and contain everything that isn't obvious. Don't
|
||||
hesitate to dump as much information as you can - it doesn't cost you
|
||||
anything. Put some effort into it. If someone finds a bug months or years
|
||||
later, and finds that it's caused by your commit (even though your commit was
|
||||
supposed to fix another bug), it would be bad if there wasn't enough
|
||||
information to test the original bug. The old bug might be reintroduced while
|
||||
fixing the new bug.
|
||||
|
||||
The commit message should be wrapped on 72 characters per line, because git
|
||||
tools usually do not break text automatically. On the other hand, you do not
|
||||
need to break text that would be unnatural to break (like data for test cases,
|
||||
or long URLs).
|
||||
|
||||
Important: put an empty line between the subject line and the commit message.
|
||||
If this is missing, it will break display in common git tools.
|
||||
- Try to separate cosmetic and functional changes. It's ok to make a few
|
||||
additional cosmetic changes in the same file you're working on, but don't do
|
||||
something like reformatting a whole file and hiding an actual functional
|
||||
change in the same commit.
|
||||
@@ -9,6 +9,8 @@ Using mingw-w64-cmake to setup a MinGW-w64 environment is recommended (this will
|
||||
also build mpv and its dependencies): https://github.com/lachs0r/mingw-w64-cmake
|
||||
|
||||
Alternatively, use MXE: http://mxe.cc
|
||||
With MXE, you have to modify the file settings.mk to target MinGW-w64 (even if
|
||||
you compile to 32 bit).
|
||||
|
||||
Warning: the original MinGW (http://www.mingw.org) is unsupported.
|
||||
|
||||
|
||||
+1
-1
@@ -134,9 +134,9 @@ What works
|
||||
* Deinterlacing/Inverse Telecine with any of mpv's filters for that
|
||||
* Audio file converting: mpv -o outfile.mp3 infile.flac -no-video -oac
|
||||
libmp3lame -oacopts ab=320k
|
||||
* inverse telecine filters (confirmed working: detc, pullup, filmdint)
|
||||
|
||||
What does not work yet
|
||||
======================
|
||||
|
||||
* 3-pass encoding (ensuring constant total size and bitrate constraints while
|
||||
having VBR audio; mencoder calls this "frameno")
|
||||
|
||||
+5
-5
@@ -147,7 +147,7 @@ Available filters are:
|
||||
0 no matrix decoding (default)
|
||||
==== ===================================
|
||||
|
||||
``equalizer=[g1:g2:g3:...:g10]``
|
||||
``equalizer=g1:g2:g3:...:g10``
|
||||
10 octave band graphic equalizer, implemented using 10 IIR band-pass
|
||||
filters. This means that it works regardless of what type of audio is
|
||||
being played back. The center frequencies for the 10 bands are:
|
||||
@@ -266,7 +266,7 @@ Available filters are:
|
||||
Filter for internal use only. Converts between signed/unsigned formats
|
||||
and formats with different endian.
|
||||
|
||||
``volume[=volumedb[:softclip[:s16]]]``
|
||||
``volume[=<volumedb>[:...]]``
|
||||
Implements software volume control. Use this filter with caution since it
|
||||
can reduce the signal to noise ratio of the sound. In most cases it is
|
||||
best to use the *Master* volume control of your sound card or the volume
|
||||
@@ -279,14 +279,14 @@ Available filters are:
|
||||
Sets the desired gain in dB for all channels in the stream from -200dB
|
||||
to +60dB, where -200dB mutes the sound completely and +60dB equals a
|
||||
gain of 1000 (default: 0).
|
||||
``<softclip>``
|
||||
``softclip``
|
||||
Turns soft clipping on. Soft-clipping can make the
|
||||
sound more smooth if very high volume levels are used. Enable this
|
||||
option if the dynamic range of the loudspeakers is very low.
|
||||
|
||||
*WARNING*: This feature creates distortion and should be considered a
|
||||
last resort.
|
||||
``<s16>``
|
||||
``s16``
|
||||
Force S16 sample format if set. Lower quality, but might be faster
|
||||
in some situations.
|
||||
|
||||
@@ -296,7 +296,7 @@ Available filters are:
|
||||
Would amplify the sound by 10.1dB and hard-clip if the sound level
|
||||
is too high.
|
||||
|
||||
``pan=n[:<matrix>]``
|
||||
``pan=n:[<matrix>]``
|
||||
Mixes channels arbitrarily. Basically a combination of the volume and the
|
||||
channels filter that can be used to down-mix many channels to only a few,
|
||||
e.g. stereo to mono, or vary the "width" of the center speaker in a
|
||||
|
||||
+25
-1
@@ -18,7 +18,12 @@ normal driver parameters.
|
||||
|
||||
.. note::
|
||||
|
||||
See ``--ao=help`` for a list of compiled-in audio output drivers.
|
||||
See ``--ao=help`` for a list of compiled-in audio output drivers. The
|
||||
driver ``--ao=alsa`` is preferred. ``--ao=pulse`` is preferred on systems
|
||||
where PulseAudio is used. On Windows, ``--ao=wasapi`` is preferred,
|
||||
though it might cause trouble sometimes, in which case ``--ao=dsound``
|
||||
should be used. On BSD systems, ``--ao=oss`` or `--ao=sndio`` may work
|
||||
(the latter being experimental). On OSX systems, use ``--ao=coreaudio``.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
@@ -118,6 +123,9 @@ Available audio output drivers are:
|
||||
``openal``
|
||||
Experimental OpenAL audio output driver
|
||||
|
||||
.. note:: This driver is not very useful. Playing multi-channel audio with
|
||||
it is slow.
|
||||
|
||||
``pulse``
|
||||
PulseAudio audio output driver
|
||||
|
||||
@@ -130,6 +138,10 @@ Available audio output drivers are:
|
||||
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,
|
||||
@@ -138,6 +150,8 @@ Available audio output drivers are:
|
||||
``dsound`` (Windows only)
|
||||
DirectX DirectSound audio output driver
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``device=<devicenum>``
|
||||
Sets the device number to use. Playing a file with ``-v`` will show a
|
||||
list of available devices.
|
||||
@@ -147,6 +161,10 @@ Available audio output drivers are:
|
||||
1.2, but may require the ``SDL_AUDIODRIVER`` environment variable to be set
|
||||
appropriately for your system.
|
||||
|
||||
.. note:: This driver is for compatibility with extremely foreign
|
||||
environments, such as systems where none of the other drivers
|
||||
are available.
|
||||
|
||||
``buflen=<length>``
|
||||
Sets the audio buffer length in seconds. Is used only as a hint by the
|
||||
sound system. Playing a file with ``-v`` will show the requested and
|
||||
@@ -186,6 +204,10 @@ Available audio output drivers are:
|
||||
``rsound``
|
||||
Audio output to an RSound daemon
|
||||
|
||||
.. note:: Completely useless, unless you intend to run RSound. Not to be
|
||||
confused with RoarAudio, which is something completely
|
||||
different.
|
||||
|
||||
``host=<name/path>``
|
||||
Set the address of the server (default: localhost). Can be either a
|
||||
network hostname for TCP connections or a Unix domain socket path
|
||||
@@ -197,6 +219,8 @@ Available audio output drivers are:
|
||||
``sndio``
|
||||
Audio output to the OpenBSD sndio sound system
|
||||
|
||||
.. note:: Experimental. There are known bugs and issues.
|
||||
|
||||
(Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
|
||||
layouts.)
|
||||
|
||||
|
||||
@@ -52,11 +52,6 @@ You can bind multiple commands to one key. For example:
|
||||
|
||||
| a show_text "command 1" ; show_text "command 2"
|
||||
|
||||
Note that some magic is disabled for keys: seek commands inside lists are not
|
||||
coalesced (seeking will appear slower), and no check is done for abort commands
|
||||
(so these commands can't be used to abort playback if the network cache is
|
||||
stuck).
|
||||
|
||||
List of Input Commands
|
||||
----------------------
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ LUA SCRIPTING
|
||||
|
||||
mpv can load Lua scripts. These scripts can be used to control mpv in a similar
|
||||
way to slave mode. mpv provides the builtin module ``mp`` (can be loaded
|
||||
with ``require 'mpv'``), which provides functions to send commands to the
|
||||
with ``require '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.
|
||||
|
||||
|
||||
+49
-17
@@ -103,6 +103,13 @@ OPTIONS
|
||||
Override movie aspect ratio, in case aspect information is incorrect or
|
||||
missing in the file being played. See also ``--no-aspect``.
|
||||
|
||||
Two values have special meaning:
|
||||
|
||||
:0: disable aspect ratio handling, pretend the video has square pixels
|
||||
:-1: use the video stream or container aspect (default)
|
||||
|
||||
But note that handling of these special values might change in the future.
|
||||
|
||||
.. admonition:: Examples
|
||||
|
||||
- ``--aspect=4:3`` or ``--aspect=1.3333``
|
||||
@@ -789,7 +796,7 @@ OPTIONS
|
||||
|
||||
``--field-dominance=<auto|top|bottom>``
|
||||
Set first field for interlaced content. Useful for deinterlacers that
|
||||
double the framerate: ``--vf=yadif=1`` and ``--vo=vdpau:deint``.
|
||||
double the framerate: ``--vf=yadif=field`` and ``--vo=vdpau:deint``.
|
||||
|
||||
:auto: (default) If the decoder does not export the appropriate
|
||||
information, it falls back on ``top`` (top field first).
|
||||
@@ -1142,7 +1149,12 @@ OPTIONS
|
||||
Allow hardware decoding for a given list of codecs only. The special value
|
||||
``all`` always allows all codecs.
|
||||
|
||||
By default this is set to ``h264,vc1,wmv3``.
|
||||
You can get the list of allowed codecs with ``mpv --vd=help``. Remove the
|
||||
prefix, e.g. instead of ``lavc:h264`` use ``h264``.
|
||||
|
||||
By default this is set to ``h264,vc1,wmv3``. Note that the hardware
|
||||
acceleration special codecs like ``h264_vdpau`` are not relevant anymore,
|
||||
and in fact have been removed from Libav in this form.
|
||||
|
||||
This is usually only needed with broken GPUs, where a codec is reported
|
||||
as supported, but decoding causes more problems than it solves.
|
||||
@@ -1369,8 +1381,7 @@ OPTIONS
|
||||
:trace: very noisy debug messages
|
||||
|
||||
One special case is the ``identify`` module name. This is silenced by
|
||||
default, and can be set to ``trace`` level to enable the remains of the
|
||||
code once enabled with the ``-identify`` option.
|
||||
default, and can be enabled with the ``-identify`` option.
|
||||
|
||||
``--msgmodule``
|
||||
Prepend module name in front of each console message.
|
||||
@@ -1547,10 +1558,10 @@ OPTIONS
|
||||
``--osd-level=<0-3>``
|
||||
Specifies which mode the OSD should start in.
|
||||
|
||||
:0: subtitles only
|
||||
:1: volume + seek (default)
|
||||
:2: volume + seek + timer + percentage
|
||||
:3: volume + seek + timer + percentage + total time
|
||||
:0: OSD completely disabled (subtitles only)
|
||||
:1: enabled (shows up only on user interaction)
|
||||
:2: enabled + current time visible by default
|
||||
:3: enabled + ``--osd-status-msg`` (current time and status by default)
|
||||
|
||||
``--osd-margin-x=<size>, --sub-text-margin-x=<size>``
|
||||
Left and right screen margin for the OSD/subs in scaled pixels (see
|
||||
@@ -1609,6 +1620,9 @@ OPTIONS
|
||||
controls how much of the image is cropped. May not work with all video
|
||||
output drivers.
|
||||
|
||||
``--pause``
|
||||
Start the player in paused state.
|
||||
|
||||
``--playing-msg=<string>``
|
||||
Print out a string after starting playback. The string is expanded for
|
||||
properties, e.g. ``--playing-msg='file: ${filename}'`` will print the string
|
||||
@@ -1634,20 +1648,25 @@ OPTIONS
|
||||
file is dumped.
|
||||
|
||||
``--playlist=<filename>``
|
||||
Play files according to a playlist file (ASX, Winamp, SMIL, or
|
||||
one-file-per-line format).
|
||||
Play files according to a playlist file (Supports some common formats.If
|
||||
no format is detected, t will be treated as list of files, separated by
|
||||
newline characters. Note that XML playlist formats are not supported.)
|
||||
|
||||
.. warning::
|
||||
|
||||
The way mpv parses and uses playlist files is not safe against
|
||||
maliciously constructed files. Such files may trigger harmful actions.
|
||||
The way mpv uses playlist files is not safe against maliciously
|
||||
constructed files. Such files may trigger harmful actions.
|
||||
This has been the case for all mpv and MPlayer versions, but
|
||||
unfortunately this fact was not well documented earlier, and some people
|
||||
have even misguidedly recommended use of ``--playlist`` with untrusted
|
||||
sources. Do NOT use ``--playlist`` with random internet sources or files
|
||||
you do not trust!
|
||||
|
||||
FIXME: This needs to be clarified and documented thoroughly.
|
||||
The main problem is that playlists can point to arbitrary network
|
||||
addresses (including local addresses inside of your LAN), and thus
|
||||
can't be considered secure. Playlists also can contain entries using
|
||||
other protocols, such as local files, or (most severely), special
|
||||
protocols like ``avdevice://``, which are inherently unsafe.
|
||||
|
||||
``--priority=<prio>``
|
||||
(Windows only.)
|
||||
@@ -1741,6 +1760,15 @@ OPTIONS
|
||||
|
||||
Also see ``--really-quiet`` and ``--msglevel``.
|
||||
|
||||
``--quvi-fetch-subtitles=<yes|no>``
|
||||
Toggles fetching of subtitles from streaming sites with libquvi. Disabled
|
||||
by default, because it's unreliable and slow. Note that when enabled,
|
||||
subtitles will always be fetched, even if subtitles are explicitly
|
||||
disabled with ``--no-sub`` (because you might want to enable subtitles
|
||||
at runtime).
|
||||
|
||||
Supported when using libquvi 0.9.x.
|
||||
|
||||
``--quvi-format=<best|default|...>``
|
||||
Video format/quality that is directly passed to libquvi (default: ``best``).
|
||||
This is used when opening links to streaming sites like YouTube. The
|
||||
@@ -1759,7 +1787,7 @@ OPTIONS
|
||||
libquvi 0.9.x:
|
||||
|
||||
The following explanations are relevant:
|
||||
`<http://quvi.sourceforge.net/doc/0.9/glossary_termino.html#m_stream_id>`_
|
||||
`<http://quvi.sourceforge.net/r/api/0.9/glossary_termino.html#m_stream_id>`_
|
||||
|
||||
The ``quvi-format`` property can be used at runtime to cycle through the
|
||||
list of formats. Unfortunately, this is slow. On libquvi 0.4.x, this
|
||||
@@ -2023,8 +2051,10 @@ OPTIONS
|
||||
the top of the screen) alongside the normal subtitle, and provides a way
|
||||
to render two subtitles at once.
|
||||
|
||||
there are some caveats associated with this feature. For example, secondary
|
||||
subtitles are never shown on the terminal if video is disabled.
|
||||
there are some caveats associated with this feature. For example, bitmap
|
||||
subtitles will always be rendered in their usual position, so selecting a
|
||||
bitmap subtitle as secondary subtitle will result in overlapping subtitles.
|
||||
Secondary subtitles are never shown on the terminal if video is disabled.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -2362,7 +2392,7 @@ OPTIONS
|
||||
Some ``--sws`` options are tunable. The description of the ``scale``
|
||||
video filter has further information.
|
||||
|
||||
``--term-osd, --no-term-osd``
|
||||
``--term-osd, --no-term-osd``, ``--term-osd=force``
|
||||
Display OSD messages on the console when no video output is available.
|
||||
Enabled by default.
|
||||
|
||||
@@ -2371,6 +2401,8 @@ OPTIONS
|
||||
console. The escape sequence should move the pointer to the beginning of
|
||||
the line used for the OSD and clear it (default: ``^[[A\r^[[K``).
|
||||
|
||||
``force`` enables terminal OSD even if a video window is created.
|
||||
|
||||
``--title=<string>``
|
||||
Set the window title. Properties are expanded on playback start.
|
||||
(See `Property Expansion`_.)
|
||||
|
||||
+14
-12
@@ -98,10 +98,12 @@ Available filters are:
|
||||
:2: Rotate by 90 degrees counterclockwise.
|
||||
:3: Rotate by 90 degrees counterclockwise and flip.
|
||||
|
||||
``scale[=w:h[:interlaced[:chr_drop[:par[:par2[:noup[:arnd]]]]]]]``
|
||||
``scale[=w:h:param:param2:chr-drop:noup:arnd``
|
||||
Scales the image with the software scaler (slow) and performs a YUV<->RGB
|
||||
colorspace conversion (see also ``--sws``).
|
||||
|
||||
All parameters are optional.
|
||||
|
||||
``<w>,<h>``
|
||||
scaled width/height (default: original width/height)
|
||||
|
||||
@@ -114,15 +116,7 @@ Available filters are:
|
||||
:-(n+8): Like -n above, but rounding the dimension to the closest
|
||||
multiple of 16.
|
||||
|
||||
``<chr_drop>``
|
||||
chroma skipping
|
||||
|
||||
:0: Use all available input lines for chroma.
|
||||
:1: Use only every 2. input line for chroma.
|
||||
:2: Use only every 4. input line for chroma.
|
||||
:3: Use only every 8. input line for chroma.
|
||||
|
||||
``<par>[:<par2>]`` (see also ``--sws``)
|
||||
``<param>[:<param2>]`` (see also ``--sws``)
|
||||
Set some scaling parameters depending on the type of scaler selected
|
||||
with ``--sws``::
|
||||
|
||||
@@ -137,6 +131,14 @@ Available filters are:
|
||||
|
||||
--sws=9 (lanczos): filter length (1-10)
|
||||
|
||||
``<chr-drop>``
|
||||
chroma skipping
|
||||
|
||||
:0: Use all available input lines for chroma (default).
|
||||
:1: Use only every 2. input line for chroma.
|
||||
:2: Use only every 4. input line for chroma.
|
||||
:3: Use only every 8. input line for chroma.
|
||||
|
||||
``<noup>``
|
||||
Disallow upscaling past the original dimensions.
|
||||
|
||||
@@ -429,7 +431,7 @@ Available filters are:
|
||||
``'--vf=lavfi=yadif:o="threads=2,thread_type=slice"'``
|
||||
forces a specific threading configuration.
|
||||
|
||||
``noise[=<strength>[:average][:pattern][:temporal][:uniform][:hq]``
|
||||
``noise[=<strength>[:averaged][:pattern][:temporal][:uniform][:hq]``
|
||||
Adds noise.
|
||||
|
||||
``strength``
|
||||
@@ -438,7 +440,7 @@ Available filters are:
|
||||
(using ``--vf=lavfi=[noise=...]``), or tell the libavfilter developers
|
||||
to stop being stupid.
|
||||
|
||||
``average``
|
||||
``averaged``
|
||||
averaged temporal noise (smoother, but a lot slower)
|
||||
|
||||
``pattern``
|
||||
|
||||
@@ -20,6 +20,9 @@ normal driver parameters.
|
||||
|
||||
See ``--vo=help`` for a list of compiled-in video output drivers.
|
||||
|
||||
The recommended output drivers are ``--vo=vdpau`` and ``--vo=opengl-hq``.
|
||||
All other drivers are just for compatibility or special purposes.
|
||||
|
||||
.. admonition:: Example
|
||||
|
||||
``--vo=opengl,xv,``
|
||||
@@ -32,6 +35,8 @@ Available video output drivers are:
|
||||
the most compatible VO on X, but may be low-quality, and has issues with
|
||||
OSD and subtitle display.
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``adaptor=<number>``
|
||||
Select a specific XVideo adaptor (check xvinfo results).
|
||||
``port=<number>``
|
||||
@@ -172,6 +177,9 @@ Available video output drivers are:
|
||||
``direct3d_shaders`` (Windows only)
|
||||
Video output driver that uses the Direct3D interface.
|
||||
|
||||
.. note:: This driver is for compatibility with systems that don't provide
|
||||
proper OpenGL drivers.
|
||||
|
||||
``prefer-stretchrect``
|
||||
Use ``IDirect3DDevice9::StretchRect`` over other methods if possible.
|
||||
|
||||
@@ -228,11 +236,15 @@ Available video output drivers are:
|
||||
Same as ``direct3d_shaders``, but with the options ``disable-textures``
|
||||
and ``disable-shaders`` forced.
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``corevideo`` (Mac OS X 10.6 and later)
|
||||
Mac OS X CoreVideo video output driver. Uses the CoreVideo APIs to fill
|
||||
PixelBuffers and generate OpenGL textures from them (useful as a fallback
|
||||
for ``opengl``).
|
||||
|
||||
.. note:: This driver is for compatibility with old systems.
|
||||
|
||||
``opengl``
|
||||
OpenGL video output driver. It supports extended scaling methods, dithering
|
||||
and color management.
|
||||
@@ -519,6 +531,8 @@ Available video output drivers are:
|
||||
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
|
||||
@@ -692,6 +706,9 @@ Available video output drivers are:
|
||||
hardware acceleration. Should work on all platforms supported by SDL 2.0.
|
||||
For tuning, refer to your copy of the file ``SDL_hints.h``.
|
||||
|
||||
.. note:: This driver is for compatibility with systems that don't provide
|
||||
proper graphics drivers, or which support GLES only.
|
||||
|
||||
``sw``
|
||||
Continue even if a software renderer is detected.
|
||||
|
||||
@@ -704,6 +721,9 @@ Available video output drivers are:
|
||||
hardware decoding to save power on laptops, or possibly preventing video
|
||||
tearing with some setups.
|
||||
|
||||
.. note:: This driver is for compatibility with crappy systems. You can
|
||||
use vaapi hardware decoding with ``--vo=opengl`` too.
|
||||
|
||||
``scaling=<algorithm>``
|
||||
default
|
||||
Driver default (mpv default as well).
|
||||
@@ -744,6 +764,8 @@ Available video output drivers are:
|
||||
``caca``
|
||||
Color ASCII art video output driver that works on a text console.
|
||||
|
||||
.. note:: This driver is a joke.
|
||||
|
||||
``image``
|
||||
Output each frame into an image file in the current directory. Each file
|
||||
takes the frame number padded with leading zeros as name.
|
||||
@@ -789,6 +811,9 @@ Available video output drivers are:
|
||||
``wayland`` (Wayland only)
|
||||
Wayland shared memory video output as fallback for ``opengl``.
|
||||
|
||||
.. note:: This driver is for compatibility with systems that don't provide
|
||||
working OpenGL drivers.
|
||||
|
||||
``default-format``
|
||||
Use the default RGB32 format instead of an auto-detected one.
|
||||
|
||||
|
||||
@@ -45,13 +45,24 @@ Essential dependencies (incomplete list):
|
||||
- gcc or clang
|
||||
- X development headers (xlib, X extensions, libvdpau, libGL, libXv, ...)
|
||||
- Audio output development headers (libasound, pulseaudio)
|
||||
- fribidi, freetype, fontconfig development headers (for libass)
|
||||
- libass
|
||||
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libpostproc)
|
||||
- libjpeg
|
||||
- FFmpeg libraries (libavutil libavcodec libavformat libswscale libavresample)
|
||||
At least FFmpeg 1.2.4 or Libav 9.10 is required. (If FFmpeg was compiled
|
||||
without libavresample, at least FFmpeg 2.0 is required.)
|
||||
- libjpeg (for screenshots)
|
||||
- libquvi if you want to play Youtube videos directly
|
||||
|
||||
Libass dependencies:
|
||||
|
||||
- gcc or clang, yasm on x86 and x86_64
|
||||
- fribidi, freetype, fontconfig development headers (for libass)
|
||||
|
||||
FFmpeg dependencies:
|
||||
|
||||
- gcc or clang, yasm on x86 and x86_64
|
||||
- OpenSSL (has to be explicitly enabled when compiling ffmpeg)
|
||||
- libx264/libmp3lame/libfdk-aac if you want to use encoding (has to be
|
||||
explicitly enabled when compiling ffmpeg)
|
||||
- Libav also works, but some features will not work. (See section below.)
|
||||
|
||||
Most of the above libraries are available in suitable versions on normal
|
||||
Linux distributions. However FFmpeg is an exception (distro versions may be
|
||||
@@ -71,6 +82,22 @@ Generally, mpv should work with the latest release as well as the git version
|
||||
of both FFmpeg and Libav. But FFmpeg is preferred, and some mpv features work
|
||||
with FFmpeg only. See the [wiki article][ffmpeg_vs_libav] about the issue.
|
||||
|
||||
|
||||
Release cycle
|
||||
-------------
|
||||
|
||||
Every few months, a new release is cut off of the master branch. Currently,
|
||||
these releases are assigned a version number ``0.X.0``. Only the latest release
|
||||
is maintained. As part of the maintenance process, minor releases are made,
|
||||
which are assigned ``0.X.Y`` version numbers. Minor releases contain bug fixes
|
||||
only. They never merge the master branch, and no features are added to it. The
|
||||
goal of releases is to provide stability and an unchanged base for the sake of
|
||||
Linux distributions. If you want the newest features, just use the master
|
||||
branch. (The master branch is stable most of the time, except sometimes, when
|
||||
it's not.)
|
||||
|
||||
Releases other than the latest release are unsupported and unmaintained.
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
|
||||
@@ -84,8 +111,8 @@ For small changes you can just send us pull requests through GitHub. For bigger
|
||||
changes come and talk to us on IRC before you start working on them. It will
|
||||
make code review easier for both parties later on.
|
||||
|
||||
Contacts
|
||||
--------
|
||||
Contact
|
||||
-------
|
||||
|
||||
These forms of contact are meant to ask questions about mpv usage, give
|
||||
feedback on mpv and discuss it's development.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Build system switches to waf. The old build system is still available by
|
||||
running ``./old-configure``, but it will be removed some time in the future.
|
||||
- The "run" input command changes in a not backwards compatible way.
|
||||
- Some input.conf commands were replaced (such as speed_mult).
|
||||
- Many audio/video filter have changed sub-options in a not backwards
|
||||
compatible way. (This is a consequence of unifying audio/video filter
|
||||
option parsing.)
|
||||
- Most video filters now use libavfilter internally if available.
|
||||
- Disable key autorepeat for some key binds, which prevents accidentally
|
||||
triggering a binding multiple times.
|
||||
- Encoding: install and include encoding profiles by default.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix a bug that degraded vdpau playback after ~1 hour of runtime.
|
||||
- Restrict hardware decoding to codecs where it generally makes sense. This
|
||||
excludes mpeg4 for example, which often causes hardware decoders to decode to
|
||||
garbage. Use ``--hwdec-codecs`` to enable hardware decoding for more codecs.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
- Add window-scale property, which allows changing the window size via mpv key
|
||||
bindings.
|
||||
- Add revert_seek command, which is meant to undo accidental seeks.
|
||||
- Hardware decoding (vdpau, vda, vaapi) can now be used with vo_opengl.
|
||||
- Pulseaudio: set pulse stream name to mpv window title (like MPlayer).
|
||||
- Support showing 2 subtitles at a time (``--secondary-sid``).
|
||||
- Re-add some basic ``dvdnav://`` support. This doesn't handle navigation
|
||||
highlights correctly, but navigation should mostly work. (Note that
|
||||
``dvdnav://`` by default starts the longest title, instead of the DVD menu.
|
||||
The menu is available with ``dvdnav://menu``.)
|
||||
- Win32: you can drop files on the mpv window.
|
||||
|
||||
This listing is not complete. There are many more bug fixes and changes. The
|
||||
complete change log can be viewed by running ``git log f572d2..f06a87`` in
|
||||
the git repository.
|
||||
@@ -132,7 +132,8 @@ sub _bin2int($) {
|
||||
# creates a floating-point number with the given mantissa and exponent
|
||||
sub _ldexp {
|
||||
my ($mantissa, $exponent) = @_;
|
||||
return $mantissa * Math::BigRat->new(2)**$exponent;
|
||||
my $r = new Math::BigRat($mantissa);
|
||||
return $r * Math::BigRat->new(2)**$exponent;
|
||||
}
|
||||
|
||||
# NOTE: the read_* functions are hard to read because they're ports
|
||||
@@ -252,25 +253,27 @@ bytes from the internal filehandle.
|
||||
Only lengths C<4> and C<8> are supported (C C<float> and C<double>).
|
||||
|
||||
=cut
|
||||
sub read_float {
|
||||
my ($self, $length) = @_;
|
||||
my $i = $self->read_uint($length);
|
||||
my $f;
|
||||
{
|
||||
my $b1 = new Math::BigInt 1;
|
||||
|
||||
use bigrat try => BIGINT_TRY;
|
||||
sub read_float {
|
||||
my ($self, $length) = @_;
|
||||
my $i = new Math::BigInt $self->read_uint($length)->bstr;
|
||||
my $f;
|
||||
|
||||
# These evil expressions reinterpret an unsigned int as IEEE binary floats
|
||||
if ($length == 4) {
|
||||
$f = _ldexp(($i & (1<<23 - 1)) + (1<<23), ($i>>23 & (1<<8 - 1)) - 150);
|
||||
$f = -$f if $i & (1<<31);
|
||||
} elsif ($length == 8) {
|
||||
$f = _ldexp(($i & (1<<52 - 1)) + (1<<52), ($i>>52 & (1<<12 - 1)) - 1075);
|
||||
$f = -$f if $i & (1<<63);
|
||||
} else {
|
||||
croak "Matroska Syntax error: unsupported IEEE float byte size $length";
|
||||
# These evil expressions reinterpret an unsigned int as IEEE binary floats
|
||||
if ($length == 4) {
|
||||
$f = _ldexp(($i & ((1<<23) - 1)) + (1<<23), ($i>>23 & ((1<<8) - 1)) - 150);
|
||||
$f = -$f if $i & ($b1<<31);
|
||||
} elsif ($length == 8) {
|
||||
$f = _ldexp(($i & (($b1<<52) - 1)) + ($b1<<52), ($i>>52 & ((1<<12) - 1)) - 1075);
|
||||
$f = -$f if $i & ($b1<<63);
|
||||
} else {
|
||||
croak "Matroska Syntax error: unsupported IEEE float byte size $length";
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
|
||||
=method read_ebml_id($length)
|
||||
|
||||
+48
-17
@@ -3,20 +3,18 @@
|
||||
"""
|
||||
This script emulates "unique application" functionality on Linux. When starting
|
||||
playback with this script, it will try to reuse an already running instance of
|
||||
mpv (but only if that was started with umpv).
|
||||
mpv (but only if that was started with umpv). Other mpv instances (not started
|
||||
by umpv) are ignored, and the script doesn't know about them.
|
||||
|
||||
This script only uses mpv instances started with umpv. Other instances are
|
||||
ignored, and don't exist for the script.
|
||||
|
||||
This only takes filenames as arguments. If mpv is already running, they are
|
||||
appended to mpv's internal playlist. If the file does not exist or is otherwise
|
||||
not playable, mpv will skip the playlist entry when attempting to play it (from
|
||||
the GUI perspective, it's silently ignored).
|
||||
This only takes filenames as arguments. Custom options can't be used; the script
|
||||
interprets them as filenames. If mpv is already running, the files passed to
|
||||
umpv are appended to mpv's internal playlist. If a file does not exist or is
|
||||
otherwise not playable, mpv will skip the playlist entry when attempting to
|
||||
play it (from the GUI perspective, it's silently ignored).
|
||||
|
||||
If mpv isn't running yet, this script will start mpv and let it control the
|
||||
current terminal. If you play an audio-only file, mpv will not open a window
|
||||
(that is its normal behavior; but it might not be what a user expects if this
|
||||
script is used in a GUI setting).
|
||||
current terminal. It will not write output to stdout/stderr, because this
|
||||
will typically just fill ~/.xsession-errors with garbage.
|
||||
|
||||
mpv will terminate if there are no more files to play, and running the umpv
|
||||
script after that will start a new mpv instance.
|
||||
@@ -25,10 +23,18 @@ Note that you can control the mpv instance by writing to the command fifo:
|
||||
|
||||
echo "cycle fullscreen" > /tmp/umpv-fifo-*
|
||||
|
||||
Note: you can supply custom options with the UMPV_OPTIONS environment variable.
|
||||
The environment variable will be split on whitespace, and each item is
|
||||
passed as option to mpv _if_ the script starts mpv. If mpv is not started
|
||||
by the script (i.e. mpv is already running), the options will be ignored.
|
||||
|
||||
Warning:
|
||||
|
||||
The script attempts to make sure the FIFO is safely created (i.e. not world-
|
||||
readable, not trying to open a bogus
|
||||
writable), and checks that it's really a FIFO. This is important for security,
|
||||
because the FIFO allows anyone with write access to run arbitrary commands
|
||||
in mpv's context using the "run" input command. If you are worried about
|
||||
security, you should verify that the code handles these concerns correctly.
|
||||
"""
|
||||
|
||||
import sys
|
||||
@@ -37,13 +43,33 @@ import errno
|
||||
import subprocess
|
||||
import fcntl
|
||||
import stat
|
||||
import string
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("error: needs at least one file as argument.")
|
||||
if len(sys.argv) < 1:
|
||||
sys.exit(1)
|
||||
files = sys.argv[1:]
|
||||
|
||||
# this is about the same method mpv uses to decide this
|
||||
def is_url(filename):
|
||||
parts = filename.split(":", 1)
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
# protocol prefix has no special characters => it's an URL
|
||||
prefix = parts[0]
|
||||
for c in prefix:
|
||||
if string.ascii_letters.find(c) < 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
# make them absolute; also makes them safe against interpretation as options
|
||||
files = [os.path.abspath(f) for f in files]
|
||||
def make_abs(filename):
|
||||
if not is_url(filename):
|
||||
return os.path.abspath(filename)
|
||||
return filename
|
||||
files = [make_abs(f) for f in files]
|
||||
|
||||
opts_env = os.getenv("UMPV_OPTIONS")
|
||||
opts_env = opts_env.split() if opts_env else []
|
||||
|
||||
FIFO = "/tmp/umpv-fifo-" + os.getenv("USER")
|
||||
|
||||
@@ -86,6 +112,11 @@ else:
|
||||
pass
|
||||
else:
|
||||
raise e
|
||||
os.mkfifo(FIFO, 0600)
|
||||
os.mkfifo(FIFO, int("0600", 8))
|
||||
|
||||
subprocess.check_call(["mpv", "--input-file=" + FIFO] + files)
|
||||
opts = ["mpv", "--really-quiet", "--force-window", "--input-file=" + FIFO]
|
||||
opts.extend(opts_env)
|
||||
opts.append("--")
|
||||
opts.extend(files)
|
||||
|
||||
subprocess.check_call(opts)
|
||||
+12
-2
@@ -15,6 +15,9 @@
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libavutil/mem.h>
|
||||
@@ -145,6 +148,8 @@ static void mp_audio_destructor(void *ptr)
|
||||
void mp_audio_realloc(struct mp_audio *mpa, int samples)
|
||||
{
|
||||
assert(samples >= 0);
|
||||
if (samples >= INT_MAX / mpa->sstride)
|
||||
abort(); // oom
|
||||
int size = MPMAX(samples * mpa->sstride, 1);
|
||||
for (int n = 0; n < mpa->num_planes; n++) {
|
||||
if (size != mpa->allocated[n]) {
|
||||
@@ -168,10 +173,15 @@ void mp_audio_realloc(struct mp_audio *mpa, int samples)
|
||||
}
|
||||
|
||||
// Like mp_audio_realloc(), but only reallocate if the audio grows in size.
|
||||
// If the buffer is reallocated, also preallocate.
|
||||
void mp_audio_realloc_min(struct mp_audio *mpa, int samples)
|
||||
{
|
||||
if (samples > mp_audio_get_allocated_size(mpa))
|
||||
mp_audio_realloc(mpa, samples);
|
||||
if (samples > mp_audio_get_allocated_size(mpa)) {
|
||||
size_t alloc = ta_calc_prealloc_elems(samples);
|
||||
if (alloc > INT_MAX)
|
||||
abort(); // oom
|
||||
mp_audio_realloc(mpa, alloc);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the size allocated for the data, in number of samples. If the allocated
|
||||
|
||||
+1
-1
@@ -485,5 +485,5 @@ void mp_chmap_print_help(struct mp_log *log)
|
||||
std_layout_names[n][0], std_layout_names[n][1]);
|
||||
}
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++)
|
||||
mp_info(log, " unknown%d\n", n);
|
||||
mp_info(log, " unknown%d\n", n + 1);
|
||||
}
|
||||
+4
-10
@@ -172,11 +172,8 @@ static void set_from_wf(AVCodecContext *avctx, MP_WAVEFORMATEX *wf)
|
||||
avctx->block_align = wf->nBlockAlign;
|
||||
avctx->bits_per_coded_sample = wf->wBitsPerSample;
|
||||
|
||||
if (wf->cbSize > 0) {
|
||||
avctx->extradata = av_mallocz(wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
avctx->extradata_size = wf->cbSize;
|
||||
memcpy(avctx->extradata, wf + 1, avctx->extradata_size);
|
||||
}
|
||||
if (wf->cbSize > 0)
|
||||
mp_lavc_set_extradata(avctx, wf + 1, wf->cbSize);
|
||||
}
|
||||
|
||||
static int init(struct dec_audio *da, const char *decoder)
|
||||
@@ -244,11 +241,8 @@ static int init(struct dec_audio *da, const char *decoder)
|
||||
// demux_mkv, demux_mpg
|
||||
if (sh_audio->codecdata_len && sh_audio->codecdata &&
|
||||
!lavc_context->extradata) {
|
||||
lavc_context->extradata = av_malloc(sh_audio->codecdata_len +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
lavc_context->extradata_size = sh_audio->codecdata_len;
|
||||
memcpy(lavc_context->extradata, (char *)sh_audio->codecdata,
|
||||
lavc_context->extradata_size);
|
||||
mp_lavc_set_extradata(lavc_context, sh_audio->codecdata,
|
||||
sh_audio->codecdata_len);
|
||||
}
|
||||
|
||||
if (sh->lav_headers)
|
||||
|
||||
+18
-18
@@ -345,26 +345,28 @@ static int af_count_filters(struct af_stream *s)
|
||||
// (So we know what conversion filter with what format to insert next.)
|
||||
static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
|
||||
{
|
||||
#define NUM_FMT 64
|
||||
#define NUM_FILT 32
|
||||
#define NUM_NODES (NUM_FMT * NUM_FILT)
|
||||
#define MAX_NODES (64 * 32)
|
||||
int num_fmt = 0, num_filt = 0;
|
||||
for (int n = 0; filter_list[n]; n++)
|
||||
assert(n < NUM_FILT);
|
||||
num_filt = n + 1;
|
||||
for (int n = 0; af_fmtstr_table[n].format; n++)
|
||||
assert(n < NUM_FMT);
|
||||
num_fmt = n + 1;
|
||||
|
||||
bool visited[NUM_NODES] = {0};
|
||||
unsigned char distance[NUM_NODES];
|
||||
short previous[NUM_NODES] = {0};
|
||||
for (int n = 0; n < NUM_NODES; n++) {
|
||||
int num_nodes = num_fmt * num_filt;
|
||||
assert(num_nodes < MAX_NODES);
|
||||
|
||||
bool visited[MAX_NODES] = {0};
|
||||
unsigned char distance[MAX_NODES];
|
||||
short previous[MAX_NODES] = {0};
|
||||
for (int n = 0; n < num_nodes; n++) {
|
||||
distance[n] = 255;
|
||||
if (af_fmtstr_table[n % NUM_FMT].format == srcfmt)
|
||||
if (af_fmtstr_table[n % num_fmt].format == srcfmt)
|
||||
distance[n] = 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int next = -1;
|
||||
for (int n = 0; n < NUM_NODES; n++) {
|
||||
for (int n = 0; n < num_nodes; n++) {
|
||||
if (!visited[n] && (next < 0 || (distance[n] < distance[next])))
|
||||
next = n;
|
||||
}
|
||||
@@ -372,13 +374,13 @@ static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
|
||||
return NULL;
|
||||
visited[next] = true;
|
||||
|
||||
int fmt = next % NUM_FMT;
|
||||
int fmt = next % num_fmt;
|
||||
if (af_fmtstr_table[fmt].format == *dstfmt) {
|
||||
// Best match found
|
||||
for (int cur = next; cur >= 0; cur = previous[cur] - 1) {
|
||||
if (distance[cur] == 1) {
|
||||
*dstfmt = af_fmtstr_table[cur % NUM_FMT].format;
|
||||
return (char *)filter_list[cur / NUM_FMT]->name;
|
||||
*dstfmt = af_fmtstr_table[cur % num_fmt].format;
|
||||
return (char *)filter_list[cur / num_fmt]->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
@@ -392,7 +394,7 @@ static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
|
||||
if (i != fmt && af->test_conversion(af_fmtstr_table[fmt].format,
|
||||
af_fmtstr_table[i].format))
|
||||
{
|
||||
int other = n * NUM_FMT + i;
|
||||
int other = n * num_fmt + i;
|
||||
int ndist = distance[next] + 1;
|
||||
if (ndist < distance[other]) {
|
||||
distance[other] = ndist;
|
||||
@@ -403,9 +405,7 @@ static char *af_find_conversion_filter(int srcfmt, int *dstfmt)
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
#undef NUM_FMT
|
||||
#undef NUM_FILT
|
||||
#undef NODE_N
|
||||
#undef MAX_NODES
|
||||
}
|
||||
|
||||
static bool af_is_conversion_filter(struct af_instance *af)
|
||||
|
||||
@@ -74,7 +74,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
|
||||
struct mp_audio *in = arg;
|
||||
struct mp_audio orig_in = *in;
|
||||
|
||||
if (AF_FORMAT_IS_AC3(in->format) || in->nch < s->cfg_min_channel_num)
|
||||
if (AF_FORMAT_IS_SPECIAL(in->format) || in->nch < s->cfg_min_channel_num)
|
||||
return AF_DETACH;
|
||||
|
||||
mp_audio_set_format(in, s->in_sampleformat);
|
||||
|
||||
@@ -153,13 +153,13 @@ static int af_open(struct af_instance* af){
|
||||
int j,k;
|
||||
|
||||
int nch = s->nch;
|
||||
if(AF_OK != control(af,AF_CONTROL_SET_PAN_NOUT, &nch))
|
||||
if(nch && AF_OK != control(af,AF_CONTROL_SET_PAN_NOUT, &nch))
|
||||
return AF_ERROR;
|
||||
|
||||
// Read pan values
|
||||
char *cp = s->matrixstr;
|
||||
j = 0; k = 0;
|
||||
while(k < AF_NCH){
|
||||
while(cp && k < AF_NCH){
|
||||
sscanf(cp, "%f%n" , &s->level[j][k], &n);
|
||||
MP_VERBOSE(af, "[pan] Pan level from channel %i to"
|
||||
" channel %i = %f\n",k,j,s->level[j][k]);
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ enum af_format {
|
||||
// Planar variants
|
||||
AF_FORMAT_U8P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_8BIT|AF_FORMAT_NE),
|
||||
AF_FORMAT_S16P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_16BIT|AF_FORMAT_NE),
|
||||
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_US|AF_FORMAT_32BIT|AF_FORMAT_NE),
|
||||
AF_FORMAT_S32P = (AF_INTP|AF_FORMAT_SI|AF_FORMAT_32BIT|AF_FORMAT_NE),
|
||||
AF_FORMAT_FLOATP = (AF_FLTP|AF_FORMAT_32BIT|AF_FORMAT_NE),
|
||||
AF_FORMAT_DOUBLEP = (AF_FLTP|AF_FORMAT_64BIT|AF_FORMAT_NE),
|
||||
|
||||
|
||||
+11
-8
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
|
||||
@@ -245,8 +246,9 @@ char *mixer_get_volume_restore_data(struct mixer *mixer)
|
||||
{
|
||||
if (!mixer->driver[0])
|
||||
return NULL;
|
||||
return talloc_asprintf(NULL, "%s:%f:%f:%d", mixer->driver, mixer->vol_l,
|
||||
mixer->vol_r, mixer->muted_by_us);
|
||||
return talloc_asprintf(NULL, "%s:%f:%f:%d:%f", mixer->driver, mixer->vol_l,
|
||||
mixer->vol_r, mixer->muted_by_us,
|
||||
mixer->opts->softvol_max);
|
||||
}
|
||||
|
||||
static void probe_softvol(struct mixer *mixer)
|
||||
@@ -307,19 +309,20 @@ static void restore_volume(struct mixer *mixer)
|
||||
force_mute = opts->mixer_init_mute;
|
||||
|
||||
// Set parameters from playback resume.
|
||||
char *restore_data = mixer->opts->mixer_restore_volume_data;
|
||||
if (restore && restore_data && restore_data[0]) {
|
||||
char *data = mixer->opts->mixer_restore_volume_data;
|
||||
if (restore && data && data[0]) {
|
||||
char drv[40];
|
||||
float v_l, v_r;
|
||||
float v_l, v_r, s;
|
||||
int m;
|
||||
if (sscanf(restore_data, "%39[^:]:%f:%f:%d", drv, &v_l, &v_r, &m) == 4) {
|
||||
if (strcmp(mixer->driver, drv) == 0) {
|
||||
if (sscanf(data, "%39[^:]:%f:%f:%d:%f", drv, &v_l, &v_r, &m, &s) == 5) {
|
||||
float diff = fabs(mixer->opts->softvol_max - s);
|
||||
if (strcmp(mixer->driver, drv) == 0 && diff < 0.01) {
|
||||
force_vol_l = v_l;
|
||||
force_vol_r = v_r;
|
||||
force_mute = !!m;
|
||||
}
|
||||
}
|
||||
talloc_free(restore_data);
|
||||
talloc_free(mixer->opts->mixer_restore_volume_data);
|
||||
mixer->opts->mixer_restore_volume_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
+14
-11
@@ -100,7 +100,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
|
||||
float f_multi;
|
||||
|
||||
if (AF_FORMAT_IS_IEC61937(ao->format))
|
||||
return CONTROL_TRUE;
|
||||
return CONTROL_FALSE;
|
||||
|
||||
//allocate simple id
|
||||
snd_mixer_selem_id_alloca(&sid);
|
||||
@@ -561,9 +561,11 @@ static void audio_pause(struct ao *ao)
|
||||
int err;
|
||||
|
||||
if (p->can_pause) {
|
||||
p->delay_before_pause = get_delay(ao);
|
||||
err = snd_pcm_pause(p->alsa, 1);
|
||||
CHECK_ALSA_ERROR("pcm pause error");
|
||||
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_RUNNING) {
|
||||
p->delay_before_pause = get_delay(ao);
|
||||
err = snd_pcm_pause(p->alsa, 1);
|
||||
CHECK_ALSA_ERROR("pcm pause error");
|
||||
}
|
||||
} else {
|
||||
MP_VERBOSE(ao, "pause not supported by hardware\n");
|
||||
if (snd_pcm_delay(p->alsa, &p->prepause_frames) < 0
|
||||
@@ -585,12 +587,16 @@ static void audio_resume(struct ao *ao)
|
||||
|
||||
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_SUSPENDED) {
|
||||
MP_INFO(ao, "PCM in suspend mode, trying to resume.\n");
|
||||
|
||||
while ((err = snd_pcm_resume(p->alsa)) == -EAGAIN)
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (p->can_pause) {
|
||||
err = snd_pcm_pause(p->alsa, 0);
|
||||
CHECK_ALSA_ERROR("pcm resume error");
|
||||
if (snd_pcm_state(p->alsa) == SND_PCM_STATE_PAUSED) {
|
||||
err = snd_pcm_pause(p->alsa, 0);
|
||||
CHECK_ALSA_ERROR("pcm resume error");
|
||||
}
|
||||
} else {
|
||||
MP_VERBOSE(ao, "resume not supported by hardware\n");
|
||||
err = snd_pcm_prepare(p->alsa);
|
||||
@@ -639,11 +645,8 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
||||
/* nothing to do */
|
||||
res = 0;
|
||||
} else if (res == -ESTRPIPE) { /* suspend */
|
||||
MP_INFO(ao, "PCM in suspend mode, trying to resume.\n");
|
||||
while ((res = snd_pcm_resume(p->alsa)) == -EAGAIN)
|
||||
sleep(1);
|
||||
}
|
||||
if (res < 0) {
|
||||
audio_resume(ao);
|
||||
} else if (res < 0) {
|
||||
MP_ERR(ao, "Write error: %s\n", snd_strerror(res));
|
||||
res = snd_pcm_prepare(p->alsa);
|
||||
int err = res;
|
||||
|
||||
@@ -431,6 +431,32 @@ static bool ca_bitmap_from_ch_tag(struct ao *ao, AudioChannelLayout *layout,
|
||||
}
|
||||
}
|
||||
|
||||
static void ca_log_layout(struct ao *ao, AudioChannelLayout layout)
|
||||
{
|
||||
if (!mp_msg_test(ao->log, MSGL_V))
|
||||
return;
|
||||
|
||||
AudioChannelDescription *descs = layout.mChannelDescriptions;
|
||||
|
||||
MP_VERBOSE(ao, "layout: tag: <%d>, bitmap: <%d>, "
|
||||
"descriptions <%d>\n",
|
||||
layout.mChannelLayoutTag,
|
||||
layout.mChannelBitmap,
|
||||
layout.mNumberChannelDescriptions);
|
||||
|
||||
for (int i = 0; i < layout.mNumberChannelDescriptions; i++) {
|
||||
AudioChannelDescription d = descs[i];
|
||||
MP_VERBOSE(ao, " - description %d: label <%d, %d>, flags: <%u>, "
|
||||
"coords: <%f, %f, %f>\n", i,
|
||||
d.mChannelLabel,
|
||||
ca_label_to_mp_speaker_id(d.mChannelLabel),
|
||||
d.mChannelFlags,
|
||||
d.mCoordinates[0],
|
||||
d.mCoordinates[1],
|
||||
d.mCoordinates[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void ca_bitmaps_from_layouts(struct ao *ao,
|
||||
AudioChannelLayout *layouts, size_t n_layouts,
|
||||
uint32_t **bitmaps, size_t *n_bitmaps)
|
||||
@@ -440,6 +466,7 @@ void ca_bitmaps_from_layouts(struct ao *ao,
|
||||
|
||||
for (int i=0; i < n_layouts; i++) {
|
||||
uint32_t bitmap = 0;
|
||||
ca_log_layout(ao, layouts[i]);
|
||||
|
||||
switch (layouts[i].mChannelLayoutTag) {
|
||||
case kAudioChannelLayoutTag_UseChannelBitmap:
|
||||
|
||||
+19
-3
@@ -60,10 +60,12 @@ struct priv {
|
||||
int connect;
|
||||
int autostart;
|
||||
int stdlayout;
|
||||
int last_chunk;
|
||||
volatile int paused;
|
||||
volatile int underrun;
|
||||
volatile float callback_interval;
|
||||
volatile float callback_time;
|
||||
volatile float last_ok_time; // last time real audio was played
|
||||
|
||||
int num_ports;
|
||||
struct port_ring ports[MP_NUM_CHANNELS];
|
||||
@@ -128,11 +130,15 @@ process(jack_nframes_t nframes, void *arg)
|
||||
underrun = 1;
|
||||
}
|
||||
|
||||
float now = mp_time_us() / 1000000.0;
|
||||
|
||||
if (underrun)
|
||||
p->underrun = 1;
|
||||
|
||||
if (!p->underrun)
|
||||
p->last_ok_time = now;
|
||||
|
||||
if (p->estimate) {
|
||||
float now = mp_time_us() / 1000000.0;
|
||||
float diff = p->callback_time + p->callback_interval - now;
|
||||
if ((diff > -0.002) && (diff < 0.002))
|
||||
p->callback_time += p->callback_interval;
|
||||
@@ -289,14 +295,23 @@ static float get_delay(struct ao *ao)
|
||||
struct priv *p = ao->priv;
|
||||
int buffered = mp_ring_buffered(p->ports[0].ring); // could be less
|
||||
float in_jack = p->jack_latency;
|
||||
float now = mp_time_us() / 1000000.0;
|
||||
|
||||
if (p->estimate && p->callback_interval > 0) {
|
||||
float elapsed = mp_time_us() / 1000000.0 - p->callback_time;
|
||||
in_jack += p->callback_interval - elapsed;
|
||||
if (in_jack < 0)
|
||||
in_jack = 0;
|
||||
}
|
||||
|
||||
if (p->underrun && !buffered && p->last_chunk) {
|
||||
// Report correct buffer drainage, when our buffer is empty, but jack
|
||||
// and/or the audio device still have some audio to play.
|
||||
// Assumes audio clock goes at about the same speed as the system time.
|
||||
in_jack += p->last_ok_time - now;
|
||||
}
|
||||
|
||||
if (in_jack < 0)
|
||||
in_jack = 0;
|
||||
|
||||
return (float)buffered / (float)ao->bps + in_jack;
|
||||
}
|
||||
|
||||
@@ -369,6 +384,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
|
||||
}
|
||||
|
||||
p->underrun = 0;
|
||||
p->last_chunk = flags & AOPLAY_FINAL_CHUNK;
|
||||
return ret / ao->sstride;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ static void uninit(struct ao *ao, bool cut_audio)
|
||||
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
|
||||
|
||||
if (!encode_lavc_start(ectx)) {
|
||||
MP_WARN(ao, "not even ready to encode audio at end -> dropped");
|
||||
MP_WARN(ao, "not even ready to encode audio at end -> dropped\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,8 +111,8 @@ static int init(struct ao *ao)
|
||||
return -1;
|
||||
}
|
||||
|
||||
rsd_set_param(priv->rd, RSD_SAMPLERATE, &ao->samplerate);
|
||||
rsd_set_param(priv->rd, RSD_CHANNELS, &ao->channels.num);
|
||||
rsd_set_param(priv->rd, RSD_SAMPLERATE, (int[]) { ao->samplerate });
|
||||
rsd_set_param(priv->rd, RSD_CHANNELS, (int[]) { ao->channels.num });
|
||||
|
||||
ao->format = af_fmt_from_planar(ao->format);
|
||||
|
||||
|
||||
@@ -36,10 +36,6 @@
|
||||
#include "misc/ring.h"
|
||||
#include "ao.h"
|
||||
|
||||
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
|
||||
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 0x00000001
|
||||
#endif
|
||||
|
||||
#ifndef PKEY_Device_FriendlyName
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName,
|
||||
0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20,
|
||||
@@ -136,17 +132,6 @@ static int fill_VistaBlob(wasapi_state *state)
|
||||
{
|
||||
if (!state)
|
||||
return 1;
|
||||
HMODULE hkernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
if (!hkernel32)
|
||||
return 1;
|
||||
WINBOOL (WINAPI *pSetDllDirectory)(LPCWSTR lpPathName) =
|
||||
(WINBOOL (WINAPI *)(LPCWSTR))GetProcAddress(hkernel32, "SetDllDirectoryW");
|
||||
WINBOOL (WINAPI *pSetSearchPathMode)(DWORD Flags) =
|
||||
(WINBOOL (WINAPI *)(DWORD))GetProcAddress(hkernel32, "SetSearchPathMode");
|
||||
if (pSetSearchPathMode)
|
||||
pSetDllDirectory(L""); /* Attempt to use safe search paths */
|
||||
if (pSetSearchPathMode)
|
||||
pSetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
|
||||
state->VistaBlob.hAvrt = LoadLibraryW(L"avrt.dll");
|
||||
if (!state->VistaBlob.hAvrt)
|
||||
goto exit_label;
|
||||
@@ -160,8 +145,6 @@ static int fill_VistaBlob(wasapi_state *state)
|
||||
exit_label:
|
||||
if (state->VistaBlob.hAvrt)
|
||||
FreeLibrary(state->VistaBlob.hAvrt);
|
||||
if (pSetSearchPathMode)
|
||||
pSetDllDirectory(NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -5,9 +5,9 @@
|
||||
from __future__ import print_function
|
||||
import os, sys, stat, hashlib, subprocess
|
||||
|
||||
WAFRELEASE = "waf-1.7.13"
|
||||
WAFRELEASE = "waf-1.7.15"
|
||||
WAFURL = "https://waf.googlecode.com/files/" + WAFRELEASE
|
||||
SHA256HASH = "03cc750049350ee01cdbc584b70924e333fcc17ba4a2d04648dab1535538a873"
|
||||
SHA256HASH = "e5ae7028f9b2d8ce1acb9fe1092e8010a90ba764d3ac065ea4e846743290b1d6"
|
||||
|
||||
if os.path.exists("waf"):
|
||||
wafver = subprocess.check_output(['./waf', '--version']).decode()
|
||||
|
||||
+14
-10
@@ -29,6 +29,19 @@
|
||||
|
||||
#include "osdep/numcores.h"
|
||||
|
||||
int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size)
|
||||
{
|
||||
if (size) {
|
||||
av_free(avctx->extradata);
|
||||
avctx->extradata_size = 0;
|
||||
avctx->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (!avctx->extradata)
|
||||
return -1;
|
||||
avctx->extradata_size = size;
|
||||
memcpy(avctx->extradata, ptr, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the codec-related fields from st into avctx. This does not set the
|
||||
// codec itself, only codec related header data provided by libavformat.
|
||||
@@ -38,16 +51,7 @@
|
||||
// This is strictly for decoding only.
|
||||
void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st)
|
||||
{
|
||||
if (st->extradata_size) {
|
||||
av_free(avctx->extradata);
|
||||
avctx->extradata_size = 0;
|
||||
avctx->extradata =
|
||||
av_mallocz(st->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
if (avctx->extradata) {
|
||||
avctx->extradata_size = st->extradata_size;
|
||||
memcpy(avctx->extradata, st->extradata, st->extradata_size);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
struct mp_decoder_list;
|
||||
struct demux_packet;
|
||||
|
||||
int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size);
|
||||
void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st);
|
||||
void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb);
|
||||
int64_t mp_pts_to_av(double mp_pts, AVRational *tb);
|
||||
|
||||
+11
-2
@@ -19,5 +19,14 @@
|
||||
// At this point both gcc and clang had __sync_synchronize support for some
|
||||
// time. We only support a full memory barrier.
|
||||
|
||||
#define mp_memory_barrier() __sync_synchronize()
|
||||
#define mp_atomic_add_and_fetch(a, b) __sync_add_and_fetch(a, b)
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_ATOMIC_BUILTINS
|
||||
# define mp_memory_barrier() __atomic_thread_fence(__ATOMIC_SEQ_CST)
|
||||
# define mp_atomic_add_and_fetch(a, b) __atomic_add_fetch(a, b,__ATOMIC_SEQ_CST)
|
||||
#elif HAVE_SYNC_BUILTINS
|
||||
# define mp_memory_barrier() __sync_synchronize()
|
||||
# define mp_atomic_add_and_fetch(a, b) __sync_add_and_fetch(a, b)
|
||||
#else
|
||||
# error "this should have been a configuration error, report a bug please"
|
||||
#endif
|
||||
+8
-2
@@ -226,7 +226,7 @@ struct demux_packet *demux_copy_packet(struct demux_packet *dp)
|
||||
struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
|
||||
{
|
||||
if (demuxer->num_streams > MAX_SH_STREAMS) {
|
||||
MP_WARN(demuxer, "Too many streams.");
|
||||
MP_WARN(demuxer, "Too many streams.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ static bool demux_check_queue_full(demuxer_t *demux)
|
||||
overflow:
|
||||
|
||||
if (!demux->warned_queue_overflow) {
|
||||
MP_ERR(demux, "\nToo many packets in the demuxer "
|
||||
MP_ERR(demux, "Too many packets in the demuxer "
|
||||
"packet queue (video: %d packets in %d bytes, audio: %d "
|
||||
"packets in %d bytes, sub: %d packets in %d bytes).\n",
|
||||
count_packs(demux, STREAM_VIDEO), count_bytes(demux, STREAM_VIDEO),
|
||||
@@ -522,6 +522,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
.glog = log,
|
||||
.filename = talloc_strdup(demuxer, stream->url),
|
||||
.metadata = talloc_zero(demuxer, struct mp_tags),
|
||||
.initializing = true,
|
||||
};
|
||||
demuxer->params = params; // temporary during open()
|
||||
stream_seek(stream, stream->start_pos);
|
||||
@@ -554,6 +555,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
"File is not seekable, but there's a cache: enabling seeking.\n");
|
||||
demuxer->seekable = true;
|
||||
}
|
||||
demuxer->initializing = false;
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
@@ -724,6 +726,8 @@ int demux_info_add_bstr(demuxer_t *demuxer, struct bstr opt, struct bstr param)
|
||||
if (oldval) {
|
||||
if (bstrcmp0(param, oldval) == 0)
|
||||
return 0;
|
||||
}
|
||||
if (!demuxer->initializing) {
|
||||
MP_INFO(demuxer, "Demuxer info %.*s changed to %.*s\n",
|
||||
BSTR_P(opt), BSTR_P(param));
|
||||
}
|
||||
@@ -740,6 +744,8 @@ int demux_info_print(demuxer_t *demuxer)
|
||||
if (!info || !info->num_keys)
|
||||
return 0;
|
||||
|
||||
demux_info_update(demuxer);
|
||||
|
||||
mp_info(demuxer->glog, "Clip info:\n");
|
||||
for (n = 0; n < info->num_keys; n++) {
|
||||
mp_info(demuxer->glog, " %s: %s\n", info->keys[n], info->values[n]);
|
||||
|
||||
@@ -152,6 +152,7 @@ struct demuxer_params {
|
||||
int matroska_wanted_segment;
|
||||
bool *matroska_was_valid;
|
||||
struct ass_library *ass_library;
|
||||
bool expect_subtitle;
|
||||
};
|
||||
|
||||
typedef struct demuxer {
|
||||
@@ -169,6 +170,7 @@ typedef struct demuxer {
|
||||
// File format allows PTS resets (even if the current file is without)
|
||||
bool ts_resets_possible;
|
||||
bool warned_queue_overflow;
|
||||
bool initializing;
|
||||
|
||||
struct sh_stream **streams;
|
||||
int num_streams;
|
||||
|
||||
+36
-28
@@ -90,12 +90,16 @@ struct format_hack {
|
||||
const char *mime_type;
|
||||
int probescore;
|
||||
float analyzeduration;
|
||||
bool max_probe; // use probescore only if max. probe size reached
|
||||
};
|
||||
|
||||
static const struct format_hack format_hacks[] = {
|
||||
// for webradios
|
||||
{"aac", "audio/aacp", 25, 0.5},
|
||||
{"aac", "audio/aac", 25, 0.5},
|
||||
{"mp3", "audio/mpeg", 25, 0.5},
|
||||
// some mp3 files don't detect correctly
|
||||
{"mp3", "audio/mpeg", 24, 0.5},
|
||||
{"mp3", NULL, 24, .max_probe = true},
|
||||
{0}
|
||||
};
|
||||
|
||||
@@ -104,15 +108,6 @@ static const char *format_blacklist[] = {
|
||||
0
|
||||
};
|
||||
|
||||
static const struct format_hack *find_format_from_mime_type(char *mime_type)
|
||||
{
|
||||
for (int n = 0; format_hacks[n].ff_name; n++) {
|
||||
if (strcasecmp(format_hacks[n].mime_type, mime_type) == 0)
|
||||
return &format_hacks[n];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mp_read(void *opaque, uint8_t *buf, int size)
|
||||
{
|
||||
struct demuxer *demuxer = opaque;
|
||||
@@ -223,17 +218,9 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
|
||||
priv->filename = sep + 1;
|
||||
}
|
||||
|
||||
const char *expected_format = NULL;
|
||||
int expected_format_probescore = AVPROBE_SCORE_MAX;
|
||||
char *mime_type = demuxer->stream->mime_type;
|
||||
|
||||
if (lavfdopts->allow_mimetype && mime_type) {
|
||||
priv->format_hack = find_format_from_mime_type(mime_type);
|
||||
if (priv->format_hack) {
|
||||
expected_format = priv->format_hack->ff_name;
|
||||
expected_format_probescore = priv->format_hack->probescore;
|
||||
}
|
||||
}
|
||||
if (!lavfdopts->allow_mimetype || !mime_type)
|
||||
mime_type = "";
|
||||
|
||||
const char *format = lavfdopts->format;
|
||||
if (!format)
|
||||
@@ -264,17 +251,18 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
|
||||
|
||||
AVProbeData avpd = {
|
||||
// Disable file-extension matching with normal checks
|
||||
.filename = check <= DEMUX_CHECK_REQUEST ? priv->filename : NULL,
|
||||
.filename = check <= DEMUX_CHECK_REQUEST ? priv->filename : "",
|
||||
.buf_size = 0,
|
||||
.buf = av_mallocz(PROBE_BUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE),
|
||||
};
|
||||
|
||||
while (avpd.buf_size < PROBE_BUF_SIZE) {
|
||||
bool final_probe = false;
|
||||
do {
|
||||
int nsize = av_clip(avpd.buf_size * 2, INITIAL_PROBE_SIZE,
|
||||
PROBE_BUF_SIZE);
|
||||
bstr buf = stream_peek(s, nsize);
|
||||
if (buf.len <= avpd.buf_size)
|
||||
break;
|
||||
final_probe = true;
|
||||
memcpy(avpd.buf, buf.start, buf.len);
|
||||
avpd.buf_size = buf.len;
|
||||
|
||||
@@ -283,20 +271,32 @@ static int lavf_check_file(demuxer_t *demuxer, enum demux_check check)
|
||||
|
||||
if (priv->avif) {
|
||||
MP_VERBOSE(demuxer, "Found '%s' at score=%d size=%d.\n",
|
||||
priv->avif->name, score, avpd.buf_size);
|
||||
priv->avif->name, score, avpd.buf_size);
|
||||
|
||||
priv->format_hack = NULL;
|
||||
for (int n = 0; format_hacks[n].ff_name; n++) {
|
||||
const struct format_hack *entry = &format_hacks[n];
|
||||
if (strcmp(entry->ff_name, priv->avif->name) != 0)
|
||||
continue;
|
||||
if (entry->mime_type && strcasecmp(entry->mime_type, mime_type) != 0)
|
||||
continue;
|
||||
priv->format_hack = entry;
|
||||
break;
|
||||
}
|
||||
|
||||
if (score >= min_probe)
|
||||
break;
|
||||
|
||||
if (expected_format) {
|
||||
if (strcmp(priv->avif->name, expected_format) == 0 &&
|
||||
score >= expected_format_probescore)
|
||||
if (priv->format_hack) {
|
||||
if (score >= priv->format_hack->probescore &&
|
||||
(!priv->format_hack->max_probe || final_probe))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
priv->avif = NULL;
|
||||
}
|
||||
priv->format_hack = NULL;
|
||||
} while (!final_probe);
|
||||
|
||||
av_free(avpd.buf);
|
||||
|
||||
@@ -458,6 +458,14 @@ static void handle_stream(demuxer_t *demuxer, int i)
|
||||
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
|
||||
sh_sub->extradata_len = codec->extradata_size;
|
||||
}
|
||||
sh_sub->w = codec->width;
|
||||
sh_sub->h = codec->height;
|
||||
|
||||
// Hack for MicroDVD: if time_base matches the ffmpeg microdvd reader's
|
||||
// default FPS (23.976), assume the MicroDVD file did not declare a
|
||||
// FPS, and the MicroDVD file uses frame based timing.
|
||||
if (codec->time_base.num == 125 && codec->time_base.den == 2997)
|
||||
sh_sub->frame_based = true;
|
||||
break;
|
||||
}
|
||||
case AVMEDIA_TYPE_ATTACHMENT: {
|
||||
|
||||
+23
-12
@@ -723,7 +723,7 @@ static int demux_mkv_read_cues(demuxer_t *demuxer)
|
||||
stream_t *s = demuxer->stream;
|
||||
|
||||
if (opts->index_mode == 0 || opts->index_mode == 2) {
|
||||
ebml_read_skip(s, NULL);
|
||||
ebml_read_skip(demuxer->log, -1, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1128,7 +1128,7 @@ static int read_header_element(struct demuxer *demuxer, uint32_t id,
|
||||
res = 2;
|
||||
}
|
||||
if (!at_filepos && id != EBML_ID_INVALID)
|
||||
ebml_read_skip(s, NULL);
|
||||
ebml_read_skip(demuxer->log, -1, s);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1173,6 +1173,7 @@ typedef struct {
|
||||
char *id;
|
||||
int fourcc;
|
||||
int extradata;
|
||||
bool parse;
|
||||
} videocodec_info_t;
|
||||
|
||||
static const videocodec_info_t vinfo[] = {
|
||||
@@ -1185,11 +1186,11 @@ static const videocodec_info_t vinfo[] = {
|
||||
{MKV_V_MPEG4_AVC, MP_FOURCC('a', 'v', 'c', '1'), 1},
|
||||
{MKV_V_THEORA, MP_FOURCC('t', 'h', 'e', 'o'), 1},
|
||||
{MKV_V_VP8, MP_FOURCC('V', 'P', '8', '0'), 0},
|
||||
{MKV_V_VP9, MP_FOURCC('V', 'P', '9', '0'), 0},
|
||||
{MKV_V_VP9, MP_FOURCC('V', 'P', '9', '0'), 0, true},
|
||||
{MKV_V_DIRAC, MP_FOURCC('d', 'r', 'a', 'c'), 0},
|
||||
{MKV_V_PRORES, MP_FOURCC('p', 'r', '0', '0'), 0},
|
||||
{MKV_V_HEVC, MP_FOURCC('H', 'E', 'V', 'C'), 1},
|
||||
{NULL, 0, 0}
|
||||
{0}
|
||||
};
|
||||
|
||||
static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
|
||||
@@ -1273,6 +1274,7 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track)
|
||||
extradata = track->private_data;
|
||||
extradata_size = track->private_size;
|
||||
}
|
||||
track->parse = vi->parse;
|
||||
if (!vi->id) {
|
||||
MP_WARN(demuxer, "Unknown/unsupported "
|
||||
"CodecID (%s) or missing/bad CodecPrivate\n"
|
||||
@@ -1336,7 +1338,7 @@ static struct mkv_audio_tag {
|
||||
bool parse;
|
||||
} mkv_audio_tags[] = {
|
||||
{ MKV_A_MP2, 0, 0x0055 },
|
||||
{ MKV_A_MP3, 0, 0x0055 },
|
||||
{ MKV_A_MP3, 0, 0x0055, true },
|
||||
{ MKV_A_AC3, 1, 0x2000 },
|
||||
{ MKV_A_EAC3, 1, MP_FOURCC('E', 'A', 'C', '3') },
|
||||
{ MKV_A_DTS, 0, 0x2001 },
|
||||
@@ -2270,7 +2272,7 @@ static void index_block(demuxer_t *demuxer, struct block_info *block)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_block(demuxer_t *demuxer, struct block_info *block)
|
||||
static int read_block(demuxer_t *demuxer, int64_t end, struct block_info *block)
|
||||
{
|
||||
mkv_demuxer_t *mkv_d = (mkv_demuxer_t *) demuxer->priv;
|
||||
stream_t *s = demuxer->stream;
|
||||
@@ -2281,7 +2283,7 @@ static int read_block(demuxer_t *demuxer, struct block_info *block)
|
||||
|
||||
free_block(block);
|
||||
length = ebml_read_length(s, NULL);
|
||||
if (length > 500000000)
|
||||
if (length > 500000000 || stream_tell(s) + length > (uint64_t)end)
|
||||
goto exit;
|
||||
block->alloc = malloc(length + AV_LZO_INPUT_PADDING);
|
||||
if (!block->alloc)
|
||||
@@ -2442,7 +2444,7 @@ static int read_block_group(demuxer_t *demuxer, int64_t end,
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_BLOCK:
|
||||
if (read_block(demuxer, block) < 0)
|
||||
if (read_block(demuxer, end, block) < 0)
|
||||
goto error;
|
||||
break;
|
||||
|
||||
@@ -2454,11 +2456,12 @@ static int read_block_group(demuxer_t *demuxer, int64_t end,
|
||||
block->keyframe = false;
|
||||
break;
|
||||
|
||||
case MATROSKA_ID_CLUSTER:
|
||||
case EBML_ID_INVALID:
|
||||
goto error;
|
||||
|
||||
default:
|
||||
if (ebml_read_skip_or_resync_cluster(demuxer->log, s, NULL) != 0)
|
||||
if (ebml_read_skip(demuxer->log, end, s) != 0)
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
@@ -2491,6 +2494,8 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
|
||||
case MATROSKA_ID_BLOCKGROUP: {
|
||||
int64_t end = ebml_read_length(s, NULL);
|
||||
end += stream_tell(s);
|
||||
if (end > mkv_d->cluster_end)
|
||||
goto find_next_cluster;
|
||||
int res = read_block_group(demuxer, end, block);
|
||||
if (res < 0)
|
||||
goto find_next_cluster;
|
||||
@@ -2501,7 +2506,7 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
|
||||
|
||||
case MATROSKA_ID_SIMPLEBLOCK: {
|
||||
*block = (struct block_info){ .simple = true };
|
||||
int res = read_block(demuxer, block);
|
||||
int res = read_block(demuxer, mkv_d->cluster_end, block);
|
||||
if (res < 0)
|
||||
goto find_next_cluster;
|
||||
if (res > 0)
|
||||
@@ -2517,7 +2522,7 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
|
||||
goto find_next_cluster;
|
||||
|
||||
default: ;
|
||||
if (ebml_read_skip_or_resync_cluster(demuxer->log, s, NULL) != 0)
|
||||
if (ebml_read_skip(demuxer->log, mkv_d->cluster_end, s) != 0)
|
||||
goto find_next_cluster;
|
||||
break;
|
||||
}
|
||||
@@ -2532,7 +2537,13 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
|
||||
break;
|
||||
if (s->eof)
|
||||
return -1;
|
||||
ebml_read_skip_or_resync_cluster(demuxer->log, s, NULL);
|
||||
// For the sake of robustness, consider even unknown level 1
|
||||
// elements the same as unknown/broken IDs.
|
||||
if (!ebml_is_mkv_level1_id(id) ||
|
||||
ebml_read_skip(demuxer->log, -1, s) != 0)
|
||||
{
|
||||
ebml_resync_cluster(demuxer->log, s);
|
||||
}
|
||||
}
|
||||
next_cluster:
|
||||
mkv_d->cluster_end = ebml_read_length(s, NULL);
|
||||
|
||||
@@ -1337,6 +1337,9 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check)
|
||||
if (check > DEMUX_CHECK_REQUEST)
|
||||
return -1;
|
||||
|
||||
if (!demuxer->params || !demuxer->params->expect_subtitle)
|
||||
return -1;
|
||||
|
||||
struct stream *ps = read_probe_stream(demuxer->stream, PROBE_SIZE);
|
||||
|
||||
struct subreader sr;
|
||||
|
||||
+36
-36
@@ -41,6 +41,26 @@
|
||||
#define SIZE_MAX ((size_t)-1)
|
||||
#endif
|
||||
|
||||
// Whether the id is a known Matroska level 1 element (allowed as element on
|
||||
// global file level, after the level 0 MATROSKA_ID_SEGMENT).
|
||||
// This (intentionally) doesn't include "global" elements.
|
||||
bool ebml_is_mkv_level1_id(uint32_t id)
|
||||
{
|
||||
switch (id) {
|
||||
case MATROSKA_ID_SEEKHEAD:
|
||||
case MATROSKA_ID_INFO:
|
||||
case MATROSKA_ID_CLUSTER:
|
||||
case MATROSKA_ID_TRACKS:
|
||||
case MATROSKA_ID_CUES:
|
||||
case MATROSKA_ID_ATTACHMENTS:
|
||||
case MATROSKA_ID_CHAPTERS:
|
||||
case MATROSKA_ID_TAGS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read: the element content data ID.
|
||||
* Return: the ID.
|
||||
@@ -252,21 +272,32 @@ char *ebml_read_utf8(stream_t *s, uint64_t *length)
|
||||
|
||||
/*
|
||||
* Skip the current element.
|
||||
* end: the end of the parent element or -1 (for robust error handling)
|
||||
*/
|
||||
int ebml_read_skip(stream_t *s, uint64_t *length)
|
||||
int ebml_read_skip(struct mp_log *log, int64_t end, stream_t *s)
|
||||
{
|
||||
uint64_t len;
|
||||
int l;
|
||||
|
||||
int64_t pos = stream_tell(s);
|
||||
|
||||
len = ebml_read_length(s, &l);
|
||||
if (len == EBML_UINT_INVALID)
|
||||
return 1;
|
||||
if (length)
|
||||
*length = len + l;
|
||||
goto invalid;
|
||||
|
||||
stream_skip(s, len);
|
||||
int64_t pos2 = stream_tell(s);
|
||||
if (len >= INT64_MAX - pos2 || (end > 0 && pos2 + len > end))
|
||||
goto invalid;
|
||||
|
||||
if (!stream_skip(s, len))
|
||||
goto invalid;
|
||||
|
||||
return 0;
|
||||
|
||||
invalid:
|
||||
mp_err(log, "Invalid EBML length at position %"PRId64"\n", pos);
|
||||
stream_seek(s, pos);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -291,37 +322,6 @@ int ebml_resync_cluster(struct mp_log *log, stream_t *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the current element, or on error, call ebml_resync_cluster().
|
||||
*/
|
||||
int ebml_read_skip_or_resync_cluster(struct mp_log *log, stream_t *s,
|
||||
uint64_t *length)
|
||||
{
|
||||
uint64_t len;
|
||||
int l;
|
||||
|
||||
len = ebml_read_length(s, &l);
|
||||
if (len == EBML_UINT_INVALID)
|
||||
goto resync;
|
||||
|
||||
if (length)
|
||||
*length = len + l;
|
||||
|
||||
int64_t pos = stream_tell(s);
|
||||
|
||||
// When reading corrupted elements, len will often be a random high number,
|
||||
// and stream_skip() will fail when skipping past EOF.
|
||||
if (!stream_skip(s, len)) {
|
||||
stream_seek(s, pos);
|
||||
goto resync;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
resync:
|
||||
return ebml_resync_cluster(log, s) < 0 ? -1 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the next element, but only the header. The contents
|
||||
* are supposed to be sub-elements which can be read separately.
|
||||
|
||||
+2
-3
@@ -92,6 +92,7 @@ struct ebml_parse_ctx {
|
||||
#define EBML_FLOAT_INVALID -1000000000.0
|
||||
|
||||
|
||||
bool ebml_is_mkv_level1_id(uint32_t id);
|
||||
uint32_t ebml_read_id (stream_t *s, int *length);
|
||||
uint64_t ebml_read_vlen_uint (bstr *buffer);
|
||||
int64_t ebml_read_vlen_int (bstr *buffer);
|
||||
@@ -101,9 +102,7 @@ int64_t ebml_read_int (stream_t *s, uint64_t *length);
|
||||
double ebml_read_float (stream_t *s, uint64_t *length);
|
||||
char *ebml_read_ascii (stream_t *s, uint64_t *length);
|
||||
char *ebml_read_utf8 (stream_t *s, uint64_t *length);
|
||||
int ebml_read_skip (stream_t *s, uint64_t *length);
|
||||
int ebml_read_skip_or_resync_cluster(struct mp_log *log, stream_t *s,
|
||||
uint64_t *length);
|
||||
int ebml_read_skip(struct mp_log *log, int64_t end, stream_t *s);
|
||||
int ebml_resync_cluster(struct mp_log *log, stream_t *s);
|
||||
uint32_t ebml_read_master (stream_t *s, uint64_t *length);
|
||||
|
||||
|
||||
+3
-3
@@ -64,11 +64,11 @@ mf_t *open_mf_pattern(void *talloc_ctx, struct mp_log *log, char *filename)
|
||||
if (filename[0] == '@') {
|
||||
FILE *lst_f = fopen(filename + 1, "r");
|
||||
if (lst_f) {
|
||||
char *fname = talloc_size(mf, MP_PATH_MAX);
|
||||
while (fgets(fname, MP_PATH_MAX, lst_f)) {
|
||||
char *fname = talloc_size(mf, 512);
|
||||
while (fgets(fname, 512, lst_f)) {
|
||||
/* remove spaces from end of fname */
|
||||
char *t = fname + strlen(fname) - 1;
|
||||
while (t > fname && isspace(*t))
|
||||
while (t > fname && isspace((unsigned char)*t))
|
||||
*(t--) = 0;
|
||||
if (!mp_path_exists(fname)) {
|
||||
mp_verbose(log, "file not found: '%s'\n", fname);
|
||||
|
||||
@@ -87,6 +87,7 @@ typedef struct sh_video {
|
||||
typedef struct sh_sub {
|
||||
unsigned char *extradata; // extra header data passed from demuxer
|
||||
int extradata_len;
|
||||
int w, h; // mp4 vobsubs
|
||||
int frame_based; // timestamps are frame-based
|
||||
bool is_utf8; // if false, subtitle packet charset is unknown
|
||||
struct ass_track *track; // loaded by libass
|
||||
|
||||
@@ -83,6 +83,10 @@
|
||||
# Play Finnish audio if available, fall back to English otherwise.
|
||||
#alang = fi,en
|
||||
|
||||
# Change subtitle encoding. For Arabic subtitles use 'cp1256'.
|
||||
# If the file seems to be valid UTF-8, prefer UTF-8.
|
||||
#subcp = utf8:cp1256
|
||||
|
||||
# Enable hardware decoding if available. Often, this requires using an certain
|
||||
# video output, otherwise no hardware decoding will be used.
|
||||
#hwdec = auto
|
||||
|
||||
+4
-1
@@ -2,11 +2,14 @@
|
||||
Type=Application
|
||||
Name=mpv Media Player
|
||||
Name[ca]=Reproductor multimèdia mpv
|
||||
Name[cs]=mpv přehrávač
|
||||
Name[pl]=mpv odtwarzacz multimedialny
|
||||
Name[ru]=Проигрыватель mpv
|
||||
GenericName=Multimedia player
|
||||
GenericName[cs]=Multimediální přehrávač
|
||||
Comment=Play movies and songs
|
||||
Comment[ca]=Reproduïu vídeos i cançons
|
||||
Comment[cs]=Přehrává filmy a hudbu
|
||||
Comment[de]=Filme und Musik abspielen
|
||||
Comment[es]=Reproduzca vídeos y canciones
|
||||
Comment[fr]=Lecteur multimédia
|
||||
@@ -20,5 +23,5 @@ Exec=mpv --really-quiet --force-window -- %F
|
||||
Terminal=false
|
||||
NoDisplay=true
|
||||
Categories=AudioVideo;Audio;Video;Player;TV;
|
||||
MimeType=application/ogg;application/x-ogg;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/m4a;audio/x-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/x-mpeg;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg;video/x-mpeg2;video/mp4;video/msvideo;video/x-msvideo;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/x-fli;video/x-flv;video/x-theora;video/x-matroska;video/webm;audio/x-flac;
|
||||
MimeType=application/ogg;application/x-ogg;application/sdp;application/smil;application/x-smil;application/streamingmedia;application/x-streamingmedia;application/vnd.rn-realmedia;application/vnd.rn-realmedia-vbr;audio/aac;audio/x-aac;audio/m4a;audio/x-m4a;audio/mp1;audio/x-mp1;audio/mp2;audio/x-mp2;audio/mp3;audio/x-mp3;audio/mpeg;audio/x-mpeg;audio/mpegurl;audio/x-mpegurl;audio/mpg;audio/x-mpg;audio/rn-mpeg;audio/scpls;audio/x-scpls;audio/vnd.rn-realaudio;audio/wav;audio/x-pn-windows-pcm;audio/x-realaudio;audio/x-pn-realaudio;audio/x-ms-wma;audio/x-pls;audio/x-wav;video/mpeg;video/x-mpeg;video/x-mpeg2;video/mp4;video/msvideo;video/x-msvideo;video/quicktime;video/vnd.rn-realvideo;video/x-ms-afs;video/x-ms-asf;video/x-ms-wmv;video/x-ms-wmx;video/x-ms-wvxvideo;video/x-avi;video/x-fli;video/x-flv;video/x-theora;video/x-matroska;video/webm;audio/x-flac;audio/x-vorbis+ogg;video/x-ogm+ogg;
|
||||
X-KDE-Protocols=ftp,http,https,mms,rtmp,rtsp,sftp,smb
|
||||
+15
-1
@@ -253,7 +253,7 @@ bool mp_replace_legacy_cmd(void *t, bstr *s)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mp_input_is_abort_cmd(int cmd_id)
|
||||
static bool is_abort_cmd(int cmd_id)
|
||||
{
|
||||
switch (cmd_id) {
|
||||
case MP_CMD_QUIT:
|
||||
@@ -264,6 +264,20 @@ bool mp_input_is_abort_cmd(int cmd_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mp_input_is_abort_cmd(struct mp_cmd *cmd)
|
||||
{
|
||||
if (is_abort_cmd(cmd->id))
|
||||
return true;
|
||||
if (cmd->id == MP_CMD_COMMAND_LIST) {
|
||||
for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next)
|
||||
{
|
||||
if (mp_input_is_abort_cmd(sub))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void mp_print_cmd_list(struct mp_log *out)
|
||||
{
|
||||
for (int i = 0; mp_cmds[i].name; i++) {
|
||||
|
||||
+2
-1
@@ -107,7 +107,8 @@ enum mp_command_type {
|
||||
};
|
||||
|
||||
// Executing this command will abort playback (play something else, or quit).
|
||||
bool mp_input_is_abort_cmd(int cmd_id);
|
||||
struct mp_cmd;
|
||||
bool mp_input_is_abort_cmd(struct mp_cmd *cmd);
|
||||
|
||||
struct bstr;
|
||||
bool mp_replace_legacy_cmd(void *talloc_ctx, struct bstr *s);
|
||||
|
||||
+4
-4
@@ -237,7 +237,7 @@ static bool queue_has_abort_cmds(struct cmd_queue *queue)
|
||||
{
|
||||
bool ret = false;
|
||||
for (struct mp_cmd *cmd = queue->first; cmd; cmd = cmd->queue_next)
|
||||
if (mp_input_is_abort_cmd(cmd->id)) {
|
||||
if (mp_input_is_abort_cmd(cmd)) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
@@ -544,9 +544,9 @@ static void release_down_cmd(struct input_ctx *ictx, bool drop_current)
|
||||
|
||||
static int find_key_down(struct input_ctx *ictx, int code)
|
||||
{
|
||||
code &= ~(MP_KEY_STATE_UP | MP_KEY_STATE_DOWN);
|
||||
code &= ~(MP_KEY_STATE_UP | MP_KEY_STATE_DOWN | MP_KEY_MODIFIER_MASK);
|
||||
for (int j = 0; j < ictx->num_key_down; j++) {
|
||||
if (ictx->key_down[j] == code)
|
||||
if ((ictx->key_down[j] & ~MP_KEY_MODIFIER_MASK) == code)
|
||||
return j;
|
||||
}
|
||||
return -1;
|
||||
@@ -580,7 +580,7 @@ static bool should_drop_cmd(struct input_ctx *ictx, struct mp_cmd *cmd)
|
||||
{
|
||||
struct cmd_queue *queue = &ictx->cmd_queue;
|
||||
return (queue_count_cmds(queue) >= ictx->key_fifo_size &&
|
||||
(!mp_input_is_abort_cmd(cmd->id) || queue_has_abort_cmds(queue)));
|
||||
(!mp_input_is_abort_cmd(cmd) || queue_has_abort_cmds(queue)));
|
||||
}
|
||||
|
||||
static void interpret_key(struct input_ctx *ictx, int code, double scale)
|
||||
|
||||
+36
-2
@@ -1169,10 +1169,10 @@ fi
|
||||
|
||||
if test "$cc_vendor" = "gnu" ; then
|
||||
cflag_check -Wundef && WARNFLAGS="-Wundef $WARNFLAGS"
|
||||
# -std=gnu99 is not a warning flag but is placed in WARN_CFLAGS because
|
||||
# -std=c99 is not a warning flag but is placed in WARN_CFLAGS because
|
||||
# that's the only variable specific to C now, and this option is not valid
|
||||
# for C++.
|
||||
cflag_check -std=gnu99 && WARN_CFLAGS="-std=gnu99 $WARN_CFLAGS"
|
||||
cflag_check -std=c99 && WARN_CFLAGS="-std=c99 $WARN_CFLAGS"
|
||||
cflag_check -Wno-pointer-sign && WARN_CFLAGS="-Wno-pointer-sign $WARN_CFLAGS"
|
||||
cflag_check -Wdisabled-optimization && WARN_CFLAGS="-Wdisabled-optimization $WARN_CFLAGS"
|
||||
cflag_check -Wmissing-prototypes && WARN_CFLAGS="-Wmissing-prototypes $WARN_CFLAGS"
|
||||
@@ -1329,6 +1329,38 @@ if test "$_pthreads" = no ; then
|
||||
die "Unable to find pthreads support."
|
||||
fi
|
||||
|
||||
|
||||
echocheck "compiler support for __atomic built-ins"
|
||||
_atomic=no
|
||||
for _ld_tmp in "" "-latomic" ; do
|
||||
statement_check stdint.h 'int64_t test = 0; test = __atomic_add_fetch(&test, 1, __ATOMIC_SEQ_CST)' $_ld_tmp &&
|
||||
libs_mplayer="$libs_mplayer $_ld_tmp" && _atomic=yes && break
|
||||
done
|
||||
if test "$_atomic" = yes ; then
|
||||
def_atomic="#define HAVE_ATOMIC_BUILTINS 1"
|
||||
else
|
||||
def_atomic="#define HAVE_ATOMIC_BUILTINS 0"
|
||||
fi
|
||||
echores "$_atomic"
|
||||
|
||||
if test "$_atomic" = no ; then
|
||||
echocheck "compiler support for __sync built-ins"
|
||||
_sync=no
|
||||
statement_check stdint.h 'int64_t test = 0; test = __sync_add_and_fetch(&test, 1)' && _sync=yes
|
||||
if test "$_sync" = yes ; then
|
||||
def_sync="#define HAVE_SYNC_BUILTINS 1"
|
||||
else
|
||||
def_sync="#define HAVE_SYNC_BUILTINS 0"
|
||||
fi
|
||||
echores "$_sync"
|
||||
else
|
||||
def_sync="#define HAVE_SYNC_BUILTINS 0"
|
||||
fi
|
||||
|
||||
if test "$_atomic" = no && test "$_sync" = no ; then
|
||||
die "your compiler must support either __atomic or __sync built-ins."
|
||||
fi
|
||||
|
||||
if test "$_pthreads" = yes ; then
|
||||
|
||||
# Cargo-cult for -lrt, which is needed on not so recent glibc version for
|
||||
@@ -3521,6 +3553,8 @@ $def_avresample_has_set_channel_mapping
|
||||
|
||||
$def_fast_64bit
|
||||
$def_pthreads
|
||||
$def_atomic
|
||||
$def_sync
|
||||
|
||||
#define HAVE_INLINE_ASM 1
|
||||
|
||||
|
||||
+2
-2
@@ -27,8 +27,7 @@ SOURCES_AUDIO_INPUT-$(ALSA) += stream/ai_alsa1x.c
|
||||
SOURCES_AUDIO_INPUT-$(OSS) += stream/ai_oss.c
|
||||
SOURCES_AUDIO_INPUT-$(SNDIO) += stream/ai_sndio.c
|
||||
SOURCES-$(AUDIO_INPUT) += $(SOURCES_AUDIO_INPUT-yes)
|
||||
SOURCES-$(CDDA) += stream/stream_cdda.c \
|
||||
stream/cdinfo.c
|
||||
SOURCES-$(CDDA) += stream/stream_cdda.c
|
||||
SOURCES-$(DVBIN) += stream/dvb_tune.c \
|
||||
stream/stream_dvb.c
|
||||
SOURCES-$(DVDREAD) += stream/stream_dvd.c \
|
||||
@@ -344,6 +343,7 @@ DIRS = . \
|
||||
player/timeline \
|
||||
demux \
|
||||
misc \
|
||||
options \
|
||||
osdep \
|
||||
osdep/ar \
|
||||
player \
|
||||
|
||||
@@ -1299,6 +1299,17 @@ static int parse_msglevels(struct mp_log *log, const m_option_t *opt,
|
||||
if (param.start == NULL)
|
||||
return M_OPT_MISSING_PARAM;
|
||||
|
||||
if (bstr_equals0(param, "help")) {
|
||||
mp_info(log, "Syntax: --msglevel=module1=level:module2=level:...\n"
|
||||
"'module' is output prefix as shown with -v, or a prefix\n"
|
||||
"of it. level is one of:\n\n"
|
||||
" fatal error warn info status v debug trace\n\n"
|
||||
"The level specifies the minimum log level a message\n"
|
||||
"must have to be printed.\n"
|
||||
"The special module name 'all' affects all modules.\n");
|
||||
return M_OPT_EXIT;
|
||||
}
|
||||
|
||||
bstr s = param;
|
||||
while (1) {
|
||||
int res = mp_msg_split_msglevel(&s, &(bstr){0}, &(int){0});
|
||||
|
||||
@@ -316,6 +316,7 @@ const m_option_t mp_opts[] = {
|
||||
({"no", 0}, {"attachment", 1})),
|
||||
|
||||
OPT_STRING("quvi-format", quvi_format, 0),
|
||||
OPT_FLAG("quvi-fetch-subtitles", quvi_fetch_subtitles, 0),
|
||||
|
||||
#if HAVE_CDDA
|
||||
{ "cdda", (void *)&cdda_opts, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
@@ -718,6 +719,7 @@ const struct MPOpts mp_default_opts = {
|
||||
.sub_visibility = 1,
|
||||
.sub_pos = 100,
|
||||
.sub_speed = 1.0,
|
||||
.quvi_fetch_subtitles = 0,
|
||||
.audio_output_channels = MP_CHMAP_INIT_STEREO,
|
||||
.audio_output_format = 0, // AF_FORMAT_UNKNOWN
|
||||
.playback_speed = 1.,
|
||||
|
||||
@@ -158,6 +158,7 @@ typedef struct MPOpts {
|
||||
int forced_subs_only;
|
||||
int stretch_dvd_subs;
|
||||
char *quvi_format;
|
||||
int quvi_fetch_subtitles;
|
||||
|
||||
// subreader.c
|
||||
int suboverlap_enabled;
|
||||
|
||||
@@ -330,7 +330,8 @@ int cocoa_main(mpv_main_fn mpv_main, int argc, char *argv[])
|
||||
pthread_create(&playback_thread_id, NULL, playback_thread, &ctx);
|
||||
|
||||
[mpv_shared_app().input_ready lock];
|
||||
[mpv_shared_app().input_ready wait];
|
||||
while (!mpv_shared_app().inputContext)
|
||||
[mpv_shared_app().input_ready wait];
|
||||
[mpv_shared_app().input_ready unlock];
|
||||
|
||||
cocoa_run_runloop();
|
||||
@@ -388,13 +389,10 @@ void cocoa_stop_runloop(void)
|
||||
|
||||
void cocoa_set_input_context(struct input_ctx *input_context)
|
||||
{
|
||||
if (input_context) {
|
||||
[mpv_shared_app().input_ready lock];
|
||||
[mpv_shared_app().input_ready signal];
|
||||
[mpv_shared_app().input_ready unlock];
|
||||
}
|
||||
|
||||
[mpv_shared_app().input_ready lock];
|
||||
mpv_shared_app().inputContext = input_context;
|
||||
[mpv_shared_app().input_ready signal];
|
||||
[mpv_shared_app().input_ready unlock];
|
||||
}
|
||||
|
||||
void cocoa_post_fake_event(void)
|
||||
|
||||
+6
-2
@@ -46,7 +46,7 @@ char *mp_get_win_config_path(const char *filename)
|
||||
void *tmp = talloc_new(NULL);
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
if (SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, NULL,
|
||||
if (SHGetFolderPathW(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL,
|
||||
SHGFP_TYPE_CURRENT, w_appdir) != S_OK)
|
||||
w_appdir[0] = '\0';
|
||||
#endif
|
||||
@@ -59,7 +59,11 @@ char *mp_get_win_config_path(const char *filename)
|
||||
res = mp_path_join(NULL, bstr0(temp), bstr0(filename));
|
||||
if (!mp_path_exists(res) || mp_path_isdir(res)) {
|
||||
talloc_free(res);
|
||||
res = NULL;
|
||||
res = mp_path_join(NULL, bstr0(dir), bstr0(filename));
|
||||
if (!mp_path_exists(res) || mp_path_isdir(res)) {
|
||||
talloc_free(res);
|
||||
res = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -47,6 +47,8 @@
|
||||
#include "input/keycodes.h"
|
||||
#include "terminal.h"
|
||||
|
||||
static int use_terminal;
|
||||
|
||||
#if HAVE_TERMIOS
|
||||
static volatile struct termios tio_orig;
|
||||
static volatile int tio_orig_set;
|
||||
@@ -84,6 +86,9 @@ static char *term_smkx = NULL;
|
||||
#endif
|
||||
|
||||
static keycode_st *keys_push(char *p, int code) {
|
||||
if (strlen(p) > 8)
|
||||
return NULL;
|
||||
|
||||
if (getch2_keys.len == getch2_keys.cap) {
|
||||
getch2_keys.cap *= 2;
|
||||
if (getch2_keys.cap == 0)
|
||||
@@ -454,7 +459,7 @@ static volatile int getch2_enabled = 0;
|
||||
|
||||
static void do_activate_getch2(void)
|
||||
{
|
||||
if (getch2_active)
|
||||
if (getch2_active || !use_terminal)
|
||||
return;
|
||||
|
||||
#if HAVE_TERMINFO || HAVE_TERMCAP
|
||||
@@ -513,7 +518,7 @@ static int setsigaction(int signo, void (*handler) (int),
|
||||
else
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
sa.sa_flags = flags;
|
||||
sa.sa_flags = flags | SA_RESTART;
|
||||
return sigaction(signo, &sa, NULL);
|
||||
}
|
||||
|
||||
@@ -612,6 +617,8 @@ void terminal_setup_stdin_cmd_input(struct input_ctx *ictx)
|
||||
|
||||
int terminal_init(void)
|
||||
{
|
||||
load_termcap(NULL);
|
||||
use_terminal = isatty(1);
|
||||
if (use_terminal)
|
||||
load_termcap(NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -334,11 +334,13 @@ static int audio_start_sync(struct MPContext *mpctx, int playsize)
|
||||
res = audio_decode(d_audio, ao->buffer, a);
|
||||
if (skip_samples <= mp_audio_buffer_samples(ao->buffer)) {
|
||||
mp_audio_buffer_skip(ao->buffer, skip_samples);
|
||||
ao->buffer_playable_samples = 0;
|
||||
if (res < 0)
|
||||
return res;
|
||||
return audio_decode(d_audio, ao->buffer, playsize);
|
||||
}
|
||||
mp_audio_buffer_clear(ao->buffer);
|
||||
ao->buffer_playable_samples = 0;
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
@@ -442,6 +444,7 @@ int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
|
||||
mp_audio_buffer_peek(ao->buffer, &data);
|
||||
data.samples = MPMIN(data.samples, playsize);
|
||||
int played = write_to_ao(mpctx, &data, playflags, written_audio_pts(mpctx));
|
||||
assert(played >= 0 && played <= data.samples);
|
||||
ao->buffer_playable_samples = playsize - played;
|
||||
|
||||
if (played > 0) {
|
||||
|
||||
+10
-8
@@ -700,8 +700,8 @@ static int tag_property(m_option_t *prop, int action, void *arg,
|
||||
char **slist = NULL;
|
||||
int num = 0;
|
||||
for (int n = 0; n < tags->num_keys; n++) {
|
||||
MP_TARRAY_APPEND(NULL, slist, num, tags->keys[n]);
|
||||
MP_TARRAY_APPEND(NULL, slist, num, tags->values[n]);
|
||||
MP_TARRAY_APPEND(NULL, slist, num, talloc_strdup(NULL, tags->keys[n]));
|
||||
MP_TARRAY_APPEND(NULL, slist, num, talloc_strdup(NULL, tags->values[n]));
|
||||
}
|
||||
MP_TARRAY_APPEND(NULL, slist, num, NULL);
|
||||
*(char ***)arg = slist;
|
||||
@@ -750,11 +750,9 @@ static int mp_property_chapter_metadata(m_option_t *prop, int action, void *arg,
|
||||
{
|
||||
struct demuxer *demuxer = mpctx->master_demuxer;
|
||||
int chapter = get_current_chapter(mpctx);
|
||||
if (!demuxer || chapter < 0)
|
||||
if (!demuxer || chapter < 0 || chapter >= demuxer->num_chapters)
|
||||
return M_PROPERTY_UNAVAILABLE;
|
||||
|
||||
assert(chapter < demuxer->num_chapters);
|
||||
|
||||
return tag_property(prop, action, arg, demuxer->chapters[chapter].metadata);
|
||||
}
|
||||
|
||||
@@ -2941,7 +2939,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
}
|
||||
#endif /* HAVE_PVR */
|
||||
#if HAVE_DVBIN
|
||||
if (mpctx->stream->type == STREAMTYPE_DVB) {
|
||||
if (mpctx->stream && mpctx->stream->type == STREAMTYPE_DVB) {
|
||||
int dir;
|
||||
int v = cmd->args[0].v.i;
|
||||
|
||||
@@ -2979,7 +2977,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
|
||||
#if HAVE_DVBIN
|
||||
case MP_CMD_DVB_SET_CHANNEL:
|
||||
if (mpctx->stream->type == STREAMTYPE_DVB) {
|
||||
if (mpctx->stream && mpctx->stream->type == STREAMTYPE_DVB) {
|
||||
mpctx->last_dvb_step = 1;
|
||||
|
||||
if (dvb_set_channel(mpctx->stream, cmd->args[1].v.i,
|
||||
@@ -3052,6 +3050,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
|
||||
case MP_CMD_RUN: {
|
||||
#ifndef __MINGW32__
|
||||
mp_msg(mpctx->statusline, MSGL_STATUS, "\n");
|
||||
char *args[MP_CMD_MAX_ARGS + 1] = {0};
|
||||
for (int n = 0; n < cmd->nargs; n++)
|
||||
args[n] = cmd->args[n].v.s;
|
||||
@@ -3062,7 +3061,10 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
|
||||
// about having to wait for the second process to terminate.
|
||||
if (fork() == 0) {
|
||||
execvp(args[0], args);
|
||||
_exit(0);
|
||||
// mp_msg() is not safe to be called from a forked process.
|
||||
char s[] = "Executing program failed.\n";
|
||||
write(2, s, sizeof(s) - 1);
|
||||
_exit(1);
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
@@ -57,6 +57,13 @@ bool mp_parse_cfgfiles(struct MPContext *mpctx)
|
||||
bool r = true;
|
||||
char *conffile;
|
||||
|
||||
// The #if is a stupid hack to avoid errors if libavfilter is not available.
|
||||
#if HAVE_VF_LAVFI && HAVE_ENCODING
|
||||
conffile = mp_find_config_file(tmp, mpctx->global, "encoding-profiles.conf");
|
||||
if (conffile && mp_path_exists(conffile))
|
||||
m_config_parse_config_file(mpctx->mconfig, conffile, 0);
|
||||
#endif
|
||||
|
||||
if (m_config_parse_config_file(conf, MPLAYER_CONFDIR "/mpv.conf", 0) < 0) {
|
||||
r = false;
|
||||
goto done;
|
||||
@@ -77,13 +84,6 @@ bool mp_parse_cfgfiles(struct MPContext *mpctx)
|
||||
}
|
||||
}
|
||||
|
||||
// The #if is a stupid hack to avoid errors if libavfilter is not available.
|
||||
#if HAVE_VF_LAVFI && HAVE_ENCODING
|
||||
conffile = mp_find_config_file(tmp, mpctx->global, "encoding-profiles.conf");
|
||||
if (conffile && mp_path_exists(conffile))
|
||||
m_config_parse_config_file(mpctx->mconfig, conffile, 0);
|
||||
#endif
|
||||
|
||||
done:
|
||||
talloc_free(tmp);
|
||||
return r;
|
||||
@@ -110,8 +110,8 @@ static void mp_load_per_file_config(struct MPContext *mpctx)
|
||||
const char *file = mpctx->filename;
|
||||
|
||||
if (snprintf(cfg, sizeof(cfg), "%s.conf", file) >= sizeof(cfg)) {
|
||||
MP_WARN(mpctx, "Filename is too long, "
|
||||
"can not load file or directory specific config files\n");
|
||||
MP_VERBOSE(mpctx, "Filename is too long, "
|
||||
"can not load file or directory specific config files\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ struct track {
|
||||
|
||||
// If this track is from an external file (e.g. subtitle file).
|
||||
bool is_external;
|
||||
bool no_default; // pretend it's not external for auto-selection
|
||||
char *external_filename;
|
||||
bool auto_loaded;
|
||||
|
||||
|
||||
+7
-2
@@ -140,7 +140,10 @@ void mp_handle_nav(struct MPContext *mpctx)
|
||||
case MP_NAV_EVENT_RESET_ALL: {
|
||||
mpctx->stop_play = PT_RELOAD_DEMUXER;
|
||||
MP_VERBOSE(nav, "reload\n");
|
||||
break;
|
||||
// return immediately.
|
||||
// other events should be handled after reloaded.
|
||||
talloc_free(ev);
|
||||
return;
|
||||
}
|
||||
case MP_NAV_EVENT_RESET: {
|
||||
nav->nav_still_frame = 0;
|
||||
@@ -237,13 +240,15 @@ void mp_nav_get_highlight(struct osd_state *osd, struct mp_osd_res res,
|
||||
talloc_free(sub->bitmap);
|
||||
sub->bitmap = talloc_array(sub, uint32_t, sizes[0] * sizes[1]);
|
||||
memset(sub->bitmap, 0x80, talloc_get_size(sub->bitmap));
|
||||
nav->subsize[0] = sizes[0];
|
||||
nav->subsize[1] = sizes[1];
|
||||
}
|
||||
|
||||
sub->x = nav->highlight[0];
|
||||
sub->y = nav->highlight[1];
|
||||
sub->w = MPCLAMP(nav->highlight[2] - sub->x, 0, sizes[0]);
|
||||
sub->h = MPCLAMP(nav->highlight[3] - sub->y, 0, sizes[1]);
|
||||
sub->stride = sub->w;
|
||||
sub->stride = sub->w * 4;
|
||||
out_imgs->format = SUBBITMAP_RGBA;
|
||||
out_imgs->parts = sub;
|
||||
out_imgs->num_parts = sub->w > 0 && sub->h > 0 && nav->hi_visible;
|
||||
|
||||
+26
-15
@@ -281,7 +281,7 @@ void reselect_demux_streams(struct MPContext *mpctx)
|
||||
// Note: we assume that all demuxer streams are covered by the track list.
|
||||
for (int t = 0; t < mpctx->num_tracks; t++) {
|
||||
struct track *track = mpctx->tracks[t];
|
||||
if (track->demuxer)
|
||||
if (track->demuxer && track->stream)
|
||||
demuxer_select_track(track->demuxer, track->stream, track->selected);
|
||||
}
|
||||
}
|
||||
@@ -443,13 +443,16 @@ static struct track *add_stream_track(struct MPContext *mpctx,
|
||||
track->preloaded = !!stream->sub->track;
|
||||
|
||||
// Needed for DVD and Blu-ray.
|
||||
if (!track->lang) {
|
||||
struct stream *st = track->demuxer->stream;
|
||||
if (!track->lang && (st->uncached_type == STREAMTYPE_BLURAY ||
|
||||
st->uncached_type == STREAMTYPE_DVD))
|
||||
{
|
||||
struct stream_lang_req req = {
|
||||
.type = track->type,
|
||||
.id = map_id_from_demuxer(track->demuxer, track->type,
|
||||
track->demuxer_id)
|
||||
};
|
||||
stream_control(track->demuxer->stream, STREAM_CTRL_GET_LANG, &req);
|
||||
stream_control(st, STREAM_CTRL_GET_LANG, &req);
|
||||
if (req.name[0])
|
||||
track->lang = talloc_strdup(track, req.name);
|
||||
}
|
||||
@@ -472,6 +475,8 @@ static void add_dvd_tracks(struct MPContext *mpctx)
|
||||
struct demuxer *demuxer = mpctx->demuxer;
|
||||
struct stream *stream = demuxer->stream;
|
||||
struct stream_dvd_info_req info;
|
||||
if (stream->uncached_type != STREAMTYPE_DVD)
|
||||
return;
|
||||
if (stream_control(stream, STREAM_CTRL_GET_DVD_INFO, &info) > 0) {
|
||||
for (int n = 0; n < info.num_subs; n++) {
|
||||
struct track *track = talloc_ptrtype(NULL, track);
|
||||
@@ -508,7 +513,7 @@ static int match_lang(char **langs, char *lang)
|
||||
* lang is a string list, NULL is same as empty list
|
||||
* Sort tracks based on the following criteria, and pick the first:
|
||||
* 0) track matches tid (always wins)
|
||||
* 1) track is external
|
||||
* 1) track is external (no_default cancels this)
|
||||
* 1b) track was passed explicitly (is not an auto-loaded subtitle)
|
||||
* 2) earlier match in lang list
|
||||
* 3) track is marked default
|
||||
@@ -520,8 +525,10 @@ static int match_lang(char **langs, char *lang)
|
||||
// Return whether t1 is preferred over t2
|
||||
static bool compare_track(struct track *t1, struct track *t2, char **langs)
|
||||
{
|
||||
if (t1->is_external != t2->is_external)
|
||||
return t1->is_external;
|
||||
bool ext1 = t1->is_external && !t1->no_default;
|
||||
bool ext2 = t2->is_external && !t2->no_default;
|
||||
if (ext1 != ext2)
|
||||
return ext1;
|
||||
if (t1->auto_loaded != t2->auto_loaded)
|
||||
return !t1->auto_loaded;
|
||||
int l1 = match_lang(langs, t1->lang), l2 = match_lang(langs, t2->lang);
|
||||
@@ -549,7 +556,7 @@ static struct track *select_track(struct MPContext *mpctx,
|
||||
if (!pick || compare_track(track, pick, langs))
|
||||
pick = track;
|
||||
}
|
||||
if (pick && !select_fallback && !pick->is_external
|
||||
if (pick && !select_fallback && !(pick->is_external && !pick->no_default)
|
||||
&& !match_lang(langs, pick->lang) && !pick->default_track)
|
||||
pick = NULL;
|
||||
if (pick && pick->attached_picture && !mpctx->opts->audio_display)
|
||||
@@ -665,6 +672,8 @@ void mp_switch_track_n(struct MPContext *mpctx, int order, enum stream_type type
|
||||
}
|
||||
}
|
||||
|
||||
osd_changed_all(mpctx->osd);
|
||||
|
||||
talloc_free(mpctx->track_layout_hash);
|
||||
mpctx->track_layout_hash = talloc_steal(mpctx, track_layout_hash(mpctx));
|
||||
}
|
||||
@@ -776,6 +785,7 @@ static struct track *open_external_file(struct MPContext *mpctx, char *filename,
|
||||
opts->stream_cache_seek_min_percent);
|
||||
struct demuxer_params params = {
|
||||
.ass_library = mpctx->ass_library, // demux_libass requires it
|
||||
.expect_subtitle = filter == STREAM_SUB,
|
||||
};
|
||||
struct demuxer *demuxer =
|
||||
demux_open(stream, demuxer_name, ¶ms, mpctx->global);
|
||||
@@ -838,8 +848,10 @@ static void open_subtitles_from_resolve(struct MPContext *mpctx)
|
||||
struct track *t =
|
||||
open_external_file(mpctx, s, opts->sub_demuxer_name, 0, STREAM_SUB);
|
||||
talloc_free(s);
|
||||
if (t)
|
||||
if (t) {
|
||||
t->lang = talloc_strdup(t, sub->lang);
|
||||
t->no_default = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1002,7 +1014,7 @@ static bool demux_was_interrupted(struct MPContext *mpctx)
|
||||
mp_cmd_t *cmd = mp_input_get_cmd(mpctx->input, 0, 0);
|
||||
if (!cmd)
|
||||
break;
|
||||
if (mp_input_is_abort_cmd(cmd->id))
|
||||
if (mp_input_is_abort_cmd(cmd))
|
||||
run_command(mpctx, cmd);
|
||||
mp_cmd_free(cmd);
|
||||
}
|
||||
@@ -1295,14 +1307,13 @@ goto_reopen_demuxer: ;
|
||||
|
||||
// If there's a timeline force an absolute seek to initialize state
|
||||
double startpos = rel_time_to_abs(mpctx, opts->play_start, -1);
|
||||
if (startpos != -1 || mpctx->timeline) {
|
||||
queue_seek(mpctx, MPSEEK_ABSOLUTE, startpos, 0);
|
||||
execute_queued_seek(mpctx);
|
||||
}
|
||||
if (startpos == -1 && mpctx->resolve_result &&
|
||||
mpctx->resolve_result->start_time > 0)
|
||||
{
|
||||
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->resolve_result->start_time, 0);
|
||||
startpos = mpctx->resolve_result->start_time;
|
||||
if (startpos == -1 && mpctx->timeline)
|
||||
startpos = 0;
|
||||
if (startpos != -1) {
|
||||
queue_seek(mpctx, MPSEEK_ABSOLUTE, startpos, 0);
|
||||
execute_queued_seek(mpctx);
|
||||
}
|
||||
if (opts->chapterrange[0] > 0) {
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
/*
|
||||
* This file is part of mpv.
|
||||
*
|
||||
* mpv 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.
|
||||
*
|
||||
* mpv is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
+27
-5
@@ -64,6 +64,14 @@
|
||||
#include "command.h"
|
||||
#include "screenshot.h"
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
|
||||
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE (0x0001)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_X11
|
||||
#include "video/out/x11_common.h"
|
||||
#endif
|
||||
@@ -76,10 +84,6 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
const char mp_help_text[] =
|
||||
"Usage: mpv [options] [url|path/]filename\n"
|
||||
"\n"
|
||||
@@ -260,7 +264,23 @@ static void osdep_preinit(int *p_argc, char ***p_argv)
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
// stop Windows from showing all kinds of annoying error dialogs
|
||||
SetErrorMode(0x8003);
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||||
|
||||
// Enable heap corruption detection
|
||||
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
|
||||
|
||||
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
WINBOOL (WINAPI *pSetDllDirectory)(LPCWSTR lpPathName) =
|
||||
(WINBOOL (WINAPI *)(LPCWSTR))GetProcAddress(kernel32, "SetDllDirectoryW");
|
||||
WINBOOL (WINAPI *pSetSearchPathMode)(DWORD Flags) =
|
||||
(WINBOOL (WINAPI *)(DWORD))GetProcAddress(kernel32, "SetSearchPathMode");
|
||||
|
||||
// Always use safe search paths for DLLs and other files, ie. never use the
|
||||
// current directory
|
||||
if (pSetSearchPathMode)
|
||||
pSetDllDirectory(L"");
|
||||
if (pSetSearchPathMode)
|
||||
pSetSearchPathMode(BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE);
|
||||
#endif
|
||||
|
||||
terminal_init();
|
||||
@@ -381,8 +401,10 @@ static int mpv_main(int argc, char *argv[])
|
||||
m_config_set_option0(mpctx->mconfig, "vo", "lavc");
|
||||
m_config_set_option0(mpctx->mconfig, "ao", "lavc");
|
||||
m_config_set_option0(mpctx->mconfig, "fixed-vo", "yes");
|
||||
m_config_set_option0(mpctx->mconfig, "keep-open", "no");
|
||||
m_config_set_option0(mpctx->mconfig, "force-window", "no");
|
||||
m_config_set_option0(mpctx->mconfig, "gapless-audio", "yes");
|
||||
m_config_set_option0(mpctx->mconfig, "resume-playback", "no");
|
||||
mp_input_enable_section(mpctx->input, "encode", MP_INPUT_EXCLUSIVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
+5
-1
@@ -106,6 +106,10 @@ double get_start_time(struct MPContext *mpctx)
|
||||
struct demuxer *demuxer = mpctx->demuxer;
|
||||
if (!demuxer)
|
||||
return 0;
|
||||
// We reload the demuxer on menu transitions; don't make it use the first
|
||||
// timestamp it finds as start PTS.
|
||||
if (mpctx->nav_state)
|
||||
return 0;
|
||||
return demuxer_get_start_time(demuxer);
|
||||
}
|
||||
|
||||
@@ -134,7 +138,7 @@ void update_window_title(struct MPContext *mpctx, bool force)
|
||||
{
|
||||
if (!mpctx->video_out && !mpctx->ao) {
|
||||
talloc_free(mpctx->last_window_title);
|
||||
mpctx->last_window_title = false;
|
||||
mpctx->last_window_title = NULL;
|
||||
return;
|
||||
}
|
||||
char *title = mp_property_expand_string(mpctx, mpctx->opts->wintitle);
|
||||
|
||||
+9
-6
@@ -435,9 +435,12 @@ static void add_seek_osd_messages(struct MPContext *mpctx)
|
||||
set_osd_bar_chapters(mpctx, OSD_BAR_SEEK);
|
||||
}
|
||||
if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_TEXT) {
|
||||
mp_osd_msg_t *msg = add_osd_msg(mpctx, OSD_MSG_TEXT, 1,
|
||||
mpctx->opts->osd_duration);
|
||||
msg->show_position = true;
|
||||
// Never in term-osd mode
|
||||
if (mpctx->video_out && mpctx->opts->term_osd != 1) {
|
||||
mp_osd_msg_t *msg = add_osd_msg(mpctx, OSD_MSG_TEXT, 1,
|
||||
mpctx->opts->osd_duration);
|
||||
msg->show_position = true;
|
||||
}
|
||||
}
|
||||
if (mpctx->add_osd_seek_info & OSD_SEEK_INFO_CHAPTER_TEXT) {
|
||||
char *chapter = chapter_display_name(mpctx, get_current_chapter(mpctx));
|
||||
@@ -485,8 +488,8 @@ void update_osd_msg(struct MPContext *mpctx)
|
||||
mpctx->terminal_osd_text = talloc_strdup(mpctx, msg->msg);
|
||||
// Multi-line message => clear what will be the second line
|
||||
write_status_line(mpctx, "");
|
||||
MP_MSG(mpctx, MSGL_STATUS, "%s%s\n", opts->term_osd_esc,
|
||||
mpctx->terminal_osd_text);
|
||||
mp_msg(mpctx->statusline, MSGL_STATUS,
|
||||
"%s%s\n", opts->term_osd_esc, mpctx->terminal_osd_text);
|
||||
print_status(mpctx);
|
||||
}
|
||||
}
|
||||
@@ -512,6 +515,6 @@ void update_osd_msg(struct MPContext *mpctx)
|
||||
// Clear the term osd line
|
||||
if (opts->term_osd && mpctx->terminal_osd_text[0]) {
|
||||
mpctx->terminal_osd_text[0] = '\0';
|
||||
MP_MSG(mpctx, MSGL_STATUS, "%s\n", opts->term_osd_esc);
|
||||
mp_msg(mpctx->statusline, MSGL_STATUS, "%s\n", opts->term_osd_esc);
|
||||
}
|
||||
}
|
||||
+19
-14
@@ -66,13 +66,13 @@ static const char av_desync_help_text[] =
|
||||
" Experiment with different values for --autosync, 30 is a good start.\n"
|
||||
" If you have PulseAudio, try --ao=alsa .\n"
|
||||
"- Slow video output.\n"
|
||||
" Try a different -vo driver (-vo help for a list) or try -framedrop!\n"
|
||||
" Try a different --vo driver (--vo=help for a list) or try --framedrop!\n"
|
||||
"- Playing a video file with --vo=opengl with higher FPS than the monitor.\n"
|
||||
" This is due to vsync limiting the framerate.\n"
|
||||
"- Playing from a slow network source.\n"
|
||||
" Download the file instead.\n"
|
||||
"- Try to find out whether audio or video is causing this by experimenting\n"
|
||||
" with --no-video and --no-audio.\n"
|
||||
"- Try to find out whether audio/video/subs are causing this by experimenting\n"
|
||||
" with --no-video, --no-audio, or --no-sub.\n"
|
||||
"- If you swiched audio or video tracks, try seeking to force synchronization.\n"
|
||||
"If none of this helps you, file a bug report.\n\n";
|
||||
|
||||
@@ -168,14 +168,14 @@ void add_step_frame(struct MPContext *mpctx, int dir)
|
||||
}
|
||||
}
|
||||
|
||||
static void seek_reset(struct MPContext *mpctx, bool reset_ao)
|
||||
static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac)
|
||||
{
|
||||
if (mpctx->d_video) {
|
||||
video_reset_decoding(mpctx->d_video);
|
||||
vo_seek_reset(mpctx->video_out);
|
||||
}
|
||||
|
||||
if (mpctx->d_audio) {
|
||||
if (mpctx->d_audio && reset_ac) {
|
||||
audio_reset_decoding(mpctx->d_audio);
|
||||
if (reset_ao)
|
||||
clear_audio_output_buffers(mpctx);
|
||||
@@ -204,9 +204,6 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao)
|
||||
}
|
||||
|
||||
// return -1 if seek failed (non-seekable stream?), 0 otherwise
|
||||
// timeline_fallthrough: true if used to explicitly switch timeline - in this
|
||||
// case, don't drop buffered AO audio data, so that
|
||||
// timeline segment transition is seemless
|
||||
static int mp_seek(MPContext *mpctx, struct seek_params seek,
|
||||
bool timeline_fallthrough)
|
||||
{
|
||||
@@ -253,6 +250,9 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
|
||||
seek.amount += get_current_time(mpctx);
|
||||
}
|
||||
|
||||
/* At least the liba52 decoder wants to read from the input stream
|
||||
* during initialization, so reinit must be done after the demux_seek()
|
||||
* call that clears possible stream EOF. */
|
||||
bool need_reset = false;
|
||||
double demuxer_amount = seek.amount;
|
||||
if (mpctx->timeline) {
|
||||
@@ -271,7 +271,6 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
|
||||
}
|
||||
if (need_reset) {
|
||||
reinit_video_chain(mpctx);
|
||||
reinit_audio_chain(mpctx);
|
||||
reinit_subs(mpctx, 0);
|
||||
reinit_subs(mpctx, 1);
|
||||
}
|
||||
@@ -296,8 +295,10 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
|
||||
demuxer_amount -= hr_seek_offset;
|
||||
int seekresult = demux_seek(mpctx->demuxer, demuxer_amount, demuxer_style);
|
||||
if (seekresult == 0) {
|
||||
if (need_reset)
|
||||
seek_reset(mpctx, !timeline_fallthrough);
|
||||
if (need_reset) {
|
||||
reinit_audio_chain(mpctx);
|
||||
seek_reset(mpctx, !timeline_fallthrough, false);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -315,7 +316,11 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
|
||||
}
|
||||
}
|
||||
|
||||
seek_reset(mpctx, !timeline_fallthrough);
|
||||
if (need_reset)
|
||||
reinit_audio_chain(mpctx);
|
||||
/* If we just reinitialized audio it doesn't need to be reset,
|
||||
* and resetting could lose audio some decoders produce during init. */
|
||||
seek_reset(mpctx, !timeline_fallthrough, !need_reset);
|
||||
|
||||
if (timeline_fallthrough) {
|
||||
// Important if video reinit happens.
|
||||
@@ -571,7 +576,7 @@ bool mp_seek_chapter(struct MPContext *mpctx, int chapter)
|
||||
if (res >= 0) {
|
||||
if (pts == -1) {
|
||||
// for DVD/BD - seek happened via stream layer
|
||||
seek_reset(mpctx, true);
|
||||
seek_reset(mpctx, true, true);
|
||||
mpctx->seek = (struct seek_params){0};
|
||||
return true;
|
||||
}
|
||||
@@ -924,7 +929,7 @@ static double get_wakeup_period(struct MPContext *mpctx)
|
||||
*/
|
||||
double sleeptime = WAKEUP_PERIOD;
|
||||
|
||||
#ifndef HAVE_POSIX_SELECT
|
||||
#if !HAVE_POSIX_SELECT
|
||||
// No proper file descriptor event handling; keep waking up to poll input
|
||||
sleeptime = MPMIN(sleeptime, 0.02);
|
||||
#endif
|
||||
|
||||
@@ -164,7 +164,7 @@ static void copy_chapters(struct chapter **chapters, int *num_chapters,
|
||||
double time = demuxer_chapter_time(src, n);
|
||||
if (time >= start && time <= start + len) {
|
||||
struct chapter ch = {
|
||||
.start = dest_offset + time,
|
||||
.start = dest_offset + time - start,
|
||||
.name = talloc_steal(*chapters, demuxer_chapter_name(src, n)),
|
||||
};
|
||||
MP_TARRAY_APPEND(NULL, *chapters, *num_chapters, ch);
|
||||
@@ -201,7 +201,7 @@ static void build_timeline(struct MPContext *mpctx, struct tl_parts *parts)
|
||||
part->filename);
|
||||
}
|
||||
|
||||
// Unkown length => use rest of the file. If duration is unknown, make
|
||||
// Unknown length => use rest of the file. If duration is unknown, make
|
||||
// something up.
|
||||
if (part->length < 0)
|
||||
part->length = (len < 0 ? 1 : len) - part->offset;
|
||||
|
||||
@@ -65,6 +65,7 @@ static void reconfig_video(struct MPContext *mpctx,
|
||||
const struct mp_image_params *params,
|
||||
bool probe_only)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
struct dec_video *d_video = mpctx->d_video;
|
||||
|
||||
d_video->decoder_output = *params;
|
||||
@@ -96,6 +97,19 @@ static void reconfig_video(struct MPContext *mpctx,
|
||||
int r = vo_reconfig(mpctx->video_out, &p, 0);
|
||||
if (r < 0)
|
||||
d_video->vfilter->initialized = -1;
|
||||
|
||||
if (r >= 0) {
|
||||
if (opts->gamma_gamma != 1000)
|
||||
video_set_colors(d_video, "gamma", opts->gamma_gamma);
|
||||
if (opts->gamma_brightness != 1000)
|
||||
video_set_colors(d_video, "brightness", opts->gamma_brightness);
|
||||
if (opts->gamma_contrast != 1000)
|
||||
video_set_colors(d_video, "contrast", opts->gamma_contrast);
|
||||
if (opts->gamma_saturation != 1000)
|
||||
video_set_colors(d_video, "saturation", opts->gamma_saturation);
|
||||
if (opts->gamma_hue != 1000)
|
||||
video_set_colors(d_video, "hue", opts->gamma_hue);
|
||||
}
|
||||
}
|
||||
|
||||
static void recreate_video_filters(struct MPContext *mpctx)
|
||||
|
||||
+34
-12
@@ -33,6 +33,9 @@
|
||||
// the cache is active.
|
||||
#define CACHE_UPDATE_CONTROLS_TIME 2.0
|
||||
|
||||
// Time in seconds the cache prints a new message at all.
|
||||
#define CACHE_NO_SPAM 5.0
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -72,11 +75,13 @@ struct priv {
|
||||
int64_t fill_limit; // we should fill buffer only if space>=fill_limit
|
||||
int64_t seek_limit; // keep filling cache if distance is less that seek limit
|
||||
struct byte_meta *bm; // additional per-byte metadata
|
||||
bool seekable; // underlying stream is seekable
|
||||
|
||||
struct mp_log *log;
|
||||
|
||||
// Owned by the main thread
|
||||
stream_t *cache; // wrapper stream, used by demuxer etc.
|
||||
double last_warn_time;
|
||||
|
||||
// Owned by the cache thread
|
||||
stream_t *stream; // "real" stream, used to read from the source media
|
||||
@@ -142,15 +147,19 @@ static int cache_wakeup_and_wait(struct priv *s, double *retry_time)
|
||||
if (stream_check_interrupt(0))
|
||||
return CACHE_INTERRUPTED;
|
||||
|
||||
// Print a "more severe" warning after waiting 1 second and no new data
|
||||
if ((*retry_time) >= 1.0) {
|
||||
MP_ERR(s, "Cache keeps not responding.\n");
|
||||
} else if (*retry_time > 0.1) {
|
||||
MP_WARN(s, "Cache is not responding - slow/stuck network connection?\n");
|
||||
}
|
||||
|
||||
double start = mp_time_sec();
|
||||
|
||||
if (!s->last_warn_time || start - s->last_warn_time >= CACHE_NO_SPAM) {
|
||||
// Print a "more severe" warning after waiting 1 second and no new data
|
||||
if ((*retry_time) >= 1.0) {
|
||||
MP_ERR(s, "Cache keeps not responding.\n");
|
||||
s->last_warn_time = start;
|
||||
} else if (*retry_time > 0.1) {
|
||||
MP_WARN(s, "Cache is not responding - slow/stuck network connection?\n");
|
||||
s->last_warn_time = start;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cond_signal(&s->wakeup);
|
||||
mpthread_cond_timed_wait(&s->wakeup, &s->mutex, CACHE_WAIT_TIME);
|
||||
|
||||
@@ -467,6 +476,7 @@ static int cache_seek(stream_t *cache, int64_t pos)
|
||||
{
|
||||
struct priv *s = cache->priv;
|
||||
assert(s->cache_thread_running);
|
||||
int r = 1;
|
||||
|
||||
pthread_mutex_lock(&s->mutex);
|
||||
|
||||
@@ -474,12 +484,21 @@ static int cache_seek(stream_t *cache, int64_t pos)
|
||||
" (cur=%" PRId64 ") <= %" PRId64 " \n",
|
||||
s->min_filepos, pos, s->read_filepos, s->max_filepos);
|
||||
|
||||
cache->pos = s->read_filepos = pos;
|
||||
s->eof = false; // so that cache_read() will actually wait for new data
|
||||
pthread_cond_signal(&s->wakeup);
|
||||
if (!s->seekable && pos > s->max_filepos) {
|
||||
MP_ERR(s, "Attempting to seek past cached data in unseekable stream.\n");
|
||||
r = 0;
|
||||
} else if (!s->seekable && pos < s->min_filepos) {
|
||||
MP_ERR(s, "Attempting to seek before cached data in unseekable stream.\n");
|
||||
r = 0;
|
||||
} else {
|
||||
cache->pos = s->read_filepos = pos;
|
||||
s->eof = false; // so that cache_read() will actually wait for new data
|
||||
pthread_cond_signal(&s->wakeup);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s->mutex);
|
||||
|
||||
return 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int cache_control(stream_t *cache, int cmd, void *arg)
|
||||
@@ -495,7 +514,7 @@ static int cache_control(stream_t *cache, int cmd, void *arg)
|
||||
if (r != STREAM_ERROR)
|
||||
goto done;
|
||||
|
||||
MP_VERBOSE(s, "[cache] blocking for STREAM_CTRL %d\n", cmd);
|
||||
MP_VERBOSE(s, "blocking for STREAM_CTRL %d\n", cmd);
|
||||
|
||||
s->control = cmd;
|
||||
s->control_arg = arg;
|
||||
@@ -592,6 +611,9 @@ int stream_cache_init(stream_t *cache, stream_t *stream, int64_t size,
|
||||
if (min > s->buffer_size - s->fill_limit)
|
||||
min = s->buffer_size - s->fill_limit;
|
||||
|
||||
s->seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK &&
|
||||
stream->end_pos > 0;
|
||||
|
||||
if (pthread_create(&s->cache_thread, NULL, cache_thread, s) != 0) {
|
||||
MP_ERR(s, "Starting cache process/thread failed: %s.\n",
|
||||
strerror(errno));
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer 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.
|
||||
*
|
||||
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_CDD_H
|
||||
#define MPLAYER_CDD_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
struct mp_log;
|
||||
|
||||
typedef struct cd_track {
|
||||
char *name;
|
||||
unsigned int track_nb;
|
||||
unsigned int min;
|
||||
unsigned int sec;
|
||||
unsigned int msec;
|
||||
unsigned long frame_begin;
|
||||
unsigned long frame_length;
|
||||
struct cd_track *prev;
|
||||
struct cd_track *next;
|
||||
} cd_track_t;
|
||||
|
||||
typedef struct {
|
||||
char *artist;
|
||||
char *album;
|
||||
char *genre;
|
||||
unsigned int nb_tracks;
|
||||
unsigned int min;
|
||||
unsigned int sec;
|
||||
unsigned msec;
|
||||
cd_track_t *first;
|
||||
cd_track_t *last;
|
||||
cd_track_t *current;
|
||||
} cd_info_t;
|
||||
|
||||
cd_info_t* cd_info_new(void);
|
||||
void cd_info_free(cd_info_t *cd_info);
|
||||
cd_track_t* cd_info_add_track(cd_info_t *cd_info, char *track_name, unsigned int track_nb, unsigned int min, unsigned int sec, unsigned int msec, unsigned long frame_begin, unsigned long frame_length);
|
||||
cd_track_t* cd_info_get_track(cd_info_t *cd_info, unsigned int track_nb);
|
||||
|
||||
void cd_info_debug(cd_info_t *cd_info, struct mp_log *log);
|
||||
|
||||
#endif /* MPLAYER_CDD_H */
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* CD Info
|
||||
*
|
||||
* Copyright (C) 2002 Bertrand Baudet <bertrand_baudet@yahoo.com>
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer 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.
|
||||
*
|
||||
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common/msg.h"
|
||||
#include "cdd.h"
|
||||
|
||||
/*******************************************************************************************************************
|
||||
*
|
||||
* xmcd parser, cd info list
|
||||
*
|
||||
*******************************************************************************************************************/
|
||||
|
||||
cd_info_t*
|
||||
cd_info_new(void) {
|
||||
cd_info_t *cd_info = NULL;
|
||||
|
||||
cd_info = malloc(sizeof(cd_info_t));
|
||||
if( cd_info==NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(cd_info, 0, sizeof(cd_info_t));
|
||||
|
||||
return cd_info;
|
||||
}
|
||||
|
||||
void
|
||||
cd_info_free(cd_info_t *cd_info) {
|
||||
cd_track_t *cd_track, *cd_track_next;
|
||||
if( cd_info==NULL ) return;
|
||||
free(cd_info->artist);
|
||||
free(cd_info->album);
|
||||
free(cd_info->genre);
|
||||
|
||||
cd_track_next = cd_info->first;
|
||||
while( cd_track_next!=NULL ) {
|
||||
cd_track = cd_track_next;
|
||||
cd_track_next = cd_track->next;
|
||||
free(cd_track->name);
|
||||
free(cd_track);
|
||||
}
|
||||
}
|
||||
|
||||
cd_track_t*
|
||||
cd_info_add_track(cd_info_t *cd_info, char *track_name, unsigned int track_nb, unsigned int min, unsigned int sec, unsigned int msec, unsigned long frame_begin, unsigned long frame_length) {
|
||||
cd_track_t *cd_track;
|
||||
|
||||
if( cd_info==NULL || track_name==NULL ) return NULL;
|
||||
|
||||
cd_track = malloc(sizeof(cd_track_t));
|
||||
if( cd_track==NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
memset(cd_track, 0, sizeof(cd_track_t));
|
||||
|
||||
cd_track->name = malloc(strlen(track_name)+1);
|
||||
if( cd_track->name==NULL ) {
|
||||
free(cd_track);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(cd_track->name, track_name);
|
||||
cd_track->track_nb = track_nb;
|
||||
cd_track->min = min;
|
||||
cd_track->sec = sec;
|
||||
cd_track->msec = msec;
|
||||
cd_track->frame_begin = frame_begin;
|
||||
cd_track->frame_length = frame_length;
|
||||
|
||||
if( cd_info->first==NULL ) {
|
||||
cd_info->first = cd_track;
|
||||
}
|
||||
if( cd_info->last!=NULL ) {
|
||||
cd_info->last->next = cd_track;
|
||||
}
|
||||
|
||||
cd_track->prev = cd_info->last;
|
||||
|
||||
cd_info->last = cd_track;
|
||||
cd_info->current = cd_track;
|
||||
|
||||
cd_info->nb_tracks++;
|
||||
|
||||
return cd_track;
|
||||
}
|
||||
|
||||
cd_track_t*
|
||||
cd_info_get_track(cd_info_t *cd_info, unsigned int track_nb) {
|
||||
cd_track_t *cd_track=NULL;
|
||||
|
||||
if( cd_info==NULL ) return NULL;
|
||||
|
||||
cd_track = cd_info->first;
|
||||
while( cd_track!=NULL ) {
|
||||
if( cd_track->track_nb==track_nb ) {
|
||||
return cd_track;
|
||||
}
|
||||
cd_track = cd_track->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cd_info_debug(cd_info_t *cd_info, struct mp_log *log)
|
||||
{
|
||||
cd_track_t *current_track;
|
||||
mp_info(log, "================ CD INFO === start =========\n");
|
||||
if( cd_info==NULL ) {
|
||||
mp_info(log, "cd_info is NULL\n");
|
||||
return;
|
||||
}
|
||||
mp_info(log, " artist=[%s]\n", cd_info->artist);
|
||||
mp_info(log, " album=[%s]\n", cd_info->album);
|
||||
mp_info(log, " genre=[%s]\n", cd_info->genre);
|
||||
mp_info(log, " nb_tracks=%d\n", cd_info->nb_tracks);
|
||||
mp_info(log, " length= %2d:%02d.%02d\n", cd_info->min, cd_info->sec, cd_info->msec);
|
||||
|
||||
mp_info(log, "ID_CDDB_INFO_ARTIST=%s\n", cd_info->artist);
|
||||
mp_info(log, "ID_CDDB_INFO_ALBUM=%s\n", cd_info->album);
|
||||
mp_info(log, "ID_CDDB_INFO_GENRE=%s\n", cd_info->genre);
|
||||
mp_info(log, "ID_CDDB_INFO_LENGTH_MSF=%02d:%02d.%02d\n", cd_info->min, cd_info->sec, cd_info->msec);
|
||||
mp_info(log, "ID_CDDB_INFO_TRACKS=%d\n", cd_info->nb_tracks);
|
||||
|
||||
current_track = cd_info->first;
|
||||
while( current_track!=NULL ) {
|
||||
mp_info(log, " #%2d %2d:%02d.%02d @ %7ld\t[%s] \n", current_track->track_nb, current_track->min, current_track->sec, current_track->msec, current_track->frame_begin, current_track->name);
|
||||
mp_info(log, "ID_CDDB_INFO_TRACK_%d_NAME=%s\n", current_track->track_nb, current_track->name);
|
||||
mp_info(log, "ID_CDDB_INFO_TRACK_%d_MSF=%02d:%02d.%02d\n", current_track->track_nb, current_track->min, current_track->sec, current_track->msec);
|
||||
current_track = current_track->next;
|
||||
}
|
||||
mp_info(log, "================ CD INFO === end =========\n");
|
||||
}
|
||||
+1
-1
@@ -61,7 +61,7 @@ static char *col_dup(void *talloc_ctx, const char *src)
|
||||
}
|
||||
|
||||
/* Finds the start of all the columns */
|
||||
static int parse_line(char **ptr, char *cols[6])
|
||||
static int parse_line(char **ptr, char *cols[7])
|
||||
{
|
||||
int col;
|
||||
cols[0] = *ptr;
|
||||
|
||||
@@ -111,7 +111,7 @@ struct mp_resolve_result *mp_resolve_quvi(const char *url,
|
||||
quvi_media_free(media);
|
||||
}
|
||||
|
||||
if (quvi_supports(q, url, mode, QUVI_SUPPORTS_TYPE_SUBTITLE)) {
|
||||
if (opts->quvi_fetch_subtitles && quvi_supports(q, url, mode, QUVI_SUPPORTS_TYPE_SUBTITLE)) {
|
||||
mp_info(log, "Getting subtitles...\n");
|
||||
quvi_subtitle_t qsub = quvi_subtitle_new(q, url);
|
||||
if (mp_quvi_ok(q, log)) {
|
||||
|
||||
+9
-3
@@ -396,16 +396,22 @@ stream_t *open_output_stream(const char *filename, struct mpv_global *global)
|
||||
static int stream_reconnect(stream_t *s)
|
||||
{
|
||||
#define MAX_RECONNECT_RETRIES 5
|
||||
#define RECONNECT_SLEEP_MS 1000
|
||||
#define RECONNECT_SLEEP_MAX_MS 500
|
||||
if (!s->streaming)
|
||||
return 0;
|
||||
if (!(s->flags & MP_STREAM_SEEK_FW))
|
||||
return 0;
|
||||
int64_t pos = s->pos;
|
||||
int sleep_ms = 5;
|
||||
for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) {
|
||||
MP_WARN(s, "Connection lost! Attempting to reconnect (%d)...\n", retry + 1);
|
||||
|
||||
if (stream_check_interrupt(retry ? RECONNECT_SLEEP_MS : 0))
|
||||
if (retry) {
|
||||
mp_sleep_us(sleep_ms * 1000);
|
||||
sleep_ms = MPMIN(sleep_ms * 2, RECONNECT_SLEEP_MAX_MS);
|
||||
}
|
||||
|
||||
if (stream_check_interrupt(0))
|
||||
return 0;
|
||||
|
||||
s->eof = 1;
|
||||
@@ -562,7 +568,7 @@ struct bstr stream_peek(stream_t *s, int len)
|
||||
while (buf_valid < len) {
|
||||
int chunk = MPMAX(len - buf_valid, STREAM_BUFFER_SIZE);
|
||||
if (s->sector_size)
|
||||
chunk = STREAM_BUFFER_SIZE;
|
||||
chunk = s->sector_size;
|
||||
assert(buf_valid + chunk <= TOTAL_BUFFER_SIZE);
|
||||
int read = stream_read_unbuffered(s, &s->buffer[buf_valid], chunk);
|
||||
if (read == 0)
|
||||
|
||||
@@ -35,6 +35,7 @@ enum streamtype {
|
||||
STREAMTYPE_RADIO,
|
||||
STREAMTYPE_DVB,
|
||||
STREAMTYPE_DVD,
|
||||
STREAMTYPE_BLURAY,
|
||||
STREAMTYPE_PVR,
|
||||
STREAMTYPE_TV,
|
||||
STREAMTYPE_MF,
|
||||
|
||||
@@ -187,6 +187,7 @@ static int bluray_stream_control(stream_t *s, int cmd, void *arg)
|
||||
return STREAM_UNSUPPORTED;
|
||||
|
||||
*((double *) arg) = BD_TIME_TO_MP(ti->duration);
|
||||
bd_free_title_info(ti);
|
||||
return STREAM_OK;
|
||||
}
|
||||
|
||||
@@ -390,6 +391,7 @@ err_no_info:
|
||||
b->current_angle = angle;
|
||||
b->current_title = title;
|
||||
|
||||
s->type = STREAMTYPE_BLURAY;
|
||||
s->end_pos = title_size;
|
||||
s->sector_size = BLURAY_SECTOR_SIZE;
|
||||
s->flags = MP_STREAM_SEEK;
|
||||
|
||||
+16
-68
@@ -46,8 +46,6 @@
|
||||
#include "libavutil/common.h"
|
||||
#include "compat/mpbswap.h"
|
||||
|
||||
#include "cdd.h"
|
||||
|
||||
#include "common/msg.h"
|
||||
|
||||
typedef struct {
|
||||
@@ -56,7 +54,6 @@ typedef struct {
|
||||
int sector;
|
||||
int start_sector;
|
||||
int end_sector;
|
||||
cd_info_t *cd_info;
|
||||
|
||||
// options
|
||||
int speed;
|
||||
@@ -132,8 +129,8 @@ static bool print_cdtext(stream_t *s, int track)
|
||||
#else
|
||||
cdtext_t *text = cdio_get_cdtext(p->cd->p_cdio);
|
||||
#endif
|
||||
int header = 0;
|
||||
if (text) {
|
||||
MP_INFO(s, "CD-Text (%s):\n", track ? "track" : "CD");
|
||||
for (int i = 0; i < sizeof(cdtext_name) / sizeof(cdtext_name[0]); i++) {
|
||||
const char *name = cdtext_name[i];
|
||||
#ifdef OLD_API
|
||||
@@ -141,8 +138,12 @@ static bool print_cdtext(stream_t *s, int track)
|
||||
#else
|
||||
const char *value = cdtext_get_const(text, i, track);
|
||||
#endif
|
||||
if (name && value)
|
||||
if (name && value) {
|
||||
if (!header)
|
||||
MP_INFO(s, "CD-Text (%s):\n", track ? "track" : "CD");
|
||||
header = 1;
|
||||
MP_INFO(s, " %s: '%s'\n", name, value);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -151,17 +152,8 @@ static bool print_cdtext(stream_t *s, int track)
|
||||
|
||||
static void print_track_info(stream_t *s, int track)
|
||||
{
|
||||
cdda_priv* p = (cdda_priv*)s->priv;
|
||||
cd_track_t *cd_track = cd_info_get_track(p->cd_info, track);
|
||||
if( cd_track!=NULL ) {
|
||||
MP_INFO(s, "\n%s\n", cd_track->name);
|
||||
MP_INFO(s, "ID_CDDA_TRACK=%d\n",
|
||||
cd_track->track_nb);
|
||||
}
|
||||
if (print_cdtext(s, track)) {
|
||||
// hack for term OSD overwriting the last line of CDTEXT
|
||||
MP_INFO(s, "\n");
|
||||
}
|
||||
MP_INFO(s, "Switched to track %d\n", track);
|
||||
print_cdtext(s, track);
|
||||
}
|
||||
|
||||
static void cdparanoia_callback(long int inpos, paranoia_cb_mode_t function)
|
||||
@@ -242,7 +234,6 @@ static void close_cdda(stream_t *s)
|
||||
cdda_priv *p = (cdda_priv *)s->priv;
|
||||
paranoia_free(p->cdp);
|
||||
cdda_close(p->cd);
|
||||
cd_info_free(p->cd_info);
|
||||
free(p);
|
||||
}
|
||||
|
||||
@@ -273,37 +264,18 @@ static int control(stream_t *stream, int cmd, void *arg)
|
||||
*(unsigned int *)arg = end_track + 1 - start_track;
|
||||
return STREAM_OK;
|
||||
}
|
||||
case STREAM_CTRL_SEEK_TO_CHAPTER:
|
||||
case STREAM_CTRL_GET_CHAPTER_TIME:
|
||||
{
|
||||
int r;
|
||||
unsigned int track = *(unsigned int *)arg;
|
||||
int track = *(double *)arg;
|
||||
int start_track = get_track_by_sector(p, p->start_sector);
|
||||
int end_track = get_track_by_sector(p, p->end_sector);
|
||||
int seek_sector;
|
||||
if (start_track == -1 || end_track == -1)
|
||||
track += start_track + 1;
|
||||
if (track > end_track)
|
||||
return STREAM_ERROR;
|
||||
track += start_track;
|
||||
if (track > end_track) {
|
||||
seek(stream, (p->end_sector + 1) * CDIO_CD_FRAMESIZE_RAW);
|
||||
// seeking beyond EOF should not be an error,
|
||||
// the cache cannot handle changing stream pos and
|
||||
// returning error.
|
||||
return STREAM_OK;
|
||||
}
|
||||
seek_sector = track == 0 ? p->start_sector
|
||||
: p->cd->disc_toc[track].dwStartSector;
|
||||
r = seek(stream, seek_sector * CDIO_CD_FRAMESIZE_RAW);
|
||||
if (r)
|
||||
return STREAM_OK;
|
||||
break;
|
||||
}
|
||||
case STREAM_CTRL_GET_CURRENT_CHAPTER:
|
||||
{
|
||||
int start_track = get_track_by_sector(p, p->start_sector);
|
||||
int cur_track = get_track_by_sector(p, p->sector);
|
||||
if (start_track == -1 || cur_track == -1)
|
||||
return STREAM_ERROR;
|
||||
*(unsigned int *)arg = cur_track - start_track;
|
||||
int64_t sector = p->cd->disc_toc[track].dwStartSector;
|
||||
int64_t pos = sector * (CDIO_CD_FRAMESIZE_RAW + 1) - 1;
|
||||
// Assume standard audio CD: 44.1khz, 2 channels, s16 samples
|
||||
*(double *)arg = pos / (44100.0 * 2 * 2);
|
||||
return STREAM_OK;
|
||||
}
|
||||
}
|
||||
@@ -317,10 +289,7 @@ static int open_cdda(stream_t *st, int m)
|
||||
int mode = p->paranoia_mode;
|
||||
int offset = p->toc_offset;
|
||||
cdrom_drive_t *cdd = NULL;
|
||||
cd_info_t *cd_info;
|
||||
unsigned int audiolen = 0;
|
||||
int last_track;
|
||||
int i;
|
||||
|
||||
if (m != STREAM_READ) {
|
||||
return STREAM_UNSUPPORTED;
|
||||
@@ -355,29 +324,9 @@ static int open_cdda(stream_t *st, int m)
|
||||
return STREAM_ERROR;
|
||||
}
|
||||
|
||||
cd_info = cd_info_new();
|
||||
MP_INFO(st, "Found audio CD with %d tracks.\n",
|
||||
(int)cdda_tracks(cdd));
|
||||
for (i = 0; i < cdd->tracks; i++) {
|
||||
char track_name[80];
|
||||
long sec = cdda_track_firstsector(cdd, i + 1);
|
||||
long off = cdda_track_lastsector(cdd, i + 1) - sec + 1;
|
||||
|
||||
sprintf(track_name, "Track %d", i + 1);
|
||||
cd_info_add_track(cd_info, track_name, i + 1,
|
||||
(unsigned int)(off / (60 * 75)),
|
||||
(unsigned int)((off / 75) % 60),
|
||||
(unsigned int)(off % 75), sec, off);
|
||||
audiolen += off;
|
||||
}
|
||||
cd_info->min = (unsigned int)(audiolen / (60 * 75));
|
||||
cd_info->sec = (unsigned int)((audiolen / 75) % 60);
|
||||
cd_info->msec = (unsigned int)(audiolen % 75);
|
||||
|
||||
priv = malloc(sizeof(cdda_priv));
|
||||
memset(priv, 0, sizeof(cdda_priv));
|
||||
priv->cd = cdd;
|
||||
priv->cd_info = cd_info;
|
||||
|
||||
if (p->toc_bias)
|
||||
offset -= cdda_track_firstsector(cdd, 1);
|
||||
@@ -411,7 +360,6 @@ static int open_cdda(stream_t *st, int m)
|
||||
if (priv->cdp == NULL) {
|
||||
cdda_close(cdd);
|
||||
free(priv);
|
||||
cd_info_free(cd_info);
|
||||
return STREAM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
+37
-30
@@ -298,42 +298,47 @@ static void handle_cmd(stream_t *s, struct mp_nav_cmd *ev)
|
||||
|
||||
}
|
||||
|
||||
static inline bool set_event_type(struct priv *priv, int type,
|
||||
struct mp_nav_event *event)
|
||||
{
|
||||
if (!(priv->next_event & (1 << type)))
|
||||
return false;
|
||||
priv->next_event &= ~(1 << type);
|
||||
event->event = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void fill_next_event(stream_t *s, struct mp_nav_event **ret)
|
||||
{
|
||||
struct priv *priv = s->priv;
|
||||
struct mp_nav_event e = {0};
|
||||
for (int n = 0; n < 30; n++) {
|
||||
if (priv->next_event & (1 << n)) {
|
||||
priv->next_event &= ~(1 << n);
|
||||
e.event = n;
|
||||
switch (e.event) {
|
||||
case MP_NAV_EVENT_HIGHLIGHT: {
|
||||
dvdnav_highlight_event_t hlev = priv->hlev;
|
||||
e.u.highlight.display = hlev.display;
|
||||
e.u.highlight.sx = hlev.sx;
|
||||
e.u.highlight.sy = hlev.sy;
|
||||
e.u.highlight.ex = hlev.ex;
|
||||
e.u.highlight.ey = hlev.ey;
|
||||
e.u.highlight.palette = hlev.palette;
|
||||
break;
|
||||
}
|
||||
case MP_NAV_EVENT_MENU_MODE:
|
||||
e.u.menu_mode.enable = !dvdnav_is_domain_vts(priv->dvdnav);
|
||||
break;
|
||||
case MP_NAV_EVENT_STILL_FRAME:
|
||||
e.u.still_frame.seconds = priv->still_length;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!set_event_type(priv, MP_NAV_EVENT_RESET_ALL, &e))
|
||||
for (int n = 0; n < 30 && !set_event_type(priv, n, &e); n++) ;
|
||||
switch (e.event) {
|
||||
case MP_NAV_EVENT_NONE:
|
||||
return;
|
||||
case MP_NAV_EVENT_HIGHLIGHT: {
|
||||
dvdnav_highlight_event_t hlev = priv->hlev;
|
||||
e.u.highlight.display = hlev.display;
|
||||
e.u.highlight.sx = hlev.sx;
|
||||
e.u.highlight.sy = hlev.sy;
|
||||
e.u.highlight.ex = hlev.ex;
|
||||
e.u.highlight.ey = hlev.ey;
|
||||
e.u.highlight.palette = hlev.palette;
|
||||
break;
|
||||
}
|
||||
if (e.event) {
|
||||
*ret = talloc(NULL, struct mp_nav_event);
|
||||
**ret = e;
|
||||
case MP_NAV_EVENT_MENU_MODE:
|
||||
e.u.menu_mode.enable = !dvdnav_is_domain_vts(priv->dvdnav);
|
||||
break;
|
||||
case MP_NAV_EVENT_STILL_FRAME:
|
||||
e.u.still_frame.seconds = priv->still_length;
|
||||
break;
|
||||
}
|
||||
*ret = talloc(NULL, struct mp_nav_event);
|
||||
**ret = e;
|
||||
|
||||
MP_VERBOSE(s, "DVDNAV: player event '%s'\n",
|
||||
LOOKUP_NAME(mp_nav_event_types, e.event));
|
||||
}
|
||||
MP_VERBOSE(s, "DVDNAV: player event '%s'\n",
|
||||
LOOKUP_NAME(mp_nav_event_types, e.event));
|
||||
}
|
||||
|
||||
static int fill_buffer(stream_t *s, char *buf, int max_len)
|
||||
@@ -414,6 +419,8 @@ static int fill_buffer(stream_t *s, char *buf, int max_len)
|
||||
priv->had_initial_vts = true;
|
||||
break;
|
||||
}
|
||||
// clear all previous events
|
||||
priv->next_event = 0;
|
||||
priv->next_event |= 1 << MP_NAV_EVENT_RESET;
|
||||
priv->next_event |= 1 << MP_NAV_EVENT_RESET_ALL;
|
||||
if (dvdnav_current_title_info(dvdnav, &tit, &part) == DVDNAV_STATUS_OK)
|
||||
|
||||
@@ -33,6 +33,7 @@ mf_stream_open (stream_t *stream, int mode)
|
||||
{
|
||||
stream->type = STREAMTYPE_MF;
|
||||
stream->demuxer = "mf";
|
||||
stream->allow_caching = false;
|
||||
|
||||
return STREAM_OK;
|
||||
}
|
||||
|
||||
+2
-1
@@ -190,7 +190,7 @@ pvr_uninit (struct pvr_t *pvr)
|
||||
return;
|
||||
|
||||
/* close device */
|
||||
if (pvr->dev_fd)
|
||||
if (pvr->dev_fd != -1)
|
||||
close (pvr->dev_fd);
|
||||
|
||||
free (pvr->video_dev);
|
||||
@@ -1520,6 +1520,7 @@ pvr_stream_open (stream_t *stream, int mode)
|
||||
return STREAM_UNSUPPORTED;
|
||||
|
||||
pvr = pvr_init ();
|
||||
pvr->log = stream->log;
|
||||
|
||||
/**
|
||||
* if the url, i.e. 'pvr://8', contains the channel, use it,
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ static mp_vcd_priv_t* vcd_read_toc(stream_t *stream, int fd){
|
||||
|
||||
static int vcd_read(mp_vcd_priv_t* vcd,char *mem){
|
||||
#ifndef sun
|
||||
memcpy(vcd->buf,&vcd->entry.cdte_addr.msf,sizeof(struct cdrom_msf));
|
||||
memcpy(vcd->buf,&vcd->entry.cdte_addr.msf,sizeof(vcd->entry.cdte_addr.msf));
|
||||
if(ioctl(vcd->fd,CDROMREADRAW,vcd->buf)==-1) return 0; // EOF?
|
||||
memcpy(mem,&vcd->buf[VCD_SECTOR_OFFS],VCD_SECTOR_DATA);
|
||||
#else
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ void mp_ass_set_style(ASS_Style *style, double res_y,
|
||||
void mp_ass_add_default_styles(ASS_Track *track, struct MPOpts *opts)
|
||||
{
|
||||
if (opts->ass_styles_file && opts->ass_style_override)
|
||||
ass_read_styles(track, opts->ass_styles_file, opts->sub_cp);
|
||||
ass_read_styles(track, opts->ass_styles_file, NULL);
|
||||
|
||||
if (track->n_styles == 0) {
|
||||
if (!track->PlayResY) {
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
#define MP_ASS_FONT_PLAYRESY 288
|
||||
|
||||
#define MP_ASS_RGBA(r, g, b, a) \
|
||||
(((r) << 24U) | ((g) << 16) | ((b) << 8) | (0xFF - (a)))
|
||||
(((unsigned)(r) << 24) | ((g) << 16) | ((b) << 8) | (0xFF - (a)))
|
||||
|
||||
// m_color argument
|
||||
#define MP_ASS_COLOR(c) MP_ASS_RGBA((c).r, (c).g, (c).b, (c).a)
|
||||
|
||||
+3
-1
@@ -175,6 +175,8 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_stream *sh)
|
||||
struct sd init_sd = sub->init_sd;
|
||||
init_sd.codec = sh->codec;
|
||||
init_sd.ass_track = sh->sub->track;
|
||||
init_sd.sub_stream_w = sh->sub->w;
|
||||
init_sd.sub_stream_h = sh->sub->h;
|
||||
|
||||
while (sub->num_sd < MAX_NUM_SD) {
|
||||
struct sd *sd = talloc(NULL, struct sd);
|
||||
@@ -420,7 +422,7 @@ bool sub_read_all_packets(struct dec_sub *sub, struct sh_stream *sh)
|
||||
|
||||
// 23.976 FPS is used as default timebase for frame based formats
|
||||
if (sub->video_fps && sh->sub->frame_based)
|
||||
sub_speed *= sub->video_fps / 23.976;
|
||||
sub_speed *= 23.976 / sub->video_fps;
|
||||
|
||||
if (opts->sub_fps && sub->video_fps)
|
||||
sub_speed *= opts->sub_fps / sub->video_fps;
|
||||
|
||||
@@ -52,11 +52,9 @@ struct sub_bitmap {
|
||||
int x, y;
|
||||
int dw, dh;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint32_t color;
|
||||
} libass;
|
||||
};
|
||||
struct {
|
||||
uint32_t color;
|
||||
} libass;
|
||||
};
|
||||
|
||||
struct sub_bitmaps {
|
||||
|
||||
@@ -25,6 +25,9 @@ struct sd {
|
||||
// the resolution of the VO, nor does it have to be the OSD resolution.
|
||||
int sub_video_w, sub_video_h;
|
||||
|
||||
// Resolution hints stored in mp4 files.
|
||||
int sub_stream_w, sub_stream_h;
|
||||
|
||||
// Make sd_ass use an existing track
|
||||
struct ass_track *ass_track;
|
||||
|
||||
|
||||
+6
-3
@@ -19,6 +19,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include <ass/ass.h>
|
||||
@@ -142,9 +143,11 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res dim, double pts,
|
||||
opts->ass_vsfilter_aspect_compat))
|
||||
{
|
||||
// Let's use the original video PAR for vsfilter compatibility:
|
||||
scale = scale
|
||||
double par = scale
|
||||
* (ctx->video_params.d_w / (double)ctx->video_params.d_h)
|
||||
/ (ctx->video_params.w / (double)ctx->video_params.h);
|
||||
if (isnormal(par))
|
||||
scale = par;
|
||||
}
|
||||
mp_ass_configure(renderer, opts, &dim);
|
||||
ass_set_aspect_ratio(renderer, scale, 1);
|
||||
@@ -421,10 +424,10 @@ static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts)
|
||||
int r = (color >> 24u) & 0xff;
|
||||
int g = (color >> 16u) & 0xff;
|
||||
int b = (color >> 8u) & 0xff;
|
||||
int a = color & 0xff;
|
||||
int a = 0xff - (color & 0xff);
|
||||
int c[3] = {r, g, b};
|
||||
mp_map_int_color(vs_rgb2yuv, 8, c);
|
||||
mp_map_int_color(vs2rgb, 8, c);
|
||||
sb->libass.color = (c[0] << 24u) | (c[1] << 16) | (c[2] << 8) | a;
|
||||
sb->libass.color = MP_ASS_RGBA(c[0], c[1], c[2], a);
|
||||
}
|
||||
}
|
||||
+50
-5
@@ -17,15 +17,18 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "talloc.h"
|
||||
#include "common/msg.h"
|
||||
#include "common/av_common.h"
|
||||
#include "options/options.h"
|
||||
#include "video/mp_image.h"
|
||||
#include "video/csputils.h"
|
||||
#include "sd.h"
|
||||
#include "dec_sub.h"
|
||||
|
||||
@@ -88,9 +91,42 @@ static void get_resolution(struct sd *sd, int wh[2])
|
||||
struct sd_lavc_priv *priv = sd->priv;
|
||||
wh[0] = priv->avctx->width;
|
||||
wh[1] = priv->avctx->height;
|
||||
if (wh[0] <= 0 || wh[1] <= 0) {
|
||||
wh[0] = priv->video_params.w;
|
||||
wh[1] = priv->video_params.h;
|
||||
}
|
||||
guess_resolution(priv->avctx->codec_id, &wh[0], &wh[1]);
|
||||
}
|
||||
|
||||
static void set_mp4_vobsub_idx(AVCodecContext *avctx, char *src, int w, int h)
|
||||
{
|
||||
char pal_s[128];
|
||||
int pal_s_pos = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
unsigned int e = AV_RB32(src + i * 4);
|
||||
|
||||
// lavc doesn't accept YUV palette - "does god hate me?"
|
||||
struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS;
|
||||
csp.int_bits_in = 8;
|
||||
csp.int_bits_out = 8;
|
||||
float cmatrix[3][4];
|
||||
mp_get_yuv2rgb_coeffs(&csp, cmatrix);
|
||||
int c[3] = {(e >> 16) & 0xff, (e >> 8) & 0xff, e & 0xff};
|
||||
mp_map_int_color(cmatrix, 8, c);
|
||||
e = (c[2] << 16) | (c[1] << 8) | c[0];
|
||||
|
||||
snprintf(pal_s + pal_s_pos, sizeof(pal_s) - pal_s_pos, "%06x%s", e,
|
||||
i != 15 ? ", " : "");
|
||||
pal_s_pos = strlen(pal_s);
|
||||
if (pal_s_pos >= sizeof(pal_s))
|
||||
break;
|
||||
}
|
||||
|
||||
char buf[256] = "";
|
||||
snprintf(buf, sizeof(buf), "size: %dx%d\npalette: %s\n", w, h, pal_s);
|
||||
mp_lavc_set_extradata(avctx, buf, strlen(buf));
|
||||
}
|
||||
|
||||
static int init(struct sd *sd)
|
||||
{
|
||||
struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv);
|
||||
@@ -102,8 +138,12 @@ static int init(struct sd *sd)
|
||||
ctx = avcodec_alloc_context3(sub_codec);
|
||||
if (!ctx)
|
||||
goto error;
|
||||
ctx->extradata_size = sd->extradata_len;
|
||||
ctx->extradata = sd->extradata;
|
||||
mp_lavc_set_extradata(ctx, sd->extradata, sd->extradata_len);
|
||||
if (sd->extradata_len == 64 && sd->sub_stream_w && sd->sub_stream_h &&
|
||||
cid == AV_CODEC_ID_DVD_SUBTITLE)
|
||||
{
|
||||
set_mp4_vobsub_idx(ctx, sd->extradata, sd->sub_stream_w, sd->sub_stream_h);
|
||||
}
|
||||
if (avcodec_open2(ctx, sub_codec, NULL) < 0)
|
||||
goto error;
|
||||
priv->avctx = ctx;
|
||||
@@ -182,11 +222,13 @@ static void decode(struct sd *sd, struct demux_packet *packet)
|
||||
sub.num_rects);
|
||||
for (int i = 0; i < sub.num_rects; i++) {
|
||||
struct AVSubtitleRect *r = sub.rects[i];
|
||||
struct sub_bitmap *b = &priv->inbitmaps[i];
|
||||
struct osd_bmp_indexed *img = &priv->imgs[i];
|
||||
struct sub_bitmap *b = &priv->inbitmaps[priv->count];
|
||||
struct osd_bmp_indexed *img = &priv->imgs[priv->count];
|
||||
if (!(r->flags & AV_SUBTITLE_FLAG_FORCED) &&
|
||||
opts->forced_subs_only)
|
||||
continue;
|
||||
if (r->w == 0 || r->h == 0)
|
||||
continue;
|
||||
img->bitmap = r->pict.data[0];
|
||||
assert(r->nb_colors > 0);
|
||||
assert(r->nb_colors * 4 <= sizeof(img->palette));
|
||||
@@ -234,9 +276,11 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res d, double pts,
|
||||
if (priv->avctx->codec_id == AV_CODEC_ID_DVD_SUBTITLE &&
|
||||
opts->stretch_dvd_subs) {
|
||||
// For DVD subs, try to keep the subtitle PAR at display PAR.
|
||||
video_par =
|
||||
double par =
|
||||
(priv->video_params.d_w / (double)priv->video_params.d_h)
|
||||
/ (priv->video_params.w / (double)priv->video_params.h);
|
||||
if (isnormal(par))
|
||||
video_par = par;
|
||||
}
|
||||
int insize[2];
|
||||
get_resolution(sd, insize);
|
||||
@@ -259,6 +303,7 @@ static void uninit(struct sd *sd)
|
||||
|
||||
clear(priv);
|
||||
avcodec_close(priv->avctx);
|
||||
av_free(priv->avctx->extradata);
|
||||
av_free(priv->avctx);
|
||||
talloc_free(priv);
|
||||
}
|
||||
|
||||
+2
-30
@@ -26,7 +26,6 @@
|
||||
|
||||
struct sd_spu_priv {
|
||||
void *spudec;
|
||||
struct mp_image_params video_params;
|
||||
};
|
||||
|
||||
static bool is_dvd_sub(const char *t)
|
||||
@@ -72,22 +71,8 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res d, double pts,
|
||||
spudec_set_forced_subs_only(priv->spudec, opts->forced_subs_only);
|
||||
spudec_heartbeat(priv->spudec, pts * 90000);
|
||||
|
||||
if (spudec_visible(priv->spudec)) {
|
||||
double xscale = 1;
|
||||
double yscale = 1;
|
||||
if (opts->stretch_dvd_subs) {
|
||||
// For DVD subs, try to keep the subtitle PAR at display PAR.
|
||||
double video_par =
|
||||
(priv->video_params.d_w / (double)priv->video_params.d_h)
|
||||
/ (priv->video_params.w / (double)priv->video_params.h);
|
||||
if (video_par > 1.0) {
|
||||
xscale /= video_par;
|
||||
} else {
|
||||
yscale *= video_par;
|
||||
}
|
||||
}
|
||||
spudec_get_indexed(priv->spudec, &d, xscale, yscale, res);
|
||||
}
|
||||
if (spudec_visible(priv->spudec))
|
||||
spudec_get_indexed(priv->spudec, &d, 1, 1, res);
|
||||
}
|
||||
|
||||
static void reset(struct sd *sd)
|
||||
@@ -105,25 +90,12 @@ static void uninit(struct sd *sd)
|
||||
talloc_free(priv);
|
||||
}
|
||||
|
||||
static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
|
||||
{
|
||||
struct sd_spu_priv *priv = sd->priv;
|
||||
switch (cmd) {
|
||||
case SD_CTRL_SET_VIDEO_PARAMS:
|
||||
priv->video_params = *(struct mp_image_params *)arg;
|
||||
return CONTROL_OK;
|
||||
default:
|
||||
return CONTROL_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
const struct sd_functions sd_spu = {
|
||||
.name = "spu",
|
||||
.supports_format = supports_format,
|
||||
.init = init,
|
||||
.decode = decode,
|
||||
.get_bitmaps = get_bitmaps,
|
||||
.control = control,
|
||||
.reset = reset,
|
||||
.uninit = uninit,
|
||||
};
|
||||
@@ -31,7 +31,7 @@ will be replaced with TA calls, and the talloc wrapper will be removed.
|
||||
|
||||
Documentation for the talloc API is here:
|
||||
|
||||
http://git.samba.org/?p=samba.git;a=blob;f=lib/talloc/talloc.h;hb=HEAD
|
||||
http://talloc.samba.org/talloc/doc/html/modules.html
|
||||
|
||||
There are some minor differences with mpv's talloc bridge. mpv calls abort()
|
||||
on allocation failures, and the talloc_set_destructor() signature is slightly
|
||||
|
||||
@@ -54,6 +54,7 @@ void *ta_find_parent(void *ptr);
|
||||
|
||||
// Utility functions
|
||||
size_t ta_calc_array_size(size_t element_size, size_t count);
|
||||
size_t ta_calc_prealloc_elems(size_t nextidx);
|
||||
void *ta_new_context(void *ta_parent);
|
||||
void *ta_steal_(void *ta_parent, void *ptr);
|
||||
void *ta_memdup(void *ta_parent, void *ptr, size_t size);
|
||||
|
||||
+6
-3
@@ -77,14 +77,17 @@ char *ta_talloc_asprintf_append_buffer(char *s, const char *fmt, ...) TA_PRF(2,
|
||||
|
||||
#define MP_TALLOC_ELEMS(p) (talloc_get_size(p) / sizeof((p)[0]))
|
||||
|
||||
#define MP_RESIZE_ARRAY(ctx, p, count) do { \
|
||||
(p) = talloc_realloc_size((ctx), p, (count) * sizeof((p)[0])); } while (0)
|
||||
#define MP_RESIZE_ARRAY(ctx, p, count) \
|
||||
do { \
|
||||
(p) = ta_xrealloc_size(ctx, p, \
|
||||
ta_calc_array_size(sizeof((p)[0]), count)); \
|
||||
} while (0)
|
||||
|
||||
#define MP_TARRAY_GROW(ctx, p, nextidx) \
|
||||
do { \
|
||||
size_t nextidx_ = (nextidx); \
|
||||
if (nextidx_ >= MP_TALLOC_ELEMS(p)) \
|
||||
MP_RESIZE_ARRAY(ctx, p, (nextidx_ + 1) * 2);\
|
||||
MP_RESIZE_ARRAY(ctx, p, ta_calc_prealloc_elems(nextidx_)); \
|
||||
} while (0)
|
||||
|
||||
#define MP_GROW_ARRAY(p, nextidx) MP_TARRAY_GROW(NULL, p, nextidx)
|
||||
|
||||
@@ -30,6 +30,17 @@ size_t ta_calc_array_size(size_t element_size, size_t count)
|
||||
return element_size * count;
|
||||
}
|
||||
|
||||
// This is used when an array has to be enlarged for appending new elements.
|
||||
// Return a "good" size for the new array (in number of elements). This returns
|
||||
// a value >= nextidx, unless the calculation overflows, in which case SIZE_MAX
|
||||
// is returned.
|
||||
size_t ta_calc_prealloc_elems(size_t nextidx)
|
||||
{
|
||||
if (nextidx >= ((size_t)-1) / 2 - 1)
|
||||
return (size_t)-1;
|
||||
return (nextidx + 1) * 2;
|
||||
}
|
||||
|
||||
static void dummy_dtor(void *p){}
|
||||
|
||||
/* Create an empty (size 0) TA allocation, which is prepared in a way such that
|
||||
|
||||
@@ -399,10 +399,10 @@ int video_reconfig_filters(struct dec_video *d_video,
|
||||
}
|
||||
|
||||
float force_aspect = opts->movie_aspect;
|
||||
if (force_aspect > -1.0 && d_video->stream_aspect != 0.0)
|
||||
if (force_aspect > 0.0 && d_video->stream_aspect != 0.0)
|
||||
force_aspect = d_video->stream_aspect;
|
||||
|
||||
if (force_aspect > 0)
|
||||
if (force_aspect >= 0.0)
|
||||
vf_set_dar(&p.d_w, &p.d_h, p.w, p.h, force_aspect);
|
||||
|
||||
if (abs(p.d_w - p.w) >= 4 || abs(p.d_h - p.h) >= 4) {
|
||||
@@ -436,17 +436,6 @@ int video_reconfig_filters(struct dec_video *d_video,
|
||||
|
||||
d_video->vf_input = p;
|
||||
|
||||
if (opts->gamma_gamma != 1000)
|
||||
video_set_colors(d_video, "gamma", opts->gamma_gamma);
|
||||
if (opts->gamma_brightness != 1000)
|
||||
video_set_colors(d_video, "brightness", opts->gamma_brightness);
|
||||
if (opts->gamma_contrast != 1000)
|
||||
video_set_colors(d_video, "contrast", opts->gamma_contrast);
|
||||
if (opts->gamma_saturation != 1000)
|
||||
video_set_colors(d_video, "saturation", opts->gamma_saturation);
|
||||
if (opts->gamma_hue != 1000)
|
||||
video_set_colors(d_video, "hue", opts->gamma_hue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,5 +91,6 @@ void mp_buffer_ref(struct FrameBuffer *buffer);
|
||||
void mp_buffer_unref(struct FrameBuffer *buffer);
|
||||
bool mp_buffer_is_unique(struct FrameBuffer *buffer);
|
||||
void mp_buffer_pool_free(struct FramePool **pool);
|
||||
bool mp_buffer_check(struct FrameBuffer *buffer);
|
||||
|
||||
#endif
|
||||
@@ -204,6 +204,16 @@ void mp_buffer_ref(struct FrameBuffer *buf)
|
||||
pool_unlock();
|
||||
}
|
||||
|
||||
bool mp_buffer_check(struct FrameBuffer *buf)
|
||||
{
|
||||
pool_lock();
|
||||
bool ok = buf->refcount > 0;
|
||||
if (ok)
|
||||
buf->refcount++;
|
||||
pool_unlock();
|
||||
return ok;
|
||||
}
|
||||
|
||||
void mp_buffer_unref(struct FrameBuffer *buf)
|
||||
{
|
||||
FramePool *pool = buf->pool;
|
||||
|
||||
+20
-20
@@ -318,10 +318,7 @@ static void set_from_bih(AVCodecContext *avctx, uint32_t format,
|
||||
if (bih->biSize <= sizeof(*bih))
|
||||
break;
|
||||
av_opt_set_int(avctx, "extern_huff", 1, AV_OPT_SEARCH_CHILDREN);
|
||||
avctx->extradata_size = bih->biSize - sizeof(*bih);
|
||||
avctx->extradata = av_mallocz(avctx->extradata_size +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
memcpy(avctx->extradata, bih + 1, avctx->extradata_size);
|
||||
mp_lavc_set_extradata(avctx, bih + 1, bih->biSize - sizeof(*bih));
|
||||
break;
|
||||
|
||||
case MP_FOURCC('R','V','1','0'):
|
||||
@@ -331,29 +328,21 @@ static void set_from_bih(AVCodecContext *avctx, uint32_t format,
|
||||
case MP_FOURCC('R','V','4','0'):
|
||||
if (bih->biSize < sizeof(*bih) + 8) {
|
||||
// only 1 packet per frame & sub_id from fourcc
|
||||
avctx->extradata_size = 8;
|
||||
avctx->extradata = av_mallocz(avctx->extradata_size +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
((uint32_t *)avctx->extradata)[0] = 0;
|
||||
((uint32_t *)avctx->extradata)[1] =
|
||||
format == MP_FOURCC('R','V','1','3') ?
|
||||
0x10003001 : 0x10000000;
|
||||
uint32_t extradata[2] = {
|
||||
0,
|
||||
format == MP_FOURCC('R','V','1','3') ? 0x10003001 : 0x10000000,
|
||||
};
|
||||
mp_lavc_set_extradata(avctx, &extradata, 8);
|
||||
} else {
|
||||
// has extra slice header (demux_rm or rm->avi streamcopy)
|
||||
avctx->extradata_size = bih->biSize - sizeof(*bih);
|
||||
avctx->extradata = av_mallocz(avctx->extradata_size +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
memcpy(avctx->extradata, bih + 1, avctx->extradata_size);
|
||||
mp_lavc_set_extradata(avctx, bih + 1, bih->biSize - sizeof(*bih));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (bih->biSize <= sizeof(*bih))
|
||||
break;
|
||||
avctx->extradata_size = bih->biSize - sizeof(*bih);
|
||||
avctx->extradata = av_mallocz(avctx->extradata_size +
|
||||
FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
memcpy(avctx->extradata, bih + 1, avctx->extradata_size);
|
||||
mp_lavc_set_extradata(avctx, bih + 1, bih->biSize - sizeof(*bih));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -717,7 +706,16 @@ static struct mp_image *image_from_decoder(struct dec_video *vd)
|
||||
mp_image_copy_attributes(mpi, &new);
|
||||
} else if (ctx->do_dr1 && pic->opaque) {
|
||||
struct FrameBuffer *fb = pic->opaque;
|
||||
mp_buffer_ref(fb); // initial reference for mpi
|
||||
// initial reference for mpi
|
||||
if (!new.planes[0] || !mp_buffer_check(fb)) {
|
||||
// Decoder returned an unreferenced buffer! Taking this would just
|
||||
// lead to an eventual double-free. Nothing we can do about this.
|
||||
// So just say "fuck you" in a nice way.
|
||||
MP_FATAL(vd,
|
||||
"Impossible condition detected! This version of Libav/FFmpeg is not\n"
|
||||
"supported anymore. Please update.\n");
|
||||
return NULL;
|
||||
}
|
||||
mpi = mp_image_new_external_ref(&new, fb, fb_ref, fb_unref,
|
||||
fb_is_unique, NULL);
|
||||
} else {
|
||||
@@ -763,6 +761,8 @@ static int decode(struct dec_video *vd, struct demux_packet *packet,
|
||||
|
||||
// Note: potentially resets ctx->pic as it is transferred to mpi
|
||||
struct mp_image *mpi = image_from_decoder(vd);
|
||||
if (!mpi)
|
||||
return 0;
|
||||
assert(mpi->planes[0]);
|
||||
mp_image_set_params(mpi, ¶ms);
|
||||
|
||||
|
||||
@@ -126,7 +126,8 @@ static bool create_vdp_decoder(struct lavc_ctx *ctx)
|
||||
goto fail;
|
||||
}
|
||||
if (p->vid_width > maxw || p->vid_height > maxh) {
|
||||
MP_ERR(p, "Video too large.\n");
|
||||
MP_ERR(p, "Video resolution(%dx%d) is larger than the maximum size(%dx%d) supported.\n",
|
||||
p->vid_width, p->vid_height, maxw, maxh);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
+22
-2
@@ -115,6 +115,8 @@ static const vf_info_t *const filter_list[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static void vf_uninit_filter(vf_instance_t *vf);
|
||||
|
||||
static bool get_desc(struct m_obj_desc *dst, int index)
|
||||
{
|
||||
if (index >= MP_ARRAY_SIZE(filter_list) - 1)
|
||||
@@ -270,6 +272,17 @@ static vf_instance_t *vf_open_filter(struct vf_chain *c, const char *name,
|
||||
return vf_open(c, name, args);
|
||||
}
|
||||
|
||||
void vf_remove_filter(struct vf_chain *c, struct vf_instance *vf)
|
||||
{
|
||||
assert(vf != c->first && vf != c->last); // these are sentinels
|
||||
struct vf_instance *prev = c->first;
|
||||
while (prev && prev->next != vf)
|
||||
prev = prev->next;
|
||||
assert(prev); // not inserted
|
||||
prev->next = vf->next;
|
||||
vf_uninit_filter(vf);
|
||||
}
|
||||
|
||||
struct vf_instance *vf_append_filter(struct vf_chain *c, const char *name,
|
||||
char **args)
|
||||
{
|
||||
@@ -439,6 +452,7 @@ static void update_formats(struct vf_chain *c, struct vf_instance *vf,
|
||||
MP_INFO(c, "Using conversion filter.\n");
|
||||
struct vf_instance *conv = vf_open(c, "scale", NULL);
|
||||
if (conv) {
|
||||
conv->autoinserted = true;
|
||||
conv->next = vf->next;
|
||||
vf->next = conv;
|
||||
update_formats(c, conv, vf->last_outfmts);
|
||||
@@ -492,6 +506,12 @@ int vf_reconfig(struct vf_chain *c, const struct mp_image_params *params)
|
||||
{
|
||||
struct mp_image_params cur = *params;
|
||||
int r = 0;
|
||||
for (struct vf_instance *vf = c->first; vf; ) {
|
||||
struct vf_instance *next = vf->next;
|
||||
if (vf->autoinserted)
|
||||
vf_remove_filter(c, vf);
|
||||
vf = next;
|
||||
}
|
||||
c->first->fmt_in = *params;
|
||||
uint8_t unused[IMGFMT_END - IMGFMT_START];
|
||||
update_formats(c, c->first, unused);
|
||||
@@ -599,11 +619,11 @@ void vf_set_dar(int *d_w, int *d_h, int w, int h, double dar)
|
||||
*d_w = w;
|
||||
*d_h = h;
|
||||
if (dar > 0.01) {
|
||||
*d_w = h * dar;
|
||||
*d_w = h * dar + 0.5;
|
||||
// we don't like horizontal downscale
|
||||
if (*d_w < w) {
|
||||
*d_w = w;
|
||||
*d_h = w / dar;
|
||||
*d_h = w / dar + 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ typedef struct vf_instance {
|
||||
void (*uninit)(struct vf_instance *vf);
|
||||
|
||||
char *label;
|
||||
bool autoinserted;
|
||||
|
||||
struct mp_image_params fmt_in, fmt_out;
|
||||
|
||||
@@ -134,6 +135,7 @@ struct mp_image *vf_output_queued_frame(struct vf_chain *c);
|
||||
void vf_seek_reset(struct vf_chain *c);
|
||||
struct vf_instance *vf_append_filter(struct vf_chain *c, const char *name,
|
||||
char **args);
|
||||
void vf_remove_filter(struct vf_chain *c, struct vf_instance *vf);
|
||||
int vf_append_filter_list(struct vf_chain *c, struct m_obj_settings *list);
|
||||
struct vf_instance *vf_find_by_label(struct vf_chain *c, const char *label);
|
||||
void vf_print_filter_chain(struct vf_chain *c, int msglevel);
|
||||
|
||||
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user