[FFmpeg-devel] Fw: [PATCH] DirectShow patches

Stefano Sabatini stefano.sabatini-lala at poste.it
Tue Sep 6 14:40:40 CEST 2011


On date Sunday 2011-09-04 15:09:20 +0200, Michael Niedermayer encoded:
> Hi list
> 
> Here are some patches from ramiro that he had difficulty sending to
> ffmpeg-devel
> 
> -- 
> Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
> 
> Incandescent light bulbs waste a lot of energy as heat so the EU forbids them.
> Their replacement, compact fluorescent lamps, much more expensive, dont fit in
> many old lamps, flicker, contain toxic mercury, produce a fraction of the light
> that is claimed and in a unnatural spectrum rendering colors different than
> in natural light. Ah and we now need to turn the heaters up more in winter to
> compensate the lower wasted heat. Who wins? Not the environment, thats for sure

> From 258047ff61bc67ddf14145e052a7ef8a1472e77c Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:33:07 -0300
> Subject: [PATCH 1/7] vfwcap: actually use framerate option
> 
> ---
>  libavdevice/vfwcap.c |    5 +++++
>  1 files changed, 5 insertions(+), 0 deletions(-)
> 
> diff --git a/libavdevice/vfwcap.c b/libavdevice/vfwcap.c
> index 6f42f9e..e5ecf84 100644
> --- a/libavdevice/vfwcap.c
> +++ b/libavdevice/vfwcap.c
> @@ -314,6 +314,11 @@ static int vfw_read_header(AVFormatContext *s, AVFormatParameters *ap)
>  
>      dump_bih(s, &bi->bmiHeader);
>  
> +    ret = av_parse_video_rate(&framerate_q, ctx->framerate);
> +    if (ret < 0) {
> +        av_log(s, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
> +        goto fail;
> +    }
>  
>      if (ctx->video_size) {
>          ret = av_parse_video_size(&bi->bmiHeader.biWidth, &bi->bmiHeader.biHeight, ctx->video_size);
> -- 
> 1.7.4.1
> 

FineOfCourse.

> From 5a9489310a45a71d81903ebdba250c6fc45a89de Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:33:24 -0300
> Subject: [PATCH 2/7] dshow: remove some unused code
> 
> ---
>  libavdevice/dshow.c |    7 +------
>  1 files changed, 1 insertions(+), 6 deletions(-)
> 
> diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> index 348fda6..9913569 100644
> --- a/libavdevice/dshow.c
> +++ b/libavdevice/dshow.c
> @@ -19,8 +19,6 @@
>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>   */
>  
> -#include "libavformat/timefilter.h"
> -
>  #include "avdevice.h"
>  #include "dshow.h"
>  
> @@ -42,8 +40,6 @@ struct dshow_ctx {
>      unsigned int video_frame_num;
>  
>      IMediaControl *control;
> -
> -    TimeFilter *timefilter;
>  };
>  
>  static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> @@ -223,7 +219,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>      const char *device_name = ctx->device_name[devtype];
>      int ret = AVERROR(EIO);
>      IPin *pin;
> -    int r, i;
> +    int r;
>  
>      const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
>                                     &CLSID_AudioInputDeviceCategory };
> @@ -287,7 +283,6 @@ fail1:
>          goto error;
>      }
>  
> -    i = 0;
>      while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !device_pin) {
>          IKsPropertySet *p = NULL;
>          IEnumMediaTypes *types;
> -- 
> 1.7.4.1

Trivial, looks fine.

> From 7f31d80dcb137fdd15bfef855e4dabe6aca9f527 Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:33:41 -0300
> Subject: [PATCH 3/7] dshow: add option to list devices
> 
> ---
>  libavdevice/dshow.c |   43 ++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 42 insertions(+), 1 deletions(-)
> 
> diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> index 9913569..555a2b8 100644
> --- a/libavdevice/dshow.c
> +++ b/libavdevice/dshow.c
> @@ -19,14 +19,20 @@
>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>   */
>  
> +#include "libavutil/opt.h"
> +
>  #include "avdevice.h"
>  #include "dshow.h"
>  
>  struct dshow_ctx {
> +    AVClass *class;
> +
>      IGraphBuilder *graph;
>  
>      char *device_name[2];
>  
> +    int   list_devices;
> +
>      IBaseFilter *device_filter[2];
>      IPin        *device_pin[2];
>      libAVFilter *capture_filter[2];
> @@ -208,6 +214,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>                    enum dshowDeviceType devtype)
>  {
>      struct dshow_ctx *ctx = avctx->priv_data;
> +    int list_devices = ctx->list_devices;
>      IBaseFilter *device_filter = NULL;
>      IEnumMoniker *classenum = NULL;
>      IGraphBuilder *graph = ctx->graph;
> @@ -235,6 +242,9 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>          goto error;
>      }
>  
> +    if (list_devices) {
> +        av_log(avctx, AV_LOG_INFO, "DirectShow %s devices\n", devtypename);
> +    }
>      while (IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK && !device_filter) {
>          IPropertyBag *bag = NULL;
>          char *buf = NULL;
> @@ -251,6 +261,11 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>  
>          buf = dup_wchar_to_utf8(var.bstrVal);
>  
> +        if (list_devices) {
> +            av_log(avctx, AV_LOG_INFO, " \"%s\"\n", buf);
> +            goto fail1;
> +        }
> +
>          if (strcmp(device_name, buf))
>              goto fail1;
>  
> @@ -263,6 +278,9 @@ fail1:
>              IPropertyBag_Release(bag);
>          IMoniker_Release(m);
>      }

> +    if (list_devices) {
> +        goto error;
> +    }

And set ret to AVERROR_EXIT, like it is done in the openal input
device.

>  
>      if (!device_filter) {
>          av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n",
> @@ -520,7 +538,7 @@ static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
>      int ret = AVERROR(EIO);
>      int r;
>  
> -    if (!parse_device_name(avctx)) {
> +    if (!ctx->list_devices && !parse_device_name(avctx)) {
>          av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
>          goto error;
>      }
> @@ -542,6 +560,12 @@ static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
>          goto error;
>      }
>  
> +    if (ctx->list_devices) {
> +        dshow_open_device(avctx, devenum, VideoDevice);
> +        dshow_open_device(avctx, devenum, AudioDevice);
> +        goto error;

same here, maybe you could propagate the error code.

> +    }
> +
>      if (ctx->device_name[VideoDevice]) {
>          ret = dshow_open_device(avctx, devenum, VideoDevice);
>          if (ret < 0)
> @@ -629,6 +653,22 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
>      return pkt->size;
>  }
>  
> +#define OFFSET(x) offsetof(struct dshow_ctx, x)
> +#define DEC AV_OPT_FLAG_DECODING_PARAM
> +static const AVOption options[] = {
> +    { "list_devices", "list available devices", OFFSET(list_devices), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, DEC, "list_devices" },
> +    { "true", "", 0, FF_OPT_TYPE_CONST, {.dbl=1}, 0, 0, DEC, "list_devices" },
> +    { "false", "", 0, FF_OPT_TYPE_CONST, {.dbl=0}, 0, 0, DEC, "list_devices" },
> +    { NULL },
> +};
> +
> +static const AVClass dshow_class = {
> +    .class_name = "DirectShow indev",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
>  AVInputFormat ff_dshow_demuxer = {
>      "dshow",
>      NULL_IF_CONFIG_SMALL("DirectShow capture"),
> @@ -638,4 +678,5 @@ AVInputFormat ff_dshow_demuxer = {
>      dshow_read_packet,
>      dshow_read_close,
>      .flags = AVFMT_NOFILE,
> +    .priv_class = &dshow_class,
>  };
> -- 
> 1.7.4.1

Sounds/Looks good otherwise.

> From 2cb98e2cd3b29bc49d9dedd7af6bc3a10beadf3e Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:33:57 -0300
> Subject: [PATCH 4/7] dshow: add audio/video options
> 
> ---
>  libavdevice/dshow.c        |  150 ++++++++++++++++++++++++++++++++++++++++++++
>  libavdevice/dshow.h        |    2 +
>  libavdevice/dshow_common.c |   49 ++++++++++++++
>  3 files changed, 201 insertions(+), 0 deletions(-)
> 
> diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> index 555a2b8..4cda218 100644
> --- a/libavdevice/dshow.c
> +++ b/libavdevice/dshow.c
> @@ -19,6 +19,7 @@
>   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>   */
>  
> +#include "libavutil/parseutils.h"
>  #include "libavutil/opt.h"
>  
>  #include "avdevice.h"
> @@ -46,6 +47,17 @@ struct dshow_ctx {
>      unsigned int video_frame_num;
>  
>      IMediaControl *control;
> +
> +    char *video_size;
> +    char *framerate;
> +
> +    int requested_width;
> +    int requested_height;
> +    AVRational requested_framerate;
> +
> +    int sample_rate;
> +    int sample_size;
> +    int channels;
>  };
>  
>  static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
> @@ -210,6 +222,109 @@ fail:
>  }
>  
>  static int
> +dshow_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype,
> +                 IPin *pin, AM_MEDIA_TYPE *type)
> +{
> +    struct dshow_ctx *ctx = avctx->priv_data;
> +    IAMStreamConfig *c = NULL;

nit: better to call it "config", more readable

> +    void *caps = NULL;
> +    int i, n, size;
> +    int ret = 0;
> +
> +    if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &c) != S_OK)
> +        return 0;
> +    if (IAMStreamConfig_GetNumberOfCapabilities(c, &n, &size) != S_OK)
> +        goto end;
> +
> +    caps = av_malloc(size);
> +    if (!caps)
> +        goto end;
> +
> +    for (i = 0; i < n; i++) {
> +        IAMStreamConfig_GetStreamCaps(c, 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;

nit++: maybe ih/ih2 for consistency with the code below (fx).

> +                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 {
> +                continue;
> +            }
> +            if (ctx->framerate) {

> +                int64_t framerate = (ctx->requested_framerate.den*10000000)
> +                                  /  ctx->requested_framerate.num;

possible overflow? A cast to int64_t should be enough to fix it.

> +                if (framerate > vcaps->MaxFrameInterval ||
> +                    framerate < vcaps->MinFrameInterval)
> +                    continue;
> +                *fr = framerate;
> +            }
> +            if (ctx->video_size) {
> +                if (ctx->requested_width  > vcaps->MaxOutputSize.cx ||
> +                    ctx->requested_width  < vcaps->MinOutputSize.cx ||

> +                    ctx->requested_height < vcaps->MinOutputSize.cy ||
> +                    ctx->requested_height < vcaps->MinOutputSize.cy)

typo: missing > vcaps->MaxOutputSize.cy check

> +                    continue;
> +                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 {
> +                continue;
> +            }
> +            if (ctx->sample_rate) {
> +                if (ctx->sample_rate > acaps->MaximumSampleFrequency ||
> +                    ctx->sample_rate < acaps->MinimumSampleFrequency)
> +                    continue;
> +                fx->nSamplesPerSec = ctx->sample_rate;
> +            }
> +            if (ctx->sample_size) {
> +                if (ctx->sample_size > acaps->MaximumBitsPerSample ||
> +                    ctx->sample_size < acaps->MinimumBitsPerSample)
> +                    continue;
> +                fx->wBitsPerSample = ctx->sample_size;
> +            }
> +            if (ctx->channels) {
> +                if (ctx->channels > acaps->MaximumChannels ||
> +                    ctx->channels < acaps->MinimumChannels)
> +                    continue;
> +                fx->nChannels = ctx->channels;
> +            }
> +        }

> +        if (IAMStreamConfig_SetFormat(c, type) != S_OK)
> +            continue;
> +        ret = 1;
> +        break;

Can't get the logic of the loop, i suppose it cycles through all the
"capabilities", set the given parameters in the config struct, tries
the next one in case of failure, returns with success when it
succeeds.

What looks weird to me is the need to cycle through many capabilities
until you get the "right" one, but then I don't know the DShow API at
all, and being it from MS I expect all the kinds of quirks.

> +    }
> +end:
> +    if (c)
> +        IAMStreamConfig_Release(c);
> +    av_free(caps);
> +    return ret;
> +}
> +
> +static int
>  dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>                    enum dshowDeviceType devtype)
>  {
> @@ -234,6 +349,10 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>      const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
>      const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
>  
> +    int set_format = (devtype == VideoDevice && (ctx->video_size || ctx->framerate))
> +                  || (devtype == AudioDevice && (ctx->channels || ctx->sample_rate));
> +    int format_set = 1;
> +
>      r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype],
>                                               (IEnumMoniker **) &classenum, 0);
>      if (r != S_OK) {
> @@ -322,6 +441,13 @@ fail1:
>          if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
>              goto next;
>  
> +        if (set_format) {
> +            format_set = dshow_set_format(avctx, devtype, pin, type);
> +            if (!format_set) {
> +                goto next;
> +            }
> +        }
> +
>          if (IPin_EnumMediaTypes(pin, &types) != S_OK)
>              goto next;
>  
> @@ -342,6 +468,10 @@ next:
>          if (device_pin != pin)
>              IPin_Release(pin);
>      }
> +    if (!format_set) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not set %s options\n", devtypename);
> +        goto error;
> +    }
>  
>      if (!device_pin) {
>          av_log(avctx, AV_LOG_ERROR,
> @@ -543,6 +673,21 @@ static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
>          goto error;
>      }
>  
> +    if (ctx->video_size) {
> +        r = av_parse_video_size(&ctx->requested_width, &ctx->requested_height, ctx->video_size);
> +        if (r < 0) {
> +            av_log(avctx, AV_LOG_ERROR, "Couldn't parse video size.\n");
> +            goto error;
> +        }
> +    }
> +    if (ctx->framerate) {
> +        r = av_parse_video_rate(&ctx->requested_framerate, ctx->framerate);
> +        if (r < 0) {
> +            av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
> +            goto error;
> +        }
> +    }
> +
>      CoInitialize(0);
>  
>      r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
> @@ -656,6 +801,11 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
>  #define OFFSET(x) offsetof(struct dshow_ctx, x)
>  #define DEC AV_OPT_FLAG_DECODING_PARAM
>  static const AVOption options[] = {

> +    { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), FF_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
> +    { "framerate", "", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
> +    { "sample_rate", "", OFFSET(sample_rate), FF_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, DEC },
> +    { "sample_size", "", OFFSET(sample_size), FF_OPT_TYPE_INT, {.dbl = 0}, 0, 16, DEC },
> +    { "channels", "", OFFSET(channels), FF_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, DEC },

please document all these, also semantics is "what the option does"
rather than "what the argument is", so documentation for video_size
should be:
"set frame size, accept a string as ..." - no need for the ending point

>      { "list_devices", "list available devices", OFFSET(list_devices), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, DEC, "list_devices" },
>      { "true", "", 0, FF_OPT_TYPE_CONST, {.dbl=1}, 0, 0, DEC, "list_devices" },
>      { "false", "", 0, FF_OPT_TYPE_CONST, {.dbl=0}, 0, 0, DEC, "list_devices" },
> diff --git a/libavdevice/dshow.h b/libavdevice/dshow.h
> index 4e79680..83c71c4 100644
> --- a/libavdevice/dshow.h
> +++ b/libavdevice/dshow.h
> @@ -29,6 +29,8 @@
>  #include <dvdmedia.h>
>  
>  long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
> +void ff_print_VIDEO_STREAM_CONFIG_CAPS(const VIDEO_STREAM_CONFIG_CAPS *caps);
> +void ff_print_AUDIO_STREAM_CONFIG_CAPS(const AUDIO_STREAM_CONFIG_CAPS *caps);
>  void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type);
>  void ff_printGUID(const GUID *g);
>  
> diff --git a/libavdevice/dshow_common.c b/libavdevice/dshow_common.c
> index c813dc1..8fe2f77 100644
> --- a/libavdevice/dshow_common.c
> +++ b/libavdevice/dshow_common.c
> @@ -82,6 +82,55 @@ static void dump_bih(void *s, BITMAPINFOHEADER *bih)
>  }
>  #endif
>  
> +void ff_print_VIDEO_STREAM_CONFIG_CAPS(const VIDEO_STREAM_CONFIG_CAPS *caps)
> +{
> +#if DSHOWDEBUG
> +    dshowdebug(" VIDEO_STREAM_CONFIG_CAPS\n");
> +    dshowdebug("  guid\t");
> +    ff_printGUID(&caps->guid);
> +    dshowdebug("\n");
> +    dshowdebug("  VideoStandard\t%lu\n", caps->VideoStandard);
> +    dshowdebug("  InputSize %ld\t%ld\n", caps->InputSize.cx, caps->InputSize.cy);
> +    dshowdebug("  MinCroppingSize %ld\t%ld\n", caps->MinCroppingSize.cx, caps->MinCroppingSize.cy);
> +    dshowdebug("  MaxCroppingSize %ld\t%ld\n", caps->MaxCroppingSize.cx, caps->MaxCroppingSize.cy);
> +    dshowdebug("  CropGranularityX\t%d\n", caps->CropGranularityX);
> +    dshowdebug("  CropGranularityY\t%d\n", caps->CropGranularityY);
> +    dshowdebug("  CropAlignX\t%d\n", caps->CropAlignX);
> +    dshowdebug("  CropAlignY\t%d\n", caps->CropAlignY);
> +    dshowdebug("  MinOutputSize %ld\t%ld\n", caps->MinOutputSize.cx, caps->MinOutputSize.cy);
> +    dshowdebug("  MaxOutputSize %ld\t%ld\n", caps->MaxOutputSize.cx, caps->MaxOutputSize.cy);
> +    dshowdebug("  OutputGranularityX\t%d\n", caps->OutputGranularityX);
> +    dshowdebug("  OutputGranularityY\t%d\n", caps->OutputGranularityY);
> +    dshowdebug("  StretchTapsX\t%d\n", caps->StretchTapsX);
> +    dshowdebug("  StretchTapsY\t%d\n", caps->StretchTapsY);
> +    dshowdebug("  ShrinkTapsX\t%d\n", caps->ShrinkTapsX);
> +    dshowdebug("  ShrinkTapsY\t%d\n", caps->ShrinkTapsY);
> +    dshowdebug("  MinFrameInterval\t%"PRId64"\n", caps->MinFrameInterval);
> +    dshowdebug("  MaxFrameInterval\t%"PRId64"\n", caps->MaxFrameInterval);
> +    dshowdebug("  MinBitsPerSecond\t%ld\n", caps->MinBitsPerSecond);
> +    dshowdebug("  MaxBitsPerSecond\t%ld\n", caps->MaxBitsPerSecond);
> +#endif
> +}
> +
> +void ff_print_AUDIO_STREAM_CONFIG_CAPS(const AUDIO_STREAM_CONFIG_CAPS *caps)
> +{
> +#if DSHOWDEBUG
> +    dshowdebug(" AUDIO_STREAM_CONFIG_CAPS\n");
> +    dshowdebug("  guid\t");
> +    ff_printGUID(&caps->guid);
> +    dshowdebug("\n");
> +    dshowdebug("  MinimumChannels\t%lu\n", caps->MinimumChannels);
> +    dshowdebug("  MaximumChannels\t%lu\n", caps->MaximumChannels);
> +    dshowdebug("  ChannelsGranularity\t%lu\n", caps->ChannelsGranularity);
> +    dshowdebug("  MinimumBitsPerSample\t%lu\n", caps->MinimumBitsPerSample);
> +    dshowdebug("  MaximumBitsPerSample\t%lu\n", caps->MaximumBitsPerSample);
> +    dshowdebug("  BitsPerSampleGranularity\t%lu\n", caps->BitsPerSampleGranularity);
> +    dshowdebug("  MinimumSampleFrequency\t%lu\n", caps->MinimumSampleFrequency);
> +    dshowdebug("  MaximumSampleFrequency\t%lu\n", caps->MaximumSampleFrequency);
> +    dshowdebug("  SampleFrequencyGranularity\t%lu\n", caps->SampleFrequencyGranularity);
> +#endif
> +}
> +
>  void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
>  {
>  #if DSHOWDEBUG

> -- 
> 1.7.4.1
> 

> From bdb1c350d63f3a29b187405d33e45ddade6d287f Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:34:43 -0300
> Subject: [PATCH 5/7] dshow: add option to list audio/video options
> 
> ---
>  libavdevice/dshow.c |   37 ++++++++++++++++++++++++++++++++++---
>  1 files changed, 34 insertions(+), 3 deletions(-)
> 
> diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> index 4cda218..133e7be 100644
> --- a/libavdevice/dshow.c
> +++ b/libavdevice/dshow.c
> @@ -32,6 +32,7 @@ struct dshow_ctx {
>  
>      char *device_name[2];
>  
> +    int   list_options;
>      int   list_devices;
>  
>      IBaseFilter *device_filter[2];
> @@ -223,7 +224,7 @@ fail:
>  
>  static int
>  dshow_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype,
> -                 IPin *pin, AM_MEDIA_TYPE *type)
> +                 IPin *pin, AM_MEDIA_TYPE *type, int list_options)
>  {
>      struct dshow_ctx *ctx = avctx->priv_data;
>      IAMStreamConfig *c = NULL;
> @@ -265,6 +266,14 @@ dshow_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype,
>              } else {
>                  continue;
>              }
> +            if (list_options) {
> +                av_log(avctx, AV_LOG_INFO, "  %ldx%ld %gfps -> %ldx%ld %gfps\n",

nit maybe: min_size=WxH min_fps=%f max_size=WxH min_fps=...

so you don't need to check the code to understand what the "->" means
in this context

> +                       vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
> +                       1. / (1e-7 * vcaps->MinFrameInterval),
> +                       vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
> +                       1. / (1e-7 * vcaps->MaxFrameInterval));
> +                continue;
> +            }
>              if (ctx->framerate) {
>                  int64_t framerate = (ctx->requested_framerate.den*10000000)
>                                    /  ctx->requested_framerate.num;
> @@ -293,6 +302,12 @@ dshow_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype,
>              } else {
>                  continue;
>              }
> +            if (list_options) {
> +                av_log(avctx, AV_LOG_INFO, "  %luch %lu-bit %6luHz -> %luch %lu-bit %6luHz\n",

same consideration as above

> +                       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)
> @@ -339,6 +354,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
>      libAVPin *capture_pin = NULL;
>      libAVFilter *capture_filter = NULL;
>      const char *device_name = ctx->device_name[devtype];
> +    int list_options = ctx->list_options;
>      int ret = AVERROR(EIO);
>      IPin *pin;
>      int r;
> @@ -420,6 +436,10 @@ fail1:
>          goto error;
>      }
>  
> +    if (list_options) {
> +        av_log(avctx, AV_LOG_INFO, "DirectShow %s device \"%s\" options\n",
> +               devtypename, device_name);
> +    }
>      while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !device_pin) {
>          IKsPropertySet *p = NULL;
>          IEnumMediaTypes *types;
> @@ -441,8 +461,13 @@ fail1:
>          if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
>              goto next;
>  
> -        if (set_format) {
> -            format_set = dshow_set_format(avctx, devtype, pin, type);
> +        if (set_format || list_options) {
> +            if (list_options) {
> +                char *buf = dup_wchar_to_utf8(info.achName);
> +                av_log(avctx, AV_LOG_INFO, " Pin \"%s\"\n", buf);
> +                av_free(buf);
> +            }
> +            format_set = dshow_set_format(avctx, devtype, pin, type, list_options);
>              if (!format_set) {
>                  goto next;
>              }
> @@ -468,6 +493,9 @@ next:
>          if (device_pin != pin)
>              IPin_Release(pin);
>      }
> +    if (list_options) {
> +        goto error;
> +    }
>      if (!format_set) {
>          av_log(avctx, AV_LOG_ERROR, "Could not set %s options\n", devtypename);
>          goto error;
> @@ -809,6 +837,9 @@ static const AVOption options[] = {
>      { "list_devices", "list available devices", OFFSET(list_devices), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, DEC, "list_devices" },
>      { "true", "", 0, FF_OPT_TYPE_CONST, {.dbl=1}, 0, 0, DEC, "list_devices" },
>      { "false", "", 0, FF_OPT_TYPE_CONST, {.dbl=0}, 0, 0, DEC, "list_devices" },
> +    { "list_options", "list available options for specified device", OFFSET(list_options), FF_OPT_TYPE_INT, {.dbl=0}, 0, 1, DEC, "list_options" },
> +    { "true", "", 0, FF_OPT_TYPE_CONST, {.dbl=1}, 0, 0, DEC, "list_options" },
> +    { "false", "", 0, FF_OPT_TYPE_CONST, {.dbl=0}, 0, 0, DEC, "list_options" },
>      { NULL },
>  };

Would be possible to have distinct list_options() and list_devices()
functions, rather than have their code interspersed with the
set_format()/open_device() code?

I'm fine to do that with another patch if possible, should help
readability/maintainability.

>  
> -- 
> 1.7.4.1
> 

> From 187fb0f71a283e929712b8d47b7f540ee89eebc1 Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:35:21 -0300
> Subject: [PATCH 6/7] doc: add documentation for dshow indev
> 
> ---
>  doc/indevs.texi |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 73 insertions(+), 0 deletions(-)
> 
> diff --git a/doc/indevs.texi b/doc/indevs.texi
> index c38031f..af95e00 100644
> --- a/doc/indevs.texi
> +++ b/doc/indevs.texi
> @@ -55,6 +55,79 @@ For more information see:
>  
>  BSD video input device.
>  
> + at section dshow
> +
> +Windows DirectShow input device.
> +
> +DirectShow support is enabled when FFmpeg is built with mingw-w64.
> +Currently only audio and video devices are supported.
> +
> +Multiple devices may be opened as separate inputs, but they may also be
> +opened on the same input, which should improve synchronism between them.
> +
> +The input name should be in the format:
> +
> + at example
> + at var{TYPE}=@var{NAME}[:@var{TYPE}=@var{NAME}]
> + at end example
> +
> +where @var{TYPE} can be either @var{audio} or @var{video},
> +and @var{NAME} is the device's name.
> +
> + at subsection Options
> +
> +If no options are specified, the device's defaults are used.

> +If the device does not support the requested options, FFmpeg
> +will fail to open it.

Not clear what "FFmpeg" means in this case (the tool?, the project
code?), maybe better:

If the accessed DirectShow device does not support the requested
options, it will fail to open it.


> +
> + at table @option
> +
> + at item video_size
> +Set the video size in the captured video.
> +
> + at item framerate
> +Set the framerate in the captured video.
> +
> + at item sample_rate
> +Set the sample rate (in Hz) of the captured audio.
> +
> + at item sample_size
> +Set the sample size (in bits) of the captured audio.
> +
> + at item channels
> +Set the number of channels in the captured audio.
> +
> + at item list_devices
> +If set to @option{true}, print a list of devices and exit.
> +
> + at item list_options
> +If set to @option{true}, print a list of selected device's options
> +and exit.
> +
> + at end table
> +

> + at subsection Examples
> +
> +Print the list of DirectShow supported devices and exit:
> + at example
> +$ ffmpeg -list_devices true -f dshow -i dummy
> + at end example
> +
> +Open video device @var{Camera}:
> + at example
> +$ ffmpeg -f dshow -i video="Camera"
> + at end example
> +
> +Open video device @var{Camera} and audio device @var{Microphone}:
> + at example
> +$ ffmpeg -f dshow -i video="Camera":audio="Microphone"
> + at end example
> +
> +Print the list of supported options in selected device and exit:
> + at example
> +$ ffmpeg -list_options true -f dshow -i video="Camera"
> + at end example
> +

If you want to increase the niceness level:
@itemize
@item Do this...
@example
...
@end example

like in the lavfi device docs.

>  @section dv1394
>  
>  Linux DV 1394 input device.
> -- 
> 1.7.4.1
> 

> From dac5ebc024fdef89f2d426be918653778177b4ab Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 2 Sep 2011 01:35:47 -0300
> Subject: [PATCH 7/7] dshow: properly disconnect and remove filters from graph
> 
> ---
>  libavdevice/dshow.c |   18 ++++++++++++++----
>  1 files changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
> index 133e7be..45d3f10 100644
> --- a/libavdevice/dshow.c
> +++ b/libavdevice/dshow.c
> @@ -111,11 +111,7 @@ dshow_read_close(AVFormatContext *s)
>          IMediaControl_Stop(ctx->control);
>          IMediaControl_Release(ctx->control);
>      }
> -    if (ctx->graph)
> -        IGraphBuilder_Release(ctx->graph);
>  
> -    /* FIXME remove filters from graph */
> -    /* FIXME disconnect pins */
>      if (ctx->capture_pin[VideoDevice])
>          libAVPin_Release(ctx->capture_pin[VideoDevice]);
>      if (ctx->capture_pin[AudioDevice])
> @@ -134,6 +130,20 @@ dshow_read_close(AVFormatContext *s)
>      if (ctx->device_filter[AudioDevice])
>          IBaseFilter_Release(ctx->device_filter[AudioDevice]);
>  
> +    if (ctx->graph) {
> +        IEnumFilters *fenum;
> +        int r;
> +        r = IGraphBuilder_EnumFilters(ctx->graph, &fenum);
> +        if (r == S_OK) {
> +            IBaseFilter *f;
> +            IEnumFilters_Reset(fenum);
> +            while (IEnumFilters_Next(fenum, 1, &f, NULL) == S_OK)
> +                IGraphBuilder_RemoveFilter(ctx->graph, f);
> +            IEnumFilters_Release(fenum);
> +        }
> +        IGraphBuilder_Release(ctx->graph);
> +    }
> +
>      if (ctx->device_name[0])
>          av_free(ctx->device_name[0]);
>      if (ctx->device_name[1])

Looks fine to me.
-- 
FFmpeg = Frightening and Fundamentalist Miracolous Puritan Enigmatic Genius


More information about the ffmpeg-devel mailing list