diff --git a/content.tex b/content.tex
index 620c0e2..8b8bfed 100644
--- a/content.tex
+++ b/content.tex
@@ -6507,6 +6507,7 @@ \subsubsection{Legacy Interface: Framing Requirements}\label{sec:Device
 \input{virtio-iommu.tex}
 \input{virtio-sound.tex}
 \input{virtio-mem.tex}
+\input{virtio-video.tex}
 
 \chapter{Reserved Feature Bits}\label{sec:Reserved Feature Bits}
 
diff --git a/images/video-buffer-lifecycle.dot b/images/video-buffer-lifecycle.dot
new file mode 100644
index 0000000..d5ef184
--- /dev/null
+++ b/images/video-buffer-lifecycle.dot
@@ -0,0 +1,15 @@
+digraph {
+  graph [ rankdir = LR, layout = dot ];
+
+  init [label="Init", shape=circle]
+  attached [label="Attached", shape=circle]
+  queued [label="Queued", shape=circle]
+
+  init -> attached [label="ATTACH"]
+
+  attached -> queued [label="QUEUE"]
+  queued -> attached [label="Processing\n complete"]
+
+  attached -> init [label="CLEAR"]
+  queued -> init [label="CLEAR"]
+}
diff --git a/make-setup-generated.sh b/make-setup-generated.sh
index f15d148..073b094 100755
--- a/make-setup-generated.sh
+++ b/make-setup-generated.sh
@@ -61,3 +61,12 @@ cat > setup-generated.tex <<EOF
 \newcommand{\virtiodraftstagename}{$STAGENAME}
 \newcommand{\virtiodraftoasisstagename}{$OASISSTAGENAME}
 EOF
+
+# Generate PNG from DOT
+mkdir -p images/generated
+for file in images/*.dot
+do
+    BASENAME=`basename "$file" .dot`
+    dot -Tpng -o images/generated/${BASENAME}.png ${file}
+done
+
diff --git a/virtio-video.tex b/virtio-video.tex
new file mode 100644
index 0000000..9adac0d
--- /dev/null
+++ b/virtio-video.tex
@@ -0,0 +1,1308 @@
+\section{Video Device}\label{sec:Device Types / Video Device}
+
+The virtio video encoder and decoder devices are virtual devices that support
+video encoding and decoding, respectively. Despite being different devices, they
+use the same protocol.
+
+% TODO: be more precise about the sync or async nature of commands/responses.
+
+\subsection{Device ID}
+\label{sec:Device Types / Video Device / Device ID}
+
+\begin{description}
+\item[30] encoder device
+\item[31] decoder device
+\end{description}
+
+\subsection{Virtqueues}
+\label{sec:Device Types / Video Device / Virtqueues}
+
+\begin{description}
+\item[0] commandq - queue for driver commands and device responses to these
+  commands.
+\item[1] eventq - queue for events sent by the device to the driver.
+\end{description}
+
+\subsection{Feature bits}
+\label{sec:Device Types / Video Device / Feature bits}
+
+\begin{description}
+\item[VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES (0)] Guest pages can be used as the
+  backing memory of video buffers.
+\item[VIRTIO_VIDEO_F_RESOURCE_NON_CONTIG (1)] The device can use non-contiguous
+  memory for video buffers. Without this flag, the driver and device MUST use
+  video buffers that are contiguous for the device.
+\item[VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT (2)] Objects exported by another
+  virtio device can be used as the backing memory of video buffers.
+\end{description}
+
+The device MUST present at least one of VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES or
+VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT, since the absence of both bits would mean
+that no memory can be used at all for buffers.
+
+\subsection{Device configuration layout}
+\label{sec:Device Types / Video Device / Device configuration layout}
+
+Video device configuration uses the following layout structure:
+
+\begin{lstlisting}
+struct virtio_video_config {
+        le32 version;
+        le32 caps_length;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{version}] is the protocol version that the device understands. The
+  device MUST set this to 0.
+\item[\field{caps_length}] is the length in bytes of a device-writable
+  descriptor that can receive the response of
+  VIRTIO_VIDEO_CMD_DEVICE_QUERY_CAPS. The device MUST set it to a sufficiently
+  large value.
+\end{description}
+
+\subsection{Device Initialization}
+\label{sec:Device Types / Video Device / Device Initialization}
+
+\devicenormative{\subsubsection}{Device Initialization}{Device Types /
+  Video Device / Device Initialization}
+
+The driver SHOULD query the device capabilities using the
+VIRTIO_VIDEO_CMD_DEVICE_QUERY_CAPS command.
+
+\subsection{General Device Operation}
+\label{sec:Device Types / Video Device / Device Operation}
+
+The driver requests a new stream to be created using
+VIRTIO_VIDEO_CMD_STREAM_CREATE.
+
+It then invokes VIRTIO_VIDEO_CMD_STREAM_GET_PARAMS to retrieve the default
+parameters of the stream, modifies them to fit its needs using the device
+capabilities information queried during initialization, and calls
+VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS to apply them. The device might change the
+requested parameters to suit its own limitation, so the driver MUST check that
+the applied parameters are still acceptable, and keep adjusting them with
+subsequent calls to VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS until a mutually
+satisfying configuration is found.
+
+Each stream has one input and one output queue. The input queue accepts buffers
+in the configured input format (e.g. bitstream format for a decoder) and returns
+them once they are done being processed. The output queue accepts buffers in the
+configured output format (e.g. image format for a decoder) and will write the
+result of the decoding or encoding operation to them, i.e. a frame for a
+decoder, or a chunk of encoded stream for an encoder. There is no direct 1:1
+relationship between input and output buffers, meaning that queueing one input
+buffer can result in zero, one, or more output buffers to be emitted. The driver
+can think of the queues as operating independently from each other.
+
+Once the stream is configured, the driver attaches backing memory to buffer
+resources using VIRTIO_VIDEO_CMD_RESOURCE_ATTACH, and queues them using
+VIRTIO_VIDEO_CMD_RESOURCE_QUEUE. The device will respond once the buffer is
+processed, which then allows the driver to queue that buffer again.
+
+The driver has control over the stream: it can request for all queued input
+buffers so far to be processed and receive a notification when they are (useful
+at the end of a stream) using VIRTIO_VIDEO_CMD_STREAM_DRAIN, or abandon all
+pending operations (in order to, say, seek to a different point) with
+VIRTIO_VIDEO_CMD_STREAM_QUEUE_CLEAR.
+
+Sometimes the device will detect events that require intervention from the
+driver and signal them. One such event is
+VIRTIO_VIDEO_EVENT_DECODER_RESOLUTION_CHANGED for a decoder, meaning that the
+resolution of the stream has changed, and that the driver might need to
+reallocate the backing memory for its buffers.
+
+Once a stream is completed, it can be closed using
+VIRTIO_VIDEO_CMD_STREAM_DESTROY.
+
+The remainder of this section describes all the commands and events mentioned
+above.
+
+\subsubsection{Command Virtqueue}
+
+The command virtqueue is used for the driver to send commands to the device, and
+receive the device's response. Commands MUST be written by the driver and their
+responses MUST be written by the device in the next device-writable descriptor.
+
+Different structure layouts are used for each command and response. A command
+structure starts with the requested command code, defined as follows:
+\begin{lstlisting}
+enum virtio_video_cmd_type {
+        /* Global */
+        VIRTIO_VIDEO_CMD_DEVICE_QUERY_CAPS = 0x100,
+
+        /* Stream */
+        VIRTIO_VIDEO_CMD_STREAM_CREATE = 0x200,
+        VIRTIO_VIDEO_CMD_STREAM_DESTROY,
+        VIRTIO_VIDEO_CMD_STREAM_GET_PARAMS,
+        VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS,
+        VIRTIO_VIDEO_CMD_STREAM_DRAIN,
+
+        /* Queue */
+        VIRTIO_VIDEO_CMD_QUEUE_CLEAR = 0x300,
+
+        /* Resource*/
+        VIRTIO_VIDEO_CMD_RESOURCE_ATTACH = 0x400,
+        VIRTIO_VIDEO_CMD_RESOURCE_QUEUE,
+};
+\end{lstlisting}
+
+A response structure starts with the result of the requested command, defined as
+follows:
+\begin{lstlisting}
+enum virtio_video_result {
+         /* Success */
+         VIRTIO_VIDEO_RESULT_OK = 0x000,
+
+         /* Error */
+         VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION = 0x100,
+         VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID,
+         VIRTIO_VIDEO_RESULT_ERR_INVALID_RESOURCE_ID,
+         VIRTIO_VIDEO_RESULT_ERR_INVALID_ARGUMENT,
+         VIRTIO_VIDEO_RESULT_ERR_CANCELED,
+         VIRTIO_VIDEO_RESULT_ERR_OUT_OF_MEMORY,
+};
+\end{lstlisting}
+
+For response structures carrying an error code, the rest of the structure is
+considered invalid and must be ignored by the driver. Only response structures
+carrying VIRTIO_VIDEO_RESULT_OK shall be examined further.
+
+\paragraph{Device capabilities}
+
+\subparagraph{VIRTIO_VIDEO_CMD_DEVICE_QUERY_CAPS}
+Retrieve device capabilities.
+
+The driver sends this command with \field{struct
+virtio_video_device_query_caps}:
+\begin{lstlisting}
+struct virtio_video_device_query_caps {
+        le32 cmd_type;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be set to VIRTIO_VIDEO_CMD_DEVICE_QUERY_CAPS.
+\end{description}
+
+The total size of the device response to this command MUST be equal to
+\field{caps_length} bytes, as reported by the device configuration. The device
+responds with \field{struct virtio_video_device_query_caps_resp}:
+\begin{lstlisting}
+struct virtio_video_device_query_caps_resp {
+        le32 result; /* VIRTIO_VIDEO_RESULT_* */
+        le32 num_image_formats;
+        le32 num_bitstream_formats;
+        /**
+         * Followed by
+         * struct virtio_video_image_format_desc image_formats[num_image_formats];
+         */
+        /**
+         * Followed by
+         * struct virtio_video_bitstream_format_desc bitstream_formats[num_bitstream_formats];
+         */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_OUT_OF_MEMORY] if the descriptor was smaller
+    than the defined \field{caps_length} in the video device configuration.
+  \end{description*}
+\item[\field{num_image_formats}] is the number of supported image formats.
+\item[\field{num_bitstream_formats}] is the number of supported bitstream
+  formats.
+\end{description}
+
+The device MUST write two arrays of \field{struct
+  virtio_video_image_format_desc} and \field{struct
+  virtio_video_bitstream_format_desc} following the \field{struct
+  virtio_video_device_query_caps_resp}. The lengths of these arrays MUST be
+\field{num_image_formats} and \field{num_bitstream_formats} respectively.
+
+\subparagraph{Image format description}
+
+The image format description \field{virtio_video_image_format_desc} is defined
+as follows:
+\begin{lstlisting}
+enum virtio_video_planes_layout {
+        VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER = 0,
+        VIRTIO_VIDEO_PLANES_LAYOUT_MULTI_BUFFERS,
+};
+
+struct virtio_video_image_format_desc {
+         le32 format; /* VIRTIO_VIDEO_IMAGE_FORMAT_* */
+         le32 planes_layouts; /* Bitmask with VIRTIO_VIDEO_PLANES_LAYOUT_* */
+         le32 plane_align;
+         le32 num_format_frames;
+         /**
+          * Followed by
+          * struct virtio_video_image_format_frame frames[num_format_frames];
+          */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{format}] specifies an image format. The device MUST set one of the
+  variants of \field{enum virtio_video_image_format_frame}. See \ref{sec:Device
+  Types / Video Device / Supported formats} for a list of all valid formats.
+\item[\field{planes_layouts}] is a bitmask representing the set of plane layout
+  types that the device supports.
+  \begin{description}
+  \item[\field{VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER}] The device expects the
+    planes of a frame to be laid out one after another in the same buffer.
+  \item[\field{VIRTIO_VIDEO_PLANES_LAYOUT_MULTI_BUFFERS}] The device expects the
+    planes of a frame to be laid out in separate buffers.
+  \end{description}
+\item[\field{plane_align}] is the plane alignment the device requires when
+  multiple planes are located in the same buffer. This field is valid only if
+  \field{planes_layouts} has the
+  \field{VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER} bit, and MUST be set to zero
+  otherwise.
+\item[\field{num_format_frames}] is the number of
+  \field{virtio_video_image_format_frame} that follow.
+\end{description}
+
+The frame information \field{virtio_video_image_format_frame} is defined as
+follows:
+\begin{lstlisting}
+struct virtio_video_image_format_range {
+       le32 min;
+       le32 max;
+       le32 step;
+};
+
+struct virtio_video_image_format_frame {
+       struct virtio_video_image_format_range width;
+       struct virtio_video_image_format_range height;
+       le32 num_rates;
+       /**
+        * Followed by
+        * struct virtio_video_image_format_range frame_rates[num_rates];
+        */
+};
+\end{lstlisting}
+
+The value of \field{struct virtio_video_image_format_range} is used to represent
+the range of values supported by the device. The device MUST set \field{step} to
+a positive integer. An integer \(x\) is in a range \field{struct
+  virtio_video_image_format_range r} if \(\field{r.min} \le x \le
+\field{r.max}\) holds and \(x\) is equals to \((\field{min} + \field{step} *
+n)\) for some integer \(n\).
+
+\begin{description}
+\item[\field{width}] represents the range of widths supported by the device for
+this format.
+\item[\field{height}] represents the range of heights supported by the device
+for this format.
+\item[\field{num_rates}] is the length of the \field{frame_rates[]} array.
+% TODO we cannot support fractional rates (e.g. 29.999997 fps) with this
+% representation, can we?
+\item[\field{frame_rates}] is the set of frame rates ranges (in frames per
+  second) supported by the device for this format.
+\end{description}
+
+\subparagraph{Bitstream format description}
+
+The bitstream format description \field{virtio_video_bitstream_format_desc} is
+defined as follows:
+\begin{lstlisting}
+struct virtio_video_bitstream_format_desc {
+        le32 virtio_video_codec codec;
+        le32 num_variants;
+        /**
+         * Followed by
+         * union virtio_video_codec_params variants[num_variants];
+         */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{codec}] specifies a codec. This field MUST be set to one of the
+  variants of \field{enum virtio_video_codec}. See \ref{sec:Device Types / Video
+  Device / Supported formats} for a list of all supported codecs formats.
+\item[\field{num_variants}] is the number of \field{union
+  virtio_video_codec_params} values that follow. If \field{union
+  virtio_video_codec_params} has a field corresponding to the specified
+  \field{codec}, this value MUST be a positive integer. Otherwise, it MUST be 0.
+  See \ref{sec:Device Types / Video Device / Supported formats} for a complete
+  description of the variants.
+\item[\field{variants}] is a list of supported variants of the given
+  \field{codec}. Only the field corresponding to the given \field{codec} is
+  valid for each element.
+\end{description}
+
+\paragraph{Stream commands}
+
+\subparagraph{VIRTIO_VIDEO_CMD_STREAM_CREATE}
+Create a video stream using the device.
+
+The driver sends this command with \field{struct virtio_video_stream_create}:
+\begin{lstlisting}
+enum virtio_video_mem_type {
+       VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES = 1,
+       VIRTIO_VIDEO_MEM_TYPE_VIRTIO_OBJECT,
+};
+
+struct virtio_video_stream_create {
+        le32 cmd_type;
+        le32 in_mem_type; /* VIRTIO_VIDEO_MEM_TYPE_* */
+        le32 out_mem_type; /* VIRTIO_VIDEO_MEM_TYPE_* */
+        le32 codec; /* VIRTIO_VIDEO_CODEC_* */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be set to VIRTIO_VIDEO_CMD_STREAM_CREATE.
+\item[\field{in_mem_type, out_mem_type}] is the type of buffer management for
+  input/output buffers.
+\begin{description}
+\item[\field{VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES}] Use guest pages. The driver
+  MUST NOT use this value if the feature bit VIRTIO_VIDEO_F_RESOURCE_GUEST_PAGES
+  is not set.
+\item[\field{VIRTIO_VIDEO_MEM_TYPE_VIRTIO_OBJECT}] Use object exported by
+  another virtio device. The driver MUST NOT use this value if the feature bit
+  VIRTIO_VIDEO_F_RESOURCE_VIRTIO_OBJECT is not set.
+\end{description}
+\item[\field{codec}] is the video codec that will be used with this stream (i.e.
+  as input for a decoder, and as output for an encoder). The driver MUST set it
+  to one of the variants of \field{enum virtio_video_codec} (see \ref{sec:Device
+  Types / Video Device / Supported formats} for a list of supported values).
+\end{description}
+
+The device responds with \field{struct virtio_video_stream_create_resp}:
+\begin{lstlisting}
+struct virtio_video_stream_create_resp {
+        le32 result; /* VIRTIO_VIDEO_RESULT_* */
+        le32 stream_id;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_ARGUMENT] if the memory type
+    specified for \field{in_mem_type} or \field{out_mem_type} is not supported,
+    or if an unsupported codec has been specified in \field{codec}.
+    \item[VIRTIO_VIDEO_RESULT_ERR_OUT_OF_MEMORY] if the limit of simultaneous
+    streams has been reached on the device and no more can be created.
+  \end{description*}
+\item[\field{stream_id}] is the ID of the created stream, allocated by the
+  device.
+\end{description}
+
+\subparagraph{VIRTIO_VIDEO_CMD_STREAM_DESTROY}
+Destroy a video stream and all its resources. Any activity on the stream is
+halted and all resources released by the time the response is received by the
+driver.
+
+The driver sends this command with \field{struct virtio_video_stream_destroy}:
+\begin{lstlisting}
+struct virtio_video_stream_destroy {
+         le32 cmd_type;
+         le32 stream_id;
+};
+\end{lstlisting}
+\begin{description}
+\item{\field{cmd_type}} MUST be set to VIRTIO_VIDEO_CMD_STREAM_DESTROY.
+\item{\field{stream_id}} is the ID of the stream to be destroyed. It must be set
+to the value of an existing stream.
+\end{description}
+
+The device responds with \field{struct virtio_video_stream_destroy_resp}:
+\begin{lstlisting}
+struct virtio_video_stream_destroy_resp {
+         le32 result; /* VIRTIO_VIDEO_RESULT_* */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream ID
+    does not exist.
+  \end{description*}
+\end{description}
+
+Before the device sends a response for VIRTIO_VIDEO_CMD_STREAM_DESTROY, it MUST
+respond with VIRTIO_VIDEO_RESULT_ERR_CANCELED to the following pending commands:
+\begin{itemize*}
+\item VIRTIO_VIDEO_CMD_RESOURCE_* on the input queue,
+\item VIRTIO_VIDEO_CMD_STREAM_DRAIN.
+\end{itemize*}
+
+\subparagraph{VIRTIO_VIDEO_CMD_STREAM_GET_PARAMS}
+Obtain a stream's parameters.
+
+The driver sends this command with \field{struct
+  virtio_video_stream_get_params}:
+\begin{lstlisting}
+struct virtio_video_stream_get_params {
+    le32 cmd_type;
+    le32 stream_id;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be set to VIRTIO_VIDEO_CMD_STREAM_GET_PARAMS.
+\item[\field{stream_id}] MUST be set to the ID of an existing stream, whose
+  parameters will be returned.
+\end{description}
+
+The device responds with \field{struct virtio_video_stream_get_params_resp}:
+\begin{lstlisting}
+struct virtio_video_stream_get_params_resp {
+    le32 result; /* VIRTIO_VIDEO_RESULT_* */
+    struct virtio_video_params params;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream
+    does not exist.
+  \end{description*}
+\item[\field{params}] contains the parameters of the requested stream.
+\end{description}
+
+The struct \field{virtio_video_params} is defined as follows. Some of these
+parameters can be updated by the driver with VIRTIO_VIDEO_CMD_SET_PARAMS.
+\begin{lstlisting}
+struct virtio_video_crop {
+        le32 left;
+        le32 top;
+        le32 width;
+        le32 height;
+};
+
+enum virtio_video_rate_control {
+        VIRTIO_VIDEO_RATE_CONTROL_FRAME = 1,
+        VIRTIO_VIDEO_RATE_CONTROL_MACRO_BLOCK,
+};
+
+struct virtio_video_rc_range {
+        le32 min_qp;
+        le32 max_qp;
+};
+
+struct virtio_video_frame_qp {
+        le32 iframe_qp;
+        le32 pframe_qp;
+        le32 bframe_qp;
+};
+
+union virtio_video_quantization_param {
+        struct virtio_video_rc_range rc;
+        struct virtio_video_frame_qp no_rc;
+};
+
+struct virtio_video_params {
+        /* Image format */
+        le32 image_format; /* VIRTIO_VIDEO_IMAGE_FORMAT_* */
+        le32 min_image_buffers;
+        le32 max_image_buffers;
+        le32 cur_image_buffers;
+        le32 width;
+        le32 height;
+        struct virtio_video_crop crop;
+        le32 frame_rate;
+        le32 planes_layout;
+        le32 num_planes;
+        struct virtio_video_plane_format
+        plane_formats[VIRTIO_VIDEO_MAX_PLANES];
+
+        /* Bitstream format */
+        le32 min_bitstream_buffers;
+        le32 max_bitstream_buffers;
+        le32 cur_bitstream_buffers;
+
+        /* Bitrate  (for encoder) */
+        le32 min_bitrate;
+        le32 max_bitrate;
+        le32 cur_bitrate;
+
+        /* Quantization parameter (for encoder) */
+        le32 rc_mode; /* VIRTIO_VIDEO_RATE_CONTROL_* */
+        union virtio_video_quantization_param qp;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{image_format}] is the image format used by the stream. It is set to
+  one of the variants of \field{enum virtio_video_image_format}.
+\item[\field{min_image_buffers}] is the minimum number of image buffers that the
+  device requires. The device MUST set this to a non-zero integer. For a decoder
+  device, the device MUST set this to the minimum number of buffers required to
+  decode the stream after it has obtained this information.
+\item[\field{max_image_buffers}] is the maximum number of image buffers that the
+  device can accept. The device MUST set this to an integer larger than or equal
+  to \field{min_image_buffers}.
+\item[\field{cur_image_buffers}] is the number of image buffers that the driver
+  can enqueue via VIRTIO_VIDEO_RESOURCE_QUEUE. The device MUST initially set
+  this field to \field{min_image_buffers}, and the driver CAN update it to a
+  value between \field{min_image_buffers} and \field{max_image_buffers}
+  included.
+\item[\field{width}] is the current width of frames in the stream.
+\item[\field{height}] is the current height of frames in the stream.
+\item[\field{crop}] is the current cropping rectangle for frames in the stream.
+\item[\field{frame_rate}] is the current frame rate.
+\item[\field{planes_layout}] specifies the plane layout of the frames. The
+  driver MUST set this to one of the variants of \field{enum
+  virtio_video_planes_layout} that is supported for the current image format.
+\item[\field{num_planes}] is the number of planes per frame. The device MUST set
+  this to 1 if \field{planes_layout} is
+  VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER.
+\item[\field{plane_formats}] is an array containing the current planes format.
+  Only the first |\field{num_planes}| elements are valid. The struct
+  \field{virtio_video_plane_format} is defined as follows.
+\begin{lstlisting}
+struct virtio_video_plane_format {
+        le32 plane_size;
+        le32 stride;
+        le32 offset;
+};
+\end{lstlisting}
+\begin{description}
+\item[plane_size] is the size of the plane in bytes.
+\item[stride] is the line stride.
+\item[offset] is an offset from the beginning of the buffer. This field is valid
+  only if \field{planes_layout} is VIRTIO_VIDEO_PLANES_LAYOUT_SINGLE_BUFFER.
+\end{description}
+\item[\field{min_bitstream_buffers}] is the minimum number of bitstream buffers
+  that the device requires. The device MUST set this to a non-zero integer.
+\item[\field{max_bitstream_buffers}] is the maximum number of bitstream buffers
+  that the device can accept. The device MUST set this to an integer which is
+  larger than or equal to \field{min_bitstream_buffers}.
+\item[\field{cur_bitstream_buffers}] is the number of bitstream buffers that the
+  driver can enqueue via VIRTIO_VIDEO_RESOURCE_QUEUE. The device MUST initially
+  set this field to \field{min_bitstream_buffers}, and the driver CAN update it
+  to a value between \field{min_bitstream_buffers} and
+  \field{max_bitstream_buffers} included.
+\item[\field{min_bitrate}] is the minimum bitrate supported by the device. (only
+  for encoders)
+\item[\field{max_bitrate}] is the maximum bitrate supported by the
+  device. (only for encoders)
+\item[\field{cur_bitrate}] is the current bitrate of the stream. (only for
+  encoders)
+\item[\field{rc_mode}] whether rate control is enabled for the stream. If
+  this value is one of variants of \field{enum virtio_video_rate_control}, the
+  rate control described below is enabled. Otherwise, the quantization parameter
+  for each frame type is constant and set with \field{qp.no_rc}. (only for
+  encoders)
+  \begin{description}
+  \item[\field{VIRTIO_VIDEO_RATE_CONTROL_FRAME}] Frame level rate control is
+    enabled. In this mode, the quantization parameter is adjusted according to
+    \field{cur_bitrate}. Minimum and maximum value for the quantization
+    parameter can be set with \field{qp.rc}.
+  \item[\field{VIRTIO_VIDEO_RATE_CONTROL_MACRO_BLOCK}] Macroblock level rate
+    control is enabled. (only for MPEG4 and H.264 encoders)
+  \end{description}
+\item[\field{qp}] is the quantization parameter. (only for encoders)
+\end{description}
+
+Note that the bitstream format is not represented in the parameters; that's
+because it is decided at the time of stream creation and does not change
+afterwards.
+
+After the device responds to VIRTIO_VIDEO_CMD_STREAM_GET_PARAMS, it MUST
+keep responding the same value until one of the following events occurs:
+\begin{itemize}
+\item the driver sends VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS via commandq.
+\item the device reports VIRTIO_VIDEO_EVENT_DECODER_RESOLUTION_CHANGED
+via eventq.
+\end{itemize}
+
+\subparagraph{VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS}
+Update the parameters of a stream.
+
+The driver sends this command with \field{struct
+  virtio_video_stream_set_params}:
+\begin{lstlisting}
+struct virtio_video_stream_set_params {
+        le32 cmd_type;
+        le32 stream_id;
+        struct virtio_video_params params;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be set to VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS.
+\item[\field{stream_id}] is the ID of the stream whose parameters are to be
+  updated.
+\item[\field{params}] the new parameters requested by the driver.
+\end{description}
+
+The device responds with \field{struct virtio_video_stream_set_params_resp}:
+\begin{lstlisting}
+struct virtio_video_stream_set_params_resp {
+       le32 result; /* VIRTIO_VIDEO_RESULT_* */
+       struct virtio_video_params params;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream
+    does not exist,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION] is setting parameters is
+    not valid at the moment. Setting parameters is only valid when no drain or
+    clear operation is in progress.
+  \end{description*}
+\item[\field{params}] the updated stream parameters. Values may differ from the
+    requested one depending on the device's and codec capabilities, and values
+    that are not directly changed by the SET_PARAMS command may also be changed.
+    It is the responsibility of the driver to check all values for potential
+    changes and update its state accordingly.
+
+    The device MUST react to invalid or out-of-range parameters not by returning
+    an error, but by adjusting the invalid value to the closest valid value it
+    can support. Therefore, a successful result does not mean that all the
+    parameters have been applied as specified, and the driver still needs to
+    check the actual values set by the device and continue (or abort)
+    accordingly.
+\end{description}
+
+Not all parameters can be updated by the driver. Table~\ref{tab:set_params}
+lists the parameters that can be read and written by an encoder or decoder.
+
+\begin{table}[ht]
+  \centering
+  \begin{tabular}{|l|c|c|}
+  \hline
+  Parameter             & Decoder & Encoder \\
+  \hline
+  image_format          &   R/W   &   R/W   \\
+  min_image_buffers     &    R    &    R    \\
+  max_image_buffers     &    R    &    R    \\
+  cur_image_buffers     &   R/W   &   R/W   \\
+  width                 &   R/W   &   R/W   \\
+  height                &   R/W   &   R/W   \\
+  crop                  &   R/W   &   R/W   \\
+  frame_rate            &    R    &   R/W   \\
+  planes_layout         &   R/W   &   R/W   \\
+  num_planes            &    R    &    R    \\
+  plane_formats         &   R/W   &   R/W   \\
+  \hline
+  min_bitstream_buffers &    R    &    R    \\
+  max_bitstream_buffers &    R    &    R    \\
+  cur_bitstream_buffers &   R/W   &   R/W   \\
+  \hline
+  min_bitrate           &    -    &    R    \\
+  max_bitrate           &    -    &    R    \\
+  cur_bitrate           &    -    &   R/W   \\
+  rc_mode               &    -    &   R/W   \\
+  qp                    &    -    &   R/W   \\
+  \hline
+  \end{tabular}
+  \caption{Parameters that can be read or written by the driver, for encoder and decoder devices. "-" means that the value is not available and MUST NOT be accessed by the driver.}
+  \label{tab:set_params}
+\end{table}
+
+\subparagraph{VIRTIO_VIDEO_CMD_STREAM_DRAIN}
+Complete processing all currently queued input buffers.
+
+VIRTIO_VIDEO_CMD_STREAM_DRAIN ensures that all sent
+VIRTIO_VIDEO_CMD_RESOURCE_QUEUE commands for input buffers have been processed
+by the device and that related output buffers are available to the driver.
+
+The driver sends this command with \field{struct virtio_video_stream_drain}:
+\begin{lstlisting}
+struct virtio_video_stream_drain {
+        le32 cmd_type;
+        le32 stream_id;
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be VIRTIO_VIDEO_CMD_STREAM_DRAIN.
+\item[\field{stream_id}] is a valid stream ID.
+\end{description}
+
+The device responds with \field{struct virtio_video_stream_drain_resp}:
+\begin{lstlisting}
+struct virtio_video_stream_drain_resp {
+        le32 result; /* VIRTIO_VIDEO_RESULT_* */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream
+    does not exist,
+    \item[VIRTIO_VIDEO_RESULT_ERR_CANCELED] if the operation has been canceled by
+    a STREAM_QUEUE_CLEAR or STREAM_DESTROY operation.
+  \end{description*}
+\end{description}
+
+Before the device sends the response of a VIRTIO_VIDEO_CMD_STREAM_DRAIN command,
+it MUST process and respond to all of VIRTIO_VIDEO_CMD_RESOURCE_* commands for
+the input queue which are sent before the drain command, and produce all the
+corresponding output buffers. The driver is expected to keep queueing output
+buffers until it gets the response ; failure to do so may result in the device
+stalling as it awaits output buffers.
+
+While the device is processing a VIRTIO_VIDEO_CMD_STREAM_DRAIN command, it MUST
+return VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION to the following incoming
+commands:
+\begin{itemize*}
+\item VIRTIO_VIDEO_CMD_RESOURCE_* with an input buffer, or
+\item VIRTIO_VIDEO_CMD_STREAM_DRAIN.
+\end{itemize*}
+
+If the processing was stopped while draining due to a
+VIRTIO_VIDEO_CMD_QUEUE_CLEAR or VIRTIO_VIDEO_CMD_STREAM_DESTROY operation, the
+device MUST respond with VIRTIO_VIDEO_RESULT_ERR_CANCELED.
+
+\paragraph{Queue commands}
+
+\subparagraph{VIRTIO_VIDEO_CMD_QUEUE_CLEAR}
+Discard all pending resource commands for a given queue and detach all its
+resources.
+
+The driver sends this command with \field{struct virtio_video_queue_clear}:
+\begin{lstlisting}
+enum virtio_video_queue_type {
+        VIRTIO_VIDEO_QUEUE_TYPE_INPUT = 1,
+        VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT,
+};
+
+struct virtio_video_queue_clear {
+        le32 cmd_type;
+        le32 stream_id;
+        le32 queue_type; /* One of VIRTIO_VIDEO_QUEUE_TYPE_* types */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be VIRTIO_VIDEO_CMD_QUEUE_CLEAR.
+\item[\field{stream_id}] is a valid stream ID.
+\item[\field{queue_type}] is the queue to be cleared. This MUST be one of
+  variants of \field{enum virtio_video_queue_type}.
+\end{description}
+
+The device responds with \field{struct virtio_video_queue_clear_resp}:
+\begin{lstlisting}
+struct virtio_video_queue_clear_resp {
+        le32 result; /* VIRTIO_VIDEO_RESULT_* */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream
+    does not exist,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_ARGUMENT] if the \field{queue_type}
+    parameter has a non-valid value.
+  \end{description*}
+\end{description}
+
+Before the device sends a response for VIRTIO_VIDEO_CMD_QUEUE_CLEAR, it MUST
+respond with VIRTIO_VIDEO_RESULT_ERR_CANCELED to the following pending commands:
+\begin{itemize*}
+\item VIRTIO_VIDEO_CMD_RESOURCE_* on the input queue,
+\item VIRTIO_VIDEO_CMD_STREAM_DRAIN.
+\end{itemize*}
+
+While the device is processing a VIRTIO_VIDEO_CMD_QUEUE_CLEAR, it MUST return
+VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION to the following incoming commands:
+\begin{itemize*}
+\item VIRTIO_VIDEO_CMD_STREAM_DRAIN,
+\item VIRTIO_VIDEO_CMD_QUEUE_CLEAR, or
+\item VIRTIO_VIDEO_CMD_RESOURCE_*.
+\end{itemize*}
+
+After completion of the command, all the resources previously attached to the
+queue using VIRTIO_VIDEO_CMD_RESOURCE_ATTACH will be detached. This means
+VIRTIO_VIDEO_CMD_RESOURCE_ATTACH must be called on each resource before it can
+be queued again.
+
+\paragraph{Resource commands}
+
+\subparagraph{VIRTIO_VIDEO_CMD_RESOURCE_ATTACH}
+Attach memory entries to use as a buffer for a given resource.
+
+The driver sends this command with \field{struct virtio_video_resource_attach}:
+\begin{lstlisting}
+struct virtio_video_resource_attach {
+        le32 cmd_type;
+        le32 stream_id;
+        le32 queue_type; /* VIRTIO_VIDEO_QUEUE_TYPE_* */
+        le32 resource_id;
+        union virtio_video_resource resources[];
+};
+
+struct virtio_video_resource_attach_resp {
+        le32 result; /* VIRTIO_VIDEO_RESULT_* */
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be set to VIRTIO_VIDEO_CMD_RESOURCE_ATTACH.
+\item[\field{stream_id}] is the ID of the stream.
+\item[\field{queue_type}] is the direction of the queue.
+\item[\field{resource_id}] is the ID of the resource. If the \field{queue_type}
+  indicates the queue for an image format, \field{resource_id} MUST be an
+  integer less than \field{cur_image_buffers} in \field{virtio_video_params}
+  obtained via VIRTIO_VIDEO_GET_PARAMS. Otherwise, \field{resource_id} MUST be
+  less than \field{cur_bitstream_buffers}.
+\item[\field{resources}] specifies memory regions that will be attached. The
+  length of this array MUST be equal to \field{num_planes} in
+  \field{virtio_video_params}, as obtained via VIRTIO_VIDEO_GET_PARAMS.
+
+  The union \field{virtio_video_resource} is defined as follows:
+  \begin{lstlisting}
+union virtio_video_resource {
+        struct virtio_video_resource_sg_list sg_list;
+        struct virtio_video_resource_object object;
+};
+\end{lstlisting}
+\begin{description}
+  \item[sg_list] represents a scatter-gather list. This field is valid when
+    VIRTIO_VIDEO_MEM_TYPE_GUEST_PAGES is set for the specified queue type in
+    VIRTIO_VIDEO_CMD_STREAM_CREATE command. The struct
+    \field{virtio_video_resource_sg_list} is defined as follows:
+    \begin{lstlisting}
+struct virtio_video_resource_sg_entry {
+        le64 addr;
+        le32 length;
+        u8 padding[4];
+};
+
+struct virtio_video_resource_sg_list {
+        le32 num_entries;
+        u8 padding[4];
+        struct virtio_video_resource_sg_entry entries[];
+};
+\end{lstlisting}
+The \field{num_entries} in \field{virtio_video_resource_sg_list} is the number
+of \field{virtio_video_resource_sg_entry} instances that follow.
+
+Each field in \field{virtio_video_resource_sg_entry} is used as follows:
+    \begin{description}
+    \item[\field{addr}] is the physical guest address.
+    \item[\field{length}] is the length of the resource.
+    \end{description}
+  \end{description}
+  \item[object] represents an object exported from other virtio devices as
+    defined in \ref{sec:Basic Facilities of a Virtio Device / Exporting
+      Objects}. This field is valid when VIRTIO_VIDEO_MEM_TYPE_VIRTIO_OBJECT is
+    set for the specified queue type in VIRTIO_VIDEO_CMD_STREAM_CREATE command.
+    The struct \field{virtio_video_resource_object} is defined as follows:
+    \begin{lstlisting}
+struct virtio_video_resource_object {
+        u8 uuid[16];
+};
+    \end{lstlisting}
+    \begin{description}
+    \item[uuid] is a version 4 UUID specified by
+      \hyperref[intro:rfc4122]{[RFC4122]}.
+    \end{description}
+\end{description}
+
+The device responds with \field{struct virtio_video_resource_attach_resp}:
+\begin{lstlisting}
+struct virtio_video_resource_attach_resp {
+        le32 result; /* VIRTIO_VIDEO_RESULT_* */
+};
+\end{lstlisting}
+\begin{description}
+  \item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream
+    does not exist,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_ARGUMENT] if the \field{queue_type},
+    \field{resource_id}, or \field{resources} have an invalid value,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION] if the operation can not be
+    performed at the moment.
+  \end{description*}
+\end{description}
+
+VIRTIO_VIDEO_CMD_RESOURCE_ATTACH can only be called during the following times:
+
+\begin{itemize*}
+\item AFTER a VIRTIO_VIDEO_CMD_STREAM_CREATE and BEFORE invoking
+    VIRTIO_VIDEO_CMD_RESOURCE_QUEUE for the first time on the resource,
+\item AFTER a VIRTIO_VIDEO_CMD_QUEUE_CLEAR and BEFORE
+    VIRTIO_VIDEO_CMD_RESOURCE_QUEUE is called again on this resource.
+\end{itemize*}
+
+At any other time, the device MUST return
+VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION.
+
+This is to ensure that the device can rely on the fact that a given resource
+will always point to the same memory for as long as it may be used by the video
+device. For instance, a decoder may use returned decoded frames as reference
+frames and won't overwrite a resource until it is not needed. It is only before
+a stream is started and after a VIRTIO_VIDEO_CMD_QUEUE_CLEAR command is issued
+that we can be sure that all buffers won't be used in that way.
+
+\subparagraph{VIRTIO_VIDEO_CMD_RESOURCE_QUEUE}
+Add a buffer to the device's queue.
+
+\begin{lstlisting}
+enum virtio_video_enqueue_flag {
+        VIRTIO_VIDEO_ENQUEUE_FLAG_FORCE_KEY_FRAME = 0,
+};
+
+struct virtio_video_resource_queue {
+        le32 cmd_type;
+        le32 stream_id;
+        le32 queue_type; /* VIRTIO_VIDEO_QUEUE_TYPE_* */
+        le32 resource_id;
+        le32 flags; /* Bitmask with VIRTIO_VIDEO_ENQUEUE_FLAG_* */
+        u8 padding[4];
+        le64 timestamp;
+        le32 data_sizes[VIRTIO_VIDEO_MAX_PLANES];
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{cmd_type}] MUST be set to VIRTIO_VIDEO_CMD_RESOURCE_QUEUE.
+\item[\field{stream_id}] is the ID of the stream.
+\item[\field{queue_type}] is the direction of the queue.
+\item[\field{resource_id}] is the ID of the resource to be queued.
+\item[\field{flags}] is a bitmask of VIRTIO_VIDEO_ENQUEUE_FLAG_* values
+  representing requirements when processing the resource. If the driver doesn't
+  have any requirement, it MUST set this value to 0.
+  \begin{description}
+    \item[\field{VIRTIO_VIDEO_ENQUEUE_FLAG_FORCE_KEY_FRAME}] The frame MUST be
+      encoded as a key frame. (only for encoders)
+  \end{description}
+\item[\field{timestamp}] is an abstract sequence counter that can be
+  used for synchronization. When \field{queue_type} is set to
+  VIRTIO_VIDEO_QUEUE_TYPE_INPUT, the driver MUST set this field to a unique
+  value per frame. If using multiple VIRTIO_VIDEO_RESOURCE_QUEUE requests per
+  frame, then the timestamps for a given frame MUST be identical.
+  For VIRTIO_VIDEO_QUEUE_TYPE_OUTPUT, the driver MUST set it to 0.
+\item[\field{data_sizes}] number of data bytes used for each plane. The driver
+  MUST set this for each plane of an input buffer. For output buffers, the
+  driver MUST set this to zero.
+\end{description}
+
+The device responds with \field{virtio_video_resource_queue_resp}:
+\begin{lstlisting}
+enum virtio_video_dequeue_flag {
+        VIRTIO_VIDEO_DEQUEUE_FLAG_ERR = 0,
+        VIRTIO_VIDEO_DEQUEUE_FLAG_EOS,
+
+        /* Encoder only */
+        VIRTIO_VIDEO_DEQUEUE_FLAG_KEY_FRAME,
+        VIRTIO_VIDEO_DEQUEUE_FLAG_P_FRAME,
+        VIRTIO_VIDEO_DEQUEUE_FLAG_B_FRAME,
+};
+
+struct virtio_video_resource_queue_resp {
+        le32 result;
+        le32 flags;
+        le64 timestamp;
+        le32 data_sizes[VIRTIO_VIDEO_MAX_PLANES];
+};
+\end{lstlisting}
+\begin{description}
+\item[\field{result}] is
+  \begin{description*}
+    \item[VIRTIO_VIDEO_RESULT_OK] if the operation succeeded,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_STREAM_ID] if the requested stream
+    does not exist,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_ARGUMENT] if the \field{queue_type}
+    \field{resource_id} or \field{flags} parameters have a non-valid value,
+    \item[VIRTIO_VIDEO_RESULT_ERR_INVALID_OPERATION] if
+    VIRTIO_VIDEO_CMD_RESOURCE_ATTACH has not been successfully called on the
+    resource prior to queueing it.
+  \end{description*}
+\item[\field{flags}] is a bitmask of VIRTIO_VIDEO_DEQUEUE_FLAG_* flags.
+  \begin{description}
+  \item[\field{VIRTIO_VIDEO_DEQUEUE_FLAG_ERR}] When this flag is set, the data
+    might have been corrupted or the process was terminated by
+    VIRTIO_VIDEO_CMD_QUEUE_CLEAR.
+  \item[\field{VIRTIO_VIDEO_DEQUEUE_FLAG_EOS}] When this flag is set, this is
+    the last frame for the current stream.
+  \item[\field{VIRTIO_VIDEO_DEQUEUE_FLAG_KEY_FRAME}] When this flag is set, the
+    buffer contains a compressed image which is a key frame. (only for encoders)
+  \item[\field{VIRTIO_VIDEO_DEQUEUE_FLAG_P_FRAME}] When this flag is set, the
+    buffer contains contain only differences to a previous key frame. (only for
+    encoders)
+  \item[\field{VIRTIO_VIDEO_DEQUEUE_FLAG_B_FRAME}] When this flag is set,
+    the buffer contains only the differences between the current frame and both
+    the preceding and following key frames to specify its content. (only for
+    encoders)
+  \end{description}
+\item[\field{timestamp}] is an abstract sequence counter that can be
+  used for synchronization. For an input buffer, the device MUST set this field
+  to 0. For an output buffer, the device MUST copy the \field{timestamp} of the
+  input buffer this output buffer was produced from.
+\item[\field{data_sizes}] is the size written by the device, for each valid
+  plane of an output buffer. For an input buffer device MUST set this to 0.
+\end{description}
+
+The device MUST mark output buffers that might contain corrupted content due to
+and error with the VIRTIO_VIDEO_BUFFER_FLAG_ERR flag.
+
+It MUST mark the last buffer with the VIRTIO_VIDEO_DEQUEUE_FLAG_EOS flag to
+  denote completion of the drain sequence.
+
+In case of encoder, the device MUST mark each output buffer with one of
+VIRTIO_VIDEO_BUFFER_IFRAME, VIRTIO_VIDEO_BUFFER_PFRAME, or
+VIRTIO_VIDEO_BUFFER_BFRAME.
+
+If the processing of a buffer was stopped due to VIRTIO_VIDEO_CMD_QUEUE_CLEAR,
+  the device MUST set \field{result} to VIRTIO_VIDEO_RESULT_OK and set
+  VIRTIO_VIDEO_DEQUEUE_FLAG_ERR in \field{flags}.
+
+The driver and device MUST follow requirements about buffer ownership explained
+  in \ref{sec:Device Types / Video Device / Device Operation / Buffer
+  lifecycle}.
+
+\subsubsection{Event Virtqueue}
+
+While processing buffers, the device can send asynchronous event notifications
+to the driver. The behavior depends on the exact stream. For example, the
+decoder device sends a resolution change event when it encounters new resolution
+metadata in the stream.
+
+The device reports events on the event queue. The driver initially populates the
+queue with device-writeable buffers. When the device needs to report an event,
+it fills a buffer and notifies the driver. The driver consumes the event and
+adds a new buffer to the virtqueue.
+\begin{lstlisting}
+enum virtio_video_event_type {
+        /* For all devices */
+        VIRTIO_VIDEO_EVENT_ERROR = 0x0100,
+
+        /* For decoder only */
+        VIRTIO_VIDEO_EVENT_DECODER_RESOLUTION_CHANGED = 0x0200,
+};
+
+struct virtio_video_event {
+        le32 event_type; /* One of VIRTIO_VIDEO_EVENT_* types */
+        le32 stream_id;
+};
+\end{lstlisting}
+
+\begin{description}
+\item[\field{event_type}] type of the triggered event.
+\item[\field{stream_id}] id of the source stream.
+\end{description}
+
+The device MUST send VIRTIO_VIDEO_EVENT_DECODER_RESOLUTION_CHANGED whenever it
+encounters new resolution data in the stream. This includes the case of the
+initial device configuration after metadata has been parsed and the case of
+dynamic resolution change.
+
+Upon receiving a RESOLUTION_CHANGED event, the driver MUST perform the following
+sequence:
+
+\begin{itemize*}
+\item Keep queueing and receiving output buffers until an output buffer with
+VIRTIO_VIDEO_DEQUEUE_FLAG_EOS is received\footnote{Conversely, upon receiving an
+output buffer with VIRTIO_VIDEO_DEQUEUE_FLAG_EOS, the driver MUST check whether
+there is a pending resolution change event before deciding that the stream is
+over.}.
+\item Send a VIRTIO_VIDEO_CMD_QUEUE_CLEAR command on the output queue and
+    process its response,
+\item Perform a VIRTIO_VIDEO_CMD_STREAM_GET_PARAMS to get the new stream
+    parameters, including resolution and crop,
+\item If needed, adjust the output resolution and desired output parameters
+    (like number of output buffers) using VIRTIO_VIDEO_CMD_STREAM_SET_PARAMS,
+\item Call VIRTIO_VIDEO_CMD_RESOURCE_ATTACH on each output resource,
+\item Queue the new output resources using VIRTIO_VIDEO_CMD_RESOURCE_QUEUE and
+    resume regular operation.
+\end{itemize*}
+
+\subsubsection{Buffer life cycle}
+\label{sec:Device Types / Video Device / Device Operation / Buffer
+  lifecycle}
+
+The state machine in Figure~\ref{fig:virtio-video-buffer-lifecycle} shows the
+life cycle of a video buffer. Edges represent operations
+VIRTIO_VIDEO_CMD_RESOURCE_ATTACH, VIRTIO_VIDEO_CMD_RESOURCE_QUEUE, and
+VIRTIO_VIDEO_CMD_QUEUE_CLEAR, or the fact that a queued buffer is done being
+processed.
+
+\begin{figure}[h]
+  \centering
+  \includegraphics[width=.5\textwidth]{images/generated/video-buffer-lifecycle.png}
+  \caption{Life Cycle of a Buffer}
+  \label{fig:virtio-video-buffer-lifecycle}
+\end{figure}
+
+\drivernormative{\paragraph}{Buffer life cycle}{Device Types / Video Device /
+  Device Operation / Buffer life cycle}
+
+The following table shows whether the driver can read or write each buffer in
+each state in Figure~\ref{fig:virtio-video-buffer-lifecycle}. The driver MUST
+not read or write buffers in the state that doesn't permit.
+\begin{center}
+  \begin{tabular}{|c|c|c|}
+    \hline
+    State    & Input buffers & Output buffers \\
+    \hline
+    Init     & -             & - \\
+    Attached & Read / Write  & Read \\
+    Queued   & -             & -    \\
+    \hline
+  \end{tabular}
+\end{center}
+
+\devicenormative{\paragraph}{Buffer life cycle}{Device Types / Video
+  Device / Device Operation / Buffer life cycle}
+
+The following table shows whether the device can read or write each buffer in
+each state in Figure~\ref{fig:virtio-video-buffer-lifecycle}. The device MUST
+not read or write buffers in a non-allowed state.
+\begin{center}
+  \begin{tabular}{|c|c|c|}
+    \hline
+    State    & Input buffers & Output buffers \\
+    \hline
+    Init     & -             & - \\
+    Attached & -             & Read (for reference frames) \\
+    Queued   & Read          & Read / Write \\
+    \hline
+  \end{tabular}
+\end{center}
+
+
+\subsection{Supported formats}
+\label{sec:Device Types / Video Device / Supported formats}
+
+\subsubsection{Supported image formats}
+
+The following image formats are defined:
+\begin{lstlisting}
+enum virtio_video_image_format {
+        /* Raw formats */
+        VIRTIO_VIDEO_IMAGE_FORMAT_ARGB8888 = 1,
+        VIRTIO_VIDEO_IMAGE_FORMAT_BGRA8888,
+        VIRTIO_VIDEO_IMAGE_FORMAT_NV12,   /* 12  Y/CbCr 4:2:0  */
+        VIRTIO_VIDEO_IMAGE_FORMAT_YUV420, /* 12  YUV 4:2:0     */
+        VIRTIO_VIDEO_IMAGE_FORMAT_YVU420, /* 12  YVU 4:2:0     */
+};
+\end{lstlisting}
+
+\subsubsection{Supported bitstream formats}
+
+The following bitstream formats are defined:
+\begin{lstlisting}
+enum virtio_video_codec {
+        VIRTIO_VIDEO_CODEC_MPEG2 = 1, /* MPEG-2 Part 2 */
+        VIRTIO_VIDEO_CODEC_MPEG4,     /* MPEG-4 Part 2 */
+        VIRTIO_VIDEO_CODEC_H264,      /* H.264 */
+        VIRTIO_VIDEO_CODEC_HEVC,      /* HEVC aka H.265*/
+        VIRTIO_VIDEO_CODEC_VP8,       /* VP8 */
+        VIRTIO_VIDEO_CODEC_VP9,       /* VP9 */
+};
+
+union virtio_video_codec_params {
+        struct virtio_video_codec_h264 h264;
+        struct virtio_video_codec_hevc hevc;
+        struct virtio_video_codec_vp8 vp8;
+        struct virtio_video_codec_vp9 vp9;
+}
+
+struct virtio_video_bitstream_format {
+        le32 virtio_video_codec codec; /* VIRTIO_VIDEO_CODEC_* */
+        union virtio_video_codec_params params;
+};
+\end{lstlisting}
+
+The field \field{params} in \field{struct virtio_video_bitstream_format} is
+valid only when \field{codec} designates a value which has a corresponding field
+in \field{union virtio_video_codec_params}.
+
+The fields in \field{union virtio_video_codec_params} are defined below.
+
+\paragraph{H.264}
+
+When the field \field{codec} in \field{struct virtio_video_bitstream_format}
+is set to VIRTIO_VIDEO_CODEC_H264, \field{params.h264} MUST be set to a
+valid value defined as follows:
+
+\begin{lstlisting}
+enum virtio_video_codec_h264_profile {
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_BASELINE = 1,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_MAIN,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_EXTENDED,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_HIGH,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_HIGH10PROFILE,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_HIGH422PROFILE,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_HIGH444PREDICTIVEPROFILE,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_SCALABLEBASELINE,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_SCALABLEHIGH,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_STEREOHIGH,
+        VIRTIO_VIDEO_CODEC_H264_PROFILE_MULTIVIEWHIGH,
+};
+
+enum virtio_video_codec_h264_level {
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_1_0 = 1,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_1_1,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_1_2,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_1_3,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_2_0,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_2_1,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_2_2,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_3_0,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_3_1,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_3_2,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_4_0,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_4_1,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_4_2,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_5_0,
+        VIRTIO_VIDEO_CODEC_H264_LEVEL_5_1,
+};
+
+struct virtio_video_codec_h264 {
+        le32 profile; /* VIRTIO_VIDEO_CODEC_H264_PROFILE_* */
+        le32 level;   /* VIRTIO_VIDEO_CODEC_H264_LEVEL_* */
+};
+\end{lstlisting}
+
+\paragraph{HEVC}
+
+When the field \field{codec} in \field{struct virtio_video_bitstream_format}
+is set to VIRTIO_VIDEO_CODEC_HEVC, \field{params.hevc} MUST be set to a
+valid value defined as follows:
+
+\begin{lstlisting}
+enum virtio_video_codec_hevc_profile {
+        VIRTIO_VIDEO_CODEC_HEVC_PROFILE_MAIN = 1,
+        VIRTIO_VIDEO_CODEC_HEVC_PROFILE_MAIN10,
+        VIRTIO_VIDEO_CODEC_HEVC_PROFILE_MAIN_STILL_PICTURE,
+};
+
+struct virtio_video_codec_hevc {
+        le32 profile; /* VIRTIO_VIDEO_CODEC_HEVC_PROFILE_* */
+};
+\end{lstlisting}
+
+\paragraph{VP8}
+
+When the field \field{codec} in \field{struct virtio_video_bitstream_format}
+is set to VIRTIO_VIDEO_CODEC_VP8, \field{params.vp8} MUST be set to a
+valid value defined as follows:
+
+\begin{lstlisting}
+enum virtio_video_codec_vp8_profile {
+        VIRTIO_VIDEO_CODEC_VP8_PROFILE_0 = 1,
+        VIRTIO_VIDEO_CODEC_VP8_PROFILE_1,
+        VIRTIO_VIDEO_CODEC_VP8_PROFILE_2,
+        VIRTIO_VIDEO_CODEC_VP8_PROFILE_3,
+};
+
+struct virtio_video_codec_vp8 {
+        le32 profile; /* VIRTIO_VIDEO_CODEC_VP8_PROFILE_* */
+};
+\end{lstlisting}
+
+\paragraph{VP9}
+
+When the field \field{codec} in \field{struct virtio_video_bitstream_format}
+is set to VIRTIO_VIDEO_CODEC_VP9, \field{params.vp9} MUST be set to a
+valid value defined as follows:
+
+\begin{lstlisting}
+enum virtio_video_codec_vp9_profile {
+        VIRTIO_VIDEO_CODEC_VP9_PROFILE_0 = 1,
+        VIRTIO_VIDEO_CODEC_VP9_PROFILE_1,
+        VIRTIO_VIDEO_CODEC_VP9_PROFILE_2,
+        VIRTIO_VIDEO_CODEC_VP9_PROFILE_3,
+};
+
+struct virtio_video_codec_vp9 {
+        le32 profile; /* VIRTIO_VIDEO_CODEC_VP9_PROFILE_* */
+};
+\end{lstlisting}
