From: Mirela Rabulea <mirela.rabulea@nxp.com>
To: "p.zabel@pengutronix.de" <p.zabel@pengutronix.de>,
"linux-media@vger.kernel.org" <linux-media@vger.kernel.org>
Cc: "s.nawrocki@samsung.com" <s.nawrocki@samsung.com>,
"andrzejtp2010@gmail.com" <andrzejtp2010@gmail.com>,
"jacek.anaszewski@gmail.com" <jacek.anaszewski@gmail.com>,
"mikhail.ulyanov@cogentembedded.com"
<mikhail.ulyanov@cogentembedded.com>,
"bin.liu@mediatek.com" <bin.liu@mediatek.com>,
"hverkuil-cisco@xs4all.nl" <hverkuil-cisco@xs4all.nl>,
"ezequiel@collabora.com" <ezequiel@collabora.com>,
"kernel@pengutronix.de" <kernel@pengutronix.de>,
"rick.chang@mediatek.com" <rick.chang@mediatek.com>
Subject: Re: [EXT] [PATCH 1/5] media: add v4l2 JPEG helpers
Date: Mon, 25 Nov 2019 11:36:58 +0000 [thread overview]
Message-ID: <1574681817.19906.28.camel@nxp.com> (raw)
In-Reply-To: <20191113150538.9807-2-p.zabel@pengutronix.de>
Hi Philipp,
I tried using these helpers for imx8 jpeg encoder/decoder, and the main
issues that I have are:
1. It is necessary to support ARGB (4 components)
2. It is necessary to support extended sequential (parse SOF1)
3. It is necessary to distinguish somehow between YUV and RGB, I used
APP14 marker to do that
4. It is necessary to be able to modify/patch the component ID's inside
SOF & SOS segments; this is due to a hardware limitation that the
component ID's must be 0..3 or 1..4, however it is possible to decode a
jpeg that violates this condition, if the component ID's are patched to
accepted values.
I have a concern related to performance, about parsing the jpeg like
that, but I did not get to measure anything yet, as I could not fully
integrate imx8 jpeg driver with the helpers, I
used v4l2_jpeg_parse_header, but I also had to keep my old structures.
Please take a look in my imx8 patch, at mxc-jpeg.h, struct
mxc_jpeg_sof/struct mxc_jpeg_sos, these are __packed structures, they
work quite well via a simple cast and allow modifications too, the
downside is that fields bigger than u8 might require swapping.
Please also see below my comments.
On Mi, 2019-11-13 at 16:05 +0100, Philipp Zabel wrote:
> Add helpers for JPEG header parsing. They allow both scanning for
> marker
> segment positions and later parsing the segments individually, as
> required by s5p-jpeg, as well as parsing all headers in one go, as
> required by coda-vpu. The frame header is always parsed, as basically
> all decoders are interested in width, height, and number of
> components.
> For convenience, the JPEG chroma subsampling factors are decoded into
> a
> v4l2_jpeg_chroma_subsampling enum.
>
> Only baseline DCT encoded JPEGs with 8-bit precision and either
> grayscale (1 component) or YCbCr (3 components) encodings are
> supported,
> as current drivers do not support different formats.
For imx8 jpeg enc/dec, there is a 4-component format that should be
supported, ARGB.
Also, extended sequential DCF should be supported.
>
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
> drivers/media/v4l2-core/Kconfig | 4 +
> drivers/media/v4l2-core/Makefile | 2 +
> drivers/media/v4l2-core/v4l2-jpeg.c | 614
> ++++++++++++++++++++++++++++
> include/media/v4l2-jpeg.h | 135 ++++++
> 4 files changed, 755 insertions(+)
> create mode 100644 drivers/media/v4l2-core/v4l2-jpeg.c
> create mode 100644 include/media/v4l2-jpeg.h
>
> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-
> core/Kconfig
> index 39e3fb30ba0b..89809ec24779 100644
> --- a/drivers/media/v4l2-core/Kconfig
> +++ b/drivers/media/v4l2-core/Kconfig
> @@ -45,6 +45,10 @@ config VIDEO_PCI_SKELETON
> config VIDEO_TUNER
> tristate
>
> +# Used by drivers that need v4l2-jpeg.ko
> +config V4L2_JPEG_HELPER
> + tristate
> +
> # Used by drivers that need v4l2-mem2mem.ko
> config V4L2_MEM2MEM_DEV
> tristate
> diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-
> core/Makefile
> index 786bd1ec4d1b..144564656d22 100644
> --- a/drivers/media/v4l2-core/Makefile
> +++ b/drivers/media/v4l2-core/Makefile
> @@ -24,6 +24,8 @@ obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
>
> obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o
>
> +obj-$(CONFIG_V4L2_JPEG_HELPER) += v4l2-jpeg.o
> +
> obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
> obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
> obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
> diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c
> b/drivers/media/v4l2-core/v4l2-jpeg.c
> new file mode 100644
> index 000000000000..f1e1a818b47c
> --- /dev/null
> +++ b/drivers/media/v4l2-core/v4l2-jpeg.c
> @@ -0,0 +1,614 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * V4L2 JPEG header parser helpers.
> + *
> + * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix
> .de>
> + *
> + * For reference, see JPEG ITU-T.81 (ISO/IEC 10918-1) [1]
> + *
> + * [1] https://eur01.safelinks.protection.outlook.com/?url=https%3A%
> 2F%2Fwww.w3.org%2FGraphics%2FJPEG%2Fitu-
> t81.pdf&data=02%7C01%7Cmirela.rabulea%40nxp.com%7C956e2804c0cb4b1
> 115e508d7684b015d%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637092
> 543660676373&sdata=ucUFNyEMiBRtd9syRPy22RBEikoPsve7j%2BtB%2FtEn%2
> FQU%3D&reserved=0
> + */
> +
> +#include <asm/unaligned.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <media/v4l2-jpeg.h>
> +
> +MODULE_DESCRIPTION("V4L2 JPEG header parser helpers");
> +MODULE_AUTHOR("Philipp Zabel <kernel@pengutronix.de>");
> +MODULE_LICENSE("GPL");
> +
> +/* Table B.1 - Marker code assignments */
> +#define SOF0 0xffc0 /* start of frame */
> +#define SOF1 0xffc1
> +#define SOF3 0xffc3
> +#define SOF5 0xffc5
> +#define SOF7 0xffc7
> +#define JPG 0xffc8 /* extensions */
> +#define SOF9 0xffc9
> +#define SOF11 0xffcb
> +#define SOF13 0xffcd
> +#define SOF15 0xffcf
> +#define DHT 0xffc4 /* huffman table */
> +#define DAC 0xffcc /* arithmetic coding conditioning */
> +#define RST0 0xffd0 /* restart */
> +#define RST7 0xffd7
> +#define SOI 0xffd8 /* start of image */
> +#define EOI 0xffd9 /* end of image */
> +#define SOS 0xffda /* start of stream */
> +#define DQT 0xffdb /* quantization table */
> +#define DNL 0xffdc /* number of lines */
> +#define DRI 0xffdd /* restart interval */
> +#define DHP 0xffde /* hierarchical progression */
> +#define EXP 0xffdf /* expand reference */
> +#define APP0 0xffe0 /* application data */
APP14 would be nice to have.
> +#define APP15 0xffef
> +#define JPG0 0xfff0 /* extensions */
> +#define JPG13 0xfffd
> +#define COM 0xfffe /* comment */
> +#define TEM 0xff01 /* temporary */
> +
> +/**
> + * struct jpeg_stream - JPEG byte stream
> + * @curr: current position in stream
> + * @end: end position, after last byte
> + */
> +struct jpeg_stream {
> + u8 *curr;
> + u8 *end;
> +};
> +
> +/* returns a value that fits into u8, or negative error */
> +static int jpeg_get_byte(struct jpeg_stream *stream)
> +{
> + if (stream->curr >= stream->end)
> + return -EINVAL;
> +
> + return *stream->curr++;
> +}
> +
> +/* returns a value that fits into u16, or negative error */
> +static int jpeg_get_word_be(struct jpeg_stream *stream)
> +{
> + u16 word;
> +
> + if (stream->curr + sizeof(__be16) > stream->end)
> + return -EINVAL;
> +
> + word = get_unaligned_be16(stream->curr);
> + stream->curr += sizeof(__be16);
> +
> + return word;
> +}
> +
> +static int jpeg_skip(struct jpeg_stream *stream, size_t len)
> +{
> + if (stream->curr + len > stream->end)
> + return -EINVAL;
> +
> + stream->curr += len;
> +
> + return 0;
> +}
> +
> +static int jpeg_next_marker(struct jpeg_stream *stream)
> +{
> + int byte;
> + u16 marker = 0;
> +
> + while ((byte = jpeg_get_byte(stream)) >= 0) {
> + marker = (marker << 8) | byte;
> + /* skip stuffing bytes and REServed markers */
> + if (marker == TEM || (marker > 0xffbf && marker <
> 0xffff))
> + return marker;
> + }
> +
> + return byte;
> +}
> +
> +/* this does not advance the current position in the stream */
> +static int jpeg_reference_segment(struct jpeg_stream *stream,
> + struct v4l2_jpeg_reference
> *segment)
> +{
> + u16 len;
> +
> + if (stream->curr + sizeof(__be16) > stream->end)
> + return -EINVAL;
> +
> + len = get_unaligned_be16(stream->curr);
> + if (stream->curr + len > stream->end)
> + return -EINVAL;
> +
> + segment->start = stream->curr;
> + segment->length = len;
> +
> + return 0;
> +}
> +
> +static int v4l2_jpeg_decode_subsampling(u8 nf, u8 h_v)
> +{
> + if (nf == 1)
> + return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
> +
> + switch (h_v) {
> + case 0x11:
> + return V4L2_JPEG_CHROMA_SUBSAMPLING_444;
> + case 0x21:
> + return V4L2_JPEG_CHROMA_SUBSAMPLING_422;
> + case 0x22:
> + return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
> + case 0x41:
> + return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int jpeg_parse_frame_header(struct jpeg_stream *stream,
> + struct v4l2_jpeg_frame_header
> *frame_header)
> +{
> + int len = jpeg_get_word_be(stream);
> +
> + if (len < 0)
> + return len;
> + /* Lf = 8 + 3 * Nf, Nf >= 1 */
> + if (len < 8 + 3)
> + return -EINVAL;
> +
> + if (frame_header) {
> + /* Table B.2 - Frame header parameter sizes and
> values */
> + int p, y, x, nf;
> + int i;
> +
> + p = jpeg_get_byte(stream);
> + if (p < 0)
> + return p;
> + /* baseline DCT only supports 8-bit precision */
> + if (p != 8)
> + return -EINVAL;
> +
> + y = jpeg_get_word_be(stream);
> + if (y < 0)
> + return y;
> + if (y == 0)
> + return -EINVAL;
> +
> + x = jpeg_get_word_be(stream);
> + if (x < 0)
> + return x;
> + if (x == 0)
> + return -EINVAL;
> +
> + nf = jpeg_get_byte(stream);
> + if (nf < 0)
> + return nf;
> + /*
> + * The spec allows 1 <= Nf <= 255, but we only
> support YCbCr
> + * and grayscale.
> + */
> + if (nf != 1 && nf != 3)
This will be a problem for ARGB (4 components)
> + return -EINVAL;
> + if (len != 8 + 3 * nf)
> + return -EINVAL;
> +
> + frame_header->precision = p;
> + frame_header->height = y;
> + frame_header->width = x;
> + frame_header->num_components = nf;
> +
> + for (i = 0; i < nf; i++) {
> + struct v4l2_jpeg_frame_component_spec
> *component;
> + int c, h_v, tq;
> +
> + c = jpeg_get_byte(stream);
> + if (c < 0)
> + return c;
> +
> + h_v = jpeg_get_byte(stream);
> + if (h_v < 0)
> + return h_v;
> + if (i == 0) {
> + int subs;
> +
> + subs =
> v4l2_jpeg_decode_subsampling(nf, h_v);
> + if (subs < 0)
> + return subs;
> + frame_header->subsampling = subs;
> + } else if (h_v != 0x11) {
> + /* all chroma sampling factors must
> be 1 */
> + return -EINVAL;
> + }
> +
> + tq = jpeg_get_byte(stream);
> + if (tq < 0)
> + return tq;
> +
> + component = &frame_header->component[i];
> + component->component_identifier = c;
> + component->horizontal_sampling_factor =
> + (h_v >> 4) & 0xf;
> + component->vertical_sampling_factor = h_v &
> 0xf;
> + component->quantization_table_selector = tq;
> + }
> + } else {
> + return jpeg_skip(stream, len - 2);
> + }
> +
> + return 0;
> +}
> +
> +static int jpeg_parse_scan_header(struct jpeg_stream *stream,
> + struct v4l2_jpeg_scan_header
> *scan_header)
> +{
> + size_t skip;
> + int len = jpeg_get_word_be(stream);
> +
> + if (len < 0)
> + return len;
> + /* Ls = 8 + 3 * Ns, Ns >= 1 */
> + if (len < 6 + 2)
> + return -EINVAL;
> +
> + if (scan_header) {
> + int ns;
> + int i;
> +
> + ns = jpeg_get_byte(stream);
> + if (ns < 0)
> + return ns;
> + if (ns < 1 || ns > 4 || len != 6 + 2 * ns)
> + return -EINVAL;
> +
> + scan_header->num_components = ns;
> +
> + for (i = 0; i < ns; i++) {
> + struct v4l2_jpeg_scan_component_spec
> *component;
> + int cs, td_ta;
> +
> + cs = jpeg_get_byte(stream);
> + if (cs < 0)
> + return cs;
> +
> + td_ta = jpeg_get_byte(stream);
> + if (td_ta < 0)
> + return td_ta;
> +
> + component = &scan_header->component[i];
> + component->component_selector = cs;
> + component->dc_entropy_coding_table_selector =
> + (td_ta >> 4) & 0xf;
> + component->ac_entropy_coding_table_selector =
> + td_ta & 0xf;
> + }
> +
> + skip = 3; /* skip Ss, Se, Ah, and Al */
> + } else {
> + skip = len - 2;
> + }
> +
> + return jpeg_skip(stream, skip);
> +}
> +
> +/* B.2.4.1 Quantization table-specification syntax */
> +static int jpeg_parse_quantization_tables(struct jpeg_stream
> *stream,
> + struct v4l2_jpeg_reference
> *tables)
> +{
> + int len = jpeg_get_word_be(stream);
> +
> + if (len < 0)
> + return len;
> + /* Lq = 2 + n * 65 (for baseline DCT), n >= 1 */
> + if (len < 2 + 65)
> + return -EINVAL;
> +
> + for (len -= 2; len >= 65; len -= 65) {
> + u8 pq, tq, *qk;
> + int ret;
> + int pq_tq = jpeg_get_byte(stream);
> +
> + if (pq_tq < 0)
> + return pq_tq;
> +
> + /* quantization table element precision */
> + pq = (pq_tq >> 4) & 0xf;
> + /* only 8-bit Qk values for baseline DCT */
> + if (pq != 0)
> + return -EINVAL;
> +
> + /* quantization table destination identifier */
> + tq = pq_tq & 0xf;
> + if (tq > 3)
> + return -EINVAL;
> +
> + /* quantization table element */
> + qk = stream->curr;
> + ret = jpeg_skip(stream, 64);
> + if (ret < 0)
> + return -EINVAL;
> +
> + if (tables) {
> + tables[tq].start = qk;
> + tables[tq].length = 64;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* B.2.4.2 Huffman table-specification syntax */
> +static int jpeg_parse_huffman_tables(struct jpeg_stream *stream,
> + struct v4l2_jpeg_reference
> *tables)
> +{
> + int mt;
> + int len = jpeg_get_word_be(stream);
> +
> + if (len < 0)
> + return len;
> + /* Table B.5 - Huffman table specification parameter sizes
> and values */
> + if (len < 2 + 17)
> + return -EINVAL;
> +
> + for (len -= 2; len >= 17; len -= 17 + mt) {
> + u8 tc, th, *table;
> + int tc_th = jpeg_get_byte(stream);
> + int i, ret;
> +
> + if (tc_th < 0)
> + return tc_th;
> +
> + /* table class - 0 = DC, 1 = AC */
> + tc = (tc_th >> 4) & 0xf;
> + if (tc > 1)
> + return -EINVAL;
> +
> + /* huffman table destination identifier */
> + th = tc_th & 0xf;
> + /* only two Huffman tables for baseline DCT */
> + if (th > 1)
> + return -EINVAL;
> +
> + /* BITS - number of Huffman codes with length i */
> + table = stream->curr;
> + mt = 0;
> + for (i = 0; i < 16; i++) {
> + int li;
> +
> + li = jpeg_get_byte(stream);
> + if (li < 0)
> + return li;
> +
> + mt += li;
> + }
> + /* HUFFVAL - values associated with each Huffman code
> */
> + ret = jpeg_skip(stream, mt);
> + if (ret < 0)
> + return ret;
> +
> + if (tables) {
> + tables[(tc << 1) | th].start = table;
> + tables[(tc << 1) | th].length = stream->curr
> - table;
> + }
> + }
> +
> + return jpeg_skip(stream, len - 2);
> +}
> +
> +/* B.2.4.4 Restart interval definition syntax */
> +static int jpeg_parse_restart_interval(struct jpeg_stream *stream,
> + u16 *restart_interval)
> +{
> + int len = jpeg_get_word_be(stream);
> + int ri;
> +
> + if (len < 0)
> + return len;
> + if (len != 4)
> + return -EINVAL;
> +
> + ri = jpeg_get_word_be(stream);
> + if (ri < 0)
> + return ri;
> +
> + *restart_interval = ri;
> +
> + return 0;
> +}
> +
> +static int jpeg_skip_segment(struct jpeg_stream *stream)
> +{
> + int len = jpeg_get_word_be(stream);
> +
> + if (len < 0)
> + return len;
> + if (len < 2)
> + return -EINVAL;
> +
> + return jpeg_skip(stream, len - 2);
> +}
> +
> +/**
> + * jpeg_parse_header - locate marker segments and optionally parse
> headers
> + * @buf: address of the JPEG buffer, should start with a SOI marker
> + * @len: length of the JPEG buffer
> + * @out: returns marker segment positions and optionally parsed
> headers
> + *
> + * The out->scan_header pointer must be initialized to NULL or point
> to a valid
> + * v4l2_jpeg_scan_header structure. The out->huffman_tables and
> + * out->quantization_tables pointers must be initialized to NULL or
> point to a
> + * valid array of 4 v4l2_jpeg_reference structures each.
> + *
> + * Returns 0 or negative error if parsing failed.
> + */
> +int v4l2_jpeg_parse_header(void *buf, size_t len, struct
> v4l2_jpeg_header *out)
> +{
> + struct jpeg_stream stream;
> + int marker;
> + int ret = 0;
> +
> + stream.curr = buf;
> + stream.end = stream.curr + len;
> +
> + out->num_dht = 0;
> + out->num_dqt = 0;
> +
> + /* the first marker must be SOI */
> + marker = jpeg_next_marker(&stream);
> + if (marker < 0)
> + return marker;
> + if (marker != SOI)
> + return -EINVAL;
> +
> + /* loop through marker segments */
> + while ((marker = jpeg_next_marker(&stream)) >= 0) {
> + switch (marker) {
> + /* baseline DCT */
> + case SOF0:
For imx8 jpeg, extended sequential should be supported. Adding the SOF1
here would help, but maybe other changes are needed too.
> + ret = jpeg_reference_segment(&stream, &out-
> >sof);
> + if (ret < 0)
> + return ret;
> + ret = jpeg_parse_frame_header(&stream, &out-
> >frame);
> + break;
> + /* extended sequential, progressive, lossless */
> + case SOF1 ... SOF3:
> + /* differential coding */
> + case SOF5 ... SOF7:
> + /* arithmetic coding */
> + case SOF9 ... SOF11:
> + case SOF13 ... SOF15:
> + /* fallthrough */
> + case DAC:
> + case TEM:
> + return -EINVAL;
> +
> + case DHT:
> + ret = jpeg_reference_segment(&stream,
> + &out->dht[out->num_dht++ %
> 4]);
> + if (ret < 0)
> + return ret;
> + ret = jpeg_parse_huffman_tables(&stream,
> + out-
> >huffman_tables);
> + break;
> + case DQT:
> + ret = jpeg_reference_segment(&stream,
> + &out->dqt[out->num_dqt++ %
> 4]);
> + if (ret < 0)
> + return ret;
> + ret = jpeg_parse_quantization_tables(&stream,
> + out->quantization_tables);
> + break;
> + case DRI:
> + ret = jpeg_parse_restart_interval(&stream,
> + &out-
> >restart_interval);
> + break;
> +
> + case SOS:
> + ret = jpeg_reference_segment(&stream, &out-
> >sos);
> + if (ret < 0)
> + return ret;
> + ret = jpeg_parse_scan_header(&stream, out-
> >scan);
> + /*
> + * stop parsing, the scan header marks the
> beginning of
> + * the entropy coded segment
> + */
> + out->ecs_offset = stream.curr - (u8 *)buf;
> + return ret;
> +
> + /* markers without parameters */
> + case RST0 ... RST7: /* restart */
> + case SOI: /* start of image */
> + case EOI: /* end of image */
> + break;
> +
> + /* skip unknown or unsupported marker segments */
> + default:
> + ret = jpeg_skip_segment(&stream);
> + break;
> + }
> + if (ret < 0)
> + return ret;
> + }
> +
> + return marker;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_header);
> +
> +/**
> + * v4l2_jpeg_parse_frame_header - parse frame header
> + * @buf: address of the frame header, after the SOF0 marker
> + * @len: length of the frame header
> + * @frame_header: returns the parsed frame header
> + *
> + * Returns 0 or negative error if parsing failed.
> + */
> +int v4l2_jpeg_parse_frame_header(void *buf, size_t len,
> + struct v4l2_jpeg_frame_header
> *frame_header)
> +{
> + struct jpeg_stream stream;
> +
> + stream.curr = buf;
> + stream.end = stream.curr + len;
> + return jpeg_parse_frame_header(&stream, frame_header);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_frame_header);
> +
> +/**
> + * v4l2_jpeg_parse_scan_header - parse scan header
> + * @buf: address of the scan header, after the SOS marker
> + * @len: length of the scan header
> + * @scan_header: returns the parsed scan header
> + *
> + * Returns 0 or negative error if parsing failed.
> + */
> +int v4l2_jpeg_parse_scan_header(void *buf, size_t len,
> + struct v4l2_jpeg_scan_header
> *scan_header)
> +{
> + struct jpeg_stream stream;
> +
> + stream.curr = buf;
> + stream.end = stream.curr + len;
> + return jpeg_parse_scan_header(&stream, scan_header);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_scan_header);
> +
> +/**
> + * v4l2_jpeg_parse_quantization_tables - parse quantization tables
> segment
> + * @buf: address of the quantization table segment, after the DQT
> marker
> + * @len: length of the quantization table segment
> + * @q_tables: returns four references into the buffer for the
> + * four possible quantization table destinations
> + *
> + * Returns 0 or negative error if parsing failed.
> + */
> +int v4l2_jpeg_parse_quantization_tables(void *buf, size_t len,
> + struct v4l2_jpeg_reference
> *q_tables)
> +{
> + struct jpeg_stream stream;
> +
> + stream.curr = buf;
> + stream.end = stream.curr + len;
> + return jpeg_parse_quantization_tables(&stream, q_tables);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_quantization_tables);
> +
> +/**
> + * v4l2_jpeg_parse_huffman_tables - parse huffman tables segment
> + * @buf: address of the Huffman table segment, after the DHT marker
> + * @len: length of the Huffman table segment
> + * @huffman_tables: returns four references into the buffer for the
> + * four possible Huffman table destinations, in
> + * the order DC0, DC1, AC0, AC1
> + *
> + * Returns 0 or negative error if parsing failed.
> + */
> +int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len,
> + struct v4l2_jpeg_reference
> *huffman_tables)
> +{
> + struct jpeg_stream stream;
> +
> + stream.curr = buf;
> + stream.end = stream.curr + len;
> + return jpeg_parse_huffman_tables(&stream, huffman_tables);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_huffman_tables);
> diff --git a/include/media/v4l2-jpeg.h b/include/media/v4l2-jpeg.h
> new file mode 100644
> index 000000000000..2f6292c75122
> --- /dev/null
> +++ b/include/media/v4l2-jpeg.h
> @@ -0,0 +1,135 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * V4L2 JPEG helpers header
> + *
> + * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix
> .de>
> + *
> + * For reference, see JPEG ITU-T.81 (ISO/IEC 10918-1)
> + */
> +
> +#ifndef _V4L2_JPEG_H
> +#define _V4L2_JPEG_H
> +
> +#include <linux/v4l2-controls.h>
> +
> +#define V4L2_JPEG_MAX_COMPONENTS 3
And V4L2_JPEG_MAX_COMPONENTS 4 is neccesary (imx8, ARGB), not sure it
other changes needed...
> +#define V4L2_JPEG_MAX_TABLES 4
> +
> +/**
> + * struct v4l2_jpeg_reference - reference into the JPEG buffer
> + * @start: pointer to the start of the referenced segment or table
> + * @length: size of the referenced segment or table
> + *
> + * Wnen referencing marker segments, start points right after the
> marker code,
> + * and length is the size of the segment parameters, excluding the
> marker code.
> + */
> +struct v4l2_jpeg_reference {
> + u8 *start;
> + size_t length;
> +};
> +
> +/* B.2.2 Frame header syntax */
> +
> +/**
> + * struct v4l2_jpeg_frame_component_spec - frame component-
> specification
> + * @component_identifier: C[i]
> + * @horizontal_sampling_factor: H[i]
> + * @vertical_sampling_factor: V[i]
> + * @quantization_table_selector: quantization table destination
> selector Tq[i]
> + */
> +struct v4l2_jpeg_frame_component_spec {
> + u8 component_identifier;
> + u8 horizontal_sampling_factor;
> + u8 vertical_sampling_factor;
> + u8 quantization_table_selector;
> +};
> +
> +/**
> + * struct v4l2_jpeg_frame_header - JPEG frame header
> + * @height: Y
> + * @width: X
> + * @precision: P
> + * @num_components: Nf
> + * @component: component-specification, see
> v4l2_jpeg_frame_component_spec
> + * @subsampling: decoded subsampling from component-specification
> + */
> +struct v4l2_jpeg_frame_header {
> + u16 height;
> + u16 width;
> + u8 precision;
> + u8 num_components;
> + struct v4l2_jpeg_frame_component_spec
> component[V4L2_JPEG_MAX_COMPONENTS];
> + enum v4l2_jpeg_chroma_subsampling subsampling;
> +};
> +
> +/* B.2.3 Scan header syntax */
> +
> +/**
> + * struct v4l2_jpeg_scan_component_spec - scan component-
> specification
> + * @component_selector: Cs[j]
> + * @dc_entropy_coding_table_selector: Td[j]
> + * @ac_entropy_coding_table_selector: Ta[j]
> + */
> +struct v4l2_jpeg_scan_component_spec {
> + u8 component_selector;
> + u8 dc_entropy_coding_table_selector;
> + u8 ac_entropy_coding_table_selector;
> +};
> +
> +/**
> + * struct v4l2_jpeg_scan_header - JPEG scan header
> + * @num_components: Ns
> + * @component: component-specification, see
> v4l2_jpeg_scan_component_spec
> + */
> +struct v4l2_jpeg_scan_header {
> + u8 num_components; /* Ns */
> + struct v4l2_jpeg_scan_component_spec
> component[V4L2_JPEG_MAX_COMPONENTS];
> + /* Ss, Se, Ah, and Al are not used by any driver */
> +};
> +
> +/**
> + * struct v4l2_jpeg_header - parsed JPEG header
> + * @sof: pointer to frame header and size
> + * @sos: pointer to scan header and size
> + * @dht: pointers to huffman tables and sizes
> + * @dqt: pointers to quantization tables and sizes
> + * @frame: parsed frame header
> + * @scan: pointer to parsed scan header, optional
> + * @quantization_tables: references to four quantization tables,
> optional
> + * @huffman_tables: references to four Huffman tables in DC0, DC1,
> AC0, AC1
> + * order, optional
> + * @restart_interval: number of MCU per restart interval, Ri
> + * @ecs_offset: buffer offset in bytes to the entropy coded segment
> + *
> + * When this structure is passed to v4l2_jpeg_parse_header, the
> optional scan,
> + * quantization_tables, and huffman_tables pointers must be
> initialized to NULL
> + * or point at valid memory.
> + */
> +struct v4l2_jpeg_header {
> + struct v4l2_jpeg_reference sof;
> + struct v4l2_jpeg_reference sos;
> + unsigned int num_dht;
> + struct v4l2_jpeg_reference dht[V4L2_JPEG_MAX_TABLES];
> + unsigned int num_dqt;
> + struct v4l2_jpeg_reference dqt[V4L2_JPEG_MAX_TABLES];
> +
> + struct v4l2_jpeg_frame_header frame;
> + struct v4l2_jpeg_scan_header *scan;
> + struct v4l2_jpeg_reference *quantization_tables;
> + struct v4l2_jpeg_reference *huffman_tables;
> + u16 restart_interval;
> + size_t ecs_offset;
> +};
> +
> +int v4l2_jpeg_parse_header(void *buf, size_t len, struct
> v4l2_jpeg_header *out);
> +
> +int v4l2_jpeg_parse_frame_header(void *buf, size_t len,
> + struct v4l2_jpeg_frame_header
> *frame_header);
> +int v4l2_jpeg_parse_scan_header(void *buf, size_t len,
> + struct v4l2_jpeg_scan_header
> *scan_header);
> +int v4l2_jpeg_parse_quantization_tables(void *buf, size_t len,
> + struct v4l2_jpeg_reference
> *q_tables);
> +int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len,
> + struct v4l2_jpeg_reference
> *huffman_tables);
> +
> +#endif
> --
> 2.20.1
>
next prev parent reply other threads:[~2019-11-25 11:37 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-13 15:05 [PATCH 0/5] v4l2 JPEG helpers and CODA960 JPEG decoder Philipp Zabel
2019-11-13 15:05 ` [PATCH 1/5] media: add v4l2 JPEG helpers Philipp Zabel
2019-11-25 11:36 ` Mirela Rabulea [this message]
2019-11-25 16:36 ` [EXT] " Philipp Zabel
2019-11-26 9:07 ` Mirela Rabulea
2019-11-13 15:05 ` [PATCH 2/5] media: coda: jpeg: add CODA960 JPEG decoder support Philipp Zabel
2020-03-06 20:31 ` Tim Harvey
2020-03-06 21:01 ` Adrian Ratiu
2020-03-06 21:57 ` Tim Harvey
2020-03-07 12:14 ` Ezequiel Garcia
2020-03-11 17:06 ` Adrian Ratiu
2019-11-13 15:05 ` [PATCH 3/5] media: rcar_jpu: use V4L2 JPEG helpers Philipp Zabel
2019-11-13 15:05 ` [PATCH 4/5] media: s5p-jpeg: use v4l2 " Philipp Zabel
2019-11-13 15:05 ` [PATCH 5/5] media: mtk-jpeg: use V4L2 " Philipp Zabel
2019-11-13 19:42 ` [PATCH 0/5] v4l2 JPEG helpers and CODA960 JPEG decoder Ezequiel Garcia
2019-11-13 20:36 ` Jacek Anaszewski
2019-11-13 21:25 ` Nicolas Dufresne
2019-11-14 10:00 ` Philipp Zabel
2019-11-25 11:36 ` [EXT] " Mirela Rabulea
2019-12-04 10:30 ` Adrian Ratiu
2019-12-13 9:18 ` Hans Verkuil
2020-03-18 10:41 ` Adrian Ratiu
2020-03-18 12:15 ` Andrzej Pietrasiewicz
2020-03-18 12:42 ` Adrian Ratiu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1574681817.19906.28.camel@nxp.com \
--to=mirela.rabulea@nxp.com \
--cc=andrzejtp2010@gmail.com \
--cc=bin.liu@mediatek.com \
--cc=ezequiel@collabora.com \
--cc=hverkuil-cisco@xs4all.nl \
--cc=jacek.anaszewski@gmail.com \
--cc=kernel@pengutronix.de \
--cc=linux-media@vger.kernel.org \
--cc=mikhail.ulyanov@cogentembedded.com \
--cc=p.zabel@pengutronix.de \
--cc=rick.chang@mediatek.com \
--cc=s.nawrocki@samsung.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).