media: Add parsing for APP14 data segment in jpeg helpers
authorMirela Rabulea <mirela.rabulea@nxp.com>
Thu, 11 Mar 2021 00:28:49 +0000 (01:28 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Mon, 22 Mar 2021 09:35:36 +0000 (10:35 +0100)
According to Rec. ITU-T T.872 (06/2012) 6.5.3
APP14 segment is for color encoding, it contains a transform flag, which
may have values of 0, 1 and 2 and are interpreted as follows:
0 - CMYK for images that are encoded with four components
  - RGB for images that are encoded with three components
1 - An image encoded with three components using YCbCr colour encoding.
2 - An image encoded with four components using YCCK colour encoding.

This is used in imx-jpeg decoder, to distinguish between
YUV444 and RGB24.

Signed-off-by: Mirela Rabulea <mirela.rabulea@nxp.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/v4l2-core/v4l2-jpeg.c
include/media/v4l2-jpeg.h

index 9071b6c..ede40f2 100644 (file)
@@ -45,6 +45,7 @@ MODULE_LICENSE("GPL");
 #define DHP    0xffde  /* hierarchical progression */
 #define EXP    0xffdf  /* expand reference */
 #define APP0   0xffe0  /* application data */
+#define APP14  0xffee  /* application data for colour encoding */
 #define APP15  0xffef
 #define JPG0   0xfff0  /* extensions */
 #define JPG13  0xfffd
@@ -444,6 +445,39 @@ static int jpeg_skip_segment(struct jpeg_stream *stream)
        return jpeg_skip(stream, len - 2);
 }
 
+/* Rec. ITU-T T.872 (06/2012) 6.5.3 */
+static int jpeg_parse_app14_data(struct jpeg_stream *stream,
+                                enum v4l2_jpeg_app14_tf *tf)
+{
+       int ret;
+       int lp;
+       int skip;
+
+       lp = jpeg_get_word_be(stream);
+       if (lp < 0)
+               return lp;
+
+       /* Check for "Adobe\0" in Ap1..6 */
+       if (stream->curr + 6 > stream->end ||
+           strncmp(stream->curr, "Adobe\0", 6))
+               return -EINVAL;
+
+       /* get to Ap12 */
+       ret = jpeg_skip(stream, 11);
+       if (ret < 0)
+               return ret;
+
+       ret = jpeg_get_byte(stream);
+       if (ret < 0)
+               return ret;
+
+       *tf = ret;
+
+       /* skip the rest of the segment, this ensures at least it is complete */
+       skip = lp - 2 - 11;
+       return jpeg_skip(stream, skip);
+}
+
 /**
  * v4l2_jpeg_parse_header - locate marker segments and optionally parse headers
  * @buf: address of the JPEG buffer, should start with a SOI marker
@@ -476,6 +510,9 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out)
        if (marker != SOI)
                return -EINVAL;
 
+       /* init value to signal if this marker is not present */
+       out->app14_tf = V4L2_JPEG_APP14_TF_UNKNOWN;
+
        /* loop through marker segments */
        while ((marker = jpeg_next_marker(&stream)) >= 0) {
                switch (marker) {
@@ -519,7 +556,10 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out)
                        ret = jpeg_parse_restart_interval(&stream,
                                                        &out->restart_interval);
                        break;
-
+               case APP14:
+                       ret = jpeg_parse_app14_data(&stream,
+                                                   &out->app14_tf);
+                       break;
                case SOS:
                        ret = jpeg_reference_segment(&stream, &out->sos);
                        if (ret < 0)
index 3a3344a..2dba843 100644 (file)
@@ -88,6 +88,24 @@ struct v4l2_jpeg_scan_header {
 };
 
 /**
+ * enum v4l2_jpeg_app14_tf - APP14 transform flag
+ * According to Rec. ITU-T T.872 (06/2012) 6.5.3
+ * APP14 segment is for color encoding, it contains a transform flag,
+ * which may have values of 0, 1 and 2 and are interpreted as follows:
+ * @V4L2_JPEG_APP14_TF_CMYK_RGB: CMYK for images encoded with four components
+ *                               RGB for images encoded with three components
+ * @V4L2_JPEG_APP14_TF_YCBCR: an image encoded with three components using YCbCr
+ * @V4L2_JPEG_APP14_TF_YCCK: an image encoded with four components using YCCK
+ * @V4L2_JPEG_APP14_TF_UNKNOWN: indicate app14 is not present
+ */
+enum v4l2_jpeg_app14_tf {
+       V4L2_JPEG_APP14_TF_CMYK_RGB     = 0,
+       V4L2_JPEG_APP14_TF_YCBCR        = 1,
+       V4L2_JPEG_APP14_TF_YCCK         = 2,
+       V4L2_JPEG_APP14_TF_UNKNOWN      = -1,
+};
+
+/**
  * struct v4l2_jpeg_header - parsed JPEG header
  * @sof: pointer to frame header and size
  * @sos: pointer to scan header and size
@@ -102,6 +120,7 @@ struct v4l2_jpeg_scan_header {
  *                  order, optional
  * @restart_interval: number of MCU per restart interval, Ri
  * @ecs_offset: buffer offset in bytes to the entropy coded segment
+ * @app14_tf: transform flag from app14 data
  *
  * When this structure is passed to v4l2_jpeg_parse_header, the optional scan,
  * quantization_tables, and huffman_tables pointers must be initialized to NULL
@@ -121,6 +140,7 @@ struct v4l2_jpeg_header {
        struct v4l2_jpeg_reference *huffman_tables;
        u16 restart_interval;
        size_t ecs_offset;
+       enum v4l2_jpeg_app14_tf app14_tf;
 };
 
 int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out);