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/string_util.h" | 6 #include "base/string_util.h" |
7 #include "base/time.h" | 7 #include "base/time.h" |
8 #include "media/base/filter_host.h" | 8 #include "media/base/filter_host.h" |
9 #include "media/filters/ffmpeg_common.h" | 9 #include "media/filters/ffmpeg_common.h" |
10 #include "media/filters/ffmpeg_demuxer.h" | 10 #include "media/filters/ffmpeg_demuxer.h" |
11 #include "media/filters/ffmpeg_glue.h" | 11 #include "media/filters/ffmpeg_glue.h" |
12 | 12 |
13 namespace media { | 13 namespace media { |
14 | 14 |
15 // | 15 // |
16 // AVPacketBuffer | 16 // AVPacketBuffer |
17 // | 17 // |
18 class AVPacketBuffer : public Buffer { | 18 class AVPacketBuffer : public Buffer { |
19 public: | 19 public: |
20 AVPacketBuffer(AVPacket* packet, const base::TimeDelta& timestamp, | 20 AVPacketBuffer(AVPacket* packet, const base::TimeDelta& timestamp, |
21 const base::TimeDelta& duration) | 21 const base::TimeDelta& duration) |
22 : packet_(packet) { | 22 : packet_(packet) { |
23 DCHECK(packet); | |
24 SetTimestamp(timestamp); | 23 SetTimestamp(timestamp); |
25 SetDuration(duration); | 24 SetDuration(duration); |
26 } | 25 } |
27 | 26 |
28 virtual ~AVPacketBuffer() { | 27 virtual ~AVPacketBuffer() { |
29 av_free_packet(packet_.get()); | 28 av_free_packet(packet_.get()); |
30 } | 29 } |
31 | 30 |
32 // Buffer implementation. | 31 // Buffer implementation. |
33 virtual const uint8* GetData() const { | 32 virtual const uint8* GetData() const { |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 void FFmpegDemuxer::DemuxTask() { | 310 void FFmpegDemuxer::DemuxTask() { |
312 // Make sure we have work to do before demuxing. | 311 // Make sure we have work to do before demuxing. |
313 if (!StreamsHavePendingReads()) { | 312 if (!StreamsHavePendingReads()) { |
314 return; | 313 return; |
315 } | 314 } |
316 | 315 |
317 // Allocate and read an AVPacket from the media. | 316 // Allocate and read an AVPacket from the media. |
318 scoped_ptr<AVPacket> packet(new AVPacket()); | 317 scoped_ptr<AVPacket> packet(new AVPacket()); |
319 int result = av_read_frame(format_context_.get(), packet.get()); | 318 int result = av_read_frame(format_context_.get(), packet.get()); |
320 if (result < 0) { | 319 if (result < 0) { |
321 // TODO(scherkus): handle end of stream by marking Buffer with the end | 320 // If we have reached the end of stream, tell the downstream filters about |
322 // of stream flag. | 321 // the event. |
323 NOTIMPLEMENTED(); | 322 StreamHasEnded(); |
324 return; | 323 return; |
325 } | 324 } |
326 | 325 |
327 // Queue the packet with the appropriate stream. | 326 // Queue the packet with the appropriate stream. |
328 // TODO(scherkus): should we post this back to the pipeline thread? I'm | 327 // TODO(scherkus): should we post this back to the pipeline thread? I'm |
329 // worried about downstream filters (i.e., decoders) executing on this | 328 // worried about downstream filters (i.e., decoders) executing on this |
330 // thread. | 329 // thread. |
331 DCHECK(packet->stream_index >= 0); | 330 DCHECK(packet->stream_index >= 0); |
332 DCHECK(packet->stream_index < static_cast<int>(packet_streams_.size())); | 331 DCHECK(packet->stream_index < static_cast<int>(packet_streams_.size())); |
333 FFmpegDemuxerStream* demuxer_stream = packet_streams_[packet->stream_index]; | 332 FFmpegDemuxerStream* demuxer_stream = packet_streams_[packet->stream_index]; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 bool FFmpegDemuxer::StreamsHavePendingReads() { | 365 bool FFmpegDemuxer::StreamsHavePendingReads() { |
367 StreamVector::iterator iter; | 366 StreamVector::iterator iter; |
368 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 367 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
369 if ((*iter)->HasPendingReads()) { | 368 if ((*iter)->HasPendingReads()) { |
370 return true; | 369 return true; |
371 } | 370 } |
372 } | 371 } |
373 return false; | 372 return false; |
374 } | 373 } |
375 | 374 |
| 375 void FFmpegDemuxer::StreamHasEnded() { |
| 376 StreamVector::iterator iter; |
| 377 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 378 AVPacket* packet = new AVPacket(); |
| 379 memset(packet, 0, sizeof(*packet)); |
| 380 (*iter)->EnqueuePacket(packet); |
| 381 } |
| 382 } |
| 383 |
376 AVPacket* FFmpegDemuxer::ClonePacket(AVPacket* packet) { | 384 AVPacket* FFmpegDemuxer::ClonePacket(AVPacket* packet) { |
377 scoped_ptr<AVPacket> clone(new AVPacket()); | 385 scoped_ptr<AVPacket> clone(new AVPacket()); |
378 if (!clone.get() || av_new_packet(clone.get(), packet->size) < 0) { | 386 if (!clone.get() || av_new_packet(clone.get(), packet->size) < 0) { |
379 return NULL; | 387 return NULL; |
380 } | 388 } |
381 DCHECK_EQ(clone->size, packet->size); | 389 DCHECK_EQ(clone->size, packet->size); |
382 clone->dts = packet->dts; | 390 clone->dts = packet->dts; |
383 clone->pts = packet->pts; | 391 clone->pts = packet->pts; |
384 clone->duration = packet->duration; | 392 clone->duration = packet->duration; |
385 memcpy(clone->data, packet->data, clone->size); | 393 memcpy(clone->data, packet->data, clone->size); |
386 return clone.release(); | 394 return clone.release(); |
387 } | 395 } |
388 | 396 |
389 } // namespace media | 397 } // namespace media |
OLD | NEW |