OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |