Need to shuffle some stuff around but it's pretty simple. Mute the audio stream before the frame step and then unmute it when we're done. It's exactly the same as the default play mode otherwise.
Unified · Split
| @@ -1 +1,2 @@ | |||
| 1 | - add optional `frames` and `flags` arguments to `frame-step` command controlling the direction and amount of frames mpv steps through | 1 | - add optional `frames` and `flags` arguments to `frame-step` command controlling the direction and amount of frames mpv steps through |
| 2 | - add optional `mute` flag to `frame-step` command which mutes the player during the duration of the frame step | ||
| @@ -370,6 +370,9 @@ Playback Control · 369 unmodified lines | |||
| 370 | Perform a very exact seek that attempts to seek by the desired amount | 370 | Perform a very exact seek that attempts to seek by the desired amount |
| 371 | of frames. If ``<frames>`` is ``-1``, this will go exactly to the | 371 | of frames. If ``<frames>`` is ``-1``, this will go exactly to the |
| 372 | previous frame. | 372 | previous frame. |
| 373 | mute | ||
| 374 | The same as ``play`` but mutes the audio stream if there is any during | ||
| 375 | the duration of the frame step. | ||
| 373 | 376 | ||
| 374 | Note that the default frameskip mode, play, is more accurate but can be | 377 | Note that the default frameskip mode, play, is more accurate but can be |
| 375 | slow depending on how many frames you are skipping (i.e. skipping forward | 378 | slow depending on how many frames you are skipping (i.e. skipping forward |
| @@ -170,21 +170,26 @@ static float compute_replaygain(struct MPContext *mpctx) · 169 unmodified lines | |||
| 170 | return rgain; | 170 | return rgain; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | // Called when opts->softvol_volume or opts->softvol_mute were changed. | 173 | float audio_get_gain(struct MPContext *mpctx) |
| 174 | void audio_update_volume(struct MPContext *mpctx) | ||
| 175 | { | 174 | { |
| 176 | struct MPOpts *opts = mpctx->opts; | 175 | struct MPOpts *opts = mpctx->opts; |
| 177 | struct ao_chain *ao_c = mpctx->ao_chain; | ||
| 178 | if (!ao_c || !ao_c->ao) | ||
| 179 | return; | ||
| 180 | |||
| 181 | float gain = MPMAX(opts->softvol_volume / 100.0, 0); | 176 | float gain = MPMAX(opts->softvol_volume / 100.0, 0); |
| 182 | gain = pow(gain, 3); | 177 | gain = pow(gain, 3); |
| 183 | gain *= compute_replaygain(mpctx); | 178 | gain *= compute_replaygain(mpctx); |
| 184 | gain *= db_gain(opts->softvol_gain); | 179 | gain *= db_gain(opts->softvol_gain); |
| 185 | if (opts->softvol_mute) | 180 | if (opts->softvol_mute) |
| 186 | gain = 0.0; | 181 | gain = 0.0; |
| 182 | return gain; | ||
| 183 | } | ||
| 184 | |||
| 185 | // Called when opts->softvol_volume or opts->softvol_mute were changed. | ||
| 186 | void audio_update_volume(struct MPContext *mpctx) | ||
| 187 | { | ||
| 188 | struct ao_chain *ao_c = mpctx->ao_chain; | ||
| 189 | if (!ao_c || !ao_c->ao) | ||
| 190 | return; | ||
| 187 | 191 | ||
| 192 | float gain = audio_get_gain(mpctx); | ||
| 188 | ao_set_gain(ao_c->ao, gain); | 193 | ao_set_gain(ao_c->ao, gain); |
| 189 | } | 194 | } |
| 190 | 195 | ||
| @@ -5731,18 +5731,20 @@ static void cmd_frame_step(void *p) · 5730 unmodified lines | |||
| 5731 | return; | 5731 | return; |
| 5732 | } | 5732 | } |
| 5733 | 5733 | ||
| 5734 | if (flags) { | 5734 | if (flags == 1) { |
| 5735 | if (!cmd->cmd->is_up) | 5735 | if (!cmd->cmd->is_up) |
| 5736 | add_step_frame(mpctx, frames, flags); | 5736 | add_step_frame(mpctx, frames, true); |
| 5737 | } else { | 5737 | } else { |
| 5738 | if (cmd->cmd->is_up) { | 5738 | if (cmd->cmd->is_up) { |
| 5739 | if (mpctx->step_frames < 1) | 5739 | if (mpctx->step_frames < 1) |
| 5740 | set_pause_state(mpctx, true); | 5740 | set_pause_state(mpctx, true); |
| 5741 | } else { | 5741 | } else { |
| 5742 | if (flags == 2) | ||
| 5743 | step_frame_mute(mpctx, true); | ||
| 5742 | if (cmd->cmd->repeated) { | 5744 | if (cmd->cmd->repeated) { |
| 5743 | set_pause_state(mpctx, false); | 5745 | set_pause_state(mpctx, false); |
| 5744 | } else { | 5746 | } else { |
| 5745 | add_step_frame(mpctx, frames, flags); | 5747 | add_step_frame(mpctx, frames, false); |
| 5746 | } | 5748 | } |
| 5747 | } | 5749 | } |
| 5748 | } | 5750 | } |
| @@ -7038,7 +7040,8 @@ const struct mp_cmd_def mp_cmds[] = { · 1289 unmodified lines | |||
| 7038 | {"frames", OPT_INT(v.i), OPTDEF_INT(1)}, | 7040 | {"frames", OPT_INT(v.i), OPTDEF_INT(1)}, |
| 7039 | {"flags", OPT_CHOICE(v.i, | 7041 | {"flags", OPT_CHOICE(v.i, |
| 7040 | {"play", 0}, | 7042 | {"play", 0}, |
| 7041 | {"seek", 1}), | 7043 | {"seek", 1}, |
| 7044 | {"mute", 2}), | ||
| 7042 | .flags = MP_CMD_OPT_ARG}, | 7045 | .flags = MP_CMD_OPT_ARG}, |
| 7043 | }, | 7046 | }, |
| 7044 | .allow_auto_repeat = true, | 7047 | .allow_auto_repeat = true, |
| @@ -506,6 +506,7 @@ void update_playback_speed(struct MPContext *mpctx); · 505 unmodified lines | |||
| 506 | void uninit_audio_out(struct MPContext *mpctx); | 506 | void uninit_audio_out(struct MPContext *mpctx); |
| 507 | void uninit_audio_chain(struct MPContext *mpctx); | 507 | void uninit_audio_chain(struct MPContext *mpctx); |
| 508 | void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track); | 508 | void reinit_audio_chain_src(struct MPContext *mpctx, struct track *track); |
| 509 | float audio_get_gain(struct MPContext *mpctx); | ||
| 509 | void audio_update_volume(struct MPContext *mpctx); | 510 | void audio_update_volume(struct MPContext *mpctx); |
| 510 | void reload_audio_output(struct MPContext *mpctx); | 511 | void reload_audio_output(struct MPContext *mpctx); |
| 511 | void audio_start_ao(struct MPContext *mpctx); | 512 | void audio_start_ao(struct MPContext *mpctx); |
| @@ -607,6 +608,7 @@ void set_pause_state(struct MPContext *mpctx, bool user_pause); · 95 unmodified lines | |||
| 607 | void update_internal_pause_state(struct MPContext *mpctx); | 608 | void update_internal_pause_state(struct MPContext *mpctx); |
| 608 | void update_core_idle_state(struct MPContext *mpctx); | 609 | void update_core_idle_state(struct MPContext *mpctx); |
| 609 | void add_step_frame(struct MPContext *mpctx, int dir, bool use_seek); | 610 | void add_step_frame(struct MPContext *mpctx, int dir, bool use_seek); |
| 611 | void step_frame_mute(struct MPContext *mpctx, bool mute); | ||
| 610 | void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, | 612 | void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, |
| 611 | enum seek_precision exact, int flags); | 613 | enum seek_precision exact, int flags); |
| 612 | double get_time_length(struct MPContext *mpctx); | 614 | double get_time_length(struct MPContext *mpctx); |
| @@ -226,6 +226,15 @@ void add_step_frame(struct MPContext *mpctx, int dir, bool use_seek) · 225 unmodified lines | |||
| 226 | } | 226 | } |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | void step_frame_mute(struct MPContext *mpctx, bool mute) | ||
| 230 | { | ||
| 231 | if (!mpctx->ao_chain || !mpctx->ao_chain->ao) | ||
| 232 | return; | ||
| 233 | |||
| 234 | float gain = mute ? 0 : audio_get_gain(mpctx); | ||
| 235 | ao_set_gain(mpctx->ao_chain->ao, gain); | ||
| 236 | } | ||
| 237 | |||
| 229 | // Clear some playback-related fields on file loading or after seeks. | 238 | // Clear some playback-related fields on file loading or after seeks. |
| 230 | void reset_playback_state(struct MPContext *mpctx) | 239 | void reset_playback_state(struct MPContext *mpctx) |
| 231 | { | 240 | { |
| @@ -1294,8 +1294,10 @@ void write_video(struct MPContext *mpctx) · 1293 unmodified lines | |||
| 1294 | if (mpctx->video_status != STATUS_EOF) { | 1294 | if (mpctx->video_status != STATUS_EOF) { |
| 1295 | if (mpctx->step_frames > 0) { | 1295 | if (mpctx->step_frames > 0) { |
| 1296 | mpctx->step_frames--; | 1296 | mpctx->step_frames--; |
| 1297 | if (!mpctx->step_frames) | 1297 | if (!mpctx->step_frames) { |
| 1298 | set_pause_state(mpctx, true); | 1298 | set_pause_state(mpctx, true); |
| 1299 | step_frame_mute(mpctx, false); | ||
| 1300 | } | ||
| 1299 | } | 1301 | } |
| 1300 | if (mpctx->max_frames == 0 && !mpctx->stop_play) | 1302 | if (mpctx->max_frames == 0 && !mpctx->stop_play) |
| 1301 | mpctx->stop_play = AT_END_OF_FILE; | 1303 | mpctx->stop_play = AT_END_OF_FILE; |