ImxVpuDecReturnCodes imx_vpu_jpeg_dec_decode(ImxVpuJPEGDecoder *jpeg_decoder, uint8_t const *jpeg_data, size_t const jpeg_data_size) { unsigned int output_code; ImxVpuDecReturnCodes ret; ImxVpuEncodedFrame encoded_frame; assert(jpeg_data != NULL); assert(jpeg_data_size > 0); assert(jpeg_decoder != NULL); assert(jpeg_decoder->decoder != NULL); memset(&encoded_frame, 0, sizeof(encoded_frame)); encoded_frame.data = (uint8_t *)jpeg_data; encoded_frame.data_size = jpeg_data_size; if ((ret = imx_vpu_dec_decode(jpeg_decoder->decoder, &encoded_frame, &output_code)) != IMX_VPU_DEC_RETURN_CODE_OK) return ret; if (output_code & IMX_VPU_DEC_OUTPUT_CODE_DECODED_FRAME_AVAILABLE) { if ((ret = imx_vpu_dec_get_decoded_frame(jpeg_decoder->decoder, &(jpeg_decoder->raw_frame))) != IMX_VPU_DEC_RETURN_CODE_OK) return ret; } else { jpeg_decoder->raw_frame.framebuffer = NULL; } return IMX_VPU_DEC_RETURN_CODE_OK; }
Retval run(Context *ctx) { unsigned int output_code; { long size; void *buf; fseek(ctx->fin, 0, SEEK_END); size = ftell(ctx->fin); fseek(ctx->fin, 0, SEEK_SET); buf = malloc(size); fread(buf, 1, size, ctx->fin); ImxVpuEncodedFrame encoded_frame; encoded_frame.data.virtual_address = buf; encoded_frame.data_size = size; /* Codec data is out-of-band data that is typically stored in a separate space * in containers for each elementary stream; JPEG data does not need it */ encoded_frame.codec_data = NULL; encoded_frame.codec_data_size = 0; fprintf(stderr, "encoded input frame: size: %u byte\n", encoded_frame.data_size); /* Perform the actual decoding */ imx_vpu_dec_decode(ctx->vpudec, &encoded_frame, &output_code); free(buf); } /* Initial info is now available; this usually happens right after the * first frame is decoded, and this is the situation where one must register * output framebuffers, which the decoder then uses like a buffer pool for * picking buffers to decode frame into */ if (output_code & IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE) { unsigned int i; imx_vpu_dec_get_initial_info(ctx->vpudec, &(ctx->initial_info)); fprintf( stderr, "initial info: size: %ux%u pixel rate: %u/%u min num required framebuffers: %u interlacing: %d framebuffer alignment: %u color format: ", ctx->initial_info.frame_width, ctx->initial_info.frame_height, ctx->initial_info.frame_rate_numerator, ctx->initial_info.frame_rate_denominator, ctx->initial_info.min_num_required_framebuffers, ctx->initial_info.interlacing, ctx->initial_info.framebuffer_alignment ); switch (ctx->initial_info.color_format) { case IMX_VPU_COLOR_FORMAT_YUV420: fprintf(stderr, "YUV 4:2:0"); break; case IMX_VPU_COLOR_FORMAT_YUV422_HORIZONTAL: fprintf(stderr, "YUV 4:2:2 horizontal"); break; case IMX_VPU_COLOR_FORMAT_YUV422_VERTICAL: fprintf(stderr, "YUV 4:2:2 vertical"); break; case IMX_VPU_COLOR_FORMAT_YUV444: fprintf(stderr, "YUV 4:4:4"); break; case IMX_VPU_COLOR_FORMAT_YUV400: fprintf(stderr, "YUV 4:0:0 (8-bit grayscale)"); break; } fprintf(stderr, "\n"); ctx->num_framebuffers = ctx->initial_info.min_num_required_framebuffers; imx_vpu_calc_framebuffer_sizes(ctx->initial_info.color_format, ctx->initial_info.frame_width, ctx->initial_info.frame_height, ctx->initial_info.framebuffer_alignment, ctx->initial_info.interlacing, &(ctx->calculated_sizes)); fprintf( stderr, "calculated sizes: frame width&height: %dx%d Y stride: %u CbCr stride: %u Y size: %u CbCr size: %u MvCol size: %u total size: %u\n", ctx->calculated_sizes.aligned_frame_width, ctx->calculated_sizes.aligned_frame_height, ctx->calculated_sizes.y_stride, ctx->calculated_sizes.cbcr_stride, ctx->calculated_sizes.y_size, ctx->calculated_sizes.cbcr_size, ctx->calculated_sizes.mvcol_size, ctx->calculated_sizes.total_size ); ctx->framebuffers = malloc(sizeof(ImxVpuFramebuffer) * ctx->num_framebuffers); ctx->fb_dmabuffers = malloc(sizeof(ImxVpuDMABuffer*) * ctx->num_framebuffers); for (i = 0; i < ctx->num_framebuffers; ++i) { /* Allocate a DMA buffer for each framebuffer. It is possible to specify alternate allocators; * all that is required is that the allocator provides physically contiguous memory * (necessary for DMA transfers) and respecs the alignment value. */ ctx->fb_dmabuffers[i] = imx_vpu_dma_buffer_allocate(imx_vpu_dec_get_default_allocator(), ctx->calculated_sizes.total_size, ctx->initial_info.framebuffer_alignment, 0); imx_vpu_fill_framebuffer_params(&(ctx->framebuffers[i]), &(ctx->calculated_sizes), ctx->fb_dmabuffers[i], 0); } /* Actual registration is done here. From this moment on, the VPU knows which buffers to use for * storing decoded pictures into. This call must not be done again until decoding is shut down or * IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE is set again. */ imx_vpu_dec_register_framebuffers(ctx->vpudec, ctx->framebuffers, ctx->num_framebuffers); } /* Enable drain mode. All available input data is * inserted. Now We want one output picture. */ imx_vpu_dec_enable_drain_mode(ctx->vpudec, 1); /* Get the decoded picture out of the VPU */ { ImxVpuEncodedFrame encoded_frame; /* In drain mode there is no input data */ encoded_frame.data.virtual_address = NULL; encoded_frame.data_size = 0; encoded_frame.codec_data = NULL; encoded_frame.codec_data_size = 0; encoded_frame.context = NULL; imx_vpu_dec_decode(ctx->vpudec, &encoded_frame, &output_code); /* A decoded picture is available for further processing. Retrieve it, do something * with it, and once the picture is no longer needed, mark it as displayed. This * marks it internally as available for further decoding by the VPU. */ if (output_code & IMX_VPU_DEC_OUTPUT_CODE_DECODED_PICTURE_AVAILABLE) { ImxVpuPicture decoded_picture; uint8_t *mapped_virtual_address; size_t num_out_byte = ctx->calculated_sizes.y_size + ctx->calculated_sizes.cbcr_size * 2; /* This call retrieves information about the decoded picture, including * a pointer to the corresponding framebuffer structure. This must not be called more * than once after IMX_VPU_DEC_OUTPUT_CODE_DECODED_PICTURE_AVAILABLE was set. */ imx_vpu_dec_get_decoded_picture(ctx->vpudec, &decoded_picture); fprintf(stderr, "decoded output picture: writing %u byte", num_out_byte); /* Map buffer to the local address space, dump the decoded frame to file, * and unmap again. The decoded frame uses the I420 color format for all * bitstream formats (h.264, MPEG2 etc.), with one exception; with motion JPEG data, * the format can be different. See imxvpuapi.h for details. */ mapped_virtual_address = imx_vpu_dma_buffer_map(decoded_picture.framebuffer->dma_buffer, IMX_VPU_MAPPING_FLAG_READ_ONLY); fwrite(mapped_virtual_address, 1, num_out_byte, ctx->fout); imx_vpu_dma_buffer_unmap(decoded_picture.framebuffer->dma_buffer); /* Mark the framebuffer as displayed, thus returning it to the list of *framebuffers available for decoding. */ imx_vpu_dec_mark_framebuffer_as_displayed(ctx->vpudec, decoded_picture.framebuffer); } } return RETVAL_OK; }