summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorkaren@chromium.org <karen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-19 19:07:06 +0000
committerkaren@chromium.org <karen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-19 19:07:06 +0000
commit64395b1bec214b57e44bbd7c2aafb5f03483a908 (patch)
tree477c8cfe463cbf387293a78c89eeda501102262f /content
parent5b0b93d9511e272310d4a713d9ca0b293b8966bb (diff)
downloadchromium_src-64395b1bec214b57e44bbd7c2aafb5f03483a908.zip
chromium_src-64395b1bec214b57e44bbd7c2aafb5f03483a908.tar.gz
chromium_src-64395b1bec214b57e44bbd7c2aafb5f03483a908.tar.bz2
Revert 218088 "Merge 217805 "ExynosVideoEncodeAccelerator""
> Merge 217805 "ExynosVideoEncodeAccelerator" > > > ExynosVideoEncodeAccelerator > > > > This is the media::VideoEncodeAccelerator implementation for the Exynos > > platform. > > > > BUG=221441 > > BUG=260210 > > > > TEST=build, run on CrOS snow > > > > Review URL: https://chromiumcodereview.appspot.com/20962003 > > TBR=sheu@chromium.org > > Review URL: https://codereview.chromium.org/23296002 TBR=hshi@chromium.org Review URL: https://codereview.chromium.org/22986012 git-svn-id: svn://svn.chromium.org/chrome/branches/1599/src@218293 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/common/gpu/media/exynos_video_encode_accelerator.cc1476
-rw-r--r--content/common/gpu/media/exynos_video_encode_accelerator.h303
-rw-r--r--content/common/gpu/media/gpu_video_encode_accelerator.cc14
-rw-r--r--content/common/sandbox_seccomp_bpf_linux.cc5
-rw-r--r--content/content_common.gypi2
5 files changed, 2 insertions, 1798 deletions
diff --git a/content/common/gpu/media/exynos_video_encode_accelerator.cc b/content/common/gpu/media/exynos_video_encode_accelerator.cc
deleted file mode 100644
index 572b831..0000000
--- a/content/common/gpu/media/exynos_video_encode_accelerator.cc
+++ /dev/null
@@ -1,1476 +0,0 @@
-// Copyright 2013 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 "content/common/gpu/media/exynos_video_encode_accelerator.h"
-
-#include <fcntl.h>
-#include <linux/videodev2.h>
-#include <poll.h>
-#include <sys/eventfd.h>
-#include <sys/ioctl.h>
-
-#include "base/callback.h"
-#include "base/debug/trace_event.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "base/posix/eintr_wrapper.h"
-#include "media/base/bitstream_buffer.h"
-
-#define NOTIFY_ERROR(x) \
- do { \
- SetEncoderState(kError); \
- DLOG(ERROR) << "calling NotifyError(): " << x; \
- NotifyError(x); \
- } while (0)
-
-#define IOCTL_OR_ERROR_RETURN(fd, type, arg) \
- do { \
- if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
- DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
- NOTIFY_ERROR(kPlatformFailureError); \
- return; \
- } \
- } while (0)
-
-#define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg) \
- do { \
- if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
- DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
- NOTIFY_ERROR(kPlatformFailureError); \
- return false; \
- } \
- } while (0)
-
-namespace content {
-
-namespace {
-
-const char kExynosGscDevice[] = "/dev/gsc1";
-const char kExynosMfcDevice[] = "/dev/mfc-enc";
-
-// File descriptors we need to poll, one-bit flag for each.
-enum PollFds {
- kPollGsc = (1 << 0),
- kPollMfc = (1 << 1),
-};
-
-} // anonymous namespace
-
-struct ExynosVideoEncodeAccelerator::BitstreamBufferRef {
- BitstreamBufferRef(int32 id, scoped_ptr<base::SharedMemory> shm, size_t size)
- : id(id), shm(shm.Pass()), size(size) {}
- const int32 id;
- const scoped_ptr<base::SharedMemory> shm;
- const size_t size;
-};
-
-
-ExynosVideoEncodeAccelerator::GscInputRecord::GscInputRecord()
- : at_device(false) {}
-
-ExynosVideoEncodeAccelerator::GscOutputRecord::GscOutputRecord()
- : at_device(false), mfc_input(-1) {}
-
-ExynosVideoEncodeAccelerator::MfcInputRecord::MfcInputRecord()
- : at_device(false) {
- fd[0] = fd[1] = -1;
-}
-
-ExynosVideoEncodeAccelerator::MfcOutputRecord::MfcOutputRecord()
- : at_device(false) {}
-
-ExynosVideoEncodeAccelerator::ExynosVideoEncodeAccelerator(
- media::VideoEncodeAccelerator::Client* client)
- : child_message_loop_proxy_(base::MessageLoopProxy::current()),
- weak_this_ptr_factory_(this),
- weak_this_(weak_this_ptr_factory_.GetWeakPtr()),
- client_ptr_factory_(client),
- client_(client_ptr_factory_.GetWeakPtr()),
- encoder_thread_("ExynosEncoderThread"),
- encoder_state_(kUninitialized),
- output_buffer_byte_size_(0),
- stream_header_size_(0),
- input_format_fourcc_(0),
- output_format_fourcc_(0),
- gsc_fd_(-1),
- gsc_input_streamon_(false),
- gsc_input_buffer_queued_count_(0),
- gsc_output_streamon_(false),
- gsc_output_buffer_queued_count_(0),
- mfc_fd_(-1),
- mfc_input_streamon_(false),
- mfc_input_buffer_queued_count_(0),
- mfc_output_streamon_(false),
- mfc_output_buffer_queued_count_(0),
- device_poll_thread_("ExynosEncoderDevicePollThread"),
- device_poll_interrupt_fd_(-1) {
- DCHECK(client_);
-}
-
-ExynosVideoEncodeAccelerator::~ExynosVideoEncodeAccelerator() {
- DCHECK(!encoder_thread_.IsRunning());
- DCHECK(!device_poll_thread_.IsRunning());
-
- if (device_poll_interrupt_fd_ != -1) {
- HANDLE_EINTR(close(device_poll_interrupt_fd_));
- device_poll_interrupt_fd_ = -1;
- }
- if (mfc_fd_ != -1) {
- DestroyMfcInputBuffers();
- DestroyMfcOutputBuffers();
- HANDLE_EINTR(close(mfc_fd_));
- mfc_fd_ = -1;
- }
- if (gsc_fd_ != -1) {
- DestroyGscInputBuffers();
- DestroyGscOutputBuffers();
- HANDLE_EINTR(close(gsc_fd_));
- gsc_fd_ = -1;
- }
-}
-
-void ExynosVideoEncodeAccelerator::Initialize(
- media::VideoFrame::Format input_format,
- const gfx::Size& input_visible_size,
- media::VideoCodecProfile output_profile,
- uint32 initial_bitrate) {
- DVLOG(3) << "Initialize(): input_format=" << input_format
- << ", input_visible_size=" << input_visible_size.ToString()
- << ", output_profile=" << output_profile
- << ", initial_bitrate=" << initial_bitrate;
-
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK_EQ(encoder_state_, kUninitialized);
-
- input_visible_size_ = input_visible_size;
- input_allocated_size_.SetSize((input_visible_size_.width() + 0xF) & ~0xF,
- (input_visible_size_.height() + 0xF) & ~0xF);
- converted_visible_size_.SetSize((input_visible_size_.width() + 0x1) & ~0x1,
- (input_visible_size_.height() + 0x1) & ~0x1);
- converted_allocated_size_.SetSize(
- (converted_visible_size_.width() + 0xF) & ~0xF,
- (converted_visible_size_.height() + 0xF) & ~0xF);
- output_visible_size_ = converted_visible_size_;
-
- switch (input_format) {
- case media::VideoFrame::RGB32:
- input_format_fourcc_ = V4L2_PIX_FMT_RGB32;
- break;
- case media::VideoFrame::I420:
- input_format_fourcc_ = V4L2_PIX_FMT_YUV420M;
- break;
- default:
- NOTIFY_ERROR(kInvalidArgumentError);
- return;
- }
-
- if (output_profile >= media::H264PROFILE_MIN &&
- output_profile <= media::H264PROFILE_MAX) {
- output_format_fourcc_ = V4L2_PIX_FMT_H264;
- } else {
- NOTIFY_ERROR(kInvalidArgumentError);
- return;
- }
-
- // Open the color conversion device.
- DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice;
- gsc_fd_ =
- HANDLE_EINTR(open(kExynosGscDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
- if (gsc_fd_ == -1) {
- DPLOG(ERROR) << "Initialize(): could not open GSC device: "
- << kExynosGscDevice;
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- // Capabilities check.
- struct v4l2_capability caps;
- memset(&caps, 0, sizeof(caps));
- const __u32 kCapsRequired = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
- V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING;
- IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_QUERYCAP, &caps);
- if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
- DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
- "caps check failed: 0x" << std::hex << caps.capabilities;
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- // Open the video encoder device.
- DVLOG(2) << "Initialize(): opening MFC device: " << kExynosMfcDevice;
- mfc_fd_ =
- HANDLE_EINTR(open(kExynosMfcDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
- if (mfc_fd_ == -1) {
- DPLOG(ERROR) << "Initialize(): could not open MFC device: "
- << kExynosMfcDevice;
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- memset(&caps, 0, sizeof(caps));
- IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_QUERYCAP, &caps);
- if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
- DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
- "caps check failed: 0x" << std::hex << caps.capabilities;
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- // Create the interrupt fd.
- DCHECK_EQ(device_poll_interrupt_fd_, -1);
- device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- if (device_poll_interrupt_fd_ == -1) {
- DPLOG(ERROR) << "Initialize(): eventfd() failed";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- DVLOG(3)
- << "Initialize(): input_visible_size_=" << input_visible_size_.ToString()
- << ", input_allocated_size_=" << input_allocated_size_.ToString()
- << ", converted_visible_size_=" << converted_visible_size_.ToString()
- << ", converted_allocated_size_=" << converted_allocated_size_.ToString()
- << ", output_visible_size_=" << output_visible_size_.ToString();
-
- if (!CreateGscInputBuffers() || !CreateGscOutputBuffers())
- return;
-
- // MFC setup for encoding is rather particular in ordering:
- //
- // 1. Format (VIDIOC_S_FMT) set first on OUTPUT and CAPTURE queues.
- // 2. VIDIOC_REQBUFS, VIDIOC_QBUF, and VIDIOC_STREAMON on CAPTURE queue.
- // 3. VIDIOC_REQBUFS (and later VIDIOC_QBUF and VIDIOC_STREAMON) on OUTPUT
- // queue.
- //
- // Unfortunately, we cannot do (3) in Initialize() here since we have no
- // buffers to QBUF in step (2) until the client has provided output buffers
- // through UseOutputBitstreamBuffer(). So, we just do (1), and the
- // VIDIOC_REQBUFS part of (2) here. The rest is done the first time we get
- // a UseOutputBitstreamBuffer() callback.
-
- if (!SetMfcFormats())
- return;
-
- // VIDIOC_REQBUFS on CAPTURE queue.
- if (!CreateMfcOutputBuffers())
- return;
-
-
- if (!encoder_thread_.Start()) {
- DLOG(ERROR) << "Initialize(): encoder thread failed to start";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- RequestEncodingParametersChange(initial_bitrate, kInitialFramerate);
-
- SetEncoderState(kInitialized);
-
- child_message_loop_proxy_->PostTask(
- FROM_HERE, base::Bind(&Client::NotifyInitializeDone, client_));
-
- child_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&Client::RequireBitstreamBuffers,
- client_,
- gsc_input_buffer_map_.size(),
- input_allocated_size_,
- output_buffer_byte_size_));
-}
-
-void ExynosVideoEncodeAccelerator::Encode(
- const scoped_refptr<media::VideoFrame>& frame,
- bool force_keyframe) {
- DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
-
- encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::EncodeTask,
- base::Unretained(this),
- frame,
- force_keyframe));
-}
-
-void ExynosVideoEncodeAccelerator::UseOutputBitstreamBuffer(
- const media::BitstreamBuffer& buffer) {
- DVLOG(3) << "UseOutputBitstreamBuffer(): id=" << buffer.id();
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
-
- if (buffer.size() < output_buffer_byte_size_) {
- NOTIFY_ERROR(kInvalidArgumentError);
- return;
- }
-
- scoped_ptr<base::SharedMemory> shm(
- new base::SharedMemory(buffer.handle(), false));
- if (!shm->Map(buffer.size())) {
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- scoped_ptr<BitstreamBufferRef> buffer_ref(
- new BitstreamBufferRef(buffer.id(), shm.Pass(), buffer.size()));
- encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
- base::Unretained(this),
- base::Passed(&buffer_ref)));
-}
-
-void ExynosVideoEncodeAccelerator::RequestEncodingParametersChange(
- uint32 bitrate,
- uint32 framerate) {
- DVLOG(3) << "RequestEncodingParametersChange(): bitrate=" << bitrate
- << ", framerate=" << framerate;
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
-
- encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(
- &ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask,
- base::Unretained(this),
- bitrate,
- framerate));
-}
-
-void ExynosVideoEncodeAccelerator::Destroy() {
- DVLOG(3) << "Destroy()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
-
- // We're destroying; cancel all callbacks.
- client_ptr_factory_.InvalidateWeakPtrs();
-
- // If the encoder thread is running, destroy using posted task.
- if (encoder_thread_.IsRunning()) {
- encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::DestroyTask,
- base::Unretained(this)));
- // DestroyTask() will put the encoder into kError state and cause all tasks
- // to no-op.
- encoder_thread_.Stop();
- } else {
- // Otherwise, call the destroy task directly.
- DestroyTask();
- }
-
- // Set to kError state just in case.
- SetEncoderState(kError);
-
- delete this;
-}
-
-// static
-std::vector<media::VideoEncodeAccelerator::SupportedProfile>
-ExynosVideoEncodeAccelerator::GetSupportedProfiles() {
- std::vector<SupportedProfile> profiles(1);
- SupportedProfile& profile = profiles[0];
- profile.profile = media::H264PROFILE_MAIN;
- profile.max_resolution.SetSize(1920, 1088);
- profile.max_framerate.numerator = 30;
- profile.max_framerate.denominator = 1;
- return profiles;
-}
-
-void ExynosVideoEncodeAccelerator::EncodeTask(
- const scoped_refptr<media::VideoFrame>& frame, bool force_keyframe) {
- DVLOG(3) << "EncodeTask(): force_keyframe=" << force_keyframe;
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
- DCHECK_NE(encoder_state_, kUninitialized);
-
- if (encoder_state_ == kError) {
- DVLOG(2) << "EncodeTask(): early out: kError state";
- return;
- }
-
- encoder_input_queue_.push_back(frame);
- EnqueueGsc();
-
- if (force_keyframe) {
- // TODO(sheu): this presently makes for slightly imprecise encoding
- // parameters updates. To precisely align the parameter updates with the
- // incoming input frame, we should track the parameters through the GSC
- // pipeline and only apply them when the MFC input is about to be queued.
- struct v4l2_ext_control ctrls[1];
- struct v4l2_ext_controls control;
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&control, 0, sizeof(control));
- ctrls[0].id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE;
- ctrls[0].value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
- control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
- control.count = 1;
- control.controls = ctrls;
- IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
- }
-}
-
-void ExynosVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
- scoped_ptr<BitstreamBufferRef> buffer_ref) {
- DVLOG(3) << "UseOutputBitstreamBufferTask(): id=" << buffer_ref->id;
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
-
- encoder_output_queue_.push_back(
- linked_ptr<BitstreamBufferRef>(buffer_ref.release()));
- EnqueueMfc();
-
- if (encoder_state_ == kInitialized) {
- // Finish setting up our MFC OUTPUT queue. See: Initialize().
- // VIDIOC_REQBUFS on OUTPUT queue.
- if (!CreateMfcInputBuffers())
- return;
- if (!StartDevicePoll())
- return;
- encoder_state_ = kEncoding;
- }
-}
-
-void ExynosVideoEncodeAccelerator::DestroyTask() {
- DVLOG(3) << "DestroyTask()";
-
- // DestroyTask() should run regardless of encoder_state_.
-
- // Stop streaming and the device_poll_thread_.
- StopDevicePoll();
-
- // Set our state to kError, and early-out all tasks.
- encoder_state_ = kError;
-}
-
-void ExynosVideoEncodeAccelerator::ServiceDeviceTask() {
- DVLOG(3) << "ServiceDeviceTask()";
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
- DCHECK_NE(encoder_state_, kUninitialized);
- DCHECK_NE(encoder_state_, kInitialized);
-
- if (encoder_state_ == kError) {
- DVLOG(2) << "ServiceDeviceTask(): early out: kError state";
- return;
- }
-
- DequeueGsc();
- DequeueMfc();
- EnqueueGsc();
- EnqueueMfc();
-
- // Clear the interrupt fd.
- if (!ClearDevicePollInterrupt())
- return;
-
- unsigned int poll_fds = 0;
- // Add GSC fd, if we should poll on it.
- // GSC has to wait until both input and output buffers are queued.
- if (gsc_input_buffer_queued_count_ > 0 && gsc_output_buffer_queued_count_ > 0)
- poll_fds |= kPollGsc;
- // Add MFC fd, if we should poll on it.
- // MFC can be polled as soon as either input or output buffers are queued.
- if (mfc_input_buffer_queued_count_ + mfc_output_buffer_queued_count_ > 0)
- poll_fds |= kPollMfc;
-
- // ServiceDeviceTask() should only ever be scheduled from DevicePollTask(),
- // so either:
- // * device_poll_thread_ is running normally
- // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
- // in which case we're in kError state, and we should have early-outed
- // already.
- DCHECK(device_poll_thread_.message_loop());
- // Queue the DevicePollTask() now.
- device_poll_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
- base::Unretained(this),
- poll_fds));
-
- DVLOG(2) << "ServiceDeviceTask(): buffer counts: ENC["
- << encoder_input_queue_.size() << "] => GSC["
- << gsc_free_input_buffers_.size() << "+"
- << gsc_input_buffer_queued_count_ << "/"
- << gsc_input_buffer_map_.size() << "->"
- << gsc_free_output_buffers_.size() << "+"
- << gsc_output_buffer_queued_count_ << "/"
- << gsc_output_buffer_map_.size() << "] => "
- << mfc_ready_input_buffers_.size() << " => MFC["
- << mfc_free_input_buffers_.size() << "+"
- << mfc_input_buffer_queued_count_ << "/"
- << mfc_input_buffer_map_.size() << "->"
- << mfc_free_output_buffers_.size() << "+"
- << mfc_output_buffer_queued_count_ << "/"
- << mfc_output_buffer_map_.size() << "] => OUT["
- << encoder_output_queue_.size() << "]";
-}
-
-void ExynosVideoEncodeAccelerator::EnqueueGsc() {
- DVLOG(3) << "EnqueueGsc()";
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
-
- const int old_gsc_inputs_queued = gsc_input_buffer_queued_count_;
- while (!encoder_input_queue_.empty() && !gsc_free_input_buffers_.empty()) {
- if (!EnqueueGscInputRecord())
- return;
- }
- if (old_gsc_inputs_queued == 0 && gsc_input_buffer_queued_count_ != 0) {
- // We started up a previously empty queue.
- // Queue state changed; signal interrupt.
- if (!SetDevicePollInterrupt())
- return;
- // Start VIDIOC_STREAMON if we haven't yet.
- if (!gsc_input_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_STREAMON, &type);
- gsc_input_streamon_ = true;
- }
- }
-
- // Enqueue a GSC output, only if we need one. GSC output buffers write
- // directly to MFC input buffers, so we'll have to check for free MFC input
- // buffers as well.
- // GSC is liable to race conditions if more than one output buffer is
- // simultaneously enqueued, so enqueue just one.
- if (gsc_input_buffer_queued_count_ != 0 &&
- gsc_output_buffer_queued_count_ == 0 &&
- !gsc_free_output_buffers_.empty() && !mfc_free_input_buffers_.empty()) {
- const int old_gsc_outputs_queued = gsc_output_buffer_queued_count_;
- if (!EnqueueGscOutputRecord())
- return;
- if (old_gsc_outputs_queued == 0 && gsc_output_buffer_queued_count_ != 0) {
- // We just started up a previously empty queue.
- // Queue state changed; signal interrupt.
- if (!SetDevicePollInterrupt())
- return;
- // Start VIDIOC_STREAMON if we haven't yet.
- if (!gsc_output_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_STREAMON, &type);
- gsc_output_streamon_ = true;
- }
- }
- }
- DCHECK_LE(gsc_output_buffer_queued_count_, 1);
-}
-
-void ExynosVideoEncodeAccelerator::DequeueGsc() {
- DVLOG(3) << "DequeueGsc()";
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
-
- // Dequeue completed GSC input (VIDEO_OUTPUT) buffers, and recycle to the free
- // list.
- struct v4l2_buffer dqbuf;
- struct v4l2_plane planes[3];
- while (gsc_input_buffer_queued_count_ > 0) {
- DCHECK(gsc_input_streamon_);
- memset(&dqbuf, 0, sizeof(dqbuf));
- memset(&planes, 0, sizeof(planes));
- dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- dqbuf.memory = V4L2_MEMORY_USERPTR;
- dqbuf.m.planes = planes;
- dqbuf.length = arraysize(planes);
- if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
- if (errno == EAGAIN) {
- // EAGAIN if we're just out of buffers to dequeue.
- break;
- }
- DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
- GscInputRecord& input_record = gsc_input_buffer_map_[dqbuf.index];
- DCHECK(input_record.at_device);
- DCHECK(input_record.frame.get());
- input_record.at_device = false;
- input_record.frame = NULL;
- gsc_free_input_buffers_.push_back(dqbuf.index);
- gsc_input_buffer_queued_count_--;
- }
-
- // Dequeue completed GSC output (VIDEO_CAPTURE) buffers, and recycle to the
- // free list. Queue the corresponding MFC buffer to the GSC->MFC holding
- // queue.
- while (gsc_output_buffer_queued_count_ > 0) {
- DCHECK(gsc_output_streamon_);
- memset(&dqbuf, 0, sizeof(dqbuf));
- memset(&planes, 0, sizeof(planes));
- dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dqbuf.memory = V4L2_MEMORY_DMABUF;
- dqbuf.m.planes = planes;
- dqbuf.length = 2;
- if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
- if (errno == EAGAIN) {
- // EAGAIN if we're just out of buffers to dequeue.
- break;
- }
- DPLOG(ERROR) << "DequeueGsc(): ioctl() failed: VIDIOC_DQBUF";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
- GscOutputRecord& output_record = gsc_output_buffer_map_[dqbuf.index];
- DCHECK(output_record.at_device);
- DCHECK(output_record.mfc_input != -1);
- mfc_ready_input_buffers_.push_back(output_record.mfc_input);
- output_record.at_device = false;
- output_record.mfc_input = -1;
- gsc_free_output_buffers_.push_back(dqbuf.index);
- gsc_output_buffer_queued_count_--;
- }
-}
-void ExynosVideoEncodeAccelerator::EnqueueMfc() {
- DVLOG(3) << "EnqueueMfc()";
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
-
- // Enqueue all the MFC inputs we can.
- const int old_mfc_inputs_queued = mfc_input_buffer_queued_count_;
- while (!mfc_ready_input_buffers_.empty()) {
- if (!EnqueueMfcInputRecord())
- return;
- }
- if (old_mfc_inputs_queued == 0 && mfc_input_buffer_queued_count_ != 0) {
- // We just started up a previously empty queue.
- // Queue state changed; signal interrupt.
- if (!SetDevicePollInterrupt())
- return;
- // Start VIDIOC_STREAMON if we haven't yet.
- if (!mfc_input_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_STREAMON, &type);
- mfc_input_streamon_ = true;
- }
- }
-
- // Enqueue all the MFC outputs we can.
- const int old_mfc_outputs_queued = mfc_output_buffer_queued_count_;
- while (!mfc_free_output_buffers_.empty() && !encoder_output_queue_.empty()) {
- if (!EnqueueMfcOutputRecord())
- return;
- }
- if (old_mfc_outputs_queued == 0 && mfc_output_buffer_queued_count_ != 0) {
- // We just started up a previously empty queue.
- // Queue state changed; signal interrupt.
- if (!SetDevicePollInterrupt())
- return;
- // Start VIDIOC_STREAMON if we haven't yet.
- if (!mfc_output_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_STREAMON, &type);
- mfc_output_streamon_ = true;
- }
- }
-}
-
-void ExynosVideoEncodeAccelerator::DequeueMfc() {
- DVLOG(3) << "DequeueMfc()";
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
-
- // Dequeue completed MFC input (VIDEO_OUTPUT) buffers, and recycle to the free
- // list.
- struct v4l2_buffer dqbuf;
- struct v4l2_plane planes[2];
- while (mfc_input_buffer_queued_count_ > 0) {
- DCHECK(mfc_input_streamon_);
- memset(&dqbuf, 0, sizeof(dqbuf));
- memset(&planes, 0, sizeof(planes));
- dqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- dqbuf.memory = V4L2_MEMORY_MMAP;
- dqbuf.m.planes = planes;
- dqbuf.length = 2;
- if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
- if (errno == EAGAIN) {
- // EAGAIN if we're just out of buffers to dequeue.
- break;
- }
- DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
- MfcInputRecord& input_record = mfc_input_buffer_map_[dqbuf.index];
- DCHECK(input_record.at_device);
- input_record.at_device = false;
- mfc_free_input_buffers_.push_back(dqbuf.index);
- mfc_input_buffer_queued_count_--;
- }
-
- // Dequeue completed MFC output (VIDEO_CAPTURE) buffers, and recycle to the
- // free list. Notify the client that an output buffer is complete.
- while (mfc_output_buffer_queued_count_ > 0) {
- DCHECK(mfc_output_streamon_);
- memset(&dqbuf, 0, sizeof(dqbuf));
- memset(planes, 0, sizeof(planes));
- dqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dqbuf.memory = V4L2_MEMORY_USERPTR;
- dqbuf.m.planes = planes;
- dqbuf.length = 1;
- if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_DQBUF, &dqbuf)) != 0) {
- if (errno == EAGAIN) {
- // EAGAIN if we're just out of buffers to dequeue.
- break;
- }
- DPLOG(ERROR) << "DequeueMfc(): ioctl() failed: VIDIOC_DQBUF";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
- const bool key_frame = ((dqbuf.flags & V4L2_BUF_FLAG_KEYFRAME) != 0);
- const size_t output_size = dqbuf.m.planes[0].bytesused;
- MfcOutputRecord& output_record = mfc_output_buffer_map_[dqbuf.index];
- DCHECK(output_record.at_device);
- DCHECK(output_record.buffer_ref.get());
- uint8* data =
- reinterpret_cast<uint8*>(output_record.buffer_ref->shm->memory());
- if (stream_header_size_ == 0) {
- // Assume that the first buffer dequeued is the stream header.
- stream_header_size_ = output_size;
- stream_header_.reset(new uint8[stream_header_size_]);
- memcpy(stream_header_.get(), data, stream_header_size_);
- }
- if (key_frame &&
- output_buffer_byte_size_ - stream_header_size_ >= output_size) {
- // Insert stream header before every keyframe.
- memmove(data + stream_header_size_, data, output_size);
- memcpy(data, stream_header_.get(), stream_header_size_);
- }
- DVLOG(3) << "DequeueMfc(): returning "
- "bitstream_buffer_id=" << output_record.buffer_ref->id
- << ", key_frame=" << key_frame;
- child_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(&Client::BitstreamBufferReady,
- client_,
- output_record.buffer_ref->id,
- dqbuf.m.planes[0].bytesused,
- key_frame));
- output_record.at_device = false;
- output_record.buffer_ref.reset();
- mfc_free_output_buffers_.push_back(dqbuf.index);
- mfc_output_buffer_queued_count_--;
- }
-}
-
-bool ExynosVideoEncodeAccelerator::EnqueueGscInputRecord() {
- DVLOG(3) << "EnqueueGscInputRecord()";
- DCHECK(!encoder_input_queue_.empty());
- DCHECK(!gsc_free_input_buffers_.empty());
-
- // Enqueue a GSC input (VIDEO_OUTPUT) buffer for an input video frame
- scoped_refptr<media::VideoFrame> frame = encoder_input_queue_.front();
- const int gsc_buffer = gsc_free_input_buffers_.back();
- GscInputRecord& input_record = gsc_input_buffer_map_[gsc_buffer];
- DCHECK(!input_record.at_device);
- DCHECK(!input_record.frame.get());
- struct v4l2_buffer qbuf;
- struct v4l2_plane qbuf_planes[3];
- memset(&qbuf, 0, sizeof(qbuf));
- memset(qbuf_planes, 0, sizeof(qbuf_planes));
- qbuf.index = gsc_buffer;
- qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- qbuf.memory = V4L2_MEMORY_USERPTR;
- qbuf.m.planes = qbuf_planes;
- switch (input_format_fourcc_) {
- case V4L2_PIX_FMT_RGB32: {
- qbuf.m.planes[0].bytesused = input_allocated_size_.GetArea() * 4;
- qbuf.m.planes[0].length = input_allocated_size_.GetArea() * 4;
- qbuf.m.planes[0].m.userptr = reinterpret_cast<unsigned long>(
- frame->data(media::VideoFrame::kRGBPlane));
- qbuf.length = 1;
- break;
- }
- case V4L2_PIX_FMT_YUV420M: {
- qbuf.m.planes[0].bytesused = input_allocated_size_.GetArea();
- qbuf.m.planes[0].length = input_allocated_size_.GetArea();
- qbuf.m.planes[0].m.userptr = reinterpret_cast<unsigned long>(
- frame->data(media::VideoFrame::kYPlane));
- qbuf.m.planes[1].bytesused = input_allocated_size_.GetArea() / 4;
- qbuf.m.planes[1].length = input_allocated_size_.GetArea() / 4;
- qbuf.m.planes[1].m.userptr = reinterpret_cast<unsigned long>(
- frame->data(media::VideoFrame::kUPlane));
- qbuf.m.planes[2].bytesused = input_allocated_size_.GetArea() / 4;
- qbuf.m.planes[2].length = input_allocated_size_.GetArea() / 4;
- qbuf.m.planes[2].m.userptr = reinterpret_cast<unsigned long>(
- frame->data(media::VideoFrame::kVPlane));
- qbuf.length = 3;
- break;
- }
- default:
- NOTREACHED();
- NOTIFY_ERROR(kIllegalStateError);
- return false;
- }
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_QBUF, &qbuf);
- input_record.at_device = true;
- input_record.frame = frame;
- encoder_input_queue_.pop_front();
- gsc_free_input_buffers_.pop_back();
- gsc_input_buffer_queued_count_++;
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::EnqueueGscOutputRecord() {
- DVLOG(3) << "EnqueueGscOutputRecord()";
- DCHECK(!gsc_free_output_buffers_.empty());
- DCHECK(!mfc_free_input_buffers_.empty());
-
- // Enqueue a GSC output (VIDEO_CAPTURE) buffer.
- const int gsc_buffer = gsc_free_output_buffers_.back();
- const int mfc_buffer = mfc_free_input_buffers_.back();
- GscOutputRecord& output_record = gsc_output_buffer_map_[gsc_buffer];
- MfcInputRecord& input_record = mfc_input_buffer_map_[mfc_buffer];
- DCHECK(!output_record.at_device);
- DCHECK_EQ(output_record.mfc_input, -1);
- DCHECK(!input_record.at_device);
- struct v4l2_buffer qbuf;
- struct v4l2_plane qbuf_planes[2];
- memset(&qbuf, 0, sizeof(qbuf));
- memset(qbuf_planes, 0, sizeof(qbuf_planes));
- qbuf.index = gsc_buffer;
- qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- qbuf.memory = V4L2_MEMORY_DMABUF;
- qbuf.m.planes = qbuf_planes;
- qbuf.m.planes[0].m.fd = input_record.fd[0];
- qbuf.m.planes[1].m.fd = input_record.fd[1];
- qbuf.length = 2;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_QBUF, &qbuf);
- output_record.at_device = true;
- output_record.mfc_input = mfc_buffer;
- mfc_free_input_buffers_.pop_back();
- gsc_free_output_buffers_.pop_back();
- gsc_output_buffer_queued_count_++;
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::EnqueueMfcInputRecord() {
- DVLOG(3) << "EnqueueMfcInputRecord()";
- DCHECK(!mfc_ready_input_buffers_.empty());
-
- // Enqueue a MFC input (VIDEO_OUTPUT) buffer.
- const int mfc_buffer = mfc_ready_input_buffers_.front();
- MfcInputRecord& input_record = mfc_input_buffer_map_[mfc_buffer];
- DCHECK(!input_record.at_device);
- struct v4l2_buffer qbuf;
- struct v4l2_plane qbuf_planes[2];
- memset(&qbuf, 0, sizeof(qbuf));
- memset(qbuf_planes, 0, sizeof(qbuf_planes));
- qbuf.index = mfc_buffer;
- qbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- qbuf.memory = V4L2_MEMORY_MMAP;
- qbuf.m.planes = qbuf_planes;
- qbuf.length = 2;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_QBUF, &qbuf);
- input_record.at_device = true;
- mfc_ready_input_buffers_.pop_front();
- mfc_input_buffer_queued_count_++;
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::EnqueueMfcOutputRecord() {
- DVLOG(3) << "EnqueueMfcOutputRecord()";
- DCHECK(!mfc_free_output_buffers_.empty());
- DCHECK(!encoder_output_queue_.empty());
-
- // Enqueue a MFC output (VIDEO_CAPTURE) buffer.
- linked_ptr<BitstreamBufferRef> output_buffer = encoder_output_queue_.back();
- const int mfc_buffer = mfc_free_output_buffers_.back();
- MfcOutputRecord& output_record = mfc_output_buffer_map_[mfc_buffer];
- DCHECK(!output_record.at_device);
- DCHECK(!output_record.buffer_ref.get());
- struct v4l2_buffer qbuf;
- struct v4l2_plane qbuf_planes[1];
- memset(&qbuf, 0, sizeof(qbuf));
- memset(qbuf_planes, 0, sizeof(qbuf_planes));
- qbuf.index = mfc_buffer;
- qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- qbuf.memory = V4L2_MEMORY_USERPTR;
- qbuf.m.planes = qbuf_planes;
- qbuf.m.planes[0].bytesused = output_buffer->size;
- qbuf.m.planes[0].length = output_buffer->size;
- qbuf.m.planes[0].m.userptr =
- reinterpret_cast<unsigned long>(output_buffer->shm->memory());
- qbuf.length = 1;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_QBUF, &qbuf);
- output_record.at_device = true;
- output_record.buffer_ref = output_buffer;
- encoder_output_queue_.pop_back();
- mfc_free_output_buffers_.pop_back();
- mfc_output_buffer_queued_count_++;
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::StartDevicePoll() {
- DVLOG(3) << "StartDevicePoll()";
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
- DCHECK(!device_poll_thread_.IsRunning());
-
- // Start up the device poll thread and schedule its first DevicePollTask().
- if (!device_poll_thread_.Start()) {
- DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
- NOTIFY_ERROR(kPlatformFailureError);
- return false;
- }
- // Enqueue a poll task with no devices to poll on -- it will wait only on the
- // interrupt fd.
- device_poll_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::DevicePollTask,
- base::Unretained(this),
- 0));
-
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::StopDevicePoll() {
- DVLOG(3) << "StopDevicePoll()";
-
- // Signal the DevicePollTask() to stop, and stop the device poll thread.
- if (!SetDevicePollInterrupt())
- return false;
- device_poll_thread_.Stop();
- // Clear the interrupt now, to be sure.
- if (!ClearDevicePollInterrupt())
- return false;
-
- // Stop streaming.
- if (gsc_input_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_STREAMOFF, &type);
- }
- gsc_input_streamon_ = false;
- if (gsc_output_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_STREAMOFF, &type);
- }
- gsc_output_streamon_ = false;
- if (mfc_input_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_STREAMOFF, &type);
- }
- mfc_input_streamon_ = false;
- if (mfc_output_streamon_) {
- __u32 type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_STREAMOFF, &type);
- }
- mfc_output_streamon_ = false;
-
- // Reset all our accounting info.
- encoder_input_queue_.clear();
- gsc_free_input_buffers_.clear();
- for (size_t i = 0; i < gsc_input_buffer_map_.size(); ++i) {
- GscInputRecord& input_record = gsc_input_buffer_map_[i];
- input_record.at_device = false;
- input_record.frame = NULL;
- gsc_free_input_buffers_.push_back(i);
- }
- gsc_input_buffer_queued_count_ = 0;
- gsc_free_output_buffers_.clear();
- for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i) {
- GscOutputRecord& output_record = gsc_output_buffer_map_[i];
- output_record.at_device = false;
- output_record.mfc_input = -1;
- gsc_free_output_buffers_.push_back(i);
- }
- gsc_output_buffer_queued_count_ = 0;
- mfc_ready_input_buffers_.clear();
- mfc_free_input_buffers_.clear();
- for (size_t i = 0; i < mfc_input_buffer_map_.size(); ++i) {
- MfcInputRecord& input_record = mfc_input_buffer_map_[i];
- input_record.at_device = false;
- mfc_free_input_buffers_.push_back(i);
- }
- mfc_input_buffer_queued_count_ = 0;
- mfc_free_output_buffers_.clear();
- for (size_t i = 0; i < mfc_output_buffer_map_.size(); ++i) {
- MfcOutputRecord& output_record = mfc_output_buffer_map_[i];
- output_record.at_device = false;
- output_record.buffer_ref.reset();
- mfc_free_output_buffers_.push_back(i);
- }
- mfc_output_buffer_queued_count_ = 0;
- encoder_output_queue_.clear();
-
- DVLOG(3) << "StopDevicePoll(): device poll stopped";
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::SetDevicePollInterrupt() {
- DVLOG(3) << "SetDevicePollInterrupt()";
-
- // We might get called here if we fail during initialization, in which case we
- // don't have a file descriptor.
- if (device_poll_interrupt_fd_ == -1)
- return true;
-
- const uint64 buf = 1;
- if (HANDLE_EINTR((write(device_poll_interrupt_fd_, &buf, sizeof(buf)))) <
- static_cast<ssize_t>(sizeof(buf))) {
- DPLOG(ERROR) << "SetDevicePollInterrupt(): write() failed";
- NOTIFY_ERROR(kPlatformFailureError);
- return false;
- }
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::ClearDevicePollInterrupt() {
- DVLOG(3) << "ClearDevicePollInterrupt()";
-
- // We might get called here if we fail during initialization, in which case we
- // don't have a file descriptor.
- if (device_poll_interrupt_fd_ == -1)
- return true;
-
- uint64 buf;
- if (HANDLE_EINTR(read(device_poll_interrupt_fd_, &buf, sizeof(buf))) <
- static_cast<ssize_t>(sizeof(buf))) {
- if (errno == EAGAIN) {
- // No interrupt flag set, and we're reading nonblocking. Not an error.
- return true;
- } else {
- DPLOG(ERROR) << "ClearDevicePollInterrupt(): read() failed";
- NOTIFY_ERROR(kPlatformFailureError);
- return false;
- }
- }
- return true;
-}
-
-void ExynosVideoEncodeAccelerator::DevicePollTask(unsigned int poll_fds) {
- DVLOG(3) << "DevicePollTask()";
- DCHECK_EQ(device_poll_thread_.message_loop(), base::MessageLoop::current());
- DCHECK_NE(device_poll_interrupt_fd_, -1);
-
- // This routine just polls the set of device fds, and schedules a
- // ServiceDeviceTask() on encoder_thread_ when processing needs to occur.
- // Other threads may notify this task to return early by writing to
- // device_poll_interrupt_fd_.
- struct pollfd pollfds[3];
- nfds_t nfds;
-
- // Add device_poll_interrupt_fd_;
- pollfds[0].fd = device_poll_interrupt_fd_;
- pollfds[0].events = POLLIN | POLLERR;
- nfds = 1;
-
- // Add GSC fd, if we should poll on it.
- // GSC has to wait until both input and output buffers are queued.
- if (poll_fds & kPollGsc) {
- DVLOG(3) << "DevicePollTask(): adding GSC to poll() set";
- pollfds[nfds].fd = gsc_fd_;
- pollfds[nfds].events = POLLIN | POLLOUT | POLLERR;
- nfds++;
- }
- if (poll_fds & kPollMfc) {
- DVLOG(3) << "DevicePollTask(): adding MFC to poll() set";
- pollfds[nfds].fd = mfc_fd_;
- pollfds[nfds].events = POLLIN | POLLOUT | POLLERR;
- nfds++;
- }
-
- // Poll it!
- if (HANDLE_EINTR(poll(pollfds, nfds, -1)) == -1) {
- DPLOG(ERROR) << "DevicePollTask(): poll() failed";
- NOTIFY_ERROR(kPlatformFailureError);
- return;
- }
-
- // All processing should happen on ServiceDeviceTask(), since we shouldn't
- // touch encoder state from this thread.
- encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::ServiceDeviceTask,
- base::Unretained(this)));
-}
-
-void ExynosVideoEncodeAccelerator::NotifyError(Error error) {
- DVLOG(1) << "NotifyError(): error=" << error;
-
- if (!child_message_loop_proxy_->BelongsToCurrentThread()) {
- child_message_loop_proxy_->PostTask(
- FROM_HERE,
- base::Bind(
- &ExynosVideoEncodeAccelerator::NotifyError, weak_this_, error));
- return;
- }
-
- if (client_) {
- client_->NotifyError(error);
- client_ptr_factory_.InvalidateWeakPtrs();
- }
-}
-
-void ExynosVideoEncodeAccelerator::SetEncoderState(State state) {
- DVLOG(3) << "SetEncoderState(): state=" << state;
-
- // We can touch encoder_state_ only if this is the encoder thread or the
- // encoder thread isn't running.
- if (encoder_thread_.message_loop() != NULL &&
- encoder_thread_.message_loop() != base::MessageLoop::current()) {
- encoder_thread_.message_loop()->PostTask(
- FROM_HERE,
- base::Bind(&ExynosVideoEncodeAccelerator::SetEncoderState,
- base::Unretained(this),
- state));
- } else {
- encoder_state_ = state;
- }
-}
-
-void ExynosVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
- uint32 bitrate,
- uint32 framerate) {
- DVLOG(3) << "RequestEncodingParametersChangeTask(): bitrate=" << bitrate
- << ", framerate=" << framerate;
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
-
- if (bitrate < 1)
- bitrate = 1;
- if (framerate < 1)
- framerate = 1;
-
- struct v4l2_ext_control ctrls[1];
- struct v4l2_ext_controls control;
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&control, 0, sizeof(control));
- ctrls[0].id = V4L2_CID_MPEG_VIDEO_BITRATE;
- ctrls[0].value = bitrate;
- control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
- control.count = arraysize(ctrls);
- control.controls = ctrls;
- IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
-
- struct v4l2_streamparm parms;
- memset(&parms, 0, sizeof(parms));
- parms.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- // Note that we are provided "frames per second" but V4L2 expects "time per
- // frame"; hence we provide the reciprocal of the framerate here.
- parms.parm.output.timeperframe.numerator = 1;
- parms.parm.output.timeperframe.denominator = framerate;
- IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_S_PARM, &parms);
-}
-
-bool ExynosVideoEncodeAccelerator::CreateGscInputBuffers() {
- DVLOG(3) << "CreateGscInputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK_EQ(encoder_state_, kUninitialized);
- DCHECK(!gsc_input_streamon_);
-
- struct v4l2_control control;
- memset(&control, 0, sizeof(control));
- control.id = V4L2_CID_ROTATE;
- control.value = 0;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
-
- // HFLIP actually seems to control vertical mirroring for GSC, and vice-versa.
- memset(&control, 0, sizeof(control));
- control.id = V4L2_CID_HFLIP;
- control.value = 0;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
-
- memset(&control, 0, sizeof(control));
- control.id = V4L2_CID_VFLIP;
- control.value = 0;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
-
- memset(&control, 0, sizeof(control));
- control.id = V4L2_CID_GLOBAL_ALPHA;
- control.value = 255;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CTRL, &control);
-
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- format.fmt.pix_mp.width = input_allocated_size_.width();
- format.fmt.pix_mp.height = input_allocated_size_.height();
- format.fmt.pix_mp.pixelformat = input_format_fourcc_;
- switch (input_format_fourcc_) {
- case V4L2_PIX_FMT_RGB32:
- format.fmt.pix_mp.plane_fmt[0].sizeimage =
- input_allocated_size_.GetArea() * 4;
- format.fmt.pix_mp.plane_fmt[0].bytesperline =
- input_allocated_size_.width() * 4;
- format.fmt.pix_mp.num_planes = 1;
- break;
- case V4L2_PIX_FMT_YUV420M:
- format.fmt.pix_mp.plane_fmt[0].sizeimage =
- input_allocated_size_.GetArea();
- format.fmt.pix_mp.plane_fmt[0].bytesperline =
- input_allocated_size_.width();
- format.fmt.pix_mp.plane_fmt[1].sizeimage =
- input_allocated_size_.GetArea() / 4;
- format.fmt.pix_mp.plane_fmt[1].bytesperline =
- input_allocated_size_.width() / 2;
- format.fmt.pix_mp.plane_fmt[2].sizeimage =
- input_allocated_size_.GetArea() / 4;
- format.fmt.pix_mp.plane_fmt[2].bytesperline =
- input_allocated_size_.width() / 2;
- format.fmt.pix_mp.num_planes = 3;
- break;
- default:
- NOTREACHED();
- NOTIFY_ERROR(kIllegalStateError);
- return false;
- }
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_FMT, &format);
-
- struct v4l2_crop crop;
- memset(&crop, 0, sizeof(crop));
- crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- crop.c.left = 0;
- crop.c.top = 0;
- crop.c.width = input_visible_size_.width();
- crop.c.height = input_visible_size_.height();
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CROP, &crop);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = kGscInputBufferCount;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- reqbufs.memory = V4L2_MEMORY_USERPTR;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
-
- DCHECK(gsc_input_buffer_map_.empty());
- gsc_input_buffer_map_.resize(reqbufs.count);
- for (size_t i = 0; i < gsc_input_buffer_map_.size(); ++i)
- gsc_free_input_buffers_.push_back(i);
-
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::CreateGscOutputBuffers() {
- DVLOG(3) << "CreateGscOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK_EQ(encoder_state_, kUninitialized);
- DCHECK(!gsc_output_streamon_);
-
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- format.fmt.pix_mp.width = converted_allocated_size_.width();
- format.fmt.pix_mp.height = converted_allocated_size_.height();
- format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
- format.fmt.pix_mp.plane_fmt[0].sizeimage =
- converted_allocated_size_.GetArea();
- format.fmt.pix_mp.plane_fmt[1].sizeimage =
- converted_allocated_size_.GetArea() / 2;
- format.fmt.pix_mp.plane_fmt[0].bytesperline =
- converted_allocated_size_.width();
- format.fmt.pix_mp.plane_fmt[1].bytesperline =
- converted_allocated_size_.width();
- format.fmt.pix_mp.num_planes = 2;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_FMT, &format);
-
- struct v4l2_crop crop;
- memset(&crop, 0, sizeof(crop));
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- crop.c.left = 0;
- crop.c.top = 0;
- crop.c.width = converted_visible_size_.width();
- crop.c.height = converted_visible_size_.height();
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_S_CROP, &crop);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = kGscOutputBufferCount;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- reqbufs.memory = V4L2_MEMORY_DMABUF;
- IOCTL_OR_ERROR_RETURN_FALSE(gsc_fd_, VIDIOC_REQBUFS, &reqbufs);
-
- DCHECK(gsc_output_buffer_map_.empty());
- gsc_output_buffer_map_.resize(reqbufs.count);
- for (size_t i = 0; i < gsc_output_buffer_map_.size(); ++i)
- gsc_free_output_buffers_.push_back(i);
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::SetMfcFormats() {
- DVLOG(3) << "SetMfcFormats()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK(!mfc_input_streamon_);
- DCHECK(!mfc_output_streamon_);
-
- // VIDIOC_S_FMT on OUTPUT queue.
- struct v4l2_format format;
- memset(&format, 0, sizeof(format));
- format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- format.fmt.pix_mp.width = input_allocated_size_.width();
- format.fmt.pix_mp.height = input_allocated_size_.height();
- format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
- format.fmt.pix_mp.num_planes = 2;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
- // We read direct from GSC, so we rely on the HW not changing our set
- // size/stride.
- DCHECK_EQ(format.fmt.pix_mp.plane_fmt[0].sizeimage,
- static_cast<__u32>(input_allocated_size_.GetArea()));
- DCHECK_EQ(format.fmt.pix_mp.plane_fmt[0].bytesperline,
- static_cast<__u32>(input_allocated_size_.width()));
- DCHECK_EQ(format.fmt.pix_mp.plane_fmt[1].sizeimage,
- static_cast<__u32>(input_allocated_size_.GetArea() / 2));
- DCHECK_EQ(format.fmt.pix_mp.plane_fmt[1].bytesperline,
- static_cast<__u32>(input_allocated_size_.width()));
-
- struct v4l2_crop crop;
- memset(&crop, 0, sizeof(crop));
- crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- crop.c.left = 0;
- crop.c.top = 0;
- crop.c.width = input_visible_size_.width();
- crop.c.height = input_visible_size_.height();
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_CROP, &crop);
-
- // VIDIOC_S_FMT on CAPTURE queue.
- output_buffer_byte_size_ = kMfcOutputBufferSize;
- memset(&format, 0, sizeof(format));
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- format.fmt.pix_mp.width = output_visible_size_.width();
- format.fmt.pix_mp.height = output_visible_size_.height();
- format.fmt.pix_mp.pixelformat = output_format_fourcc_;
- format.fmt.pix_mp.plane_fmt[0].sizeimage = output_buffer_byte_size_;
- format.fmt.pix_mp.num_planes = 1;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_FMT, &format);
-
- struct v4l2_ext_control ctrls[6];
- struct v4l2_ext_controls control;
- memset(&ctrls, 0, sizeof(ctrls));
- memset(&control, 0, sizeof(control));
- // No B-frames, for lowest decoding latency.
- ctrls[0].id = V4L2_CID_MPEG_VIDEO_B_FRAMES;
- ctrls[0].value = 0;
- // Enable variable bitrate control.
- ctrls[1].id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE;
- ctrls[1].value = 1;
- // Enable "loose" variable bitrate.
- ctrls[2].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF;
- ctrls[2].value = 10;
- // Force bitrate control to average over a GOP (for tight bitrate tolerance).
- ctrls[3].id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT;
- ctrls[3].value = 1;
- // Quantization parameter maximum value (for variable bitrate control).
- ctrls[4].id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
- ctrls[4].value = 51;
- // Separate stream header so we can cache it and insert into the stream.
- ctrls[5].id = V4L2_CID_MPEG_VIDEO_HEADER_MODE;
- ctrls[5].value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE;
- control.ctrl_class = V4L2_CTRL_CLASS_MPEG;
- control.count = arraysize(ctrls);
- control.controls = ctrls;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_S_EXT_CTRLS, &control);
-
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::CreateMfcInputBuffers() {
- DVLOG(3) << "CreateMfcInputBuffers()";
- // This function runs on encoder_thread_ after output buffers have been
- // provided by the client.
- DCHECK_EQ(encoder_thread_.message_loop(), base::MessageLoop::current());
- DCHECK(!mfc_input_streamon_);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = 1; // Driver will allocate the appropriate number of buffers.
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- reqbufs.memory = V4L2_MEMORY_MMAP;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
-
- DCHECK(mfc_input_buffer_map_.empty());
- mfc_input_buffer_map_.resize(reqbufs.count);
- for (size_t i = 0; i < mfc_input_buffer_map_.size(); ++i) {
- MfcInputRecord& input_record = mfc_input_buffer_map_[i];
- for (int j = 0; j < 2; ++j) {
- // Export the DMABUF fd so GSC can write to it.
- struct v4l2_exportbuffer expbuf;
- memset(&expbuf, 0, sizeof(expbuf));
- expbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- expbuf.index = i;
- expbuf.plane = j;
- expbuf.flags = O_CLOEXEC;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_EXPBUF, &expbuf);
- input_record.fd[j] = expbuf.fd;
- }
- mfc_free_input_buffers_.push_back(i);
- }
-
- return true;
-}
-
-bool ExynosVideoEncodeAccelerator::CreateMfcOutputBuffers() {
- DVLOG(3) << "CreateMfcOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK(!mfc_output_streamon_);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = kMfcOutputBufferCount;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- reqbufs.memory = V4L2_MEMORY_USERPTR;
- IOCTL_OR_ERROR_RETURN_FALSE(mfc_fd_, VIDIOC_REQBUFS, &reqbufs);
-
- DCHECK(mfc_output_buffer_map_.empty());
- mfc_output_buffer_map_.resize(reqbufs.count);
- for (size_t i = 0; i < mfc_output_buffer_map_.size(); ++i)
- mfc_free_output_buffers_.push_back(i);
-
- return true;
-}
-
-void ExynosVideoEncodeAccelerator::DestroyGscInputBuffers() {
- DVLOG(3) << "DestroyGscInputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK(!gsc_input_streamon_);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = 0;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- reqbufs.memory = V4L2_MEMORY_USERPTR;
- if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
- DPLOG(ERROR) << "DestroyGscInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
-
- gsc_input_buffer_map_.clear();
- gsc_free_input_buffers_.clear();
-}
-
-void ExynosVideoEncodeAccelerator::DestroyGscOutputBuffers() {
- DVLOG(3) << "DestroyGscOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK(!gsc_output_streamon_);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = 0;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- reqbufs.memory = V4L2_MEMORY_DMABUF;
- if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
- DPLOG(ERROR) << "DestroyGscOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
-
- gsc_output_buffer_map_.clear();
- gsc_free_output_buffers_.clear();
-}
-
-void ExynosVideoEncodeAccelerator::DestroyMfcInputBuffers() {
- DVLOG(3) << "DestroyMfcInputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK(!mfc_input_streamon_);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = 0;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- reqbufs.memory = V4L2_MEMORY_MMAP;
- if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
- DPLOG(ERROR) << "DestroyMfcInputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
-
- mfc_input_buffer_map_.clear();
- mfc_free_input_buffers_.clear();
-}
-
-void ExynosVideoEncodeAccelerator::DestroyMfcOutputBuffers() {
- DVLOG(3) << "DestroyMfcOutputBuffers()";
- DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
- DCHECK(!mfc_output_streamon_);
-
- struct v4l2_requestbuffers reqbufs;
- memset(&reqbufs, 0, sizeof(reqbufs));
- reqbufs.count = 0;
- reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- reqbufs.memory = V4L2_MEMORY_USERPTR;
- if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
- DPLOG(ERROR) << "DestroyMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
-
- mfc_output_buffer_map_.clear();
- mfc_free_output_buffers_.clear();
-}
-
-} // namespace content
diff --git a/content/common/gpu/media/exynos_video_encode_accelerator.h b/content/common/gpu/media/exynos_video_encode_accelerator.h
deleted file mode 100644
index 5b4102c..0000000
--- a/content/common/gpu/media/exynos_video_encode_accelerator.h
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2013 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.
-
-#ifndef CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_
-#define CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_
-
-#include <list>
-#include <vector>
-
-#include "base/memory/linked_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread.h"
-#include "media/video/video_encode_accelerator.h"
-#include "ui/gfx/size.h"
-
-namespace base {
-
-class MessageLoopProxy;
-
-} // namespace base
-
-namespace media {
-
-class BitstreamBuffer;
-
-} // namespace media
-
-namespace content {
-
-// This class handles Exynos video encode acceleration by interfacing with the
-// V4L2 devices exported by the Multi Format Codec and GScaler hardware blocks
-// on the Exynos platform. The threading model of this class is the same as the
-// ExynosVideoDecodeAccelerator (from which class this was designed).
-class ExynosVideoEncodeAccelerator : public media::VideoEncodeAccelerator {
- public:
- explicit ExynosVideoEncodeAccelerator(
- media::VideoEncodeAccelerator::Client* client);
- virtual ~ExynosVideoEncodeAccelerator();
-
- // media::VideoEncodeAccelerator implementation.
- virtual void Initialize(media::VideoFrame::Format format,
- const gfx::Size& input_visible_size,
- media::VideoCodecProfile output_profile,
- uint32 initial_bitrate) OVERRIDE;
- virtual void Encode(const scoped_refptr<media::VideoFrame>& frame,
- bool force_keyframe) OVERRIDE;
- virtual void UseOutputBitstreamBuffer(
- const media::BitstreamBuffer& buffer) OVERRIDE;
- virtual void RequestEncodingParametersChange(uint32 bitrate,
- uint32 framerate) OVERRIDE;
- virtual void Destroy() OVERRIDE;
-
- static std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- GetSupportedProfiles();
-
- private:
- // Auto-destroy reference for BitstreamBuffer, for tracking buffers passed to
- // this instance.
- struct BitstreamBufferRef;
-
- // Record for GSC input buffers.
- struct GscInputRecord {
- GscInputRecord();
- bool at_device;
- scoped_refptr<media::VideoFrame> frame;
- };
-
- // Record for GSC output buffers.
- struct GscOutputRecord {
- GscOutputRecord();
- bool at_device;
- int mfc_input;
- };
-
- // Record for MFC input buffers.
- struct MfcInputRecord {
- MfcInputRecord();
- bool at_device;
- int fd[2];
- };
-
- // Record for MFC output buffers.
- struct MfcOutputRecord {
- MfcOutputRecord();
- bool at_device;
- linked_ptr<BitstreamBufferRef> buffer_ref;
- };
-
- enum {
- kInitialFramerate = 30,
- // These are rather subjectively tuned.
- kGscInputBufferCount = 2,
- kGscOutputBufferCount = 2,
- kMfcOutputBufferCount = 2,
- // MFC hardware does not report required output buffer size correctly.
- // Use maximum theoretical size to avoid hanging the hardware.
- kMfcOutputBufferSize = (2 * 1024 * 1024),
- };
-
- // Internal state of the encoder.
- enum State {
- kUninitialized, // Initialize() not yet called.
- kInitialized, // Initialize() returned true; ready to start encoding.
- kEncoding, // Encoding frames.
- kError, // Error in encoder state.
- };
-
- //
- // Encoding tasks, to be run on encode_thread_.
- //
-
- // Encode a GSC input buffer.
- void EncodeTask(const scoped_refptr<media::VideoFrame>& frame,
- bool force_keyframe);
-
- // Add a BitstreamBuffer to the queue of buffers ready to be used for encoder
- // output.
- void UseOutputBitstreamBufferTask(scoped_ptr<BitstreamBufferRef> buffer_ref);
-
- // Device destruction task.
- void DestroyTask();
-
- // Service I/O on the V4L2 devices. This task should only be scheduled from
- // DevicePollTask().
- void ServiceDeviceTask();
-
- // Handle the various device queues.
- void EnqueueGsc();
- void DequeueGsc();
- void EnqueueMfc();
- void DequeueMfc();
- // Enqueue a buffer on the corresponding queue. Returns false on fatal error.
- bool EnqueueGscInputRecord();
- bool EnqueueGscOutputRecord();
- bool EnqueueMfcInputRecord();
- bool EnqueueMfcOutputRecord();
-
- // Attempt to start/stop device_poll_thread_.
- bool StartDevicePoll();
- bool StopDevicePoll();
- // Set/clear the device poll interrupt (using device_poll_interrupt_fd_).
- bool SetDevicePollInterrupt();
- bool ClearDevicePollInterrupt();
-
- //
- // Device tasks, to be run on device_poll_thread_.
- //
-
- // The device task.
- void DevicePollTask(unsigned int poll_fds);
-
- //
- // Safe from any thread.
- //
-
- // Error notification (using PostTask() to child thread, if necessary).
- void NotifyError(Error error);
-
- // Set the encoder_thread_ state (using PostTask to encoder thread, if
- // necessary).
- void SetEncoderState(State state);
-
- //
- // Other utility functions. Called on encoder_thread_, unless
- // encoder_thread_ is not yet started, in which case the child thread can call
- // these (e.g. in Initialize() or Destroy()).
- //
-
- // Change the parameters of encoding.
- void RequestEncodingParametersChangeTask(uint32 bitrate, uint32 framerate);
-
- // Create the buffers we need.
- bool CreateGscInputBuffers();
- bool CreateGscOutputBuffers();
- bool SetMfcFormats();
- bool CreateMfcInputBuffers();
- bool CreateMfcOutputBuffers();
-
- // Destroy these buffers.
- void DestroyGscInputBuffers();
- void DestroyGscOutputBuffers();
- void DestroyMfcInputBuffers();
- void DestroyMfcOutputBuffers();
-
- // Our original calling message loop for the child thread.
- const scoped_refptr<base::MessageLoopProxy> child_message_loop_proxy_;
-
- // WeakPtr<> pointing to |this| for use in posting tasks from the encoder or
- // device worker threads back to the child thread. Because the worker threads
- // are members of this class, any task running on those threads is guaranteed
- // that this object is still alive. As a result, tasks posted from the child
- // thread to the encoder or device thread should use base::Unretained(this),
- // and tasks posted the other way should use |weak_this_|.
- base::WeakPtrFactory<ExynosVideoEncodeAccelerator> weak_this_ptr_factory_;
- base::WeakPtr<ExynosVideoEncodeAccelerator> weak_this_;
-
- // To expose client callbacks from VideoEncodeAccelerator.
- // NOTE: all calls to these objects *MUST* be executed on
- // child_message_loop_proxy_.
- base::WeakPtrFactory<Client> client_ptr_factory_;
- base::WeakPtr<Client> client_;
-
- //
- // Encoder state, owned and operated by encoder_thread_.
- // Before encoder_thread_ has started, the encoder state is managed by
- // the child (main) thread. After encoder_thread_ has started, the encoder
- // thread should be the only one managing these.
- //
-
- // This thread services tasks posted from the VEA API entry points by the
- // child thread and device service callbacks posted from the device thread.
- base::Thread encoder_thread_;
- // Encoder state.
- State encoder_state_;
- // The visible/allocated sizes of the input frame.
- gfx::Size input_visible_size_;
- gfx::Size input_allocated_size_;
- // The visible/allocated sizes of the color-converted intermediate frame.
- gfx::Size converted_visible_size_;
- gfx::Size converted_allocated_size_;
- // The logical visible size of the output frame.
- gfx::Size output_visible_size_;
- // The required byte size of output BitstreamBuffers.
- size_t output_buffer_byte_size_;
-
- // We need to provide the stream header with every keyframe, to allow
- // midstream decoding restarts. Store it here.
- scoped_ptr<uint8[]> stream_header_;
- size_t stream_header_size_;
-
- // V4L2 formats for input frames and the output stream.
- uint32 input_format_fourcc_;
- uint32 output_format_fourcc_;
-
- // Video frames ready to be encoded.
- std::list<scoped_refptr<media::VideoFrame> > encoder_input_queue_;
-
- // GSC color conversion device.
- int gsc_fd_;
- // GSC input queue state.
- bool gsc_input_streamon_;
- // GSC input buffers enqueued to device.
- int gsc_input_buffer_queued_count_;
- // GSC input buffers ready to use; LIFO since we don't care about ordering.
- std::vector<int> gsc_free_input_buffers_;
- // Mapping of int index to GSC input buffer record.
- std::vector<GscInputRecord> gsc_input_buffer_map_;
-
- // GSC output queue state.
- bool gsc_output_streamon_;
- // GSC output buffers enqueued to device.
- int gsc_output_buffer_queued_count_;
- // GSC output buffers ready to use; LIFO since we don't care about ordering.
- std::vector<int> gsc_free_output_buffers_;
- // Mapping of int index to GSC output buffer record.
- std::vector<GscOutputRecord> gsc_output_buffer_map_;
-
- // MFC input buffers filled by GSC, waiting to be queued to MFC.
- std::list<int> mfc_ready_input_buffers_;
-
- // MFC video encoding device.
- int mfc_fd_;
-
- // MFC input queue state.
- bool mfc_input_streamon_;
- // MFC input buffers enqueued to device.
- int mfc_input_buffer_queued_count_;
- // MFC input buffers ready to use; LIFO since we don't care about ordering.
- std::vector<int> mfc_free_input_buffers_;
- // Mapping of int index to MFC input buffer record.
- std::vector<MfcInputRecord> mfc_input_buffer_map_;
-
- // MFC output queue state.
- bool mfc_output_streamon_;
- // MFC output buffers enqueued to device.
- int mfc_output_buffer_queued_count_;
- // MFC output buffers ready to use; LIFO since we don't care about ordering.
- std::vector<int> mfc_free_output_buffers_;
- // Mapping of int index to MFC output buffer record.
- std::vector<MfcOutputRecord> mfc_output_buffer_map_;
-
- // Bitstream buffers ready to be used to return encoded output, as a LIFO
- // since we don't care about ordering.
- std::vector<linked_ptr<BitstreamBufferRef> > encoder_output_queue_;
-
- //
- // The device polling thread handles notifications of V4L2 device changes.
- // TODO(sheu): replace this thread with an TYPE_IO encoder_thread_.
- //
-
- // The thread.
- base::Thread device_poll_thread_;
- // eventfd fd to signal device poll thread when its poll() should be
- // interrupted.
- int device_poll_interrupt_fd_;
-
- DISALLOW_COPY_AND_ASSIGN(ExynosVideoEncodeAccelerator);
-};
-
-} // namespace content
-
-#endif // CONTENT_COMMON_GPU_MEDIA_EXYNOS_VIDEO_ENCODE_ACCELERATOR_H_
diff --git a/content/common/gpu/media/gpu_video_encode_accelerator.cc b/content/common/gpu/media/gpu_video_encode_accelerator.cc
index d49d9a9..b15f04b 100644
--- a/content/common/gpu/media/gpu_video_encode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_encode_accelerator.cc
@@ -13,10 +13,6 @@
#include "ipc/ipc_message_macros.h"
#include "media/base/video_frame.h"
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
-#include "content/common/gpu/media/exynos_video_encode_accelerator.h"
-#endif
-
namespace content {
GpuVideoEncodeAccelerator::GpuVideoEncodeAccelerator(GpuChannel* gpu_channel,
@@ -84,18 +80,12 @@ std::vector<media::VideoEncodeAccelerator::SupportedProfile>
GpuVideoEncodeAccelerator::GetSupportedProfiles() {
std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
- profiles = ExynosVideoEncodeAccelerator::GetSupportedProfiles();
-#endif
-
// TODO(sheu): return platform-specific profiles.
return profiles;
}
void GpuVideoEncodeAccelerator::CreateEncoder() {
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
- encoder_.reset(new ExynosVideoEncodeAccelerator(this));
-#endif
+ // TODO(sheu): actual create the encoder.
}
void GpuVideoEncodeAccelerator::OnInitialize(
@@ -157,7 +147,7 @@ void GpuVideoEncodeAccelerator::OnEncode(int32 frame_id,
scoped_refptr<media::VideoFrame> frame =
media::VideoFrame::WrapExternalSharedMemory(
- input_format_,
+ media::VideoFrame::I420,
input_coded_size_,
gfx::Rect(input_visible_size_),
input_visible_size_,
diff --git a/content/common/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_seccomp_bpf_linux.cc
index d6ebdad..5d8c42a 100644
--- a/content/common/sandbox_seccomp_bpf_linux.cc
+++ b/content/common/sandbox_seccomp_bpf_linux.cc
@@ -1794,18 +1794,13 @@ void AddArmMaliGpuWhitelist(std::vector<std::string>* read_whitelist,
static const char kDevMfcDecPath[] = "/dev/mfc-dec";
static const char kDevGsc1Path[] = "/dev/gsc1";
- // Devices needed for video encode acceleration on ARM.
- static const char kDevMfcEncPath[] = "/dev/mfc-enc";
-
read_whitelist->push_back(kMali0Path);
read_whitelist->push_back(kDevMfcDecPath);
read_whitelist->push_back(kDevGsc1Path);
- read_whitelist->push_back(kDevMfcEncPath);
write_whitelist->push_back(kMali0Path);
write_whitelist->push_back(kDevMfcDecPath);
write_whitelist->push_back(kDevGsc1Path);
- write_whitelist->push_back(kDevMfcEncPath);
}
void AddArmTegraGpuWhitelist(std::vector<std::string>* read_whitelist,
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 18ecdea..0747f02 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -490,8 +490,6 @@
'sources': [
'common/gpu/media/exynos_video_decode_accelerator.cc',
'common/gpu/media/exynos_video_decode_accelerator.h',
- 'common/gpu/media/exynos_video_encode_accelerator.cc',
- 'common/gpu/media/exynos_video_encode_accelerator.h',
],
'include_dirs': [
'<(DEPTH)/third_party/khronos',