summaryrefslogtreecommitdiffstats
path: root/mpvcore
diff options
context:
space:
mode:
Diffstat (limited to 'mpvcore')
-rw-r--r--mpvcore/player/audio.c471
-rw-r--r--mpvcore/player/command.c3243
-rw-r--r--mpvcore/player/command.h50
-rw-r--r--mpvcore/player/configfiles.c354
-rw-r--r--mpvcore/player/dvdnav.c251
-rw-r--r--mpvcore/player/loadfile.c1423
-rw-r--r--mpvcore/player/lua/assdraw.lua98
-rw-r--r--mpvcore/player/lua/defaults.lua82
-rw-r--r--mpvcore/player/lua/osc.lua1288
-rw-r--r--mpvcore/player/main.c450
-rw-r--r--mpvcore/player/misc.c210
-rw-r--r--mpvcore/player/mp_core.h459
-rw-r--r--mpvcore/player/mp_lua.c683
-rw-r--r--mpvcore/player/mp_lua.h14
-rw-r--r--mpvcore/player/osd.c518
-rw-r--r--mpvcore/player/playloop.c1343
-rw-r--r--mpvcore/player/screenshot.c404
-rw-r--r--mpvcore/player/screenshot.h46
-rw-r--r--mpvcore/player/sub.c233
-rw-r--r--mpvcore/player/timeline/tl_cue.c417
-rw-r--r--mpvcore/player/timeline/tl_matroska.c591
-rw-r--r--mpvcore/player/timeline/tl_mpv_edl.c274
-rw-r--r--mpvcore/player/video.c422
23 files changed, 0 insertions, 13324 deletions
diff --git a/mpvcore/player/audio.c b/mpvcore/player/audio.c
deleted file mode 100644
index ec2f039531..0000000000
--- a/mpvcore/player/audio.c
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stddef.h>
-#include <stdbool.h>
-#include <inttypes.h>
-#include <math.h>
-#include <assert.h>
-
-#include "config.h"
-#include "talloc.h"
-
-#include "mpvcore/mp_msg.h"
-#include "mpvcore/options.h"
-#include "mpvcore/mp_common.h"
-
-#include "audio/mixer.h"
-#include "audio/audio.h"
-#include "audio/audio_buffer.h"
-#include "audio/decode/dec_audio.h"
-#include "audio/filter/af.h"
-#include "audio/out/ao.h"
-#include "demux/demux.h"
-#include "video/decode/dec_video.h"
-
-#include "mp_core.h"
-
-static int build_afilter_chain(struct MPContext *mpctx)
-{
- struct dec_audio *d_audio = mpctx->d_audio;
- struct ao *ao = mpctx->ao;
- struct MPOpts *opts = mpctx->opts;
-
- if (!d_audio)
- return 0;
-
- struct mp_audio in_format;
- mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format);
-
- int new_srate;
- if (af_control_any_rev(d_audio->afilter, AF_CONTROL_SET_PLAYBACK_SPEED,
- &opts->playback_speed))
- new_srate = in_format.rate;
- else {
- new_srate = in_format.rate * opts->playback_speed;
- if (new_srate != ao->samplerate) {
- // limits are taken from libaf/af_resample.c
- if (new_srate < 8000)
- new_srate = 8000;
- if (new_srate > 192000)
- new_srate = 192000;
- opts->playback_speed = new_srate / (double)in_format.rate;
- }
- }
- return audio_init_filters(d_audio, new_srate,
- &ao->samplerate, &ao->channels, &ao->format);
-}
-
-static int recreate_audio_filters(struct MPContext *mpctx)
-{
- assert(mpctx->d_audio);
-
- // init audio filters:
- if (!build_afilter_chain(mpctx)) {
- MP_ERR(mpctx, "Couldn't find matching filter/ao format!\n");
- return -1;
- }
-
- mixer_reinit_audio(mpctx->mixer, mpctx->ao, mpctx->d_audio->afilter);
-
- return 0;
-}
-
-int reinit_audio_filters(struct MPContext *mpctx)
-{
- struct dec_audio *d_audio = mpctx->d_audio;
- if (!d_audio)
- return -2;
-
- af_uninit(mpctx->d_audio->afilter);
- if (af_init(mpctx->d_audio->afilter) < 0)
- return -1;
- if (recreate_audio_filters(mpctx) < 0)
- return -1;
-
- return 0;
-}
-
-void reinit_audio_chain(struct MPContext *mpctx)
-{
- struct MPOpts *opts = mpctx->opts;
- struct sh_stream *sh = init_demux_stream(mpctx, STREAM_AUDIO);
- if (!sh) {
- uninit_player(mpctx, INITIALIZED_AO);
- goto no_audio;
- }
-
- if (!(mpctx->initialized_flags & INITIALIZED_ACODEC)) {
- mpctx->initialized_flags |= INITIALIZED_ACODEC;
- assert(!mpctx->d_audio);
- mpctx->d_audio = talloc_zero(NULL, struct dec_audio);
- mpctx->d_audio->opts = opts;
- mpctx->d_audio->header = sh;
- if (!audio_init_best_codec(mpctx->d_audio, opts->audio_decoders))
- goto init_error;
- }
- assert(mpctx->d_audio);
-
- struct mp_audio in_format;
- mp_audio_buffer_get_format(mpctx->d_audio->decode_buffer, &in_format);
-
- int ao_srate = opts->force_srate;
- int ao_format = opts->audio_output_format;
- struct mp_chmap ao_channels = {0};
- if (mpctx->initialized_flags & INITIALIZED_AO) {
- ao_srate = mpctx->ao->samplerate;
- ao_format = mpctx->ao->format;
- ao_channels = mpctx->ao->channels;
- } else {
- // Automatic downmix
- if (mp_chmap_is_stereo(&opts->audio_output_channels) &&
- !mp_chmap_is_stereo(&in_format.channels))
- {
- mp_chmap_from_channels(&ao_channels, 2);
- }
- }
-
- // Determine what the filter chain outputs. build_afilter_chain() also
- // needs this for testing whether playback speed is changed by resampling
- // or using a special filter.
- if (!audio_init_filters(mpctx->d_audio, // preliminary init
- // input:
- in_format.rate,
- // output:
- &ao_srate, &ao_channels, &ao_format)) {
- MP_ERR(mpctx, "Error at audio filter chain pre-init!\n");
- goto init_error;
- }
-
- if (!(mpctx->initialized_flags & INITIALIZED_AO)) {
- mpctx->initialized_flags |= INITIALIZED_AO;
- mp_chmap_remove_useless_channels(&ao_channels,
- &opts->audio_output_channels);
- mpctx->ao = ao_init_best(mpctx->global, mpctx->input,
- mpctx->encode_lavc_ctx, ao_srate, ao_format,
- ao_channels);
- struct ao *ao = mpctx->ao;
- if (!ao) {
- MP_ERR(mpctx, "Could not open/initialize audio device -> no sound.\n");
- goto init_error;
- }
-
- ao->buffer = mp_audio_buffer_create(ao);
- mp_audio_buffer_reinit_fmt(ao->buffer, ao->format, &ao->channels,
- ao->samplerate);
-
- char *s = mp_audio_fmt_to_str(ao->samplerate, &ao->channels, ao->format);
- MP_INFO(mpctx, "AO: [%s] %s\n", ao->driver->name, s);
- talloc_free(s);
- MP_VERBOSE(mpctx, "AO: Description: %s\n", ao->driver->description);
- update_window_title(mpctx, true);
- }
-
- if (recreate_audio_filters(mpctx) < 0)
- goto init_error;
-
- mpctx->syncing_audio = true;
- return;
-
-init_error:
- uninit_player(mpctx, INITIALIZED_ACODEC | INITIALIZED_AO);
- cleanup_demux_stream(mpctx, STREAM_AUDIO);
-no_audio:
- mpctx->current_track[STREAM_AUDIO] = NULL;
- MP_INFO(mpctx, "Audio: no audio\n");
-}
-
-// Return pts value corresponding to the end point of audio written to the
-// ao so far.
-double written_audio_pts(struct MPContext *mpctx)
-{
- struct dec_audio *d_audio = mpctx->d_audio;
- if (!d_audio)
- return MP_NOPTS_VALUE;
-
- struct mp_audio in_format;
- mp_audio_buffer_get_format(d_audio->decode_buffer, &in_format);
-
- // first calculate the end pts of audio that has been output by decoder
- double a_pts = d_audio->pts;
- if (a_pts == MP_NOPTS_VALUE)
- return MP_NOPTS_VALUE;
-
- // d_audio->pts is the timestamp of the latest input packet with
- // known pts that the decoder has decoded. d_audio->pts_bytes is
- // the amount of bytes the decoder has written after that timestamp.
- a_pts += d_audio->pts_offset / (double)in_format.rate;
-
- // Now a_pts hopefully holds the pts for end of audio from decoder.
- // Subtract data in buffers between decoder and audio out.
-
- // Decoded but not filtered
- a_pts -= mp_audio_buffer_seconds(d_audio->decode_buffer);
-
- // Data buffered in audio filters, measured in seconds of "missing" output
- double buffered_output = af_calc_delay(d_audio->afilter);
-
- // Data that was ready for ao but was buffered because ao didn't fully
- // accept everything to internal buffers yet
- buffered_output += mp_audio_buffer_seconds(mpctx->ao->buffer);
-
- // Filters divide audio length by playback_speed, so multiply by it
- // to get the length in original units without speedup or slowdown
- a_pts -= buffered_output * mpctx->opts->playback_speed;
-
- return a_pts + mpctx->video_offset;
-}
-
-// Return pts value corresponding to currently playing audio.
-double playing_audio_pts(struct MPContext *mpctx)
-{
- double pts = written_audio_pts(mpctx);
- if (pts == MP_NOPTS_VALUE)
- return pts;
- return pts - mpctx->opts->playback_speed * ao_get_delay(mpctx->ao);
-}
-
-static int write_to_ao(struct MPContext *mpctx, struct mp_audio *data, int flags,
- double pts)
-{
- if (mpctx->paused)
- return 0;
- struct ao *ao = mpctx->ao;
- ao->pts = pts;
- double real_samplerate = ao->samplerate / mpctx->opts->playback_speed;
- int played = ao_play(mpctx->ao, data->planes, data->samples, flags);
- assert(played <= data->samples);
- if (played > 0) {
- mpctx->shown_aframes += played;
- mpctx->delay += played / real_samplerate;
- // Keep correct pts for remaining data - could be used to flush
- // remaining buffer when closing ao.
- ao->pts += played / real_samplerate;
- return played;
- }
- return 0;
-}
-
-static int write_silence_to_ao(struct MPContext *mpctx, int samples, int flags,
- double pts)
-{
- struct mp_audio tmp = {0};
- mp_audio_buffer_get_format(mpctx->ao->buffer, &tmp);
- tmp.samples = samples;
- char *p = talloc_size(NULL, tmp.samples * tmp.sstride);
- for (int n = 0; n < tmp.num_planes; n++)
- tmp.planes[n] = p;
- mp_audio_fill_silence(&tmp, 0, tmp.samples);
- int r = write_to_ao(mpctx, &tmp, 0, pts);
- talloc_free(p);
- return r;
-}
-
-#define ASYNC_PLAY_DONE -3
-static int audio_start_sync(struct MPContext *mpctx, int playsize)
-{
- struct ao *ao = mpctx->ao;
- struct MPOpts *opts = mpctx->opts;
- struct dec_audio *d_audio = mpctx->d_audio;
- int res;
-
- assert(d_audio);
-
- // Timing info may not be set without
- res = audio_decode(d_audio, ao->buffer, 1);
- if (res < 0)
- return res;
-
- int samples;
- bool did_retry = false;
- double written_pts;
- double real_samplerate = ao->samplerate / opts->playback_speed;
- bool hrseek = mpctx->hrseek_active; // audio only hrseek
- mpctx->hrseek_active = false;
- while (1) {
- written_pts = written_audio_pts(mpctx);
- double ptsdiff;
- if (hrseek)
- ptsdiff = written_pts - mpctx->hrseek_pts;
- else
- ptsdiff = written_pts - mpctx->video_next_pts - mpctx->delay
- - mpctx->audio_delay;
- samples = ptsdiff * real_samplerate;
-
- // ogg demuxers give packets without timing
- if (written_pts <= 1 && d_audio->pts == MP_NOPTS_VALUE) {
- if (!did_retry) {
- // Try to read more data to see packets that have pts
- res = audio_decode(d_audio, ao->buffer, ao->samplerate);
- if (res < 0)
- return res;
- did_retry = true;
- continue;
- }
- samples = 0;
- }
-
- if (fabs(ptsdiff) > 300 || isnan(ptsdiff)) // pts reset or just broken?
- samples = 0;
-
- if (samples > 0)
- break;
-
- mpctx->syncing_audio = false;
- int skip_samples = -samples;
- int a = MPMIN(skip_samples, MPMAX(playsize, 2500));
- res = audio_decode(d_audio, ao->buffer, a);
- if (skip_samples <= mp_audio_buffer_samples(ao->buffer)) {
- mp_audio_buffer_skip(ao->buffer, skip_samples);
- if (res < 0)
- return res;
- return audio_decode(d_audio, ao->buffer, playsize);
- }
- mp_audio_buffer_clear(ao->buffer);
- if (res < 0)
- return res;
- }
- if (hrseek)
- // Don't add silence in audio-only case even if position is too late
- return 0;
- if (samples >= playsize) {
- /* This case could fall back to the one below with
- * samples = playsize, but then silence would keep accumulating
- * in ao->buffer if the AO accepts less data than it asks for
- * in playsize. */
- write_silence_to_ao(mpctx, playsize, 0,
- written_pts - samples / real_samplerate);
- return ASYNC_PLAY_DONE;
- }
- mpctx->syncing_audio = false;
- mp_audio_buffer_prepend_silence(ao->buffer, samples);
- return audio_decode(d_audio, ao->buffer, playsize);
-}
-
-int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
-{
- struct MPOpts *opts = mpctx->opts;
- struct ao *ao = mpctx->ao;
- int playsize;
- int playflags = 0;
- bool audio_eof = false;
- bool signal_eof = false;
- bool partial_fill = false;
- struct dec_audio *d_audio = mpctx->d_audio;
- // Can't adjust the start of audio with spdif pass-through.
- bool modifiable_audio_format = !(ao->format & AF_FORMAT_SPECIAL_MASK);
-
- assert(d_audio);
-
- if (mpctx->paused)
- playsize = 1; // just initialize things (audio pts at least)
- else
- playsize = ao_get_space(ao);
-
- // Coming here with hrseek_active still set means audio-only
- if (!mpctx->d_video || !mpctx->sync_audio_to_video)
- mpctx->syncing_audio = false;
- if (!opts->initial_audio_sync || !modifiable_audio_format) {
- mpctx->syncing_audio = false;
- mpctx->hrseek_active = false;
- }
-
- int res;
- if (mpctx->syncing_audio || mpctx->hrseek_active)
- res = audio_start_sync(mpctx, playsize);
- else
- res = audio_decode(d_audio, ao->buffer, playsize);
-
- if (res < 0) { // EOF, error or format change
- if (res == -2) {
- /* The format change isn't handled too gracefully. A more precise
- * implementation would require draining buffered old-format audio
- * while displaying video, then doing the output format switch.
- */
- if (!mpctx->opts->gapless_audio)
- uninit_player(mpctx, INITIALIZED_AO);
- reinit_audio_chain(mpctx);
- return -1;
- } else if (res == ASYNC_PLAY_DONE)
- return 0;
- else if (demux_stream_eof(d_audio->header))
- audio_eof = true;
- }
-
- if (endpts != MP_NOPTS_VALUE) {
- double samples = (endpts - written_audio_pts(mpctx) + mpctx->audio_delay)
- * ao->samplerate / opts->playback_speed;
- if (playsize > samples) {
- playsize = MPMAX(samples, 0);
- audio_eof = true;
- partial_fill = true;
- }
- }
-
- if (playsize > mp_audio_buffer_samples(ao->buffer)) {
- playsize = mp_audio_buffer_samples(ao->buffer);
- partial_fill = true;
- }
- if (!playsize)
- return partial_fill && audio_eof ? -2 : -partial_fill;
-
- if (audio_eof && partial_fill) {
- if (opts->gapless_audio) {
- // With gapless audio, delay this to ao_uninit. There must be only
- // 1 final chunk, and that is handled when calling ao_uninit().
- signal_eof = true;
- } else {
- playflags |= AOPLAY_FINAL_CHUNK;
- }
- }
-
- assert(ao->buffer_playable_samples <= mp_audio_buffer_samples(ao->buffer));
-
- struct mp_audio data;
- mp_audio_buffer_peek(ao->buffer, &data);
- data.samples = MPMIN(data.samples, playsize);
- int played = write_to_ao(mpctx, &data, playflags, written_audio_pts(mpctx));
- ao->buffer_playable_samples = playsize - played;
-
- if (played > 0) {
- mp_audio_buffer_skip(ao->buffer, played);
- } else if (!mpctx->paused && audio_eof && ao_get_delay(ao) < .04) {
- // Sanity check to avoid hanging in case current ao doesn't output
- // partial chunks and doesn't check for AOPLAY_FINAL_CHUNK
- signal_eof = true;
- }
-
- return signal_eof ? -2 : -partial_fill;
-}
-
-// Drop data queued for output, or which the AO is currently outputting.
-void clear_audio_output_buffers(struct MPContext *mpctx)
-{
- if (mpctx->ao) {
- ao_reset(mpctx->ao);
- mp_audio_buffer_clear(mpctx->ao->buffer);
- mpctx->ao->buffer_playable_samples = 0;
- }
-}
-
-// Drop decoded data queued for filtering.
-void clear_audio_decode_buffers(struct MPContext *mpctx)
-{
- if (mpctx->d_audio)
- mp_audio_buffer_clear(mpctx->d_audio->decode_buffer);
-}
diff --git a/mpvcore/player/command.c b/mpvcore/player/command.c
deleted file mode 100644
index 10dfb4c261..0000000000
--- a/mpvcore/player/command.c
+++ /dev/null
@@ -1,3243 +0,0 @@
-/*
- * This file is part of MPlayer.
- *
- * MPlayer is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * MPlayer is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with MPlayer; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdlib.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdbool.h>
-#include <assert.h>
-#include <time.h>
-#include <sys/types.h>
-
-#include <libavutil/avstring.h>
-#include <libavutil/common.h>
-
-#include "config.h"
-#include "talloc.h"
-#include "command.h"
-#include "osdep/timer.h"
-#include "mpvcore/mp_common.h"
-#include "mpvcore/input/input.h"
-#include "stream/stream.h"
-#include "demux/demux.h"
-#include "demux/stheader.h"
-#include "mpvcore/resolve.h"
-#include "mpvcore/playlist.h"
-#include "mpvcore/playlist_parser.h"
-#include "sub/osd.h"
-#include "sub/dec_sub.h"
-#include "mpvcore/m_option.h"
-#include "mpvcore/m_property.h"
-#include "mpvcore/m_config.h"
-#include "video/filter/vf.h"
-#include "video/decode/vd.h"
-#include "video/out/vo.h"
-#include "video/csputils.h"
-#include "audio/mixer.h"
-#include "audio/audio_buffer.h"
-#include "audio/out/ao.h"
-#include "audio/filter/af.h"
-#include "video/decode/dec_video.h"
-#include "audio/decode/dec_audio.h"
-#include "mpvcore/path.h"
-#include "stream/tv.h"
-#include "stream/stream_radio.h"
-#include "stream/pvr.h"
-#if HAVE_DVBIN
-#include "stream/dvbin.h"
-#endif
-#include "screenshot.h"
-#if HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-#ifndef __MINGW32__
-#include <sys/wait.h>
-#endif
-
-#include "osdep/io.h"
-
-#include "mp_core.h"
-#include "mp_lua.h"
-
-struct command_ctx {
- int events;
-
- double last_seek_time;
- double last_seek_pts;
-
- struct cycle_counter *cycle_counters;
- int num_cycle_counters;
-
-#define OVERLAY_MAX_ID 64
- void *overlay_map[OVERLAY_MAX_ID];
-};
-
-static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype,
- const char *cmd, const char *arg);
-static int set_filters(struct MPContext *mpctx, enum stream_type mediatype,
- struct m_obj_settings *new_chain);
-
-// Call before a seek, in order to allow revert_seek to undo the seek.
-static void mark_seek(struct MPContext *mpctx)
-{
- struct command_ctx *cmd = mpctx->command_ctx;
- double now = mp_time_sec();
- if (now > cmd->last_seek_time + 2.0 || cmd->last_seek_pts == MP_NOPTS_VALUE)
- cmd->last_seek_pts = get_current_time(mpctx);
- cmd->last_seek_time = now;
-}
-
-static char *format_bitrate(int rate)
-{
- return talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000);
-}
-
-static char *format_delay(double time)
-{
- return talloc_asprintf(NULL, "%d ms", ROUND(time * 1000));
-}
-
-// Property-option bridge.
-static int mp_property_generic_option(struct m_option *prop, int action,
- void *arg, MPContext *mpctx)
-{
- char *optname = prop->priv;
- struct m_config_option *opt = m_config_get_co(mpctx->mconfig,
- bstr0(optname));
- void *valptr = opt->data;
-
- switch (action) {
- case M_PROPERTY_GET_TYPE:
- *(struct m_option *)arg = *(opt->opt);
- return M_PROPERTY_OK;
- case M_PROPERTY_GET:
- m_option_copy(opt->opt, arg, valptr);
- return M_PROPERTY_OK;
- case M_PROPERTY_SET:
- m_option_copy(opt->opt, valptr, arg);
- return M_PROPERTY_OK;
- }
- return M_PROPERTY_NOT_IMPLEMENTED;
-}
-
-/// Playback speed (RW)
-static int mp_property_playback_speed(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- struct MPOpts *opts = mpctx->opts;
- double orig_speed = opts->playback_speed;
- switch (action) {
- case M_PROPERTY_SET: {
- opts->playback_speed = *(double *) arg;
- // Adjust time until next frame flip for nosound mode
- mpctx->time_frame *= orig_speed / opts->playback_speed;
- if (mpctx->d_audio)
- reinit_audio_chain(mpctx);
- return M_PROPERTY_OK;
- }
- case M_PROPERTY_PRINT:
- *(char **)arg = talloc_asprintf(NULL, "x %6.2f", orig_speed);
- return M_PROPERTY_OK;
- }
- return mp_property_generic_option(prop, action, arg, mpctx);
-}
-
-/// filename with path (RO)
-static int mp_property_path(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- if (!mpctx->filename)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_strdup_ro(prop, action, arg, mpctx->filename);
-}
-
-static int mp_property_filename(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- if (!mpctx->filename)
- return M_PROPERTY_UNAVAILABLE;
- char *filename = talloc_strdup(NULL, mpctx->filename);
- if (mp_is_url(bstr0(filename)))
- mp_url_unescape_inplace(filename);
- char *f = (char *)mp_basename(filename);
- int r = m_property_strdup_ro(prop, action, arg, f[0] ? f : filename);
- talloc_free(filename);
- return r;
-}
-
-static int mp_property_media_title(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- char *name = NULL;
- if (mpctx->resolve_result)
- name = mpctx->resolve_result->title;
- if (name && name[0])
- return m_property_strdup_ro(prop, action, arg, name);
- if (mpctx->master_demuxer) {
- name = demux_info_get(mpctx->master_demuxer, "title");
- if (name && name[0])
- return m_property_strdup_ro(prop, action, arg, name);
- }
- return mp_property_filename(prop, action, arg, mpctx);
-}
-
-static int mp_property_stream_path(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- struct stream *stream = mpctx->stream;
- if (!stream || !stream->url)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_strdup_ro(prop, action, arg, stream->url);
-}
-
-static int mp_property_stream_capture(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- if (!mpctx->stream)
- return M_PROPERTY_UNAVAILABLE;
-
- if (action == M_PROPERTY_SET) {
- char *filename = *(char **)arg;
- stream_set_capture_file(mpctx->stream, filename);
- // fall through to mp_property_generic_option
- }
- return mp_property_generic_option(prop, action, arg, mpctx);
-}
-
-/// Demuxer name (RO)
-static int mp_property_demuxer(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- struct demuxer *demuxer = mpctx->master_demuxer;
- if (!demuxer)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_strdup_ro(prop, action, arg, demuxer->desc->name);
-}
-
-/// Position in the stream (RW)
-static int mp_property_stream_pos(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- struct stream *stream = mpctx->stream;
- if (!stream)
- return M_PROPERTY_UNAVAILABLE;
- switch (action) {
- case M_PROPERTY_GET:
- *(int64_t *) arg = stream_tell(stream);
- return M_PROPERTY_OK;
- case M_PROPERTY_SET:
- stream_seek(stream, *(int64_t *) arg);
- return M_PROPERTY_OK;
- }
- return M_PROPERTY_NOT_IMPLEMENTED;
-}
-
-/// Stream start offset (RO)
-static int mp_property_stream_start(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- struct stream *stream = mpctx->stream;
- if (!stream)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_int64_ro(prop, action, arg, stream->start_pos);
-}
-
-/// Stream end offset (RO)
-static int mp_property_stream_end(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- struct stream *stream = mpctx->stream;
- if (!stream)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_int64_ro(prop, action, arg, stream->end_pos);
-}
-
-/// Stream length (RO)
-static int mp_property_stream_length(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- struct stream *stream = mpctx->stream;
- if (!stream)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_int64_ro(prop, action, arg,
- stream->end_pos - stream->start_pos);
-}
-
-// Does some magic to handle "<name>/full" as time formatted with milliseconds.
-// Assumes prop is the type of the actual property.
-static int property_time(m_option_t *prop, int action, void *arg, double time)
-{
- switch (action) {
- case M_PROPERTY_GET:
- *(double *)arg = time;
- return M_PROPERTY_OK;
- case M_PROPERTY_KEY_ACTION: {
- struct m_property_action_arg *ka = arg;
-
- if (strcmp(ka->key, "full") != 0)
- return M_PROPERTY_UNKNOWN;
-
- switch (ka->action) {
- case M_PROPERTY_GET:
- *(double *)ka->arg = time;
- return M_PROPERTY_OK;
- case M_PROPERTY_PRINT:
- *(char **)ka->arg = mp_format_time(time, true);
- return M_PROPERTY_OK;
- case M_PROPERTY_GET_TYPE:
- *(struct m_option *)ka->arg = *prop;
- return M_PROPERTY_OK;
- }
- }
- }
- return M_PROPERTY_NOT_IMPLEMENTED;
-}
-
-/// Current stream position in seconds (RO)
-static int mp_property_stream_time_pos(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- struct demuxer *demuxer = mpctx->demuxer;
- if (!demuxer)
- return M_PROPERTY_UNAVAILABLE;
- double pts = demuxer->stream_pts;
- if (pts == MP_NOPTS_VALUE)
- return M_PROPERTY_UNAVAILABLE;
-
- return property_time(prop, action, arg, pts);
-}
-
-
-/// Media length in seconds (RO)
-static int mp_property_length(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- double len;
-
- if (!(int) (len = get_time_length(mpctx)))
- return M_PROPERTY_UNAVAILABLE;
-
- return property_time(prop, action, arg, len);
-}
-
-static int mp_property_avsync(m_option_t *prop, int action, void *arg,
- MPContext *mpctx)
-{
- if (!mpctx->d_audio || !mpctx->d_video)
- return M_PROPERTY_UNAVAILABLE;
- if (mpctx->last_av_difference == MP_NOPTS_VALUE)
- return M_PROPERTY_UNAVAILABLE;
- return m_property_double_ro(prop, action, arg, mpctx->last_av_difference);
-}
-
-/// Current position in percent (RW)
-static int mp_property_percent_pos(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- if (!mpctx->num_sources)
- return M_PROPERTY_UNAVAILABLE;
-
- switch (action) {
- case M_PROPERTY_SET: ;
- double pos = *(double *)arg;
- queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0);
- return M_PROPERTY_OK;
- case M_PROPERTY_GET:
- *(double *)arg = get_current_pos_ratio(mpctx, false) * 100.0;
- return M_PROPERTY_OK;
- case M_PROPERTY_PRINT:
- *(char **)arg = talloc_asprintf(NULL, "%d", get_percent_pos(mpctx));
- return M_PROPERTY_OK;
- }
- return M_PROPERTY_NOT_IMPLEMENTED;
-}
-
-/// Current position in seconds (RW)
-static int mp_property_time_pos(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{
- if (!mpctx->num_sources)
- return M_PROPERTY_UNAVAILABLE;
-
- if (action == M_PROPERTY_SET) {
- queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0);
- return M_PROPERTY_OK;
- }
- return property_time(prop, action, arg, get_current_time(mpctx));
-}
-
-static bool time_remaining(MPContext *mpctx, double *remaining)
-{
- double len = get_time_length(mpctx);
- double pos = get_current_time(mpctx);
- double start = get_start_time(mpctx);
-
- *remaining = len - (pos - start);
-
- return !!(int)len;
-}
-
-static int mp_property_remaining(m_option_t *prop, int action,
- void *arg, MPContext *mpctx)
-{