Beispiel #1
0
Datei: mixer.c Projekt: kax4/mpv
static void checkvolume(struct mixer *mixer)
{
    if (!mixer->ao)
        return;

    if (mixer->softvol == SOFTVOL_AUTO) {
        mixer->softvol = mixer->ao->per_application_mixer
                         ? 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->afilter)
            return;
        float db_vals[AF_NCH];
        if (!af_control_any_rev(mixer->afilter,
                        AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_GET, db_vals))
            db_vals[0] = db_vals[1] = 1.0;
        else
            af_from_dB(2, db_vals, db_vals, 20.0, -200.0, 60.0);
        vol.left = (db_vals[0] / (mixer->softvol_max / 100.0)) * 100.0;
        vol.right = (db_vals[1] / (mixer->softvol_max / 100.0)) * 100.0;
    }
    float l = mixer->vol_l;
    float r = mixer->vol_r;
    if (mixer->muted_using_volume)
        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).
     * We don't test for exact equality, as some AOs may round the value
     * we last set to some nearby supported value. 3 has been the default
     * volume step for increase/decrease keys, and is apparently big enough
     * to step to the next possible value in most setups.
     */
    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)
            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;
}
Beispiel #2
0
void update_window_title(struct MPContext *mpctx, bool force)
{
    if (!mpctx->video_out && !mpctx->ao) {
        talloc_free(mpctx->last_window_title);
        mpctx->last_window_title = NULL;
        return;
    }
    char *title = mp_property_expand_string(mpctx, mpctx->opts->wintitle);
    if (!mpctx->last_window_title || force ||
        strcmp(title, mpctx->last_window_title) != 0)
    {
        talloc_free(mpctx->last_window_title);
        mpctx->last_window_title = talloc_steal(mpctx, title);

        if (mpctx->video_out) {
            mpctx->video_out->window_title = talloc_strdup(mpctx->video_out, title);
            vo_control(mpctx->video_out, VOCTRL_UPDATE_WINDOW_TITLE, title);
        }

        if (mpctx->ao) {
            ao_control(mpctx->ao, AOCONTROL_UPDATE_STREAM_TITLE, title);
        }
    } else {
        talloc_free(title);
    }
}
Beispiel #3
0
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;
        }
        mixer->muted = mute;
        mixer->muted_by_us = mute;
    }
}
Beispiel #4
0
Datei: mixer.c Projekt: kax4/mpv
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->afilter)
        return;
    // af_volume uses values in dB
    float db_vals[AF_NCH];
    int i;
    db_vals[0] = (l / 100.0) * (mixer->softvol_max / 100.0);
    db_vals[1] = (r / 100.0) * (mixer->softvol_max / 100.0);
    for (i = 2; i < AF_NCH; i++)
        db_vals[i] = ((l + r) / 100.0) * (mixer->softvol_max / 100.0) / 2.0;
    af_to_dB(AF_NCH, db_vals, db_vals, 20.0);
    if (!af_control_any_rev(mixer->afilter,
                            AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
                            db_vals))
    {
        mp_tmsg(MSGT_GLOBAL, mixer->softvol ? MSGL_V : MSGL_WARN,
                "[Mixer] No hardware mixing, inserting volume filter.\n");
        if (!(af_add(mixer->afilter, "volume")
              && af_control_any_rev(mixer->afilter,
                                    AF_CONTROL_VOLUME_LEVEL | AF_CONTROL_SET,
                                    db_vals)))
            mp_tmsg(MSGT_GLOBAL, MSGL_ERR,
                    "[Mixer] No volume control available.\n");
    }
}
Beispiel #5
0
Datei: misc.c Projekt: Ionic/mpv
void update_vo_playback_state(struct MPContext *mpctx)
{
    if (mpctx->video_out && mpctx->video_out->config_ok) {
        struct voctrl_playback_state oldstate = mpctx->vo_playback_state;
        struct voctrl_playback_state newstate = {
            .taskbar_progress = mpctx->opts->vo->taskbar_progress,
            .playing = mpctx->playing,
            .paused = mpctx->paused,
            .percent_pos = get_percent_pos(mpctx),
        };

        if (oldstate.taskbar_progress != newstate.taskbar_progress ||
            oldstate.playing != newstate.playing ||
            oldstate.paused != newstate.paused ||
            oldstate.percent_pos != newstate.percent_pos)
        {
            // Don't update progress bar if it was and still is hidden
            if ((oldstate.playing && oldstate.taskbar_progress) ||
                (newstate.playing && newstate.taskbar_progress))
            {
                vo_control_async(mpctx->video_out,
                                 VOCTRL_UPDATE_PLAYBACK_STATE, &newstate);
            }
            mpctx->vo_playback_state = newstate;
        }
    } else {
        mpctx->vo_playback_state = (struct voctrl_playback_state){ 0 };
    }
}

