/** * 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; }
static int dshow_add_device(AVFormatContext *avctx, enum dshowDeviceType devtype) { struct dshow_ctx *ctx = avctx->priv_data; AM_MEDIA_TYPE type; AVCodecParameters *par; AVStream *st; int ret = AVERROR(EIO); st = avformat_new_stream(avctx, NULL); if (!st) { ret = AVERROR(ENOMEM); goto error; } st->id = devtype; ctx->capture_filter[devtype]->stream_index = st->index; libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type); par = st->codecpar; if (devtype == VideoDevice) { BITMAPINFOHEADER *bih = NULL; AVRational time_base; if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) { VIDEOINFOHEADER *v = (void *) type.pbFormat; time_base = (AVRational) { v->AvgTimePerFrame, 10000000 }; bih = &v->bmiHeader; } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) { VIDEOINFOHEADER2 *v = (void *) type.pbFormat; time_base = (AVRational) { v->AvgTimePerFrame, 10000000 }; bih = &v->bmiHeader; } if (!bih) { av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n"); goto error; } st->avg_frame_rate = av_inv_q(time_base); st->r_frame_rate = av_inv_q(time_base); par->codec_type = AVMEDIA_TYPE_VIDEO; par->width = bih->biWidth; par->height = bih->biHeight; par->codec_tag = bih->biCompression; par->format = dshow_pixfmt(bih->biCompression, bih->biBitCount); if (bih->biCompression == MKTAG('H', 'D', 'Y', 'C')) { av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n"); par->color_range = AVCOL_RANGE_MPEG; // just in case it needs this... } if (par->format == AV_PIX_FMT_NONE) { const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL }; par->codec_id = av_codec_get_id(tags, bih->biCompression); if (par->codec_id == AV_CODEC_ID_NONE) { av_log(avctx, AV_LOG_ERROR, "Unknown compression type. " "Please report type 0x%X.\n", (int) bih->biCompression); return AVERROR_PATCHWELCOME; } par->bits_per_coded_sample = bih->biBitCount; } else { par->codec_id = AV_CODEC_ID_RAWVIDEO; if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) { par->bits_per_coded_sample = bih->biBitCount; par->extradata = av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE); if (par->extradata) { par->extradata_size = 9; memcpy(par->extradata, "BottomUp", 9); } } } } else { WAVEFORMATEX *fx = NULL; if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) { fx = (void *) type.pbFormat; } if (!fx) { av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n"); goto error; } par->codec_type = AVMEDIA_TYPE_AUDIO; par->format = sample_fmt_bits_per_sample(fx->wBitsPerSample); par->codec_id = waveform_codec_id(par->format); par->sample_rate = fx->nSamplesPerSec; par->channels = fx->nChannels; } avpriv_set_pts_info(st, 64, 1, 10000000); ret = 0; error: return ret; }
static int dshow_add_device(AVFormatContext *avctx, enum dshowDeviceType devtype) { struct dshow_ctx *ctx = avctx->priv_data; AM_MEDIA_TYPE type; AVCodecContext *codec; AVStream *st; int ret = AVERROR(EIO); st = avformat_new_stream(avctx, NULL); if (!st) { ret = AVERROR(ENOMEM); goto error; } st->id = devtype; ctx->capture_filter[devtype]->stream_index = st->index; libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type); codec = st->codec; if (devtype == VideoDevice) { BITMAPINFOHEADER *bih = NULL; AVRational time_base; if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) { VIDEOINFOHEADER *v = (void *) type.pbFormat; time_base = (AVRational) { v->AvgTimePerFrame, 10000000 }; bih = &v->bmiHeader; } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) { VIDEOINFOHEADER2 *v = (void *) type.pbFormat; time_base = (AVRational) { v->AvgTimePerFrame, 10000000 }; bih = &v->bmiHeader; } if (!bih) { av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n"); goto error; } codec->time_base = time_base; codec->codec_type = AVMEDIA_TYPE_VIDEO; codec->width = bih->biWidth; codec->height = bih->biHeight; codec->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount); if (codec->pix_fmt == AV_PIX_FMT_NONE) { codec->codec_id = dshow_codecid(bih->biCompression); if (codec->codec_id == AV_CODEC_ID_NONE) { av_log(avctx, AV_LOG_ERROR, "Unknown compression type. " "Please report verbose (-v 9) debug information.\n"); dshow_read_close(avctx); return AVERROR_PATCHWELCOME; } codec->bits_per_coded_sample = bih->biBitCount; } else { codec->codec_id = AV_CODEC_ID_RAWVIDEO; if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) { codec->bits_per_coded_sample = bih->biBitCount; codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE); if (codec->extradata) { codec->extradata_size = 9; memcpy(codec->extradata, "BottomUp", 9); } } } } else { WAVEFORMATEX *fx = NULL; if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) { fx = (void *) type.pbFormat; } if (!fx) { av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n"); goto error; } codec->codec_type = AVMEDIA_TYPE_AUDIO; codec->sample_fmt = sample_fmt_bits_per_sample(fx->wBitsPerSample); codec->codec_id = waveform_codec_id(codec->sample_fmt); codec->sample_rate = fx->nSamplesPerSec; codec->channels = fx->nChannels; } avpriv_set_pts_info(st, 64, 1, 10000000); ret = 0; error: return ret; }