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; }
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 gboolean gst_imx_vpu_encoder_base_set_format(GstVideoEncoder *encoder, GstVideoCodecState *state) { GstVideoCodecState *output_state; GstImxVpuEncoderBaseClass *klass; GstImxVpuEncoderBase *vpu_encoder_base; ImxVpuEncReturnCodes enc_ret; vpu_encoder_base = GST_IMX_VPU_ENCODER_BASE(encoder); klass = GST_IMX_VPU_ENCODER_BASE_CLASS(G_OBJECT_GET_CLASS(vpu_encoder_base)); g_assert(klass->get_output_caps != NULL); GST_INFO_OBJECT(encoder, "setting encoder format"); /* Cleanup any existing old encoder */ gst_imx_vpu_encoder_base_close(vpu_encoder_base); /* Set up the open params */ memset(&(vpu_encoder_base->open_params), 0, sizeof(ImxVpuEncOpenParams)); imx_vpu_enc_set_default_open_params(klass->codec_format, &(vpu_encoder_base->open_params)); /* Fill the open params. (Derived classes can set different values.) */ /* All encoders except MJPEG support only grayscale and 4:2:0 color formats */ vpu_encoder_base->open_params.color_format = (GST_VIDEO_INFO_FORMAT(&(state->info)) == GST_VIDEO_FORMAT_GRAY8) ? IMX_VPU_COLOR_FORMAT_YUV400 : IMX_VPU_COLOR_FORMAT_YUV420; vpu_encoder_base->open_params.frame_width = GST_VIDEO_INFO_WIDTH(&(state->info)); vpu_encoder_base->open_params.frame_height = GST_VIDEO_INFO_HEIGHT(&(state->info)); vpu_encoder_base->open_params.frame_rate_numerator = GST_VIDEO_INFO_FPS_N(&(state->info)); vpu_encoder_base->open_params.frame_rate_denominator = GST_VIDEO_INFO_FPS_D(&(state->info)); vpu_encoder_base->open_params.bitrate = vpu_encoder_base->bitrate; vpu_encoder_base->open_params.gop_size = vpu_encoder_base->gop_size; /* If the input format has one plane with interleaved chroma data * (= the input format is NV12/NV16/NV24), set chroma_interleave * to 1, otherwise set it to 0 */ switch (GST_VIDEO_INFO_FORMAT(&(state->info))) { case GST_VIDEO_FORMAT_NV12: case GST_VIDEO_FORMAT_NV16: case GST_VIDEO_FORMAT_NV24: GST_DEBUG_OBJECT(vpu_encoder_base, "input format uses shared chroma plane; enabling chroma interleave"); vpu_encoder_base->open_params.chroma_interleave = 1; break; default: GST_DEBUG_OBJECT(vpu_encoder_base, "input format uses separate chroma planes; disabling chroma interleave"); vpu_encoder_base->open_params.chroma_interleave = 0; } GST_INFO_OBJECT(vpu_encoder_base, "setting bitrate to %u kbps and GOP size to %u", vpu_encoder_base->open_params.bitrate, vpu_encoder_base->open_params.gop_size); if (vpu_encoder_base->slice_size != 0) { vpu_encoder_base->open_params.slice_mode.multiple_slices_per_frame = 1; if (vpu_encoder_base->slice_size < 0) { vpu_encoder_base->open_params.slice_mode.slice_size_unit = IMX_VPU_ENC_SLICE_SIZE_UNIT_MACROBLOCKS; vpu_encoder_base->open_params.slice_mode.slice_size = -vpu_encoder_base->slice_size; } else { vpu_encoder_base->open_params.slice_mode.slice_size_unit = IMX_VPU_ENC_SLICE_SIZE_UNIT_BITS; vpu_encoder_base->open_params.slice_mode.slice_size = vpu_encoder_base->slice_size; } } vpu_encoder_base->open_params.min_intra_refresh_mb_count = vpu_encoder_base->intra_refresh; vpu_encoder_base->open_params.me_search_range = vpu_encoder_base->me_search_range; /* Give the derived class a chance to set params */ if (klass->set_open_params && !klass->set_open_params(vpu_encoder_base, state, &(vpu_encoder_base->open_params))) { GST_ERROR_OBJECT(vpu_encoder_base, "derived class could not set open params"); return FALSE; } /* Open and configure encoder */ if ((enc_ret = imx_vpu_enc_open(&(vpu_encoder_base->encoder), &(vpu_encoder_base->open_params), gst_imx_vpu_get_dma_buffer_from(vpu_encoder_base->bitstream_buffer)) != IMX_VPU_ENC_RETURN_CODE_OK)) { GST_ERROR_OBJECT(vpu_encoder_base, "could not open encoder: %s", imx_vpu_enc_error_string(enc_ret)); return FALSE; } GST_TRACE_OBJECT(vpu_encoder_base, "configuring encoder"); if (vpu_encoder_base->bitrate != 0) imx_vpu_enc_configure_bitrate(vpu_encoder_base->encoder, vpu_encoder_base->bitrate); if (vpu_encoder_base->intra_refresh != 0) imx_vpu_enc_configure_min_intra_refresh(vpu_encoder_base->encoder, vpu_encoder_base->intra_refresh); /* Retrieve initial info */ GST_TRACE_OBJECT(vpu_encoder_base, "retrieving initial info"); if ((enc_ret = imx_vpu_enc_get_initial_info(vpu_encoder_base->encoder, &(vpu_encoder_base->initial_info))) != IMX_VPU_ENC_RETURN_CODE_OK) { GST_ERROR_OBJECT(vpu_encoder_base, "could not get initial info: %s", imx_vpu_enc_error_string(enc_ret)); return FALSE; } /* Allocate and register framebuffer array */ GST_TRACE_OBJECT(vpu_encoder_base, "allocating framebuffer array"); vpu_encoder_base->framebuffer_array = gst_imx_vpu_framebuffer_array_new( vpu_encoder_base->open_params.color_format, vpu_encoder_base->open_params.frame_width, vpu_encoder_base->open_params.frame_height, vpu_encoder_base->initial_info.framebuffer_alignment, FALSE, FALSE, vpu_encoder_base->initial_info.min_num_required_framebuffers, (GstImxPhysMemAllocator *)(vpu_encoder_base->phys_mem_allocator) ); if (vpu_encoder_base->framebuffer_array == NULL) { GST_ERROR_OBJECT(vpu_encoder_base, "could not create new framebuffer array"); return FALSE; } GST_TRACE_OBJECT(vpu_encoder_base, "registering framebuffer array"); if ((enc_ret = imx_vpu_enc_register_framebuffers(vpu_encoder_base->encoder, vpu_encoder_base->framebuffer_array->framebuffers, vpu_encoder_base->framebuffer_array->num_framebuffers)) != IMX_VPU_ENC_RETURN_CODE_OK) { GST_ERROR_OBJECT(vpu_encoder_base, "could not register framebuffers: %s", imx_vpu_enc_error_string(enc_ret)); return FALSE; } GST_TRACE_OBJECT(vpu_encoder_base, "allocating output buffer with %u bytes", vpu_encoder_base->framebuffer_array->framebuffer_sizes.total_size); /* Set the output state, using caps defined by the derived class */ output_state = gst_video_encoder_set_output_state( encoder, klass->get_output_caps(vpu_encoder_base), state ); gst_video_codec_state_unref(output_state); vpu_encoder_base->video_info = state->info; GST_TRACE_OBJECT(vpu_encoder_base, "encoder format set"); return TRUE; }