150 lines
3.1 KiB
C
150 lines
3.1 KiB
C
// 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;
|
|
}
|