ImxVpuDecReturnCodes imx_vpu_dec_close(ImxVpuDecoder *decoder)
{
	VpuDecRetCode ret;

	IMX_VPU_TRACE("closing decoder");

	ret = VPU_DecFlushAll(decoder->handle);
	if (ret == VPU_DEC_RET_FAILURE_TIMEOUT)
	{
		IMX_VPU_WARNING("resetting decoder after a timeout occurred");
		ret = VPU_DecReset(decoder->handle);
		if (ret != VPU_DEC_RET_SUCCESS)
			IMX_VPU_ERROR("resetting decoder failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
	}
	else if (ret != VPU_DEC_RET_SUCCESS)
		IMX_VPU_ERROR("flushing decoder failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));

	ret = VPU_DecClose(decoder->handle);
	if (ret != VPU_DEC_RET_SUCCESS)
		IMX_VPU_ERROR("closing decoder failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));

	if (decoder->user_data_for_frames != NULL)
		IMX_VPU_FREE(decoder->user_data_for_frames, sizeof(void*) * decoder->num_framebuffers);
	if (decoder->wrapper_framebuffers != NULL)
		IMX_VPU_FREE(decoder->wrapper_framebuffers, sizeof(VpuFrameBuffer*) * decoder->num_framebuffers);
	if (decoder->virt_mem_sub_block != NULL)
		IMX_VPU_FREE(decoder->virt_mem_sub_block, decoder->virt_mem_sub_block_size);
	IMX_VPU_FREE(decoder, sizeof(ImxVpuDecoder));

	IMX_VPU_TRACE("closed decoder");

	return dec_convert_retcode(ret);
}
ImxVpuDecReturnCodes imx_vpu_dec_flush(ImxVpuDecoder *decoder)
{
	VpuDecRetCode ret = VPU_DEC_RET_SUCCESS;

	decoder->delay_pending_user_data = FALSE;

	if (decoder->flush_vpu_upon_reset)
	{
		ret = VPU_DecFlushAll(decoder->handle);
		if (ret == VPU_DEC_RET_FAILURE_TIMEOUT)
		{
			IMX_VPU_WARNING("resetting decoder after a timeout occurred");
			ret = VPU_DecReset(decoder->handle);
			if (ret != VPU_DEC_RET_SUCCESS)
				IMX_VPU_ERROR("resetting decoder failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		}
		else if (ret != VPU_DEC_RET_SUCCESS)
			IMX_VPU_ERROR("flushing decoder failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		else
			IMX_VPU_INFO("flushed decoder");

		decoder->recalculate_num_avail_framebuffers = TRUE;
	}
	else
		IMX_VPU_INFO("decoder not flushed, because it is unnecessary for this codec format");

	if (decoder->user_data_for_frames != NULL)
		memset(decoder->user_data_for_frames, 0, sizeof(void*) * decoder->num_framebuffers);
	decoder->num_user_data = 0;

	return dec_convert_retcode(ret);
}
ImxVpuDecReturnCodes imx_vpu_dec_mark_framebuffer_as_displayed(ImxVpuDecoder *decoder, ImxVpuFramebuffer const *framebuffer)
{
	VpuDecRetCode ret;
	VpuFrameBuffer *wrapper_fb = (VpuFrameBuffer *)(framebuffer->internal);

	ret = VPU_DecOutFrameDisplayed(decoder->handle, wrapper_fb);
	if (ret != VPU_DEC_RET_SUCCESS)
	{
		ImxVpuDecReturnCodes imxret = dec_convert_retcode(ret);
		IMX_VPU_ERROR("error marking output frame as displayed: %s", imx_vpu_dec_error_string(imxret));
		return imxret;
	}

	IMX_VPU_LOG("marked framebuffer %p with physical address 0x%x as displayed", (void *)framebuffer, framebuffer->physical_address);

	if (decoder->num_times_counter_decremented > 0)
	{
		decoder->num_available_framebuffers++;
		decoder->num_times_counter_decremented--;
		decoder->num_framebuffers_in_use--;

		IMX_VPU_LOG("num_available_framebuffers %d  num_times_counter_decremented %d  num_framebuffers_in_use %d", decoder->num_available_framebuffers, decoder->num_times_counter_decremented, decoder->num_framebuffers_in_use);
	}

	return IMX_VPU_DEC_RETURN_CODE_OK;
}
ImxVpuDecReturnCodes imx_vpu_dec_get_decoded_frame(ImxVpuDecoder *decoder, ImxVpuDecodedFrame *decoded_frame)
{
	VpuDecRetCode ret;
	VpuDecOutFrameInfo out_frame_info;
	int fb_index;
	void *user_data;

	ret = VPU_DecGetOutputFrame(decoder->handle, &out_frame_info);
	if (ret != VPU_DEC_RET_SUCCESS)
	{
		ImxVpuDecReturnCodes imxret = dec_convert_retcode(ret);
		IMX_VPU_ERROR("error getting decoded output frame: %s", imx_vpu_dec_error_string(imxret));
		return imxret;
	}

	fb_index = dec_get_wrapper_framebuffer_index(decoder, out_frame_info.pDisplayFrameBuf);

	user_data = NULL;
	if (decoder->consumption_info_available)
	{
		if ((fb_index >= 0) && (fb_index < (int)(decoder->num_framebuffers)))
		{
			user_data = decoder->user_data_for_frames[fb_index];
			IMX_VPU_LOG("framebuffer index %d for framebuffer %p and user data %p", fb_index, (void *)(out_frame_info.pDisplayFrameBuf), user_data);
			decoder->user_data_for_frames[fb_index] = NULL;
		}
		else
			IMX_VPU_ERROR("framebuffer index %d for framebuffer %p and user data %p out of bounds", fb_index, (void *)(out_frame_info.pDisplayFrameBuf), user_data);
	}
	else
	{
		if (decoder->num_user_data > 0)
		{
			user_data = decoder->user_data_for_frames[0];
			decoder->user_data_for_frames[0] = NULL;
			IMX_VPU_LOG("framebuffer index %d user data %p retrieved as oldest", fb_index, user_data);
			memmove(decoder->user_data_for_frames, decoder->user_data_for_frames + 1, sizeof(void*) * (decoder->num_user_data - 1));
			decoder->num_user_data--;
		}
	}

	decoded_frame->pic_type = convert_from_wrapper_pic_type(out_frame_info.ePicType);
	decoded_frame->user_data = user_data;

	/* XXX
	 * This association assumes that the order of internal framebuffer entries
	 * inside the VPU wrapper is the same as the order of the framebuffers here.
	 * So, decoder->framebuffers[1] equals internal framebuffer entry with index 1 etc.
	 */
	decoded_frame->framebuffer = &(decoder->framebuffers[fb_index]);
	/* This is used in imx_vpu_dec_mark_framebuffer_as_displayed() to be able
	 * to mark the vpuwrapper framebuffer as displayed */
	decoded_frame->framebuffer->internal = out_frame_info.pDisplayFrameBuf;

	decoder->num_framebuffers_in_use++;

	return IMX_VPU_DEC_RETURN_CODE_OK;
}
ImxVpuDecReturnCodes imx_vpu_dec_register_framebuffers(ImxVpuDecoder *decoder, ImxVpuFramebuffer *framebuffers, unsigned int num_framebuffers)
{
	unsigned int i;
	VpuDecRetCode ret;
	VpuFrameBuffer *temp_fbs;

	IMX_VPU_TRACE("attempting to register %u framebuffers", num_framebuffers);

	decoder->wrapper_framebuffers = NULL;

	temp_fbs = IMX_VPU_ALLOC(sizeof(VpuFrameBuffer) * num_framebuffers);
	if (temp_fbs == NULL)
	{
		IMX_VPU_ERROR("allocating memory for framebuffers failed");
		return IMX_VPU_DEC_RETURN_CODE_ERROR;
	}

	for (i = 0; i < num_framebuffers; ++i)
		convert_to_wrapper_framebuffer(&framebuffers[i], &(temp_fbs[i]));

	ret = VPU_DecRegisterFrameBuffer(decoder->handle, temp_fbs, num_framebuffers);

	IMX_VPU_FREE(temp_fbs, sizeof(VpuFrameBuffer) * num_framebuffers);

	if (ret != VPU_DEC_RET_SUCCESS)
	{
		ImxVpuDecReturnCodes imxret = dec_convert_retcode(ret);
		IMX_VPU_ERROR("registering framebuffers failed: %s", imx_vpu_dec_error_string(imxret));
		return ret;
	}

	decoder->wrapper_framebuffers = IMX_VPU_ALLOC(sizeof(VpuFrameBuffer*) * num_framebuffers);
	{
		int out_num;
		VPU_DecAllRegFrameInfo(decoder->handle, decoder->wrapper_framebuffers, &out_num);
		IMX_VPU_LOG("out_num: %d  num_framebuffers: %u", out_num, num_framebuffers);
	}

	decoder->framebuffers = framebuffers;
	decoder->num_framebuffers = num_framebuffers;
	decoder->num_available_framebuffers = num_framebuffers;

	decoder->user_data_for_frames = IMX_VPU_ALLOC(sizeof(void*) * num_framebuffers);
	if (decoder->user_data_for_frames == NULL)
	{
		IMX_VPU_ERROR("allocating memory for user data failed");
		IMX_VPU_FREE(decoder->wrapper_framebuffers, sizeof(VpuFrameBuffer*) * num_framebuffers);
		decoder->wrapper_framebuffers = NULL;
		return IMX_VPU_DEC_RETURN_CODE_ERROR;
	}

	memset(decoder->user_data_for_frames, 0, sizeof(void*) * num_framebuffers);
	decoder->num_user_data = 0;

	return IMX_VPU_DEC_RETURN_CODE_OK;
}
ImxVpuDecReturnCodes imx_vpu_dec_set_drain_mode(ImxVpuDecoder *decoder, int enabled)
{
	int config_param;
	VpuDecRetCode ret;

	config_param = enabled ? VPU_DEC_IN_DRAIN : VPU_DEC_IN_NORMAL;
	ret = VPU_DecConfig(decoder->handle, VPU_DEC_CONF_INPUTTYPE, &config_param);

	if (ret != VPU_DEC_RET_SUCCESS)
		IMX_VPU_ERROR("setting decoder drain mode failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
	else
		IMX_VPU_INFO("set decoder drain mode to %d", enabled);

	return dec_convert_retcode(ret);
}
ImxVpuDecReturnCodes imx_vpu_dec_unload(void)
{
	IMX_VPU_TRACE("VPU load instance counter: %lu", vpu_load_inst_counter);
	if (vpu_load_inst_counter == 0)
		return IMX_VPU_DEC_RETURN_CODE_OK;

	ImxVpuDecReturnCodes ret = dec_convert_retcode(VPU_DecUnLoad());
	if (ret != IMX_VPU_DEC_RETURN_CODE_OK)
		IMX_VPU_ERROR("unloading decoder failed: %s", imx_vpu_dec_error_string(ret));
	else
	{
		IMX_VPU_TRACE("unloaded decoder");
		--vpu_load_inst_counter;
	}

	return ret;
}
ImxVpuDecReturnCodes imx_vpu_dec_decode_frame(ImxVpuDecoder *decoder, ImxVpuEncodedFrame const *encoded_frame, unsigned int *output_code)
{
	VpuDecRetCode ret;
	VpuBufferNode node;
	int buf_ret_code;

	node.pVirAddr = encoded_frame->virtual_address;
	node.pPhyAddr = 0; /* encoded data is always read from a regular memory block, not a DMA buffer */
	node.nSize = encoded_frame->data_size;

	node.sCodecData.pData = encoded_frame->codec_data;
	node.sCodecData.nSize = encoded_frame->codec_data_size;

	decoder->pending_user_data = encoded_frame->user_data;

	ret = VPU_DecDecodeBuf(decoder->handle, &node, &buf_ret_code);
	IMX_VPU_LOG("VPU_DecDecodeBuf buf ret code: 0x%x", buf_ret_code);

	*output_code = dec_convert_outcode(buf_ret_code);

	if (ret != VPU_DEC_RET_SUCCESS)
	{
		IMX_VPU_ERROR("decoding frame failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		return dec_convert_retcode(ret);
	}

	if (decoder->recalculate_num_avail_framebuffers)
	{
		decoder->num_available_framebuffers = decoder->num_framebuffers - decoder->num_framebuffers_in_use;
		IMX_VPU_LOG("recalculated number of available framebuffers to %d", decoder->num_available_framebuffers);
		decoder->recalculate_num_avail_framebuffers = FALSE;
	}

	if (buf_ret_code & VPU_DEC_INIT_OK)
	{
		decoder->delay_pending_user_data = TRUE;
		decoder->last_pending_user_data = decoder->pending_user_data;
	}

	if (buf_ret_code & VPU_DEC_FLUSH)
	{
		IMX_VPU_INFO("VPU requested a decoder flush");
		ret = VPU_DecFlushAll(decoder->handle);
		if (ret == VPU_DEC_RET_FAILURE_TIMEOUT)
		{
			IMX_VPU_WARNING("timeout detected, resetting decoder");

			ret = VPU_DecReset(decoder->handle);
			if (ret != VPU_DEC_RET_SUCCESS)
			{
				ImxVpuDecReturnCodes imxret = dec_convert_retcode(ret);
				IMX_VPU_ERROR("resetting decoder failed: %s", imx_vpu_dec_error_string(imxret));
				return imxret;
			}
			else
				*output_code |= IMX_VPU_DEC_OUTPUT_CODE_INTERNAL_RESET;
		}
		else if (ret != VPU_DEC_RET_SUCCESS)
		{
			ImxVpuDecReturnCodes imxret = dec_convert_retcode(ret);
			IMX_VPU_ERROR("flushing decoder failed: %s", imx_vpu_dec_error_string(imxret));
			return imxret;
		}
		else
			IMX_VPU_INFO("flushed decoder");
	}

	if (buf_ret_code & VPU_DEC_RESOLUTION_CHANGED)
	{
		IMX_VPU_INFO("resolution changed - resetting internal states");

		*output_code |= IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE;

		decoder->delay_pending_user_data = TRUE;
		decoder->recalculate_num_avail_framebuffers = FALSE;

		decoder->num_user_data = 0;

		if (decoder->user_data_for_frames != NULL)
			IMX_VPU_FREE(decoder->user_data_for_frames, sizeof(void*) * decoder->num_framebuffers);
		if (decoder->wrapper_framebuffers != NULL)
			IMX_VPU_FREE(decoder->wrapper_framebuffers, sizeof(VpuFrameBuffer*) * decoder->num_framebuffers);

		decoder->user_data_for_frames = NULL;
		decoder->wrapper_framebuffers = NULL;
	}

	if (buf_ret_code & VPU_DEC_NO_ENOUGH_INBUF)
	{
		/* Not dropping frame here on purpose; the next input frame may
		 * complete the input */
	}

	{
		void *user_data = decoder->delay_pending_user_data ? decoder->last_pending_user_data : decoder->pending_user_data;

		/* The first time this location is reached, VPU_DEC_INIT_OK will be set in the output_code.
		 * This implies that the framebuffers have not been allocated and registered yet,
		 * so no user data can be stored yet.
		 * With codec formats that produce consumption info, this is not a problem, because
		 * VPU_DEC_ONE_FRM_CONSUMED will be returned only when framebuffers are present.
		 * But with other formats, an explicit decoder->framebuffers != NULL check is necessary
		 * (see below). The user_data pointer does not get lost; it is stored in last_pending_user_data. */
		if ((buf_ret_code & VPU_DEC_ONE_FRM_CONSUMED) && !(buf_ret_code & VPU_DEC_OUTPUT_DROPPED))
		{
			int fb_index;

			VpuDecFrameLengthInfo consumed_frame_info;
			ret = VPU_DecGetConsumedFrameInfo(decoder->handle, &consumed_frame_info);
			if (ret != VPU_DEC_RET_SUCCESS)
			{
				ImxVpuDecReturnCodes imxret = dec_convert_retcode(ret);
				IMX_VPU_ERROR("getting consumed frame info failed: %s", imx_vpu_dec_error_string(imxret));
				return imxret;
			}

			fb_index = dec_get_wrapper_framebuffer_index(decoder, consumed_frame_info.pFrame);

			if (consumed_frame_info.pFrame != NULL)
			{
				if ((fb_index >= 0) && (fb_index < (int)(decoder->num_framebuffers)))
				{
					IMX_VPU_LOG("framebuffer index %d for framebuffer %p user data %p", fb_index, (void *)(consumed_frame_info.pFrame), user_data);
					decoder->user_data_for_frames[fb_index] = user_data;
				}
				else
					IMX_VPU_ERROR("framebuffer index %d for framebuffer %p user data %p out of bounds", fb_index, (void *)(consumed_frame_info.pFrame), user_data);
			}
			else
				IMX_VPU_WARNING("consumed frame info contains a NULL frame");
		}
		else if (!(decoder->consumption_info_available) && (decoder->framebuffers != NULL))
		{
			if (decoder->num_user_data < (int)(decoder->num_framebuffers))
			{
				decoder->user_data_for_frames[decoder->num_user_data] = user_data;
				decoder->num_user_data++;

				IMX_VPU_LOG("user data %p stored as newest", user_data);

				IMX_VPU_TRACE("incremented number of userdata pointers to %d", decoder->num_user_data);
			}
			else
				IMX_VPU_WARNING("too many user data pointers in memory - cannot store current one");
		}

		decoder->last_pending_user_data = decoder->pending_user_data;
		decoder->pending_user_data = NULL;
	}

	if ((buf_ret_code & VPU_DEC_ONE_FRM_CONSUMED) && !(buf_ret_code & VPU_DEC_OUTPUT_DROPPED))
	{
		decoder->num_available_framebuffers--;
		decoder->num_times_counter_decremented++;
		IMX_VPU_LOG("decremented number of available framebuffers to %d (with consumed frame info); number of times decremented is now %d", decoder->num_available_framebuffers, decoder->num_times_counter_decremented);
	}

	if (buf_ret_code & VPU_DEC_OUTPUT_NODIS)
	{
		if ((encoded_frame->virtual_address != NULL) && (decoder->codec_format == IMX_VPU_CODEC_FORMAT_VP8))
			*output_code |= IMX_VPU_DEC_OUTPUT_CODE_DECODE_ONLY;
	}

	/* VPU_DEC_NO_ENOUGH_BUF handled by caller - should be treated as an error */

	if ((buf_ret_code & VPU_DEC_OUTPUT_DIS) && !(decoder->consumption_info_available))
	{
		decoder->num_available_framebuffers--;
		decoder->num_times_counter_decremented++;
		IMX_VPU_LOG("decremented number of available framebuffers to %d (no consumed frame info); number of times decremented is now %d", decoder->num_available_framebuffers, decoder->num_times_counter_decremented);
	}
	else if (buf_ret_code & VPU_DEC_OUTPUT_MOSAIC_DIS)
	{
		IMX_VPU_TRACE("dropping mosaic frame");

		/* mosaic frames do not seem to be useful for anything, so they are just dropped here */

		ImxVpuDecReturnCodes imxret;
		ImxVpuDecodedFrame decoded_frame;

		if ((imxret = imx_vpu_dec_get_decoded_frame(decoder, &decoded_frame)) != IMX_VPU_DEC_RETURN_CODE_OK)
		{
			IMX_VPU_ERROR("error getting output mosaic frame: %s", imx_vpu_dec_error_string(imxret));
			return imxret;
		}

		if ((imxret = imx_vpu_dec_mark_framebuffer_as_displayed(decoder, decoded_frame.framebuffer)) != IMX_VPU_DEC_RETURN_CODE_OK)
		{
			IMX_VPU_ERROR("error marking mosaic frame as displayed: %s", imx_vpu_dec_error_string(imxret));
			return imxret;
		}

		decoder->dropped_frame_user_data = decoded_frame.user_data;

		*output_code |= IMX_VPU_DEC_OUTPUT_CODE_DROPPED;
	}
	else if (buf_ret_code & VPU_DEC_OUTPUT_DROPPED)
	{
		// TODO make this work for formats with consumption info
		if (decoder->num_user_data > 0)
		{
			decoder->dropped_frame_user_data = decoder->user_data_for_frames[0];
			decoder->user_data_for_frames[0] = NULL;
			memmove(decoder->user_data_for_frames, decoder->user_data_for_frames + 1, sizeof(void*) * (decoder->num_user_data - 1));
			decoder->num_user_data--;
		}
		else
			decoder->dropped_frame_user_data = NULL;
	}

	/* In case the VPU didn't use the input and no consumed frame info is available,
	 * drop the input frame to make sure timestamps are okay
	 * (If consumed frame info is present it is still possible it might be used for input-output frame
	 * associations; unlikely to occur thought) */
	if ((encoded_frame->virtual_address != NULL) && !(buf_ret_code & (VPU_DEC_ONE_FRM_CONSUMED | VPU_DEC_INPUT_USED | VPU_DEC_RESOLUTION_CHANGED)))
	{
		decoder->dropped_frame_user_data = encoded_frame->user_data;
		*output_code |= IMX_VPU_DEC_OUTPUT_CODE_DROPPED;
	}

	return IMX_VPU_DEC_RETURN_CODE_OK;
}
ImxVpuDecReturnCodes imx_vpu_dec_open(ImxVpuDecoder **decoder, ImxVpuDecOpenParams const *open_params, void *bitstream_buffer_virtual_address, imx_vpu_phys_addr_t bitstream_buffer_physical_addres)
{
	int config_param;
	VpuDecRetCode ret;
	VpuMemInfo mem_info;
	VpuDecOpenParam open_param;

	*decoder = IMX_VPU_ALLOC(sizeof(ImxVpuDecoder));
	if ((*decoder) == NULL)
	{
		IMX_VPU_ERROR("allocating memory for decoder object failed");
		return IMX_VPU_DEC_RETURN_CODE_ERROR;
	}

	memset(*decoder, 0, sizeof(ImxVpuDecoder));

	{
		int i;

		VPU_DecQueryMem(&mem_info);

		IMX_VPU_INFO("about to allocate %d memory sub blocks", mem_info.nSubBlockNum);
		for (i = 0; i < mem_info.nSubBlockNum; ++i)
		{
			char const *type_str = "<unknown>";
			VpuMemSubBlockInfo *sub_block = &(mem_info.MemSubBlock[i]);

			switch (sub_block->MemType)
			{
				case VPU_MEM_VIRT:
					type_str = "virtual";

					(*decoder)->virt_mem_sub_block_size = sub_block->nSize + sub_block->nAlignment;
					(*decoder)->virt_mem_sub_block = IMX_VPU_ALLOC((*decoder)->virt_mem_sub_block_size);
					if ((*decoder)->virt_mem_sub_block == NULL)
					{
						IMX_VPU_ERROR("allocating memory for sub block failed");
						return IMX_VPU_DEC_RETURN_CODE_ERROR;
					}

					sub_block->pVirtAddr = (unsigned char *)IMX_VPU_ALIGN_VAL_TO((*decoder)->virt_mem_sub_block, sub_block->nAlignment);
					sub_block->pPhyAddr = 0;
					break;

				case VPU_MEM_PHY:
					type_str = "physical";

					sub_block->pVirtAddr = (unsigned char *)(bitstream_buffer_virtual_address);
					sub_block->pPhyAddr = (unsigned char *)(bitstream_buffer_physical_addres);
					break;
				default:
					break;
			}

			IMX_VPU_INFO("allocated memory sub block #%d:  type: %s  size: %d  alignment: %d  virtual address: %p  physical address: %p", i, type_str, sub_block->nSize, sub_block->nAlignment, sub_block->pVirtAddr, sub_block->pPhyAddr);
		}
	}

	dec_convert_to_wrapper_open_param(open_params, &open_param);

	IMX_VPU_TRACE("opening decoder");

	switch (open_params->codec_format)
	{
		case IMX_VPU_CODEC_FORMAT_H264:
		case IMX_VPU_CODEC_FORMAT_H264_MVC:
		case IMX_VPU_CODEC_FORMAT_MPEG2:
		case IMX_VPU_CODEC_FORMAT_MPEG4:
			(*decoder)->consumption_info_available = TRUE;
			(*decoder)->flush_vpu_upon_reset = TRUE;
			break;
		case IMX_VPU_CODEC_FORMAT_H263:
		case IMX_VPU_CODEC_FORMAT_WMV3:
		case IMX_VPU_CODEC_FORMAT_WVC1:
			(*decoder)->consumption_info_available = FALSE;
			(*decoder)->flush_vpu_upon_reset = FALSE;
			break;
		case IMX_VPU_CODEC_FORMAT_MJPEG:
		case IMX_VPU_CODEC_FORMAT_VP8:
			(*decoder)->consumption_info_available = FALSE;
			(*decoder)->flush_vpu_upon_reset = TRUE;
			break;
		default:
			break;
	}

	ret = VPU_DecOpen(&((*decoder)->handle), &open_param, &mem_info);
	if (ret != VPU_DEC_RET_SUCCESS)
	{
		IMX_VPU_ERROR("opening decoder failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		goto cleanup;
	}

	IMX_VPU_TRACE("setting configuration");

	config_param = VPU_DEC_SKIPNONE;
	ret = VPU_DecConfig((*decoder)->handle, VPU_DEC_CONF_SKIPMODE, &config_param);
	if (ret != VPU_DEC_RET_SUCCESS)
	{
		IMX_VPU_ERROR("setting skipmode to NONE failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		goto cleanup;
	}

	config_param = 0;
	ret = VPU_DecConfig((*decoder)->handle, VPU_DEC_CONF_BUFDELAY, &config_param);
	if (ret != VPU_DEC_RET_SUCCESS)
	{
		IMX_VPU_ERROR("setting bufdelay to 0 failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		goto cleanup;
	}

	config_param = VPU_DEC_IN_NORMAL;
	ret = VPU_DecConfig((*decoder)->handle, VPU_DEC_CONF_INPUTTYPE, &config_param);
	if (ret != VPU_DEC_RET_SUCCESS)
	{
		IMX_VPU_ERROR("setting input type to \"normal\" failed: %s", imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		goto cleanup;
	}

	(*decoder)->codec_format = open_params->codec_format;

finish:
	if (ret == VPU_DEC_RET_SUCCESS)
		IMX_VPU_TRACE("successfully opened decoder");

	return dec_convert_retcode(ret);

cleanup:
	if ((*decoder)->virt_mem_sub_block != NULL)
		IMX_VPU_FREE((*decoder)->virt_mem_sub_block, (*decoder)->virt_mem_sub_block_size);
	IMX_VPU_FREE(*decoder, sizeof(ImxVpuDecoder));
	*decoder = NULL;

	goto finish;
}
ImxVpuDecReturnCodes imx_vpu_dec_deallocate_memory(ImxVpuMemBlock *mem_block)
{
	ImxVpuDecReturnCodes ret;
	VpuMemDesc mem_desc;

	convert_to_wrapper_mem_desc(mem_block, &mem_desc);

	ret = dec_convert_retcode(VPU_DecFreeMem(&mem_desc));
	if (ret != IMX_VPU_DEC_RETURN_CODE_OK)
		IMX_VPU_ERROR("deallocating %d bytes of physical memory failed: %s", mem_block->size, imx_vpu_dec_error_string(ret));
	else
		IMX_VPU_TRACE("deallocated %d bytes of physical memory", mem_block->size);

	return ret;
}
ImxVpuDecReturnCodes imx_vpu_dec_allocate_memory(ImxVpuMemBlock *mem_block)
{
	VpuDecRetCode ret;
	VpuMemDesc mem_desc;

	if (mem_block->alignment == 0)
		mem_block->alignment = 1;

	mem_desc.nSize = mem_block->size + mem_block->alignment;

	if ((ret = VPU_DecGetMem(&mem_desc)) != VPU_DEC_RET_SUCCESS)
	{
		IMX_VPU_ERROR("allocating %d bytes of physical memory failed: %s", mem_block->size, imx_vpu_dec_error_string(dec_convert_retcode(ret)));
		return dec_convert_retcode(ret);
	}
	else
		IMX_VPU_TRACE("allocated %d bytes of physical memory", mem_block->size);

	convert_from_wrapper_mem_desc(&mem_desc, mem_block);

	mem_block->virtual_address = (void *)IMX_VPU_ALIGN_VAL_TO(mem_block->virtual_address_unaligned, mem_block->alignment);
	mem_block->physical_address = (imx_vpu_phys_addr_t)IMX_VPU_ALIGN_VAL_TO(mem_block->physical_address_unaligned, mem_block->alignment);

	return IMX_VPU_DEC_RETURN_CODE_OK;
}
Example #12
0
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;
}