summaryrefslogtreecommitdiffstats
path: root/media/filters/ffmpeg_demuxer.h
blob: 640f9cc0997c3ef33e33346697fbe572575b9beb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Implements the Demuxer interface using FFmpeg's libavformat.  At this time
// will support demuxing any audio/video format thrown at it.  The streams
// output mime types audio/x-ffmpeg and video/x-ffmpeg and include an integer
// key FFmpegCodecID which contains the CodecID enumeration value.  The CodecIDs
// can be used to create and initialize the corresponding FFmpeg decoder.
//
// FFmpegDemuxer sets the duration of pipeline during initialization by using
// the duration of the longest audio/video stream.
//
// NOTE: since FFmpegDemuxer reads packets sequentially without seeking, media
// files with very large drift between audio/video streams may result in
// excessive memory consumption.

#ifndef MEDIA_FILTERS_FFMPEG_DEMUXER_H_
#define MEDIA_FILTERS_FFMPEG_DEMUXER_H_

#include <deque>
#include <vector>

#include "base/lock.h"
#include "base/thread.h"
#include "base/waitable_event.h"
#include "media/base/buffers.h"
#include "media/base/factory.h"
#include "media/base/filters.h"
#include "media/base/media_format.h"

// FFmpeg forward declarations.
struct AVCodecContext;
struct AVBitStreamFilterContext;
struct AVFormatContext;
struct AVPacket;
struct AVStream;
enum CodecID;

namespace media {

class FFmpegDemuxer;

// Forward declaration for scoped_ptr_malloc.
class ScopedPtrAVFree;

class FFmpegDemuxerStream : public DemuxerStream {
 public:
  // Maintains a reference to |demuxer| and initializes itself using information
  // inside |stream|.
  FFmpegDemuxerStream(FFmpegDemuxer* demuxer, AVStream* stream);

  virtual ~FFmpegDemuxerStream();

  // Returns true is this stream has pending reads, false otherwise.
  //
  // Safe to call on any thread.
  bool HasPendingReads();

  // Enqueues and takes ownership over the given AVPacket, returns the timestamp
  // of the enqueued packet.
  base::TimeDelta EnqueuePacket(AVPacket* packet);

  // Signals to empty queue and mark next packet as discontinuous.
  void FlushBuffers();

  // Returns the duration of this stream.
  base::TimeDelta duration() { return duration_; }

  // DemuxerStream implementation.
  virtual const MediaFormat& media_format();
  virtual void Read(Callback1<Buffer*>::Type* read_callback);

  AVStream* av_stream() {
    return av_stream_;
  }

  static const char* interface_id();

 protected:
  virtual void* QueryInterface(const char* interface_id);

 private:
  // Returns true if there are still pending reads.
  bool FulfillPendingReads();

  FFmpegDemuxer* demuxer_;
  AVStream* av_stream_;
  MediaFormat media_format_;
  base::TimeDelta time_base_;
  base::TimeDelta duration_;
  bool discontinuous_;

  Lock lock_;

  typedef std::deque< scoped_refptr<Buffer> > BufferQueue;
  BufferQueue buffer_queue_;

  typedef std::deque<Callback1<Buffer*>::Type*> ReadQueue;
  ReadQueue read_queue_;

  DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerStream);
};

class FFmpegDemuxer : public Demuxer {
 public:
  // FilterFactory provider.
  static FilterFactory* CreateFilterFactory() {
    return new FilterFactoryImpl0<FFmpegDemuxer>();
  }

  // Called by FFmpegDemuxerStreams to post a demuxing task.
  void PostDemuxTask();

  // MediaFilter implementation.
  virtual void Stop();
  virtual void Seek(base::TimeDelta time);

  // Demuxer implementation.
  virtual bool Initialize(DataSource* data_source);
  virtual size_t GetNumberOfStreams();
  virtual scoped_refptr<DemuxerStream> GetStream(int stream_id);

 private:
  // Only allow a factory to create this class.
  friend class FilterFactoryImpl0<FFmpegDemuxer>;
  FFmpegDemuxer();
  virtual ~FFmpegDemuxer();

  // Carries out initialization on the demuxer thread.
  void InititalizeTask(DataSource* data_source);

  // Carries out a seek on the demuxer thread.
  void SeekTask(base::TimeDelta time);

  // Carries out demuxing and satisfying stream reads on the demuxer thread.
  void DemuxTask();

  // Returns true if any of the streams have pending reads.  Since we lazily
  // post a DemuxTask() for every read, we use this method to quickly terminate
  // the tasks if there is no work to do.
  //
  // Safe to call on any thread.
  bool StreamsHavePendingReads();

  // FFmpeg context handle.
  scoped_ptr_malloc<AVFormatContext, ScopedPtrAVFree> format_context_;

  // Latest timestamp read on the demuxer thread.
  base::TimeDelta current_timestamp_;

  // Two vector of streams:
  //   - |streams_| is indexed for the Demuxer interface GetStream(), which only
  //     contains supported streams and no NULL entries.
  //   - |packet_streams_| is indexed to mirror AVFormatContext when dealing
  //     with AVPackets returned from av_read_frame() and contain NULL entries
  //     representing unsupported streams where we throw away the data.
  //
  // Ownership is handled via reference counting.
  typedef std::vector< scoped_refptr<FFmpegDemuxerStream> > StreamVector;
  StreamVector streams_;
  StreamVector packet_streams_;

  // Thread handle.
  base::Thread thread_;

  DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxer);
};

}  // namespace media

#endif  // MEDIA_FILTERS_FFMPEG_DEMUXER_H_