void update_window_title(struct MPContext *mpctx, bool force)
{
    if (!mpctx->video_out && !mpctx->ao) {
        talloc_free(mpctx->last_window_title);
        mpctx->last_window_title = NULL;
        return;
    }
    char *title = mp_property_expand_string(mpctx, mpctx->opts->wintitle);
    if (!mpctx->last_window_title || force ||
        strcmp(title, mpctx->last_window_title) != 0)
    {
        talloc_free(mpctx->last_window_title);
        mpctx->last_window_title = talloc_steal(mpctx, title);

        if (mpctx->video_out)
            vo_control(mpctx->video_out, VOCTRL_UPDATE_WINDOW_TITLE, title);

        if (mpctx->ao) {
            ao_control(mpctx->ao, AOCONTROL_UPDATE_STREAM_TITLE, title);
        }
    } else {
        talloc_free(title);
    }
}

void error_on_track(struct MPContext *mpctx, struct track *track)
{
    if (!track || !track->selected)
        return;
    mp_deselect_track(mpctx, track);
    if (track->type == STREAM_AUDIO)
        MP_INFO(mpctx, "Audio: no audio\n");
    if (track->type == STREAM_VIDEO)
        MP_INFO(mpctx, "Video: no video\n");
    if (mpctx->opts->stop_playback_on_init_failure ||
        !(mpctx->vo_chain || mpctx->ao_chain))
    {
        if (!mpctx->stop_play)
            mpctx->stop_play = PT_ERROR;
        if (mpctx->error_playing >= 0)
            mpctx->error_playing = MPV_ERROR_NOTHING_TO_PLAY;
    }
    mp_wakeup_core(mpctx);
}

int stream_dump(struct MPContext *mpctx, const char *source_filename)
{
    struct MPOpts *opts = mpctx->opts;
    stream_t *stream = stream_open(source_filename, mpctx->global);
    if (!stream)
        return -1;

    int64_t size = stream_get_size(stream);

    FILE *dest = fopen(opts->stream_dump, "wb");
    if (!dest) {
        MP_ERR(mpctx, "Error opening dump file: %s\n", mp_strerror(errno));
        return -1;
    }

    bool ok = true;

    while (mpctx->stop_play == KEEP_PLAYING && ok) {
        if (!opts->quiet && ((stream->pos / (1024 * 1024)) % 2) == 1) {
            uint64_t pos = stream->pos;
            MP_MSG(mpctx, MSGL_STATUS, "Dumping %lld/%lld...",
                   (long long int)pos, (long long int)size);
        }
        bstr data = stream_peek(stream, STREAM_MAX_BUFFER_SIZE);
        if (data.len == 0) {
            ok &= stream->eof;
            break;
        }
        ok &= fwrite(data.start, data.len, 1, dest) == 1;
        stream_skip(stream, data.len);
        mp_wakeup_core(mpctx); // don't actually sleep
        mp_idle(mpctx); // but process input
    }

    ok &= fclose(dest) == 0;
    free_stream(stream);
    return ok ? 0 : -1;
}

void merge_playlist_files(struct playlist *pl)
{
    if (!pl->first)
        return;
    char *edl = talloc_strdup(NULL, "edl://");
    for (struct playlist_entry *e = pl->first; e; e = e->next) {
        if (e != pl->first)
            edl = talloc_strdup_append_buffer(edl, ";");
        // Escape if needed
        if (e->filename[strcspn(e->filename, "=%,;\n")] ||
            bstr_strip(bstr0(e->filename)).len != strlen(e->filename))
        {
            // %length%
            edl = talloc_asprintf_append_buffer(edl, "%%%zd%%", strlen(e->filename));
        }
        edl = talloc_strdup_append_buffer(edl, e->filename);
    }
    playlist_clear(pl);
    playlist_add_file(pl, edl);
    talloc_free(edl);
}