Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: content/common/gpu/media/exynos_video_encode_accelerator.cc

Issue 185403020: Make VEA client of command buffer; move sync. IPC to VDA/VEA::Initialize() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 56683e7a Rebase. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/common/gpu/media/exynos_video_encode_accelerator.h" 5 #include "content/common/gpu/media/exynos_video_encode_accelerator.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <linux/videodev2.h> 8 #include <linux/videodev2.h>
9 #include <poll.h> 9 #include <poll.h>
10 #include <sys/eventfd.h> 10 #include <sys/eventfd.h>
11 #include <sys/ioctl.h> 11 #include <sys/ioctl.h>
12 #include <sys/mman.h> 12 #include <sys/mman.h>
13 13
14 #include "base/callback.h" 14 #include "base/callback.h"
15 #include "base/command_line.h" 15 #include "base/command_line.h"
16 #include "base/debug/trace_event.h" 16 #include "base/debug/trace_event.h"
17 #include "base/message_loop/message_loop_proxy.h" 17 #include "base/message_loop/message_loop_proxy.h"
18 #include "base/posix/eintr_wrapper.h" 18 #include "base/posix/eintr_wrapper.h"
19 #include "content/public/common/content_switches.h" 19 #include "content/public/common/content_switches.h"
20 #include "media/base/bitstream_buffer.h" 20 #include "media/base/bitstream_buffer.h"
21 21
22 #define NOTIFY_ERROR(x) \ 22 #define NOTIFY_ERROR(x) \
23 do { \ 23 do { \
24 SetEncoderState(kError); \ 24 SetEncoderState(kError); \
25 DLOG(ERROR) << "calling NotifyError(): " << x; \ 25 DLOG(ERROR) << "calling NotifyError(): " << x; \
26 NotifyError(x); \ 26 NotifyError(x); \
27 } while (0) 27 } while (0)
28 28
29 #define IOCTL_OR_ERROR_RETURN(fd, type, arg) \ 29 #define IOCTL_OR_ERROR_RETURN_VALUE(fd, type, arg, value) \
30 do { \ 30 do { \
31 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \ 31 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \
32 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ 32 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \
33 NOTIFY_ERROR(kPlatformFailureError); \ 33 NOTIFY_ERROR(kPlatformFailureError); \
34 return; \ 34 return value; \
35 } \ 35 } \
36 } while (0) 36 } while (0)
37 37
38 #define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg) \ 38 #define IOCTL_OR_ERROR_RETURN(fd, type, arg) \
39 do { \ 39 IOCTL_OR_ERROR_RETURN_VALUE(fd, type, arg, ((void)0))
Pawel Osciak 2014/03/13 06:18:13 You could also just s/((void)0)// I think?
sheu 2014/03/13 22:39:52 I think that's a gcc-specific extension.
40 if (HANDLE_EINTR(ioctl(fd, type, arg) != 0)) { \ 40
41 DPLOG(ERROR) << __func__ << "(): ioctl() failed: " << #type; \ 41 #define IOCTL_OR_ERROR_RETURN_FALSE(fd, type, arg) \
42 NOTIFY_ERROR(kPlatformFailureError); \ 42 IOCTL_OR_ERROR_RETURN_VALUE(fd, type, arg, false)
43 return false; \
44 } \
45 } while (0)
46 43
47 namespace content { 44 namespace content {
48 45
49 namespace { 46 namespace {
50 47
51 const char kExynosGscDevice[] = "/dev/gsc1"; 48 const char kExynosGscDevice[] = "/dev/gsc1";
52 const char kExynosMfcDevice[] = "/dev/mfc-enc"; 49 const char kExynosMfcDevice[] = "/dev/mfc-enc";
53 50
54 // File descriptors we need to poll, one-bit flag for each. 51 // File descriptors we need to poll, one-bit flag for each.
55 enum PollFds { 52 enum PollFds {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 gsc_fd_ = -1; 117 gsc_fd_ = -1;
121 } 118 }
122 if (mfc_fd_ != -1) { 119 if (mfc_fd_ != -1) {
123 DestroyMfcInputBuffers(); 120 DestroyMfcInputBuffers();
124 DestroyMfcOutputBuffers(); 121 DestroyMfcOutputBuffers();
125 close(mfc_fd_); 122 close(mfc_fd_);
126 mfc_fd_ = -1; 123 mfc_fd_ = -1;
127 } 124 }
128 } 125 }
129 126
130 void ExynosVideoEncodeAccelerator::Initialize( 127 bool ExynosVideoEncodeAccelerator::Initialize(
131 media::VideoFrame::Format input_format, 128 media::VideoFrame::Format input_format,
132 const gfx::Size& input_visible_size, 129 const gfx::Size& input_visible_size,
133 media::VideoCodecProfile output_profile, 130 media::VideoCodecProfile output_profile,
134 uint32 initial_bitrate, 131 uint32 initial_bitrate,
135 Client* client) { 132 Client* client) {
136 DVLOG(3) << "Initialize(): input_format=" << input_format 133 DVLOG(3) << "Initialize(): input_format=" << input_format
137 << ", input_visible_size=" << input_visible_size.ToString() 134 << ", input_visible_size=" << input_visible_size.ToString()
138 << ", output_profile=" << output_profile 135 << ", output_profile=" << output_profile
139 << ", initial_bitrate=" << initial_bitrate; 136 << ", initial_bitrate=" << initial_bitrate;
140 137
(...skipping 11 matching lines...) Expand all
152 converted_allocated_size_.SetSize( 149 converted_allocated_size_.SetSize(
153 (converted_visible_size_.width() + 0xF) & ~0xF, 150 (converted_visible_size_.width() + 0xF) & ~0xF,
154 (converted_visible_size_.height() + 0xF) & ~0xF); 151 (converted_visible_size_.height() + 0xF) & ~0xF);
155 output_visible_size_ = converted_visible_size_; 152 output_visible_size_ = converted_visible_size_;
156 153
157 switch (input_format) { 154 switch (input_format) {
158 case media::VideoFrame::I420: 155 case media::VideoFrame::I420:
159 input_format_fourcc_ = V4L2_PIX_FMT_YUV420M; 156 input_format_fourcc_ = V4L2_PIX_FMT_YUV420M;
160 break; 157 break;
161 default: 158 default:
162 NOTIFY_ERROR(kInvalidArgumentError); 159 DLOG(ERROR) << "Initialize(): invalid input_format=" << input_format;
163 return; 160 return false;
164 } 161 }
165 162
166 if (output_profile >= media::H264PROFILE_MIN && 163 if (output_profile >= media::H264PROFILE_MIN &&
167 output_profile <= media::H264PROFILE_MAX) { 164 output_profile <= media::H264PROFILE_MAX) {
168 output_format_fourcc_ = V4L2_PIX_FMT_H264; 165 output_format_fourcc_ = V4L2_PIX_FMT_H264;
169 } else if (output_profile >= media::VP8PROFILE_MIN && 166 } else if (output_profile >= media::VP8PROFILE_MIN &&
170 output_profile <= media::VP8PROFILE_MAX) { 167 output_profile <= media::VP8PROFILE_MAX) {
171 output_format_fourcc_ = V4L2_PIX_FMT_VP8; 168 output_format_fourcc_ = V4L2_PIX_FMT_VP8;
172 } else { 169 } else {
173 NOTIFY_ERROR(kInvalidArgumentError); 170 DLOG(ERROR) << "Initialize(): invalid output_profile=" << output_profile;
174 return; 171 return false;
175 } 172 }
176 173
177 // Open the color conversion device. 174 // Open the color conversion device.
178 DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice; 175 DVLOG(2) << "Initialize(): opening GSC device: " << kExynosGscDevice;
179 gsc_fd_ = 176 gsc_fd_ =
180 HANDLE_EINTR(open(kExynosGscDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC)); 177 HANDLE_EINTR(open(kExynosGscDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
181 if (gsc_fd_ == -1) { 178 if (gsc_fd_ == -1) {
182 DPLOG(ERROR) << "Initialize(): could not open GSC device: " 179 DPLOG(ERROR) << "Initialize(): could not open GSC device: "
183 << kExynosGscDevice; 180 << kExynosGscDevice;
184 NOTIFY_ERROR(kPlatformFailureError); 181 return false;
185 return;
186 } 182 }
187 183
188 // Capabilities check. 184 // Capabilities check.
189 struct v4l2_capability caps; 185 struct v4l2_capability caps;
190 memset(&caps, 0, sizeof(caps)); 186 memset(&caps, 0, sizeof(caps));
191 const __u32 kCapsRequired = V4L2_CAP_VIDEO_CAPTURE_MPLANE | 187 const __u32 kCapsRequired = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
192 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING; 188 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING;
193 IOCTL_OR_ERROR_RETURN(gsc_fd_, VIDIOC_QUERYCAP, &caps); 189 if (HANDLE_EINTR(ioctl(gsc_fd_, VIDIOC_QUERYCAP, &caps))) {
190 DPLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP";
191 return false;
192 }
194 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { 193 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
195 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " 194 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
196 "caps check failed: 0x" << std::hex << caps.capabilities; 195 "caps check failed: 0x" << std::hex << caps.capabilities;
197 NOTIFY_ERROR(kPlatformFailureError); 196 return false;
198 return;
199 } 197 }
200 198
201 // Open the video encoder device. 199 // Open the video encoder device.
202 DVLOG(2) << "Initialize(): opening MFC device: " << kExynosMfcDevice; 200 DVLOG(2) << "Initialize(): opening MFC device: " << kExynosMfcDevice;
203 mfc_fd_ = 201 mfc_fd_ =
204 HANDLE_EINTR(open(kExynosMfcDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC)); 202 HANDLE_EINTR(open(kExynosMfcDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC));
205 if (mfc_fd_ == -1) { 203 if (mfc_fd_ == -1) {
206 DPLOG(ERROR) << "Initialize(): could not open MFC device: " 204 DPLOG(ERROR) << "Initialize(): could not open MFC device: "
207 << kExynosMfcDevice; 205 << kExynosMfcDevice;
208 NOTIFY_ERROR(kPlatformFailureError); 206 return false;
209 return;
210 } 207 }
211 208
212 memset(&caps, 0, sizeof(caps)); 209 memset(&caps, 0, sizeof(caps));
213 IOCTL_OR_ERROR_RETURN(mfc_fd_, VIDIOC_QUERYCAP, &caps); 210 if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_QUERYCAP, &caps))) {
211 DPLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP";
212 return false;
213 }
214 if ((caps.capabilities & kCapsRequired) != kCapsRequired) { 214 if ((caps.capabilities & kCapsRequired) != kCapsRequired) {
215 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: " 215 DLOG(ERROR) << "Initialize(): ioctl() failed: VIDIOC_QUERYCAP: "
216 "caps check failed: 0x" << std::hex << caps.capabilities; 216 "caps check failed: 0x" << std::hex << caps.capabilities;
217 NOTIFY_ERROR(kPlatformFailureError); 217 return false;
218 return;
219 } 218 }
220 219
221 // Create the interrupt fd. 220 // Create the interrupt fd.
222 DCHECK_EQ(device_poll_interrupt_fd_, -1); 221 DCHECK_EQ(device_poll_interrupt_fd_, -1);
223 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 222 device_poll_interrupt_fd_ = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
224 if (device_poll_interrupt_fd_ == -1) { 223 if (device_poll_interrupt_fd_ == -1) {
225 DPLOG(ERROR) << "Initialize(): eventfd() failed"; 224 DPLOG(ERROR) << "Initialize(): eventfd() failed";
226 NOTIFY_ERROR(kPlatformFailureError); 225 return false;
227 return;
228 } 226 }
229 227
230 DVLOG(3) 228 DVLOG(3)
231 << "Initialize(): input_visible_size_=" << input_visible_size_.ToString() 229 << "Initialize(): input_visible_size_=" << input_visible_size_.ToString()
232 << ", input_allocated_size_=" << input_allocated_size_.ToString() 230 << ", input_allocated_size_=" << input_allocated_size_.ToString()
233 << ", converted_visible_size_=" << converted_visible_size_.ToString() 231 << ", converted_visible_size_=" << converted_visible_size_.ToString()
234 << ", converted_allocated_size_=" << converted_allocated_size_.ToString() 232 << ", converted_allocated_size_=" << converted_allocated_size_.ToString()
235 << ", output_visible_size_=" << output_visible_size_.ToString(); 233 << ", output_visible_size_=" << output_visible_size_.ToString();
236 234
237 if (!CreateGscInputBuffers() || !CreateGscOutputBuffers()) 235 if (!CreateGscInputBuffers() || !CreateGscOutputBuffers())
238 return; 236 return false;
239 237
240 // MFC setup for encoding is rather particular in ordering: 238 // MFC setup for encoding is rather particular in ordering:
241 // 239 //
242 // 1. Format (VIDIOC_S_FMT) set first on OUTPUT and CAPTURE queues. 240 // 1. Format (VIDIOC_S_FMT) set first on OUTPUT and CAPTURE queues.
243 // 2. VIDIOC_REQBUFS, VIDIOC_QBUF, and VIDIOC_STREAMON on CAPTURE queue. 241 // 2. VIDIOC_REQBUFS, VIDIOC_QBUF, and VIDIOC_STREAMON on CAPTURE queue.
244 // 3. VIDIOC_REQBUFS (and later VIDIOC_QBUF and VIDIOC_STREAMON) on OUTPUT 242 // 3. VIDIOC_REQBUFS (and later VIDIOC_QBUF and VIDIOC_STREAMON) on OUTPUT
245 // queue. 243 // queue.
246 // 244 //
247 // Unfortunately, we cannot do (3) in Initialize() here since we have no 245 // Unfortunately, we cannot do (3) in Initialize() here since we have no
248 // buffers to QBUF in step (2) until the client has provided output buffers 246 // buffers to QBUF in step (2) until the client has provided output buffers
249 // through UseOutputBitstreamBuffer(). So, we just do (1), and the 247 // through UseOutputBitstreamBuffer(). So, we just do (1), and the
250 // VIDIOC_REQBUFS part of (2) here. The rest is done the first time we get 248 // VIDIOC_REQBUFS part of (2) here. The rest is done the first time we get
251 // a UseOutputBitstreamBuffer() callback. 249 // a UseOutputBitstreamBuffer() callback.
252 250
253 if (!SetMfcFormats()) 251 if (!SetMfcFormats())
254 return; 252 return false;
255 253
256 if (!InitMfcControls()) 254 if (!InitMfcControls())
257 return; 255 return false;
258 256
259 // VIDIOC_REQBUFS on CAPTURE queue. 257 // VIDIOC_REQBUFS on CAPTURE queue.
260 if (!CreateMfcOutputBuffers()) 258 if (!CreateMfcOutputBuffers())
261 return; 259 return false;
262
263 260
264 if (!encoder_thread_.Start()) { 261 if (!encoder_thread_.Start()) {
265 DLOG(ERROR) << "Initialize(): encoder thread failed to start"; 262 DLOG(ERROR) << "Initialize(): encoder thread failed to start";
266 NOTIFY_ERROR(kPlatformFailureError); 263 return false;
267 return;
268 } 264 }
269 265
270 RequestEncodingParametersChange(initial_bitrate, kInitialFramerate); 266 RequestEncodingParametersChange(initial_bitrate, kInitialFramerate);
271 267
272 SetEncoderState(kInitialized); 268 SetEncoderState(kInitialized);
273 269
274 child_message_loop_proxy_->PostTask( 270 child_message_loop_proxy_->PostTask(
275 FROM_HERE, base::Bind(&Client::NotifyInitializeDone, client_));
276
277 child_message_loop_proxy_->PostTask(
278 FROM_HERE, 271 FROM_HERE,
279 base::Bind(&Client::RequireBitstreamBuffers, 272 base::Bind(&Client::RequireBitstreamBuffers,
280 client_, 273 client_,
281 gsc_input_buffer_map_.size(), 274 gsc_input_buffer_map_.size(),
282 input_allocated_size_, 275 input_allocated_size_,
283 output_buffer_byte_size_)); 276 output_buffer_byte_size_));
277 return true;
284 } 278 }
285 279
286 void ExynosVideoEncodeAccelerator::Encode( 280 void ExynosVideoEncodeAccelerator::Encode(
287 const scoped_refptr<media::VideoFrame>& frame, 281 const scoped_refptr<media::VideoFrame>& frame,
288 bool force_keyframe) { 282 bool force_keyframe) {
289 DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe; 283 DVLOG(3) << "Encode(): force_keyframe=" << force_keyframe;
290 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); 284 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread());
291 285
292 encoder_thread_.message_loop()->PostTask( 286 encoder_thread_.message_loop()->PostTask(
293 FROM_HERE, 287 FROM_HERE,
(...skipping 1243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1537 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 1531 reqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1538 reqbufs.memory = V4L2_MEMORY_MMAP; 1532 reqbufs.memory = V4L2_MEMORY_MMAP;
1539 if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0) 1533 if (HANDLE_EINTR(ioctl(mfc_fd_, VIDIOC_REQBUFS, &reqbufs)) != 0)
1540 DPLOG(ERROR) << "DestroyMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS"; 1534 DPLOG(ERROR) << "DestroyMfcOutputBuffers(): ioctl() failed: VIDIOC_REQBUFS";
1541 1535
1542 mfc_output_buffer_map_.clear(); 1536 mfc_output_buffer_map_.clear();
1543 mfc_free_output_buffers_.clear(); 1537 mfc_free_output_buffers_.clear();
1544 } 1538 }
1545 1539
1546 } // namespace content 1540 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698