[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