[FFmpeg-devel,PATCHv3,4/4] libavcodec: v4l2: add support for v4l2 mem2mem codecs

Submitted by Jorge Ramirez-Ortiz on Aug. 2, 2017, 7:32 a.m.

Details

Message ID 1501659172-28626-5-git-send-email-jorge.ramirez-ortiz@linaro.org
State Superseded
Headers show

Commit Message

Jorge Ramirez-Ortiz Aug. 2, 2017, 7:32 a.m.
From: Alexis Ballier <aballier@gentoo.org>

This patchset enhances Alexis Ballier's original patch and validates
it using Qualcomm's Venus hardware (driver recently landed upstream
[1]).

This has been tested on Qualcomm's DragonBoard 410c and 820c

Tested decoders:
       - h264
       - mpeg4
       - vp8
       - vp9
       - hevc

Tested encoders:
       -h264
       -h263
       -mpeg4

Tested transcoding (concurrent encoding/decoding)

Some of the changes introduced:
- v4l2: code cleanup.
- v4l2: follow the decode api.
- v4l2: fix display size for NV12 output pool.
- v4l2: handle EOS.
- v4l2: vp8 and mpeg4 decoding.
- v4l2: hevc and vp9 support.
- v4l2: generate EOF on dequeue errors.
- v4l2: h264_mp4toannexb filtering.
- v4l2: import compat/v4l2 header files.
- v4l2: fixed make install and fate issues.

[1] https://lwn.net/Articles/697956/

Reviewed-by: Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
Reviewed-by: Alexis Ballier <aballier@gentoo.org>
Tested-by: Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
---
 Changelog                     |    3 +-
 compat/v4l2/v4l2-common.h     |  107 ++
 compat/v4l2/v4l2-controls.h   |  987 +++++++++++++++++
 compat/v4l2/videodev2.h       | 2402 +++++++++++++++++++++++++++++++++++++++++
 configure                     |   26 +-
 libavcodec/Makefile           |   18 +-
 libavcodec/allcodecs.c        |    9 +
 libavcodec/v4l2-common.c      |  136 ---
 libavcodec/v4l2-common.h      |   62 --
 libavcodec/v4l2_buffers.c     |  614 +++++++++++
 libavcodec/v4l2_buffers.h     |  226 ++++
 libavcodec/v4l2_fmt.c         |  142 +++
 libavcodec/v4l2_fmt.h         |   62 ++
 libavcodec/v4l2_m2m.c         |  356 ++++++
 libavcodec/v4l2_m2m.h         |   69 ++
 libavcodec/v4l2_m2m_avcodec.h |   32 +
 libavcodec/v4l2_m2m_dec.c     |  229 ++++
 libavcodec/v4l2_m2m_enc.c     |  270 +++++
 libavdevice/v4l2.c            |    2 +-
 libavdevice/v4l2enc.c         |    2 +-
 tests/ref/fate/source         |    3 +
 21 files changed, 5547 insertions(+), 210 deletions(-)
 create mode 100644 compat/v4l2/v4l2-common.h
 create mode 100644 compat/v4l2/v4l2-controls.h
 create mode 100644 compat/v4l2/videodev2.h
 delete mode 100644 libavcodec/v4l2-common.c
 delete mode 100644 libavcodec/v4l2-common.h
 create mode 100644 libavcodec/v4l2_buffers.c
 create mode 100644 libavcodec/v4l2_buffers.h
 create mode 100644 libavcodec/v4l2_fmt.c
 create mode 100644 libavcodec/v4l2_fmt.h
 create mode 100644 libavcodec/v4l2_m2m.c
 create mode 100644 libavcodec/v4l2_m2m.h
 create mode 100644 libavcodec/v4l2_m2m_avcodec.h
 create mode 100644 libavcodec/v4l2_m2m_dec.c
 create mode 100644 libavcodec/v4l2_m2m_enc.c

Comments

Mark Thompson Aug. 2, 2017, 10:16 a.m.
On 02/08/17 08:32, Jorge Ramirez-Ortiz wrote:
> From: Alexis Ballier <aballier@gentoo.org>
> 
> This patchset enhances Alexis Ballier's original patch and validates
> it using Qualcomm's Venus hardware (driver recently landed upstream
> [1]).
> 
> This has been tested on Qualcomm's DragonBoard 410c and 820c
> 
> Tested decoders:
>        - h264
>        - mpeg4
>        - vp8
>        - vp9
>        - hevc
> 
> Tested encoders:
>        -h264
>        -h263
>        -mpeg4
> 
> Tested transcoding (concurrent encoding/decoding)
> 
> Some of the changes introduced:
> - v4l2: code cleanup.
> - v4l2: follow the decode api.
> - v4l2: fix display size for NV12 output pool.
> - v4l2: handle EOS.
> - v4l2: vp8 and mpeg4 decoding.
> - v4l2: hevc and vp9 support.
> - v4l2: generate EOF on dequeue errors.
> - v4l2: h264_mp4toannexb filtering.
> - v4l2: import compat/v4l2 header files.
> - v4l2: fixed make install and fate issues.
> 
> [1] https://lwn.net/Articles/697956/
> 
> Reviewed-by: Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> Reviewed-by: Alexis Ballier <aballier@gentoo.org>
> Tested-by: Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> ---
>  Changelog                     |    3 +-
>  compat/v4l2/v4l2-common.h     |  107 ++
>  compat/v4l2/v4l2-controls.h   |  987 +++++++++++++++++
>  compat/v4l2/videodev2.h       | 2402 +++++++++++++++++++++++++++++++++++++++++
>  configure                     |   26 +-
>  libavcodec/Makefile           |   18 +-
>  libavcodec/allcodecs.c        |    9 +
>  libavcodec/v4l2-common.c      |  136 ---
>  libavcodec/v4l2-common.h      |   62 --
>  libavcodec/v4l2_buffers.c     |  614 +++++++++++
>  libavcodec/v4l2_buffers.h     |  226 ++++
>  libavcodec/v4l2_fmt.c         |  142 +++
>  libavcodec/v4l2_fmt.h         |   62 ++
>  libavcodec/v4l2_m2m.c         |  356 ++++++
>  libavcodec/v4l2_m2m.h         |   69 ++
>  libavcodec/v4l2_m2m_avcodec.h |   32 +
>  libavcodec/v4l2_m2m_dec.c     |  229 ++++
>  libavcodec/v4l2_m2m_enc.c     |  270 +++++
>  libavdevice/v4l2.c            |    2 +-
>  libavdevice/v4l2enc.c         |    2 +-
>  tests/ref/fate/source         |    3 +
>  21 files changed, 5547 insertions(+), 210 deletions(-)
>  create mode 100644 compat/v4l2/v4l2-common.h
>  create mode 100644 compat/v4l2/v4l2-controls.h
>  create mode 100644 compat/v4l2/videodev2.h
>  delete mode 100644 libavcodec/v4l2-common.c
>  delete mode 100644 libavcodec/v4l2-common.h
>  create mode 100644 libavcodec/v4l2_buffers.c
>  create mode 100644 libavcodec/v4l2_buffers.h
>  create mode 100644 libavcodec/v4l2_fmt.c
>  create mode 100644 libavcodec/v4l2_fmt.h
>  create mode 100644 libavcodec/v4l2_m2m.c
>  create mode 100644 libavcodec/v4l2_m2m.h
>  create mode 100644 libavcodec/v4l2_m2m_avcodec.h
>  create mode 100644 libavcodec/v4l2_m2m_dec.c
>  create mode 100644 libavcodec/v4l2_m2m_enc.c

Hi,

Some general questions first; I'll try to do some detailed review later.

Is the intent here only to really support software memory cases?  That is, to only consider things on the user side and to copy with the CPU between different components.

If not, I don't think the method with only user virtual pointers being visible externally is really the right approach.  For example, mapping to DRM PRIME fds is going to be wanted by a number of use-cases (for import with EGL or other APIs, or display directly via modesetting), and needs the V4L2 buffer metadata for VIDIOC_EXPBUF to work.  To that end, I think it might be better to have an opaque AV_PIX_FMT_V4L2 type carrying the buffer information and managed by the hwcontext API, which can then be mapped to user virtual memory as needed.  Such a setup would support sharing between components inside lav* (e.g. transcode with copy) as well.  Alternatively, it might be possible to use AV_PIX_FMT_DRM_PRIME directly (see the Rockchip codec patchset), though that would exclude drivers not using dma_buf inside the kernel which you suggested previously was a needed case.

Are there more patches to follow?  (Filtering?)  I note that all of the buffer functions in the current version are tagged avpriv, but aren't used outside lavc.

On devices, you mention it's tested on Qualcomm's DragonBoard 410c and 820c; is it expected to work with cores from other vendors?  If I wanted to test this, what hardware would be easiest to use?

Thanks,

- Mark
Jorge Ramirez-Ortiz Aug. 2, 2017, 12:53 p.m.
On 08/02/2017 12:16 PM, Mark Thompson wrote:
> On 02/08/17 08:32, Jorge Ramirez-Ortiz wrote:
>> From: Alexis Ballier <aballier@gentoo.org>
>>
>> This patchset enhances Alexis Ballier's original patch and validates
>> it using Qualcomm's Venus hardware (driver recently landed upstream
>> [1]).
>>
>> This has been tested on Qualcomm's DragonBoard 410c and 820c
>>
>> Tested decoders:
>>         - h264
>>         - mpeg4
>>         - vp8
>>         - vp9
>>         - hevc
>>
>> Tested encoders:
>>         -h264
>>         -h263
>>         -mpeg4
>>
>> Tested transcoding (concurrent encoding/decoding)
>>
>> Some of the changes introduced:
>> - v4l2: code cleanup.
>> - v4l2: follow the decode api.
>> - v4l2: fix display size for NV12 output pool.
>> - v4l2: handle EOS.
>> - v4l2: vp8 and mpeg4 decoding.
>> - v4l2: hevc and vp9 support.
>> - v4l2: generate EOF on dequeue errors.
>> - v4l2: h264_mp4toannexb filtering.
>> - v4l2: import compat/v4l2 header files.
>> - v4l2: fixed make install and fate issues.
>>
>> [1] https://lwn.net/Articles/697956/
>>
>> Reviewed-by: Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
>> Reviewed-by: Alexis Ballier <aballier@gentoo.org>
>> Tested-by: Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
>> ---
>>   Changelog                     |    3 +-
>>   compat/v4l2/v4l2-common.h     |  107 ++
>>   compat/v4l2/v4l2-controls.h   |  987 +++++++++++++++++
>>   compat/v4l2/videodev2.h       | 2402 +++++++++++++++++++++++++++++++++++++++++
>>   configure                     |   26 +-
>>   libavcodec/Makefile           |   18 +-
>>   libavcodec/allcodecs.c        |    9 +
>>   libavcodec/v4l2-common.c      |  136 ---
>>   libavcodec/v4l2-common.h      |   62 --
>>   libavcodec/v4l2_buffers.c     |  614 +++++++++++
>>   libavcodec/v4l2_buffers.h     |  226 ++++
>>   libavcodec/v4l2_fmt.c         |  142 +++
>>   libavcodec/v4l2_fmt.h         |   62 ++
>>   libavcodec/v4l2_m2m.c         |  356 ++++++
>>   libavcodec/v4l2_m2m.h         |   69 ++
>>   libavcodec/v4l2_m2m_avcodec.h |   32 +
>>   libavcodec/v4l2_m2m_dec.c     |  229 ++++
>>   libavcodec/v4l2_m2m_enc.c     |  270 +++++
>>   libavdevice/v4l2.c            |    2 +-
>>   libavdevice/v4l2enc.c         |    2 +-
>>   tests/ref/fate/source         |    3 +
>>   21 files changed, 5547 insertions(+), 210 deletions(-)
>>   create mode 100644 compat/v4l2/v4l2-common.h
>>   create mode 100644 compat/v4l2/v4l2-controls.h
>>   create mode 100644 compat/v4l2/videodev2.h
>>   delete mode 100644 libavcodec/v4l2-common.c
>>   delete mode 100644 libavcodec/v4l2-common.h
>>   create mode 100644 libavcodec/v4l2_buffers.c
>>   create mode 100644 libavcodec/v4l2_buffers.h
>>   create mode 100644 libavcodec/v4l2_fmt.c
>>   create mode 100644 libavcodec/v4l2_fmt.h
>>   create mode 100644 libavcodec/v4l2_m2m.c
>>   create mode 100644 libavcodec/v4l2_m2m.h
>>   create mode 100644 libavcodec/v4l2_m2m_avcodec.h
>>   create mode 100644 libavcodec/v4l2_m2m_dec.c
>>   create mode 100644 libavcodec/v4l2_m2m_enc.c
> Hi,
>
> Some general questions first; I'll try to do some detailed review later.

thanks! very much appreciated.

Alexis feel free to add your comments as well.

>
> Is the intent here only to really support software memory cases?  That is, to only consider things on the user side and to copy with the CPU between different components.

This commit adds a generic way of supporting v4l2 in ffmpeg 
(V4L2_MEMORY_MMAP)

enum v4l2_memory {
     V4L2_MEMORY_MMAP             = 1,
     V4L2_MEMORY_USERPTR          = 2,
     V4L2_MEMORY_OVERLAY          = 3,
     V4L2_MEMORY_DMABUF           = 4,
};

You are right, this patch uses the CPU to copy the preprocessed/demuxed 
bitstream to the v4l2 buffers and then as you said uses the pointers.

Extending it to support V4L2_MEMORY_DMABUF for performance is in the 
todo list.
however I think (this is just my opinion) there is value today in 
enabling the available v4l2 codecs present in many SoCs and bringing 
them under ffmpeg.
And right after work on performance and incremental optimizations.

>
> If not, I don't think the method with only user virtual pointers being visible externally is really the right approach.

if by "right" you mean with the best performance possible yes I don't 
disagree with you.

> For example, mapping to DRM PRIME fds is going to be wanted by a number of use-cases (for import with EGL or other APIs, or display directly via modesetting), and needs the V4L2 buffer metadata for VIDIOC_EXPBUF to work.  To that end, I think it might be better to have an opaque AV_PIX_FMT_V4L2 type carrying the buffer information and managed by the hwcontext API, which can then be mapped to user virtual memory as needed.

yes I am looking at this WIP 
https://github.com/LongChair/FFmpeg/commit/f852e3d6d89be3fcee90482971c3f769bdaa8e9c. 

I think it is work like this that can be used later on with v4l2 for 
optimal performance...thought I have to admit I still need to understand 
how I would use it.
but I don't see why the v4l2 patchset can not be extended afterwards?

Yes we need to add VIDIOC_EXPBUF and then on dequeing cacpture we coud 
either set the DRM plane or just pass the pointer.


> Such a setup would support sharing between components inside lav* (e.g. transcode with copy) as well.  Alternatively, it might be possible to use AV_PIX_FMT_DRM_PRIME directly (see the Rockchip codec patchset), though that would exclude drivers not using dma_buf inside the kernel which you suggested previously was a needed case.
>
> Are there more patches to follow?  (Filtering?)  I note that all of the buffer functions in the current version are tagged avpriv, but aren't used outside lavc.

yes filtering v4l2_m2m filtering is queued after this.
I just didn't want to add too much noise....

>
> On devices, you mention it's tested on Qualcomm's DragonBoard 410c and 820c; is it expected to work with cores from other vendors?  If I wanted to test this, what hardware would be easiest to use?

yes this should to work on _any_ SoC that provides a v4l2 driver 
implementing either encoding or decoding. Lukas Rusak integrated this 
ffmpeg release (with the patchset) with Kodi and was able to run on i.MX6
I just happen to have access to the Qualcomm boards really

>
> Thanks,
>
> - Mark
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Mark Thompson Aug. 2, 2017, 11:53 p.m.
On 02/08/17 08:32, Jorge Ramirez-Ortiz wrote:
> ...
> diff --git a/compat/v4l2/v4l2-common.h b/compat/v4l2/v4l2-common.h
> diff --git a/compat/v4l2/videodev2.h b/compat/v4l2/videodev2.h

These are discussed in other threads.  I don't really have any comment either way.

> diff --git a/configure b/configure
> index ed94de0..650c8fb 100755
> --- a/configure
> +++ b/configure
> @@ -10,7 +10,6 @@
>  # Prevent locale nonsense from breaking basic text processing.
>  LC_ALL=C
>  export LC_ALL
> -

Spurious change?

>  # make sure we are running under a compatible shell
>  # try to make this part work with most shells
>  
> @@ -149,6 +148,7 @@ Component options:
>    --disable-pixelutils     disable pixel utils in libavutil
>  
>  Individual component options:
> +  --disable-v4l2_m2m       disable V4L2 mem2mem code [autodetect]

s/_/-/ here.

>    --disable-everything     disable all components listed below
>    --disable-encoder=NAME   disable encoder NAME
>    --enable-encoder=NAME    enable encoder NAME
> @@ -1432,6 +1432,7 @@ AVCODEC_COMPONENTS="
>  
>  AVDEVICE_COMPONENTS="
>      indevs
> +    v4l2_m2m
>      outdevs
>  "
>  AVFILTER_COMPONENTS="
> @@ -2269,11 +2270,12 @@ map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM
>  
>  loongson2_deps="mips"
>  loongson3_deps="mips"
> -v4l2_deps_any="linux_videodev2_h sys_videoio_h"
> +v4l2_m2m_select="v4l2"
>  mipsfpu_deps="mips"
>  mipsdsp_deps="mips"
>  mipsdspr2_deps="mips"
>  mips32r2_deps="mips"
> +vc1_v4l2m2m_decoder_deps="v4l2_m2m"
>  mips32r5_deps="mips"
>  mips32r6_deps="mips"
>  mips64r2_deps="mips"
> @@ -2284,6 +2286,9 @@ mmi_deps="mips"
>  altivec_deps="ppc"
>  dcbzl_deps="ppc"
>  ldbrx_deps="ppc"
> +vp8_v4l2m2m_decoder_deps="v4l2_m2m"
> +vp8_v4l2m2m_encoder_deps="v4l2_m2m"
> +vp9_v4l2m2m_decoder_deps="v4l2_m2m"

These seem to be placed randomly in the file.  There is a hardware codec section at around line 2800, put all of these declarations there.

>  ppc4xx_deps="ppc"
>  vsx_deps="altivec"
>  power8_deps="vsx"
> @@ -2437,15 +2442,22 @@ h261_decoder_select="mpegvideo"
>  h261_encoder_select="aandcttables mpegvideoenc"
>  h263_decoder_select="h263_parser h263dsp mpegvideo qpeldsp"
>  h263_encoder_select="aandcttables h263dsp mpegvideoenc"
> +h263_v4l2m2m_decoder_deps="v4l2_m2m"
> +h263_v4l2m2m_encoder_deps="v4l2_m2m"
>  h263i_decoder_select="h263_decoder"
>  h263p_decoder_select="h263_decoder"
>  h263p_encoder_select="h263_encoder"
>  h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel videodsp"
>  h264_decoder_suggest="error_resilience"
> +h264_v4l2m2m_decoder_deps="v4l2_m2m"
> +h264_v4l2m2m_encoder_deps="v4l2_m2m"
>  hap_decoder_select="snappy texturedsp"
>  hap_encoder_deps="libsnappy"
>  hap_encoder_select="texturedspenc"
>  hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp"
> +hevc_encoder_select="hevc_v4l2m2m"
> +hevc_v4l2m2m_decoder_deps="v4l2_m2m"
> +hevc_v4l2m2m_encoder_deps="v4l2_m2m"
>  huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp"
>  huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp"
>  iac_decoder_select="imc_decoder"
> @@ -2482,6 +2494,7 @@ mpc7_decoder_select="bswapdsp mpegaudiodsp"
>  mpc8_decoder_select="mpegaudiodsp"
>  mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h"
>  mpeg_xvmc_decoder_select="mpeg2video_decoder"
> +mpeg1_v4l2m2m_decoder_deps="v4l2_m2m"
>  mpegvideo_decoder_select="mpegvideo"
>  mpeg1video_decoder_select="mpegvideo"
>  mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp"
> @@ -2489,6 +2502,8 @@ mpeg2video_decoder_select="mpegvideo"
>  mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp"
>  mpeg4_decoder_select="h263_decoder mpeg4video_parser"
>  mpeg4_encoder_select="h263_encoder"
> +mpeg4_v4l2m2m_decoder_deps="v4l2_m2m"
> +mpeg4_v4l2m2m_encoder_deps="v4l2_m2m"
>  msa1_decoder_select="mss34dsp"
>  mscc_decoder_select="zlib"
>  msmpeg4v1_decoder_select="h263_decoder"
> @@ -3042,7 +3057,6 @@ qtkit_indev_select="qtkit"
>  sdl2_outdev_deps="sdl2"
>  sndio_indev_deps="sndio"
>  sndio_outdev_deps="sndio"
> -v4l_indev_deps="linux_videodev_h"
>  v4l2_indev_select="v4l2"
>  v4l2_outdev_select="v4l2"
>  vfwcap_indev_deps="vfw32 vfwcap_defines"
> @@ -3592,7 +3606,7 @@ done
>  enable_weak audiotoolbox
>  
>  # Enable hwaccels by default.
> -enable_weak d3d11va dxva2 vaapi vda vdpau videotoolbox_hwaccel xvmc
> +enable_weak d3d11va dxva2 vaapi v4l2_m2m vda vdpau videotoolbox_hwaccel xvmc
>  enable_weak xlib
>  
>  enable_weak cuda cuvid nvenc vda_framework videotoolbox videotoolbox_encoder
> @@ -6058,12 +6072,10 @@ pod2man --help     > /dev/null 2>&1 && enable pod2man   || disable pod2man
>  rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
>  
>  check_header linux/fb.h
> -check_header linux/videodev.h
> -check_header linux/videodev2.h
> -check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
>  
>  check_header sys/videoio.h
>  check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
> +add_cflags -I$source_path/compat/v4l2

Unconditionally?  Sounds useful on Windows.

>  
>  check_lib user32 "windows.h winuser.h" GetShellWindow -luser32
>  check_lib vfw32 "windows.h vfw.h" capCreateCaptureWindow -lvfw32
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 364aec9..f45050e 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -101,7 +101,8 @@ OBJS-$(CONFIG_LZF)                     += lzf.o
>  OBJS-$(CONFIG_MDCT)                    += mdct_fixed.o mdct_float.o mdct_fixed_32.o
>  OBJS-$(CONFIG_ME_CMP)                  += me_cmp.o
>  OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec_common.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o
> -OBJS-$(CONFIG_V4L2)                    += v4l2-common.o
> +OBJS-$(CONFIG_V4L2)                    += v4l2_fmt.o v4l2_buffers.o
> +OBJS-$(CONFIG_V4L2_M2M)                += v4l2_m2m.o

Random placing?  These should be in alphabetical order.

>  OBJS-$(CONFIG_MPEG_ER)                 += mpeg_er.o
>  OBJS-$(CONFIG_MPEGAUDIO)               += mpegaudio.o
>  OBJS-$(CONFIG_MPEGAUDIODSP)            += mpegaudiodsp.o                \
> @@ -320,6 +321,8 @@ OBJS-$(CONFIG_H261_ENCODER)            += h261enc.o h261data.o h261.o
>  OBJS-$(CONFIG_H263_DECODER)            += h263dec.o h263.o ituh263dec.o        \
>                                            mpeg4video.o mpeg4videodec.o flvdec.o\
>                                            intelh263dec.o h263data.o
> +OBJS-$(CONFIG_H263_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_H263_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_H263_ENCODER)            += mpeg4videoenc.o mpeg4video.o  \
>                                            h263.o ituh263enc.o flvenc.o h263data.o
>  OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
> @@ -327,6 +330,8 @@ OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
>                                            h264_mb.o h264_picture.o \
>                                            h264_refs.o h264_sei.o \
>                                            h264_slice.o h264data.o
> +OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_H264_CUVID_DECODER)      += cuvid.o
>  OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
>  OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
> @@ -346,6 +351,8 @@ OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
>                                            hevcdsp.o hevc_filter.o hevc_data.o
>  OBJS-$(CONFIG_HEVC_CUVID_DECODER)      += cuvid.o
>  OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o
> +OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_HEVC_NVENC_ENCODER)      += nvenc_hevc.o
>  OBJS-$(CONFIG_NVENC_HEVC_ENCODER)      += nvenc_hevc.o
>  OBJS-$(CONFIG_HEVC_QSV_DECODER)        += qsvdec_h2645.o
> @@ -419,11 +426,13 @@ OBJS-$(CONFIG_MP3ON4FLOAT_DECODER)     += mpegaudiodec_float.o mpeg4audio.o
>  OBJS-$(CONFIG_MPC7_DECODER)            += mpc7.o mpc.o
>  OBJS-$(CONFIG_MPC8_DECODER)            += mpc8.o mpc.o
>  OBJS-$(CONFIG_MPEGVIDEO_DECODER)       += mpeg12dec.o mpeg12.o mpeg12data.o
> +OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_MPEG1VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
>  OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
>  OBJS-$(CONFIG_MPEG2_MMAL_DECODER)      += mmaldec.o
>  OBJS-$(CONFIG_MPEG2_QSV_DECODER)       += qsvdec_other.o
>  OBJS-$(CONFIG_MPEG2_QSV_ENCODER)       += qsvenc_mpeg2.o
> +OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
>  OBJS-$(CONFIG_MPEG2VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
>  OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o
> @@ -431,6 +440,8 @@ OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER)     += vaapi_encode_mpeg2.o
>  OBJS-$(CONFIG_MPEG4_DECODER)           += xvididct.o
>  OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
>  OBJS-$(CONFIG_MPEG4_OMX_ENCODER)       += omx.o
> +OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER)   += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_MPL2_DECODER)            += mpl2dec.o ass.o
>  OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o
>  OBJS-$(CONFIG_MSCC_DECODER)            += mscc.o
> @@ -503,6 +514,7 @@ OBJS-$(CONFIG_RALF_DECODER)            += ralf.o
>  OBJS-$(CONFIG_RAWVIDEO_DECODER)        += rawdec.o
>  OBJS-$(CONFIG_RAWVIDEO_ENCODER)        += rawenc.o
>  OBJS-$(CONFIG_REALTEXT_DECODER)        += realtextdec.o ass.o
> +OBJS-$(CONFIG_VC1_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_RL2_DECODER)             += rl2.o
>  OBJS-$(CONFIG_ROQ_DECODER)             += roqvideodec.o roqvideo.o
>  OBJS-$(CONFIG_ROQ_ENCODER)             += roqvideoenc.o roqvideo.o elbg.o
> @@ -518,6 +530,8 @@ OBJS-$(CONFIG_RV30_DECODER)            += rv30.o rv34.o rv30dsp.o
>  OBJS-$(CONFIG_RV40_DECODER)            += rv40.o rv34.o rv40dsp.o
>  OBJS-$(CONFIG_SAMI_DECODER)            += samidec.o ass.o htmlsubtitles.o
>  OBJS-$(CONFIG_S302M_DECODER)           += s302m.o
> +OBJS-$(CONFIG_VP8_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o

As should all of the rest of these.

>  OBJS-$(CONFIG_S302M_ENCODER)           += s302menc.o
>  OBJS-$(CONFIG_SANM_DECODER)            += sanm.o
>  OBJS-$(CONFIG_SCPR_DECODER)            += scpr.o
> @@ -628,6 +642,8 @@ OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r
>                                            vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o
>  OBJS-$(CONFIG_VP9_CUVID_DECODER)       += cuvid.o
>  OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER)  += mediacodecdec.o
> +OBJS-$(CONFIG_VP9_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_VP9_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_VP9_VAAPI_ENCODER)       += vaapi_encode_vp9.o
>  OBJS-$(CONFIG_VPLAYER_DECODER)         += textdec.o ass.o
>  OBJS-$(CONFIG_VQA_DECODER)             += vqavideo.o> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 4712592..d154ac9 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -207,8 +207,10 @@ static void register_all(void)
>      REGISTER_ENCDEC (H263,              h263);
>      REGISTER_DECODER(H263I,             h263i);
>      REGISTER_ENCDEC (H263P,             h263p);
> +    REGISTER_ENCDEC (H263_V4L2M2M,      h263_v4l2m2m);
>      REGISTER_DECODER(H264,              h264);
>      REGISTER_DECODER(H264_CRYSTALHD,    h264_crystalhd);
> +    REGISTER_ENCDEC (H264_V4L2M2M,      h264_v4l2m2m);
>      REGISTER_DECODER(H264_MEDIACODEC,   h264_mediacodec);
>      REGISTER_DECODER(H264_MMAL,         h264_mmal);
>      REGISTER_DECODER(H264_QSV,          h264_qsv);
> @@ -219,6 +221,7 @@ static void register_all(void)
>      REGISTER_ENCDEC (HAP,               hap);
>      REGISTER_DECODER(HEVC,              hevc);
>      REGISTER_DECODER(HEVC_QSV,          hevc_qsv);
> +    REGISTER_ENCDEC(HEVC_V4L2M2M,       hevc_v4l2m2m);
>      REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
>      REGISTER_DECODER(HQ_HQA,            hq_hqa);
>      REGISTER_DECODER(HQX,               hqx);
> @@ -253,6 +256,7 @@ static void register_all(void)
>      REGISTER_ENCDEC (MPEG2VIDEO,        mpeg2video);
>      REGISTER_ENCDEC (MPEG4,             mpeg4);
>      REGISTER_DECODER(MPEG4_CRYSTALHD,   mpeg4_crystalhd);
> +    REGISTER_ENCDEC (MPEG4_V4L2M2M,     mpeg4_v4l2m2m);
>      REGISTER_DECODER(MPEG4_MMAL,        mpeg4_mmal);
>  #if FF_API_VDPAU
>      REGISTER_DECODER(MPEG4_VDPAU,       mpeg4_vdpau);
> @@ -262,8 +266,10 @@ static void register_all(void)
>      REGISTER_DECODER(MPEG_VDPAU,        mpeg_vdpau);
>      REGISTER_DECODER(MPEG1_VDPAU,       mpeg1_vdpau);
>  #endif
> +    REGISTER_DECODER(MPEG1_V4L2M2M,     mpeg1_v4l2m2m);
>      REGISTER_DECODER(MPEG2_MMAL,        mpeg2_mmal);
>      REGISTER_DECODER(MPEG2_CRYSTALHD,   mpeg2_crystalhd);
> +    REGISTER_DECODER(MPEG2_V4L2M2M,     mpeg2_v4l2m2m);
>      REGISTER_DECODER(MPEG2_QSV,         mpeg2_qsv);
>      REGISTER_DECODER(MPEG2_MEDIACODEC,  mpeg2_mediacodec);
>      REGISTER_DECODER(MSA1,              msa1);
> @@ -361,6 +367,7 @@ static void register_all(void)
>      REGISTER_DECODER(VC1IMAGE,          vc1image);
>      REGISTER_DECODER(VC1_MMAL,          vc1_mmal);
>      REGISTER_DECODER(VC1_QSV,           vc1_qsv);
> +    REGISTER_DECODER(VC1_V4L2M2M,       vc1_v4l2m2m);
>      REGISTER_ENCODER(VC2,               vc2);
>      REGISTER_DECODER(VCR1,              vcr1);
>      REGISTER_DECODER(VMDVIDEO,          vmdvideo);
> @@ -372,7 +379,9 @@ static void register_all(void)
>      REGISTER_DECODER(VP6F,              vp6f);
>      REGISTER_DECODER(VP7,               vp7);
>      REGISTER_DECODER(VP8,               vp8);
> +    REGISTER_ENCDEC (VP8_V4L2M2M,       vp8_v4l2m2m);
>      REGISTER_DECODER(VP9,               vp9);
> +    REGISTER_DECODER(VP9_V4L2M2M,       vp9_v4l2m2m);
>      REGISTER_DECODER(VQA,               vqa);
>      REGISTER_DECODER(BITPACKED,         bitpacked);
>      REGISTER_DECODER(WEBP,              webp);

And these.

> diff --git a/libavcodec/v4l2-common.c b/libavcodec/v4l2-common.c
> deleted file mode 100644
> diff --git a/libavcodec/v4l2-common.h b/libavcodec/v4l2-common.h
> deleted file mode 100644
> diff --git a/libavcodec/v4l2_fmt.c b/libavcodec/v4l2_fmt.c
> new file mode 100644
> diff --git a/libavcodec/v4l2_fmt.h b/libavcodec/v4l2_fmt.h
> new file mode 100644

I think it would have made more sense to move these files in a previous patch rather than here.


> diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
> new file mode 100644
> index 0000000..e3a4173
> --- /dev/null
> +++ b/libavcodec/v4l2_buffers.h
> @@ -0,0 +1,226 @@
> +/*
> + * V4L2 buffer{,pool} helper functions.
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVCODEC_V4L2_BUFFERS_H
> +#define AVCODEC_V4L2_BUFFERS_H
> +
> +#include "v4l2_fmt.h"
> +#include "avcodec.h"
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/frame.h"
> +
> +struct V4LBuffer;
> +typedef struct V4LBuffer V4LBuffer;

Everywhere - the API is V4L2, not V4L.  Please use that name consistently.

> +
> +struct V4LBufferPool;
> +typedef int (*format_f)(struct V4LBufferPool *, int set);
> +typedef int (*init_f)(struct V4LBufferPool *);
> +
> +typedef struct V4LBufferPoolCfg {
> +    format_f format;
> +    init_f init;
> +} V4LBufferPoolCfg;
> +
> +typedef struct V4LBufferPool {
> +    /**
> +     * Buffer pool initial configuration.
> +     */
> +    V4LBufferPoolCfg cfg;
> +
> +    /**
> +     * Log context (for av_log()). Can be NULL.
> +     */
> +    void *log_ctx;
> +
> +    /**
> +     * Pool's name. Must be set before calling avpriv_init_v4lbufpool().
> +     */
> +    const char* name;
> +
> +    /**
> +     * File descriptor obtained from opening the associated device.
> +     * Must be set before calling avpriv_init_v4lbufpool().
> +     * Readonly after init.
> +     */
> +    int fd;
> +
> +    /**
> +     * Type of this buffer pool.
> +     * See V4L2_BUF_TYPE_VIDEO_* in videodev2.h
> +     * Must be set before calling avpriv_init_v4lbufpool().
> +     * Readonly after init.
> +     */
> +    enum v4l2_buf_type type;
> +
> +    /**
> +     * Memory type this buffer pool uses.
> +     * See V4L2_MEMORY_* in videodev2.h
> +     * Must be set before calling avpriv_init_v4lbufpool().
> +     * Readonly after init.
> +     */
> +    enum v4l2_memory memory;
> +
> +    /**
> +     * AVPixelFormat corresponding to this buffer pool.
> +     * AV_PIX_FMT_NONE means this is an encoded stream.
> +     */
> +    enum AVPixelFormat av_pix_fmt;
> +
> +    /**
> +     * AVCodecID corresponding to this buffer pool.
> +     * AV_CODEC_ID_RAWVIDEO means this is a raw stream and av_pix_fmt must be set to a valid value.
> +     */
> +    enum AVCodecID   av_codec_id;
> +
> +    /**
> +     * Format returned by the driver after initializing the buffer pool.
> +     * Must be set before calling avpriv_init_v4lbufpool().
> +     * avpriv_set_pool_format() can set it.
> +     * Readonly after init.
> +     */
> +    struct v4l2_format format;
> +
> +    /**
> +     * Width and height of the frames it produces (in case of a capture pool, e.g. when decoding)
> +     * or accepts (in case of an output pool, e.g. when encoding).
> +     *
> +     * For output pools, this must must be set before calling avpriv_init_v4lbufpool().
> +     * For capture pools, it will be set after having received the information from the driver.
> +     */
> +    int width, height;
> +
> +    /**
> +     * Default flags to set on buffers to enqueue.
> +     * See V4L2_BUF_FLAG_*.
> +     */
> +    int default_flags;
> +
> +    /**
> +     * Whether the stream has been started (VIDIOC_STREAMON has been sent).
> +     */
> +    int streamon;
> +
> +    /**
> +     * Number of queued buffers.
> +     */
> +    int num_queued;
> +
> +    /**
> +     * Minimum number of buffers that must be kept queued in this queue.
> +     *
> +     * E.g. for decoders, the drivers might have such requirements to produce proper output.
> +     */
> +    int min_queued_buffers;
> +
> +    /**
> +     * The actual number of buffers.
> +     *
> +     * Before calling avpriv_init_v4lbufpool() this is the number of buffers we would like to have available.
> +     * avpriv_init_v4lbufpool() asks for (min_buffers + num_buffers) and sets this value to the actual number
> +     * of buffers the driver gave us.
> +     * Readonly after init.
> +     */
> +    int num_buffers;
> +
> +    /**
> +     * Opaque pointers to the actual buffers representations.
> +     * After initialization, it is an array of size num_buffers.
> +     */
> +    V4LBuffer *buffers;
> +
> +    /**
> +     * Pool in unrecoverable error notified by the V4L2 kernel api
> +     */
> +    int broken;
> +
> +} V4LBufferPool;

This structure seems to me to be two pretty much separate things: an AVBufferPool (for storing the buffer structures) and a common context for streaming operations on a V4L2 device.  I think it would be better if they were actually separate, and just use AVBufferPool for the buffer pool part.

> +
> +/**
> + * Initializes a V4LBufferPool.
> + *
> + * @param[in] bp A pointer to a V4LBufferPool. See V4LBufferPool description for required variables.
> + * @return 0 in case of success, a negative value representing the error otherwise.
> + */
> +int avpriv_init_v4lbufpool(V4LBufferPool* bp);
> +
> +/**
> + * Releases a V4LBufferPool.
> + *
> + * @param[in] bp A pointer to a V4LBufferPool.
> + *               The caller is reponsible for freeing it.
> + *               It must not be used after calling this function.
> + */
> +void avpriv_release_buffer_pool(V4LBufferPool* bp);
> +
> +/**
> + * Sets the status of a V4LBufferPool.
> + *
> + * @param[in] bp A pointer to a V4LBufferPool.
> + * @param[in] cmd The status to set (VIDIOC_STREAMON or VIDIOC_STREAMOFF).
> + *                Warning: If VIDIOC_STREAMOFF is sent to a buffer pool that still has some frames buffered,
> + *                those frames will be dropped.
> + * @return 0 in case of success, a negative value representing the error otherwise.
> + */
> +int avpriv_set_stream_status(V4LBufferPool* bp, int cmd);

avpriv names are fully global.  Where you have to use them, please make them consistently namespaced - e.g. "avpriv_v4l2_foo_bar".

> +
> +/**
> + * Dequeues a buffer from a V4LBufferPool to either an AVFrame or an AVPacket.
> + *
> + * Exactly one of f or pkt must be non NULL.
> + * @param[in] bp The V4LBufferPool to dequeue from.
> + * @param[inout] f The AVFrame to dequeue to.
> + * @param[inout] pkt The AVPacket to dequeue to.
> + * @param[ino] timeout The number of milliseconds to wait for the dequeue.
> + * @return 0 in case of success, AVERROR(EAGAIN) if no buffer was ready, another negative error in case of error.
> + */
> +int avpriv_v4l_dequeue(V4LBufferPool* bp, AVFrame* f, AVPacket* pkt, unsigned int timeout);
> +
> +/**
> + * Enqueues a buffer to a V4LBufferPool from either an AVFrame, an AVPacket or a raw buffer.
> + * Exactly one of f or pkt  must be non NULL.
> + *
> + * @param[in] bp The V4LBufferPool to enqueue to.
> + * @param[in] f A pointer to an AVFrame to enqueue.
> + * @param[in] pkt A pointer to an AVPacket to enqueue.
> + * @return 0 in case of success, a negative error otherwise.
> + */
> +int avpriv_v4l_enqueue(V4LBufferPool* bp, const AVFrame* f, const AVPacket* pkt);
> +
> +/**
> + * Gets a free V4LBuffer from a V4LBufferPool.
> + *
> + * If no matching buffer is found (see below), it tries to dequeue a buffer first
> + * in order to minimize the size of the V4L queue.e
> + *
> + * @param[in] p Pointer to a V4LBufferPool where to get the buffer from.
> + * @param[in] f A pointer to an existing AVFrame:
> + *              If the AVFrame's buffers match a V4LBuffer, this V4LBuffer will be returned.
> + *              Can be NULL.
> + * @param[in] pkt A pointer to an existing AVPacket:
> + *                If the AVPacket's buffers match a V4LBuffer, this V4LBuffer will be returned.
> + *                Can be NULL.
> + * @return A pointer to the V4LBuffer or NULL in case of error.
> + */
> +V4LBuffer* avpriv_v4lbufpool_getfreebuf(V4LBufferPool *p, const AVFrame *f, const AVPacket* pkt);
> +
> +#endif // AVCODEC_V4L2_BUFFERS_H
> diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
> new file mode 100644
> index 0000000..4bae6aa
> --- /dev/null
> +++ b/libavcodec/v4l2_buffers.c
> @@ -0,0 +1,614 @@
> +/*
> + * V4L2 buffer{,pool} helper functions.
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <poll.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include "avcodec.h"
> +#include "internal.h"
> +#include "v4l2_buffers.h"
> +#include "v4l2_fmt.h"
> +
> +#define IS_BP_SUPPORTED(bp) ((bp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) || \
> +                             (bp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)  || \
> +                             (bp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)        || \
> +                             (bp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT))
> +enum V4LBuffer_status {
> +    V4LBUF_AVAILABLE,
> +    V4LBUF_IN_DRIVER,
> +    V4LBUF_RET_USER,
> +};
> +
> +struct V4LBuffer {
> +    AVBufferRef *bufrefs[VIDEO_MAX_PLANES];
> +    struct V4LBufferPool *pool;
> +    struct v4l2_plane planes[VIDEO_MAX_PLANES];
> +    struct v4l2_buffer buf;
> +
> +    void * mm_addr[VIDEO_MAX_PLANES];
> +    size_t lengths[VIDEO_MAX_PLANES];
> +    enum V4LBuffer_status status;
> +    int bytesperline[4];
> +    int num_planes;
> +    int num_lines;
> +    int index;
> +    int flags;
> +    struct timeval timestamp;
> +    int ref_cnt;
> +};
> +
> +static inline void set_pts(V4LBuffer *out, int64_t pts)
> +{
> +    if (pts == AV_NOPTS_VALUE) {
> +        out->timestamp.tv_sec  = 0;
> +        out->timestamp.tv_usec = 0;> +    } else {
> +        out->timestamp.tv_sec  = pts / INT64_C(1000000);
> +        out->timestamp.tv_usec = pts % INT64_C(1000000);
> +    }
> +}

This seems to have come from the pts supplied by the user - that should be measured in whatever the time_base is of the relevant component, which is highly unlikely to be microseconds.

Also, zero is a valid timestamp (and common - often the first frame in a file).

> +
> +static inline uint64_t get_pts(V4LBuffer *avbuf)
> +{
> +    if (avbuf->buf.timestamp.tv_sec || avbuf->buf.timestamp.tv_usec)
> +        return (avbuf->buf.timestamp.tv_sec * INT64_C(1000000) + avbuf->buf.timestamp.tv_usec);
> +
> +    return AV_NOPTS_VALUE;
> +}
> +
> +static int enqueue_v4lbuf(V4LBuffer* avbuf)
> +{
> +    int ret;
> +
> +    memset(&avbuf->buf, 0, sizeof(avbuf->buf));
> +    avbuf->buf.memory = avbuf->pool->memory;
> +    avbuf->buf.type = avbuf->pool->type;
> +    avbuf->buf.index = avbuf->index;
> +
> +    if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
> +        avbuf->buf.length   = avbuf->num_planes;
> +        avbuf->buf.m.planes = avbuf->planes;
> +    } else {
> +        avbuf->buf.bytesused = avbuf->planes[avbuf->index].bytesused;
> +        avbuf->buf.m.userptr = avbuf->planes[avbuf->index].m.userptr;
> +        avbuf->buf.length    = avbuf->planes[avbuf->index].length;
> +    }
> +
> +    avbuf->buf.flags = avbuf->pool->default_flags | avbuf->flags;
> +    avbuf->buf.timestamp = avbuf->timestamp;
> +
> +    ret = ioctl(avbuf->pool->fd, VIDIOC_QBUF, &avbuf->buf);
> +    if (ret < 0)
> +        return AVERROR(errno);
> +
> +    avbuf->status = V4LBUF_IN_DRIVER;
> +    avbuf->pool->num_queued++;
> +
> +    return 0;
> +}
> +
> +static V4LBuffer* dequeue_v4lbuf(V4LBufferPool *bp, unsigned int timeout)
> +{
> +    struct v4l2_plane planes[VIDEO_MAX_PLANES];
> +    struct v4l2_buffer buf = { 0 };
> +    V4LBuffer* avbuf = NULL;
> +    struct pollfd pfd;
> +    int ret;
> +    int i;
> +
> +    if (bp->num_queued < bp->min_queued_buffers)
> +        return NULL;
> +
> +    pfd.fd = bp->fd;
> +    switch (bp->type) {
> +    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
> +    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +        pfd.events = POLLIN | POLLERR;
> +        break;
> +    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
> +    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +        pfd.events = POLLOUT | POLLERR | POLLWRNORM;
> +        break;
> +    default:
> +        pfd.events = POLLIN | POLLERR | POLLRDNORM;

What hits this default case?

> +    }
> +
> +    ret = poll(&pfd, 1, timeout);

Can this poll be interrupted?

> +    if (ret <=  0)
> +        return NULL;
> +
> +    memset(&buf, 0, sizeof(buf));
> +    buf.memory = bp->memory;
> +    buf.type = bp->type;
> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
> +        memset(planes, 0, sizeof(planes));
> +        buf.length = VIDEO_MAX_PLANES;
> +        buf.m.planes = planes;
> +    }
> +    ret = ioctl(bp->fd, VIDIOC_DQBUF, &buf);
> +    if (ret) {
> +        if (errno != EAGAIN && errno != EINVAL) {

EINVAL is considered ok?

> +            av_log(bp->log_ctx, AV_LOG_DEBUG, "%s: VIDIOC_DQBUF, errno (%d)\n", bp->name, errno);
> +            bp->broken = errno;

errno can be overwritten by the av_log() call.

> +        }
> +        return NULL;
> +    }
> +
> +    avbuf = &(bp->buffers[buf.index]);
> +    avbuf->status = V4LBUF_AVAILABLE;
> +    avbuf->pool->num_queued--;
> +    avbuf->buf = buf;
> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
> +        memcpy(avbuf->planes, planes, sizeof(planes));
> +        avbuf->buf.m.planes = avbuf->planes;
> +    }
> +
> +    if (!V4L2_TYPE_IS_OUTPUT(avbuf->pool->type))
> +        return avbuf;
> +
> +    for (i = 0; i < avbuf->num_planes; i++) {
> +        if (avbuf->bufrefs[i])
> +            av_buffer_unref(&avbuf->bufrefs[i]);
> +    }
> +
> +    return avbuf;
> +}
> +
> +static void buffer_callback(void *opaque, uint8_t *unused)
> +{
> +    V4LBuffer* avbuf = opaque;
> +
> +    if (--avbuf->ref_cnt > 0)
> +        return;
> +
> +    if (V4LBUF_IN_DRIVER == avbuf->status)
> +        return;
> +
> +    if (!V4L2_TYPE_IS_OUTPUT(avbuf->pool->type)) {
> +        enqueue_v4lbuf(avbuf);> +    } else {
> +        avbuf->status = V4LBUF_AVAILABLE;
> +    }
> +}
> +
> +static inline int init_buffer(V4LBuffer* avbuf)
> +{
> +    int ret, i;
> +
> +    avbuf->buf.memory = avbuf->pool->memory;
> +    avbuf->buf.type = avbuf->pool->type;
> +    avbuf->buf.index = avbuf->index;
> +
> +    if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
> +        avbuf->buf.length = VIDEO_MAX_PLANES;
> +        avbuf->buf.m.planes = avbuf->planes;
> +    }
> +
> +    ret = ioctl(avbuf->pool->fd, VIDIOC_QUERYBUF, &avbuf->buf);
> +    if (ret < 0)
> +        return AVERROR(errno);
> +
> +    if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
> +        avbuf->num_planes = 0;
> +        for (;;) {
> +            if (avbuf->num_planes >= avbuf->buf.length)
> +                break;
> +            if (avbuf->buf.m.planes[avbuf->num_planes].length)
> +                avbuf->num_planes++;
> +        }
> +    } else
> +        avbuf->num_planes = 1;
> +
> +    avbuf->num_lines = avbuf->pool->format.fmt.pix_mp.height;
> +
> +    for (i = 0; i < avbuf->num_planes; i++) {
> +
> +        avbuf->bytesperline[i] = V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type) ?
> +            avbuf->pool->format.fmt.pix_mp.plane_fmt[i].bytesperline :
> +            avbuf->pool->format.fmt.pix.bytesperline;
> +
> +        switch (avbuf->pool->memory) {
> +        case V4L2_MEMORY_MMAP:
> +            if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
> +                avbuf->lengths[i] = avbuf->buf.m.planes[i].length;
> +                avbuf->mm_addr[i] = mmap(NULL, avbuf->buf.m.planes[i].length,
> +                                         PROT_READ | PROT_WRITE, MAP_SHARED,
> +                                         avbuf->pool->fd, avbuf->buf.m.planes[i].m.mem_offset);
> +            } else {
> +                avbuf->lengths[i] = avbuf->buf.length;
> +                avbuf->mm_addr[i] = mmap(NULL, avbuf->buf.length,
> +                                         PROT_READ | PROT_WRITE, MAP_SHARED,
> +                                         avbuf->pool->fd, avbuf->buf.m.offset);
> +            }
> +            if (avbuf->mm_addr[i] == MAP_FAILED)
> +                return AVERROR(ENOMEM);
> +            break;
> +
> +        case V4L2_MEMORY_USERPTR:
> +            break;
> +
> +        default:
> +            av_log(avbuf->pool->log_ctx, AV_LOG_ERROR, "memory type %i not supported\n", avbuf->pool->memory);
> +            return AVERROR_PATCHWELCOME;
> +        }
> +    }
> +    avbuf->status = V4LBUF_AVAILABLE;
> +
> +    if (V4L2_TYPE_IS_OUTPUT(avbuf->pool->type))
> +        return 0;
> +
> +    if (avbuf->pool->memory != V4L2_MEMORY_USERPTR)
> +        return enqueue_v4lbuf(avbuf);
> +
> +    return 0;
> +}
> +
> +int avpriv_init_v4lbufpool(V4LBufferPool* bufs)
> +{
> +    struct v4l2_requestbuffers req;
> +    int ret, i;
> +
> +    if (!IS_BP_SUPPORTED(bufs)) {
> +        av_log(bufs->log_ctx, AV_LOG_ERROR, "type %i not supported\n", bufs->type);
> +        return AVERROR_PATCHWELCOME;
> +    }
> +
> +    memset(&req, 0, sizeof(req));
> +    req.count = bufs->num_buffers + bufs->min_queued_buffers;
> +    req.memory = bufs->memory;
> +    req.type = bufs->type;
> +    ret = ioctl(bufs->fd, VIDIOC_REQBUFS, &req);
> +    if (ret< 0)

Log something?

> +        return AVERROR(errno);
> +
> +    bufs->num_buffers = req.count;
> +    bufs->num_queued  = 0;
> +    bufs->buffers = av_mallocz(bufs->num_buffers * sizeof(V4LBuffer));

Can fail.

> +
> +    for (i = 0; i < req.count; i++) {
> +        V4LBuffer *avbuf = &bufs->buffers[i];
> +        avbuf->pool = bufs;
> +        avbuf->index = i;
> +
> +        ret = init_buffer(avbuf);
> +        if (ret < 0) {
> +            av_log(bufs->log_ctx, AV_LOG_ERROR, "%s buffer initialization (%s)\n", bufs->name, av_err2str(ret));
> +            return ret;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static void release_buf(V4LBuffer* b)
> +{
> +    int i;
> +
> +    for (i = 0; i < b->num_planes; i++) {
> +        if (b->mm_addr[i] && b->lengths[i]) {
> +            munmap(b->mm_addr[i], b->lengths[i]);
> +        }
> +    }
> +}
> +
> +void avpriv_release_buffer_pool(V4LBufferPool* bp)
> +{
> +    int i;
> +
> +    if (!bp->buffers)
> +        return;
> +
> +    for (i = 0; i < bp->num_buffers; i++) {
> +        release_buf(&bp->buffers[i]);
> +    }
> +
> +    av_free(bp->buffers);
> +}
> +
> +static int buf2v4l(V4LBuffer *out, int plane, const uint8_t* data, int size, AVBufferRef* bref)
> +{
> +    if (plane >= out->num_planes)
> +        return AVERROR(EINVAL);
> +
> +    switch (out->pool->memory) {
> +    case V4L2_MEMORY_MMAP:
> +            memcpy(out->mm_addr[plane], data, FFMIN(size, out->lengths[plane]));

Why would the pitches be the same except by coincidence?

> +            break;
> +    case V4L2_MEMORY_USERPTR:
> +        if (!bref) {
> +            av_log(out->pool->log_ctx, AV_LOG_ERROR,
> +                   "needs to be set with an AVBufferRef for USERPTR memory type\n");
> +            return AVERROR_PATCHWELCOME;
> +        }
> +        if (out->bufrefs[plane]) {
> +            av_log(out->pool->log_ctx, AV_LOG_WARNING,
> +                   "V4L buffer already had a buffer referenced\n");
> +            av_buffer_unref(&out->bufrefs[plane]);
> +        }
> +
> +        out->bufrefs[plane] = av_buffer_ref(bref);
> +        if (!out->bufrefs[plane])
> +            return AVERROR(ENOMEM);
> +
> +        out->planes[plane].m.userptr = (unsigned long)out->bufrefs[plane]->data;
> +        out->lengths[plane] = out->bufrefs[plane]->size;
> +        break;
> +    default:
> +        av_log(out->pool->log_ctx, AV_LOG_ERROR,
> +               "memory type %i not supported", out->pool->memory);
> +        return AVERROR_PATCHWELCOME;
> +    }
> +
> +    out->planes[plane].bytesused = FFMIN(size ? size : 1, out->lengths[plane]);
> +    out->planes[plane].length = out->lengths[plane];
> +
> +    return 0;
> +}
> +
> +static int avpkt_to_v4lbuf(const AVPacket *pkt, V4LBuffer *out) {
> +    int ret;
> +
> +    ret = buf2v4l(out, 0, pkt->data, pkt->size, pkt->buf);
> +    if (ret)
> +        return ret;
> +
> +    set_pts(out, pkt->pts);
> +
> +    if (pkt->flags & AV_PKT_FLAG_KEY)
> +        out->flags = V4L2_BUF_FLAG_KEYFRAME;
> +
> +    if (!pkt->size)
> +        out->flags |= V4L2_BUF_FLAG_LAST;
> +
> +    return 0;
> +}
> +
> +static inline int v4l2bufref(V4LBuffer *in, int plane, AVBufferRef **buf)
> +{
> +    if (plane >= in->num_planes)
> +        return AVERROR(EINVAL);
> +
> +    switch (in->pool->memory) {
> +    case V4L2_MEMORY_MMAP:
> +        *buf = av_buffer_create(in->mm_addr[plane], in->lengths[plane], buffer_callback, in, 0);
> +        if (!*buf)
> +            return AVERROR(ENOMEM);
> +
> +        in->status = V4LBUF_RET_USER;
> +        in->ref_cnt++;
> +        break;
> +    case V4L2_MEMORY_USERPTR:
> +        if (!in->bufrefs[plane]) {
> +            av_log(in->pool->log_ctx, AV_LOG_ERROR, "AVBufferRef not found\n");
> +            return AVERROR(EINVAL);
> +        }
> +
> +        *buf = av_buffer_ref(in->bufrefs[plane]);
> +        if (!*buf)
> +            return AVERROR(ENOMEM);
> +
> +        av_buffer_unref(&in->bufrefs[plane]);
> +        in->status = V4LBUF_AVAILABLE;
> +        break;
> +    default:
> +        av_log(in->pool->log_ctx, AV_LOG_ERROR, "memory type %i not supported", in->pool->memory);
> +        return AVERROR_PATCHWELCOME;
> +    }
> +    return 0;
> +}
> +
> +static int v4lbuf_to_avpkt(AVPacket *pkt, V4LBuffer *avbuf)
> +{
> +    int ret;
> +
> +    av_packet_unref(pkt);
> +    if (ret = v4l2bufref(avbuf, 0, &pkt->buf))
> +        return ret;
> +
> +    pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused;
> +    pkt->data = pkt->buf->data;
> +
> +    if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME)
> +        pkt->flags |= AV_PKT_FLAG_KEY;
> +
> +    if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
> +        av_log(avbuf->pool->log_ctx, AV_LOG_ERROR, "V4L2 packet decode error\n");
> +        pkt->flags |= AV_PKT_FLAG_CORRUPT;
> +    }
> +
> +    pkt->pts = get_pts(avbuf);
> +
> +    return 0;
> +}
> +
> +static int v4lbuf_to_avframe(AVFrame *frame, V4LBuffer *avbuf)
> +{
> +    int i, ret;
> +
> +    av_frame_unref(frame);
> +
> +    for (i = 0; i < avbuf->num_planes; i++) {
> +        ret = v4l2bufref(avbuf, i, &frame->buf[i]);> +        if (ret)
> +            return ret;
> +
> +        frame->linesize[i] = avbuf->bytesperline[i];
> +        frame->data[i] = frame->buf[i]->data;
> +
> +        if (avbuf->num_planes == 1) {
> +            if (avbuf->pool->av_pix_fmt == AV_PIX_FMT_NV12) {

Special-casing like this rather inspires doubt that other formats are handled correctly.

> +                frame->linesize[1] = avbuf->bytesperline[0];
> +                frame->data[1] = frame->buf[0]->data + avbuf->bytesperline[0] * avbuf->num_lines;> +            }
> +        }
> +    }
> +
> +    frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME);
> +    frame->format = avbuf->pool->av_pix_fmt;
> +    frame->height = avbuf->pool->height;
> +    frame->width = avbuf->pool->width;
> +    frame->pts = get_pts(avbuf);
> +
> +    if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
> +        av_log(avbuf->pool->log_ctx, AV_LOG_ERROR, "V4L2 buffer decode error\n");
> +        frame->decode_error_flags |= FF_DECODE_ERROR_INVALID_BITSTREAM;
> +    }
> +
> +    return 0;
> +}
> +
> +static int avframe_to_v4lbuf(const AVFrame *pict, V4LBuffer* out)
> +{
> +    int i, ret;
> +
> +    for(i = 0; i < out->num_planes; i++) {
> +        ret = buf2v4l(out, i, pict->buf[i]->data, pict->buf[i]->size, pict->buf[i]);
Shouldn't this be using pict->data[i] rather than the buffer references (which could point anywhere)?

In any case, pict->buf[i] need not match pict->data[i] - there could be a single buffer covering all frames, for example.

> +        if (ret)
> +            return ret;
> +    }
> +
> +    set_pts(out, pict->pts);
> +
> +    return 0;
> +}
> +
> +static V4LBuffer* v4lbufpool_get_from_avframe(const AVFrame* frame, V4LBufferPool *p)
> +{
> +    int i;
> +
> +    for (i = 0; i < p->num_buffers; i++) {
> +
> +        if (V4LBUF_RET_USER != p->buffers[i].status)
> +            continue;
> +
> +        if (p->memory != V4L2_MEMORY_MMAP) {
> +            av_log(p->log_ctx, AV_LOG_ERROR, "memory type %i not supported\n", p->memory);
> +            return NULL;
> +        }
> +
> +        if (p->buffers[i].mm_addr[0] == frame->buf[0]->data)
> +            return &p->buffers[i];
> +    }
> +
> +    return NULL;
> +}
> +
> +V4LBuffer* avpriv_v4lbufpool_getfreebuf(V4LBufferPool *p, const AVFrame *f, const AVPacket* pkt)
> +{
> +    V4LBuffer* ret;
> +    unsigned int timeout = 0;
> +    int i;
> +
> +    if (V4L2_TYPE_IS_OUTPUT(p->type)) {
> +          do {
> +          } while (dequeue_v4lbuf(p, timeout));
> +    }
> +
> +    if (f) {
> +        ret = v4lbufpool_get_from_avframe(f, p);
> +        if (ret)
> +            return ret;
> +    }
> +
> +    for (i = 0; i < p->num_buffers; i++) {
> +        if (p->buffers[i].status == V4LBUF_AVAILABLE)
> +            return &p->buffers[i];
> +    }
> +
> +    return NULL;
> +}
> +
> +int avpriv_set_stream_status(V4LBufferPool* bp, int cmd)
> +{
> +    int type = bp->type;
> +    int ret;
> +
> +    ret = ioctl(bp->fd, cmd, &type);
> +    if (ret < 0)
> +        return AVERROR(errno);
> +
> +    bp->streamon = (cmd == VIDIOC_STREAMON);
> +
> +    return 0;
> +}
> +
> +int avpriv_v4l_enqueue(V4LBufferPool* bp, const AVFrame* f, const AVPacket* pkt)

Just make separate functions.

> +{
> +    V4LBuffer* avbuf;
> +    int ret;
> +
> +    if (!f && !pkt) {
> +        av_log(bp->log_ctx, AV_LOG_ERROR, "either AVFrame* or AVPacket*must valid\n");
> +        return AVERROR_BUG;
> +    }
> +
> +    avbuf = avpriv_v4lbufpool_getfreebuf(bp, f, pkt);
> +    if (!avbuf)
> +        return AVERROR(ENOMEM);
> +
> +    if (pkt) {
> +        ret = avpkt_to_v4lbuf(pkt, avbuf);
> +        if (ret)
> +            return ret;
> +    }
> +
> +    if (f) {
> +        ret = avframe_to_v4lbuf(f, avbuf);
> +        if (ret)
> +            return ret;
> +    }
> +
> +    ret = enqueue_v4lbuf(avbuf);
> +    if (ret)
> +        return ret;
> +
> +    return 0;
> +}
> +
> +int avpriv_v4l_dequeue(V4LBufferPool* bp, AVFrame* f, AVPacket* pkt, unsigned int timeout)

Likewise.

> +{
> +    V4LBuffer* avbuf = NULL;
> +
> +    if (!f && !pkt) {
> +        av_log(bp->log_ctx, AV_LOG_ERROR, "either AVFrame* or AVPacket* must be valid\n");
> +        return AVERROR_BUG;
> +    }
> +
> +    avbuf = dequeue_v4lbuf(bp, timeout);
> +    if (!avbuf) {
> +        if (bp->broken)
> +            return AVERROR_EOF;
> +
> +        return AVERROR(EAGAIN);
> +    }
> +
> +    if (f)
> +        return v4lbuf_to_avframe(f, avbuf);
> +
> +    if (pkt)
> +        return v4lbuf_to_avpkt(pkt, avbuf);
> +
> +    return AVERROR_BUG;
> +}

As noted above, I think all of this stuff should be split into the buffer pool parts and the common V4L2 streaming parts.

> diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
> new file mode 100644
> index 0000000..d457473
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m.c
> @@ -0,0 +1,356 @@
> +/*
> + * V4L mem2mem wrapper
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <unistd.h>
> +#include <dirent.h>
> +#include <fcntl.h>
> +#include "libavutil/imgutils.h"
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/pixdesc.h"
> +#include "avcodec.h"
> +#include "v4l2_m2m_avcodec.h"
> +#include "v4l2_buffers.h"
> +#include "v4l2_fmt.h"
> +#include "v4l2_m2m.h"
> +
> +#define V4L_MAX_STREAM_SIZE (3*1024*1024)

Please describe where this number comes from.

> +
> +static inline int try_raw_format(V4LBufferPool* bp, enum AVPixelFormat pixfmt)
> +{
> +    struct v4l2_format *fmt = &bp->format;
> +    int ret, i, h;
> +
> +    fmt->type  = bp->type;
> +
> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
> +        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixfmt);
> +
> +        fmt->fmt.pix_mp.pixelformat = avpriv_v4l_fmt_ff2v4l(pixfmt, bp->av_codec_id, FF_V4L_PACK_AVFRAME);
> +        if (!fmt->fmt.pix_mp.pixelformat)
> +            return AVERROR(EINVAL);
> +
> +        fmt->fmt.pix_mp.num_planes = av_pix_fmt_count_planes(pixfmt);
> +        for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
> +            fmt->fmt.pix_mp.plane_fmt[i].bytesperline = av_image_get_linesize(pixfmt, bp->width, i);
> +            h = (i == 1 || i == 2) ? FF_CEIL_RSHIFT(bp->height, desc->log2_chroma_h) : bp->height;
> +            fmt->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->fmt.pix_mp.plane_fmt[i].bytesperline * h;
> +        }
> +    } else {
> +        fmt->fmt.pix.pixelformat  = avpriv_v4l_fmt_ff2v4l(pixfmt, bp->av_codec_id, FF_V4L_PACK_AVFRAME);
> +        if (!fmt->fmt.pix.pixelformat)
> +            return AVERROR(EINVAL);
> +
> +        fmt->fmt.pix.bytesperline = av_image_get_linesize(pixfmt, bp->width, 0);
> +        fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * bp->height;
> +    }
> +
> +    ret = ioctl(bp->fd, VIDIOC_TRY_FMT, fmt);
> +    if (ret)
> +        return AVERROR(EINVAL);
> +
> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
> +        fmt->fmt.pix_mp.height = bp->height;
> +        fmt->fmt.pix_mp.width = bp->width;
> +    } else {
> +        fmt->fmt.pix.height = bp->height;
> +        fmt->fmt.pix.width = bp->width;
> +    }
> +
> +    return 0;
> +}
> +
> +static int set_raw_format(V4LBufferPool* bp, int set)
> +{
> +    enum AVPixelFormat pixfmt = bp->av_pix_fmt;
> +    struct v4l2_format *fmt = &bp->format;
> +    struct v4l2_fmtdesc fmtdesc = { 0 };
> +    int ret;
> +
> +    fmtdesc.type = bp->type;
> +    if (pixfmt != AV_PIX_FMT_NONE) {
> +        ret = try_raw_format(bp, pixfmt);
> +        if (ret)
> +            pixfmt = AV_PIX_FMT_NONE;
> +    }
> +
> +    while (AV_PIX_FMT_NONE == pixfmt && !ioctl(bp->fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
> +
> +        pixfmt = avpriv_v4l_fmt_v4l2ff(fmtdesc.pixelformat, AV_CODEC_ID_RAWVIDEO);
> +
> +        ret = try_raw_format(bp, pixfmt);
> +        if (ret)
> +            pixfmt = AV_PIX_FMT_NONE;
> +
> +        if (pixfmt != AV_PIX_FMT_NONE && set)
> +            bp->av_pix_fmt = pixfmt;
> +
> +        fmtdesc.index++;
> +    }
> +
> +    if (pixfmt == AV_PIX_FMT_NONE)
> +        return AVERROR(EINVAL);
> +
> +    if (set)
> +        return ioctl(bp->fd, VIDIOC_S_FMT, fmt);
> +
> +    return 0;
> +}
> +
> +static int set_coded_format(V4LBufferPool* bp, int set)
> +{
> +    struct v4l2_format *fmt = &bp->format;
> +    struct v4l2_fmtdesc fdesc;
> +    uint32_t v4l2_fmt;
> +    int found = 0;
> +
> +    v4l2_fmt = avpriv_v4l_fmt_ff2v4l(bp->av_pix_fmt, bp->av_codec_id, FF_V4L_PACK_AVPACKET);
> +    memset(&fdesc, 0, sizeof(fdesc));
> +    fdesc.type = bp->type;
> +
> +    while (!ioctl(bp->fd, VIDIOC_ENUM_FMT, &fdesc)) {
> +        if (v4l2_fmt == fdesc.pixelformat) {
> +            found = 1;
> +            break;
> +        }
> +        fdesc.index++;
> +    }
> +
> +    if (!found)
> +        return AVERROR(EINVAL);
> +
> +    fmt->type = bp->type;
> +
> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
> +        fmt->fmt.pix_mp.num_planes = 1;
> +        fmt->fmt.pix_mp.pixelformat = v4l2_fmt;
> +        if (!fmt->fmt.pix_mp.pixelformat) {
> +            av_log(bp->log_ctx, AV_LOG_ERROR, "no V4L codec for id %i\n", bp->av_codec_id);
> +            return AVERROR(EINVAL);
> +        }
> +        fmt->fmt.pix_mp.plane_fmt[0].sizeimage = V4L_MAX_STREAM_SIZE;
> +        fmt->fmt.pix_mp.height = bp->height;
> +        fmt->fmt.pix_mp.width = bp->width;
> +
> +    } else {
> +        fmt->fmt.pix.pixelformat = v4l2_fmt;
> +        if (!fmt->fmt.pix.pixelformat) {
> +            av_log(bp->log_ctx, AV_LOG_ERROR, "no V4L codec for id %i\n", bp->av_codec_id);
> +            return AVERROR(EINVAL);
> +        }
> +        fmt->fmt.pix.sizeimage = V4L_MAX_STREAM_SIZE;
> +        fmt->fmt.pix.height = bp->height;
> +        fmt->fmt.pix.width = bp->width;
> +    }
> +
> +    if (set)
> +        return ioctl(bp->fd, VIDIOC_S_FMT, fmt);
> +
> +    return ioctl(bp->fd, VIDIOC_TRY_FMT, fmt);
> +}
> +
> +int avpriv_set_pool_format(V4LBufferPool* bp, int set)
> +{
> +    if (bp->av_codec_id == AV_CODEC_ID_RAWVIDEO)
> +        return set_raw_format(bp, set);
> +
> +    return set_coded_format(bp, set);
> +}
> +
> +static inline int splane_video(struct v4l2_capability *cap)
> +{
> +    if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) & V4L2_CAP_STREAMING)
> +        return 1;
> +
> +    if (cap->capabilities & V4L2_CAP_VIDEO_M2M)
> +        return 1;
> +
> +    return 0;
> +}
> +
> +static inline int mplane_video(struct v4l2_capability *cap)
> +{
> +    if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE) & V4L2_CAP_STREAMING)
> +        return 1;
> +
> +    if (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
> +        return 1;
> +
> +    return 0;
> +}
> +
> +static int prepare_pools(V4Lm2mContext* s, void *log_ctx)
> +{
> +    int ret;
> +
> +    s->capture_pool.log_ctx = s->output_pool.log_ctx = log_ctx;
> +    s->capture_pool.broken = s->output_pool.broken = 0;
> +    s->capture_pool.fd = s->output_pool.fd = s->fd;
> +    s->capture_pool.name = "capture pool";
> +    s->output_pool.name = "output pool";
> +
> +    memset(&s->cap, 0, sizeof(s->cap));
> +    ret = ioctl(s->fd, VIDIOC_QUERYCAP, &s->cap);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +
> +    if (mplane_video(&s->cap)) {
> +        s->capture_pool.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +        s->output_pool.type  = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +        return 0;
> +    }
> +
> +    if (splane_video(&s->cap)) {
> +        s->capture_pool.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +        s->output_pool.type  = V4L2_BUF_TYPE_VIDEO_OUTPUT;
> +        return 0;
> +    }
> +
> +    return AVERROR(EINVAL);
> +}
> +
> +static int probe_and_set(V4Lm2mContext* s, void *log_ctx, int set)
> +{
> +    int fail_log_level = ( set ? AV_LOG_ERROR : AV_LOG_DEBUG);
> +    int ret;
> +
> +    s->fd = open(s->devname, O_RDWR, 0);

O_NONBLOCK, given DQBUF is used as if it is?

> +    if (s->fd < 0)
> +        return AVERROR(errno);
> +
> +    ret = prepare_pools(s, log_ctx);
> +    if (ret < 0)
> +        goto error;
> +
> +    if (s->output_pool.cfg.format) {
> +        ret = s->output_pool.cfg.format(&s->output_pool, set);
> +        if (ret) {
> +            av_log(log_ctx, fail_log_level, "can't set input format\n");
> +            goto error;
> +        }
> +    }
> +
> +    if (s->capture_pool.cfg.format) {
> +        ret = s->capture_pool.cfg.format(&s->capture_pool, set);
> +        if (ret) {
> +            av_log(log_ctx, fail_log_level, "can't to set output format\n");
> +            goto error;
> +        }
> +    }
> +
> +    if (s->output_pool.cfg.init && set) {
> +        ret = s->output_pool.cfg.init(&s->output_pool);
> +        if (ret) {
> +            av_log(log_ctx, fail_log_level, "no output pool's buffers\n");
> +            goto error;
> +        }
> +    }
> +
> +    if (s->capture_pool.cfg.init && set) {
> +        ret = s->capture_pool.cfg.init(&s->capture_pool);
> +        if (ret) {
> +            av_log(log_ctx, fail_log_level, "no capture pool's buffers\n");
> +            goto error;
> +        }
> +    }
> +
> +    av_log(log_ctx, AV_LOG_INFO, "using driver '%s' on card '%s'\n", s->cap.driver, s->cap.card);
> +
> +error:
> +    if (!set || ret) {
> +        close(s->fd);
> +        s->fd = 0;
> +    }
> +
> +    return ret;
> +}
> +
> +int avpriv_v4lm2m_init(V4Lm2mContext* s, void* log_ctx)
> +{
> +    char *devname_save = s->devname;
> +    int ret = AVERROR(EINVAL);
> +    char tmpbuf[PATH_MAX];
> +    struct dirent *dp;
> +    DIR *dirp;
> +
> +    if (s->devname && *s->devname)
> +        return probe_and_set(s, log_ctx, 1);
> +
> +    if (!(dirp = opendir("/dev")))
> +        return AVERROR(errno);
> +
> +    for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
> +
> +        if (!strncmp(dp->d_name, "video", sizeof("video") - 1)) {
> +            snprintf(tmpbuf, sizeof(tmpbuf) - 1, "/dev/%s", dp->d_name);
> +            av_log(log_ctx, AV_LOG_DEBUG, "probing %s\n", tmpbuf);
> +
> +            s->devname = tmpbuf;
> +            ret = probe_and_set(s, log_ctx, 0);
> +            if (!ret)
> +                break;
> +        }
> +    }
> +    closedir(dirp);
> +
> +    if (ret) {
> +        av_log(log_ctx, AV_LOG_ERROR, "Could not find a valid device\n");
> +        s->devname = devname_save;
> +        return ret;
> +    }
> +
> +    av_log(log_ctx, AV_LOG_INFO, "Using device %s\n", tmpbuf);
> +    ret = probe_and_set(s, log_ctx, 1);
> +    s->devname = devname_save;

This probing structure feels very fragile and possibly harmful (opening random devices and poking them).  It might be better to just force the user to supply the right device path?

> +
> +    return ret;
> +}
> +
> +int ff_v4lm2m_codec_init(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +
> +    return avpriv_v4lm2m_init(s, avctx);
> +}
> +
> +int avpriv_v4lm2m_end(V4Lm2mContext* s)
> +{
> +    avpriv_release_buffer_pool(&s->output_pool);
> +    avpriv_release_buffer_pool(&s->capture_pool);
> +    avpriv_set_stream_status(&s->output_pool, VIDIOC_STREAMOFF);
> +    avpriv_set_stream_status(&s->capture_pool, VIDIOC_STREAMOFF);
> +    close(s->fd);
> +
> +    return 0;
> +}
> +
> +int ff_v4lm2m_codec_end(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +
> +    av_log(avctx, AV_LOG_DEBUG, "Closing context\n");
> +
> +    return avpriv_v4lm2m_end(s);
> +}
> diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
> new file mode 100644
> index 0000000..226bc3c
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m.h
> @@ -0,0 +1,69 @@
> +/*
> + * V4L2 mem2mem helper functions
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVCODEC_V4L2_M2M_H
> +#define AVCODEC_V4L2_M2M_H
> +
> +#include "v4l2_buffers.h"
> +#include "v4l2_fmt.h"
> +
> +#define V4L_M2M_DEFAULT_OPTS \
> +    { "device",\
> +        "Path to the device to use",\
> +        OFFSET(devname),\
> +        AV_OPT_TYPE_STRING,\
> +        {.str = NULL }, 0, 0, FLAGS },\
> +    { "input_memory",\
> +        "Input memory model: See V4L2_MEMORY_* in videodev2.h. This depends on the HW but default should work with most but would imply useless memcpy()'s if used improperly.",\
> +        OFFSET(output_pool.memory),\
> +        AV_OPT_TYPE_INT,\
> +        {.i64 = V4L2_MEMORY_MMAP},\
> +        0, INT_MAX, FLAGS },\
> +    { "output_memory",\
> +        "Output memory model: See V4L2_MEMORY_* in videodev2.h. This depends on the HW but default should work with most.",\
> +        OFFSET(capture_pool.memory),\
> +        AV_OPT_TYPE_INT,\
> +        {.i64 = V4L2_MEMORY_MMAP},\
> +        0, INT_MAX, FLAGS },\
> +    { "num_output_pool_buffers",\
> +        "Number of buffers in the output pool",\
> +        OFFSET(output_pool.num_buffers),\
> +        AV_OPT_TYPE_INT,\
> +        { .i64 = 16 },\
> +        4, INT_MAX, FLAGS }

Can we attempt to set this automatically based on the codec?  16 won't be enough for worst-case H.264/H.265.

> +
> +typedef struct V4Lm2mContext
> +{
> +    AVClass *class;
> +    int fd;
> +    char *devname;
> +    struct v4l2_capability cap;
> +    V4LBufferPool output_pool;
> +    V4LBufferPool capture_pool;
> +} V4Lm2mContext;
> +
> +int avpriv_v4lm2m_init(V4Lm2mContext* s, void* log_ctx);
> +int avpriv_set_pool_format(V4LBufferPool* bp, int set);

Needs more namespace.

> +int avpriv_v4lm2m_end(V4Lm2mContext* ctx);
> +
> +#endif /* AVCODEC_V4L2_M2M_H */
> diff --git a/libavcodec/v4l2_m2m_avcodec.h b/libavcodec/v4l2_m2m_avcodec.h
> new file mode 100644
> index 0000000..2d0f1b6
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m_avcodec.h
> @@ -0,0 +1,32 @@
> +/*
> + * V4L2 mem2mem avcodec helper functions
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVCODEC_V4L2_M2M_AVCODEC_H
> +#define AVCODEC_V4L2_M2M_AVCODEC_H
> +
> +#include "avcodec.h"
> +
> +int ff_v4lm2m_codec_init(AVCodecContext *avctx);
> +int ff_v4lm2m_codec_end(AVCodecContext *avctx);
> +
> +#endif
> diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> new file mode 100644
> index 0000000..2cc59c5
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m_dec.c
> @@ -0,0 +1,229 @@
> +/*
> + * V4L2 mem2mem decoders
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/ioctl.h>
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/opt.h"
> +#include "v4l2_m2m_avcodec.h"
> +#include "v4l2_fmt.h"
> +#include "v4l2_buffers.h"
> +#include "v4l2_m2m.h"
> +#include "decode.h"
> +#include "avcodec.h"
> +
> +static int try_start(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    struct v4l2_selection selection;
> +    struct v4l2_control ctrl;
> +    int ret;
> +
> +    if (out_pool->streamon && cap_pool->streamon)
> +        return 0;
> +
> +    /* this will report the size of the frame back (see a4lbuf_to_avframe) */
> +    cap_pool->height = avctx->coded_height;
> +    cap_pool->width = avctx->coded_width;

Does coded_height/width need to be set to anything sensible here?  That won't be true in general.

> +
> +    /* start the output process */
> +    if (!out_pool->streamon) {
> +        ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMON);
> +        if (ret < 0) {
> +            av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON on output pool\n");
> +            return ret;
> +        }
> +    }
> +
> +    /* get the capture format */
> +    cap_pool->format.type = cap_pool->type;
> +    ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_pool->format);
> +    if (ret) {
> +        av_log(avctx, AV_LOG_ERROR, "VIDIOC_G_FMT ioctl\n");
> +        return ret;
> +    }
> +
> +    /* store what the decoder gives */
> +    avctx->pix_fmt = avpriv_v4l_fmt_v4l2ff(cap_pool->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
> +    cap_pool->av_pix_fmt = avctx->pix_fmt;
> +
> +    /* set the crop parameters */
> +    selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +    selection.r.height = avctx->coded_height;
> +    selection.r.width = avctx->coded_width;
> +    ret = ioctl(s->fd, VIDIOC_S_SELECTION, &selection);
> +    if (!ret) {
> +        ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_ERROR, "VIDIOC_G_SELECTION ioctl\n");
> +        } else {
> +            av_log(avctx, AV_LOG_DEBUG, "crop output %dx%d\n", selection.r.width, selection.r.height);
> +            /* update the size of the resulting frame */
> +            cap_pool->height = selection.r.height;
> +            cap_pool->width  = selection.r.width;
> +        }
> +    }
> +
> +    /* get the minimum number of buffers required by capture */
> +    memset(&ctrl, 0, sizeof(ctrl));
> +    ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
> +    ret = ioctl(s->fd, VIDIOC_G_CTRL, &ctrl);
> +    if (!ret) {
> +        cap_pool->min_queued_buffers = ctrl.value;
> +    }
> +
> +    /* init the capture pool */
> +    if (!cap_pool->buffers) {
> +        ret = avpriv_init_v4lbufpool(cap_pool);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_DEBUG, "can't request output buffers\n");
> +            return ret;
> +        }
> +    }
> +
> +    /* start the capture process */
> +    ret = avpriv_set_stream_status(cap_pool, VIDIOC_STREAMON);
> +    if (ret) {
> +        av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON, on capture pool\n");
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
> +static av_cold int v4lm2m_decode_init(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +
> +    out_pool->default_flags = cap_pool->default_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +    out_pool->cfg.format = cap_pool->cfg.format = avpriv_set_pool_format;
> +    out_pool->height = cap_pool->height = avctx->coded_height;
> +    out_pool->width = cap_pool->width =avctx->coded_width;
> +
> +    out_pool->cfg.init = avpriv_init_v4lbufpool;
> +    out_pool->av_codec_id = avctx->codec_id;
> +    out_pool->av_pix_fmt  = AV_PIX_FMT_NONE;
> +
> +    cap_pool->cfg.init = NULL;
> +    cap_pool->av_codec_id = AV_CODEC_ID_RAWVIDEO;
> +    cap_pool->av_pix_fmt = avctx->pix_fmt;
> +    cap_pool->min_queued_buffers = 6;
> +
> +    return ff_v4lm2m_codec_init(avctx);
> +}
> +
> +static int v4lm2m_receive_frame(AVCodecContext *avctx, AVFrame *frame)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    unsigned int timeout = 1000;
> +    AVPacket avpkt = {0};
> +    int ret;
> +
> +    ret = ff_decode_get_packet(avctx, &avpkt);
> +    if (ret < 0 && ret != AVERROR_EOF)
> +        return ret;
> +
> +    ret = avpriv_v4l_enqueue(out_pool, NULL, &avpkt);
> +    if (ret < 0)
> +        return ret;
> +
> +    ret = try_start(avctx);
> +    if (ret)
> +        return 0;
> +
> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);

I feel like if the stream has a lot of delay then you will end up needing to wait for the timeout to get the required EAGAIN, which at 1s is very large.  (Though I think you won't in common cases because of the min_queued_buffers constraint in dequeue.)

> +}
> +
> +#define OFFSET(x) offsetof(V4Lm2mContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
> +
> +        static const AVOption options[] = {
> +        V4L_M2M_DEFAULT_OPTS,{ "num_capture_pool_extra_buffers",
> +        "Number of extra buffers in the capture pool",
> +        OFFSET(capture_pool.num_buffers), AV_OPT_TYPE_INT,{.i64 = 6}, 4, INT_MAX, FLAGS},
> +        { NULL},
> +        };
> +
> +#define M2MDEC(NAME, LONGNAME, CODEC, bsf_name) \
> +static const AVClass v4l2_m2m_ ## NAME ## _dec_class = {\
> +    .class_name = #NAME "_v4l2_m2m_decoder",\
> +    .item_name  = av_default_item_name,\
> +    .option     = options,\
> +    .version    = LIBAVUTIL_VERSION_INT,\
> +};\
> +\
> +AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \
> +    .name           = #NAME "_v4l2m2m" ,\
> +    .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " decoder wrapper"),\
> +    .type           = AVMEDIA_TYPE_VIDEO,\
> +    .id             = CODEC ,\
> +    .priv_data_size = sizeof(V4Lm2mContext),\
> +    .priv_class     = &v4l2_m2m_ ## NAME ## _dec_class,\
> +    .init           = v4lm2m_decode_init,\
> +    .receive_frame  = v4lm2m_receive_frame,\
> +    .close          = ff_v4lm2m_codec_end,\
> +    .capabilities   = CODEC_CAP_DELAY,\
> +    .bsfs           = bsf_name, \
> +};
> +
> +#if CONFIG_H263_V4L2M2M_DECODER
> +        M2MDEC(h263, "H.263", AV_CODEC_ID_H263, NULL);
> +#endif
> +
> +#if CONFIG_H264_V4L2M2M_DECODER
> +        M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb");
> +#endif
> +
> +#if CONFIG_MPEG1_V4L2M2M_DECODER
> +        M2MDEC(mpeg1, "MPEG1", AV_CODEC_ID_MPEG1VIDEO, NULL);
> +#endif
> +
> +#if CONFIG_MPEG2_V4L2M2M_DECODER
> +        M2MDEC(mpeg2, "MPEG2", AV_CODEC_ID_MPEG2VIDEO, NULL);
> +#endif
> +
> +#if CONFIG_MPEG4_V4L2M2M_DECODER
> +        M2MDEC(mpeg4, "MPEG4", AV_CODEC_ID_MPEG4, NULL);
> +#endif
> +
> +#if CONFIG_VC1_V4L2M2M_DECODER
> +        M2MDEC(vc1 , "VC1", AV_CODEC_ID_VC1, NULL);
> +#endif
> +
> +#if CONFIG_VP8_V4L2M2M_DECODER
> +        M2MDEC(vp8, "VP8", AV_CODEC_ID_VP8, NULL);
> +#endif
> +
> +#if CONFIG_HEVC_V4L2M2M_DECODER
> +        M2MDEC(hevc , "HEVC", AV_CODEC_ID_HEVC, "hevc_mp4toannexb");
> +#endif
> +
> +#if CONFIG_VP9_V4L2M2M_DECODER
> +        M2MDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL);
> +#endif
> diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> new file mode 100644
> index 0000000..bc32e33
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m_enc.c
> @@ -0,0 +1,270 @@
> +/*
> + * V4L2 mem2mem encoders
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/ioctl.h>
> +
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/opt.h"
> +#include "v4l2_m2m_avcodec.h"
> +#include "v4l2_buffers.h"
> +#include "v4l2_fmt.h"
> +#include "v4l2_m2m.h"
> +#include "avcodec.h"
> +
> +#define STR(s) AV_TOSTRING(s)
> +#define MPEG_CID(x) V4L2_CID_MPEG_VIDEO_##x
> +#define MPEG_VIDEO(x) V4L2_MPEG_VIDEO_##x
> +
> +#define SET_V4L_EXT_CTRL(TYPE, ID, VALUE, NAME)                     \
> +{                                                                   \
> +    struct v4l2_ext_control ctrl = { 0 };                           \
> +    struct v4l2_ext_controls ctrls = { 0 };                         \
> +    ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;                        \
> +    ctrls.controls = &ctrl;                                         \
> +    ctrl.TYPE = VALUE ;                                             \
> +    ctrl.id = ID ;                                                  \
> +    ctrls.count = 1;                                                \
> +                                                                    \
> +    if ((ret = ioctl(s->fd, VIDIOC_S_EXT_CTRLS, &ctrls)) < 0)       \
> +        av_log(avctx, AV_LOG_WARNING, "Failed to set " NAME "%s\n", STR(ID));  \
> +}
> +
> +static inline int v4l_h264_profile_from_ff(int p)
> +{
> +    switch(p) {
> +    case FF_PROFILE_H264_CONSTRAINED_BASELINE:
> +        return MPEG_VIDEO(H264_PROFILE_CONSTRAINED_BASELINE);
> +    case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_444_PREDICTIVE);
> +    case FF_PROFILE_H264_HIGH_422_INTRA:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_422_INTRA);
> +    case FF_PROFILE_H264_HIGH_444_INTRA:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_444_INTRA);
> +    case FF_PROFILE_H264_HIGH_10_INTRA:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_10_INTRA);
> +    case FF_PROFILE_H264_HIGH_422:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_422);
> +    case FF_PROFILE_H264_BASELINE:
> +        return MPEG_VIDEO(H264_PROFILE_BASELINE);
> +    case FF_PROFILE_H264_EXTENDED:
> +        return MPEG_VIDEO(H264_PROFILE_EXTENDED);> +    case FF_PROFILE_H264_HIGH_10:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_10);
> +    case FF_PROFILE_H264_MAIN:
> +        return MPEG_VIDEO(H264_PROFILE_MAIN);
> +    case FF_PROFILE_H264_HIGH:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH);

Out of curiosity, how many of these actually have any support at all on real devices?

> +    }
> +
> +    return -1;
> +}
> +
> +static inline int v4l_mpeg4_profile_from_ff(int p)
> +{
> +    switch(p) {
> +    case FF_PROFILE_MPEG4_ADVANCED_CODING:
> +        return MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY);
> +    case FF_PROFILE_MPEG4_ADVANCED_SIMPLE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_SIMPLE);
> +    case FF_PROFILE_MPEG4_SIMPLE_SCALABLE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_SIMPLE_SCALABLE);
> +    case FF_PROFILE_MPEG4_SIMPLE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_SIMPLE);
> +    case FF_PROFILE_MPEG4_CORE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_CORE);
> +    }
> +
> +    return -1;
> +}
> +
> +static av_cold int v4lm2m_encode_init(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    int qmin, qmax, ret, val;
> +
> +    out_pool->default_flags = cap_pool->default_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +    out_pool->cfg.format = cap_pool->cfg.format = avpriv_set_pool_format;
> +    out_pool->cfg.init = cap_pool->cfg.init = avpriv_init_v4lbufpool;
> +    out_pool->height = cap_pool->height = avctx->height;
> +    out_pool->width = cap_pool->width = avctx->width;
> +
> +    /* out pool */
> +    out_pool->av_codec_id = AV_CODEC_ID_RAWVIDEO;
> +    out_pool->av_pix_fmt = avctx->pix_fmt;
> +
> +    /* cap pool */
> +    cap_pool->av_codec_id = avctx->codec_id;
> +    cap_pool->av_pix_fmt = AV_PIX_FMT_NONE;
> +    cap_pool->min_queued_buffers = 1;
> +
> +    if (ret = ff_v4lm2m_codec_init(avctx))
> +        return ret;
> +
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(HEADER_MODE), MPEG_VIDEO(HEADER_MODE_JOINED_WITH_1ST_FRAME), "header mode");
> +
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(B_FRAMES), avctx->max_b_frames,  "number of B-frames");
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(GOP_SIZE), avctx->gop_size,"gop size");
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(BITRATE) , avctx->bit_rate, "bit rate");
> +
> +    switch(avctx->codec_id) {
> +    case AV_CODEC_ID_H264:
> +        val = v4l_h264_profile_from_ff(avctx->profile);
> +        if (val >= 0) {
> +            SET_V4L_EXT_CTRL(value, MPEG_CID(H264_PROFILE), val, "h264 profile");
> +        }
> +        qmin = MPEG_CID(H264_MIN_QP);
> +        qmax = MPEG_CID(H264_MAX_QP);
> +        break;
> +    case AV_CODEC_ID_MPEG4:
> +        val = v4l_mpeg4_profile_from_ff(avctx->profile);
> +        if (val >= 0) {
> +            SET_V4L_EXT_CTRL(value, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile");
> +        }
> +        qmin = MPEG_CID(MPEG4_MIN_QP);
> +        qmax = MPEG_CID(MPEG4_MAX_QP);
> +        if (avctx->flags & CODEC_FLAG_QPEL) {
> +            SET_V4L_EXT_CTRL(value, MPEG_CID(MPEG4_QPEL), 1, "qpel");
> +        }
> +        break;
> +    case AV_CODEC_ID_H263:
> +        qmin = MPEG_CID(H263_MIN_QP);
> +        qmax = MPEG_CID(H263_MAX_QP);
> +        break;
> +    case AV_CODEC_ID_VP8:
> +    case AV_CODEC_ID_VP9:
> +        qmin = MPEG_CID(VPX_MIN_QP);
> +        qmax = MPEG_CID(VPX_MAX_QP);
> +        break;
> +    default:
> +        return 0;
> +    }
> +
> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");
> +
> +    return 0;
> +}

This doesn't set extradata - you need to extract the codec global headers (such as H.264 SPS and PPS) at init time to be able to write correct files for some codecs (such as H.264) with muxers requiring global headers (such as MP4).  It kindof works without it, but the files created will not conform and will not be usable on some players.

> +
> +static int v4lm2m_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> +                              const AVFrame *pict, int *got_packet)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    unsigned int timeout = 1000;
> +    int ret;
> +
> +    /* end of transfer */
> +    if (!pict) {
> +        if (out_pool->streamon) {
> +            ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMOFF);
> +            if (ret) {
> +                av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF failed on output pool\n");
> +                return ret;
> +            }
> +        }
> +        goto dequeue;
> +    }
> +
> +    ret = avpriv_v4l_enqueue(out_pool, pict, NULL);
> +    if (ret < 0)
> +        return ret;
> +
> +    if (!out_pool->streamon) {
> +        ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMON);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on output pool\n");
> +            return ret;
> +        }
> +    }
> +    if (!cap_pool->streamon) {
> +        ret = avpriv_set_stream_status(cap_pool, VIDIOC_STREAMON);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on capture pool\n");
> +            return ret;
> +        }
> +    }
> +
> +dequeue:
> +
> +    ret = avpriv_v4l_dequeue(cap_pool, NULL, pkt, timeout);
> +    if (ret == AVERROR(EAGAIN))
> +        return 0;
> +    if (!ret)
> +        *got_packet = 1;
> +
> +    return ret;
> +}

Does this actually work for a long stream?  You won't necessarily return a packet for every frame, but always need to enqueue a frame to be able to attempt to dequeue a packet.

It might be better to use the send/receive API here as well.

> +
> +#define OFFSET(x) offsetof(V4Lm2mContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> +
> +static const AVOption options[] = {
> +    V4L_M2M_DEFAULT_OPTS, { "num_capture_pool_buffers", "Number of buffers in the capture pool",
> +      OFFSET(capture_pool.num_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS }, { NULL },

4 feels very low for a default - more encode delay than that is quite common with B-frames.

> +};
> +
> +#define M2MENC(NAME, LONGNAME, CODEC) \
> +static const AVClass v4l2_m2m_ ## NAME ## _enc_class = {\
> +    .class_name = #NAME "_v4l2_m2m_encoder",\
> +    .item_name  = av_default_item_name,\
> +    .option     = options,\
> +    .version    = LIBAVUTIL_VERSION_INT,\
> +};\
> +\
> +AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
> +    .name           = #NAME "_v4l2m2m" ,\
> +    .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"),\
> +    .type           = AVMEDIA_TYPE_VIDEO,\
> +    .id             = CODEC ,\
> +    .priv_data_size = sizeof(V4Lm2mContext),\
> +    .priv_class     = &v4l2_m2m_ ## NAME ##_enc_class,\
> +    .init           = v4lm2m_encode_init,\
> +    .encode2        = v4lm2m_encode_frame,\
> +    .close          = ff_v4lm2m_codec_end,\
> +    .capabilities   = CODEC_CAP_DELAY,\
> +};
> +
> +#if CONFIG_H263_V4L2M2M_ENCODER
> +M2MENC(h263, "H.263", AV_CODEC_ID_H263);
> +#endif
> +
> +#if CONFIG_H264_V4L2M2M_ENCODER
> +M2MENC(h264, "H.264", AV_CODEC_ID_H264);
> +#endif
> +
> +#if CONFIG_MPEG4_V4L2M2M_ENCODER
> +M2MENC(mpeg4, "MPEG4", AV_CODEC_ID_MPEG4);
> +#endif
> +
> +#if CONFIG_VP8_V4L2M2M_ENCODER
> +M2MENC(vp8, "VP8", AV_CODEC_ID_VP8);
> +#endif
> +
> +#if CONFIG_HEVC_V4L2M2M_ENCODER
> +M2MENC(hevc, "HEVC", AV_CODEC_ID_HEVC);
> +#endif
> +

There is quite a bit more to think about here, I'll look at it further later.

- Mark
Jorge Ramirez-Ortiz Aug. 3, 2017, 2:51 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
> On 02/08/17 08:32, Jorge Ramirez-Ortiz wrote:
>> ...
>> diff --git a/compat/v4l2/v4l2-common.h b/compat/v4l2/v4l2-common.h
>> diff --git a/compat/v4l2/videodev2.h b/compat/v4l2/videodev2.h
> These are discussed in other threads.  I don't really have any comment either way.

ok. will be ammended in v4.

>
>> diff --git a/configure b/configure
>> index ed94de0..650c8fb 100755
>> --- a/configure
>> +++ b/configure
>> @@ -10,7 +10,6 @@
>>   # Prevent locale nonsense from breaking basic text processing.
>>   LC_ALL=C
>>   export LC_ALL
>> -
> Spurious change?
ack
>
>>   # make sure we are running under a compatible shell
>>   # try to make this part work with most shells
>>   
>> @@ -149,6 +148,7 @@ Component options:
>>     --disable-pixelutils     disable pixel utils in libavutil
>>   
>>   Individual component options:
>> +  --disable-v4l2_m2m       disable V4L2 mem2mem code [autodetect]
> s/_/-/ here.
ack

>
>>     --disable-everything     disable all components listed below
>>     --disable-encoder=NAME   disable encoder NAME
>>     --enable-encoder=NAME    enable encoder NAME
>> @@ -1432,6 +1432,7 @@ AVCODEC_COMPONENTS="
>>   
>>   AVDEVICE_COMPONENTS="
>>       indevs
>> +    v4l2_m2m
>>       outdevs
>>   "
>>   AVFILTER_COMPONENTS="
>> @@ -2269,11 +2270,12 @@ map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM
>>   
>>   loongson2_deps="mips"
>>   loongson3_deps="mips"
>> -v4l2_deps_any="linux_videodev2_h sys_videoio_h"
>> +v4l2_m2m_select="v4l2"
>>   mipsfpu_deps="mips"
>>   mipsdsp_deps="mips"
>>   mipsdspr2_deps="mips"
>>   mips32r2_deps="mips"
>> +vc1_v4l2m2m_decoder_deps="v4l2_m2m"
>>   mips32r5_deps="mips"
>>   mips32r6_deps="mips"
>>   mips64r2_deps="mips"
>> @@ -2284,6 +2286,9 @@ mmi_deps="mips"
>>   altivec_deps="ppc"
>>   dcbzl_deps="ppc"
>>   ldbrx_deps="ppc"
>> +vp8_v4l2m2m_decoder_deps="v4l2_m2m"
>> +vp8_v4l2m2m_encoder_deps="v4l2_m2m"
>> +vp9_v4l2m2m_decoder_deps="v4l2_m2m"
> These seem to be placed randomly in the file.  There is a hardware codec section at around line 2800, put all of these declarations there.

thanks for the guideline. will do.
>
>>   ppc4xx_deps="ppc"
>>   vsx_deps="altivec"
>>   power8_deps="vsx"
>> @@ -2437,15 +2442,22 @@ h261_decoder_select="mpegvideo"
>>   h261_encoder_select="aandcttables mpegvideoenc"
>>   h263_decoder_select="h263_parser h263dsp mpegvideo qpeldsp"
>>   h263_encoder_select="aandcttables h263dsp mpegvideoenc"
>> +h263_v4l2m2m_decoder_deps="v4l2_m2m"
>> +h263_v4l2m2m_encoder_deps="v4l2_m2m"
>>   h263i_decoder_select="h263_decoder"
>>   h263p_decoder_select="h263_decoder"
>>   h263p_encoder_select="h263_encoder"
>>   h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel videodsp"
>>   h264_decoder_suggest="error_resilience"
>> +h264_v4l2m2m_decoder_deps="v4l2_m2m"
>> +h264_v4l2m2m_encoder_deps="v4l2_m2m"
>>   hap_decoder_select="snappy texturedsp"
>>   hap_encoder_deps="libsnappy"
>>   hap_encoder_select="texturedspenc"
>>   hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp"
>> +hevc_encoder_select="hevc_v4l2m2m"
>> +hevc_v4l2m2m_decoder_deps="v4l2_m2m"
>> +hevc_v4l2m2m_encoder_deps="v4l2_m2m"
>>   huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp"
>>   huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp"
>>   iac_decoder_select="imc_decoder"
>> @@ -2482,6 +2494,7 @@ mpc7_decoder_select="bswapdsp mpegaudiodsp"
>>   mpc8_decoder_select="mpegaudiodsp"
>>   mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h"
>>   mpeg_xvmc_decoder_select="mpeg2video_decoder"
>> +mpeg1_v4l2m2m_decoder_deps="v4l2_m2m"
>>   mpegvideo_decoder_select="mpegvideo"
>>   mpeg1video_decoder_select="mpegvideo"
>>   mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp"
>> @@ -2489,6 +2502,8 @@ mpeg2video_decoder_select="mpegvideo"
>>   mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp"
>>   mpeg4_decoder_select="h263_decoder mpeg4video_parser"
>>   mpeg4_encoder_select="h263_encoder"
>> +mpeg4_v4l2m2m_decoder_deps="v4l2_m2m"
>> +mpeg4_v4l2m2m_encoder_deps="v4l2_m2m"
>>   msa1_decoder_select="mss34dsp"
>>   mscc_decoder_select="zlib"
>>   msmpeg4v1_decoder_select="h263_decoder"
>> @@ -3042,7 +3057,6 @@ qtkit_indev_select="qtkit"
>>   sdl2_outdev_deps="sdl2"
>>   sndio_indev_deps="sndio"
>>   sndio_outdev_deps="sndio"
>> -v4l_indev_deps="linux_videodev_h"
>>   v4l2_indev_select="v4l2"
>>   v4l2_outdev_select="v4l2"
>>   vfwcap_indev_deps="vfw32 vfwcap_defines"
>> @@ -3592,7 +3606,7 @@ done
>>   enable_weak audiotoolbox
>>   
>>   # Enable hwaccels by default.
>> -enable_weak d3d11va dxva2 vaapi vda vdpau videotoolbox_hwaccel xvmc
>> +enable_weak d3d11va dxva2 vaapi v4l2_m2m vda vdpau videotoolbox_hwaccel xvmc
>>   enable_weak xlib
>>   
>>   enable_weak cuda cuvid nvenc vda_framework videotoolbox videotoolbox_encoder
>> @@ -6058,12 +6072,10 @@ pod2man --help     > /dev/null 2>&1 && enable pod2man   || disable pod2man
>>   rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
>>   
>>   check_header linux/fb.h
>> -check_header linux/videodev.h
>> -check_header linux/videodev2.h
>> -check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
>>   
>>   check_header sys/videoio.h
>>   check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
>> +add_cflags -I$source_path/compat/v4l2
> Unconditionally?  Sounds useful on Windows.

yes forgot to restrict it. will be removed anyway on v4.

>
>>   
>>   check_lib user32 "windows.h winuser.h" GetShellWindow -luser32
>>   check_lib vfw32 "windows.h vfw.h" capCreateCaptureWindow -lvfw32
>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
>> index 364aec9..f45050e 100644
>> --- a/libavcodec/Makefile
>> +++ b/libavcodec/Makefile
>> @@ -101,7 +101,8 @@ OBJS-$(CONFIG_LZF)                     += lzf.o
>>   OBJS-$(CONFIG_MDCT)                    += mdct_fixed.o mdct_float.o mdct_fixed_32.o
>>   OBJS-$(CONFIG_ME_CMP)                  += me_cmp.o
>>   OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec_common.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o
>> -OBJS-$(CONFIG_V4L2)                    += v4l2-common.o
>> +OBJS-$(CONFIG_V4L2)                    += v4l2_fmt.o v4l2_buffers.o
>> +OBJS-$(CONFIG_V4L2_M2M)                += v4l2_m2m.o
> Random placing?  These should be in alphabetical order.

ack

>
>>   OBJS-$(CONFIG_MPEG_ER)                 += mpeg_er.o
>>   OBJS-$(CONFIG_MPEGAUDIO)               += mpegaudio.o
>>   OBJS-$(CONFIG_MPEGAUDIODSP)            += mpegaudiodsp.o                \
>> @@ -320,6 +321,8 @@ OBJS-$(CONFIG_H261_ENCODER)            += h261enc.o h261data.o h261.o
>>   OBJS-$(CONFIG_H263_DECODER)            += h263dec.o h263.o ituh263dec.o        \
>>                                             mpeg4video.o mpeg4videodec.o flvdec.o\
>>                                             intelh263dec.o h263data.o
>> +OBJS-$(CONFIG_H263_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
>> +OBJS-$(CONFIG_H263_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>>   OBJS-$(CONFIG_H263_ENCODER)            += mpeg4videoenc.o mpeg4video.o  \
>>                                             h263.o ituh263enc.o flvenc.o h263data.o
>>   OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
>> @@ -327,6 +330,8 @@ OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
>>                                             h264_mb.o h264_picture.o \
>>                                             h264_refs.o h264_sei.o \
>>                                             h264_slice.o h264data.o
>> +OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
>> +OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>>   OBJS-$(CONFIG_H264_CUVID_DECODER)      += cuvid.o
>>   OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
>>   OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
>> @@ -346,6 +351,8 @@ OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
>>                                             hevcdsp.o hevc_filter.o hevc_data.o
>>   OBJS-$(CONFIG_HEVC_CUVID_DECODER)      += cuvid.o
>>   OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o
>> +OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
>> +OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>>   OBJS-$(CONFIG_HEVC_NVENC_ENCODER)      += nvenc_hevc.o
>>   OBJS-$(CONFIG_NVENC_HEVC_ENCODER)      += nvenc_hevc.o
>>   OBJS-$(CONFIG_HEVC_QSV_DECODER)        += qsvdec_h2645.o
>> @@ -419,11 +426,13 @@ OBJS-$(CONFIG_MP3ON4FLOAT_DECODER)     += mpegaudiodec_float.o mpeg4audio.o
>>   OBJS-$(CONFIG_MPC7_DECODER)            += mpc7.o mpc.o
>>   OBJS-$(CONFIG_MPC8_DECODER)            += mpc8.o mpc.o
>>   OBJS-$(CONFIG_MPEGVIDEO_DECODER)       += mpeg12dec.o mpeg12.o mpeg12data.o
>> +OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>>   OBJS-$(CONFIG_MPEG1VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
>>   OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
>>   OBJS-$(CONFIG_MPEG2_MMAL_DECODER)      += mmaldec.o
>>   OBJS-$(CONFIG_MPEG2_QSV_DECODER)       += qsvdec_other.o
>>   OBJS-$(CONFIG_MPEG2_QSV_ENCODER)       += qsvenc_mpeg2.o
>> +OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>>   OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
>>   OBJS-$(CONFIG_MPEG2VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
>>   OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o
>> @@ -431,6 +440,8 @@ OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER)     += vaapi_encode_mpeg2.o
>>   OBJS-$(CONFIG_MPEG4_DECODER)           += xvididct.o
>>   OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
>>   OBJS-$(CONFIG_MPEG4_OMX_ENCODER)       += omx.o
>> +OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>> +OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER)   += v4l2_m2m_enc.o
>>   OBJS-$(CONFIG_MPL2_DECODER)            += mpl2dec.o ass.o
>>   OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o
>>   OBJS-$(CONFIG_MSCC_DECODER)            += mscc.o
>> @@ -503,6 +514,7 @@ OBJS-$(CONFIG_RALF_DECODER)            += ralf.o
>>   OBJS-$(CONFIG_RAWVIDEO_DECODER)        += rawdec.o
>>   OBJS-$(CONFIG_RAWVIDEO_ENCODER)        += rawenc.o
>>   OBJS-$(CONFIG_REALTEXT_DECODER)        += realtextdec.o ass.o
>> +OBJS-$(CONFIG_VC1_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
>>   OBJS-$(CONFIG_RL2_DECODER)             += rl2.o
>>   OBJS-$(CONFIG_ROQ_DECODER)             += roqvideodec.o roqvideo.o
>>   OBJS-$(CONFIG_ROQ_ENCODER)             += roqvideoenc.o roqvideo.o elbg.o
>> @@ -518,6 +530,8 @@ OBJS-$(CONFIG_RV30_DECODER)            += rv30.o rv34.o rv30dsp.o
>>   OBJS-$(CONFIG_RV40_DECODER)            += rv40.o rv34.o rv40dsp.o
>>   OBJS-$(CONFIG_SAMI_DECODER)            += samidec.o ass.o htmlsubtitles.o
>>   OBJS-$(CONFIG_S302M_DECODER)           += s302m.o
>> +OBJS-$(CONFIG_VP8_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
>> +OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
> As should all of the rest of these.

ah, I see..

>
>>   OBJS-$(CONFIG_S302M_ENCODER)           += s302menc.o
>>   OBJS-$(CONFIG_SANM_DECODER)            += sanm.o
>>   OBJS-$(CONFIG_SCPR_DECODER)            += scpr.o
>> @@ -628,6 +642,8 @@ OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r
>>                                             vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o
>>   OBJS-$(CONFIG_VP9_CUVID_DECODER)       += cuvid.o
>>   OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER)  += mediacodecdec.o
>> +OBJS-$(CONFIG_VP9_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
>> +OBJS-$(CONFIG_VP9_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
>>   OBJS-$(CONFIG_VP9_VAAPI_ENCODER)       += vaapi_encode_vp9.o
>>   OBJS-$(CONFIG_VPLAYER_DECODER)         += textdec.o ass.o
>>   OBJS-$(CONFIG_VQA_DECODER)             += vqavideo.o> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
>> index 4712592..d154ac9 100644
>> --- a/libavcodec/allcodecs.c
>> +++ b/libavcodec/allcodecs.c
>> @@ -207,8 +207,10 @@ static void register_all(void)
>>       REGISTER_ENCDEC (H263,              h263);
>>       REGISTER_DECODER(H263I,             h263i);
>>       REGISTER_ENCDEC (H263P,             h263p);
>> +    REGISTER_ENCDEC (H263_V4L2M2M,      h263_v4l2m2m);
>>       REGISTER_DECODER(H264,              h264);
>>       REGISTER_DECODER(H264_CRYSTALHD,    h264_crystalhd);
>> +    REGISTER_ENCDEC (H264_V4L2M2M,      h264_v4l2m2m);
>>       REGISTER_DECODER(H264_MEDIACODEC,   h264_mediacodec);
>>       REGISTER_DECODER(H264_MMAL,         h264_mmal);
>>       REGISTER_DECODER(H264_QSV,          h264_qsv);
>> @@ -219,6 +221,7 @@ static void register_all(void)
>>       REGISTER_ENCDEC (HAP,               hap);
>>       REGISTER_DECODER(HEVC,              hevc);
>>       REGISTER_DECODER(HEVC_QSV,          hevc_qsv);
>> +    REGISTER_ENCDEC(HEVC_V4L2M2M,       hevc_v4l2m2m);
>>       REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
>>       REGISTER_DECODER(HQ_HQA,            hq_hqa);
>>       REGISTER_DECODER(HQX,               hqx);
>> @@ -253,6 +256,7 @@ static void register_all(void)
>>       REGISTER_ENCDEC (MPEG2VIDEO,        mpeg2video);
>>       REGISTER_ENCDEC (MPEG4,             mpeg4);
>>       REGISTER_DECODER(MPEG4_CRYSTALHD,   mpeg4_crystalhd);
>> +    REGISTER_ENCDEC (MPEG4_V4L2M2M,     mpeg4_v4l2m2m);
>>       REGISTER_DECODER(MPEG4_MMAL,        mpeg4_mmal);
>>   #if FF_API_VDPAU
>>       REGISTER_DECODER(MPEG4_VDPAU,       mpeg4_vdpau);
>> @@ -262,8 +266,10 @@ static void register_all(void)
>>       REGISTER_DECODER(MPEG_VDPAU,        mpeg_vdpau);
>>       REGISTER_DECODER(MPEG1_VDPAU,       mpeg1_vdpau);
>>   #endif
>> +    REGISTER_DECODER(MPEG1_V4L2M2M,     mpeg1_v4l2m2m);
>>       REGISTER_DECODER(MPEG2_MMAL,        mpeg2_mmal);
>>       REGISTER_DECODER(MPEG2_CRYSTALHD,   mpeg2_crystalhd);
>> +    REGISTER_DECODER(MPEG2_V4L2M2M,     mpeg2_v4l2m2m);
>>       REGISTER_DECODER(MPEG2_QSV,         mpeg2_qsv);
>>       REGISTER_DECODER(MPEG2_MEDIACODEC,  mpeg2_mediacodec);
>>       REGISTER_DECODER(MSA1,              msa1);
>> @@ -361,6 +367,7 @@ static void register_all(void)
>>       REGISTER_DECODER(VC1IMAGE,          vc1image);
>>       REGISTER_DECODER(VC1_MMAL,          vc1_mmal);
>>       REGISTER_DECODER(VC1_QSV,           vc1_qsv);
>> +    REGISTER_DECODER(VC1_V4L2M2M,       vc1_v4l2m2m);
>>       REGISTER_ENCODER(VC2,               vc2);
>>       REGISTER_DECODER(VCR1,              vcr1);
>>       REGISTER_DECODER(VMDVIDEO,          vmdvideo);
>> @@ -372,7 +379,9 @@ static void register_all(void)
>>       REGISTER_DECODER(VP6F,              vp6f);
>>       REGISTER_DECODER(VP7,               vp7);
>>       REGISTER_DECODER(VP8,               vp8);
>> +    REGISTER_ENCDEC (VP8_V4L2M2M,       vp8_v4l2m2m);
>>       REGISTER_DECODER(VP9,               vp9);
>> +    REGISTER_DECODER(VP9_V4L2M2M,       vp9_v4l2m2m);
>>       REGISTER_DECODER(VQA,               vqa);
>>       REGISTER_DECODER(BITPACKED,         bitpacked);
>>       REGISTER_DECODER(WEBP,              webp);
> And these.
>
>> diff --git a/libavcodec/v4l2-common.c b/libavcodec/v4l2-common.c
>> deleted file mode 100644
>> diff --git a/libavcodec/v4l2-common.h b/libavcodec/v4l2-common.h
>> deleted file mode 100644
>> diff --git a/libavcodec/v4l2_fmt.c b/libavcodec/v4l2_fmt.c
>> new file mode 100644
>> diff --git a/libavcodec/v4l2_fmt.h b/libavcodec/v4l2_fmt.h
>> new file mode 100644
> I think it would have made more sense to move these files in a previous patch rather than here.
>
>
yes, that is changed on v4.

thanks!
Jorge Ramirez-Ortiz Aug. 4, 2017, 8:46 a.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:

agree with all your previous comments up to here (will fix).

>> +    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
>> +    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
>> +        pfd.events = POLLOUT | POLLERR | POLLWRNORM;
>> +        break;
>> +    default:
>> +        pfd.events = POLLIN | POLLERR | POLLRDNORM;
> What hits this default case?

nothing, it can't happen will remove.
>
>> +    }
>> +
>> +    ret = poll(&pfd, 1, timeout);
> Can this poll be interrupted?
yes. when that happens, we indicate no buffer available.
I think the main program should set the necessary masks.

>> +    if (ret <=  0)
>> +        return NULL;
>> +
>> +    memset(&buf, 0, sizeof(buf));
>> +    buf.memory = bp->memory;
>> +    buf.type = bp->type;
>> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
>> +        memset(planes, 0, sizeof(planes));
>> +        buf.length = VIDEO_MAX_PLANES;
>> +        buf.m.planes = planes;
>> +    }
>> +    ret = ioctl(bp->fd, VIDIOC_DQBUF, &buf);
>> +    if (ret) {
>> +        if (errno != EAGAIN && errno != EINVAL) {
> EINVAL is considered ok?

no any ioctl that returns non zero is a fault condition.
EINVAL (just as EAGAIN) is just not an unrecoverable error (we will just 
return null indicating that there is no buffer available)
>
>> +            av_log(bp->log_ctx, AV_LOG_DEBUG, "%s: VIDIOC_DQBUF, errno (%d)\n", bp->name, errno);
>> +            bp->broken = errno;
> errno can be overwritten by the av_log() call.

OK.

>
>> +        }
>> +        return NULL;
>> +    }
>> +
Mark Thompson Aug. 4, 2017, 11:26 a.m.
On 04/08/17 09:46, Jorge Ramirez wrote:
> On 08/03/2017 01:53 AM, Mark Thompson wrote:
>>> +    }
>>> +
>>> +    ret = poll(&pfd, 1, timeout);
>> Can this poll be interrupted?
> yes. when that happens, we indicate no buffer available.
> I think the main program should set the necessary masks.

I was thinking this might violate the send/receive semantics without EINTR handling - consider a situation where send returns EAGAIN (e.g. by trying to send 9001 packets to a decoder all at once) so the caller does a receive but that then races with a signal such that poll returns EINTR, then receive would return EAGAIN as well which isn't allowed.

If you want to impose signal handling requirements on the caller then that would need to be documented somewhere.

>>> +    if (ret <=  0)
>>> +        return NULL;
>>> +
>>> +    memset(&buf, 0, sizeof(buf));
>>> +    buf.memory = bp->memory;
>>> +    buf.type = bp->type;
>>> +    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
>>> +        memset(planes, 0, sizeof(planes));
>>> +        buf.length = VIDEO_MAX_PLANES;
>>> +        buf.m.planes = planes;
>>> +    }
>>> +    ret = ioctl(bp->fd, VIDIOC_DQBUF, &buf);
>>> +    if (ret) {
>>> +        if (errno != EAGAIN && errno != EINVAL) {
>> EINVAL is considered ok?
> 
> no any ioctl that returns non zero is a fault condition.
> EINVAL (just as EAGAIN) is just not an unrecoverable error (we will just return null indicating that there is no buffer available)

EINVAL usually indicates that the arguments were invalid somehow, but I think with this setup it's just going to call it again with pretty much arguments.  In what case can EINVAL be recoverable?

- Mark
Mark Thompson Aug. 4, 2017, 11:51 a.m.
On 02/08/17 08:32, Jorge Ramirez-Ortiz wrote:
> diff --git a/configure b/configure
> index ed94de0..650c8fb 100755
> --- a/configure
> +++ b/configure
> @@ -10,7 +10,6 @@
>  # Prevent locale nonsense from breaking basic text processing.
>  LC_ALL=C
>  export LC_ALL
> -
>  # make sure we are running under a compatible shell
>  # try to make this part work with most shells
>  
> @@ -149,6 +148,7 @@ Component options:
>    --disable-pixelutils     disable pixel utils in libavutil
>  
>  Individual component options:
> +  --disable-v4l2_m2m       disable V4L2 mem2mem code [autodetect]
>    --disable-everything     disable all components listed below
>    --disable-encoder=NAME   disable encoder NAME
>    --enable-encoder=NAME    enable encoder NAME
> @@ -1432,6 +1432,7 @@ AVCODEC_COMPONENTS="
>  
>  AVDEVICE_COMPONENTS="
>      indevs
> +    v4l2_m2m
>      outdevs
>  "
>  AVFILTER_COMPONENTS="
> @@ -2269,11 +2270,12 @@ map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM
>  
>  loongson2_deps="mips"
>  loongson3_deps="mips"
> -v4l2_deps_any="linux_videodev2_h sys_videoio_h"
> +v4l2_m2m_select="v4l2"
>  mipsfpu_deps="mips"
>  mipsdsp_deps="mips"
>  mipsdspr2_deps="mips"
>  mips32r2_deps="mips"
> +vc1_v4l2m2m_decoder_deps="v4l2_m2m"
>  mips32r5_deps="mips"
>  mips32r6_deps="mips"
>  mips64r2_deps="mips"
> @@ -2284,6 +2286,9 @@ mmi_deps="mips"
>  altivec_deps="ppc"
>  dcbzl_deps="ppc"
>  ldbrx_deps="ppc"
> +vp8_v4l2m2m_decoder_deps="v4l2_m2m"
> +vp8_v4l2m2m_encoder_deps="v4l2_m2m"
> +vp9_v4l2m2m_decoder_deps="v4l2_m2m"
>  ppc4xx_deps="ppc"
>  vsx_deps="altivec"
>  power8_deps="vsx"
> @@ -2437,15 +2442,22 @@ h261_decoder_select="mpegvideo"
>  h261_encoder_select="aandcttables mpegvideoenc"
>  h263_decoder_select="h263_parser h263dsp mpegvideo qpeldsp"
>  h263_encoder_select="aandcttables h263dsp mpegvideoenc"
> +h263_v4l2m2m_decoder_deps="v4l2_m2m"
> +h263_v4l2m2m_encoder_deps="v4l2_m2m"
>  h263i_decoder_select="h263_decoder"
>  h263p_decoder_select="h263_decoder"
>  h263p_encoder_select="h263_encoder"
>  h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel videodsp"
>  h264_decoder_suggest="error_resilience"
> +h264_v4l2m2m_decoder_deps="v4l2_m2m"
> +h264_v4l2m2m_encoder_deps="v4l2_m2m"
>  hap_decoder_select="snappy texturedsp"
>  hap_encoder_deps="libsnappy"
>  hap_encoder_select="texturedspenc"
>  hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp"
> +hevc_encoder_select="hevc_v4l2m2m"
> +hevc_v4l2m2m_decoder_deps="v4l2_m2m"
> +hevc_v4l2m2m_encoder_deps="v4l2_m2m"
>  huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp"
>  huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp"
>  iac_decoder_select="imc_decoder"
> @@ -2482,6 +2494,7 @@ mpc7_decoder_select="bswapdsp mpegaudiodsp"
>  mpc8_decoder_select="mpegaudiodsp"
>  mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h"
>  mpeg_xvmc_decoder_select="mpeg2video_decoder"
> +mpeg1_v4l2m2m_decoder_deps="v4l2_m2m"
>  mpegvideo_decoder_select="mpegvideo"
>  mpeg1video_decoder_select="mpegvideo"
>  mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp"
> @@ -2489,6 +2502,8 @@ mpeg2video_decoder_select="mpegvideo"
>  mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp"
>  mpeg4_decoder_select="h263_decoder mpeg4video_parser"
>  mpeg4_encoder_select="h263_encoder"
> +mpeg4_v4l2m2m_decoder_deps="v4l2_m2m"
> +mpeg4_v4l2m2m_encoder_deps="v4l2_m2m"
>  msa1_decoder_select="mss34dsp"
>  mscc_decoder_select="zlib"
>  msmpeg4v1_decoder_select="h263_decoder"
> @@ -3042,7 +3057,6 @@ qtkit_indev_select="qtkit"
>  sdl2_outdev_deps="sdl2"
>  sndio_indev_deps="sndio"
>  sndio_outdev_deps="sndio"
> -v4l_indev_deps="linux_videodev_h"
>  v4l2_indev_select="v4l2"
>  v4l2_outdev_select="v4l2"
>  vfwcap_indev_deps="vfw32 vfwcap_defines"
> @@ -3592,7 +3606,7 @@ done
>  enable_weak audiotoolbox
>  
>  # Enable hwaccels by default.
> -enable_weak d3d11va dxva2 vaapi vda vdpau videotoolbox_hwaccel xvmc
> +enable_weak d3d11va dxva2 vaapi v4l2_m2m vda vdpau videotoolbox_hwaccel xvmc
>  enable_weak xlib
>  
>  enable_weak cuda cuvid nvenc vda_framework videotoolbox videotoolbox_encoder
> @@ -6058,12 +6072,10 @@ pod2man --help     > /dev/null 2>&1 && enable pod2man   || disable pod2man
>  rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
>  
>  check_header linux/fb.h
> -check_header linux/videodev.h
> -check_header linux/videodev2.h
> -check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
>  
>  check_header sys/videoio.h
>  check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
> +add_cflags -I$source_path/compat/v4l2
>  
>  check_lib user32 "windows.h winuser.h" GetShellWindow -luser32
>  check_lib vfw32 "windows.h vfw.h" capCreateCaptureWindow -lvfw32
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 364aec9..f45050e 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -101,7 +101,8 @@ OBJS-$(CONFIG_LZF)                     += lzf.o
>  OBJS-$(CONFIG_MDCT)                    += mdct_fixed.o mdct_float.o mdct_fixed_32.o
>  OBJS-$(CONFIG_ME_CMP)                  += me_cmp.o
>  OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec_common.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o
> -OBJS-$(CONFIG_V4L2)                    += v4l2-common.o
> +OBJS-$(CONFIG_V4L2)                    += v4l2_fmt.o v4l2_buffers.o
> +OBJS-$(CONFIG_V4L2_M2M)                += v4l2_m2m.o
>  OBJS-$(CONFIG_MPEG_ER)                 += mpeg_er.o
>  OBJS-$(CONFIG_MPEGAUDIO)               += mpegaudio.o
>  OBJS-$(CONFIG_MPEGAUDIODSP)            += mpegaudiodsp.o                \
> @@ -320,6 +321,8 @@ OBJS-$(CONFIG_H261_ENCODER)            += h261enc.o h261data.o h261.o
>  OBJS-$(CONFIG_H263_DECODER)            += h263dec.o h263.o ituh263dec.o        \
>                                            mpeg4video.o mpeg4videodec.o flvdec.o\
>                                            intelh263dec.o h263data.o
> +OBJS-$(CONFIG_H263_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_H263_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_H263_ENCODER)            += mpeg4videoenc.o mpeg4video.o  \
>                                            h263.o ituh263enc.o flvenc.o h263data.o
>  OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
> @@ -327,6 +330,8 @@ OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
>                                            h264_mb.o h264_picture.o \
>                                            h264_refs.o h264_sei.o \
>                                            h264_slice.o h264data.o
> +OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_H264_CUVID_DECODER)      += cuvid.o
>  OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
>  OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
> @@ -346,6 +351,8 @@ OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
>                                            hevcdsp.o hevc_filter.o hevc_data.o
>  OBJS-$(CONFIG_HEVC_CUVID_DECODER)      += cuvid.o
>  OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o
> +OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_HEVC_NVENC_ENCODER)      += nvenc_hevc.o
>  OBJS-$(CONFIG_NVENC_HEVC_ENCODER)      += nvenc_hevc.o
>  OBJS-$(CONFIG_HEVC_QSV_DECODER)        += qsvdec_h2645.o
> @@ -419,11 +426,13 @@ OBJS-$(CONFIG_MP3ON4FLOAT_DECODER)     += mpegaudiodec_float.o mpeg4audio.o
>  OBJS-$(CONFIG_MPC7_DECODER)            += mpc7.o mpc.o
>  OBJS-$(CONFIG_MPC8_DECODER)            += mpc8.o mpc.o
>  OBJS-$(CONFIG_MPEGVIDEO_DECODER)       += mpeg12dec.o mpeg12.o mpeg12data.o
> +OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_MPEG1VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
>  OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
>  OBJS-$(CONFIG_MPEG2_MMAL_DECODER)      += mmaldec.o
>  OBJS-$(CONFIG_MPEG2_QSV_DECODER)       += qsvdec_other.o
>  OBJS-$(CONFIG_MPEG2_QSV_ENCODER)       += qsvenc_mpeg2.o
> +OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
>  OBJS-$(CONFIG_MPEG2VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
>  OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o
> @@ -431,6 +440,8 @@ OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER)     += vaapi_encode_mpeg2.o
>  OBJS-$(CONFIG_MPEG4_DECODER)           += xvididct.o
>  OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
>  OBJS-$(CONFIG_MPEG4_OMX_ENCODER)       += omx.o
> +OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER)   += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_MPL2_DECODER)            += mpl2dec.o ass.o
>  OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o
>  OBJS-$(CONFIG_MSCC_DECODER)            += mscc.o
> @@ -503,6 +514,7 @@ OBJS-$(CONFIG_RALF_DECODER)            += ralf.o
>  OBJS-$(CONFIG_RAWVIDEO_DECODER)        += rawdec.o
>  OBJS-$(CONFIG_RAWVIDEO_ENCODER)        += rawenc.o
>  OBJS-$(CONFIG_REALTEXT_DECODER)        += realtextdec.o ass.o
> +OBJS-$(CONFIG_VC1_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
>  OBJS-$(CONFIG_RL2_DECODER)             += rl2.o
>  OBJS-$(CONFIG_ROQ_DECODER)             += roqvideodec.o roqvideo.o
>  OBJS-$(CONFIG_ROQ_ENCODER)             += roqvideoenc.o roqvideo.o elbg.o
> @@ -518,6 +530,8 @@ OBJS-$(CONFIG_RV30_DECODER)            += rv30.o rv34.o rv30dsp.o
>  OBJS-$(CONFIG_RV40_DECODER)            += rv40.o rv34.o rv40dsp.o
>  OBJS-$(CONFIG_SAMI_DECODER)            += samidec.o ass.o htmlsubtitles.o
>  OBJS-$(CONFIG_S302M_DECODER)           += s302m.o
> +OBJS-$(CONFIG_VP8_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_S302M_ENCODER)           += s302menc.o
>  OBJS-$(CONFIG_SANM_DECODER)            += sanm.o
>  OBJS-$(CONFIG_SCPR_DECODER)            += scpr.o
> @@ -628,6 +642,8 @@ OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r
>                                            vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o
>  OBJS-$(CONFIG_VP9_CUVID_DECODER)       += cuvid.o
>  OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER)  += mediacodecdec.o
> +OBJS-$(CONFIG_VP9_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
> +OBJS-$(CONFIG_VP9_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
>  OBJS-$(CONFIG_VP9_VAAPI_ENCODER)       += vaapi_encode_vp9.o
>  OBJS-$(CONFIG_VPLAYER_DECODER)         += textdec.o ass.o
>  OBJS-$(CONFIG_VQA_DECODER)             += vqavideo.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 4712592..d154ac9 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -207,8 +207,10 @@ static void register_all(void)
>      REGISTER_ENCDEC (H263,              h263);
>      REGISTER_DECODER(H263I,             h263i);
>      REGISTER_ENCDEC (H263P,             h263p);
> +    REGISTER_ENCDEC (H263_V4L2M2M,      h263_v4l2m2m);
>      REGISTER_DECODER(H264,              h264);
>      REGISTER_DECODER(H264_CRYSTALHD,    h264_crystalhd);
> +    REGISTER_ENCDEC (H264_V4L2M2M,      h264_v4l2m2m);
>      REGISTER_DECODER(H264_MEDIACODEC,   h264_mediacodec);
>      REGISTER_DECODER(H264_MMAL,         h264_mmal);
>      REGISTER_DECODER(H264_QSV,          h264_qsv);
> @@ -219,6 +221,7 @@ static void register_all(void)
>      REGISTER_ENCDEC (HAP,               hap);
>      REGISTER_DECODER(HEVC,              hevc);
>      REGISTER_DECODER(HEVC_QSV,          hevc_qsv);
> +    REGISTER_ENCDEC(HEVC_V4L2M2M,       hevc_v4l2m2m);
>      REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
>      REGISTER_DECODER(HQ_HQA,            hq_hqa);
>      REGISTER_DECODER(HQX,               hqx);
> @@ -253,6 +256,7 @@ static void register_all(void)
>      REGISTER_ENCDEC (MPEG2VIDEO,        mpeg2video);
>      REGISTER_ENCDEC (MPEG4,             mpeg4);
>      REGISTER_DECODER(MPEG4_CRYSTALHD,   mpeg4_crystalhd);
> +    REGISTER_ENCDEC (MPEG4_V4L2M2M,     mpeg4_v4l2m2m);
>      REGISTER_DECODER(MPEG4_MMAL,        mpeg4_mmal);
>  #if FF_API_VDPAU
>      REGISTER_DECODER(MPEG4_VDPAU,       mpeg4_vdpau);
> @@ -262,8 +266,10 @@ static void register_all(void)
>      REGISTER_DECODER(MPEG_VDPAU,        mpeg_vdpau);
>      REGISTER_DECODER(MPEG1_VDPAU,       mpeg1_vdpau);
>  #endif
> +    REGISTER_DECODER(MPEG1_V4L2M2M,     mpeg1_v4l2m2m);
>      REGISTER_DECODER(MPEG2_MMAL,        mpeg2_mmal);
>      REGISTER_DECODER(MPEG2_CRYSTALHD,   mpeg2_crystalhd);
> +    REGISTER_DECODER(MPEG2_V4L2M2M,     mpeg2_v4l2m2m);
>      REGISTER_DECODER(MPEG2_QSV,         mpeg2_qsv);
>      REGISTER_DECODER(MPEG2_MEDIACODEC,  mpeg2_mediacodec);
>      REGISTER_DECODER(MSA1,              msa1);
> @@ -361,6 +367,7 @@ static void register_all(void)
>      REGISTER_DECODER(VC1IMAGE,          vc1image);
>      REGISTER_DECODER(VC1_MMAL,          vc1_mmal);
>      REGISTER_DECODER(VC1_QSV,           vc1_qsv);
> +    REGISTER_DECODER(VC1_V4L2M2M,       vc1_v4l2m2m);
>      REGISTER_ENCODER(VC2,               vc2);
>      REGISTER_DECODER(VCR1,              vcr1);
>      REGISTER_DECODER(VMDVIDEO,          vmdvideo);
> @@ -372,7 +379,9 @@ static void register_all(void)
>      REGISTER_DECODER(VP6F,              vp6f);
>      REGISTER_DECODER(VP7,               vp7);
>      REGISTER_DECODER(VP8,               vp8);
> +    REGISTER_ENCDEC (VP8_V4L2M2M,       vp8_v4l2m2m);
>      REGISTER_DECODER(VP9,               vp9);
> +    REGISTER_DECODER(VP9_V4L2M2M,       vp9_v4l2m2m);
>      REGISTER_DECODER(VQA,               vqa);
>      REGISTER_DECODER(BITPACKED,         bitpacked);
>      REGISTER_DECODER(WEBP,              webp);

MPEG-2 is never mentioned at all in this configure change, so it will never even be compiled.  It might be best if you only add the decoders you can actually verify.


> diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
> new file mode 100644
> index 0000000..2cc59c5
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m_dec.c
> @@ -0,0 +1,229 @@
> +/*
> + * V4L2 mem2mem decoders
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/ioctl.h>
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/opt.h"
> +#include "v4l2_m2m_avcodec.h"
> +#include "v4l2_fmt.h"
> +#include "v4l2_buffers.h"
> +#include "v4l2_m2m.h"
> +#include "decode.h"
> +#include "avcodec.h"
> +
> +static int try_start(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    struct v4l2_selection selection;
> +    struct v4l2_control ctrl;
> +    int ret;
> +
> +    if (out_pool->streamon && cap_pool->streamon)
> +        return 0;
> +
> +    /* this will report the size of the frame back (see a4lbuf_to_avframe) */
> +    cap_pool->height = avctx->coded_height;
> +    cap_pool->width = avctx->coded_width;
> +
> +    /* start the output process */
> +    if (!out_pool->streamon) {
> +        ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMON);
> +        if (ret < 0) {
> +            av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON on output pool\n");
> +            return ret;
> +        }
> +    }
> +
> +    /* get the capture format */
> +    cap_pool->format.type = cap_pool->type;
> +    ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_pool->format);
> +    if (ret) {
> +        av_log(avctx, AV_LOG_ERROR, "VIDIOC_G_FMT ioctl\n");
> +        return ret;
> +    }
> +
> +    /* store what the decoder gives */
> +    avctx->pix_fmt = avpriv_v4l_fmt_v4l2ff(cap_pool->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
> +    cap_pool->av_pix_fmt = avctx->pix_fmt;
> +
> +    /* set the crop parameters */
> +    selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +    selection.r.height = avctx->coded_height;
> +    selection.r.width = avctx->coded_width;
> +    ret = ioctl(s->fd, VIDIOC_S_SELECTION, &selection);
> +    if (!ret) {
> +        ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_ERROR, "VIDIOC_G_SELECTION ioctl\n");
> +        } else {
> +            av_log(avctx, AV_LOG_DEBUG, "crop output %dx%d\n", selection.r.width, selection.r.height);
> +            /* update the size of the resulting frame */
> +            cap_pool->height = selection.r.height;
> +            cap_pool->width  = selection.r.width;
> +        }
> +    }
> +
> +    /* get the minimum number of buffers required by capture */
> +    memset(&ctrl, 0, sizeof(ctrl));
> +    ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
> +    ret = ioctl(s->fd, VIDIOC_G_CTRL, &ctrl);
> +    if (!ret) {
> +        cap_pool->min_queued_buffers = ctrl.value;
> +    }
> +
> +    /* init the capture pool */
> +    if (!cap_pool->buffers) {
> +        ret = avpriv_init_v4lbufpool(cap_pool);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_DEBUG, "can't request output buffers\n");
> +            return ret;
> +        }
> +    }
> +
> +    /* start the capture process */
> +    ret = avpriv_set_stream_status(cap_pool, VIDIOC_STREAMON);
> +    if (ret) {
> +        av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON, on capture pool\n");
> +        return ret;
> +    }
> +
> +    return 0;
> +}
> +
> +static av_cold int v4lm2m_decode_init(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +
> +    out_pool->default_flags = cap_pool->default_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +    out_pool->cfg.format = cap_pool->cfg.format = avpriv_set_pool_format;
> +    out_pool->height = cap_pool->height = avctx->coded_height;
> +    out_pool->width = cap_pool->width =avctx->coded_width;
> +
> +    out_pool->cfg.init = avpriv_init_v4lbufpool;
> +    out_pool->av_codec_id = avctx->codec_id;
> +    out_pool->av_pix_fmt  = AV_PIX_FMT_NONE;
> +
> +    cap_pool->cfg.init = NULL;
> +    cap_pool->av_codec_id = AV_CODEC_ID_RAWVIDEO;
> +    cap_pool->av_pix_fmt = avctx->pix_fmt;
> +    cap_pool->min_queued_buffers = 6;
> +
> +    return ff_v4lm2m_codec_init(avctx);
> +}
> +
> +static int v4lm2m_receive_frame(AVCodecContext *avctx, AVFrame *frame)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    unsigned int timeout = 1000;
> +    AVPacket avpkt = {0};
> +    int ret;
> +
> +    ret = ff_decode_get_packet(avctx, &avpkt);
> +    if (ret < 0 && ret != AVERROR_EOF)
> +        return ret;
> +
> +    ret = avpriv_v4l_enqueue(out_pool, NULL, &avpkt);
> +    if (ret < 0)
> +        return ret;
> +
> +    ret = try_start(avctx);
> +    if (ret)
> +        return 0;
> +
> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
> +}

What happens to the decoder if some parameters like resolution change mid-stream?  (Try the stream h264/reinit-large_420_8-to-small_420_8.h264 in the fate samples.)

Also, are the frames returned here actually still used by the decoder internally as reference frames, or is the reference frame copied somewhere else?  (Seems slightly unlikely that they would be copied given the additional memory requirements, but I know discrete desktop GPUs (which admittedly have 9001x the memory bandwidth and power budget) do do this to hide the possible issues.)  I think, though I'm not entirely sure because I haven't run it, that the returned buffers will only have the user reference, so will appear to be writable to following filters - if that ends up writing on reference frames then the decoder will break.

> +
> +#define OFFSET(x) offsetof(V4Lm2mContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
> +
> +        static const AVOption options[] = {
> +        V4L_M2M_DEFAULT_OPTS,{ "num_capture_pool_extra_buffers",
> +        "Number of extra buffers in the capture pool",
> +        OFFSET(capture_pool.num_buffers), AV_OPT_TYPE_INT,{.i64 = 6}, 4, INT_MAX, FLAGS},
> +        { NULL},
> +        };
> +
> +#define M2MDEC(NAME, LONGNAME, CODEC, bsf_name) \
> +static const AVClass v4l2_m2m_ ## NAME ## _dec_class = {\
> +    .class_name = #NAME "_v4l2_m2m_decoder",\
> +    .item_name  = av_default_item_name,\
> +    .option     = options,\
> +    .version    = LIBAVUTIL_VERSION_INT,\
> +};\
> +\
> +AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \
> +    .name           = #NAME "_v4l2m2m" ,\
> +    .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " decoder wrapper"),\
> +    .type           = AVMEDIA_TYPE_VIDEO,\
> +    .id             = CODEC ,\
> +    .priv_data_size = sizeof(V4Lm2mContext),\
> +    .priv_class     = &v4l2_m2m_ ## NAME ## _dec_class,\
> +    .init           = v4lm2m_decode_init,\
> +    .receive_frame  = v4lm2m_receive_frame,\
> +    .close          = ff_v4lm2m_codec_end,\
> +    .capabilities   = CODEC_CAP_DELAY,\
> +    .bsfs           = bsf_name, \
> +};
> +
> +#if CONFIG_H263_V4L2M2M_DECODER
> +        M2MDEC(h263, "H.263", AV_CODEC_ID_H263, NULL);
> +#endif
> +
> +#if CONFIG_H264_V4L2M2M_DECODER
> +        M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb");
> +#endif
> +
> +#if CONFIG_MPEG1_V4L2M2M_DECODER
> +        M2MDEC(mpeg1, "MPEG1", AV_CODEC_ID_MPEG1VIDEO, NULL);
> +#endif
> +
> +#if CONFIG_MPEG2_V4L2M2M_DECODER
> +        M2MDEC(mpeg2, "MPEG2", AV_CODEC_ID_MPEG2VIDEO, NULL);
> +#endif
> +
> +#if CONFIG_MPEG4_V4L2M2M_DECODER
> +        M2MDEC(mpeg4, "MPEG4", AV_CODEC_ID_MPEG4, NULL);
> +#endif
> +
> +#if CONFIG_VC1_V4L2M2M_DECODER
> +        M2MDEC(vc1 , "VC1", AV_CODEC_ID_VC1, NULL);
> +#endif
> +
> +#if CONFIG_VP8_V4L2M2M_DECODER
> +        M2MDEC(vp8, "VP8", AV_CODEC_ID_VP8, NULL);
> +#endif
> +
> +#if CONFIG_HEVC_V4L2M2M_DECODER
> +        M2MDEC(hevc , "HEVC", AV_CODEC_ID_HEVC, "hevc_mp4toannexb");
> +#endif
> +
> +#if CONFIG_VP9_V4L2M2M_DECODER
> +        M2MDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL);
> +#endif
> diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
> new file mode 100644
> index 0000000..bc32e33
> --- /dev/null
> +++ b/libavcodec/v4l2_m2m_enc.c
> @@ -0,0 +1,270 @@
> +/*
> + * V4L2 mem2mem encoders
> + *
> + * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
> + * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/ioctl.h>
> +
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/opt.h"
> +#include "v4l2_m2m_avcodec.h"
> +#include "v4l2_buffers.h"
> +#include "v4l2_fmt.h"
> +#include "v4l2_m2m.h"
> +#include "avcodec.h"
> +
> +#define STR(s) AV_TOSTRING(s)
> +#define MPEG_CID(x) V4L2_CID_MPEG_VIDEO_##x
> +#define MPEG_VIDEO(x) V4L2_MPEG_VIDEO_##x
> +
> +#define SET_V4L_EXT_CTRL(TYPE, ID, VALUE, NAME)                     \
> +{                                                                   \
> +    struct v4l2_ext_control ctrl = { 0 };                           \
> +    struct v4l2_ext_controls ctrls = { 0 };                         \
> +    ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;                        \
> +    ctrls.controls = &ctrl;                                         \
> +    ctrl.TYPE = VALUE ;                                             \
> +    ctrl.id = ID ;                                                  \
> +    ctrls.count = 1;                                                \
> +                                                                    \
> +    if ((ret = ioctl(s->fd, VIDIOC_S_EXT_CTRLS, &ctrls)) < 0)       \
> +        av_log(avctx, AV_LOG_WARNING, "Failed to set " NAME "%s\n", STR(ID));  \
> +}
> +
> +static inline int v4l_h264_profile_from_ff(int p)
> +{
> +    switch(p) {
> +    case FF_PROFILE_H264_CONSTRAINED_BASELINE:
> +        return MPEG_VIDEO(H264_PROFILE_CONSTRAINED_BASELINE);
> +    case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_444_PREDICTIVE);
> +    case FF_PROFILE_H264_HIGH_422_INTRA:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_422_INTRA);
> +    case FF_PROFILE_H264_HIGH_444_INTRA:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_444_INTRA);
> +    case FF_PROFILE_H264_HIGH_10_INTRA:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_10_INTRA);
> +    case FF_PROFILE_H264_HIGH_422:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_422);
> +    case FF_PROFILE_H264_BASELINE:
> +        return MPEG_VIDEO(H264_PROFILE_BASELINE);
> +    case FF_PROFILE_H264_EXTENDED:
> +        return MPEG_VIDEO(H264_PROFILE_EXTENDED);
> +    case FF_PROFILE_H264_HIGH_10:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH_10);
> +    case FF_PROFILE_H264_MAIN:
> +        return MPEG_VIDEO(H264_PROFILE_MAIN);
> +    case FF_PROFILE_H264_HIGH:
> +        return MPEG_VIDEO(H264_PROFILE_HIGH);
> +    }
> +
> +    return -1;
> +}
> +
> +static inline int v4l_mpeg4_profile_from_ff(int p)
> +{
> +    switch(p) {
> +    case FF_PROFILE_MPEG4_ADVANCED_CODING:
> +        return MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY);
> +    case FF_PROFILE_MPEG4_ADVANCED_SIMPLE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_SIMPLE);
> +    case FF_PROFILE_MPEG4_SIMPLE_SCALABLE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_SIMPLE_SCALABLE);
> +    case FF_PROFILE_MPEG4_SIMPLE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_SIMPLE);
> +    case FF_PROFILE_MPEG4_CORE:
> +        return MPEG_VIDEO(MPEG4_PROFILE_CORE);
> +    }
> +
> +    return -1;
> +}
> +
> +static av_cold int v4lm2m_encode_init(AVCodecContext *avctx)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    int qmin, qmax, ret, val;
> +
> +    out_pool->default_flags = cap_pool->default_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +    out_pool->cfg.format = cap_pool->cfg.format = avpriv_set_pool_format;
> +    out_pool->cfg.init = cap_pool->cfg.init = avpriv_init_v4lbufpool;
> +    out_pool->height = cap_pool->height = avctx->height;
> +    out_pool->width = cap_pool->width = avctx->width;
> +
> +    /* out pool */
> +    out_pool->av_codec_id = AV_CODEC_ID_RAWVIDEO;
> +    out_pool->av_pix_fmt = avctx->pix_fmt;
> +
> +    /* cap pool */
> +    cap_pool->av_codec_id = avctx->codec_id;
> +    cap_pool->av_pix_fmt = AV_PIX_FMT_NONE;
> +    cap_pool->min_queued_buffers = 1;
> +
> +    if (ret = ff_v4lm2m_codec_init(avctx))
> +        return ret;
> +
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(HEADER_MODE), MPEG_VIDEO(HEADER_MODE_JOINED_WITH_1ST_FRAME), "header mode");
> +
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(B_FRAMES), avctx->max_b_frames,  "number of B-frames");
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(GOP_SIZE), avctx->gop_size,"gop size");
> +    SET_V4L_EXT_CTRL(value, MPEG_CID(BITRATE) , avctx->bit_rate, "bit rate");
> +
> +    switch(avctx->codec_id) {
> +    case AV_CODEC_ID_H264:
> +        val = v4l_h264_profile_from_ff(avctx->profile);
> +        if (val >= 0) {
> +            SET_V4L_EXT_CTRL(value, MPEG_CID(H264_PROFILE), val, "h264 profile");
> +        }
> +        qmin = MPEG_CID(H264_MIN_QP);
> +        qmax = MPEG_CID(H264_MAX_QP);
> +        break;
> +    case AV_CODEC_ID_MPEG4:
> +        val = v4l_mpeg4_profile_from_ff(avctx->profile);
> +        if (val >= 0) {
> +            SET_V4L_EXT_CTRL(value, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile");
> +        }
> +        qmin = MPEG_CID(MPEG4_MIN_QP);
> +        qmax = MPEG_CID(MPEG4_MAX_QP);
> +        if (avctx->flags & CODEC_FLAG_QPEL) {
> +            SET_V4L_EXT_CTRL(value, MPEG_CID(MPEG4_QPEL), 1, "qpel");
> +        }
> +        break;
> +    case AV_CODEC_ID_H263:
> +        qmin = MPEG_CID(H263_MIN_QP);
> +        qmax = MPEG_CID(H263_MAX_QP);
> +        break;
> +    case AV_CODEC_ID_VP8:
> +    case AV_CODEC_ID_VP9:
> +        qmin = MPEG_CID(VPX_MIN_QP);
> +        qmax = MPEG_CID(VPX_MAX_QP);
> +        break;
> +    default:
> +        return 0;
> +    }
> +
> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");

The default values of qmin/qmax in options_table.h are set for the MPEG-4 part 2 encoder, and will do nasty things to others.  (Certainly for VP9 (assuming it maps to qindex) it's a very low value, so it probably won't ever get anywhere near the bitrate target for normal video.  H.26[45] and VP8 also, but to a lesser degree.)

Maybe add per-codec default options?

> +
> +    return 0;
> +}
> +
> +static int v4lm2m_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
> +                              const AVFrame *pict, int *got_packet)
> +{
> +    V4Lm2mContext *s = avctx->priv_data;
> +    V4LBufferPool *const cap_pool = &s->capture_pool;
> +    V4LBufferPool *const out_pool = &s->output_pool;
> +    unsigned int timeout = 1000;
> +    int ret;
> +
> +    /* end of transfer */
> +    if (!pict) {
> +        if (out_pool->streamon) {
> +            ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMOFF);
> +            if (ret) {
> +                av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF failed on output pool\n");
> +                return ret;
> +            }
> +        }
> +        goto dequeue;
> +    }
> +
> +    ret = avpriv_v4l_enqueue(out_pool, pict, NULL);
> +    if (ret < 0)
> +        return ret;
> +
> +    if (!out_pool->streamon) {
> +        ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMON);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on output pool\n");
> +            return ret;
> +        }
> +    }
> +    if (!cap_pool->streamon) {
> +        ret = avpriv_set_stream_status(cap_pool, VIDIOC_STREAMON);
> +        if (ret) {
> +            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on capture pool\n");
> +            return ret;
> +        }
> +    }
> +
> +dequeue:
> +
> +    ret = avpriv_v4l_dequeue(cap_pool, NULL, pkt, timeout);
> +    if (ret == AVERROR(EAGAIN))
> +        return 0;
> +    if (!ret)
> +        *got_packet = 1;
> +
> +    return ret;
> +}
> +
> +#define OFFSET(x) offsetof(V4Lm2mContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> +
> +static const AVOption options[] = {
> +    V4L_M2M_DEFAULT_OPTS, { "num_capture_pool_buffers", "Number of buffers in the capture pool",
> +      OFFSET(capture_pool.num_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS }, { NULL },
> +};
> +
> +#define M2MENC(NAME, LONGNAME, CODEC) \
> +static const AVClass v4l2_m2m_ ## NAME ## _enc_class = {\
> +    .class_name = #NAME "_v4l2_m2m_encoder",\
> +    .item_name  = av_default_item_name,\
> +    .option     = options,\
> +    .version    = LIBAVUTIL_VERSION_INT,\
> +};\
> +\
> +AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
> +    .name           = #NAME "_v4l2m2m" ,\
> +    .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"),\
> +    .type           = AVMEDIA_TYPE_VIDEO,\
> +    .id             = CODEC ,\
> +    .priv_data_size = sizeof(V4Lm2mContext),\
> +    .priv_class     = &v4l2_m2m_ ## NAME ##_enc_class,\
> +    .init           = v4lm2m_encode_init,\
> +    .encode2        = v4lm2m_encode_frame,\
> +    .close          = ff_v4lm2m_codec_end,\
> +    .capabilities   = CODEC_CAP_DELAY,\
> +};
> +
> +#if CONFIG_H263_V4L2M2M_ENCODER
> +M2MENC(h263, "H.263", AV_CODEC_ID_H263);
> +#endif
> +
> +#if CONFIG_H264_V4L2M2M_ENCODER
> +M2MENC(h264, "H.264", AV_CODEC_ID_H264);
> +#endif
> +
> +#if CONFIG_MPEG4_V4L2M2M_ENCODER
> +M2MENC(mpeg4, "MPEG4", AV_CODEC_ID_MPEG4);
> +#endif
> +
> +#if CONFIG_VP8_V4L2M2M_ENCODER
> +M2MENC(vp8, "VP8", AV_CODEC_ID_VP8);
> +#endif
> +
> +#if CONFIG_HEVC_V4L2M2M_ENCODER
> +M2MENC(hevc, "HEVC", AV_CODEC_ID_HEVC);
> +#endif
> +
Jorge Ramirez-Ortiz Aug. 4, 2017, 1:02 p.m.
On 08/04/2017 01:51 PM, Mark Thompson wrote:
>> +    REGISTER_ENCDEC (VP8_V4L2M2M,       vp8_v4l2m2m);
>>       REGISTER_DECODER(VP9,               vp9);
>> +    REGISTER_DECODER(VP9_V4L2M2M,       vp9_v4l2m2m);
>>       REGISTER_DECODER(VQA,               vqa);
>>       REGISTER_DECODER(BITPACKED,         bitpacked);
>>       REGISTER_DECODER(WEBP,              webp);
> MPEG-2 is never mentioned at all in this configure change, so it will never even be compiled.  It might be best if you only add the decoders you can actually verify.
>
>

thanks. yes fixed in v4
Jorge Ramirez-Ortiz Aug. 4, 2017, 1:06 p.m.
On 08/04/2017 01:51 PM, Mark Thompson wrote:
>> +    if (ret)
>> +        return 0;
>> +
>> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
>> +}
> What happens to the decoder if some parameters like resolution change mid-stream?  (Try the stream h264/reinit-large_420_8-to-small_420_8.h264 in the fate samples.)

yes, it breaks - the player still shows and image but it is corrupted.
I am not sure how to handle this situation to be honest...so need to 
look into this.

>
> Also, are the frames returned here actually still used by the decoder internally as reference frames, or is the reference frame copied somewhere else?

I think once the buffers are dequeued, the v4l2 decoder doesnt keep any 
references to it.
>   (Seems slightly unlikely that they would be copied given the additional memory requirements, but I know discrete desktop GPUs (which admittedly have 9001x the memory bandwidth and power budget) do do this to hide the possible issues.)  I think, though I'm not entirely sure because I haven't run it, that the returned buffers will only have the user reference, so will appear to be writable to following filters - if that ends up writing on reference frames then the decoder will break.

ack
Mark Thompson Aug. 4, 2017, 1:32 p.m.
On 04/08/17 14:06, Jorge Ramirez wrote:
> On 08/04/2017 01:51 PM, Mark Thompson wrote:
>>> +    if (ret)
>>> +        return 0;
>>> +
>>> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
>>> +}
>> What happens to the decoder if some parameters like resolution change mid-stream?  (Try the stream h264/reinit-large_420_8-to-small_420_8.h264 in the fate samples.)
> 
> yes, it breaks - the player still shows and image but it is corrupted.
> I am not sure how to handle this situation to be honest...so need to look into this.

There should be some way to detect it from the decoder, I think?  (I don't actually know how this works in V4L2.)

To compare, if you look at MMAL (perhaps the most similar API in current lavc) there is a special FORMAT_CHANGED return when dequeuing a frame, and the decoder is reconfigured with new buffers when that happens: <http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/mmaldec.c;h=0b1195dc3e6f09beb74e3e47404456114596c499;hb=HEAD#l713>.

>>
>> Also, are the frames returned here actually still used by the decoder internally as reference frames, or is the reference frame copied somewhere else? 
> 
> I think once the buffers are dequeued, the v4l2 decoder doesnt keep any references to it.
>>  (Seems slightly unlikely that they would be copied given the additional memory requirements, but I know discrete desktop GPUs (which admittedly have 9001x the memory bandwidth and power budget) do do this to hide the possible issues.)  I think, though I'm not entirely sure because I haven't run it, that the returned buffers will only have the user reference, so will appear to be writable to following filters - if that ends up writing on reference frames then the decoder will break.
> 
> ack

Ok.  I'm a bit surprised because of the performance implications of writing everything twice, but if we don't have to think about it at all then whatever.

- Mark
Jorge Ramirez-Ortiz Aug. 7, 2017, 6:51 p.m.
On 08/04/2017 01:51 PM, Mark Thompson wrote:
>> +        break;
>> +    case AV_CODEC_ID_H263:
>> +        qmin = MPEG_CID(H263_MIN_QP);
>> +        qmax = MPEG_CID(H263_MAX_QP);
>> +        break;
>> +    case AV_CODEC_ID_VP8:
>> +    case AV_CODEC_ID_VP9:
>> +        qmin = MPEG_CID(VPX_MIN_QP);
>> +        qmax = MPEG_CID(VPX_MAX_QP);
>> +        break;
>> +    default:
>> +        return 0;
>> +    }
>> +
>> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
>> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");
> The default values of qmin/qmax in options_table.h are set for the MPEG-4 part 2 encoder, and will do nasty things to others.  (Certainly for VP9 (assuming it maps to qindex) it's a very low value, so it probably won't ever get anywhere near the bitrate target for normal video.  H.26[45] and VP8 also, but to a lesser degree.)

would you know where can I get this information from (qmin/qmx for the 
other encoders)?
Jorge Ramirez-Ortiz Aug. 7, 2017, 6:57 p.m.
On 08/04/2017 03:32 PM, Mark Thompson wrote:
> On 04/08/17 14:06, Jorge Ramirez wrote:
>> On 08/04/2017 01:51 PM, Mark Thompson wrote:
>>>> +    if (ret)
>>>> +        return 0;
>>>> +
>>>> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
>>>> +}
>>> What happens to the decoder if some parameters like resolution change mid-stream?  (Try the stream h264/reinit-large_420_8-to-small_420_8.h264 in the fate samples.)
>> yes, it breaks - the player still shows and image but it is corrupted.
>> I am not sure how to handle this situation to be honest...so need to look into this.
> There should be some way to detect it from the decoder, I think?  (I don't actually know how this works in V4L2.)
>
> To compare, if you look at MMAL (perhaps the most similar API in current lavc) there is a special FORMAT_CHANGED return when dequeuing a frame, and the decoder is reconfigured with new buffers when that happens:<http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/mmaldec.c;h=0b1195dc3e6f09beb74e3e47404456114596c499;hb=HEAD#l713>.
>

great, thanks for that.
The issue I have is that the V4L2 driver I am using to test - yes this 
needs to be detected by the decoder- has not implemented the feature 
yet. Will keep it in mind before sending the last series of the patchset.

also, I have rewritten the patchset to add clarity and clean some of the 
sedimentation from testing/hacking. is it ok with you if I post v4 now? 
it will simplify the discussion - the driver now much easier to follow.
Jorge Ramirez-Ortiz Aug. 7, 2017, 6:58 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +
>> +static int v4lbuf_to_avframe(AVFrame *frame, V4LBuffer *avbuf)
>> +{
>> +    int i, ret;
>> +
>> +    av_frame_unref(frame);
>> +
>> +    for (i = 0; i < avbuf->num_planes; i++) {
>> +        ret = v4l2bufref(avbuf, i, &frame->buf[i]);> +        if (ret)
>> +            return ret;
>> +
>> +        frame->linesize[i] = avbuf->bytesperline[i];
>> +        frame->data[i] = frame->buf[i]->data;
>> +
>> +        if (avbuf->num_planes == 1) {
>> +            if (avbuf->pool->av_pix_fmt == AV_PIX_FMT_NV12) {
> Special-casing like this rather inspires doubt that other formats are handled correctly.
>
I dont disagree with you but this was the only way I could play the 
decoded videos with ffplay. do you think this could be an ffplay issue?
Jorge Ramirez-Ortiz Aug. 7, 2017, 6:59 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +        return AVERROR(errno);
>> +
>> +    bp->streamon = (cmd == VIDIOC_STREAMON);
>> +
>> +    return 0;
>> +}
>> +
>> +int avpriv_v4l_enqueue(V4LBufferPool* bp, const AVFrame* f, const AVPacket* pkt)
> Just make separate functions.
>
done in v4
thanks
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:15 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +static int probe_and_set(V4Lm2mContext* s, void *log_ctx, int set)
>> +{
>> +    int fail_log_level = ( set ? AV_LOG_ERROR : AV_LOG_DEBUG);
>> +    int ret;
>> +
>> +    s->fd = open(s->devname, O_RDWR, 0);
> O_NONBLOCK, given DQBUF is used as if it is?
>
ack
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:18 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +        return ret;
>> +    }
>> +
>> +    av_log(log_ctx, AV_LOG_INFO, "Using device %s\n", tmpbuf);
>> +    ret = probe_and_set(s, log_ctx, 1);
>> +    s->devname = devname_save;
> This probing structure feels very fragile and possibly harmful (opening random devices and poking them).  It might be better to just force the user to supply the right device path?
>
>> +
I cleaned it up on v4 but I dont think it can be done much differently: 
the user needs to query the capabilities of every /dev/videoX node..

btw the same probing is already done in  libavdevice/v4l2.c
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:20 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +
>> +    /* this will report the size of the frame back (see a4lbuf_to_avframe) */
>> +    cap_pool->height = avctx->coded_height;
>> +    cap_pool->width = avctx->coded_width;
> Does coded_height/width need to be set to anything sensible here?  That won't be true in general.
>
not at this point. this code has been removed.
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:21 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +    if (ret)
>> +        return 0;
>> +
>> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
> I feel like if the stream has a lot of delay then you will end up needing to wait for the timeout to get the required EAGAIN, which at 1s is very large.  (Though I think you won't in common cases because of the min_queued_buffers constraint in dequeue.)
>
>> +}
yes, you are correct. fixed on v4
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:24 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +    default:
>> +        return 0;
>> +    }
>> +
>> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
>> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");
>> +
>> +    return 0;
>> +}
> This doesn't set extradata - you need to extract the codec global headers (such as H.264 SPS and PPS) at init time to be able to write correct files for some codecs (such as H.264) with muxers requiring global headers (such as MP4).  It kindof works without it, but the files created will not conform and will not be usable on some players.
>
ah that might explain some things (when I play back the encoded video 
the quality is pretty lousy)
is there already some code I can use as a reference? I might be out of 
my depth here so any help will be more than welcome
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:25 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +    }
>> +
>> +dequeue:
>> +
>> +    ret = avpriv_v4l_dequeue(cap_pool, NULL, pkt, timeout);
>> +    if (ret == AVERROR(EAGAIN))
>> +        return 0;
>> +    if (!ret)
>> +        *got_packet = 1;
>> +
>> +    return ret;
>> +}
> Does this actually work for a long stream?  You won't necessarily return a packet for every frame, but always need to enqueue a frame to be able to attempt to dequeue a packet.
>
> It might be better to use the send/receive API here as well.
>
how long does it have to be? I have only tried a couple of minutes

ok will check the API
Jorge Ramirez-Ortiz Aug. 7, 2017, 7:28 p.m.
On 08/03/2017 01:53 AM, Mark Thompson wrote:
>> +        AV_OPT_TYPE_INT,\
>> +        {.i64 = V4L2_MEMORY_MMAP},\
>> +        0, INT_MAX, FLAGS },\
>> +    { "output_memory",\
>> +        "Output memory model: See V4L2_MEMORY_* in videodev2.h. This depends on the HW but default should work with most.",\
>> +        OFFSET(capture_pool.memory),\
>> +        AV_OPT_TYPE_INT,\
>> +        {.i64 = V4L2_MEMORY_MMAP},\
>> +        0, INT_MAX, FLAGS },\
>> +    { "num_output_pool_buffers",\
>> +        "Number of buffers in the output pool",\
>> +        OFFSET(output_pool.num_buffers),\
>> +        AV_OPT_TYPE_INT,\
>> +        { .i64 = 16 },\
>> +        4, INT_MAX, FLAGS }
> Can we attempt to set this automatically based on the codec?  16 won't be enough for worst-case H.264/H.265.
>

please could you suggest some defaults so I can prepare the table?
Mark Thompson Aug. 7, 2017, 9:55 p.m.
On 07/08/17 19:51, Jorge Ramirez wrote:
> On 08/04/2017 01:51 PM, Mark Thompson wrote:
>>> +        break;
>>> +    case AV_CODEC_ID_H263:
>>> +        qmin = MPEG_CID(H263_MIN_QP);
>>> +        qmax = MPEG_CID(H263_MAX_QP);
>>> +        break;
>>> +    case AV_CODEC_ID_VP8:
>>> +    case AV_CODEC_ID_VP9:
>>> +        qmin = MPEG_CID(VPX_MIN_QP);
>>> +        qmax = MPEG_CID(VPX_MAX_QP);
>>> +        break;
>>> +    default:
>>> +        return 0;
>>> +    }
>>> +
>>> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
>>> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");
>> The default values of qmin/qmax in options_table.h are set for the MPEG-4 part 2 encoder, and will do nasty things to others.  (Certainly for VP9 (assuming it maps to qindex) it's a very low value, so it probably won't ever get anywhere near the bitrate target for normal video.  H.26[45] and VP8 also, but to a lesser degree.)
> 
> would you know where can I get this information from (qmin/qmx for the other encoders)?

From the relevant language standards.

H.263 / MPEG-4 part 2:  [1, 31]  (<https://www.itu.int/rec/T-REC-H.263>: PQUANT, GQUANT.)
H.264 / MPEG-4 part 10 / AVC:  [48 - 6 * bitdepth, 51]  (<https://www.itu.int/rec/T-REC-H.264>: QpBdOffsety, pic_init_qp_minus26, slice_qp_delta.)
H.265 / MPEG-H part 2 / HEVC:  [48 - 6 * bitdepth, 51]  (<https://www.itu.int/rec/T-REC-H.265>: QpBdOffsety, init_qp_minus26, slice_qp_delta.)
VP8:  [0, 127]  (<https://tools.ietf.org/html/rfc6386>: q_index.)
VP9:  [0, 255]  (<https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf>: base_q_idx.)


- Mark
Mark Thompson Aug. 7, 2017, 10:01 p.m.
On 07/08/17 19:57, Jorge Ramirez wrote:
> On 08/04/2017 03:32 PM, Mark Thompson wrote:
>> On 04/08/17 14:06, Jorge Ramirez wrote:
>>> On 08/04/2017 01:51 PM, Mark Thompson wrote:
>>>>> +    if (ret)
>>>>> +        return 0;
>>>>> +
>>>>> +    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
>>>>> +}
>>>> What happens to the decoder if some parameters like resolution change mid-stream?  (Try the stream h264/reinit-large_420_8-to-small_420_8.h264 in the fate samples.)
>>> yes, it breaks - the player still shows and image but it is corrupted.
>>> I am not sure how to handle this situation to be honest...so need to look into this.
>> There should be some way to detect it from the decoder, I think?  (I don't actually know how this works in V4L2.)
>>
>> To compare, if you look at MMAL (perhaps the most similar API in current lavc) there is a special FORMAT_CHANGED return when dequeuing a frame, and the decoder is reconfigured with new buffers when that happens:<http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/mmaldec.c;h=0b1195dc3e6f09beb74e3e47404456114596c499;hb=HEAD#l713>.
>>
> 
> great, thanks for that.
> The issue I have is that the V4L2 driver I am using to test - yes this needs to be detected by the decoder- has not implemented the feature yet. Will keep it in mind before sending the last series of the patchset.

Are they actually expecting the user to parse the stream externally to detect this case?  That wouldn't be too horrible to implement if many drivers are likely to have this problem - we already do essentially the same thing in the QSV decoder - see the parser use at <http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/qsvdec.c;h=c00817f1d93e533c75c186b3477bc83a78822aa9;hb=HEAD#l459>.

> also, I have rewritten the patchset to add clarity and clean some of the sedimentation from testing/hacking. is it ok with you if I post v4 now? it will simplify the discussion - the driver now much easier to follow.

Sure.  I'll go through it again within a few days.

- Mark
Jorge Ramirez-Ortiz Aug. 7, 2017, 10:03 p.m.
On 08/07/2017 11:55 PM, Mark Thompson wrote:
>> would you know where can I get this information from (qmin/qmx for the other encoders)?
>  From the relevant language standards.
>
> H.263 / MPEG-4 part 2:  [1, 31]  (<https://www.itu.int/rec/T-REC-H.263>: PQUANT, GQUANT.)
> H.264 / MPEG-4 part 10 / AVC:  [48 - 6 * bitdepth, 51]  (<https://www.itu.int/rec/T-REC-H.264>: QpBdOffsety, pic_init_qp_minus26, slice_qp_delta.)
> H.265 / MPEG-H part 2 / HEVC:  [48 - 6 * bitdepth, 51]  (<https://www.itu.int/rec/T-REC-H.265>: QpBdOffsety, init_qp_minus26, slice_qp_delta.)
> VP8:  [0, 127]  (<https://tools.ietf.org/html/rfc6386>: q_index.)
> VP9:  [0, 255]  (<https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf>: base_q_idx.)
ah thanks a lot.

btw, how come that that this information is not already present in some 
ffmpeg table?
Just trying to decide if I should just import the relevant data into the 
v4l2_m2m_enc file or somewhere else?
Jorge Ramirez-Ortiz Aug. 7, 2017, 10:08 p.m.
On 08/08/2017 12:01 AM, Mark Thompson wrote:
>> great, thanks for that.
>> The issue I have is that the V4L2 driver I am using to test - yes this needs to be detected by the decoder- has not implemented the feature yet. Will keep it in mind before sending the last series of the patchset.
> Are they actually expecting the user to parse the stream externally to detect this case?  That wouldn't be too horrible to implement if many drivers are likely to have this problem - we already do essentially the same thing in the QSV decoder - see the parser use at<http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/qsvdec.c;h=c00817f1d93e533c75c186b3477bc83a78822aa9;hb=HEAD#l459>.

the detection if I understood it correctly is handled and flagged by the 
hardware codec (the v4l2 driver) and the user (ie ffmpeg) is then 
notified and need to do some corrections.

But yes, I need to look this in detail (will not be in the next v4 
patchset, probably in v5)

>
>> also, I have rewritten the patchset to add clarity and clean some of the sedimentation from testing/hacking. is it ok with you if I post v4 now? it will simplify the discussion - the driver now much easier to follow.
> Sure.  I'll go through it again within a few days.

thanks a lot for your help on this.

>
> - Mark
Mark Thompson Aug. 7, 2017, 10:16 p.m.
On 07/08/17 20:24, Jorge Ramirez wrote:
> On 08/03/2017 01:53 AM, Mark Thompson wrote:
>>> +    default:
>>> +        return 0;
>>> +    }
>>> +
>>> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
>>> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");
>>> +
>>> +    return 0;
>>> +}
>> This doesn't set extradata - you need to extract the codec global headers (such as H.264 SPS and PPS) at init time to be able to write correct files for some codecs (such as H.264) with muxers requiring global headers (such as MP4).  It kindof works without it, but the files created will not conform and will not be usable on some players.
>>
> ah that might explain some things (when I play back the encoded video the quality is pretty lousy)
> is there already some code I can use as a reference? I might be out of my depth here so any help will be more than welcome

Methods used by other codecs to extract the headers:

Something to call directly to get them:
* x264_encoder_headers in libx264: <http://git.videolan.org/?p=x264.git;a=blob;f=x264.h#l895>.
* nvEncGetSequenceParams in nvenc: <http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/nvenc.c;h=f79b9a502e33c66e62513c56e54e9cec041e9d45;hb=HEAD#l1282>.

They appear on the front of the stream and can be read from there at init time:
* OMX_BUFFERFLAG_CODECCONFIG in OpenMAX IL: <http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/omx.c;h=19b4f33836b68fabe7be921ca959c619dd28e535;hb=HEAD#l685>.

Know the answer magically in advance (probably not applicable here):
* VAAPI makes the user write their own headers, so we can just write those to the extradata directly as well: <http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/vaapi_encode.c;h=2de5f76cabf329c92272627ee13ab3c8689806d3;hb=HEAD#l1471>.
Mark Thompson Aug. 7, 2017, 10:22 p.m.
On 07/08/17 20:28, Jorge Ramirez wrote:
> On 08/03/2017 01:53 AM, Mark Thompson wrote:
>>> +        AV_OPT_TYPE_INT,\
>>> +        {.i64 = V4L2_MEMORY_MMAP},\
>>> +        0, INT_MAX, FLAGS },\
>>> +    { "output_memory",\
>>> +        "Output memory model: See V4L2_MEMORY_* in videodev2.h. This depends on the HW but default should work with most.",\
>>> +        OFFSET(capture_pool.memory),\
>>> +        AV_OPT_TYPE_INT,\
>>> +        {.i64 = V4L2_MEMORY_MMAP},\
>>> +        0, INT_MAX, FLAGS },\
>>> +    { "num_output_pool_buffers",\
>>> +        "Number of buffers in the output pool",\
>>> +        OFFSET(output_pool.num_buffers),\
>>> +        AV_OPT_TYPE_INT,\
>>> +        { .i64 = 16 },\
>>> +        4, INT_MAX, FLAGS }
>> Can we attempt to set this automatically based on the codec?  16 won't be enough for worst-case H.264/H.265.
>>
> 
> please could you suggest some defaults so I can prepare the table?

If, as you've suggested elsewhere, the decoder doesn't actually use these frames for reference and instead has its own copies internally then this won't actually matter.

If it turns out that you do need the buffering here then the numbers of surfaces used by other hardware decoders are probably good - e.g. <http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/vaapi_decode.c;h=cf58aae4c6f1a815e391cc4095afb16edb0bfed8;hb=HEAD#l434>.
Mark Thompson Aug. 7, 2017, 10:46 p.m.
On 07/08/17 23:03, Jorge Ramirez wrote:
> On 08/07/2017 11:55 PM, Mark Thompson wrote:
>>> would you know where can I get this information from (qmin/qmx for the other encoders)?
>>  From the relevant language standards.
>>
>> H.263 / MPEG-4 part 2:  [1, 31]  (<https://www.itu.int/rec/T-REC-H.263>: PQUANT, GQUANT.)
>> H.264 / MPEG-4 part 10 / AVC:  [48 - 6 * bitdepth, 51]  (<https://www.itu.int/rec/T-REC-H.264>: QpBdOffsety, pic_init_qp_minus26, slice_qp_delta.)
>> H.265 / MPEG-H part 2 / HEVC:  [48 - 6 * bitdepth, 51]  (<https://www.itu.int/rec/T-REC-H.265>: QpBdOffsety, init_qp_minus26, slice_qp_delta.)

(Possibly relevant: many implementations normalise these to be nonnegative on the user side rather than using the standard values, making them [0, 3 + bitdepth * 6].  If you have 10-bit video then you should check what range the codecs actually use here.)

>> VP8:  [0, 127]  (<https://tools.ietf.org/html/rfc6386>: q_index.)
>> VP9:  [0, 255]  (<https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf>: base_q_idx.)
> ah thanks a lot.
> 
> btw, how come that that this information is not already present in some ffmpeg table?

Most files only deal with one codec.  It's only when you've delegated almost everything to somewhere else that you run into the problem of all of these together :)

> Just trying to decide if I should just import the relevant data into the v4l2_m2m_enc file or somewhere else?
Put them in the v4l2_m2m_enc file, I think.  How you want do that probably depends on how V4L2 acts without the options: if it acts sensibly when you don't pass them, then make a defaults table with sentinel values and don't pass anything if you see them (so they are only passed to the codec if the user sets them manually).  If they are required, then you'll need to make a defaults table for each codec with the correct values in.
Martin Storsjö Aug. 8, 2017, 8:23 a.m.
Hi Jorge,

On Mon, 7 Aug 2017, Jorge Ramirez wrote:

> On 08/03/2017 01:53 AM, Mark Thompson wrote:
>>> +    default:
>>> +        return 0;
>>> +    }
>>> +
>>> +    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer 
> scale");
>>> +    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer 
> scale");
>>> +
>>> +    return 0;
>>> +}
>> This doesn't set extradata - you need to extract the codec global headers 
> (such as H.264 SPS and PPS) at init time to be able to write correct files 
> for some codecs (such as H.264) with muxers requiring global headers (such as 
> MP4).  It kindof works without it, but the files created will not conform and 
> will not be usable on some players.
>>
> ah that might explain some things (when I play back the encoded video 
> the quality is pretty lousy)
> is there already some code I can use as a reference? I might be out of 
> my depth here so any help will be more than welcome

This is exactly the thing I was trying to tell you about, off list, 
before.

In the OMX driver used on android, this is requested on startup, via an 
ioctl with the following private ioctl value:
V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER

See this code here:
https://android.googlesource.com/platform/hardware/qcom/media/+/63abe022/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp#2991

This is a qcom specific, private ioctl. In the android kernel for 
qualcomm, this is handled correctly here:

https://android.googlesource.com/kernel/msm/+/android-7.1.2_r0.33/drivers/media/platform/msm/vidc/msm_venc.c#2987
https://android.googlesource.com/kernel/msm/+/android-7.1.2_r0.33/drivers/media/platform/msm/vidc/msm_vidc_common.c#3767

In the dragonboard kernel snapshot I had been testing, that I referred to 
you before, there are incomplete stubs of handling of this. In the 
debian-qcom-dragonboard410c-16.04 tag in the linaro kernel tree:

http://git.linaro.org/landing-teams/working/qualcomm/kernel.git/tree/drivers/media/platform/msm/vidc/msm_venc-ctrls.c?h=debian-qcom-dragonboard410c-16.04&id=8205f603ceeb02d08a720676d9075c9e75e47b0f#n2116
This increments seq_hdr_reqs, just like in the android kernel tree (where 
this is working). However in this kernel tree, nothing actually ever reads 
the seq_hdr_reqs, so it's a non-functional stub.

Now in the kernel tree you referred me to, in the 
release/db820c/qcomlt-4.11 branch, I don't see anything similar to 
V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER. I can't help you from there, 
you need to figure that out what alternative codepath there is, intended 
to replace it - if any. If there aren't any, you first need to fix the 
v4l2 driver before userspace apps can get what they need.

There is a clear need for this, as you witness in the android version of 
the kernel. It just seems to have been removed in the vanilla linux 
version of the driver.

// Martin
Jorge Ramirez-Ortiz Aug. 8, 2017, 8:33 a.m.
On 08/08/2017 10:23 AM, Martin Storsjö wrote:
>>>>
>>> This doesn't set extradata - you need to extract the codec global 
>>> headers 
>> (such as H.264 SPS and PPS) at init time to be able to write correct 
>> files for some codecs (such as H.264) with muxers requiring global 
>> headers (such as MP4).  It kindof works without it, but the files 
>> created will not conform and will not be usable on some players.
>>>
>> ah that might explain some things (when I play back the encoded video 
>> the quality is pretty lousy)
>> is there already some code I can use as a reference? I might be out 
>> of my depth here so any help will be more than welcome
>
> This is exactly the thing I was trying to tell you about, off list, 
> before.

Hi Martin,

yes sorry I was just thinking about that. I was going to follow up but 
little details here on this patchset keep on piling up.

btw -just for info- the encoding issues I was seeing were related to the 
time stamps not being properly passed to the encoder...still trying to 
figure out that as well but at least I now get a proper encoded/decoded 
frame (even though just one, that keeps on being played when I reproduce 
the encoded video)

the encoder however does not complain during the process so I assume the 
other frames are also there

[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.63e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.61e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.6e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.58e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.56e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.55e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.53e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.52e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.5e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.48e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.47e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.45e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.44e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.42e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.41e-07x
[rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 
1920trate=4923.1kbits/s speed=3.39e-07x
[out_0_0 @ 0xaaaae5e64be0] EOF on sink link 
out_0_0:default.bitrate=4923.1kbits/s speed=3.36e-07x

No more output streams to write to, finishing.
frame=  232 fps=1.0 q=-0.0 Lsize=      42kB time=00:00:00.00 
bitrate=736989.3kbits/s speed=2.01e-06x
video:41kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB 
muxing overhead: 1.783316%
Input file #0 (/home/linaro/Videos/raw/freeway.yuv):
   Input stream #0:0 (video): 232 packets read (320716800 bytes); 232 
frames decoded;
   Total: 232 packets (320716800 bytes) demuxed
Output file #0 (out/out.h264.mp4):
   Output stream #0:0 (video): 232 frames encoded; 6 packets muxed 
(42449 bytes);
   Total: 6 packets (42449 bytes) muxed
232 frames successfully decoded, 0 decoding errors

>
> In the OMX driver used on android, this is requested on startup, via 
> an ioctl with the following private ioctl value:
> V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER
>
> See this code here:
> https://android.googlesource.com/platform/hardware/qcom/media/+/63abe022/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp#2991 
>
>
> This is a qcom specific, private ioctl. In the android kernel for 
> qualcomm, this is handled correctly here:
>
> https://android.googlesource.com/kernel/msm/+/android-7.1.2_r0.33/drivers/media/platform/msm/vidc/msm_venc.c#2987 
>
> https://android.googlesource.com/kernel/msm/+/android-7.1.2_r0.33/drivers/media/platform/msm/vidc/msm_vidc_common.c#3767 
>
>
> In the dragonboard kernel snapshot I had been testing, that I referred 
> to you before, there are incomplete stubs of handling of this. In the 
> debian-qcom-dragonboard410c-16.04 tag in the linaro kernel tree:
>
> http://git.linaro.org/landing-teams/working/qualcomm/kernel.git/tree/drivers/media/platform/msm/vidc/msm_venc-ctrls.c?h=debian-qcom-dragonboard410c-16.04&id=8205f603ceeb02d08a720676d9075c9e75e47b0f#n2116 
>
> This increments seq_hdr_reqs, just like in the android kernel tree 
> (where this is working). However in this kernel tree, nothing actually 
> ever reads the seq_hdr_reqs, so it's a non-functional stub.

ok. thanks for the info

>
> Now in the kernel tree you referred me to, in the 
> release/db820c/qcomlt-4.11 branch, I don't see anything similar to 
> V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER. I can't help you from 
> there, you need to figure that out what alternative codepath there is, 
> intended to replace it - if any. If there aren't any, you first need 
> to fix the v4l2 driver before userspace apps can get what they need.

many thanks for all the details (extremely helpful)
Just added  Stanimir to this thread so he can look at it once he is back 
from his break.

>
> There is a clear need for this, as you witness in the android version 
> of the kernel. It just seems to have been removed in the vanilla linux 
> version of the driver.

understood.
Mark Thompson Aug. 8, 2017, 9:30 a.m.
On 08/08/17 09:33, Jorge Ramirez wrote:
> On 08/08/2017 10:23 AM, Martin Storsjö wrote:
>>>>>
>>>> This doesn't set extradata - you need to extract the codec global headers 
>>> (such as H.264 SPS and PPS) at init time to be able to write correct files for some codecs (such as H.264) with muxers requiring global headers (such as MP4).  It kindof works without it, but the files created will not conform and will not be usable on some players.
>>>>
>>> ah that might explain some things (when I play back the encoded video the quality is pretty lousy)
>>> is there already some code I can use as a reference? I might be out of my depth here so any help will be more than welcome
>>
>> This is exactly the thing I was trying to tell you about, off list, before.
> 
> Hi Martin,
> 
> yes sorry I was just thinking about that. I was going to follow up but little details here on this patchset keep on piling up.
> 
> btw -just for info- the encoding issues I was seeing were related to the time stamps not being properly passed to the encoder...still trying to figure out that as well but at least I now get a proper encoded/decoded frame (even though just one, that keeps on being played when I reproduce the encoded video)
> 
> the encoder however does not complain during the process so I assume the other frames are also there
> 
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.63e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.61e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.6e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.58e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.56e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.55e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.53e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.52e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.5e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.48e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.47e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.45e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.44e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.42e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.41e-07x
> [rawvideo @ 0xaaaae5e600a0] PACKET SIZE: 1382400, STRIDE: 1920trate=4923.1kbits/s speed=3.39e-07x
> [out_0_0 @ 0xaaaae5e64be0] EOF on sink link out_0_0:default.bitrate=4923.1kbits/s speed=3.36e-07x
> 
> No more output streams to write to, finishing.
> frame=  232 fps=1.0 q=-0.0 Lsize=      42kB time=00:00:00.00 bitrate=736989.3kbits/s speed=2.01e-06x
> video:41kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.783316%
> Input file #0 (/home/linaro/Videos/raw/freeway.yuv):
>   Input stream #0:0 (video): 232 packets read (320716800 bytes); 232 frames decoded;
>   Total: 232 packets (320716800 bytes) demuxed
> Output file #0 (out/out.h264.mp4):
>   Output stream #0:0 (video): 232 frames encoded; 6 packets muxed (42449 bytes);
>   Total: 6 packets (42449 bytes) muxed
> 232 frames successfully decoded, 0 decoding errors
> 
>>
>> In the OMX driver used on android, this is requested on startup, via an ioctl with the following private ioctl value:
>> V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER
>>
>> See this code here:
>> https://android.googlesource.com/platform/hardware/qcom/media/+/63abe022/msm8996/mm-video-v4l2/vidc/venc/src/video_encoder_device_v4l2.cpp#2991
>>
>> This is a qcom specific, private ioctl. In the android kernel for qualcomm, this is handled correctly here:
>>
>> https://android.googlesource.com/kernel/msm/+/android-7.1.2_r0.33/drivers/media/platform/msm/vidc/msm_venc.c#2987
>> https://android.googlesource.com/kernel/msm/+/android-7.1.2_r0.33/drivers/media/platform/msm/vidc/msm_vidc_common.c#3767
>>
>> In the dragonboard kernel snapshot I had been testing, that I referred to you before, there are incomplete stubs of handling of this. In the debian-qcom-dragonboard410c-16.04 tag in the linaro kernel tree:
>>
>> http://git.linaro.org/landing-teams/working/qualcomm/kernel.git/tree/drivers/media/platform/msm/vidc/msm_venc-ctrls.c?h=debian-qcom-dragonboard410c-16.04&id=8205f603ceeb02d08a720676d9075c9e75e47b0f#n2116
>> This increments seq_hdr_reqs, just like in the android kernel tree (where this is working). However in this kernel tree, nothing actually ever reads the seq_hdr_reqs, so it's a non-functional stub.
> 
> ok. thanks for the info
> 
>>
>> Now in the kernel tree you referred me to, in the release/db820c/qcomlt-4.11 branch, I don't see anything similar to V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER. I can't help you from there, you need to figure that out what alternative codepath there is, intended to replace it - if any. If there aren't any, you first need to fix the v4l2 driver before userspace apps can get what they need.
> 
> many thanks for all the details (extremely helpful)
> Just added  Stanimir to this thread so he can look at it once he is back from his break.
> 
>>
>> There is a clear need for this, as you witness in the android version of the kernel. It just seems to have been removed in the vanilla linux version of the driver.
> 
> understood.

Note that while this may be blocking for all ITU/ISO codecs, you can still support VP8/VP9 without it.

- Mark

Patch hide | download patch | download mbox

diff --git a/Changelog b/Changelog
index 187ae79..d31de07 100644
--- a/Changelog
+++ b/Changelog
@@ -29,6 +29,7 @@  version <next>:
 - limiter video filter
 - libvmaf video filter
 - Dolby E decoder and SMPTE 337M demuxer
+- V4L2 mem2mem HW accelerated codecs support
 
 version 3.3:
 - CrystalHD decoder moved to new decode API
@@ -65,7 +66,6 @@  version 3.3:
 - Intel QSV-accelerated VP8 video decoding
 - VAAPI-accelerated deinterlacing
 
-
 version 3.2:
 - libopenmpt demuxer
 - tee protocol
@@ -105,7 +105,6 @@  version 3.2:
 - Changed mapping of rtp MIME type G726 to codec g726le.
 - spec compliant VAAPI/DXVA2 VC-1 decoding of slices in frame-coded images
 
-
 version 3.1:
 - DXVA2-accelerated HEVC Main10 decoding
 - fieldhint filter
diff --git a/compat/v4l2/v4l2-common.h b/compat/v4l2/v4l2-common.h
new file mode 100644
index 0000000..5b3f685
--- /dev/null
+++ b/compat/v4l2/v4l2-common.h
@@ -0,0 +1,107 @@ 
+/*
+ * include/linux/v4l2-common.h
+ *
+ * Common V4L2 and V4L2 subdev definitions.
+ *
+ * Users are advised to #include this file either through videodev2.h
+ * (V4L2) or through v4l2-subdev.h (V4L2 subdev) rather than to refer
+ * to this file directly.
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __V4L2_COMMON__
+#define __V4L2_COMMON__
+
+#include <linux/types.h>
+
+/*
+ *
+ * Selection interface definitions
+ *
+ */
+
+/* Current cropping area */
+#define V4L2_SEL_TGT_CROP		0x0000
+/* Default cropping area */
+#define V4L2_SEL_TGT_CROP_DEFAULT	0x0001
+/* Cropping bounds */
+#define V4L2_SEL_TGT_CROP_BOUNDS	0x0002
+/* Native frame size */
+#define V4L2_SEL_TGT_NATIVE_SIZE	0x0003
+/* Current composing area */
+#define V4L2_SEL_TGT_COMPOSE		0x0100
+/* Default composing area */
+#define V4L2_SEL_TGT_COMPOSE_DEFAULT	0x0101
+/* Composing bounds */
+#define V4L2_SEL_TGT_COMPOSE_BOUNDS	0x0102
+/* Current composing area plus all padding pixels */
+#define V4L2_SEL_TGT_COMPOSE_PADDED	0x0103
+
+/* Backward compatibility target definitions --- to be removed. */
+#define V4L2_SEL_TGT_CROP_ACTIVE	V4L2_SEL_TGT_CROP
+#define V4L2_SEL_TGT_COMPOSE_ACTIVE	V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL	V4L2_SEL_TGT_CROP
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS	V4L2_SEL_TGT_CROP_BOUNDS
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
+
+/* Selection flags */
+#define V4L2_SEL_FLAG_GE		(1 << 0)
+#define V4L2_SEL_FLAG_LE		(1 << 1)
+#define V4L2_SEL_FLAG_KEEP_CONFIG	(1 << 2)
+
+/* Backward compatibility flag definitions --- to be removed. */
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE	V4L2_SEL_FLAG_GE
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE	V4L2_SEL_FLAG_LE
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG V4L2_SEL_FLAG_KEEP_CONFIG
+
+struct v4l2_edid {
+	__u32 pad;
+	__u32 start_block;
+	__u32 blocks;
+	__u32 reserved[5];
+	__u8  *edid;
+};
+
+#endif /* __V4L2_COMMON__ */
diff --git a/compat/v4l2/v4l2-controls.h b/compat/v4l2/v4l2-controls.h
new file mode 100644
index 0000000..31bfc68
--- /dev/null
+++ b/compat/v4l2/v4l2-controls.h
@@ -0,0 +1,987 @@ 
+/*
+ *  Video for Linux Two controls header file
+ *
+ *  Copyright (C) 1999-2012 the contributors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  The contents of this header was split off from videodev2.h. All control
+ *  definitions should be added to this header, which is included by
+ *  videodev2.h.
+ */
+
+#ifndef __LINUX_V4L2_CONTROLS_H
+#define __LINUX_V4L2_CONTROLS_H
+
+/* Control classes */
+#define V4L2_CTRL_CLASS_USER		0x00980000	/* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG		0x00990000	/* MPEG-compression controls */
+#define V4L2_CTRL_CLASS_CAMERA		0x009a0000	/* Camera class controls */
+#define V4L2_CTRL_CLASS_FM_TX		0x009b0000	/* FM Modulator controls */
+#define V4L2_CTRL_CLASS_FLASH		0x009c0000	/* Camera flash controls */
+#define V4L2_CTRL_CLASS_JPEG		0x009d0000	/* JPEG-compression controls */
+#define V4L2_CTRL_CLASS_IMAGE_SOURCE	0x009e0000	/* Image source controls */
+#define V4L2_CTRL_CLASS_IMAGE_PROC	0x009f0000	/* Image processing controls */
+#define V4L2_CTRL_CLASS_DV		0x00a00000	/* Digital Video controls */
+#define V4L2_CTRL_CLASS_FM_RX		0x00a10000	/* FM Receiver controls */
+#define V4L2_CTRL_CLASS_RF_TUNER	0x00a20000	/* RF tuner controls */
+#define V4L2_CTRL_CLASS_DETECT		0x00a30000	/* Detection controls */
+
+/* User-class control IDs */
+
+#define V4L2_CID_BASE			(V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE 		V4L2_CID_BASE
+#define V4L2_CID_USER_CLASS 		(V4L2_CTRL_CLASS_USER | 1)
+#define V4L2_CID_BRIGHTNESS		(V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST		(V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION		(V4L2_CID_BASE+2)
+#define V4L2_CID_HUE			(V4L2_CID_BASE+3)
+#define V4L2_CID_AUDIO_VOLUME		(V4L2_CID_BASE+5)
+#define V4L2_CID_AUDIO_BALANCE		(V4L2_CID_BASE+6)
+#define V4L2_CID_AUDIO_BASS		(V4L2_CID_BASE+7)
+#define V4L2_CID_AUDIO_TREBLE		(V4L2_CID_BASE+8)
+#define V4L2_CID_AUDIO_MUTE		(V4L2_CID_BASE+9)
+#define V4L2_CID_AUDIO_LOUDNESS		(V4L2_CID_BASE+10)
+#define V4L2_CID_BLACK_LEVEL		(V4L2_CID_BASE+11) /* Deprecated */
+#define V4L2_CID_AUTO_WHITE_BALANCE	(V4L2_CID_BASE+12)
+#define V4L2_CID_DO_WHITE_BALANCE	(V4L2_CID_BASE+13)
+#define V4L2_CID_RED_BALANCE		(V4L2_CID_BASE+14)
+#define V4L2_CID_BLUE_BALANCE		(V4L2_CID_BASE+15)
+#define V4L2_CID_GAMMA			(V4L2_CID_BASE+16)
+#define V4L2_CID_WHITENESS		(V4L2_CID_GAMMA) /* Deprecated */
+#define V4L2_CID_EXPOSURE		(V4L2_CID_BASE+17)
+#define V4L2_CID_AUTOGAIN		(V4L2_CID_BASE+18)
+#define V4L2_CID_GAIN			(V4L2_CID_BASE+19)
+#define V4L2_CID_HFLIP			(V4L2_CID_BASE+20)
+#define V4L2_CID_VFLIP			(V4L2_CID_BASE+21)
+
+#define V4L2_CID_POWER_LINE_FREQUENCY	(V4L2_CID_BASE+24)
+enum v4l2_power_line_frequency {
+	V4L2_CID_POWER_LINE_FREQUENCY_DISABLED	= 0,
+	V4L2_CID_POWER_LINE_FREQUENCY_50HZ	= 1,
+	V4L2_CID_POWER_LINE_FREQUENCY_60HZ	= 2,
+	V4L2_CID_POWER_LINE_FREQUENCY_AUTO	= 3,
+};
+#define V4L2_CID_HUE_AUTO			(V4L2_CID_BASE+25)
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE	(V4L2_CID_BASE+26)
+#define V4L2_CID_SHARPNESS			(V4L2_CID_BASE+27)
+#define V4L2_CID_BACKLIGHT_COMPENSATION 	(V4L2_CID_BASE+28)
+#define V4L2_CID_CHROMA_AGC                     (V4L2_CID_BASE+29)
+#define V4L2_CID_COLOR_KILLER                   (V4L2_CID_BASE+30)
+#define V4L2_CID_COLORFX			(V4L2_CID_BASE+31)
+enum v4l2_colorfx {
+	V4L2_COLORFX_NONE			= 0,
+	V4L2_COLORFX_BW				= 1,
+	V4L2_COLORFX_SEPIA			= 2,
+	V4L2_COLORFX_NEGATIVE			= 3,
+	V4L2_COLORFX_EMBOSS			= 4,
+	V4L2_COLORFX_SKETCH			= 5,
+	V4L2_COLORFX_SKY_BLUE			= 6,
+	V4L2_COLORFX_GRASS_GREEN		= 7,
+	V4L2_COLORFX_SKIN_WHITEN		= 8,
+	V4L2_COLORFX_VIVID			= 9,
+	V4L2_COLORFX_AQUA			= 10,
+	V4L2_COLORFX_ART_FREEZE			= 11,
+	V4L2_COLORFX_SILHOUETTE			= 12,
+	V4L2_COLORFX_SOLARIZATION		= 13,
+	V4L2_COLORFX_ANTIQUE			= 14,
+	V4L2_COLORFX_SET_CBCR			= 15,
+};
+#define V4L2_CID_AUTOBRIGHTNESS			(V4L2_CID_BASE+32)
+#define V4L2_CID_BAND_STOP_FILTER		(V4L2_CID_BASE+33)
+
+#define V4L2_CID_ROTATE				(V4L2_CID_BASE+34)
+#define V4L2_CID_BG_COLOR			(V4L2_CID_BASE+35)
+
+#define V4L2_CID_CHROMA_GAIN                    (V4L2_CID_BASE+36)
+
+#define V4L2_CID_ILLUMINATORS_1			(V4L2_CID_BASE+37)
+#define V4L2_CID_ILLUMINATORS_2			(V4L2_CID_BASE+38)
+
+#define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE	(V4L2_CID_BASE+39)
+#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT		(V4L2_CID_BASE+40)
+
+#define V4L2_CID_ALPHA_COMPONENT		(V4L2_CID_BASE+41)
+#define V4L2_CID_COLORFX_CBCR			(V4L2_CID_BASE+42)
+
+/* last CID + 1 */
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+43)
+
+/* USER-class private control IDs */
+
+/* The base for the meye driver controls. See linux/meye.h for the list
+ * of controls. We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_MEYE_BASE			(V4L2_CID_USER_BASE + 0x1000)
+
+/* The base for the bttv driver controls.
+ * We reserve 32 controls for this driver. */
+#define V4L2_CID_USER_BTTV_BASE			(V4L2_CID_USER_BASE + 0x1010)
+
+
+/* The base for the s2255 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_S2255_BASE		(V4L2_CID_USER_BASE + 0x1030)
+
+/*
+ * The base for the si476x driver controls. See include/media/drv-intf/si476x.h
+ * for the list of controls. Total of 16 controls is reserved for this driver
+ */
+#define V4L2_CID_USER_SI476X_BASE		(V4L2_CID_USER_BASE + 0x1040)
+
+/* The base for the TI VPE driver controls. Total of 16 controls is reserved for
+ * this driver */
+#define V4L2_CID_USER_TI_VPE_BASE		(V4L2_CID_USER_BASE + 0x1050)
+
+/* The base for the saa7134 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_SAA7134_BASE		(V4L2_CID_USER_BASE + 0x1060)
+
+/* The base for the adv7180 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_ADV7180_BASE		(V4L2_CID_USER_BASE + 0x1070)
+
+/* The base for the tc358743 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_TC358743_BASE		(V4L2_CID_USER_BASE + 0x1080)
+
+/* The base for the max217x driver controls.
+ * We reserve 32 controls for this driver
+ */
+#define V4L2_CID_USER_MAX217X_BASE		(V4L2_CID_USER_BASE + 0x1090)
+
+/* The base for the imx driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_IMX_BASE			(V4L2_CID_USER_BASE + 0x1090)
+
+/* MPEG-class control IDs */
+/* The MPEG controls are applicable to all codec controls
+ * and the 'MPEG' part of the define is historical */
+
+#define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS 			(V4L2_CTRL_CLASS_MPEG | 1)
+
+/*  MPEG streams, specific to multiplexed streams */
+#define V4L2_CID_MPEG_STREAM_TYPE 		(V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+	V4L2_MPEG_STREAM_TYPE_MPEG2_PS   = 0, /* MPEG-2 program stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_TS   = 1, /* MPEG-2 transport stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG1_SS   = 2, /* MPEG-1 system stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_DVD  = 3, /* MPEG-2 DVD-compatible stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG1_VCD  = 4, /* MPEG-1 VCD-compatible stream */
+	V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT 		(V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO 		(V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO 		(V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR 		(V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO 	(V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO 	(V4L2_CID_MPEG_BASE+6)
+#define V4L2_CID_MPEG_STREAM_VBI_FMT 		(V4L2_CID_MPEG_BASE+7)
+enum v4l2_mpeg_stream_vbi_fmt {
+	V4L2_MPEG_STREAM_VBI_FMT_NONE = 0,  /* No VBI in the MPEG stream */
+	V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1,  /* VBI in private packets, IVTV format */
+};
+
+/*  MPEG audio controls specific to multiplexed streams  */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ 	(V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+	V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING 		(V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+	V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+	V4L2_MPEG_AUDIO_ENCODING_AAC     = 3,
+	V4L2_MPEG_AUDIO_ENCODING_AC3     = 4,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE 		(V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+	V4L2_MPEG_AUDIO_L1_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L1_BITRATE_64K  = 1,
+	V4L2_MPEG_AUDIO_L1_BITRATE_96K  = 2,
+	V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+	V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+	V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+	V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+	V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+	V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+	V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+	V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+	V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+	V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+	V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE 		(V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+	V4L2_MPEG_AUDIO_L2_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L2_BITRATE_48K  = 1,
+	V4L2_MPEG_AUDIO_L2_BITRATE_56K  = 2,
+	V4L2_MPEG_AUDIO_L2_BITRATE_64K  = 3,
+	V4L2_MPEG_AUDIO_L2_BITRATE_80K  = 4,
+	V4L2_MPEG_AUDIO_L2_BITRATE_96K  = 5,
+	V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+	V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+	V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+	V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+	V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+	V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+	V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+	V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE 		(V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+	V4L2_MPEG_AUDIO_L3_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_L3_BITRATE_40K  = 1,
+	V4L2_MPEG_AUDIO_L3_BITRATE_48K  = 2,
+	V4L2_MPEG_AUDIO_L3_BITRATE_56K  = 3,
+	V4L2_MPEG_AUDIO_L3_BITRATE_64K  = 4,
+	V4L2_MPEG_AUDIO_L3_BITRATE_80K  = 5,
+	V4L2_MPEG_AUDIO_L3_BITRATE_96K  = 6,
+	V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+	V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+	V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+	V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+	V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+	V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+	V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE 		(V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+	V4L2_MPEG_AUDIO_MODE_STEREO       = 0,
+	V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+	V4L2_MPEG_AUDIO_MODE_DUAL         = 2,
+	V4L2_MPEG_AUDIO_MODE_MONO         = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION 	(V4L2_CID_MPEG_BASE+106)
+enum v4l2_mpeg_audio_mode_extension {
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4  = 0,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8  = 1,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+	V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS 		(V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+	V4L2_MPEG_AUDIO_EMPHASIS_NONE         = 0,
+	V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+	V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17    = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC 		(V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+	V4L2_MPEG_AUDIO_CRC_NONE  = 0,
+	V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+#define V4L2_CID_MPEG_AUDIO_MUTE 		(V4L2_CID_MPEG_BASE+109)
+#define V4L2_CID_MPEG_AUDIO_AAC_BITRATE		(V4L2_CID_MPEG_BASE+110)
+#define V4L2_CID_MPEG_AUDIO_AC3_BITRATE		(V4L2_CID_MPEG_BASE+111)
+enum v4l2_mpeg_audio_ac3_bitrate {
+	V4L2_MPEG_AUDIO_AC3_BITRATE_32K  = 0,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_40K  = 1,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_48K  = 2,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_56K  = 3,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_64K  = 4,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_80K  = 5,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_96K  = 6,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17,
+	V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18,
+};
+#define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK	(V4L2_CID_MPEG_BASE+112)
+enum v4l2_mpeg_audio_dec_playback {
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO	    = 0,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO	    = 1,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT	    = 2,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT	    = 3,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO	    = 4,
+	V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5,
+};
+#define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113)
+
+/*  MPEG video controls specific to multiplexed streams */
+#define V4L2_CID_MPEG_VIDEO_ENCODING 		(V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_1     = 0,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_2     = 1,
+	V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT 		(V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+	V4L2_MPEG_VIDEO_ASPECT_1x1     = 0,
+	V4L2_MPEG_VIDEO_ASPECT_4x3     = 1,
+	V4L2_MPEG_VIDEO_ASPECT_16x9    = 2,
+	V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES 		(V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE 		(V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE 	(V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN 		(V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE 	(V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+	V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE 		(V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK 	(V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+#define V4L2_CID_MPEG_VIDEO_MUTE 		(V4L2_CID_MPEG_BASE+210)
+#define V4L2_CID_MPEG_VIDEO_MUTE_YUV 		(V4L2_CID_MPEG_BASE+211)
+#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE		(V4L2_CID_MPEG_BASE+212)
+#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER	(V4L2_CID_MPEG_BASE+213)
+#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB		(V4L2_CID_MPEG_BASE+214)
+#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE			(V4L2_CID_MPEG_BASE+215)
+#define V4L2_CID_MPEG_VIDEO_HEADER_MODE				(V4L2_CID_MPEG_BASE+216)
+enum v4l2_mpeg_video_header_mode {
+	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
+
+};
+#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
+#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE		(V4L2_CID_MPEG_BASE+218)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES	(V4L2_CID_MPEG_BASE+219)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB		(V4L2_CID_MPEG_BASE+220)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE		(V4L2_CID_MPEG_BASE+221)
+enum v4l2_mpeg_video_multi_slice_mode {
+	V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE		= 0,
+	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB		= 1,
+	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_DEC_PTS			(V4L2_CID_MPEG_BASE+223)
+#define V4L2_CID_MPEG_VIDEO_DEC_FRAME			(V4L2_CID_MPEG_BASE+224)
+#define V4L2_CID_MPEG_VIDEO_VBV_DELAY			(V4L2_CID_MPEG_BASE+225)
+#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER		(V4L2_CID_MPEG_BASE+226)
+#define V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE		(V4L2_CID_MPEG_BASE+227)
+#define V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE		(V4L2_CID_MPEG_BASE+228)
+#define V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME		(V4L2_CID_MPEG_BASE+229)
+
+#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP		(V4L2_CID_MPEG_BASE+300)
+#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP		(V4L2_CID_MPEG_BASE+301)
+#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP		(V4L2_CID_MPEG_BASE+302)
+#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP			(V4L2_CID_MPEG_BASE+303)
+#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP			(V4L2_CID_MPEG_BASE+304)
+#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP		(V4L2_CID_MPEG_BASE+350)
+#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP		(V4L2_CID_MPEG_BASE+351)
+#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP		(V4L2_CID_MPEG_BASE+352)
+#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP			(V4L2_CID_MPEG_BASE+353)
+#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP			(V4L2_CID_MPEG_BASE+354)
+#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM		(V4L2_CID_MPEG_BASE+355)
+#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE		(V4L2_CID_MPEG_BASE+356)
+#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE		(V4L2_CID_MPEG_BASE+357)
+enum v4l2_mpeg_video_h264_entropy_mode {
+	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC	= 0,
+	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD		(V4L2_CID_MPEG_BASE+358)
+#define V4L2_CID_MPEG_VIDEO_H264_LEVEL			(V4L2_CID_MPEG_BASE+359)
+enum v4l2_mpeg_video_h264_level {
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_0	= 0,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1B	= 1,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_1	= 2,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_2	= 3,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_3	= 4,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_0	= 5,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_1	= 6,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_2	= 7,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_0	= 8,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_1	= 9,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_2	= 10,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_0	= 11,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_1	= 12,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_2	= 13,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_0	= 14,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_1	= 15,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA	(V4L2_CID_MPEG_BASE+360)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA	(V4L2_CID_MPEG_BASE+361)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE	(V4L2_CID_MPEG_BASE+362)
+enum v4l2_mpeg_video_h264_loop_filter_mode {
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED				= 0,
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED				= 1,
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_PROFILE		(V4L2_CID_MPEG_BASE+363)
+enum v4l2_mpeg_video_h264_profile {
+	V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE			= 0,
+	V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE	= 1,
+	V4L2_MPEG_VIDEO_H264_PROFILE_MAIN			= 2,
+	V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED			= 3,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH			= 4,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10			= 5,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422			= 6,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE	= 7,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA		= 8,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA		= 9,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA		= 10,
+	V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA		= 11,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE		= 12,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH		= 13,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA	= 14,
+	V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH		= 15,
+	V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH		= 16,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT	(V4L2_CID_MPEG_BASE+364)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH	(V4L2_CID_MPEG_BASE+365)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE		(V4L2_CID_MPEG_BASE+366)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC		(V4L2_CID_MPEG_BASE+367)
+enum v4l2_mpeg_video_h264_vui_sar_idc {
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED	= 0,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1		= 1,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11		= 2,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11		= 3,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11		= 4,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33		= 5,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11		= 6,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11		= 7,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11		= 8,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33		= 9,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11		= 10,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11		= 11,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33		= 12,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99		= 13,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3		= 14,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2		= 15,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1		= 16,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED	= 17,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING		(V4L2_CID_MPEG_BASE+368)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0		(V4L2_CID_MPEG_BASE+369)
+#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE	(V4L2_CID_MPEG_BASE+370)
+enum v4l2_mpeg_video_h264_sei_fp_arrangement_type {
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD	= 0,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN		= 1,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW		= 2,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE	= 3,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM		= 4,
+	V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL		= 5,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO			(V4L2_CID_MPEG_BASE+371)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE		(V4L2_CID_MPEG_BASE+372)
+enum v4l2_mpeg_video_h264_fmo_map_type {
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES		= 0,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES		= 1,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER	= 2,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT			= 3,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN			= 4,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN			= 5,
+	V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT			= 6,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP	(V4L2_CID_MPEG_BASE+373)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION	(V4L2_CID_MPEG_BASE+374)
+enum v4l2_mpeg_video_h264_fmo_change_dir {
+	V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT	= 0,
+	V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE	(V4L2_CID_MPEG_BASE+375)
+#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH		(V4L2_CID_MPEG_BASE+376)
+#define V4L2_CID_MPEG_VIDEO_H264_ASO			(V4L2_CID_MPEG_BASE+377)
+#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER	(V4L2_CID_MPEG_BASE+378)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING		(V4L2_CID_MPEG_BASE+379)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE	(V4L2_CID_MPEG_BASE+380)
+enum v4l2_mpeg_video_h264_hierarchical_coding_type {
+	V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B	= 0,
+	V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER	(V4L2_CID_MPEG_BASE+381)
+#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP	(V4L2_CID_MPEG_BASE+382)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP	(V4L2_CID_MPEG_BASE+400)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP	(V4L2_CID_MPEG_BASE+401)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP	(V4L2_CID_MPEG_BASE+402)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP	(V4L2_CID_MPEG_BASE+403)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP	(V4L2_CID_MPEG_BASE+404)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL		(V4L2_CID_MPEG_BASE+405)
+enum v4l2_mpeg_video_mpeg4_level {
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0	= 0,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B	= 1,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_1	= 2,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_2	= 3,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_3	= 4,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B	= 5,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_4	= 6,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_5	= 7,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE	(V4L2_CID_MPEG_BASE+406)
+enum v4l2_mpeg_video_mpeg4_profile {
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE				= 0,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE			= 1,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE				= 2,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE			= 3,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY	= 4,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL		(V4L2_CID_MPEG_BASE+407)
+
+/*  Control IDs for VP8 streams
+ *  Although VP8 is not part of MPEG we add these controls to the MPEG class
+ *  as that class is already handling other video compression standards
+ */
+#define V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS		(V4L2_CID_MPEG_BASE+500)
+enum v4l2_vp8_num_partitions {
+	V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION	= 0,
+	V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS	= 1,
+	V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS	= 2,
+	V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS	= 3,
+};
+#define V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4		(V4L2_CID_MPEG_BASE+501)
+#define V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES		(V4L2_CID_MPEG_BASE+502)
+enum v4l2_vp8_num_ref_frames {
+	V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME	= 0,
+	V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME	= 1,
+	V4L2_CID_MPEG_VIDEO_VPX_3_REF_FRAME	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL		(V4L2_CID_MPEG_BASE+503)
+#define V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS	(V4L2_CID_MPEG_BASE+504)
+#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD	(V4L2_CID_MPEG_BASE+505)
+#define V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL	(V4L2_CID_MPEG_BASE+506)
+enum v4l2_vp8_golden_frame_sel {
+	V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV		= 0,
+	V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_VPX_MIN_QP			(V4L2_CID_MPEG_BASE+507)
+#define V4L2_CID_MPEG_VIDEO_VPX_MAX_QP			(V4L2_CID_MPEG_BASE+508)
+#define V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP		(V4L2_CID_MPEG_BASE+509)
+#define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP		(V4L2_CID_MPEG_BASE+510)
+#define V4L2_CID_MPEG_VIDEO_VPX_PROFILE			(V4L2_CID_MPEG_BASE+511)
+
+/*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE 				(V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE 	(V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+	V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+	V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER 		(V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE 	(V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF                  = 0,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR               = 1,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT              = 2,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE      = 3,
+	V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE 	(V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF    = 0,
+	V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE 	(V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+	V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+	V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO   = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER 		(V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE 		(V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF      = 0,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR      = 1,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT     = 2,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+	V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG     = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM 	(V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM	(V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+10)
+#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS 	(V4L2_CID_MPEG_CX2341X_BASE+11)
+
+/*  MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
+#define V4L2_CID_MPEG_MFC51_BASE				(V4L2_CTRL_CLASS_MPEG | 0x1100)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY		(V4L2_CID_MPEG_MFC51_BASE+0)
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE	(V4L2_CID_MPEG_MFC51_BASE+1)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE			(V4L2_CID_MPEG_MFC51_BASE+2)
+enum v4l2_mpeg_mfc51_video_frame_skip_mode {
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED		= 0,
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT	= 1,
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT		= 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE			(V4L2_CID_MPEG_MFC51_BASE+3)
+enum v4l2_mpeg_mfc51_video_force_frame_type {
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED		= 0,
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME		= 1,
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED	= 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING				(V4L2_CID_MPEG_MFC51_BASE+4)
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV				(V4L2_CID_MPEG_MFC51_BASE+5)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT			(V4L2_CID_MPEG_MFC51_BASE+6)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF			(V4L2_CID_MPEG_MFC51_BASE+7)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY		(V4L2_CID_MPEG_MFC51_BASE+50)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK			(V4L2_CID_MPEG_MFC51_BASE+51)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH		(V4L2_CID_MPEG_MFC51_BASE+52)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC		(V4L2_CID_MPEG_MFC51_BASE+53)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P		(V4L2_CID_MPEG_MFC51_BASE+54)
+
+
+/*  Camera class control IDs */
+
+#define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
+#define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
+
+#define V4L2_CID_EXPOSURE_AUTO			(V4L2_CID_CAMERA_CLASS_BASE+1)
+enum  v4l2_exposure_auto_type {
+	V4L2_EXPOSURE_AUTO = 0,
+	V4L2_EXPOSURE_MANUAL = 1,
+	V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
+	V4L2_EXPOSURE_APERTURE_PRIORITY = 3
+};
+#define V4L2_CID_EXPOSURE_ABSOLUTE		(V4L2_CID_CAMERA_CLASS_BASE+2)
+#define V4L2_CID_EXPOSURE_AUTO_PRIORITY		(V4L2_CID_CAMERA_CLASS_BASE+3)
+
+#define V4L2_CID_PAN_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+4)
+#define V4L2_CID_TILT_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+5)
+#define V4L2_CID_PAN_RESET			(V4L2_CID_CAMERA_CLASS_BASE+6)
+#define V4L2_CID_TILT_RESET			(V4L2_CID_CAMERA_CLASS_BASE+7)
+
+#define V4L2_CID_PAN_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+8)
+#define V4L2_CID_TILT_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+9)
+
+#define V4L2_CID_FOCUS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+10)
+#define V4L2_CID_FOCUS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+11)
+#define V4L2_CID_FOCUS_AUTO			(V4L2_CID_CAMERA_CLASS_BASE+12)
+
+#define V4L2_CID_ZOOM_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+13)
+#define V4L2_CID_ZOOM_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+14)
+#define V4L2_CID_ZOOM_CONTINUOUS		(V4L2_CID_CAMERA_CLASS_BASE+15)
+
+#define V4L2_CID_PRIVACY			(V4L2_CID_CAMERA_CLASS_BASE+16)
+
+#define V4L2_CID_IRIS_ABSOLUTE			(V4L2_CID_CAMERA_CLASS_BASE+17)
+#define V4L2_CID_IRIS_RELATIVE			(V4L2_CID_CAMERA_CLASS_BASE+18)
+
+#define V4L2_CID_AUTO_EXPOSURE_BIAS		(V4L2_CID_CAMERA_CLASS_BASE+19)
+
+#define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE	(V4L2_CID_CAMERA_CLASS_BASE+20)
+enum v4l2_auto_n_preset_white_balance {
+	V4L2_WHITE_BALANCE_MANUAL		= 0,
+	V4L2_WHITE_BALANCE_AUTO			= 1,
+	V4L2_WHITE_BALANCE_INCANDESCENT		= 2,
+	V4L2_WHITE_BALANCE_FLUORESCENT		= 3,
+	V4L2_WHITE_BALANCE_FLUORESCENT_H	= 4,
+	V4L2_WHITE_BALANCE_HORIZON		= 5,
+	V4L2_WHITE_BALANCE_DAYLIGHT		= 6,
+	V4L2_WHITE_BALANCE_FLASH		= 7,
+	V4L2_WHITE_BALANCE_CLOUDY		= 8,
+	V4L2_WHITE_BALANCE_SHADE		= 9,
+};
+
+#define V4L2_CID_WIDE_DYNAMIC_RANGE		(V4L2_CID_CAMERA_CLASS_BASE+21)
+#define V4L2_CID_IMAGE_STABILIZATION		(V4L2_CID_CAMERA_CLASS_BASE+22)
+
+#define V4L2_CID_ISO_SENSITIVITY		(V4L2_CID_CAMERA_CLASS_BASE+23)
+#define V4L2_CID_ISO_SENSITIVITY_AUTO		(V4L2_CID_CAMERA_CLASS_BASE+24)
+enum v4l2_iso_sensitivity_auto_type {
+	V4L2_ISO_SENSITIVITY_MANUAL		= 0,
+	V4L2_ISO_SENSITIVITY_AUTO		= 1,
+};
+
+#define V4L2_CID_EXPOSURE_METERING		(V4L2_CID_CAMERA_CLASS_BASE+25)
+enum v4l2_exposure_metering {
+	V4L2_EXPOSURE_METERING_AVERAGE		= 0,
+	V4L2_EXPOSURE_METERING_CENTER_WEIGHTED	= 1,
+	V4L2_EXPOSURE_METERING_SPOT		= 2,
+	V4L2_EXPOSURE_METERING_MATRIX		= 3,
+};
+
+#define V4L2_CID_SCENE_MODE			(V4L2_CID_CAMERA_CLASS_BASE+26)
+enum v4l2_scene_mode {
+	V4L2_SCENE_MODE_NONE			= 0,
+	V4L2_SCENE_MODE_BACKLIGHT		= 1,
+	V4L2_SCENE_MODE_BEACH_SNOW		= 2,
+	V4L2_SCENE_MODE_CANDLE_LIGHT		= 3,
+	V4L2_SCENE_MODE_DAWN_DUSK		= 4,
+	V4L2_SCENE_MODE_FALL_COLORS		= 5,
+	V4L2_SCENE_MODE_FIREWORKS		= 6,
+	V4L2_SCENE_MODE_LANDSCAPE		= 7,
+	V4L2_SCENE_MODE_NIGHT			= 8,
+	V4L2_SCENE_MODE_PARTY_INDOOR		= 9,
+	V4L2_SCENE_MODE_PORTRAIT		= 10,
+	V4L2_SCENE_MODE_SPORTS			= 11,
+	V4L2_SCENE_MODE_SUNSET			= 12,
+	V4L2_SCENE_MODE_TEXT			= 13,
+};
+
+#define V4L2_CID_3A_LOCK			(V4L2_CID_CAMERA_CLASS_BASE+27)
+#define V4L2_LOCK_EXPOSURE			(1 << 0)
+#define V4L2_LOCK_WHITE_BALANCE			(1 << 1)
+#define V4L2_LOCK_FOCUS				(1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_START		(V4L2_CID_CAMERA_CLASS_BASE+28)
+#define V4L2_CID_AUTO_FOCUS_STOP		(V4L2_CID_CAMERA_CLASS_BASE+29)
+#define V4L2_CID_AUTO_FOCUS_STATUS		(V4L2_CID_CAMERA_CLASS_BASE+30)
+#define V4L2_AUTO_FOCUS_STATUS_IDLE		(0 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_BUSY		(1 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_REACHED		(1 << 1)
+#define V4L2_AUTO_FOCUS_STATUS_FAILED		(1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_RANGE		(V4L2_CID_CAMERA_CLASS_BASE+31)
+enum v4l2_auto_focus_range {
+	V4L2_AUTO_FOCUS_RANGE_AUTO		= 0,
+	V4L2_AUTO_FOCUS_RANGE_NORMAL		= 1,
+	V4L2_AUTO_FOCUS_RANGE_MACRO		= 2,
+	V4L2_AUTO_FOCUS_RANGE_INFINITY		= 3,
+};
+
+#define V4L2_CID_PAN_SPEED			(V4L2_CID_CAMERA_CLASS_BASE+32)
+#define V4L2_CID_TILT_SPEED			(V4L2_CID_CAMERA_CLASS_BASE+33)
+
+/* FM Modulator class control IDs */
+
+#define V4L2_CID_FM_TX_CLASS_BASE		(V4L2_CTRL_CLASS_FM_TX | 0x900)
+#define V4L2_CID_FM_TX_CLASS			(V4L2_CTRL_CLASS_FM_TX | 1)
+
+#define V4L2_CID_RDS_TX_DEVIATION		(V4L2_CID_FM_TX_CLASS_BASE + 1)
+#define V4L2_CID_RDS_TX_PI			(V4L2_CID_FM_TX_CLASS_BASE + 2)
+#define V4L2_CID_RDS_TX_PTY			(V4L2_CID_FM_TX_CLASS_BASE + 3)
+#define V4L2_CID_RDS_TX_PS_NAME			(V4L2_CID_FM_TX_CLASS_BASE + 5)
+#define V4L2_CID_RDS_TX_RADIO_TEXT		(V4L2_CID_FM_TX_CLASS_BASE + 6)
+#define V4L2_CID_RDS_TX_MONO_STEREO		(V4L2_CID_FM_TX_CLASS_BASE + 7)
+#define V4L2_CID_RDS_TX_ARTIFICIAL_HEAD		(V4L2_CID_FM_TX_CLASS_BASE + 8)
+#define V4L2_CID_RDS_TX_COMPRESSED		(V4L2_CID_FM_TX_CLASS_BASE + 9)
+#define V4L2_CID_RDS_TX_DYNAMIC_PTY		(V4L2_CID_FM_TX_CLASS_BASE + 10)
+#define V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_TX_CLASS_BASE + 11)
+#define V4L2_CID_RDS_TX_TRAFFIC_PROGRAM		(V4L2_CID_FM_TX_CLASS_BASE + 12)
+#define V4L2_CID_RDS_TX_MUSIC_SPEECH		(V4L2_CID_FM_TX_CLASS_BASE + 13)
+#define V4L2_CID_RDS_TX_ALT_FREQS_ENABLE	(V4L2_CID_FM_TX_CLASS_BASE + 14)
+#define V4L2_CID_RDS_TX_ALT_FREQS		(V4L2_CID_FM_TX_CLASS_BASE + 15)
+
+#define V4L2_CID_AUDIO_LIMITER_ENABLED		(V4L2_CID_FM_TX_CLASS_BASE + 64)
+#define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 65)
+#define V4L2_CID_AUDIO_LIMITER_DEVIATION	(V4L2_CID_FM_TX_CLASS_BASE + 66)
+
+#define V4L2_CID_AUDIO_COMPRESSION_ENABLED	(V4L2_CID_FM_TX_CLASS_BASE + 80)
+#define V4L2_CID_AUDIO_COMPRESSION_GAIN		(V4L2_CID_FM_TX_CLASS_BASE + 81)
+#define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD	(V4L2_CID_FM_TX_CLASS_BASE + 82)
+#define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 83)
+#define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 84)
+
+#define V4L2_CID_PILOT_TONE_ENABLED		(V4L2_CID_FM_TX_CLASS_BASE + 96)
+#define V4L2_CID_PILOT_TONE_DEVIATION		(V4L2_CID_FM_TX_CLASS_BASE + 97)
+#define V4L2_CID_PILOT_TONE_FREQUENCY		(V4L2_CID_FM_TX_CLASS_BASE + 98)
+
+#define V4L2_CID_TUNE_PREEMPHASIS		(V4L2_CID_FM_TX_CLASS_BASE + 112)
+enum v4l2_preemphasis {
+	V4L2_PREEMPHASIS_DISABLED	= 0,
+	V4L2_PREEMPHASIS_50_uS		= 1,
+	V4L2_PREEMPHASIS_75_uS		= 2,
+};
+#define V4L2_CID_TUNE_POWER_LEVEL		(V4L2_CID_FM_TX_CLASS_BASE + 113)
+#define V4L2_CID_TUNE_ANTENNA_CAPACITOR		(V4L2_CID_FM_TX_CLASS_BASE + 114)
+
+
+/* Flash and privacy (indicator) light controls */
+
+#define V4L2_CID_FLASH_CLASS_BASE		(V4L2_CTRL_CLASS_FLASH | 0x900)
+#define V4L2_CID_FLASH_CLASS			(V4L2_CTRL_CLASS_FLASH | 1)
+
+#define V4L2_CID_FLASH_LED_MODE			(V4L2_CID_FLASH_CLASS_BASE + 1)
+enum v4l2_flash_led_mode {
+	V4L2_FLASH_LED_MODE_NONE,
+	V4L2_FLASH_LED_MODE_FLASH,
+	V4L2_FLASH_LED_MODE_TORCH,
+};
+
+#define V4L2_CID_FLASH_STROBE_SOURCE		(V4L2_CID_FLASH_CLASS_BASE + 2)
+enum v4l2_flash_strobe_source {
+	V4L2_FLASH_STROBE_SOURCE_SOFTWARE,
+	V4L2_FLASH_STROBE_SOURCE_EXTERNAL,
+};
+
+#define V4L2_CID_FLASH_STROBE			(V4L2_CID_FLASH_CLASS_BASE + 3)
+#define V4L2_CID_FLASH_STROBE_STOP		(V4L2_CID_FLASH_CLASS_BASE + 4)
+#define V4L2_CID_FLASH_STROBE_STATUS		(V4L2_CID_FLASH_CLASS_BASE + 5)
+
+#define V4L2_CID_FLASH_TIMEOUT			(V4L2_CID_FLASH_CLASS_BASE + 6)
+#define V4L2_CID_FLASH_INTENSITY		(V4L2_CID_FLASH_CLASS_BASE + 7)
+#define V4L2_CID_FLASH_TORCH_INTENSITY		(V4L2_CID_FLASH_CLASS_BASE + 8)
+#define V4L2_CID_FLASH_INDICATOR_INTENSITY	(V4L2_CID_FLASH_CLASS_BASE + 9)
+
+#define V4L2_CID_FLASH_FAULT			(V4L2_CID_FLASH_CLASS_BASE + 10)
+#define V4L2_FLASH_FAULT_OVER_VOLTAGE		(1 << 0)
+#define V4L2_FLASH_FAULT_TIMEOUT		(1 << 1)
+#define V4L2_FLASH_FAULT_OVER_TEMPERATURE	(1 << 2)
+#define V4L2_FLASH_FAULT_SHORT_CIRCUIT		(1 << 3)
+#define V4L2_FLASH_FAULT_OVER_CURRENT		(1 << 4)
+#define V4L2_FLASH_FAULT_INDICATOR		(1 << 5)
+#define V4L2_FLASH_FAULT_UNDER_VOLTAGE		(1 << 6)
+#define V4L2_FLASH_FAULT_INPUT_VOLTAGE		(1 << 7)
+#define V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE	(1 << 8)
+
+#define V4L2_CID_FLASH_CHARGE			(V4L2_CID_FLASH_CLASS_BASE + 11)
+#define V4L2_CID_FLASH_READY			(V4L2_CID_FLASH_CLASS_BASE + 12)
+
+
+/* JPEG-class control IDs */
+
+#define V4L2_CID_JPEG_CLASS_BASE		(V4L2_CTRL_CLASS_JPEG | 0x900)
+#define V4L2_CID_JPEG_CLASS			(V4L2_CTRL_CLASS_JPEG | 1)
+
+#define	V4L2_CID_JPEG_CHROMA_SUBSAMPLING	(V4L2_CID_JPEG_CLASS_BASE + 1)
+enum v4l2_jpeg_chroma_subsampling {
+	V4L2_JPEG_CHROMA_SUBSAMPLING_444	= 0,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_422	= 1,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_420	= 2,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_411	= 3,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_410	= 4,
+	V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY	= 5,
+};
+#define	V4L2_CID_JPEG_RESTART_INTERVAL		(V4L2_CID_JPEG_CLASS_BASE + 2)
+#define	V4L2_CID_JPEG_COMPRESSION_QUALITY	(V4L2_CID_JPEG_CLASS_BASE + 3)
+
+#define	V4L2_CID_JPEG_ACTIVE_MARKER		(V4L2_CID_JPEG_CLASS_BASE + 4)
+#define	V4L2_JPEG_ACTIVE_MARKER_APP0		(1 << 0)
+#define	V4L2_JPEG_ACTIVE_MARKER_APP1		(1 << 1)
+#define	V4L2_JPEG_ACTIVE_MARKER_COM		(1 << 16)
+#define	V4L2_JPEG_ACTIVE_MARKER_DQT		(1 << 17)
+#define	V4L2_JPEG_ACTIVE_MARKER_DHT		(1 << 18)
+
+
+/* Image source controls */
+#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE	(V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900)
+#define V4L2_CID_IMAGE_SOURCE_CLASS		(V4L2_CTRL_CLASS_IMAGE_SOURCE | 1)
+
+#define V4L2_CID_VBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
+#define V4L2_CID_HBLANK				(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
+#define V4L2_CID_ANALOGUE_GAIN			(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+#define V4L2_CID_TEST_PATTERN_RED		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 4)
+#define V4L2_CID_TEST_PATTERN_GREENR		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5)
+#define V4L2_CID_TEST_PATTERN_BLUE		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6)
+#define V4L2_CID_TEST_PATTERN_GREENB		(V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7)
+
+
+/* Image processing controls */
+
+#define V4L2_CID_IMAGE_PROC_CLASS_BASE		(V4L2_CTRL_CLASS_IMAGE_PROC | 0x900)
+#define V4L2_CID_IMAGE_PROC_CLASS		(V4L2_CTRL_CLASS_IMAGE_PROC | 1)
+
+#define V4L2_CID_LINK_FREQ			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 1)
+#define V4L2_CID_PIXEL_RATE			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 2)
+#define V4L2_CID_TEST_PATTERN			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 3)
+#define V4L2_CID_DEINTERLACING_MODE		(V4L2_CID_IMAGE_PROC_CLASS_BASE + 4)
+#define V4L2_CID_DIGITAL_GAIN			(V4L2_CID_IMAGE_PROC_CLASS_BASE + 5)
+
+/*  DV-class control IDs defined by V4L2 */
+#define V4L2_CID_DV_CLASS_BASE			(V4L2_CTRL_CLASS_DV | 0x900)
+#define V4L2_CID_DV_CLASS			(V4L2_CTRL_CLASS_DV | 1)
+
+#define	V4L2_CID_DV_TX_HOTPLUG			(V4L2_CID_DV_CLASS_BASE + 1)
+#define	V4L2_CID_DV_TX_RXSENSE			(V4L2_CID_DV_CLASS_BASE + 2)
+#define	V4L2_CID_DV_TX_EDID_PRESENT		(V4L2_CID_DV_CLASS_BASE + 3)
+#define	V4L2_CID_DV_TX_MODE			(V4L2_CID_DV_CLASS_BASE + 4)
+enum v4l2_dv_tx_mode {
+	V4L2_DV_TX_MODE_DVI_D	= 0,
+	V4L2_DV_TX_MODE_HDMI	= 1,
+};
+#define V4L2_CID_DV_TX_RGB_RANGE		(V4L2_CID_DV_CLASS_BASE + 5)
+enum v4l2_dv_rgb_range {
+	V4L2_DV_RGB_RANGE_AUTO	  = 0,
+	V4L2_DV_RGB_RANGE_LIMITED = 1,
+	V4L2_DV_RGB_RANGE_FULL	  = 2,
+};
+
+#define V4L2_CID_DV_TX_IT_CONTENT_TYPE		(V4L2_CID_DV_CLASS_BASE + 6)
+enum v4l2_dv_it_content_type {
+	V4L2_DV_IT_CONTENT_TYPE_GRAPHICS  = 0,
+	V4L2_DV_IT_CONTENT_TYPE_PHOTO	  = 1,
+	V4L2_DV_IT_CONTENT_TYPE_CINEMA	  = 2,
+	V4L2_DV_IT_CONTENT_TYPE_GAME	  = 3,
+	V4L2_DV_IT_CONTENT_TYPE_NO_ITC	  = 4,
+};
+
+#define	V4L2_CID_DV_RX_POWER_PRESENT		(V4L2_CID_DV_CLASS_BASE + 100)
+#define V4L2_CID_DV_RX_RGB_RANGE		(V4L2_CID_DV_CLASS_BASE + 101)
+#define V4L2_CID_DV_RX_IT_CONTENT_TYPE		(V4L2_CID_DV_CLASS_BASE + 102)
+
+#define V4L2_CID_FM_RX_CLASS_BASE		(V4L2_CTRL_CLASS_FM_RX | 0x900)
+#define V4L2_CID_FM_RX_CLASS			(V4L2_CTRL_CLASS_FM_RX | 1)
+
+#define V4L2_CID_TUNE_DEEMPHASIS		(V4L2_CID_FM_RX_CLASS_BASE + 1)
+enum v4l2_deemphasis {
+	V4L2_DEEMPHASIS_DISABLED	= V4L2_PREEMPHASIS_DISABLED,
+	V4L2_DEEMPHASIS_50_uS		= V4L2_PREEMPHASIS_50_uS,
+	V4L2_DEEMPHASIS_75_uS		= V4L2_PREEMPHASIS_75_uS,
+};
+
+#define V4L2_CID_RDS_RECEPTION			(V4L2_CID_FM_RX_CLASS_BASE + 2)
+#define V4L2_CID_RDS_RX_PTY			(V4L2_CID_FM_RX_CLASS_BASE + 3)
+#define V4L2_CID_RDS_RX_PS_NAME			(V4L2_CID_FM_RX_CLASS_BASE + 4)
+#define V4L2_CID_RDS_RX_RADIO_TEXT		(V4L2_CID_FM_RX_CLASS_BASE + 5)
+#define V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_RX_CLASS_BASE + 6)
+#define V4L2_CID_RDS_RX_TRAFFIC_PROGRAM		(V4L2_CID_FM_RX_CLASS_BASE + 7)
+#define V4L2_CID_RDS_RX_MUSIC_SPEECH		(V4L2_CID_FM_RX_CLASS_BASE + 8)
+
+#define V4L2_CID_RF_TUNER_CLASS_BASE		(V4L2_CTRL_CLASS_RF_TUNER | 0x900)
+#define V4L2_CID_RF_TUNER_CLASS			(V4L2_CTRL_CLASS_RF_TUNER | 1)
+
+#define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 11)
+#define V4L2_CID_RF_TUNER_BANDWIDTH		(V4L2_CID_RF_TUNER_CLASS_BASE + 12)
+#define V4L2_CID_RF_TUNER_RF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 32)
+#define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO		(V4L2_CID_RF_TUNER_CLASS_BASE + 41)
+#define V4L2_CID_RF_TUNER_LNA_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 42)
+#define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 51)
+#define V4L2_CID_RF_TUNER_MIXER_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 52)
+#define V4L2_CID_RF_TUNER_IF_GAIN_AUTO		(V4L2_CID_RF_TUNER_CLASS_BASE + 61)
+#define V4L2_CID_RF_TUNER_IF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 62)
+#define V4L2_CID_RF_TUNER_PLL_LOCK			(V4L2_CID_RF_TUNER_CLASS_BASE + 91)
+
+
+/*  Detection-class control IDs defined by V4L2 */
+#define V4L2_CID_DETECT_CLASS_BASE		(V4L2_CTRL_CLASS_DETECT | 0x900)
+#define V4L2_CID_DETECT_CLASS			(V4L2_CTRL_CLASS_DETECT | 1)
+
+#define V4L2_CID_DETECT_MD_MODE			(V4L2_CID_DETECT_CLASS_BASE + 1)
+enum v4l2_detect_md_mode {
+	V4L2_DETECT_MD_MODE_DISABLED		= 0,
+	V4L2_DETECT_MD_MODE_GLOBAL		= 1,
+	V4L2_DETECT_MD_MODE_THRESHOLD_GRID	= 2,
+	V4L2_DETECT_MD_MODE_REGION_GRID		= 3,
+};
+#define V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD	(V4L2_CID_DETECT_CLASS_BASE + 2)
+#define V4L2_CID_DETECT_MD_THRESHOLD_GRID	(V4L2_CID_DETECT_CLASS_BASE + 3)
+#define V4L2_CID_DETECT_MD_REGION_GRID		(V4L2_CID_DETECT_CLASS_BASE + 4)
+
+#endif
diff --git a/compat/v4l2/videodev2.h b/compat/v4l2/videodev2.h
new file mode 100644
index 0000000..b98f472
--- /dev/null
+++ b/compat/v4l2/videodev2.h
@@ -0,0 +1,2402 @@ 
+/*
+ *  Video for Linux Two header file
+ *
+ *  Copyright (C) 1999-2012 the contributors
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  Alternatively you can redistribute this file under the terms of the
+ *  BSD license as stated below:
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *  3. The names of its contributors may not be used to endorse or promote
+ *     products derived from this software without specific prior written
+ *     permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
+ *
+ *	See https://linuxtv.org for more info
+ *
+ *	Author: Bill Dirks <bill@thedirks.org>
+ *		Justin Schoeman
+ *              Hans Verkuil <hverkuil@xs4all.nl>
+ *		et al.
+ */
+#ifndef _UAPI__LINUX_VIDEODEV2_H
+#define _UAPI__LINUX_VIDEODEV2_H
+
+
+#include <sys/time.h>
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#include "v4l2-common.h"
+#include "v4l2-controls.h"
+#define __user
+
+/*
+ * Common stuff for both V4L1 and V4L2
+ * Moved from videodev.h
+ */
+#define VIDEO_MAX_FRAME               32
+#define VIDEO_MAX_PLANES               8
+
+/*
+ *	M I S C E L L A N E O U S
+ */
+
+/*  Four-character-code (FOURCC) */
+#define v4l2_fourcc(a, b, c, d)\
+	((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24))
+#define v4l2_fourcc_be(a, b, c, d)	(v4l2_fourcc(a, b, c, d) | (1 << 31))
+
+/*
+ *	E N U M S
+ */
+enum v4l2_field {
+	V4L2_FIELD_ANY           = 0, /* driver can choose from none,
+					 top, bottom, interlaced
+					 depending on whatever it thinks
+					 is approximate ... */
+	V4L2_FIELD_NONE          = 1, /* this device has no fields ... */
+	V4L2_FIELD_TOP           = 2, /* top field only */
+	V4L2_FIELD_BOTTOM        = 3, /* bottom field only */
+	V4L2_FIELD_INTERLACED    = 4, /* both fields interlaced */
+	V4L2_FIELD_SEQ_TB        = 5, /* both fields sequential into one
+					 buffer, top-bottom order */
+	V4L2_FIELD_SEQ_BT        = 6, /* same as above + bottom-top order */
+	V4L2_FIELD_ALTERNATE     = 7, /* both fields alternating into
+					 separate buffers */
+	V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field
+					 first and the top field is
+					 transmitted first */
+	V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field
+					 first and the bottom field is
+					 transmitted first */
+};
+#define V4L2_FIELD_HAS_TOP(field)	\
+	((field) == V4L2_FIELD_TOP 	||\
+	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTTOM(field)	\
+	((field) == V4L2_FIELD_BOTTOM 	||\
+	 (field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB	||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_BOTH(field)	\
+	((field) == V4L2_FIELD_INTERLACED ||\
+	 (field) == V4L2_FIELD_INTERLACED_TB ||\
+	 (field) == V4L2_FIELD_INTERLACED_BT ||\
+	 (field) == V4L2_FIELD_SEQ_TB ||\
+	 (field) == V4L2_FIELD_SEQ_BT)
+#define V4L2_FIELD_HAS_T_OR_B(field)	\
+	((field) == V4L2_FIELD_BOTTOM ||\
+	 (field) == V4L2_FIELD_TOP ||\
+	 (field) == V4L2_FIELD_ALTERNATE)
+
+enum v4l2_buf_type {
+	V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2,
+	V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3,
+	V4L2_BUF_TYPE_VBI_CAPTURE          = 4,
+	V4L2_BUF_TYPE_VBI_OUTPUT           = 5,
+	V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   = 6,
+	V4L2_BUF_TYPE_SLICED_VBI_OUTPUT    = 7,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
+	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
+	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
+	V4L2_BUF_TYPE_SDR_CAPTURE          = 11,
+	V4L2_BUF_TYPE_SDR_OUTPUT           = 12,
+	V4L2_BUF_TYPE_META_CAPTURE         = 13,
+	/* Deprecated, do not use */
+	V4L2_BUF_TYPE_PRIVATE              = 0x80,
+};
+
+#define V4L2_TYPE_IS_MULTIPLANAR(type)			\
+	((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE	\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+
+#define V4L2_TYPE_IS_OUTPUT(type)				\
+	((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT			\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE		\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY		\
+	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY	\
+	 || (type) == V4L2_BUF_TYPE_VBI_OUTPUT			\
+	 || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT		\
+	 || (type) == V4L2_BUF_TYPE_SDR_OUTPUT)
+
+enum v4l2_tuner_type {
+	V4L2_TUNER_RADIO	     = 1,
+	V4L2_TUNER_ANALOG_TV	     = 2,
+	V4L2_TUNER_DIGITAL_TV	     = 3,
+	V4L2_TUNER_SDR               = 4,
+	V4L2_TUNER_RF                = 5,
+};
+
+/* Deprecated, do not use */
+#define V4L2_TUNER_ADC  V4L2_TUNER_SDR
+
+enum v4l2_memory {
+	V4L2_MEMORY_MMAP             = 1,
+	V4L2_MEMORY_USERPTR          = 2,
+	V4L2_MEMORY_OVERLAY          = 3,
+	V4L2_MEMORY_DMABUF           = 4,
+};
+
+/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
+enum v4l2_colorspace {
+	/*
+	 * Default colorspace, i.e. let the driver figure it out.
+	 * Can only be used with video capture.
+	 */
+	V4L2_COLORSPACE_DEFAULT       = 0,
+
+	/* SMPTE 170M: used for broadcast NTSC/PAL SDTV */
+	V4L2_COLORSPACE_SMPTE170M     = 1,
+
+	/* Obsolete pre-1998 SMPTE 240M HDTV standard, superseded by Rec 709 */
+	V4L2_COLORSPACE_SMPTE240M     = 2,
+
+	/* Rec.709: used for HDTV */
+	V4L2_COLORSPACE_REC709        = 3,
+
+	/*
+	 * Deprecated, do not use. No driver will ever return this. This was
+	 * based on a misunderstanding of the bt878 datasheet.
+	 */
+	V4L2_COLORSPACE_BT878         = 4,
+
+	/*
+	 * NTSC 1953 colorspace. This only makes sense when dealing with
+	 * really, really old NTSC recordings. Superseded by SMPTE 170M.
+	 */
+	V4L2_COLORSPACE_470_SYSTEM_M  = 5,
+
+	/*
+	 * EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when
+	 * dealing with really old PAL/SECAM recordings. Superseded by
+	 * SMPTE 170M.
+	 */
+	V4L2_COLORSPACE_470_SYSTEM_BG = 6,
+
+	/*
+	 * Effectively shorthand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601
+	 * and V4L2_QUANTIZATION_FULL_RANGE. To be used for (Motion-)JPEG.
+	 */
+	V4L2_COLORSPACE_JPEG          = 7,
+
+	/* For RGB colorspaces such as produces by most webcams. */
+	V4L2_COLORSPACE_SRGB          = 8,
+
+	/* AdobeRGB colorspace */
+	V4L2_COLORSPACE_ADOBERGB      = 9,
+
+	/* BT.2020 colorspace, used for UHDTV. */
+	V4L2_COLORSPACE_BT2020        = 10,
+
+	/* Raw colorspace: for RAW unprocessed images */
+	V4L2_COLORSPACE_RAW           = 11,
+
+	/* DCI-P3 colorspace, used by cinema projectors */
+	V4L2_COLORSPACE_DCI_P3        = 12,
+};
+
+/*
+ * Determine how COLORSPACE_DEFAULT should map to a proper colorspace.
+ * This depends on whether this is a SDTV image (use SMPTE 170M), an
+ * HDTV image (use Rec. 709), or something else (use sRGB).
+ */
+#define V4L2_MAP_COLORSPACE_DEFAULT(is_sdtv, is_hdtv) \
+	((is_sdtv) ? V4L2_COLORSPACE_SMPTE170M : \
+	 ((is_hdtv) ? V4L2_COLORSPACE_REC709 : V4L2_COLORSPACE_SRGB))
+
+enum v4l2_xfer_func {
+	/*
+	 * Mapping of V4L2_XFER_FUNC_DEFAULT to actual transfer functions
+	 * for the various colorspaces:
+	 *
+	 * V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_470_SYSTEM_M,
+	 * V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_REC709 and
+	 * V4L2_COLORSPACE_BT2020: V4L2_XFER_FUNC_709
+	 *
+	 * V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_JPEG: V4L2_XFER_FUNC_SRGB
+	 *
+	 * V4L2_COLORSPACE_ADOBERGB: V4L2_XFER_FUNC_ADOBERGB
+	 *
+	 * V4L2_COLORSPACE_SMPTE240M: V4L2_XFER_FUNC_SMPTE240M
+	 *
+	 * V4L2_COLORSPACE_RAW: V4L2_XFER_FUNC_NONE
+	 *
+	 * V4L2_COLORSPACE_DCI_P3: V4L2_XFER_FUNC_DCI_P3
+	 */
+	V4L2_XFER_FUNC_DEFAULT     = 0,
+	V4L2_XFER_FUNC_709         = 1,
+	V4L2_XFER_FUNC_SRGB        = 2,
+	V4L2_XFER_FUNC_ADOBERGB    = 3,
+	V4L2_XFER_FUNC_SMPTE240M   = 4,
+	V4L2_XFER_FUNC_NONE        = 5,
+	V4L2_XFER_FUNC_DCI_P3      = 6,
+	V4L2_XFER_FUNC_SMPTE2084   = 7,
+};
+
+/*
+ * Determine how XFER_FUNC_DEFAULT should map to a proper transfer function.
+ * This depends on the colorspace.
+ */
+#define V4L2_MAP_XFER_FUNC_DEFAULT(colsp) \
+	((colsp) == V4L2_COLORSPACE_ADOBERGB ? V4L2_XFER_FUNC_ADOBERGB : \
+	 ((colsp) == V4L2_COLORSPACE_SMPTE240M ? V4L2_XFER_FUNC_SMPTE240M : \
+	  ((colsp) == V4L2_COLORSPACE_DCI_P3 ? V4L2_XFER_FUNC_DCI_P3 : \
+	   ((colsp) == V4L2_COLORSPACE_RAW ? V4L2_XFER_FUNC_NONE : \
+	    ((colsp) == V4L2_COLORSPACE_SRGB || (colsp) == V4L2_COLORSPACE_JPEG ? \
+	     V4L2_XFER_FUNC_SRGB : V4L2_XFER_FUNC_709)))))
+
+enum v4l2_ycbcr_encoding {
+	/*
+	 * Mapping of V4L2_YCBCR_ENC_DEFAULT to actual encodings for the
+	 * various colorspaces:
+	 *
+	 * V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_470_SYSTEM_M,
+	 * V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_SRGB,
+	 * V4L2_COLORSPACE_ADOBERGB and V4L2_COLORSPACE_JPEG: V4L2_YCBCR_ENC_601
+	 *
+	 * V4L2_COLORSPACE_REC709 and V4L2_COLORSPACE_DCI_P3: V4L2_YCBCR_ENC_709
+	 *
+	 * V4L2_COLORSPACE_BT2020: V4L2_YCBCR_ENC_BT2020
+	 *
+	 * V4L2_COLORSPACE_SMPTE240M: V4L2_YCBCR_ENC_SMPTE240M
+	 */
+	V4L2_YCBCR_ENC_DEFAULT        = 0,
+
+	/* ITU-R 601 -- SDTV */
+	V4L2_YCBCR_ENC_601            = 1,
+
+	/* Rec. 709 -- HDTV */
+	V4L2_YCBCR_ENC_709            = 2,
+
+	/* ITU-R 601/EN 61966-2-4 Extended Gamut -- SDTV */
+	V4L2_YCBCR_ENC_XV601          = 3,
+
+	/* Rec. 709/EN 61966-2-4 Extended Gamut -- HDTV */
+	V4L2_YCBCR_ENC_XV709          = 4,
+
+#ifndef __KERNEL__
+	/*
+	 * sYCC (Y'CbCr encoding of sRGB), identical to ENC_601. It was added
+	 * originally due to a misunderstanding of the sYCC standard. It should
+	 * not be used, instead use V4L2_YCBCR_ENC_601.
+	 */
+	V4L2_YCBCR_ENC_SYCC           = 5,
+#endif
+
+	/* BT.2020 Non-constant Luminance Y'CbCr */
+	V4L2_YCBCR_ENC_BT2020         = 6,
+
+	/* BT.2020 Constant Luminance Y'CbcCrc */
+	V4L2_YCBCR_ENC_BT2020_CONST_LUM = 7,
+
+	/* SMPTE 240M -- Obsolete HDTV */
+	V4L2_YCBCR_ENC_SMPTE240M      = 8,
+};
+
+/*
+ * enum v4l2_hsv_encoding values should not collide with the ones from
+ * enum v4l2_ycbcr_encoding.
+ */
+enum v4l2_hsv_encoding {
+
+	/* Hue mapped to 0 - 179 */
+	V4L2_HSV_ENC_180		= 128,
+
+	/* Hue mapped to 0-255 */
+	V4L2_HSV_ENC_256		= 129,
+};
+
+/*
+ * Determine how YCBCR_ENC_DEFAULT should map to a proper Y'CbCr encoding.
+ * This depends on the colorspace.
+ */
+#define V4L2_MAP_YCBCR_ENC_DEFAULT(colsp) \
+	(((colsp) == V4L2_COLORSPACE_REC709 || \
+	  (colsp) == V4L2_COLORSPACE_DCI_P3) ? V4L2_YCBCR_ENC_709 : \
+	 ((colsp) == V4L2_COLORSPACE_BT2020 ? V4L2_YCBCR_ENC_BT2020 : \
+	  ((colsp) == V4L2_COLORSPACE_SMPTE240M ? V4L2_YCBCR_ENC_SMPTE240M : \
+	   V4L2_YCBCR_ENC_601)))
+
+enum v4l2_quantization {
+	/*
+	 * The default for R'G'B' quantization is always full range, except
+	 * for the BT2020 colorspace. For Y'CbCr the quantization is always
+	 * limited range, except for COLORSPACE_JPEG: this is full range.
+	 */
+	V4L2_QUANTIZATION_DEFAULT     = 0,
+	V4L2_QUANTIZATION_FULL_RANGE  = 1,
+	V4L2_QUANTIZATION_LIM_RANGE   = 2,
+};
+
+/*
+ * Determine how QUANTIZATION_DEFAULT should map to a proper quantization.
+ * This depends on whether the image is RGB or not, the colorspace and the
+ * Y'CbCr encoding.
+ */
+#define V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb_or_hsv, colsp, ycbcr_enc) \
+	(((is_rgb_or_hsv) && (colsp) == V4L2_COLORSPACE_BT2020) ? \
+	 V4L2_QUANTIZATION_LIM_RANGE : \
+	 (((is_rgb_or_hsv) || (colsp) == V4L2_COLORSPACE_JPEG) ? \
+	 V4L2_QUANTIZATION_FULL_RANGE : V4L2_QUANTIZATION_LIM_RANGE))
+
+enum v4l2_priority {
+	V4L2_PRIORITY_UNSET       = 0,  /* not initialized */
+	V4L2_PRIORITY_BACKGROUND  = 1,
+	V4L2_PRIORITY_INTERACTIVE = 2,
+	V4L2_PRIORITY_RECORD      = 3,
+	V4L2_PRIORITY_DEFAULT     = V4L2_PRIORITY_INTERACTIVE,
+};
+
+struct v4l2_rect {
+	__s32   left;
+	__s32   top;
+	__u32   width;
+	__u32   height;
+};
+
+struct v4l2_fract {
+	__u32   numerator;
+	__u32   denominator;
+};
+
+/**
+  * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
+  *
+  * @driver:	   name of the driver module (e.g. "bttv")
+  * @card:	   name of the card (e.g. "Hauppauge WinTV")
+  * @bus_info:	   name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
+  * @version:	   KERNEL_VERSION
+  * @capabilities: capabilities of the physical device as a whole
+  * @device_caps:  capabilities accessed via this particular device (node)
+  * @reserved:	   reserved fields for future extensions
+  */
+struct v4l2_capability {
+	__u8	driver[16];
+	__u8	card[32];
+	__u8	bus_info[32];
+	__u32   version;
+	__u32	capabilities;
+	__u32	device_caps;
+	__u32	reserved[3];
+};
+
+/* Values for 'capabilities' field */
+#define V4L2_CAP_VIDEO_CAPTURE		0x00000001  /* Is a video capture device */
+#define V4L2_CAP_VIDEO_OUTPUT		0x00000002  /* Is a video output device */
+#define V4L2_CAP_VIDEO_OVERLAY		0x00000004  /* Can do video overlay */
+#define V4L2_CAP_VBI_CAPTURE		0x00000010  /* Is a raw VBI capture device */
+#define V4L2_CAP_VBI_OUTPUT		0x00000020  /* Is a raw VBI output device */
+#define V4L2_CAP_SLICED_VBI_CAPTURE	0x00000040  /* Is a sliced VBI capture device */
+#define V4L2_CAP_SLICED_VBI_OUTPUT	0x00000080  /* Is a sliced VBI output device */
+#define V4L2_CAP_RDS_CAPTURE		0x00000100  /* RDS data capture */
+#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY	0x00000200  /* Can do video output overlay */
+#define V4L2_CAP_HW_FREQ_SEEK		0x00000400  /* Can do hardware frequency seek  */
+#define V4L2_CAP_RDS_OUTPUT		0x00000800  /* Is an RDS encoder */
+
+/* Is a video capture device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_CAPTURE_MPLANE	0x00001000
+/* Is a video output device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_OUTPUT_MPLANE	0x00002000
+/* Is a video mem-to-mem device that supports multiplanar formats */
+#define V4L2_CAP_VIDEO_M2M_MPLANE	0x00004000
+/* Is a video mem-to-mem device */
+#define V4L2_CAP_VIDEO_M2M		0x00008000
+
+#define V4L2_CAP_TUNER			0x00010000  /* has a tuner */
+#define V4L2_CAP_AUDIO			0x00020000  /* has audio support */
+#define V4L2_CAP_RADIO			0x00040000  /* is a radio device */
+#define V4L2_CAP_MODULATOR		0x00080000  /* has a modulator */
+
+#define V4L2_CAP_SDR_CAPTURE		0x00100000  /* Is a SDR capture device */
+#define V4L2_CAP_EXT_PIX_FORMAT		0x00200000  /* Supports the extended pixel format */
+#define V4L2_CAP_SDR_OUTPUT		0x00400000  /* Is a SDR output device */
+#define V4L2_CAP_META_CAPTURE		0x00800000  /* Is a metadata capture device */
+
+#define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
+#define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
+#define V4L2_CAP_STREAMING              0x04000000  /* streaming I/O ioctls */
+
+#define V4L2_CAP_TOUCH                  0x10000000  /* Is a touch device */
+
+#define V4L2_CAP_DEVICE_CAPS            0x80000000  /* sets device capabilities field */
+
+/*
+ *	V I D E O   I M A G E   F O R M A T
+ */
+struct v4l2_pix_format {
+	__u32         		width;
+	__u32			height;
+	__u32			pixelformat;
+	__u32			field;		/* enum v4l2_field */
+	__u32            	bytesperline;	/* for padding, zero if unused */
+	__u32          		sizeimage;
+	__u32			colorspace;	/* enum v4l2_colorspace */
+	__u32			priv;		/* private data, depends on pixelformat */
+	__u32			flags;		/* format flags (V4L2_PIX_FMT_FLAG_*) */
+	union {
+		/* enum v4l2_ycbcr_encoding */
+		__u32			ycbcr_enc;
+		/* enum v4l2_hsv_encoding */
+		__u32			hsv_enc;
+	};
+	__u32			quantization;	/* enum v4l2_quantization */
+	__u32			xfer_func;	/* enum v4l2_xfer_func */
+};
+
+/*      Pixel format         FOURCC                          depth  Description  */
+
+/* RGB formats */
+#define V4L2_PIX_FMT_RGB332  v4l2_fourcc('R', 'G', 'B', '1') /*  8  RGB-3-3-2     */
+#define V4L2_PIX_FMT_RGB444  v4l2_fourcc('R', '4', '4', '4') /* 16  xxxxrrrr ggggbbbb */
+#define V4L2_PIX_FMT_ARGB444 v4l2_fourcc('A', 'R', '1', '2') /* 16  aaaarrrr ggggbbbb */
+#define V4L2_PIX_FMT_XRGB444 v4l2_fourcc('X', 'R', '1', '2') /* 16  xxxxrrrr ggggbbbb */
+#define V4L2_PIX_FMT_RGB555  v4l2_fourcc('R', 'G', 'B', 'O') /* 16  RGB-5-5-5     */
+#define V4L2_PIX_FMT_ARGB555 v4l2_fourcc('A', 'R', '1', '5') /* 16  ARGB-1-5-5-5  */
+#define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16  XRGB-1-5-5-5  */
+#define V4L2_PIX_FMT_RGB565  v4l2_fourcc('R', 'G', 'B', 'P') /* 16  RGB-5-6-5     */
+#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16  RGB-5-5-5 BE  */
+#define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16  ARGB-5-5-5 BE */
+#define V4L2_PIX_FMT_XRGB555X v4l2_fourcc_be('X', 'R', '1', '5') /* 16  XRGB-5-5-5 BE */
+#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16  RGB-5-6-5 BE  */
+#define V4L2_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', 'H') /* 18  BGR-6-6-6	  */
+#define V4L2_PIX_FMT_BGR24   v4l2_fourcc('B', 'G', 'R', '3') /* 24  BGR-8-8-8     */
+#define V4L2_PIX_FMT_RGB24   v4l2_fourcc('R', 'G', 'B', '3') /* 24  RGB-8-8-8     */
+#define V4L2_PIX_FMT_BGR32   v4l2_fourcc('B', 'G', 'R', '4') /* 32  BGR-8-8-8-8   */
+#define V4L2_PIX_FMT_ABGR32  v4l2_fourcc('A', 'R', '2', '4') /* 32  BGRA-8-8-8-8  */
+#define V4L2_PIX_FMT_XBGR32  v4l2_fourcc('X', 'R', '2', '4') /* 32  BGRX-8-8-8-8  */
+#define V4L2_PIX_FMT_RGB32   v4l2_fourcc('R', 'G', 'B', '4') /* 32  RGB-8-8-8-8   */
+#define V4L2_PIX_FMT_ARGB32  v4l2_fourcc('B', 'A', '2', '4') /* 32  ARGB-8-8-8-8  */
+#define V4L2_PIX_FMT_XRGB32  v4l2_fourcc('B', 'X', '2', '4') /* 32  XRGB-8-8-8-8  */
+
+/* Grey formats */
+#define V4L2_PIX_FMT_GREY    v4l2_fourcc('G', 'R', 'E', 'Y') /*  8  Greyscale     */
+#define V4L2_PIX_FMT_Y4      v4l2_fourcc('Y', '0', '4', ' ') /*  4  Greyscale     */
+#define V4L2_PIX_FMT_Y6      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
+#define V4L2_PIX_FMT_Y10     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
+#define V4L2_PIX_FMT_Y12     v4l2_fourcc('Y', '1', '2', ' ') /* 12  Greyscale     */
+#define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
+#define V4L2_PIX_FMT_Y16_BE  v4l2_fourcc_be('Y', '1', '6', ' ') /* 16  Greyscale BE  */
+
+/* Grey bit-packed formats */
+#define V4L2_PIX_FMT_Y10BPACK    v4l2_fourcc('Y', '1', '0', 'B') /* 10  Greyscale bit-packed */
+
+/* Palette formats */
+#define V4L2_PIX_FMT_PAL8    v4l2_fourcc('P', 'A', 'L', '8') /*  8  8-bit palette */
+
+/* Chrominance formats */
+#define V4L2_PIX_FMT_UV8     v4l2_fourcc('U', 'V', '8', ' ') /*  8  UV 4:4 */
+
+/* Luminance+Chrominance formats */
+#define V4L2_PIX_FMT_YUYV    v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YYUV    v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_UYVY    v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_VYUY    v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16  YUV 4:2:2     */
+#define V4L2_PIX_FMT_Y41P    v4l2_fourcc('Y', '4', '1', 'P') /* 12  YUV 4:1:1     */
+#define V4L2_PIX_FMT_YUV444  v4l2_fourcc('Y', '4', '4', '4') /* 16  xxxxyyyy uuuuvvvv */
+#define V4L2_PIX_FMT_YUV555  v4l2_fourcc('Y', 'U', 'V', 'O') /* 16  YUV-5-5-5     */
+#define V4L2_PIX_FMT_YUV565  v4l2_fourcc('Y', 'U', 'V', 'P') /* 16  YUV-5-6-5     */
+#define V4L2_PIX_FMT_YUV32   v4l2_fourcc('Y', 'U', 'V', '4') /* 32  YUV-8-8-8-8   */
+#define V4L2_PIX_FMT_HI240   v4l2_fourcc('H', 'I', '2', '4') /*  8  8-bit color   */
+#define V4L2_PIX_FMT_HM12    v4l2_fourcc('H', 'M', '1', '2') /*  8  YUV 4:2:0 16x16 macroblocks */
+#define V4L2_PIX_FMT_M420    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
+
+/* two planes -- one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12    v4l2_fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV21    v4l2_fourcc('N', 'V', '2', '1') /* 12  Y/CrCb 4:2:0  */
+#define V4L2_PIX_FMT_NV16    v4l2_fourcc('N', 'V', '1', '6') /* 16  Y/CbCr 4:2:2  */
+#define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
+#define V4L2_PIX_FMT_NV24    v4l2_fourcc('N', 'V', '2', '4') /* 24  Y/CbCr 4:4:4  */
+#define V4L2_PIX_FMT_NV42    v4l2_fourcc('N', 'V', '4', '2') /* 24  Y/CrCb 4:4:4  */
+
+/* two non contiguous planes - one Y, one Cr + Cb interleaved  */
+#define V4L2_PIX_FMT_NV12M   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
+#define V4L2_PIX_FMT_NV21M   v4l2_fourcc('N', 'M', '2', '1') /* 21  Y/CrCb 4:2:0  */
+#define V4L2_PIX_FMT_NV16M   v4l2_fourcc('N', 'M', '1', '6') /* 16  Y/CbCr 4:2:2  */
+#define V4L2_PIX_FMT_NV61M   v4l2_fourcc('N', 'M', '6', '1') /* 16  Y/CrCb 4:2:2  */
+#define V4L2_PIX_FMT_NV12MT  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 macroblocks */
+#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 16x16 macroblocks */
+
+/* three planes - Y Cb, Cr */
+#define V4L2_PIX_FMT_YUV410  v4l2_fourcc('Y', 'U', 'V', '9') /*  9  YUV 4:1:0     */
+#define V4L2_PIX_FMT_YVU410  v4l2_fourcc('Y', 'V', 'U', '9') /*  9  YVU 4:1:0     */
+#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 12  YVU411 planar */
+#define V4L2_PIX_FMT_YUV420  v4l2_fourcc('Y', 'U', '1', '2') /* 12  YUV 4:2:0     */
+#define V4L2_PIX_FMT_YVU420  v4l2_fourcc('Y', 'V', '1', '2') /* 12  YVU 4:2:0     */
+#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16  YVU422 planar */
+
+/* three non contiguous planes - Y, Cb, Cr */
+#define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12  YUV420 planar */
+#define V4L2_PIX_FMT_YVU420M v4l2_fourcc('Y', 'M', '2', '1') /* 12  YVU420 planar */
+#define V4L2_PIX_FMT_YUV422M v4l2_fourcc('Y', 'M', '1', '6') /* 16  YUV422 planar */
+#define V4L2_PIX_FMT_YVU422M v4l2_fourcc('Y', 'M', '6', '1') /* 16  YVU422 planar */
+#define V4L2_PIX_FMT_YUV444M v4l2_fourcc('Y', 'M', '2', '4') /* 24  YUV444 planar */
+#define V4L2_PIX_FMT_YVU444M v4l2_fourcc('Y', 'M', '4', '2') /* 24  YVU444 planar */
+
+/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
+#define V4L2_PIX_FMT_SBGGR8  v4l2_fourcc('B', 'A', '8', '1') /*  8  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG8  v4l2_fourcc('G', 'B', 'R', 'G') /*  8  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG8  v4l2_fourcc('G', 'R', 'B', 'G') /*  8  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB8  v4l2_fourcc('R', 'G', 'G', 'B') /*  8  RGRG.. GBGB.. */
+#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10  RGRG.. GBGB.. */
+	/* 10bit raw bayer packed, 5 bytes for every 4 pixels */
+#define V4L2_PIX_FMT_SBGGR10P v4l2_fourcc('p', 'B', 'A', 'A')
+#define V4L2_PIX_FMT_SGBRG10P v4l2_fourcc('p', 'G', 'A', 'A')
+#define V4L2_PIX_FMT_SGRBG10P v4l2_fourcc('p', 'g', 'A', 'A')
+#define V4L2_PIX_FMT_SRGGB10P v4l2_fourcc('p', 'R', 'A', 'A')
+	/* 10bit raw bayer a-law compressed to 8 bits */
+#define V4L2_PIX_FMT_SBGGR10ALAW8 v4l2_fourcc('a', 'B', 'A', '8')
+#define V4L2_PIX_FMT_SGBRG10ALAW8 v4l2_fourcc('a', 'G', 'A', '8')
+#define V4L2_PIX_FMT_SGRBG10ALAW8 v4l2_fourcc('a', 'g', 'A', '8')
+#define V4L2_PIX_FMT_SRGGB10ALAW8 v4l2_fourcc('a', 'R', 'A', '8')
+	/* 10bit raw bayer DPCM compressed to 8 bits */
+#define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8')
+#define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8')
+#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+#define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8')
+#define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12  RGRG.. GBGB.. */
+#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16  RGRG.. GBGB.. */
+
+/* HSV formats */
+#define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3')
+#define V4L2_PIX_FMT_HSV32 v4l2_fourcc('H', 'S', 'V', '4')
+
+/* compressed formats */
+#define V4L2_PIX_FMT_MJPEG    v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG   */
+#define V4L2_PIX_FMT_JPEG     v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG     */
+#define V4L2_PIX_FMT_DV       v4l2_fourcc('d', 'v', 's', 'd') /* 1394          */
+#define V4L2_PIX_FMT_MPEG     v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */
+#define V4L2_PIX_FMT_H264     v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */
+#define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */
+#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */
+#define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
+#define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
+#define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
+#define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 part 2 ES */
+#define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
+#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
+#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
+#define V4L2_PIX_FMT_VP8      v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
+#define V4L2_PIX_FMT_VP9      v4l2_fourcc('V', 'P', '9', '0') /* VP9 */
+#define V4L2_PIX_FMT_HEVC	v4l2_fourcc('H', 'E', 'V', 'C') /* HEVC */
+
+/*  Vendor-specific formats   */
+#define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
+#define V4L2_PIX_FMT_WNVA     v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
+#define V4L2_PIX_FMT_SN9C10X  v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
+#define V4L2_PIX_FMT_PWC1     v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */
+#define V4L2_PIX_FMT_PWC2     v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */
+#define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */
+#define V4L2_PIX_FMT_SPCA501  v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */
+#define V4L2_PIX_FMT_SPCA505  v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */
+#define V4L2_PIX_FMT_SPCA508  v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */
+#define V4L2_PIX_FMT_SPCA561  v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
+#define V4L2_PIX_FMT_PAC207   v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */
+#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
+#define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
+#define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
+#define V4L2_PIX_FMT_OV511    v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
+#define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
+#define V4L2_PIX_FMT_STV0680  v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
+#define V4L2_PIX_FMT_TM6000   v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
+#define V4L2_PIX_FMT_KONICA420  v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
+#define V4L2_PIX_FMT_JPGL	v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */
+#define V4L2_PIX_FMT_SE401      v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */
+#define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */
+#define V4L2_PIX_FMT_Y8I      v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
+#define V4L2_PIX_FMT_Y12I     v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
+#define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
+#define V4L2_PIX_FMT_MT21C    v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode  */
+#define V4L2_PIX_FMT_INZI     v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
+
+/* SDR formats - used only for Software Defined Radio devices */
+#define V4L2_SDR_FMT_CU8          v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
+#define V4L2_SDR_FMT_CU16LE       v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */
+#define V4L2_SDR_FMT_CS8          v4l2_fourcc('C', 'S', '0', '8') /* complex s8 */
+#define V4L2_SDR_FMT_CS14LE       v4l2_fourcc('C', 'S', '1', '4') /* complex s14le */
+#define V4L2_SDR_FMT_RU12LE       v4l2_fourcc('R', 'U', '1', '2') /* real u12le */
+#define V4L2_SDR_FMT_PCU16BE	  v4l2_fourcc('P', 'C', '1', '6') /* planar complex u16be */
+#define V4L2_SDR_FMT_PCU18BE	  v4l2_fourcc('P', 'C', '1', '8') /* planar complex u18be */
+#define V4L2_SDR_FMT_PCU20BE	  v4l2_fourcc('P', 'C', '2', '0') /* planar complex u20be */
+
+/* Touch formats - used for Touch devices */
+#define V4L2_TCH_FMT_DELTA_TD16	v4l2_fourcc('T', 'D', '1', '6') /* 16-bit signed deltas */
+#define V4L2_TCH_FMT_DELTA_TD08	v4l2_fourcc('T', 'D', '0', '8') /* 8-bit signed deltas */
+#define V4L2_TCH_FMT_TU16	v4l2_fourcc('T', 'U', '1', '6') /* 16-bit unsigned touch data */
+#define V4L2_TCH_FMT_TU08	v4l2_fourcc('T', 'U', '0', '8') /* 8-bit unsigned touch data */
+
+/* Meta-data formats */
+#define V4L2_META_FMT_VSP1_HGO    v4l2_fourcc('V', 'S', 'P', 'H') /* R-Car VSP1 1-D Histogram */
+#define V4L2_META_FMT_VSP1_HGT    v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */
+
+/* priv field value to indicates that subsequent fields are valid. */
+#define V4L2_PIX_FMT_PRIV_MAGIC		0xfeedcafe
+
+/* Flags */
+#define V4L2_PIX_FMT_FLAG_PREMUL_ALPHA	0x00000001
+
+/*
+ *	F O R M A T   E N U M E R A T I O N
+ */
+struct v4l2_fmtdesc {
+	__u32		    index;             /* Format number      */
+	__u32		    type;              /* enum v4l2_buf_type */
+	__u32               flags;
+	__u8		    description[32];   /* Description string */
+	__u32		    pixelformat;       /* Format fourcc      */
+	__u32		    reserved[4];
+};
+
+#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+#define V4L2_FMT_FLAG_EMULATED   0x0002
+
+	/* Frame Size and frame rate enumeration */
+/*
+ *	F R A M E   S I Z E   E N U M E R A T I O N
+ */
+enum v4l2_frmsizetypes {
+	V4L2_FRMSIZE_TYPE_DISCRETE	= 1,
+	V4L2_FRMSIZE_TYPE_CONTINUOUS	= 2,
+	V4L2_FRMSIZE_TYPE_STEPWISE	= 3,
+};
+
+struct v4l2_frmsize_discrete {
+	__u32			width;		/* Frame width [pixel] */
+	__u32			height;		/* Frame height [pixel] */
+};
+
+struct v4l2_frmsize_stepwise {
+	__u32			min_width;	/* Minimum frame width [pixel] */
+	__u32			max_width;	/* Maximum frame width [pixel] */
+	__u32			step_width;	/* Frame width step size [pixel] */
+	__u32			min_height;	/* Minimum frame height [pixel] */
+	__u32			max_height;	/* Maximum frame height [pixel] */
+	__u32			step_height;	/* Frame height step size [pixel] */
+};
+
+struct v4l2_frmsizeenum {
+	__u32			index;		/* Frame size number */
+	__u32			pixel_format;	/* Pixel format */
+	__u32			type;		/* Frame size type the device supports. */
+
+	union {					/* Frame size */
+		struct v4l2_frmsize_discrete	discrete;
+		struct v4l2_frmsize_stepwise	stepwise;
+	};
+
+	__u32   reserved[2];			/* Reserved space for future use */
+};
+
+/*
+ *	F R A M E   R A T E   E N U M E R A T I O N
+ */
+enum v4l2_frmivaltypes {
+	V4L2_FRMIVAL_TYPE_DISCRETE	= 1,
+	V4L2_FRMIVAL_TYPE_CONTINUOUS	= 2,
+	V4L2_FRMIVAL_TYPE_STEPWISE	= 3,
+};
+
+struct v4l2_frmival_stepwise {
+	struct v4l2_fract	min;		/* Minimum frame interval [s] */
+	struct v4l2_fract	max;		/* Maximum frame interval [s] */
+	struct v4l2_fract	step;		/* Frame interval step size [s] */
+};
+
+struct v4l2_frmivalenum {
+	__u32			index;		/* Frame format index */
+	__u32			pixel_format;	/* Pixel format */
+	__u32			width;		/* Frame width */
+	__u32			height;		/* Frame height */
+	__u32			type;		/* Frame interval type the device supports. */
+
+	union {					/* Frame interval */
+		struct v4l2_fract		discrete;
+		struct v4l2_frmival_stepwise	stepwise;
+	};
+
+	__u32	reserved[2];			/* Reserved space for future use */
+};
+
+/*
+ *	T I M E C O D E
+ */
+struct v4l2_timecode {
+	__u32	type;
+	__u32	flags;
+	__u8	frames;
+	__u8	seconds;
+	__u8	minutes;
+	__u8	hours;
+	__u8	userbits[4];
+};
+
+/*  Type  */
+#define V4L2_TC_TYPE_24FPS		1
+#define V4L2_TC_TYPE_25FPS		2
+#define V4L2_TC_TYPE_30FPS		3
+#define V4L2_TC_TYPE_50FPS		4
+#define V4L2_TC_TYPE_60FPS		5
+
+/*  Flags  */
+#define V4L2_TC_FLAG_DROPFRAME		0x0001 /* "drop-frame" mode */
+#define V4L2_TC_FLAG_COLORFRAME		0x0002
+#define V4L2_TC_USERBITS_field		0x000C
+#define V4L2_TC_USERBITS_USERDEFINED	0x0000
+#define V4L2_TC_USERBITS_8BITCHARS	0x0008
+/* The above is based on SMPTE timecodes */
+
+struct v4l2_jpegcompression {
+	int quality;
+
+	int  APPn;              /* Number of APP segment to be written,
+				 * must be 0..15 */
+	int  APP_len;           /* Length of data in JPEG APPn segment */
+	char APP_data[60];      /* Data in the JPEG APPn segment. */
+
+	int  COM_len;           /* Length of data in JPEG COM segment */
+	char COM_data[60];      /* Data in JPEG COM segment */
+
+	__u32 jpeg_markers;     /* Which markers should go into the JPEG
+				 * output. Unless you exactly know what
+				 * you do, leave them untouched.
+				 * Including less markers will make the
+				 * resulting code smaller, but there will
+				 * be fewer applications which can read it.
+				 * The presence of the APP and COM marker
+				 * is influenced by APP_len and COM_len
+				 * ONLY, not by this property! */
+
+#define V4L2_JPEG_MARKER_DHT (1<<3)    /* Define Huffman Tables */
+#define V4L2_JPEG_MARKER_DQT (1<<4)    /* Define Quantization Tables */
+#define V4L2_JPEG_MARKER_DRI (1<<5)    /* Define Restart Interval */
+#define V4L2_JPEG_MARKER_COM (1<<6)    /* Comment segment */
+#define V4L2_JPEG_MARKER_APP (1<<7)    /* App segment, driver will
+					* always use APP0 */
+};
+
+/*
+ *	M E M O R Y - M A P P I N G   B U F F E R S
+ */
+struct v4l2_requestbuffers {
+	__u32			count;
+	__u32			type;		/* enum v4l2_buf_type */
+	__u32			memory;		/* enum v4l2_memory */
+	__u32			reserved[2];
+};
+
+/**
+ * struct v4l2_plane - plane info for multi-planar buffers
+ * @bytesused:		number of bytes occupied by data in the plane (payload)
+ * @length:		size of this plane (NOT the payload) in bytes
+ * @mem_offset:		when memory in the associated struct v4l2_buffer is
+ *			V4L2_MEMORY_MMAP, equals the offset from the start of
+ *			the device memory for this plane (or is a "cookie" that
+ *			should be passed to mmap() called on the video node)
+ * @userptr:		when memory is V4L2_MEMORY_USERPTR, a userspace pointer
+ *			pointing to this plane
+ * @fd:			when memory is V4L2_MEMORY_DMABUF, a userspace file
+ *			descriptor associated with this plane
+ * @data_offset:	offset in the plane to the start of data; usually 0,
+ *			unless there is a header in front of the data
+ *
+ * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
+ * with two planes can have one plane for Y, and another for interleaved CbCr
+ * components. Each plane can reside in a separate memory buffer, or even in
+ * a completely separate memory node (e.g. in embedded devices).
+ */
+struct v4l2_plane {
+	__u32			bytesused;
+	__u32			length;
+	union {
+		__u32		mem_offset;
+		unsigned long	userptr;
+		__s32		fd;
+	} m;
+	__u32			data_offset;
+	__u32			reserved[11];
+};
+
+/**
+ * struct v4l2_buffer - video buffer info
+ * @index:	id number of the buffer
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
+ * @bytesused:	number of bytes occupied by data in the buffer (payload);
+ *		unused (set to 0) for multiplanar buffers
+ * @flags:	buffer informational flags
+ * @field:	enum v4l2_field; field order of the image in the buffer
+ * @timestamp:	frame timestamp
+ * @timecode:	frame timecode
+ * @sequence:	sequence count of this frame
+ * @memory:	enum v4l2_memory; the method, in which the actual video data is
+ *		passed
+ * @offset:	for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
+ *		offset from the start of the device memory for this plane,
+ *		(or a "cookie" that should be passed to mmap() as offset)
+ * @userptr:	for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
+ *		a userspace pointer pointing to this buffer
+ * @fd:		for non-multiplanar buffers with memory == V4L2_MEMORY_DMABUF;
+ *		a userspace file descriptor associated with this buffer
+ * @planes:	for multiplanar buffers; userspace pointer to the array of plane
+ *		info structs for this buffer
+ * @length:	size in bytes of the buffer (NOT its payload) for single-plane
+ *		buffers (when type != *_MPLANE); number of elements in the
+ *		planes array for multi-plane buffers
+ *
+ * Contains data exchanged by application and driver using one of the Streaming
+ * I/O methods.
+ */
+struct v4l2_buffer {
+	__u32			index;
+	__u32			type;
+	__u32			bytesused;
+	__u32			flags;
+	__u32			field;
+	struct timeval		timestamp;
+	struct v4l2_timecode	timecode;
+	__u32			sequence;
+
+	/* memory location */
+	__u32			memory;
+	union {
+		__u32           offset;
+		unsigned long   userptr;
+		struct v4l2_plane *planes;
+		__s32		fd;
+	} m;
+	__u32			length;
+	__u32			reserved2;
+	__u32			reserved;
+};
+
+/*  Flags for 'flags' field */
+/* Buffer is mapped (flag) */
+#define V4L2_BUF_FLAG_MAPPED			0x00000001
+/* Buffer is queued for processing */
+#define V4L2_BUF_FLAG_QUEUED			0x00000002
+/* Buffer is ready */
+#define V4L2_BUF_FLAG_DONE			0x00000004
+/* Image is a keyframe (I-frame) */
+#define V4L2_BUF_FLAG_KEYFRAME			0x00000008
+/* Image is a P-frame */
+#define V4L2_BUF_FLAG_PFRAME			0x00000010
+/* Image is a B-frame */
+#define V4L2_BUF_FLAG_BFRAME			0x00000020
+/* Buffer is ready, but the data contained within is corrupted. */
+#define V4L2_BUF_FLAG_ERROR			0x00000040
+/* timecode field is valid */
+#define V4L2_BUF_FLAG_TIMECODE			0x00000100
+/* Buffer is prepared for queuing */
+#define V4L2_BUF_FLAG_PREPARED			0x00000400
+/* Cache handling flags */
+#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x00000800
+#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x00001000
+/* Timestamp type */
+#define V4L2_BUF_FLAG_TIMESTAMP_MASK		0x0000e000
+#define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN		0x00000000
+#define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC	0x00002000
+#define V4L2_BUF_FLAG_TIMESTAMP_COPY		0x00004000
+/* Timestamp sources. */
+#define V4L2_BUF_FLAG_TSTAMP_SRC_MASK		0x00070000
+#define V4L2_BUF_FLAG_TSTAMP_SRC_EOF		0x00000000
+#define V4L2_BUF_FLAG_TSTAMP_SRC_SOE		0x00010000
+/* mem2mem encoder/decoder */
+#define V4L2_BUF_FLAG_LAST			0x00100000
+
+/**
+ * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor
+ *
+ * @index:	id number of the buffer
+ * @type:	enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ *		multiplanar buffers);
+ * @plane:	index of the plane to be exported, 0 for single plane queues
+ * @flags:	flags for newly created file, currently only O_CLOEXEC is
+ *		supported, refer to manual of open syscall for more details
+ * @fd:		file descriptor associated with DMABUF (set by driver)
+ *
+ * Contains data used for exporting a video buffer as DMABUF file descriptor.
+ * The buffer is identified by a 'cookie' returned by VIDIOC_QUERYBUF
+ * (identical to the cookie used to mmap() the buffer to userspace). All
+ * reserved fields must be set to zero. The field reserved0 is expected to
+ * become a structure 'type' allowing an alternative layout of the structure
+ * content. Therefore this field should not be used for any other extensions.
+ */
+struct v4l2_exportbuffer {
+	__u32		type; /* enum v4l2_buf_type */
+	__u32		index;
+	__u32		plane;
+	__u32		flags;
+	__s32		fd;
+	__u32		reserved[11];
+};
+
+/*
+ *	O V E R L A Y   P R E V I E W
+ */
+struct v4l2_framebuffer {
+	__u32			capability;
+	__u32			flags;
+/* FIXME: in theory we should pass something like PCI device + memory
+ * region + offset instead of some physical address */
+	void                    *base;
+	struct {
+		__u32		width;
+		__u32		height;
+		__u32		pixelformat;
+		__u32		field;		/* enum v4l2_field */
+		__u32		bytesperline;	/* for padding, zero if unused */
+		__u32		sizeimage;
+		__u32		colorspace;	/* enum v4l2_colorspace */
+		__u32		priv;		/* reserved field, set to 0 */
+	} fmt;
+};
+/*  Flags for the 'capability' field. Read only */
+#define V4L2_FBUF_CAP_EXTERNOVERLAY	0x0001
+#define V4L2_FBUF_CAP_CHROMAKEY		0x0002
+#define V4L2_FBUF_CAP_LIST_CLIPPING     0x0004
+#define V4L2_FBUF_CAP_BITMAP_CLIPPING	0x0008
+#define V4L2_FBUF_CAP_LOCAL_ALPHA	0x0010
+#define V4L2_FBUF_CAP_GLOBAL_ALPHA	0x0020
+#define V4L2_FBUF_CAP_LOCAL_INV_ALPHA	0x0040
+#define V4L2_FBUF_CAP_SRC_CHROMAKEY	0x0080
+/*  Flags for the 'flags' field. */
+#define V4L2_FBUF_FLAG_PRIMARY		0x0001
+#define V4L2_FBUF_FLAG_OVERLAY		0x0002
+#define V4L2_FBUF_FLAG_CHROMAKEY	0x0004
+#define V4L2_FBUF_FLAG_LOCAL_ALPHA	0x0008
+#define V4L2_FBUF_FLAG_GLOBAL_ALPHA	0x0010
+#define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA	0x0020
+#define V4L2_FBUF_FLAG_SRC_CHROMAKEY	0x0040
+
+struct v4l2_clip {
+	struct v4l2_rect        c;
+	struct v4l2_clip	__user *next;
+};
+
+struct v4l2_window {
+	struct v4l2_rect        w;
+	__u32			field;	 /* enum v4l2_field */
+	__u32			chromakey;
+	struct v4l2_clip	__user *clips;
+	__u32			clipcount;
+	void			__user *bitmap;
+	__u8                    global_alpha;
+};
+
+/*
+ *	C A P T U R E   P A R A M E T E R S
+ */
+struct v4l2_captureparm {
+	__u32		   capability;	  /*  Supported modes */
+	__u32		   capturemode;	  /*  Current mode */
+	struct v4l2_fract  timeperframe;  /*  Time per frame in seconds */
+	__u32		   extendedmode;  /*  Driver-specific extensions */
+	__u32              readbuffers;   /*  # of buffers for read */
+	__u32		   reserved[4];
+};
+
+/*  Flags for 'capability' and 'capturemode' fields */
+#define V4L2_MODE_HIGHQUALITY	0x0001	/*  High quality imaging mode */
+#define V4L2_CAP_TIMEPERFRAME	0x1000	/*  timeperframe field is supported */
+
+struct v4l2_outputparm {
+	__u32		   capability;	 /*  Supported modes */
+	__u32		   outputmode;	 /*  Current mode */
+	struct v4l2_fract  timeperframe; /*  Time per frame in seconds */
+	__u32		   extendedmode; /*  Driver-specific extensions */
+	__u32              writebuffers; /*  # of buffers for write */
+	__u32		   reserved[4];
+};
+
+/*
+ *	I N P U T   I M A G E   C R O P P I N G
+ */
+struct v4l2_cropcap {
+	__u32			type;	/* enum v4l2_buf_type */
+	struct v4l2_rect        bounds;
+	struct v4l2_rect        defrect;
+	struct v4l2_fract       pixelaspect;
+};
+
+struct v4l2_crop {
+	__u32			type;	/* enum v4l2_buf_type */
+	struct v4l2_rect        c;
+};
+
+/**
+ * struct v4l2_selection - selection info
+ * @type:	buffer type (do not use *_MPLANE types)
+ * @target:	Selection target, used to choose one of possible rectangles;
+ *		defined in v4l2-common.h; V4L2_SEL_TGT_* .
+ * @flags:	constraints flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
+ * @r:		coordinates of selection window
+ * @reserved:	for future use, rounds structure size to 64 bytes, set to zero
+ *
+ * Hardware may use multiple helper windows to process a video stream.
+ * The structure is used to exchange this selection areas between
+ * an application and a driver.
+ */
+struct v4l2_selection {
+	__u32			type;
+	__u32			target;
+	__u32                   flags;
+	struct v4l2_rect        r;
+	__u32                   reserved[9];
+};
+
+
+/*
+ *      A N A L O G   V I D E O   S T A N D A R D
+ */
+
+typedef __u64 v4l2_std_id;
+
+/* one bit for each */
+#define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
+#define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
+#define V4L2_STD_PAL_G          ((v4l2_std_id)0x00000004)
+#define V4L2_STD_PAL_H          ((v4l2_std_id)0x00000008)
+#define V4L2_STD_PAL_I          ((v4l2_std_id)0x00000010)
+#define V4L2_STD_PAL_D          ((v4l2_std_id)0x00000020)
+#define V4L2_STD_PAL_D1         ((v4l2_std_id)0x00000040)
+#define V4L2_STD_PAL_K          ((v4l2_std_id)0x00000080)
+
+#define V4L2_STD_PAL_M          ((v4l2_std_id)0x00000100)
+#define V4L2_STD_PAL_N          ((v4l2_std_id)0x00000200)
+#define V4L2_STD_PAL_Nc         ((v4l2_std_id)0x00000400)
+#define V4L2_STD_PAL_60         ((v4l2_std_id)0x00000800)
+
+#define V4L2_STD_NTSC_M         ((v4l2_std_id)0x00001000)	/* BTSC */
+#define V4L2_STD_NTSC_M_JP      ((v4l2_std_id)0x00002000)	/* EIA-J */
+#define V4L2_STD_NTSC_443       ((v4l2_std_id)0x00004000)
+#define V4L2_STD_NTSC_M_KR      ((v4l2_std_id)0x00008000)	/* FM A2 */
+
+#define V4L2_STD_SECAM_B        ((v4l2_std_id)0x00010000)
+#define V4L2_STD_SECAM_D        ((v4l2_std_id)0x00020000)
+#define V4L2_STD_SECAM_G        ((v4l2_std_id)0x00040000)
+#define V4L2_STD_SECAM_H        ((v4l2_std_id)0x00080000)
+#define V4L2_STD_SECAM_K        ((v4l2_std_id)0x00100000)
+#define V4L2_STD_SECAM_K1       ((v4l2_std_id)0x00200000)
+#define V4L2_STD_SECAM_L        ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC       ((v4l2_std_id)0x00800000)
+
+/* ATSC/HDTV */
+#define V4L2_STD_ATSC_8_VSB     ((v4l2_std_id)0x01000000)
+#define V4L2_STD_ATSC_16_VSB    ((v4l2_std_id)0x02000000)
+
+/* FIXME:
+   Although std_id is 64 bits, there is an issue on PPC32 architecture that
+   makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
+   this value to 32 bits.
+   As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide),
+   it should work fine. However, if needed to add more than two standards,
+   v4l2-common.c should be fixed.
+ */
+
+/*
+ * Some macros to merge video standards in order to make live easier for the
+ * drivers and V4L2 applications
+ */
+
+/*
+ * "Common" NTSC/M - It should be noticed that V4L2_STD_NTSC_443 is
+ * Missing here.
+ */
+#define V4L2_STD_NTSC           (V4L2_STD_NTSC_M	|\
+				 V4L2_STD_NTSC_M_JP     |\
+				 V4L2_STD_NTSC_M_KR)
+/* Secam macros */
+#define V4L2_STD_SECAM_DK      	(V4L2_STD_SECAM_D	|\
+				 V4L2_STD_SECAM_K	|\
+				 V4L2_STD_SECAM_K1)
+/* All Secam Standards */
+#define V4L2_STD_SECAM		(V4L2_STD_SECAM_B	|\
+				 V4L2_STD_SECAM_G	|\
+				 V4L2_STD_SECAM_H	|\
+				 V4L2_STD_SECAM_DK	|\
+				 V4L2_STD_SECAM_L       |\
+				 V4L2_STD_SECAM_LC)
+/* PAL macros */
+#define V4L2_STD_PAL_BG		(V4L2_STD_PAL_B		|\
+				 V4L2_STD_PAL_B1	|\
+				 V4L2_STD_PAL_G)
+#define V4L2_STD_PAL_DK		(V4L2_STD_PAL_D		|\
+				 V4L2_STD_PAL_D1	|\
+				 V4L2_STD_PAL_K)
+/*
+ * "Common" PAL - This macro is there to be compatible with the old
+ * V4L1 concept of "PAL": /BGDKHI.
+ * Several PAL standards are missing here: /M, /N and /Nc
+ */
+#define V4L2_STD_PAL		(V4L2_STD_PAL_BG	|\
+				 V4L2_STD_PAL_DK	|\
+				 V4L2_STD_PAL_H		|\
+				 V4L2_STD_PAL_I)
+/* Chroma "agnostic" standards */
+#define V4L2_STD_B		(V4L2_STD_PAL_B		|\
+				 V4L2_STD_PAL_B1	|\
+				 V4L2_STD_SECAM_B)
+#define V4L2_STD_G		(V4L2_STD_PAL_G		|\
+				 V4L2_STD_SECAM_G)
+#define V4L2_STD_H		(V4L2_STD_PAL_H		|\
+				 V4L2_STD_SECAM_H)
+#define V4L2_STD_L		(V4L2_STD_SECAM_L	|\
+				 V4L2_STD_SECAM_LC)
+#define V4L2_STD_GH		(V4L2_STD_G		|\
+				 V4L2_STD_H)
+#define V4L2_STD_DK		(V4L2_STD_PAL_DK	|\
+				 V4L2_STD_SECAM_DK)
+#define V4L2_STD_BG		(V4L2_STD_B		|\
+				 V4L2_STD_G)
+#define V4L2_STD_MN		(V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc	|\
+				 V4L2_STD_NTSC)
+
+/* Standards where MTS/BTSC stereo could be found */
+#define V4L2_STD_MTS		(V4L2_STD_NTSC_M	|\
+				 V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc)
+
+/* Standards for Countries with 60Hz Line frequency */
+#define V4L2_STD_525_60		(V4L2_STD_PAL_M		|\
+				 V4L2_STD_PAL_60	|\
+				 V4L2_STD_NTSC		|\
+				 V4L2_STD_NTSC_443)
+/* Standards for Countries with 50Hz Line frequency */
+#define V4L2_STD_625_50		(V4L2_STD_PAL		|\
+				 V4L2_STD_PAL_N		|\
+				 V4L2_STD_PAL_Nc	|\
+				 V4L2_STD_SECAM)
+
+#define V4L2_STD_ATSC           (V4L2_STD_ATSC_8_VSB    |\
+				 V4L2_STD_ATSC_16_VSB)
+/* Macros with none and all analog standards */
+#define V4L2_STD_UNKNOWN        0
+#define V4L2_STD_ALL            (V4L2_STD_525_60	|\
+				 V4L2_STD_625_50)
+
+struct v4l2_standard {
+	__u32		     index;
+	v4l2_std_id          id;
+	__u8		     name[24];
+	struct v4l2_fract    frameperiod; /* Frames, not fields */
+	__u32		     framelines;
+	__u32		     reserved[4];
+};
+
+/*
+ *	D V 	B T	T I M I N G S
+ */
+
+/** struct v4l2_bt_timings - BT.656/BT.1120 timing data
+ * @width:	total width of the active video in pixels
+ * @height:	total height of the active video in lines
+ * @interlaced:	Interlaced or progressive
+ * @polarities:	Positive or negative polarities
+ * @pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @hfrontporch:Horizontal front porch in pixels
+ * @hsync:	Horizontal Sync length in pixels
+ * @hbackporch:	Horizontal back porch in pixels
+ * @vfrontporch:Vertical front porch in lines
+ * @vsync:	Vertical Sync length in lines
+ * @vbackporch:	Vertical back porch in lines
+ * @il_vfrontporch:Vertical front porch for the even field
+ *		(aka field 2) of interlaced field formats
+ * @il_vsync:	Vertical Sync length for the even field
+ *		(aka field 2) of interlaced field formats
+ * @il_vbackporch:Vertical back porch for the even field
+ *		(aka field 2) of interlaced field formats
+ * @standards:	Standards the timing belongs to
+ * @flags:	Flags
+ * @picture_aspect: The picture aspect ratio (hor/vert).
+ * @cea861_vic:	VIC code as per the CEA-861 standard.
+ * @hdmi_vic:	VIC code as per the HDMI standard.
+ * @reserved:	Reserved fields, must be zeroed.
+ *
+ * A note regarding vertical interlaced timings: height refers to the total
+ * height of the active video frame (= two fields). The blanking timings refer
+ * to the blanking of each field. So the height of the total frame is
+ * calculated as follows:
+ *
+ * tot_height = height + vfrontporch + vsync + vbackporch +
+ *                       il_vfrontporch + il_vsync + il_vbackporch
+ *
+ * The active height of each field is height / 2.
+ */
+struct v4l2_bt_timings {
+	__u32	width;
+	__u32	height;
+	__u32	interlaced;
+	__u32	polarities;
+	__u64	pixelclock;
+	__u32	hfrontporch;
+	__u32	hsync;
+	__u32	hbackporch;
+	__u32	vfrontporch;
+	__u32	vsync;
+	__u32	vbackporch;
+	__u32	il_vfrontporch;
+	__u32	il_vsync;
+	__u32	il_vbackporch;
+	__u32	standards;
+	__u32	flags;
+	struct v4l2_fract picture_aspect;
+	__u8	cea861_vic;
+	__u8	hdmi_vic;
+	__u8	reserved[46];
+} __attribute__ ((packed));
+
+/* Interlaced or progressive format */
+#define	V4L2_DV_PROGRESSIVE	0
+#define	V4L2_DV_INTERLACED	1
+
+/* Polarities. If bit is not set, it is assumed to be negative polarity */
+#define V4L2_DV_VSYNC_POS_POL	0x00000001
+#define V4L2_DV_HSYNC_POS_POL	0x00000002
+
+/* Timings standards */
+#define V4L2_DV_BT_STD_CEA861	(1 << 0)  /* CEA-861 Digital TV Profile */
+#define V4L2_DV_BT_STD_DMT	(1 << 1)  /* VESA Discrete Monitor Timings */
+#define V4L2_DV_BT_STD_CVT	(1 << 2)  /* VESA Coordinated Video Timings */
+#define V4L2_DV_BT_STD_GTF	(1 << 3)  /* VESA Generalized Timings Formula */
+#define V4L2_DV_BT_STD_SDI	(1 << 4)  /* SDI Timings */
+
+/* Flags */
+
+/*
+ * CVT/GTF specific: timing uses reduced blanking (CVT) or the 'Secondary
+ * GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
+ * intervals are reduced, allowing a higher resolution over the same
+ * bandwidth. This is a read-only flag.
+ */
+#define V4L2_DV_FL_REDUCED_BLANKING		(1 << 0)
+/*
+ * CEA-861 specific: set for CEA-861 formats with a framerate of a multiple
+ * of six. These formats can be optionally played at 1 / 1.001 speed.
+ * This is a read-only flag.
+ */
+#define V4L2_DV_FL_CAN_REDUCE_FPS		(1 << 1)
+/*
+ * CEA-861 specific: only valid for video transmitters, the flag is cleared
+ * by receivers.
+ * If the framerate of the format is a multiple of six, then the pixelclock
+ * used to set up the transmitter is divided by 1.001 to make it compatible
+ * with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
+ * 29.97 Hz. Otherwise this flag is cleared. If the transmitter can't generate
+ * such frequencies, then the flag will also be cleared.
+ */
+#define V4L2_DV_FL_REDUCED_FPS			(1 << 2)
+/*
+ * Specific to interlaced formats: if set, then field 1 is really one half-line
+ * longer and field 2 is really one half-line shorter, so each field has
+ * exactly the same number of half-lines. Whether half-lines can be detected
+ * or used depends on the hardware.
+ */
+#define V4L2_DV_FL_HALF_LINE			(1 << 3)
+/*
+ * If set, then this is a Consumer Electronics (CE) video format. Such formats
+ * differ from other formats (commonly called IT formats) in that if RGB
+ * encoding is used then by default the RGB values use limited range (i.e.
+ * use the range 16-235) as opposed to 0-255. All formats defined in CEA-861
+ * except for the 640x480 format are CE formats.
+ */
+#define V4L2_DV_FL_IS_CE_VIDEO			(1 << 4)
+/* Some formats like SMPTE-125M have an interlaced signal with a odd
+ * total height. For these formats, if this flag is set, the first
+ * field has the extra line. If not, it is the second field.
+ */
+#define V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE	(1 << 5)
+/*
+ * If set, then the picture_aspect field is valid. Otherwise assume that the
+ * pixels are square, so the picture aspect ratio is the same as the width to
+ * height ratio.
+ */
+#define V4L2_DV_FL_HAS_PICTURE_ASPECT		(1 << 6)
+/*
+ * If set, then the cea861_vic field is valid and contains the Video
+ * Identification Code as per the CEA-861 standard.
+ */
+#define V4L2_DV_FL_HAS_CEA861_VIC		(1 << 7)
+/*
+ * If set, then the hdmi_vic field is valid and contains the Video
+ * Identification Code as per the HDMI standard (HDMI Vendor Specific
+ * InfoFrame).
+ */
+#define V4L2_DV_FL_HAS_HDMI_VIC			(1 << 8)
+
+/* A few useful defines to calculate the total blanking and frame sizes */
+#define V4L2_DV_BT_BLANKING_WIDTH(bt) \
+	((bt)->hfrontporch + (bt)->hsync + (bt)->hbackporch)
+#define V4L2_DV_BT_FRAME_WIDTH(bt) \
+	((bt)->width + V4L2_DV_BT_BLANKING_WIDTH(bt))
+#define V4L2_DV_BT_BLANKING_HEIGHT(bt) \
+	((bt)->vfrontporch + (bt)->vsync + (bt)->vbackporch + \
+	 (bt)->il_vfrontporch + (bt)->il_vsync + (bt)->il_vbackporch)
+#define V4L2_DV_BT_FRAME_HEIGHT(bt) \
+	((bt)->height + V4L2_DV_BT_BLANKING_HEIGHT(bt))
+
+/** struct v4l2_dv_timings - DV timings
+ * @type:	the type of the timings
+ * @bt:	BT656/1120 timings
+ */
+struct v4l2_dv_timings {
+	__u32 type;
+	union {
+		struct v4l2_bt_timings	bt;
+		__u32	reserved[32];
+	};
+} __attribute__ ((packed));
+
+/* Values for the type field */
+#define V4L2_DV_BT_656_1120	0	/* BT.656/1120 timing type */
+
+
+/** struct v4l2_enum_dv_timings - DV timings enumeration
+ * @index:	enumeration index
+ * @pad:	the pad number for which to enumerate timings (used with
+ *		v4l-subdev nodes only)
+ * @reserved:	must be zeroed
+ * @timings:	the timings for the given index
+ */
+struct v4l2_enum_dv_timings {
+	__u32 index;
+	__u32 pad;
+	__u32 reserved[2];
+	struct v4l2_dv_timings timings;
+};
+
+/** struct v4l2_bt_timings_cap - BT.656/BT.1120 timing capabilities
+ * @min_width:		width in pixels
+ * @max_width:		width in pixels
+ * @min_height:		height in lines
+ * @max_height:		height in lines
+ * @min_pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @max_pixelclock:	Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @standards:		Supported standards
+ * @capabilities:	Supported capabilities
+ * @reserved:		Must be zeroed
+ */
+struct v4l2_bt_timings_cap {
+	__u32	min_width;
+	__u32	max_width;
+	__u32	min_height;
+	__u32	max_height;
+	__u64	min_pixelclock;
+	__u64	max_pixelclock;
+	__u32	standards;
+	__u32	capabilities;
+	__u32	reserved[16];
+} __attribute__ ((packed));
+
+/* Supports interlaced formats */
+#define V4L2_DV_BT_CAP_INTERLACED	(1 << 0)
+/* Supports progressive formats */
+#define V4L2_DV_BT_CAP_PROGRESSIVE	(1 << 1)
+/* Supports CVT/GTF reduced blanking */
+#define V4L2_DV_BT_CAP_REDUCED_BLANKING	(1 << 2)
+/* Supports custom formats */
+#define V4L2_DV_BT_CAP_CUSTOM		(1 << 3)
+
+/** struct v4l2_dv_timings_cap - DV timings capabilities
+ * @type:	the type of the timings (same as in struct v4l2_dv_timings)
+ * @pad:	the pad number for which to query capabilities (used with
+ *		v4l-subdev nodes only)
+ * @bt:		the BT656/1120 timings capabilities
+ */
+struct v4l2_dv_timings_cap {
+	__u32 type;
+	__u32 pad;
+	__u32 reserved[2];
+	union {
+		struct v4l2_bt_timings_cap bt;
+		__u32 raw_data[32];
+	};
+};
+
+
+/*
+ *	V I D E O   I N P U T S
+ */
+struct v4l2_input {
+	__u32	     index;		/*  Which input */
+	__u8	     name[32];		/*  Label */
+	__u32	     type;		/*  Type of input */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
+	__u32        tuner;             /*  enum v4l2_tuner_type */
+	v4l2_std_id  std;
+	__u32	     status;
+	__u32	     capabilities;
+	__u32	     reserved[3];
+};
+
+/*  Values for the 'type' field */
+#define V4L2_INPUT_TYPE_TUNER		1
+#define V4L2_INPUT_TYPE_CAMERA		2
+#define V4L2_INPUT_TYPE_TOUCH		3
+
+/* field 'status' - general */
+#define V4L2_IN_ST_NO_POWER    0x00000001  /* Attached device is off */
+#define V4L2_IN_ST_NO_SIGNAL   0x00000002
+#define V4L2_IN_ST_NO_COLOR    0x00000004
+
+/* field 'status' - sensor orientation */
+/* If sensor is mounted upside down set both bits */
+#define V4L2_IN_ST_HFLIP       0x00000010 /* Frames are flipped horizontally */
+#define V4L2_IN_ST_VFLIP       0x00000020 /* Frames are flipped vertically */
+
+/* field 'status' - analog */
+#define V4L2_IN_ST_NO_H_LOCK   0x00000100  /* No horizontal sync lock */
+#define V4L2_IN_ST_COLOR_KILL  0x00000200  /* Color killer is active */
+#define V4L2_IN_ST_NO_V_LOCK   0x00000400  /* No vertical sync lock */
+#define V4L2_IN_ST_NO_STD_LOCK 0x00000800  /* No standard format lock */
+
+/* field 'status' - digital */
+#define V4L2_IN_ST_NO_SYNC     0x00010000  /* No synchronization lock */
+#define V4L2_IN_ST_NO_EQU      0x00020000  /* No equalizer lock */
+#define V4L2_IN_ST_NO_CARRIER  0x00040000  /* Carrier recovery failed */
+
+/* field 'status' - VCR and set-top box */
+#define V4L2_IN_ST_MACROVISION 0x01000000  /* Macrovision detected */
+#define V4L2_IN_ST_NO_ACCESS   0x02000000  /* Conditional access denied */
+#define V4L2_IN_ST_VTR         0x04000000  /* VTR time constant */
+
+/* capabilities flags */
+#define V4L2_IN_CAP_DV_TIMINGS		0x00000002 /* Supports S_DV_TIMINGS */
+#define V4L2_IN_CAP_CUSTOM_TIMINGS	V4L2_IN_CAP_DV_TIMINGS /* For compatibility */
+#define V4L2_IN_CAP_STD			0x00000004 /* Supports S_STD */
+#define V4L2_IN_CAP_NATIVE_SIZE		0x00000008 /* Supports setting native size */
+
+/*
+ *	V I D E O   O U T P U T S
+ */
+struct v4l2_output {
+	__u32	     index;		/*  Which output */
+	__u8	     name[32];		/*  Label */
+	__u32	     type;		/*  Type of output */
+	__u32	     audioset;		/*  Associated audios (bitfield) */
+	__u32	     modulator;         /*  Associated modulator */
+	v4l2_std_id  std;
+	__u32	     capabilities;
+	__u32	     reserved[3];
+};
+/*  Values for the 'type' field */
+#define V4L2_OUTPUT_TYPE_MODULATOR		1
+#define V4L2_OUTPUT_TYPE_ANALOG			2
+#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY	3
+
+/* capabilities flags */
+#define V4L2_OUT_CAP_DV_TIMINGS		0x00000002 /* Supports S_DV_TIMINGS */
+#define V4L2_OUT_CAP_CUSTOM_TIMINGS	V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */
+#define V4L2_OUT_CAP_STD		0x00000004 /* Supports S_STD */
+#define V4L2_OUT_CAP_NATIVE_SIZE	0x00000008 /* Supports setting native size */
+
+/*
+ *	C O N T R O L S
+ */
+struct v4l2_control {
+	__u32		     id;
+	__s32		     value;
+};
+
+struct v4l2_ext_control {
+	__u32 id;
+	__u32 size;
+	__u32 reserved2[1];
+	union {
+		__s32 value;
+		__s64 value64;
+		char __user *string;
+		__u8 __user *p_u8;
+		__u16 __user *p_u16;
+		__u32 __user *p_u32;
+		void __user *ptr;
+	};
+} __attribute__ ((packed));
+
+struct v4l2_ext_controls {
+	union {
+#ifndef __KERNEL__
+		__u32 ctrl_class;
+#endif
+		__u32 which;
+	};
+	__u32 count;
+	__u32 error_idx;
+	__u32 reserved[2];
+	struct v4l2_ext_control *controls;
+};
+
+#define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
+#ifndef __KERNEL__
+#define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
+#endif
+#define V4L2_CTRL_ID2WHICH(id)    ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+#define V4L2_CTRL_MAX_DIMS	  (4)
+#define V4L2_CTRL_WHICH_CUR_VAL   0
+#define V4L2_CTRL_WHICH_DEF_VAL   0x0f000000
+
+enum v4l2_ctrl_type {
+	V4L2_CTRL_TYPE_INTEGER	     = 1,
+	V4L2_CTRL_TYPE_BOOLEAN	     = 2,
+	V4L2_CTRL_TYPE_MENU	     = 3,
+	V4L2_CTRL_TYPE_BUTTON	     = 4,
+	V4L2_CTRL_TYPE_INTEGER64     = 5,
+	V4L2_CTRL_TYPE_CTRL_CLASS    = 6,
+	V4L2_CTRL_TYPE_STRING        = 7,
+	V4L2_CTRL_TYPE_BITMASK       = 8,
+	V4L2_CTRL_TYPE_INTEGER_MENU  = 9,
+
+	/* Compound types are >= 0x0100 */
+	V4L2_CTRL_COMPOUND_TYPES     = 0x0100,
+	V4L2_CTRL_TYPE_U8	     = 0x0100,
+	V4L2_CTRL_TYPE_U16	     = 0x0101,
+	V4L2_CTRL_TYPE_U32	     = 0x0102,
+};
+
+/*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
+struct v4l2_queryctrl {
+	__u32		     id;
+	__u32		     type;	/* enum v4l2_ctrl_type */
+	__u8		     name[32];	/* Whatever */
+	__s32		     minimum;	/* Note signedness */
+	__s32		     maximum;
+	__s32		     step;
+	__s32		     default_value;
+	__u32                flags;
+	__u32		     reserved[2];
+};
+
+/*  Used in the VIDIOC_QUERY_EXT_CTRL ioctl for querying extended controls */
+struct v4l2_query_ext_ctrl {
+	__u32		     id;
+	__u32		     type;
+	char		     name[32];
+	__s64		     minimum;
+	__s64		     maximum;
+	__u64		     step;
+	__s64		     default_value;
+	__u32                flags;
+	__u32                elem_size;
+	__u32                elems;
+	__u32                nr_of_dims;
+	__u32                dims[V4L2_CTRL_MAX_DIMS];
+	__u32		     reserved[32];
+};
+
+/*  Used in the VIDIOC_QUERYMENU ioctl for querying menu items */
+struct v4l2_querymenu {
+	__u32		id;
+	__u32		index;
+	union {
+		__u8	name[32];	/* Whatever */
+		__s64	value;
+	};
+	__u32		reserved;
+} __attribute__ ((packed));
+
+/*  Control flags  */
+#define V4L2_CTRL_FLAG_DISABLED		0x0001
+#define V4L2_CTRL_FLAG_GRABBED		0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY 	0x0004
+#define V4L2_CTRL_FLAG_UPDATE 		0x0008
+#define V4L2_CTRL_FLAG_INACTIVE 	0x0010
+#define V4L2_CTRL_FLAG_SLIDER 		0x0020
+#define V4L2_CTRL_FLAG_WRITE_ONLY 	0x0040
+#define V4L2_CTRL_FLAG_VOLATILE		0x0080
+#define V4L2_CTRL_FLAG_HAS_PAYLOAD	0x0100
+#define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE	0x0200
+#define V4L2_CTRL_FLAG_MODIFY_LAYOUT	0x0400
+
+/*  Query flags, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL	0x80000000
+#define V4L2_CTRL_FLAG_NEXT_COMPOUND	0x40000000
+
+/*  User-class control IDs defined by V4L2 */
+#define V4L2_CID_MAX_CTRLS		1024
+/*  IDs reserved for driver specific controls */
+#define V4L2_CID_PRIVATE_BASE		0x08000000
+
+
+/*
+ *	T U N I N G
+ */
+struct v4l2_tuner {
+	__u32                   index;
+	__u8			name[32];
+	__u32			type;	/* enum v4l2_tuner_type */
+	__u32			capability;
+	__u32			rangelow;
+	__u32			rangehigh;
+	__u32			rxsubchans;
+	__u32			audmode;
+	__s32			signal;
+	__s32			afc;
+	__u32			reserved[4];
+};
+
+struct v4l2_modulator {
+	__u32			index;
+	__u8			name[32];
+	__u32			capability;
+	__u32			rangelow;
+	__u32			rangehigh;
+	__u32			txsubchans;
+	__u32			type;	/* enum v4l2_tuner_type */
+	__u32			reserved[3];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_TUNER_CAP_LOW		0x0001
+#define V4L2_TUNER_CAP_NORM		0x0002
+#define V4L2_TUNER_CAP_HWSEEK_BOUNDED	0x0004
+#define V4L2_TUNER_CAP_HWSEEK_WRAP	0x0008
+#define V4L2_TUNER_CAP_STEREO		0x0010
+#define V4L2_TUNER_CAP_LANG2		0x0020
+#define V4L2_TUNER_CAP_SAP		0x0020
+#define V4L2_TUNER_CAP_LANG1		0x0040
+#define V4L2_TUNER_CAP_RDS		0x0080
+#define V4L2_TUNER_CAP_RDS_BLOCK_IO	0x0100
+#define V4L2_TUNER_CAP_RDS_CONTROLS	0x0200
+#define V4L2_TUNER_CAP_FREQ_BANDS	0x0400
+#define V4L2_TUNER_CAP_HWSEEK_PROG_LIM	0x0800
+#define V4L2_TUNER_CAP_1HZ		0x1000
+
+/*  Flags for the 'rxsubchans' field */
+#define V4L2_TUNER_SUB_MONO		0x0001
+#define V4L2_TUNER_SUB_STEREO		0x0002
+#define V4L2_TUNER_SUB_LANG2		0x0004
+#define V4L2_TUNER_SUB_SAP		0x0004
+#define V4L2_TUNER_SUB_LANG1		0x0008
+#define V4L2_TUNER_SUB_RDS		0x0010
+
+/*  Values for the 'audmode' field */
+#define V4L2_TUNER_MODE_MONO		0x0000
+#define V4L2_TUNER_MODE_STEREO		0x0001
+#define V4L2_TUNER_MODE_LANG2		0x0002
+#define V4L2_TUNER_MODE_SAP		0x0002
+#define V4L2_TUNER_MODE_LANG1		0x0003
+#define V4L2_TUNER_MODE_LANG1_LANG2	0x0004
+
+struct v4l2_frequency {
+	__u32	tuner;
+	__u32	type;	/* enum v4l2_tuner_type */
+	__u32	frequency;
+	__u32	reserved[8];
+};
+
+#define V4L2_BAND_MODULATION_VSB	(1 << 1)
+#define V4L2_BAND_MODULATION_FM		(1 << 2)
+#define V4L2_BAND_MODULATION_AM		(1 << 3)
+
+struct v4l2_frequency_band {
+	__u32	tuner;
+	__u32	type;	/* enum v4l2_tuner_type */
+	__u32	index;
+	__u32	capability;
+	__u32	rangelow;
+	__u32	rangehigh;
+	__u32	modulation;
+	__u32	reserved[9];
+};
+
+struct v4l2_hw_freq_seek {
+	__u32	tuner;
+	__u32	type;	/* enum v4l2_tuner_type */
+	__u32	seek_upward;
+	__u32	wrap_around;
+	__u32	spacing;
+	__u32	rangelow;
+	__u32	rangehigh;
+	__u32	reserved[5];
+};
+
+/*
+ *	R D S
+ */
+
+struct v4l2_rds_data {
+	__u8 	lsb;
+	__u8 	msb;
+	__u8 	block;
+} __attribute__ ((packed));
+
+#define V4L2_RDS_BLOCK_MSK 	 0x7
+#define V4L2_RDS_BLOCK_A 	 0
+#define V4L2_RDS_BLOCK_B 	 1
+#define V4L2_RDS_BLOCK_C 	 2
+#define V4L2_RDS_BLOCK_D 	 3
+#define V4L2_RDS_BLOCK_C_ALT 	 4
+#define V4L2_RDS_BLOCK_INVALID 	 7
+
+#define V4L2_RDS_BLOCK_CORRECTED 0x40
+#define V4L2_RDS_BLOCK_ERROR 	 0x80
+
+/*
+ *	A U D I O
+ */
+struct v4l2_audio {
+	__u32	index;
+	__u8	name[32];
+	__u32	capability;
+	__u32	mode;
+	__u32	reserved[2];
+};
+
+/*  Flags for the 'capability' field */
+#define V4L2_AUDCAP_STEREO		0x00001
+#define V4L2_AUDCAP_AVL			0x00002
+
+/*  Flags for the 'mode' field */
+#define V4L2_AUDMODE_AVL		0x00001
+
+struct v4l2_audioout {
+	__u32	index;
+	__u8	name[32];
+	__u32	capability;
+	__u32	mode;
+	__u32	reserved[2];
+};
+
+/*
+ *	M P E G   S E R V I C E S
+ */
+#if 1
+#define V4L2_ENC_IDX_FRAME_I    (0)
+#define V4L2_ENC_IDX_FRAME_P    (1)
+#define V4L2_ENC_IDX_FRAME_B    (2)
+#define V4L2_ENC_IDX_FRAME_MASK (0xf)
+
+struct v4l2_enc_idx_entry {
+	__u64 offset;
+	__u64 pts;
+	__u32 length;
+	__u32 flags;
+	__u32 reserved[2];
+};
+
+#define V4L2_ENC_IDX_ENTRIES (64)
+struct v4l2_enc_idx {
+	__u32 entries;
+	__u32 entries_cap;
+	__u32 reserved[4];
+	struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES];
+};
+
+
+#define V4L2_ENC_CMD_START      (0)
+#define V4L2_ENC_CMD_STOP       (1)
+#define V4L2_ENC_CMD_PAUSE      (2)
+#define V4L2_ENC_CMD_RESUME     (3)
+
+/* Flags for V4L2_ENC_CMD_STOP */
+#define V4L2_ENC_CMD_STOP_AT_GOP_END    (1 << 0)
+
+struct v4l2_encoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u32 data[8];
+		} raw;
+	};
+};
+
+/* Decoder commands */
+#define V4L2_DEC_CMD_START       (0)
+#define V4L2_DEC_CMD_STOP        (1)
+#define V4L2_DEC_CMD_PAUSE       (2)
+#define V4L2_DEC_CMD_RESUME      (3)
+
+/* Flags for V4L2_DEC_CMD_START */
+#define V4L2_DEC_CMD_START_MUTE_AUDIO	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_PAUSE */
+#define V4L2_DEC_CMD_PAUSE_TO_BLACK	(1 << 0)
+
+/* Flags for V4L2_DEC_CMD_STOP */
+#define V4L2_DEC_CMD_STOP_TO_BLACK	(1 << 0)
+#define V4L2_DEC_CMD_STOP_IMMEDIATELY	(1 << 1)
+
+/* Play format requirements (returned by the driver): */
+
+/* The decoder has no special format requirements */
+#define V4L2_DEC_START_FMT_NONE		(0)
+/* The decoder requires full GOPs */
+#define V4L2_DEC_START_FMT_GOP		(1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct v4l2_decoder_cmd {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} start;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
+#endif
+
+
+/*
+ *	D A T A   S E R V I C E S   ( V B I )
+ *
+ *	Data services API by Michael Schimek
+ */
+
+/* Raw VBI */
+struct v4l2_vbi_format {
+	__u32	sampling_rate;		/* in 1 Hz */
+	__u32	offset;
+	__u32	samples_per_line;
+	__u32	sample_format;		/* V4L2_PIX_FMT_* */
+	__s32	start[2];
+	__u32	count[2];
+	__u32	flags;			/* V4L2_VBI_* */
+	__u32	reserved[2];		/* must be zero */
+};
+
+/*  VBI flags  */
+#define V4L2_VBI_UNSYNC		(1 << 0)
+#define V4L2_VBI_INTERLACED	(1 << 1)
+
+/* ITU-R start lines for each field */
+#define V4L2_VBI_ITU_525_F1_START (1)
+#define V4L2_VBI_ITU_525_F2_START (264)
+#define V4L2_VBI_ITU_625_F1_START (1)
+#define V4L2_VBI_ITU_625_F2_START (314)
+
+/* Sliced VBI
+ *
+ *    This implements is a proposal V4L2 API to allow SLICED VBI
+ * required for some hardware encoders. It should change without
+ * notice in the definitive implementation.
+ */
+
+struct v4l2_sliced_vbi_format {
+	__u16   service_set;
+	/* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+	   service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+				 (equals frame lines 313-336 for 625 line video
+				  standards, 263-286 for 525 line standards) */
+	__u16   service_lines[2][24];
+	__u32   io_size;
+	__u32   reserved[2];            /* must be zero */
+};
+
+/* Teletext World System Teletext
+   (WST), defined on ITU-R BT.653-2 */
+#define V4L2_SLICED_TELETEXT_B          (0x0001)
+/* Video Program System, defined on ETS 300 231*/
+#define V4L2_SLICED_VPS                 (0x0400)
+/* Closed Caption, defined on EIA-608 */
+#define V4L2_SLICED_CAPTION_525         (0x1000)
+/* Wide Screen System, defined on ITU-R BT1119.1 */
+#define V4L2_SLICED_WSS_625             (0x4000)
+
+#define V4L2_SLICED_VBI_525             (V4L2_SLICED_CAPTION_525)
+#define V4L2_SLICED_VBI_625             (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625)
+
+struct v4l2_sliced_vbi_cap {
+	__u16   service_set;
+	/* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field
+	   service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field
+				 (equals frame lines 313-336 for 625 line video
+				  standards, 263-286 for 525 line standards) */
+	__u16   service_lines[2][24];
+	__u32	type;		/* enum v4l2_buf_type */
+	__u32   reserved[3];    /* must be 0 */
+};
+
+struct v4l2_sliced_vbi_data {
+	__u32   id;
+	__u32   field;          /* 0: first field, 1: second field */
+	__u32   line;           /* 1-23 */
+	__u32   reserved;       /* must be 0 */
+	__u8    data[48];
+};
+
+/*
+ * Sliced VBI data inserted into MPEG Streams
+ */
+
+/*
+ * V4L2_MPEG_STREAM_VBI_FMT_IVTV:
+ *
+ * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an
+ * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI
+ * data
+ *
+ * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header
+ * definitions are not included here.  See the MPEG-2 specifications for details
+ * on these headers.
+ */
+
+/* Line type IDs */
+#define V4L2_MPEG_VBI_IVTV_TELETEXT_B     (1)
+#define V4L2_MPEG_VBI_IVTV_CAPTION_525    (4)
+#define V4L2_MPEG_VBI_IVTV_WSS_625        (5)
+#define V4L2_MPEG_VBI_IVTV_VPS            (7)
+
+struct v4l2_mpeg_vbi_itv0_line {
+	__u8 id;	/* One of V4L2_MPEG_VBI_IVTV_* above */
+	__u8 data[42];	/* Sliced VBI data for the line */
+} __attribute__ ((packed));
+
+struct v4l2_mpeg_vbi_itv0 {
+	__le32 linemask[2]; /* Bitmasks of VBI service lines present */
+	struct v4l2_mpeg_vbi_itv0_line line[35];
+} __attribute__ ((packed));
+
+struct v4l2_mpeg_vbi_ITV0 {
+	struct v4l2_mpeg_vbi_itv0_line line[36];
+} __attribute__ ((packed));
+
+#define V4L2_MPEG_VBI_IVTV_MAGIC0	"itv0"
+#define V4L2_MPEG_VBI_IVTV_MAGIC1	"ITV0"
+
+struct v4l2_mpeg_vbi_fmt_ivtv {
+	__u8 magic[4];
+	union {
+		struct v4l2_mpeg_vbi_itv0 itv0;
+		struct v4l2_mpeg_vbi_ITV0 ITV0;
+	};
+} __attribute__ ((packed));
+
+/*
+ *	A G G R E G A T E   S T R U C T U R E S
+ */
+
+/**
+ * struct v4l2_plane_pix_format - additional, per-plane format definition
+ * @sizeimage:		maximum size in bytes required for data, for which
+ *			this plane will be used
+ * @bytesperline:	distance in bytes between the leftmost pixels in two
+ *			adjacent lines
+ */
+struct v4l2_plane_pix_format {
+	__u32		sizeimage;
+	__u32		bytesperline;
+	__u16		reserved[6];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_pix_format_mplane - multiplanar format definition
+ * @width:		image width in pixels
+ * @height:		image height in pixels
+ * @pixelformat:	little endian four character code (fourcc)
+ * @field:		enum v4l2_field; field order (for interlaced video)
+ * @colorspace:		enum v4l2_colorspace; supplemental to pixelformat
+ * @plane_fmt:		per-plane information
+ * @num_planes:		number of planes for this format
+ * @flags:		format flags (V4L2_PIX_FMT_FLAG_*)
+ * @ycbcr_enc:		enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization:	enum v4l2_quantization, colorspace quantization
+ * @xfer_func:		enum v4l2_xfer_func, colorspace transfer function
+ */
+struct v4l2_pix_format_mplane {
+	__u32				width;
+	__u32				height;
+	__u32				pixelformat;
+	__u32				field;
+	__u32				colorspace;
+
+	struct v4l2_plane_pix_format	plane_fmt[VIDEO_MAX_PLANES];
+	__u8				num_planes;
+	__u8				flags;
+	 union {
+		__u8				ycbcr_enc;
+		__u8				hsv_enc;
+	};
+	__u8				quantization;
+	__u8				xfer_func;
+	__u8				reserved[7];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_sdr_format - SDR format definition
+ * @pixelformat:	little endian four character code (fourcc)
+ * @buffersize:		maximum size in bytes required for data
+ */
+struct v4l2_sdr_format {
+	__u32				pixelformat;
+	__u32				buffersize;
+	__u8				reserved[24];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_meta_format - metadata format definition
+ * @dataformat:		little endian four character code (fourcc)
+ * @buffersize:		maximum size in bytes required for data
+ */
+struct v4l2_meta_format {
+	__u32				dataformat;
+	__u32				buffersize;
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_format - stream data format
+ * @type:	enum v4l2_buf_type; type of the data stream
+ * @pix:	definition of an image format
+ * @pix_mp:	definition of a multiplanar image format
+ * @win:	definition of an overlaid image
+ * @vbi:	raw VBI capture or output parameters
+ * @sliced:	sliced VBI capture or output parameters
+ * @raw_data:	placeholder for future extensions and custom formats
+ */
+struct v4l2_format {
+	__u32	 type;
+	union {
+		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
+		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
+		struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
+		struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
+		struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
+		struct v4l2_sdr_format		sdr;     /* V4L2_BUF_TYPE_SDR_CAPTURE */
+		struct v4l2_meta_format		meta;    /* V4L2_BUF_TYPE_META_CAPTURE */
+		__u8	raw_data[200];                   /* user-defined */
+	} fmt;
+};
+
+/*	Stream type-dependent parameters
+ */
+struct v4l2_streamparm {
+	__u32	 type;			/* enum v4l2_buf_type */
+	union {
+		struct v4l2_captureparm	capture;
+		struct v4l2_outputparm	output;
+		__u8	raw_data[200];  /* user-defined */
+	} parm;
+};
+
+/*
+ *	E V E N T S
+ */
+
+#define V4L2_EVENT_ALL				0
+#define V4L2_EVENT_VSYNC			1
+#define V4L2_EVENT_EOS				2
+#define V4L2_EVENT_CTRL				3
+#define V4L2_EVENT_FRAME_SYNC			4
+#define V4L2_EVENT_SOURCE_CHANGE		5
+#define V4L2_EVENT_MOTION_DET			6
+#define V4L2_EVENT_PRIVATE_START		0x08000000
+
+/* Payload for V4L2_EVENT_VSYNC */
+struct v4l2_event_vsync {
+	/* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
+	__u8 field;
+} __attribute__ ((packed));
+
+/* Payload for V4L2_EVENT_CTRL */
+#define V4L2_EVENT_CTRL_CH_VALUE		(1 << 0)
+#define V4L2_EVENT_CTRL_CH_FLAGS		(1 << 1)
+#define V4L2_EVENT_CTRL_CH_RANGE		(1 << 2)
+
+struct v4l2_event_ctrl {
+	__u32 changes;
+	__u32 type;
+	union {
+		__s32 value;
+		__s64 value64;
+	};
+	__u32 flags;
+	__s32 minimum;
+	__s32 maximum;
+	__s32 step;
+	__s32 default_value;
+};
+
+struct v4l2_event_frame_sync {
+	__u32 frame_sequence;
+};
+
+#define V4L2_EVENT_SRC_CH_RESOLUTION		(1 << 0)
+
+struct v4l2_event_src_change {
+	__u32 changes;
+};
+
+#define V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ	(1 << 0)
+
+/**
+ * struct v4l2_event_motion_det - motion detection event
+ * @flags:             if V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ is set, then the
+ *                     frame_sequence field is valid.
+ * @frame_sequence:    the frame sequence number associated with this event.
+ * @region_mask:       which regions detected motion.
+ */
+struct v4l2_event_motion_det {
+	__u32 flags;
+	__u32 frame_sequence;
+	__u32 region_mask;
+};
+
+struct v4l2_event {
+	__u32				type;
+	union {
+		struct v4l2_event_vsync		vsync;
+		struct v4l2_event_ctrl		ctrl;
+		struct v4l2_event_frame_sync	frame_sync;
+		struct v4l2_event_src_change	src_change;
+		struct v4l2_event_motion_det	motion_det;
+		__u8				data[64];
+	} u;
+	__u32				pending;
+	__u32				sequence;
+	struct timespec			timestamp;
+	__u32				id;
+	__u32				reserved[8];
+};
+
+#define V4L2_EVENT_SUB_FL_SEND_INITIAL		(1 << 0)
+#define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK	(1 << 1)
+
+struct v4l2_event_subscription {
+	__u32				type;
+	__u32				id;
+	__u32				flags;
+	__u32				reserved[5];
+};
+
+/*
+ *	A D V A N C E D   D E B U G G I N G
+ *
+ *	NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
+ *	FOR DEBUGGING, TESTING AND INTERNAL USE ONLY!
+ */
+
+/* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */
+
+#define V4L2_CHIP_MATCH_BRIDGE      0  /* Match against chip ID on the bridge (0 for the bridge) */
+#define V4L2_CHIP_MATCH_SUBDEV      4  /* Match against subdev index */
+
+/* The following four defines are no longer in use */
+#define V4L2_CHIP_MATCH_HOST V4L2_CHIP_MATCH_BRIDGE
+#define V4L2_CHIP_MATCH_I2C_DRIVER  1  /* Match against I2C driver name */
+#define V4L2_CHIP_MATCH_I2C_ADDR    2  /* Match against I2C 7-bit address */
+#define V4L2_CHIP_MATCH_AC97        3  /* Match against ancillary AC97 chip */
+
+struct v4l2_dbg_match {
+	__u32 type; /* Match type */
+	union {     /* Match this chip, meaning determined by type */
+		__u32 addr;
+		char name[32];
+	};
+} __attribute__ ((packed));
+
+struct v4l2_dbg_register {
+	struct v4l2_dbg_match match;
+	__u32 size;	/* register size in bytes */
+	__u64 reg;
+	__u64 val;
+} __attribute__ ((packed));
+
+#define V4L2_CHIP_FL_READABLE (1 << 0)
+#define V4L2_CHIP_FL_WRITABLE (1 << 1)
+
+/* VIDIOC_DBG_G_CHIP_INFO */
+struct v4l2_dbg_chip_info {
+	struct v4l2_dbg_match match;
+	char name[32];
+	__u32 flags;
+	__u32 reserved[32];
+} __attribute__ ((packed));
+
+/**
+ * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument
+ * @index:	on return, index of the first created buffer
+ * @count:	entry: number of requested buffers,
+ *		return: number of created buffers
+ * @memory:	enum v4l2_memory; buffer memory type
+ * @format:	frame format, for which buffers are requested
+ * @reserved:	future extensions
+ */
+struct v4l2_create_buffers {
+	__u32			index;
+	__u32			count;
+	__u32			memory;
+	struct v4l2_format	format;
+	__u32			reserved[8];
+};
+
+/*
+ *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
+ *
+ */
+#define VIDIOC_QUERYCAP		 _IOR('V',  0, struct v4l2_capability)
+#define VIDIOC_RESERVED		  _IO('V',  1)
+#define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct v4l2_fmtdesc)
+#define VIDIOC_G_FMT		_IOWR('V',  4, struct v4l2_format)
+#define VIDIOC_S_FMT		_IOWR('V',  5, struct v4l2_format)
+#define VIDIOC_REQBUFS		_IOWR('V',  8, struct v4l2_requestbuffers)
+#define VIDIOC_QUERYBUF		_IOWR('V',  9, struct v4l2_buffer)
+#define VIDIOC_G_FBUF		 _IOR('V', 10, struct v4l2_framebuffer)
+#define VIDIOC_S_FBUF		 _IOW('V', 11, struct v4l2_framebuffer)
+#define VIDIOC_OVERLAY		 _IOW('V', 14, int)
+#define VIDIOC_QBUF		_IOWR('V', 15, struct v4l2_buffer)
+#define VIDIOC_EXPBUF		_IOWR('V', 16, struct v4l2_exportbuffer)
+#define VIDIOC_DQBUF		_IOWR('V', 17, struct v4l2_buffer)
+#define VIDIOC_STREAMON		 _IOW('V', 18, int)
+#define VIDIOC_STREAMOFF	 _IOW('V', 19, int)
+#define VIDIOC_G_PARM		_IOWR('V', 21, struct v4l2_streamparm)
+#define VIDIOC_S_PARM		_IOWR('V', 22, struct v4l2_streamparm)
+#define VIDIOC_G_STD		 _IOR('V', 23, v4l2_std_id)
+#define VIDIOC_S_STD		 _IOW('V', 24, v4l2_std_id)
+#define VIDIOC_ENUMSTD		_IOWR('V', 25, struct v4l2_standard)
+#define VIDIOC_ENUMINPUT	_IOWR('V', 26, struct v4l2_input)
+#define VIDIOC_G_CTRL		_IOWR('V', 27, struct v4l2_control)
+#define VIDIOC_S_CTRL		_IOWR('V', 28, struct v4l2_control)
+#define VIDIOC_G_TUNER		_IOWR('V', 29, struct v4l2_tuner)
+#define VIDIOC_S_TUNER		 _IOW('V', 30, struct v4l2_tuner)
+#define VIDIOC_G_AUDIO		 _IOR('V', 33, struct v4l2_audio)
+#define VIDIOC_S_AUDIO		 _IOW('V', 34, struct v4l2_audio)
+#define VIDIOC_QUERYCTRL	_IOWR('V', 36, struct v4l2_queryctrl)
+#define VIDIOC_QUERYMENU	_IOWR('V', 37, struct v4l2_querymenu)
+#define VIDIOC_G_INPUT		 _IOR('V', 38, int)
+#define VIDIOC_S_INPUT		_IOWR('V', 39, int)
+#define VIDIOC_G_EDID		_IOWR('V', 40, struct v4l2_edid)
+#define VIDIOC_S_EDID		_IOWR('V', 41, struct v4l2_edid)
+#define VIDIOC_G_OUTPUT		 _IOR('V', 46, int)
+#define VIDIOC_S_OUTPUT		_IOWR('V', 47, int)
+#define VIDIOC_ENUMOUTPUT	_IOWR('V', 48, struct v4l2_output)
+#define VIDIOC_G_AUDOUT		 _IOR('V', 49, struct v4l2_audioout)
+#define VIDIOC_S_AUDOUT		 _IOW('V', 50, struct v4l2_audioout)
+#define VIDIOC_G_MODULATOR	_IOWR('V', 54, struct v4l2_modulator)
+#define VIDIOC_S_MODULATOR	 _IOW('V', 55, struct v4l2_modulator)
+#define VIDIOC_G_FREQUENCY	_IOWR('V', 56, struct v4l2_frequency)
+#define VIDIOC_S_FREQUENCY	 _IOW('V', 57, struct v4l2_frequency)
+#define VIDIOC_CROPCAP		_IOWR('V', 58, struct v4l2_cropcap)
+#define VIDIOC_G_CROP		_IOWR('V', 59, struct v4l2_crop)
+#define VIDIOC_S_CROP		 _IOW('V', 60, struct v4l2_crop)
+#define VIDIOC_G_JPEGCOMP	 _IOR('V', 61, struct v4l2_jpegcompression)
+#define VIDIOC_S_JPEGCOMP	 _IOW('V', 62, struct v4l2_jpegcompression)
+#define VIDIOC_QUERYSTD      	 _IOR('V', 63, v4l2_std_id)
+#define VIDIOC_TRY_FMT      	_IOWR('V', 64, struct v4l2_format)
+#define VIDIOC_ENUMAUDIO	_IOWR('V', 65, struct v4l2_audio)
+#define VIDIOC_ENUMAUDOUT	_IOWR('V', 66, struct v4l2_audioout)
+#define VIDIOC_G_PRIORITY	 _IOR('V', 67, __u32) /* enum v4l2_priority */
+#define VIDIOC_S_PRIORITY	 _IOW('V', 68, __u32) /* enum v4l2_priority */
+#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap)
+#define VIDIOC_LOG_STATUS         _IO('V', 70)
+#define VIDIOC_G_EXT_CTRLS	_IOWR('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS	_IOWR('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS	_IOWR('V', 73, struct v4l2_ext_controls)
+#define VIDIOC_ENUM_FRAMESIZES	_IOWR('V', 74, struct v4l2_frmsizeenum)
+#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum)
+#define VIDIOC_G_ENC_INDEX       _IOR('V', 76, struct v4l2_enc_idx)
+#define VIDIOC_ENCODER_CMD      _IOWR('V', 77, struct v4l2_encoder_cmd)
+#define VIDIOC_TRY_ENCODER_CMD  _IOWR('V', 78, struct v4l2_encoder_cmd)
+
+/*
+ * Experimental, meant for debugging, testing and internal use.
+ * Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
+ * You must be root to use these ioctls. Never use these in applications!
+ */
+#define	VIDIOC_DBG_S_REGISTER 	 _IOW('V', 79, struct v4l2_dbg_register)
+#define	VIDIOC_DBG_G_REGISTER 	_IOWR('V', 80, struct v4l2_dbg_register)
+
+#define VIDIOC_S_HW_FREQ_SEEK	 _IOW('V', 82, struct v4l2_hw_freq_seek)
+#define	VIDIOC_S_DV_TIMINGS	_IOWR('V', 87, struct v4l2_dv_timings)
+#define	VIDIOC_G_DV_TIMINGS	_IOWR('V', 88, struct v4l2_dv_timings)
+#define	VIDIOC_DQEVENT		 _IOR('V', 89, struct v4l2_event)
+#define	VIDIOC_SUBSCRIBE_EVENT	 _IOW('V', 90, struct v4l2_event_subscription)
+#define	VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)
+#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
+#define VIDIOC_PREPARE_BUF	_IOWR('V', 93, struct v4l2_buffer)
+#define VIDIOC_G_SELECTION	_IOWR('V', 94, struct v4l2_selection)
+#define VIDIOC_S_SELECTION	_IOWR('V', 95, struct v4l2_selection)
+#define VIDIOC_DECODER_CMD	_IOWR('V', 96, struct v4l2_decoder_cmd)
+#define VIDIOC_TRY_DECODER_CMD	_IOWR('V', 97, struct v4l2_decoder_cmd)
+#define VIDIOC_ENUM_DV_TIMINGS  _IOWR('V', 98, struct v4l2_enum_dv_timings)
+#define VIDIOC_QUERY_DV_TIMINGS  _IOR('V', 99, struct v4l2_dv_timings)
+#define VIDIOC_DV_TIMINGS_CAP   _IOWR('V', 100, struct v4l2_dv_timings_cap)
+#define VIDIOC_ENUM_FREQ_BANDS	_IOWR('V', 101, struct v4l2_frequency_band)
+
+/*
+ * Experimental, meant for debugging, testing and internal use.
+ * Never use this in applications!
+ */
+#define VIDIOC_DBG_G_CHIP_INFO  _IOWR('V', 102, struct v4l2_dbg_chip_info)
+
+#define VIDIOC_QUERY_EXT_CTRL	_IOWR('V', 103, struct v4l2_query_ext_ctrl)
+
+/* Reminder: when adding new ioctls please add support for them to
+   drivers/media/v4l2-core/v4l2-compat-ioctl32.c as well! */
+
+#define BASE_VIDIOC_PRIVATE	192		/* 192-255 are private */
+
+#endif /* _UAPI__LINUX_VIDEODEV2_H */
diff --git a/configure b/configure
index ed94de0..650c8fb 100755
--- a/configure
+++ b/configure
@@ -10,7 +10,6 @@ 
 # Prevent locale nonsense from breaking basic text processing.
 LC_ALL=C
 export LC_ALL
-
 # make sure we are running under a compatible shell
 # try to make this part work with most shells
 
@@ -149,6 +148,7 @@  Component options:
   --disable-pixelutils     disable pixel utils in libavutil
 
 Individual component options:
+  --disable-v4l2_m2m       disable V4L2 mem2mem code [autodetect]
   --disable-everything     disable all components listed below
   --disable-encoder=NAME   disable encoder NAME
   --enable-encoder=NAME    enable encoder NAME
@@ -1432,6 +1432,7 @@  AVCODEC_COMPONENTS="
 
 AVDEVICE_COMPONENTS="
     indevs
+    v4l2_m2m
     outdevs
 "
 AVFILTER_COMPONENTS="
@@ -2269,11 +2270,12 @@  map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM
 
 loongson2_deps="mips"
 loongson3_deps="mips"
-v4l2_deps_any="linux_videodev2_h sys_videoio_h"
+v4l2_m2m_select="v4l2"
 mipsfpu_deps="mips"
 mipsdsp_deps="mips"
 mipsdspr2_deps="mips"
 mips32r2_deps="mips"
+vc1_v4l2m2m_decoder_deps="v4l2_m2m"
 mips32r5_deps="mips"
 mips32r6_deps="mips"
 mips64r2_deps="mips"
@@ -2284,6 +2286,9 @@  mmi_deps="mips"
 altivec_deps="ppc"
 dcbzl_deps="ppc"
 ldbrx_deps="ppc"
+vp8_v4l2m2m_decoder_deps="v4l2_m2m"
+vp8_v4l2m2m_encoder_deps="v4l2_m2m"
+vp9_v4l2m2m_decoder_deps="v4l2_m2m"
 ppc4xx_deps="ppc"
 vsx_deps="altivec"
 power8_deps="vsx"
@@ -2437,15 +2442,22 @@  h261_decoder_select="mpegvideo"
 h261_encoder_select="aandcttables mpegvideoenc"
 h263_decoder_select="h263_parser h263dsp mpegvideo qpeldsp"
 h263_encoder_select="aandcttables h263dsp mpegvideoenc"
+h263_v4l2m2m_decoder_deps="v4l2_m2m"
+h263_v4l2m2m_encoder_deps="v4l2_m2m"
 h263i_decoder_select="h263_decoder"
 h263p_decoder_select="h263_decoder"
 h263p_encoder_select="h263_encoder"
 h264_decoder_select="cabac golomb h264chroma h264dsp h264parse h264pred h264qpel videodsp"
 h264_decoder_suggest="error_resilience"
+h264_v4l2m2m_decoder_deps="v4l2_m2m"
+h264_v4l2m2m_encoder_deps="v4l2_m2m"
 hap_decoder_select="snappy texturedsp"
 hap_encoder_deps="libsnappy"
 hap_encoder_select="texturedspenc"
 hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp"
+hevc_encoder_select="hevc_v4l2m2m"
+hevc_v4l2m2m_decoder_deps="v4l2_m2m"
+hevc_v4l2m2m_encoder_deps="v4l2_m2m"
 huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp"
 huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp"
 iac_decoder_select="imc_decoder"
@@ -2482,6 +2494,7 @@  mpc7_decoder_select="bswapdsp mpegaudiodsp"
 mpc8_decoder_select="mpegaudiodsp"
 mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h"
 mpeg_xvmc_decoder_select="mpeg2video_decoder"
+mpeg1_v4l2m2m_decoder_deps="v4l2_m2m"
 mpegvideo_decoder_select="mpegvideo"
 mpeg1video_decoder_select="mpegvideo"
 mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp"
@@ -2489,6 +2502,8 @@  mpeg2video_decoder_select="mpegvideo"
 mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp"
 mpeg4_decoder_select="h263_decoder mpeg4video_parser"
 mpeg4_encoder_select="h263_encoder"
+mpeg4_v4l2m2m_decoder_deps="v4l2_m2m"
+mpeg4_v4l2m2m_encoder_deps="v4l2_m2m"
 msa1_decoder_select="mss34dsp"
 mscc_decoder_select="zlib"
 msmpeg4v1_decoder_select="h263_decoder"
@@ -3042,7 +3057,6 @@  qtkit_indev_select="qtkit"
 sdl2_outdev_deps="sdl2"
 sndio_indev_deps="sndio"
 sndio_outdev_deps="sndio"
-v4l_indev_deps="linux_videodev_h"
 v4l2_indev_select="v4l2"
 v4l2_outdev_select="v4l2"
 vfwcap_indev_deps="vfw32 vfwcap_defines"
@@ -3592,7 +3606,7 @@  done
 enable_weak audiotoolbox
 
 # Enable hwaccels by default.
-enable_weak d3d11va dxva2 vaapi vda vdpau videotoolbox_hwaccel xvmc
+enable_weak d3d11va dxva2 vaapi v4l2_m2m vda vdpau videotoolbox_hwaccel xvmc
 enable_weak xlib
 
 enable_weak cuda cuvid nvenc vda_framework videotoolbox videotoolbox_encoder
@@ -6058,12 +6072,10 @@  pod2man --help     > /dev/null 2>&1 && enable pod2man   || disable pod2man
 rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout
 
 check_header linux/fb.h
-check_header linux/videodev.h
-check_header linux/videodev2.h
-check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
 
 check_header sys/videoio.h
 check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete
+add_cflags -I$source_path/compat/v4l2
 
 check_lib user32 "windows.h winuser.h" GetShellWindow -luser32
 check_lib vfw32 "windows.h vfw.h" capCreateCaptureWindow -lvfw32
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 364aec9..f45050e 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -101,7 +101,8 @@  OBJS-$(CONFIG_LZF)                     += lzf.o
 OBJS-$(CONFIG_MDCT)                    += mdct_fixed.o mdct_float.o mdct_fixed_32.o
 OBJS-$(CONFIG_ME_CMP)                  += me_cmp.o
 OBJS-$(CONFIG_MEDIACODEC)              += mediacodecdec_common.o mediacodec_surface.o mediacodec_wrapper.o mediacodec_sw_buffer.o
-OBJS-$(CONFIG_V4L2)                    += v4l2-common.o
+OBJS-$(CONFIG_V4L2)                    += v4l2_fmt.o v4l2_buffers.o
+OBJS-$(CONFIG_V4L2_M2M)                += v4l2_m2m.o
 OBJS-$(CONFIG_MPEG_ER)                 += mpeg_er.o
 OBJS-$(CONFIG_MPEGAUDIO)               += mpegaudio.o
 OBJS-$(CONFIG_MPEGAUDIODSP)            += mpegaudiodsp.o                \
@@ -320,6 +321,8 @@  OBJS-$(CONFIG_H261_ENCODER)            += h261enc.o h261data.o h261.o
 OBJS-$(CONFIG_H263_DECODER)            += h263dec.o h263.o ituh263dec.o        \
                                           mpeg4video.o mpeg4videodec.o flvdec.o\
                                           intelh263dec.o h263data.o
+OBJS-$(CONFIG_H263_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
+OBJS-$(CONFIG_H263_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
 OBJS-$(CONFIG_H263_ENCODER)            += mpeg4videoenc.o mpeg4video.o  \
                                           h263.o ituh263enc.o flvenc.o h263data.o
 OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
@@ -327,6 +330,8 @@  OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
                                           h264_mb.o h264_picture.o \
                                           h264_refs.o h264_sei.o \
                                           h264_slice.o h264data.o
+OBJS-$(CONFIG_H264_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
+OBJS-$(CONFIG_H264_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
 OBJS-$(CONFIG_H264_CUVID_DECODER)      += cuvid.o
 OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
 OBJS-$(CONFIG_H264_MMAL_DECODER)       += mmaldec.o
@@ -346,6 +351,8 @@  OBJS-$(CONFIG_HEVC_DECODER)            += hevcdec.o hevc_mvs.o \
                                           hevcdsp.o hevc_filter.o hevc_data.o
 OBJS-$(CONFIG_HEVC_CUVID_DECODER)      += cuvid.o
 OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o
+OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER)    += v4l2_m2m_dec.o
+OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER)    += v4l2_m2m_enc.o
 OBJS-$(CONFIG_HEVC_NVENC_ENCODER)      += nvenc_hevc.o
 OBJS-$(CONFIG_NVENC_HEVC_ENCODER)      += nvenc_hevc.o
 OBJS-$(CONFIG_HEVC_QSV_DECODER)        += qsvdec_h2645.o
@@ -419,11 +426,13 @@  OBJS-$(CONFIG_MP3ON4FLOAT_DECODER)     += mpegaudiodec_float.o mpeg4audio.o
 OBJS-$(CONFIG_MPC7_DECODER)            += mpc7.o mpc.o
 OBJS-$(CONFIG_MPC8_DECODER)            += mpc8.o mpc.o
 OBJS-$(CONFIG_MPEGVIDEO_DECODER)       += mpeg12dec.o mpeg12.o mpeg12data.o
+OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
 OBJS-$(CONFIG_MPEG1VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
 OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
 OBJS-$(CONFIG_MPEG2_MMAL_DECODER)      += mmaldec.o
 OBJS-$(CONFIG_MPEG2_QSV_DECODER)       += qsvdec_other.o
 OBJS-$(CONFIG_MPEG2_QSV_ENCODER)       += qsvenc_mpeg2.o
+OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
 OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12dec.o mpeg12.o mpeg12data.o
 OBJS-$(CONFIG_MPEG2VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
 OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o
@@ -431,6 +440,8 @@  OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER)     += vaapi_encode_mpeg2.o
 OBJS-$(CONFIG_MPEG4_DECODER)           += xvididct.o
 OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o
 OBJS-$(CONFIG_MPEG4_OMX_ENCODER)       += omx.o
+OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER)   += v4l2_m2m_dec.o
+OBJS-$(CONFIG_MPEG4_V4L2M2M_ENCODER)   += v4l2_m2m_enc.o
 OBJS-$(CONFIG_MPL2_DECODER)            += mpl2dec.o ass.o
 OBJS-$(CONFIG_MSA1_DECODER)            += mss3.o
 OBJS-$(CONFIG_MSCC_DECODER)            += mscc.o
@@ -503,6 +514,7 @@  OBJS-$(CONFIG_RALF_DECODER)            += ralf.o
 OBJS-$(CONFIG_RAWVIDEO_DECODER)        += rawdec.o
 OBJS-$(CONFIG_RAWVIDEO_ENCODER)        += rawenc.o
 OBJS-$(CONFIG_REALTEXT_DECODER)        += realtextdec.o ass.o
+OBJS-$(CONFIG_VC1_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
 OBJS-$(CONFIG_RL2_DECODER)             += rl2.o
 OBJS-$(CONFIG_ROQ_DECODER)             += roqvideodec.o roqvideo.o
 OBJS-$(CONFIG_ROQ_ENCODER)             += roqvideoenc.o roqvideo.o elbg.o
@@ -518,6 +530,8 @@  OBJS-$(CONFIG_RV30_DECODER)            += rv30.o rv34.o rv30dsp.o
 OBJS-$(CONFIG_RV40_DECODER)            += rv40.o rv34.o rv40dsp.o
 OBJS-$(CONFIG_SAMI_DECODER)            += samidec.o ass.o htmlsubtitles.o
 OBJS-$(CONFIG_S302M_DECODER)           += s302m.o
+OBJS-$(CONFIG_VP8_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
+OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
 OBJS-$(CONFIG_S302M_ENCODER)           += s302menc.o
 OBJS-$(CONFIG_SANM_DECODER)            += sanm.o
 OBJS-$(CONFIG_SCPR_DECODER)            += scpr.o
@@ -628,6 +642,8 @@  OBJS-$(CONFIG_VP9_DECODER)             += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9r
                                           vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o
 OBJS-$(CONFIG_VP9_CUVID_DECODER)       += cuvid.o
 OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER)  += mediacodecdec.o
+OBJS-$(CONFIG_VP9_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
+OBJS-$(CONFIG_VP9_V4L2M2M_ENCODER)     += v4l2_m2m_enc.o
 OBJS-$(CONFIG_VP9_VAAPI_ENCODER)       += vaapi_encode_vp9.o
 OBJS-$(CONFIG_VPLAYER_DECODER)         += textdec.o ass.o
 OBJS-$(CONFIG_VQA_DECODER)             += vqavideo.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 4712592..d154ac9 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -207,8 +207,10 @@  static void register_all(void)
     REGISTER_ENCDEC (H263,              h263);
     REGISTER_DECODER(H263I,             h263i);
     REGISTER_ENCDEC (H263P,             h263p);
+    REGISTER_ENCDEC (H263_V4L2M2M,      h263_v4l2m2m);
     REGISTER_DECODER(H264,              h264);
     REGISTER_DECODER(H264_CRYSTALHD,    h264_crystalhd);
+    REGISTER_ENCDEC (H264_V4L2M2M,      h264_v4l2m2m);
     REGISTER_DECODER(H264_MEDIACODEC,   h264_mediacodec);
     REGISTER_DECODER(H264_MMAL,         h264_mmal);
     REGISTER_DECODER(H264_QSV,          h264_qsv);
@@ -219,6 +221,7 @@  static void register_all(void)
     REGISTER_ENCDEC (HAP,               hap);
     REGISTER_DECODER(HEVC,              hevc);
     REGISTER_DECODER(HEVC_QSV,          hevc_qsv);
+    REGISTER_ENCDEC(HEVC_V4L2M2M,       hevc_v4l2m2m);
     REGISTER_DECODER(HNM4_VIDEO,        hnm4_video);
     REGISTER_DECODER(HQ_HQA,            hq_hqa);
     REGISTER_DECODER(HQX,               hqx);
@@ -253,6 +256,7 @@  static void register_all(void)
     REGISTER_ENCDEC (MPEG2VIDEO,        mpeg2video);
     REGISTER_ENCDEC (MPEG4,             mpeg4);
     REGISTER_DECODER(MPEG4_CRYSTALHD,   mpeg4_crystalhd);
+    REGISTER_ENCDEC (MPEG4_V4L2M2M,     mpeg4_v4l2m2m);
     REGISTER_DECODER(MPEG4_MMAL,        mpeg4_mmal);
 #if FF_API_VDPAU
     REGISTER_DECODER(MPEG4_VDPAU,       mpeg4_vdpau);
@@ -262,8 +266,10 @@  static void register_all(void)
     REGISTER_DECODER(MPEG_VDPAU,        mpeg_vdpau);
     REGISTER_DECODER(MPEG1_VDPAU,       mpeg1_vdpau);
 #endif
+    REGISTER_DECODER(MPEG1_V4L2M2M,     mpeg1_v4l2m2m);
     REGISTER_DECODER(MPEG2_MMAL,        mpeg2_mmal);
     REGISTER_DECODER(MPEG2_CRYSTALHD,   mpeg2_crystalhd);
+    REGISTER_DECODER(MPEG2_V4L2M2M,     mpeg2_v4l2m2m);
     REGISTER_DECODER(MPEG2_QSV,         mpeg2_qsv);
     REGISTER_DECODER(MPEG2_MEDIACODEC,  mpeg2_mediacodec);
     REGISTER_DECODER(MSA1,              msa1);
@@ -361,6 +367,7 @@  static void register_all(void)
     REGISTER_DECODER(VC1IMAGE,          vc1image);
     REGISTER_DECODER(VC1_MMAL,          vc1_mmal);
     REGISTER_DECODER(VC1_QSV,           vc1_qsv);
+    REGISTER_DECODER(VC1_V4L2M2M,       vc1_v4l2m2m);
     REGISTER_ENCODER(VC2,               vc2);
     REGISTER_DECODER(VCR1,              vcr1);
     REGISTER_DECODER(VMDVIDEO,          vmdvideo);
@@ -372,7 +379,9 @@  static void register_all(void)
     REGISTER_DECODER(VP6F,              vp6f);
     REGISTER_DECODER(VP7,               vp7);
     REGISTER_DECODER(VP8,               vp8);
+    REGISTER_ENCDEC (VP8_V4L2M2M,       vp8_v4l2m2m);
     REGISTER_DECODER(VP9,               vp9);
+    REGISTER_DECODER(VP9_V4L2M2M,       vp9_v4l2m2m);
     REGISTER_DECODER(VQA,               vqa);
     REGISTER_DECODER(BITPACKED,         bitpacked);
     REGISTER_DECODER(WEBP,              webp);
diff --git a/libavcodec/v4l2-common.c b/libavcodec/v4l2-common.c
deleted file mode 100644
index 13744fb..0000000
--- a/libavcodec/v4l2-common.c
+++ /dev/null
@@ -1,136 +0,0 @@ 
-/*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include "v4l2-common.h"
-
-const struct v4l_fmt_map avpriv_v4l_fmt_conversion_table[] = {
-    //ff_fmt              codec_id              v4l2_fmt                  pack_flags
-    { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420     , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU420     , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_YUV422P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV422P    , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_YUYV422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUYV       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_UYVY422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_UYVY       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_YUV411P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV411P    , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV410     , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU410     , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_RGB555LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555     , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_RGB555BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555X    , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_RGB565LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565     , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_RGB565BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565X    , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_BGR24,   AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR24      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_RGB24,   AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB24      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_BGR0,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_0RGB,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB32      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_GRAY8,   AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_GREY       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-#ifdef V4L2_PIX_FMT_Y16
-    { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Y16        , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-#endif
-    { AV_PIX_FMT_NV12,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12       , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MJPEG,    V4L2_PIX_FMT_MJPEG      , FF_V4L_PACK_AVPACKET },
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MJPEG,    V4L2_PIX_FMT_JPEG       , FF_V4L_PACK_AVPACKET },
-#ifdef V4L2_PIX_FMT_H264
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_H264,     V4L2_PIX_FMT_H264       , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_MPEG4
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MPEG4,    V4L2_PIX_FMT_MPEG4      , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_CPIA1
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_CPIA,     V4L2_PIX_FMT_CPIA1      , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_SRGGB8
-    { AV_PIX_FMT_BAYER_BGGR8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SBGGR8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_BAYER_GBRG8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SGBRG8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_BAYER_GRBG8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SGRBG8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-    { AV_PIX_FMT_BAYER_RGGB8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SRGGB8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
-#endif
-#ifdef V4L2_PIX_FMT_NV12M
-    { AV_PIX_FMT_NV12,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12M      , FF_V4L_PACK_AVFRAME  },
-#endif
-#ifdef V4L2_PIX_FMT_NV21M
-    { AV_PIX_FMT_NV21,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV21M      , FF_V4L_PACK_AVFRAME  },
-#endif
-#ifdef V4L2_PIX_FMT_YUV420M
-    { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420M    , FF_V4L_PACK_AVFRAME  },
-#endif
-#ifdef V4L2_PIX_FMT_NV16M
-    { AV_PIX_FMT_NV16,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV16M      , FF_V4L_PACK_AVFRAME  },
-#endif
-#ifdef V4L2_PIX_FMT_DV
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_DVVIDEO,  V4L2_PIX_FMT_DV         , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_H263
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_H263,     V4L2_PIX_FMT_H263       , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_MPEG1
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MPEG1VIDEO, V4L2_PIX_FMT_MPEG1    , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_MPEG2
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MPEG2VIDEO, V4L2_PIX_FMT_MPEG2    , FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_VC1_ANNEX_G
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_VC1,      V4L2_PIX_FMT_VC1_ANNEX_G, FF_V4L_PACK_AVPACKET },
-#endif
-#ifdef V4L2_PIX_FMT_VP8
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_VP8,      V4L2_PIX_FMT_VP8        , FF_V4L_PACK_AVPACKET },
-#endif
-    { AV_PIX_FMT_NONE,    AV_CODEC_ID_NONE,     0                    },
-};
-
-uint32_t avpriv_v4l_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id, int pack_flags)
-{
-    int i;
-
-    for (i = 0; avpriv_v4l_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
-        if ((codec_id == AV_CODEC_ID_NONE ||
-             avpriv_v4l_fmt_conversion_table[i].codec_id == codec_id) &&
-            (pix_fmt == AV_PIX_FMT_NONE ||
-             avpriv_v4l_fmt_conversion_table[i].ff_fmt == pix_fmt) &&
-             (avpriv_v4l_fmt_conversion_table[i].pack_flags & pack_flags)) {
-            return avpriv_v4l_fmt_conversion_table[i].v4l2_fmt;
-        }
-    }
-
-    return 0;
-}
-
-enum AVPixelFormat avpriv_v4l_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id)
-{
-    int i;
-
-    for (i = 0; avpriv_v4l_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
-        if (avpriv_v4l_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt &&
-            avpriv_v4l_fmt_conversion_table[i].codec_id == codec_id) {
-            return avpriv_v4l_fmt_conversion_table[i].ff_fmt;
-        }
-    }
-
-    return AV_PIX_FMT_NONE;
-}
-
-enum AVCodecID avpriv_v4l_fmt_v4l2codec(uint32_t v4l2_fmt)
-{
-    int i;
-
-    for (i = 0; avpriv_v4l_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
-        if (avpriv_v4l_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt) {
-            return avpriv_v4l_fmt_conversion_table[i].codec_id;
-        }
-    }
-
-    return AV_CODEC_ID_NONE;
-}
diff --git a/libavcodec/v4l2-common.h b/libavcodec/v4l2-common.h
deleted file mode 100644
index 346887c..0000000
--- a/libavcodec/v4l2-common.h
+++ /dev/null
@@ -1,62 +0,0 @@ 
-/*
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVCODEC_V4L2_COMMON_H
-#define AVCODEC_V4L2_COMMON_H
-
-#undef __STRICT_ANSI__ //workaround due to broken kernel headers
-#include "config.h"
-#if HAVE_SYS_VIDEOIO_H
-#include <sys/videoio.h>
-#else
-#if HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-#include <linux/videodev2.h>
-#endif
-#include "libavutil/avassert.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/log.h"
-#include "libavutil/opt.h"
-#include "libavdevice/avdevice.h"
-#include "libavdevice/timefilter.h"
-#include "libavutil/parseutils.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/time.h"
-#include "libavutil/avstring.h"
-#include "libavutil/pixfmt.h"
-#include "libavcodec/avcodec.h"
-
-/* for v4l_fmt_map.pack_flags */
-#define FF_V4L_PACK_AVPACKET (1 << 0)
-#define FF_V4L_PACK_AVFRAME  (1 << 1)
-
-struct v4l_fmt_map {
-    enum AVPixelFormat ff_fmt;
-    enum AVCodecID codec_id;
-    uint32_t v4l2_fmt;
-    int pack_flags;
-};
-
-extern const struct v4l_fmt_map avpriv_v4l_fmt_conversion_table[];
-
-uint32_t avpriv_v4l_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id, int pack_flags);
-enum AVPixelFormat avpriv_v4l_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id);
-enum AVCodecID avpriv_v4l_fmt_v4l2codec(uint32_t v4l2_fmt);
-
-#endif /* AVCODEC_V4L2_COMMON_H */
diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c
new file mode 100644
index 0000000..4bae6aa
--- /dev/null
+++ b/libavcodec/v4l2_buffers.c
@@ -0,0 +1,614 @@ 
+/*
+ * V4L2 buffer{,pool} helper functions.
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "avcodec.h"
+#include "internal.h"
+#include "v4l2_buffers.h"
+#include "v4l2_fmt.h"
+
+#define IS_BP_SUPPORTED(bp) ((bp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) || \
+                             (bp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)  || \
+                             (bp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)        || \
+                             (bp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT))
+enum V4LBuffer_status {
+    V4LBUF_AVAILABLE,
+    V4LBUF_IN_DRIVER,
+    V4LBUF_RET_USER,
+};
+
+struct V4LBuffer {
+    AVBufferRef *bufrefs[VIDEO_MAX_PLANES];
+    struct V4LBufferPool *pool;
+    struct v4l2_plane planes[VIDEO_MAX_PLANES];
+    struct v4l2_buffer buf;
+
+    void * mm_addr[VIDEO_MAX_PLANES];
+    size_t lengths[VIDEO_MAX_PLANES];
+    enum V4LBuffer_status status;
+    int bytesperline[4];
+    int num_planes;
+    int num_lines;
+    int index;
+    int flags;
+    struct timeval timestamp;
+    int ref_cnt;
+};
+
+static inline void set_pts(V4LBuffer *out, int64_t pts)
+{
+    if (pts == AV_NOPTS_VALUE) {
+        out->timestamp.tv_sec  = 0;
+        out->timestamp.tv_usec = 0;
+    } else {
+        out->timestamp.tv_sec  = pts / INT64_C(1000000);
+        out->timestamp.tv_usec = pts % INT64_C(1000000);
+    }
+}
+
+static inline uint64_t get_pts(V4LBuffer *avbuf)
+{
+    if (avbuf->buf.timestamp.tv_sec || avbuf->buf.timestamp.tv_usec)
+        return (avbuf->buf.timestamp.tv_sec * INT64_C(1000000) + avbuf->buf.timestamp.tv_usec);
+
+    return AV_NOPTS_VALUE;
+}
+
+static int enqueue_v4lbuf(V4LBuffer* avbuf)
+{
+    int ret;
+
+    memset(&avbuf->buf, 0, sizeof(avbuf->buf));
+    avbuf->buf.memory = avbuf->pool->memory;
+    avbuf->buf.type = avbuf->pool->type;
+    avbuf->buf.index = avbuf->index;
+
+    if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
+        avbuf->buf.length   = avbuf->num_planes;
+        avbuf->buf.m.planes = avbuf->planes;
+    } else {
+        avbuf->buf.bytesused = avbuf->planes[avbuf->index].bytesused;
+        avbuf->buf.m.userptr = avbuf->planes[avbuf->index].m.userptr;
+        avbuf->buf.length    = avbuf->planes[avbuf->index].length;
+    }
+
+    avbuf->buf.flags = avbuf->pool->default_flags | avbuf->flags;
+    avbuf->buf.timestamp = avbuf->timestamp;
+
+    ret = ioctl(avbuf->pool->fd, VIDIOC_QBUF, &avbuf->buf);
+    if (ret < 0)
+        return AVERROR(errno);
+
+    avbuf->status = V4LBUF_IN_DRIVER;
+    avbuf->pool->num_queued++;
+
+    return 0;
+}
+
+static V4LBuffer* dequeue_v4lbuf(V4LBufferPool *bp, unsigned int timeout)
+{
+    struct v4l2_plane planes[VIDEO_MAX_PLANES];
+    struct v4l2_buffer buf = { 0 };
+    V4LBuffer* avbuf = NULL;
+    struct pollfd pfd;
+    int ret;
+    int i;
+
+    if (bp->num_queued < bp->min_queued_buffers)
+        return NULL;
+
+    pfd.fd = bp->fd;
+    switch (bp->type) {
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+    case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+        pfd.events = POLLIN | POLLERR;
+        break;
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+    case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+        pfd.events = POLLOUT | POLLERR | POLLWRNORM;
+        break;
+    default:
+        pfd.events = POLLIN | POLLERR | POLLRDNORM;
+    }
+
+    ret = poll(&pfd, 1, timeout);
+    if (ret <=  0)
+        return NULL;
+
+    memset(&buf, 0, sizeof(buf));
+    buf.memory = bp->memory;
+    buf.type = bp->type;
+    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
+        memset(planes, 0, sizeof(planes));
+        buf.length = VIDEO_MAX_PLANES;
+        buf.m.planes = planes;
+    }
+    ret = ioctl(bp->fd, VIDIOC_DQBUF, &buf);
+    if (ret) {
+        if (errno != EAGAIN && errno != EINVAL) {
+            av_log(bp->log_ctx, AV_LOG_DEBUG, "%s: VIDIOC_DQBUF, errno (%d)\n", bp->name, errno);
+            bp->broken = errno;
+        }
+        return NULL;
+    }
+
+    avbuf = &(bp->buffers[buf.index]);
+    avbuf->status = V4LBUF_AVAILABLE;
+    avbuf->pool->num_queued--;
+    avbuf->buf = buf;
+    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
+        memcpy(avbuf->planes, planes, sizeof(planes));
+        avbuf->buf.m.planes = avbuf->planes;
+    }
+
+    if (!V4L2_TYPE_IS_OUTPUT(avbuf->pool->type))
+        return avbuf;
+
+    for (i = 0; i < avbuf->num_planes; i++) {
+        if (avbuf->bufrefs[i])
+            av_buffer_unref(&avbuf->bufrefs[i]);
+    }
+
+    return avbuf;
+}
+
+static void buffer_callback(void *opaque, uint8_t *unused)
+{
+    V4LBuffer* avbuf = opaque;
+
+    if (--avbuf->ref_cnt > 0)
+        return;
+
+    if (V4LBUF_IN_DRIVER == avbuf->status)
+        return;
+
+    if (!V4L2_TYPE_IS_OUTPUT(avbuf->pool->type)) {
+        enqueue_v4lbuf(avbuf);
+    } else {
+        avbuf->status = V4LBUF_AVAILABLE;
+    }
+}
+
+static inline int init_buffer(V4LBuffer* avbuf)
+{
+    int ret, i;
+
+    avbuf->buf.memory = avbuf->pool->memory;
+    avbuf->buf.type = avbuf->pool->type;
+    avbuf->buf.index = avbuf->index;
+
+    if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
+        avbuf->buf.length = VIDEO_MAX_PLANES;
+        avbuf->buf.m.planes = avbuf->planes;
+    }
+
+    ret = ioctl(avbuf->pool->fd, VIDIOC_QUERYBUF, &avbuf->buf);
+    if (ret < 0)
+        return AVERROR(errno);
+
+    if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
+        avbuf->num_planes = 0;
+        for (;;) {
+            if (avbuf->num_planes >= avbuf->buf.length)
+                break;
+            if (avbuf->buf.m.planes[avbuf->num_planes].length)
+                avbuf->num_planes++;
+        }
+    } else
+        avbuf->num_planes = 1;
+
+    avbuf->num_lines = avbuf->pool->format.fmt.pix_mp.height;
+
+    for (i = 0; i < avbuf->num_planes; i++) {
+
+        avbuf->bytesperline[i] = V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type) ?
+            avbuf->pool->format.fmt.pix_mp.plane_fmt[i].bytesperline :
+            avbuf->pool->format.fmt.pix.bytesperline;
+
+        switch (avbuf->pool->memory) {
+        case V4L2_MEMORY_MMAP:
+            if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type)) {
+                avbuf->lengths[i] = avbuf->buf.m.planes[i].length;
+                avbuf->mm_addr[i] = mmap(NULL, avbuf->buf.m.planes[i].length,
+                                         PROT_READ | PROT_WRITE, MAP_SHARED,
+                                         avbuf->pool->fd, avbuf->buf.m.planes[i].m.mem_offset);
+            } else {
+                avbuf->lengths[i] = avbuf->buf.length;
+                avbuf->mm_addr[i] = mmap(NULL, avbuf->buf.length,
+                                         PROT_READ | PROT_WRITE, MAP_SHARED,
+                                         avbuf->pool->fd, avbuf->buf.m.offset);
+            }
+            if (avbuf->mm_addr[i] == MAP_FAILED)
+                return AVERROR(ENOMEM);
+            break;
+
+        case V4L2_MEMORY_USERPTR:
+            break;
+
+        default:
+            av_log(avbuf->pool->log_ctx, AV_LOG_ERROR, "memory type %i not supported\n", avbuf->pool->memory);
+            return AVERROR_PATCHWELCOME;
+        }
+    }
+    avbuf->status = V4LBUF_AVAILABLE;
+
+    if (V4L2_TYPE_IS_OUTPUT(avbuf->pool->type))
+        return 0;
+
+    if (avbuf->pool->memory != V4L2_MEMORY_USERPTR)
+        return enqueue_v4lbuf(avbuf);
+
+    return 0;
+}
+
+int avpriv_init_v4lbufpool(V4LBufferPool* bufs)
+{
+    struct v4l2_requestbuffers req;
+    int ret, i;
+
+    if (!IS_BP_SUPPORTED(bufs)) {
+        av_log(bufs->log_ctx, AV_LOG_ERROR, "type %i not supported\n", bufs->type);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    memset(&req, 0, sizeof(req));
+    req.count = bufs->num_buffers + bufs->min_queued_buffers;
+    req.memory = bufs->memory;
+    req.type = bufs->type;
+    ret = ioctl(bufs->fd, VIDIOC_REQBUFS, &req);
+    if (ret< 0)
+        return AVERROR(errno);
+
+    bufs->num_buffers = req.count;
+    bufs->num_queued  = 0;
+    bufs->buffers = av_mallocz(bufs->num_buffers * sizeof(V4LBuffer));
+
+    for (i = 0; i < req.count; i++) {
+        V4LBuffer *avbuf = &bufs->buffers[i];
+        avbuf->pool = bufs;
+        avbuf->index = i;
+
+        ret = init_buffer(avbuf);
+        if (ret < 0) {
+            av_log(bufs->log_ctx, AV_LOG_ERROR, "%s buffer initialization (%s)\n", bufs->name, av_err2str(ret));
+            return ret;
+        }
+    }
+
+    return 0;
+}
+
+static void release_buf(V4LBuffer* b)
+{
+    int i;
+
+    for (i = 0; i < b->num_planes; i++) {
+        if (b->mm_addr[i] && b->lengths[i]) {
+            munmap(b->mm_addr[i], b->lengths[i]);
+        }
+    }
+}
+
+void avpriv_release_buffer_pool(V4LBufferPool* bp)
+{
+    int i;
+
+    if (!bp->buffers)
+        return;
+
+    for (i = 0; i < bp->num_buffers; i++) {
+        release_buf(&bp->buffers[i]);
+    }
+
+    av_free(bp->buffers);
+}
+
+static int buf2v4l(V4LBuffer *out, int plane, const uint8_t* data, int size, AVBufferRef* bref)
+{
+    if (plane >= out->num_planes)
+        return AVERROR(EINVAL);
+
+    switch (out->pool->memory) {
+    case V4L2_MEMORY_MMAP:
+            memcpy(out->mm_addr[plane], data, FFMIN(size, out->lengths[plane]));
+            break;
+    case V4L2_MEMORY_USERPTR:
+        if (!bref) {
+            av_log(out->pool->log_ctx, AV_LOG_ERROR,
+                   "needs to be set with an AVBufferRef for USERPTR memory type\n");
+            return AVERROR_PATCHWELCOME;
+        }
+        if (out->bufrefs[plane]) {
+            av_log(out->pool->log_ctx, AV_LOG_WARNING,
+                   "V4L buffer already had a buffer referenced\n");
+            av_buffer_unref(&out->bufrefs[plane]);
+        }
+
+        out->bufrefs[plane] = av_buffer_ref(bref);
+        if (!out->bufrefs[plane])
+            return AVERROR(ENOMEM);
+
+        out->planes[plane].m.userptr = (unsigned long)out->bufrefs[plane]->data;
+        out->lengths[plane] = out->bufrefs[plane]->size;
+        break;
+    default:
+        av_log(out->pool->log_ctx, AV_LOG_ERROR,
+               "memory type %i not supported", out->pool->memory);
+        return AVERROR_PATCHWELCOME;
+    }
+
+    out->planes[plane].bytesused = FFMIN(size ? size : 1, out->lengths[plane]);
+    out->planes[plane].length = out->lengths[plane];
+
+    return 0;
+}
+
+static int avpkt_to_v4lbuf(const AVPacket *pkt, V4LBuffer *out) {
+    int ret;
+
+    ret = buf2v4l(out, 0, pkt->data, pkt->size, pkt->buf);
+    if (ret)
+        return ret;
+
+    set_pts(out, pkt->pts);
+
+    if (pkt->flags & AV_PKT_FLAG_KEY)
+        out->flags = V4L2_BUF_FLAG_KEYFRAME;
+
+    if (!pkt->size)
+        out->flags |= V4L2_BUF_FLAG_LAST;
+
+    return 0;
+}
+
+static inline int v4l2bufref(V4LBuffer *in, int plane, AVBufferRef **buf)
+{
+    if (plane >= in->num_planes)
+        return AVERROR(EINVAL);
+
+    switch (in->pool->memory) {
+    case V4L2_MEMORY_MMAP:
+        *buf = av_buffer_create(in->mm_addr[plane], in->lengths[plane], buffer_callback, in, 0);
+        if (!*buf)
+            return AVERROR(ENOMEM);
+
+        in->status = V4LBUF_RET_USER;
+        in->ref_cnt++;
+        break;
+    case V4L2_MEMORY_USERPTR:
+        if (!in->bufrefs[plane]) {
+            av_log(in->pool->log_ctx, AV_LOG_ERROR, "AVBufferRef not found\n");
+            return AVERROR(EINVAL);
+        }
+
+        *buf = av_buffer_ref(in->bufrefs[plane]);
+        if (!*buf)
+            return AVERROR(ENOMEM);
+
+        av_buffer_unref(&in->bufrefs[plane]);
+        in->status = V4LBUF_AVAILABLE;
+        break;
+    default:
+        av_log(in->pool->log_ctx, AV_LOG_ERROR, "memory type %i not supported", in->pool->memory);
+        return AVERROR_PATCHWELCOME;
+    }
+    return 0;
+}
+
+static int v4lbuf_to_avpkt(AVPacket *pkt, V4LBuffer *avbuf)
+{
+    int ret;
+
+    av_packet_unref(pkt);
+    if (ret = v4l2bufref(avbuf, 0, &pkt->buf))
+        return ret;
+
+    pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->pool->type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused;
+    pkt->data = pkt->buf->data;
+
+    if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME)
+        pkt->flags |= AV_PKT_FLAG_KEY;
+
+    if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
+        av_log(avbuf->pool->log_ctx, AV_LOG_ERROR, "V4L2 packet decode error\n");
+        pkt->flags |= AV_PKT_FLAG_CORRUPT;
+    }
+
+    pkt->pts = get_pts(avbuf);
+
+    return 0;
+}
+
+static int v4lbuf_to_avframe(AVFrame *frame, V4LBuffer *avbuf)
+{
+    int i, ret;
+
+    av_frame_unref(frame);
+
+    for (i = 0; i < avbuf->num_planes; i++) {
+        ret = v4l2bufref(avbuf, i, &frame->buf[i]);
+        if (ret)
+            return ret;
+
+        frame->linesize[i] = avbuf->bytesperline[i];
+        frame->data[i] = frame->buf[i]->data;
+
+        if (avbuf->num_planes == 1) {
+            if (avbuf->pool->av_pix_fmt == AV_PIX_FMT_NV12) {
+                frame->linesize[1] = avbuf->bytesperline[0];
+                frame->data[1] = frame->buf[0]->data + avbuf->bytesperline[0] * avbuf->num_lines;
+            }
+        }
+    }
+
+    frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME);
+    frame->format = avbuf->pool->av_pix_fmt;
+    frame->height = avbuf->pool->height;
+    frame->width = avbuf->pool->width;
+    frame->pts = get_pts(avbuf);
+
+    if (avbuf->buf.flags & V4L2_BUF_FLAG_ERROR) {
+        av_log(avbuf->pool->log_ctx, AV_LOG_ERROR, "V4L2 buffer decode error\n");
+        frame->decode_error_flags |= FF_DECODE_ERROR_INVALID_BITSTREAM;
+    }
+
+    return 0;
+}
+
+static int avframe_to_v4lbuf(const AVFrame *pict, V4LBuffer* out)
+{
+    int i, ret;
+
+    for(i = 0; i < out->num_planes; i++) {
+        ret = buf2v4l(out, i, pict->buf[i]->data, pict->buf[i]->size, pict->buf[i]);
+        if (ret)
+            return ret;
+    }
+
+    set_pts(out, pict->pts);
+
+    return 0;
+}
+
+static V4LBuffer* v4lbufpool_get_from_avframe(const AVFrame* frame, V4LBufferPool *p)
+{
+    int i;
+
+    for (i = 0; i < p->num_buffers; i++) {
+
+        if (V4LBUF_RET_USER != p->buffers[i].status)
+            continue;
+
+        if (p->memory != V4L2_MEMORY_MMAP) {
+            av_log(p->log_ctx, AV_LOG_ERROR, "memory type %i not supported\n", p->memory);
+            return NULL;
+        }
+
+        if (p->buffers[i].mm_addr[0] == frame->buf[0]->data)
+            return &p->buffers[i];
+    }
+
+    return NULL;
+}
+
+V4LBuffer* avpriv_v4lbufpool_getfreebuf(V4LBufferPool *p, const AVFrame *f, const AVPacket* pkt)
+{
+    V4LBuffer* ret;
+    unsigned int timeout = 0;
+    int i;
+
+    if (V4L2_TYPE_IS_OUTPUT(p->type)) {
+          do {
+          } while (dequeue_v4lbuf(p, timeout));
+    }
+
+    if (f) {
+        ret = v4lbufpool_get_from_avframe(f, p);
+        if (ret)
+            return ret;
+    }
+
+    for (i = 0; i < p->num_buffers; i++) {
+        if (p->buffers[i].status == V4LBUF_AVAILABLE)
+            return &p->buffers[i];
+    }
+
+    return NULL;
+}
+
+int avpriv_set_stream_status(V4LBufferPool* bp, int cmd)
+{
+    int type = bp->type;
+    int ret;
+
+    ret = ioctl(bp->fd, cmd, &type);
+    if (ret < 0)
+        return AVERROR(errno);
+
+    bp->streamon = (cmd == VIDIOC_STREAMON);
+
+    return 0;
+}
+
+int avpriv_v4l_enqueue(V4LBufferPool* bp, const AVFrame* f, const AVPacket* pkt)
+{
+    V4LBuffer* avbuf;
+    int ret;
+
+    if (!f && !pkt) {
+        av_log(bp->log_ctx, AV_LOG_ERROR, "either AVFrame* or AVPacket*must valid\n");
+        return AVERROR_BUG;
+    }
+
+    avbuf = avpriv_v4lbufpool_getfreebuf(bp, f, pkt);
+    if (!avbuf)
+        return AVERROR(ENOMEM);
+
+    if (pkt) {
+        ret = avpkt_to_v4lbuf(pkt, avbuf);
+        if (ret)
+            return ret;
+    }
+
+    if (f) {
+        ret = avframe_to_v4lbuf(f, avbuf);
+        if (ret)
+            return ret;
+    }
+
+    ret = enqueue_v4lbuf(avbuf);
+    if (ret)
+        return ret;
+
+    return 0;
+}
+
+int avpriv_v4l_dequeue(V4LBufferPool* bp, AVFrame* f, AVPacket* pkt, unsigned int timeout)
+{
+    V4LBuffer* avbuf = NULL;
+
+    if (!f && !pkt) {
+        av_log(bp->log_ctx, AV_LOG_ERROR, "either AVFrame* or AVPacket* must be valid\n");
+        return AVERROR_BUG;
+    }
+
+    avbuf = dequeue_v4lbuf(bp, timeout);
+    if (!avbuf) {
+        if (bp->broken)
+            return AVERROR_EOF;
+
+        return AVERROR(EAGAIN);
+    }
+
+    if (f)
+        return v4lbuf_to_avframe(f, avbuf);
+
+    if (pkt)
+        return v4lbuf_to_avpkt(pkt, avbuf);
+
+    return AVERROR_BUG;
+}
diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h
new file mode 100644
index 0000000..e3a4173
--- /dev/null
+++ b/libavcodec/v4l2_buffers.h
@@ -0,0 +1,226 @@ 
+/*
+ * V4L2 buffer{,pool} helper functions.
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_V4L2_BUFFERS_H
+#define AVCODEC_V4L2_BUFFERS_H
+
+#include "v4l2_fmt.h"
+#include "avcodec.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/frame.h"
+
+struct V4LBuffer;
+typedef struct V4LBuffer V4LBuffer;
+
+struct V4LBufferPool;
+typedef int (*format_f)(struct V4LBufferPool *, int set);
+typedef int (*init_f)(struct V4LBufferPool *);
+
+typedef struct V4LBufferPoolCfg {
+    format_f format;
+    init_f init;
+} V4LBufferPoolCfg;
+
+typedef struct V4LBufferPool {
+    /**
+     * Buffer pool initial configuration.
+     */
+    V4LBufferPoolCfg cfg;
+
+    /**
+     * Log context (for av_log()). Can be NULL.
+     */
+    void *log_ctx;
+
+    /**
+     * Pool's name. Must be set before calling avpriv_init_v4lbufpool().
+     */
+    const char* name;
+
+    /**
+     * File descriptor obtained from opening the associated device.
+     * Must be set before calling avpriv_init_v4lbufpool().
+     * Readonly after init.
+     */
+    int fd;
+
+    /**
+     * Type of this buffer pool.
+     * See V4L2_BUF_TYPE_VIDEO_* in videodev2.h
+     * Must be set before calling avpriv_init_v4lbufpool().
+     * Readonly after init.
+     */
+    enum v4l2_buf_type type;
+
+    /**
+     * Memory type this buffer pool uses.
+     * See V4L2_MEMORY_* in videodev2.h
+     * Must be set before calling avpriv_init_v4lbufpool().
+     * Readonly after init.
+     */
+    enum v4l2_memory memory;
+
+    /**
+     * AVPixelFormat corresponding to this buffer pool.
+     * AV_PIX_FMT_NONE means this is an encoded stream.
+     */
+    enum AVPixelFormat av_pix_fmt;
+
+    /**
+     * AVCodecID corresponding to this buffer pool.
+     * AV_CODEC_ID_RAWVIDEO means this is a raw stream and av_pix_fmt must be set to a valid value.
+     */
+    enum AVCodecID   av_codec_id;
+
+    /**
+     * Format returned by the driver after initializing the buffer pool.
+     * Must be set before calling avpriv_init_v4lbufpool().
+     * avpriv_set_pool_format() can set it.
+     * Readonly after init.
+     */
+    struct v4l2_format format;
+
+    /**
+     * Width and height of the frames it produces (in case of a capture pool, e.g. when decoding)
+     * or accepts (in case of an output pool, e.g. when encoding).
+     *
+     * For output pools, this must must be set before calling avpriv_init_v4lbufpool().
+     * For capture pools, it will be set after having received the information from the driver.
+     */
+    int width, height;
+
+    /**
+     * Default flags to set on buffers to enqueue.
+     * See V4L2_BUF_FLAG_*.
+     */
+    int default_flags;
+
+    /**
+     * Whether the stream has been started (VIDIOC_STREAMON has been sent).
+     */
+    int streamon;
+
+    /**
+     * Number of queued buffers.
+     */
+    int num_queued;
+
+    /**
+     * Minimum number of buffers that must be kept queued in this queue.
+     *
+     * E.g. for decoders, the drivers might have such requirements to produce proper output.
+     */
+    int min_queued_buffers;
+
+    /**
+     * The actual number of buffers.
+     *
+     * Before calling avpriv_init_v4lbufpool() this is the number of buffers we would like to have available.
+     * avpriv_init_v4lbufpool() asks for (min_buffers + num_buffers) and sets this value to the actual number
+     * of buffers the driver gave us.
+     * Readonly after init.
+     */
+    int num_buffers;
+
+    /**
+     * Opaque pointers to the actual buffers representations.
+     * After initialization, it is an array of size num_buffers.
+     */
+    V4LBuffer *buffers;
+
+    /**
+     * Pool in unrecoverable error notified by the V4L2 kernel api
+     */
+    int broken;
+
+} V4LBufferPool;
+
+/**
+ * Initializes a V4LBufferPool.
+ *
+ * @param[in] bp A pointer to a V4LBufferPool. See V4LBufferPool description for required variables.
+ * @return 0 in case of success, a negative value representing the error otherwise.
+ */
+int avpriv_init_v4lbufpool(V4LBufferPool* bp);
+
+/**
+ * Releases a V4LBufferPool.
+ *
+ * @param[in] bp A pointer to a V4LBufferPool.
+ *               The caller is reponsible for freeing it.
+ *               It must not be used after calling this function.
+ */
+void avpriv_release_buffer_pool(V4LBufferPool* bp);
+
+/**
+ * Sets the status of a V4LBufferPool.
+ *
+ * @param[in] bp A pointer to a V4LBufferPool.
+ * @param[in] cmd The status to set (VIDIOC_STREAMON or VIDIOC_STREAMOFF).
+ *                Warning: If VIDIOC_STREAMOFF is sent to a buffer pool that still has some frames buffered,
+ *                those frames will be dropped.
+ * @return 0 in case of success, a negative value representing the error otherwise.
+ */
+int avpriv_set_stream_status(V4LBufferPool* bp, int cmd);
+
+/**
+ * Dequeues a buffer from a V4LBufferPool to either an AVFrame or an AVPacket.
+ *
+ * Exactly one of f or pkt must be non NULL.
+ * @param[in] bp The V4LBufferPool to dequeue from.
+ * @param[inout] f The AVFrame to dequeue to.
+ * @param[inout] pkt The AVPacket to dequeue to.
+ * @param[ino] timeout The number of milliseconds to wait for the dequeue.
+ * @return 0 in case of success, AVERROR(EAGAIN) if no buffer was ready, another negative error in case of error.
+ */
+int avpriv_v4l_dequeue(V4LBufferPool* bp, AVFrame* f, AVPacket* pkt, unsigned int timeout);
+
+/**
+ * Enqueues a buffer to a V4LBufferPool from either an AVFrame, an AVPacket or a raw buffer.
+ * Exactly one of f or pkt  must be non NULL.
+ *
+ * @param[in] bp The V4LBufferPool to enqueue to.
+ * @param[in] f A pointer to an AVFrame to enqueue.
+ * @param[in] pkt A pointer to an AVPacket to enqueue.
+ * @return 0 in case of success, a negative error otherwise.
+ */
+int avpriv_v4l_enqueue(V4LBufferPool* bp, const AVFrame* f, const AVPacket* pkt);
+
+/**
+ * Gets a free V4LBuffer from a V4LBufferPool.
+ *
+ * If no matching buffer is found (see below), it tries to dequeue a buffer first
+ * in order to minimize the size of the V4L queue.e
+ *
+ * @param[in] p Pointer to a V4LBufferPool where to get the buffer from.
+ * @param[in] f A pointer to an existing AVFrame:
+ *              If the AVFrame's buffers match a V4LBuffer, this V4LBuffer will be returned.
+ *              Can be NULL.
+ * @param[in] pkt A pointer to an existing AVPacket:
+ *                If the AVPacket's buffers match a V4LBuffer, this V4LBuffer will be returned.
+ *                Can be NULL.
+ * @return A pointer to the V4LBuffer or NULL in case of error.
+ */
+V4LBuffer* avpriv_v4lbufpool_getfreebuf(V4LBufferPool *p, const AVFrame *f, const AVPacket* pkt);
+
+#endif // AVCODEC_V4L2_BUFFERS_H
diff --git a/libavcodec/v4l2_fmt.c b/libavcodec/v4l2_fmt.c
new file mode 100644
index 0000000..29d59fe
--- /dev/null
+++ b/libavcodec/v4l2_fmt.c
@@ -0,0 +1,142 @@ 
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "v4l2_fmt.h"
+
+const struct v4l_fmt_map avpriv_v4l_fmt_conversion_table[] = {
+    /* ff_fmt             codec_id              v4l2_fmt                  pack_flags */
+    { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420     , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_YUV422P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV422P    , FF_V4L_PACK_AVPACKET                       },
+    { AV_PIX_FMT_YUYV422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUYV       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_UYVY422, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_UYVY       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_YUV411P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV411P    , FF_V4L_PACK_AVPACKET                       },
+    { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV410     , FF_V4L_PACK_AVPACKET                       },
+    { AV_PIX_FMT_YUV410P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YVU410     , FF_V4L_PACK_AVPACKET                       },
+    { AV_PIX_FMT_RGB555LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555     , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_RGB555BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB555X    , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_RGB565LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565     , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_RGB565BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565X    , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_BGR24,   AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR24      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_RGB24,   AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB24      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_BGR0,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_0RGB,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB32      , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_GRAY8,   AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_GREY       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+#ifdef V4L2_PIX_FMT_Y16
+    { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Y16        , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+#endif
+    { AV_PIX_FMT_NV12,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12       , FF_V4L_PACK_AVPACKET                       },
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MJPEG,    V4L2_PIX_FMT_MJPEG      , FF_V4L_PACK_AVPACKET                       },
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MJPEG,    V4L2_PIX_FMT_JPEG       , FF_V4L_PACK_AVPACKET                       },
+#ifdef V4L2_PIX_FMT_H264
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_H264,     V4L2_PIX_FMT_H264       , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_MPEG4
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MPEG4,    V4L2_PIX_FMT_MPEG4      , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_CPIA1
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_CPIA,     V4L2_PIX_FMT_CPIA1      , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_SRGGB8
+    { AV_PIX_FMT_BAYER_BGGR8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SBGGR8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_BAYER_GBRG8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SGBRG8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_BAYER_GRBG8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SGRBG8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+    { AV_PIX_FMT_BAYER_RGGB8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_SRGGB8 , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+#endif
+#ifdef V4L2_PIX_FMT_NV12M
+    { AV_PIX_FMT_NV12,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12M      , FF_V4L_PACK_AVFRAME                        },
+#endif
+#ifdef V4L2_PIX_FMT_NV21M
+    { AV_PIX_FMT_NV21,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV21M      , FF_V4L_PACK_AVFRAME                        },
+#endif
+#ifdef V4L2_PIX_FMT_YUV420M
+    { AV_PIX_FMT_YUV420P, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_YUV420M    , FF_V4L_PACK_AVFRAME                        },
+#endif
+#ifdef V4L2_PIX_FMT_NV16M
+    { AV_PIX_FMT_NV16,    AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV16M      , FF_V4L_PACK_AVFRAME                        },
+#endif
+#ifdef V4L2_PIX_FMT_DV
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_DVVIDEO,  V4L2_PIX_FMT_DV         , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_H263
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_H263,     V4L2_PIX_FMT_H263       , FF_V4L_PACK_AVPACKET | FF_V4L_PACK_AVFRAME },
+#endif
+#ifdef V4L2_PIX_FMT_MPEG1
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MPEG1VIDEO, V4L2_PIX_FMT_MPEG1    , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_MPEG2
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_MPEG2VIDEO, V4L2_PIX_FMT_MPEG2    , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_VC1_ANNEX_G
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_VC1,      V4L2_PIX_FMT_VC1_ANNEX_G, FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_VP8
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_VP8,      V4L2_PIX_FMT_VP8        , FF_V4L_PACK_AVPACKET                       },
+#endif
+#ifdef V4L2_PIX_FMT_HEVC
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_HEVC,     V4L2_PIX_FMT_HEVC        , FF_V4L_PACK_AVPACKET                      },
+#endif
+#ifdef V4L2_PIX_FMT_VP9
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_VP9,      V4L2_PIX_FMT_VP9        , FF_V4L_PACK_AVPACKET                       },
+#endif
+    { AV_PIX_FMT_NONE,    AV_CODEC_ID_NONE,     0                       , 0                                          },
+};
+
+uint32_t avpriv_v4l_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id, int pack_flags)
+{
+    int i;
+
+    for (i = 0; avpriv_v4l_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+        if ((codec_id == AV_CODEC_ID_NONE ||
+             avpriv_v4l_fmt_conversion_table[i].codec_id == codec_id) &&
+            (pix_fmt == AV_PIX_FMT_NONE ||
+             avpriv_v4l_fmt_conversion_table[i].ff_fmt == pix_fmt) &&
+             (avpriv_v4l_fmt_conversion_table[i].pack_flags & pack_flags)) {
+
+            return avpriv_v4l_fmt_conversion_table[i].v4l2_fmt;
+        }
+    }
+
+    return 0;
+}
+
+enum AVPixelFormat avpriv_v4l_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id)
+{
+    int i;
+
+    for (i = 0; avpriv_v4l_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+        if (avpriv_v4l_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt &&
+            avpriv_v4l_fmt_conversion_table[i].codec_id == codec_id) {
+            return avpriv_v4l_fmt_conversion_table[i].ff_fmt;
+        }
+    }
+
+    return AV_PIX_FMT_NONE;
+}
+
+enum AVCodecID avpriv_v4l_fmt_v4l2codec(uint32_t v4l2_fmt)
+{
+    int i;
+
+    for (i = 0; avpriv_v4l_fmt_conversion_table[i].codec_id != AV_CODEC_ID_NONE; i++) {
+        if (avpriv_v4l_fmt_conversion_table[i].v4l2_fmt == v4l2_fmt) {
+            return avpriv_v4l_fmt_conversion_table[i].codec_id;
+        }
+    }
+
+    return AV_CODEC_ID_NONE;
+}
diff --git a/libavcodec/v4l2_fmt.h b/libavcodec/v4l2_fmt.h
new file mode 100644
index 0000000..23302ba
--- /dev/null
+++ b/libavcodec/v4l2_fmt.h
@@ -0,0 +1,62 @@ 
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_V4L2_FMT_H
+#define AVCODEC_V4L2_FMT_H
+
+#undef __STRICT_ANSI__ //workaround due to broken kernel headers
+#include "config.h"
+#if HAVE_SYS_VIDEOIO_H
+#include <sys/videoio.h>
+#else
+#if HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+#include "videodev2.h"
+#endif
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/log.h"
+#include "libavutil/opt.h"
+#include "libavdevice/avdevice.h"
+#include "libavdevice/timefilter.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/time.h"
+#include "libavutil/avstring.h"
+#include "libavutil/pixfmt.h"
+#include "libavcodec/avcodec.h"
+
+/* for v4l_fmt_map.pack_flags */
+#define FF_V4L_PACK_AVPACKET (1 << 0)
+#define FF_V4L_PACK_AVFRAME  (1 << 1)
+
+struct v4l_fmt_map {
+    enum AVPixelFormat ff_fmt;
+    enum AVCodecID codec_id;
+    uint32_t v4l2_fmt;
+    int pack_flags;
+};
+
+extern const struct v4l_fmt_map avpriv_v4l_fmt_conversion_table[];
+
+uint32_t avpriv_v4l_fmt_ff2v4l(enum AVPixelFormat pix_fmt, enum AVCodecID codec_id, int pack_flags);
+enum AVPixelFormat avpriv_v4l_fmt_v4l2ff(uint32_t v4l2_fmt, enum AVCodecID codec_id);
+enum AVCodecID avpriv_v4l_fmt_v4l2codec(uint32_t v4l2_fmt);
+
+#endif /* AVCODEC_V4L2_FMT_H */
diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
new file mode 100644
index 0000000..d457473
--- /dev/null
+++ b/libavcodec/v4l2_m2m.c
@@ -0,0 +1,356 @@ 
+/*
+ * V4L mem2mem wrapper
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include "libavutil/imgutils.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/pixdesc.h"
+#include "avcodec.h"
+#include "v4l2_m2m_avcodec.h"
+#include "v4l2_buffers.h"
+#include "v4l2_fmt.h"
+#include "v4l2_m2m.h"
+
+#define V4L_MAX_STREAM_SIZE (3*1024*1024)
+
+static inline int try_raw_format(V4LBufferPool* bp, enum AVPixelFormat pixfmt)
+{
+    struct v4l2_format *fmt = &bp->format;
+    int ret, i, h;
+
+    fmt->type  = bp->type;
+
+    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
+        const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixfmt);
+
+        fmt->fmt.pix_mp.pixelformat = avpriv_v4l_fmt_ff2v4l(pixfmt, bp->av_codec_id, FF_V4L_PACK_AVFRAME);
+        if (!fmt->fmt.pix_mp.pixelformat)
+            return AVERROR(EINVAL);
+
+        fmt->fmt.pix_mp.num_planes = av_pix_fmt_count_planes(pixfmt);
+        for (i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
+            fmt->fmt.pix_mp.plane_fmt[i].bytesperline = av_image_get_linesize(pixfmt, bp->width, i);
+            h = (i == 1 || i == 2) ? FF_CEIL_RSHIFT(bp->height, desc->log2_chroma_h) : bp->height;
+            fmt->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->fmt.pix_mp.plane_fmt[i].bytesperline * h;
+        }
+    } else {
+        fmt->fmt.pix.pixelformat  = avpriv_v4l_fmt_ff2v4l(pixfmt, bp->av_codec_id, FF_V4L_PACK_AVFRAME);
+        if (!fmt->fmt.pix.pixelformat)
+            return AVERROR(EINVAL);
+
+        fmt->fmt.pix.bytesperline = av_image_get_linesize(pixfmt, bp->width, 0);
+        fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * bp->height;
+    }
+
+    ret = ioctl(bp->fd, VIDIOC_TRY_FMT, fmt);
+    if (ret)
+        return AVERROR(EINVAL);
+
+    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
+        fmt->fmt.pix_mp.height = bp->height;
+        fmt->fmt.pix_mp.width = bp->width;
+    } else {
+        fmt->fmt.pix.height = bp->height;
+        fmt->fmt.pix.width = bp->width;
+    }
+
+    return 0;
+}
+
+static int set_raw_format(V4LBufferPool* bp, int set)
+{
+    enum AVPixelFormat pixfmt = bp->av_pix_fmt;
+    struct v4l2_format *fmt = &bp->format;
+    struct v4l2_fmtdesc fmtdesc = { 0 };
+    int ret;
+
+    fmtdesc.type = bp->type;
+    if (pixfmt != AV_PIX_FMT_NONE) {
+        ret = try_raw_format(bp, pixfmt);
+        if (ret)
+            pixfmt = AV_PIX_FMT_NONE;
+    }
+
+    while (AV_PIX_FMT_NONE == pixfmt && !ioctl(bp->fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
+
+        pixfmt = avpriv_v4l_fmt_v4l2ff(fmtdesc.pixelformat, AV_CODEC_ID_RAWVIDEO);
+
+        ret = try_raw_format(bp, pixfmt);
+        if (ret)
+            pixfmt = AV_PIX_FMT_NONE;
+
+        if (pixfmt != AV_PIX_FMT_NONE && set)
+            bp->av_pix_fmt = pixfmt;
+
+        fmtdesc.index++;
+    }
+
+    if (pixfmt == AV_PIX_FMT_NONE)
+        return AVERROR(EINVAL);
+
+    if (set)
+        return ioctl(bp->fd, VIDIOC_S_FMT, fmt);
+
+    return 0;
+}
+
+static int set_coded_format(V4LBufferPool* bp, int set)
+{
+    struct v4l2_format *fmt = &bp->format;
+    struct v4l2_fmtdesc fdesc;
+    uint32_t v4l2_fmt;
+    int found = 0;
+
+    v4l2_fmt = avpriv_v4l_fmt_ff2v4l(bp->av_pix_fmt, bp->av_codec_id, FF_V4L_PACK_AVPACKET);
+    memset(&fdesc, 0, sizeof(fdesc));
+    fdesc.type = bp->type;
+
+    while (!ioctl(bp->fd, VIDIOC_ENUM_FMT, &fdesc)) {
+        if (v4l2_fmt == fdesc.pixelformat) {
+            found = 1;
+            break;
+        }
+        fdesc.index++;
+    }
+
+    if (!found)
+        return AVERROR(EINVAL);
+
+    fmt->type = bp->type;
+
+    if (V4L2_TYPE_IS_MULTIPLANAR(bp->type)) {
+        fmt->fmt.pix_mp.num_planes = 1;
+        fmt->fmt.pix_mp.pixelformat = v4l2_fmt;
+        if (!fmt->fmt.pix_mp.pixelformat) {
+            av_log(bp->log_ctx, AV_LOG_ERROR, "no V4L codec for id %i\n", bp->av_codec_id);
+            return AVERROR(EINVAL);
+        }
+        fmt->fmt.pix_mp.plane_fmt[0].sizeimage = V4L_MAX_STREAM_SIZE;
+        fmt->fmt.pix_mp.height = bp->height;
+        fmt->fmt.pix_mp.width = bp->width;
+
+    } else {
+        fmt->fmt.pix.pixelformat = v4l2_fmt;
+        if (!fmt->fmt.pix.pixelformat) {
+            av_log(bp->log_ctx, AV_LOG_ERROR, "no V4L codec for id %i\n", bp->av_codec_id);
+            return AVERROR(EINVAL);
+        }
+        fmt->fmt.pix.sizeimage = V4L_MAX_STREAM_SIZE;
+        fmt->fmt.pix.height = bp->height;
+        fmt->fmt.pix.width = bp->width;
+    }
+
+    if (set)
+        return ioctl(bp->fd, VIDIOC_S_FMT, fmt);
+
+    return ioctl(bp->fd, VIDIOC_TRY_FMT, fmt);
+}
+
+int avpriv_set_pool_format(V4LBufferPool* bp, int set)
+{
+    if (bp->av_codec_id == AV_CODEC_ID_RAWVIDEO)
+        return set_raw_format(bp, set);
+
+    return set_coded_format(bp, set);
+}
+
+static inline int splane_video(struct v4l2_capability *cap)
+{
+    if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT) & V4L2_CAP_STREAMING)
+        return 1;
+
+    if (cap->capabilities & V4L2_CAP_VIDEO_M2M)
+        return 1;
+
+    return 0;
+}
+
+static inline int mplane_video(struct v4l2_capability *cap)
+{
+    if (cap->capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE) & V4L2_CAP_STREAMING)
+        return 1;
+
+    if (cap->capabilities & V4L2_CAP_VIDEO_M2M_MPLANE)
+        return 1;
+
+    return 0;
+}
+
+static int prepare_pools(V4Lm2mContext* s, void *log_ctx)
+{
+    int ret;
+
+    s->capture_pool.log_ctx = s->output_pool.log_ctx = log_ctx;
+    s->capture_pool.broken = s->output_pool.broken = 0;
+    s->capture_pool.fd = s->output_pool.fd = s->fd;
+    s->capture_pool.name = "capture pool";
+    s->output_pool.name = "output pool";
+
+    memset(&s->cap, 0, sizeof(s->cap));
+    ret = ioctl(s->fd, VIDIOC_QUERYCAP, &s->cap);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (mplane_video(&s->cap)) {
+        s->capture_pool.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+        s->output_pool.type  = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+        return 0;
+    }
+
+    if (splane_video(&s->cap)) {
+        s->capture_pool.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        s->output_pool.type  = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+        return 0;
+    }
+
+    return AVERROR(EINVAL);
+}
+
+static int probe_and_set(V4Lm2mContext* s, void *log_ctx, int set)
+{
+    int fail_log_level = ( set ? AV_LOG_ERROR : AV_LOG_DEBUG);
+    int ret;
+
+    s->fd = open(s->devname, O_RDWR, 0);
+    if (s->fd < 0)
+        return AVERROR(errno);
+
+    ret = prepare_pools(s, log_ctx);
+    if (ret < 0)
+        goto error;
+
+    if (s->output_pool.cfg.format) {
+        ret = s->output_pool.cfg.format(&s->output_pool, set);
+        if (ret) {
+            av_log(log_ctx, fail_log_level, "can't set input format\n");
+            goto error;
+        }
+    }
+
+    if (s->capture_pool.cfg.format) {
+        ret = s->capture_pool.cfg.format(&s->capture_pool, set);
+        if (ret) {
+            av_log(log_ctx, fail_log_level, "can't to set output format\n");
+            goto error;
+        }
+    }
+
+    if (s->output_pool.cfg.init && set) {
+        ret = s->output_pool.cfg.init(&s->output_pool);
+        if (ret) {
+            av_log(log_ctx, fail_log_level, "no output pool's buffers\n");
+            goto error;
+        }
+    }
+
+    if (s->capture_pool.cfg.init && set) {
+        ret = s->capture_pool.cfg.init(&s->capture_pool);
+        if (ret) {
+            av_log(log_ctx, fail_log_level, "no capture pool's buffers\n");
+            goto error;
+        }
+    }
+
+    av_log(log_ctx, AV_LOG_INFO, "using driver '%s' on card '%s'\n", s->cap.driver, s->cap.card);
+
+error:
+    if (!set || ret) {
+        close(s->fd);
+        s->fd = 0;
+    }
+
+    return ret;
+}
+
+int avpriv_v4lm2m_init(V4Lm2mContext* s, void* log_ctx)
+{
+    char *devname_save = s->devname;
+    int ret = AVERROR(EINVAL);
+    char tmpbuf[PATH_MAX];
+    struct dirent *dp;
+    DIR *dirp;
+
+    if (s->devname && *s->devname)
+        return probe_and_set(s, log_ctx, 1);
+
+    if (!(dirp = opendir("/dev")))
+        return AVERROR(errno);
+
+    for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
+
+        if (!strncmp(dp->d_name, "video", sizeof("video") - 1)) {
+            snprintf(tmpbuf, sizeof(tmpbuf) - 1, "/dev/%s", dp->d_name);
+            av_log(log_ctx, AV_LOG_DEBUG, "probing %s\n", tmpbuf);
+
+            s->devname = tmpbuf;
+            ret = probe_and_set(s, log_ctx, 0);
+            if (!ret)
+                break;
+        }
+    }
+    closedir(dirp);
+
+    if (ret) {
+        av_log(log_ctx, AV_LOG_ERROR, "Could not find a valid device\n");
+        s->devname = devname_save;
+        return ret;
+    }
+
+    av_log(log_ctx, AV_LOG_INFO, "Using device %s\n", tmpbuf);
+    ret = probe_and_set(s, log_ctx, 1);
+    s->devname = devname_save;
+
+    return ret;
+}
+
+int ff_v4lm2m_codec_init(AVCodecContext *avctx)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+
+    return avpriv_v4lm2m_init(s, avctx);
+}
+
+int avpriv_v4lm2m_end(V4Lm2mContext* s)
+{
+    avpriv_release_buffer_pool(&s->output_pool);
+    avpriv_release_buffer_pool(&s->capture_pool);
+    avpriv_set_stream_status(&s->output_pool, VIDIOC_STREAMOFF);
+    avpriv_set_stream_status(&s->capture_pool, VIDIOC_STREAMOFF);
+    close(s->fd);
+
+    return 0;
+}
+
+int ff_v4lm2m_codec_end(AVCodecContext *avctx)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+
+    av_log(avctx, AV_LOG_DEBUG, "Closing context\n");
+
+    return avpriv_v4lm2m_end(s);
+}
diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
new file mode 100644
index 0000000..226bc3c
--- /dev/null
+++ b/libavcodec/v4l2_m2m.h
@@ -0,0 +1,69 @@ 
+/*
+ * V4L2 mem2mem helper functions
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_V4L2_M2M_H
+#define AVCODEC_V4L2_M2M_H
+
+#include "v4l2_buffers.h"
+#include "v4l2_fmt.h"
+
+#define V4L_M2M_DEFAULT_OPTS \
+    { "device",\
+        "Path to the device to use",\
+        OFFSET(devname),\
+        AV_OPT_TYPE_STRING,\
+        {.str = NULL }, 0, 0, FLAGS },\
+    { "input_memory",\
+        "Input memory model: See V4L2_MEMORY_* in videodev2.h. This depends on the HW but default should work with most but would imply useless memcpy()'s if used improperly.",\
+        OFFSET(output_pool.memory),\
+        AV_OPT_TYPE_INT,\
+        {.i64 = V4L2_MEMORY_MMAP},\
+        0, INT_MAX, FLAGS },\
+    { "output_memory",\
+        "Output memory model: See V4L2_MEMORY_* in videodev2.h. This depends on the HW but default should work with most.",\
+        OFFSET(capture_pool.memory),\
+        AV_OPT_TYPE_INT,\
+        {.i64 = V4L2_MEMORY_MMAP},\
+        0, INT_MAX, FLAGS },\
+    { "num_output_pool_buffers",\
+        "Number of buffers in the output pool",\
+        OFFSET(output_pool.num_buffers),\
+        AV_OPT_TYPE_INT,\
+        { .i64 = 16 },\
+        4, INT_MAX, FLAGS }
+
+typedef struct V4Lm2mContext
+{
+    AVClass *class;
+    int fd;
+    char *devname;
+    struct v4l2_capability cap;
+    V4LBufferPool output_pool;
+    V4LBufferPool capture_pool;
+} V4Lm2mContext;
+
+int avpriv_v4lm2m_init(V4Lm2mContext* s, void* log_ctx);
+int avpriv_set_pool_format(V4LBufferPool* bp, int set);
+int avpriv_v4lm2m_end(V4Lm2mContext* ctx);
+
+#endif /* AVCODEC_V4L2_M2M_H */
diff --git a/libavcodec/v4l2_m2m_avcodec.h b/libavcodec/v4l2_m2m_avcodec.h
new file mode 100644
index 0000000..2d0f1b6
--- /dev/null
+++ b/libavcodec/v4l2_m2m_avcodec.h
@@ -0,0 +1,32 @@ 
+/*
+ * V4L2 mem2mem avcodec helper functions
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_V4L2_M2M_AVCODEC_H
+#define AVCODEC_V4L2_M2M_AVCODEC_H
+
+#include "avcodec.h"
+
+int ff_v4lm2m_codec_init(AVCodecContext *avctx);
+int ff_v4lm2m_codec_end(AVCodecContext *avctx);
+
+#endif
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
new file mode 100644
index 0000000..2cc59c5
--- /dev/null
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -0,0 +1,229 @@ 
+/*
+ * V4L2 mem2mem decoders
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/ioctl.h>
+#include "libavutil/pixfmt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "v4l2_m2m_avcodec.h"
+#include "v4l2_fmt.h"
+#include "v4l2_buffers.h"
+#include "v4l2_m2m.h"
+#include "decode.h"
+#include "avcodec.h"
+
+static int try_start(AVCodecContext *avctx)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+    V4LBufferPool *const cap_pool = &s->capture_pool;
+    V4LBufferPool *const out_pool = &s->output_pool;
+    struct v4l2_selection selection;
+    struct v4l2_control ctrl;
+    int ret;
+
+    if (out_pool->streamon && cap_pool->streamon)
+        return 0;
+
+    /* this will report the size of the frame back (see a4lbuf_to_avframe) */
+    cap_pool->height = avctx->coded_height;
+    cap_pool->width = avctx->coded_width;
+
+    /* start the output process */
+    if (!out_pool->streamon) {
+        ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMON);
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON on output pool\n");
+            return ret;
+        }
+    }
+
+    /* get the capture format */
+    cap_pool->format.type = cap_pool->type;
+    ret = ioctl(s->fd, VIDIOC_G_FMT, &cap_pool->format);
+    if (ret) {
+        av_log(avctx, AV_LOG_ERROR, "VIDIOC_G_FMT ioctl\n");
+        return ret;
+    }
+
+    /* store what the decoder gives */
+    avctx->pix_fmt = avpriv_v4l_fmt_v4l2ff(cap_pool->format.fmt.pix_mp.pixelformat, AV_CODEC_ID_RAWVIDEO);
+    cap_pool->av_pix_fmt = avctx->pix_fmt;
+
+    /* set the crop parameters */
+    selection.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    selection.r.height = avctx->coded_height;
+    selection.r.width = avctx->coded_width;
+    ret = ioctl(s->fd, VIDIOC_S_SELECTION, &selection);
+    if (!ret) {
+        ret = ioctl(s->fd, VIDIOC_G_SELECTION, &selection);
+        if (ret) {
+            av_log(avctx, AV_LOG_ERROR, "VIDIOC_G_SELECTION ioctl\n");
+        } else {
+            av_log(avctx, AV_LOG_DEBUG, "crop output %dx%d\n", selection.r.width, selection.r.height);
+            /* update the size of the resulting frame */
+            cap_pool->height = selection.r.height;
+            cap_pool->width  = selection.r.width;
+        }
+    }
+
+    /* get the minimum number of buffers required by capture */
+    memset(&ctrl, 0, sizeof(ctrl));
+    ctrl.id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE;
+    ret = ioctl(s->fd, VIDIOC_G_CTRL, &ctrl);
+    if (!ret) {
+        cap_pool->min_queued_buffers = ctrl.value;
+    }
+
+    /* init the capture pool */
+    if (!cap_pool->buffers) {
+        ret = avpriv_init_v4lbufpool(cap_pool);
+        if (ret) {
+            av_log(avctx, AV_LOG_DEBUG, "can't request output buffers\n");
+            return ret;
+        }
+    }
+
+    /* start the capture process */
+    ret = avpriv_set_stream_status(cap_pool, VIDIOC_STREAMON);
+    if (ret) {
+        av_log(avctx, AV_LOG_DEBUG, "VIDIOC_STREAMON, on capture pool\n");
+        return ret;
+    }
+
+    return 0;
+}
+
+static av_cold int v4lm2m_decode_init(AVCodecContext *avctx)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+    V4LBufferPool *const cap_pool = &s->capture_pool;
+    V4LBufferPool *const out_pool = &s->output_pool;
+
+    out_pool->default_flags = cap_pool->default_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+    out_pool->cfg.format = cap_pool->cfg.format = avpriv_set_pool_format;
+    out_pool->height = cap_pool->height = avctx->coded_height;
+    out_pool->width = cap_pool->width =avctx->coded_width;
+
+    out_pool->cfg.init = avpriv_init_v4lbufpool;
+    out_pool->av_codec_id = avctx->codec_id;
+    out_pool->av_pix_fmt  = AV_PIX_FMT_NONE;
+
+    cap_pool->cfg.init = NULL;
+    cap_pool->av_codec_id = AV_CODEC_ID_RAWVIDEO;
+    cap_pool->av_pix_fmt = avctx->pix_fmt;
+    cap_pool->min_queued_buffers = 6;
+
+    return ff_v4lm2m_codec_init(avctx);
+}
+
+static int v4lm2m_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+    V4LBufferPool *const cap_pool = &s->capture_pool;
+    V4LBufferPool *const out_pool = &s->output_pool;
+    unsigned int timeout = 1000;
+    AVPacket avpkt = {0};
+    int ret;
+
+    ret = ff_decode_get_packet(avctx, &avpkt);
+    if (ret < 0 && ret != AVERROR_EOF)
+        return ret;
+
+    ret = avpriv_v4l_enqueue(out_pool, NULL, &avpkt);
+    if (ret < 0)
+        return ret;
+
+    ret = try_start(avctx);
+    if (ret)
+        return 0;
+
+    return avpriv_v4l_dequeue(cap_pool, frame, NULL, timeout);
+}
+
+#define OFFSET(x) offsetof(V4Lm2mContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
+
+        static const AVOption options[] = {
+        V4L_M2M_DEFAULT_OPTS,{ "num_capture_pool_extra_buffers",
+        "Number of extra buffers in the capture pool",
+        OFFSET(capture_pool.num_buffers), AV_OPT_TYPE_INT,{.i64 = 6}, 4, INT_MAX, FLAGS},
+        { NULL},
+        };
+
+#define M2MDEC(NAME, LONGNAME, CODEC, bsf_name) \
+static const AVClass v4l2_m2m_ ## NAME ## _dec_class = {\
+    .class_name = #NAME "_v4l2_m2m_decoder",\
+    .item_name  = av_default_item_name,\
+    .option     = options,\
+    .version    = LIBAVUTIL_VERSION_INT,\
+};\
+\
+AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \
+    .name           = #NAME "_v4l2m2m" ,\
+    .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " decoder wrapper"),\
+    .type           = AVMEDIA_TYPE_VIDEO,\
+    .id             = CODEC ,\
+    .priv_data_size = sizeof(V4Lm2mContext),\
+    .priv_class     = &v4l2_m2m_ ## NAME ## _dec_class,\
+    .init           = v4lm2m_decode_init,\
+    .receive_frame  = v4lm2m_receive_frame,\
+    .close          = ff_v4lm2m_codec_end,\
+    .capabilities   = CODEC_CAP_DELAY,\
+    .bsfs           = bsf_name, \
+};
+
+#if CONFIG_H263_V4L2M2M_DECODER
+        M2MDEC(h263, "H.263", AV_CODEC_ID_H263, NULL);
+#endif
+
+#if CONFIG_H264_V4L2M2M_DECODER
+        M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb");
+#endif
+
+#if CONFIG_MPEG1_V4L2M2M_DECODER
+        M2MDEC(mpeg1, "MPEG1", AV_CODEC_ID_MPEG1VIDEO, NULL);
+#endif
+
+#if CONFIG_MPEG2_V4L2M2M_DECODER
+        M2MDEC(mpeg2, "MPEG2", AV_CODEC_ID_MPEG2VIDEO, NULL);
+#endif
+
+#if CONFIG_MPEG4_V4L2M2M_DECODER
+        M2MDEC(mpeg4, "MPEG4", AV_CODEC_ID_MPEG4, NULL);
+#endif
+
+#if CONFIG_VC1_V4L2M2M_DECODER
+        M2MDEC(vc1 , "VC1", AV_CODEC_ID_VC1, NULL);
+#endif
+
+#if CONFIG_VP8_V4L2M2M_DECODER
+        M2MDEC(vp8, "VP8", AV_CODEC_ID_VP8, NULL);
+#endif
+
+#if CONFIG_HEVC_V4L2M2M_DECODER
+        M2MDEC(hevc , "HEVC", AV_CODEC_ID_HEVC, "hevc_mp4toannexb");
+#endif
+
+#if CONFIG_VP9_V4L2M2M_DECODER
+        M2MDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL);
+#endif
diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
new file mode 100644
index 0000000..bc32e33
--- /dev/null
+++ b/libavcodec/v4l2_m2m_enc.c
@@ -0,0 +1,270 @@ 
+/*
+ * V4L2 mem2mem encoders
+ *
+ * Copyright (C) 2017 Alexis Ballier <aballier@gentoo.org>
+ * Copyright (C) 2017 Jorge Ramirez <jorge.ramirez-ortiz@linaro.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/ioctl.h>
+
+#include "libavutil/pixfmt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/opt.h"
+#include "v4l2_m2m_avcodec.h"
+#include "v4l2_buffers.h"
+#include "v4l2_fmt.h"
+#include "v4l2_m2m.h"
+#include "avcodec.h"
+
+#define STR(s) AV_TOSTRING(s)
+#define MPEG_CID(x) V4L2_CID_MPEG_VIDEO_##x
+#define MPEG_VIDEO(x) V4L2_MPEG_VIDEO_##x
+
+#define SET_V4L_EXT_CTRL(TYPE, ID, VALUE, NAME)                     \
+{                                                                   \
+    struct v4l2_ext_control ctrl = { 0 };                           \
+    struct v4l2_ext_controls ctrls = { 0 };                         \
+    ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;                        \
+    ctrls.controls = &ctrl;                                         \
+    ctrl.TYPE = VALUE ;                                             \
+    ctrl.id = ID ;                                                  \
+    ctrls.count = 1;                                                \
+                                                                    \
+    if ((ret = ioctl(s->fd, VIDIOC_S_EXT_CTRLS, &ctrls)) < 0)       \
+        av_log(avctx, AV_LOG_WARNING, "Failed to set " NAME "%s\n", STR(ID));  \
+}
+
+static inline int v4l_h264_profile_from_ff(int p)
+{
+    switch(p) {
+    case FF_PROFILE_H264_CONSTRAINED_BASELINE:
+        return MPEG_VIDEO(H264_PROFILE_CONSTRAINED_BASELINE);
+    case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
+        return MPEG_VIDEO(H264_PROFILE_HIGH_444_PREDICTIVE);
+    case FF_PROFILE_H264_HIGH_422_INTRA:
+        return MPEG_VIDEO(H264_PROFILE_HIGH_422_INTRA);
+    case FF_PROFILE_H264_HIGH_444_INTRA:
+        return MPEG_VIDEO(H264_PROFILE_HIGH_444_INTRA);
+    case FF_PROFILE_H264_HIGH_10_INTRA:
+        return MPEG_VIDEO(H264_PROFILE_HIGH_10_INTRA);
+    case FF_PROFILE_H264_HIGH_422:
+        return MPEG_VIDEO(H264_PROFILE_HIGH_422);
+    case FF_PROFILE_H264_BASELINE:
+        return MPEG_VIDEO(H264_PROFILE_BASELINE);
+    case FF_PROFILE_H264_EXTENDED:
+        return MPEG_VIDEO(H264_PROFILE_EXTENDED);
+    case FF_PROFILE_H264_HIGH_10:
+        return MPEG_VIDEO(H264_PROFILE_HIGH_10);
+    case FF_PROFILE_H264_MAIN:
+        return MPEG_VIDEO(H264_PROFILE_MAIN);
+    case FF_PROFILE_H264_HIGH:
+        return MPEG_VIDEO(H264_PROFILE_HIGH);
+    }
+
+    return -1;
+}
+
+static inline int v4l_mpeg4_profile_from_ff(int p)
+{
+    switch(p) {
+    case FF_PROFILE_MPEG4_ADVANCED_CODING:
+        return MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY);
+    case FF_PROFILE_MPEG4_ADVANCED_SIMPLE:
+        return MPEG_VIDEO(MPEG4_PROFILE_ADVANCED_SIMPLE);
+    case FF_PROFILE_MPEG4_SIMPLE_SCALABLE:
+        return MPEG_VIDEO(MPEG4_PROFILE_SIMPLE_SCALABLE);
+    case FF_PROFILE_MPEG4_SIMPLE:
+        return MPEG_VIDEO(MPEG4_PROFILE_SIMPLE);
+    case FF_PROFILE_MPEG4_CORE:
+        return MPEG_VIDEO(MPEG4_PROFILE_CORE);
+    }
+
+    return -1;
+}
+
+static av_cold int v4lm2m_encode_init(AVCodecContext *avctx)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+    V4LBufferPool *const cap_pool = &s->capture_pool;
+    V4LBufferPool *const out_pool = &s->output_pool;
+    int qmin, qmax, ret, val;
+
+    out_pool->default_flags = cap_pool->default_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+    out_pool->cfg.format = cap_pool->cfg.format = avpriv_set_pool_format;
+    out_pool->cfg.init = cap_pool->cfg.init = avpriv_init_v4lbufpool;
+    out_pool->height = cap_pool->height = avctx->height;
+    out_pool->width = cap_pool->width = avctx->width;
+
+    /* out pool */
+    out_pool->av_codec_id = AV_CODEC_ID_RAWVIDEO;
+    out_pool->av_pix_fmt = avctx->pix_fmt;
+
+    /* cap pool */
+    cap_pool->av_codec_id = avctx->codec_id;
+    cap_pool->av_pix_fmt = AV_PIX_FMT_NONE;
+    cap_pool->min_queued_buffers = 1;
+
+    if (ret = ff_v4lm2m_codec_init(avctx))
+        return ret;
+
+    SET_V4L_EXT_CTRL(value, MPEG_CID(HEADER_MODE), MPEG_VIDEO(HEADER_MODE_JOINED_WITH_1ST_FRAME), "header mode");
+
+    SET_V4L_EXT_CTRL(value, MPEG_CID(B_FRAMES), avctx->max_b_frames,  "number of B-frames");
+    SET_V4L_EXT_CTRL(value, MPEG_CID(GOP_SIZE), avctx->gop_size,"gop size");
+    SET_V4L_EXT_CTRL(value, MPEG_CID(BITRATE) , avctx->bit_rate, "bit rate");
+
+    switch(avctx->codec_id) {
+    case AV_CODEC_ID_H264:
+        val = v4l_h264_profile_from_ff(avctx->profile);
+        if (val >= 0) {
+            SET_V4L_EXT_CTRL(value, MPEG_CID(H264_PROFILE), val, "h264 profile");
+        }
+        qmin = MPEG_CID(H264_MIN_QP);
+        qmax = MPEG_CID(H264_MAX_QP);
+        break;
+    case AV_CODEC_ID_MPEG4:
+        val = v4l_mpeg4_profile_from_ff(avctx->profile);
+        if (val >= 0) {
+            SET_V4L_EXT_CTRL(value, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile");
+        }
+        qmin = MPEG_CID(MPEG4_MIN_QP);
+        qmax = MPEG_CID(MPEG4_MAX_QP);
+        if (avctx->flags & CODEC_FLAG_QPEL) {
+            SET_V4L_EXT_CTRL(value, MPEG_CID(MPEG4_QPEL), 1, "qpel");
+        }
+        break;
+    case AV_CODEC_ID_H263:
+        qmin = MPEG_CID(H263_MIN_QP);
+        qmax = MPEG_CID(H263_MAX_QP);
+        break;
+    case AV_CODEC_ID_VP8:
+    case AV_CODEC_ID_VP9:
+        qmin = MPEG_CID(VPX_MIN_QP);
+        qmax = MPEG_CID(VPX_MAX_QP);
+        break;
+    default:
+        return 0;
+    }
+
+    SET_V4L_EXT_CTRL(value, qmin, avctx->qmin, "minimum video quantizer scale");
+    SET_V4L_EXT_CTRL(value, qmax, avctx->qmax, "maximum video quantizer scale");
+
+    return 0;
+}
+
+static int v4lm2m_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+                              const AVFrame *pict, int *got_packet)
+{
+    V4Lm2mContext *s = avctx->priv_data;
+    V4LBufferPool *const cap_pool = &s->capture_pool;
+    V4LBufferPool *const out_pool = &s->output_pool;
+    unsigned int timeout = 1000;
+    int ret;
+
+    /* end of transfer */
+    if (!pict) {
+        if (out_pool->streamon) {
+            ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMOFF);
+            if (ret) {
+                av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF failed on output pool\n");
+                return ret;
+            }
+        }
+        goto dequeue;
+    }
+
+    ret = avpriv_v4l_enqueue(out_pool, pict, NULL);
+    if (ret < 0)
+        return ret;
+
+    if (!out_pool->streamon) {
+        ret = avpriv_set_stream_status(out_pool, VIDIOC_STREAMON);
+        if (ret) {
+            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on output pool\n");
+            return ret;
+        }
+    }
+    if (!cap_pool->streamon) {
+        ret = avpriv_set_stream_status(cap_pool, VIDIOC_STREAMON);
+        if (ret) {
+            av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMON failed on capture pool\n");
+            return ret;
+        }
+    }
+
+dequeue:
+
+    ret = avpriv_v4l_dequeue(cap_pool, NULL, pkt, timeout);
+    if (ret == AVERROR(EAGAIN))
+        return 0;
+    if (!ret)
+        *got_packet = 1;
+
+    return ret;
+}
+
+#define OFFSET(x) offsetof(V4Lm2mContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+
+static const AVOption options[] = {
+    V4L_M2M_DEFAULT_OPTS, { "num_capture_pool_buffers", "Number of buffers in the capture pool",
+      OFFSET(capture_pool.num_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS }, { NULL },
+};
+
+#define M2MENC(NAME, LONGNAME, CODEC) \
+static const AVClass v4l2_m2m_ ## NAME ## _enc_class = {\
+    .class_name = #NAME "_v4l2_m2m_encoder",\
+    .item_name  = av_default_item_name,\
+    .option     = options,\
+    .version    = LIBAVUTIL_VERSION_INT,\
+};\
+\
+AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
+    .name           = #NAME "_v4l2m2m" ,\
+    .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"),\
+    .type           = AVMEDIA_TYPE_VIDEO,\
+    .id             = CODEC ,\
+    .priv_data_size = sizeof(V4Lm2mContext),\
+    .priv_class     = &v4l2_m2m_ ## NAME ##_enc_class,\
+    .init           = v4lm2m_encode_init,\
+    .encode2        = v4lm2m_encode_frame,\
+    .close          = ff_v4lm2m_codec_end,\
+    .capabilities   = CODEC_CAP_DELAY,\
+};
+
+#if CONFIG_H263_V4L2M2M_ENCODER
+M2MENC(h263, "H.263", AV_CODEC_ID_H263);
+#endif
+
+#if CONFIG_H264_V4L2M2M_ENCODER
+M2MENC(h264, "H.264", AV_CODEC_ID_H264);
+#endif
+
+#if CONFIG_MPEG4_V4L2M2M_ENCODER
+M2MENC(mpeg4, "MPEG4", AV_CODEC_ID_MPEG4);
+#endif
+
+#if CONFIG_VP8_V4L2M2M_ENCODER
+M2MENC(vp8, "VP8", AV_CODEC_ID_VP8);
+#endif
+
+#if CONFIG_HEVC_V4L2M2M_ENCODER
+M2MENC(hevc, "HEVC", AV_CODEC_ID_HEVC);
+#endif
+
diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c
index 0d40fd5..e9e82f6 100644
--- a/libavdevice/v4l2.c
+++ b/libavdevice/v4l2.c
@@ -44,7 +44,7 @@ 
 #include "libavutil/imgutils.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/time.h"
-#include "libavcodec/v4l2-common.h"
+#include "libavcodec/v4l2_fmt.h"
 #include "libavformat/internal.h"
 #include "libavdevice/avdevice.h"
 #include "libavdevice/timefilter.h"
diff --git a/libavdevice/v4l2enc.c b/libavdevice/v4l2enc.c
index f2fc8f4..11ca7a8 100644
--- a/libavdevice/v4l2enc.c
+++ b/libavdevice/v4l2enc.c
@@ -26,7 +26,7 @@ 
 
 #include "libavutil/imgutils.h"
 #include "libavutil/pixdesc.h"
-#include "libavcodec/v4l2-common.h"
+#include "libavcodec/v4l2_fmt.h"
 #include "libavdevice/avdevice.h"
 
 typedef struct {
diff --git a/tests/ref/fate/source b/tests/ref/fate/source
index 2def034..f6fd69c 100644
--- a/tests/ref/fate/source
+++ b/tests/ref/fate/source
@@ -30,5 +30,8 @@  compat/cuda/dynlink_nvcuvid.h
 compat/float/float.h
 compat/float/limits.h
 compat/nvenc/nvEncodeAPI.h
+compat/v4l2/v4l2-common.h
+compat/v4l2/v4l2-controls.h
+compat/v4l2/videodev2.h
 Use of av_clip() where av_clip_uintp2() could be used:
 Use of av_clip() where av_clip_intp2() could be used: