OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/dxva_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" |
6 | 6 |
7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
10 | 10 |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 } | 423 } |
424 | 424 |
425 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( | 425 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
426 const base::Callback<bool(void)>& make_context_current) | 426 const base::Callback<bool(void)>& make_context_current) |
427 : client_(NULL), | 427 : client_(NULL), |
428 dev_manager_reset_token_(0), | 428 dev_manager_reset_token_(0), |
429 egl_config_(NULL), | 429 egl_config_(NULL), |
430 state_(kUninitialized), | 430 state_(kUninitialized), |
431 pictures_requested_(false), | 431 pictures_requested_(false), |
432 inputs_before_decode_(0), | 432 inputs_before_decode_(0), |
433 make_context_current_(make_context_current) { | 433 make_context_current_(make_context_current), |
| 434 weak_this_factory_(this) { |
434 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); | 435 memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
435 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); | 436 memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
436 } | 437 } |
437 | 438 |
438 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { | 439 DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
439 client_ = NULL; | 440 client_ = NULL; |
440 } | 441 } |
441 | 442 |
442 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, | 443 bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
443 Client* client) { | 444 Client* client) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), | 492 SendMFTMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), |
492 "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", | 493 "Send MFT_MESSAGE_NOTIFY_BEGIN_STREAMING notification failed", |
493 PLATFORM_FAILURE, false); | 494 PLATFORM_FAILURE, false); |
494 | 495 |
495 RETURN_AND_NOTIFY_ON_FAILURE( | 496 RETURN_AND_NOTIFY_ON_FAILURE( |
496 SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), | 497 SendMFTMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), |
497 "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", | 498 "Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", |
498 PLATFORM_FAILURE, false); | 499 PLATFORM_FAILURE, false); |
499 | 500 |
500 state_ = kNormal; | 501 state_ = kNormal; |
501 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | |
502 &DXVAVideoDecodeAccelerator::NotifyInitializeDone, | |
503 base::AsWeakPtr(this))); | |
504 return true; | 502 return true; |
505 } | 503 } |
506 | 504 |
507 void DXVAVideoDecodeAccelerator::Decode( | 505 void DXVAVideoDecodeAccelerator::Decode( |
508 const media::BitstreamBuffer& bitstream_buffer) { | 506 const media::BitstreamBuffer& bitstream_buffer) { |
509 DCHECK(CalledOnValidThread()); | 507 DCHECK(CalledOnValidThread()); |
510 | 508 |
511 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped || | 509 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped || |
512 state_ == kFlushing), | 510 state_ == kFlushing), |
513 "Invalid state: " << state_, ILLEGAL_STATE,); | 511 "Invalid state: " << state_, ILLEGAL_STATE,); |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 | 601 |
604 state_ = kResetting; | 602 state_ = kResetting; |
605 | 603 |
606 pending_output_samples_.clear(); | 604 pending_output_samples_.clear(); |
607 | 605 |
608 NotifyInputBuffersDropped(); | 606 NotifyInputBuffersDropped(); |
609 | 607 |
610 RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), | 608 RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), |
611 "Reset: Failed to send message.", PLATFORM_FAILURE,); | 609 "Reset: Failed to send message.", PLATFORM_FAILURE,); |
612 | 610 |
613 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 611 base::MessageLoop::current()->PostTask( |
614 &DXVAVideoDecodeAccelerator::NotifyResetDone, base::AsWeakPtr(this))); | 612 FROM_HERE, |
| 613 base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone, |
| 614 weak_this_factory_.GetWeakPtr())); |
615 | 615 |
616 state_ = DXVAVideoDecodeAccelerator::kNormal; | 616 state_ = DXVAVideoDecodeAccelerator::kNormal; |
617 } | 617 } |
618 | 618 |
619 void DXVAVideoDecodeAccelerator::Destroy() { | 619 void DXVAVideoDecodeAccelerator::Destroy() { |
620 DCHECK(CalledOnValidThread()); | 620 DCHECK(CalledOnValidThread()); |
621 Invalidate(); | 621 Invalidate(); |
622 delete this; | 622 delete this; |
623 } | 623 } |
624 | 624 |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 } | 877 } |
878 | 878 |
879 // We only read the surface description, which contains its width/height when | 879 // We only read the surface description, which contains its width/height when |
880 // we need the picture buffers from the client. Once we have those, then they | 880 // we need the picture buffers from the client. Once we have those, then they |
881 // are reused. | 881 // are reused. |
882 D3DSURFACE_DESC surface_desc; | 882 D3DSURFACE_DESC surface_desc; |
883 hr = surface->GetDesc(&surface_desc); | 883 hr = surface->GetDesc(&surface_desc); |
884 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); | 884 RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
885 | 885 |
886 // Go ahead and request picture buffers. | 886 // Go ahead and request picture buffers. |
887 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 887 base::MessageLoop::current()->PostTask( |
888 &DXVAVideoDecodeAccelerator::RequestPictureBuffers, | 888 FROM_HERE, |
889 base::AsWeakPtr(this), surface_desc.Width, surface_desc.Height)); | 889 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
| 890 weak_this_factory_.GetWeakPtr(), |
| 891 surface_desc.Width, |
| 892 surface_desc.Height)); |
890 | 893 |
891 pictures_requested_ = true; | 894 pictures_requested_ = true; |
892 return true; | 895 return true; |
893 } | 896 } |
894 | 897 |
895 void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { | 898 void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { |
896 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), | 899 RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), |
897 "Failed to make context current", PLATFORM_FAILURE,); | 900 "Failed to make context current", PLATFORM_FAILURE,); |
898 | 901 |
899 OutputBuffers::iterator index; | 902 OutputBuffers::iterator index; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
931 return; | 934 return; |
932 } | 935 } |
933 | 936 |
934 RETURN_AND_NOTIFY_ON_FAILURE( | 937 RETURN_AND_NOTIFY_ON_FAILURE( |
935 index->second->CopyOutputSampleDataToPictureBuffer(*this, surface), | 938 index->second->CopyOutputSampleDataToPictureBuffer(*this, surface), |
936 "Failed to copy output sample", | 939 "Failed to copy output sample", |
937 PLATFORM_FAILURE, ); | 940 PLATFORM_FAILURE, ); |
938 | 941 |
939 media::Picture output_picture(index->second->id(), | 942 media::Picture output_picture(index->second->id(), |
940 sample_info.input_buffer_id); | 943 sample_info.input_buffer_id); |
941 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 944 base::MessageLoop::current()->PostTask( |
942 &DXVAVideoDecodeAccelerator::NotifyPictureReady, | 945 FROM_HERE, |
943 base::AsWeakPtr(this), output_picture)); | 946 base::Bind(&DXVAVideoDecodeAccelerator::NotifyPictureReady, |
| 947 weak_this_factory_.GetWeakPtr(), |
| 948 output_picture)); |
944 | 949 |
945 index->second->set_available(false); | 950 index->second->set_available(false); |
946 pending_output_samples_.pop_front(); | 951 pending_output_samples_.pop_front(); |
947 } | 952 } |
948 } | 953 } |
949 | 954 |
950 if (!pending_input_buffers_.empty() && pending_output_samples_.empty()) { | 955 if (!pending_input_buffers_.empty() && pending_output_samples_.empty()) { |
951 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 956 base::MessageLoop::current()->PostTask( |
952 &DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 957 FROM_HERE, |
953 base::AsWeakPtr(this))); | 958 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
| 959 weak_this_factory_.GetWeakPtr())); |
954 } | 960 } |
955 } | 961 } |
956 | 962 |
957 void DXVAVideoDecodeAccelerator::StopOnError( | 963 void DXVAVideoDecodeAccelerator::StopOnError( |
958 media::VideoDecodeAccelerator::Error error) { | 964 media::VideoDecodeAccelerator::Error error) { |
959 DCHECK(CalledOnValidThread()); | 965 DCHECK(CalledOnValidThread()); |
960 | 966 |
961 if (client_) | 967 if (client_) |
962 client_->NotifyError(error); | 968 client_->NotifyError(error); |
963 client_ = NULL; | 969 client_ = NULL; |
964 | 970 |
965 if (state_ != kUninitialized) { | 971 if (state_ != kUninitialized) { |
966 Invalidate(); | 972 Invalidate(); |
967 } | 973 } |
968 } | 974 } |
969 | 975 |
970 void DXVAVideoDecodeAccelerator::Invalidate() { | 976 void DXVAVideoDecodeAccelerator::Invalidate() { |
971 if (state_ == kUninitialized) | 977 if (state_ == kUninitialized) |
972 return; | 978 return; |
| 979 weak_this_factory_.InvalidateWeakPtrs(); |
973 output_picture_buffers_.clear(); | 980 output_picture_buffers_.clear(); |
974 pending_output_samples_.clear(); | 981 pending_output_samples_.clear(); |
975 pending_input_buffers_.clear(); | 982 pending_input_buffers_.clear(); |
976 decoder_.Release(); | 983 decoder_.Release(); |
977 MFShutdown(); | 984 MFShutdown(); |
978 state_ = kUninitialized; | 985 state_ = kUninitialized; |
979 } | 986 } |
980 | 987 |
981 void DXVAVideoDecodeAccelerator::NotifyInitializeDone() { | |
982 if (client_) | |
983 client_->NotifyInitializeDone(); | |
984 } | |
985 | |
986 void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { | 988 void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { |
987 if (client_) | 989 if (client_) |
988 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); | 990 client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
989 } | 991 } |
990 | 992 |
991 void DXVAVideoDecodeAccelerator::NotifyFlushDone() { | 993 void DXVAVideoDecodeAccelerator::NotifyFlushDone() { |
992 if (client_) | 994 if (client_) |
993 client_->NotifyFlushDone(); | 995 client_->NotifyFlushDone(); |
994 } | 996 } |
995 | 997 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1050 // MF_E_TRANSFORM_NEED_MORE_INPUT. | 1052 // MF_E_TRANSFORM_NEED_MORE_INPUT. |
1051 // The MFT decoder can buffer upto 30 frames worth of input before returning | 1053 // The MFT decoder can buffer upto 30 frames worth of input before returning |
1052 // an output frame. This loop here attempts to retrieve as many output frames | 1054 // an output frame. This loop here attempts to retrieve as many output frames |
1053 // as possible from the buffered set. | 1055 // as possible from the buffered set. |
1054 while (state_ != kStopped) { | 1056 while (state_ != kStopped) { |
1055 DoDecode(); | 1057 DoDecode(); |
1056 if (!pending_output_samples_.empty()) | 1058 if (!pending_output_samples_.empty()) |
1057 return; | 1059 return; |
1058 } | 1060 } |
1059 | 1061 |
1060 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 1062 base::MessageLoop::current()->PostTask( |
1061 &DXVAVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); | 1063 FROM_HERE, |
| 1064 base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, |
| 1065 weak_this_factory_.GetWeakPtr())); |
1062 | 1066 |
1063 state_ = kNormal; | 1067 state_ = kNormal; |
1064 } | 1068 } |
1065 | 1069 |
1066 void DXVAVideoDecodeAccelerator::DecodeInternal( | 1070 void DXVAVideoDecodeAccelerator::DecodeInternal( |
1067 const base::win::ScopedComPtr<IMFSample>& sample) { | 1071 const base::win::ScopedComPtr<IMFSample>& sample) { |
1068 DCHECK(CalledOnValidThread()); | 1072 DCHECK(CalledOnValidThread()); |
1069 | 1073 |
1070 if (state_ == kUninitialized) | 1074 if (state_ == kUninitialized) |
1071 return; | 1075 return; |
(...skipping 29 matching lines...) Expand all Loading... |
1101 // 2. If we don't have any output samples we post the | 1105 // 2. If we don't have any output samples we post the |
1102 // DecodePendingInputBuffers task to process the pending input samples. | 1106 // DecodePendingInputBuffers task to process the pending input samples. |
1103 // If we have an output sample then the above task is posted when the | 1107 // If we have an output sample then the above task is posted when the |
1104 // output samples are sent to the client. | 1108 // output samples are sent to the client. |
1105 // This is because we only support 1 pending output sample at any | 1109 // This is because we only support 1 pending output sample at any |
1106 // given time due to the limitation with the Microsoft media foundation | 1110 // given time due to the limitation with the Microsoft media foundation |
1107 // decoder where it recycles the output Decoder surfaces. | 1111 // decoder where it recycles the output Decoder surfaces. |
1108 if (hr == MF_E_NOTACCEPTING) { | 1112 if (hr == MF_E_NOTACCEPTING) { |
1109 pending_input_buffers_.push_back(sample); | 1113 pending_input_buffers_.push_back(sample); |
1110 if (pending_output_samples_.empty()) { | 1114 if (pending_output_samples_.empty()) { |
1111 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 1115 base::MessageLoop::current()->PostTask( |
1112 &DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, | 1116 FROM_HERE, |
1113 base::AsWeakPtr(this))); | 1117 base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
| 1118 weak_this_factory_.GetWeakPtr())); |
1114 } | 1119 } |
1115 return; | 1120 return; |
1116 } | 1121 } |
1117 } | 1122 } |
1118 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to process input sample", | 1123 RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to process input sample", |
1119 PLATFORM_FAILURE,); | 1124 PLATFORM_FAILURE,); |
1120 | 1125 |
1121 DoDecode(); | 1126 DoDecode(); |
1122 | 1127 |
1123 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal), | 1128 RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal), |
1124 "Failed to process output. Unexpected decoder state: " << state_, | 1129 "Failed to process output. Unexpected decoder state: " << state_, |
1125 ILLEGAL_STATE,); | 1130 ILLEGAL_STATE,); |
1126 | 1131 |
1127 LONGLONG input_buffer_id = 0; | 1132 LONGLONG input_buffer_id = 0; |
1128 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), | 1133 RETURN_ON_HR_FAILURE(sample->GetSampleTime(&input_buffer_id), |
1129 "Failed to get input buffer id associated with sample",); | 1134 "Failed to get input buffer id associated with sample",); |
1130 // The Microsoft Media foundation decoder internally buffers up to 30 frames | 1135 // The Microsoft Media foundation decoder internally buffers up to 30 frames |
1131 // before returning a decoded frame. We need to inform the client that this | 1136 // before returning a decoded frame. We need to inform the client that this |
1132 // input buffer is processed as it may stop sending us further input. | 1137 // input buffer is processed as it may stop sending us further input. |
1133 // Note: This may break clients which expect every input buffer to be | 1138 // Note: This may break clients which expect every input buffer to be |
1134 // associated with a decoded output buffer. | 1139 // associated with a decoded output buffer. |
1135 // TODO(ananta) | 1140 // TODO(ananta) |
1136 // Do some more investigation into whether it is possible to get the MFT | 1141 // Do some more investigation into whether it is possible to get the MFT |
1137 // decoder to emit an output packet for every input packet. | 1142 // decoder to emit an output packet for every input packet. |
1138 // http://code.google.com/p/chromium/issues/detail?id=108121 | 1143 // http://code.google.com/p/chromium/issues/detail?id=108121 |
1139 // http://code.google.com/p/chromium/issues/detail?id=150925 | 1144 // http://code.google.com/p/chromium/issues/detail?id=150925 |
1140 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 1145 base::MessageLoop::current()->PostTask( |
1141 &DXVAVideoDecodeAccelerator::NotifyInputBufferRead, | 1146 FROM_HERE, |
1142 base::AsWeakPtr(this), input_buffer_id)); | 1147 base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead, |
| 1148 weak_this_factory_.GetWeakPtr(), |
| 1149 input_buffer_id)); |
1143 } | 1150 } |
1144 | 1151 |
1145 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, | 1152 void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, |
1146 int height) { | 1153 int height) { |
1147 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 1154 base::MessageLoop::current()->PostTask( |
1148 &DXVAVideoDecodeAccelerator::DismissStaleBuffers, | 1155 FROM_HERE, |
1149 base::AsWeakPtr(this), output_picture_buffers_)); | 1156 base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers, |
| 1157 weak_this_factory_.GetWeakPtr(), |
| 1158 output_picture_buffers_)); |
1150 | 1159 |
1151 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 1160 base::MessageLoop::current()->PostTask( |
1152 &DXVAVideoDecodeAccelerator::RequestPictureBuffers, | 1161 FROM_HERE, |
1153 base::AsWeakPtr(this), width, height)); | 1162 base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
| 1163 weak_this_factory_.GetWeakPtr(), |
| 1164 width, |
| 1165 height)); |
1154 | 1166 |
1155 output_picture_buffers_.clear(); | 1167 output_picture_buffers_.clear(); |
1156 } | 1168 } |
1157 | 1169 |
1158 void DXVAVideoDecodeAccelerator::DismissStaleBuffers( | 1170 void DXVAVideoDecodeAccelerator::DismissStaleBuffers( |
1159 const OutputBuffers& picture_buffers) { | 1171 const OutputBuffers& picture_buffers) { |
1160 OutputBuffers::const_iterator index; | 1172 OutputBuffers::const_iterator index; |
1161 | 1173 |
1162 for (index = picture_buffers.begin(); | 1174 for (index = picture_buffers.begin(); |
1163 index != picture_buffers.end(); | 1175 index != picture_buffers.end(); |
1164 ++index) { | 1176 ++index) { |
1165 DVLOG(1) << "Dismissing picture id: " << index->second->id(); | 1177 DVLOG(1) << "Dismissing picture id: " << index->second->id(); |
1166 client_->DismissPictureBuffer(index->second->id()); | 1178 client_->DismissPictureBuffer(index->second->id()); |
1167 } | 1179 } |
1168 } | 1180 } |
1169 | 1181 |
1170 } // namespace content | 1182 } // namespace content |
OLD | NEW |