// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2013
* Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
*/
#include "delta.h"
#include "delta-mjpeg.h"
#define MJPEG_SOF_0 0xc0
#define MJPEG_SOF_1 0xc1
#define MJPEG_SOI 0xd8
#define MJPEG_MARKER 0xff
static char *header_str(struct mjpeg_header *header,
char *str,
unsigned int len)
{
char *cur = str;
unsigned int left = len;
if (!header)
return "";
snprintf(cur, left, "[MJPEG header]\n"
"|- length = %d\n"
"|- precision = %d\n"
"|- width = %d\n"
"|- height = %d\n"
"|- components = %d\n",
header->length,
header->sample_precision,
header->frame_width,
header->frame_height,
header->nb_of_components);
return str;
}
static int delta_mjpeg_read_sof(struct delta_ctx *pctx,
unsigned char *data, unsigned int size,
struct mjpeg_header *header)
{
struct delta_dev *delta = pctx->dev;
unsigned int offset = 0;
if (size < 64)
goto err_no_more;
memset(header, 0, sizeof(*header));
header->length = be16_to_cpu(*(__be16 *)(data + offset));
offset += sizeof(u16);
header->sample_precision = *(u8 *)(data + offset);
offset += sizeof(u8);
header->frame_height = be16_to_cpu(*(__be16 *)(data + offset));
offset += sizeof(u16);
header->frame_width = be16_to_cpu(*(__be16 *)(data + offset));
offset += sizeof(u16);
header->nb_of_components = *(u8 *)(data + offset);
offset += sizeof(u8);
if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) {
dev_err(delta->dev,
"%s unsupported number of components (%d > %d)\n",
pctx->name, header->nb_of_components,
MJPEG_MAX_COMPONENTS);
return -EINVAL;
}
if ((offset + header->nb_of_components *
sizeof(header->components[0])) > size)
goto err_no_more;
return 0;
err_no_more:
dev_err(delta->dev,
"%s sof: reached end of %d size input stream\n",
pctx->name, size);
return -ENODATA;
}
int delta_mjpeg_read_header(struct delta_ctx *pctx,
unsigned char *data, unsigned int size,
struct mjpeg_header *header,
unsigned int *data_offset)
{
struct delta_dev *delta = pctx->dev;
unsigned char str[200];
unsigned int ret = 0;
unsigned int offset = 0;
unsigned int soi = 0;
if (size < 2)
goto err_no_more;
offset = 0;
while (1) {
if (data[offset] == MJPEG_MARKER)
switch (data[offset + 1]) {
case MJPEG_SOI:
soi = 1;
*data_offset = offset;
break;
case MJPEG_SOF_0:
case MJPEG_SOF_1:
if (!soi) {
dev_err(delta->dev,
"%s wrong sequence, got SOF while SOI not seen\n",
pctx->name);
return -EINVAL;
}
ret = delta_mjpeg_read_sof(pctx,
&data[offset + 2],
size - (offset + 2),
header);
if (ret)
goto err;
goto done;
default:
break;
}
offset++;
if ((offset + 2) >= size)
goto err_no_more;
}
done:
dev_dbg(delta->dev,
"%s found header @ offset %d:\n%s", pctx->name,
*data_offset,
header_str(header, str, sizeof(str)));
return 0;
err_no_more:
dev_err(delta->dev,
"%s no header found within %d bytes input stream\n",
pctx->name, size);
return -ENODATA;
err:
return ret;
}