Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4db470e08a | ||
|
|
cf3819ece9 | ||
|
|
575b631d67 | ||
|
|
4c1b45b5ab | ||
|
|
8932d90ec6 | ||
|
|
fc4da23c64 | ||
|
|
017c2808e4 | ||
|
|
c5a8fc793c | ||
|
|
3dcd3476c6 | ||
|
|
ad119460d7 | ||
|
|
e865543be2 | ||
|
|
e84a00651a | ||
|
|
b17ccd1c43 | ||
|
|
62d922e4f0 | ||
|
|
eaa5393c4a | ||
|
|
50b74bf407 | ||
|
|
414cdc9da6 | ||
|
|
1c4bdfaf9c | ||
|
|
76809e5ef7 | ||
|
|
efc72daea9 | ||
|
|
b414d9a9a7 | ||
|
|
2b737f8bfc | ||
|
|
9e99a0c8b9 | ||
|
|
e22ecb1585 | ||
|
|
6358e9be5c | ||
|
|
d57a48c64e | ||
|
|
22691f2e6a | ||
|
|
623a259eee | ||
|
|
fa81e835bc | ||
|
|
46cc45223c | ||
|
|
0e160123fd | ||
|
|
710979e0e8 | ||
|
|
18d3c2ab85 | ||
|
|
f84ca3a516 | ||
|
|
324a40d2e1 | ||
|
|
83e98d3ada | ||
|
|
a424fe1296 | ||
|
|
e09803ae6b | ||
|
|
80669188d6 | ||
|
|
1a3a3aba63 | ||
|
|
0b141eaa82 | ||
|
|
cac071dc23 | ||
|
|
c77f076ae4 | ||
|
|
f4393eaa6c | ||
|
|
bbd6501bd3 | ||
|
|
dc29a21b5c | ||
|
|
4d87844508 | ||
|
|
cced4bf4d6 | ||
|
|
5734cd7063 | ||
|
|
52324a494c | ||
|
|
7ee8237e66 | ||
|
|
6fc0b4e24b | ||
|
|
3d3b1b8bba | ||
|
|
21a90cc49c | ||
|
|
83119f05c4 | ||
|
|
081ddd26b4 | ||
|
|
78349cc188 | ||
|
|
931f614257 | ||
|
|
e682d82527 | ||
|
|
76fd4b4e33 | ||
|
|
623b0a77e1 | ||
|
|
c6c4c3ea9c | ||
|
|
8e5a854374 | ||
|
|
90a0add131 | ||
|
|
443fd456a1 | ||
|
|
910da3af6a | ||
|
|
517f15dc49 | ||
|
|
62cf557b5f | ||
|
|
95e1952377 | ||
|
|
90126b9f88 | ||
|
|
01223a3e0f | ||
|
|
76b0291bf2 | ||
|
|
3fc0c18997 | ||
|
|
7fe9126bba | ||
|
|
22863d6a79 |
No files matched your search
@@ -33,6 +33,7 @@ static inline void check_error(int status)
|
||||
mpv_handle *mpv;
|
||||
dispatch_queue_t queue;
|
||||
NSWindow *w;
|
||||
NSView *wrapper;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -55,11 +56,19 @@ static void wakeup(void *);
|
||||
[self->w makeMainWindow];
|
||||
[self->w makeKeyAndOrderFront:nil];
|
||||
|
||||
NSRect frame = [[self->w contentView] bounds];
|
||||
self->wrapper = [[NSView alloc] initWithFrame:frame];
|
||||
[self->wrapper setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
|
||||
[[self->w contentView] addSubview:self->wrapper];
|
||||
[self->wrapper release];
|
||||
|
||||
NSMenu *m = [[NSMenu alloc] initWithTitle:@"AMainMenu"];
|
||||
NSMenuItem *item = [m addItemWithTitle:@"Apple" action:nil keyEquivalent:@""];
|
||||
NSMenu *sm = [[NSMenu alloc] initWithTitle:@"Apple"];
|
||||
[m setSubmenu:sm forItem:item];
|
||||
[sm addItemWithTitle: @"Shutdown mpv" action:@selector(shutdown) keyEquivalent:@"s"];
|
||||
[sm addItemWithTitle: @"mpv_command('stop')" action:@selector(mpv_stop) keyEquivalent:@""];
|
||||
[sm addItemWithTitle: @"mpv_command('quit')" action:@selector(mpv_quit) keyEquivalent:@""];
|
||||
[sm addItemWithTitle: @"quit" action:@selector(terminate:) keyEquivalent:@"q"];
|
||||
[NSApp setMenu:m];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
@@ -93,7 +102,7 @@ static void wakeup(void *);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int64_t wid = (intptr_t) [self->w contentView];
|
||||
int64_t wid = (intptr_t) self->wrapper;
|
||||
check_error(mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid));
|
||||
|
||||
// Maybe set some options here, like default key bindings.
|
||||
@@ -122,24 +131,28 @@ static void wakeup(void *);
|
||||
- (void) handleEvent:(mpv_event *)event
|
||||
{
|
||||
switch (event->event_id) {
|
||||
case MPV_EVENT_SHUTDOWN:
|
||||
// Clean up and shut down.
|
||||
mpv_terminate_destroy(mpv);
|
||||
case MPV_EVENT_SHUTDOWN: {
|
||||
mpv_detach_destroy(mpv);
|
||||
mpv = NULL;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSApplication sharedApplication] terminate:nil];
|
||||
});
|
||||
printf("event: shutdown\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case MPV_EVENT_LOG_MESSAGE: {
|
||||
struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
|
||||
printf("[%s] %s: %s", msg->prefix, msg->level, msg->text);
|
||||
}
|
||||
|
||||
case MPV_EVENT_VIDEO_RECONFIG:
|
||||
case MPV_EVENT_VIDEO_RECONFIG: {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self->w selectNextKeyView:nil];
|
||||
NSArray *subviews = [self->wrapper subviews];
|
||||
if ([subviews count] > 0) {
|
||||
// mpv's events view
|
||||
NSView *eview = [self->wrapper subviews][0];
|
||||
[self->w makeFirstResponder:eview];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
default:
|
||||
printf("event: %s\n", mpv_event_name(event->event_id));
|
||||
@@ -166,13 +179,18 @@ static void wakeup(void *context) {
|
||||
// Ostensibly, mpv's window would be hooked up to this.
|
||||
- (BOOL) windowShouldClose:(id)sender
|
||||
{
|
||||
[self shutdown];
|
||||
if (self->w)
|
||||
[self->w release];
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) shutdown
|
||||
- (void) mpv_stop
|
||||
{
|
||||
if (mpv) {
|
||||
const char *args[] = {"stop", NULL};
|
||||
mpv_command(mpv, args);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) mpv_quit
|
||||
{
|
||||
if (mpv) {
|
||||
const char *args[] = {"quit", NULL};
|
||||
|
||||
@@ -66,9 +66,9 @@ echo "MXE_TARGETS := i686-w64-mingw32.static" >> settings.mk
|
||||
# echo "MXE_TARGETS := x86_64-w64-mingw32.static" >> settings.mk
|
||||
|
||||
# Build required packages. The following provide a minimum required to build
|
||||
# mpv.
|
||||
# a reasonable mpv binary (though not an absolute minimum).
|
||||
|
||||
make gcc ffmpeg libass jpeg pthreads
|
||||
make gcc ffmpeg libass jpeg pthreads lua
|
||||
|
||||
# Add MXE binaries to $PATH
|
||||
export PATH=/opt/mxe/usr/bin/:$PATH
|
||||
|
||||
@@ -118,6 +118,8 @@ mpv uses C99 with K&R formatting, with some exceptions.
|
||||
very_long_condition_b)
|
||||
{
|
||||
code();
|
||||
} else {
|
||||
...
|
||||
}
|
||||
```
|
||||
- Remove any trailing whitespace.
|
||||
|
||||
+4
-3
@@ -565,9 +565,10 @@ Available filters are:
|
||||
Scale tempo in sync with speed (default).
|
||||
pitch
|
||||
Reverses effect of filter. Scales pitch without altering tempo.
|
||||
Add ``[ multiply speed 0.9438743126816935`` and
|
||||
``] multiply speed 1.059463094352953`` to your ``input.conf``
|
||||
to step by musical semi-tones.
|
||||
Add this to your ``input.conf`` to step by musical semi-tones::
|
||||
|
||||
[ multiply speed 0.9438743126816935
|
||||
] multiply speed 1.059463094352953
|
||||
|
||||
.. warning::
|
||||
|
||||
|
||||
+1
-1
@@ -495,7 +495,7 @@ Example implementation::
|
||||
optionB = -0.5,
|
||||
optionC = true,
|
||||
}
|
||||
options.read_options(options, "myscript")
|
||||
read_options(options, "myscript")
|
||||
print(option.optionA)
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -517,7 +517,7 @@ listed.
|
||||
- Cache state, e.g. ``Cache: 2s+134KB``. Visible if the stream cache is enabled.
|
||||
The first value shows the amount of video buffered in the demuxer in seconds,
|
||||
the second value shows *additional* data buffered in the stream cache in
|
||||
kilobytes. (``demuxer-cache-duration`` and ``cached-used`` properties.)
|
||||
kilobytes. (``demuxer-cache-duration`` and ``cache-used`` properties.)
|
||||
|
||||
|
||||
PROTOCOLS
|
||||
|
||||
@@ -104,8 +104,9 @@ Playback Control
|
||||
``--speed=<0.01-100>``
|
||||
Slow down or speed up playback by the factor given as parameter.
|
||||
|
||||
If ``--audio-pitch-correction`` is used, playing with a speed higher than
|
||||
normal automatically inserts the ``scaletempo`` audio filter.
|
||||
If ``--audio-pitch-correction`` (on by default) is used, playing with a
|
||||
speed higher than normal automatically inserts the ``scaletempo`` audio
|
||||
filter.
|
||||
|
||||
``--loop=<N|inf|force|no>``
|
||||
Loops playback ``N`` times. A value of ``1`` plays it one time (default),
|
||||
|
||||
+2
-1
@@ -419,7 +419,8 @@ Available video output drivers are:
|
||||
|
||||
``swapinterval=<n>``
|
||||
Interval in displayed frames between two buffer swaps.
|
||||
1 is equivalent to enable VSYNC, 0 to disable VSYNC.
|
||||
1 is equivalent to enable VSYNC, 0 to disable VSYNC. Defaults to 1 if
|
||||
not specified.
|
||||
|
||||
``cscale=<filter>``
|
||||
As ``scale``, but for interpolating chroma information. If the image
|
||||
|
||||
@@ -7,8 +7,13 @@ Overview
|
||||
**mpv** is a media player based on MPlayer and mplayer2. It supports a wide
|
||||
variety of video file formats, audio and video codecs, and subtitle types.
|
||||
|
||||
If you are wondering what's different from mplayer2 and MPlayer you can read
|
||||
more about the [changes][changes].
|
||||
Releases can be found on the [release list][releases].
|
||||
|
||||
Downloads
|
||||
---------
|
||||
|
||||
For semi-official builds and third-party packages please see
|
||||
[mpv.io](http://mpv.io/installation/).
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
@@ -124,6 +129,28 @@ For small changes you can just send us pull requests through GitHub. For bigger
|
||||
changes come and talk to us on IRC before you start working on them. It will
|
||||
make code review easier for both parties later on.
|
||||
|
||||
Relation to MPlayer and mplayer2
|
||||
--------------------------------
|
||||
|
||||
mpv is based on mplayer2, which in turn is based on the original MPlayer
|
||||
(also called mplayer, mplayer-svn, mplayer1). Many changes have been made, a
|
||||
large part of which is incompatible or completely changes how the player
|
||||
behaves. Although there are still many similarities to its ancestors, mpv
|
||||
should generally be treated as a completely different program.
|
||||
|
||||
mpv was forked because we wanted to modernize MPlayer. This includes
|
||||
removing cruft (including features which stopped making sense 10 years ago),
|
||||
and of course adding modern features. Such huge and intrusive changes made it
|
||||
infeasible to work directly with MPlayer, which is mostly focused on
|
||||
preservation, so a fork had to be made. (Actually, mpv is based on mplayer2,
|
||||
which already started this process of removing cruft.)
|
||||
|
||||
In general, mpv should be considered a completely new program, rather than a
|
||||
MPlayer drop-in replacement.
|
||||
|
||||
If you are wondering what's different from mplayer2 and MPlayer, an incomplete
|
||||
list of changes is located [here][mplayer-changes].
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
@@ -139,7 +166,7 @@ mailing lists are mostly unused.
|
||||
To contact the `mpv` team in private write to `mpv-team@googlegroups.com`. Use
|
||||
only if discretion is required.
|
||||
|
||||
[changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/man/changes.rst
|
||||
[releases]: https://github.com/mpv-player/mpv/releases
|
||||
[mpv-build]: https://github.com/mpv-player/mpv-build
|
||||
[homebrew-mpv]: https://github.com/mpv-player/homebrew-mpv
|
||||
[issue-tracker]: https://github.com/mpv-player/mpv/issues
|
||||
@@ -148,3 +175,4 @@ only if discretion is required.
|
||||
[ffmpeg_vs_libav]: https://github.com/mpv-player/mpv/wiki/FFmpeg-versus-Libav
|
||||
[release-policy]: https://github.com/mpv-player/mpv/blob/master/DOCS/release-policy.md
|
||||
[windows_compilation]: https://github.com/mpv-player/mpv/blob/master/DOCS/compile-windows.md
|
||||
[mplayer-changes]: https://github.com/mpv-player/mpv/blob/master/DOCS/mplayer-changes.rst
|
||||
@@ -1,3 +1,41 @@
|
||||
Release 0.8.3
|
||||
=============
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
- Documentation fixes and updates.
|
||||
- (Client API) Clarify `mpv_opengl_cb_render`'s viewport parameter behavior.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- (X11) Fix crash on `vo_xv:no-colorkey` with the Overlay adapter. (bug #1629)
|
||||
- Make the video equalizer work correctly on some VAAPI drivers. (bug #1647)
|
||||
- Prevent OSD from disappearing when clicking on mozplugger. (bug #1672)
|
||||
- The new DVB-S2 support code, using S2API, now builds on FreeBSD.
|
||||
- Fix decoding of seekable matroska from unseekable network stream. (bug #1656)
|
||||
- (OSX) Fix crashing when closing a VO's window (usually at exit). (bug #1657)
|
||||
- (OSX) Unhide the mouse cursor when over the Dock or Launchpad. (bug #513)
|
||||
- (OSX) Fix mouse cursor autohiding when the player is fullscreen.
|
||||
- `vf_vavpp` (VAAPI postprocessing) now deinterlaces video correctly.
|
||||
- `smb://` streams now use the stream cache (used to be inefficient).
|
||||
- (Windows) Do not hide the mouse cursor when it is hovering the window menu.
|
||||
- Fix 8-channel output on `ao_jack`. (bug #1688)
|
||||
- Fix `--mf-fps` parameter on JPEG files. (bug #1689)
|
||||
- Fix anamorphic scaling being ignored if it was very minor.
|
||||
|
||||
This listing is not complete. A complete changelog can be seen by running
|
||||
`git log v0.8.2..v0.8.3` in the git repository.
|
||||
|
||||
Release 0.8.2
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
- Fix OSD placement accidentally messed up in 0.8.1.
|
||||
|
||||
Release 0.8.1
|
||||
=============
|
||||
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ sub generate_c_header {
|
||||
|
||||
# Output a counter variable for each element
|
||||
# (presence/absence for scalars, item count for arrays)
|
||||
for my $subel (values %{$el->{subelements}}) {
|
||||
for my $subel (sort values %{$el->{subelements}}) {
|
||||
print " int n_$subel->{fieldname};\n"
|
||||
}
|
||||
print "};\n";
|
||||
|
||||
+2
-2
@@ -74,7 +74,7 @@ void mp_chmap_sel_add_waveext(struct mp_chmap_sel *s)
|
||||
// Classic ALSA-based MPlayer layouts.
|
||||
void mp_chmap_sel_add_alsa_def(struct mp_chmap_sel *s)
|
||||
{
|
||||
for (int n = 0; n < MP_NUM_CHANNELS; n++) {
|
||||
for (int n = 1; n <= MP_NUM_CHANNELS; n++) {
|
||||
struct mp_chmap t;
|
||||
mp_chmap_from_channels_alsa(&t, n);
|
||||
if (t.num)
|
||||
@@ -102,7 +102,7 @@ void mp_chmap_sel_add_map(struct mp_chmap_sel *s, const struct mp_chmap *map)
|
||||
// Allow all waveext formats in default order.
|
||||
void mp_chmap_sel_add_waveext_def(struct mp_chmap_sel *s)
|
||||
{
|
||||
for (int n = 1; n < MP_NUM_CHANNELS; n++) {
|
||||
for (int n = 1; n <= MP_NUM_CHANNELS; n++) {
|
||||
struct mp_chmap map;
|
||||
mp_chmap_from_channels(&map, n);
|
||||
mp_chmap_sel_add_map(s, &map);
|
||||
|
||||
@@ -200,7 +200,6 @@ static int decode_packet(struct dec_audio *da, struct mp_audio **out)
|
||||
AVPacket pkt;
|
||||
mp_set_av_packet(&pkt, mpkt, NULL);
|
||||
pkt.pts = pkt.dts = 0;
|
||||
MP_VERBOSE(da, "spdif packet, size=%d\n", pkt.size);
|
||||
if (mpkt->pts != MP_NOPTS_VALUE) {
|
||||
da->pts = mpkt->pts;
|
||||
da->pts_offset = 0;
|
||||
|
||||
+18
-5
@@ -6,7 +6,8 @@ from __future__ import print_function
|
||||
import os, sys, stat, hashlib, subprocess
|
||||
|
||||
WAFRELEASE = "waf-1.8.4"
|
||||
WAFURL = "http://ftp.waf.io/pub/release/" + WAFRELEASE
|
||||
WAFURLS = ["http://ftp.waf.io/pub/release/" + WAFRELEASE,
|
||||
"http://www.freehackers.org/~tnagy/release/" + WAFRELEASE]
|
||||
SHA256HASH = "f02035fa5d8814f33f19b2b20d43822ddef6bb39b955ca196c2a247a1f9ffaa8"
|
||||
|
||||
if os.path.exists("waf"):
|
||||
@@ -16,12 +17,24 @@ if os.path.exists("waf"):
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
from urllib.request import urlopen, URLError
|
||||
except:
|
||||
from urllib2 import urlopen
|
||||
from urllib2 import urlopen, URLError
|
||||
|
||||
print("Downloading %s..." % WAFURL)
|
||||
waf = urlopen(WAFURL).read()
|
||||
waf = None
|
||||
|
||||
for WAFURL in WAFURLS:
|
||||
try:
|
||||
print("Downloading {}...".format(WAFURL))
|
||||
waf = urlopen(WAFURL).read()
|
||||
break
|
||||
except URLError:
|
||||
print("Download failed.")
|
||||
|
||||
if not waf:
|
||||
print("Could not download {}.".format(WAFRELEASE))
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
if SHA256HASH == hashlib.sha256(waf).hexdigest():
|
||||
with open("waf", "wb") as wf:
|
||||
|
||||
@@ -135,6 +135,8 @@ void mp_set_avcodec_threads(struct mp_log *l, AVCodecContext *avctx, int threads
|
||||
threads = 1;
|
||||
} else {
|
||||
mp_verbose(l, "Detected %d logical cores.\n", threads);
|
||||
if (threads > 1)
|
||||
threads += 1; // extra thread for better load balancing
|
||||
}
|
||||
// Apparently some libavcodec versions have or had trouble with more
|
||||
// than 16 threads, and/or print a warning when using > 16.
|
||||
|
||||
+4
-1
@@ -136,8 +136,11 @@ bool mp_msg_test(struct mp_log *log, int lev)
|
||||
struct mp_log_root *root = log->root;
|
||||
if (!root || root->mute)
|
||||
return false;
|
||||
if (atomic_load(&log->reload_counter) != atomic_load(&root->reload_counter))
|
||||
if (atomic_load_explicit(&log->reload_counter, memory_order_relaxed) !=
|
||||
atomic_load_explicit(&root->reload_counter, memory_order_relaxed))
|
||||
{
|
||||
update_loglevel(log);
|
||||
}
|
||||
return lev <= log->level;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ struct playlist {
|
||||
// current_was_replaced is set to true.
|
||||
struct playlist_entry *current;
|
||||
bool current_was_replaced;
|
||||
|
||||
bool disable_safety;
|
||||
};
|
||||
|
||||
void playlist_entry_add_param(struct playlist_entry *e, bstr name, bstr value);
|
||||
|
||||
+6
-1
@@ -888,7 +888,7 @@ static struct demuxer *open_given_type(struct mpv_global *global,
|
||||
stream_seek(stream, 0);
|
||||
|
||||
// Peek this much data to avoid that stream_read() run by some demuxers
|
||||
// or stream filters will flush previous peeked data.
|
||||
// will flush previous peeked data.
|
||||
stream_peek(stream, STREAM_BUFFER_SIZE);
|
||||
|
||||
int ret = demuxer->desc->open(in->d_thread, check);
|
||||
@@ -1378,6 +1378,11 @@ void demux_unpause(demuxer_t *demuxer)
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
}
|
||||
|
||||
bool demux_cancel_test(struct demuxer *demuxer)
|
||||
{
|
||||
return mp_cancel_test(demuxer->stream->cancel);
|
||||
}
|
||||
|
||||
struct demux_chapter *demux_copy_chapter_data(struct demux_chapter *c, int num)
|
||||
{
|
||||
struct demux_chapter *new = talloc_array(NULL, struct demux_chapter, num);
|
||||
|
||||
@@ -251,6 +251,8 @@ void demux_start_thread(struct demuxer *demuxer);
|
||||
void demux_stop_thread(struct demuxer *demuxer);
|
||||
void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *ctx);
|
||||
|
||||
bool demux_cancel_test(struct demuxer *demuxer);
|
||||
|
||||
void demux_flush(struct demuxer *demuxer);
|
||||
int demux_seek(struct demuxer *demuxer, double rel_seek_secs, int flags);
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ static const struct format_hack format_hacks[] = {
|
||||
BLACKLIST("bin"),
|
||||
// Image demuxers, disabled in favor of demux_mf (for now):
|
||||
BLACKLIST("image"),
|
||||
BLACKLIST("image2"),
|
||||
BLACKLIST("image2pipe"),
|
||||
BLACKLIST("bmp_pipe"), BLACKLIST("dpx_pipe"), BLACKLIST("exr_pipe"),
|
||||
BLACKLIST("j2k_pipe"), BLACKLIST("png_pipe"), BLACKLIST("tiff_pipe"),
|
||||
|
||||
+19
-14
@@ -1036,9 +1036,6 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
|
||||
struct ebml_seek_head seekhead = {0};
|
||||
struct ebml_parse_ctx parse_ctx = {demuxer->log};
|
||||
|
||||
int64_t end = 0;
|
||||
stream_control(s, STREAM_CTRL_GET_SIZE, &end);
|
||||
|
||||
MP_VERBOSE(demuxer, "/---- [ parsing seek head ] ---------\n");
|
||||
if (ebml_read_element(s, &parse_ctx, &seekhead, &ebml_seek_head_desc) < 0) {
|
||||
res = -1;
|
||||
@@ -1053,16 +1050,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer)
|
||||
uint64_t pos = seek->seek_position + mkv_d->segment_start;
|
||||
MP_DBG(demuxer, "Element 0x%x at %"PRIu64".\n",
|
||||
(unsigned)seek->seek_id, pos);
|
||||
struct header_elem *elem = get_header_element(demuxer, seek->seek_id, pos);
|
||||
// Warn against incomplete files.
|
||||
if (elem && pos >= end) {
|
||||
elem->parsed = true; // don't bother
|
||||
if (!mkv_d->eof_warning) {
|
||||
MP_WARN(demuxer, "SeekHead position beyond "
|
||||
"end of file - incomplete file?\n");
|
||||
mkv_d->eof_warning = true;
|
||||
}
|
||||
}
|
||||
get_header_element(demuxer, seek->seek_id, pos);
|
||||
}
|
||||
out:
|
||||
MP_VERBOSE(demuxer, "\\---- [ parsing seek head ] ---------\n");
|
||||
@@ -1810,12 +1798,27 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int64_t end = 0;
|
||||
stream_control(s, STREAM_CTRL_GET_SIZE, &end);
|
||||
|
||||
// Read headers that come after the first cluster (i.e. require seeking).
|
||||
// Note: reading might increase ->num_headers.
|
||||
// Likewise, ->headers might be reallocated.
|
||||
for (int n = 0; n < mkv_d->num_headers; n++) {
|
||||
struct header_elem *elem = &mkv_d->headers[n];
|
||||
if (elem->id == MATROSKA_ID_CUES && !elem->parsed) {
|
||||
if (elem->parsed)
|
||||
continue;
|
||||
// Warn against incomplete files and skip headers outside of range.
|
||||
if (elem->pos >= end) {
|
||||
elem->parsed = true; // don't bother if file is incomplete
|
||||
if (!mkv_d->eof_warning) {
|
||||
MP_WARN(demuxer, "SeekHead position beyond "
|
||||
"end of file - incomplete file?\n");
|
||||
mkv_d->eof_warning = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (elem->id == MATROSKA_ID_CUES) {
|
||||
// Read cues when they are needed, to avoid seeking on opening.
|
||||
MP_VERBOSE(demuxer, "Deferring reading cues.\n");
|
||||
continue;
|
||||
@@ -2519,6 +2522,8 @@ static int read_next_block(demuxer_t *demuxer, struct block_info *block)
|
||||
break;
|
||||
if (s->eof)
|
||||
return -1;
|
||||
if (demux_cancel_test(demuxer))
|
||||
return -1;
|
||||
if (id == EBML_ID_EBML && stream_tell(s) >= mkv_d->segment_end) {
|
||||
// Appended segment - don't use its clusters, consider this EOF.
|
||||
stream_seek(s, stream_tell(s) - 4);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "common/playlist.h"
|
||||
#include "options/path.h"
|
||||
#include "stream/stream.h"
|
||||
#include "stream/rar.h"
|
||||
#include "demux.h"
|
||||
|
||||
#define PROBE_SIZE (8 * 1024)
|
||||
@@ -188,6 +189,30 @@ static int parse_pls(struct pl_parser *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_rar(struct pl_parser *p)
|
||||
{
|
||||
if (RarProbe(p->s))
|
||||
return -1;
|
||||
if (p->probing)
|
||||
return 0;
|
||||
|
||||
int count;
|
||||
rar_file_t **files;
|
||||
if (RarParse(p->s, &count, &files))
|
||||
return -1;
|
||||
|
||||
p->pl->disable_safety = true; // make it load rar://
|
||||
char *prefix = mp_url_escape(p, p->real_stream->url, "~|");
|
||||
for (int n = 0; n < count; n++) {
|
||||
// stream_rar.c does the real work
|
||||
playlist_add_file(p->pl,
|
||||
talloc_asprintf(p, "rar://%s|%s", prefix, files[n]->name));
|
||||
RarFileDelete(files[n]);
|
||||
}
|
||||
talloc_free(files);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_txt(struct pl_parser *p)
|
||||
{
|
||||
if (!p->force)
|
||||
@@ -220,6 +245,7 @@ static const struct pl_format formats[] = {
|
||||
{"mov", parse_mov_rtsptext},
|
||||
{"pls", parse_pls,
|
||||
MIME_TYPES("audio/x-scpls")},
|
||||
{"rar", parse_rar},
|
||||
{"txt", parse_txt},
|
||||
};
|
||||
|
||||
|
||||
+4
-2
@@ -228,8 +228,10 @@ int ebml_resync_cluster(struct mp_log *log, stream_t *s)
|
||||
{
|
||||
int64_t pos = stream_tell(s);
|
||||
uint32_t last_4_bytes = 0;
|
||||
mp_err(log, "Corrupt file detected. "
|
||||
"Trying to resync starting from position %"PRId64"...\n", pos);
|
||||
if (!s->eof) {
|
||||
mp_err(log, "Corrupt file detected. "
|
||||
"Trying to resync starting from position %"PRId64"...\n", pos);
|
||||
}
|
||||
while (!s->eof) {
|
||||
// Assumes MATROSKA_ID_CLUSTER is 4 bytes, with no 0 bytes.
|
||||
if (last_4_bytes == MATROSKA_ID_CLUSTER) {
|
||||
|
||||
+4
-1
@@ -186,11 +186,14 @@ int mpv_opengl_cb_init_gl(mpv_opengl_cb_context *ctx, const char *exts,
|
||||
* postprocessing, it will always bind and unbind FBOs itself. If
|
||||
* you want mpv to render on the main framebuffer, pass 0.
|
||||
* @param vp Viewport to render on. The renderer will essentially call:
|
||||
* glViewport(vp[0], vp[1], vp[2], vp[3]);
|
||||
* glViewport(0, 0, vp[2], vp[3]);
|
||||
* before rendering. The height (vp[3]) can be negative to flip the
|
||||
* image - the renderer will flip it before setting the viewport
|
||||
* (typically you want to flip the image if you are rendering
|
||||
* directly to the main framebuffer).
|
||||
* vp[0] and vp[1] should be set to 0.
|
||||
* The viewport width and height imply the target FBO or framebuffer's
|
||||
* size. It will always render to the full size of it.
|
||||
* @return the number of left frames in the internal queue to be rendered
|
||||
*/
|
||||
int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4]);
|
||||
|
||||
+2
-2
@@ -240,7 +240,7 @@ char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2)
|
||||
return bstrdup0(talloc_ctx, p1);
|
||||
|
||||
#if HAVE_DOS_PATHS
|
||||
if (p2.len >= 2 && p2.start[1] == ':'
|
||||
if ((p2.len >= 2 && p2.start[1] == ':')
|
||||
|| p2.start[0] == '\\' || p2.start[0] == '/')
|
||||
#else
|
||||
if (p2.start[0] == '/')
|
||||
@@ -251,7 +251,7 @@ char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2)
|
||||
int endchar1 = p1.start[p1.len - 1];
|
||||
#if HAVE_DOS_PATHS
|
||||
have_separator = endchar1 == '/' || endchar1 == '\\'
|
||||
|| p1.len == 2 && endchar1 == ':'; // "X:" only
|
||||
|| (p1.len == 2 && endchar1 == ':'); // "X:" only
|
||||
#else
|
||||
have_separator = endchar1 == '/';
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,11 @@ typedef struct { volatile unsigned long long v; } atomic_ullong;
|
||||
#define ATOMIC_VAR_INIT(x) \
|
||||
{.v = (x)}
|
||||
|
||||
#define memory_order_relaxed 1
|
||||
#define memory_order_seq_cst 2
|
||||
|
||||
#define atomic_load_explicit(p, e) atomic_load(p)
|
||||
|
||||
#if HAVE_ATOMIC_BUILTINS
|
||||
|
||||
#define atomic_load(p) \
|
||||
|
||||
@@ -376,7 +376,7 @@ void cocoa_set_input_context(struct input_ctx *input_context)
|
||||
if (cocoaModifiers & NSControlKeyMask)
|
||||
mask |= MP_KEY_MODIFIER_CTRL;
|
||||
if (LeftAltPressed(cocoaModifiers) ||
|
||||
RightAltPressed(cocoaModifiers) && ![self useAltGr])
|
||||
(RightAltPressed(cocoaModifiers) && ![self useAltGr]))
|
||||
mask |= MP_KEY_MODIFIER_ALT;
|
||||
if (cocoaModifiers & NSCommandKeyMask)
|
||||
mask |= MP_KEY_MODIFIER_META;
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ void set_playback_speed(struct MPContext *mpctx, double new_speed)
|
||||
|
||||
opts->playback_speed = new_speed;
|
||||
|
||||
if (!mpctx->d_audio)
|
||||
if (!mpctx->d_audio || mpctx->d_audio->afilter->initialized < 1)
|
||||
return;
|
||||
|
||||
recreate_audio_filters(mpctx);
|
||||
|
||||
+4
-5
@@ -2297,15 +2297,15 @@ static int panscan_property_helper(void *ctx, struct m_property *prop,
|
||||
static int mp_property_vo_flag(struct m_property *prop, int action, void *arg,
|
||||
int vo_ctrl, int *vo_var, MPContext *mpctx)
|
||||
{
|
||||
if (!mpctx->video_out)
|
||||
return M_PROPERTY_UNAVAILABLE;
|
||||
|
||||
if (action == M_PROPERTY_SET) {
|
||||
int desired = !!*(int *) arg;
|
||||
if (*vo_var == desired)
|
||||
return M_PROPERTY_OK;
|
||||
if (mpctx->video_out->config_ok)
|
||||
if (mpctx->video_out) {
|
||||
vo_control(mpctx->video_out, vo_ctrl, 0);
|
||||
} else {
|
||||
*vo_var = desired;
|
||||
}
|
||||
return *vo_var == desired ? M_PROPERTY_OK : M_PROPERTY_ERROR;
|
||||
}
|
||||
return mp_property_generic_option(mpctx, prop, action, arg);
|
||||
@@ -3808,7 +3808,6 @@ static bool reinit_filters(MPContext *mpctx, enum stream_type mediatype)
|
||||
case STREAM_VIDEO:
|
||||
return reinit_video_filters(mpctx) >= 0;
|
||||
case STREAM_AUDIO:
|
||||
clear_audio_output_buffers(mpctx);
|
||||
return reinit_audio_filters(mpctx) >= 0;
|
||||
}
|
||||
return false;
|
||||
|
||||
+6
-3
@@ -1118,10 +1118,13 @@ goto_reopen_demuxer: ;
|
||||
load_timeline(mpctx);
|
||||
|
||||
if (mpctx->demuxer->playlist) {
|
||||
int entry_stream_flags =
|
||||
(mpctx->demuxer->stream->safe_origin ? 0 : STREAM_SAFE_ONLY) |
|
||||
(mpctx->demuxer->stream->is_network ? STREAM_NETWORK_ONLY : 0);
|
||||
struct playlist *pl = mpctx->demuxer->playlist;
|
||||
int entry_stream_flags = 0;
|
||||
if (!pl->disable_safety) {
|
||||
entry_stream_flags = STREAM_SAFE_ONLY;
|
||||
if (mpctx->demuxer->stream->is_network)
|
||||
entry_stream_flags |= STREAM_NETWORK_ONLY;
|
||||
}
|
||||
for (struct playlist_entry *e = pl->first; e; e = e->next)
|
||||
e->stream_flags |= entry_stream_flags;
|
||||
transfer_playlist(mpctx, pl);
|
||||
|
||||
@@ -971,6 +971,17 @@ static int script_get_screen_size(lua_State *L)
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int script_get_screen_margins(lua_State *L)
|
||||
{
|
||||
struct MPContext *mpctx = get_mpctx(L);
|
||||
struct mp_osd_res vo_res = osd_get_vo_res(mpctx->osd, OSDTYPE_EXTERNAL);
|
||||
lua_pushnumber(L, vo_res.ml);
|
||||
lua_pushnumber(L, vo_res.mt);
|
||||
lua_pushnumber(L, vo_res.mr);
|
||||
lua_pushnumber(L, vo_res.mb);
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int script_get_mouse_pos(lua_State *L)
|
||||
{
|
||||
struct MPContext *mpctx = get_mpctx(L);
|
||||
@@ -1280,6 +1291,7 @@ static const struct fn_entry main_fns[] = {
|
||||
FN_ENTRY(set_osd_ass),
|
||||
FN_ENTRY(get_osd_resolution),
|
||||
FN_ENTRY(get_screen_size),
|
||||
FN_ENTRY(get_screen_margins),
|
||||
FN_ENTRY(get_mouse_pos),
|
||||
FN_ENTRY(get_time),
|
||||
FN_ENTRY(input_define_section),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
-- Compatibility shim for lua 5.2/5.3
|
||||
unpack = unpack or table.unpack
|
||||
|
||||
-- these are used internally by lua.c
|
||||
mp.UNKNOWN_TYPE.info = "this value is inserted if the C type is not supported"
|
||||
|
||||
@@ -167,6 +167,8 @@ static char *create_fname(struct MPContext *mpctx, char *template,
|
||||
}
|
||||
case 'f':
|
||||
case 'F': {
|
||||
if (!mpctx->filename)
|
||||
goto error_exit;
|
||||
char *video_file = mp_basename(mpctx->filename);
|
||||
if (video_file) {
|
||||
char *name = video_file;
|
||||
|
||||
+2
-2
@@ -127,8 +127,8 @@ void uninit_sub_renderer(struct MPContext *mpctx)
|
||||
static void init_sub_renderer(struct MPContext *mpctx) {}
|
||||
void uninit_sub_renderer(struct MPContext *mpctx) {}
|
||||
|
||||
void mp_ass_configure_fonts(struct ass_renderer *a, struct MPOpts *b,
|
||||
struct mpv_global *c, struct mp_log *d) {}
|
||||
static void mp_ass_configure_fonts(struct ass_renderer *a, struct osd_style_opts *b,
|
||||
struct mpv_global *c, struct mp_log *d) {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+3
-3
@@ -70,11 +70,11 @@ static const char av_desync_help_text[] =
|
||||
"- Slow video output.\n"
|
||||
" Try a different --vo driver (--vo=help for a list). Make sure framedrop\n"
|
||||
" is not disabled, or experiment with different values for --framedrop.\n"
|
||||
"- Playing from a slow network source.\n"
|
||||
" Download the file instead.\n"
|
||||
" Make sure you have proper drivers for your GPU installed. If mpv\n"
|
||||
" autoselects 'VO: [x11]', it's a sure sign your drivers are messed up.\n"
|
||||
"- Playing from a slow network source. Download the file instead.\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 switched audio or video tracks, try seeking to force synchronization.\n"
|
||||
"If none of this helps you, file a bug report.\n\n";
|
||||
|
||||
void update_fps(struct MPContext *mpctx)
|
||||
|
||||
+8
-2
@@ -102,6 +102,9 @@ struct priv {
|
||||
int64_t reads; // number of actual read attempts performed
|
||||
|
||||
int64_t read_filepos; // client read position (mirrors cache->pos)
|
||||
|
||||
int64_t eof_pos;
|
||||
|
||||
int control; // requested STREAM_CTRL_... or CACHE_CTRL_...
|
||||
void *control_arg; // temporary for executing STREAM_CTRLs
|
||||
int control_res;
|
||||
@@ -277,8 +280,10 @@ done:
|
||||
s->eof = len <= 0;
|
||||
s->idle = s->eof;
|
||||
s->reads++;
|
||||
if (s->eof)
|
||||
if (s->eof) {
|
||||
s->eof_pos = stream_tell(s->stream);
|
||||
MP_TRACE(s, "EOF reached.\n");
|
||||
}
|
||||
|
||||
pthread_cond_signal(&s->wakeup);
|
||||
|
||||
@@ -352,7 +357,7 @@ static void update_cached_controls(struct priv *s)
|
||||
talloc_free(s->stream_metadata);
|
||||
s->stream_metadata = talloc_steal(s, tags);
|
||||
}
|
||||
s->stream_size = -1;
|
||||
s->stream_size = s->eof_pos;
|
||||
if (stream_control(s->stream, STREAM_CTRL_GET_SIZE, &i64) == STREAM_OK)
|
||||
s->stream_size = i64;
|
||||
s->has_avseek = stream_control(s->stream, STREAM_CTRL_HAS_AVSEEK, NULL) > 0;
|
||||
@@ -610,6 +615,7 @@ int stream_cache_init(stream_t *cache, stream_t *stream,
|
||||
|
||||
struct priv *s = talloc_zero(NULL, struct priv);
|
||||
s->log = cache->log;
|
||||
s->eof_pos = -1;
|
||||
|
||||
cache_drop_contents(s);
|
||||
|
||||
|
||||
+1
-1
@@ -37,12 +37,12 @@
|
||||
#ifndef DTV_STREAM_ID
|
||||
#define DTV_STREAM_ID DTV_ISDBS_TS_ID
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This is only defined, for convenience, since API 5.8.
|
||||
#ifndef NO_STREAM_ID_FILTER
|
||||
#define NO_STREAM_ID_FILTER (~0U)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (DVB_API_VERSION == 3 && DVB_API_VERSION_MINOR >= 1) || DVB_API_VERSION == 5
|
||||
#define DVB_ATSC 1
|
||||
|
||||
+2
-4
@@ -385,8 +385,7 @@ int RarParse(struct stream *s, int *count, rar_file_t ***file)
|
||||
if (!volume_mrl)
|
||||
goto done;
|
||||
|
||||
vol = stream_create(volume_mrl, STREAM_READ | STREAM_NO_FILTERS,
|
||||
s->cancel, s->global);
|
||||
vol = stream_create(volume_mrl, STREAM_READ, s->cancel, s->global);
|
||||
|
||||
if (!vol)
|
||||
goto done;
|
||||
@@ -421,8 +420,7 @@ int RarSeek(rar_file_t *file, uint64_t position)
|
||||
if (strcmp(old_chunk->mrl, file->current_chunk->mrl)) {
|
||||
if (file->s)
|
||||
free_stream(file->s);
|
||||
file->s = stream_create(file->current_chunk->mrl,
|
||||
STREAM_READ | STREAM_NO_FILTERS,
|
||||
file->s = stream_create(file->current_chunk->mrl, STREAM_READ,
|
||||
file->cancel, file->global);
|
||||
}
|
||||
return file->s ? stream_seek(file->s, offset) : 0;
|
||||
|
||||
+14
-39
@@ -74,8 +74,7 @@ extern const stream_info_t stream_info_dvdnav;
|
||||
extern const stream_info_t stream_info_bdmv_dir;
|
||||
extern const stream_info_t stream_info_bluray;
|
||||
extern const stream_info_t stream_info_bdnav;
|
||||
extern const stream_info_t stream_info_rar_filter;
|
||||
extern const stream_info_t stream_info_rar_entry;
|
||||
extern const stream_info_t stream_info_rar;
|
||||
extern const stream_info_t stream_info_edl;
|
||||
|
||||
static const stream_info_t *const stream_list[] = {
|
||||
@@ -115,8 +114,7 @@ static const stream_info_t *const stream_list[] = {
|
||||
&stream_info_null,
|
||||
&stream_info_mf,
|
||||
&stream_info_edl,
|
||||
&stream_info_rar_filter,
|
||||
&stream_info_rar_entry,
|
||||
&stream_info_rar,
|
||||
&stream_info_file,
|
||||
NULL
|
||||
};
|
||||
@@ -256,32 +254,25 @@ static const char *match_proto(const char *url, const char *proto)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int open_internal(const stream_info_t *sinfo, struct stream *underlying,
|
||||
const char *url, int flags, struct mp_cancel *c,
|
||||
struct mpv_global *global, struct stream **ret)
|
||||
static int open_internal(const stream_info_t *sinfo, const char *url, int flags,
|
||||
struct mp_cancel *c, struct mpv_global *global,
|
||||
struct stream **ret)
|
||||
{
|
||||
if (sinfo->stream_filter != !!underlying)
|
||||
return STREAM_NO_MATCH;
|
||||
if (sinfo->stream_filter && (flags & STREAM_NO_FILTERS))
|
||||
return STREAM_NO_MATCH;
|
||||
if (!sinfo->is_safe && (flags & STREAM_SAFE_ONLY))
|
||||
return STREAM_UNSAFE;
|
||||
if (!sinfo->is_network && (flags & STREAM_NETWORK_ONLY))
|
||||
return STREAM_UNSAFE;
|
||||
|
||||
const char *path = NULL;
|
||||
// Stream filters use the original URL, with no protocol matching at all.
|
||||
if (!sinfo->stream_filter) {
|
||||
for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
|
||||
path = match_proto(url, sinfo->protocols[n]);
|
||||
if (path)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!path)
|
||||
return STREAM_NO_MATCH;
|
||||
for (int n = 0; sinfo->protocols && sinfo->protocols[n]; n++) {
|
||||
path = match_proto(url, sinfo->protocols[n]);
|
||||
if (path)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!path)
|
||||
return STREAM_NO_MATCH;
|
||||
|
||||
stream_t *s = new_stream();
|
||||
s->log = mp_log_new(s, global->log, sinfo->name);
|
||||
s->info = sinfo;
|
||||
@@ -290,7 +281,6 @@ static int open_internal(const stream_info_t *sinfo, struct stream *underlying,
|
||||
s->global = global;
|
||||
s->url = talloc_strdup(s, url);
|
||||
s->path = talloc_strdup(s, path);
|
||||
s->source = underlying;
|
||||
s->allow_caching = true;
|
||||
s->is_network = sinfo->is_network;
|
||||
s->mode = flags & (STREAM_READ | STREAM_WRITE);
|
||||
@@ -357,7 +347,7 @@ struct stream *stream_create(const char *url, int flags,
|
||||
// Open stream proper
|
||||
bool unsafe = false;
|
||||
for (int i = 0; stream_list[i]; i++) {
|
||||
int r = open_internal(stream_list[i], NULL, url, flags, c, global, &s);
|
||||
int r = open_internal(stream_list[i], url, flags, c, global, &s);
|
||||
if (r == STREAM_OK)
|
||||
break;
|
||||
if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED)
|
||||
@@ -386,19 +376,6 @@ struct stream *stream_create(const char *url, int flags,
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Open stream filters
|
||||
for (;;) {
|
||||
struct stream *new = NULL;
|
||||
for (int i = 0; stream_list[i]; i++) {
|
||||
int r = open_internal(stream_list[i], s, s->url, flags, c, global, &new);
|
||||
if (r == STREAM_OK)
|
||||
break;
|
||||
}
|
||||
if (!new)
|
||||
break;
|
||||
s = new;
|
||||
}
|
||||
|
||||
done:
|
||||
talloc_free(log);
|
||||
return s;
|
||||
@@ -730,7 +707,6 @@ void free_stream(stream_t *s)
|
||||
if (s->close)
|
||||
s->close(s);
|
||||
free_stream(s->uncached_stream);
|
||||
free_stream(s->source);
|
||||
talloc_free(s);
|
||||
}
|
||||
|
||||
@@ -759,7 +735,6 @@ static stream_t *open_cache(stream_t *orig, const char *name)
|
||||
cache->mime_type = talloc_strdup(cache, orig->mime_type);
|
||||
cache->demuxer = talloc_strdup(cache, orig->demuxer);
|
||||
cache->lavf_type = talloc_strdup(cache, orig->lavf_type);
|
||||
cache->safe_origin = orig->safe_origin;
|
||||
cache->streaming = orig->streaming,
|
||||
cache->is_network = orig->is_network;
|
||||
cache->opts = orig->opts;
|
||||
@@ -1012,7 +987,7 @@ void mp_cancel_reset(struct mp_cancel *c)
|
||||
// For convenience, c==NULL is allowed.
|
||||
bool mp_cancel_test(struct mp_cancel *c)
|
||||
{
|
||||
return c ? atomic_load(&c->triggered) : false;
|
||||
return c ? atomic_load_explicit(&c->triggered, memory_order_relaxed) : false;
|
||||
}
|
||||
|
||||
// Wait until the even is signaled. If the timeout (in seconds) expires, return
|
||||
|
||||
@@ -54,7 +54,6 @@ enum streamtype {
|
||||
#define STREAM_WRITE 1
|
||||
|
||||
// flags for stream_open_ext (this includes STREAM_READ and STREAM_WRITE)
|
||||
#define STREAM_NO_FILTERS 2
|
||||
#define STREAM_SAFE_ONLY 4
|
||||
#define STREAM_NETWORK_ONLY 8
|
||||
|
||||
@@ -157,7 +156,6 @@ typedef struct stream_info_st {
|
||||
void *(*get_defaults)(struct stream *st);
|
||||
const struct m_option *options;
|
||||
const char *const *url_options;
|
||||
bool stream_filter;
|
||||
bool can_write; // correctly checks for READ/WRITE modes
|
||||
bool is_safe; // opening is no security issue, even with remote provided URLs
|
||||
bool is_network; // used to restrict remote playlist entries to remote URLs
|
||||
@@ -196,7 +194,6 @@ typedef struct stream {
|
||||
bool streaming : 1; // known to be a network stream if true
|
||||
bool seekable : 1; // presence of general byte seeking support
|
||||
bool fast_skip : 1; // consider stream fast enough to fw-seek by skipping
|
||||
bool safe_origin : 1; // used for playlists that can be opened safely
|
||||
bool is_network : 1; // original stream_info_t.is_network flag
|
||||
bool allow_caching : 1; // stream cache makes sense
|
||||
struct mp_log *log;
|
||||
@@ -209,7 +206,6 @@ typedef struct stream {
|
||||
char *capture_filename;
|
||||
|
||||
struct stream *uncached_stream; // underlying stream for cache wrapper
|
||||
struct stream *source;
|
||||
|
||||
// Includes additional padding in case sizes get rounded up by sector size.
|
||||
unsigned char buffer[];
|
||||
|
||||
@@ -227,7 +227,6 @@ static void close_cdda(stream_t *s)
|
||||
cdda_priv *p = (cdda_priv *)s->priv;
|
||||
paranoia_free(p->cdp);
|
||||
cdda_close(p->cd);
|
||||
free(p);
|
||||
}
|
||||
|
||||
static int get_track_by_sector(cdda_priv *p, unsigned int sector)
|
||||
@@ -313,7 +312,6 @@ static int open_cdda(stream_t *st)
|
||||
return STREAM_ERROR;
|
||||
}
|
||||
|
||||
priv = calloc(1,sizeof(cdda_priv));
|
||||
priv->cd = cdd;
|
||||
|
||||
if (p->toc_bias)
|
||||
|
||||
+5
-74
@@ -43,11 +43,10 @@ This works as follows:
|
||||
|
||||
- stream_open() with file01.rar
|
||||
- is opened as normal file (stream_file.c or others) first
|
||||
- stream_info_rar_filter stream filter applies
|
||||
- leads to rar_filter_open()
|
||||
- the rar code in demux_playlist.c detects it
|
||||
- if multi-part, opens file02.rar, file03.rar, etc. as actual streams
|
||||
(recursive opening is prevented with the STREAM_NO_FILTERS flag)
|
||||
- read accesses return a m3u playlist with entries like:
|
||||
- it returns a playlist like this to the player:
|
||||
rar://bla01.rar|subfile.mkv
|
||||
(one such entry for each file contained in the rar)
|
||||
- stream_open() with the playlist entry, e.g. rar://bla01.rar|subfile.mkv
|
||||
@@ -99,7 +98,7 @@ static int rar_entry_open(stream_t *stream)
|
||||
*name++ = '\0';
|
||||
mp_url_unescape_inplace(base);
|
||||
|
||||
struct stream *rar = stream_create(base, STREAM_READ | STREAM_NO_FILTERS,
|
||||
struct stream *rar = stream_create(base, STREAM_READ | STREAM_SAFE_ONLY,
|
||||
stream->cancel, stream->global);
|
||||
if (!rar)
|
||||
return STREAM_ERROR;
|
||||
@@ -143,76 +142,8 @@ static int rar_entry_open(stream_t *stream)
|
||||
return STREAM_OK;
|
||||
}
|
||||
|
||||
static int rar_filter_fill_buffer(stream_t *s, char *buffer, int max_len)
|
||||
{
|
||||
struct stream *m = s->priv;
|
||||
return stream_read_partial(m, buffer, max_len);
|
||||
}
|
||||
|
||||
static int rar_filter_seek(stream_t *s, int64_t newpos)
|
||||
{
|
||||
struct stream *m = s->priv;
|
||||
return stream_seek(m, newpos);
|
||||
}
|
||||
|
||||
static void rar_filter_close(stream_t *s)
|
||||
{
|
||||
struct stream *m = s->priv;
|
||||
free_stream(m);
|
||||
}
|
||||
|
||||
static int rar_filter_control(stream_t *s, int cmd, void *arg)
|
||||
{
|
||||
struct stream *m = s->priv;
|
||||
return stream_control(m, cmd, arg);
|
||||
}
|
||||
|
||||
static int rar_filter_open(stream_t *stream)
|
||||
{
|
||||
struct stream *rar = stream->source;
|
||||
if (!rar)
|
||||
return STREAM_UNSUPPORTED;
|
||||
|
||||
int count;
|
||||
rar_file_t **files;
|
||||
if (!rar || RarProbe(rar) || RarParse(rar, &count, &files))
|
||||
return STREAM_UNSUPPORTED;
|
||||
|
||||
void *tmp = talloc_new(NULL);
|
||||
|
||||
// Create a playlist containing all entries of the .rar file. The URLs
|
||||
// link to rar_entry_open().
|
||||
char *prefix = mp_url_escape(tmp, stream->url, "~|");
|
||||
char *pl = talloc_strdup(tmp, "#EXTM3U\n");
|
||||
for (int n = 0; n < count; n++) {
|
||||
pl = talloc_asprintf_append_buffer(pl, "rar://%s|%s\n",
|
||||
prefix, files[n]->name);
|
||||
RarFileDelete(files[n]);
|
||||
}
|
||||
talloc_free(files);
|
||||
|
||||
struct stream *m = open_memory_stream(pl, strlen(pl));
|
||||
|
||||
stream->priv = m;
|
||||
stream->fill_buffer = rar_filter_fill_buffer;
|
||||
stream->seek = rar_filter_seek;
|
||||
stream->seekable = true;
|
||||
stream->close = rar_filter_close;
|
||||
stream->control = rar_filter_control;
|
||||
stream->safe_origin = true;
|
||||
|
||||
talloc_free(tmp);
|
||||
return STREAM_OK;
|
||||
}
|
||||
|
||||
const stream_info_t stream_info_rar_entry = {
|
||||
.name = "rar_entry",
|
||||
const stream_info_t stream_info_rar = {
|
||||
.name = "rar",
|
||||
.open = rar_entry_open,
|
||||
.protocols = (const char*const[]){ "rar", NULL },
|
||||
};
|
||||
|
||||
const stream_info_t stream_info_rar_filter = {
|
||||
.name = "rar_filter",
|
||||
.open = rar_filter_open,
|
||||
.stream_filter = true,
|
||||
};
|
||||
@@ -133,6 +133,7 @@ static int open_f (stream_t *stream)
|
||||
stream->close = close_f;
|
||||
stream->control = control;
|
||||
stream->read_chunk = 128 * 1024;
|
||||
stream->streaming = true;
|
||||
|
||||
return STREAM_OK;
|
||||
}
|
||||
|
||||
+1
-2
@@ -111,6 +111,7 @@ static void create_ass_track(struct osd_state *osd, struct osd_object *obj,
|
||||
int sid = ass_alloc_style(track);
|
||||
track->default_style = sid;
|
||||
ASS_Style *style = track->styles + sid;
|
||||
style->Alignment = 5; // top-title, left
|
||||
style->Name = strdup("OSD");
|
||||
// Set to neutral base direction, as opposed to VSFilter LTR default
|
||||
style->Encoding = -1;
|
||||
@@ -316,8 +317,6 @@ static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj,
|
||||
// Rendering with shadow is broken (because there's more than one shape)
|
||||
style->Shadow = 0;
|
||||
|
||||
style->Alignment = 5;
|
||||
|
||||
*o_border = style->Outline;
|
||||
|
||||
*o_x = get_align(opts->osd_bar_align_x, track->PlayResX, *o_w, *o_border);
|
||||
|
||||
@@ -402,6 +402,7 @@ int video_reconfig_filters(struct dec_video *d_video,
|
||||
if (sh->aspect > 0)
|
||||
vf_set_dar(&p.d_w, &p.d_h, p.w, p.h, sh->aspect);
|
||||
} else {
|
||||
MP_VERBOSE(d_video, "Using bitstream aspect ratio.\n");
|
||||
// Even if the aspect switches back, don't use container aspect again.
|
||||
d_video->initial_decoder_aspect = -1;
|
||||
}
|
||||
@@ -410,14 +411,6 @@ int video_reconfig_filters(struct dec_video *d_video,
|
||||
if (force_aspect >= 0.0)
|
||||
vf_set_dar(&p.d_w, &p.d_h, p.w, p.h, force_aspect);
|
||||
|
||||
if (abs(p.d_w - p.w) >= 4 || abs(p.d_h - p.h) >= 4) {
|
||||
MP_VERBOSE(d_video, "Aspect ratio is %.2f:1 - "
|
||||
"scaling to correct movie aspect.\n", sh->aspect);
|
||||
} else {
|
||||
p.d_w = p.w;
|
||||
p.d_h = p.h;
|
||||
}
|
||||
|
||||
// Apply user overrides
|
||||
if (opts->requested_colorspace != MP_CSP_AUTO)
|
||||
p.colorspace = opts->requested_colorspace;
|
||||
|
||||
@@ -130,8 +130,8 @@ static const struct vd_lavc_hwdec *const hwdec_list[] = {
|
||||
&mp_vd_lavc_vda,
|
||||
#endif
|
||||
#if HAVE_VAAPI_HWACCEL
|
||||
&mp_vd_lavc_vaapi,
|
||||
&mp_vd_lavc_vaapi_copy,
|
||||
&mp_vd_lavc_vaapi,
|
||||
#endif
|
||||
#if HAVE_DXVA2_HWACCEL
|
||||
&mp_vd_lavc_dxva2_copy,
|
||||
|
||||
@@ -163,6 +163,14 @@ static struct mp_image *render(struct vf_instance *vf, struct mp_image *in,
|
||||
status = vaMapBuffer(p->display, buffer, (void**)¶m);
|
||||
if (!check_error(vf, status, "vaMapBuffer()"))
|
||||
break;
|
||||
|
||||
VAProcFilterParameterBufferDeinterlacing *filter_params;
|
||||
status = vaMapBuffer(p->display, *(p->pipe.filters), (void**)&filter_params);
|
||||
if (!check_error(vf, status, "vaMapBuffer()"))
|
||||
break;
|
||||
filter_params->flags = flags & VA_TOP_FIELD ? 0 : VA_DEINTERLACING_BOTTOM_FIELD;
|
||||
vaUnmapBuffer(p->display, *(p->pipe.filters));
|
||||
|
||||
param->surface = in_id;
|
||||
param->surface_region = NULL;
|
||||
param->output_region = NULL;
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
- (void)setFullScreen:(BOOL)willBeFullscreen;
|
||||
- (void)clear;
|
||||
- (BOOL)canHideCursor;
|
||||
- (void)signalMousePosition;
|
||||
@end
|
||||
@@ -28,7 +28,6 @@
|
||||
@property(nonatomic, assign) BOOL clearing;
|
||||
@property(nonatomic, assign) BOOL hasMouseDown;
|
||||
@property(nonatomic, retain) NSTrackingArea *tracker;
|
||||
- (void)signalMousePosition;
|
||||
- (BOOL)hasDock:(NSScreen*)screen;
|
||||
- (BOOL)hasMenubar:(NSScreen*)screen;
|
||||
- (int)mpvButtonNumber:(NSEvent*)event;
|
||||
@@ -167,7 +166,8 @@
|
||||
|
||||
- (BOOL)canHideCursor
|
||||
{
|
||||
return !self.hasMouseDown && [self containsMouseLocation];
|
||||
return !self.hasMouseDown && [self containsMouseLocation]
|
||||
&& [[self window] isKeyWindow];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(NSEvent *)event
|
||||
@@ -207,6 +207,8 @@
|
||||
- (void)signalMousePosition
|
||||
{
|
||||
NSPoint p = [self convertPointToPixels:[self mouseLocation]];
|
||||
p.x = MIN(MAX(p.x, 0), self.bounds.size.width-1);
|
||||
p.y = MIN(MAX(p.y, 0), self.bounds.size.height-1);
|
||||
[self.adapter signalMouseMovement:p];
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "video/out/vo.h"
|
||||
|
||||
@interface MpvCocoaAdapter : NSObject
|
||||
@interface MpvCocoaAdapter : NSObject<NSWindowDelegate>
|
||||
- (void)setNeedsResize;
|
||||
- (void)signalMouseMovement:(NSPoint)point;
|
||||
- (void)putKeyEvent:(NSEvent*)event;
|
||||
@@ -28,6 +28,7 @@
|
||||
- (void)handleFilesArray:(NSArray *)files;
|
||||
- (void)didChangeWindowedScreenProfile:(NSScreen *)screen;
|
||||
- (void)performAsyncResize:(NSSize)size;
|
||||
- (void)didChangeMousePosition;
|
||||
|
||||
- (BOOL)isInFullScreenMode;
|
||||
- (BOOL)keyboardEnabled;
|
||||
|
||||
@@ -61,6 +61,16 @@
|
||||
[self.adapter didChangeWindowedScreenProfile:[self screen]];
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
[self.adapter windowDidResignKey:notification];
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
[self.adapter windowDidBecomeKey:notification];
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeMainWindow { return YES; }
|
||||
- (BOOL)canBecomeKeyWindow { return YES; }
|
||||
- (BOOL)windowShouldClose:(id)sender
|
||||
|
||||
+48
-37
@@ -52,12 +52,13 @@
|
||||
#define cocoa_unlock(s) pthread_mutex_unlock(&s->mutex)
|
||||
|
||||
static void vo_cocoa_fullscreen(struct vo *vo);
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo *vo);
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s);
|
||||
|
||||
struct vo_cocoa_state {
|
||||
NSWindow *window;
|
||||
NSView *view;
|
||||
MpvVideoView *video;
|
||||
MpvCocoaAdapter *adapter;
|
||||
NSOpenGLContext *gl_ctx;
|
||||
|
||||
NSScreen *current_screen;
|
||||
@@ -87,9 +88,8 @@ struct vo_cocoa_state {
|
||||
void (*resize_redraw)(struct vo *vo, int w, int h);
|
||||
};
|
||||
|
||||
static void with_cocoa_lock(struct vo *vo, void(^block)(void))
|
||||
static void with_cocoa_lock(struct vo_cocoa_state *s, void(^block)(void))
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
cocoa_lock(s);
|
||||
block();
|
||||
cocoa_unlock(s);
|
||||
@@ -97,8 +97,9 @@ static void with_cocoa_lock(struct vo *vo, void(^block)(void))
|
||||
|
||||
static void with_cocoa_lock_on_main_thread(struct vo *vo, void(^block)(void))
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
with_cocoa_lock(vo, block);
|
||||
with_cocoa_lock(s, block);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -111,17 +112,15 @@ static void queue_new_video_size(struct vo *vo, int w, int h)
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_power_management(struct vo *vo)
|
||||
static void enable_power_management(struct vo_cocoa_state *s)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
if (!s->power_mgmt_assertion) return;
|
||||
IOPMAssertionRelease(s->power_mgmt_assertion);
|
||||
s->power_mgmt_assertion = kIOPMNullAssertionID;
|
||||
}
|
||||
|
||||
static void disable_power_management(struct vo *vo)
|
||||
static void disable_power_management(struct vo_cocoa_state *s)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
if (s->power_mgmt_assertion) return;
|
||||
IOPMAssertionCreateWithName(
|
||||
kIOPMAssertionTypePreventUserIdleDisplaySleep,
|
||||
@@ -148,7 +147,7 @@ static void set_application_icon(NSApplication *app)
|
||||
|
||||
int vo_cocoa_init(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = talloc_zero(vo, struct vo_cocoa_state);
|
||||
struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state);
|
||||
*s = (struct vo_cocoa_state){
|
||||
.waiting_frame = false,
|
||||
.power_mgmt_assertion = kIOPMNullAssertionID,
|
||||
@@ -190,16 +189,10 @@ void vo_cocoa_register_resize_callback(struct vo *vo,
|
||||
void vo_cocoa_uninit(struct vo *vo)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
NSView *ev = s->view;
|
||||
|
||||
// keep the event view around for later in order to call -clear
|
||||
if (!s->embedded) {
|
||||
[ev retain];
|
||||
}
|
||||
|
||||
with_cocoa_lock_on_main_thread(vo, ^{
|
||||
enable_power_management(vo);
|
||||
cocoa_rm_fs_screen_profile_observer(vo);
|
||||
enable_power_management(s);
|
||||
cocoa_rm_fs_screen_profile_observer(s);
|
||||
|
||||
[s->gl_ctx release];
|
||||
|
||||
@@ -208,21 +201,15 @@ void vo_cocoa_uninit(struct vo *vo)
|
||||
[s->video removeFromSuperview];
|
||||
|
||||
[s->view removeFromSuperview];
|
||||
[(MpvEventsView *)s->view clear];
|
||||
[s->view release];
|
||||
|
||||
// if using --wid + libmpv there's no window to release
|
||||
if (s->window)
|
||||
[s->window release];
|
||||
});
|
||||
|
||||
// don't use the mutex, because at that point it could have been destroyed
|
||||
// and no one is accessing the events view anyway
|
||||
if (!s->embedded) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[(MpvEventsView *)ev clear];
|
||||
[ev release];
|
||||
});
|
||||
}
|
||||
talloc_free(s);
|
||||
});
|
||||
}
|
||||
|
||||
static int get_screen_handle(struct vo *vo, int identifier, NSWindow *window,
|
||||
@@ -279,6 +266,8 @@ static void vo_cocoa_update_screen_fps(struct vo *vo)
|
||||
s->screen_fps = (t.timeScale / (double) t.timeValue);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
|
||||
s->pending_events |= VO_EVENT_WIN_STATE;
|
||||
}
|
||||
|
||||
static void vo_cocoa_update_screen_info(struct vo *vo, struct mp_rect *out_rc)
|
||||
@@ -379,10 +368,9 @@ static void create_ui(struct vo *vo, struct mp_rect *win, int geo_flags)
|
||||
view.adapter = adapter;
|
||||
s->view = view;
|
||||
[parent addSubview:s->view];
|
||||
|
||||
// insert ourselves as the next key view so that clients can give key
|
||||
// focus to the mpv view by calling -[NSWindow selectNextKeyView:]
|
||||
[parent setNextKeyView:s->view];
|
||||
// update the cursor position now that the view has been added.
|
||||
[view signalMousePosition];
|
||||
s->adapter = adapter;
|
||||
|
||||
#if HAVE_COCOA_APPLICATION
|
||||
cocoa_register_menu_item_action(MPM_H_SIZE, @selector(halfSize));
|
||||
@@ -427,9 +415,8 @@ static int cocoa_set_window_title(struct vo *vo, const char *title)
|
||||
return VO_TRUE;
|
||||
}
|
||||
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo *vo)
|
||||
static void cocoa_rm_fs_screen_profile_observer(struct vo_cocoa_state *s)
|
||||
{
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
removeObserver:s->fs_icc_changed_ns_observer];
|
||||
}
|
||||
@@ -439,7 +426,7 @@ static void cocoa_add_fs_screen_profile_observer(struct vo *vo)
|
||||
struct vo_cocoa_state *s = vo->cocoa;
|
||||
|
||||
if (s->fs_icc_changed_ns_observer)
|
||||
cocoa_rm_fs_screen_profile_observer(vo);
|
||||
cocoa_rm_fs_screen_profile_observer(s);
|
||||
|
||||
if (vo->opts->fsscreen_id < 0)
|
||||
return;
|
||||
@@ -501,7 +488,7 @@ int vo_cocoa_config_window(struct vo *vo, uint32_t flags, void *gl_ctx)
|
||||
}
|
||||
|
||||
// trigger a resize -> don't set vo->dwidth and vo->dheight directly
|
||||
// since this block is executed asynchrolously to the video
|
||||
// since this block is executed asynchronously to the video
|
||||
// reconfiguration code.
|
||||
s->pending_events |= VO_EVENT_RESIZE;
|
||||
});
|
||||
@@ -612,6 +599,13 @@ static void vo_cocoa_fullscreen(struct vo *vo)
|
||||
draw_changes_after_next_frame(vo);
|
||||
[(MpvEventsView *)s->view setFullScreen:opts->fullscreen];
|
||||
|
||||
if ([s->view window] != s->window) {
|
||||
// cocoa implements fullscreen views by moving the view to a fullscreen
|
||||
// window. Set that window delegate to the cocoa adapter to trigger
|
||||
// calls to -windowDidResignKey: and -windowDidBecomeKey:
|
||||
[[s->view window] setDelegate:s->adapter];
|
||||
}
|
||||
|
||||
s->pending_events |= VO_EVENT_ICC_PROFILE_CHANGED;
|
||||
s->pending_events |= VO_EVENT_RESIZE;
|
||||
}
|
||||
@@ -645,7 +639,7 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
||||
return vo_cocoa_ontop(vo);
|
||||
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
|
||||
int *s = arg;
|
||||
with_cocoa_lock(vo, ^{
|
||||
with_cocoa_lock(vo->cocoa, ^{
|
||||
NSSize size = [vo->cocoa->view frame].size;
|
||||
s[0] = size.width;
|
||||
s[1] = size.height;
|
||||
@@ -667,10 +661,10 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
||||
case VOCTRL_UPDATE_WINDOW_TITLE:
|
||||
return cocoa_set_window_title(vo, (const char *) arg);
|
||||
case VOCTRL_RESTORE_SCREENSAVER:
|
||||
enable_power_management(vo);
|
||||
enable_power_management(vo->cocoa);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_KILL_SCREENSAVER:
|
||||
disable_power_management(vo);
|
||||
disable_power_management(vo->cocoa);
|
||||
return VO_TRUE;
|
||||
case VOCTRL_GET_ICC_PROFILE:
|
||||
vo_cocoa_control_get_icc_profile(vo, arg);
|
||||
@@ -769,4 +763,21 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
s->pending_events |= VO_EVENT_ICC_PROFILE_CHANGED;
|
||||
}
|
||||
|
||||
- (void)didChangeMousePosition
|
||||
{
|
||||
struct vo_cocoa_state *s = self.vout->cocoa;
|
||||
[(MpvEventsView *)s->view signalMousePosition];
|
||||
}
|
||||
|
||||
- (void)windowDidResignKey:(NSNotification *)notification
|
||||
{
|
||||
[self didChangeMousePosition];
|
||||
}
|
||||
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
[self didChangeMousePosition];
|
||||
}
|
||||
|
||||
@end
|
||||
+32
-33
@@ -467,9 +467,9 @@ void gl_video_set_debug(struct gl_video *p, bool enable)
|
||||
}
|
||||
|
||||
// Draw a textured quad.
|
||||
// x0, y0, x1, y1 = destination coordinates of the quad
|
||||
// tx0, ty0, tx1, ty1 = source texture coordinates (usually in pixels)
|
||||
// texture_w, texture_h = size of the texture, or an inverse factor
|
||||
// x0, y0, x1, y1 = destination coordinates of the quad in pixels
|
||||
// tx0, ty0, tx1, ty1 = source texture coordinates in pixels
|
||||
// tex_w, tex_h = size of the texture in pixels
|
||||
// flags = bits 0-1: rotate, bits 2: flip vertically
|
||||
static void draw_quad(struct gl_video *p,
|
||||
float x0, float y0, float x1, float y1,
|
||||
@@ -2086,20 +2086,26 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
|
||||
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
}
|
||||
|
||||
static bool test_fbo(struct gl_video *p, GLenum format)
|
||||
static bool test_fbo(struct gl_video *p, bool *success)
|
||||
{
|
||||
if (!*success)
|
||||
return false;
|
||||
|
||||
GL *gl = p->gl;
|
||||
bool success = false;
|
||||
*success = false;
|
||||
MP_VERBOSE(p, "Testing user-set FBO format (0x%x)\n",
|
||||
(unsigned)p->opts.fbo_format);
|
||||
struct fbotex fbo = {0};
|
||||
if (fbotex_init(&fbo, p->gl, p->log, 16, 16, p->gl_target, GL_LINEAR, format))
|
||||
if (fbotex_init(&fbo, p->gl, p->log, 16, 16, p->gl_target, GL_LINEAR,
|
||||
p->opts.fbo_format))
|
||||
{
|
||||
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo.fbo);
|
||||
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
success = true;
|
||||
*success = true;
|
||||
}
|
||||
fbotex_uninit(&fbo);
|
||||
glCheckError(gl, p->log, "FBO test");
|
||||
return success;
|
||||
return *success;
|
||||
}
|
||||
|
||||
// Disable features that are not supported with the current OpenGL version.
|
||||
@@ -2116,33 +2122,25 @@ static void check_gl_features(struct gl_video *p)
|
||||
char *disabled[10];
|
||||
int n_disabled = 0;
|
||||
|
||||
if (have_fbo) {
|
||||
MP_VERBOSE(p, "Testing user-set FBO format (0x%x)\n",
|
||||
(unsigned)p->opts.fbo_format);
|
||||
have_fbo = test_fbo(p, p->opts.fbo_format);
|
||||
}
|
||||
|
||||
// Normally, we want to disable them by default if FBOs are unavailable,
|
||||
// because they will be slow (not critically slow, but still slower).
|
||||
// Without FP textures, we must always disable them.
|
||||
// I don't know if luminance alpha float textures exist, so disregard them.
|
||||
if (!have_float_tex || !have_arrays || !have_fbo || !have_1d_tex) {
|
||||
for (int n = 0; n < 2; n++) {
|
||||
const struct filter_kernel *kernel = mp_find_filter_kernel(p->opts.scalers[n]);
|
||||
if (kernel) {
|
||||
char *reason = "";
|
||||
if (!have_fbo)
|
||||
reason = "scaler (FBO)";
|
||||
if (!have_float_tex)
|
||||
reason = "scaler (float tex.)";
|
||||
if (!have_arrays)
|
||||
reason = "scaler (no GLSL support)";
|
||||
if (!have_1d_tex && kernel->polar)
|
||||
reason = "scaler (1D tex.)";
|
||||
if (*reason) {
|
||||
p->opts.scalers[n] = "bilinear";
|
||||
disabled[n_disabled++] = reason;
|
||||
}
|
||||
for (int n = 0; n < 2; n++) {
|
||||
const struct filter_kernel *kernel = mp_find_filter_kernel(p->opts.scalers[n]);
|
||||
if (kernel) {
|
||||
char *reason = NULL;
|
||||
if (!test_fbo(p, &have_fbo))
|
||||
reason = "scaler (FBO)";
|
||||
if (!have_float_tex)
|
||||
reason = "scaler (float tex.)";
|
||||
if (!have_arrays)
|
||||
reason = "scaler (no GLSL support)";
|
||||
if (!have_1d_tex && kernel->polar)
|
||||
reason = "scaler (1D tex.)";
|
||||
if (reason) {
|
||||
p->opts.scalers[n] = "bilinear";
|
||||
disabled[n_disabled++] = reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2167,12 +2165,12 @@ static void check_gl_features(struct gl_video *p)
|
||||
p->opts.srgb = false;
|
||||
disabled[n_disabled++] = "sRGB output (GLSL version)";
|
||||
}
|
||||
if (!have_fbo && use_cms) {
|
||||
if (use_cms && !test_fbo(p, &have_fbo)) {
|
||||
p->opts.srgb = false;
|
||||
p->use_lut_3d = false;
|
||||
disabled[n_disabled++] = "color management (FBO)";
|
||||
}
|
||||
if (!have_fbo && p->opts.smoothmotion) {
|
||||
if (p->opts.smoothmotion && !test_fbo(p, &have_fbo)) {
|
||||
p->opts.smoothmotion = false;
|
||||
disabled[n_disabled++] = "smoothmotion (FBO)";
|
||||
}
|
||||
@@ -2232,6 +2230,7 @@ static int init_gl(struct gl_video *p)
|
||||
MP_VERBOSE(p, "16 bit texture depth: %d.\n", (int)param);
|
||||
p->texture_16bit_depth = param;
|
||||
}
|
||||
gl->DeleteTextures(1, &tex);
|
||||
}
|
||||
|
||||
debug_check_gl(p, "after init_gl");
|
||||
|
||||
+33
-13
@@ -129,7 +129,8 @@ struct vo_internal {
|
||||
bool paused;
|
||||
bool vsync_timed; // the VO redraws itself as fast as possible
|
||||
// at every vsync
|
||||
int queued_events;
|
||||
int queued_events; // event mask for the user
|
||||
int internal_events; // event mask for us
|
||||
|
||||
int64_t flip_queue_offset; // queue flip events at most this much in advance
|
||||
|
||||
@@ -145,8 +146,9 @@ struct vo_internal {
|
||||
int64_t frame_pts; // realtime of intended display
|
||||
int64_t frame_duration; // realtime frame duration (for framedrop)
|
||||
|
||||
// --- The following fields can be accessed from the VO thread only
|
||||
int64_t vsync_interval;
|
||||
|
||||
// --- The following fields can be accessed from the VO thread only
|
||||
int64_t vsync_interval_approx;
|
||||
int64_t last_flip;
|
||||
char *window_title;
|
||||
@@ -166,7 +168,7 @@ static bool get_desc(struct m_obj_desc *dst, int index)
|
||||
.priv_size = vo->priv_size,
|
||||
.priv_defaults = vo->priv_defaults,
|
||||
.options = vo->options,
|
||||
.hidden = vo->encode,
|
||||
.hidden = vo->encode || !strcmp(vo->name, "opengl-cb"),
|
||||
.p = vo,
|
||||
};
|
||||
return true;
|
||||
@@ -230,6 +232,7 @@ static struct vo *vo_create(bool probing, struct mpv_global *global,
|
||||
talloc_steal(vo, log);
|
||||
*vo->in = (struct vo_internal) {
|
||||
.dispatch = mp_dispatch_create(vo),
|
||||
.internal_events = VO_EVENT_WIN_STATE,
|
||||
};
|
||||
mp_make_wakeup_pipe(vo->in->wakeup_pipe);
|
||||
mp_dispatch_set_wakeup_fn(vo->in->dispatch, dispatch_wakeup_cb, vo);
|
||||
@@ -302,16 +305,27 @@ void vo_destroy(struct vo *vo)
|
||||
// to be called from VO thread only
|
||||
static void update_display_fps(struct vo *vo)
|
||||
{
|
||||
double display_fps = 1000.0; // assume infinite if unset
|
||||
if (vo->global->opts->frame_drop_fps > 0) {
|
||||
display_fps = vo->global->opts->frame_drop_fps;
|
||||
} else {
|
||||
vo->driver->control(vo, VOCTRL_GET_DISPLAY_FPS, &display_fps);
|
||||
struct vo_internal *in = vo->in;
|
||||
pthread_mutex_lock(&in->lock);
|
||||
if (in->internal_events & VO_EVENT_WIN_STATE) {
|
||||
in->internal_events &= ~(unsigned)VO_EVENT_WIN_STATE;
|
||||
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
|
||||
double display_fps = 1000.0; // assume infinite if unset
|
||||
if (vo->global->opts->frame_drop_fps > 0) {
|
||||
display_fps = vo->global->opts->frame_drop_fps;
|
||||
} else {
|
||||
vo->driver->control(vo, VOCTRL_GET_DISPLAY_FPS, &display_fps);
|
||||
}
|
||||
int64_t n_interval = MPMAX((int64_t)(1e6 / display_fps), 1);
|
||||
|
||||
pthread_mutex_lock(&in->lock);
|
||||
if (vo->in->vsync_interval != n_interval)
|
||||
MP_VERBOSE(vo, "Assuming %f FPS for framedrop.\n", display_fps);
|
||||
vo->in->vsync_interval = n_interval;
|
||||
}
|
||||
int64_t n_interval = MPMAX((int64_t)(1e6 / display_fps), 1);
|
||||
if (vo->in->vsync_interval != n_interval)
|
||||
MP_VERBOSE(vo, "Assuming %f FPS for framedrop.\n", display_fps);
|
||||
vo->in->vsync_interval = n_interval;
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
}
|
||||
|
||||
static void check_vo_caps(struct vo *vo)
|
||||
@@ -533,6 +547,7 @@ void vo_wait_frame(struct vo *vo)
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
}
|
||||
|
||||
// needs lock
|
||||
static int64_t prev_sync(struct vo *vo, int64_t ts)
|
||||
{
|
||||
struct vo_internal *in = vo->in;
|
||||
@@ -895,7 +910,11 @@ void vo_set_flip_queue_params(struct vo *vo, int64_t offset_us, bool vsync_timed
|
||||
|
||||
int64_t vo_get_vsync_interval(struct vo *vo)
|
||||
{
|
||||
return vo->in->vsync_interval;
|
||||
struct vo_internal *in = vo->in;
|
||||
pthread_mutex_lock(&in->lock);
|
||||
int64_t res = vo->in->vsync_interval;
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Set specific event flags, and wakeup the playback core if needed.
|
||||
@@ -907,6 +926,7 @@ void vo_event(struct vo *vo, int event)
|
||||
if ((in->queued_events & event & VO_EVENTS_USER) != (event & VO_EVENTS_USER))
|
||||
mp_input_wakeup(vo->input_ctx);
|
||||
in->queued_events |= event;
|
||||
in->internal_events |= event;
|
||||
pthread_mutex_unlock(&in->lock);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
#define VO_EVENT_RESIZE 2
|
||||
// The ICC profile needs to be reloaded
|
||||
#define VO_EVENT_ICC_PROFILE_CHANGED 4
|
||||
// Some other window state changed
|
||||
// Some other window state changed (position, window state, fps)
|
||||
#define VO_EVENT_WIN_STATE 8
|
||||
|
||||
// Set of events the player core may be interested in.
|
||||
|
||||
@@ -940,7 +940,7 @@ render_osd:
|
||||
// Return the high byte of the value that represents white in chroma (U/V)
|
||||
static int get_chroma_clear_val(int bit_depth)
|
||||
{
|
||||
return 1 << (bit_depth - 1 & 7);
|
||||
return 1 << ((bit_depth - 1) & 7);
|
||||
}
|
||||
|
||||
// this macro is supposed to work on all formats supported by 3D rendering, and
|
||||
|
||||
@@ -254,15 +254,17 @@ static bool get_and_update_icc_profile(struct gl_priv *p, int *events)
|
||||
{
|
||||
if (p->icc_opts->profile_auto) {
|
||||
MP_VERBOSE(p, "Querying ICC profile...\n");
|
||||
bstr icc;
|
||||
bstr icc = bstr0(NULL);
|
||||
int r = p->glctx->vo_control(p->vo, events, VOCTRL_GET_ICC_PROFILE, &icc);
|
||||
|
||||
if (r == VO_TRUE) {
|
||||
if (r != VO_NOTAVAIL) {
|
||||
if (r == VO_FALSE) {
|
||||
MP_WARN(p, "Could not retrieve an ICC profile.\n");
|
||||
} else if (r == VO_NOTIMPL) {
|
||||
MP_ERR(p, "icc-profile-auto not implemented on this platform.\n");
|
||||
}
|
||||
|
||||
gl_lcms_set_memory_profile(p->cms, &icc);
|
||||
} else if (r == VO_NOTIMPL) {
|
||||
MP_ERR(p, "icc-profile-auto not implemented on this platform.\n");
|
||||
} else {
|
||||
MP_ERR(p, "Could not retrieve an ICC profile.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -306,20 +306,20 @@ int mpv_opengl_cb_render(struct mpv_opengl_cb_context *ctx, int fbo, int vp[4])
|
||||
gl_video_resize(ctx->renderer, &wnd, &src, &dst, &osd, !ctx->flip);
|
||||
}
|
||||
|
||||
if (vo) {
|
||||
struct vo_priv *p = vo->priv;
|
||||
if (ctx->reconfigured)
|
||||
gl_video_config(ctx->renderer, &ctx->img_params);
|
||||
if (ctx->reconfigured || ctx->update_new_opts) {
|
||||
struct vo_priv *opts = p->ctx->new_opts ? p->ctx->new_opts : p;
|
||||
if (ctx->reconfigured)
|
||||
gl_video_config(ctx->renderer, &ctx->img_params);
|
||||
if (ctx->update_new_opts) {
|
||||
struct vo_priv *p = vo ? vo->priv : NULL;
|
||||
struct vo_priv *opts = ctx->new_opts ? ctx->new_opts : p;
|
||||
if (opts) {
|
||||
gl_video_set_options(ctx->renderer, opts->renderer_opts);
|
||||
ctx->gl->debug_context = opts->use_gl_debug;
|
||||
gl_video_set_debug(ctx->renderer, opts->use_gl_debug);
|
||||
frame_queue_shrink(ctx, opts->frame_queue_size);
|
||||
}
|
||||
ctx->reconfigured = false;
|
||||
ctx->update_new_opts = false;
|
||||
}
|
||||
ctx->reconfigured = false;
|
||||
ctx->update_new_opts = false;
|
||||
|
||||
struct mp_csp_equalizer *eq = gl_video_eq_ptr(ctx->renderer);
|
||||
if (ctx->eq_changed) {
|
||||
@@ -507,6 +507,7 @@ static void uninit(struct vo *vo)
|
||||
p->ctx->img_params = (struct mp_image_params){0};
|
||||
p->ctx->reconfigured = true;
|
||||
p->ctx->active = NULL;
|
||||
update(p);
|
||||
pthread_mutex_unlock(&p->ctx->lock);
|
||||
}
|
||||
|
||||
|
||||
+41
-14
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
@@ -100,6 +101,7 @@ struct priv {
|
||||
unsigned int *va_subpic_flags;
|
||||
int va_num_subpic_formats;
|
||||
VADisplayAttribute *va_display_attrs;
|
||||
int *mp_display_attr;
|
||||
int va_num_display_attrs;
|
||||
};
|
||||
|
||||
@@ -446,46 +448,70 @@ static int get_displayattribtype(const char *name)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static VADisplayAttribute *get_display_attribute(struct priv *p,
|
||||
const char *name)
|
||||
static int get_display_attribute(struct priv *p, const char *name)
|
||||
{
|
||||
int type = get_displayattribtype(name);
|
||||
for (int n = 0; n < p->va_num_display_attrs; n++) {
|
||||
VADisplayAttribute *attr = &p->va_display_attrs[n];
|
||||
if (attr->type == type)
|
||||
return attr;
|
||||
return n;
|
||||
}
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mp_eq_to_va(VADisplayAttribute * const attr, int mpvalue)
|
||||
{
|
||||
/* normalize to attribute value range */
|
||||
int r = attr->max_value - attr->min_value;
|
||||
if (r == 0)
|
||||
return INT_MIN; // assume INT_MIN is outside allowed min/max range
|
||||
return ((mpvalue + 100) * r + 100) / 200 + attr->min_value;
|
||||
}
|
||||
|
||||
static int get_equalizer(struct priv *p, const char *name, int *value)
|
||||
{
|
||||
VADisplayAttribute * const attr = get_display_attribute(p, name);
|
||||
int index = get_display_attribute(p, name);
|
||||
if (index < 0)
|
||||
return VO_NOTIMPL;
|
||||
|
||||
if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_GETTABLE))
|
||||
VADisplayAttribute *attr = &p->va_display_attrs[index];
|
||||
|
||||
if (!(attr->flags & VA_DISPLAY_ATTRIB_GETTABLE))
|
||||
return VO_NOTIMPL;
|
||||
|
||||
/* normalize to -100 .. 100 range */
|
||||
int r = attr->max_value - attr->min_value;
|
||||
if (r == 0)
|
||||
return VO_NOTIMPL;
|
||||
*value = ((attr->value - attr->min_value) * 200) / r - 100;
|
||||
|
||||
*value = ((attr->value - attr->min_value) * 200 + r / 2) / r - 100;
|
||||
if (mp_eq_to_va(attr, p->mp_display_attr[index]) == attr->value)
|
||||
*value = p->mp_display_attr[index];
|
||||
|
||||
return VO_TRUE;
|
||||
}
|
||||
|
||||
static int set_equalizer(struct priv *p, const char *name, int value)
|
||||
{
|
||||
VADisplayAttribute * const attr = get_display_attribute(p, name);
|
||||
VAStatus status;
|
||||
|
||||
if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_SETTABLE))
|
||||
int index = get_display_attribute(p, name);
|
||||
if (index < 0)
|
||||
return VO_NOTIMPL;
|
||||
|
||||
/* normalize to attribute value range */
|
||||
int r = attr->max_value - attr->min_value;
|
||||
if (r == 0)
|
||||
VADisplayAttribute *attr = &p->va_display_attrs[index];
|
||||
|
||||
if (!(attr->flags & VA_DISPLAY_ATTRIB_SETTABLE))
|
||||
return VO_NOTIMPL;
|
||||
attr->value = ((value + 100) * r) / 200 + attr->min_value;
|
||||
|
||||
int r = mp_eq_to_va(attr, value);
|
||||
if (r == INT_MIN)
|
||||
return VO_NOTIMPL;
|
||||
|
||||
attr->value = r;
|
||||
p->mp_display_attr[index] = value;
|
||||
|
||||
MP_VERBOSE(p, "Changing '%s' (range [%d, %d]) to %d\n", name,
|
||||
attr->max_value, attr->min_value, attr->value);
|
||||
|
||||
va_lock(p->mpvaapi);
|
||||
status = vaSetDisplayAttributes(p->display, attr, 1);
|
||||
@@ -642,6 +668,7 @@ static int preinit(struct vo *vo)
|
||||
&p->va_num_display_attrs);
|
||||
if (!CHECK_VA_STATUS(p, "vaQueryDisplayAttributes()"))
|
||||
p->va_num_display_attrs = 0;
|
||||
p->mp_display_attr = talloc_zero_array(vo, int, p->va_num_display_attrs);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -382,6 +382,8 @@ static void xv_draw_colorkey(struct vo *vo, const struct mp_rect *rc)
|
||||
if (ctx->xv_ck_info.method == CK_METHOD_MANUALFILL ||
|
||||
ctx->xv_ck_info.method == CK_METHOD_BACKGROUND)
|
||||
{
|
||||
if (!x11->vo_gc)
|
||||
return;
|
||||
//less tearing than XClearWindow()
|
||||
XSetForeground(x11->display, x11->vo_gc, ctx->xv_colorkey);
|
||||
XFillRectangle(x11->display, x11->window, x11->vo_gc, rc->x0, rc->y0,
|
||||
|
||||
+10
-17
@@ -98,6 +98,9 @@ struct vo_w32_state {
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
|
||||
// Should SetCursor be called when handling VOCTRL_SET_CURSOR_VISIBILITY?
|
||||
bool can_set_cursor;
|
||||
|
||||
// UTF-16 decoding state for WM_CHAR and VK_PACKET
|
||||
int high_surrogate;
|
||||
|
||||
@@ -312,16 +315,9 @@ static void subtract_window_borders(HWND hwnd, RECT *rc)
|
||||
rc->bottom -= b.bottom;
|
||||
}
|
||||
|
||||
static bool is_maximized(struct vo_w32_state *w32)
|
||||
{
|
||||
WINDOWPLACEMENT wp = { .length = sizeof(WINDOWPLACEMENT) };
|
||||
GetWindowPlacement(w32->window, &wp);
|
||||
return wp.showCmd == SW_SHOWMAXIMIZED;
|
||||
}
|
||||
|
||||
static LRESULT borderless_nchittest(struct vo_w32_state *w32, int x, int y)
|
||||
{
|
||||
if (is_maximized(w32))
|
||||
if (IsMaximized(w32->window))
|
||||
return HTCLIENT;
|
||||
|
||||
POINT mouse = { x, y };
|
||||
@@ -403,7 +399,7 @@ static int mod_state(struct vo_w32_state *w32)
|
||||
|
||||
static int decode_surrogate_pair(wchar_t lead, wchar_t trail)
|
||||
{
|
||||
return 0x10000 + ((lead & 0x3ff) << 10) | (trail & 0x3ff);
|
||||
return 0x10000 + (((lead & 0x3ff) << 10) | (trail & 0x3ff));
|
||||
}
|
||||
|
||||
static int decode_utf16(struct vo_w32_state *w32, wchar_t c)
|
||||
@@ -686,7 +682,10 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
mp_input_put_key(w32->input_ctx, MP_INPUT_RELEASE_ALL);
|
||||
break;
|
||||
case WM_SETCURSOR:
|
||||
if (LOWORD(lParam) == HTCLIENT && !w32->cursor_visible) {
|
||||
// The cursor should only be hidden if the mouse is in the client area
|
||||
// and if the window isn't in menu mode (HIWORD(lParam) is non-zero)
|
||||
w32->can_set_cursor = LOWORD(lParam) == HTCLIENT && HIWORD(lParam);
|
||||
if (w32->can_set_cursor && !w32->cursor_visible) {
|
||||
SetCursor(NULL);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1206,12 +1205,6 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool vo_w32_is_cursor_in_client(struct vo_w32_state *w32)
|
||||
{
|
||||
DWORD pos = GetMessagePos();
|
||||
return SendMessage(w32->window, WM_NCHITTEST, 0, pos) == HTCLIENT;
|
||||
}
|
||||
|
||||
static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
|
||||
{
|
||||
switch (request) {
|
||||
@@ -1257,7 +1250,7 @@ static int gui_thread_control(struct vo_w32_state *w32, int request, void *arg)
|
||||
case VOCTRL_SET_CURSOR_VISIBILITY:
|
||||
w32->cursor_visible = *(bool *)arg;
|
||||
|
||||
if (vo_w32_is_cursor_in_client(w32)) {
|
||||
if (w32->can_set_cursor && w32->tracking) {
|
||||
if (w32->cursor_visible)
|
||||
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
||||
else
|
||||
|
||||
@@ -931,6 +931,8 @@ int vo_x11_check_events(struct vo *vo)
|
||||
x11->win_drag_button1_down = false;
|
||||
break;
|
||||
case LeaveNotify:
|
||||
if (Event.xcrossing.mode != NotifyNormal)
|
||||
break;
|
||||
x11->win_drag_button1_down = false;
|
||||
mp_input_put_key(vo->input_ctx, MP_KEY_MOUSE_LEAVE);
|
||||
break;
|
||||
@@ -1672,6 +1674,7 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg)
|
||||
case VOCTRL_GET_WIN_STATE: {
|
||||
if (!x11->pseudo_mapped)
|
||||
return VO_FALSE;
|
||||
*(int *)arg = 0;
|
||||
int num_elems;
|
||||
long *elems = x11_get_property(x11, x11->window, XA(x11, _NET_WM_STATE),
|
||||
XA_ATOM, 32, &num_elems);
|
||||
@@ -1700,6 +1703,8 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg)
|
||||
return VO_TRUE;
|
||||
}
|
||||
case VOCTRL_GET_ICC_PROFILE: {
|
||||
if (!x11->pseudo_mapped)
|
||||
return VO_NOTAVAIL;
|
||||
int screen = 0; // xinerama screen number
|
||||
for (int n = 0; n < x11->num_displays; n++) {
|
||||
struct xrandr_display *disp = &x11->displays[n];
|
||||
@@ -1714,6 +1719,7 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg)
|
||||
mp_snprintf_cat(prop, sizeof(prop), "_%d", screen);
|
||||
x11->icc_profile_property = XAs(x11, prop);
|
||||
int len;
|
||||
MP_VERBOSE(x11, "Retrieving ICC profile for display: %d\n", screen);
|
||||
void *icc = x11_get_property(x11, x11->rootwin, x11->icc_profile_property,
|
||||
XA_CARDINAL, 8, &len);
|
||||
if (!icc)
|
||||
|
||||
+9
-3
@@ -238,9 +238,11 @@ int mp_sws_reinit(struct mp_sws_context *ctx)
|
||||
|
||||
// This can fail even with normal operation, e.g. if a conversion path
|
||||
// simply does not support these settings.
|
||||
sws_setColorspaceDetails(ctx->sws, sws_getCoefficients(s_csp), s_range,
|
||||
sws_getCoefficients(d_csp), d_range,
|
||||
ctx->brightness, ctx->contrast, ctx->saturation);
|
||||
int r =
|
||||
sws_setColorspaceDetails(ctx->sws, sws_getCoefficients(s_csp), s_range,
|
||||
sws_getCoefficients(d_csp), d_range,
|
||||
ctx->brightness, ctx->contrast, ctx->saturation);
|
||||
ctx->supports_csp = r >= 0;
|
||||
|
||||
if (sws_init_context(ctx->sws, ctx->src_filter, ctx->dst_filter) < 0)
|
||||
return -1;
|
||||
@@ -294,6 +296,8 @@ int mp_image_sw_blur_scale(struct mp_image *dst, struct mp_image *src,
|
||||
|
||||
int mp_sws_get_vf_equalizer(struct mp_sws_context *sws, struct vf_seteq *eq)
|
||||
{
|
||||
if (!sws->supports_csp)
|
||||
return 0;
|
||||
if (!strcmp(eq->item, "brightness"))
|
||||
eq->value = ((sws->brightness * 100) + (1 << 15)) >> 16;
|
||||
else if (!strcmp(eq->item, "contrast"))
|
||||
@@ -307,6 +311,8 @@ int mp_sws_get_vf_equalizer(struct mp_sws_context *sws, struct vf_seteq *eq)
|
||||
|
||||
int mp_sws_set_vf_equalizer(struct mp_sws_context *sws, struct vf_seteq *eq)
|
||||
{
|
||||
if (!sws->supports_csp)
|
||||
return 0;
|
||||
if (!strcmp(eq->item, "brightness"))
|
||||
sws->brightness = ((eq->value << 16) + 50) / 100;
|
||||
else if (!strcmp(eq->item, "contrast"))
|
||||
|
||||
@@ -44,6 +44,7 @@ struct mp_sws_context {
|
||||
|
||||
// Cached context (if any)
|
||||
struct SwsContext *sws;
|
||||
bool supports_csp;
|
||||
|
||||
// Contains parameters for which sws is valid
|
||||
struct mp_sws_context *cached;
|
||||
|
||||
@@ -109,7 +109,7 @@ def check_pkg_config(*args, **kw_ext):
|
||||
return result
|
||||
return fn
|
||||
|
||||
def check_headers(*headers):
|
||||
def check_headers(*headers, **kw_ext):
|
||||
def undef_others(ctx, headers, found):
|
||||
not_found_hs = set(headers) - set([found])
|
||||
for not_found_h in not_found_hs:
|
||||
@@ -119,7 +119,7 @@ def check_headers(*headers):
|
||||
def fn(ctx, dependency_identifier):
|
||||
for header in headers:
|
||||
defaults = {'header_name': header, 'features': 'c cprogram'}
|
||||
options = __merge_options__(dependency_identifier, defaults)
|
||||
options = __merge_options__(dependency_identifier, defaults, kw_ext)
|
||||
if ctx.check(**options):
|
||||
undef_others(ctx, headers, header)
|
||||
defkey = DependencyInflector(dependency_identifier).define_key()
|
||||
|
||||
@@ -84,6 +84,7 @@ build_options = [
|
||||
'name': '--test',
|
||||
'desc': 'test suite (using cmocka)',
|
||||
'func': check_pkg_config('cmocka >= 0.4.1'),
|
||||
'default': 'disable',
|
||||
}, {
|
||||
'name': '--clang-database',
|
||||
'desc': 'generate a clang compilation database',
|
||||
@@ -691,7 +692,7 @@ hwaccel_features = [
|
||||
'name': '--vaapi-hwaccel',
|
||||
'desc': 'libavcodec VAAPI hwaccel',
|
||||
'deps': [ 'vaapi' ],
|
||||
'func': check_true,
|
||||
'func': check_headers('libavcodec/vaapi.h', use='libav'),
|
||||
} , {
|
||||
'name': '--vda-hwaccel',
|
||||
'desc': 'libavcodec VDA hwaccel',
|
||||
@@ -710,12 +711,14 @@ hwaccel_features = [
|
||||
'name': '--vdpau-hwaccel',
|
||||
'desc': 'libavcodec VDPAU hwaccel',
|
||||
'deps': [ 'vdpau' ],
|
||||
'func': check_true,
|
||||
'func': check_statement('libavcodec/vdpau.h',
|
||||
'av_vdpau_alloc_context()',
|
||||
use='libav'),
|
||||
}, {
|
||||
'name': '--dxva2-hwaccel',
|
||||
'desc': 'libavcodec DXVA2 hwaccel',
|
||||
'deps': [ 'gdi' ],
|
||||
'func': check_true,
|
||||
'func': check_headers('libavcodec/dxva2.h', use='libav'),
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
Reference in new issue
Block a user