From bb8ddb8ebe0a5a8708eb4901927a9b1ab4d0f052 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sun, 17 Jan 2016 13:25:53 +0100 Subject: [PATCH] Cleanup IMX.6 decoder code --- src/video/imx.c | 320 ++++++++++++++++++++++++------------------------ 1 file changed, 163 insertions(+), 157 deletions(-) diff --git a/src/video/imx.c b/src/video/imx.c index 7047d26..740b566 100644 --- a/src/video/imx.c +++ b/src/video/imx.c @@ -50,6 +50,10 @@ #define MODE422 2 #define MODE224 3 +#define THRESHOLD 2 +#define MIN_FRAME_BUFFER_COUNT 18; +#define WORST_SLICE_SIZE 3188 + struct v4l_buf { void *start; off_t offset; @@ -62,11 +66,14 @@ static vpu_mem_desc slice_mem_desc = {0}; static DecHandle handle = {0}; static DecParam decparam = {0}; +static DecBufInfo bufinfo = {0}; static int fd; +static int regfbcount, stride; + static bool initialized = false, decoding = false, displaying = false; -static int queued_count, threshold; +static int queued_count; static int disp_clr_index = 0; static FrameBuffer *fb; @@ -141,182 +148,183 @@ static void decoder_renderer_setup(int width, int height, int redrawRate, void* decparam.skipframeMode = 0; decparam.skipframeNum = 0; decparam.iframeSearchEnable = 0; -} -static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { - PLENTRY entry = decodeUnit->bufferList; - while (entry != NULL) { - Uint32 space; - PhysicalAddress pa_read_ptr, pa_write_ptr; - if (vpu_DecGetBitstreamBuffer(handle, &pa_read_ptr, &pa_write_ptr, &space) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't get video decoder buffer\n"); - exit(EXIT_FAILURE); - } + regfbcount = MIN_FRAME_BUFFER_COUNT + 2; + int picWidth = ((width + 15) & ~15); + int picHeight = ((height + 15) & ~15); + stride = picWidth; - Uint32 target_addr = mem_desc.virt_uaddr + (pa_write_ptr - mem_desc.phy_addr); + int phy_slicebuf_size = WORST_SLICE_SIZE * 1024; - if ( (target_addr + entry->length) > mem_desc.virt_uaddr + STREAM_BUF_SIZE) { - int room = mem_desc.virt_uaddr + STREAM_BUF_SIZE - target_addr; - memcpy((void *)target_addr, entry->data, room); - memcpy((void *)mem_desc.virt_uaddr, entry->data + room, entry->length - room); - } else { - memcpy((void *)target_addr, entry->data, entry->length); - } - vpu_DecUpdateBitstreamBuffer(handle, entry->length); - entry = entry->next; + slice_mem_desc.size = phy_slicebuf_size; + if (IOGetPhyMem(&slice_mem_desc)){ + fprintf(stderr, "Can't get slice physical address\n"); + exit(EXIT_FAILURE); } - if (!initialized) { - initialized = true; + fb = calloc(regfbcount, sizeof(FrameBuffer)); + if (fb == NULL) { + fprintf(stderr, "Can't allocate framebuffers\n"); + exit(EXIT_FAILURE); + } + + char v4l_device[16], node[8]; + sprintf(node, "%d", 17); + strcpy(v4l_device, "/dev/video"); + strcat(v4l_device, node); + fd = open(v4l_device, O_RDWR, 0); + if (fd < 0){ + fprintf(stderr, "Can't access video output\n"); + exit(EXIT_FAILURE); + } + + struct v4l2_format fmt = {0}; + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + fmt.fmt.pix.width = picWidth; + fmt.fmt.pix.height = picHeight; + fmt.fmt.pix.bytesperline = picWidth; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; + if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { + fprintf(stderr, "Can't set source video format\n"); + exit(EXIT_FAILURE); + } + + if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) { + fprintf(stderr, "Can't set output video format\n"); + exit(EXIT_FAILURE); + } + + struct v4l2_requestbuffers reqbuf = {0}; + reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + reqbuf.memory = V4L2_MEMORY_MMAP; + reqbuf.count = regfbcount; + + struct v4l_buf* buffers[regfbcount]; + + if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { + fprintf(stderr, "Can't get video buffers\n"); + exit(EXIT_FAILURE); + } + + if (reqbuf.count < regfbcount) { + fprintf(stderr, "Not enough video buffers\n"); + exit(EXIT_FAILURE); + } - vpu_DecSetEscSeqInit(handle, 1); - DecInitialInfo initinfo = {0}; - if (vpu_DecGetInitialInfo(handle, &initinfo) != RETCODE_SUCCESS) { - fprintf(stderr, "Can't get initial info\n"); - exit(EXIT_FAILURE); - } - vpu_DecSetEscSeqInit(handle, 0); - - int regfbcount = initinfo.minFrameBufferCount + 2; - threshold = regfbcount - initinfo.minFrameBufferCount; - int picWidth = ((initinfo.picWidth + 15) & ~15); - int picHeight = ((initinfo.picHeight + 15) & ~15); - int stride = picWidth; + for (int i = 0; i < regfbcount; i++) { + struct v4l2_buffer buffer = {0}; + struct v4l_buf *buf; - int phy_slicebuf_size = initinfo.worstSliceSize * 1024; - - slice_mem_desc.size = phy_slicebuf_size; - if (IOGetPhyMem(&slice_mem_desc)){ - fprintf(stderr, "Can't get slice physical address\n"); + buf = calloc(1, sizeof(struct v4l_buf)); + if (buf == NULL) { + fprintf(stderr, "Not enough memory\n"); exit(EXIT_FAILURE); } - fb = calloc(regfbcount, sizeof(FrameBuffer)); - if (fb == NULL) { - fprintf(stderr, "Can't allocate framebuffers\n"); + buffers[i] = buf; + + buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + buffer.memory = V4L2_MEMORY_MMAP; + buffer.index = i; + + if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { + fprintf(stderr, "Can't get video buffer\n"); exit(EXIT_FAILURE); } + buf->start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buffer.m.offset); - char v4l_device[16], node[8]; - sprintf(node, "%d", 17); - strcpy(v4l_device, "/dev/video"); - strcat(v4l_device, node); - fd = open(v4l_device, O_RDWR, 0); - if (fd < 0){ - fprintf(stderr, "Can't access video output\n"); - exit(EXIT_FAILURE); - } - - struct v4l2_format fmt = {0}; - fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - fmt.fmt.pix.width = picWidth; - fmt.fmt.pix.height = picHeight; - fmt.fmt.pix.bytesperline = picWidth; - fmt.fmt.pix.field = V4L2_FIELD_ANY; - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; - if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { + /* + * Workaround for new V4L interface change, this change + * will be removed after V4L driver is updated for this. + * Need to call QUERYBUF ioctl again after mmap. + */ + if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { fprintf(stderr, "Can't set source video format\n"); exit(EXIT_FAILURE); } - if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) { - fprintf(stderr, "Can't set output video format\n"); + buf->offset = buffer.m.offset; + buf->length = buffer.length; + + if (buf->start == MAP_FAILED) { + fprintf(stderr, "Failed to map video buffer\n"); exit(EXIT_FAILURE); } + } - struct v4l2_requestbuffers reqbuf = {0}; - reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - reqbuf.memory = V4L2_MEMORY_MMAP; - reqbuf.count = regfbcount; + int img_size = stride * picHeight; + vpu_mem_desc *mvcol_md = NULL; - struct v4l_buf* buffers[regfbcount]; + int mjpg_fmt = MODE420; + int divX = (mjpg_fmt == MODE420 || mjpg_fmt == MODE422) ? 2 : 1; + int divY = (mjpg_fmt == MODE420 || mjpg_fmt == MODE224) ? 2 : 1; - if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { - fprintf(stderr, "Can't get video buffers\n"); + mvcol_md = calloc(regfbcount, sizeof(vpu_mem_desc)); + + for (int i = 0; i < regfbcount; i++) { + fb[i].myIndex = i; + fb[i].bufY = buffers[i]->offset; + fb[i].bufCb = fb[i].bufY + img_size; + fb[i].bufCr = fb[i].bufCb + (img_size / divX / divY); + + /* allocate MvCol buffer here */ + memset(&mvcol_md[i], 0, sizeof(vpu_mem_desc)); + mvcol_md[i].size = img_size / divX / divY; + if (IOGetPhyMem(&mvcol_md[i])) { + fprintf(stderr, "Can't get physical address of colomn buffer\n"); exit(EXIT_FAILURE); } + fb[i].bufMvCol = mvcol_md[i].phy_addr; + } + + bufinfo.avcSliceBufInfo.bufferBase = slice_mem_desc.phy_addr; + bufinfo.avcSliceBufInfo.bufferSize = phy_slicebuf_size; - if (reqbuf.count < regfbcount) { - fprintf(stderr, "Not enough video buffers\n"); - exit(EXIT_FAILURE); + bufinfo.maxDecFrmInfo.maxMbX = stride / 16; + bufinfo.maxDecFrmInfo.maxMbY = picHeight / 16; + bufinfo.maxDecFrmInfo.maxMbNum = stride * picHeight / 256; + + int delay = -1; + vpu_DecGiveCommand(handle, DEC_SET_FRAME_DELAY, &delay); +} + +static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { + Uint32 space; + PhysicalAddress pa_read_ptr, pa_write_ptr; + if (vpu_DecGetBitstreamBuffer(handle, &pa_read_ptr, &pa_write_ptr, &space) != RETCODE_SUCCESS) { + fprintf(stderr, "Can't get video decoder buffer\n"); + exit(EXIT_FAILURE); + } + Uint32 target_addr = mem_desc.virt_uaddr + (pa_write_ptr - mem_desc.phy_addr); + + if (space < decodeUnit->fullLength) { + fprintf(stderr, "Not enough space in buffer %d/%d\n", decodeUnit->fullLength, space); + } + + PLENTRY entry = decodeUnit->bufferList; + int written = 0; + while (entry != NULL) { + if ( (target_addr + entry->length) > mem_desc.virt_uaddr + STREAM_BUF_SIZE) { + int room = mem_desc.virt_uaddr + STREAM_BUF_SIZE - target_addr; + memcpy((void *)target_addr, entry->data, room); + memcpy((void *)mem_desc.virt_uaddr, entry->data + room, entry->length - room); + target_addr = mem_desc.virt_uaddr + entry->length - room; + } else { + memcpy((void *)target_addr, entry->data, entry->length); + target_addr += entry->length; } - - for (int i = 0; i < regfbcount; i++) { - struct v4l2_buffer buffer = {0}; - struct v4l_buf *buf; - buf = calloc(1, sizeof(struct v4l_buf)); - if (buf == NULL) { - return -9; - } - - buffers[i] = buf; - - buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - buffer.memory = V4L2_MEMORY_MMAP; - buffer.index = i; - - if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { - fprintf(stderr, "Can't get video buffer\n"); - exit(EXIT_FAILURE); - } - buf->start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buffer.m.offset); - - /* - * Workaround for new V4L interface change, this change - * will be removed after V4L driver is updated for this. - * Need to call QUERYBUF ioctl again after mmap. - */ - if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { - fprintf(stderr, "Can't set source video format\n"); - exit(EXIT_FAILURE); - } - - buf->offset = buffer.m.offset; - buf->length = buffer.length; - - if (buf->start == MAP_FAILED) { - fprintf(stderr, "Failed to map video buffer\n"); - exit(EXIT_FAILURE); - } - } - - int img_size = stride * picHeight; - vpu_mem_desc *mvcol_md = NULL; - - int mjpg_fmt = MODE420; - int divX = (mjpg_fmt == MODE420 || mjpg_fmt == MODE422) ? 2 : 1; - int divY = (mjpg_fmt == MODE420 || mjpg_fmt == MODE224) ? 2 : 1; - - mvcol_md = calloc(regfbcount, sizeof(vpu_mem_desc)); - - for (int i = 0; i < regfbcount; i++) { - fb[i].myIndex = i; - fb[i].bufY = buffers[i]->offset; - fb[i].bufCb = fb[i].bufY + img_size; - fb[i].bufCr = fb[i].bufCb + (img_size / divX / divY); - - /* allocate MvCol buffer here */ - memset(&mvcol_md[i], 0, sizeof(vpu_mem_desc)); - mvcol_md[i].size = img_size / divX / divY; - if (IOGetPhyMem(&mvcol_md[i])) { - fprintf(stderr, "Can't get physical address of colomn buffer\n"); - exit(EXIT_FAILURE); - } - fb[i].bufMvCol = mvcol_md[i].phy_addr; - } - - DecBufInfo bufinfo; - bufinfo.avcSliceBufInfo.bufferBase = slice_mem_desc.phy_addr; - bufinfo.avcSliceBufInfo.bufferSize = phy_slicebuf_size; - - bufinfo.maxDecFrmInfo.maxMbX = stride / 16; - bufinfo.maxDecFrmInfo.maxMbY = picHeight / 16; - bufinfo.maxDecFrmInfo.maxMbNum = stride * picHeight / 256; - - int delay = -1; - vpu_DecGiveCommand(handle, DEC_SET_FRAME_DELAY, &delay); + entry = entry->next; + } + vpu_DecUpdateBitstreamBuffer(handle, decodeUnit->fullLength); + if (!initialized) { + initialized = true; + DecInitialInfo info = {0}; + vpu_DecSetEscSeqInit(handle, 1); + vpu_DecGetInitialInfo(handle, &info); + vpu_DecSetEscSeqInit(handle, 0); if (vpu_DecRegisterFrameBuffer(handle, fb, regfbcount, stride, &bufinfo) != RETCODE_SUCCESS) { fprintf(stderr, "Can't register decoder to framebuffer\n"); exit(EXIT_FAILURE); @@ -330,7 +338,7 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { } decoding = true; } - + int loop_id = 0; while (vpu_IsBusy()) { if (loop_id > 50) { @@ -341,7 +349,6 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { vpu_WaitForInt(100); loop_id++; } - loop_id = 0; if (decoding) { decoding = 0; @@ -353,7 +360,7 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { } if (outinfo.decodingSuccess & 0x10) { - return 0; + return DR_OK; } else if (outinfo.notSufficientPsBuffer) { fprintf(stderr, "Not enough space in stream buffer\n"); exit(EXIT_FAILURE); @@ -394,7 +401,7 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { queued_count++; - if (queued_count > threshold) { + if (queued_count > THRESHOLD) { dbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; dbuf.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, &dbuf) < 0) { @@ -402,9 +409,8 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { exit(EXIT_FAILURE); } else queued_count--; - } else - dbuf.index = -1; - + } + if (disp_clr_index >= 0) vpu_DecClrDispFlag(handle, disp_clr_index); @@ -431,5 +437,5 @@ DECODER_RENDERER_CALLBACKS decoder_callbacks_imx = { .setup = decoder_renderer_setup, .cleanup = decoder_renderer_cleanup, .submitDecodeUnit = decoder_renderer_submit_decode_unit, - .capabilities = CAPABILITY_DIRECT_SUBMIT, + .capabilities = CAPABILITY_DIRECT_SUBMIT | CAPABILITY_SLICES_PER_FRAME(2), };