|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #if !defined(DirectShowReader_h_) |
|
8 #define DirectShowReader_h_ |
|
9 |
|
10 #include "windows.h" // HRESULT, DWORD |
|
11 #include "MediaDecoderReader.h" |
|
12 #include "mozilla/RefPtr.h" |
|
13 #include "MP3FrameParser.h" |
|
14 |
|
15 class IGraphBuilder; |
|
16 class IMediaControl; |
|
17 class IMediaSeeking; |
|
18 class IMediaEventEx; |
|
19 |
|
20 namespace mozilla { |
|
21 |
|
22 class AudioSinkFilter; |
|
23 class SourceFilter; |
|
24 |
|
25 namespace dom { |
|
26 class TimeRanges; |
|
27 } |
|
28 |
|
29 // Decoder backend for decoding MP3 using DirectShow. DirectShow operates as |
|
30 // a filter graph. The basic design of the DirectShowReader is that we have |
|
31 // a SourceFilter that wraps the MediaResource that connects to the |
|
32 // MP3 decoder filter. The MP3 decoder filter "pulls" data as it requires it |
|
33 // downstream on its own thread. When the MP3 decoder has produced a block of |
|
34 // decoded samples, its thread calls downstream into our AudioSinkFilter, |
|
35 // passing the decoded buffer in. The AudioSinkFilter inserts the samples into |
|
36 // a SampleSink object. The SampleSink blocks the MP3 decoder's thread until |
|
37 // the decode thread calls DecodeAudioData(), whereupon the SampleSink |
|
38 // releases the decoded samples to the decode thread, and unblocks the MP3 |
|
39 // decoder's thread. The MP3 decoder can then request more data from the |
|
40 // SourceFilter, and decode more data. If the decode thread calls |
|
41 // DecodeAudioData() and there's no decoded samples waiting to be extracted |
|
42 // in the SampleSink, the SampleSink blocks the decode thread until the MP3 |
|
43 // decoder produces a decoded sample. |
|
44 class DirectShowReader : public MediaDecoderReader |
|
45 { |
|
46 public: |
|
47 DirectShowReader(AbstractMediaDecoder* aDecoder); |
|
48 |
|
49 virtual ~DirectShowReader(); |
|
50 |
|
51 nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE; |
|
52 |
|
53 bool DecodeAudioData() MOZ_OVERRIDE; |
|
54 bool DecodeVideoFrame(bool &aKeyframeSkip, |
|
55 int64_t aTimeThreshold) MOZ_OVERRIDE; |
|
56 |
|
57 bool HasAudio() MOZ_OVERRIDE; |
|
58 bool HasVideo() MOZ_OVERRIDE; |
|
59 |
|
60 nsresult ReadMetadata(MediaInfo* aInfo, |
|
61 MetadataTags** aTags) MOZ_OVERRIDE; |
|
62 |
|
63 nsresult Seek(int64_t aTime, |
|
64 int64_t aStartTime, |
|
65 int64_t aEndTime, |
|
66 int64_t aCurrentTime) MOZ_OVERRIDE; |
|
67 |
|
68 void NotifyDataArrived(const char* aBuffer, |
|
69 uint32_t aLength, |
|
70 int64_t aOffset) MOZ_OVERRIDE; |
|
71 |
|
72 private: |
|
73 |
|
74 // Notifies the filter graph that playback is complete. aStatus is |
|
75 // the code to send to the filter graph. Always returns false, so |
|
76 // that we can just "return Finish()" from DecodeAudioData(). |
|
77 bool Finish(HRESULT aStatus); |
|
78 |
|
79 // DirectShow filter graph, and associated playback and seeking |
|
80 // control interfaces. |
|
81 RefPtr<IGraphBuilder> mGraph; |
|
82 RefPtr<IMediaControl> mControl; |
|
83 RefPtr<IMediaSeeking> mMediaSeeking; |
|
84 |
|
85 // Wraps the MediaResource, and feeds undecoded data into the filter graph. |
|
86 RefPtr<SourceFilter> mSourceFilter; |
|
87 |
|
88 // Sits at the end of the graph, removing decoded samples from the graph. |
|
89 // The graph will block while this is blocked, i.e. it will pause decoding. |
|
90 RefPtr<AudioSinkFilter> mAudioSinkFilter; |
|
91 |
|
92 // Some MP3s are variable bitrate, so DirectShow's duration estimation |
|
93 // can make its duration estimation based on the wrong bitrate. So we parse |
|
94 // the MP3 frames to get a more accuate estimate of the duration. |
|
95 MP3FrameParser mMP3FrameParser; |
|
96 |
|
97 #ifdef DEBUG |
|
98 // Used to add/remove the filter graph to the Running Object Table. You can |
|
99 // connect GraphEdit/GraphStudio to the graph to observe and/or debug its |
|
100 // topology and state. |
|
101 DWORD mRotRegister; |
|
102 #endif |
|
103 |
|
104 // Number of channels in the audio stream. |
|
105 uint32_t mNumChannels; |
|
106 |
|
107 // Samples per second in the audio stream. |
|
108 uint32_t mAudioRate; |
|
109 |
|
110 // Number of bytes per sample. Can be either 1 or 2. |
|
111 uint32_t mBytesPerSample; |
|
112 |
|
113 // Duration of the stream, in microseconds. |
|
114 int64_t mDuration; |
|
115 }; |
|
116 |
|
117 } // namespace mozilla |
|
118 |
|
119 #endif |