Description: Added Freescale i.MX VPU hardware support
 Freescale i.MX VPU hardware video decoding support for Chromium's GPU media stack
 .
 chromium-browser (40.0.2214.111-0udoobuntu0.14.04.1.1069) UNRELEASED; urgency=medium
 .
   * Added IMX Freescale/Vivante patches (https://github.com/Freescale/chromium-imx)
Author: UDOO Team <social@udoo.org>

---

Origin: Freescale, https://github.com/Freescale/chromium-imx 
Reviewed-By: Carlos Rafael Giani <dv@pseudoterminal.org> 
Last-Update: <2015-01-27>

--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imx_gl_viv_direct_texture.cc
@@ -0,0 +1,38 @@
+#include "ui/gl/gl_implementation.h"
+#include "imx_gl_viv_direct_texture.h"
+
+
+bool init_viv_direct_texture(gfx::GLContext &context, GLESVIVDirectTextureProcs &procs)
+{
+	VLOG(1) << "Initializing Vivante direct texture GLES extension";
+
+	gfx::GLImplementation glimpl = gfx::GetGLImplementation();
+	if (glimpl != gfx::kGLImplementationEGLGLES2)
+	{
+		LOG(INFO) << "Cannot initialize direct textures - GL implementation is "
+		          << gfx::GetGLImplementationName(glimpl)
+		          << ", expected " <<
+		          gfx::GetGLImplementationName(gfx::kGLImplementationEGLGLES2);
+		return false;
+	}
+
+	// Newer Vivante drivers call the extension GL_VIV_tex_direct instead of GL_VIV_direct_texture,
+	// even though it is the same extension
+	if (context.HasExtension("GL_VIV_direct_texture"))
+		VLOG(1) << "GL_VIV_direct_texture supported";
+	else if (context.HasExtension("GL_VIV_tex_direct"))
+		VLOG(1) << "GL_VIV_tex_direct supported";
+	else
+	{
+		VLOG(1) << "Neither GL_VIV_direct_texture nor GL_VIV_tex_direct supported";
+		return false;
+	}
+
+	procs.TexDirectVIV           = reinterpret_cast < PFNGLTEXDIRECTVIVPROC >           (gfx::GetGLProcAddress("glTexDirectVIV"));
+	procs.TexDirectVIVMap        = reinterpret_cast < PFNGLTEXDIRECTVIVMAPPROC >        (gfx::GetGLProcAddress("glTexDirectVIVMap"));
+	procs.TexDirectTiledMapVIV   = reinterpret_cast < PFNGLTEXDIRECTTILEDMAPVIVPROC >   (gfx::GetGLProcAddress("glTexDirectTiledMapVIV"));
+	procs.TexDirectInvalidateVIV = reinterpret_cast < PFNGLTEXDIRECTINVALIDATEVIVPROC > (gfx::GetGLProcAddress("glTexDirectInvalidateVIV"));
+
+	return true;
+}
+
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imx_gl_viv_direct_texture.h
@@ -0,0 +1,55 @@
+#ifndef IMX_GL_VIV_DIRECT_TEXTURE_H
+#define IMX_GL_VIV_DIRECT_TEXTURE_H
+
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+
+
+/* GL_VIV_direct_texture */
+#ifndef GL_VIV_direct_texture
+#define GL_VIV_YV12                                             0x8FC0
+#define GL_VIV_NV12                                             0x8FC1
+#define GL_VIV_YUY2                                             0x8FC2
+#define GL_VIV_UYVY                                             0x8FC3
+#define GL_VIV_NV21                                             0x8FC4
+#define GL_VIV_I420                                             0x8FC5
+#endif
+
+
+#ifndef GL_APICALL
+#define GL_APICALL  KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#ifndef GL_APIENTRYP
+#define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+
+/* GL_VIV_direct_texture */
+#ifndef GL_VIV_direct_texture
+#define GL_VIV_direct_texture 1
+
+typedef void (GL_APIENTRYP PFNGLTEXDIRECTVIVPROC)           (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Pixels);
+typedef void (GL_APIENTRYP PFNGLTEXDIRECTVIVMAPPROC)        (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical);
+typedef void (GL_APIENTRYP PFNGLTEXDIRECTTILEDMAPVIVPROC)   (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical);
+typedef void (GL_APIENTRYP PFNGLTEXDIRECTINVALIDATEVIVPROC) (GLenum Target);
+
+#endif
+
+struct GLESVIVDirectTextureProcs
+{
+	PFNGLTEXDIRECTVIVPROC           TexDirectVIV;
+	PFNGLTEXDIRECTVIVMAPPROC        TexDirectVIVMap;
+	PFNGLTEXDIRECTTILEDMAPVIVPROC   TexDirectTiledMapVIV;
+	PFNGLTEXDIRECTINVALIDATEVIVPROC TexDirectInvalidateVIV;
+};
+
+
+bool init_viv_direct_texture(gfx::GLContext &context, GLESVIVDirectTextureProcs &procs);
+
+
+#endif
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpu_video_decode_accelerator.cc
@@ -0,0 +1,721 @@
+#include <iomanip>
+#include "media/base/limits.h"
+#include "base/bind.h"
+#include "base/memory/singleton.h"
+#include "content/common/gpu/media/imxvpu_video_decode_accelerator.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_implementation.h"
+
+
+namespace content
+{
+
+
+namespace
+{
+
+
+class ImxVpuLoadSingleton
+{
+public:
+	static ImxVpuLoadSingleton* GetInstance()
+	{
+		return Singleton < ImxVpuLoadSingleton > ::get();
+	}
+
+	bool Load()
+	{
+		base::AutoLock auto_lock(lock_);
+
+		ImxVpuDecReturnCodes ret;
+
+		if ((ret = imx_vpu_dec_load()) != IMX_VPU_DEC_RETURN_CODE_OK)
+		{
+			LOG(ERROR) << "Could not load VPU: " << imx_vpu_dec_error_string(ret);
+			return false;
+		}
+		else
+			return true;
+	}
+
+	bool Unload()
+	{
+		base::AutoLock auto_lock(lock_);
+
+		ImxVpuDecReturnCodes ret;
+
+		if ((ret = imx_vpu_dec_unload()) != IMX_VPU_DEC_RETURN_CODE_OK)
+		{
+			LOG(ERROR) << "Could not unload VPU: " << imx_vpu_dec_error_string(ret);
+			return false;
+		}
+		else
+			return true;
+	}
+
+private:
+	ImxVpuLoadSingleton()
+	{
+	}
+
+	friend struct DefaultSingletonTraits < ImxVpuLoadSingleton >;
+
+	DISALLOW_COPY_AND_ASSIGN(ImxVpuLoadSingleton);
+
+	base::Lock lock_;
+};
+
+
+} // unnamed namespace end
+
+
+ImxVpuVideoDecodeAccelerator::ImxVpuVideoDecodeAccelerator(base::WeakPtr < gpu::gles2::GLES2Decoder > const gles2_decoder, base::Callback < bool(void) > const &make_context_current)
+	: gles2_decoder_(gles2_decoder)
+	, make_context_current_(make_context_current)
+	, vpu_decoder_(NULL)
+	, initial_info_received_(false)
+	, message_loop_(base::MessageLoop::current())
+{
+	vpu_bitstream_buffer_block_.virtual_address = NULL;
+}
+
+
+ImxVpuVideoDecodeAccelerator::~ImxVpuVideoDecodeAccelerator()
+{
+	DCHECK_EQ(message_loop_, base::MessageLoop::current());
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, Client *client)
+{
+	gfx::GLContext *context;
+
+	DCHECK_EQ(message_loop_, base::MessageLoop::current());
+
+	client_ptr_factory_.reset(new base::WeakPtrFactory < Client > (client));
+	client_ = client_ptr_factory_->GetWeakPtr();
+
+	base::AutoLock auto_lock(lock_);
+
+	LOG(INFO) << "Initializing i.MX VPU decoder";
+
+	if (!make_context_current_.Run())
+	{
+		LOG(ERROR) << "Failed to make this decoder's GL context current.";
+		return false;
+	}
+
+	if ((context = gles2_decoder_->GetGLContext()) == NULL)
+	{
+		LOG(ERROR) << "GLES2 context is NULL";
+		return false;
+	}
+
+	if (!init_viv_direct_texture(*context, direct_texture_procs_))
+	{
+		LOG(ERROR) << "Initializing the direct texture extension failed";
+		return false;
+	}
+
+	if ((profile >= media::H264PROFILE_MIN) && (profile <= media::H264PROFILE_MAX))
+	{
+		codec_format_ = IMX_VPU_CODEC_FORMAT_H264;
+		VLOG(1) << "Setting h.264 as codec format";
+	}
+	else if ((profile >= media::VP8PROFILE_MIN) && (profile <= media::VP8PROFILE_MAX))
+	{
+		codec_format_ = IMX_VPU_CODEC_FORMAT_VP8;
+		VLOG(1) << "Setting VP8 as codec format";
+	}
+	else
+	{
+		VLOG(1) << "Unsupported profile";
+		return false;
+	}
+
+	VLOG(1) << "Loading VPU";
+	if (!(ImxVpuLoadSingleton::GetInstance()->Load()))
+		return false;
+
+	if (!AllocateVpuBitstreamBuffer())
+	{
+		ImxVpuLoadSingleton::GetInstance()->Unload();
+		return false;
+	}
+
+	VLOG(1) << "Opening decoder";
+	if (!OpenDecoder())
+	{
+		ImxVpuLoadSingleton::GetInstance()->Unload();
+		return false;
+	}
+
+	VLOG(1) << "Initialization done";
+
+	return true;
+}
+
+
+void ImxVpuVideoDecodeAccelerator::Decode(media::BitstreamBuffer const &bitstream_buffer)
+{
+	VLOG(3) << "Decoding bitstream buffer";
+
+	base::AutoLock auto_lock(lock_);
+
+	input_queue_.push(bitstream_buffer);
+	ProcessQueuedInput();
+}
+
+
+void ImxVpuVideoDecodeAccelerator::AssignPictureBuffers(std::vector < media::PictureBuffer > const &buffers)
+{
+	DCHECK(output_picture_buffers_.empty());
+	DCHECK(buffers.size() == vpu_framebuffers_.size());
+
+	base::AutoLock auto_lock(lock_);
+
+	VLOG(1) << buffers.size() << " picture buffers are being provided by the client";
+
+
+	// without this call, the GL calls below would not use the correct context
+	make_context_current_.Run();
+
+	for (size_t i = 0; i < buffers.size(); ++i)
+	{
+		int32 id = buffers[i].id();
+
+		output_picture_buffers_.insert(std::make_pair(id, buffers[i]));
+
+		ImxVpuFramebuffer &framebuffer = vpu_framebuffers_[i];
+		framebuffer.user_data = reinterpret_cast < void* > (id);
+
+		// associate VIV direct textures with VPU framebuffers (one texture per framebuffer)
+		// by mapping the framebuffer to the direct texture
+		// only needs to be done once, since this mapping doesn't change
+		GLuint picture_buffer_texture_id = buffers[i].texture_id();
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, picture_buffer_texture_id);
+
+		GLvoid *virt_addr = framebuffer.virtual_address;
+		GLuint phys_addr = reinterpret_cast < GLuint > (framebuffer.physical_address);
+
+		direct_texture_procs_.TexDirectVIVMap(
+			GL_TEXTURE_2D,
+			aligned_width_, aligned_height_,
+			GL_VIV_I420,
+			&virt_addr, &phys_addr
+		);
+
+		VLOG(1)
+			<< "Associating picture buffer " << i << "/" << buffers.size() << " ID " << id << " with framebuffer #" << i << std::hex
+			<< " virtual address " << std::setfill('0') << std::setw(8) << reinterpret_cast < void* > (virt_addr)
+			<< " physical address " << std::setfill('0') << std::setw(8) << reinterpret_cast < void* > (phys_addr)
+			<< std::dec;
+	}
+
+
+	ProcessQueuedInput();
+}
+
+
+void ImxVpuVideoDecodeAccelerator::ReusePictureBuffer(int32 picture_buffer_id)
+{
+	base::AutoLock auto_lock(lock_);
+
+	VLOG(3) << "Reusing picture buffer with ID " << picture_buffer_id;
+
+	for (size_t i = 0; i < vpu_framebuffers_.size(); ++i)
+	{
+		ImxVpuFramebuffer &framebuffer = vpu_framebuffers_[i];
+		int32 id = reinterpret_cast < int32 > (framebuffer.user_data);
+		if (id == picture_buffer_id)
+		{
+			ImxVpuDecReturnCodes ret;
+
+			if ((ret = imx_vpu_dec_mark_framebuffer_as_displayed(vpu_decoder_, &framebuffer)) != IMX_VPU_DEC_RETURN_CODE_OK)
+			{
+				LOG(ERROR) << "Marking framebuffer for picture buffer with ID " << picture_buffer_id << "as displayed failed : " << imx_vpu_dec_error_string(ret);
+			}
+			else
+				ProcessQueuedInput();
+
+			return;
+		}
+	}
+
+	LOG(WARNING) << "Picture buffer ID " << picture_buffer_id << " could not be associated with a framebuffer";
+}
+
+
+void ImxVpuVideoDecodeAccelerator::Flush()
+{
+	base::AutoLock auto_lock(lock_);
+
+	VLOG(2) << "Flush: processing all currently queued input bitstream buffers";
+	ProcessQueuedInput();
+
+	VLOG(2) << "Flush: draining VPU decoder";
+	imx_vpu_dec_set_drain_mode(vpu_decoder_, 1);
+	while (true)
+	{
+		ProcessRetval pretval = ProcessInput(NULL);
+		if (pretval != ProcessOK)
+			break;
+		// TODO: handle ProcessFail (ProcessEOS should just cause the loop to terminate)
+	}
+	imx_vpu_dec_set_drain_mode(vpu_decoder_, 0);
+
+	VLOG(2) << "Flush: done";
+	base::MessageLoop::current()->PostTask(
+		FROM_HERE,
+		base::Bind(
+			&Client::NotifyFlushDone,
+			client_
+		)
+	);
+
+}
+
+
+void ImxVpuVideoDecodeAccelerator::Reset()
+{
+	base::AutoLock auto_lock(lock_);
+
+	VLOG(2) << "Reset: flushing decoder";
+	imx_vpu_dec_flush(vpu_decoder_);
+
+	VLOG(2) << "Reset: ending all queued bitstream buffers";
+	while (!input_queue_.empty())
+	{
+		int32 bitstream_buffer_id = input_queue_.front().id();
+		input_queue_.pop();
+
+		if (bitstream_buffer_id != -1)
+		{
+			base::MessageLoop::current()->PostTask(
+				FROM_HERE,
+				base::Bind(
+					&Client::NotifyEndOfBitstreamBuffer,
+					client_, bitstream_buffer_id
+				)
+			);
+		}
+	}
+
+	BitstreamBufferQueue empty_queue;
+	std::swap(input_queue_, empty_queue);
+
+	VLOG(2) << "Reset: done";
+	base::MessageLoop::current()->PostTask(
+		FROM_HERE,
+		base::Bind(
+			&Client::NotifyResetDone,
+			client_
+		)
+	);
+}
+
+
+void ImxVpuVideoDecodeAccelerator::Destroy()
+{
+	DCHECK_EQ(message_loop_, base::MessageLoop::current());
+	Cleanup();
+	delete this;
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::CanDecodeOnIOThread()
+{
+	return false;
+}
+
+
+void ImxVpuVideoDecodeAccelerator::Cleanup()
+{
+	DCHECK_EQ(message_loop_, base::MessageLoop::current());
+
+	base::AutoLock auto_lock(lock_);
+	client_ptr_factory_.reset();
+
+	CloseDecoder();
+
+	DeallocateVpuBitstreamBuffer();
+
+	ImxVpuLoadSingleton::GetInstance()->Unload();
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::OpenDecoder()
+{
+	lock_.AssertAcquired();
+
+	ImxVpuDecOpenParams open_params;
+
+	open_params.codec_format = codec_format_;
+
+	open_params.enable_frame_reordering = (codec_format_ == IMX_VPU_CODEC_FORMAT_H264) ? 1 : 0;
+
+	// frame width & height are read from the bitstream
+	open_params.frame_width = 0;
+	open_params.frame_height = 0;
+
+	if (imx_vpu_dec_open(&(vpu_decoder_), &open_params, vpu_bitstream_buffer_block_.virtual_address, vpu_bitstream_buffer_block_.physical_address) != IMX_VPU_DEC_RETURN_CODE_OK)
+		return false;
+
+	return true;
+}
+
+
+void ImxVpuVideoDecodeAccelerator::CloseDecoder()
+{
+	lock_.AssertAcquired();
+
+	if (vpu_decoder_ == NULL)
+		return;
+
+	imx_vpu_dec_close(vpu_decoder_);
+	DeallocateVpuFramebuffers();
+
+	vpu_decoder_ = NULL;
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::AllocateVpuBitstreamBuffer()
+{
+	lock_.AssertAcquired();
+
+	ImxVpuDecReturnCodes ret;
+
+	imx_vpu_dec_get_bitstream_buffer_info(&(vpu_bitstream_buffer_block_.alignment), &(vpu_bitstream_buffer_block_.size));
+	if ((ret = imx_vpu_dec_allocate_memory(&vpu_bitstream_buffer_block_)) != IMX_VPU_DEC_RETURN_CODE_OK)
+	{
+		LOG(ERROR) << "Allocating VPU bitstream buffer failed: " << imx_vpu_dec_error_string(ret);
+		return false;
+	}
+	else
+		return true;
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::DeallocateVpuBitstreamBuffer()
+{
+	lock_.AssertAcquired();
+
+	ImxVpuDecReturnCodes ret;
+
+	if (vpu_bitstream_buffer_block_.virtual_address == NULL)
+		return true;
+
+	if ((ret = imx_vpu_dec_deallocate_memory(&vpu_bitstream_buffer_block_)) != IMX_VPU_DEC_RETURN_CODE_OK)
+	{
+		LOG(ERROR) << "Deallocating VPU bitstream buffer failed: " << imx_vpu_dec_error_string(ret);
+		return false;
+	}
+	else
+		return true;
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::AllocateAndRegisterVPUFramebuffers()
+{
+	lock_.AssertAcquired();
+
+	ImxVpuDecReturnCodes ret;
+	unsigned int y_stride, cbcr_stride, y_size, cbcr_size, mvcol_size, total_size;
+
+	aligned_width_ = vpu_dec_initial_info_.frame_width;
+	aligned_height_ = vpu_dec_initial_info_.frame_height;
+
+	imx_vpu_dec_calc_framebuffer_sizes(
+		&vpu_dec_initial_info_,
+		&aligned_width_, &aligned_height_,
+		&y_stride, &cbcr_stride,
+		&y_size, &cbcr_size,
+		&mvcol_size,
+		&total_size
+	);
+
+	vpu_framebuffers_.resize(vpu_dec_initial_info_.min_num_required_framebuffers + media::limits::kMaxVideoFrames);
+	vpu_framebuffer_mem_blocks_.resize(vpu_framebuffers_.size());
+	memset(&(vpu_framebuffers_[0]), 0, sizeof(ImxVpuFramebuffer) * vpu_framebuffers_.size());
+	memset(&(vpu_framebuffer_mem_blocks_[0]), 0, sizeof(ImxVpuMemBlock) * vpu_framebuffers_.size());
+
+	for (unsigned int i = 0; i < vpu_framebuffers_.size(); ++i)
+	{
+		ImxVpuFramebuffer &framebuffer = vpu_framebuffers_[i];
+		ImxVpuMemBlock &memblock = vpu_framebuffer_mem_blocks_[i];
+
+		memblock.size = total_size;
+		memblock.alignment = vpu_dec_initial_info_.framebuffer_alignment;
+		if (imx_vpu_dec_allocate_memory(&memblock) != IMX_VPU_DEC_RETURN_CODE_OK)
+		{
+			LOG(ERROR) << "Could not allocate framebuffer memory for framebuffer " << i << "/" << vpu_framebuffers_.size();
+			memblock.physical_address = 0;
+			return false;
+		}
+
+		framebuffer.y_stride = y_stride;
+		framebuffer.cbcr_stride = cbcr_stride;
+		framebuffer.virtual_address = memblock.virtual_address;
+		framebuffer.physical_address = memblock.physical_address;
+		framebuffer.y_offset = 0;
+		framebuffer.cb_offset = y_size;
+		framebuffer.cr_offset = y_size + cbcr_size;
+		framebuffer.mvcol_offset = y_size + cbcr_size * 2;
+	}
+
+	if ((ret = imx_vpu_dec_register_framebuffers(vpu_decoder_, &(vpu_framebuffers_[0]), vpu_framebuffers_.size())) != IMX_VPU_DEC_RETURN_CODE_OK)
+	{
+		LOG(ERROR) << "Registering framebuffers failed: " << imx_vpu_dec_error_string(ret);
+		return false;
+	}
+	else
+		return true;
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::DeallocateVpuFramebuffers()
+{
+	lock_.AssertAcquired();
+
+	for (unsigned int i = 0; i < vpu_framebuffer_mem_blocks_.size(); ++i)
+	{
+		ImxVpuMemBlock &memblock = vpu_framebuffer_mem_blocks_[i];
+		if (memblock.physical_address != 0)
+		{
+			if (imx_vpu_dec_deallocate_memory(&memblock) != IMX_VPU_DEC_RETURN_CODE_OK)
+			{
+				LOG(ERROR) << "Deallocating memory block of framebuffer " << i << "/" << vpu_framebuffer_mem_blocks_.size() << " failed";
+			}
+		}
+	}
+	vpu_framebuffer_mem_blocks_.clear();
+
+	return true;
+}
+
+
+void ImxVpuVideoDecodeAccelerator::ProcessQueuedInput()
+{
+	lock_.AssertAcquired();
+
+	VLOG(1) << "Input queue size: " << input_queue_.size();
+
+	{
+		if (input_queue_.empty())
+		{
+			VLOG(1) << "Input queue empty - nothing to process";
+			return;
+		}
+
+		if (initial_info_received_ && output_picture_buffers_.empty())
+		{
+			VLOG(1) << "No picture buffers have been provided yet - will try again later";
+			return;
+		}
+
+		if (initial_info_received_ && (imx_vpu_dec_get_num_free_framebuffers(vpu_decoder_) < imx_vpu_dec_get_min_num_free_required(vpu_decoder_)))
+		{
+			VLOG(1) << "Not enough free framebuffers available - will try again later";
+			return;
+		}
+
+		media::BitstreamBuffer const &queued_bitstream_buffer = input_queue_.front();
+		ProcessRetval ret = ProcessInput(&queued_bitstream_buffer);
+		input_queue_.pop();
+
+		if (ret != ProcessOK)
+			return;
+	}
+}
+
+
+ImxVpuVideoDecodeAccelerator::ProcessRetval ImxVpuVideoDecodeAccelerator::ProcessInput(media::BitstreamBuffer const *input_bitstream_buffer)
+{
+	ImxVpuDecReturnCodes ret;
+
+	lock_.AssertAcquired();
+
+
+	ImxVpuEncodedFrame encoded_frame;
+	scoped_ptr < base::SharedMemory > shm;
+
+	// bitstream_buffer is NULL while draining
+	if (input_bitstream_buffer != NULL)
+	{
+		VLOG(3) << "Processing input bitstream buffer with ID " << input_bitstream_buffer->id();
+
+		shm.reset(new base::SharedMemory(input_bitstream_buffer->handle(), true));
+		// The shared memory block is automatically unmapped by the destructor
+		shm->Map(input_bitstream_buffer->size());
+
+		// The stored bitstream IDs are incremented to make debug output clearer
+		// (otherwise, the imxvpucodec debug printout will print (nil) for the ID 0,
+		// 0x1 for the ID 1 etc.)
+		encoded_frame.virtual_address = shm->memory();
+		encoded_frame.data_size = input_bitstream_buffer->size();
+		encoded_frame.user_data = reinterpret_cast < void* > (input_bitstream_buffer->id() + 1);
+
+		VLOG(3) << "Creating encoded frame (data address " << encoded_frame.virtual_address << " size " << encoded_frame.data_size << " id " << input_bitstream_buffer->id();
+	}
+	else
+	{
+		VLOG(2) << "Setting input data to NULL";
+
+		encoded_frame.virtual_address = NULL;
+		encoded_frame.data_size = 0;
+		encoded_frame.user_data = NULL;
+	}
+
+	encoded_frame.codec_data = NULL;
+	encoded_frame.codec_data_size = 0;
+
+
+	unsigned int output_code;
+	if ((ret = imx_vpu_dec_decode_frame(vpu_decoder_, &encoded_frame, &output_code)) != IMX_VPU_DEC_RETURN_CODE_OK)
+	{
+		LOG(ERROR) << "Decoding frame failed: " << imx_vpu_dec_error_string(ret);
+		return ProcessFailed;
+	}
+
+	VLOG(1) << "Output code of decoded frame: 0x" << std::hex << output_code;
+
+	if (input_bitstream_buffer != NULL)
+	{
+		base::MessageLoop::current()->PostTask(
+			FROM_HERE,
+			base::Bind(
+				&Client::NotifyEndOfBitstreamBuffer,
+				client_,
+				input_bitstream_buffer->id()
+			)
+		);
+	}
+
+	if (output_code & (IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE | IMX_VPU_DEC_OUTPUT_CODE_RESOLUTION_CHANGED))
+	{
+		VLOG(1) << "Initial information is available - retrieving";
+
+		if ((ret = imx_vpu_dec_get_initial_info(vpu_decoder_, &vpu_dec_initial_info_)) != IMX_VPU_DEC_RETURN_CODE_OK)
+		{
+			LOG(ERROR) << "Retrieving initial info failed: " << imx_vpu_dec_error_string(ret);
+			return ProcessFailed;
+		}
+
+		VLOG(1) << "Initial info: frame size " << vpu_dec_initial_info_.frame_width << "x" << vpu_dec_initial_info_.frame_height << "  min num required framebuffers: " << vpu_dec_initial_info_.min_num_required_framebuffers;
+
+		if (
+			!DeallocateVpuFramebuffers() ||
+			!AllocateAndRegisterVPUFramebuffers()
+		)
+			return ProcessFailed;
+
+		initial_info_received_ = true;
+
+		base::MessageLoop::current()->PostTask(
+			FROM_HERE,
+			base::Bind(
+				&Client::ProvidePictureBuffers,
+				client_,
+				vpu_framebuffers_.size(),
+				gfx::Size(aligned_width_, aligned_height_),
+				GL_TEXTURE_2D
+			)
+		);
+	}
+
+	ProcessRetval pretval = (output_code & IMX_VPU_DEC_OUTPUT_CODE_EOS) ? ProcessEOS : ProcessOK;
+
+	int32 bitstream_buffer_id = 0;
+	if (output_code & IMX_VPU_DEC_OUTPUT_CODE_FRAME_OUTPUT)
+	{
+		ImxVpuDecodedFrame decoded_frame;
+		if ((ret = imx_vpu_dec_get_decoded_frame(vpu_decoder_, &decoded_frame)) != IMX_VPU_DEC_RETURN_CODE_OK)
+		{
+			LOG(ERROR) << "Retrieving decoded frame failed: " << imx_vpu_dec_error_string(ret);
+			return ProcessFailed;
+		}
+
+		bitstream_buffer_id = reinterpret_cast < int32 > (decoded_frame.user_data) - 1;
+
+		VLOG(3) << "Decoded frame was retrieved, bitstream buffer id " << bitstream_buffer_id;
+
+		if (decoded_frame.framebuffer == NULL)
+		{
+			LOG(ERROR) << "Framebuffer of decoded frame is NULL";
+			pretval = ProcessFailed;
+		}
+		else
+		{
+			if (!ProcessOutput(*(decoded_frame.framebuffer), bitstream_buffer_id))
+			{
+				// if ProcessOutput returns false, then no picture buffer has
+				// been sent to the client, so the decoded frame must be returned
+				// to the VPU pool here
+				VLOG(1) << "ProcessOutput failed -> returning decoded frame to internal VPU pool";
+				imx_vpu_dec_mark_framebuffer_as_displayed(vpu_decoder_, decoded_frame.framebuffer);
+				pretval = ProcessFailed;
+			}
+
+			// if processing the output was successful, the framebuffer is
+			// _not_ marked as displayed here; this is done in ReusePictureBuffer(),
+			// because only then it is certain that the client is done with that frame
+		}
+	}
+	else if (output_code & IMX_VPU_DEC_OUTPUT_CODE_DROPPED)
+	{
+		void *user_data = imx_vpu_dec_get_dropped_frame_user_data(vpu_decoder_);
+		bitstream_buffer_id = reinterpret_cast < int32 > (user_data) - 1;
+		VLOG(2) << "Frame was dropped, bitstream buffer id " << bitstream_buffer_id;
+	}
+
+	return pretval;
+}
+
+
+bool ImxVpuVideoDecodeAccelerator::ProcessOutput(ImxVpuFramebuffer const &output_framebuffer, int32 input_bitstream_buffer_id)
+{
+	lock_.AssertAcquired();
+
+	int32 picture_buffer_id = reinterpret_cast < int32 > (output_framebuffer.user_data);
+	OutputBufferMap::const_iterator iter = output_picture_buffers_.find(picture_buffer_id);
+	if (iter == output_picture_buffers_.end())
+	{
+		LOG(ERROR) << "No picture buffer with ID " << picture_buffer_id << " found";
+		return false;
+	}
+	GLuint picture_buffer_texture_id = iter->second.texture_id();
+
+	make_context_current_.Run();
+
+	glActiveTexture(GL_TEXTURE0);
+	glBindTexture(GL_TEXTURE_2D, picture_buffer_texture_id);
+
+	direct_texture_procs_.TexDirectInvalidateVIV(GL_TEXTURE_2D);
+
+	gles2_decoder_->RestoreTextureUnitBindings(0);
+	gles2_decoder_->RestoreActiveTexture();
+
+	base::MessageLoop::current()->PostTask(
+		FROM_HERE,
+		base::Bind(
+			&Client::PictureReady,
+			client_,
+			media::Picture(
+				picture_buffer_id,
+				input_bitstream_buffer_id,
+				gfx::Rect(
+					0,
+					0,
+					vpu_dec_initial_info_.frame_width,
+					vpu_dec_initial_info_.frame_height
+				)
+			)
+		)
+	);
+
+	return true;
+}
+
+
+}  // namespace content
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpu_video_decode_accelerator.h
@@ -0,0 +1,106 @@
+#ifndef CONTENT_COMMON_GPU_MEDIA_IMXVPU_VIDEO_DECODE_ACCELERATOR_H_
+#define CONTENT_COMMON_GPU_MEDIA_IMXVPU_VIDEO_DECODE_ACCELERATOR_H_
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "content/common/content_export.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "media/base/bitstream_buffer.h"
+#include "media/video/picture.h"
+#include "media/video/video_decode_accelerator.h"
+
+#include "imxvpucodec.h"
+#include "imx_gl_viv_direct_texture.h"
+
+
+namespace content
+{
+
+
+class CONTENT_EXPORT ImxVpuVideoDecodeAccelerator
+	: public media::VideoDecodeAccelerator
+{
+public:
+	explicit ImxVpuVideoDecodeAccelerator(base::WeakPtr < gpu::gles2::GLES2Decoder > const gles2_decoder, base::Callback < bool(void) > const &make_context_current);
+	virtual ~ImxVpuVideoDecodeAccelerator();
+
+	virtual bool Initialize(media::VideoCodecProfile profile, Client *client) override;
+	virtual void Decode(media::BitstreamBuffer const &bitstream_buffer) override;
+	virtual void AssignPictureBuffers(std::vector < media::PictureBuffer > const &buffers) override;
+	virtual void ReusePictureBuffer(int32 picture_buffer_id) override;
+	virtual void Flush() override;
+	virtual void Reset() override;
+	virtual void Destroy() override;
+	virtual bool CanDecodeOnIOThread() override;
+
+
+private:
+	enum ProcessRetval
+	{
+		ProcessOK,
+		ProcessEOS,
+		ProcessFailed
+	};
+
+	void Cleanup();
+
+	// VPU specifics
+	bool OpenDecoder();
+	void CloseDecoder();
+	bool AllocateVpuBitstreamBuffer();
+	bool DeallocateVpuBitstreamBuffer();
+	bool AllocateAndRegisterVPUFramebuffers();
+	bool DeallocateVpuFramebuffers();
+
+	// Bitstream buffer and framebuffer processing
+	void ProcessQueuedInput();
+	ProcessRetval ProcessInput(media::BitstreamBuffer const *input_bitstream_buffer);
+	bool ProcessOutput(ImxVpuFramebuffer const &output_framebuffer, int32 input_bitstream_buffer_id);
+
+
+	scoped_ptr < base::WeakPtrFactory < Client > > client_ptr_factory_;
+	base::WeakPtr < Client > client_;
+
+	base::WeakPtr < gpu::gles2::GLES2Decoder > const gles2_decoder_;
+	base::Callback < bool(void) > make_context_current_;
+
+	typedef std::vector < ImxVpuFramebuffer > ImxVpuFramebuffers;
+	typedef std::vector < ImxVpuMemBlock > ImxVpuMemBlocks;
+	ImxVpuDecoder *vpu_decoder_;
+	ImxVpuCodecFormats codec_format_;
+	ImxVpuMemBlock vpu_bitstream_buffer_block_;
+	ImxVpuDecInitialInfo vpu_dec_initial_info_;
+	ImxVpuFramebuffers vpu_framebuffers_;
+	ImxVpuMemBlocks vpu_framebuffer_mem_blocks_;
+	unsigned int aligned_width_, aligned_height_;
+	bool initial_info_received_;
+
+	GLESVIVDirectTextureProcs direct_texture_procs_;
+
+	base::Lock lock_;
+
+	typedef std::queue < media::BitstreamBuffer > BitstreamBufferQueue;
+	BitstreamBufferQueue input_queue_;
+
+	typedef std::map < int32, media::PictureBuffer > OutputBufferMap;
+	OutputBufferMap output_picture_buffers_;
+
+	// ChildThread's message loop
+	base::MessageLoop* message_loop_;
+
+	DISALLOW_COPY_AND_ASSIGN(ImxVpuVideoDecodeAccelerator);
+};
+
+
+} // namespace content end
+
+
+#endif  // CONTENT_COMMON_GPU_MEDIA_IMXVPU_VIDEO_DECODE_ACCELERATOR_H_
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpucodec.h
@@ -0,0 +1,418 @@
+/*
+ * imxvpucodec - i.MX6 VPU hardware codec engine API library
+ * Copyright (c) 2014 Carlos Rafael Giani
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any
+ * damages arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software. If you use this
+ *    software in a product, an acknowledgment in the product
+ *    documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+
+#ifndef IMXVPUCODEC_H
+#define IMXVPUCODEC_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* This library provides a high-level interface for controlling the Freescale
+ * i.MX VPU en/decoder.
+ * Other libraries do not provide a way of associating frames with user defined
+ * information, and lack calls to check the number of currently free framebuffers
+ * (when decoding). The former is required by many media frameworks such as
+ * GStreamer, FFmpeg/libav, the Chromium media codebase etc. The latter is
+ * necessary when framebuffer display and decoding can happen in different
+ * threads (the counter makes it possible to use synchronization primitives
+ * like thread condition variables to wait until enough frames are free).
+ *
+ * Note that the functions are _not_ thread safe. If they may be called from
+ * different threads, you must make sure they are surrounded by a mutex lock.
+ * It is recommended to use one global mutex for the imx_vpu_*_load()/unload()
+ * functions, and another de/encoder instance specific mutex for all of the other
+ * calls.
+ *
+ * How to use the decoder (error handling omitted for clarity):
+ * 1. Call imx_vpu_dec_load()
+ * 2. Call imx_vpu_dec_get_bitstream_buffer_info(), and allocate a DMA buffer
+ *    with the given size and alignment.
+ * 3. Fill an instance of ImxVpuDecOpenParams with the values specific to the
+ *    input data. In most cases, one wants to set enable_frame_reordering to 1
+ *    with h.264 data here.
+ * 4. Call imx_vpu_dec_open(), passing in a pointer to the filled ImxVpuDecOpenParams
+ *    instance, and the virtual and physical addresses of the bitstream DMA buffer
+ *    which was allocated in step 2.
+ * 5. Call imx_vpu_dec_decode_frame() with the first encoded frame.
+ *    If the output_code bitmask contains IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE,
+ *    proceed, otherwise continue feeding in data.
+ * 6. Once IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE has been set in the output code,
+ *    call imx_vpu_dec_get_initial_info() with a pointer to an ImxVpuDecInitialInfo
+ *    instance.
+ * 7. (Optional) Perform the necessary size and alignment calculations by calling
+ *    imx_vpu_dec_calc_framebuffer_sizes().
+ * 8. Create an array of at least as many ImxVpuFramebuffer instances as specified in
+ *    min_num_required_framebuffers. Each instance must point to a DMA buffer that is big
+ *    enough to hold a frame. If step 7 was performed, allocating as many bytes as indicated
+ *    by total_size is enough. Make sure the Y,Cb,Cr,MvCol offsets in each ImxVpuFramebuffer
+ *    instance are valid.
+ * 9. Call imx_vpu_dec_register_framebuffers() and pass in the ImxVpuFramebuffer array
+ *    and the number of ImxVpuFramebuffer instances.
+ * 10. Continue calling imx_vpu_dec_decode_frame(). The virtual address in encoded_frame
+ *     must not be NULL.
+ *     If the IMX_VPU_DEC_OUTPUT_CODE_FRAME_OUTPUT flag is set in the output code,
+ *     call imx_vpu_dec_get_decoded_frame() with a pointer to an ImxVpuDecodedFrame instance
+ *     which gets filled with information about the decoded frame. Once the decoded frame
+ *     has been processed by the user, imx_vpu_dec_mark_framebuffer_as_displayed() must be
+ *     called to let the decoder know that the framebuffer is available for storing new
+ *     decoded frames again.
+ *     If IMX_VPU_DEC_OUTPUT_CODE_DROPPED is set, you can call
+ *     imx_vpu_dec_get_dropped_frame_user_data() to retrieve the user_data field
+ *     of the dropped frame. If IMX_VPU_DEC_OUTPUT_CODE_EOS is set, stop playback and close
+ *     the decoder.
+ * 11. In case a flush/reset is desired (typically after seeking), call imx_vpu_dec_flush().
+ *     Note that any internal user_data pointers from the en/decoded frames will be
+ *     set to NULL after this call (this is the only exception where the library modifies
+ *     the user_data fields).
+ * 12. When there is no more incoming data, and pending decoded frames need to be retrieved
+ *     from the decoder, call imx_vpu_dec_set_drain_mode(). This is typically necessary when
+ *     the data source reached its end, playback is finishing, and there is a delay
+ *     of N frames at the beginning.
+ *     After this call, continue calling imx_vpu_dec_decode_frame() to retrieve the pending
+ *     decoded frames, but the virtual address of encoded_frame must be NULL.
+ *     As in step 10, if IMX_VPU_DEC_OUTPUT_CODE_EOS is set, stop playback, close the decoder.
+ * 13. After playback is finished, close the decoder with imx_vpu_dec_close().
+ * 14. Deallocate framebuffer memory blocks and the bitstream buffer memory block.
+ * 15. Call imx_vpu_dec_unload().
+ *
+ * Step 15 should only be called if no more playback sessions will occur.
+ *
+ * As mentioned before, in situations where decoding and display of decoded frames happen in
+ * different thread, it is necessary to let the decoder wait until enough framebuffers
+ * are free (= available for the VPU to decode into). This is typically done by such a check
+ * (in pseudo code):
+ *
+ *   mutex_lock(&mutex);
+ *
+ *   while (imx_vpu_dec_get_num_free_framebuffers(decoder) < imx_vpu_dec_get_min_num_free_required(decoder))
+ *     condition_wait(&condition_variable, &mutex);
+ *
+ *   imx_vpu_dec_decode_frame(decoder, encoded_frame, &output_code);
+ *   ...
+ *
+ *   mutex_unlock(&mutex);
+ */
+
+
+
+/***********************************************/
+/******* COMMON STRUCTURES AND FUNCTIONS *******/
+/***********************************************/
+
+
+#define IMX_VPU_ALIGN_VAL_TO(LENGTH, ALIGN_SIZE)  ( ((uintptr_t)(((uint8_t*)(LENGTH)) + (ALIGN_SIZE) - 1) / (ALIGN_SIZE)) * (ALIGN_SIZE) )
+
+
+typedef uint32_t imx_vpu_phys_addr_t;
+typedef uint32_t imx_vpu_cpu_addr_t; /* used only in allocators so far */
+
+
+typedef enum
+{
+	IMX_VPU_PIC_TYPE_UNKNOWN = 0,
+	IMX_VPU_PIC_TYPE_I,
+	IMX_VPU_PIC_TYPE_P,
+	IMX_VPU_PIC_TYPE_B,
+	IMX_VPU_PIC_TYPE_IDR,
+	IMX_VPU_PIC_TYPE_BI,
+	IMX_VPU_PIC_TYPE_SKIP
+}
+ImxVpuPicType;
+
+
+typedef enum
+{
+	IMX_VPU_CODEC_FORMAT_MPEG2 = 0, /* includes MPEG1 */
+	IMX_VPU_CODEC_FORMAT_MPEG4,
+	IMX_VPU_CODEC_FORMAT_H263,
+	IMX_VPU_CODEC_FORMAT_H264,
+	IMX_VPU_CODEC_FORMAT_H264_MVC,
+	IMX_VPU_CODEC_FORMAT_WMV3,
+	IMX_VPU_CODEC_FORMAT_WVC1,
+	IMX_VPU_CODEC_FORMAT_MJPEG,
+	IMX_VPU_CODEC_FORMAT_VP8
+	/* XXX others will be added when the firmware supports them */
+}
+ImxVpuCodecFormats;
+
+
+typedef enum
+{
+	IMX_VPU_MJPEG_FORMAT_YUV420            = 0, /* also known as I420 */
+	IMX_VPU_MJPEG_FORMAT_YUV422_HORIZONTAL = 1,
+	IMX_VPU_MJPEG_FORMAT_YUV422_VERTICAL   = 2, /* 4:2:2 vertical, actually 2:2:4 (according to the VPU docs) */
+	IMX_VPU_MJPEG_FORMAT_YUV444            = 3,
+	IMX_VPU_MJPEG_FORMAT_YUV400            = 4  /* 8-bit grayscale */
+}
+ImxVpuMJpegFormat;
+
+
+typedef struct
+{
+	/* Stride of the Y and of the Cb&Cr components.
+	 * Specified in bytes. */
+	unsigned int y_stride, cbcr_stride;
+
+	/* The virtual address of is actually not used by the VPU,
+	 * and only of interest to the user. It can be NULL for cases
+	 * where only a physical address exists or where a virtual
+	 * address is not necessary. */
+	void *virtual_address;
+	/* The physical address must always be valid. */
+	imx_vpu_phys_addr_t physical_address;
+
+	/* These define the starting offsets of each component
+	 * relative to the start of the buffer. Specified in bytes.
+	 *
+	 * mvcol is the "co-located motion vector" data. */
+	size_t
+		y_offset,
+		cb_offset,
+		cr_offset,
+		mvcol_offset;
+
+	/* User-defined pointer. The library does not touch this value.
+	 * This can be used to identify framebuffers for example.
+	 * Not to be confused with the user_data fields of ImxVpuEncodedFrame
+	 * and ImxVpuDecodedFrame. */
+	void *user_data;
+
+	/* Internal, implementation-defined data. Do not modify. */
+	void *internal;
+}
+ImxVpuFramebuffer;
+
+
+typedef struct
+{
+	/* Virtual and physical addresses pointing to the encoded data.
+	 * The virtual address must always be valid. The physical address
+	 * is only required for encoding. */
+	void *virtual_address;
+	imx_vpu_phys_addr_t physical_address;
+
+	/* Size of the encoded data, in bytes. */
+	unsigned int data_size;
+
+	/* Pointer to out-of-band codec/header data. If such data exists,
+	 * specify the pointer to the memory block containing the data,
+	 * as well as the size of the memory block (in bytes).
+	 * Set pointer and size for every encoded frame when decoding.
+	 * If no such data exists or is required, set pointer to NULL and
+	 * size to 0. */
+	void *codec_data;
+	unsigned int codec_data_size;
+
+	/* User-defined pointer. The library does not touch this value.
+	 * This pointer and the one from the corresponding
+	 * decoded frame will have the same value. The library will
+	 * pass then through.
+	 * It can be used to identify frames and associated corresponding
+	 * en- and decoded frames for example. */
+	void *user_data;
+}
+ImxVpuEncodedFrame;
+
+
+typedef struct
+{
+	/* When decoding: pointer to the framebuffer containing the decoded frame.
+	 * When encoding: pointer to the framebuffer containing the frame to be encoded.
+	 * Must always be valid. */
+	ImxVpuFramebuffer *framebuffer;
+
+	/* picture type (I, P, B, ..) */
+	ImxVpuPicType pic_type;
+
+	/* User-defined pointer. The library does not touch this value.
+	 * This pointer and the one from the corresponding
+	 * encoded frame will have the same value. The library will
+	 * pass then through.
+	 * It can be used to identify frames and associated corresponding
+	 * en- and decoded frames for example. */
+	void *user_data;
+}
+ImxVpuDecodedFrame;
+
+
+/* This structure is only used by the allocate/deallocate calls below,
+ * which in turn are convenience calls that wrap VPU-provided DMA buffer
+ * allocators. If a different DMA buffer allocator is used (like ION),
+ * this structure does not have to be used. */
+typedef struct
+{
+	size_t size;
+	unsigned int alignment;
+
+	void*               virtual_address;
+	imx_vpu_phys_addr_t physical_address;
+	imx_vpu_cpu_addr_t  cpu_address;
+
+	void*               virtual_address_unaligned;
+	imx_vpu_phys_addr_t physical_address_unaligned;
+}
+ImxVpuMemBlock;
+
+
+
+
+/************************************************/
+/******* DECODER STRUCTURES AND FUNCTIONS *******/
+/************************************************/
+
+
+typedef struct _ImxVpuDecoder ImxVpuDecoder;
+
+
+typedef enum
+{
+	IMX_VPU_DEC_RETURN_CODE_OK = 0,
+	IMX_VPU_DEC_RETURN_CODE_ERROR,
+	IMX_VPU_DEC_RETURN_CODE_INVALID_PARAMS,
+	IMX_VPU_DEC_RETURN_CODE_INVALID_HANDLE,
+	IMX_VPU_DEC_RETURN_CODE_INVALID_FRAMEBUFFER,
+	IMX_VPU_DEC_RETURN_CODE_INSUFFICIENT_FRAMEBUFFERS,
+	IMX_VPU_DEC_RETURN_CODE_INVALID_STRIDE,
+	IMX_VPU_DEC_RETURN_CODE_WRONG_CALL_SEQUENCE,
+	IMX_VPU_DEC_RETURN_CODE_TIMEOUT
+}
+ImxVpuDecReturnCodes;
+
+
+typedef enum
+{
+	IMX_VPU_DEC_OUTPUT_CODE_INPUT_USED               = (1UL << 0),
+	IMX_VPU_DEC_OUTPUT_CODE_EOS                      = (1UL << 1),
+	IMX_VPU_DEC_OUTPUT_CODE_FRAME_OUTPUT             = (1UL << 2),
+	IMX_VPU_DEC_OUTPUT_CODE_NO_FRAME_OUTPUT          = (1UL << 3),
+	IMX_VPU_DEC_OUTPUT_CODE_DROPPED                  = (1UL << 4),
+	IMX_VPU_DEC_OUTPUT_CODE_NOT_ENOUGH_OUTPUT_FRAMES = (1UL << 5),
+	IMX_VPU_DEC_OUTPUT_CODE_NOT_ENOUGH_INPUT_DATA    = (1UL << 6),
+	IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE   = (1UL << 7),
+	IMX_VPU_DEC_OUTPUT_CODE_RESOLUTION_CHANGED       = (1UL << 8),
+	IMX_VPU_DEC_OUTPUT_CODE_DECODE_ONLY              = (1UL << 9),
+	IMX_VPU_DEC_OUTPUT_CODE_INTERNAL_RESET           = (1UL << 10)
+}
+ImxVpuDecOutputCodes;
+
+
+typedef struct
+{
+	ImxVpuCodecFormats codec_format;
+
+	int enable_frame_reordering;
+	unsigned int frame_width, frame_height;
+}
+ImxVpuDecOpenParams;
+
+
+typedef struct
+{
+	/* Width of height of frames, in pixels. */
+	unsigned int frame_width, frame_height;
+	/* Frame rate ratio. */
+	unsigned int frame_rate_numerator, frame_rate_denominator;
+
+	/* Caller must register at least this many framebuffers
+	 * with the decoder. */
+	unsigned int min_num_required_framebuffers;
+
+	/* Pixel format of the decoded frames. For codec formats
+	 * other than motion JPEG, this value will always be
+	 * IMX_VPU_MJPEG_FORMAT_YUV420. */
+	ImxVpuMJpegFormat mjpeg_source_format;
+
+	/* 0 = no interlacing, 1 = interlacing. */
+	int interlacing;
+
+	/* Fixed point, shifted by 16.
+	 * Example: 1.0 -> floor(1.0*(1<<16)) = 0x10000
+	 *          0.5 -> floor(0.5*(1<<16)) = 0x8000 */
+	unsigned int width_height_ratio;
+
+	/* Physical framebuffer addresses must be aligned to this value. */
+	unsigned int framebuffer_alignment;
+}
+ImxVpuDecInitialInfo;
+
+
+/* Returns a human-readable description of the error code.
+ * Useful for logging. */
+char const * imx_vpu_dec_error_string(ImxVpuDecReturnCodes code);
+
+/* These two functions load/unload the decoder. Thanks to an internal reference
+ * counter, it is safe to call these functions more than once. However, the
+ * number of unload() calls must match the number of load() calls.
+ *
+ * The decoder must be loaded before doing anything else with the decoder.
+ * Similarly, the decoder must not be unloaded before all decoder activities
+ * have been finished. This includes opening/decoding decoder instances. */
+ImxVpuDecReturnCodes imx_vpu_dec_load(void);
+ImxVpuDecReturnCodes imx_vpu_dec_unload(void);
+
+/* Convenience allocator for allocating DMA buffers. */
+ImxVpuDecReturnCodes imx_vpu_dec_allocate_memory(ImxVpuMemBlock *mem_block);
+ImxVpuDecReturnCodes imx_vpu_dec_deallocate_memory(ImxVpuMemBlock *mem_block);
+
+/* Called before imx_vpu_dec_open(), it returns the alignment and size for the
+ * physical memory block necessary for the decoder's bitstream buffer. The user
+ * must allocate a DMA buffer of at least this size, and its physical address
+ * must be aligned according to the alignment value. */
+void imx_vpu_dec_get_bitstream_buffer_info(unsigned int *alignment, size_t *size);
+
+ImxVpuDecReturnCodes imx_vpu_dec_open(ImxVpuDecoder **decoder, ImxVpuDecOpenParams const *open_params, void *bitstream_buffer_virtual_address, imx_vpu_phys_addr_t bitstream_buffer_physical_address);
+ImxVpuDecReturnCodes imx_vpu_dec_close(ImxVpuDecoder *decoder);
+
+ImxVpuDecReturnCodes imx_vpu_dec_set_drain_mode(ImxVpuDecoder *decoder, int enabled);
+ImxVpuDecReturnCodes imx_vpu_dec_flush(ImxVpuDecoder *decoder);
+
+ImxVpuDecReturnCodes imx_vpu_dec_register_framebuffers(ImxVpuDecoder *decoder, ImxVpuFramebuffer *framebuffers, unsigned int num_framebuffers);
+void imx_vpu_dec_calc_framebuffer_sizes(ImxVpuDecInitialInfo const *initial_info, unsigned int *frame_width, unsigned int *frame_height, unsigned int *y_stride, unsigned int *cbcr_stride, unsigned int *y_size, unsigned int *cbcr_size, unsigned int *mvcol_size, unsigned int *total_size);
+
+ImxVpuDecReturnCodes imx_vpu_dec_get_initial_info(ImxVpuDecoder *decoder, ImxVpuDecInitialInfo *info);
+
+ImxVpuDecReturnCodes imx_vpu_dec_decode_frame(ImxVpuDecoder *decoder, ImxVpuEncodedFrame const *encoded_frame, unsigned int *output_code);
+ImxVpuDecReturnCodes imx_vpu_dec_get_decoded_frame(ImxVpuDecoder *decoder, ImxVpuDecodedFrame *decoded_frame);
+void* imx_vpu_dec_get_dropped_frame_user_data(ImxVpuDecoder *decoder);
+int imx_vpu_dec_get_num_free_framebuffers(ImxVpuDecoder *decoder);
+int imx_vpu_dec_get_min_num_free_required(ImxVpuDecoder *decoder);
+ImxVpuDecReturnCodes imx_vpu_dec_mark_framebuffer_as_displayed(ImxVpuDecoder *decoder, ImxVpuFramebuffer const *framebuffer);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpucodec_fslwrapper.c
@@ -0,0 +1,1050 @@
+/*
+ * imxvpucodec - i.MX6 VPU hardware codec engine API library
+ * Copyright (c) 2014 Carlos Rafael Giani
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any
+ * damages arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software. If you use this
+ *    software in a product, an acknowledgment in the product
+ *    documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vpu_wrapper.h>
+#include "imxvpucodec.h"
+#include "imxvpucodec_platform.h"
+
+
+
+
+/***********************************************/
+/******* COMMON STRUCTURES AND FUNCTIONS *******/
+/***********************************************/
+
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+
+#ifndef BOOL
+#define BOOL int
+#endif
+
+
+static ImxVpuMJpegFormat convert_from_wrapper_mjpg_format(int format)
+{
+	return (ImxVpuMJpegFormat)format;
+}
+
+
+static ImxVpuPicType convert_from_wrapper_pic_type(VpuPicType type)
+{
+	switch (type)
+	{
+		case VPU_I_PIC:    return IMX_VPU_PIC_TYPE_I;
+		case VPU_P_PIC:    return IMX_VPU_PIC_TYPE_P;
+		case VPU_B_PIC:    return IMX_VPU_PIC_TYPE_B;
+		case VPU_IDR_PIC:  return IMX_VPU_PIC_TYPE_IDR;
+		case VPU_BI_PIC:   return IMX_VPU_PIC_TYPE_BI;
+		case VPU_SKIP_PIC: return IMX_VPU_PIC_TYPE_SKIP;
+		default: return IMX_VPU_PIC_TYPE_UNKNOWN;
+	}
+}
+
+
+static VpuCodStd convert_to_wrapper_codec_std(ImxVpuCodecFormats format)
+{
+	switch (format)
+	{
+		case IMX_VPU_CODEC_FORMAT_MPEG4:    return VPU_V_MPEG4;
+		case IMX_VPU_CODEC_FORMAT_H263:     return VPU_V_H263;
+		case IMX_VPU_CODEC_FORMAT_H264:     return VPU_V_AVC;
+		case IMX_VPU_CODEC_FORMAT_H264_MVC: return VPU_V_AVC_MVC;
+		case IMX_VPU_CODEC_FORMAT_WMV3:     return VPU_V_VC1;
+		case IMX_VPU_CODEC_FORMAT_WVC1:     return VPU_V_VC1_AP;
+		case IMX_VPU_CODEC_FORMAT_MPEG2:    return VPU_V_MPEG2;
+		case IMX_VPU_CODEC_FORMAT_MJPEG:    return VPU_V_MJPG;
+		case IMX_VPU_CODEC_FORMAT_VP8:      return VPU_V_VP8;
+		default: assert(FALSE);
+	}
+
+	return VPU_V_MPEG2; /* should never be reached */
+}
+
+
+static void convert_from_wrapper_mem_desc(VpuMemDesc *mem_desc, ImxVpuMemBlock *mem_block)
+{
+	mem_block->size = mem_desc->nSize;
+	mem_block->virtual_address_unaligned = (void*)(mem_desc->nVirtAddr);
+	mem_block->physical_address_unaligned = mem_desc->nPhyAddr;
+	mem_block->cpu_address = mem_desc->nCpuAddr;
+}
+
+
+static void convert_to_wrapper_mem_desc(ImxVpuMemBlock *mem_block, VpuMemDesc *mem_desc)
+{
+	mem_desc->nSize = mem_block->size;
+	mem_desc->nVirtAddr = (unsigned long)(mem_block->virtual_address_unaligned);
+	mem_desc->nPhyAddr = mem_block->physical_address_unaligned;
+	mem_desc->nCpuAddr = mem_block->cpu_address;
+}
+
+
+static void convert_to_wrapper_framebuffer(ImxVpuFramebuffer *fb, VpuFrameBuffer *wrapper_fb)
+{
+	memset(wrapper_fb, 0, sizeof(VpuFrameBuffer));
+
+	wrapper_fb->nStrideY = fb->y_stride;
+	wrapper_fb->nStrideC = fb->cbcr_stride;
+
+	wrapper_fb->pbufY = (unsigned char*)(fb->physical_address + fb->y_offset);
+	wrapper_fb->pbufCb = (unsigned char*)(fb->physical_address + fb->cb_offset);
+	wrapper_fb->pbufCr = (unsigned char*)(fb->physical_address + fb->cr_offset);
+	wrapper_fb->pbufMvCol = (unsigned char*)(fb->physical_address + fb->mvcol_offset);
+}
+
+
+
+
+/************************************************/
+/******* DECODER STRUCTURES AND FUNCTIONS *******/
+/************************************************/
+
+
+#define MIN_NUM_FREE_FB_REQUIRED 6
+#define FRAME_ALIGN 16
+
+
+struct _ImxVpuDecoder
+{
+	VpuDecHandle handle;
+
+	void *virt_mem_sub_block;
+	size_t virt_mem_sub_block_size;
+
+	ImxVpuCodecFormats codec_format;
+
+	unsigned int num_framebuffers;
+	VpuFrameBuffer **wrapper_framebuffers;
+	ImxVpuFramebuffer *framebuffers;
+	void **user_data_for_frames;
+	void *pending_user_data;
+	void *dropped_frame_user_data;
+	int num_user_data;
+	BOOL delay_pending_user_data;
+	void *last_pending_user_data;
+
+	BOOL consumption_info_available;
+	BOOL flush_vpu_upon_reset;
+
+	BOOL recalculate_num_avail_framebuffers;
+	int num_available_framebuffers;
+	int num_times_counter_decremented;
+	int num_framebuffers_in_use;
+};
+
+
+static ImxVpuDecReturnCodes dec_convert_retcode(VpuDecRetCode code)
+{
+	switch (code)
+	{
+		case VPU_DEC_RET_SUCCESS:                    return IMX_VPU_DEC_RETURN_CODE_OK;
+		case VPU_DEC_RET_FAILURE:                    return IMX_VPU_DEC_RETURN_CODE_ERROR;
+		case VPU_DEC_RET_INVALID_PARAM:              return IMX_VPU_DEC_RETURN_CODE_INVALID_PARAMS;
+		case VPU_DEC_RET_INVALID_HANDLE:             return IMX_VPU_DEC_RETURN_CODE_INVALID_HANDLE;
+		case VPU_DEC_RET_INVALID_FRAME_BUFFER:       return IMX_VPU_DEC_RETURN_CODE_INVALID_FRAMEBUFFER;
+		case VPU_DEC_RET_INSUFFICIENT_FRAME_BUFFERS: return IMX_VPU_DEC_RETURN_CODE_INSUFFICIENT_FRAMEBUFFERS;
+		case VPU_DEC_RET_INVALID_STRIDE:             return IMX_VPU_DEC_RETURN_CODE_INVALID_STRIDE;
+		case VPU_DEC_RET_WRONG_CALL_SEQUENCE:        return IMX_VPU_DEC_RETURN_CODE_WRONG_CALL_SEQUENCE;
+		case VPU_DEC_RET_FAILURE_TIMEOUT:            return IMX_VPU_DEC_RETURN_CODE_TIMEOUT;
+
+		default: return IMX_VPU_DEC_RETURN_CODE_ERROR;
+	}
+}
+
+
+static unsigned int dec_convert_outcode(VpuDecBufRetCode code)
+{
+	/* TODO: REPEAT? SKIP? */
+	unsigned int out = 0;
+	if (code & VPU_DEC_INPUT_USED)         out |= IMX_VPU_DEC_OUTPUT_CODE_INPUT_USED;
+	if (code & VPU_DEC_OUTPUT_EOS)         out |= IMX_VPU_DEC_OUTPUT_CODE_EOS;
+	if (code & VPU_DEC_OUTPUT_DIS)         out |= IMX_VPU_DEC_OUTPUT_CODE_FRAME_OUTPUT;
+	if (code & VPU_DEC_OUTPUT_NODIS)       out |= IMX_VPU_DEC_OUTPUT_CODE_NO_FRAME_OUTPUT;
+	if (code & VPU_DEC_OUTPUT_DROPPED)     out |= IMX_VPU_DEC_OUTPUT_CODE_DROPPED;
+	if (code & VPU_DEC_OUTPUT_MOSAIC_DIS)  out |= IMX_VPU_DEC_OUTPUT_CODE_DROPPED; /* mosaic frames are dropped */
+	if (code & VPU_DEC_NO_ENOUGH_BUF)      out |= IMX_VPU_DEC_OUTPUT_CODE_NOT_ENOUGH_OUTPUT_FRAMES;
+	if (code & VPU_DEC_NO_ENOUGH_INBUF)    out |= IMX_VPU_DEC_OUTPUT_CODE_NOT_ENOUGH_INPUT_DATA;
+	if (code & VPU_DEC_INIT_OK)            out |= IMX_VPU_DEC_OUTPUT_CODE_INITIAL_INFO_AVAILABLE;
+	if (code & VPU_DEC_RESOLUTION_CHANGED) out |= IMX_VPU_DEC_OUTPUT_CODE_RESOLUTION_CHANGED;
+	return out;
+}
+
+
+static void dec_convert_to_wrapper_open_param(ImxVpuDecOpenParams const *open_params, VpuDecOpenParam *wrapper_open_param)
+{
+	memset(wrapper_open_param, 0, sizeof(VpuDecOpenParam));
+	
+	wrapper_open_param->CodecFormat    = convert_to_wrapper_codec_std(open_params->codec_format);
+	wrapper_open_param->nReorderEnable = open_params->enable_frame_reordering;
+	wrapper_open_param->nPicWidth      = open_params->frame_width;
+	wrapper_open_param->nPicHeight     = open_params->frame_height;
+}
+
+
+static void dec_convert_from_wrapper_initial_info(VpuDecInitInfo *wrapper_info, ImxVpuDecInitialInfo *info)
+{
+	info->frame_width             = wrapper_info->nPicWidth;
+	info->frame_height            = wrapper_info->nPicHeight;
+	info->frame_rate_numerator    = wrapper_info->nFrameRateRes;
+	info->frame_rate_denominator  = wrapper_info->nFrameRateDiv;
+
+	info->min_num_required_framebuffers = wrapper_info->nMinFrameBufferCount + MIN_NUM_FREE_FB_REQUIRED;
+	info->mjpeg_source_format           = convert_from_wrapper_mjpg_format(wrapper_info->nMjpgSourceFormat);
+
+	info->interlacing = wrapper_info->nInterlace;
+
+	info->width_height_ratio = wrapper_info->nQ16ShiftWidthDivHeightRatio;
+
+	info->framebuffer_alignment = wrapper_info->nAddressAlignment;
+}
+
+
+static int dec_get_wrapper_framebuffer_index(ImxVpuDecoder *decoder, VpuFrameBuffer *wrapper_fb)
+{
+	unsigned int i;
+
+	// TODO: do something faster, like a hash table
+	for (i = 0; i < decoder->num_framebuffers; ++i)
+	{
+		if (wrapper_fb == decoder->wrapper_framebuffers[i])
+			return (int)i;
+	}
+	return -1;
+}
+
+
+char const * imx_vpu_dec_error_string(ImxVpuDecReturnCodes code)
+{
+	switch (code)
+	{
+		case IMX_VPU_DEC_RETURN_CODE_OK:                        return "ok";
+		case IMX_VPU_DEC_RETURN_CODE_ERROR:                     return "unspecified error";
+		case IMX_VPU_DEC_RETURN_CODE_INVALID_PARAMS:            return "invalid params";
+		case IMX_VPU_DEC_RETURN_CODE_INVALID_HANDLE:            return "invalid handle";
+		case IMX_VPU_DEC_RETURN_CODE_INVALID_FRAMEBUFFER:       return "invalid framebuffer";
+		case IMX_VPU_DEC_RETURN_CODE_INSUFFICIENT_FRAMEBUFFERS: return "insufficient_framebuffers";
+		case IMX_VPU_DEC_RETURN_CODE_INVALID_STRIDE:            return "invalid stride";
+		case IMX_VPU_DEC_RETURN_CODE_WRONG_CALL_SEQUENCE:       return "wrong call sequence";
+		case IMX_VPU_DEC_RETURN_CODE_TIMEOUT:                   return "timeout";
+		default: return "<unknown>";
+	}
+}
+
+
+static unsigned long vpu_load_inst_counter = 0;
+
+
+ImxVpuDecReturnCodes imx_vpu_dec_load(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_DecLoad());
+	if (ret != IMX_VPU_DEC_RETURN_CODE_OK)
+		IMX_VPU_ERROR("loading decoder failed: %s", imx_vpu_dec_error_string(ret));
+	else
+	{
+		IMX_VPU_TRACE("loaded decoder");
+		++vpu_load_inst_counter;
+	}
+
+	return 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_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;
+}
+
+
+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;
+}
+
+
+void imx_vpu_dec_get_bitstream_buffer_info(unsigned int *alignment, size_t *size)
+{
+	int i;
+	VpuMemInfo mem_info;
+
+	VPU_DecQueryMem(&mem_info);
+
+	/* only two sub blocks are ever present - get the VPU_MEM_PHY one */
+
+	for (i = 0; i < mem_info.nSubBlockNum; ++i)
+	{
+		if (mem_info.MemSubBlock[i].MemType == VPU_MEM_PHY)
+		{
+			*alignment = mem_info.MemSubBlock[i].nAlignment;
+			*size = mem_info.MemSubBlock[i].nSize;
+			IMX_VPU_TRACE("determined alignment %d and size %d for the physical memory for the bitstream buffer", *alignment, *size);
+			break;
+		}
+	}
+
+	/* virtual memory block is allocated internally inside imx_vpu_dec_open() */
+}
+
+
+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_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_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_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_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;
+}
+
+
+void imx_vpu_dec_calc_framebuffer_sizes(ImxVpuDecInitialInfo const *initial_info, unsigned int *frame_width, unsigned int *frame_height, unsigned int *y_stride, unsigned int *uv_stride, unsigned int *y_size, unsigned int *uv_size, unsigned int *mvcol_size, unsigned int *total_size)
+{
+	int alignment;
+
+	*frame_width = IMX_VPU_ALIGN_VAL_TO(*frame_width, FRAME_ALIGN);
+	if (initial_info->interlacing)
+		*frame_height = IMX_VPU_ALIGN_VAL_TO(*frame_height, (2 * FRAME_ALIGN));
+	else
+		*frame_height = IMX_VPU_ALIGN_VAL_TO(*frame_height, FRAME_ALIGN);
+
+	*y_stride = *frame_width;
+	*y_size = (*y_stride) * (*frame_height);
+
+	switch (initial_info->mjpeg_source_format)
+	{
+		case IMX_VPU_MJPEG_FORMAT_YUV420:
+			*uv_stride = *y_stride / 2;
+			*uv_size = *mvcol_size = *y_size / 4;
+			break;
+		case IMX_VPU_MJPEG_FORMAT_YUV422_HORIZONTAL:
+			*uv_stride = *y_stride / 2;
+			*uv_size = *mvcol_size = *y_size / 2;
+			break;
+		case IMX_VPU_MJPEG_FORMAT_YUV444:
+			*uv_stride = *y_stride;
+			*uv_size = *mvcol_size = *y_size;
+			break;
+		case IMX_VPU_MJPEG_FORMAT_YUV400:
+			/* TODO: check if this is OK */
+			*uv_stride = 0;
+			*uv_size = *mvcol_size = 0;
+			break;
+		default:
+			assert(FALSE);
+	}
+
+	alignment = initial_info->framebuffer_alignment;
+	if (alignment > 1)
+	{
+		*y_size = IMX_VPU_ALIGN_VAL_TO(*y_size, alignment);
+		*uv_size = IMX_VPU_ALIGN_VAL_TO(*uv_size, alignment);
+		*mvcol_size = IMX_VPU_ALIGN_VAL_TO(*mvcol_size, alignment);
+	}
+
+	*total_size = *y_size + *uv_size + *uv_size + *mvcol_size + alignment;
+}
+
+
+ImxVpuDecReturnCodes imx_vpu_dec_get_initial_info(ImxVpuDecoder *decoder, ImxVpuDecInitialInfo *info)
+{
+	VpuDecRetCode ret;
+	VpuDecInitInfo init_info;
+
+	ret = VPU_DecGetInitialInfo(decoder->handle, &init_info);
+	IMX_VPU_LOG("VPU_DecGetInitialInfo: min num framebuffers required: %d", init_info.nMinFrameBufferCount);
+	dec_convert_from_wrapper_initial_info(&init_info, info);
+	return dec_convert_retcode(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_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;
+}
+
+
+void* imx_vpu_dec_get_dropped_frame_user_data(ImxVpuDecoder *decoder)
+{
+	return decoder->dropped_frame_user_data;
+}
+
+
+int imx_vpu_dec_get_num_free_framebuffers(ImxVpuDecoder *decoder)
+{
+	return decoder->num_available_framebuffers;
+}
+
+
+int imx_vpu_dec_get_min_num_free_required(ImxVpuDecoder *decoder)
+{
+	IMXVPUCODEC_UNUSED_PARAM(decoder);
+	return MIN_NUM_FREE_FB_REQUIRED;
+}
+
+
+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;
+}
+
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpucodec_platform.h
@@ -0,0 +1,35 @@
+/*
+ * imxvpucodec - i.MX6 VPU hardware codec engine API library
+ * Copyright (c) 2014 Carlos Rafael Giani
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any
+ * damages arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software. If you use this
+ *    software in a product, an acknowledgment in the product
+ *    documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+
+#ifndef IMXVPUCODEC_PLATFORM_H
+#define IMXVPUCODEC_PLATFORM_H
+
+
+#define IMXVPUCODEC_UNUSED_PARAM(x) ((void)(x))
+
+
+#include "imxvpucodec_platform_chromium.h"
+
+
+#endif
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpucodec_platform_chromium.cc
@@ -0,0 +1,40 @@
+#include "imxvpucodec_platform_chromium.h"
+#include "base/logging.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void imx_vpu_log(ImxVpuLogLevel level, char const *file, int const line, char const *fn, const char * format, ...)
+{
+	va_list args;
+	char buf[500];
+
+	va_start(args, format);
+	vsnprintf(buf, sizeof(buf), format, args);
+	va_end(args);
+
+	#define DO_LOG(severity) do { LOG(severity) << file << ":" << line << " (" << fn << ")  " << buf; } while(0)
+	#define DO_VLOG(severity) do { VLOG(severity) << file << ":" << line << " (" << fn << ")  " << buf; } while(0)
+
+	switch (level)
+	{
+		case IMX_VPU_LOG_LEVEL_ERROR: DO_LOG(ERROR); break;
+		case IMX_VPU_LOG_LEVEL_WARNING: DO_LOG(WARNING); break;
+		case IMX_VPU_LOG_LEVEL_INFO: DO_LOG(INFO); break;
+		case IMX_VPU_LOG_LEVEL_DEBUG: DO_VLOG(0); break;
+		case IMX_VPU_LOG_LEVEL_LOG: DO_VLOG(1); break;
+		case IMX_VPU_LOG_LEVEL_TRACE: DO_VLOG(2); break;
+		default: break;
+	}
+}
+
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+++ chromium-browser-40.0.2214.111/content/common/gpu/media/imxvpucodec_platform_chromium.h
@@ -0,0 +1,71 @@
+/*
+ * imxvpucodec - i.MX6 VPU hardware codec engine API library
+ * Copyright (c) 2014 Carlos Rafael Giani
+ * 
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any
+ * damages arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software. If you use this
+ *    software in a product, an acknowledgment in the product
+ *    documentation would be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+
+#ifndef IMXVPUCODEC_PLATFORM_CHROMIUM_H
+#define IMXVPUCODEC_PLATFORM_CHROMIUM_H
+
+
+#include <stdlib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define IMX_VPU_ALLOC(SIZE) malloc(SIZE)
+#define IMX_VPU_FREE(PTR, SIZE) free(PTR)
+
+
+#define IMX_VPU_ERROR(...)   imx_vpu_log(IMX_VPU_LOG_LEVEL_ERROR,   __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+#define IMX_VPU_WARNING(...) imx_vpu_log(IMX_VPU_LOG_LEVEL_WARNING, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+#define IMX_VPU_INFO(...)    imx_vpu_log(IMX_VPU_LOG_LEVEL_INFO,    __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+#define IMX_VPU_DEBUG(...)   imx_vpu_log(IMX_VPU_LOG_LEVEL_DEBUG,   __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+#define IMX_VPU_LOG(...)     imx_vpu_log(IMX_VPU_LOG_LEVEL_LOG,     __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+#define IMX_VPU_TRACE(...)   imx_vpu_log(IMX_VPU_LOG_LEVEL_TRACE,   __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
+
+
+typedef enum
+{
+	IMX_VPU_LOG_LEVEL_ERROR = 0,
+	IMX_VPU_LOG_LEVEL_WARNING,
+	IMX_VPU_LOG_LEVEL_INFO,
+	IMX_VPU_LOG_LEVEL_DEBUG,
+	IMX_VPU_LOG_LEVEL_LOG,
+	IMX_VPU_LOG_LEVEL_TRACE
+}
+ImxVpuLogLevel;
+
+
+void imx_vpu_log(ImxVpuLogLevel level, char const *file, int const line, char const *fn, const char * format, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+
