Index: content/common/gpu/media/tegra_v4l2_video_device.cc |
diff --git a/content/common/gpu/media/tegra_v4l2_video_device.cc b/content/common/gpu/media/tegra_v4l2_video_device.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b042a28ccdc5ded313269c37fa2e3158a6eef68b |
--- /dev/null |
+++ b/content/common/gpu/media/tegra_v4l2_video_device.cc |
@@ -0,0 +1,188 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <dlfcn.h> |
+#include <fcntl.h> |
+#include <linux/videodev2.h> |
+ |
+#include "base/debug/trace_event.h" |
+#include "base/lazy_instance.h" |
+#include "base/posix/eintr_wrapper.h" |
+#include "content/common/gpu/media/tegra_v4l2_video_device.h" |
+#include "ui/gl/gl_bindings.h" |
+ |
+namespace content { |
+ |
+namespace { |
+const char kDevice[] = "/dev/tegra_avpchannel"; |
+} |
+ |
+typedef int32 (*TegraV4L2Open)(const char* name, int32 flags); |
+typedef int32 (*TegraV4L2Close)(int32 fd); |
+typedef int32 (*TegraV4L2Ioctl)(int32 fd, unsigned long cmd, ...); |
+typedef int32 (*TegraV4L2Poll)(int32 fd, bool poll_device, bool* event_pending); |
+typedef int32 (*TegraV4L2SetDevicePollInterrupt)(int32 fd); |
+typedef int32 (*TegraV4L2ClearDevicePollInterrupt)(int32 fd); |
+typedef void* (*TegraV4L2Mmap)(void* addr, |
+ size_t length, |
+ int prot, |
+ int flags, |
+ int fd, |
+ unsigned int offset); |
+typedef int32 (*TegraV4L2Munmap)(void* addr, size_t length); |
+typedef int32 (*TegraV4L2UseEglImage)(int fd, |
+ unsigned int buffer_index, |
+ void* egl_image); |
+ |
+#define TEGRAV4L2_SYM(name) TegraV4L2##name TegraV4L2_##name = NULL |
+ |
+TEGRAV4L2_SYM(Open); |
+TEGRAV4L2_SYM(Close); |
+TEGRAV4L2_SYM(Ioctl); |
+TEGRAV4L2_SYM(Poll); |
+TEGRAV4L2_SYM(SetDevicePollInterrupt); |
+TEGRAV4L2_SYM(ClearDevicePollInterrupt); |
+TEGRAV4L2_SYM(Mmap); |
+TEGRAV4L2_SYM(Munmap); |
+TEGRAV4L2_SYM(UseEglImage); |
+ |
+#undef TEGRAV4L2_SYM |
+ |
+class TegraFunctionSymbolFinder { |
+ public: |
+ TegraFunctionSymbolFinder() : initialized_(false) { |
+ if (!dlopen("/usr/lib/libtegrav4l2.so", |
+ RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE)) { |
+ DLOG(ERROR) << "Failed to load libtegrav4l2.so "; |
+ return; |
+ } |
+#define TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(name) \ |
+ do { \ |
+ TegraV4L2_##name = reinterpret_cast<TegraV4L2##name>( \ |
+ dlsym(RTLD_DEFAULT, "TegraV4L2_" #name)); \ |
+ if (TegraV4L2_##name == NULL) { \ |
+ LOG(ERROR) << "Failed to dlsym TegraV4L2_" #name; \ |
+ return; \ |
+ } \ |
+ } while (0) |
+ |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Open); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Close); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Ioctl); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Poll); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(SetDevicePollInterrupt); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(ClearDevicePollInterrupt); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Mmap); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(Munmap); |
+ TEGRAV4L2_DLSYM_OR_RETURN_ON_ERROR(UseEglImage); |
+#undef TEGRAV4L2_DLSYM |
+ initialized_ = true; |
+ } |
Ami GONE FROM CHROMIUM
2014/03/29 08:23:51
nit: newline after this
shivdasp
2014/03/29 17:47:37
Done.
|
+ bool Initialized() { return initialized_; } |
Ami GONE FROM CHROMIUM
2014/03/29 08:23:51
nit: simple accessors are typically lowercased:
b
shivdasp
2014/03/29 17:47:37
Done.
|
+ |
+ private: |
+ bool initialized_; |
+}; |
+ |
+base::LazyInstance<TegraFunctionSymbolFinder> g_tegra_function_symbol_finder_ = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+TegraV4L2Device::TegraV4L2Device(EGLContext egl_context) |
+ : device_fd_(-1), egl_context_(egl_context) {} |
+ |
+TegraV4L2Device::~TegraV4L2Device() { |
+ if (device_fd_ != -1) { |
+ TegraV4L2_Close(device_fd_); |
+ device_fd_ = -1; |
+ } |
+} |
+ |
+int TegraV4L2Device::Ioctl(int flags, void* arg) { |
+ return TegraV4L2_Ioctl(device_fd_, flags, arg); |
+} |
+ |
+bool TegraV4L2Device::Poll(bool poll_device, bool* event_pending) { |
+ if (HANDLE_EINTR(TegraV4L2_Poll(device_fd_, poll_device, event_pending)) == |
+ -1) { |
+ DLOG(ERROR) << "TegraV4L2Poll returned -1 "; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+void* TegraV4L2Device::Mmap(void* addr, |
+ unsigned int len, |
+ int prot, |
+ int flags, |
+ unsigned int offset) { |
+ return TegraV4L2_Mmap(addr, len, prot, flags, device_fd_, offset); |
+} |
+ |
+void TegraV4L2Device::Munmap(void* addr, unsigned int len) { |
+ TegraV4L2_Munmap(addr, len); |
+} |
+ |
+bool TegraV4L2Device::SetDevicePollInterrupt() { |
+ if (HANDLE_EINTR(TegraV4L2_SetDevicePollInterrupt(device_fd_)) == -1) { |
+ DLOG(ERROR) << "Error in calling TegraV4L2SetDevicePollInterrupt"; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool TegraV4L2Device::ClearDevicePollInterrupt() { |
+ if (HANDLE_EINTR(TegraV4L2_ClearDevicePollInterrupt(device_fd_)) == -1) { |
+ DLOG(ERROR) << "Error in calling TegraV4L2ClearDevicePollInterrupt"; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+bool TegraV4L2Device::Initialize() { |
+ if (!g_tegra_function_symbol_finder_.Get().Initialized()) { |
+ DLOG(ERROR) << "Unable to initialize functions "; |
+ return false; |
+ } |
+ device_fd_ = |
+ HANDLE_EINTR(TegraV4L2_Open(kDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC)); |
+ if (device_fd_ == -1) { |
+ DLOG(ERROR) << "Unable to open tegra_v4l2_open "; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+EGLImageKHR TegraV4L2Device::CreateEGLImage(EGLDisplay egl_display, |
+ GLuint texture_id, |
+ gfx::Size /* frame_buffer_size */, |
+ unsigned int buffer_index, |
+ size_t /* planes_count */) { |
+ DVLOG(3) << "CreateEGLImage()"; |
+ EGLint attr = EGL_NONE; |
+ EGLImageKHR egl_image = |
+ eglCreateImageKHR(egl_display, |
+ egl_context_, |
+ EGL_GL_TEXTURE_2D_KHR, |
+ reinterpret_cast<EGLClientBuffer>(texture_id), |
+ &attr); |
+ if (egl_image == EGL_NO_IMAGE_KHR) { |
+ return egl_image; |
+ } |
+ if (TegraV4L2_UseEglImage(device_fd_, buffer_index, egl_image) != 0) { |
+ eglDestroyImageKHR(egl_display, egl_image); |
+ egl_image = EGL_NO_IMAGE_KHR; |
+ } |
+ return egl_image; |
+} |
+ |
+EGLBoolean TegraV4L2Device::DestroyEGLImage(EGLDisplay egl_display, |
+ EGLImageKHR egl_image) { |
+ return eglDestroyImageKHR(egl_display, egl_image); |
+} |
+ |
+GLenum TegraV4L2Device::GetTextureTarget() { return GL_TEXTURE_2D; } |
+ |
+uint32 TegraV4L2Device::PreferredOutputFormat() { return V4L2_PIX_FMT_NV12M; } |
+ |
+} // namespace content |