/** * Set audio device buffer size in milliseconds (which can directly impact * latency, depending on the device). */ static int dshow_set_audio_buffer_size(AVFormatContext *avctx, IPin *pin) { struct dshow_ctx *ctx = avctx->priv_data; IAMBufferNegotiation *buffer_negotiation = NULL; ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 }; IAMStreamConfig *config = NULL; AM_MEDIA_TYPE *type = NULL; int ret = AVERROR(EIO); if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK) goto end; if (IAMStreamConfig_GetFormat(config, &type) != S_OK) goto end; if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) goto end; props.cbBuffer = (((WAVEFORMATEX *) type->pbFormat)->nAvgBytesPerSec) * ctx->audio_buffer_size / 1000; if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (void **) &buffer_negotiation) != S_OK) goto end; if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK) goto end; ret = 0; end: if (buffer_negotiation) IAMBufferNegotiation_Release(buffer_negotiation); if (type) { if (type->pbFormat) CoTaskMemFree(type->pbFormat); CoTaskMemFree(type); } if (config) IAMStreamConfig_Release(config); return ret; }
static GstCaps * gst_dshowaudiosrc_get_caps (GstBaseSrc * basesrc) { HRESULT hres = S_OK; IBindCtx *lpbc = NULL; IMoniker *audiom = NULL; DWORD dwEaten; GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (basesrc); gunichar2 *unidevice = NULL; if (src->device) { g_free (src->device); src->device = NULL; } src->device = gst_dshow_getdevice_from_devicename (&CLSID_AudioInputDeviceCategory, &src->device_name); if (!src->device) { GST_CAT_ERROR (dshowaudiosrc_debug, "No audio device found."); return NULL; } unidevice = g_utf8_to_utf16 (src->device, strlen (src->device), NULL, NULL, NULL); if (!src->audio_cap_filter) { hres = CreateBindCtx (0, &lpbc); if (SUCCEEDED (hres)) { hres = MkParseDisplayName (lpbc, unidevice, &dwEaten, &audiom); if (SUCCEEDED (hres)) { hres = IMoniker_BindToObject (audiom, lpbc, NULL, &IID_IBaseFilter, &src->audio_cap_filter); IMoniker_Release (audiom); } IBindCtx_Release (lpbc); } } if (src->audio_cap_filter && !src->caps) { /* get the capture pins supported types */ IPin *capture_pin = NULL; IEnumPins *enumpins = NULL; HRESULT hres; hres = IBaseFilter_EnumPins (src->audio_cap_filter, &enumpins); if (SUCCEEDED (hres)) { while (IEnumPins_Next (enumpins, 1, &capture_pin, NULL) == S_OK) { IKsPropertySet *pKs = NULL; hres = IPin_QueryInterface (capture_pin, &IID_IKsPropertySet, (void **) &pKs); if (SUCCEEDED (hres) && pKs) { DWORD cbReturned; GUID pin_category; RPC_STATUS rpcstatus; hres = IKsPropertySet_Get (pKs, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, &pin_category, sizeof (GUID), &cbReturned); /* we only want capture pins */ if (UuidCompare (&pin_category, &PIN_CATEGORY_CAPTURE, &rpcstatus) == 0) { IAMStreamConfig *streamcaps = NULL; if (SUCCEEDED (IPin_QueryInterface (capture_pin, &IID_IAMStreamConfig, (void **) &streamcaps))) { src->caps = gst_dshowaudiosrc_getcaps_from_streamcaps (src, capture_pin, streamcaps); IAMStreamConfig_Release (streamcaps); } } IKsPropertySet_Release (pKs); } IPin_Release (capture_pin); } IEnumPins_Release (enumpins); } } if (unidevice) { g_free (unidevice); } if (src->caps) { return gst_caps_ref (src->caps); } return NULL; }
/** * Cycle through available formats using the specified pin, * try to set parameters specified through AVOptions and if successful * return 1 in *pformat_set. * If pformat_set is NULL, list all pin capabilities. */ static void dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, IPin *pin, int *pformat_set) { struct dshow_ctx *ctx = avctx->priv_data; IAMStreamConfig *config = NULL; AM_MEDIA_TYPE *type = NULL; int format_set = 0; void *caps = NULL; int i, n, size, r; if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK) return; if (IAMStreamConfig_GetNumberOfCapabilities(config, &n, &size) != S_OK) goto end; caps = av_malloc(size); if (!caps) goto end; for (i = 0; i < n && !format_set; i++) { r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps); if (r != S_OK) goto next; #if DSHOWDEBUG ff_print_AM_MEDIA_TYPE(type); #endif if (devtype == VideoDevice) { VIDEO_STREAM_CONFIG_CAPS *vcaps = caps; BITMAPINFOHEADER *bih; int64_t *fr; const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL }; #if DSHOWDEBUG ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps); #endif if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) { VIDEOINFOHEADER *v = (void *) type->pbFormat; fr = &v->AvgTimePerFrame; bih = &v->bmiHeader; } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) { VIDEOINFOHEADER2 *v = (void *) type->pbFormat; fr = &v->AvgTimePerFrame; bih = &v->bmiHeader; } else { goto next; } if (!pformat_set) { enum AVPixelFormat pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount); if (pix_fmt == AV_PIX_FMT_NONE) { enum AVCodecID codec_id = av_codec_get_id(tags, bih->biCompression); AVCodec *codec = avcodec_find_decoder(codec_id); if (codec_id == AV_CODEC_ID_NONE || !codec) { av_log(avctx, AV_LOG_INFO, " unknown compression type 0x%X", (int) bih->biCompression); } else { av_log(avctx, AV_LOG_INFO, " vcodec=%s", codec->name); } } else { av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(pix_fmt)); } av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n", vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy, 1e7 / vcaps->MaxFrameInterval, vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy, 1e7 / vcaps->MinFrameInterval); continue; } if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) { if (ctx->video_codec_id != av_codec_get_id(tags, bih->biCompression)) goto next; } if (ctx->pixel_format != AV_PIX_FMT_NONE && ctx->pixel_format != dshow_pixfmt(bih->biCompression, bih->biBitCount)) { goto next; } if (ctx->framerate) { int64_t framerate = ((int64_t) ctx->requested_framerate.den*10000000) / ctx->requested_framerate.num; if (framerate > vcaps->MaxFrameInterval || framerate < vcaps->MinFrameInterval) goto next; *fr = framerate; } if (ctx->requested_width && ctx->requested_height) { if (ctx->requested_width > vcaps->MaxOutputSize.cx || ctx->requested_width < vcaps->MinOutputSize.cx || ctx->requested_height > vcaps->MaxOutputSize.cy || ctx->requested_height < vcaps->MinOutputSize.cy) goto next; bih->biWidth = ctx->requested_width; bih->biHeight = ctx->requested_height; } } else { AUDIO_STREAM_CONFIG_CAPS *acaps = caps; WAVEFORMATEX *fx; #if DSHOWDEBUG ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps); #endif if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) { fx = (void *) type->pbFormat; } else { goto next; } if (!pformat_set) { av_log(avctx, AV_LOG_INFO, " min ch=%lu bits=%lu rate=%6lu max ch=%lu bits=%lu rate=%6lu\n", acaps->MinimumChannels, acaps->MinimumBitsPerSample, acaps->MinimumSampleFrequency, acaps->MaximumChannels, acaps->MaximumBitsPerSample, acaps->MaximumSampleFrequency); continue; } if (ctx->sample_rate) { if (ctx->sample_rate > acaps->MaximumSampleFrequency || ctx->sample_rate < acaps->MinimumSampleFrequency) goto next; fx->nSamplesPerSec = ctx->sample_rate; } if (ctx->sample_size) { if (ctx->sample_size > acaps->MaximumBitsPerSample || ctx->sample_size < acaps->MinimumBitsPerSample) goto next; fx->wBitsPerSample = ctx->sample_size; } if (ctx->channels) { if (ctx->channels > acaps->MaximumChannels || ctx->channels < acaps->MinimumChannels) goto next; fx->nChannels = ctx->channels; } } if (IAMStreamConfig_SetFormat(config, type) != S_OK) goto next; format_set = 1; next: if (type->pbFormat) CoTaskMemFree(type->pbFormat); CoTaskMemFree(type); } end: IAMStreamConfig_Release(config); av_free(caps); if (pformat_set) *pformat_set = format_set; }
/** * Cycle through available formats using the specified pin, * try to set parameters specified through AVOptions and if successful * return 1 in *pformat_set. * If pformat_set is NULL, list all pin capabilities. */ static void dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype, IPin *pin, int *pformat_set) { struct dshow_ctx *ctx = avctx->priv_data; IAMStreamConfig *config = NULL; AM_MEDIA_TYPE *type = NULL; int format_set = 0; void *caps = NULL; int i, n, size; if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK) return; if (IAMStreamConfig_GetNumberOfCapabilities(config, &n, &size) != S_OK) goto end; caps = av_malloc(size); if (!caps) goto end; for (i = 0; i < n && !format_set; i++) { IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps); #if DSHOWDEBUG ff_print_AM_MEDIA_TYPE(type); #endif if (devtype == VideoDevice) { VIDEO_STREAM_CONFIG_CAPS *vcaps = caps; BITMAPINFOHEADER *bih; int64_t *fr; #if DSHOWDEBUG ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps); #endif if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) { VIDEOINFOHEADER *v = (void *) type->pbFormat; fr = &v->AvgTimePerFrame; bih = &v->bmiHeader; } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) { VIDEOINFOHEADER2 *v = (void *) type->pbFormat; fr = &v->AvgTimePerFrame; bih = &v->bmiHeader; } else { goto next; } if (!pformat_set) { av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g\n", vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy, 1e7 / vcaps->MaxFrameInterval, vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy, 1e7 / vcaps->MinFrameInterval); continue; } if (ctx->framerate) { int64_t framerate = ((int64_t) ctx->requested_framerate.den*10000000) / ctx->requested_framerate.num; if (framerate > vcaps->MaxFrameInterval || framerate < vcaps->MinFrameInterval) goto next; *fr = framerate; } if (ctx->video_size) { if (ctx->requested_width > vcaps->MaxOutputSize.cx || ctx->requested_width < vcaps->MinOutputSize.cx || ctx->requested_height > vcaps->MaxOutputSize.cy || ctx->requested_height < vcaps->MinOutputSize.cy) goto next; bih->biWidth = ctx->requested_width; bih->biHeight = ctx->requested_height; } } else { AUDIO_STREAM_CONFIG_CAPS *acaps = caps; WAVEFORMATEX *fx; #if DSHOWDEBUG ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps); #endif if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) { fx = (void *) type->pbFormat; } else { goto next; } if (!pformat_set) { av_log(avctx, AV_LOG_INFO, " min ch=%lu bits=%lu rate=%6lu max ch=%lu bits=%lu rate=%6lu\n", acaps->MinimumChannels, acaps->MinimumBitsPerSample, acaps->MinimumSampleFrequency, acaps->MaximumChannels, acaps->MaximumBitsPerSample, acaps->MaximumSampleFrequency); continue; } if (ctx->sample_rate) { if (ctx->sample_rate > acaps->MaximumSampleFrequency || ctx->sample_rate < acaps->MinimumSampleFrequency) goto next; fx->nSamplesPerSec = ctx->sample_rate; } if (ctx->sample_size) { if (ctx->sample_size > acaps->MaximumBitsPerSample || ctx->sample_size < acaps->MinimumBitsPerSample) goto next; fx->wBitsPerSample = ctx->sample_size; } if (ctx->channels) { if (ctx->channels > acaps->MaximumChannels || ctx->channels < acaps->MinimumChannels) goto next; fx->nChannels = ctx->channels; } } if (IAMStreamConfig_SetFormat(config, type) != S_OK) goto next; format_set = 1; next: if (type->pbFormat) CoTaskMemFree(type->pbFormat); CoTaskMemFree(type); } end: IAMStreamConfig_Release(config); if (caps) av_free(caps); if (pformat_set) *pformat_set = format_set; }