/* * Contains the data that needs to be sent in the marker segment of an * interchange format JPEG stream or an abbreviated format table specification * data stream. Specifies the huffman table used for encoding the luminance DC * coefficient differences. The table represents Table K.3 of ITU-T.81
*/ const u8 v4l2_jpeg_ref_table_luma_dc_ht[V4L2_JPEG_REF_HT_DC_LEN] = { 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
};
EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_luma_dc_ht);
/* * Contains the data that needs to be sent in the marker segment of an interchange format JPEG * stream or an abbreviated format table specification data stream. * Specifies the huffman table used for encoding the chrominance DC coefficient differences. * The table represents Table K.4 of ITU-T.81
*/ const u8 v4l2_jpeg_ref_table_chroma_dc_ht[V4L2_JPEG_REF_HT_DC_LEN] = { 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
};
EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_chroma_dc_ht);
/** * 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 */ staticint 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 */ staticint 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;
}
staticint jpeg_skip(struct jpeg_stream *stream, size_t len)
{ if (stream->curr + len > stream->end) return -EINVAL;
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 */ staticint 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;
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. * Extended sequential DCT also supports 12-bit precision.
*/ if (p != 8 && (p != 12 || sof_marker != SOF1)) 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 up to 4 * components.
*/ if (nf < 1 || nf > V4L2_JPEG_MAX_COMPONENTS) return -EINVAL; if (len != 8 + 3 * nf) return -EINVAL;
/* B.2.4.4 Restart interval definition syntax */ staticint 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;
return0;
}
staticint 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);
}
/* Rec. ITU-T T.872 (06/2012) 6.5.3 */ staticint 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 jpeg_skip(stream, lp - 2);
/* 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 - 1; 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 * @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;
/* the first bytes must be SOI, B.2.1 High-level syntax */ if (jpeg_get_word_be(&stream) != 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) { /* baseline DCT, extended sequential DCT */ case SOF0 ... SOF1:
ret = jpeg_reference_segment(&stream, &out->sof); if (ret < 0) return ret;
ret = jpeg_parse_frame_header(&stream, marker,
&out->frame); break; /* progressive, lossless */ case SOF2 ... SOF3: /* differential coding */ case SOF5 ... SOF7: /* arithmetic coding */ case SOF9 ... SOF11: case SOF13 ... SOF15: case DAC: case TEM: return -EINVAL;
case DHT:
ret = jpeg_reference_segment(&stream,
&out->dht[out->num_dht++ % 4]); if (ret < 0) return ret; if (!out->huffman_tables) {
ret = jpeg_skip_segment(&stream); break;
}
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; if (!out->quantization_tables) {
ret = jpeg_skip_segment(&stream); break;
}
ret = jpeg_parse_quantization_tables(&stream,
out->frame.precision,
out->quantization_tables); break; case DRI:
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) 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.