Пример #1
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}