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