[FFmpeg-devel] [PATCH 1/4] lavf: add probe device API

Nicolas George george at nsup.org
Sun Jan 26 19:40:56 CET 2014


Le sextidi 6 pluviôse, an CCXXII, Lukasz Marek a écrit :
> >From c1e66d75f698fbd301743cd0664733a5d48f03e8 Mon Sep 17 00:00:00 2001
> From: Lukasz Marek <lukasz.m.luki at gmail.com>
> Date: Sat, 25 Jan 2014 22:46:03 +0100
> Subject: [PATCH] lavd: add probe device API
> 
> ---
>  libavformat/avformat.h | 103 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 103 insertions(+)
> 
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index a495ee0..0ff4560 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -323,6 +323,101 @@ typedef struct AVFrac {
>      int64_t val, num, den;
>  } AVFrac;
>  

> +//TODO: Move this stuff to libavdevice.

I wonder. Being able to query the list of codecs supported by RTP, for
example, would be nice.

> +
> +/**
> + * TODO: desc
> + */
> +typedef struct AVDeviceFormat
> +{
> +    enum AVCodecID codec;  /**< codec */
> +    int *formats;          /**< list of formats supported with codec.
> +                                AVPixelFormat/AVSampleFormat terminated with -1 */
> +} AVDeviceFomat;

First, I suggest, here and everywhere, to replace "terminated with X" lists
with a count indicator: "int *formats; unsigned nb_formats;". I believe this
is more practical for everyone. Also, some list are terminated by -1, some
by 0, some by NULL, that takes effort to remember.

Second, I am not sure whether codec/format is the only pair that needs to be
linked. That is the most obvious one, but I can easily imagine a camera with
limited bandwidth supporting 50 FPS in MJPEG mode but only 30 FPS in
RAWVIDEO mode.

Basically, we have the full Cartesian product:
CODECS × PIXEL_FORMAT × RESOLUTIONS × FRAME_RATES
CODECS × SAMPLE_FORMAT × CHANNEL_COUNTS × SAMPLE_RATES
and we need to be able to express a part of the set.

The obvious simple idea is to consider that the subset is itself a Cartesian
product:

SUPPORTED_FORMATS × SUPPORTED_RESOLUTIONS × SUPPORTED_FRAME_RATES \subset
PIXEL_FORMAT × RESOLUTIONS × FRAME_RATES

Except for CODECS and FORMAT, because they always are strongly linked.

I can suggest two solutions, one simple and one powerful.

The simple one: each device can return a small list of AVDeviceCapabilities.
Each device expands its list the way it is most convenient. For example:

[
  { codec = MJPEG, format = YUV420, list of supported resolutions and rates },
  { codec = MJPEG, format = YUV422, list of supported resolutions and rates },
  { codec = RAWVIDEO, format = RGB, list of supported resolutions and rates },
]

The powerful one: the AVDeviceCapabilities can leave fields unset and point
to a list of AVDeviceCapabilities to define them. Something like that:

[
  { codec = MJPEG, pointer to sublist by format for MJPEG },
  { codec = RAWVIDEO, idem },
]

sublist = [
  { format = YUV420, pointer to sublist of frame sizes and rates },
  { format = YUV422, pointer to sublist of frame sizes and rates },
]

> +
> +/**
> + * TODO: desc
> + */
> +typedef struct AVDeviceInfo {
> +    char *device_name;         /**< device name, format depends on device */
> +    char *device_description;  /**< human friendly name */
> +    int is_default;            /**< non-zero for default device, zero otherwise */
> +} AVDeviceInfo;

I am not sure if is_default is very convenient: applications need to look
for it. Maybe state that the default device should always be the first one.
Or maybe add a global structure:

typedef struct AVDeviceInfoList {
    AVDeviceInfo *devices;
    int nb_devices;
    int default;
} AVDeviceInfoList;

