| 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 <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include <CoreVideo/CoreVideo.h> | 7 #include <CoreVideo/CoreVideo.h> |
| 8 #include <OpenGL/CGLIOSurface.h> | 8 #include <OpenGL/CGLIOSurface.h> |
| 9 #include <OpenGL/gl.h> | 9 #include <OpenGL/gl.h> |
| 10 | 10 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 // that we can bind decoded frames to. We need enough to satisfy preroll, and | 58 // that we can bind decoded frames to. We need enough to satisfy preroll, and |
| 59 // enough to avoid unnecessary stalling, but no more than that. The resource | 59 // enough to avoid unnecessary stalling, but no more than that. The resource |
| 60 // requirements are low, as we don't need the textures to be backed by storage. | 60 // requirements are low, as we don't need the textures to be backed by storage. |
| 61 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; | 61 static const int kNumPictureBuffers = media::limits::kMaxVideoFrames + 1; |
| 62 | 62 |
| 63 // Maximum number of frames to queue for reordering before we stop asking for | 63 // Maximum number of frames to queue for reordering before we stop asking for |
| 64 // more. (NotifyEndOfBitstreamBuffer() is called when frames are moved into the | 64 // more. (NotifyEndOfBitstreamBuffer() is called when frames are moved into the |
| 65 // reorder queue.) | 65 // reorder queue.) |
| 66 static const int kMaxReorderQueueSize = 16; | 66 static const int kMaxReorderQueueSize = 16; |
| 67 | 67 |
| 68 // When set to false, always create a new decoder instead of reusing the | |
| 69 // existing configuration when the configuration changes. This works around a | |
| 70 // bug in VideoToolbox that results in corruption before Mac OS X 10.10.3. The | |
| 71 // value is set in InitializeVideoToolbox(). | |
| 72 static bool g_enable_compatible_configuration_reuse = true; | |
| 73 | |
| 74 // Build an |image_config| dictionary for VideoToolbox initialization. | 68 // Build an |image_config| dictionary for VideoToolbox initialization. |
| 75 static base::ScopedCFTypeRef<CFMutableDictionaryRef> | 69 static base::ScopedCFTypeRef<CFMutableDictionaryRef> |
| 76 BuildImageConfig(CMVideoDimensions coded_dimensions) { | 70 BuildImageConfig(CMVideoDimensions coded_dimensions) { |
| 77 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config; | 71 base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config; |
| 78 | 72 |
| 79 // 4:2:2 is used over the native 4:2:0 because only 4:2:2 can be directly | 73 // 4:2:2 is used over the native 4:2:0 because only 4:2:2 can be directly |
| 80 // bound to a texture by CGLTexImageIOSurface2D(). | 74 // bound to a texture by CGLTexImageIOSurface2D(). |
| 81 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; | 75 int32_t pixel_format = kCVPixelFormatType_422YpCbCr8; |
| 82 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) | 76 #define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i) |
| 83 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); | 77 base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format)); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 static bool InitializeVideoToolboxInternal() { | 175 static bool InitializeVideoToolboxInternal() { |
| 182 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 176 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 183 switches::kDisableAcceleratedVideoDecode)) { | 177 switches::kDisableAcceleratedVideoDecode)) { |
| 184 return false; | 178 return false; |
| 185 } | 179 } |
| 186 | 180 |
| 187 if (!IsVtInitialized()) { | 181 if (!IsVtInitialized()) { |
| 188 // CoreVideo is also required, but the loader stops after the first path is | 182 // CoreVideo is also required, but the loader stops after the first path is |
| 189 // loaded. Instead we rely on the transitive dependency from VideoToolbox to | 183 // loaded. Instead we rely on the transitive dependency from VideoToolbox to |
| 190 // CoreVideo. | 184 // CoreVideo. |
| 191 // TODO(sandersd): Fallback to PrivateFrameworks to support OS X < 10.8. | |
| 192 StubPathMap paths; | 185 StubPathMap paths; |
| 193 paths[kModuleVt].push_back(FILE_PATH_LITERAL( | 186 paths[kModuleVt].push_back(FILE_PATH_LITERAL( |
| 194 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox")); | 187 "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox")); |
| 195 if (!InitializeStubs(paths)) { | 188 if (!InitializeStubs(paths)) { |
| 196 LOG(WARNING) << "Failed to initialize VideoToolbox framework. " | 189 LOG(WARNING) << "Failed to initialize VideoToolbox framework. " |
| 197 << "Hardware accelerated video decoding will be disabled."; | 190 << "Hardware accelerated video decoding will be disabled."; |
| 198 return false; | 191 return false; |
| 199 } | 192 } |
| 200 } | 193 } |
| 201 | 194 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 218 0x22, 0x10, 0x00, 0x00, 0x3e, 0x90, 0x00, 0x0e, | 211 0x22, 0x10, 0x00, 0x00, 0x3e, 0x90, 0x00, 0x0e, |
| 219 0xa6, 0x08, 0xf1, 0x22, 0x59, 0xa0}; | 212 0xa6, 0x08, 0xf1, 0x22, 0x59, 0xa0}; |
| 220 const uint8_t pps_small[] = {0x68, 0xe9, 0x79, 0x72, 0xc0}; | 213 const uint8_t pps_small[] = {0x68, 0xe9, 0x79, 0x72, 0xc0}; |
| 221 if (!CreateVideoToolboxSession(sps_small, arraysize(sps_small), pps_small, | 214 if (!CreateVideoToolboxSession(sps_small, arraysize(sps_small), pps_small, |
| 222 arraysize(pps_small), false)) { | 215 arraysize(pps_small), false)) { |
| 223 LOG(WARNING) << "Failed to create software VideoToolbox session. " | 216 LOG(WARNING) << "Failed to create software VideoToolbox session. " |
| 224 << "Hardware accelerated video decoding will be disabled."; | 217 << "Hardware accelerated video decoding will be disabled."; |
| 225 return false; | 218 return false; |
| 226 } | 219 } |
| 227 | 220 |
| 228 // Set |g_enable_compatible_configuration_reuse| to false on | |
| 229 // Mac OS X < 10.10.3. | |
| 230 base::Version os_x_version(base::SysInfo::OperatingSystemVersion()); | |
| 231 if (os_x_version.IsOlderThan("10.10.3")) | |
| 232 g_enable_compatible_configuration_reuse = false; | |
| 233 | |
| 234 return true; | 221 return true; |
| 235 } | 222 } |
| 236 | 223 |
| 237 bool InitializeVideoToolbox() { | 224 bool InitializeVideoToolbox() { |
| 238 // InitializeVideoToolbox() is called only from the GPU process main thread; | 225 // InitializeVideoToolbox() is called only from the GPU process main thread; |
| 239 // once for sandbox warmup, and then once each time a VTVideoDecodeAccelerator | 226 // once for sandbox warmup, and then once each time a VTVideoDecodeAccelerator |
| 240 // is initialized. | 227 // is initialized. |
| 241 static bool attempted = false; | 228 static bool attempted = false; |
| 242 static bool succeeded = false; | 229 static bool succeeded = false; |
| 243 | 230 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 263 vda->Output(source_frame_refcon, status, image_buffer); | 250 vda->Output(source_frame_refcon, status, image_buffer); |
| 264 } | 251 } |
| 265 | 252 |
| 266 VTVideoDecodeAccelerator::Task::Task(TaskType type) : type(type) { | 253 VTVideoDecodeAccelerator::Task::Task(TaskType type) : type(type) { |
| 267 } | 254 } |
| 268 | 255 |
| 269 VTVideoDecodeAccelerator::Task::~Task() { | 256 VTVideoDecodeAccelerator::Task::~Task() { |
| 270 } | 257 } |
| 271 | 258 |
| 272 VTVideoDecodeAccelerator::Frame::Frame(int32_t bitstream_id) | 259 VTVideoDecodeAccelerator::Frame::Frame(int32_t bitstream_id) |
| 273 : bitstream_id(bitstream_id), pic_order_cnt(0), reorder_window(0) { | 260 : bitstream_id(bitstream_id), |
| 261 pic_order_cnt(0), |
| 262 is_idr(false), |
| 263 reorder_window(0) { |
| 274 } | 264 } |
| 275 | 265 |
| 276 VTVideoDecodeAccelerator::Frame::~Frame() { | 266 VTVideoDecodeAccelerator::Frame::~Frame() { |
| 277 } | 267 } |
| 278 | 268 |
| 279 VTVideoDecodeAccelerator::PictureInfo::PictureInfo(uint32_t client_texture_id, | 269 VTVideoDecodeAccelerator::PictureInfo::PictureInfo(uint32_t client_texture_id, |
| 280 uint32_t service_texture_id) | 270 uint32_t service_texture_id) |
| 281 : client_texture_id(client_texture_id), | 271 : client_texture_id(client_texture_id), |
| 282 service_texture_id(service_texture_id) {} | 272 service_texture_id(service_texture_id) {} |
| 283 | 273 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 nalu_data_ptrs.push_back(&last_sps_.front()); | 369 nalu_data_ptrs.push_back(&last_sps_.front()); |
| 380 nalu_data_sizes.push_back(last_sps_.size()); | 370 nalu_data_sizes.push_back(last_sps_.size()); |
| 381 if (!last_spsext_.empty()) { | 371 if (!last_spsext_.empty()) { |
| 382 nalu_data_ptrs.push_back(&last_spsext_.front()); | 372 nalu_data_ptrs.push_back(&last_spsext_.front()); |
| 383 nalu_data_sizes.push_back(last_spsext_.size()); | 373 nalu_data_sizes.push_back(last_spsext_.size()); |
| 384 } | 374 } |
| 385 nalu_data_ptrs.push_back(&last_pps_.front()); | 375 nalu_data_ptrs.push_back(&last_pps_.front()); |
| 386 nalu_data_sizes.push_back(last_pps_.size()); | 376 nalu_data_sizes.push_back(last_pps_.size()); |
| 387 | 377 |
| 388 // Construct a new format description from the parameter sets. | 378 // Construct a new format description from the parameter sets. |
| 389 // TODO(sandersd): Replace this with custom code to support OS X < 10.9. | |
| 390 format_.reset(); | 379 format_.reset(); |
| 391 OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets( | 380 OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets( |
| 392 kCFAllocatorDefault, | 381 kCFAllocatorDefault, |
| 393 nalu_data_ptrs.size(), // parameter_set_count | 382 nalu_data_ptrs.size(), // parameter_set_count |
| 394 &nalu_data_ptrs.front(), // ¶meter_set_pointers | 383 &nalu_data_ptrs.front(), // ¶meter_set_pointers |
| 395 &nalu_data_sizes.front(), // ¶meter_set_sizes | 384 &nalu_data_sizes.front(), // ¶meter_set_sizes |
| 396 kNALUHeaderLength, // nal_unit_header_length | 385 kNALUHeaderLength, // nal_unit_header_length |
| 397 format_.InitializeInto()); | 386 format_.InitializeInto()); |
| 398 if (status) { | 387 if (status) { |
| 399 NOTIFY_STATUS("CMVideoFormatDescriptionCreateFromH264ParameterSets()", | 388 NOTIFY_STATUS("CMVideoFormatDescriptionCreateFromH264ParameterSets()", |
| 400 status, SFT_PLATFORM_ERROR); | 389 status, SFT_PLATFORM_ERROR); |
| 401 return false; | 390 return false; |
| 402 } | 391 } |
| 403 | 392 |
| 404 // Store the new configuration data. | 393 // Store the new configuration data. |
| 394 // TODO(sandersd): Despite the documentation, this seems to return the visible |
| 395 // size. However, the output always appears to be top-left aligned, so it |
| 396 // makes no difference. Re-verify this and update the variable name. |
| 405 CMVideoDimensions coded_dimensions = | 397 CMVideoDimensions coded_dimensions = |
| 406 CMVideoFormatDescriptionGetDimensions(format_); | 398 CMVideoFormatDescriptionGetDimensions(format_); |
| 407 coded_size_.SetSize(coded_dimensions.width, coded_dimensions.height); | 399 coded_size_.SetSize(coded_dimensions.width, coded_dimensions.height); |
| 408 | 400 |
| 409 // If the session is compatible, there's nothing else to do. | |
| 410 if (g_enable_compatible_configuration_reuse && session_ && | |
| 411 VTDecompressionSessionCanAcceptFormatDescription(session_, format_)) { | |
| 412 return true; | |
| 413 } | |
| 414 | |
| 415 // Prepare VideoToolbox configuration dictionaries. | 401 // Prepare VideoToolbox configuration dictionaries. |
| 416 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config( | 402 base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config( |
| 417 CFDictionaryCreateMutable( | 403 CFDictionaryCreateMutable( |
| 418 kCFAllocatorDefault, | 404 kCFAllocatorDefault, |
| 419 1, // capacity | 405 1, // capacity |
| 420 &kCFTypeDictionaryKeyCallBacks, | 406 &kCFTypeDictionaryKeyCallBacks, |
| 421 &kCFTypeDictionaryValueCallBacks)); | 407 &kCFTypeDictionaryValueCallBacks)); |
| 422 if (!decoder_config.get()) { | 408 if (!decoder_config.get()) { |
| 423 DLOG(ERROR) << "Failed to create CFMutableDictionary."; | 409 DLOG(ERROR) << "Failed to create CFMutableDictionary."; |
| 424 NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); | 410 NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM); | 537 NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM); |
| 552 return; | 538 return; |
| 553 } | 539 } |
| 554 pps.assign(nalu.data, nalu.data + nalu.size); | 540 pps.assign(nalu.data, nalu.data + nalu.size); |
| 555 break; | 541 break; |
| 556 | 542 |
| 557 case media::H264NALU::kSliceDataA: | 543 case media::H264NALU::kSliceDataA: |
| 558 case media::H264NALU::kSliceDataB: | 544 case media::H264NALU::kSliceDataB: |
| 559 case media::H264NALU::kSliceDataC: | 545 case media::H264NALU::kSliceDataC: |
| 560 case media::H264NALU::kNonIDRSlice: | 546 case media::H264NALU::kNonIDRSlice: |
| 561 // TODO(sandersd): Check that there has been an IDR slice since the | |
| 562 // last reset. | |
| 563 case media::H264NALU::kIDRSlice: | 547 case media::H264NALU::kIDRSlice: |
| 564 // Compute the |pic_order_cnt| for the picture from the first slice. | 548 // Compute the |pic_order_cnt| for the picture from the first slice. |
| 565 // TODO(sandersd): Make sure that any further slices are part of the | |
| 566 // same picture or a redundant coded picture. | |
| 567 if (!has_slice) { | 549 if (!has_slice) { |
| 568 media::H264SliceHeader slice_hdr; | 550 media::H264SliceHeader slice_hdr; |
| 569 result = parser_.ParseSliceHeader(nalu, &slice_hdr); | 551 result = parser_.ParseSliceHeader(nalu, &slice_hdr); |
| 570 if (result == media::H264Parser::kUnsupportedStream) { | 552 if (result == media::H264Parser::kUnsupportedStream) { |
| 571 DLOG(ERROR) << "Unsupported slice header"; | 553 DLOG(ERROR) << "Unsupported slice header"; |
| 572 NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM); | 554 NotifyError(PLATFORM_FAILURE, SFT_UNSUPPORTED_STREAM); |
| 573 return; | 555 return; |
| 574 } | 556 } |
| 575 if (result != media::H264Parser::kOk) { | 557 if (result != media::H264Parser::kOk) { |
| 576 DLOG(ERROR) << "Could not parse slice header"; | 558 DLOG(ERROR) << "Could not parse slice header"; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 596 NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM); | 578 NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM); |
| 597 return; | 579 return; |
| 598 } | 580 } |
| 599 | 581 |
| 600 if (!poc_.ComputePicOrderCnt(sps, slice_hdr, &frame->pic_order_cnt)) { | 582 if (!poc_.ComputePicOrderCnt(sps, slice_hdr, &frame->pic_order_cnt)) { |
| 601 DLOG(ERROR) << "Unable to compute POC"; | 583 DLOG(ERROR) << "Unable to compute POC"; |
| 602 NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM); | 584 NotifyError(UNREADABLE_INPUT, SFT_INVALID_STREAM); |
| 603 return; | 585 return; |
| 604 } | 586 } |
| 605 | 587 |
| 588 if (nalu.nal_unit_type == media::H264NALU::kIDRSlice) |
| 589 frame->is_idr = true; |
| 590 |
| 606 if (sps->vui_parameters_present_flag && | 591 if (sps->vui_parameters_present_flag && |
| 607 sps->bitstream_restriction_flag) { | 592 sps->bitstream_restriction_flag) { |
| 608 frame->reorder_window = std::min(sps->max_num_reorder_frames, | 593 frame->reorder_window = std::min(sps->max_num_reorder_frames, |
| 609 kMaxReorderQueueSize - 1); | 594 kMaxReorderQueueSize - 1); |
| 610 } | 595 } |
| 611 } | 596 } |
| 612 has_slice = true; | 597 has_slice = true; |
| 613 default: | 598 default: |
| 614 nalus.push_back(nalu); | 599 nalus.push_back(nalu); |
| 615 data_size += kNALUHeaderLength + nalu.size; | 600 data_size += kNALUHeaderLength + nalu.size; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 632 if (last_sps_.empty()) { | 617 if (last_sps_.empty()) { |
| 633 DLOG(ERROR) << "Invalid configuration; no SPS"; | 618 DLOG(ERROR) << "Invalid configuration; no SPS"; |
| 634 NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); | 619 NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); |
| 635 return; | 620 return; |
| 636 } | 621 } |
| 637 if (last_pps_.empty()) { | 622 if (last_pps_.empty()) { |
| 638 DLOG(ERROR) << "Invalid configuration; no PPS"; | 623 DLOG(ERROR) << "Invalid configuration; no PPS"; |
| 639 NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); | 624 NotifyError(INVALID_ARGUMENT, SFT_INVALID_STREAM); |
| 640 return; | 625 return; |
| 641 } | 626 } |
| 642 if (!ConfigureDecoder()) | 627 |
| 628 // If it's not an IDR frame, we can't reconfigure the decoder anyway. We |
| 629 // assume that any config change not on an IDR must be compatible. |
| 630 if (frame->is_idr && !ConfigureDecoder()) |
| 643 return; | 631 return; |
| 644 } | 632 } |
| 645 | 633 |
| 646 // If there are no image slices, drop the bitstream buffer by returning an | 634 // If there are no image slices, drop the bitstream buffer by returning an |
| 647 // empty frame. | 635 // empty frame. |
| 648 if (!has_slice) { | 636 if (!has_slice) { |
| 649 if (!FinishDelayedFrames()) | 637 if (!FinishDelayedFrames()) |
| 650 return; | 638 return; |
| 651 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( | 639 gpu_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 652 &VTVideoDecodeAccelerator::DecodeDone, weak_this_, frame)); | 640 &VTVideoDecodeAccelerator::DecodeDone, weak_this_, frame)); |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 bool VTVideoDecodeAccelerator::ProcessTaskQueue() { | 877 bool VTVideoDecodeAccelerator::ProcessTaskQueue() { |
| 890 DCHECK(gpu_thread_checker_.CalledOnValidThread()); | 878 DCHECK(gpu_thread_checker_.CalledOnValidThread()); |
| 891 DCHECK_EQ(state_, STATE_DECODING); | 879 DCHECK_EQ(state_, STATE_DECODING); |
| 892 | 880 |
| 893 if (task_queue_.empty()) | 881 if (task_queue_.empty()) |
| 894 return false; | 882 return false; |
| 895 | 883 |
| 896 const Task& task = task_queue_.front(); | 884 const Task& task = task_queue_.front(); |
| 897 switch (task.type) { | 885 switch (task.type) { |
| 898 case TASK_FRAME: | 886 case TASK_FRAME: |
| 899 // TODO(sandersd): Signal IDR explicitly (not using pic_order_cnt == 0). | |
| 900 if (reorder_queue_.size() < kMaxReorderQueueSize && | 887 if (reorder_queue_.size() < kMaxReorderQueueSize && |
| 901 (task.frame->pic_order_cnt != 0 || reorder_queue_.empty())) { | 888 (!task.frame->is_idr || reorder_queue_.empty())) { |
| 902 assigned_bitstream_ids_.erase(task.frame->bitstream_id); | 889 assigned_bitstream_ids_.erase(task.frame->bitstream_id); |
| 903 client_->NotifyEndOfBitstreamBuffer(task.frame->bitstream_id); | 890 client_->NotifyEndOfBitstreamBuffer(task.frame->bitstream_id); |
| 904 reorder_queue_.push(task.frame); | 891 reorder_queue_.push(task.frame); |
| 905 task_queue_.pop(); | 892 task_queue_.pop(); |
| 906 return true; | 893 return true; |
| 907 } | 894 } |
| 908 return false; | 895 return false; |
| 909 | 896 |
| 910 case TASK_FLUSH: | 897 case TASK_FLUSH: |
| 911 DCHECK_EQ(task.type, pending_flush_tasks_.front()); | 898 DCHECK_EQ(task.type, pending_flush_tasks_.front()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 945 DCHECK_EQ(state_, STATE_DECODING); | 932 DCHECK_EQ(state_, STATE_DECODING); |
| 946 | 933 |
| 947 if (reorder_queue_.empty()) | 934 if (reorder_queue_.empty()) |
| 948 return false; | 935 return false; |
| 949 | 936 |
| 950 // If the next task is a flush (because there is a pending flush or becuase | 937 // If the next task is a flush (because there is a pending flush or becuase |
| 951 // the next frame is an IDR), then we don't need a full reorder buffer to send | 938 // the next frame is an IDR), then we don't need a full reorder buffer to send |
| 952 // the next frame. | 939 // the next frame. |
| 953 bool flushing = !task_queue_.empty() && | 940 bool flushing = !task_queue_.empty() && |
| 954 (task_queue_.front().type != TASK_FRAME || | 941 (task_queue_.front().type != TASK_FRAME || |
| 955 task_queue_.front().frame->pic_order_cnt == 0); | 942 task_queue_.front().frame->is_idr); |
| 956 | 943 |
| 957 size_t reorder_window = std::max(0, reorder_queue_.top()->reorder_window); | 944 size_t reorder_window = std::max(0, reorder_queue_.top()->reorder_window); |
| 958 if (flushing || reorder_queue_.size() > reorder_window) { | 945 if (flushing || reorder_queue_.size() > reorder_window) { |
| 959 if (ProcessFrame(*reorder_queue_.top())) { | 946 if (ProcessFrame(*reorder_queue_.top())) { |
| 960 reorder_queue_.pop(); | 947 reorder_queue_.pop(); |
| 961 return true; | 948 return true; |
| 962 } | 949 } |
| 963 } | 950 } |
| 964 | 951 |
| 965 return false; | 952 return false; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 DCHECK(gpu_thread_checker_.CalledOnValidThread()); | 1101 DCHECK(gpu_thread_checker_.CalledOnValidThread()); |
| 1115 | 1102 |
| 1116 // In a forceful shutdown, the decoder thread may be dead already. | 1103 // In a forceful shutdown, the decoder thread may be dead already. |
| 1117 if (!decoder_thread_.IsRunning()) { | 1104 if (!decoder_thread_.IsRunning()) { |
| 1118 delete this; | 1105 delete this; |
| 1119 return; | 1106 return; |
| 1120 } | 1107 } |
| 1121 | 1108 |
| 1122 // For a graceful shutdown, return assigned buffers and flush before | 1109 // For a graceful shutdown, return assigned buffers and flush before |
| 1123 // destructing |this|. | 1110 // destructing |this|. |
| 1124 // TODO(sandersd): Make sure the decoder won't try to read the buffers again | 1111 // TODO(sandersd): Prevent the decoder from reading buffers before discarding |
| 1125 // before discarding them. | 1112 // them. |
| 1126 for (int32_t bitstream_id : assigned_bitstream_ids_) | 1113 for (int32_t bitstream_id : assigned_bitstream_ids_) |
| 1127 client_->NotifyEndOfBitstreamBuffer(bitstream_id); | 1114 client_->NotifyEndOfBitstreamBuffer(bitstream_id); |
| 1128 assigned_bitstream_ids_.clear(); | 1115 assigned_bitstream_ids_.clear(); |
| 1129 state_ = STATE_DESTROYING; | 1116 state_ = STATE_DESTROYING; |
| 1130 QueueFlush(TASK_DESTROY); | 1117 QueueFlush(TASK_DESTROY); |
| 1131 } | 1118 } |
| 1132 | 1119 |
| 1133 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { | 1120 bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() { |
| 1134 return false; | 1121 return false; |
| 1135 } | 1122 } |
| 1136 | 1123 |
| 1137 // static | 1124 // static |
| 1138 media::VideoDecodeAccelerator::SupportedProfiles | 1125 media::VideoDecodeAccelerator::SupportedProfiles |
| 1139 VTVideoDecodeAccelerator::GetSupportedProfiles() { | 1126 VTVideoDecodeAccelerator::GetSupportedProfiles() { |
| 1140 SupportedProfiles profiles; | 1127 SupportedProfiles profiles; |
| 1141 for (const auto& supported_profile : kSupportedProfiles) { | 1128 for (const auto& supported_profile : kSupportedProfiles) { |
| 1142 SupportedProfile profile; | 1129 SupportedProfile profile; |
| 1143 profile.profile = supported_profile; | 1130 profile.profile = supported_profile; |
| 1144 profile.min_resolution.SetSize(16, 16); | 1131 profile.min_resolution.SetSize(16, 16); |
| 1145 profile.max_resolution.SetSize(4096, 2160); | 1132 profile.max_resolution.SetSize(4096, 2160); |
| 1146 profiles.push_back(profile); | 1133 profiles.push_back(profile); |
| 1147 } | 1134 } |
| 1148 return profiles; | 1135 return profiles; |
| 1149 } | 1136 } |
| 1150 | 1137 |
| 1151 } // namespace content | 1138 } // namespace content |
| OLD | NEW |