static void mp_media_next_audio(mp_media_t *m) { struct mp_decode *d = &m->a; struct obs_source_audio audio = {0}; AVFrame *f = d->frame; if (!mp_media_can_play_frame(m, d)) return; d->frame_ready = false; if (!m->a_cb) return; for (size_t i = 0; i < MAX_AV_PLANES; i++) audio.data[i] = f->data[i]; audio.samples_per_sec = f->sample_rate * m->speed / 100; audio.speakers = convert_speaker_layout(f->channels); audio.format = convert_sample_format(f->format); audio.frames = f->nb_samples; audio.timestamp = m->base_ts + d->frame_pts - m->start_ts + m->play_sys_ts - base_sys_ts; if (audio.format == AUDIO_FORMAT_UNKNOWN) return; m->a_cb(m->opaque, &audio); }
bool ffmpeg_decode_audio(struct ffmpeg_decode *decode, uint8_t *data, size_t size, struct obs_source_audio *audio, bool *got_output) { AVPacket packet = {0}; int got_frame = false; int ret = 0; *got_output = false; copy_data(decode, data, size); av_init_packet(&packet); packet.data = decode->packet_buffer; packet.size = (int)size; if (!decode->frame) { decode->frame = av_frame_alloc(); if (!decode->frame) return false; } if (data && size) ret = avcodec_send_packet(decode->decoder, &packet); if (ret == 0) ret = avcodec_receive_frame(decode->decoder, decode->frame); got_frame = (ret == 0); if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) ret = 0; if (ret < 0) return false; else if (!got_frame) return true; for (size_t i = 0; i < MAX_AV_PLANES; i++) audio->data[i] = decode->frame->data[i]; audio->samples_per_sec = decode->frame->sample_rate; audio->format = convert_sample_format(decode->frame->format); audio->speakers = convert_speaker_layout((uint8_t)decode->decoder->channels); audio->frames = decode->frame->nb_samples; if (audio->format == AUDIO_FORMAT_UNKNOWN) return false; *got_output = true; return true; }
static bool audio_monitor_init(struct audio_monitor *monitor, obs_source_t *source) { IMMDeviceEnumerator *immde = NULL; WAVEFORMATEX *wfex = NULL; bool success = false; UINT32 frames; HRESULT hr; pthread_mutex_init_value(&monitor->playback_mutex); monitor->source = source; const char *id = obs->audio.monitoring_device_id; if (!id) { return false; } if (source->info.output_flags & OBS_SOURCE_DO_NOT_SELF_MONITOR) { obs_data_t *s = obs_source_get_settings(source); const char *s_dev_id = obs_data_get_string(s, "device_id"); bool match = devices_match(s_dev_id, id); obs_data_release(s); if (match) { monitor->ignore = true; return true; } } /* ------------------------------------------ * * Init device */ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (void**)&immde); if (FAILED(hr)) { return false; } if (strcmp(id, "default") == 0) { hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender, eConsole, &monitor->device); } else { wchar_t w_id[512]; os_utf8_to_wcs(id, 0, w_id, 512); hr = immde->lpVtbl->GetDevice(immde, w_id, &monitor->device); } if (FAILED(hr)) { goto fail; } /* ------------------------------------------ * * Init client */ hr = monitor->device->lpVtbl->Activate(monitor->device, &IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&monitor->client); if (FAILED(hr)) { goto fail; } hr = monitor->client->lpVtbl->GetMixFormat(monitor->client, &wfex); if (FAILED(hr)) { goto fail; } hr = monitor->client->lpVtbl->Initialize(monitor->client, AUDCLNT_SHAREMODE_SHARED, 0, 10000000, 0, wfex, NULL); if (FAILED(hr)) { goto fail; } /* ------------------------------------------ * * Init resampler */ const struct audio_output_info *info = audio_output_get_info( obs->audio.audio); WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)wfex; struct resample_info from; struct resample_info to; from.samples_per_sec = info->samples_per_sec; from.speakers = info->speakers; from.format = AUDIO_FORMAT_FLOAT_PLANAR; to.samples_per_sec = (uint32_t)wfex->nSamplesPerSec; to.speakers = convert_speaker_layout(ext->dwChannelMask, wfex->nChannels); to.format = AUDIO_FORMAT_FLOAT; monitor->sample_rate = (uint32_t)wfex->nSamplesPerSec; monitor->channels = wfex->nChannels; monitor->resampler = audio_resampler_create(&to, &from); if (!monitor->resampler) { goto fail; } /* ------------------------------------------ * * Init client */ hr = monitor->client->lpVtbl->GetBufferSize(monitor->client, &frames); if (FAILED(hr)) { goto fail; } hr = monitor->client->lpVtbl->GetService(monitor->client, &IID_IAudioRenderClient, (void**)&monitor->render); if (FAILED(hr)) { goto fail; } if (pthread_mutex_init(&monitor->playback_mutex, NULL) != 0) { goto fail; } hr = monitor->client->lpVtbl->Start(monitor->client); if (FAILED(hr)) { goto fail; } success = true; fail: safe_release(immde); if (wfex) CoTaskMemFree(wfex); return success; }