> +
> +/**
> + * TODO: desc
> + */
> +typedef struct AVDeviceCapabilities {
> +    /**
> +     * List of supported codec/formats pairs terminated with NULL.
> +     */
> +    AVDeviceFomat **formats;
> +
> +    /**
> +     * Device may support distinct values of sample rate, or any value in given range.
> +     * In first case sample_rates array is returned, min_sample_rate and max_sample_rate otherwise.
> +     */
> +    int *sample_rates;           /**< Audio: supported sample rates terminated with 0 */
> +    int min_sample_rate;         /**< Audio: minimum sample rate */
> +    int max_sample_rate;         /**< Audio: maximum sample rate */
> +
> +    /**
> +     * Device may support distinct values of channels, or any value in given range.
> +     * In first case channels array is returned, min_channels and max_channels otherwise.
> +     */

> +    int *channels;               /**< Audio: supported channel counts terminated with 0 */
> +    int min_channels;            /**< Audio: minimum channel count */
> +    int max_channels;            /**< Audio: maximum channel count */
> +
> +    int64_t *channel_layouts;    /**< Audio: supported channel layouts terminated with 0 */

The doxy will need to explain how channels and channel_layouts interact.

> +
> +    int min_width;               /**< Video: minimum width */
> +    int max_width;               /**< Video: maximum width */
> +    int min_height;              /**< Video: minimum height */
> +    int max_height;              /**< Video: maximum height */

The device could also support a small set of fixed resolutions. For example,
a Logitech webcam near at hand: 160x120 176x144 320x176 320x240 352x288
432x240 544x288 640x360 640x480.

> +    int max_fps;                 /**< Video: maximum supported fps */

The frame rate can also be limited to a small set of values. And it needs to
be rational.

> +} AVDeviceCapabilities;

Did you consider the case of device controls? v4l, for example, has
per-device controls for exposure and contrast adjustment and the like.
FFmpeg can not currently access them, but I have an almost finished patch
somewhere for that.

> +
> +/**
> + * List available devices.
> + *
> + * @param ofmt         device format.
> + * @param[out] devices list of autodetected devices.
> + * @return count of autodetected devices, negative on error.
> + */
> +int avdevice_list_devices(const AVOutputFormat *ofmt, AVDeviceInfo ***devices);

Using the AVDeviceInfoList structure above would avoid the triple
indirection on the return value, this is always confusing.

> +
> +/**
> + * Returns capabilities of selected device.
> + *
> + * When wanted is set then function returns intersection of wanted configuration
> + * and real device capabilities.
> + *
> + * @param ofmt        device format.
> + * @param device_name device name.
> + * @param opts        device options.
> + * @param wanted      preferred configuration.
> + * @param[out] caps   device capabilities of the device.
> + * @return >= 0 on success, negative otherwise.
> + */
> +int avdevice_get_capabilities(const AVOutputFormat *ofmt, const char *device_name,
> +                              AVDictionary *opts, const AVDeviceCapabilities *wanted,
> +                              AVDeviceCapabilities **caps);

How does wanted apply to the returned caps? Keep only compatible
configurations? Find the nearest one?

> +
> +/**
> + * Convinient function to free result of avdevice_list_devices().
> + *
> + * @param devices device list to be freed.
> + */
> +void avdevice_free_list_devices(AVDeviceInfo ***devices);
> +
> +/**
> + * Free AVDeviceCapabilities structure with all allocated data.
> + *
> + * @param caps structure to be freed.
> + */
> +void av_device_free_device_capabilities(AVDeviceCapabilities **caps);
> +
>  /*************************************************/
>  /* input/output formats */
>  
> @@ -379,6 +474,7 @@ typedef struct AVProbeData {
>  
>  #define AVFMT_SEEK_TO_PTS   0x4000000 /**< Seeking is based on PTS */
>  
> +
>  /**
>   * @addtogroup lavf_encoding
>   * @{
> @@ -453,6 +549,13 @@ typedef struct AVOutputFormat {
>  
>      void (*get_output_timestamp)(struct AVFormatContext *s, int stream,
>                                   int64_t *dts, int64_t *wall);
> +
> +    int (*list_devices)(AVDeviceInfo ***devices);
> +
> +    int (*get_capabilities)(const char *device_name, AVDictionary *opts,
> +                            const AVDeviceCapabilities *wanted,
> +                            AVDeviceCapabilities **caps);
> +
>  } AVOutputFormat;
>  /**
>   * @}
> -- 
> 1.8.3.2
> 

> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140126/cba63b0d/attachment.asc>


More information about the ffmpeg-devel mailing list