linux/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) STMicroelectronics SA 2013
   4 * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
   5 */
   6
   7#include "delta.h"
   8#include "delta-mjpeg.h"
   9
  10#define MJPEG_SOF_0  0xc0
  11#define MJPEG_SOF_1  0xc1
  12#define MJPEG_SOI    0xd8
  13#define MJPEG_MARKER 0xff
  14
  15static char *header_str(struct mjpeg_header *header,
  16                        char *str,
  17                        unsigned int len)
  18{
  19        char *cur = str;
  20        unsigned int left = len;
  21
  22        if (!header)
  23                return "";
  24
  25        snprintf(cur, left, "[MJPEG header]\n"
  26                        "|- length     = %d\n"
  27                        "|- precision  = %d\n"
  28                        "|- width      = %d\n"
  29                        "|- height     = %d\n"
  30                        "|- components = %d\n",
  31                        header->length,
  32                        header->sample_precision,
  33                        header->frame_width,
  34                        header->frame_height,
  35                        header->nb_of_components);
  36
  37        return str;
  38}
  39
  40static int delta_mjpeg_read_sof(struct delta_ctx *pctx,
  41                                unsigned char *data, unsigned int size,
  42                                struct mjpeg_header *header)
  43{
  44        struct delta_dev *delta = pctx->dev;
  45        unsigned int offset = 0;
  46
  47        if (size < 64)
  48                goto err_no_more;
  49
  50        memset(header, 0, sizeof(*header));
  51        header->length           = be16_to_cpu(*(__be16 *)(data + offset));
  52        offset += sizeof(u16);
  53        header->sample_precision = *(u8 *)(data + offset);
  54        offset += sizeof(u8);
  55        header->frame_height     = be16_to_cpu(*(__be16 *)(data + offset));
  56        offset += sizeof(u16);
  57        header->frame_width      = be16_to_cpu(*(__be16 *)(data + offset));
  58        offset += sizeof(u16);
  59        header->nb_of_components = *(u8 *)(data + offset);
  60        offset += sizeof(u8);
  61
  62        if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) {
  63                dev_err(delta->dev,
  64                        "%s   unsupported number of components (%d > %d)\n",
  65                        pctx->name, header->nb_of_components,
  66                        MJPEG_MAX_COMPONENTS);
  67                return -EINVAL;
  68        }
  69
  70        if ((offset + header->nb_of_components *
  71             sizeof(header->components[0])) > size)
  72                goto err_no_more;
  73
  74        return 0;
  75
  76err_no_more:
  77        dev_err(delta->dev,
  78                "%s   sof: reached end of %d size input stream\n",
  79                pctx->name, size);
  80        return -ENODATA;
  81}
  82
  83int delta_mjpeg_read_header(struct delta_ctx *pctx,
  84                            unsigned char *data, unsigned int size,
  85                            struct mjpeg_header *header,
  86                            unsigned int *data_offset)
  87{
  88        struct delta_dev *delta = pctx->dev;
  89        unsigned char str[200];
  90
  91        unsigned int ret = 0;
  92        unsigned int offset = 0;
  93        unsigned int soi = 0;
  94
  95        if (size < 2)
  96                goto err_no_more;
  97
  98        offset = 0;
  99        while (1) {
 100                if (data[offset] == MJPEG_MARKER)
 101                        switch (data[offset + 1]) {
 102                        case MJPEG_SOI:
 103                                soi = 1;
 104                                *data_offset = offset;
 105                                break;
 106
 107                        case MJPEG_SOF_0:
 108                        case MJPEG_SOF_1:
 109                                if (!soi) {
 110                                        dev_err(delta->dev,
 111                                                "%s   wrong sequence, got SOF while SOI not seen\n",
 112                                                pctx->name);
 113                                        return -EINVAL;
 114                                }
 115
 116                                ret = delta_mjpeg_read_sof(pctx,
 117                                                           &data[offset + 2],
 118                                                           size - (offset + 2),
 119                                                           header);
 120                                if (ret)
 121                                        goto err;
 122
 123                                goto done;
 124
 125                        default:
 126                                break;
 127                        }
 128
 129                offset++;
 130                if ((offset + 2) >= size)
 131                        goto err_no_more;
 132        }
 133
 134done:
 135        dev_dbg(delta->dev,
 136                "%s   found header @ offset %d:\n%s", pctx->name,
 137                *data_offset,
 138                header_str(header, str, sizeof(str)));
 139        return 0;
 140
 141err_no_more:
 142        dev_err(delta->dev,
 143                "%s   no header found within %d bytes input stream\n",
 144                pctx->name, size);
 145        return -ENODATA;
 146
 147err:
 148        return ret;
 149}
 150