[meta-freescale] [PATCH 1/3] Add Chromium patches for VPU-based video decoding
Carlos Rafael Giani
dv at pseudoterminal.org
Tue Jun 3 15:22:31 PDT 2014
IMPORTANT: this was sent accidentally. It is a very early stage, and is
not to be used. It has several problems, relies on the older Chromium
version, and contains severe hacks.
> Signed-off-by: Carlos Rafael Giani <dv at pseudoterminal.org>
> ---
> ...-imxvpu-decode-accelerator-to-content-gyp.patch | 64 +
> ...0002-add-imxvpu-to-gpu-decode-accelerator.patch | 31 +
> ...3-remove-linux-video-accel-from-blacklist.patch | 44 +
> .../chromium/add-imx-vpu-decode-accel-src.patch | 2559 ++++++++++++++++++++
> .../chromium/chromium_35.0.1883.0.bbappend | 15 +
> 5 files changed, 2713 insertions(+)
> create mode 100644 recipes-browser/chromium/chromium/0001-add-imxvpu-decode-accelerator-to-content-gyp.patch
> create mode 100644 recipes-browser/chromium/chromium/0002-add-imxvpu-to-gpu-decode-accelerator.patch
> create mode 100644 recipes-browser/chromium/chromium/0003-remove-linux-video-accel-from-blacklist.patch
> create mode 100644 recipes-browser/chromium/chromium/add-imx-vpu-decode-accel-src.patch
> create mode 100644 recipes-browser/chromium/chromium_35.0.1883.0.bbappend
>
> diff --git a/recipes-browser/chromium/chromium/0001-add-imxvpu-decode-accelerator-to-content-gyp.patch b/recipes-browser/chromium/chromium/0001-add-imxvpu-decode-accelerator-to-content-gyp.patch
> new file mode 100644
> index 0000000..5ac5d74
> --- /dev/null
> +++ b/recipes-browser/chromium/chromium/0001-add-imxvpu-decode-accelerator-to-content-gyp.patch
> @@ -0,0 +1,64 @@
> +Introduces a GPU video decode accelerator wrapper for the i.MX VPU
> +Requires EGL/OpenGL ES , since it makes use of Vivante direct textures
> +
> +Upstream-Status: Inappropriate [other]
> +Chromium developers currently do not accept patches for video accel in Linux
> +
> +Signed-off-by: Carlos Rafael Giani <carlos.giani at streamunlimited.com>
> +
> +diff --git a/content/content.gyp b/content/content.gyp
> +index 73f8625..50d7c1f 100644
> +--- a/content/content.gyp
> ++++ b/content/content.gyp
> +@@ -7,6 +7,7 @@
> + 'chromium_code': 1, # Use higher warning level.
> + 'chromium_enable_vtune_jit_for_v8%': 0, # enable the vtune support for V8 engine.
> + 'directxsdk_exists': '<!(python <(DEPTH)/build/dir_exists.py ../third_party/directxsdk)',
> ++ 'imx_platform%': 1,
> + },
> + 'target_defaults': {
> + 'defines': ['CONTENT_IMPLEMENTATION'],
> +diff --git a/content/content_common.gypi b/content/content_common.gypi
> +index 2a23d52..2f0b552 100644
> +--- a/content/content_common.gypi
> ++++ b/content/content_common.gypi
> +@@ -617,6 +617,39 @@
> + '<(DEPTH)/third_party/khronos',
> + ],
> + }],
> ++ ['target_arch == "arm" and imx_platform == 1', {
> ++ 'variables': {
> ++ 'conditions': [
> ++ ['sysroot!=""', {
> ++ 'pkg-config': '../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)"',
> ++ }, {
> ++ 'pkg-config': 'pkg-config'
> ++ }],
> ++ ],
> ++ },
> ++ 'sources': [
> ++ 'common/gpu/media/imxvpucodec_fslwrapper.c',
> ++ 'common/gpu/media/imxvpucodec.h',
> ++ 'common/gpu/media/imxvpucodec_platform_chromium.cc',
> ++ 'common/gpu/media/imxvpucodec_platform_chromium.h',
> ++ 'common/gpu/media/imxvpucodec_platform.h',
> ++ 'common/gpu/media/imxvpu_video_decode_accelerator.cc',
> ++ 'common/gpu/media/imxvpu_video_decode_accelerator.h',
> ++ ],
> ++ 'defines': ['IMX_PLATFORM'],
> ++ 'cflags': [
> ++ '<!@(<(pkg-config) --cflags libfslvpuwrap)',
> ++ ],
> ++ 'link_settings': {
> ++ 'libraries': [
> ++ # TODO: -lEGL and -lGLESv2 are temporary until the vivante direct texture
> ++ # extension is fully integrated into the Chromium GL command buffer
> ++ '-lEGL',
> ++ '-lGLESv2',
> ++ '<!@(<(pkg-config) --libs libfslvpuwrap)',
> ++ ],
> ++ },
> ++ }],
> + ['OS=="win" and directxsdk_exists=="True"', {
> + 'actions': [
> + {
> diff --git a/recipes-browser/chromium/chromium/0002-add-imxvpu-to-gpu-decode-accelerator.patch b/recipes-browser/chromium/chromium/0002-add-imxvpu-to-gpu-decode-accelerator.patch
> new file mode 100644
> index 0000000..832e16b
> --- /dev/null
> +++ b/recipes-browser/chromium/chromium/0002-add-imxvpu-to-gpu-decode-accelerator.patch
> @@ -0,0 +1,31 @@
> +This is necessary to make the GPU process use the imxvpu video
> +decode accelerator (otherwise it will use software decoding)
> +
> +Upstream-Status: Inappropriate [other]
> +Chromium developers currently do not accept patches for video accel in Linux
> +
> +Signed-off-by: Carlos Rafael Giani <carlos.giani at streamunlimited.com>
> +
> +--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
> ++++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
> +@@ -34,6 +34,8 @@
> + #include "ui/gl/gl_implementation.h"
> + #elif defined(OS_ANDROID)
> + #include "content/common/gpu/media/android_video_decode_accelerator.h"
> ++#elif defined(IMX_PLATFORM)
> ++#include "content/common/gpu/media/imxvpu_video_decode_accelerator.h"
> + #endif
> +
> + #include "ui/gfx/size.h"
> +@@ -299,6 +301,11 @@ void GpuVideoDecodeAccelerator::Initialize(
> + video_decode_accelerator_.reset(new AndroidVideoDecodeAccelerator(
> + stub_->decoder()->AsWeakPtr(),
> + make_context_current_));
> ++#elif defined(IMX_PLATFORM)
> ++ VLOG(1) << "Using the i.MX6 VPU decode accelerator";
> ++ video_decode_accelerator_.reset(new ImxVpuVideoDecodeAccelerator(
> ++ stub_->decoder()->AsWeakPtr(),
> ++ make_context_current_));
> + #else
> + NOTIMPLEMENTED() << "HW video decode acceleration not available.";
> + NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
> diff --git a/recipes-browser/chromium/chromium/0003-remove-linux-video-accel-from-blacklist.patch b/recipes-browser/chromium/chromium/0003-remove-linux-video-accel-from-blacklist.patch
> new file mode 100644
> index 0000000..849e4bb
> --- /dev/null
> +++ b/recipes-browser/chromium/chromium/0003-remove-linux-video-accel-from-blacklist.patch
> @@ -0,0 +1,44 @@
> +Currently, video decode acceleration is disabled in Linux, due to problems with
> +VA-API, VDPAU etc. Removing this entry from the blacklist enables it again
> +
> +Upstream-Status: Inappropriate [other]
> +Chromium developers currently do not accept patches for video accel in Linux
> +
> +Signed-off-by: Carlos Rafael Giani <carlos.giani at streamunlimited.com>
> +
> +diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
> +index 4bd6ef5..cf790d3 100644
> +--- a/gpu/config/software_rendering_list_json.cc
> ++++ b/gpu/config/software_rendering_list_json.cc
> +@@ -481,31 +481,6 @@ const char kSoftwareRenderingListJson[] = LONG_STRING_CONST(
> + ]
> + },
> + {
> +- "id": 48,
> +- "description": "Accelerated video decode is unavailable on Mac and Linux",
> +- "cr_bugs": [137247, 133828],
> +- "exceptions": [
> +- {
> +- "os": {
> +- "type": "chromeos"
> +- }
> +- },
> +- {
> +- "os": {
> +- "type": "win"
> +- }
> +- },
> +- {
> +- "os": {
> +- "type": "android"
> +- }
> +- }
> +- ],
> +- "features": [
> +- "accelerated_video_decode"
> +- ]
> +- },
> +- {
> + "id": 49,
> + "description": "NVidia GeForce GT 650M can cause the system to hang with flash 3D",
> + "cr_bugs": [140175],
> diff --git a/recipes-browser/chromium/chromium/add-imx-vpu-decode-accel-src.patch b/recipes-browser/chromium/chromium/add-imx-vpu-decode-accel-src.patch
> new file mode 100644
> index 0000000..1385165
> --- /dev/null
> +++ b/recipes-browser/chromium/chromium/add-imx-vpu-decode-accel-src.patch
> @@ -0,0 +1,2559 @@
> +From 151da43ee4327e45fd48e71c823e2e4cd178f7c1 Mon Sep 17 00:00:00 2001
> +From: Carlos Rafael Giani <dv at pseudoterminal.org>
> +Date: Fri, 16 May 2014 20:40:17 +0200
> +Subject: [PATCH] Add imx vpu decode accelerator sources
> +
> +Signed-off-by: Carlos Rafael Giani <dv at pseudoterminal.org>
> +---
> + .../common/gpu/media/imx_gl_viv_direct_texture.h | 47 +
> + .../gpu/media/imxvpu_video_decode_accelerator.cc | 732 ++++++++++++++
> + .../gpu/media/imxvpu_video_decode_accelerator.h | 110 +++
> + content/common/gpu/media/imxvpucodec.h | 418 ++++++++
> + content/common/gpu/media/imxvpucodec_fslwrapper.c | 1030 ++++++++++++++++++++
> + content/common/gpu/media/imxvpucodec_platform.h | 35 +
> + .../gpu/media/imxvpucodec_platform_chromium.cc | 40 +
> + .../gpu/media/imxvpucodec_platform_chromium.h | 71 ++
> + 8 files changed, 2483 insertions(+)
> + create mode 100644 content/common/gpu/media/imx_gl_viv_direct_texture.h
> + create mode 100644 content/common/gpu/media/imxvpu_video_decode_accelerator.cc
> + create mode 100644 content/common/gpu/media/imxvpu_video_decode_accelerator.h
> + create mode 100644 content/common/gpu/media/imxvpucodec.h
> + create mode 100644 content/common/gpu/media/imxvpucodec_fslwrapper.c
> + create mode 100644 content/common/gpu/media/imxvpucodec_platform.h
> + create mode 100644 content/common/gpu/media/imxvpucodec_platform_chromium.cc
> + create mode 100644 content/common/gpu/media/imxvpucodec_platform_chromium.h
> +
> +diff --git a/content/common/gpu/media/imx_gl_viv_direct_texture.h b/content/common/gpu/media/imx_gl_viv_direct_texture.h
> +new file mode 100644
> +index 0000000..53f0be5
> +--- /dev/null
> ++++ b/content/common/gpu/media/imx_gl_viv_direct_texture.h
> +@@ -0,0 +1,47 @@
> ++#ifndef IMX_GL_VIV_DIRECT_TEXTURE_H
> ++#define IMX_GL_VIV_DIRECT_TEXTURE_H
> ++
> ++#include "ui/gl/gl_bindings.h"
> ++
> ++
> ++#ifdef __cplusplus
> ++extern "C" {
> ++#endif
> ++
> ++
> ++/* 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
> ++
> ++
> ++/* GL_VIV_direct_texture */
> ++#ifndef GL_VIV_direct_texture
> ++#define GL_VIV_direct_texture 1
> ++GL_APICALL void GL_APIENTRY glTexDirectVIVMap(GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical);
> ++GL_APICALL void GL_APIENTRY glTexDirectVIV (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Pixels);
> ++GL_APICALL void GL_APIENTRY glTexDirectInvalidateVIV (GLenum Target);
> ++GL_APICALL void GL_APIENTRY glTexDirectTiledMapVIV (GLenum Target, GLsizei Width, GLsizei Height, GLenum Format, GLvoid ** Logical, const GLuint * Physical);
> ++#endif
> ++
> ++
> ++#ifdef __cplusplus
> ++}
> ++#endif
> ++
> ++
> ++#endif
> +diff --git a/content/common/gpu/media/imxvpu_video_decode_accelerator.cc b/content/common/gpu/media/imxvpu_video_decode_accelerator.cc
> +new file mode 100644
> +index 0000000..a764acd
> +--- /dev/null
> ++++ b/content/common/gpu/media/imxvpu_video_decode_accelerator.cc
> +@@ -0,0 +1,732 @@
> ++#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"
> ++
> ++
> ++#define USE_VIV_DIRECT_TEXTURE
> ++
> ++
> ++#ifdef USE_VIV_DIRECT_TEXTURE
> ++#include "imx_gl_viv_direct_texture.h"
> ++#endif
> ++
> ++
> ++namespace content
> ++{
> ++
> ++
> ++namespace
> ++{
> ++
> ++
> ++enum { kMaxBitstreamsNotifiedInAdvance = 32 };
> ++
> ++
> ++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)
> ++{
> ++ 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 ((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
> ++ NOTREACHED();
> ++
> ++ 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";
> ++ message_loop_->PostTask(FROM_HERE, base::Bind(&Client::NotifyInitializeDone, client_));
> ++
> ++ 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());
> ++
> ++ base::AutoLock auto_lock(lock_);
> ++
> ++ VLOG(1) << buffers.size() << " picture buffers are being provided by the client";
> ++
> ++ // TODO: is the size of "buffers" always exactly the same size as the one
> ++ // requested in ProvidePictureBuffers? In other words, is
> ++ // buffers.size() always the same as the size of the vpu_framebuffers_ array?
> ++ 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);
> ++
> ++ VLOG(2) << "Associating picture buffer " << i << "/" << buffers.size() << " ID " << id << " with framebuffer";
> ++ }
> ++
> ++ 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);
> ++
> ++ bitstreams_notified_in_advance_.clear();
> ++
> ++ 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;
> ++}
> ++
> ++
> ++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_;
> ++
> ++ // XXX Chromium seems to do frame reordering by itself
> ++ open_params.enable_frame_reordering = (codec_format_ == IMX_VPU_CODEC_FORMAT_H264) ? 1 : 0;
> ++ //open_params.enable_frame_reordering = 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() << " advance size: " << bitstreams_notified_in_advance_.size();
> ++
> ++ //while (true)
> ++ {
> ++ if (bitstreams_notified_in_advance_.size() > kMaxBitstreamsNotifiedInAdvance)
> ++ {
> ++ VLOG(1) << "List of bitstreams notified in advance full - will try again later";
> ++ return;
> ++ }
> ++
> ++ 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;
> ++ }
> ++
> ++ /*if (!input_queue_.empty())
> ++ {
> ++ base::MessageLoop::current()->PostTask(
> ++ FROM_HERE,
> ++ base::Bind(
> ++ &ImxVpuVideoDecodeAccelerator::ProcessQueuedInput,
> ++ base::Unretained(this)
> ++ )
> ++ );
> ++ }*/
> ++}
> ++
> ++
> ++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)
> ++ {
> ++ bitstreams_notified_in_advance_.push_back(input_bitstream_buffer->id());
> ++ 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)
> ++ {
> ++ 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 (!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;
> ++ }
> ++
> ++#if 0
> ++ if (output_code & (IMX_VPU_DEC_OUTPUT_CODE_FRAME_OUTPUT|IMX_VPU_DEC_OUTPUT_CODE_DROPPED))
> ++ {
> ++ VLOG(3) << "Notifying client that bitstream buffer with id " << bitstream_buffer_id << " has been processed";
> ++
> ++ base::MessageLoop::current()->PostTask(
> ++ FROM_HERE,
> ++ base::Bind(
> ++ &Client::NotifyEndOfBitstreamBuffer,
> ++ client_,
> ++ bitstream_buffer_id
> ++ )
> ++ );
> ++ }
> ++#else
> ++#endif
> ++
> ++ 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);
> ++
> ++ GLvoid *virt_addr = output_framebuffer.virtual_address;
> ++#ifdef USE_VIV_DIRECT_TEXTURE
> ++ GLuint phys_addr = reinterpret_cast < GLuint > (output_framebuffer.physical_address);
> ++
> ++ glTexDirectVIVMap(
> ++ GL_TEXTURE_2D,
> ++ aligned_width_, aligned_height_,
> ++ GL_VIV_I420,
> ++ &virt_addr, &phys_addr
> ++ );
> ++ glTexDirectInvalidateVIV(GL_TEXTURE_2D);
> ++#else
> ++ // Fallback for debugging; only copies the first (luma) plane,
> ++ // effectively producing a black&white image
> ++ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, aligned_width_, aligned_height_, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, virt_addr);
> ++#endif
> ++
> ++ 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)
> ++ )
> ++ );
> ++
> ++ {
> ++ for (std::list < int32 > ::iterator iter = bitstreams_notified_in_advance_.begin(); iter != bitstreams_notified_in_advance_.end(); ++iter)
> ++ {
> ++ if ((*iter) == input_bitstream_buffer_id)
> ++ {
> ++ bitstreams_notified_in_advance_.erase(bitstreams_notified_in_advance_.begin(), ++iter);
> ++ }
> ++ }
> ++ }
> ++
> ++ return true;
> ++}
> ++
> ++
> ++} // namespace content
> +diff --git a/content/common/gpu/media/imxvpu_video_decode_accelerator.h b/content/common/gpu/media/imxvpu_video_decode_accelerator.h
> +new file mode 100644
> +index 0000000..13b31e6
> +--- /dev/null
> ++++ b/content/common/gpu/media/imxvpu_video_decode_accelerator.h
> +@@ -0,0 +1,110 @@
> ++#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 "content/common/gpu/media/video_decode_accelerator_impl.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"
> ++
> ++
> ++namespace content
> ++{
> ++
> ++
> ++class CONTENT_EXPORT ImxVpuVideoDecodeAccelerator
> ++ : public VideoDecodeAcceleratorImpl
> ++{
> ++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;
> ++
> ++
> ++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_;
> ++
> ++ base::Lock lock_;
> ++
> ++ typedef std::queue < media::BitstreamBuffer > BitstreamBufferQueue;
> ++ BitstreamBufferQueue input_queue_;
> ++
> ++ typedef std::map < int32, media::PictureBuffer > OutputBufferMap;
> ++ OutputBufferMap output_picture_buffers_;
> ++
> ++ //typedef std::set < int32 > PictureIDSet;
> ++ //PictureIDSet dismissed_picture_ids_, available_picture_ids_;
> ++
> ++ // Keeps track of bitstream ids notified to the client with
> ++ // NotifyEndOfBitstreamBuffer() before getting output from the bitstream.
> ++ std::list<int32> bitstreams_notified_in_advance_;
> ++
> ++ // 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_
> +diff --git a/content/common/gpu/media/imxvpucodec.h b/content/common/gpu/media/imxvpucodec.h
> +new file mode 100644
> +index 0000000..28e3f1d
> +--- /dev/null
> ++++ b/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 *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 *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 *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 *framebuffer);
> ++
> ++
> ++
> ++
> ++#ifdef __cplusplus
> ++}
> ++#endif
> ++
> ++
> ++#endif
> ++
> +diff --git a/content/common/gpu/media/imxvpucodec_fslwrapper.c b/content/common/gpu/media/imxvpucodec_fslwrapper.c
> +new file mode 100644
> +index 0000000..38ec52b
> +--- /dev/null
> ++++ b/content/common/gpu/media/imxvpucodec_fslwrapper.c
> +@@ -0,0 +1,1030 @@
> ++/*
> ++ * 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 *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 *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 *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 *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_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)))
> ++ {
> ++ 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 *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;
> ++}
> ++
> +diff --git a/content/common/gpu/media/imxvpucodec_platform.h b/content/common/gpu/media/imxvpucodec_platform.h
> +new file mode 100644
> +index 0000000..83fe05a
> +--- /dev/null
> ++++ b/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
> +diff --git a/content/common/gpu/media/imxvpucodec_platform_chromium.cc b/content/common/gpu/media/imxvpucodec_platform_chromium.cc
> +new file mode 100644
> +index 0000000..b5e861d
> +--- /dev/null
> ++++ b/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
> +diff --git a/content/common/gpu/media/imxvpucodec_platform_chromium.h b/content/common/gpu/media/imxvpucodec_platform_chromium.h
> +new file mode 100644
> +index 0000000..8803d3a
> +--- /dev/null
> ++++ b/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
> ++
> ++
> +--
> +1.8.3.2
> +
> diff --git a/recipes-browser/chromium/chromium_35.0.1883.0.bbappend b/recipes-browser/chromium/chromium_35.0.1883.0.bbappend
> new file mode 100644
> index 0000000..3caa5b4
> --- /dev/null
> +++ b/recipes-browser/chromium/chromium_35.0.1883.0.bbappend
> @@ -0,0 +1,15 @@
> +FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
> +
> +SRC_URI += "file://add-imx-vpu-decode-accel-src.patch \
> + file://0001-add-imxvpu-decode-accelerator-to-content-gyp.patch \
> + file://0002-add-imxvpu-to-gpu-decode-accelerator.patch \
> + file://0003-remove-linux-video-accel-from-blacklist.patch \
> + "
> +
> +DEPENDS_append_mx6 = " libfslvpuwrap"
> +
> +PACKAGECONFIG_append_mx6 = " component-build use-egl ignore-lost-context"
> +
> +# Necessary flags to enable support for h.264 and MP4 in Chromium
> +# (Parsing is done by ffmpeg)
> +EXTRA_OEGYP += "-Dproprietary_codecs=1 -Dffmpeg_branding=Chrome"
More information about the meta-freescale
mailing list