summaryrefslogtreecommitdiffstats
path: root/include/media/stagefright/MediaSourceSplitter.h
blob: 568f4c296db2904fa3a8c948cdf985aa272ceba9 (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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// This class provides a way to split a single media source into multiple sources.
// The constructor takes in the real mediaSource and createClient() can then be
// used to create multiple sources served from this real mediaSource.
//
// Usage:
// - Create MediaSourceSplitter by passing in a real mediaSource from which
// multiple duplicate channels are needed.
// - Create a client using createClient() and use it as any other mediaSource.
//
// Note that multiple clients can be created using createClient() and
// started/stopped in any order. MediaSourceSplitter stops the real source only
// when all clients have been stopped.
//
// If a new client is created/started after some existing clients have already
// started, the new client will start getting its read frames from the current
// time.

#ifndef MEDIA_SOURCE_SPLITTER_H_

#define MEDIA_SOURCE_SPLITTER_H_

#include <media/stagefright/MediaSource.h>
#include <utils/threads.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>

namespace android {

class MediaBuffer;
class MetaData;

class MediaSourceSplitter : public RefBase {
public:
    // Constructor
    // mediaSource: The real mediaSource. The class keeps a reference to it to
    // implement the various clients.
    MediaSourceSplitter(sp<MediaSource> mediaSource);

    ~MediaSourceSplitter();

    // Creates a new client of base type MediaSource. Multiple clients can be
    // created which get their data through the same real mediaSource. These
    // clients can then be used like any other MediaSource, all of which provide
    // data from the same real source.
    sp<MediaSource> createClient();

private:
    // Total number of clients created through createClient().
    int32_t mNumberOfClients;

    // reference to the real MediaSource passed to the constructor.
    sp<MediaSource> mSource;

    // Stores pointer to the MediaBuffer read from the real MediaSource.
    // All clients use this to implement the read() call.
    MediaBuffer *mLastReadMediaBuffer;

    // Status code for read from the real MediaSource. All clients return
    // this for their read().
    status_t mLastReadStatus;

    // Boolean telling whether the real MediaSource has started.
    bool mSourceStarted;

    // List of booleans, one for each client, storing whether the corresponding
    // client's start() has been called.
    Vector<bool> mClientsStarted;

    // Stores the number of clients which are currently started.
    int32_t mNumberOfClientsStarted;

    // Since different clients call read() asynchronously, we need to keep track
    // of what data is currently read into the mLastReadMediaBuffer.
    // mCurrentReadBit stores the bit for the current read buffer. This bit
    // flips each time a new buffer is read from the source.
    // mClientsDesiredReadBit stores the bit for the next desired read buffer
    // for each client. This bit flips each time read() is completed for this
    // client.
    bool mCurrentReadBit;
    Vector<bool> mClientsDesiredReadBit;

    // Number of clients whose current read has been completed.
    int32_t mNumberOfCurrentReads;

    // Boolean telling whether the last read has been completed for all clients.
    // The variable is reset to false each time buffer is read from the real
    // source.
    bool mLastReadCompleted;

    // A global mutex for access to critical sections.
    Mutex mLock;

    // Condition variable for waiting on read from source to complete.
    Condition mReadFromSourceCondition;

    // Condition variable for waiting on all client's last read to complete.
    Condition mAllReadsCompleteCondition;

    // Functions used by Client to implement the MediaSource interface.

    // If the real source has not been started yet by any client, starts it.
    status_t start(int clientId, MetaData *params);

    // Stops the real source after all clients have called stop().
    status_t stop(int clientId);

    // returns the real source's getFormat().
    sp<MetaData> getFormat(int clientId);

    // If the client's desired buffer has already been read into
    // mLastReadMediaBuffer, points the buffer to that. Otherwise if it is the
    // master client, reads the buffer from source or else waits for the master
    // client to read the buffer and uses that.
    status_t read(int clientId,
            MediaBuffer **buffer, const MediaSource::ReadOptions *options = NULL);

    // Not implemented right now.
    status_t pause(int clientId);

    // Function which reads a buffer from the real source into
    // mLastReadMediaBuffer
    void readFromSource_lock(const MediaSource::ReadOptions *options);

    // Waits until read from the real source has been completed.
    // _lock means that the function should be called when the thread has already
    // obtained the lock for the mutex mLock.
    void waitForReadFromSource_lock(int32_t clientId);

    // Waits until all clients have read the current buffer in
    // mLastReadCompleted.
    void waitForAllClientsLastRead_lock(int32_t clientId);

    // Each client calls this after it completes its read(). Once all clients
    // have called this for the current buffer, the function calls
    // mAllReadsCompleteCondition.broadcast() to signal the waiting clients.
    void signalReadComplete_lock(bool readAborted);

    // Make these constructors private.
    MediaSourceSplitter();
    MediaSourceSplitter(const MediaSourceSplitter &);
    MediaSourceSplitter &operator=(const MediaSourceSplitter &);

    // This class implements the MediaSource interface. Each client stores a
    // reference to the parent MediaSourceSplitter and uses it to complete the
    // various calls.
    class Client : public MediaSource {
    public:
        // Constructor stores reference to the parent MediaSourceSplitter and it
        // client id.
        Client(sp<MediaSourceSplitter> splitter, int32_t clientId);

        // MediaSource interface
        virtual status_t start(MetaData *params = NULL);

        virtual status_t stop();

        virtual sp<MetaData> getFormat();

        virtual status_t read(
                MediaBuffer **buffer, const ReadOptions *options = NULL);

        virtual status_t pause();

    private:
        // Refernce to the parent MediaSourceSplitter
        sp<MediaSourceSplitter> mSplitter;

        // Id of this client.
        int32_t mClientId;
    };

    friend class Client;
};

}  // namespace android

#endif  // MEDIA_SOURCE_SPLITTER_H_