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 "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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |