static vod_status_t
mp4_encrypt_write_encrypted(
	mp4_encrypt_state_t* state,
	u_char* cur_pos, 
	uint32_t write_size)
{
	uint32_t cur_write_size;
	size_t alloc_size;
	u_char* write_end;
	u_char* output;
	vod_status_t rc;

	write_end = cur_pos + write_size;
	while (cur_pos < write_end)
	{
		rc = write_buffer_get_bytes(&state->write_buffer, MIN_ALLOC_SIZE, &alloc_size, &output);
		if (rc != VOD_OK)
		{
			return rc;
		}

		cur_write_size = write_end - cur_pos;
		cur_write_size = vod_min(cur_write_size, alloc_size);

		rc = mp4_aes_ctr_process(&state->cipher, output, cur_pos, cur_write_size);
		if (rc != VOD_OK)
		{
			return rc;
		}
		cur_pos += cur_write_size;
		state->write_buffer.cur_pos += cur_write_size;
	}

	return VOD_OK;
}
static vod_status_t
mp4_decrypt_process(
	mp4_decrypt_state_t* state, 
	size_t size)
{
	u_char* dest = state->output_pos;
	u_char* src = state->input_pos;
	vod_status_t rc;
	size_t cur_size;

	while (size > 0)
	{
		if (state->clear_bytes <= 0 && state->encrypted_bytes <= 0)
		{
			// finished a subsample, read the next one
			if (state->subsample_count <= 0)
			{
				vod_log_error(VOD_LOG_ERR, state->request_context->log, 0,
					"mp4_decrypt_process: exhausted subsample bytes");
				return VOD_BAD_DATA;
			}

			if (state->auxiliary_info_pos + sizeof(cenc_sample_auxiliary_data_subsample_t) > state->auxiliary_info_end)
			{
				vod_log_error(VOD_LOG_ERR, state->request_context->log, 0,
					"mp4_decrypt_process: failed to get subsample info from auxiliary info");
				return VOD_BAD_DATA;
			}

			read_be16(state->auxiliary_info_pos, state->clear_bytes);
			read_be32(state->auxiliary_info_pos, state->encrypted_bytes);

			state->subsample_count--;
		}

		if (state->clear_bytes > 0)
		{
			// copy clear bytes
			cur_size = vod_min(state->clear_bytes, size);
			dest = vod_copy(dest, src, cur_size);
			src += cur_size;
			size -= cur_size;
			state->clear_bytes -= cur_size;
		}

		// decrypt encrypted bytes
		cur_size = vod_min(state->encrypted_bytes, size);
		rc = mp4_aes_ctr_process(&state->cipher, dest, src, cur_size);
		if (rc != VOD_OK)
		{
			return rc;
		}

		dest += cur_size;
		src += cur_size;
		size -= cur_size;
		state->encrypted_bytes -= cur_size;
	}

	state->output_pos = dest;
	state->input_pos = src;

	return VOD_OK;
}