mirror of
https://github.com/mpv-player/mpv.git
synced 2025-12-28 05:33:14 +00:00
mixer: refactor, fix some aspects of --volume handling
Refactor how mixer.c does volume/mute restoration and initialization. Move to handling of --volume and --mute to mixer.c. Simplify the implementation of these and hopefully fix bugs/strange behavior related to using them as file-local options (this uses a somewhat dirty trick: the option values are reverted to "auto" after initialization). Put most code related to initialization and volume restoring in probe_softvol() and restore_volume(). Having this code all in one place is less confusing. Instead of trying to detect whether to use softvol at runtime, detect it at initialization time using AOCONTROL_GET_VOLUME (same with mute, AOCONTROL_GET_MUTE). This implies we expect SET_VOLUME/SET_MUTE to work if the GET variants work. Hopefully this is always the case. This is also preparation for being able to change volume/mute settings if audio is disabled, and for allowing restoring value with playback resume.
This commit is contained in:
192
audio/mixer.c
192
audio/mixer.c
@@ -26,34 +26,34 @@
|
||||
#include "mpvcore/mp_msg.h"
|
||||
#include "mixer.h"
|
||||
|
||||
void mixer_init(struct mixer *mixer, struct MPOpts *opts)
|
||||
{
|
||||
mixer->opts = opts;
|
||||
mixer->vol_l = mixer->vol_r = 100;
|
||||
mixer->driver = "";
|
||||
}
|
||||
|
||||
static void checkvolume(struct mixer *mixer)
|
||||
{
|
||||
if (!mixer->ao)
|
||||
return;
|
||||
|
||||
if (mixer->softvol == SOFTVOL_AUTO) {
|
||||
mixer->softvol = mixer->ao->per_application_mixer
|
||||
|| mixer->ao->no_persistent_volume
|
||||
? SOFTVOL_NO : SOFTVOL_YES;
|
||||
}
|
||||
|
||||
ao_control_vol_t vol;
|
||||
if (mixer->softvol || CONTROL_OK != ao_control(mixer->ao,
|
||||
AOCONTROL_GET_VOLUME, &vol)) {
|
||||
mixer->softvol = SOFTVOL_YES;
|
||||
if (!mixer->af)
|
||||
return;
|
||||
ao_control_vol_t vol = {mixer->vol_l, mixer->vol_r};
|
||||
if (mixer->softvol) {
|
||||
float vals[AF_NCH];
|
||||
if (!af_control_any_rev(mixer->af,
|
||||
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET, vals))
|
||||
vals[0] = vals[1] = 1.0;
|
||||
vol.left = (vals[0] / (mixer->opts->softvol_max / 100.0)) * 100.0;
|
||||
vol.right = (vals[1] / (mixer->opts->softvol_max / 100.0)) * 100.0;
|
||||
} else {
|
||||
// Rely on the values not changing if the query is not supported
|
||||
ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol);
|
||||
ao_control(mixer->ao, AOCONTROL_GET_MUTE, &mixer->muted);
|
||||
}
|
||||
float l = mixer->vol_l;
|
||||
float r = mixer->vol_r;
|
||||
if (mixer->muted_using_volume)
|
||||
if (mixer->emulate_mute && mixer->muted)
|
||||
l = r = 0;
|
||||
/* Try to detect cases where the volume has been changed by some external
|
||||
* action (such as something else changing a shared system-wide volume).
|
||||
@@ -65,14 +65,10 @@ static void checkvolume(struct mixer *mixer)
|
||||
if (FFABS(vol.left - l) >= 3 || FFABS(vol.right - r) >= 3) {
|
||||
mixer->vol_l = vol.left;
|
||||
mixer->vol_r = vol.right;
|
||||
if (mixer->muted_using_volume)
|
||||
if (mixer->emulate_mute)
|
||||
mixer->muted = false;
|
||||
}
|
||||
if (!mixer->softvol)
|
||||
// Rely on the value not changing if the query is not supported
|
||||
ao_control(mixer->ao, AOCONTROL_GET_MUTE, &mixer->muted);
|
||||
mixer->muted_by_us &= mixer->muted;
|
||||
mixer->muted_using_volume &= mixer->muted;
|
||||
}
|
||||
|
||||
void mixer_getvolume(mixer_t *mixer, float *l, float *r)
|
||||
@@ -86,17 +82,11 @@ static void setvolume_internal(mixer_t *mixer, float l, float r)
|
||||
{
|
||||
struct ao_control_vol vol = {.left = l, .right = r};
|
||||
if (!mixer->softvol) {
|
||||
// relies on the driver data being permanent (so ptr stays valid)
|
||||
mixer->restore_volume = mixer->ao->no_persistent_volume ?
|
||||
mixer->ao->driver->info->short_name : NULL;
|
||||
if (ao_control(mixer->ao, AOCONTROL_SET_VOLUME, &vol) != CONTROL_OK)
|
||||
mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
|
||||
"[Mixer] Failed to change audio output volume.\n");
|
||||
return;
|
||||
}
|
||||
mixer->restore_volume = "softvol";
|
||||
if (!mixer->af)
|
||||
return;
|
||||
float vals[AF_NCH];
|
||||
vals[0] = l / 100.0 * mixer->opts->softvol_max / 100.0;
|
||||
vals[1] = r / 100.0 * mixer->opts->softvol_max / 100.0;
|
||||
@@ -106,8 +96,7 @@ static void setvolume_internal(mixer_t *mixer, float l, float r)
|
||||
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
|
||||
vals))
|
||||
{
|
||||
mp_tmsg(MSGT_GLOBAL, mixer->softvol ? MSGL_V : MSGL_WARN,
|
||||
"[Mixer] No hardware mixing, inserting volume filter.\n");
|
||||
mp_tmsg(MSGT_GLOBAL, MSGL_V, "[Mixer] Inserting volume filter.\n");
|
||||
if (!(af_add(mixer->af, "volume", NULL)
|
||||
&& af_control_any_rev(mixer->af,
|
||||
AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
|
||||
@@ -119,13 +108,13 @@ static void setvolume_internal(mixer_t *mixer, float l, float r)
|
||||
|
||||
void mixer_setvolume(mixer_t *mixer, float l, float r)
|
||||
{
|
||||
checkvolume(mixer); // to check mute status and AO support for volume
|
||||
checkvolume(mixer); // to check mute status
|
||||
if (mixer->vol_l == l && mixer->vol_r == r)
|
||||
return; // just prevent af_volume insertion when not needed
|
||||
mixer->vol_l = av_clipf(l, 0, 100);
|
||||
mixer->vol_r = av_clipf(r, 0, 100);
|
||||
if (!mixer->ao || mixer->muted_using_volume)
|
||||
return;
|
||||
setvolume_internal(mixer, mixer->vol_l, mixer->vol_r);
|
||||
mixer->user_set_volume = true;
|
||||
if (mixer->ao && !(mixer->emulate_mute && mixer->muted))
|
||||
setvolume_internal(mixer, mixer->vol_l, mixer->vol_r);
|
||||
}
|
||||
|
||||
void mixer_getbothvolume(mixer_t *mixer, float *b)
|
||||
@@ -138,17 +127,20 @@ void mixer_getbothvolume(mixer_t *mixer, float *b)
|
||||
void mixer_setmute(struct mixer *mixer, bool mute)
|
||||
{
|
||||
checkvolume(mixer);
|
||||
if (mute != mixer->muted) {
|
||||
if (!mixer->softvol && !mixer->muted_using_volume && ao_control(
|
||||
mixer->ao, AOCONTROL_SET_MUTE, &mute) == CONTROL_OK) {
|
||||
mixer->muted_using_volume = false;
|
||||
} else {
|
||||
setvolume_internal(mixer, mixer->vol_l*!mute, mixer->vol_r*!mute);
|
||||
mixer->muted_using_volume = mute;
|
||||
}
|
||||
if (mute == mixer->muted)
|
||||
return;
|
||||
if (mixer->ao) {
|
||||
mixer->muted = mute;
|
||||
mixer->muted_by_us = mute;
|
||||
if (mixer->emulate_mute) {
|
||||
setvolume_internal(mixer, mixer->vol_l*!mute, mixer->vol_r*!mute);
|
||||
} else {
|
||||
ao_control(mixer->ao, AOCONTROL_SET_MUTE, &mute);
|
||||
}
|
||||
checkvolume(mixer);
|
||||
} else {
|
||||
mixer->muted = mute;
|
||||
mixer->muted_by_us = mute;
|
||||
mixer->user_set_mute = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +152,9 @@ bool mixer_getmute(struct mixer *mixer)
|
||||
|
||||
static void addvolume(struct mixer *mixer, float d)
|
||||
{
|
||||
checkvolume(mixer);
|
||||
mixer_setvolume(mixer, mixer->vol_l + d, mixer->vol_r + d);
|
||||
float vol_l, vol_r;
|
||||
mixer_getvolume(mixer, &vol_l, &vol_r);
|
||||
mixer_setvolume(mixer, vol_l + d, vol_r + d);
|
||||
if (d > 0)
|
||||
mixer_setmute(mixer, false);
|
||||
}
|
||||
@@ -237,37 +230,95 @@ void mixer_setbalance(mixer_t *mixer, float val)
|
||||
AF_CONTROL_PAN_BALANCE | AF_CONTROL_SET, &val);
|
||||
}
|
||||
|
||||
// Called after the audio filter chain is built or rebuilt.
|
||||
void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af)
|
||||
static void probe_softvol(struct mixer *mixer)
|
||||
{
|
||||
mixer->ao = ao;
|
||||
mixer->af = af;
|
||||
mixer->softvol = mixer->opts->softvol;
|
||||
/* Use checkvolume() to see if softvol needs to be enabled because of
|
||||
* lacking AO support, but first store values it could overwrite. */
|
||||
float left = mixer->vol_l, right = mixer->vol_r;
|
||||
bool muted = mixer->muted_by_us;
|
||||
checkvolume(mixer);
|
||||
/* Try to avoid restoring volume stored from one control method with
|
||||
* another. Especially, restoring softvol volume (typically high) on
|
||||
* system mixer could have very nasty effects. */
|
||||
const char *restore_reason = mixer->softvol ? "softvol" :
|
||||
mixer->ao->driver->info->short_name;
|
||||
if (mixer->restore_volume && !strcmp(mixer->restore_volume,
|
||||
restore_reason))
|
||||
mixer_setvolume(mixer, left, right);
|
||||
/* We turn mute off at AO uninit, so it has to be restored (unless
|
||||
* we're reinitializing filter chain while keeping AO); but we only
|
||||
* enable mute, not turn external mute off. */
|
||||
if (muted)
|
||||
mixer_setmute(mixer, true);
|
||||
if (mixer->balance != 0)
|
||||
mixer_setbalance(mixer, mixer->balance);
|
||||
mixer->user_set_mute = false;
|
||||
mixer->user_set_volume = false;
|
||||
if (mixer->opts->softvol == SOFTVOL_AUTO) {
|
||||
// No system-wide volume => fine with AO volume control.
|
||||
mixer->softvol = !(mixer->ao->per_application_mixer ||
|
||||
mixer->ao->no_persistent_volume);
|
||||
} else {
|
||||
mixer->softvol = mixer->opts->softvol == SOFTVOL_YES;
|
||||
}
|
||||
|
||||
// If we can't use real volume control => force softvol.
|
||||
if (!mixer->softvol) {
|
||||
ao_control_vol_t vol;
|
||||
if (ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol) != CONTROL_OK) {
|
||||
mixer->softvol = true;
|
||||
mp_tmsg(MSGT_GLOBAL, MSGL_WARN,
|
||||
"[mixer] Hardware volume control unavailable.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Probe native mute support.
|
||||
mixer->emulate_mute = true;
|
||||
if (!mixer->softvol) {
|
||||
if (ao_control(mixer->ao, AOCONTROL_GET_MUTE, &(bool){0}) == CONTROL_OK)
|
||||
mixer->emulate_mute = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called before uninitializing the audio output. The main purpose is to
|
||||
static void restore_volume(struct mixer *mixer)
|
||||
{
|
||||
struct MPOpts *opts = mixer->opts;
|
||||
struct ao *ao = mixer->ao;
|
||||
|
||||
float force_vol_l = -1, force_vol_r = -1;
|
||||
int force_mute = -1;
|
||||
|
||||
const char *prev_driver = mixer->driver;
|
||||
mixer->driver = mixer->softvol ? "softvol" : ao->driver->info->short_name;
|
||||
|
||||
bool restore = mixer->softvol || ao->no_persistent_volume;
|
||||
|
||||
// Restore old parameters if volume won't survive reinitialization.
|
||||
// But not if volume scale is possibly different.
|
||||
if (restore && strcmp(mixer->driver, prev_driver) == 0) {
|
||||
force_vol_l = mixer->vol_l;
|
||||
force_vol_r = mixer->vol_r;
|
||||
}
|
||||
|
||||
// Set mute if we disabled it on uninit last time.
|
||||
if (mixer->muted_by_us)
|
||||
force_mute = 1;
|
||||
|
||||
// Set parameters from command line.
|
||||
if (opts->mixer_init_volume >= 0)
|
||||
force_vol_l = force_vol_r = opts->mixer_init_volume;
|
||||
if (opts->mixer_init_mute >= 0)
|
||||
force_mute = opts->mixer_init_mute;
|
||||
|
||||
// Using --volume should not reset the volume on every file (i.e. reinit),
|
||||
// OTOH mpv --{ --volume 10 f1.mkv --} --{ --volume 20 f2.mkv --} must work.
|
||||
// Resetting the option volumes to "auto" (-1) is easiest. If file local
|
||||
// options (as shown above) are used, these are reset to other values.
|
||||
opts->mixer_init_volume = -1;
|
||||
opts->mixer_init_mute = -1;
|
||||
|
||||
checkvolume(mixer);
|
||||
if (force_vol_l >= 0 && force_vol_r >= 0)
|
||||
mixer_setvolume(mixer, force_vol_l, force_vol_r);
|
||||
if (force_mute >= 0)
|
||||
mixer_setmute(mixer, force_mute);
|
||||
}
|
||||
|
||||
// Called after the audio filter chain is built or rebuilt.
|
||||
// (Can be called multiple times, even without mixer_uninit() in-between.)
|
||||
void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af)
|
||||
{
|
||||
if (!ao || !af)
|
||||
return;
|
||||
mixer->ao = ao;
|
||||
mixer->af = af;
|
||||
|
||||
probe_softvol(mixer);
|
||||
restore_volume(mixer);
|
||||
|
||||
if (mixer->balance != 0)
|
||||
mixer_setbalance(mixer, mixer->balance);
|
||||
}
|
||||
|
||||
/* Called before uninitializing the audio filter chain. The main purpose is to
|
||||
* turn off mute, in case it's a global/persistent setting which might
|
||||
* otherwise be left enabled even after this player instance exits.
|
||||
*/
|
||||
@@ -291,4 +342,5 @@ void mixer_uninit_audio(struct mixer *mixer)
|
||||
mixer->muted_by_us = true;
|
||||
}
|
||||
mixer->ao = NULL;
|
||||
mixer->af = NULL;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// Values of MPOpts.softvol
|
||||
enum {
|
||||
SOFTVOL_NO = 0,
|
||||
SOFTVOL_YES = 1,
|
||||
@@ -31,19 +32,22 @@ typedef struct mixer {
|
||||
struct MPOpts *opts;
|
||||
struct ao *ao;
|
||||
struct af_stream *af;
|
||||
int softvol;
|
||||
bool muted;
|
||||
bool muted_by_us;
|
||||
bool muted_using_volume;
|
||||
// Static, dependent on ao/softvol settings
|
||||
bool softvol; // use AO (true) or af_volume (false)
|
||||
bool emulate_mute; // if true, emulate mute with volume=0
|
||||
// Last known values (possibly out of sync with reality)
|
||||
float vol_l, vol_r;
|
||||
bool muted;
|
||||
// Used to decide whether we should unmute on uninit
|
||||
bool muted_by_us;
|
||||
/* Contains ao driver name or "softvol" if volume is not persistent
|
||||
* and needs to be restored after the driver is reinitialized. */
|
||||
const char *restore_volume;
|
||||
const char *driver;
|
||||
// Other stuff
|
||||
float balance;
|
||||
bool user_set_mute;
|
||||
bool user_set_volume;
|
||||
} mixer_t;
|
||||
|
||||
void mixer_init(struct mixer *mixer, struct MPOpts *opts);
|
||||
void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af);
|
||||
void mixer_uninit_audio(struct mixer *mixer);
|
||||
void mixer_getvolume(mixer_t *mixer, float *l, float *r);
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#define INITIALIZED_VO 1
|
||||
#define INITIALIZED_AO 2
|
||||
#define INITIALIZED_VOL 4
|
||||
#define INITIALIZED_GETCH2 8
|
||||
#define INITIALIZED_PLAYBACK 16
|
||||
#define INITIALIZED_STREAM 64
|
||||
|
||||
@@ -443,18 +443,16 @@ static void uninit_subs(struct demuxer *demuxer)
|
||||
|
||||
void uninit_player(struct MPContext *mpctx, unsigned int mask)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
|
||||
mask &= mpctx->initialized_flags;
|
||||
|
||||
mp_msg(MSGT_CPLAYER, MSGL_DBG2, "\n*** uninit(0x%X)\n", mask);
|
||||
|
||||
if (mask & INITIALIZED_ACODEC) {
|
||||
mpctx->initialized_flags &= ~INITIALIZED_ACODEC;
|
||||
mixer_uninit_audio(&mpctx->mixer);
|
||||
if (mpctx->sh_audio)
|
||||
uninit_audio(mpctx->sh_audio);
|
||||
cleanup_demux_stream(mpctx, STREAM_AUDIO);
|
||||
mpctx->mixer.af = NULL;
|
||||
}
|
||||
|
||||
if (mask & INITIALIZED_SUB) {
|
||||
@@ -526,24 +524,8 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask)
|
||||
getch2_disable();
|
||||
}
|
||||
|
||||
if (mask & INITIALIZED_VOL) {
|
||||
mpctx->initialized_flags &= ~INITIALIZED_VOL;
|
||||
if (mpctx->mixer.ao) {
|
||||
// Normally the mixer remembers volume, but do it even if the
|
||||
// volume is set explicitly with --volume=... (so that the same
|
||||
// volume is restored on reinit)
|
||||
if (opts->mixer_init_volume >= 0 && mpctx->mixer.user_set_volume)
|
||||
mixer_getbothvolume(&mpctx->mixer, &opts->mixer_init_volume);
|
||||
if (opts->mixer_init_mute >= 0 && mpctx->mixer.user_set_mute)
|
||||
opts->mixer_init_mute = mixer_getmute(&mpctx->mixer);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & INITIALIZED_AO) {
|
||||
mpctx->initialized_flags &= ~INITIALIZED_AO;
|
||||
if (mpctx->mixer.ao)
|
||||
mixer_uninit_audio(&mpctx->mixer);
|
||||
mpctx->mixer.ao = NULL;
|
||||
if (mpctx->ao)
|
||||
ao_uninit(mpctx->ao, mpctx->stop_play != AT_END_OF_FILE);
|
||||
mpctx->ao = NULL;
|
||||
@@ -1618,7 +1600,6 @@ static int build_afilter_chain(struct MPContext *mpctx)
|
||||
|
||||
static int recreate_audio_filters(struct MPContext *mpctx)
|
||||
{
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
assert(mpctx->sh_audio);
|
||||
|
||||
// init audio filters:
|
||||
@@ -1629,15 +1610,6 @@ static int recreate_audio_filters(struct MPContext *mpctx)
|
||||
}
|
||||
|
||||
mixer_reinit_audio(&mpctx->mixer, mpctx->ao, mpctx->sh_audio->afilter);
|
||||
if (!(mpctx->initialized_flags & INITIALIZED_VOL)) {
|
||||
if (opts->mixer_init_volume >= 0) {
|
||||
mixer_setvolume(&mpctx->mixer, opts->mixer_init_volume,
|
||||
opts->mixer_init_volume);
|
||||
}
|
||||
if (opts->mixer_init_mute >= 0)
|
||||
mixer_setmute(&mpctx->mixer, opts->mixer_init_mute);
|
||||
mpctx->initialized_flags |= INITIALIZED_VOL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1662,7 +1634,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
|
||||
struct MPOpts *opts = mpctx->opts;
|
||||
init_demux_stream(mpctx, STREAM_AUDIO);
|
||||
if (!mpctx->sh_audio) {
|
||||
uninit_player(mpctx, INITIALIZED_VOL | INITIALIZED_AO);
|
||||
uninit_player(mpctx, INITIALIZED_AO);
|
||||
goto no_audio;
|
||||
}
|
||||
|
||||
@@ -1733,7 +1705,7 @@ void reinit_audio_chain(struct MPContext *mpctx)
|
||||
return;
|
||||
|
||||
init_error:
|
||||
uninit_player(mpctx, INITIALIZED_ACODEC | INITIALIZED_AO | INITIALIZED_VOL);
|
||||
uninit_player(mpctx, INITIALIZED_ACODEC | INITIALIZED_AO);
|
||||
cleanup_demux_stream(mpctx, STREAM_AUDIO);
|
||||
no_audio:
|
||||
mpctx->current_track[STREAM_AUDIO] = NULL;
|
||||
@@ -2040,7 +2012,7 @@ void mp_switch_track(struct MPContext *mpctx, enum stream_type type,
|
||||
uninit_player(mpctx, INITIALIZED_VCODEC |
|
||||
(mpctx->opts->fixed_vo && track ? 0 : INITIALIZED_VO));
|
||||
} else if (type == STREAM_AUDIO) {
|
||||
uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC | INITIALIZED_VOL);
|
||||
uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_ACODEC);
|
||||
} else if (type == STREAM_SUB) {
|
||||
uninit_player(mpctx, INITIALIZED_SUB);
|
||||
}
|
||||
@@ -2280,7 +2252,7 @@ static int fill_audio_out_buffers(struct MPContext *mpctx, double endpts)
|
||||
* while displaying video, then doing the output format switch.
|
||||
*/
|
||||
if (!mpctx->opts->gapless_audio)
|
||||
uninit_player(mpctx, INITIALIZED_AO | INITIALIZED_VOL);
|
||||
uninit_player(mpctx, INITIALIZED_AO);
|
||||
reinit_audio_chain(mpctx);
|
||||
return -1;
|
||||
} else if (res == ASYNC_PLAY_DONE)
|
||||
@@ -2909,7 +2881,7 @@ static bool timeline_set_part(struct MPContext *mpctx, int i, bool force)
|
||||
enum stop_play_reason orig_stop_play = mpctx->stop_play;
|
||||
if (!mpctx->sh_video && mpctx->stop_play == KEEP_PLAYING)
|
||||
mpctx->stop_play = AT_END_OF_FILE; // let audio uninit drain data
|
||||
uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo ? 0 : INITIALIZED_VO) | (mpctx->opts->gapless_audio ? 0 : INITIALIZED_AO) | INITIALIZED_VOL | INITIALIZED_ACODEC | INITIALIZED_SUB);
|
||||
uninit_player(mpctx, INITIALIZED_VCODEC | (mpctx->opts->fixed_vo ? 0 : INITIALIZED_VO) | (mpctx->opts->gapless_audio ? 0 : INITIALIZED_AO) | INITIALIZED_ACODEC | INITIALIZED_SUB);
|
||||
mpctx->stop_play = orig_stop_play;
|
||||
|
||||
mpctx->demuxer = n->source;
|
||||
@@ -4855,7 +4827,7 @@ static int mpv_main(int argc, char *argv[])
|
||||
init_libav();
|
||||
GetCpuCaps(&gCpuCaps);
|
||||
screenshot_init(mpctx);
|
||||
mpctx->mixer.opts = opts;
|
||||
mixer_init(&mpctx->mixer, opts);
|
||||
|
||||
// Preparse the command line
|
||||
m_config_preparse_command_line(mpctx->mconfig, argc, argv);
|
||||
|
||||
Reference in New Issue
Block a user