// Returns a "score" that serves as heuristic how lossy or hard a conversion is. // If the formats are equal, 1024 is returned. If they are gravely incompatible // (like s16<->ac3), INT_MIN is returned. If there is implied loss of precision // (like s16->s8), a value <0 is returned. int af_format_conversion_score(int dst_format, int src_format) { if (dst_format == AF_FORMAT_UNKNOWN || src_format == AF_FORMAT_UNKNOWN) return INT_MIN; if (dst_format == src_format) return 1024; // Can't be normally converted if (AF_FORMAT_IS_SPECIAL(dst_format) || AF_FORMAT_IS_SPECIAL(src_format)) return INT_MIN; int score = 1024; if (FMT_DIFF(AF_FORMAT_INTERLEAVING_MASK, dst_format, src_format)) score -= 1; // has to (de-)planarize if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) { int dst_bits = dst_format & AF_FORMAT_BITS_MASK; if ((dst_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F) { // For int->float, always prefer 32 bit float. score -= dst_bits == AF_FORMAT_32BIT ? 8 : 0; } else { // For float->int, always prefer highest bit depth int score -= 8 * (AF_FORMAT_64BIT - dst_bits); } } else { int bits = FMT_DIFF(AF_FORMAT_BITS_MASK, dst_format, src_format); if (bits > 0) { score -= 8 * bits; // has to add padding } else if (bits < 0) { score -= 1024 - 8 * bits; // has to reduce bit depth } } // Consider this the worst case. if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) score -= 2048; // has to convert float<->int return score; }
// Initialization and runtime control static int control(struct af_instance *af, int cmd, void *arg) { af_ac3enc_t *s = af->priv; static const int default_bit_rate[AC3_MAX_CHANNELS+1] = \ {0, 96000, 192000, 256000, 384000, 448000, 448000}; switch (cmd){ case AF_CONTROL_REINIT: { struct mp_audio *in = arg; struct mp_audio orig_in = *in; if (AF_FORMAT_IS_SPECIAL(in->format) || in->nch < s->cfg_min_channel_num) return AF_DETACH; mp_audio_set_format(in, s->in_sampleformat); if (in->rate != 48000 && in->rate != 44100 && in->rate != 32000) in->rate = 48000; af->data->rate = in->rate; mp_chmap_reorder_to_lavc(&in->channels); if (in->nch > AC3_MAX_CHANNELS) mp_audio_set_num_channels(in, AC3_MAX_CHANNELS); mp_audio_set_format(af->data, AF_FORMAT_AC3_BE); mp_audio_set_num_channels(af->data, 2); if (!mp_audio_config_equals(in, &orig_in)) return AF_FALSE; s->in_samples = AC3_FRAME_SIZE; if (s->cfg_add_iec61937_header) { s->out_samples = AC3_FRAME_SIZE; } else { s->out_samples = AC3_MAX_CODED_FRAME_SIZE / af->data->sstride; } af->mul = s->out_samples / (double)s->in_samples; mp_audio_buffer_reinit(s->pending, in); MP_DBG(af, "af_lavcac3enc reinit: %d, %d, %f, %d.\n", in->nch, in->rate, af->mul, s->in_samples); int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch]; if (s->lavc_actx->channels != in->nch || s->lavc_actx->sample_rate != in->rate || s->lavc_actx->bit_rate != bit_rate) { avcodec_close(s->lavc_actx); // Put sample parameters s->lavc_actx->channels = in->nch; s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels); s->lavc_actx->sample_rate = in->rate; s->lavc_actx->bit_rate = bit_rate; if (avcodec_open2(s->lavc_actx, s->lavc_acodec, NULL) < 0) { MP_ERR(af, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate); return AF_ERROR; } } if (s->lavc_actx->frame_size != AC3_FRAME_SIZE) { MP_ERR(af, "lavcac3enc: unexpected ac3 " "encoder frame size %d\n", s->lavc_actx->frame_size); return AF_ERROR; } return AF_OK; } } return AF_UNKNOWN; }
static int control(struct ao *ao, enum aocontrol cmd, void *arg) { struct priv *p = ao->priv; snd_mixer_t *handle = NULL; switch (cmd) { case AOCONTROL_GET_MUTE: case AOCONTROL_SET_MUTE: case AOCONTROL_GET_VOLUME: case AOCONTROL_SET_VOLUME: { int err; snd_mixer_elem_t *elem; snd_mixer_selem_id_t *sid; long pmin, pmax; long get_vol, set_vol; float f_multi; if (AF_FORMAT_IS_SPECIAL(ao->format)) return CONTROL_FALSE; snd_mixer_selem_id_alloca(&sid); snd_mixer_selem_id_set_index(sid, p->cfg_mixer_index); snd_mixer_selem_id_set_name(sid, p->cfg_mixer_name); err = snd_mixer_open(&handle, 0); CHECK_ALSA_ERROR("Mixer open error"); err = snd_mixer_attach(handle, p->cfg_mixer_device); CHECK_ALSA_ERROR("Mixer attach error"); err = snd_mixer_selem_register(handle, NULL, NULL); CHECK_ALSA_ERROR("Mixer register error"); err = snd_mixer_load(handle); CHECK_ALSA_ERROR("Mixer load error"); elem = snd_mixer_find_selem(handle, sid); if (!elem) { MP_VERBOSE(ao, "Unable to find simple control '%s',%i.\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); goto alsa_error; } snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax); f_multi = (100 / (float)(pmax - pmin)); switch (cmd) { case AOCONTROL_SET_VOLUME: { ao_control_vol_t *vol = arg; set_vol = vol->left / f_multi + pmin + 0.5; err = snd_mixer_selem_set_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol); CHECK_ALSA_ERROR("Error setting left channel"); MP_DBG(ao, "left=%li, ", set_vol); set_vol = vol->right / f_multi + pmin + 0.5; err = snd_mixer_selem_set_playback_volume (elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol); CHECK_ALSA_ERROR("Error setting right channel"); MP_DBG(ao, "right=%li, pmin=%li, pmax=%li, mult=%f\n", set_vol, pmin, pmax, f_multi); break; } case AOCONTROL_GET_VOLUME: { ao_control_vol_t *vol = arg; snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol); vol->left = (get_vol - pmin) * f_multi; snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol); vol->right = (get_vol - pmin) * f_multi; MP_DBG(ao, "left=%f, right=%f\n", vol->left, vol->right); break; } case AOCONTROL_SET_MUTE: { bool *mute = arg; if (!snd_mixer_selem_has_playback_switch(elem)) goto alsa_error; if (!snd_mixer_selem_has_playback_switch_joined(elem)) { snd_mixer_selem_set_playback_switch (elem, SND_MIXER_SCHN_FRONT_RIGHT, !*mute); } snd_mixer_selem_set_playback_switch (elem, SND_MIXER_SCHN_FRONT_LEFT, !*mute); break; } case AOCONTROL_GET_MUTE: { bool *mute = arg; if (!snd_mixer_selem_has_playback_switch(elem)) goto alsa_error; int tmp = 1; snd_mixer_selem_get_playback_switch (elem, SND_MIXER_SCHN_FRONT_LEFT, &tmp); *mute = !tmp; if (!snd_mixer_selem_has_playback_switch_joined(elem)) { snd_mixer_selem_get_playback_switch (elem, SND_MIXER_SCHN_FRONT_RIGHT, &tmp); *mute &= !tmp; } break; } } snd_mixer_close(handle); return CONTROL_OK; } } //end switch return CONTROL_UNKNOWN; alsa_error: if (handle) snd_mixer_close(handle); return CONTROL_ERROR; }