static int try_format(struct wasapi_state *state, struct ao *const ao, int bits, int samplerate, const struct mp_chmap channels) { WAVEFORMATEXTENSIBLE wformat; set_format(&wformat, bits / 8, samplerate, channels.num, mp_chmap_to_waveext(&channels)); int af_format = format_set_bits(ao->format, bits, bits == 32); EnterCriticalSection(&state->print_lock); mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: trying %dch %s @ %dhz\n", channels.num, af_fmt_to_str(af_format), samplerate); LeaveCriticalSection(&state->print_lock); union WAVEFMT u; u.extensible = &wformat; WAVEFORMATEX *closestMatch; HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient, state->share_mode, u.ex, &closestMatch); if (closestMatch) { if (closestMatch->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { u.ex = closestMatch; wformat = *u.extensible; } else { wformat.Format = *closestMatch; } CoTaskMemFree(closestMatch); } if (hr == S_FALSE) { if (set_ao_format(state, ao, wformat)) { EnterCriticalSection(&state->print_lock); mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: accepted as %dch %s @ %dhz\n", ao->channels.num, af_fmt_to_str(ao->format), ao->samplerate); LeaveCriticalSection(&state->print_lock); return 1; } } if (hr == S_OK || (!state->opt_exclusive && hr == AUDCLNT_E_UNSUPPORTED_FORMAT)) { // AUDCLNT_E_UNSUPPORTED_FORMAT here means "works in shared, doesn't in exclusive" if (set_ao_format(state, ao, wformat)) { EnterCriticalSection(&state->print_lock); mp_msg(MSGT_AO, MSGL_V, "ao-wasapi: %dch %s @ %dhz accepted\n", ao->channels.num, af_fmt_to_str(af_format), samplerate); LeaveCriticalSection(&state->print_lock); return 1; } } return 0; }
static int af_open(struct af_instance* af){ af_ac3enc_t *s = af->priv; af->control=control; af->uninit=uninit; af->filter_frame = filter_frame; af->filter_out = filter_out; s->lavc_acodec = avcodec_find_encoder_by_name("ac3"); if (!s->lavc_acodec) { MP_ERR(af, "Audio LAVC, couldn't find encoder for codec %s.\n", "ac3"); return AF_ERROR; } s->lavc_actx = avcodec_alloc_context3(s->lavc_acodec); if (!s->lavc_actx) { MP_ERR(af, "Audio LAVC, couldn't allocate context!\n"); return AF_ERROR; } const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts; for (int i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++) { s->in_sampleformat = af_from_avformat(fmts[i]); if (s->in_sampleformat) { s->lavc_actx->sample_fmt = fmts[i]; break; } } if (!s->in_sampleformat) { MP_ERR(af, "Audio LAVC, encoder doesn't " "support expected sample formats!\n"); return AF_ERROR; } MP_VERBOSE(af, "[af_lavcac3enc]: in sample format: %s\n", af_fmt_to_str(s->in_sampleformat)); av_init_packet(&s->pkt); s->input = talloc_zero(s, struct mp_audio); if (s->cfg_bit_rate) { int i; for (i = 0; i < 19; i++) { if (ac3_bitrate_tab[i] == s->cfg_bit_rate) break; } if (i >= 19) { MP_WARN(af, "af_lavcac3enc unable set unsupported " "bitrate %d, use default bitrate (check manpage to see " "supported bitrates).\n", s->cfg_bit_rate); s->cfg_bit_rate = 0; } } return AF_OK; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { switch(cmd){ case AF_CONTROL_REINIT: ; *af->data = *(struct mp_audio*)arg; MP_VERBOSE(af, "Was reinitialized: %iHz/%ich/%s\n", af->data->rate,af->data->nch,af_fmt_to_str(af->data->format)); return AF_OK; } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance* af, int cmd, void* arg) { switch(cmd){ case AF_CONTROL_REINIT: ; *af->data = *(struct mp_audio*)arg; mp_msg(MSGT_AFILTER, MSGL_V, "[dummy] Was reinitialized: %iHz/%ich/%s\n", af->data->rate,af->data->nch,af_fmt_to_str(af->data->format)); return AF_OK; } return AF_UNKNOWN; }
static char *audio_config_to_str_buf(char *buf, size_t buf_sz, int rate, int format, struct mp_chmap channels) { char ch[128]; mp_chmap_to_str_buf(ch, sizeof(ch), &channels); char *hr_ch = mp_chmap_to_str_hr(&channels); if (strcmp(hr_ch, ch) != 0) mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch); snprintf(buf, buf_sz, "%dHz %s %dch %s", rate, ch, channels.num, af_fmt_to_str(format)); return buf; }
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders) { assert(!d_audio->ad_driver); audio_reset_decoding(d_audio); struct mp_decoder_entry *decoder = NULL; struct mp_decoder_list *list = audio_select_decoders(d_audio->header->codec, audio_decoders); mp_print_decoders(MSGT_DECAUDIO, MSGL_V, "Codec list:", list); for (int n = 0; n < list->num_entries; n++) { struct mp_decoder_entry *sel = &list->entries[n]; const struct ad_functions *driver = find_driver(sel->family); if (!driver) continue; mp_msg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder %s:%s\n", sel->family, sel->decoder); d_audio->ad_driver = driver; if (init_audio_codec(d_audio, sel->decoder)) { decoder = sel; break; } mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for " "%s:%s\n", sel->family, sel->decoder); } if (d_audio->ad_driver) { d_audio->decoder_desc = talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family, decoder->decoder); mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s\n", d_audio->decoder_desc); mp_msg(MSGT_DECAUDIO, MSGL_V, "AUDIO: %d Hz, %d ch, %s\n", d_audio->decoded.rate, d_audio->decoded.channels.num, af_fmt_to_str(d_audio->decoded.format)); mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n", d_audio->i_bps * 8, d_audio->decoded.rate, d_audio->decoded.channels.num); } else { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Failed to initialize an audio decoder for codec '%s'.\n", d_audio->header->codec ? d_audio->header->codec : "<unknown>"); } talloc_free(list); return !!d_audio->ad_driver; }
static char *waveformat_to_str_buf(char *buf, size_t buf_size, WAVEFORMATEX *wf) { struct mp_chmap channels; chmap_from_waveformat(&channels, wf); unsigned valid_bits = waveformat_valid_bits(wf); char validstr[12] = ""; if (valid_bits != wf->wBitsPerSample) snprintf(validstr, sizeof(validstr), " (%u valid)", valid_bits); snprintf(buf, buf_size, "%s %s%s @ %uhz", mp_chmap_to_str(&channels), af_fmt_to_str(format_from_waveformat(wf)), validstr, (unsigned) wf->nSamplesPerSec); return buf; }
static int demux_open_tv(demuxer_t *demuxer, enum demux_check check) { tvi_handle_t *tvh; const tvi_functions_t *funcs; if (check > DEMUX_CHECK_REQUEST || demuxer->stream->type != STREAMTYPE_TV) return -1; tv_param_t *params = mp_get_config_group(demuxer, demuxer->global, &tv_params_conf); bstr urlparams = bstr0(demuxer->stream->path); bstr channel, input; bstr_split_tok(urlparams, "/", &channel, &input); if (channel.len) { talloc_free(params->channels); params->channel = bstrto0(NULL, channel); } if (input.len) { bstr r; params->input = bstrtoll(input, &r, 0); if (r.len) { MP_ERR(demuxer->stream, "invalid input: '%.*s'\n", BSTR_P(input)); return -1; } } assert(demuxer->priv==NULL); if(!(tvh=tv_begin(params, demuxer->log))) return -1; if (!tvh->functions->init(tvh->priv)) return -1; tvh->demuxer = demuxer; if (!open_tv(tvh)){ tv_uninit(tvh); return -1; } funcs = tvh->functions; demuxer->priv=tvh; struct sh_stream *sh_v = demux_alloc_sh_stream(STREAM_VIDEO); /* get IMAGE FORMAT */ int fourcc; funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &fourcc); if (fourcc == MP_FOURCC_MJPEG) { sh_v->codec->codec = "mjpeg"; } else { sh_v->codec->codec = "rawvideo"; sh_v->codec->codec_tag = fourcc; } /* set FPS and FRAMETIME */ if(!sh_v->codec->fps) { float tmp; if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE) sh_v->codec->fps = 25.0f; /* on PAL */ else sh_v->codec->fps = tmp; } if (tvh->tv_param->fps != -1.0f) sh_v->codec->fps = tvh->tv_param->fps; /* If playback only mode, go to immediate mode, fail silently */ if(tvh->tv_param->immediate == 1) { funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0); tvh->tv_param->audio = 0; } /* set width */ funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_v->codec->disp_w); /* set height */ funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_v->codec->disp_h); demux_add_sh_stream(demuxer, sh_v); demuxer->seekable = 0; /* here comes audio init */ if (tvh->tv_param->audio && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) { int audio_format; /* yeah, audio is present */ funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE, &tvh->tv_param->audiorate); if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE) goto no_audio; switch(audio_format) { // This is the only format any of the current inputs generate. case AF_FORMAT_S16: break; default: MP_ERR(tvh, "Audio type '%s' unsupported!\n", af_fmt_to_str(audio_format)); goto no_audio; } struct sh_stream *sh_a = demux_alloc_sh_stream(STREAM_AUDIO); funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, &sh_a->codec->samplerate); int nchannels = sh_a->codec->channels.num; funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, &nchannels); mp_chmap_from_channels(&sh_a->codec->channels, nchannels); // s16ne mp_set_pcm_codec(sh_a->codec, true, false, 16, BYTE_ORDER == BIG_ENDIAN); demux_add_sh_stream(demuxer, sh_a); MP_VERBOSE(tvh, " TV audio: %d channels, %d bits, %d Hz\n", nchannels, 16, sh_a->codec->samplerate); } no_audio: if(!(funcs->start(tvh->priv))){ // start failed :( tv_uninit(tvh); return -1; } /* set color eq */ tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tvh->tv_param->brightness); tv_set_color_options(tvh, TV_COLOR_HUE, tvh->tv_param->hue); tv_set_color_options(tvh, TV_COLOR_SATURATION, tvh->tv_param->saturation); tv_set_color_options(tvh, TV_COLOR_CONTRAST, tvh->tv_param->contrast); if(tvh->tv_param->gain!=-1) if(funcs->control(tvh->priv,TVI_CONTROL_VID_SET_GAIN,&tvh->tv_param->gain)!=TVI_CONTROL_TRUE) MP_WARN(tvh, "Unable to set gain control!\n"); return 0; }
/** \brief setup sound device \param rate samplerate \param channels number of channels \param format format \param flags unused \return 0=success -1=fail */ static int init(struct ao *ao) { struct priv *p = ao->priv; int res; if (!InitDirectSound(ao)) return -1; ao->no_persistent_volume = true; p->audio_volume = 100; // ok, now create the buffers WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; int format = af_fmt_from_planar(ao->format); int rate = ao->samplerate; if (AF_FORMAT_IS_AC3(format)) format = AF_FORMAT_AC3; else { struct mp_chmap_sel sel = {0}; mp_chmap_sel_add_waveext(&sel); if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) return -1; } switch (format) { case AF_FORMAT_AC3: case AF_FORMAT_S24_LE: case AF_FORMAT_S16_LE: case AF_FORMAT_U8: break; default: MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n", af_fmt_to_str(format)); format = AF_FORMAT_S16_LE; } //set our audio parameters ao->samplerate = rate; ao->format = format; ao->bps = ao->channels.num * rate * (af_fmt2bits(format) >> 3); int buffersize = ao->bps; // space for 1 sec MP_VERBOSE(ao, "Samplerate:%iHz Channels:%i Format:%s\n", rate, ao->channels.num, af_fmt_to_str(format)); MP_VERBOSE(ao, "Buffersize:%d bytes (%d msec)\n", buffersize, buffersize / ao->bps * 1000); //fill waveformatex ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); wformat.Format.cbSize = (ao->channels.num > 2) ? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0; wformat.Format.nChannels = ao->channels.num; wformat.Format.nSamplesPerSec = rate; if (AF_FORMAT_IS_AC3(format)) { wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; wformat.Format.wBitsPerSample = 16; wformat.Format.nBlockAlign = 4; } else { wformat.Format.wFormatTag = (ao->channels.num > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; wformat.Format.wBitsPerSample = af_fmt2bits(format); wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); } // fill in primary sound buffer descriptor memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC)); dsbpridesc.dwSize = sizeof(DSBUFFERDESC); dsbpridesc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbpridesc.dwBufferBytes = 0; dsbpridesc.lpwfxFormat = NULL; // fill in the secondary sound buffer (=stream buffer) descriptor memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); dsbdesc.dwSize = sizeof(DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */ | DSBCAPS_GLOBALFOCUS /** Allows background playing */ | DSBCAPS_CTRLVOLUME; /** volume control enabled */ if (ao->channels.num > 2) { wformat.dwChannelMask = mp_chmap_to_waveext(&ao->channels); wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample; // Needed for 5.1 on emu101k - shit soundblaster dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE; } wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign; dsbdesc.dwBufferBytes = buffersize; dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat; p->buffer_size = dsbdesc.dwBufferBytes; p->write_offset = 0; p->min_free_space = wformat.Format.nBlockAlign; p->outburst = wformat.Format.nBlockAlign * 512; // create primary buffer and set its format res = IDirectSound_CreateSoundBuffer(p->hds, &dsbpridesc, &p->hdspribuf, NULL); if (res != DS_OK) { UninitDirectSound(ao); MP_ERR(ao, "cannot create primary buffer (%s)\n", dserr2str(res)); return -1; } res = IDirectSoundBuffer_SetFormat(p->hdspribuf, (WAVEFORMATEX *)&wformat); if (res != DS_OK) { MP_WARN(ao, "cannot set primary buffer format (%s), using " "standard setting (bad quality)", dserr2str(res)); } MP_VERBOSE(ao, "primary buffer created\n"); // now create the stream buffer res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL); if (res != DS_OK) { if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) { // Try without DSBCAPS_LOCHARDWARE dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL); } if (res != DS_OK) { UninitDirectSound(ao); MP_ERR(ao, "cannot create secondary (stream)buffer (%s)\n", dserr2str(res)); return -1; } } MP_VERBOSE(ao, "secondary (stream)buffer created\n"); return 0; }
static int demux_open_tv(demuxer_t *demuxer, enum demux_check check) { tvi_handle_t *tvh; sh_video_t *sh_video; sh_audio_t *sh_audio = NULL; const tvi_functions_t *funcs; if (check > DEMUX_CHECK_REQUEST || demuxer->stream->type != STREAMTYPE_TV) return -1; demuxer->priv=NULL; if(!(tvh=tv_begin(demuxer->stream->priv, demuxer->log))) return -1; if (!tvh->functions->init(tvh->priv)) return -1; tvh->demuxer = demuxer; if (!open_tv(tvh)){ tv_uninit(tvh); return -1; } funcs = tvh->functions; demuxer->priv=tvh; struct sh_stream *sh_v = new_sh_stream(demuxer, STREAM_VIDEO); sh_video = sh_v->video; /* get IMAGE FORMAT */ int fourcc; funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FORMAT, &fourcc); if (fourcc == MP_FOURCC_MJPEG) { sh_v->codec = "mjpeg"; } else { sh_v->codec = "rawvideo"; sh_v->format = fourcc; } /* set FPS and FRAMETIME */ if(!sh_video->fps) { float tmp; if (funcs->control(tvh->priv, TVI_CONTROL_VID_GET_FPS, &tmp) != TVI_CONTROL_TRUE) sh_video->fps = 25.0f; /* on PAL */ else sh_video->fps = tmp; } if (tvh->tv_param->fps != -1.0f) sh_video->fps = tvh->tv_param->fps; /* If playback only mode, go to immediate mode, fail silently */ if(tvh->tv_param->immediate == 1) { funcs->control(tvh->priv, TVI_CONTROL_IMMEDIATE, 0); tvh->tv_param->noaudio = 1; } /* set width */ funcs->control(tvh->priv, TVI_CONTROL_VID_GET_WIDTH, &sh_video->disp_w); /* set height */ funcs->control(tvh->priv, TVI_CONTROL_VID_GET_HEIGHT, &sh_video->disp_h); demuxer->seekable = 0; /* here comes audio init */ if (tvh->tv_param->noaudio == 0 && funcs->control(tvh->priv, TVI_CONTROL_IS_AUDIO, 0) == TVI_CONTROL_TRUE) { int audio_format; /* yeah, audio is present */ funcs->control(tvh->priv, TVI_CONTROL_AUD_SET_SAMPLERATE, &tvh->tv_param->audiorate); if (funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_FORMAT, &audio_format) != TVI_CONTROL_TRUE) goto no_audio; switch(audio_format) { case AF_FORMAT_U8: case AF_FORMAT_S8: case AF_FORMAT_U16_LE: case AF_FORMAT_U16_BE: case AF_FORMAT_S16_LE: case AF_FORMAT_S16_BE: case AF_FORMAT_S32_LE: case AF_FORMAT_S32_BE: break; case AF_FORMAT_MPEG2: default: MP_ERR(tvh, "Audio type '%s' unsupported!\n", af_fmt_to_str(audio_format)); goto no_audio; } struct sh_stream *sh_a = new_sh_stream(demuxer, STREAM_AUDIO); sh_audio = sh_a->audio; funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_SAMPLERATE, &sh_audio->samplerate); int nchannels = sh_audio->channels.num; funcs->control(tvh->priv, TVI_CONTROL_AUD_GET_CHANNELS, &nchannels); mp_chmap_from_channels(&sh_audio->channels, nchannels); sh_a->codec = "mp-pcm"; sh_a->format = audio_format; int samplesize = af_fmt2bits(audio_format) / 8; sh_audio->i_bps = sh_audio->samplerate * samplesize * sh_audio->channels.num; // emulate WF for win32 codecs: sh_audio->wf = talloc_zero(sh_audio, MP_WAVEFORMATEX); sh_audio->wf->wFormatTag = sh_a->format; sh_audio->wf->nChannels = sh_audio->channels.num; sh_audio->wf->wBitsPerSample = samplesize * 8; sh_audio->wf->nSamplesPerSec = sh_audio->samplerate; sh_audio->wf->nBlockAlign = samplesize * sh_audio->channels.num; sh_audio->wf->nAvgBytesPerSec = sh_audio->i_bps; MP_VERBOSE(tvh, " TV audio: %d channels, %d bits, %d Hz\n", sh_audio->wf->nChannels, sh_audio->wf->wBitsPerSample, sh_audio->wf->nSamplesPerSec); } no_audio: if(!(funcs->start(tvh->priv))){ // start failed :( tv_uninit(tvh); return -1; } /* set color eq */ tv_set_color_options(tvh, TV_COLOR_BRIGHTNESS, tvh->tv_param->brightness); tv_set_color_options(tvh, TV_COLOR_HUE, tvh->tv_param->hue); tv_set_color_options(tvh, TV_COLOR_SATURATION, tvh->tv_param->saturation); tv_set_color_options(tvh, TV_COLOR_CONTRAST, tvh->tv_param->contrast); if(tvh->tv_param->gain!=-1) if(funcs->control(tvh->priv,TVI_CONTROL_VID_SET_GAIN,&tvh->tv_param->gain)!=TVI_CONTROL_TRUE) MP_WARN(tvh, "Unable to set gain control!\n"); return 0; }
.nAvgBytesPerSec = (ao->samplerate) * (ao->channels.num * 2), .nBlockAlign = ao->channels.num * 2, .wBitsPerSample = 16, .cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), }, .Samples.wValidBitsPerSample = 16, .dwChannelMask = mp_chmap_to_waveext(&ao->channels), .SubFormat = local_KSDATAFORMAT_SUBTYPE_PCM, }; wformat.SubFormat.Data1 = WAVE_FORMAT_DOLBY_AC3_SPDIF; // see INIT_WAVEFORMATEX_GUID macro union WAVEFMT u; u.extensible = &wformat; MP_VERBOSE(ao, "trying passthrough for %s...\n", af_fmt_to_str((ao->format&~AF_FORMAT_END_MASK) | AF_FORMAT_LE)); HRESULT hr = IAudioClient_IsFormatSupported(state->pAudioClient, state->share_mode, u.ex, NULL); if (!FAILED(hr)) { ao->format = (ao->format&~AF_FORMAT_END_MASK) | AF_FORMAT_LE; state->format = wformat; return 1; } return 0; } static int find_formats(struct ao *const ao) { struct wasapi_state *state = (struct wasapi_state *)ao->priv;
int AudioController::reinitialize(mp_audio *in) { if (!in) return AF_ERROR; auto makeFormat = [] (const mp_audio *audio) { AudioFormat format; format.m_samplerate = audio->rate/1000.0; // kHz format.m_bitrate = audio->rate*audio->nch*audio->bps*8; format.m_bits = audio->bps*8; format.m_channels = ChannelLayoutInfo::description(ChannelLayoutMap::toLayout(audio->channels)); format.m_type = af_fmt_to_str(audio->format); return format; }; d->input = makeFormat(in); auto out = d->af->data; out->rate = in->rate; bool ret = true; if (!isSupported(in->format)) { ret = false; mp_audio_set_format(in, af_fmt_is_planar(in->format) ? AF_FORMAT_FLOATP : AF_FORMAT_FLOAT); } if (d->fmt_conv) { mp_audio_set_format(out, d->fmt_conv); d->fmt_conv = AF_FORMAT_UNKNOWN; } else mp_audio_set_format(out, in->format); d->chmap = in->channels; if (!mp_chmap_from_str(&d->chmap, bstr0(ChannelLayoutInfo::data(d->layout).constData()))) _Error("Cannot find matched channel layout for '%%'", ChannelLayoutInfo::description(d->layout)); mp_audio_set_channels(out, &d->chmap); if (d->outrate != 0) out->rate = d->outrate; if (!ret) return false; d->af->mul = (double)out->channels.num/in->channels.num; if (d->tempoScalerActivated) d->af->mul /= d->scale; if ((d->resample = out->rate != in->rate)) { d->af->mul *= (double)out->rate/in->rate; const auto nch = in->channels.num;/*mp_chmap_to_lavc_unchecked(&in->channels);*/ const auto fmt = af_to_avformat(in->format); if (!d->swr) d->swr = swr_alloc(); av_opt_set_int(d->swr, "in_channel_count", nch, 0); av_opt_set_int(d->swr, "out_channel_count", nch, 0); av_opt_set_int(d->swr, "in_sample_rate", in->rate, 0); av_opt_set_int(d->swr, "out_sample_rate", out->rate, 0); av_opt_set_sample_fmt(d->swr, "in_sample_fmt", fmt, 0); av_opt_set_sample_fmt(d->swr, "out_sample_fmt", fmt, 0); swr_init(d->swr); if (!d->resampled) d->resampled = talloc_zero(nullptr, mp_audio); *d->resampled = *in; d->resampled->rate = out->rate; in = d->resampled; } d->output = makeFormat(out); const AudioDataFormat fmt_in(*in), fmt_out(*out); check(d->mixer, d->clip, fmt_in, fmt_out); d->mixer->setOutput(out); d->mixer->setChannelLayoutMap(d->map); d->dirty = 0xffffffff; return true; }