GstImxVpuFramebufferArray * gst_imx_vpu_framebuffer_array_new(ImxVpuColorFormat color_format, unsigned int frame_width, unsigned int frame_height, unsigned int framebuffer_alignment, gboolean uses_interlacing, gboolean chroma_interleave, unsigned int num_framebuffers, GstImxPhysMemAllocator *phys_mem_allocator) { guint i; GstImxVpuFramebufferArray *framebuffer_array = g_object_new(gst_imx_vpu_framebuffer_array_get_type(), NULL); framebuffer_array->original_frame_width = frame_width; framebuffer_array->original_frame_height = frame_height; imx_vpu_calc_framebuffer_sizes( color_format, frame_width, frame_height, framebuffer_alignment, uses_interlacing, chroma_interleave, &(framebuffer_array->framebuffer_sizes) ); framebuffer_array->framebuffers = (ImxVpuFramebuffer *)g_slice_alloc(sizeof(ImxVpuFramebuffer) * num_framebuffers); framebuffer_array->num_framebuffers = num_framebuffers; framebuffer_array->allocator = (GstAllocator *)gst_object_ref(GST_OBJECT(phys_mem_allocator)); GST_DEBUG_OBJECT(framebuffer_array, "allocating and registering %u framebuffers", num_framebuffers); for (i = 0; i < num_framebuffers; ++i) { GstImxPhysMemory *memory; ImxVpuFramebuffer *framebuffer = &(framebuffer_array->framebuffers[i]); // TODO: pass on framebuffer_alignment to the internal allocator somehow memory = (GstImxPhysMemory *)gst_allocator_alloc( framebuffer_array->allocator, framebuffer_array->framebuffer_sizes.total_size, NULL ); if (memory == NULL) return FALSE; /* When filling in the params, use "memory" as the user-defined context parameter * This is useful to be able to later determine which memory block this framebuffer * is associated with. See gst_imx_vpu_framebuffer_array_get_gst_phys_memory(). */ imx_vpu_fill_framebuffer_params( framebuffer, &(framebuffer_array->framebuffer_sizes), GST_IMX_VPU_MEM_IMXVPUAPI_DMA_BUFFER(memory), memory ); GST_DEBUG_OBJECT( framebuffer_array, "memory block %p physical address %" GST_IMX_PHYS_ADDR_FORMAT " ref count %d", (gpointer)memory, memory->phys_addr, GST_MINI_OBJECT_REFCOUNT_VALUE(memory) ); } return framebuffer_array; }
static ImxVpuEncReturnCodes imx_vpu_jpeg_enc_open_internal(ImxVpuJPEGEncoder *jpeg_encoder) { unsigned int i; ImxVpuEncOpenParams open_params; ImxVpuEncReturnCodes ret = IMX_VPU_ENC_RETURN_CODE_OK; assert(jpeg_encoder != NULL); assert(jpeg_encoder->frame_width > 0); assert(jpeg_encoder->frame_height > 0); assert(jpeg_encoder->encoder == NULL); imx_vpu_enc_set_default_open_params(IMX_VPU_CODEC_FORMAT_MJPEG, &open_params); open_params.frame_width = jpeg_encoder->frame_width; open_params.frame_height = jpeg_encoder->frame_height; open_params.codec_params.mjpeg_params.quality_factor = jpeg_encoder->quality_factor; if ((ret = imx_vpu_enc_open(&(jpeg_encoder->encoder), &open_params, jpeg_encoder->bitstream_buffer)) != IMX_VPU_ENC_RETURN_CODE_OK) goto error; if ((ret = imx_vpu_enc_get_initial_info(jpeg_encoder->encoder, &(jpeg_encoder->initial_info))) != IMX_VPU_ENC_RETURN_CODE_OK) goto error; jpeg_encoder->num_framebuffers = jpeg_encoder->initial_info.min_num_required_framebuffers; jpeg_encoder->framebuffers = IMX_VPU_ALLOC(sizeof(ImxVpuFramebuffer) * jpeg_encoder->num_framebuffers); jpeg_encoder->fb_dmabuffers = IMX_VPU_ALLOC(sizeof(ImxVpuDMABuffer *) * jpeg_encoder->num_framebuffers); memset(jpeg_encoder->framebuffers, 0, sizeof(ImxVpuFramebuffer) * jpeg_encoder->num_framebuffers); memset(jpeg_encoder->fb_dmabuffers, 0, sizeof(ImxVpuDMABuffer *) * jpeg_encoder->num_framebuffers); imx_vpu_calc_framebuffer_sizes(jpeg_encoder->color_format, jpeg_encoder->frame_width, jpeg_encoder->frame_height, jpeg_encoder->initial_info.framebuffer_alignment, 0, 0, &(jpeg_encoder->calculated_sizes)); for (i = 0; i < jpeg_encoder->num_framebuffers; ++i) { jpeg_encoder->fb_dmabuffers[i] = imx_vpu_dma_buffer_allocate(jpeg_encoder->dma_buffer_allocator, jpeg_encoder->calculated_sizes.total_size, jpeg_encoder->initial_info.framebuffer_alignment, 0); if (jpeg_encoder->fb_dmabuffers[i] == NULL) { IMX_VPU_ERROR("could not allocate DMA buffer for framebuffer #%u", i); ret = IMX_VPU_ENC_RETURN_CODE_ERROR; goto error; } imx_vpu_fill_framebuffer_params(&(jpeg_encoder->framebuffers[i]), &(jpeg_encoder->calculated_sizes), jpeg_encoder->fb_dmabuffers[i], 0); } if ((ret = imx_vpu_enc_register_framebuffers(jpeg_encoder->encoder, jpeg_encoder->framebuffers, jpeg_encoder->num_framebuffers)) != IMX_VPU_ENC_RETURN_CODE_OK) { IMX_VPU_ERROR("could not register framebuffers: %s", imx_vpu_enc_error_string(ret)); goto error; } return ret; error: imx_vpu_jpeg_enc_close_internal(jpeg_encoder); return ret; }
Context* init(FILE *input_file, FILE *output_file) { Context *ctx; ImxVpuEncOpenParams open_params; unsigned int i; ctx = calloc(1, sizeof(Context)); ctx->fin = input_file; ctx->fout = output_file; /* Set the open params. Use the default values (note that memset must still * be called to ensure all values are set to 0 initially; the * imx_vpu_enc_set_default_open_params() function does not do this!). * Then, set a bitrate of 0 kbps, which tells the VPU to use constant quality * mode instead (controlled by the quant_param field in ImxVpuEncParams). * Frame width & height are also necessary, as are the frame rate numerator * and denominator. */ memset(&open_params, 0, sizeof(open_params)); imx_vpu_enc_set_default_open_params(IMX_VPU_CODEC_FORMAT_H264, &open_params); open_params.bitrate = 0; open_params.frame_width = FRAME_WIDTH; open_params.frame_height = FRAME_HEIGHT; open_params.frame_rate_numerator = FPS_N; open_params.frame_rate_denominator = FPS_D; /* Load the VPU firmware */ imx_vpu_enc_load(); /* Retrieve information about the required bitstream buffer and allocate one based on this */ imx_vpu_enc_get_bitstream_buffer_info(&(ctx->bitstream_buffer_size), &(ctx->bitstream_buffer_alignment)); ctx->bitstream_buffer = imx_vpu_dma_buffer_allocate( imx_vpu_enc_get_default_allocator(), ctx->bitstream_buffer_size, ctx->bitstream_buffer_alignment, 0 ); /* Open an encoder instance, using the previously allocated bitstream buffer */ imx_vpu_enc_open(&(ctx->vpuenc), &open_params, ctx->bitstream_buffer); /* Retrieve the initial information to allocate framebuffers for the * encoding process (unlike with decoding, these framebuffers are used * only internally by the encoder as temporary storage; encoded data * doesn't go in there, nor do raw input frames) */ imx_vpu_enc_get_initial_info(ctx->vpuenc, &(ctx->initial_info)); ctx->num_framebuffers = ctx->initial_info.min_num_required_framebuffers; fprintf(stderr, "num framebuffers: %u\n", ctx->num_framebuffers); /* Using the initial information, calculate appropriate framebuffer sizes */ imx_vpu_calc_framebuffer_sizes(COLOR_FORMAT, FRAME_WIDTH, FRAME_HEIGHT, ctx->initial_info.framebuffer_alignment, 0, 0, &(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 ); /* Allocate memory blocks for the framebuffer and DMA buffer structures, * and allocate the DMA buffers themselves */ 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); } /* allocate DMA buffers for the raw input frames. Since the encoder can only read * raw input pixels from a DMA memory region, it is necessary to allocate one, * and later copy the pixels into it. In production, it is generally a better * idea to make sure that the raw input frames are already placed in DMA memory * (either allocated by imx_vpu_dma_buffer_allocate() or by some other means of * getting DMA / physically contiguous memory with known physical addresses). */ ctx->input_fb_dmabuffer = 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->input_framebuffer), &(ctx->calculated_sizes), ctx->input_fb_dmabuffer, 0); /* Actual registration is done here. From this moment on, the VPU knows which buffers to use for * storing temporary frames into. This call must not be done again until encoding is shut down. */ imx_vpu_enc_register_framebuffers(ctx->vpuenc, ctx->framebuffers, ctx->num_framebuffers); return ctx; }
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; }
Context* init(FILE *input_file, FILE *output_file) { Context *ctx; ImxVpuEncOpenParams open_params; unsigned int i; ctx = calloc(1, sizeof(Context)); ctx->fin = input_file; ctx->fout = output_file; imx_vpu_enc_set_default_open_params(IMX_VPU_CODEC_FORMAT_H264, &open_params); open_params.frame_width = FRAME_WIDTH; open_params.frame_height = FRAME_HEIGHT; open_params.framerate = FPS; imx_vpu_enc_load(); imx_vpu_enc_get_bitstream_buffer_info(&(ctx->bitstream_buffer_size), &(ctx->bitstream_buffer_alignment)); ctx->bitstream_buffer = imx_vpu_dma_buffer_allocate(imx_vpu_enc_get_default_allocator(), ctx->bitstream_buffer_size, ctx->bitstream_buffer_alignment, 0); imx_vpu_enc_open(&(ctx->vpuenc), &open_params, ctx->bitstream_buffer); imx_vpu_enc_get_initial_info(ctx->vpuenc, &(ctx->initial_info)); ctx->num_framebuffers = ctx->initial_info.min_num_required_framebuffers; fprintf(stderr, "num framebuffers: %u\n", ctx->num_framebuffers); imx_vpu_calc_framebuffer_sizes(COLOR_FORMAT, FRAME_WIDTH, FRAME_HEIGHT, ctx->initial_info.framebuffer_alignment, 0, &(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); } /* allocate DMA buffers for the input and output buffers. Use total_size as size for both; * the output buffer will most likely contain data later that is much smaller than the input, * but just to be on the safe side, make sure that even an uncompressed frame could fit */ ctx->input_fb_dmabuffer = 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->input_framebuffer), &(ctx->calculated_sizes), ctx->input_fb_dmabuffer, 0); ctx->output_dmabuffer = imx_vpu_dma_buffer_allocate(imx_vpu_dec_get_default_allocator(), ctx->calculated_sizes.total_size, ctx->initial_info.framebuffer_alignment, 0); /* Actual registration is done here. From this moment on, the VPU knows which buffers to use for * storing temporary pictures into. This call must not be done again until encoding is shut down. */ imx_vpu_enc_register_framebuffers(ctx->vpuenc, ctx->framebuffers, ctx->num_framebuffers); return ctx; }
static int initial_info_callback(ImxVpuDecoder *decoder, ImxVpuDecInitialInfo *new_initial_info, unsigned int output_code, void *user_data) { unsigned int i; ImxVpuDecReturnCodes ret; ImxVpuJPEGDecoder *jpeg_decoder = (ImxVpuJPEGDecoder *)user_data; IMXVPUAPI_UNUSED_PARAM(decoder); IMXVPUAPI_UNUSED_PARAM(output_code); imx_vpu_jpeg_dec_deallocate_framebuffers(jpeg_decoder); jpeg_decoder->initial_info = *new_initial_info; IMX_VPU_DEBUG( "initial info: size: %ux%u pixel rate: %u/%u min num required framebuffers: %u interlacing: %d framebuffer alignment: %u color format: %s", new_initial_info->frame_width, new_initial_info->frame_height, new_initial_info->frame_rate_numerator, new_initial_info->frame_rate_denominator, new_initial_info->min_num_required_framebuffers, new_initial_info->interlacing, new_initial_info->framebuffer_alignment, imx_vpu_color_format_string(new_initial_info->color_format) ); jpeg_decoder->num_framebuffers = new_initial_info->min_num_required_framebuffers + jpeg_decoder->num_extra_framebuffers; imx_vpu_calc_framebuffer_sizes(new_initial_info->color_format, new_initial_info->frame_width, new_initial_info->frame_height, new_initial_info->framebuffer_alignment, new_initial_info->interlacing, 0, &(jpeg_decoder->calculated_sizes)); IMX_VPU_DEBUG( "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", jpeg_decoder->calculated_sizes.aligned_frame_width, jpeg_decoder->calculated_sizes.aligned_frame_height, jpeg_decoder->calculated_sizes.y_stride, jpeg_decoder->calculated_sizes.cbcr_stride, jpeg_decoder->calculated_sizes.y_size, jpeg_decoder->calculated_sizes.cbcr_size, jpeg_decoder->calculated_sizes.mvcol_size, jpeg_decoder->calculated_sizes.total_size ); jpeg_decoder->framebuffers = IMX_VPU_ALLOC(sizeof(ImxVpuFramebuffer) * jpeg_decoder->num_framebuffers); jpeg_decoder->fb_dmabuffers = IMX_VPU_ALLOC(sizeof(ImxVpuDMABuffer *) * jpeg_decoder->num_framebuffers); memset(jpeg_decoder->framebuffers, 0, sizeof(ImxVpuFramebuffer) * jpeg_decoder->num_framebuffers); memset(jpeg_decoder->fb_dmabuffers, 0, sizeof(ImxVpuDMABuffer *) * jpeg_decoder->num_framebuffers); for (i = 0; i < jpeg_decoder->num_framebuffers; ++i) { jpeg_decoder->fb_dmabuffers[i] = imx_vpu_dma_buffer_allocate(jpeg_decoder->dma_buffer_allocator, jpeg_decoder->calculated_sizes.total_size, jpeg_decoder->initial_info.framebuffer_alignment, 0); if (jpeg_decoder->fb_dmabuffers[i] == NULL) { IMX_VPU_ERROR("could not allocate DMA buffer for framebuffer #%u", i); goto error; } imx_vpu_fill_framebuffer_params(&(jpeg_decoder->framebuffers[i]), &(jpeg_decoder->calculated_sizes), jpeg_decoder->fb_dmabuffers[i], 0); } if ((ret = imx_vpu_dec_register_framebuffers(jpeg_decoder->decoder, jpeg_decoder->framebuffers, jpeg_decoder->num_framebuffers)) != IMX_VPU_DEC_RETURN_CODE_OK) { IMX_VPU_ERROR("could not register framebuffers: %s", imx_vpu_dec_error_string(ret)); goto error; } return 1; error: imx_vpu_jpeg_deallocate_dma_buffers(jpeg_decoder->fb_dmabuffers, jpeg_decoder->num_framebuffers); return 0; }