1 /* 2 * Copyright 2014 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 ANDROID_GUI_STREAMSPLITTER_H 18 #define ANDROID_GUI_STREAMSPLITTER_H 19 20 #include <gui/IConsumerListener.h> 21 #include <gui/IProducerListener.h> 22 23 #include <utils/Condition.h> 24 #include <utils/KeyedVector.h> 25 #include <utils/Mutex.h> 26 #include <utils/StrongPointer.h> 27 28 namespace android { 29 30 class GraphicBuffer; 31 class IGraphicBufferConsumer; 32 class IGraphicBufferProducer; 33 34 // StreamSplitter is an autonomous class that manages one input BufferQueue 35 // and multiple output BufferQueues. By using the buffer attach and detach logic 36 // in BufferQueue, it is able to present the illusion of a single split 37 // BufferQueue, where each buffer queued to the input is available to be 38 // acquired by each of the outputs, and is able to be dequeued by the input 39 // again only once all of the outputs have released it. 40 class StreamSplitter : public BnConsumerListener { 41 public: 42 // createSplitter creates a new splitter, outSplitter, using inputQueue as 43 // the input BufferQueue. Output BufferQueues must be added using addOutput 44 // before queueing any buffers to the input. 45 // 46 // A return value other than NO_ERROR means that an error has occurred and 47 // outSplitter has not been modified. BAD_VALUE is returned if inputQueue or 48 // outSplitter is NULL. See IGraphicBufferConsumer::consumerConnect for 49 // explanations of other error codes. 50 static status_t createSplitter(const sp<IGraphicBufferConsumer>& inputQueue, 51 sp<StreamSplitter>* outSplitter); 52 53 // addOutput adds an output BufferQueue to the splitter. The splitter 54 // connects to outputQueue as a CPU producer, and any buffers queued 55 // to the input will be queued to each output. It is assumed that all of the 56 // outputs are added before any buffers are queued on the input. If any 57 // output is abandoned by its consumer, the splitter will abandon its input 58 // queue (see onAbandoned). 59 // 60 // A return value other than NO_ERROR means that an error has occurred and 61 // outputQueue has not been added to the splitter. BAD_VALUE is returned if 62 // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations 63 // of other error codes. 64 status_t addOutput(const sp<IGraphicBufferProducer>& outputQueue); 65 66 // setName sets the consumer name of the input queue 67 void setName(const String8& name); 68 69 private: 70 // From IConsumerListener 71 // 72 // During this callback, we store some tracking information, detach the 73 // buffer from the input, and attach it to each of the outputs. This call 74 // can block if there are too many outstanding buffers. If it blocks, it 75 // will resume when onBufferReleasedByOutput releases a buffer back to the 76 // input. 77 virtual void onFrameAvailable(const BufferItem& item); 78 79 // From IConsumerListener 80 // We don't care about released buffers because we detach each buffer as 81 // soon as we acquire it. See the comment for onBufferReleased below for 82 // some clarifying notes about the name. onBuffersReleased()83 virtual void onBuffersReleased() {} 84 85 // From IConsumerListener 86 // We don't care about sideband streams, since we won't be splitting them onSidebandStreamChanged()87 virtual void onSidebandStreamChanged() {} 88 89 // This is the implementation of the onBufferReleased callback from 90 // IProducerListener. It gets called from an OutputListener (see below), and 91 // 'from' is which producer interface from which the callback was received. 92 // 93 // During this callback, we detach the buffer from the output queue that 94 // generated the callback, update our state tracking to see if this is the 95 // last output releasing the buffer, and if so, release it to the input. 96 // If we release the buffer to the input, we allow a blocked 97 // onFrameAvailable call to proceed. 98 void onBufferReleasedByOutput(const sp<IGraphicBufferProducer>& from); 99 100 // When this is called, the splitter disconnects from (i.e., abandons) its 101 // input queue and signals any waiting onFrameAvailable calls to wake up. 102 // It still processes callbacks from other outputs, but only detaches their 103 // buffers so they can continue operating until they run out of buffers to 104 // acquire. This must be called with mMutex locked. 105 void onAbandonedLocked(); 106 107 // This is a thin wrapper class that lets us determine which BufferQueue 108 // the IProducerListener::onBufferReleased callback is associated with. We 109 // create one of these per output BufferQueue, and then pass the producer 110 // into onBufferReleasedByOutput above. 111 class OutputListener : public BnProducerListener, 112 public IBinder::DeathRecipient { 113 public: 114 OutputListener(const sp<StreamSplitter>& splitter, 115 const sp<IGraphicBufferProducer>& output); 116 virtual ~OutputListener(); 117 118 // From IProducerListener 119 virtual void onBufferReleased(); 120 121 // From IBinder::DeathRecipient 122 virtual void binderDied(const wp<IBinder>& who); 123 124 private: 125 sp<StreamSplitter> mSplitter; 126 sp<IGraphicBufferProducer> mOutput; 127 }; 128 129 class BufferTracker : public LightRefBase<BufferTracker> { 130 public: 131 BufferTracker(const sp<GraphicBuffer>& buffer); 132 getBuffer()133 const sp<GraphicBuffer>& getBuffer() const { return mBuffer; } getMergedFence()134 const sp<Fence>& getMergedFence() const { return mMergedFence; } 135 136 void mergeFence(const sp<Fence>& with); 137 138 // Returns the new value 139 // Only called while mMutex is held incrementReleaseCountLocked()140 size_t incrementReleaseCountLocked() { return ++mReleaseCount; } 141 142 private: 143 // Only destroy through LightRefBase 144 friend LightRefBase<BufferTracker>; 145 ~BufferTracker(); 146 147 // Disallow copying 148 BufferTracker(const BufferTracker& other); 149 BufferTracker& operator=(const BufferTracker& other); 150 151 sp<GraphicBuffer> mBuffer; // One instance that holds this native handle 152 sp<Fence> mMergedFence; 153 size_t mReleaseCount; 154 }; 155 156 // Only called from createSplitter 157 StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue); 158 159 // Must be accessed through RefBase 160 virtual ~StreamSplitter(); 161 162 static const int MAX_OUTSTANDING_BUFFERS = 2; 163 164 // mIsAbandoned is set to true when an output dies. Once the StreamSplitter 165 // has been abandoned, it will continue to detach buffers from other 166 // outputs, but it will disconnect from the input and not attempt to 167 // communicate with it further. 168 bool mIsAbandoned; 169 170 Mutex mMutex; 171 Condition mReleaseCondition; 172 int mOutstandingBuffers; 173 sp<IGraphicBufferConsumer> mInput; 174 Vector<sp<IGraphicBufferProducer> > mOutputs; 175 176 // Map of GraphicBuffer IDs (GraphicBuffer::getId()) to buffer tracking 177 // objects (which are mostly for counting how many outputs have released the 178 // buffer, but also contain merged release fences). 179 KeyedVector<uint64_t, sp<BufferTracker> > mBuffers; 180 }; 181 182 } // namespace android 183 184 #endif 185