Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(600)

Side by Side Diff: media/filters/ffmpeg_video_decoder.cc

Issue 11428095: Pass in media message loop to VideoRendererBase and enforce calling on the right thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: GVD Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "media/filters/ffmpeg_video_decoder.h" 5 #include "media/filters/ffmpeg_video_decoder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/message_loop_proxy.h" 14 #include "base/message_loop_proxy.h"
15 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
16 #include "media/base/bind_to_loop.h"
16 #include "media/base/decoder_buffer.h" 17 #include "media/base/decoder_buffer.h"
17 #include "media/base/demuxer_stream.h" 18 #include "media/base/demuxer_stream.h"
18 #include "media/base/limits.h" 19 #include "media/base/limits.h"
19 #include "media/base/media_switches.h" 20 #include "media/base/media_switches.h"
20 #include "media/base/pipeline.h" 21 #include "media/base/pipeline.h"
21 #include "media/base/video_decoder_config.h" 22 #include "media/base/video_decoder_config.h"
22 #include "media/base/video_frame.h" 23 #include "media/base/video_frame.h"
23 #include "media/base/video_util.h" 24 #include "media/base/video_util.h"
24 #include "media/ffmpeg/ffmpeg_common.h" 25 #include "media/ffmpeg/ffmpeg_common.h"
25 #include "media/filters/ffmpeg_glue.h" 26 #include "media/filters/ffmpeg_glue.h"
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 127
127 // The FFmpeg API expects us to zero the data pointers in 128 // The FFmpeg API expects us to zero the data pointers in
128 // this callback 129 // this callback
129 memset(frame->data, 0, sizeof(frame->data)); 130 memset(frame->data, 0, sizeof(frame->data));
130 frame->opaque = NULL; 131 frame->opaque = NULL;
131 } 132 }
132 133
133 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream, 134 void FFmpegVideoDecoder::Initialize(const scoped_refptr<DemuxerStream>& stream,
134 const PipelineStatusCB& status_cb, 135 const PipelineStatusCB& status_cb,
135 const StatisticsCB& statistics_cb) { 136 const StatisticsCB& statistics_cb) {
136 if (!message_loop_->BelongsToCurrentThread()) { 137 DCHECK(message_loop_->BelongsToCurrentThread());
137 message_loop_->PostTask(FROM_HERE, base::Bind( 138 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
138 &FFmpegVideoDecoder::Initialize, this,
139 stream, status_cb, statistics_cb));
140 return;
141 }
142 139
143 FFmpegGlue::InitializeFFmpeg(); 140 FFmpegGlue::InitializeFFmpeg();
144 DCHECK(!demuxer_stream_) << "Already initialized."; 141 DCHECK(!demuxer_stream_) << "Already initialized.";
145 142
146 if (!stream) { 143 if (!stream) {
147 status_cb.Run(PIPELINE_ERROR_DECODE); 144 initialize_cb.Run(PIPELINE_ERROR_DECODE);
148 return; 145 return;
149 } 146 }
150 147
151 demuxer_stream_ = stream; 148 demuxer_stream_ = stream;
152 statistics_cb_ = statistics_cb; 149 statistics_cb_ = statistics_cb;
153 150
154 if (!ConfigureDecoder()) { 151 if (!ConfigureDecoder()) {
155 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 152 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
156 return; 153 return;
157 } 154 }
158 155
159 // Success! 156 // Success!
160 state_ = kNormal; 157 state_ = kNormal;
161 status_cb.Run(PIPELINE_OK); 158 initialize_cb.Run(PIPELINE_OK);
162 } 159 }
163 160
164 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { 161 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) {
165 // Complete operation asynchronously on different stack of execution as per 162 DCHECK(message_loop_->BelongsToCurrentThread());
166 // the API contract of VideoDecoder::Read() 163 DCHECK(!read_cb.is_null());
167 message_loop_->PostTask(FROM_HERE, base::Bind( 164 CHECK_NE(state_, kUninitialized);
168 &FFmpegVideoDecoder::DoRead, this, read_cb)); 165 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
166 read_cb_ = BindToCurrentLoop(read_cb);
167
168 // Return empty frames if decoding has finished.
169 if (state_ == kDecodeFinished) {
170 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame());
171 return;
172 }
173
174 ReadFromDemuxerStream();
169 } 175 }
170 176
171 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { 177 void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
172 if (!message_loop_->BelongsToCurrentThread()) { 178 DCHECK(message_loop_->BelongsToCurrentThread());
173 message_loop_->PostTask(FROM_HERE, base::Bind(
174 &FFmpegVideoDecoder::Reset, this, closure));
175 return;
176 }
177
178 DCHECK(reset_cb_.is_null()); 179 DCHECK(reset_cb_.is_null());
179 reset_cb_ = closure; 180 reset_cb_ = BindToCurrentLoop(closure);
180 181
181 if (decryptor_) 182 if (decryptor_)
182 decryptor_->CancelDecrypt(Decryptor::kVideo); 183 decryptor_->CancelDecrypt(Decryptor::kVideo);
183 184
184 // Defer the reset if a read is pending. 185 // Defer the reset if a read is pending.
185 if (!read_cb_.is_null()) 186 if (!read_cb_.is_null())
186 return; 187 return;
187 188
188 DoReset(); 189 DoReset();
189 } 190 }
190 191
191 void FFmpegVideoDecoder::DoReset() { 192 void FFmpegVideoDecoder::DoReset() {
192 DCHECK(read_cb_.is_null()); 193 DCHECK(read_cb_.is_null());
193 194
194 avcodec_flush_buffers(codec_context_); 195 avcodec_flush_buffers(codec_context_);
195 state_ = kNormal; 196 state_ = kNormal;
196 reset_cb_.Run(); 197 base::ResetAndReturn(&reset_cb_).Run();
197 reset_cb_.Reset();
198 } 198 }
199 199
200 void FFmpegVideoDecoder::Stop(const base::Closure& closure) { 200 void FFmpegVideoDecoder::Stop(const base::Closure& closure) {
201 if (!message_loop_->BelongsToCurrentThread()) { 201 DCHECK(message_loop_->BelongsToCurrentThread());
202 message_loop_->PostTask(FROM_HERE, base::Bind( 202 base::ScopedClosureRunner runner(BindToCurrentLoop(closure));
203 &FFmpegVideoDecoder::Stop, this, closure)); 203
204 if (state_ == kUninitialized)
204 return; 205 return;
205 }
206
207 if (state_ == kUninitialized) {
208 closure.Run();
209 return;
210 }
211 206
212 if (decryptor_) 207 if (decryptor_)
213 decryptor_->CancelDecrypt(Decryptor::kVideo); 208 decryptor_->CancelDecrypt(Decryptor::kVideo);
214 209
215 if (!read_cb_.is_null()) 210 if (!read_cb_.is_null())
216 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 211 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
217 212
218 ReleaseFFmpegResources(); 213 ReleaseFFmpegResources();
219 state_ = kUninitialized; 214 state_ = kUninitialized;
220 closure.Run();
221 } 215 }
222 216
223 FFmpegVideoDecoder::~FFmpegVideoDecoder() { 217 FFmpegVideoDecoder::~FFmpegVideoDecoder() {
224 DCHECK_EQ(kUninitialized, state_); 218 DCHECK_EQ(kUninitialized, state_);
225 DCHECK(!codec_context_); 219 DCHECK(!codec_context_);
226 DCHECK(!av_frame_); 220 DCHECK(!av_frame_);
227 } 221 }
228 222
229 void FFmpegVideoDecoder::DoRead(const ReadCB& read_cb) {
230 DCHECK(message_loop_->BelongsToCurrentThread());
231 DCHECK(!read_cb.is_null());
232 CHECK_NE(state_, kUninitialized);
233 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
234
235 // Return empty frames if decoding has finished.
236 if (state_ == kDecodeFinished) {
237 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame());
238 return;
239 }
240
241 read_cb_ = read_cb;
242 ReadFromDemuxerStream();
243 }
244
245 void FFmpegVideoDecoder::ReadFromDemuxerStream() { 223 void FFmpegVideoDecoder::ReadFromDemuxerStream() {
246 DCHECK_NE(state_, kUninitialized); 224 DCHECK_NE(state_, kUninitialized);
247 DCHECK_NE(state_, kDecodeFinished); 225 DCHECK_NE(state_, kDecodeFinished);
248 DCHECK(!read_cb_.is_null()); 226 DCHECK(!read_cb_.is_null());
249 227
250 demuxer_stream_->Read(base::Bind( 228 demuxer_stream_->Read(base::Bind(
251 &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this)); 229 &FFmpegVideoDecoder::DecryptOrDecodeBuffer, this));
252 } 230 }
253 231
254 void FFmpegVideoDecoder::DoDecryptOrDecodeBuffer( 232 void FFmpegVideoDecoder::DecryptOrDecodeBuffer(
255 DemuxerStream::Status status, 233 DemuxerStream::Status status,
256 const scoped_refptr<DecoderBuffer>& buffer) { 234 const scoped_refptr<DecoderBuffer>& buffer) {
257 if (!message_loop_->BelongsToCurrentThread()) { 235 DCHECK(message_loop_->BelongsToCurrentThread());
258 message_loop_->PostTask(FROM_HERE, base::Bind(
259 &FFmpegVideoDecoder::DoDecryptOrDecodeBuffer, this, status, buffer));
260 return;
261 }
262
263 DCHECK_NE(state_, kDecodeFinished); 236 DCHECK_NE(state_, kDecodeFinished);
264 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status; 237 DCHECK_EQ(status != DemuxerStream::kOk, !buffer) << status;
265 238
266 if (state_ == kUninitialized) 239 if (state_ == kUninitialized)
267 return; 240 return;
268 241
269 DCHECK(!read_cb_.is_null()); 242 DCHECK(!read_cb_.is_null());
270 243
271 if (!reset_cb_.is_null()) { 244 if (!reset_cb_.is_null()) {
272 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 245 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
(...skipping 11 matching lines...) Expand all
284 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 257 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
285 return; 258 return;
286 } 259 }
287 260
288 ReadFromDemuxerStream(); 261 ReadFromDemuxerStream();
289 return; 262 return;
290 } 263 }
291 264
292 DCHECK_EQ(status, DemuxerStream::kOk); 265 DCHECK_EQ(status, DemuxerStream::kOk);
293 266
267 // TODO(xhwang): Remove decryptor after DecryptingDemuxerStream is ready.
294 if (buffer->GetDecryptConfig() && buffer->GetDataSize()) { 268 if (buffer->GetDecryptConfig() && buffer->GetDataSize()) {
295 decryptor_->Decrypt(Decryptor::kVideo, 269 decryptor_->Decrypt(Decryptor::kVideo, buffer, BindToCurrentLoop(
296 buffer, 270 base::Bind(&FFmpegVideoDecoder::BufferDecrypted, this)));
297 base::Bind(&FFmpegVideoDecoder::BufferDecrypted, this));
298 return; 271 return;
299 } 272 }
300 273
301 DecodeBuffer(buffer); 274 DecodeBuffer(buffer);
302 } 275 }
303 276
304 void FFmpegVideoDecoder::BufferDecrypted( 277 void FFmpegVideoDecoder::BufferDecrypted(
305 Decryptor::Status decrypt_status, 278 Decryptor::Status decrypt_status,
306 const scoped_refptr<DecoderBuffer>& buffer) { 279 const scoped_refptr<DecoderBuffer>& buffer) {
307 message_loop_->PostTask(FROM_HERE, base::Bind(
308 &FFmpegVideoDecoder::DoBufferDecrypted, this, decrypt_status, buffer));
309 }
310
311 void FFmpegVideoDecoder::DoBufferDecrypted(
312 Decryptor::Status decrypt_status,
313 const scoped_refptr<DecoderBuffer>& buffer) {
314 DCHECK(message_loop_->BelongsToCurrentThread()); 280 DCHECK(message_loop_->BelongsToCurrentThread());
315 DCHECK_NE(state_, kDecodeFinished); 281 DCHECK_NE(state_, kDecodeFinished);
316 282
317 if (state_ == kUninitialized) 283 if (state_ == kUninitialized)
318 return; 284 return;
319 285
320 DCHECK(!read_cb_.is_null()); 286 DCHECK(!read_cb_.is_null());
321 287
322 if (!reset_cb_.is_null()) { 288 if (!reset_cb_.is_null()) {
323 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 289 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) { 490 if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) {
525 ReleaseFFmpegResources(); 491 ReleaseFFmpegResources();
526 return false; 492 return false;
527 } 493 }
528 494
529 av_frame_ = avcodec_alloc_frame(); 495 av_frame_ = avcodec_alloc_frame();
530 return true; 496 return true;
531 } 497 }
532 498
533 } // namespace media 499 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/ffmpeg_video_decoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698