Index: content/common/gpu/media/dxva_video_decode_accelerator.cc |
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator.cc b/content/common/gpu/media/dxva_video_decode_accelerator.cc |
index 2fc53e7188acfd223d8cb847dd96e2b866adc4c9..9485c598b2042864b3035044d5b5d1140d24c118 100644 |
--- a/content/common/gpu/media/dxva_video_decode_accelerator.cc |
+++ b/content/common/gpu/media/dxva_video_decode_accelerator.cc |
@@ -487,8 +487,10 @@ DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
pictures_requested_(false), |
inputs_before_decode_(0), |
make_context_current_(make_context_current), |
+ codec_(media::kUnknownVideoCodec), |
+ decoder_thread_("DXVAVideoDecoderThread"), |
weak_this_factory_(this), |
- codec_(media::kUnknownVideoCodec) { |
+ weak_ptr_(weak_this_factory_.GetWeakPtr()) { |
memset(&input_stream_info_, 0, sizeof(input_stream_info_)); |
memset(&output_stream_info_, 0, sizeof(output_stream_info_)); |
} |
@@ -498,11 +500,11 @@ DXVAVideoDecodeAccelerator::~DXVAVideoDecodeAccelerator() { |
} |
bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
- Client* client) { |
- DCHECK(CalledOnValidThread()); |
- |
+ Client* client) { |
client_ = client; |
+ main_thread_task_runner_ = base::MessageLoop::current()->task_runner(); |
+ |
// Not all versions of Windows 7 and later include Media Foundation DLLs. |
// Instead of crashing while delay loading the DLL when calling MFStartup() |
// below, probe whether we can successfully load the DLL now. |
@@ -511,8 +513,8 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
HMODULE mfplat_dll = ::LoadLibrary(L"MFPlat.dll"); |
RETURN_ON_FAILURE(mfplat_dll, "MFPlat.dll is required for decoding", false); |
- // TODO(ananta) |
- // H264PROFILE_HIGH video decoding is janky at times. Needs more |
+ // TODO(ananta) |
+ // H264PROFILE_HIGH video decoding is janky at times. Needs more |
// investigation. http://crbug.com/426707 |
if (profile != media::H264PROFILE_BASELINE && |
profile != media::H264PROFILE_MAIN && |
@@ -528,8 +530,9 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
PLATFORM_FAILURE, |
false); |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kUninitialized), |
- "Initialize: invalid state: " << state_, ILLEGAL_STATE, false); |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kUninitialized), |
+ "Initialize: invalid state: " << state, ILLEGAL_STATE, false); |
HRESULT hr = MFStartup(MF_VERSION, MFSTARTUP_FULL); |
RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "MFStartup failed.", PLATFORM_FAILURE, |
@@ -556,17 +559,20 @@ bool DXVAVideoDecodeAccelerator::Initialize(media::VideoCodecProfile profile, |
"Send MFT_MESSAGE_NOTIFY_START_OF_STREAM notification failed", |
PLATFORM_FAILURE, false); |
- state_ = kNormal; |
+ SetState(kNormal); |
+ |
+ StartDecoderThread(); |
return true; |
} |
void DXVAVideoDecodeAccelerator::Decode( |
const media::BitstreamBuffer& bitstream_buffer) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped || |
- state_ == kFlushing), |
- "Invalid state: " << state_, ILLEGAL_STATE,); |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped || |
+ state == kFlushing), |
+ "Invalid state: " << state, ILLEGAL_STATE,); |
base::win::ScopedComPtr<IMFSample> sample; |
sample.Attach(CreateSampleFromInputBuffer(bitstream_buffer, |
@@ -578,15 +584,19 @@ void DXVAVideoDecodeAccelerator::Decode( |
RETURN_AND_NOTIFY_ON_HR_FAILURE(sample->SetSampleTime(bitstream_buffer.id()), |
"Failed to associate input buffer id with sample", PLATFORM_FAILURE,); |
- DecodeInternal(sample); |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodeInternal, |
+ base::Unretained(this), sample)); |
} |
void DXVAVideoDecodeAccelerator::AssignPictureBuffers( |
const std::vector<media::PictureBuffer>& buffers) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), |
- "Invalid state: " << state_, ILLEGAL_STATE,); |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized), |
+ "Invalid state: " << state, ILLEGAL_STATE,); |
RETURN_AND_NOTIFY_ON_FAILURE((kNumPictureBuffers == buffers.size()), |
"Failed to provide requested picture buffers. (Got " << buffers.size() << |
", requested " << kNumPictureBuffers << ")", INVALID_ARGUMENT,); |
@@ -605,16 +615,22 @@ void DXVAVideoDecodeAccelerator::AssignPictureBuffers( |
DCHECK(inserted); |
} |
ProcessPendingSamples(); |
- if (state_ == kFlushing && pending_output_samples_.empty()) |
- FlushInternal(); |
+ |
+ if (state == kFlushing) { |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
+ base::Unretained(this))); |
+ } |
} |
void DXVAVideoDecodeAccelerator::ReusePictureBuffer( |
int32 picture_buffer_id) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), |
- "Invalid state: " << state_, ILLEGAL_STATE,); |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized), |
+ "Invalid state: " << state, ILLEGAL_STATE,); |
if (output_picture_buffers_.empty() && stale_output_picture_buffers_.empty()) |
return; |
@@ -630,65 +646,75 @@ void DXVAVideoDecodeAccelerator::ReusePictureBuffer( |
it = stale_output_picture_buffers_.find(picture_buffer_id); |
RETURN_AND_NOTIFY_ON_FAILURE(it != stale_output_picture_buffers_.end(), |
"Invalid picture id: " << picture_buffer_id, INVALID_ARGUMENT,); |
- base::MessageLoop::current()->PostTask(FROM_HERE, |
+ main_thread_task_runner_->PostTask( |
+ FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer, |
- weak_this_factory_.GetWeakPtr(), picture_buffer_id)); |
+ weak_this_factory_.GetWeakPtr(), picture_buffer_id)); |
return; |
} |
it->second->ReusePictureBuffer(); |
ProcessPendingSamples(); |
- if (state_ == kFlushing && pending_output_samples_.empty()) |
- FlushInternal(); |
+ if (state == kFlushing) { |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
+ base::Unretained(this))); |
+ } |
} |
void DXVAVideoDecodeAccelerator::Flush() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
DVLOG(1) << "DXVAVideoDecodeAccelerator::Flush"; |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped), |
- "Unexpected decoder state: " << state_, ILLEGAL_STATE,); |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped), |
+ "Unexpected decoder state: " << state, ILLEGAL_STATE,); |
- state_ = kFlushing; |
+ SetState(kFlushing); |
RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_DRAIN, 0), |
"Failed to send drain message", PLATFORM_FAILURE,); |
- if (!pending_output_samples_.empty()) |
- return; |
- |
- FlushInternal(); |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
+ base::Unretained(this))); |
} |
void DXVAVideoDecodeAccelerator::Reset() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
DVLOG(1) << "DXVAVideoDecodeAccelerator::Reset"; |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kNormal || state_ == kStopped), |
- "Reset: invalid state: " << state_, ILLEGAL_STATE,); |
- |
- state_ = kResetting; |
- |
- pending_output_samples_.clear(); |
- |
- NotifyInputBuffersDropped(); |
- |
- RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), |
- "Reset: Failed to send message.", PLATFORM_FAILURE,); |
- |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone, |
- weak_this_factory_.GetWeakPtr())); |
- |
- state_ = DXVAVideoDecodeAccelerator::kNormal; |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kNormal || state == kStopped), |
+ "Reset: invalid state: " << state, ILLEGAL_STATE,); |
+ |
+ decoder_thread_.Stop(); |
+ |
+ SetState(kResetting); |
+ |
+ pending_output_samples_.clear(); |
+ |
+ NotifyInputBuffersDropped(); |
+ |
+ RETURN_AND_NOTIFY_ON_FAILURE(SendMFTMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), |
+ "Reset: Failed to send message.", PLATFORM_FAILURE,); |
+ |
+ main_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::NotifyResetDone, |
+ weak_this_factory_.GetWeakPtr())); |
+ |
+ StartDecoderThread(); |
+ SetState(kNormal); |
} |
void DXVAVideoDecodeAccelerator::Destroy() { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
Invalidate(); |
delete this; |
} |
@@ -929,11 +955,13 @@ bool DXVAVideoDecodeAccelerator::GetStreamsInfoAndBufferReqs() { |
} |
void DXVAVideoDecodeAccelerator::DoDecode() { |
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
// This function is also called from FlushInternal in a loop which could |
// result in the state transitioning to kStopped due to no decoded output. |
+ State state = GetState(); |
RETURN_AND_NOTIFY_ON_FAILURE( |
- (state_ == kNormal || state_ == kFlushing || |
- state_ == kStopped || state_ == kFlushingPendingInputBuffers), |
+ (state == kNormal || state == kFlushing || |
+ state == kStopped || state == kFlushingPendingInputBuffers), |
"DoDecode: not in normal/flushing/stopped state", ILLEGAL_STATE,); |
MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0}; |
@@ -956,7 +984,7 @@ void DXVAVideoDecodeAccelerator::DoDecode() { |
// Decoder didn't let us set NV12 output format. Not sure as to why |
// this can happen. Give up in disgust. |
NOTREACHED() << "Failed to set decoder output media type to NV12"; |
- state_ = kStopped; |
+ SetState(kStopped); |
} else { |
DVLOG(1) << "Received output format change from the decoder." |
" Recursively invoking DoDecode"; |
@@ -965,8 +993,10 @@ void DXVAVideoDecodeAccelerator::DoDecode() { |
return; |
} else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { |
// No more output from the decoder. Stop playback. |
- if (state_ != kFlushingPendingInputBuffers) |
- state_ = kStopped; |
+ if (state != kFlushingPendingInputBuffers || |
+ pending_input_buffers_.empty()) { |
+ SetState(kStopped); |
+ } |
return; |
} else { |
NOTREACHED() << "Unhandled error in DoDecode()"; |
@@ -1002,17 +1032,18 @@ bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { |
"Failed to get input buffer id associated with sample", |
false); |
- pending_output_samples_.push_back( |
- PendingSampleInfo(input_buffer_id, sample)); |
- |
- // If we have available picture buffers to copy the output data then use the |
- // first one and then flag it as not being available for use. |
- if (output_picture_buffers_.size()) { |
- ProcessPendingSamples(); |
- return true; |
+ { |
+ base::AutoLock lock(decoder_lock_); |
+ pending_output_samples_.push_back( |
+ PendingSampleInfo(input_buffer_id, sample)); |
} |
+ |
if (pictures_requested_) { |
DVLOG(1) << "Waiting for picture slots from the client."; |
+ main_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::ProcessPendingSamples, |
+ weak_this_factory_.GetWeakPtr())); |
return true; |
} |
@@ -1024,7 +1055,7 @@ bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { |
RETURN_ON_HR_FAILURE(hr, "Failed to get surface description", false); |
// Go ahead and request picture buffers. |
- base::MessageLoop::current()->PostTask( |
+ main_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
weak_this_factory_.GetWeakPtr(), |
@@ -1036,6 +1067,11 @@ bool DXVAVideoDecodeAccelerator::ProcessOutputSample(IMFSample* sample) { |
} |
void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
+ |
+ if (!output_picture_buffers_.size()) |
+ return; |
+ |
RETURN_AND_NOTIFY_ON_FAILURE(make_context_current_.Run(), |
"Failed to make context current", PLATFORM_FAILURE,); |
@@ -1043,7 +1079,7 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { |
for (index = output_picture_buffers_.begin(); |
index != output_picture_buffers_.end() && |
- !pending_output_samples_.empty(); |
+ OutputSamplesPresent(); |
++index) { |
if (index->second->available()) { |
PendingSampleInfo sample_info = pending_output_samples_.front(); |
@@ -1082,41 +1118,57 @@ void DXVAVideoDecodeAccelerator::ProcessPendingSamples() { |
media::Picture output_picture(index->second->id(), |
sample_info.input_buffer_id, |
gfx::Rect(index->second->size())); |
- base::MessageLoop::current()->PostTask( |
+ main_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::NotifyPictureReady, |
weak_this_factory_.GetWeakPtr(), |
output_picture)); |
index->second->set_available(false); |
- pending_output_samples_.pop_front(); |
+ { |
+ base::AutoLock lock(decoder_lock_); |
+ pending_output_samples_.pop_front(); |
+ } |
} |
} |
- if (!pending_input_buffers_.empty() && pending_output_samples_.empty()) { |
- base::MessageLoop::current()->PostTask( |
+ State state = GetState(); |
+ if (state == kFlushing) { |
+ decoder_thread_task_runner_->PostTask( |
FROM_HERE, |
- base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
- weak_this_factory_.GetWeakPtr())); |
+ base::Bind(&DXVAVideoDecodeAccelerator::FlushInternal, |
+ base::Unretained(this))); |
} |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
+ base::Unretained(this))); |
} |
void DXVAVideoDecodeAccelerator::StopOnError( |
media::VideoDecodeAccelerator::Error error) { |
- DCHECK(CalledOnValidThread()); |
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
+ main_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::StopOnError, |
+ weak_this_factory_.GetWeakPtr(), |
+ error)); |
+ return; |
+ } |
if (client_) |
client_->NotifyError(error); |
client_ = NULL; |
- if (state_ != kUninitialized) { |
+ if (GetState() != kUninitialized) { |
Invalidate(); |
} |
} |
void DXVAVideoDecodeAccelerator::Invalidate() { |
- if (state_ == kUninitialized) |
+ if (GetState() == kUninitialized) |
return; |
+ decoder_thread_.Stop(); |
weak_this_factory_.InvalidateWeakPtrs(); |
output_picture_buffers_.clear(); |
stale_output_picture_buffers_.clear(); |
@@ -1124,27 +1176,31 @@ void DXVAVideoDecodeAccelerator::Invalidate() { |
pending_input_buffers_.clear(); |
decoder_.Release(); |
MFShutdown(); |
- state_ = kUninitialized; |
+ SetState(kUninitialized); |
} |
void DXVAVideoDecodeAccelerator::NotifyInputBufferRead(int input_buffer_id) { |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
if (client_) |
client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
} |
void DXVAVideoDecodeAccelerator::NotifyFlushDone() { |
- if (client_) |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
+ if (client_ && GetState() == kStopped) |
client_->NotifyFlushDone(); |
} |
void DXVAVideoDecodeAccelerator::NotifyResetDone() { |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
if (client_) |
client_->NotifyResetDone(); |
} |
void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) { |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
// This task could execute after the decoder has been torn down. |
- if (state_ != kUninitialized && client_) { |
+ if (GetState() != kUninitialized && client_) { |
client_->ProvidePictureBuffers( |
kNumPictureBuffers, |
gfx::Size(width, height), |
@@ -1154,30 +1210,34 @@ void DXVAVideoDecodeAccelerator::RequestPictureBuffers(int width, int height) { |
void DXVAVideoDecodeAccelerator::NotifyPictureReady( |
const media::Picture& picture) { |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
// This task could execute after the decoder has been torn down. |
- if (state_ != kUninitialized && client_) |
+ if (GetState() != kUninitialized && client_) |
client_->PictureReady(picture); |
} |
void DXVAVideoDecodeAccelerator::NotifyInputBuffersDropped() { |
- if (!client_ || !pending_output_samples_.empty()) |
- return; |
- |
- for (PendingInputs::iterator it = pending_input_buffers_.begin(); |
- it != pending_input_buffers_.end(); ++it) { |
- LONGLONG input_buffer_id = 0; |
- RETURN_ON_HR_FAILURE((*it)->GetSampleTime(&input_buffer_id), |
- "Failed to get buffer id associated with sample",); |
- client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
- } |
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); |
+ if (!client_) |
+ return; |
+ |
+ for (PendingInputs::iterator it = pending_input_buffers_.begin(); |
+ it != pending_input_buffers_.end(); ++it) { |
+ LONGLONG input_buffer_id = 0; |
+ RETURN_ON_HR_FAILURE((*it)->GetSampleTime(&input_buffer_id), |
+ "Failed to get buffer id associated with sample",); |
+ client_->NotifyEndOfBitstreamBuffer(input_buffer_id); |
+ } |
pending_input_buffers_.clear(); |
} |
void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() { |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ != kUninitialized), |
- "Invalid state: " << state_, ILLEGAL_STATE,); |
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state != kUninitialized), |
+ "Invalid state: " << state, ILLEGAL_STATE,); |
- if (pending_input_buffers_.empty() || !pending_output_samples_.empty()) |
+ if (pending_input_buffers_.empty() || OutputSamplesPresent()) |
return; |
PendingInputs pending_input_buffers_copy; |
@@ -1187,66 +1247,56 @@ void DXVAVideoDecodeAccelerator::DecodePendingInputBuffers() { |
it != pending_input_buffers_copy.end(); ++it) { |
DecodeInternal(*it); |
} |
- |
- if (state_ != kFlushingPendingInputBuffers) |
- return; |
- |
- // If we are scheduled during a flush operation then mark the flush as |
- // complete if we have no pending input and pending output frames. |
- // If we don't have available output slots then this function will be |
- // scheduled again by the ProcessPendingSamples function once slots become |
- // available. |
- if (pending_input_buffers_.empty() && pending_output_samples_.empty()) { |
- state_ = kNormal; |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, |
- weak_this_factory_.GetWeakPtr())); |
- } |
} |
void DXVAVideoDecodeAccelerator::FlushInternal() { |
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
+ |
+ // We allow only one output frame to be present at any given time. If we have |
+ // an output frame, then we cannot complete the flush at this time. |
+ if (OutputSamplesPresent()) |
+ return; |
+ |
// The DoDecode function sets the state to kStopped when the decoder returns |
// MF_E_TRANSFORM_NEED_MORE_INPUT. |
// The MFT decoder can buffer upto 30 frames worth of input before returning |
// an output frame. This loop here attempts to retrieve as many output frames |
// as possible from the buffered set. |
- while (state_ != kStopped) { |
+ while (GetState() != kStopped) { |
DoDecode(); |
- if (!pending_output_samples_.empty()) |
+ if (OutputSamplesPresent()) |
return; |
} |
- |
// TODO(ananta) |
// Look into whether we can simplify this function by combining the while |
// above and the code below into a single block which achieves both. The Flush |
// transitions in the decoder are a touch intertwined with other portions of |
// the code like AssignPictureBuffers, ReusePictureBuffers etc. |
if (!pending_input_buffers_.empty()) { |
- state_ = kFlushingPendingInputBuffers; |
- base::MessageLoop::current()->PostTask( |
+ SetState(kFlushingPendingInputBuffers); |
+ decoder_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
- weak_this_factory_.GetWeakPtr())); |
+ base::Unretained(this))); |
return; |
} |
- base::MessageLoop::current()->PostTask( |
+ main_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::NotifyFlushDone, |
weak_this_factory_.GetWeakPtr())); |
- state_ = kNormal; |
+ SetState(kNormal); |
} |
void DXVAVideoDecodeAccelerator::DecodeInternal( |
const base::win::ScopedComPtr<IMFSample>& sample) { |
- DCHECK(CalledOnValidThread()); |
+ DCHECK(decoder_thread_task_runner_->BelongsToCurrentThread()); |
- if (state_ == kUninitialized) |
+ if (GetState() == kUninitialized) |
return; |
- if (!pending_output_samples_.empty() || !pending_input_buffers_.empty()) { |
+ if (OutputSamplesPresent() || !pending_input_buffers_.empty()) { |
pending_input_buffers_.push_back(sample); |
return; |
} |
@@ -1268,8 +1318,10 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( |
// decoder failure. |
if (hr == MF_E_NOTACCEPTING) { |
DoDecode(); |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal), |
- "Failed to process output. Unexpected decoder state: " << state_, |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kStopped || state == kNormal || |
+ state == kFlushing), |
+ "Failed to process output. Unexpected decoder state: " << state, |
PLATFORM_FAILURE,); |
hr = decoder_->ProcessInput(0, sample.get(), 0); |
// If we continue to get the MF_E_NOTACCEPTING error we do the following:- |
@@ -1283,12 +1335,10 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( |
// decoder where it recycles the output Decoder surfaces. |
if (hr == MF_E_NOTACCEPTING) { |
pending_input_buffers_.push_back(sample); |
- if (pending_output_samples_.empty()) { |
- base::MessageLoop::current()->PostTask( |
- FROM_HERE, |
- base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
- weak_this_factory_.GetWeakPtr())); |
- } |
+ decoder_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::DecodePendingInputBuffers, |
+ base::Unretained(this))); |
return; |
} |
} |
@@ -1297,9 +1347,11 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( |
DoDecode(); |
- RETURN_AND_NOTIFY_ON_FAILURE((state_ == kStopped || state_ == kNormal || |
- state_ == kFlushingPendingInputBuffers), |
- "Failed to process output. Unexpected decoder state: " << state_, |
+ State state = GetState(); |
+ RETURN_AND_NOTIFY_ON_FAILURE((state == kStopped || state == kNormal || |
+ state == kFlushingPendingInputBuffers || |
+ state == kFlushing), |
+ "Failed to process output. Unexpected decoder state: " << state, |
ILLEGAL_STATE,); |
LONGLONG input_buffer_id = 0; |
@@ -1315,7 +1367,7 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( |
// decoder to emit an output packet for every input packet. |
// http://code.google.com/p/chromium/issues/detail?id=108121 |
// http://code.google.com/p/chromium/issues/detail?id=150925 |
- base::MessageLoop::current()->PostTask( |
+ main_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::NotifyInputBufferRead, |
weak_this_factory_.GetWeakPtr(), |
@@ -1324,12 +1376,12 @@ void DXVAVideoDecodeAccelerator::DecodeInternal( |
void DXVAVideoDecodeAccelerator::HandleResolutionChanged(int width, |
int height) { |
- base::MessageLoop::current()->PostTask( |
+ main_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::DismissStaleBuffers, |
weak_this_factory_.GetWeakPtr())); |
- base::MessageLoop::current()->PostTask( |
+ main_thread_task_runner_->PostTask( |
FROM_HERE, |
base::Bind(&DXVAVideoDecodeAccelerator::RequestPictureBuffers, |
weak_this_factory_.GetWeakPtr(), |
@@ -1366,4 +1418,38 @@ void DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer( |
stale_output_picture_buffers_.erase(it); |
} |
+DXVAVideoDecodeAccelerator::State |
+DXVAVideoDecodeAccelerator::GetState() const { |
+ State state = kUninitialized; |
+ ::InterlockedExchange(reinterpret_cast<long*>(&state), |
+ state_); |
+ return state; |
+} |
+ |
+void DXVAVideoDecodeAccelerator::SetState(State new_state) { |
+ if (!main_thread_task_runner_->BelongsToCurrentThread()) { |
+ main_thread_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&DXVAVideoDecodeAccelerator::SetState, |
+ weak_this_factory_.GetWeakPtr(), |
+ new_state)); |
+ return; |
+ } |
+ ::InterlockedCompareExchange(reinterpret_cast<long*>(&state_), |
+ new_state, |
+ state_); |
+ DCHECK_EQ(state_, new_state); |
+} |
+ |
+void DXVAVideoDecodeAccelerator::StartDecoderThread() { |
+ decoder_thread_.init_com_with_mta(false); |
+ decoder_thread_.Start(); |
+ decoder_thread_task_runner_ = decoder_thread_.task_runner(); |
+} |
+ |
+bool DXVAVideoDecodeAccelerator::OutputSamplesPresent() { |
+ base::AutoLock lock(decoder_lock_); |
+ return !pending_output_samples_.empty(); |
+} |
+ |
} // namespace content |