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

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

Issue 65803002: Replace MessageLoopProxy with SingleThreadTaskRunner for media/filters/ + associated code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month 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
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_demuxer.h" 5 #include "media/filters/ffmpeg_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/base64.h" 10 #include "base/base64.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "base/callback_helpers.h" 13 #include "base/callback_helpers.h"
14 #include "base/command_line.h" 14 #include "base/command_line.h"
15 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/metrics/sparse_histogram.h" 16 #include "base/metrics/sparse_histogram.h"
18 #include "base/stl_util.h" 17 #include "base/stl_util.h"
19 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
21 #include "base/sys_byteorder.h" 20 #include "base/sys_byteorder.h"
22 #include "base/task_runner_util.h" 21 #include "base/task_runner_util.h"
23 #include "base/time/time.h" 22 #include "base/time/time.h"
24 #include "media/base/audio_decoder_config.h" 23 #include "media/base/audio_decoder_config.h"
25 #include "media/base/bind_to_loop.h" 24 #include "media/base/bind_to_loop.h"
26 #include "media/base/decoder_buffer.h" 25 #include "media/base/decoder_buffer.h"
27 #include "media/base/decrypt_config.h" 26 #include "media/base/decrypt_config.h"
28 #include "media/base/limits.h" 27 #include "media/base/limits.h"
29 #include "media/base/media_log.h" 28 #include "media/base/media_log.h"
30 #include "media/base/media_switches.h" 29 #include "media/base/media_switches.h"
31 #include "media/base/video_decoder_config.h" 30 #include "media/base/video_decoder_config.h"
32 #include "media/ffmpeg/ffmpeg_common.h" 31 #include "media/ffmpeg/ffmpeg_common.h"
33 #include "media/filters/ffmpeg_glue.h" 32 #include "media/filters/ffmpeg_glue.h"
34 #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h" 33 #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h"
35 #include "media/webm/webm_crypto_helpers.h" 34 #include "media/webm/webm_crypto_helpers.h"
36 35
37 namespace media { 36 namespace media {
38 37
39 // 38 //
40 // FFmpegDemuxerStream 39 // FFmpegDemuxerStream
41 // 40 //
42 FFmpegDemuxerStream::FFmpegDemuxerStream( 41 FFmpegDemuxerStream::FFmpegDemuxerStream(
43 FFmpegDemuxer* demuxer, 42 FFmpegDemuxer* demuxer,
43 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
44 AVStream* stream) 44 AVStream* stream)
45 : demuxer_(demuxer), 45 : demuxer_(demuxer),
46 message_loop_(base::MessageLoopProxy::current()), 46 task_runner_(task_runner),
Ami GONE FROM CHROMIUM 2013/11/08 16:54:46 I find this version slightly implying that task_ru
scherkus (not reviewing) 2013/11/08 21:51:39 This change was induced by globally removing all m
47 stream_(stream), 47 stream_(stream),
48 type_(UNKNOWN), 48 type_(UNKNOWN),
49 end_of_stream_(false), 49 end_of_stream_(false),
50 last_packet_timestamp_(kNoTimestamp()), 50 last_packet_timestamp_(kNoTimestamp()),
51 bitstream_converter_enabled_(false) { 51 bitstream_converter_enabled_(false) {
52 DCHECK(demuxer_); 52 DCHECK(demuxer_);
53 53
54 bool is_encrypted = false; 54 bool is_encrypted = false;
55 55
56 // Determine our media format. 56 // Determine our media format.
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 DCHECK(!enc_key_id.empty()); 91 DCHECK(!enc_key_id.empty());
92 if (enc_key_id.empty()) 92 if (enc_key_id.empty())
93 return; 93 return;
94 94
95 encryption_key_id_.assign(enc_key_id); 95 encryption_key_id_.assign(enc_key_id);
96 demuxer_->FireNeedKey(kWebMEncryptInitDataType, enc_key_id); 96 demuxer_->FireNeedKey(kWebMEncryptInitDataType, enc_key_id);
97 } 97 }
98 } 98 }
99 99
100 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { 100 void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
101 DCHECK(message_loop_->BelongsToCurrentThread()); 101 DCHECK(task_runner_->BelongsToCurrentThread());
102 102
103 if (!demuxer_ || end_of_stream_) { 103 if (!demuxer_ || end_of_stream_) {
104 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; 104 NOTREACHED() << "Attempted to enqueue packet on a stopped stream";
105 return; 105 return;
106 } 106 }
107 107
108 // Convert the packet if there is a bitstream filter. 108 // Convert the packet if there is a bitstream filter.
109 if (packet->data && bitstream_converter_enabled_ && 109 if (packet->data && bitstream_converter_enabled_ &&
110 !bitstream_converter_->ConvertPacket(packet.get())) { 110 !bitstream_converter_->ConvertPacket(packet.get())) {
111 LOG(ERROR) << "Format conversion failed."; 111 LOG(ERROR) << "Format conversion failed.";
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 buffered_ranges_.Add(last_packet_timestamp_, buffer->timestamp()); 170 buffered_ranges_.Add(last_packet_timestamp_, buffer->timestamp());
171 demuxer_->NotifyBufferingChanged(); 171 demuxer_->NotifyBufferingChanged();
172 } 172 }
173 last_packet_timestamp_ = buffer->timestamp(); 173 last_packet_timestamp_ = buffer->timestamp();
174 174
175 buffer_queue_.Push(buffer); 175 buffer_queue_.Push(buffer);
176 SatisfyPendingRead(); 176 SatisfyPendingRead();
177 } 177 }
178 178
179 void FFmpegDemuxerStream::SetEndOfStream() { 179 void FFmpegDemuxerStream::SetEndOfStream() {
180 DCHECK(message_loop_->BelongsToCurrentThread()); 180 DCHECK(task_runner_->BelongsToCurrentThread());
181 end_of_stream_ = true; 181 end_of_stream_ = true;
182 SatisfyPendingRead(); 182 SatisfyPendingRead();
183 } 183 }
184 184
185 void FFmpegDemuxerStream::FlushBuffers() { 185 void FFmpegDemuxerStream::FlushBuffers() {
186 DCHECK(message_loop_->BelongsToCurrentThread()); 186 DCHECK(task_runner_->BelongsToCurrentThread());
187 DCHECK(read_cb_.is_null()) << "There should be no pending read"; 187 DCHECK(read_cb_.is_null()) << "There should be no pending read";
188 buffer_queue_.Clear(); 188 buffer_queue_.Clear();
189 end_of_stream_ = false; 189 end_of_stream_ = false;
190 last_packet_timestamp_ = kNoTimestamp(); 190 last_packet_timestamp_ = kNoTimestamp();
191 } 191 }
192 192
193 void FFmpegDemuxerStream::Stop() { 193 void FFmpegDemuxerStream::Stop() {
194 DCHECK(message_loop_->BelongsToCurrentThread()); 194 DCHECK(task_runner_->BelongsToCurrentThread());
195 buffer_queue_.Clear(); 195 buffer_queue_.Clear();
196 if (!read_cb_.is_null()) { 196 if (!read_cb_.is_null()) {
197 base::ResetAndReturn(&read_cb_).Run( 197 base::ResetAndReturn(&read_cb_).Run(
198 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 198 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
199 } 199 }
200 demuxer_ = NULL; 200 demuxer_ = NULL;
201 stream_ = NULL; 201 stream_ = NULL;
202 end_of_stream_ = true; 202 end_of_stream_ = true;
203 } 203 }
204 204
205 base::TimeDelta FFmpegDemuxerStream::duration() { 205 base::TimeDelta FFmpegDemuxerStream::duration() {
206 return duration_; 206 return duration_;
207 } 207 }
208 208
209 DemuxerStream::Type FFmpegDemuxerStream::type() { 209 DemuxerStream::Type FFmpegDemuxerStream::type() {
210 DCHECK(message_loop_->BelongsToCurrentThread()); 210 DCHECK(task_runner_->BelongsToCurrentThread());
211 return type_; 211 return type_;
212 } 212 }
213 213
214 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { 214 void FFmpegDemuxerStream::Read(const ReadCB& read_cb) {
215 DCHECK(message_loop_->BelongsToCurrentThread()); 215 DCHECK(task_runner_->BelongsToCurrentThread());
216 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported"; 216 CHECK(read_cb_.is_null()) << "Overlapping reads are not supported";
217 read_cb_ = BindToCurrentLoop(read_cb); 217 read_cb_ = BindToCurrentLoop(read_cb);
218 218
219 // Don't accept any additional reads if we've been told to stop. 219 // Don't accept any additional reads if we've been told to stop.
220 // The |demuxer_| may have been destroyed in the pipeline thread. 220 // The |demuxer_| may have been destroyed in the pipeline thread.
221 // 221 //
222 // TODO(scherkus): it would be cleaner to reply with an error message. 222 // TODO(scherkus): it would be cleaner to reply with an error message.
223 if (!demuxer_) { 223 if (!demuxer_) {
224 base::ResetAndReturn(&read_cb_).Run( 224 base::ResetAndReturn(&read_cb_).Run(
225 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 225 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
226 return; 226 return;
227 } 227 }
228 228
229 SatisfyPendingRead(); 229 SatisfyPendingRead();
230 } 230 }
231 231
232 void FFmpegDemuxerStream::EnableBitstreamConverter() { 232 void FFmpegDemuxerStream::EnableBitstreamConverter() {
233 DCHECK(message_loop_->BelongsToCurrentThread()); 233 DCHECK(task_runner_->BelongsToCurrentThread());
234 CHECK(bitstream_converter_.get()); 234 CHECK(bitstream_converter_.get());
235 bitstream_converter_enabled_ = true; 235 bitstream_converter_enabled_ = true;
236 } 236 }
237 237
238 AudioDecoderConfig FFmpegDemuxerStream::audio_decoder_config() { 238 AudioDecoderConfig FFmpegDemuxerStream::audio_decoder_config() {
239 DCHECK(message_loop_->BelongsToCurrentThread()); 239 DCHECK(task_runner_->BelongsToCurrentThread());
240 CHECK_EQ(type_, AUDIO); 240 CHECK_EQ(type_, AUDIO);
241 return audio_config_; 241 return audio_config_;
242 } 242 }
243 243
244 VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() { 244 VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() {
245 DCHECK(message_loop_->BelongsToCurrentThread()); 245 DCHECK(task_runner_->BelongsToCurrentThread());
246 CHECK_EQ(type_, VIDEO); 246 CHECK_EQ(type_, VIDEO);
247 return video_config_; 247 return video_config_;
248 } 248 }
249 249
250 FFmpegDemuxerStream::~FFmpegDemuxerStream() { 250 FFmpegDemuxerStream::~FFmpegDemuxerStream() {
251 DCHECK(!demuxer_); 251 DCHECK(!demuxer_);
252 DCHECK(read_cb_.is_null()); 252 DCHECK(read_cb_.is_null());
253 DCHECK(buffer_queue_.IsEmpty()); 253 DCHECK(buffer_queue_.IsEmpty());
254 } 254 }
255 255
256 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const { 256 base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const {
257 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts); 257 return ConvertStreamTimestamp(stream_->time_base, stream_->cur_dts);
258 } 258 }
259 259
260 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const { 260 Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const {
261 return buffered_ranges_; 261 return buffered_ranges_;
262 } 262 }
263 263
264 void FFmpegDemuxerStream::SatisfyPendingRead() { 264 void FFmpegDemuxerStream::SatisfyPendingRead() {
265 DCHECK(message_loop_->BelongsToCurrentThread()); 265 DCHECK(task_runner_->BelongsToCurrentThread());
266 if (!read_cb_.is_null()) { 266 if (!read_cb_.is_null()) {
267 if (!buffer_queue_.IsEmpty()) { 267 if (!buffer_queue_.IsEmpty()) {
268 base::ResetAndReturn(&read_cb_).Run( 268 base::ResetAndReturn(&read_cb_).Run(
269 DemuxerStream::kOk, buffer_queue_.Pop()); 269 DemuxerStream::kOk, buffer_queue_.Pop());
270 } else if (end_of_stream_) { 270 } else if (end_of_stream_) {
271 base::ResetAndReturn(&read_cb_).Run( 271 base::ResetAndReturn(&read_cb_).Run(
272 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); 272 DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
273 } 273 }
274 } 274 }
275 275
(...skipping 20 matching lines...) Expand all
296 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) 296 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE))
297 return kNoTimestamp(); 297 return kNoTimestamp();
298 298
299 return ConvertFromTimeBase(time_base, timestamp); 299 return ConvertFromTimeBase(time_base, timestamp);
300 } 300 }
301 301
302 // 302 //
303 // FFmpegDemuxer 303 // FFmpegDemuxer
304 // 304 //
305 FFmpegDemuxer::FFmpegDemuxer( 305 FFmpegDemuxer::FFmpegDemuxer(
306 const scoped_refptr<base::MessageLoopProxy>& message_loop, 306 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
307 DataSource* data_source, 307 DataSource* data_source,
308 const NeedKeyCB& need_key_cb, 308 const NeedKeyCB& need_key_cb,
309 const scoped_refptr<MediaLog>& media_log) 309 const scoped_refptr<MediaLog>& media_log)
310 : host_(NULL), 310 : host_(NULL),
311 message_loop_(message_loop), 311 task_runner_(task_runner),
312 weak_factory_(this), 312 weak_factory_(this),
313 blocking_thread_("FFmpegDemuxer"), 313 blocking_thread_("FFmpegDemuxer"),
314 pending_read_(false), 314 pending_read_(false),
315 pending_seek_(false), 315 pending_seek_(false),
316 data_source_(data_source), 316 data_source_(data_source),
317 media_log_(media_log), 317 media_log_(media_log),
318 bitrate_(0), 318 bitrate_(0),
319 start_time_(kNoTimestamp()), 319 start_time_(kNoTimestamp()),
320 audio_disabled_(false), 320 audio_disabled_(false),
321 duration_known_(false), 321 duration_known_(false),
322 url_protocol_(data_source, BindToLoop(message_loop_, base::Bind( 322 url_protocol_(data_source, BindToLoop(task_runner_, base::Bind(
323 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))), 323 &FFmpegDemuxer::OnDataSourceError, base::Unretained(this)))),
324 need_key_cb_(need_key_cb) { 324 need_key_cb_(need_key_cb) {
325 DCHECK(message_loop_.get()); 325 DCHECK(task_runner_.get());
326 DCHECK(data_source_); 326 DCHECK(data_source_);
327 } 327 }
328 328
329 FFmpegDemuxer::~FFmpegDemuxer() {} 329 FFmpegDemuxer::~FFmpegDemuxer() {}
330 330
331 void FFmpegDemuxer::Stop(const base::Closure& callback) { 331 void FFmpegDemuxer::Stop(const base::Closure& callback) {
332 DCHECK(message_loop_->BelongsToCurrentThread()); 332 DCHECK(task_runner_->BelongsToCurrentThread());
333 url_protocol_.Abort(); 333 url_protocol_.Abort();
334 data_source_->Stop(BindToCurrentLoop(base::Bind( 334 data_source_->Stop(BindToCurrentLoop(base::Bind(
335 &FFmpegDemuxer::OnDataSourceStopped, weak_this_, 335 &FFmpegDemuxer::OnDataSourceStopped, weak_this_,
336 BindToCurrentLoop(callback)))); 336 BindToCurrentLoop(callback))));
337 data_source_ = NULL; 337 data_source_ = NULL;
338 } 338 }
339 339
340 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { 340 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
341 DCHECK(message_loop_->BelongsToCurrentThread()); 341 DCHECK(task_runner_->BelongsToCurrentThread());
342 CHECK(!pending_seek_); 342 CHECK(!pending_seek_);
343 343
344 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, 344 // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|,
345 // otherwise we can end up waiting for a pre-seek read to complete even though 345 // otherwise we can end up waiting for a pre-seek read to complete even though
346 // we know we're going to drop it on the floor. 346 // we know we're going to drop it on the floor.
347 347
348 // Always seek to a timestamp less than or equal to the desired timestamp. 348 // Always seek to a timestamp less than or equal to the desired timestamp.
349 int flags = AVSEEK_FLAG_BACKWARD; 349 int flags = AVSEEK_FLAG_BACKWARD;
350 350
351 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg 351 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg
352 // will attempt to use the lowest-index video stream, if present, followed by 352 // will attempt to use the lowest-index video stream, if present, followed by
353 // the lowest-index audio stream. 353 // the lowest-index audio stream.
354 pending_seek_ = true; 354 pending_seek_ = true;
355 base::PostTaskAndReplyWithResult( 355 base::PostTaskAndReplyWithResult(
356 blocking_thread_.message_loop_proxy().get(), 356 blocking_thread_.message_loop_proxy().get(),
357 FROM_HERE, 357 FROM_HERE,
358 base::Bind(&av_seek_frame, 358 base::Bind(&av_seek_frame,
359 glue_->format_context(), 359 glue_->format_context(),
360 -1, 360 -1,
361 time.InMicroseconds(), 361 time.InMicroseconds(),
362 flags), 362 flags),
363 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_this_, cb)); 363 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_this_, cb));
364 } 364 }
365 365
366 void FFmpegDemuxer::OnAudioRendererDisabled() { 366 void FFmpegDemuxer::OnAudioRendererDisabled() {
367 DCHECK(message_loop_->BelongsToCurrentThread()); 367 DCHECK(task_runner_->BelongsToCurrentThread());
368 audio_disabled_ = true; 368 audio_disabled_ = true;
369 StreamVector::iterator iter; 369 StreamVector::iterator iter;
370 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 370 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
371 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { 371 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
372 (*iter)->Stop(); 372 (*iter)->Stop();
373 } 373 }
374 } 374 }
375 } 375 }
376 376
377 void FFmpegDemuxer::Initialize(DemuxerHost* host, 377 void FFmpegDemuxer::Initialize(DemuxerHost* host,
378 const PipelineStatusCB& status_cb) { 378 const PipelineStatusCB& status_cb) {
379 DCHECK(message_loop_->BelongsToCurrentThread()); 379 DCHECK(task_runner_->BelongsToCurrentThread());
380 host_ = host; 380 host_ = host;
381 weak_this_ = weak_factory_.GetWeakPtr(); 381 weak_this_ = weak_factory_.GetWeakPtr();
382 382
383 // TODO(scherkus): DataSource should have a host by this point, 383 // TODO(scherkus): DataSource should have a host by this point,
384 // see http://crbug.com/122071 384 // see http://crbug.com/122071
385 data_source_->set_host(host); 385 data_source_->set_host(host);
386 386
387 glue_.reset(new FFmpegGlue(&url_protocol_)); 387 glue_.reset(new FFmpegGlue(&url_protocol_));
388 AVFormatContext* format_context = glue_->format_context(); 388 AVFormatContext* format_context = glue_->format_context();
389 389
390 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we 390 // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we
391 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is 391 // don't use. FFmpeg will only read ID3v1 tags if no other metadata is
392 // available, so add a metadata entry to ensure some is always present. 392 // available, so add a metadata entry to ensure some is always present.
393 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); 393 av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0);
394 394
395 // Open the AVFormatContext using our glue layer. 395 // Open the AVFormatContext using our glue layer.
396 CHECK(blocking_thread_.Start()); 396 CHECK(blocking_thread_.Start());
397 base::PostTaskAndReplyWithResult( 397 base::PostTaskAndReplyWithResult(
398 blocking_thread_.message_loop_proxy().get(), 398 blocking_thread_.message_loop_proxy().get(),
399 FROM_HERE, 399 FROM_HERE,
400 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), 400 base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())),
401 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_this_, status_cb)); 401 base::Bind(&FFmpegDemuxer::OnOpenContextDone, weak_this_, status_cb));
402 } 402 }
403 403
404 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) { 404 DemuxerStream* FFmpegDemuxer::GetStream(DemuxerStream::Type type) {
405 DCHECK(message_loop_->BelongsToCurrentThread()); 405 DCHECK(task_runner_->BelongsToCurrentThread());
406 return GetFFmpegStream(type); 406 return GetFFmpegStream(type);
407 } 407 }
408 408
409 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream( 409 FFmpegDemuxerStream* FFmpegDemuxer::GetFFmpegStream(
410 DemuxerStream::Type type) const { 410 DemuxerStream::Type type) const {
411 StreamVector::const_iterator iter; 411 StreamVector::const_iterator iter;
412 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 412 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
413 if (*iter && (*iter)->type() == type) { 413 if (*iter && (*iter)->type() == type) {
414 return *iter; 414 return *iter;
415 } 415 }
416 } 416 }
417 return NULL; 417 return NULL;
418 } 418 }
419 419
420 base::TimeDelta FFmpegDemuxer::GetStartTime() const { 420 base::TimeDelta FFmpegDemuxer::GetStartTime() const {
421 DCHECK(message_loop_->BelongsToCurrentThread()); 421 DCHECK(task_runner_->BelongsToCurrentThread());
422 return start_time_; 422 return start_time_;
423 } 423 }
424 424
425 // Helper for calculating the bitrate of the media based on information stored 425 // Helper for calculating the bitrate of the media based on information stored
426 // in |format_context| or failing that the size and duration of the media. 426 // in |format_context| or failing that the size and duration of the media.
427 // 427 //
428 // Returns 0 if a bitrate could not be determined. 428 // Returns 0 if a bitrate could not be determined.
429 static int CalculateBitrate( 429 static int CalculateBitrate(
430 AVFormatContext* format_context, 430 AVFormatContext* format_context,
431 const base::TimeDelta& duration, 431 const base::TimeDelta& duration,
(...skipping 21 matching lines...) Expand all
453 453
454 // Do math in floating point as we'd overflow an int64 if the filesize was 454 // Do math in floating point as we'd overflow an int64 if the filesize was
455 // larger than ~1073GB. 455 // larger than ~1073GB.
456 double bytes = filesize_in_bytes; 456 double bytes = filesize_in_bytes;
457 double duration_us = duration.InMicroseconds(); 457 double duration_us = duration.InMicroseconds();
458 return bytes * 8000000.0 / duration_us; 458 return bytes * 8000000.0 / duration_us;
459 } 459 }
460 460
461 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, 461 void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb,
462 bool result) { 462 bool result) {
463 DCHECK(message_loop_->BelongsToCurrentThread()); 463 DCHECK(task_runner_->BelongsToCurrentThread());
464 if (!blocking_thread_.IsRunning()) { 464 if (!blocking_thread_.IsRunning()) {
465 status_cb.Run(PIPELINE_ERROR_ABORT); 465 status_cb.Run(PIPELINE_ERROR_ABORT);
466 return; 466 return;
467 } 467 }
468 468
469 if (!result) { 469 if (!result) {
470 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN); 470 status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
471 return; 471 return;
472 } 472 }
473 473
474 // Fully initialize AVFormatContext by parsing the stream a little. 474 // Fully initialize AVFormatContext by parsing the stream a little.
475 base::PostTaskAndReplyWithResult( 475 base::PostTaskAndReplyWithResult(
476 blocking_thread_.message_loop_proxy().get(), 476 blocking_thread_.message_loop_proxy().get(),
477 FROM_HERE, 477 FROM_HERE,
478 base::Bind(&avformat_find_stream_info, 478 base::Bind(&avformat_find_stream_info,
479 glue_->format_context(), 479 glue_->format_context(),
480 static_cast<AVDictionary**>(NULL)), 480 static_cast<AVDictionary**>(NULL)),
481 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, weak_this_, status_cb)); 481 base::Bind(&FFmpegDemuxer::OnFindStreamInfoDone, weak_this_, status_cb));
482 } 482 }
483 483
484 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, 484 void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
485 int result) { 485 int result) {
486 DCHECK(message_loop_->BelongsToCurrentThread()); 486 DCHECK(task_runner_->BelongsToCurrentThread());
487 if (!blocking_thread_.IsRunning() || !data_source_) { 487 if (!blocking_thread_.IsRunning() || !data_source_) {
488 status_cb.Run(PIPELINE_ERROR_ABORT); 488 status_cb.Run(PIPELINE_ERROR_ABORT);
489 return; 489 return;
490 } 490 }
491 491
492 if (result < 0) { 492 if (result < 0) {
493 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE); 493 status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
494 return; 494 return;
495 } 495 }
496 496
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 // frame size and visible size are valid. 537 // frame size and visible size are valid.
538 AVStreamToVideoDecoderConfig(stream, &video_config, false); 538 AVStreamToVideoDecoderConfig(stream, &video_config, false);
539 539
540 if (!video_config.IsValidConfig()) 540 if (!video_config.IsValidConfig())
541 continue; 541 continue;
542 video_stream = stream; 542 video_stream = stream;
543 } else { 543 } else {
544 continue; 544 continue;
545 } 545 }
546 546
547 streams_[i] = new FFmpegDemuxerStream(this, stream); 547 streams_[i] = new FFmpegDemuxerStream(this, task_runner_, stream);
548 max_duration = std::max(max_duration, streams_[i]->duration()); 548 max_duration = std::max(max_duration, streams_[i]->duration());
549 549
550 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) { 550 if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
551 const base::TimeDelta first_dts = ConvertFromTimeBase( 551 const base::TimeDelta first_dts = ConvertFromTimeBase(
552 stream->time_base, stream->first_dts); 552 stream->time_base, stream->first_dts);
553 if (start_time_ == kNoTimestamp() || first_dts < start_time_) 553 if (start_time_ == kNoTimestamp() || first_dts < start_time_)
554 start_time_ = first_dts; 554 start_time_ = first_dts;
555 } 555 }
556 } 556 }
557 557
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 647
648 648
649 media_log_->SetDoubleProperty("max_duration", max_duration.InSecondsF()); 649 media_log_->SetDoubleProperty("max_duration", max_duration.InSecondsF());
650 media_log_->SetDoubleProperty("start_time", start_time_.InSecondsF()); 650 media_log_->SetDoubleProperty("start_time", start_time_.InSecondsF());
651 media_log_->SetIntegerProperty("bitrate", bitrate_); 651 media_log_->SetIntegerProperty("bitrate", bitrate_);
652 652
653 status_cb.Run(PIPELINE_OK); 653 status_cb.Run(PIPELINE_OK);
654 } 654 }
655 655
656 void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) { 656 void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) {
657 DCHECK(message_loop_->BelongsToCurrentThread()); 657 DCHECK(task_runner_->BelongsToCurrentThread());
658 CHECK(pending_seek_); 658 CHECK(pending_seek_);
659 pending_seek_ = false; 659 pending_seek_ = false;
660 660
661 if (!blocking_thread_.IsRunning()) { 661 if (!blocking_thread_.IsRunning()) {
662 cb.Run(PIPELINE_ERROR_ABORT); 662 cb.Run(PIPELINE_ERROR_ABORT);
663 return; 663 return;
664 } 664 }
665 665
666 if (result < 0) { 666 if (result < 0) {
667 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being 667 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being
(...skipping 10 matching lines...) Expand all
678 } 678 }
679 679
680 // Resume reading until capacity. 680 // Resume reading until capacity.
681 ReadFrameIfNeeded(); 681 ReadFrameIfNeeded();
682 682
683 // Notify we're finished seeking. 683 // Notify we're finished seeking.
684 cb.Run(PIPELINE_OK); 684 cb.Run(PIPELINE_OK);
685 } 685 }
686 686
687 void FFmpegDemuxer::ReadFrameIfNeeded() { 687 void FFmpegDemuxer::ReadFrameIfNeeded() {
688 DCHECK(message_loop_->BelongsToCurrentThread()); 688 DCHECK(task_runner_->BelongsToCurrentThread());
689 689
690 // Make sure we have work to do before reading. 690 // Make sure we have work to do before reading.
691 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || 691 if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() ||
692 pending_read_ || pending_seek_) { 692 pending_read_ || pending_seek_) {
693 return; 693 return;
694 } 694 }
695 695
696 // Allocate and read an AVPacket from the media. Save |packet_ptr| since 696 // Allocate and read an AVPacket from the media. Save |packet_ptr| since
697 // evaluation order of packet.get() and base::Passed(&packet) is 697 // evaluation order of packet.get() and base::Passed(&packet) is
698 // undefined. 698 // undefined.
699 ScopedAVPacket packet(new AVPacket()); 699 ScopedAVPacket packet(new AVPacket());
700 AVPacket* packet_ptr = packet.get(); 700 AVPacket* packet_ptr = packet.get();
701 701
702 pending_read_ = true; 702 pending_read_ = true;
703 base::PostTaskAndReplyWithResult( 703 base::PostTaskAndReplyWithResult(
704 blocking_thread_.message_loop_proxy().get(), 704 blocking_thread_.message_loop_proxy().get(),
705 FROM_HERE, 705 FROM_HERE,
706 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr), 706 base::Bind(&av_read_frame, glue_->format_context(), packet_ptr),
707 base::Bind( 707 base::Bind(
708 &FFmpegDemuxer::OnReadFrameDone, weak_this_, base::Passed(&packet))); 708 &FFmpegDemuxer::OnReadFrameDone, weak_this_, base::Passed(&packet)));
709 } 709 }
710 710
711 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { 711 void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
712 DCHECK(message_loop_->BelongsToCurrentThread()); 712 DCHECK(task_runner_->BelongsToCurrentThread());
713 DCHECK(pending_read_); 713 DCHECK(pending_read_);
714 pending_read_ = false; 714 pending_read_ = false;
715 715
716 if (!blocking_thread_.IsRunning() || pending_seek_) { 716 if (!blocking_thread_.IsRunning() || pending_seek_) {
717 return; 717 return;
718 } 718 }
719 719
720 if (result < 0) { 720 if (result < 0) {
721 // Update the duration based on the audio stream if 721 // Update the duration based on the audio stream if
722 // it was previously unknown http://crbug.com/86830 722 // it was previously unknown http://crbug.com/86830
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
777 777
778 // Keep reading until we've reached capacity. 778 // Keep reading until we've reached capacity.
779 ReadFrameIfNeeded(); 779 ReadFrameIfNeeded();
780 } 780 }
781 781
782 void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) { 782 void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) {
783 // This will block until all tasks complete. Note that after this returns it's 783 // This will block until all tasks complete. Note that after this returns it's
784 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this 784 // possible for reply tasks (e.g., OnReadFrameDone()) to be queued on this
785 // thread. Each of the reply task methods must check whether we've stopped the 785 // thread. Each of the reply task methods must check whether we've stopped the
786 // thread and drop their results on the floor. 786 // thread and drop their results on the floor.
787 DCHECK(message_loop_->BelongsToCurrentThread()); 787 DCHECK(task_runner_->BelongsToCurrentThread());
788 blocking_thread_.Stop(); 788 blocking_thread_.Stop();
789 789
790 StreamVector::iterator iter; 790 StreamVector::iterator iter;
791 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 791 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
792 if (*iter) 792 if (*iter)
793 (*iter)->Stop(); 793 (*iter)->Stop();
794 } 794 }
795 795
796 callback.Run(); 796 callback.Run();
797 } 797 }
798 798
799 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { 799 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() {
800 DCHECK(message_loop_->BelongsToCurrentThread()); 800 DCHECK(task_runner_->BelongsToCurrentThread());
801 StreamVector::iterator iter; 801 StreamVector::iterator iter;
802 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 802 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
803 if (*iter && (*iter)->HasAvailableCapacity()) { 803 if (*iter && (*iter)->HasAvailableCapacity()) {
804 return true; 804 return true;
805 } 805 }
806 } 806 }
807 return false; 807 return false;
808 } 808 }
809 809
810 void FFmpegDemuxer::StreamHasEnded() { 810 void FFmpegDemuxer::StreamHasEnded() {
811 DCHECK(message_loop_->BelongsToCurrentThread()); 811 DCHECK(task_runner_->BelongsToCurrentThread());
812 StreamVector::iterator iter; 812 StreamVector::iterator iter;
813 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { 813 for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
814 if (!*iter || 814 if (!*iter ||
815 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { 815 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) {
816 continue; 816 continue;
817 } 817 }
818 (*iter)->SetEndOfStream(); 818 (*iter)->SetEndOfStream();
819 } 819 }
820 } 820 }
821 821
822 void FFmpegDemuxer::FireNeedKey(const std::string& init_data_type, 822 void FFmpegDemuxer::FireNeedKey(const std::string& init_data_type,
823 const std::string& encryption_key_id) { 823 const std::string& encryption_key_id) {
824 std::vector<uint8> key_id_local(encryption_key_id.begin(), 824 std::vector<uint8> key_id_local(encryption_key_id.begin(),
825 encryption_key_id.end()); 825 encryption_key_id.end());
826 need_key_cb_.Run(init_data_type, key_id_local); 826 need_key_cb_.Run(init_data_type, key_id_local);
827 } 827 }
828 828
829 void FFmpegDemuxer::NotifyCapacityAvailable() { 829 void FFmpegDemuxer::NotifyCapacityAvailable() {
830 DCHECK(message_loop_->BelongsToCurrentThread()); 830 DCHECK(task_runner_->BelongsToCurrentThread());
831 ReadFrameIfNeeded(); 831 ReadFrameIfNeeded();
832 } 832 }
833 833
834 void FFmpegDemuxer::NotifyBufferingChanged() { 834 void FFmpegDemuxer::NotifyBufferingChanged() {
835 DCHECK(message_loop_->BelongsToCurrentThread()); 835 DCHECK(task_runner_->BelongsToCurrentThread());
836 Ranges<base::TimeDelta> buffered; 836 Ranges<base::TimeDelta> buffered;
837 FFmpegDemuxerStream* audio = 837 FFmpegDemuxerStream* audio =
838 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); 838 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO);
839 FFmpegDemuxerStream* video = GetFFmpegStream(DemuxerStream::VIDEO); 839 FFmpegDemuxerStream* video = GetFFmpegStream(DemuxerStream::VIDEO);
840 if (audio && video) { 840 if (audio && video) {
841 buffered = audio->GetBufferedRanges().IntersectionWith( 841 buffered = audio->GetBufferedRanges().IntersectionWith(
842 video->GetBufferedRanges()); 842 video->GetBufferedRanges());
843 } else if (audio) { 843 } else if (audio) {
844 buffered = audio->GetBufferedRanges(); 844 buffered = audio->GetBufferedRanges();
845 } else if (video) { 845 } else if (video) {
846 buffered = video->GetBufferedRanges(); 846 buffered = video->GetBufferedRanges();
847 } 847 }
848 for (size_t i = 0; i < buffered.size(); ++i) 848 for (size_t i = 0; i < buffered.size(); ++i)
849 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 849 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
850 } 850 }
851 851
852 void FFmpegDemuxer::OnDataSourceError() { 852 void FFmpegDemuxer::OnDataSourceError() {
853 host_->OnDemuxerError(PIPELINE_ERROR_READ); 853 host_->OnDemuxerError(PIPELINE_ERROR_READ);
854 } 854 }
855 855
856 } // namespace media 856 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698