Ejemplo n.º 1
0
Retval run(Context *ctx)
{
	ImxVpuPicture input_picture;
	ImxVpuEncodedFrame output_frame;
	ImxVpuEncParams enc_params;
	unsigned int output_code;

	memset(&input_picture, 0, sizeof(input_picture));
	input_picture.framebuffer = &(ctx->input_framebuffer);

	memset(&enc_params, 0, sizeof(enc_params));
	enc_params.frame_width = FRAME_WIDTH;
	enc_params.frame_height = FRAME_HEIGHT;
	enc_params.framerate = FPS;
	enc_params.quant_param = 0;

	memset(&output_frame, 0, sizeof(output_frame));
	output_frame.data.dma_buffer = ctx->output_dmabuffer;

	/* Read input i420 frames and encode them until the end of the input file is reached */
	for (;;)
	{
		uint8_t *mapped_virtual_address;

		/* Read uncompressed pixels into the input DMA buffer */
		mapped_virtual_address = imx_vpu_dma_buffer_map(ctx->input_fb_dmabuffer, IMX_VPU_MAPPING_FLAG_WRITE_ONLY);
		fread(mapped_virtual_address, 1, FRAME_SIZE, ctx->fin);
		imx_vpu_dma_buffer_unmap(ctx->input_fb_dmabuffer);

		/* Stop encoding if EOF was reached */
		if (feof(ctx->fin))
			break;

		/* The actual encoding */
		imx_vpu_enc_encode(ctx->vpuenc, &input_picture, &output_frame, &enc_params, &output_code);

		/* Write out the encoded frame to the output file */
		mapped_virtual_address = imx_vpu_dma_buffer_map(ctx->output_dmabuffer, IMX_VPU_MAPPING_FLAG_READ_ONLY);
		fwrite(mapped_virtual_address, 1, output_frame.data_size, ctx->fout);
		imx_vpu_dma_buffer_unmap(ctx->input_fb_dmabuffer);
	}

	return RETVAL_OK;
}
Ejemplo n.º 2
0
Retval run(Context *ctx)
{
	ImxVpuRawFrame input_frame;
	ImxVpuEncodedFrame output_frame;
	ImxVpuEncParams enc_params;
	unsigned int output_code;

	/* Set up the input frame. The only field that needs to be
	 * set is the input framebuffer. The encoder will read from it.
	 * The rest can remain zero/NULL. */
	memset(&input_frame, 0, sizeof(input_frame));
	input_frame.framebuffer = &(ctx->input_framebuffer);

	/* Set the encoding parameters for this frame. quant_param 0 is
	 * the highest quality in h.264 constant quality encoding mode.
	 * (The range in h.264 is 0-51, where 0 is best quality and worst
	 * compression, and 51 vice versa.) */
	memset(&enc_params, 0, sizeof(enc_params));
	enc_params.quant_param = 0;
	enc_params.acquire_output_buffer = acquire_output_buffer;
	enc_params.finish_output_buffer = finish_output_buffer;
	enc_params.output_buffer_context = NULL;

	/* Set up the output frame. Simply setting all fields to zero/NULL
	 * is enough. The encoder will fill in data. */
	memset(&output_frame, 0, sizeof(output_frame));

	/* Read input i420 frames and encode them until the end of the input file is reached */
	for (;;)
	{
		uint8_t *mapped_virtual_address;
		void *output_block;

		/* Read uncompressed pixels into the input DMA buffer */
		mapped_virtual_address = imx_vpu_dma_buffer_map(ctx->input_fb_dmabuffer, IMX_VPU_MAPPING_FLAG_WRITE);
		fread(mapped_virtual_address, 1, FRAME_SIZE, ctx->fin);
		imx_vpu_dma_buffer_unmap(ctx->input_fb_dmabuffer);

		/* Stop encoding if EOF was reached */
		if (feof(ctx->fin))
			break;

		/* The actual encoding */
		imx_vpu_enc_encode(ctx->vpuenc, &input_frame, &output_frame, &enc_params, &output_code);

		/* Write out the encoded frame to the output file. The encoder
		 * will have called acquire_output_buffer(), which acquires a
		 * buffer by malloc'ing it. The "handle" in this example is
		 * just the pointer to the allocated memory. This means that
		 * here, acquired_handle is the pointer to the encoded frame
		 * data. Write it to file, and then free the previously
		 * allocated block. In production, the acquire function could
		 * retrieve an output memory block from a buffer pool for
		 * example. */
		output_block = output_frame.acquired_handle;
		fwrite(output_block, 1, output_frame.data_size, ctx->fout);
		free(output_block);
	}

	return RETVAL_OK;
}
Ejemplo n.º 3
0
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;
}