Compare commits
97
Commits
harmony-port
...
v0.3.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
+1
-1
@@ -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:
|
||||
|
||||
+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.
|
||||
|
||||
|
||||
+23
-5
@@ -1142,6 +1142,9 @@ OPTIONS
|
||||
Allow hardware decoding for a given list of codecs only. The special value
|
||||
``all`` always allows all codecs.
|
||||
|
||||
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``.
|
||||
|
||||
This is usually only needed with broken GPUs, where a codec is reported
|
||||
@@ -1369,8 +1372,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.
|
||||
@@ -1609,6 +1611,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
|
||||
@@ -1741,6 +1746,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
|
||||
@@ -2023,8 +2037,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 +2378,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 +2387,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`_.)
|
||||
|
||||
+2
-2
@@ -429,7 +429,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 +438,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``
|
||||
|
||||
@@ -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.
|
||||
@@ -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]) {
|
||||
|
||||
+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)
|
||||
|
||||
@@ -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]);
|
||||
|
||||
+4
-5
@@ -585,9 +585,11 @@ 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");
|
||||
@@ -639,11 +641,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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+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
|
||||
@@ -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 {
|
||||
|
||||
+33
-27
@@ -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", 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,12 @@ 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;
|
||||
}
|
||||
|
||||
// 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: {
|
||||
|
||||
+18
-9
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2270,7 +2270,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 +2281,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 +2442,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 +2454,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 +2492,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 +2504,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 +2520,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 +2535,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);
|
||||
|
||||
|
||||
+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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -454,7 +456,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
|
||||
@@ -612,6 +614,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;
|
||||
}
|
||||
+5
-1
@@ -3052,6 +3052,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 +3063,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ void mp_nav_get_highlight(struct osd_state *osd, struct mp_osd_res res,
|
||||
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;
|
||||
|
||||
+18
-8
@@ -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)
|
||||
@@ -776,6 +783,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 +846,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-1
@@ -78,6 +78,14 @@
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
|
||||
#ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE
|
||||
#define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE (0x0001)
|
||||
#endif
|
||||
|
||||
#ifndef BASE_SEARCH_PATH_PERMANENT
|
||||
#define BASE_SEARCH_PATH_PERMANENT (0x8000)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const char mp_help_text[] =
|
||||
@@ -260,7 +268,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();
|
||||
|
||||
+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);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -71,8 +71,8 @@ static const char av_desync_help_text[] =
|
||||
" 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";
|
||||
|
||||
@@ -924,7 +924,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
+15
-7
@@ -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>
|
||||
@@ -77,6 +80,7 @@ struct priv {
|
||||
|
||||
// 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 +146,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);
|
||||
|
||||
|
||||
+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)) {
|
||||
|
||||
+1
-1
@@ -562,7 +562,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,
|
||||
|
||||
@@ -390,6 +390,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;
|
||||
|
||||
+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
@@ -420,7 +420,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;
|
||||
|
||||
+4
-1
@@ -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);
|
||||
|
||||
+8
-3
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/common.h>
|
||||
@@ -182,11 +183,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 +237,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);
|
||||
|
||||
+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,
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,10 @@ static int mp_chroma_div_up(int size, int shift)
|
||||
// Caller has to make sure this doesn't exceed the allocated plane data/strides.
|
||||
void mp_image_set_size(struct mp_image *mpi, int w, int h)
|
||||
{
|
||||
// av_image_check_size has similar checks and triggers around 16000*16000
|
||||
if (w >= (1 << 14) || h >= (1 << 14) || w < 0 || h < 0)
|
||||
abort();
|
||||
|
||||
mpi->w = mpi->display_w = w;
|
||||
mpi->h = mpi->display_h = h;
|
||||
for (int n = 0; n < mpi->num_planes; n++) {
|
||||
|
||||
+17
-20
@@ -71,6 +71,9 @@ struct vo_cocoa_state {
|
||||
void (*resize_redraw)(struct vo *vo, int w, int h);
|
||||
|
||||
struct mp_log *log;
|
||||
|
||||
uint32_t old_dwidth;
|
||||
uint32_t old_dheight;
|
||||
};
|
||||
|
||||
void *vo_cocoa_glgetaddr(const char *s)
|
||||
@@ -218,8 +221,6 @@ static void vo_cocoa_update_screen_info(struct vo *vo)
|
||||
aspect_save_screenres(vo, r.size.width, r.size.height);
|
||||
opts->screenwidth = r.size.width;
|
||||
opts->screenheight = r.size.height;
|
||||
vo->xinerama_x = r.origin.x;
|
||||
vo->xinerama_y = r.origin.y;
|
||||
}
|
||||
|
||||
static void resize_window(struct vo *vo)
|
||||
@@ -259,7 +260,7 @@ static void create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
struct mp_vo_opts *opts = vo->opts;
|
||||
|
||||
const NSRect contentRect = NSMakeRect(0, 0, d_width, d_height);
|
||||
const NSRect contentRect = NSMakeRect(vo->dx, vo->dy, d_width, d_height);
|
||||
|
||||
int window_mask = 0;
|
||||
if (opts->border) {
|
||||
@@ -273,7 +274,8 @@ static void create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
|
||||
[[MpvVideoWindow alloc] initWithContentRect:contentRect
|
||||
styleMask:window_mask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
defer:NO
|
||||
screen:s->current_screen];
|
||||
s->view = [[[MpvVideoView alloc] initWithFrame:contentRect] autorelease];
|
||||
|
||||
[s->view setWantsBestResolutionOpenGLSurface:YES];
|
||||
@@ -296,7 +298,6 @@ static void create_window(struct vo *vo, uint32_t d_width, uint32_t d_height,
|
||||
[s->window setDelegate:s->window];
|
||||
[s->window makeMainWindow];
|
||||
|
||||
[s->window setFrameOrigin:NSMakePoint(vo->dx, vo->dy)];
|
||||
[s->window makeKeyAndOrderFront:nil];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
|
||||
@@ -356,14 +357,6 @@ static void cocoa_set_window_title(struct vo *vo, const char *title)
|
||||
talloc_free(talloc_ctx);
|
||||
}
|
||||
|
||||
static void update_window(struct vo *vo, int d_width, int d_height)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
[s->window queueNewVideoSize:NSMakeSize(d_width, d_height)];
|
||||
cocoa_set_window_title(vo, vo_get_window_title(vo));
|
||||
vo_cocoa_fullscreen(vo);
|
||||
}
|
||||
|
||||
static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
@@ -386,9 +379,8 @@ static void vo_cocoa_resize_redraw(struct vo *vo, int width, int height)
|
||||
vo_cocoa_set_current_context(vo, false);
|
||||
}
|
||||
|
||||
int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
|
||||
uint32_t d_height, uint32_t flags,
|
||||
int gl3profile)
|
||||
int vo_cocoa_config_window(struct vo *vo, uint32_t width, uint32_t height,
|
||||
uint32_t flags, int gl3profile)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
__block int ctxok = 0;
|
||||
@@ -398,6 +390,10 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
|
||||
s->enable_resize_redraw = false;
|
||||
s->aspdat = vo->aspdat;
|
||||
|
||||
bool reset_size = s->old_dwidth != width || s->old_dheight != height;
|
||||
s->old_dwidth = width;
|
||||
s->old_dheight = height;
|
||||
|
||||
if (flags & VOFLAG_HIDDEN) {
|
||||
// This is certainly the first execution of vo_config_window and
|
||||
// is called in order for an OpenGL based VO to perform detection
|
||||
@@ -417,16 +413,17 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t d_width,
|
||||
}
|
||||
|
||||
if (!s->window)
|
||||
create_window(vo, d_width, d_height, flags);
|
||||
create_window(vo, width, height, flags);
|
||||
}
|
||||
|
||||
if (s->window) {
|
||||
// Everything is properly initialized
|
||||
update_window(vo, d_width, d_height);
|
||||
if (reset_size)
|
||||
[s->window queueNewVideoSize:NSMakeSize(width, height)];
|
||||
cocoa_set_window_title(vo, vo_get_window_title(vo));
|
||||
vo_cocoa_fullscreen(vo);
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
s->inside_sync_section = false;
|
||||
s->enable_resize_redraw = true;
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <IOSurface/IOSurface.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/CGLIOSurface.h>
|
||||
|
||||
#include "video/decode/dec_video.h"
|
||||
#include "cocoa_common.h"
|
||||
|
||||
+55
-72
@@ -16,27 +16,10 @@
|
||||
* with mpv. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <wayland-egl.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "wayland_common.h"
|
||||
#include "gl_common.h"
|
||||
|
||||
struct egl_context {
|
||||
EGLSurface egl_surface;
|
||||
|
||||
struct wl_egl_window *egl_window;
|
||||
|
||||
struct {
|
||||
EGLDisplay dpy;
|
||||
EGLContext ctx;
|
||||
EGLConfig conf;
|
||||
} egl;
|
||||
};
|
||||
|
||||
static void egl_resize(struct vo_wayland_state *wl,
|
||||
struct egl_context *ctx)
|
||||
static void egl_resize(struct vo_wayland_state *wl)
|
||||
{
|
||||
int32_t x = wl->window.sh_x;
|
||||
int32_t y = wl->window.sh_y;
|
||||
@@ -45,7 +28,7 @@ static void egl_resize(struct vo_wayland_state *wl,
|
||||
|
||||
// get the real size of the window
|
||||
// this improves moving the window while resizing it
|
||||
wl_egl_window_get_attached_size(ctx->egl_window,
|
||||
wl_egl_window_get_attached_size(wl->egl_context.egl_window,
|
||||
&wl->window.width,
|
||||
&wl->window.height);
|
||||
|
||||
@@ -60,7 +43,7 @@ static void egl_resize(struct vo_wayland_state *wl,
|
||||
if (y != 0)
|
||||
y = wl->window.height - height;
|
||||
|
||||
wl_egl_window_resize(ctx->egl_window, width, height, x, y);
|
||||
wl_egl_window_resize(wl->egl_context.egl_window, width, height, x, y);
|
||||
|
||||
wl->window.width = width;
|
||||
wl->window.height = height;
|
||||
@@ -74,7 +57,6 @@ static void egl_resize(struct vo_wayland_state *wl,
|
||||
}
|
||||
|
||||
static bool egl_create_context(struct vo_wayland_state *wl,
|
||||
struct egl_context *egl_ctx,
|
||||
MPGLContext *ctx,
|
||||
bool enable_alpha)
|
||||
{
|
||||
@@ -83,7 +65,7 @@ static bool egl_create_context(struct vo_wayland_state *wl,
|
||||
GL *gl = ctx->gl;
|
||||
const char *eglstr = "";
|
||||
|
||||
if (!(egl_ctx->egl.dpy = eglGetDisplay(wl->display.display)))
|
||||
if (!(wl->egl_context.egl.dpy = eglGetDisplay(wl->display.display)))
|
||||
return false;
|
||||
|
||||
EGLint config_attribs[] = {
|
||||
@@ -98,7 +80,7 @@ static bool egl_create_context(struct vo_wayland_state *wl,
|
||||
};
|
||||
|
||||
/* major and minor here returns the supported EGL version (e.g.: 1.4) */
|
||||
if (eglInitialize(egl_ctx->egl.dpy, &major, &minor) != EGL_TRUE)
|
||||
if (eglInitialize(wl->egl_context.egl.dpy, &major, &minor) != EGL_TRUE)
|
||||
return false;
|
||||
|
||||
MP_VERBOSE(wl, "EGL version %d.%d\n", major, minor);
|
||||
@@ -106,38 +88,36 @@ static bool egl_create_context(struct vo_wayland_state *wl,
|
||||
EGLint context_attribs[] = {
|
||||
EGL_CONTEXT_MAJOR_VERSION_KHR,
|
||||
MPGL_VER_GET_MAJOR(ctx->requested_gl_version),
|
||||
/* EGL_CONTEXT_MINOR_VERSION_KHR, */
|
||||
/* MPGL_VER_GET_MINOR(ctx->requested_gl_version), */
|
||||
/* EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, 0, */
|
||||
/* Segfaults on anything else than the major version */
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
if (eglBindAPI(EGL_OPENGL_API) != EGL_TRUE)
|
||||
return false;
|
||||
|
||||
eglChooseConfig(egl_ctx->egl.dpy, config_attribs,
|
||||
&egl_ctx->egl.conf, 1, &n);
|
||||
eglChooseConfig(wl->egl_context.egl.dpy, config_attribs,
|
||||
&wl->egl_context.egl.conf, 1, &n);
|
||||
|
||||
egl_ctx->egl.ctx = eglCreateContext(egl_ctx->egl.dpy,
|
||||
egl_ctx->egl.conf,
|
||||
EGL_NO_CONTEXT,
|
||||
context_attribs);
|
||||
if (!egl_ctx->egl.ctx) {
|
||||
wl->egl_context.egl.ctx = eglCreateContext(wl->egl_context.egl.dpy,
|
||||
wl->egl_context.egl.conf,
|
||||
EGL_NO_CONTEXT,
|
||||
context_attribs);
|
||||
if (!wl->egl_context.egl.ctx) {
|
||||
/* fallback to any GL version */
|
||||
MP_WARN(wl, "can't create context for requested OpenGL version: "
|
||||
"fall back to any version available\n");
|
||||
context_attribs[0] = EGL_NONE;
|
||||
egl_ctx->egl.ctx = eglCreateContext(egl_ctx->egl.dpy,
|
||||
egl_ctx->egl.conf,
|
||||
EGL_NO_CONTEXT,
|
||||
context_attribs);
|
||||
wl->egl_context.egl.ctx = eglCreateContext(wl->egl_context.egl.dpy,
|
||||
wl->egl_context.egl.conf,
|
||||
EGL_NO_CONTEXT,
|
||||
context_attribs);
|
||||
|
||||
if (!egl_ctx->egl.ctx)
|
||||
if (!wl->egl_context.egl.ctx)
|
||||
return false;
|
||||
}
|
||||
|
||||
eglMakeCurrent(egl_ctx->egl.dpy, NULL, NULL, egl_ctx->egl.ctx);
|
||||
eglMakeCurrent(wl->egl_context.egl.dpy, NULL, NULL, wl->egl_context.egl.ctx);
|
||||
|
||||
eglstr = eglQueryString(egl_ctx->egl.dpy, EGL_EXTENSIONS);
|
||||
eglstr = eglQueryString(wl->egl_context.egl.dpy, EGL_EXTENSIONS);
|
||||
|
||||
mpgl_load_functions(gl, (void*(*)(const GLubyte*))eglGetProcAddress, eglstr,
|
||||
wl->log);
|
||||
@@ -148,26 +128,24 @@ static bool egl_create_context(struct vo_wayland_state *wl,
|
||||
}
|
||||
|
||||
static void egl_create_window(struct vo_wayland_state *wl,
|
||||
struct egl_context *egl_ctx,
|
||||
uint32_t width,
|
||||
uint32_t height)
|
||||
{
|
||||
egl_ctx->egl_window = wl_egl_window_create(wl->window.surface,
|
||||
wl->window.width,
|
||||
wl->window.height);
|
||||
wl->egl_context.egl_window = wl_egl_window_create(wl->window.surface,
|
||||
wl->window.width,
|
||||
wl->window.height);
|
||||
|
||||
egl_ctx->egl_surface = eglCreateWindowSurface(egl_ctx->egl.dpy,
|
||||
egl_ctx->egl.conf,
|
||||
egl_ctx->egl_window,
|
||||
NULL);
|
||||
wl->egl_context.egl_surface = eglCreateWindowSurface(wl->egl_context.egl.dpy,
|
||||
wl->egl_context.egl.conf,
|
||||
wl->egl_context.egl_window,
|
||||
NULL);
|
||||
|
||||
eglMakeCurrent(egl_ctx->egl.dpy,
|
||||
egl_ctx->egl_surface,
|
||||
egl_ctx->egl_surface,
|
||||
egl_ctx->egl.ctx);
|
||||
eglMakeCurrent(wl->egl_context.egl.dpy,
|
||||
wl->egl_context.egl_surface,
|
||||
wl->egl_context.egl_surface,
|
||||
wl->egl_context.egl.ctx);
|
||||
|
||||
wl_display_dispatch_pending(wl->display.display);
|
||||
|
||||
}
|
||||
|
||||
static bool config_window_wayland(struct MPGLContext *ctx,
|
||||
@@ -175,7 +153,6 @@ static bool config_window_wayland(struct MPGLContext *ctx,
|
||||
uint32_t d_height,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct egl_context * egl_ctx = ctx->priv;
|
||||
struct vo_wayland_state * wl = ctx->vo->wayland;
|
||||
bool enable_alpha = !!(flags & VOFLAG_ALPHA);
|
||||
bool ret = false;
|
||||
@@ -183,23 +160,23 @@ static bool config_window_wayland(struct MPGLContext *ctx,
|
||||
if (!vo_wayland_config(ctx->vo, d_width, d_height, flags))
|
||||
return false;
|
||||
|
||||
if (!egl_ctx->egl.ctx) {
|
||||
if (!wl->egl_context.egl.ctx) {
|
||||
/* Create OpenGL context */
|
||||
ret = egl_create_context(wl, egl_ctx, ctx, enable_alpha);
|
||||
ret = egl_create_context(wl, ctx, enable_alpha);
|
||||
|
||||
/* If successfully created the context and we don't want to hide the
|
||||
* window than also create the window immediately */
|
||||
if (ret && !(VOFLAG_HIDDEN & flags))
|
||||
egl_create_window(wl, egl_ctx, d_width, d_height);
|
||||
egl_create_window(wl, d_width, d_height);
|
||||
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
if (!egl_ctx->egl_window) {
|
||||
if (!wl->egl_context.egl_window) {
|
||||
/* If the context exists and the hidden flag is unset then
|
||||
* create the window */
|
||||
if (!(VOFLAG_HIDDEN & flags))
|
||||
egl_create_window(wl, egl_ctx, d_width, d_height);
|
||||
egl_create_window(wl, d_width, d_height);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -208,35 +185,41 @@ static bool config_window_wayland(struct MPGLContext *ctx,
|
||||
static void releaseGlContext_wayland(MPGLContext *ctx)
|
||||
{
|
||||
GL *gl = ctx->gl;
|
||||
struct egl_context * egl_ctx = ctx->priv;
|
||||
struct vo_wayland_state *wl = ctx->vo->wayland;
|
||||
|
||||
gl->Finish();
|
||||
eglMakeCurrent(egl_ctx->egl.dpy, NULL, NULL, EGL_NO_CONTEXT);
|
||||
eglDestroyContext(egl_ctx->egl.dpy, egl_ctx->egl.ctx);
|
||||
eglTerminate(egl_ctx->egl.dpy);
|
||||
eglReleaseThread();
|
||||
wl_egl_window_destroy(egl_ctx->egl_window);
|
||||
egl_ctx->egl.ctx = NULL;
|
||||
wl_egl_window_destroy(wl->egl_context.egl_window);
|
||||
eglDestroySurface(wl->egl_context.egl.dpy, wl->egl_context.egl_surface);
|
||||
eglMakeCurrent(wl->egl_context.egl.dpy, NULL, NULL, EGL_NO_CONTEXT);
|
||||
eglDestroyContext(wl->egl_context.egl.dpy, wl->egl_context.egl.ctx);
|
||||
eglTerminate(wl->egl_context.egl.dpy);
|
||||
wl->egl_context.egl.ctx = NULL;
|
||||
}
|
||||
|
||||
static void swapGlBuffers_wayland(MPGLContext *ctx)
|
||||
{
|
||||
struct egl_context * egl_ctx = ctx->priv;
|
||||
struct vo_wayland_state *wl = ctx->vo->wayland;
|
||||
eglSwapBuffers(wl->egl_context.egl.dpy, wl->egl_context.egl_surface);
|
||||
}
|
||||
|
||||
eglSwapBuffers(egl_ctx->egl.dpy, egl_ctx->egl_surface);
|
||||
static int control(struct vo *vo, int *events, int request, void *data)
|
||||
{
|
||||
struct vo_wayland_state *wl = vo->wayland;
|
||||
int r = vo_wayland_control(vo, events, request, data);
|
||||
|
||||
if (wl->window.events & VO_EVENT_RESIZE)
|
||||
egl_resize(wl, egl_ctx);
|
||||
if (*events & VO_EVENT_RESIZE)
|
||||
egl_resize(wl);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void mpgl_set_backend_wayland(MPGLContext *ctx)
|
||||
{
|
||||
ctx->priv = talloc_zero(ctx, struct egl_context);
|
||||
ctx->config_window = config_window_wayland;
|
||||
ctx->releaseGlContext = releaseGlContext_wayland;
|
||||
ctx->swapGlBuffers = swapGlBuffers_wayland;
|
||||
ctx->vo_control = vo_wayland_control;
|
||||
ctx->vo_control = control;
|
||||
ctx->vo_init = vo_wayland_init;
|
||||
ctx->vo_uninit = vo_wayland_uninit;
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
#if HAVE_VDA_HWACCEL
|
||||
#include <IOSurface/IOSurface.h>
|
||||
#include <OpenGL/CGLIOSurface.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
+62
-56
@@ -149,7 +149,7 @@ struct priv {
|
||||
|
||||
// options
|
||||
int enable_alpha;
|
||||
int use_default;
|
||||
int use_rgb565;
|
||||
};
|
||||
|
||||
/* copied from weston clients */
|
||||
@@ -232,6 +232,21 @@ static bool is_alpha_format(const struct fmtentry *fmt)
|
||||
return !!(mp_imgfmt_get_desc(fmt->mp_fmt).flags & MP_IMGFLAG_ALPHA);
|
||||
}
|
||||
|
||||
static const struct fmtentry * is_wayland_format_supported(struct priv *p,
|
||||
enum wl_shm_format fmt)
|
||||
{
|
||||
struct supported_format *sf;
|
||||
|
||||
// find the matching format first
|
||||
wl_list_for_each(sf, &p->format_list, link) {
|
||||
if (sf->fmt->wl_fmt == fmt) {
|
||||
return sf->fmt;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void buffer_swap(struct priv *p)
|
||||
{
|
||||
if (!p->back_buffer->is_new)
|
||||
@@ -240,9 +255,6 @@ static void buffer_swap(struct priv *p)
|
||||
struct buffer *tmp = p->back_buffer;
|
||||
p->back_buffer = p->front_buffer;
|
||||
p->front_buffer = tmp;
|
||||
|
||||
// after swap set is_new to false, but keep busy
|
||||
p->back_buffer->is_new = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -250,31 +262,30 @@ static void buffer_swap(struct priv *p)
|
||||
// is busy (unlikely)
|
||||
static struct buffer * buffer_get_back(struct priv *p)
|
||||
{
|
||||
if (p->back_buffer->is_new || p->back_buffer->is_busy)
|
||||
if (p->back_buffer->is_busy)
|
||||
return NULL;
|
||||
|
||||
p->back_buffer->is_busy = true;
|
||||
|
||||
return p->back_buffer;
|
||||
}
|
||||
|
||||
static bool buffer_finalise_back(struct priv *p)
|
||||
static bool buffer_finalise_back(struct buffer *buf)
|
||||
{
|
||||
p->back_buffer->is_new = true;
|
||||
p->back_buffer->is_busy = false;
|
||||
|
||||
buf->is_new = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct buffer * buffer_get_front(struct priv *p)
|
||||
{
|
||||
if (!p->front_buffer->is_new)
|
||||
return NULL;
|
||||
|
||||
p->front_buffer->is_busy = true;
|
||||
return p->front_buffer;
|
||||
}
|
||||
|
||||
static bool buffer_finalise_front(struct priv *p)
|
||||
static bool buffer_finalise_front(struct buffer *buf)
|
||||
{
|
||||
p->front_buffer->is_new = false; // is_busy is reset on handle_release
|
||||
buf->is_new = false; // is_busy is reset on handle_release
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -469,36 +480,30 @@ static void frame_handle_redraw(void *data,
|
||||
struct vo_wayland_state *wl = p->wl;
|
||||
struct buffer *buf = buffer_get_front(p);
|
||||
|
||||
if (p->resize_attach) {
|
||||
if (buf) {
|
||||
wl_surface_attach(wl->window.surface, buf->wlbuf, p->x, p->y);
|
||||
wl_surface_damage(wl->window.surface, 0, 0, p->dst_w, p->dst_h);
|
||||
wl_surface_commit(wl->window.surface);
|
||||
|
||||
if (callback)
|
||||
wl_callback_destroy(callback);
|
||||
|
||||
p->redraw_callback = NULL;
|
||||
buffer_finalise_front(p);
|
||||
p->resize_attach = false;
|
||||
p->redraw_callback = wl_surface_frame(wl->window.surface);
|
||||
wl_callback_add_listener(p->redraw_callback, &frame_listener, p);
|
||||
wl_surface_commit(wl->window.surface);
|
||||
buffer_finalise_front(buf);
|
||||
|
||||
destroy_shm_buffer(&p->tmp_buffer);
|
||||
|
||||
// I have to destroy the callback and return early to avoid black flickers
|
||||
// I don't exactly know why this, but I guess the back buffer is still
|
||||
// empty. The callback loop will be restored on the next flip_page call
|
||||
return;
|
||||
// to avoid multiple resizes of non-shown frames
|
||||
if (p->resize_attach) {
|
||||
destroy_shm_buffer(&p->tmp_buffer);
|
||||
p->resize_attach = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (callback)
|
||||
wl_callback_destroy(callback);
|
||||
|
||||
wl_surface_attach(wl->window.surface, buf->wlbuf, 0, 0);
|
||||
wl_surface_damage(wl->window.surface, 0, 0, p->dst_w, p->dst_h);
|
||||
|
||||
if (callback)
|
||||
wl_callback_destroy(callback);
|
||||
|
||||
p->redraw_callback = wl_surface_frame(wl->window.surface);
|
||||
wl_callback_add_listener(p->redraw_callback, &frame_listener, p);
|
||||
wl_surface_commit(wl->window.surface);
|
||||
buffer_finalise_front(p);
|
||||
p->redraw_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
@@ -535,7 +540,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
||||
struct buffer *buf = buffer_get_back(p);
|
||||
|
||||
if (!buf) {
|
||||
MP_WARN(p->wl, "can't draw, back buffer is busy\n");
|
||||
MP_VERBOSE(p->wl, "can't draw, back buffer is busy\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -549,7 +554,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
|
||||
mp_sws_scale(p->sws, &img, &src);
|
||||
|
||||
mp_image_setrefp(&p->original_image, mpi);
|
||||
buffer_finalise_back(p);
|
||||
buffer_finalise_back(buf);
|
||||
}
|
||||
|
||||
static void draw_osd(struct vo *vo, struct osd_state *osd)
|
||||
@@ -566,7 +571,7 @@ static void flip_page(struct vo *vo)
|
||||
buffer_swap(p);
|
||||
|
||||
if (!p->redraw_callback) {
|
||||
MP_INFO(p->wl, "restart frame callback\n");
|
||||
MP_DBG(p->wl, "restart frame callback\n");
|
||||
frame_handle_redraw(p, NULL, 0);
|
||||
}
|
||||
}
|
||||
@@ -591,13 +596,13 @@ static int reconfig(struct vo *vo, struct mp_image_params *fmt, int flags)
|
||||
struct priv *p = vo->priv;
|
||||
mp_image_unrefp(&p->original_image);
|
||||
|
||||
p->width = vo->dwidth;
|
||||
p->height = vo->dheight;
|
||||
p->width = fmt->w;
|
||||
p->height = fmt->h;
|
||||
p->in_format = *fmt;
|
||||
|
||||
struct supported_format *sf;
|
||||
|
||||
// find the same format first
|
||||
// find the matching format first
|
||||
wl_list_for_each(sf, &p->format_list, link) {
|
||||
if (sf->fmt->mp_fmt == fmt->imgfmt && (p->enable_alpha == sf->is_alpha)) {
|
||||
p->pref_format = sf->fmt;
|
||||
@@ -605,25 +610,22 @@ static int reconfig(struct vo *vo, struct mp_image_params *fmt, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
// if the format is not supported choose one of the fancy formats next
|
||||
// the default formats are always last
|
||||
if (!p->pref_format) {
|
||||
wl_list_for_each(sf, &p->format_list, link) {
|
||||
if (p->enable_alpha == sf->is_alpha) {
|
||||
p->pref_format = sf->fmt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if use default is enable overwrite the auto selected one
|
||||
if (p->use_default) {
|
||||
// if use default is enable overwrite the auto selected one
|
||||
if (p->enable_alpha)
|
||||
p->pref_format = &fmttable[DEFAULT_ALPHA_FORMAT_ENTRY];
|
||||
else
|
||||
p->pref_format = &fmttable[DEFAULT_FORMAT_ENTRY];
|
||||
}
|
||||
|
||||
// overides alpha
|
||||
// use rgb565 if performance is your main concern
|
||||
if (p->use_rgb565) {
|
||||
const struct fmtentry *mp_fmt =
|
||||
is_wayland_format_supported(p, WL_SHM_FORMAT_RGB565);
|
||||
if (mp_fmt)
|
||||
p->pref_format = mp_fmt;
|
||||
}
|
||||
|
||||
p->bytes_per_pixel = mp_imgfmt_get_desc(p->pref_format->mp_fmt).bytes[0];
|
||||
MP_VERBOSE(p->wl, "bytes per pixel: %d\n", p->bytes_per_pixel);
|
||||
@@ -635,6 +637,9 @@ static int reconfig(struct vo *vo, struct mp_image_params *fmt, int flags)
|
||||
|
||||
vo_wayland_config(vo, vo->dwidth, vo->dheight, flags);
|
||||
|
||||
if (p->wl->window.events & VO_EVENT_RESIZE)
|
||||
resize(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -644,6 +649,9 @@ static void uninit(struct vo *vo)
|
||||
for (int i = 0; i < MAX_BUFFERS; ++i)
|
||||
destroy_shm_buffer(&p->buffers[i]);
|
||||
|
||||
if (p->redraw_callback)
|
||||
wl_callback_destroy(p->redraw_callback);
|
||||
|
||||
talloc_free(p->original_image);
|
||||
|
||||
vo_wayland_uninit(vo);
|
||||
@@ -653,10 +661,8 @@ static int preinit(struct vo *vo)
|
||||
{
|
||||
struct priv *p = vo->priv;
|
||||
|
||||
if (!vo_wayland_init(vo)) {
|
||||
MP_ERR(p->wl, "could not initalise backend\n");
|
||||
if (!vo_wayland_init(vo))
|
||||
return -1;
|
||||
}
|
||||
|
||||
p->vo = vo;
|
||||
p->wl = vo->wayland;
|
||||
@@ -724,7 +730,7 @@ const struct vo_driver video_out_wayland = {
|
||||
.uninit = uninit,
|
||||
.options = (const struct m_option[]) {
|
||||
OPT_FLAG("alpha", enable_alpha, 0),
|
||||
OPT_FLAG("default-format", use_default, 0),
|
||||
OPT_FLAG("rgb565", use_rgb565, 0),
|
||||
{0}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -486,7 +486,7 @@ static int reinit_window_state(struct vo *vo)
|
||||
|
||||
DWORD style = update_style(vo, GetWindowLong(w32->window, GWL_STYLE));
|
||||
|
||||
if (vo->opts->fullscreen || vo->opts->ontop)
|
||||
if (vo->opts->ontop)
|
||||
layer = HWND_TOPMOST;
|
||||
|
||||
// xxx not sure if this can trigger any unwanted messages (WM_MOVE/WM_SIZE)
|
||||
@@ -506,6 +506,7 @@ static int reinit_window_state(struct vo *vo)
|
||||
vo->dheight = vo->opts->screenheight;
|
||||
w32->window_x = vo->xinerama_x;
|
||||
w32->window_y = vo->xinerama_y;
|
||||
style &= ~WS_OVERLAPPEDWINDOW;
|
||||
} else {
|
||||
if (toggle_fs) {
|
||||
// Restore window position and size when switching from fullscreen.
|
||||
|
||||
+86
-46
@@ -144,7 +144,7 @@ static void display_handle_delete_id(void *data,
|
||||
MP_DBG(wl, "Object %u deleted\n", id);
|
||||
}
|
||||
|
||||
const struct wl_display_listener display_listener = {
|
||||
static const struct wl_display_listener display_listener = {
|
||||
display_handle_error,
|
||||
display_handle_delete_id
|
||||
};
|
||||
@@ -171,7 +171,7 @@ static void ssurface_handle_popup_done(void *data,
|
||||
{
|
||||
}
|
||||
|
||||
const struct wl_shell_surface_listener shell_surface_listener = {
|
||||
static const struct wl_shell_surface_listener shell_surface_listener = {
|
||||
ssurface_handle_ping,
|
||||
ssurface_handle_configure,
|
||||
ssurface_handle_popup_done
|
||||
@@ -220,7 +220,7 @@ static void output_handle_mode(void *data,
|
||||
output->flags = flags;
|
||||
}
|
||||
|
||||
const struct wl_output_listener output_listener = {
|
||||
static const struct wl_output_listener output_listener = {
|
||||
output_handle_geometry,
|
||||
output_handle_mode
|
||||
};
|
||||
@@ -329,7 +329,7 @@ static void keyboard_handle_modifiers(void *data,
|
||||
0, 0, group);
|
||||
}
|
||||
|
||||
const struct wl_keyboard_listener keyboard_listener = {
|
||||
static const struct wl_keyboard_listener keyboard_listener = {
|
||||
keyboard_handle_keymap,
|
||||
keyboard_handle_enter,
|
||||
keyboard_handle_leave,
|
||||
@@ -443,7 +443,6 @@ static void seat_handle_capabilities(void *data,
|
||||
|
||||
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl->input.keyboard) {
|
||||
wl->input.keyboard = wl_seat_get_keyboard(seat);
|
||||
wl_keyboard_set_user_data(wl->input.keyboard, wl);
|
||||
wl_keyboard_add_listener(wl->input.keyboard, &keyboard_listener, wl);
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl->input.keyboard) {
|
||||
@@ -452,7 +451,6 @@ static void seat_handle_capabilities(void *data,
|
||||
}
|
||||
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl->input.pointer) {
|
||||
wl->input.pointer = wl_seat_get_pointer(seat);
|
||||
wl_pointer_set_user_data(wl->input.pointer, wl);
|
||||
wl_pointer_add_listener(wl->input.pointer, &pointer_listener, wl);
|
||||
}
|
||||
else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->input.pointer) {
|
||||
@@ -466,13 +464,12 @@ static const struct wl_seat_listener seat_listener = {
|
||||
};
|
||||
|
||||
static void registry_handle_global (void *data,
|
||||
struct wl_registry *registry,
|
||||
struct wl_registry *reg,
|
||||
uint32_t id,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
struct vo_wayland_state *wl = data;
|
||||
struct wl_registry *reg = wl->display.registry;
|
||||
|
||||
if (strcmp(interface, "wl_compositor") == 0) {
|
||||
|
||||
@@ -578,6 +575,8 @@ static void shedule_resize(struct vo_wayland_state *wl,
|
||||
int32_t x, y;
|
||||
float temp_aspect = width / (float) MPMAX(height, 1);
|
||||
|
||||
MP_DBG(wl, "shedule resize: %dx%d\n", width, height);
|
||||
|
||||
if (width < minimum_size)
|
||||
width = minimum_size;
|
||||
|
||||
@@ -587,29 +586,27 @@ static void shedule_resize(struct vo_wayland_state *wl,
|
||||
// don't keep the aspect ration in fullscreen mode, because the compositor
|
||||
// shows the desktop in the border regions if the video has not the same
|
||||
// aspect ration as the screen
|
||||
if (!wl->window.is_fullscreen) {
|
||||
/* if only the height is changed we have to calculate the width
|
||||
* in any other case we calculate the height */
|
||||
switch (edges) {
|
||||
case WL_SHELL_SURFACE_RESIZE_TOP:
|
||||
case WL_SHELL_SURFACE_RESIZE_BOTTOM:
|
||||
/* if only the height is changed we have to calculate the width
|
||||
* in any other case we calculate the height */
|
||||
switch (edges) {
|
||||
case WL_SHELL_SURFACE_RESIZE_TOP:
|
||||
case WL_SHELL_SURFACE_RESIZE_BOTTOM:
|
||||
width = wl->window.aspect * height;
|
||||
break;
|
||||
case WL_SHELL_SURFACE_RESIZE_LEFT:
|
||||
case WL_SHELL_SURFACE_RESIZE_RIGHT:
|
||||
case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: // just a preference
|
||||
case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
|
||||
case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
|
||||
case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
|
||||
height = (1 / wl->window.aspect) * width;
|
||||
break;
|
||||
default:
|
||||
if (wl->window.aspect < temp_aspect)
|
||||
width = wl->window.aspect * height;
|
||||
break;
|
||||
case WL_SHELL_SURFACE_RESIZE_LEFT:
|
||||
case WL_SHELL_SURFACE_RESIZE_RIGHT:
|
||||
case WL_SHELL_SURFACE_RESIZE_TOP_LEFT: // just a preference
|
||||
case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
|
||||
case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
|
||||
case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
|
||||
else
|
||||
height = (1 / wl->window.aspect) * width;
|
||||
break;
|
||||
default:
|
||||
if (wl->window.aspect < temp_aspect)
|
||||
width = wl->window.aspect * height;
|
||||
else
|
||||
height = (1 / wl->window.aspect) * width;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (edges & WL_SHELL_SURFACE_RESIZE_LEFT)
|
||||
@@ -634,6 +631,9 @@ static void shedule_resize(struct vo_wayland_state *wl,
|
||||
|
||||
static bool create_display (struct vo_wayland_state *wl)
|
||||
{
|
||||
if (wl->vo->probing && !getenv("XDG_RUNTIME_DIR"))
|
||||
return false;
|
||||
|
||||
wl->display.display = wl_display_connect(NULL);
|
||||
|
||||
if (!wl->display.display) {
|
||||
@@ -646,7 +646,6 @@ static bool create_display (struct vo_wayland_state *wl)
|
||||
|
||||
wl_display_add_listener(wl->display.display, &display_listener, wl);
|
||||
|
||||
wl_list_init(&wl->display.output_list);
|
||||
wl->display.registry = wl_display_get_registry(wl->display.display);
|
||||
wl_registry_add_listener(wl->display.registry, ®istry_listener, wl);
|
||||
|
||||
@@ -659,15 +658,33 @@ static bool create_display (struct vo_wayland_state *wl)
|
||||
|
||||
static void destroy_display (struct vo_wayland_state *wl)
|
||||
{
|
||||
struct vo_wayland_output *output = NULL;
|
||||
struct vo_wayland_output *tmp = NULL;
|
||||
|
||||
wl_list_for_each_safe(output, tmp, &wl->display.output_list, link) {
|
||||
if (output && output->output) {
|
||||
wl_output_destroy(output->output);
|
||||
output->output = NULL;
|
||||
wl_list_remove(&output->link);
|
||||
}
|
||||
}
|
||||
|
||||
if (wl->display.shm)
|
||||
wl_shm_destroy(wl->display.shm);
|
||||
|
||||
if (wl->display.shell)
|
||||
wl_shell_destroy(wl->display.shell);
|
||||
|
||||
if (wl->display.compositor)
|
||||
wl_compositor_destroy(wl->display.compositor);
|
||||
|
||||
wl_registry_destroy(wl->display.registry);
|
||||
wl_display_flush(wl->display.display);
|
||||
wl_display_disconnect(wl->display.display);
|
||||
if (wl->display.registry)
|
||||
wl_registry_destroy(wl->display.registry);
|
||||
|
||||
if (wl->display.display) {
|
||||
wl_display_flush(wl->display.display);
|
||||
wl_display_disconnect(wl->display.display);
|
||||
}
|
||||
}
|
||||
|
||||
static bool create_window (struct vo_wayland_state *wl)
|
||||
@@ -692,8 +709,11 @@ static bool create_window (struct vo_wayland_state *wl)
|
||||
|
||||
static void destroy_window (struct vo_wayland_state *wl)
|
||||
{
|
||||
wl_shell_surface_destroy(wl->window.shell_surface);
|
||||
wl_surface_destroy(wl->window.surface);
|
||||
if (wl->window.shell_surface)
|
||||
wl_shell_surface_destroy(wl->window.shell_surface);
|
||||
|
||||
if (wl->window.surface)
|
||||
wl_surface_destroy(wl->window.surface);
|
||||
}
|
||||
|
||||
static bool create_cursor (struct vo_wayland_state *wl)
|
||||
@@ -742,9 +762,11 @@ static void destroy_input (struct vo_wayland_state *wl)
|
||||
wl_keyboard_destroy(wl->input.keyboard);
|
||||
xkb_map_unref(wl->input.xkb.keymap);
|
||||
xkb_state_unref(wl->input.xkb.state);
|
||||
xkb_context_unref(wl->input.xkb.context);
|
||||
}
|
||||
|
||||
if (wl->input.xkb.context)
|
||||
xkb_context_unref(wl->input.xkb.context);
|
||||
|
||||
if (wl->input.pointer)
|
||||
wl_pointer_destroy(wl->input.pointer);
|
||||
|
||||
@@ -762,11 +784,14 @@ int vo_wayland_init (struct vo *vo)
|
||||
wl->vo = vo;
|
||||
wl->log = mp_log_new(wl, vo->log, "wayland");
|
||||
|
||||
wl_list_init(&wl->display.output_list);
|
||||
|
||||
if (!create_input(wl)
|
||||
|| !create_display(wl)
|
||||
|| !create_window(wl)
|
||||
|| !create_cursor(wl))
|
||||
{
|
||||
vo_wayland_uninit(vo);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -788,12 +813,11 @@ void vo_wayland_uninit (struct vo *vo)
|
||||
|
||||
static void vo_wayland_ontop (struct vo *vo)
|
||||
{
|
||||
vo->opts->ontop = !vo->opts->ontop;
|
||||
vo->opts->fullscreen = !vo->opts->fullscreen;
|
||||
|
||||
/* use the already existing code to leave fullscreen mode and go into
|
||||
* toplevel mode */
|
||||
vo_wayland_fullscreen(vo);
|
||||
struct vo_wayland_state *wl = vo->wayland;
|
||||
MP_DBG(wl, "going ontop\n");
|
||||
vo->opts->ontop = 1;
|
||||
wl_shell_surface_set_toplevel(wl->window.shell_surface);
|
||||
shedule_resize(wl, 0, wl->window.width, wl->window.height);
|
||||
}
|
||||
|
||||
static void vo_wayland_border (struct vo *vo)
|
||||
@@ -919,6 +943,9 @@ static void vo_wayland_update_screeninfo (struct vo *vo)
|
||||
}
|
||||
}
|
||||
|
||||
wl->window.fs_width = opts->screenwidth;
|
||||
wl->window.fs_height = opts->screenheight;
|
||||
|
||||
aspect_save_screenres(vo, opts->screenwidth, opts->screenheight);
|
||||
}
|
||||
|
||||
@@ -980,13 +1007,26 @@ bool vo_wayland_config (struct vo *vo, uint32_t d_width,
|
||||
{
|
||||
struct vo_wayland_state *wl = vo->wayland;
|
||||
|
||||
wl->window.width = d_width;
|
||||
wl->window.height = d_height;
|
||||
wl->window.p_width = d_width;
|
||||
wl->window.p_height = d_height;
|
||||
wl->window.aspect = wl->window.width / (float) MPMAX(wl->window.height, 1);
|
||||
wl->window.aspect = d_width / (float) MPMAX(d_height, 1);
|
||||
|
||||
vo_wayland_fullscreen(vo);
|
||||
if (!(flags & VOFLAG_HIDDEN)) {
|
||||
if (!wl->window.is_init) {
|
||||
wl->window.width = d_width;
|
||||
wl->window.height = d_height;
|
||||
}
|
||||
|
||||
if (vo->opts->fullscreen) {
|
||||
if (wl->window.is_fullscreen)
|
||||
shedule_resize(wl, 0, wl->window.fs_width, wl->window.fs_height);
|
||||
else
|
||||
vo_wayland_fullscreen(vo);
|
||||
}
|
||||
else
|
||||
vo_wayland_ontop(vo);
|
||||
wl->window.is_init = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -27,6 +27,12 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_GL_WAYLAND
|
||||
#include <wayland-egl.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#endif
|
||||
|
||||
struct vo;
|
||||
|
||||
struct vo_wayland_output {
|
||||
@@ -43,6 +49,20 @@ struct vo_wayland_state {
|
||||
struct vo *vo;
|
||||
struct mp_log* log;
|
||||
|
||||
#if HAVE_GL_WAYLAND
|
||||
struct {
|
||||
EGLSurface egl_surface;
|
||||
|
||||
struct wl_egl_window *egl_window;
|
||||
|
||||
struct {
|
||||
EGLDisplay dpy;
|
||||
EGLContext ctx;
|
||||
EGLConfig conf;
|
||||
} egl;
|
||||
} egl_context;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
int fd;
|
||||
struct wl_display *display;
|
||||
@@ -60,7 +80,7 @@ struct vo_wayland_state {
|
||||
} display;
|
||||
|
||||
struct {
|
||||
int32_t width;
|
||||
int32_t width; // current size of the window
|
||||
int32_t height;
|
||||
int32_t p_width; // previous sizes for leaving fullscreen
|
||||
int32_t p_height;
|
||||
@@ -70,7 +90,10 @@ struct vo_wayland_state {
|
||||
int32_t sh_y;
|
||||
float aspect;
|
||||
|
||||
bool is_init; // true if the window has a valid size
|
||||
bool is_fullscreen; // don't keep aspect ratio in fullscreen mode
|
||||
int32_t fs_width; // fullscreen sizes
|
||||
int32_t fs_height;
|
||||
|
||||
struct wl_surface *surface;
|
||||
int32_t mouse_x; // mouse position inside the surface
|
||||
|
||||
@@ -3,7 +3,8 @@ from waftools.checks.generic import *
|
||||
from waflib import Utils
|
||||
import os
|
||||
|
||||
__all__ = ["check_pthreads", "check_iconv", "check_lua", "check_oss_4front"]
|
||||
__all__ = ["check_pthreads", "check_iconv", "check_lua", "check_oss_4front",
|
||||
"check_cocoa"]
|
||||
|
||||
pthreads_program = load_fragment('pthreads.c')
|
||||
|
||||
@@ -51,10 +52,12 @@ def check_lua(ctx, dependency_identifier):
|
||||
lua_versions = [
|
||||
( '51', 'lua >= 5.1.0 lua < 5.2.0'),
|
||||
( '51deb', 'lua5.1 >= 5.1.0'), # debian
|
||||
( '51fbsd', 'lua-5.1 >= 5.1.0'), # FreeBSD
|
||||
( 'luajit', 'luajit >= 2.0.0' ),
|
||||
# assume all our dependencies (libquvi in particular) link with 5.1
|
||||
( '52', 'lua >= 5.2.0' ),
|
||||
( '52deb', 'lua5.2 >= 5.2.0'), # debian
|
||||
( '52fbsd', 'lua-5.2 >= 5.2.0'), # FreeBSD
|
||||
]
|
||||
|
||||
if ctx.options.LUA_VER:
|
||||
@@ -101,3 +104,13 @@ def check_oss_4front(ctx, dependency_identifier):
|
||||
fragment=load_fragment('oss_audio.c'))
|
||||
|
||||
return fn(ctx, dependency_identifier)
|
||||
|
||||
def check_cocoa(ctx, dependency_identifier):
|
||||
fn = check_cc(
|
||||
fragment = load_fragment('cocoa.m'),
|
||||
compile_filename = 'test.m',
|
||||
framework_name = ['Cocoa', 'IOKit', 'OpenGL'],
|
||||
includes = ctx.srcnode.abspath(),
|
||||
linkflags = '-fobjc-arc')
|
||||
|
||||
return fn(ctx, dependency_identifier)
|
||||
@@ -2,6 +2,8 @@
|
||||
#import <OpenGL/OpenGL.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "osdep/macosx_compat.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@autoreleasepool {
|
||||
NSArray *ary = @[@1, @2, @3];
|
||||
|
||||
@@ -6,7 +6,7 @@ def __get_version__(ctx):
|
||||
cwd=ctx.srcnode.abspath())
|
||||
process.wait()
|
||||
(version, err) = process.communicate()
|
||||
return version.strip()
|
||||
return version.strip().decode("utf-8")
|
||||
|
||||
def __get_build_date__():
|
||||
import time
|
||||
|
||||
@@ -77,7 +77,7 @@ main_dependencies = [
|
||||
'desc': 'linker support for --nxcompat --no-seh --dynamicbase',
|
||||
'func': check_cc(linkflags=['-Wl,--nxcompat', '-Wl,--no-seh', '-Wl,--dynamicbase'])
|
||||
}, {
|
||||
'name': 'ebx_available',
|
||||
'name': 'ebx-available',
|
||||
'desc': 'ebx availability',
|
||||
'func': check_cc(fragment=load_fragment('ebx.c'))
|
||||
} , {
|
||||
@@ -98,6 +98,27 @@ main_dependencies = [
|
||||
'func': check_pthreads,
|
||||
'req': True,
|
||||
'fmsg': 'Unable to find pthreads support.'
|
||||
}, {
|
||||
'name': 'atomic-builtins',
|
||||
'desc': 'compiler support for __atomic built-ins',
|
||||
'func': check_libs(['atomic'],
|
||||
check_statement('stdint.h',
|
||||
'int64_t test = 0;'
|
||||
'test = __atomic_add_fetch(&test, 1, __ATOMIC_SEQ_CST)'))
|
||||
}, {
|
||||
'name': 'sync-builtins',
|
||||
'desc': 'compiler support for __sync built-ins',
|
||||
'func': check_statement('stdint.h',
|
||||
'int64_t test = 0;'
|
||||
'test = __sync_add_and_fetch(&test, 1)'),
|
||||
'deps_neg': [ 'atomic-builtins' ],
|
||||
}, {
|
||||
'name': 'thread-synchronization-builtins',
|
||||
'desc': 'compiler support for usable thread synchronization built-ins',
|
||||
'func': check_true,
|
||||
'deps_any': ['atomic-builtins', 'sync-builtins'],
|
||||
'req': True,
|
||||
'fmsg': 'your compiler must support either __atomic or __sync built-ins',
|
||||
}, {
|
||||
'name': 'librt',
|
||||
'desc': 'linking with -lrt',
|
||||
@@ -314,6 +335,7 @@ Libav libraries ({0}). Aborting.".format(" ".join(libav_pkg_config_checks))
|
||||
'name': '--libswresample',
|
||||
'desc': 'libswresample',
|
||||
'func': check_pkg_config('libswresample', '>= 0.17.102'),
|
||||
'deps_neg': ['libavresample'],
|
||||
}, {
|
||||
'name': 'resampler',
|
||||
'desc': 'usable resampler found',
|
||||
@@ -477,11 +499,7 @@ video_output_features = [
|
||||
{
|
||||
'name': '--cocoa',
|
||||
'desc': 'Cocoa',
|
||||
'func': check_cc(
|
||||
fragment=load_fragment('cocoa.m'),
|
||||
compile_filename='test.m',
|
||||
framework_name=['Cocoa', 'IOKit', 'OpenGL'],
|
||||
linkflags='-fobjc-arc')
|
||||
'func': check_cocoa
|
||||
} , {
|
||||
'name': 'gdi',
|
||||
'desc': 'GDI',
|
||||
@@ -748,7 +766,7 @@ def options(opt):
|
||||
group.add_option('--lua',
|
||||
type = 'string',
|
||||
dest = 'LUA_VER',
|
||||
help = "select Lua package which should be autodetected. Choices: 51 51deb 52 52deb luajit")
|
||||
help = "select Lua package which should be autodetected. Choices: 51 51deb 51fbsd 52 52deb 52fbsd luajit")
|
||||
|
||||
@conf
|
||||
def is_debug_build(ctx):
|
||||
|
||||
Reference in new issue
Block a user