| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "base/scoped_ptr.h" | 5 #include "base/scoped_ptr.h" |
| 6 #include "base/stl_util-inl.h" | 6 #include "base/stl_util-inl.h" |
| 7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
| 8 #include "base/time.h" | 8 #include "base/time.h" |
| 9 #include "media/base/filter_host.h" | 9 #include "media/base/filter_host.h" |
| 10 #include "media/filters/ffmpeg_common.h" | 10 #include "media/filters/ffmpeg_common.h" |
| 11 #include "media/filters/ffmpeg_demuxer.h" | 11 #include "media/filters/ffmpeg_demuxer.h" |
| 12 #include "media/filters/ffmpeg_glue.h" | 12 #include "media/filters/ffmpeg_glue.h" |
| 13 | 13 |
| 14 namespace { | |
| 15 | |
| 16 // Helper function to deep copy an AVPacket's data, size and timestamps. | |
| 17 // Returns NULL if a packet could not be cloned (i.e., out of memory). | |
| 18 AVPacket* ClonePacket(AVPacket* packet) { | |
| 19 scoped_ptr<AVPacket> clone(new AVPacket()); | |
| 20 if (!clone.get() || av_new_packet(clone.get(), packet->size) < 0) { | |
| 21 return NULL; | |
| 22 } | |
| 23 DCHECK_EQ(clone->size, packet->size); | |
| 24 clone->dts = packet->dts; | |
| 25 clone->pts = packet->pts; | |
| 26 clone->duration = packet->duration; | |
| 27 memcpy(clone->data, packet->data, clone->size); | |
| 28 return clone.release(); | |
| 29 } | |
| 30 | |
| 31 } // namespace | |
| 32 | |
| 33 namespace media { | 14 namespace media { |
| 34 | 15 |
| 35 // | 16 // |
| 36 // AVPacketBuffer | 17 // AVPacketBuffer |
| 37 // | 18 // |
| 38 class AVPacketBuffer : public Buffer { | 19 class AVPacketBuffer : public Buffer { |
| 39 public: | 20 public: |
| 40 AVPacketBuffer(AVPacket* packet, const base::TimeDelta& timestamp, | 21 AVPacketBuffer(AVPacket* packet, const base::TimeDelta& timestamp, |
| 41 const base::TimeDelta& duration) | 22 const base::TimeDelta& duration) |
| 42 : packet_(packet) { | 23 : packet_(packet) { |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 message_loop()->PostTask(FROM_HERE, | 272 message_loop()->PostTask(FROM_HERE, |
| 292 NewRunnableMethod(this, &FFmpegDemuxer::InitializeTask, data_source, | 273 NewRunnableMethod(this, &FFmpegDemuxer::InitializeTask, data_source, |
| 293 callback)); | 274 callback)); |
| 294 } | 275 } |
| 295 | 276 |
| 296 size_t FFmpegDemuxer::GetNumberOfStreams() { | 277 size_t FFmpegDemuxer::GetNumberOfStreams() { |
| 297 return streams_.size(); | 278 return streams_.size(); |
| 298 } | 279 } |
| 299 | 280 |
| 300 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { | 281 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(int stream) { |
| 301 DCHECK(stream >= 0); | 282 DCHECK_GE(stream, 0); |
| 302 DCHECK(stream < static_cast<int>(streams_.size())); | 283 DCHECK_LT(stream, static_cast<int>(streams_.size())); |
| 303 return streams_[stream].get(); | 284 return streams_[stream].get(); |
| 304 } | 285 } |
| 305 | 286 |
| 306 int FFmpegDemuxer::Read(int size, uint8* data) { | 287 int FFmpegDemuxer::Read(int size, uint8* data) { |
| 307 DCHECK(data_source_); | 288 DCHECK(data_source_); |
| 308 | 289 |
| 309 // If read has ever failed, return with an error. | 290 // If read has ever failed, return with an error. |
| 310 // TODO(hclam): use a more meaningful constant as error. | 291 // TODO(hclam): use a more meaningful constant as error. |
| 311 if (read_has_failed_) | 292 if (read_has_failed_) |
| 312 return AVERROR_IO; | 293 return AVERROR_IO; |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 // If we have reached the end of stream, tell the downstream filters about | 465 // If we have reached the end of stream, tell the downstream filters about |
| 485 // the event. | 466 // the event. |
| 486 StreamHasEnded(); | 467 StreamHasEnded(); |
| 487 return; | 468 return; |
| 488 } | 469 } |
| 489 | 470 |
| 490 // Queue the packet with the appropriate stream. | 471 // Queue the packet with the appropriate stream. |
| 491 // TODO(scherkus): should we post this back to the pipeline thread? I'm | 472 // TODO(scherkus): should we post this back to the pipeline thread? I'm |
| 492 // worried about downstream filters (i.e., decoders) executing on this | 473 // worried about downstream filters (i.e., decoders) executing on this |
| 493 // thread. | 474 // thread. |
| 494 DCHECK(packet->stream_index >= 0); | 475 DCHECK_GE(packet->stream_index, 0); |
| 495 DCHECK(packet->stream_index < static_cast<int>(packet_streams_.size())); | 476 DCHECK_LT(packet->stream_index, static_cast<int>(packet_streams_.size())); |
| 496 FFmpegDemuxerStream* demuxer_stream = packet_streams_[packet->stream_index]; | 477 FFmpegDemuxerStream* demuxer_stream = packet_streams_[packet->stream_index]; |
| 497 if (demuxer_stream) { | 478 if (demuxer_stream) { |
| 498 // Duplicate the entire packet to avoid aliasing. | 479 // If a packet is returned by FFmpeg's av_parser_parse2() |
| 499 // Directly affects MP3, but do all formats to be safe. | 480 // the packet will reference an inner memory of FFmpeg. |
| 500 scoped_ptr<AVPacket> clone(ClonePacket(packet.get())); | 481 // In this case, the packet's "destruct" member is NULL, |
| 501 if (!clone.get()) { | 482 // and it MUST be duplicated. Fixes issue with MP3. |
| 502 NOTREACHED(); | 483 av_dup_packet(packet.get()); |
| 503 return; | |
| 504 } | |
| 505 // Free FFmpeg-allocated memory and swap original packet into |clone| so | |
| 506 // that it gets deleted as |clone| goes out of scope. | |
| 507 av_free_packet(packet.get()); | |
| 508 packet.swap(clone); | |
| 509 | 484 |
| 510 // Queue the packet with the appropriate stream. The stream takes | 485 // Queue the packet with the appropriate stream. The stream takes |
| 511 // ownership of the AVPacket. | 486 // ownership of the AVPacket. |
| 512 current_timestamp_ = demuxer_stream->EnqueuePacket(packet.release()); | 487 current_timestamp_ = demuxer_stream->EnqueuePacket(packet.release()); |
| 513 } else { | 488 } else { |
| 514 av_free_packet(packet.get()); | 489 av_free_packet(packet.get()); |
| 515 } | 490 } |
| 516 | 491 |
| 517 // Create a loop by posting another task. This allows seek and message loop | 492 // Create a loop by posting another task. This allows seek and message loop |
| 518 // quit tasks to get processed. | 493 // quit tasks to get processed. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 read_event_.Wait(); | 551 read_event_.Wait(); |
| 577 return last_read_bytes_; | 552 return last_read_bytes_; |
| 578 } | 553 } |
| 579 | 554 |
| 580 void FFmpegDemuxer::SignalReadCompleted(size_t size) { | 555 void FFmpegDemuxer::SignalReadCompleted(size_t size) { |
| 581 last_read_bytes_ = size; | 556 last_read_bytes_ = size; |
| 582 read_event_.Signal(); | 557 read_event_.Signal(); |
| 583 } | 558 } |
| 584 | 559 |
| 585 } // namespace media | 560 } // namespace media |
| OLD | NEW |