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
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    Mutex::Autolock lock(mMutex);
117    const int MAX_FRAME_RATE = 60;
118    if (fps < 0 || fps > MAX_FRAME_RATE) {
119        return BAD_VALUE;
120    }
121    mFrameRate = fps;
122    return OK;
123}
124
125bool SurfaceMediaSource::isMetaDataStoredInVideoBuffers() const {
126    ALOGV("isMetaDataStoredInVideoBuffers");
127    return true;
128}
129
130int32_t SurfaceMediaSource::getFrameRate( ) const {
131    Mutex::Autolock lock(mMutex);
132    return mFrameRate;
133}
134
135status_t SurfaceMediaSource::start(MetaData *params)
136{
137    ALOGV("started!");
138
139    mStartTimeNs = 0;
140    int64_t startTimeUs;
141    if (params && params->findInt64(kKeyTime, &startTimeUs)) {
142        mStartTimeNs = startTimeUs * 1000;
143    }
144
145    return OK;
146}
147
148
149status_t SurfaceMediaSource::reset()
150{
151    ALOGV("Reset");
152
153    Mutex::Autolock lock(mMutex);
154    // TODO: Add waiting on mFrameCompletedCondition here?
155    mStopped = true;
156
157    mFrameAvailableCondition.signal();
158    mBufferQueue->consumerDisconnect();
159
160    return OK;
161}
162
163sp<MetaData> SurfaceMediaSource::getFormat()
164{
165    ALOGV("getFormat");
166
167    Mutex::Autolock lock(mMutex);
168    sp<MetaData> meta = new MetaData;
169
170    meta->setInt32(kKeyWidth, mWidth);
171    meta->setInt32(kKeyHeight, mHeight);
172    // The encoder format is set as an opaque colorformat
173    // The encoder will later find out the actual colorformat
174    // from the GL Frames itself.
175    meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque);
176    meta->setInt32(kKeyStride, mWidth);
177    meta->setInt32(kKeySliceHeight, mHeight);
178    meta->setInt32(kKeyFrameRate, mFrameRate);
179    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
180    return meta;
181}
182
183// Pass the data to the MediaBuffer. Pass in only the metadata
184// The metadata passed consists of two parts:
185// 1. First, there is an integer indicating that it is a GRAlloc
186// source (kMetadataBufferTypeGrallocSource)
187// 2. This is followed by the buffer_handle_t that is a handle to the
188// GRalloc buffer. The encoder needs to interpret this GRalloc handle
189// and encode the frames.
190// --------------------------------------------------------------
191// |  kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) |
192// --------------------------------------------------------------
193// Note: Call only when you have the lock
194static void passMetadataBuffer(MediaBuffer **buffer,
195        buffer_handle_t bufferHandle) {
196    // MediaBuffer allocates and owns this data
197    MediaBuffer *tempBuffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
198    char *data = (char *)tempBuffer->data();
199    if (data == NULL) {
200        ALOGE("Cannot allocate memory for metadata buffer!");
201        return;
202    }
203    OMX_U32 type = kMetadataBufferTypeGrallocSource;
204    memcpy(data, &type, 4);
205    memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t));
206    *buffer = tempBuffer;
207
208    ALOGV("handle = %p, , offset = %d, length = %d",
209            bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
210}
211
212status_t SurfaceMediaSource::read( MediaBuffer **buffer,
213                                    const ReadOptions *options)
214{
215    ALOGV("read");
216    Mutex::Autolock lock(mMutex);
217
218    *buffer = NULL;
219
220    // Update the current buffer info
221    // TODO: mCurrentSlot can be made a bufferstate since there
222    // can be more than one "current" slots.
223
224    BufferQueue::BufferItem item;
225    // If the recording has started and the queue is empty, then just
226    // wait here till the frames come in from the client side
227    while (!mStopped) {
228
229        status_t err = mBufferQueue->acquireBuffer(&item);
230        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
231            // wait for a buffer to be queued
232            mFrameAvailableCondition.wait(mMutex);
233        } else if (err == OK) {
234
235            // First time seeing the buffer?  Added it to the SMS slot
236            if (item.mGraphicBuffer != NULL) {
237                mBufferSlot[item.mBuf] = item.mGraphicBuffer;
238            }
239
240            // check for the timing of this buffer
241            if (mNumFramesReceived == 0) {
242                mFirstFrameTimestamp = item.mTimestamp;
243                // Initial delay
244                if (mStartTimeNs > 0) {
245                    if (item.mTimestamp < mStartTimeNs) {
246                        // This frame predates start of record, discard
247                        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
248                        continue;
249                    }
250                    mStartTimeNs = item.mTimestamp - mStartTimeNs;
251                }
252            }
253            item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp);
254
255            mNumFramesReceived++;
256
257            break;
258        } else {
259            ALOGE("read: acquire failed with error code %d", err);
260            return ERROR_END_OF_STREAM;
261        }
262
263    }
264
265    // If the loop was exited as a result of stopping the recording,
266    // it is OK
267    if (mStopped) {
268        ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM.");
269        return ERROR_END_OF_STREAM;
270    }
271
272    mCurrentSlot = item.mBuf;
273
274    // First time seeing the buffer?  Added it to the SMS slot
275    if (item.mGraphicBuffer != NULL) {
276        mBufferSlot[mCurrentSlot] = item.mGraphicBuffer;
277    }
278
279    mCurrentBuffers.push_back(mBufferSlot[mCurrentSlot]);
280    int64_t prevTimeStamp = mCurrentTimestamp;
281    mCurrentTimestamp = item.mTimestamp;
282
283    mNumFramesEncoded++;
284    // Pass the data to the MediaBuffer. Pass in only the metadata
285    passMetadataBuffer(buffer, mBufferSlot[mCurrentSlot]->handle);
286
287    (*buffer)->setObserver(this);
288    (*buffer)->add_ref();
289    (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000);
290    ALOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld",
291            mNumFramesEncoded, mCurrentTimestamp / 1000,
292            mCurrentTimestamp / 1000 - prevTimeStamp / 1000);
293
294
295    return OK;
296}
297
298static buffer_handle_t getMediaBufferHandle(MediaBuffer *buffer) {
299    // need to convert to char* for pointer arithmetic and then
300    // copy the byte stream into our handle
301    buffer_handle_t bufferHandle;
302    memcpy(&bufferHandle, (char*)(buffer->data()) + 4, sizeof(buffer_handle_t));
303    return bufferHandle;
304}
305
306void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
307    ALOGV("signalBufferReturned");
308
309    bool foundBuffer = false;
310
311    Mutex::Autolock lock(mMutex);
312
313    buffer_handle_t bufferHandle = getMediaBufferHandle(buffer);
314
315    for (size_t i = 0; i < mCurrentBuffers.size(); i++) {
316        if (mCurrentBuffers[i]->handle == bufferHandle) {
317            mCurrentBuffers.removeAt(i);
318            foundBuffer = true;
319            break;
320        }
321    }
322
323    if (!foundBuffer) {
324        ALOGW("returned buffer was not found in the current buffer list");
325    }
326
327    for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) {
328        if (mBufferSlot[id] == NULL) {
329            continue;
330        }
331
332        if (bufferHandle == mBufferSlot[id]->handle) {
333            ALOGV("Slot %d returned, matches handle = %p", id,
334                    mBufferSlot[id]->handle);
335
336            mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
337
338            buffer->setObserver(0);
339            buffer->release();
340
341            foundBuffer = true;
342            break;
343        }
344    }
345
346    if (!foundBuffer) {
347        CHECK(!"signalBufferReturned: bogus buffer");
348    }
349}
350
351// Part of the BufferQueue::ConsumerListener
352void SurfaceMediaSource::onFrameAvailable() {
353    ALOGV("onFrameAvailable");
354
355    sp<FrameAvailableListener> listener;
356    { // scope for the lock
357        Mutex::Autolock lock(mMutex);
358        mFrameAvailableCondition.broadcast();
359        listener = mFrameAvailableListener;
360    }
361
362    if (listener != NULL) {
363        ALOGV("actually calling onFrameAvailable");
364        listener->onFrameAvailable();
365    }
366}
367
368// SurfaceMediaSource hijacks this event to assume
369// the prodcuer is disconnecting from the BufferQueue
370// and that it should stop the recording
371void SurfaceMediaSource::onBuffersReleased() {
372    ALOGV("onBuffersReleased");
373
374    Mutex::Autolock lock(mMutex);
375
376    mFrameAvailableCondition.signal();
377    mStopped = true;
378
379    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
380       mBufferSlot[i] = 0;
381    }
382}
383
384} // end of namespace android
385