Home | History | Annotate | Download | only in media
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 
      6 #include <fcntl.h>
      7 #include <libdrm/drm_fourcc.h>
      8 #include <linux/videodev2.h>
      9 #include <poll.h>
     10 #include <sys/eventfd.h>
     11 #include <sys/ioctl.h>
     12 #include <sys/mman.h>
     13 
     14 #include "base/debug/trace_event.h"
     15 #include "base/files/scoped_file.h"
     16 #include "base/posix/eintr_wrapper.h"
     17 #include "content/common/gpu/media/exynos_v4l2_video_device.h"
     18 #include "ui/gl/gl_bindings.h"
     19 
     20 namespace content {
     21 
     22 namespace {
     23 const char kDecoderDevice[] = "/dev/mfc-dec";
     24 const char kEncoderDevice[] = "/dev/mfc-enc";
     25 const char kImageProcessorDevice[] = "/dev/gsc1";
     26 }
     27 
     28 ExynosV4L2Device::ExynosV4L2Device(Type type)
     29     : type_(type),
     30       device_fd_(-1),
     31       device_poll_interrupt_fd_(-1) {}
     32 
     33 ExynosV4L2Device::~ExynosV4L2Device() {
     34   if (device_poll_interrupt_fd_ != -1) {
     35     close(device_poll_interrupt_fd_);
     36     device_poll_interrupt_fd_ = -1;
     37   }
     38   if (device_fd_ != -1) {
     39     close(device_fd_);
     40     device_fd_ = -1;
     41   }
     42 }
     43 
     44 int ExynosV4L2Device::Ioctl(int request, void* arg) {
     45   return HANDLE_EINTR(ioctl(device_fd_, request, arg));
     46 }
     47 
     48 bool ExynosV4L2Device::Poll(bool poll_device, bool* event_pending) {
     49   struct pollfd pollfds[2];
     50   nfds_t nfds;
     51   int pollfd = -1;
     52 
     53   pollfds[0].fd = device_poll_interrupt_fd_;
     54   pollfds[0].events = POLLIN | POLLERR;
     55   nfds = 1;
     56 
     57   if (poll_device) {
     58     DVLOG(3) << "Poll(): adding device fd to poll() set";
     59     pollfds[nfds].fd = device_fd_;
     60     pollfds[nfds].events = POLLIN | POLLOUT | POLLERR | POLLPRI;
     61     pollfd = nfds;
     62     nfds++;
     63   }
     64 
     65   if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
     66     DPLOG(ERROR) << "poll() failed";
     67     return false;
     68   }
     69   *event_pending = (pollfd != -1 && pollfds[pollfd].revents & POLLPRI);
     70   return true;
     71 }
     72 
     73 void* ExynosV4L2Device::Mmap(void* addr,
     74                              unsigned int len,
     75                              int prot,
     76                              int flags,
     77                              unsigned int offset) {
     78   return mmap(addr, len, prot, flags, device_fd_, offset);
     79 }
     80 
     81 void ExynosV4L2Device::Munmap(void* addr, unsigned int len) {
     82   munmap(addr, len);
     83 }
     84 
     85 bool ExynosV4L2Device::SetDevicePollInterrupt() {
     86   DVLOG(3) << "SetDevicePollInterrupt()";
     87 
     88   const uint64 buf = 1;
     89   if (HANDLE_EINTR(write(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) {
     90     DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
     91     return false;
     92   }
     93   return true;
     94 }
     95 
     96 bool ExynosV4L2Device::ClearDevicePollInterrupt() {
     97   DVLOG(3) << "ClearDevicePollInterrupt()";
     98 
     99   uint64 buf;
    100   if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) == -1) {
    101     if (errno == EAGAIN) {
    102       // No interrupt flag set, and we're reading nonblocking.  Not an error.
    103       return true;
    104     } else {
    105       DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
    106       return false;
    107     }
    108   }
    109   return true;
    110 }
    111 
    112 bool ExynosV4L2Device::Initialize() {
    113   const char* device_path = NULL;
    114   switch (type_) {
    115     case kDecoder:
    116       device_path = kDecoderDevice;
    117       break;
    118     case kEncoder:
    119       device_path = kEncoderDevice;
    120       break;
    121     case kImageProcessor:
    122       device_path = kImageProcessorDevice;
    123       break;
    124   }
    125 
    126   DVLOG(2) << "Initialize(): opening device: " << device_path;
    127   // Open the video device.
    128   device_fd_ = HANDLE_EINTR(open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC));
    129   if (device_fd_ == -1) {
    130     return false;
    131   }
    132 
    133   device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    134   if (device_poll_interrupt_fd_ == -1) {
    135     return false;
    136   }
    137   return true;
    138 }
    139 
    140 EGLImageKHR ExynosV4L2Device::CreateEGLImage(EGLDisplay egl_display,
    141                                              EGLContext /* egl_context */,
    142                                              GLuint texture_id,
    143                                              gfx::Size frame_buffer_size,
    144                                              unsigned int buffer_index,
    145                                              size_t planes_count) {
    146   DVLOG(3) << "CreateEGLImage()";
    147 
    148   scoped_ptr<base::ScopedFD[]> dmabuf_fds(new base::ScopedFD[planes_count]);
    149   for (size_t i = 0; i < planes_count; ++i) {
    150     // Export the DMABUF fd so we can export it as a texture.
    151     struct v4l2_exportbuffer expbuf;
    152     memset(&expbuf, 0, sizeof(expbuf));
    153     expbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    154     expbuf.index = buffer_index;
    155     expbuf.plane = i;
    156     expbuf.flags = O_CLOEXEC;
    157     if (Ioctl(VIDIOC_EXPBUF, &expbuf) != 0) {
    158       return EGL_NO_IMAGE_KHR;
    159     }
    160     dmabuf_fds[i].reset(expbuf.fd);
    161   }
    162   DCHECK_EQ(planes_count, 2u);
    163   EGLint attrs[] = {
    164       EGL_WIDTH,                     0, EGL_HEIGHT,                    0,
    165       EGL_LINUX_DRM_FOURCC_EXT,      0, EGL_DMA_BUF_PLANE0_FD_EXT,     0,
    166       EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT,  0,
    167       EGL_DMA_BUF_PLANE1_FD_EXT,     0, EGL_DMA_BUF_PLANE1_OFFSET_EXT, 0,
    168       EGL_DMA_BUF_PLANE1_PITCH_EXT,  0, EGL_NONE, };
    169   attrs[1] = frame_buffer_size.width();
    170   attrs[3] = frame_buffer_size.height();
    171   attrs[5] = DRM_FORMAT_NV12;
    172   attrs[7] = dmabuf_fds[0].get();
    173   attrs[9] = 0;
    174   attrs[11] = frame_buffer_size.width();
    175   attrs[13] = dmabuf_fds[1].get();
    176   attrs[15] = 0;
    177   attrs[17] = frame_buffer_size.width();
    178 
    179   EGLImageKHR egl_image = eglCreateImageKHR(
    180       egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attrs);
    181   if (egl_image == EGL_NO_IMAGE_KHR) {
    182     return egl_image;
    183   }
    184   glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
    185   glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
    186 
    187   return egl_image;
    188 }
    189 
    190 EGLBoolean ExynosV4L2Device::DestroyEGLImage(EGLDisplay egl_display,
    191                                              EGLImageKHR egl_image) {
    192   return eglDestroyImageKHR(egl_display, egl_image);
    193 }
    194 
    195 GLenum ExynosV4L2Device::GetTextureTarget() { return GL_TEXTURE_EXTERNAL_OES; }
    196 
    197 uint32 ExynosV4L2Device::PreferredInputFormat() {
    198   // TODO(posciak): We should support "dontcare" returns here once we
    199   // implement proper handling (fallback, negotiation) for this in users.
    200   CHECK_EQ(type_, kEncoder);
    201   return V4L2_PIX_FMT_NV12M;
    202 }
    203 
    204 uint32 ExynosV4L2Device::PreferredOutputFormat() {
    205   // TODO(posciak): We should support "dontcare" returns here once we
    206   // implement proper handling (fallback, negotiation) for this in users.
    207   CHECK_EQ(type_, kDecoder);
    208   return V4L2_PIX_FMT_NV12M;
    209 }
    210 
    211 }  //  namespace content
    212