SurfaceMediaSource.cpp revision 8add6cf4976de9b7bca7b73b1473a1e5f7201087
1/*
2 * Copyright (C) 2011 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//#define LOG_NDEBUG 0
17#define LOG_TAG "SurfaceMediaSource"
18
19#include <media/stagefright/foundation/ADebug.h>
20#include <media/stagefright/SurfaceMediaSource.h>
21#include <media/stagefright/MetaData.h>
22#include <media/stagefright/MediaDefs.h>
23#include <OMX_IVCommon.h>
24#include <MetadataBufferType.h>
25
26#include <ui/GraphicBuffer.h>
27#include <gui/ISurfaceComposer.h>
28#include <gui/IGraphicBufferAlloc.h>
29#include <OMX_Component.h>
30
31#include <utils/Log.h>
32#include <utils/String8.h>
33
34#include <private/gui/ComposerService.h>
35
36namespace android {
37
38SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight) :
39    mWidth(bufferWidth),
40    mHeight(bufferHeight),
41    mCurrentSlot(BufferQueue::INVALID_BUFFER_SLOT),
42    mCurrentTimestamp(0),
43    mFrameRate(30),
44    mStopped(false),
45    mNumFramesReceived(0),
46    mNumFramesEncoded(0),
47    mFirstFrameTimestamp(0)
48{
49    ALOGV("SurfaceMediaSource::SurfaceMediaSource");
50
51    if (bufferWidth == 0 || bufferHeight == 0) {
52        ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
53    }
54
55    mBufferQueue = new BufferQueue(true, MIN_UNDEQUEUED_BUFFERS);
56    mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
57    mBufferQueue->setSynchronousMode(true);
58    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
59            GRALLOC_USAGE_HW_TEXTURE);
60
61    sp<ISurfaceComposer> composer(ComposerService::getComposerService());
62
63    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
64    // reference once the ctor ends, as that would cause the refcount of 'this'
65    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
66    // that's what we create.
67    wp<BufferQueue::ConsumerListener> listener;
68    sp<BufferQueue::ConsumerListener> proxy;
69    listener = static_cast<BufferQueue::ConsumerListener*>(this);
70    proxy = new BufferQueue::ProxyConsumerListener(listener);
71
72    status_t err = mBufferQueue->consumerConnect(proxy);
73    if (err != NO_ERROR) {
74        ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)",
75                strerror(-err), err);
76    }
77}
78
79SurfaceMediaSource::~SurfaceMediaSource() {
80    ALOGV("SurfaceMediaSource::~SurfaceMediaSource");
81    if (!mStopped) {
82        reset();
83    }
84}
85
86nsecs_t SurfaceMediaSource::getTimestamp() {
87    ALOGV("SurfaceMediaSource::getTimestamp");
88    Mutex::Autolock lock(mMutex);
89    return mCurrentTimestamp;
90}
91
92void SurfaceMediaSource::setFrameAvailableListener(
93        const sp<FrameAvailableListener>& listener) {
94    ALOGV("SurfaceMediaSource::setFrameAvailableListener");
95    Mutex::Autolock lock(mMutex);
96    mFrameAvailableListener = listener;
97}
98
99sp<GraphicBuffer> SurfaceMediaSource::getCurrentBuffer() const {
100    Mutex::Autolock lock(mMutex);
101    return mCurrentBuf;
102}
103
104void SurfaceMediaSource::dump(String8& result) const
105{
106    char buffer[1024];
107    dump(result, "", buffer, 1024);
108}
109
110void SurfaceMediaSource::dump(String8& result, const char* prefix,
111        char* buffer, size_t SIZE) const
112{
113    Mutex::Autolock lock(mMutex);
114
115    result.append(buffer);
116    mBufferQueue->dump(result);
117}
118
119status_t SurfaceMediaSource::setFrameRate(int32_t fps)
120{
121    Mutex::Autolock lock(mMutex);
122    const int MAX_FRAME_RATE = 60;
123    if (fps < 0 || fps > MAX_FRAME_RATE) {
124        return BAD_VALUE;
125    }
126    mFrameRate = fps;
127    return OK;
128}
129
130bool SurfaceMediaSource::isMetaDataStoredInVideoBuffers() const {
131    ALOGV("isMetaDataStoredInVideoBuffers");
132    return true;
133}
134
135int32_t SurfaceMediaSource::getFrameRate( ) const {
136    Mutex::Autolock lock(mMutex);
137    return mFrameRate;
138}
139
140status_t SurfaceMediaSource::start(MetaData *params)
141{
142    ALOGV("started!");
143
144    mStartTimeNs = 0;
145    int64_t startTimeUs;
146    if (params && params->findInt64(kKeyTime, &startTimeUs)) {
147        mStartTimeNs = startTimeUs * 1000;
148    }
149
150    return OK;
151}
152
153
154status_t SurfaceMediaSource::reset()
155{
156    ALOGV("Reset");
157
158    Mutex::Autolock lock(mMutex);
159    // TODO: Add waiting on mFrameCompletedCondition here?
160    mStopped = true;
161
162    mFrameAvailableCondition.signal();
163    mBufferQueue->consumerDisconnect();
164
165    return OK;
166}
167
168sp<MetaData> SurfaceMediaSource::getFormat()
169{
170    ALOGV("getFormat");
171
172    Mutex::Autolock lock(mMutex);
173    sp<MetaData> meta = new MetaData;
174
175    meta->setInt32(kKeyWidth, mWidth);
176    meta->setInt32(kKeyHeight, mHeight);
177    // The encoder format is set as an opaque colorformat
178    // The encoder will later find out the actual colorformat
179    // from the GL Frames itself.
180    meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque);
181    meta->setInt32(kKeyStride, mWidth);
182    meta->setInt32(kKeySliceHeight, mHeight);
183    meta->setInt32(kKeyFrameRate, mFrameRate);
184    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
185    return meta;
186}
187
188status_t SurfaceMediaSource::read( MediaBuffer **buffer,
189                                    const ReadOptions *options)
190{
191    ALOGV("read");
192    Mutex::Autolock lock(mMutex);
193
194    *buffer = NULL;
195
196    // Update the current buffer info
197    // TODO: mCurrentSlot can be made a bufferstate since there
198    // can be more than one "current" slots.
199
200    BufferQueue::BufferItem item;
201    // If the recording has started and the queue is empty, then just
202    // wait here till the frames come in from the client side
203    while (!mStopped) {
204
205        status_t err = mBufferQueue->acquireBuffer(&item);
206        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
207            // wait for a buffer to be queued
208            mFrameAvailableCondition.wait(mMutex);
209        } else if (err == OK) {
210
211            // First time seeing the buffer?  Added it to the SMS slot
212            if (item.mGraphicBuffer != NULL) {
213                mBufferSlot[item.mBuf] = item.mGraphicBuffer;
214            }
215
216            // check for the timing of this buffer
217            if (mNumFramesReceived == 0) {
218                mFirstFrameTimestamp = item.mTimestamp;
219                // Initial delay
220                if (mStartTimeNs > 0) {
221                    if (item.mTimestamp < mStartTimeNs) {
222                        // This frame predates start of record, discard
223                        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
224                        continue;
225                    }
226                    mStartTimeNs = item.mTimestamp - mStartTimeNs;
227                }
228            }
229            item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp);
230
231            mNumFramesReceived++;
232
233            break;
234        } else {
235            ALOGE("read: acquire failed with error code %d", err);
236            return ERROR_END_OF_STREAM;
237        }
238
239    }
240
241    // If the loop was exited as a result of stopping the recording,
242    // it is OK
243    if (mStopped) {
244        ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM.");
245        return ERROR_END_OF_STREAM;
246    }
247
248    mCurrentSlot = item.mBuf;
249
250    // First time seeing the buffer?  Added it to the SMS slot
251    if (item.mGraphicBuffer != NULL) {
252        mBufferSlot[mCurrentSlot] = item.mGraphicBuffer;
253    }
254    mCurrentBuf = mBufferSlot[mCurrentSlot];
255    int64_t prevTimeStamp = mCurrentTimestamp;
256    mCurrentTimestamp = item.mTimestamp;
257
258    mNumFramesEncoded++;
259    // Pass the data to the MediaBuffer. Pass in only the metadata
260    passMetadataBufferLocked(buffer);
261
262    (*buffer)->setObserver(this);
263    (*buffer)->add_ref();
264    (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000);
265    ALOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld",
266            mNumFramesEncoded, mCurrentTimestamp / 1000,
267            mCurrentTimestamp / 1000 - prevTimeStamp / 1000);
268
269
270    return OK;
271}
272
273// Pass the data to the MediaBuffer. Pass in only the metadata
274// The metadata passed consists of two parts:
275// 1. First, there is an integer indicating that it is a GRAlloc
276// source (kMetadataBufferTypeGrallocSource)
277// 2. This is followed by the buffer_handle_t that is a handle to the
278// GRalloc buffer. The encoder needs to interpret this GRalloc handle
279// and encode the frames.
280// --------------------------------------------------------------
281// |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
282// --------------------------------------------------------------
283// Note: Call only when you have the lock
284void SurfaceMediaSource::passMetadataBufferLocked(MediaBuffer **buffer) {
285    ALOGV("passMetadataBuffer");
286    // MediaBuffer allocates and owns this data
287    MediaBuffer *tempBuffer =
288        new MediaBuffer(4 + sizeof(buffer_handle_t));
289    char *data = (char *)tempBuffer->data();
290    if (data == NULL) {
291        ALOGE("Cannot allocate memory for metadata buffer!");
292        return;
293    }
294    OMX_U32 type = kMetadataBufferTypeGrallocSource;
295    memcpy(data, &type, 4);
296    memcpy(data + 4, &(mCurrentBuf->handle), sizeof(buffer_handle_t));
297    *buffer = tempBuffer;
298
299    ALOGV("handle = %p, , offset = %d, length = %d",
300            mCurrentBuf->handle, (*buffer)->range_length(), (*buffer)->range_offset());
301}
302
303void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
304    ALOGV("signalBufferReturned");
305
306    bool foundBuffer = false;
307
308    Mutex::Autolock lock(mMutex);
309
310    if (mStopped) {
311        ALOGV("signalBufferReturned: mStopped = true! Nothing to do!");
312        return;
313    }
314
315    for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) {
316        if (mBufferSlot[id] == NULL) {
317            continue;
318        }
319        if (checkBufferMatchesSlot(id, buffer)) {
320            ALOGV("Slot %d returned, matches handle = %p", id,
321                    mBufferSlot[id]->handle);
322
323            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
324
325            buffer->setObserver(0);
326            buffer->release();
327
328            foundBuffer = true;
329            break;
330        }
331    }
332
333    if (!foundBuffer) {
334        CHECK(!"signalBufferReturned: bogus buffer");
335    }
336}
337
338bool SurfaceMediaSource::checkBufferMatchesSlot(int slot, MediaBuffer *buffer) {
339    ALOGV("Check if Buffer matches slot");
340    // need to convert to char* for pointer arithmetic and then
341    // copy the byte stream into our handle
342    buffer_handle_t bufferHandle ;
343    memcpy( &bufferHandle, (char *)(buffer->data()) + 4, sizeof(buffer_handle_t));
344    return mBufferSlot[slot]->handle  ==  bufferHandle;
345}
346
347// Part of the BufferQueue::ConsumerListener
348void SurfaceMediaSource::onFrameAvailable() {
349    ALOGV("onFrameAvailable");
350
351    sp<FrameAvailableListener> listener;
352    { // scope for the lock
353        Mutex::Autolock lock(mMutex);
354        mFrameAvailableCondition.broadcast();
355        listener = mFrameAvailableListener;
356    }
357
358    if (listener != NULL) {
359        ALOGV("actually calling onFrameAvailable");
360        listener->onFrameAvailable();
361    }
362}
363
364// SurfaceMediaSource hijacks this event to assume
365// the prodcuer is disconnecting from the BufferQueue
366// and that it should stop the recording
367void SurfaceMediaSource::onBuffersReleased() {
368    ALOGV("onBuffersReleased");
369
370    Mutex::Autolock lock(mMutex);
371
372    mFrameAvailableCondition.signal();
373    mStopped = true;
374
375    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
376       mBufferSlot[i] = 0;
377    }
378}
379
380} // end of namespace android
381