summaryrefslogtreecommitdiff
path: root/drivers/mxc/vpu_malone/insert_startcode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mxc/vpu_malone/insert_startcode.c')
-rw-r--r--drivers/mxc/vpu_malone/insert_startcode.c659
1 files changed, 659 insertions, 0 deletions
diff --git a/drivers/mxc/vpu_malone/insert_startcode.c b/drivers/mxc/vpu_malone/insert_startcode.c
new file mode 100644
index 000000000000..3d945ba00e3d
--- /dev/null
+++ b/drivers/mxc/vpu_malone/insert_startcode.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright 2018-2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file insert_startcode.c
+ *
+ * copyright here may be changed later
+ *
+ *
+ */
+#include "insert_startcode.h"
+
+static void set_payload_hdr(unsigned char *dst, unsigned int scd_type, unsigned int codec_id,
+ unsigned int buffer_size, unsigned int width, unsigned int height)
+{
+ unsigned int payload_size;
+ /* payload_size = buffer_size + itself_size(16) - start_code(4) */
+ payload_size = buffer_size + 12;
+
+ dst[0] = 0x00;
+ dst[1] = 0x00;
+ dst[2] = 0x01;
+ dst[3] = scd_type;
+
+ /* length */
+ dst[4] = ((payload_size>>16)&0xff);
+ dst[5] = ((payload_size>>8)&0xff);
+ dst[6] = 0x4e;
+ dst[7] = ((payload_size>>0)&0xff);
+
+ /* Codec ID and Version */
+ dst[8] = codec_id;
+ dst[9] = IMX_CODEC_VERSION_ID;
+
+ /* width */
+ dst[10] = ((width>>8)&0xff);
+ dst[11] = ((width>>0)&0xff);
+ dst[12] = 0x58;
+
+ /* height */
+ dst[13] = ((height>>8)&0xff);
+ dst[14] = ((height>>0)&0xff);
+ dst[15] = 0x50;
+}
+
+static void set_vc1_rcv_seqhdr(unsigned char *dst, unsigned char *src,
+ unsigned int width, unsigned int height)
+{
+ unsigned int frames = IMX_VC1_RCV_NUM_FRAMES;
+ unsigned int ext_data_size = IMX_VC1_RCV_SEQ_EXT_DATA_SIZE;
+
+ /* 0-2 Number of frames, used default value 0xFF */
+ dst[0] = (unsigned char)frames;
+ dst[1] = (unsigned char)(frames >> 8);
+ dst[2] = (unsigned char)(frames >> 16);
+
+ /* 3 RCV version, used V1 */
+ dst[3] = (unsigned char)(IMX_VC1_RCV_CODEC_V1_VERSION);
+
+ /* 4-7 extension data size */
+ dst[4] = (unsigned char)ext_data_size;
+ dst[5] = (unsigned char)(ext_data_size >> 8);
+ dst[6] = (unsigned char)(ext_data_size >> 16);
+ dst[7] = (unsigned char)(ext_data_size >> 24);
+ /* 8-11 extension data */
+ dst[8] = src[0];
+ dst[9] = src[1];
+ dst[10] = src[2];
+ dst[11] = src[3];
+
+ /* height */
+ dst[12] = (unsigned char)height;
+ dst[13] = (unsigned char)(((height >> 8) & 0xff));
+ dst[14] = (unsigned char)(((height >> 16) & 0xff));
+ dst[15] = (unsigned char)(((height >> 24) & 0xff));
+ /* width */
+ dst[16] = (unsigned char)width;
+ dst[17] = (unsigned char)(((width >> 8) & 0xff));
+ dst[18] = (unsigned char)(((width >> 16) & 0xff));
+ dst[19] = (unsigned char)(((width >> 24) & 0xff));
+}
+
+static void set_vc1_rcv_pichdr(unsigned char *dst, unsigned int buffer_size)
+{
+ dst[0] = (unsigned char)buffer_size;
+ dst[1] = (unsigned char)(buffer_size >> 8);
+ dst[2] = (unsigned char)(buffer_size >> 16);
+ dst[3] = (unsigned char)(buffer_size >> 24);
+}
+
+static int create_vc1_nal_pichdr(unsigned char *dst, void *data)
+{
+ int len = 0;
+
+ if (IMX_VC1_IS_NOT_NAL(*((unsigned int *)data))) {
+ /* need insert nal header: special ID */
+ dst[0] = 0x0;
+ dst[1] = 0x0;
+ dst[2] = 0x01;
+ dst[3] = 0x0D;
+
+ len = 4;
+ }
+
+ return len;
+}
+
+static unsigned int insert_scd_pic_vc1(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+
+ if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) {
+ unsigned int rcv_pichdr_size = IMX_VC1_RCV_PIC_HEADER_LEN;
+ unsigned char rcv_pichdr[IMX_VC1_RCV_PIC_HEADER_LEN] = { 0 };
+ unsigned char scd_pichdr[16] = { 0 };
+
+ set_payload_hdr(scd_pichdr, SCODE_NEW_PICTURE, IMX_CODEC_ID_VC1_SIMPLE,
+ rcv_pichdr_size + buffer_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, scd_pichdr, 16);
+ set_vc1_rcv_pichdr(rcv_pichdr, buffer_size);
+ length += copy_buffer_to_stream(ctx, rcv_pichdr, rcv_pichdr_size);
+ } else {
+ unsigned char nal_hdr[IMX_VC1_NAL_HEADER_LEN] = { 0 };
+ unsigned int len;
+
+ len = create_vc1_nal_pichdr(nal_hdr, data);
+ length += copy_buffer_to_stream(ctx, nal_hdr, len);
+ }
+
+ return length;
+}
+
+static unsigned int insert_scd_seq_vc1(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned int rvc_seqhdr_size = IMX_VC1_RCV_SEQ_HEADER_LEN;
+ unsigned char rcv_seqhdr[IMX_VC1_RCV_SEQ_HEADER_LEN] = { 0 };
+ unsigned char scd_seqhdr[16] = { 0 };
+
+ if (q_data->fourcc == V4L2_PIX_FMT_VC1_ANNEX_G) {
+ set_payload_hdr(scd_seqhdr, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_VC1_SIMPLE,
+ rvc_seqhdr_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, scd_seqhdr, 16);
+
+ set_vc1_rcv_seqhdr(rcv_seqhdr, data, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, rcv_seqhdr, rvc_seqhdr_size);
+ } else {
+ length += copy_buffer_to_stream(ctx, data, buffer_size);
+ }
+
+ return length;
+}
+
+static unsigned int insert_scd_pic_vp6(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char pic_header[16] = { 0 };
+
+ set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_VC1_SIMPLE,
+ buffer_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, pic_header, 16);
+
+ return length;
+}
+
+static unsigned int insert_scd_seq_vp6(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char seq_header[16] = {0};
+ unsigned char *src = (unsigned char *)data;
+
+ set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_VP6,
+ 0, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, seq_header, 16);
+
+ /* first data include frame data, need to handle them too */
+ length += insert_scd_pic_vp6(ctx, buffer_size, data);
+ length += copy_buffer_to_stream(ctx, src, buffer_size);
+
+ return length;
+}
+
+static void set_vp8_ivf_seqhdr(unsigned char *dst, int width, int height)
+{
+ /* 0-3byte signature "DKIF" */
+ dst[0] = 0x44;
+ dst[1] = 0x4b;
+ dst[2] = 0x49;
+ dst[3] = 0x46;
+ /* 4-5byte version: should be 0*/
+ dst[4] = 0x00;
+ dst[5] = 0x00;
+ /* 6-7 length of Header */
+ dst[6] = IMX_VP8_IVF_SEQ_HEADER_LEN;
+ dst[7] = IMX_VP8_IVF_SEQ_HEADER_LEN >> 8;
+ /* 8-11 VP8 fourcc */
+ dst[8] = 0x56;
+ dst[9] = 0x50;
+ dst[10] = 0x38;
+ dst[11] = 0x30;
+ /* 12-13 width in pixels */
+ dst[12] = width;
+ dst[13] = width >> 8;
+ /* 14-15 height in pixels */
+ dst[14] = height;
+ dst[15] = height >> 8;
+ /* 16-19 frame rate */
+ dst[16] = 0xe8;
+ dst[17] = 0x03;
+ dst[18] = 0x00;
+ dst[19] = 0x00;
+ /* 20-23 time scale */
+ dst[20] = 0x01;
+ dst[21] = 0x00;
+ dst[22] = 0x00;
+ dst[23] = 0x00;
+ /* 24-27 number frames */
+ dst[24] = 0xdf;
+ dst[25] = 0xf9;
+ dst[26] = 0x09;
+ dst[27] = 0x00;
+ /* 28-31 reserved */
+}
+
+static void set_vp8_ivf_pichdr(unsigned char *dst, unsigned int frame_size)
+{
+ /*
+ * firmware just parse 64-bit timestamp(8 bytes).
+ * As not transfer timestamp to firmware, use default value(ZERO).
+ * No need to do anything here
+ */
+}
+
+static unsigned int insert_scd_pic_vp8(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned int ivf_pichdr_size = IMX_VP8_IVF_FRAME_HEADER_LEN;
+ unsigned char pic_header[16] = { 0 };
+ unsigned char ivf_frame_header[IMX_VP8_IVF_FRAME_HEADER_LEN] = { 0 };
+
+ set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_VP8,
+ ivf_pichdr_size + buffer_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, pic_header, 16);
+ set_vp8_ivf_pichdr(ivf_frame_header, buffer_size);
+ length += copy_buffer_to_stream(ctx, ivf_frame_header, ivf_pichdr_size);
+
+ return length;
+}
+
+static unsigned int insert_scd_seq_vp8(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned int ivf_seqhdr_size = IMX_VP8_IVF_SEQ_HEADER_LEN;
+ unsigned char scd_seqhdr[16] = { 0 };
+ unsigned char ivf_seqhdr[IMX_VP8_IVF_SEQ_HEADER_LEN] = { 0 };
+ unsigned char *src = (unsigned char *)data;
+
+ set_payload_hdr(scd_seqhdr, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_VP8,
+ ivf_seqhdr_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, scd_seqhdr, 16);
+ set_vp8_ivf_seqhdr(ivf_seqhdr, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, ivf_seqhdr, ivf_seqhdr_size);
+
+ /* first data include frame data, need to handle them too */
+ length += insert_scd_pic_vp8(ctx, buffer_size, data);
+ length += copy_buffer_to_stream(ctx, src, buffer_size);
+
+ return length;
+}
+
+static unsigned int insert_scd_pic_asp(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char pic_header[16] = { 0 };
+
+ if (q_data->fourcc == VPU_PIX_FMT_DIV3) {
+ set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_DIVX3,
+ buffer_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, pic_header, 16);
+ }
+
+ return length;
+}
+
+static unsigned int insert_scd_seq_asp(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char seq_header[16] = {0};
+ unsigned char *src = (unsigned char *)data;
+
+ if (q_data->fourcc == VPU_PIX_FMT_DIV3) {
+ set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_DIVX3,
+ 0, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, seq_header, 16);
+
+ /* first data include frame data, need to handle them too */
+ length += insert_scd_pic_asp(ctx, buffer_size, data);
+ length += copy_buffer_to_stream(ctx, src, buffer_size);
+ } else {
+ /*
+ * other format no sequence or picture header
+ * directly copy frame data to ring buffer
+ */
+ length += copy_buffer_to_stream(ctx, src, buffer_size);
+ }
+
+ return length;
+}
+
+static unsigned int insert_scd_pic_spk(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char pic_header[16] = { 0 };
+
+ set_payload_hdr(pic_header, SCODE_NEW_PICTURE, IMX_CODEC_ID_SPK,
+ buffer_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, pic_header, 16);
+
+ return length;
+}
+
+static unsigned int insert_scd_seq_spk(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char seq_header[16] = {0};
+ unsigned char *src = (unsigned char *)data;
+
+ set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, IMX_CODEC_ID_SPK,
+ 0, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, seq_header, 16);
+
+ /* first data include frame data, need to handle them too */
+ length += insert_scd_pic_spk(ctx, buffer_size, data);
+ length += copy_buffer_to_stream(ctx, src, buffer_size);
+
+ return length;
+}
+
+static unsigned int insert_slice_arv(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char slice_header[16] = { 0 };
+ unsigned int codec_id;
+
+ if (ctx->arv_type == ARV_8)
+ codec_id = IMX_CODEC_ID_ARV8;
+ else
+ codec_id = IMX_CODEC_ID_ARV9;
+
+ set_payload_hdr(slice_header, SCODE_NEW_SLICE, codec_id, buffer_size,
+ q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, slice_header, 16);
+
+ return length;
+}
+
+static unsigned int insert_scd_pic_arv(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned int slice_num = 0;
+ unsigned int packlen = 0;
+ unsigned char pic_header[16] = { 0 };
+ unsigned char *src = (unsigned char *)data;
+ unsigned int codec_id;
+
+ slice_num = ((src[16] << 24) | (src[17] << 16) | (src[18] << 8) | (src[19]));
+ packlen = 20 + 8 * slice_num;
+ if (ctx->arv_type == ARV_8)
+ codec_id = IMX_CODEC_ID_ARV8;
+ else
+ codec_id = IMX_CODEC_ID_ARV9;
+
+ set_payload_hdr(pic_header, SCODE_NEW_PICTURE, codec_id, packlen,
+ q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, pic_header, 16);
+
+ return length;
+}
+
+static unsigned int insert_scd_seq_arv(struct vpu_ctx *ctx, unsigned int buffer_size, void *data)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+ unsigned char seq_header[16] = {0};
+ unsigned int codec_id;
+
+ if (strncmp((const char *)(data + 8), "RV30", 4) == 0) {
+ ctx->arv_type = ARV_8;
+ codec_id = IMX_CODEC_ID_ARV8;
+ } else {
+ ctx->arv_type = ARV_9;
+ codec_id = IMX_CODEC_ID_ARV9;
+ }
+
+ set_payload_hdr(seq_header, SCODE_NEW_SEQUENCE, codec_id,
+ buffer_size, q_data->width, q_data->height);
+ length += copy_buffer_to_stream(ctx, seq_header, 16);
+ length += copy_buffer_to_stream(ctx, data, buffer_size);
+
+ return length;
+}
+
+u_int32 single_seq_info_format(struct queue_data *q_data)
+{
+ u_int32 ret = 0;
+
+ switch (q_data->fourcc) {
+ case V4L2_PIX_FMT_VC1_ANNEX_G:
+ case V4L2_PIX_FMT_VC1_ANNEX_L:
+ case VPU_PIX_FMT_RV:
+ case V4L2_PIX_FMT_MPEG4:
+ case V4L2_PIX_FMT_MPEG2:
+ case V4L2_PIX_FMT_XVID:
+ ret = 1;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+bool check_free_size_4_seq(struct vpu_ctx *ctx, u_int32 uPayloadSize)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ u_int32 nfreespace = 0;
+ u_int32 length = 0;
+
+ switch (q_data->vdec_std) {
+ case VPU_VIDEO_VC1:
+ length = IMX_VC1_RCV_SEQ_HEADER_LEN + 16;
+ break;
+ case VPU_VIDEO_VP6:
+ length = uPayloadSize + 32;
+ break;
+ case VPU_VIDEO_VP8:
+ length = uPayloadSize + 72;
+ break;
+ case VPU_VIDEO_ASP:
+ length = uPayloadSize + 16;
+ break;
+ case VPU_VIDEO_SPK:
+ length = uPayloadSize + 32;
+ break;
+ case VPU_VIDEO_RV:
+ length = uPayloadSize + 16;
+ break;
+ case VPU_VIDEO_AVC:
+ case VPU_VIDEO_MPEG2:
+ case VPU_VIDEO_AVS:
+ case VPU_VIDEO_JPEG:
+ case VPU_VIDEO_AVC_MVC:
+ case VPU_VIDEO_HEVC:
+ case VPU_VIDEO_UNDEFINED:
+ length = uPayloadSize;
+ break;
+ default:
+ break;
+ }
+
+ pStrBufDesc = get_str_buffer_desc(ctx);
+ nfreespace = got_free_space(pStrBufDesc->wptr, pStrBufDesc->rptr,
+ pStrBufDesc->start, pStrBufDesc->end);
+ if (nfreespace < (length + MIN_SPACE)) {
+ vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool check_free_size_pic(struct vpu_ctx *ctx, unsigned int buffer_size)
+{
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ pSTREAM_BUFFER_DESCRIPTOR_TYPE pStrBufDesc;
+ unsigned int nfreespace = 0;
+ unsigned int length = 0;
+
+ switch (q_data->vdec_std) {
+ case VPU_VIDEO_VC1:
+ length = buffer_size + IMX_VC1_RCV_PIC_HEADER_LEN
+ + IMX_PAYLOAD_HEADER_SIZE;
+ break;
+ case VPU_VIDEO_VP8:
+ length = buffer_size + IMX_VP8_IVF_FRAME_HEADER_LEN + IMX_PAYLOAD_HEADER_SIZE;
+ break;
+ case VPU_VIDEO_VP6:
+ case VPU_VIDEO_ASP:
+ case VPU_VIDEO_SPK:
+ length = buffer_size + IMX_PAYLOAD_HEADER_SIZE;
+ break;
+ case VPU_VIDEO_RV:
+ /* speciall: buffer_size need to include all slice header size*/
+ length = buffer_size + IMX_PAYLOAD_HEADER_SIZE;
+ break;
+ case VPU_VIDEO_AVC:
+ case VPU_VIDEO_MPEG2:
+ case VPU_VIDEO_AVS:
+ case VPU_VIDEO_JPEG:
+ case VPU_VIDEO_AVC_MVC:
+ case VPU_VIDEO_HEVC:
+ case VPU_VIDEO_UNDEFINED:
+ length = buffer_size;
+ break;
+ default:
+ break;
+ }
+
+ pStrBufDesc = get_str_buffer_desc(ctx);
+ nfreespace = got_free_space(pStrBufDesc->wptr, pStrBufDesc->rptr,
+ pStrBufDesc->start, pStrBufDesc->end);
+ if (nfreespace < (length + MIN_SPACE)) {
+ vpu_dbg(LVL_INFO, "buffer_full: the circular buffer freespace < buffer_size\n");
+ return false;
+ }
+
+ return true;
+}
+
+struct VPU_FMT_INFO_ARV *get_arv_info(struct vpu_ctx *ctx, u_int8 *src, u_int32 size)
+{
+ u_int32 i;
+ struct VPU_FMT_INFO_ARV *arv_frame;
+
+ if (!ctx || !src)
+ return NULL;
+
+ if (size < 28)
+ return NULL;
+
+ arv_frame = kzalloc(sizeof(struct VPU_FMT_INFO_ARV), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(arv_frame)) {
+ vpu_err("%s() error: arv_frame alloc failed\n", __func__);
+ goto err;
+ }
+
+ arv_frame->type = ctx->arv_type;
+
+ arv_frame->data_len = ((src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]));
+ arv_frame->slice_num = ((src[16] << 24) | (src[17] << 16) | (src[18] << 8) | (src[19]));
+ if (arv_frame->data_len > size || arv_frame->slice_num > size) {
+ vpu_dbg(LVL_WARN, "arv frame info incorrect, data_len=%d slice_num=%d buffer_size=%d\n",
+ arv_frame->data_len, arv_frame->slice_num, size);
+ goto err;
+ }
+
+ arv_frame->slice_offset = kcalloc(arv_frame->slice_num, sizeof(u_int32), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(arv_frame->slice_offset)) {
+ vpu_err("%s() error: slice_offset alloc failed\n", __func__);
+ goto err;
+ }
+
+ for (i = 0; i < arv_frame->slice_num; i++)
+ arv_frame->slice_offset[i] = ((src[20+8*i+4] << 24) | (src[20+8*i+5] << 16) | (src[20+8*i+6] << 8) | (src[20+8*i+7]));
+
+ return arv_frame;
+
+err:
+ kfree(arv_frame->slice_offset);
+ kfree(arv_frame);
+ return NULL;
+}
+
+void put_arv_info(struct VPU_FMT_INFO_ARV *arv_frame)
+{
+ kfree(arv_frame->slice_offset);
+ kfree(arv_frame);
+}
+
+static const struct imx_scd_handler handlers[] = {
+ {.vdec_std = VPU_VIDEO_VC1,
+ .insert_scd_seq = insert_scd_seq_vc1,
+ .insert_scd_pic = insert_scd_pic_vc1,
+ },
+ {.vdec_std = VPU_VIDEO_VP6,
+ .insert_scd_seq = insert_scd_seq_vp6,
+ .insert_scd_pic = insert_scd_pic_vp6,
+ },
+ {.vdec_std = VPU_VIDEO_VP8,
+ .insert_scd_seq = insert_scd_seq_vp8,
+ .insert_scd_pic = insert_scd_pic_vp8,
+ },
+ {.vdec_std = VPU_VIDEO_ASP,
+ .insert_scd_seq = insert_scd_seq_asp,
+ .insert_scd_pic = insert_scd_pic_asp,
+ },
+ {.vdec_std = VPU_VIDEO_SPK,
+ .insert_scd_seq = insert_scd_seq_spk,
+ .insert_scd_pic = insert_scd_pic_spk,
+ },
+ {.vdec_std = VPU_VIDEO_RV,
+ .insert_scd_seq = insert_scd_seq_arv,
+ .insert_scd_pic = insert_scd_pic_arv,
+ .insert_scd_slice = insert_slice_arv,
+ },
+};
+
+unsigned int insert_scode(struct vpu_ctx *ctx, unsigned int scd_type, unsigned int buffer_size, void *data)
+{
+ const struct imx_scd_handler *handler;
+ int i = 0;
+ bool found = false;
+ struct queue_data *q_data = &ctx->q_data[V4L2_SRC];
+ unsigned int length = 0;
+
+ for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+ handler = &handlers[i];
+ if (handler->vdec_std != q_data->vdec_std)
+ continue;
+ found = true;
+ break;
+ }
+
+ if (scd_type == SCODE_NEW_SEQUENCE) {
+ if (!check_free_size_4_seq(ctx, buffer_size))
+ return length;
+
+ /* some format first data is frame data, and no need to add
+ * any header, directly copy it to ring buffer.
+ */
+ if (found && handler->insert_scd_seq)
+ length = handler->insert_scd_seq(ctx, buffer_size, data);
+ else
+ length = copy_buffer_to_stream(ctx, data, buffer_size);
+ } else if (scd_type == SCODE_NEW_PICTURE) {
+ if (found && handler->insert_scd_pic)
+ length = handler->insert_scd_pic(ctx, buffer_size, data);
+ } else if (scd_type == SCODE_NEW_SLICE) {
+ if (found && handler->insert_scd_slice)
+ length = handler->insert_scd_slice(ctx, buffer_size, data);
+ } else {
+ vpu_dbg(LVL_WARN, "ctx[%d] scd_type invalid\n", ctx->str_index);
+ }
+
+ return length;
+}