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