55 files changed, 11471 insertions, 2282 deletions
diff --git a/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c new file mode 100644 index 0000000..1d9d94b --- a/dev/null +++ b/drivers/amvdec_ports/decoder/aml_mjpeg_parser.c @@ -0,0 +1,397 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/vmalloc.h> +#include <linux/mm.h> +#include <linux/string.h> + +#include "aml_mjpeg_parser.h" +#include "../utils/get_bits.h" +#include "../utils/put_bits.h" +#include "../utils/golomb.h" +#include "../utils/common.h" +#include "utils.h" + +/* return the 8 bit start code value and update the search +state. Return -1 if no start code found */ +static int find_marker(const u8 **pbuf_ptr, const u8 *buf_end) +{ + const u8 *buf_ptr; + u32 v, v2; + int val; + int skipped = 0; + + buf_ptr = *pbuf_ptr; + while (buf_end - buf_ptr > 1) { + v = *buf_ptr++; + v2 = *buf_ptr; + if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe) && buf_ptr < buf_end) { + val = *buf_ptr++; + goto found; + } + skipped++; + } + buf_ptr = buf_end; + val = -1; +found: + pr_info("find_marker skipped %d bytes\n", skipped); + *pbuf_ptr = buf_ptr; + + return val; +} + +int ff_mjpeg_find_marker(struct MJpegDecodeContext *s, + const u8 **buf_ptr, const u8 *buf_end, + const u8 **unescaped_buf_ptr, + int *unescaped_buf_size) +{ + int start_code; + + start_code = find_marker(buf_ptr, buf_end); + + /* unescape buffer of SOS, use special treatment for JPEG-LS */ + if (start_code == SOS && !s->ls) { + const u8 *src = *buf_ptr; + const u8 *ptr = src; + u8 *dst = s->buffer; + + #define copy_data_segment(skip) do { \ + int length = (ptr - src) - (skip); \ + if (length > 0) { \ + memcpy(dst, src, length); \ + dst += length; \ + src = ptr; \ + } \ + } while (0) + + + while (ptr < buf_end) { + u8 x = *(ptr++); + + if (x == 0xff) { + int skip = 0; + while (ptr < buf_end && x == 0xff) { + x = *(ptr++); + skip++; + } + + /* 0xFF, 0xFF, ... */ + if (skip > 1) { + copy_data_segment(skip); + + /* decrement src as it is equal to ptr after the + * copy_data_segment macro and we might want to + * copy the current value of x later on */ + src--; + } + + if (x < 0xd0 || x > 0xd7) { + copy_data_segment(1); + if (x) + break; + } + } + if (src < ptr) + copy_data_segment(0); + } + #undef copy_data_segment + + *unescaped_buf_ptr = s->buffer; + *unescaped_buf_size = dst - s->buffer; + memset(s->buffer + *unescaped_buf_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + + pr_info("escaping removed %d bytes\n", + (int)((buf_end - *buf_ptr) - (dst - s->buffer))); + } else if (start_code == SOS && s->ls) { + const u8 *src = *buf_ptr; + u8 *dst = s->buffer; + int bit_count = 0; + int t = 0, b = 0; + struct put_bits_context pb; + + /* find marker */ + while (src + t < buf_end) { + u8 x = src[t++]; + if (x == 0xff) { + while ((src + t < buf_end) && x == 0xff) + x = src[t++]; + if (x & 0x80) { + t -= FFMIN(2, t); + break; + } + } + } + bit_count = t * 8; + init_put_bits(&pb, dst, t); + + /* unescape bitstream */ + while (b < t) { + u8 x = src[b++]; + put_bits(&pb, 8, x); + if (x == 0xFF && b < t) { + x = src[b++]; + if (x & 0x80) { + pr_err("Invalid escape sequence\n"); + x &= 0x7f; + } + put_bits(&pb, 7, x); + bit_count--; + } + } + flush_put_bits(&pb); + + *unescaped_buf_ptr = dst; + *unescaped_buf_size = (bit_count + 7) >> 3; + memset(s->buffer + *unescaped_buf_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + } else { + *unescaped_buf_ptr = *buf_ptr; + *unescaped_buf_size = buf_end - *buf_ptr; + } + + return start_code; +} + + +int ff_mjpeg_decode_sof(struct MJpegDecodeContext *s) +{ + int len, nb_components, i, width, height, bits, size_change; + int h_count[MAX_COMPONENTS] = { 0 }; + int v_count[MAX_COMPONENTS] = { 0 }; + + s->cur_scan = 0; + memset(s->upscale_h, 0, sizeof(s->upscale_h)); + memset(s->upscale_v, 0, sizeof(s->upscale_v)); + + /* XXX: verify len field validity */ + len = get_bits(&s->gb, 16); + bits = get_bits(&s->gb, 8); + + if (bits > 16 || bits < 1) { + pr_err("bits %d is invalid\n", bits); + return -1; + } + + height = get_bits(&s->gb, 16); + width = get_bits(&s->gb, 16); + + pr_info("sof0: picture: %dx%d\n", width, height); + + nb_components = get_bits(&s->gb, 8); + if (nb_components <= 0 || + nb_components > MAX_COMPONENTS) + return -1; + + s->nb_components = nb_components; + s->h_max = 1; + s->v_max = 1; + for (i = 0; i < nb_components; i++) { + /* component id */ + s->component_id[i] = get_bits(&s->gb, 8) - 1; + h_count[i] = get_bits(&s->gb, 4); + v_count[i] = get_bits(&s->gb, 4); + /* compute hmax and vmax (only used in interleaved case) */ + if (h_count[i] > s->h_max) + s->h_max = h_count[i]; + if (v_count[i] > s->v_max) + s->v_max = v_count[i]; + s->quant_index[i] = get_bits(&s->gb, 8); + if (s->quant_index[i] >= 4) { + pr_err("quant_index is invalid\n"); + return -1; + } + if (!h_count[i] || !v_count[i]) { + pr_err("Invalid sampling factor in component %d %d:%d\n", + i, h_count[i], v_count[i]); + return -1; + } + + pr_info("component %d %d:%d id: %d quant:%d\n", + i, h_count[i], v_count[i], + s->component_id[i], s->quant_index[i]); + } + if (nb_components == 4 + && s->component_id[0] == 'C' - 1 + && s->component_id[1] == 'M' - 1 + && s->component_id[2] == 'Y' - 1 + && s->component_id[3] == 'K' - 1) + s->adobe_transform = 0; + + /* if different size, realloc/alloc picture */ + if (width != s->width || height != s->height || bits != s->bits || + memcmp(s->h_count, h_count, sizeof(h_count)) || + memcmp(s->v_count, v_count, sizeof(v_count))) { + size_change = 1; + + s->width = width; + s->height = height; + s->bits = bits; + memcpy(s->h_count, h_count, sizeof(h_count)); + memcpy(s->v_count, v_count, sizeof(v_count)); + s->interlaced = 0; + s->got_picture = 0; + } else { + size_change = 0; + } + + return 0; +} + +static int ff_mjpeg_decode_frame(u8 *buf, int buf_size, struct MJpegDecodeContext *s) +{ + const u8 *buf_end, *buf_ptr; + const u8 *unescaped_buf_ptr; + int unescaped_buf_size; + int start_code; + int ret = 0; + + buf_ptr = buf; + buf_end = buf + buf_size; + while (buf_ptr < buf_end) { + /* find start next marker */ + start_code = ff_mjpeg_find_marker(s, &buf_ptr, buf_end, + &unescaped_buf_ptr, + &unescaped_buf_size); + /* EOF */ + if (start_code < 0) { + break; + } else if (unescaped_buf_size > INT_MAX / 8) { + pr_err("MJPEG packet 0x%x too big (%d/%d), corrupt data?\n", + start_code, unescaped_buf_size, buf_size); + return -1; + } + pr_info("marker=%x avail_size_in_buf=%d\n", + start_code, (int)(buf_end - buf_ptr)); + + ret = init_get_bits8(&s->gb, unescaped_buf_ptr, unescaped_buf_size); + if (ret < 0) { + pr_err("invalid buffer\n"); + goto fail; + } + + s->start_code = start_code; + pr_info("startcode: %X\n", start_code); + + switch (start_code) { + case SOF0: + case SOF1: + case SOF2: + case SOF3: + case SOF48: + case SOI: + case SOS: + case EOI: + break; + default: + goto skip; + } + + switch (start_code) { + case SOI: + s->restart_interval = 0; + s->restart_count = 0; + s->raw_image_buffer = buf_ptr; + s->raw_image_buffer_size = buf_end - buf_ptr; + /* nothing to do on SOI */ + break; + case SOF0: + case SOF1: + if (start_code == SOF0) + s->profile = FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT; + else + s->profile = FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT; + s->lossless = 0; + s->ls = 0; + s->progressive = 0; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case SOF2: + s->profile = FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT; + s->lossless = 0; + s->ls = 0; + s->progressive = 1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case SOF3: + s->profile = FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS; + s->properties |= FF_CODEC_PROPERTY_LOSSLESS; + s->lossless = 1; + s->ls = 0; + s->progressive = 0; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case SOF48: + s->profile = FF_PROFILE_MJPEG_JPEG_LS; + s->properties |= FF_CODEC_PROPERTY_LOSSLESS; + s->lossless = 1; + s->ls = 1; + s->progressive = 0; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + goto fail; + break; + case EOI: + goto the_end; + case DHT: + case LSE: + case SOS: + case DRI: + case SOF5: + case SOF6: + case SOF7: + case SOF9: + case SOF10: + case SOF11: + case SOF13: + case SOF14: + case SOF15: + case JPG: + pr_err("mjpeg: unsupported coding type (%x)\n", start_code); + break; + } +skip: + /* eof process start code */ + buf_ptr += (get_bits_count(&s->gb) + 7) / 8; + pr_info("marker parser used %d bytes (%d bits)\n", + (get_bits_count(&s->gb) + 7) / 8, get_bits_count(&s->gb)); + } + + pr_err("No JPEG data found in image\n"); + return -1; +fail: + s->got_picture = 0; + return ret; +the_end: + pr_info("decode frame unused %d bytes\n", (int)(buf_end - buf_ptr)); + + return 0; +} + +int mjpeg_decode_extradata_ps(u8 *buf, int size, struct mjpeg_param_sets *ps) +{ + int ret; + + ps->head_parsed = false; + + ps->dec_ps.buf_size = size; + ps->dec_ps.buffer = vzalloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ps->dec_ps.buffer) + return -1; + + ret = ff_mjpeg_decode_frame(buf, size, &ps->dec_ps); + if (ret) { + pr_err("parse extra data failed. err: %d\n", ret); + vfree(ps->dec_ps.buffer); + return ret; + } + + if (ps->dec_ps.width && ps->dec_ps.height) + ps->head_parsed = true; + + vfree(ps->dec_ps.buffer); + + return 0; +} + |