OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 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 <dlfcn.h> | 5 #include <dlfcn.h> |
6 #include <errno.h> | 6 #include <errno.h> |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <libdrm/drm_fourcc.h> | 8 #include <libdrm/drm_fourcc.h> |
9 #include <linux/videodev2.h> | 9 #include <linux/videodev2.h> |
10 #include <poll.h> | 10 #include <poll.h> |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} | 153 V4L2VideoDecodeAccelerator::PictureRecord::~PictureRecord() {} |
154 | 154 |
155 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( | 155 V4L2VideoDecodeAccelerator::V4L2VideoDecodeAccelerator( |
156 EGLDisplay egl_display, | 156 EGLDisplay egl_display, |
157 const base::WeakPtr<Client>& io_client, | 157 const base::WeakPtr<Client>& io_client, |
158 const base::Callback<bool(void)>& make_context_current, | 158 const base::Callback<bool(void)>& make_context_current, |
159 scoped_ptr<V4L2Device> device, | 159 scoped_ptr<V4L2Device> device, |
160 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) | 160 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy) |
161 : child_message_loop_proxy_(base::MessageLoopProxy::current()), | 161 : child_message_loop_proxy_(base::MessageLoopProxy::current()), |
162 io_message_loop_proxy_(io_message_loop_proxy), | 162 io_message_loop_proxy_(io_message_loop_proxy), |
163 weak_this_(base::AsWeakPtr(this)), | |
164 io_client_(io_client), | 163 io_client_(io_client), |
165 decoder_thread_("V4L2DecoderThread"), | 164 decoder_thread_("V4L2DecoderThread"), |
166 decoder_state_(kUninitialized), | 165 decoder_state_(kUninitialized), |
167 device_(device.Pass()), | 166 device_(device.Pass()), |
168 decoder_delay_bitstream_buffer_id_(-1), | 167 decoder_delay_bitstream_buffer_id_(-1), |
169 decoder_current_input_buffer_(-1), | 168 decoder_current_input_buffer_(-1), |
170 decoder_decode_buffer_tasks_scheduled_(0), | 169 decoder_decode_buffer_tasks_scheduled_(0), |
171 decoder_frames_at_client_(0), | 170 decoder_frames_at_client_(0), |
172 decoder_flushing_(false), | 171 decoder_flushing_(false), |
173 resolution_change_pending_(false), | 172 resolution_change_pending_(false), |
174 resolution_change_reset_pending_(false), | 173 resolution_change_reset_pending_(false), |
175 decoder_partial_frame_pending_(false), | 174 decoder_partial_frame_pending_(false), |
176 input_streamon_(false), | 175 input_streamon_(false), |
177 input_buffer_queued_count_(0), | 176 input_buffer_queued_count_(0), |
178 output_streamon_(false), | 177 output_streamon_(false), |
179 output_buffer_queued_count_(0), | 178 output_buffer_queued_count_(0), |
180 output_buffer_pixelformat_(0), | 179 output_buffer_pixelformat_(0), |
181 output_dpb_size_(0), | 180 output_dpb_size_(0), |
182 picture_clearing_count_(0), | 181 picture_clearing_count_(0), |
183 pictures_assigned_(false, false), | 182 pictures_assigned_(false, false), |
184 device_poll_thread_("V4L2DevicePollThread"), | 183 device_poll_thread_("V4L2DevicePollThread"), |
185 make_context_current_(make_context_current), | 184 make_context_current_(make_context_current), |
186 egl_display_(egl_display), | 185 egl_display_(egl_display), |
187 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN) {} | 186 video_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 187 weak_this_factory_(this) { |
| 188 weak_this_ = weak_this_factory_.GetWeakPtr(); |
| 189 } |
188 | 190 |
189 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { | 191 V4L2VideoDecodeAccelerator::~V4L2VideoDecodeAccelerator() { |
190 DCHECK(!decoder_thread_.IsRunning()); | 192 DCHECK(!decoder_thread_.IsRunning()); |
191 DCHECK(!device_poll_thread_.IsRunning()); | 193 DCHECK(!device_poll_thread_.IsRunning()); |
192 | 194 |
193 DestroyInputBuffers(); | 195 DestroyInputBuffers(); |
194 DestroyOutputBuffers(); | 196 DestroyOutputBuffers(); |
195 | 197 |
196 // These maps have members that should be manually destroyed, e.g. file | 198 // These maps have members that should be manually destroyed, e.g. file |
197 // descriptors, mmap() segments, etc. | 199 // descriptors, mmap() segments, etc. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 decoder_h264_parser_.reset(new media::H264Parser()); | 284 decoder_h264_parser_.reset(new media::H264Parser()); |
283 } | 285 } |
284 | 286 |
285 if (!decoder_thread_.Start()) { | 287 if (!decoder_thread_.Start()) { |
286 DLOG(ERROR) << "Initialize(): decoder thread failed to start"; | 288 DLOG(ERROR) << "Initialize(): decoder thread failed to start"; |
287 NOTIFY_ERROR(PLATFORM_FAILURE); | 289 NOTIFY_ERROR(PLATFORM_FAILURE); |
288 return false; | 290 return false; |
289 } | 291 } |
290 | 292 |
291 SetDecoderState(kInitialized); | 293 SetDecoderState(kInitialized); |
292 | |
293 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | |
294 &Client::NotifyInitializeDone, client_)); | |
295 return true; | 294 return true; |
296 } | 295 } |
297 | 296 |
298 void V4L2VideoDecodeAccelerator::Decode( | 297 void V4L2VideoDecodeAccelerator::Decode( |
299 const media::BitstreamBuffer& bitstream_buffer) { | 298 const media::BitstreamBuffer& bitstream_buffer) { |
300 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() | 299 DVLOG(1) << "Decode(): input_id=" << bitstream_buffer.id() |
301 << ", size=" << bitstream_buffer.size(); | 300 << ", size=" << bitstream_buffer.size(); |
302 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 301 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); |
303 | 302 |
304 // DecodeTask() will take care of running a DecodeBufferTask(). | 303 // DecodeTask() will take care of running a DecodeBufferTask(). |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 420 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
422 &V4L2VideoDecodeAccelerator::ResetTask, base::Unretained(this))); | 421 &V4L2VideoDecodeAccelerator::ResetTask, base::Unretained(this))); |
423 } | 422 } |
424 | 423 |
425 void V4L2VideoDecodeAccelerator::Destroy() { | 424 void V4L2VideoDecodeAccelerator::Destroy() { |
426 DVLOG(3) << "Destroy()"; | 425 DVLOG(3) << "Destroy()"; |
427 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); | 426 DCHECK(child_message_loop_proxy_->BelongsToCurrentThread()); |
428 | 427 |
429 // We're destroying; cancel all callbacks. | 428 // We're destroying; cancel all callbacks. |
430 client_ptr_factory_.reset(); | 429 client_ptr_factory_.reset(); |
| 430 weak_this_factory_.InvalidateWeakPtrs(); |
431 | 431 |
432 // If the decoder thread is running, destroy using posted task. | 432 // If the decoder thread is running, destroy using posted task. |
433 if (decoder_thread_.IsRunning()) { | 433 if (decoder_thread_.IsRunning()) { |
434 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 434 decoder_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
435 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this))); | 435 &V4L2VideoDecodeAccelerator::DestroyTask, base::Unretained(this))); |
436 pictures_assigned_.Signal(); | 436 pictures_assigned_.Signal(); |
437 // DestroyTask() will cause the decoder_thread_ to flush all tasks. | 437 // DestroyTask() will cause the decoder_thread_ to flush all tasks. |
438 decoder_thread_.Stop(); | 438 decoder_thread_.Stop(); |
439 } else { | 439 } else { |
440 // Otherwise, call the destroy task directly. | 440 // Otherwise, call the destroy task directly. |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 | 748 |
749 // We expect to process the initial buffer once during stream init to | 749 // We expect to process the initial buffer once during stream init to |
750 // configure stream parameters, but will not consume the steam data on that | 750 // configure stream parameters, but will not consume the steam data on that |
751 // iteration. Subsequent iterations (including after reset) do not require | 751 // iteration. Subsequent iterations (including after reset) do not require |
752 // the stream init step. | 752 // the stream init step. |
753 *endpos = 0; | 753 *endpos = 0; |
754 } else { | 754 } else { |
755 *endpos = size; | 755 *endpos = size; |
756 } | 756 } |
757 | 757 |
758 // StartDevicePoll will raise the error if there is one. | 758 if (!StartDevicePoll()) { |
759 if (!StartDevicePoll()) | 759 NOTIFY_ERROR(PLATFORM_FAILURE); |
760 return false; | 760 return false; |
| 761 } |
761 | 762 |
762 decoder_state_ = kDecoding; | 763 decoder_state_ = kDecoding; |
763 ScheduleDecodeBufferTaskIfNeeded(); | 764 ScheduleDecodeBufferTaskIfNeeded(); |
764 return true; | 765 return true; |
765 } | 766 } |
766 | 767 |
767 bool V4L2VideoDecodeAccelerator::DecodeBufferContinue( | 768 bool V4L2VideoDecodeAccelerator::DecodeBufferContinue( |
768 const void* data, size_t size) { | 769 const void* data, size_t size) { |
769 DVLOG(3) << "DecodeBufferContinue(): data=" << data << ", size=" << size; | 770 DVLOG(3) << "DecodeBufferContinue(): data=" << data << ", size=" << size; |
770 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 771 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1277 | 1278 |
1278 // TODO(posciak): crbug.com/270039. Exynos requires a streamoff-streamon | 1279 // TODO(posciak): crbug.com/270039. Exynos requires a streamoff-streamon |
1279 // sequence after flush to continue, even if we are not resetting. This would | 1280 // sequence after flush to continue, even if we are not resetting. This would |
1280 // make sense, because we don't really want to resume from a non-resume point | 1281 // make sense, because we don't really want to resume from a non-resume point |
1281 // (e.g. not from an IDR) if we are flushed. | 1282 // (e.g. not from an IDR) if we are flushed. |
1282 // MSE player however triggers a Flush() on chunk end, but never Reset(). One | 1283 // MSE player however triggers a Flush() on chunk end, but never Reset(). One |
1283 // could argue either way, or even say that Flush() is not needed/harmful when | 1284 // could argue either way, or even say that Flush() is not needed/harmful when |
1284 // transitioning to next chunk. | 1285 // transitioning to next chunk. |
1285 // For now, do the streamoff-streamon cycle to satisfy Exynos and not freeze | 1286 // For now, do the streamoff-streamon cycle to satisfy Exynos and not freeze |
1286 // when doing MSE. This should be harmless otherwise. | 1287 // when doing MSE. This should be harmless otherwise. |
1287 if (!StopDevicePoll(false)) | 1288 if (!StopDevicePoll(false)) { |
| 1289 NOTIFY_ERROR(PLATFORM_FAILURE); |
1288 return; | 1290 return; |
| 1291 } |
1289 | 1292 |
1290 if (!StartDevicePoll()) | 1293 if (!StartDevicePoll()) { |
| 1294 NOTIFY_ERROR(PLATFORM_FAILURE); |
1291 return; | 1295 return; |
| 1296 } |
1292 | 1297 |
1293 decoder_delay_bitstream_buffer_id_ = -1; | 1298 decoder_delay_bitstream_buffer_id_ = -1; |
1294 decoder_flushing_ = false; | 1299 decoder_flushing_ = false; |
1295 DVLOG(3) << "NotifyFlushDoneIfNeeded(): returning flush"; | 1300 DVLOG(3) << "NotifyFlushDoneIfNeeded(): returning flush"; |
1296 child_message_loop_proxy_->PostTask( | 1301 child_message_loop_proxy_->PostTask( |
1297 FROM_HERE, base::Bind(&Client::NotifyFlushDone, client_)); | 1302 FROM_HERE, base::Bind(&Client::NotifyFlushDone, client_)); |
1298 | 1303 |
1299 // While we were flushing, we early-outed DecodeBufferTask()s. | 1304 // While we were flushing, we early-outed DecodeBufferTask()s. |
1300 ScheduleDecodeBufferTaskIfNeeded(); | 1305 ScheduleDecodeBufferTaskIfNeeded(); |
1301 } | 1306 } |
(...skipping 13 matching lines...) Expand all Loading... |
1315 // because input pipe is already stopped if we are changing resolution. | 1320 // because input pipe is already stopped if we are changing resolution. |
1316 // We will come back here after we are done with the resolution change. | 1321 // We will come back here after we are done with the resolution change. |
1317 DCHECK(!resolution_change_reset_pending_); | 1322 DCHECK(!resolution_change_reset_pending_); |
1318 if (resolution_change_pending_ || decoder_state_ == kChangingResolution) { | 1323 if (resolution_change_pending_ || decoder_state_ == kChangingResolution) { |
1319 resolution_change_reset_pending_ = true; | 1324 resolution_change_reset_pending_ = true; |
1320 return; | 1325 return; |
1321 } | 1326 } |
1322 | 1327 |
1323 // We stop streaming and clear buffer tracking info (not preserving inputs). | 1328 // We stop streaming and clear buffer tracking info (not preserving inputs). |
1324 // StopDevicePoll() unconditionally does _not_ destroy buffers, however. | 1329 // StopDevicePoll() unconditionally does _not_ destroy buffers, however. |
1325 if (!StopDevicePoll(false)) | 1330 if (!StopDevicePoll(false)) { |
| 1331 NOTIFY_ERROR(PLATFORM_FAILURE); |
1326 return; | 1332 return; |
| 1333 } |
1327 | 1334 |
1328 decoder_current_bitstream_buffer_.reset(); | 1335 decoder_current_bitstream_buffer_.reset(); |
1329 while (!decoder_input_queue_.empty()) | 1336 while (!decoder_input_queue_.empty()) |
1330 decoder_input_queue_.pop(); | 1337 decoder_input_queue_.pop(); |
1331 | 1338 |
1332 decoder_current_input_buffer_ = -1; | 1339 decoder_current_input_buffer_ = -1; |
1333 | 1340 |
1334 // If we were flushing, we'll never return any more BitstreamBuffers or | 1341 // If we were flushing, we'll never return any more BitstreamBuffers or |
1335 // PictureBuffers; they have all been dropped and returned by now. | 1342 // PictureBuffers; they have all been dropped and returned by now. |
1336 NotifyFlushDoneIfNeeded(); | 1343 NotifyFlushDoneIfNeeded(); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1406 } | 1413 } |
1407 | 1414 |
1408 bool V4L2VideoDecodeAccelerator::StartDevicePoll() { | 1415 bool V4L2VideoDecodeAccelerator::StartDevicePoll() { |
1409 DVLOG(3) << "StartDevicePoll()"; | 1416 DVLOG(3) << "StartDevicePoll()"; |
1410 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1417 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1411 DCHECK(!device_poll_thread_.IsRunning()); | 1418 DCHECK(!device_poll_thread_.IsRunning()); |
1412 | 1419 |
1413 // Start up the device poll thread and schedule its first DevicePollTask(). | 1420 // Start up the device poll thread and schedule its first DevicePollTask(). |
1414 if (!device_poll_thread_.Start()) { | 1421 if (!device_poll_thread_.Start()) { |
1415 DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; | 1422 DLOG(ERROR) << "StartDevicePoll(): Device thread failed to start"; |
1416 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1417 return false; | 1423 return false; |
1418 } | 1424 } |
1419 device_poll_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( | 1425 device_poll_thread_.message_loop()->PostTask(FROM_HERE, base::Bind( |
1420 &V4L2VideoDecodeAccelerator::DevicePollTask, | 1426 &V4L2VideoDecodeAccelerator::DevicePollTask, |
1421 base::Unretained(this), | 1427 base::Unretained(this), |
1422 0)); | 1428 0)); |
1423 | 1429 |
1424 return true; | 1430 return true; |
1425 } | 1431 } |
1426 | 1432 |
1427 bool V4L2VideoDecodeAccelerator::StopDevicePoll(bool keep_input_state) { | 1433 bool V4L2VideoDecodeAccelerator::StopDevicePoll(bool keep_input_state) { |
1428 DVLOG(3) << "StopDevicePoll()"; | 1434 DVLOG(3) << "StopDevicePoll()"; |
1429 if (decoder_thread_.IsRunning()) | 1435 if (decoder_thread_.IsRunning()) |
1430 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1436 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1431 | 1437 |
1432 // Signal the DevicePollTask() to stop, and stop the device poll thread. | 1438 // Signal the DevicePollTask() to stop, and stop the device poll thread. |
1433 if (!device_->SetDevicePollInterrupt()) { | 1439 if (!device_->SetDevicePollInterrupt()) { |
1434 DPLOG(ERROR) << "SetDevicePollInterrupt(): failed"; | 1440 DPLOG(ERROR) << "SetDevicePollInterrupt(): failed"; |
1435 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1436 return false; | 1441 return false; |
1437 } | 1442 } |
1438 device_poll_thread_.Stop(); | 1443 device_poll_thread_.Stop(); |
1439 // Clear the interrupt now, to be sure. | 1444 // Clear the interrupt now, to be sure. |
1440 if (!device_->ClearDevicePollInterrupt()) { | 1445 if (!device_->ClearDevicePollInterrupt()) { |
1441 NOTIFY_ERROR(PLATFORM_FAILURE); | |
1442 return false; | 1446 return false; |
1443 } | 1447 } |
1444 | 1448 |
1445 // Stop streaming. | 1449 // Stop streaming. |
1446 if (!keep_input_state) { | 1450 if (!keep_input_state) { |
1447 if (input_streamon_) { | 1451 if (input_streamon_) { |
1448 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 1452 __u32 type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
1449 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); | 1453 IOCTL_OR_ERROR_RETURN_FALSE(VIDIOC_STREAMOFF, &type); |
1450 } | 1454 } |
1451 input_streamon_ = false; | 1455 input_streamon_ = false; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1496 void V4L2VideoDecodeAccelerator::StartResolutionChangeIfNeeded() { | 1500 void V4L2VideoDecodeAccelerator::StartResolutionChangeIfNeeded() { |
1497 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1501 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1498 DCHECK_EQ(decoder_state_, kDecoding); | 1502 DCHECK_EQ(decoder_state_, kDecoding); |
1499 | 1503 |
1500 if (!resolution_change_pending_) | 1504 if (!resolution_change_pending_) |
1501 return; | 1505 return; |
1502 | 1506 |
1503 DVLOG(3) << "No more work, initiate resolution change"; | 1507 DVLOG(3) << "No more work, initiate resolution change"; |
1504 | 1508 |
1505 // Keep input queue. | 1509 // Keep input queue. |
1506 if (!StopDevicePoll(true)) | 1510 if (!StopDevicePoll(true)) { |
| 1511 NOTIFY_ERROR(PLATFORM_FAILURE); |
1507 return; | 1512 return; |
| 1513 } |
1508 | 1514 |
1509 decoder_state_ = kChangingResolution; | 1515 decoder_state_ = kChangingResolution; |
1510 DCHECK(resolution_change_pending_); | 1516 DCHECK(resolution_change_pending_); |
1511 resolution_change_pending_ = false; | 1517 resolution_change_pending_ = false; |
1512 | 1518 |
1513 // Post a task to clean up buffers on child thread. This will also ensure | 1519 // Post a task to clean up buffers on child thread. This will also ensure |
1514 // that we won't accept ReusePictureBuffer() anymore after that. | 1520 // that we won't accept ReusePictureBuffer() anymore after that. |
1515 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( | 1521 child_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( |
1516 &V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers, | 1522 &V4L2VideoDecodeAccelerator::ResolutionChangeDestroyBuffers, |
1517 weak_this_)); | 1523 weak_this_)); |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1919 | 1925 |
1920 void V4L2VideoDecodeAccelerator::PictureCleared() { | 1926 void V4L2VideoDecodeAccelerator::PictureCleared() { |
1921 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; | 1927 DVLOG(3) << "PictureCleared(). clearing count=" << picture_clearing_count_; |
1922 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); | 1928 DCHECK_EQ(decoder_thread_.message_loop(), base::MessageLoop::current()); |
1923 DCHECK_GT(picture_clearing_count_, 0); | 1929 DCHECK_GT(picture_clearing_count_, 0); |
1924 picture_clearing_count_--; | 1930 picture_clearing_count_--; |
1925 SendPictureReady(); | 1931 SendPictureReady(); |
1926 } | 1932 } |
1927 | 1933 |
1928 } // namespace content | 1934 } // namespace content |
OLD | NEW |