1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef IMEDIA_SOURCE_BASE_H_
18 
19 #define IMEDIA_SOURCE_BASE_H_
20 
21 #include <map>
22 
23 #include <binder/IInterface.h>
24 #include <binder/IMemory.h>
25 #include <media/MediaSource.h>
26 #include <media/stagefright/MediaBuffer.h>
27 #include <media/stagefright/MediaErrors.h>
28 
29 namespace android {
30 
31 class MediaBufferGroup;
32 
33 class IMediaSource : public IInterface {
34 public:
35     DECLARE_META_INTERFACE(MediaSource);
36 
37     enum {
38         // Maximum number of buffers would be read in readMultiple.
39         kMaxNumReadMultiple = 128,
40     };
41 
42     // To be called before any other methods on this object, except
43     // getFormat().
44     virtual status_t start(MetaData *params = NULL) = 0;
45 
46     // Any blocking read call returns immediately with a result of NO_INIT.
47     // It is an error to call any methods other than start after this call
48     // returns. Any buffers the object may be holding onto at the time of
49     // the stop() call are released.
50     // Also, it is imperative that any buffers output by this object and
51     // held onto by callers be released before a call to stop() !!!
52     virtual status_t stop() = 0;
53 
54     // Returns the format of the data output by this media source.
55     virtual sp<MetaData> getFormat() = 0;
56 
57     // Returns a new buffer of data. Call blocks until a
58     // buffer is available, an error is encountered or the end of the stream
59     // is reached.
60     // End of stream is signalled by a result of ERROR_END_OF_STREAM.
61     // A result of INFO_FORMAT_CHANGED indicates that the format of this
62     // MediaSource has changed mid-stream, the client can continue reading
63     // but should be prepared for buffers of the new configuration.
64     //
65     // TODO: consider removing read() in favor of readMultiple().
66     virtual status_t read(
67             MediaBufferBase **buffer,
68             const MediaSource::ReadOptions *options = NULL) = 0;
69 
70     // Returns a vector of new buffers of data, where the new buffers are added
71     // to the end of the vector.
72     // Call blocks until an error is encountered, or the end of the stream is
73     // reached, or format change is hit, or |kMaxNumReadMultiple| buffers have
74     // been read.
75     // End of stream is signaled by a result of ERROR_END_OF_STREAM.
76     // A result of INFO_FORMAT_CHANGED indicates that the format of this
77     // MediaSource has changed mid-stream, the client can continue reading
78     // but should be prepared for buffers of the new configuration.
79     //
80     // ReadOptions may be specified. Persistent options apply to all reads;
81     // non-persistent options (e.g. seek) apply only to the first read.
82     virtual status_t readMultiple(
83             Vector<MediaBufferBase *> *buffers, uint32_t maxNumBuffers = 1,
84             const MediaSource::ReadOptions *options = nullptr) = 0;
85 
86     // Returns true if |readMultiple| is supported, otherwise false.
87     virtual bool supportReadMultiple() = 0;
88 
89     // Returns true if |read| supports nonblocking option, otherwise false.
90     // |readMultiple| if supported, always allows the nonblocking option.
91     virtual bool supportNonblockingRead() = 0;
92 
93     // Causes this source to suspend pulling data from its upstream source
94     // until a subsequent read-with-seek. Currently only supported by
95     // OMXCodec.
96     virtual status_t pause()  = 0;
97 };
98 
99 class BnMediaSource: public BnInterface<IMediaSource>
100 {
101 public:
102     BnMediaSource();
103 
104     virtual status_t    onTransact(uint32_t code, const Parcel& data, Parcel* reply,
105                                 uint32_t flags = 0);
106 
pause()107     virtual status_t pause() {
108         return ERROR_UNSUPPORTED;
109     }
110 
111     // TODO: Implement this for local media sources.
readMultiple(Vector<MediaBufferBase * > *,uint32_t,const MediaSource::ReadOptions *)112     virtual status_t readMultiple(
113             Vector<MediaBufferBase *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */,
114             const MediaSource::ReadOptions * /* options = nullptr */) {
115         return ERROR_UNSUPPORTED;
116     }
117 
supportReadMultiple()118     virtual bool supportReadMultiple() {
119         return false;
120     }
121 
122     // Override in source if nonblocking reads are supported.
supportNonblockingRead()123     virtual bool supportNonblockingRead() {
124         return false;
125     }
126 
127     // align buffer count with video request size in NuMediaExtractor::selectTrack()
128     static const size_t kBinderMediaBuffers = 8; // buffers managed by BnMediaSource
129     static const size_t kTransferSharedAsSharedThreshold = 4 * 1024;  // if >= shared, else inline
130     static const size_t kTransferInlineAsSharedThreshold = 8 * 1024; // if >= shared, else inline
131     static const size_t kInlineMaxTransfer = 64 * 1024; // Binder size limited to BINDER_VM_SIZE.
132 
133 protected:
134     virtual ~BnMediaSource();
135 
136 private:
137     uint32_t mBuffersSinceStop; // Buffer tracking variable
138 
139     std::unique_ptr<MediaBufferGroup> mGroup;
140 
141     // To prevent marshalling IMemory with each read transaction, we cache the IMemory pointer
142     // into a map.
143     //
144     // This is converted into an index, which is used to identify the associated memory
145     // on the receiving side.  We hold a reference to the IMemory here to ensure it doesn't
146     // change underneath us.
147 
148     struct IndexCache {
IndexCacheIndexCache149         IndexCache() : mIndex(0) { }
150 
151         // Returns the index of the IMemory stored in cache or 0 if not found.
lookupIndexCache152         uint64_t lookup(const sp<IMemory> &mem) {
153             auto p = mMemoryToIndex.find(mem.get());
154             if (p == mMemoryToIndex.end()) {
155                 return 0;
156             }
157             if (MediaBuffer::isDeadObject(p->second.first)) {
158                 // this object's dead
159                 ALOGW("Attempting to lookup a dead IMemory");
160                 (void)mMemoryToIndex.erase(p);
161                 return 0;
162             }
163             ALOGW_IF(p->second.first.get() != mem.get(), "Mismatched buffers without reset");
164             return p->second.second;
165         }
166 
167         // Returns the index of the IMemory stored in the index cache.
insertIndexCache168         uint64_t insert(const sp<IMemory> &mem) {
169             auto p = mMemoryToIndex.find(mem.get());
170             if (p == mMemoryToIndex.end()) {
171                 if (mIndex == UINT64_MAX) {
172                     ALOGE("Index overflow");
173                     mIndex = 1; // skip overflow condition and hope for the best
174                 } else {
175                     ++mIndex;
176                 }
177                 (void)mMemoryToIndex.emplace(// C++11 mem.get(), std::make_pair(mem, mIndex))
178                         std::piecewise_construct,
179                         std::forward_as_tuple(mem.get()), std::forward_as_tuple(mem, mIndex));
180                 return mIndex;
181             }
182             ALOGW("IMemory already inserted into cache");
183             return p->second.second;
184         }
185 
resetIndexCache186         void reset() {
187             mMemoryToIndex.clear();
188             mIndex = 0;
189         }
190 
gcIndexCache191         void gc() {
192             for (auto it = mMemoryToIndex.begin(); it != mMemoryToIndex.end(); ) {
193                 if (MediaBuffer::isDeadObject(it->second.first)) {
194                     it = mMemoryToIndex.erase(it);
195                 } else {
196                     ++it;
197                 }
198             }
199         }
200 
201     private:
202         uint64_t mIndex;
203         // C++14 unordered_map erase on iterator is stable; C++11 has no guarantee.
204         // Could key on uintptr_t instead of IMemory *
205         std::map<IMemory *, std::pair<sp<IMemory>, uint64_t>> mMemoryToIndex;
206     } mIndexCache;
207 };
208 
209 }  // namespace android
210 
211 #endif  // IMEDIA_SOURCE_BASE_H_
212