Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 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 | */ |
Pannag Sanketi | 7dc9b30 | 2011-09-08 14:15:00 -0700 | [diff] [blame] | 16 | //#define LOG_NDEBUG 0 |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 17 | #define LOG_TAG "SurfaceMediaSource" |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 18 | |
James Dong | f1d5aa1 | 2012-02-06 23:46:37 -0800 | [diff] [blame] | 19 | #include <media/stagefright/foundation/ADebug.h> |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 20 | #include <media/stagefright/SurfaceMediaSource.h> |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 21 | #include <media/stagefright/MediaDefs.h> |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 22 | #include <media/stagefright/MetaData.h> |
James Dong | 6c6b4d0 | 2012-03-12 14:37:53 -0700 | [diff] [blame] | 23 | #include <OMX_IVCommon.h> |
| 24 | #include <MetadataBufferType.h> |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 25 | |
James Dong | f1d5aa1 | 2012-02-06 23:46:37 -0800 | [diff] [blame] | 26 | #include <ui/GraphicBuffer.h> |
Mathias Agopian | df712ea | 2012-02-25 18:48:35 -0800 | [diff] [blame] | 27 | #include <gui/ISurfaceComposer.h> |
| 28 | #include <gui/IGraphicBufferAlloc.h> |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 29 | #include <OMX_Component.h> |
| 30 | |
| 31 | #include <utils/Log.h> |
| 32 | #include <utils/String8.h> |
| 33 | |
Mathias Agopian | 404a123 | 2011-11-17 17:48:35 -0800 | [diff] [blame] | 34 | #include <private/gui/ComposerService.h> |
| 35 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 36 | namespace android { |
| 37 | |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 38 | SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight) : |
| 39 | mWidth(bufferWidth), |
| 40 | mHeight(bufferHeight), |
| 41 | mCurrentSlot(BufferQueue::INVALID_BUFFER_SLOT), |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 42 | mNumPendingBuffers(0), |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 43 | mCurrentTimestamp(0), |
| 44 | mFrameRate(30), |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 45 | mStarted(false), |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 46 | mNumFramesReceived(0), |
| 47 | mNumFramesEncoded(0), |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 48 | mFirstFrameTimestamp(0), |
Andreas Huber | 90689fd | 2012-10-01 15:59:54 -0700 | [diff] [blame] | 49 | mMaxAcquiredBufferCount(4), // XXX double-check the default |
| 50 | mUseAbsoluteTimestamps(false) { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 51 | ALOGV("SurfaceMediaSource"); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 52 | |
| 53 | if (bufferWidth == 0 || bufferHeight == 0) { |
| 54 | ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight); |
| 55 | } |
| 56 | |
James Dong | 56fc8fb | 2012-08-23 09:23:07 -0700 | [diff] [blame] | 57 | mBufferQueue = new BufferQueue(true); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 58 | mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); |
| 59 | mBufferQueue->setSynchronousMode(true); |
Eino-Ville Talvala | 8add6cf | 2012-04-13 16:06:16 -0700 | [diff] [blame] | 60 | mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | |
| 61 | GRALLOC_USAGE_HW_TEXTURE); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 62 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 63 | sp<ISurfaceComposer> composer(ComposerService::getComposerService()); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 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); |
Daniel Lam | abf0610 | 2012-02-23 14:35:13 -0800 | [diff] [blame] | 78 | } |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 79 | } |
| 80 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 81 | SurfaceMediaSource::~SurfaceMediaSource() { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 82 | ALOGV("~SurfaceMediaSource"); |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 83 | CHECK(!mStarted); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 84 | } |
| 85 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 86 | nsecs_t SurfaceMediaSource::getTimestamp() { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 87 | ALOGV("getTimestamp"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 88 | Mutex::Autolock lock(mMutex); |
| 89 | return mCurrentTimestamp; |
| 90 | } |
| 91 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 92 | void SurfaceMediaSource::setFrameAvailableListener( |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 93 | const sp<FrameAvailableListener>& listener) { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 94 | ALOGV("setFrameAvailableListener"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 95 | Mutex::Autolock lock(mMutex); |
| 96 | mFrameAvailableListener = listener; |
| 97 | } |
| 98 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 99 | void SurfaceMediaSource::dump(String8& result) const |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 100 | { |
| 101 | char buffer[1024]; |
| 102 | dump(result, "", buffer, 1024); |
| 103 | } |
| 104 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 105 | void SurfaceMediaSource::dump(String8& result, const char* prefix, |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 106 | char* buffer, size_t SIZE) const |
| 107 | { |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 108 | Mutex::Autolock lock(mMutex); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 109 | |
| 110 | result.append(buffer); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 111 | mBufferQueue->dump(result); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 112 | } |
| 113 | |
Pannag Sanketi | b33f340 | 2011-07-01 17:39:39 -0700 | [diff] [blame] | 114 | status_t SurfaceMediaSource::setFrameRate(int32_t fps) |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 115 | { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 116 | ALOGV("setFrameRate"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 117 | Mutex::Autolock lock(mMutex); |
Pannag Sanketi | b33f340 | 2011-07-01 17:39:39 -0700 | [diff] [blame] | 118 | const int MAX_FRAME_RATE = 60; |
| 119 | if (fps < 0 || fps > MAX_FRAME_RATE) { |
| 120 | return BAD_VALUE; |
| 121 | } |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 122 | mFrameRate = fps; |
Pannag Sanketi | b33f340 | 2011-07-01 17:39:39 -0700 | [diff] [blame] | 123 | return OK; |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 124 | } |
| 125 | |
Pannag Sanketi | b33f340 | 2011-07-01 17:39:39 -0700 | [diff] [blame] | 126 | bool SurfaceMediaSource::isMetaDataStoredInVideoBuffers() const { |
Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 127 | ALOGV("isMetaDataStoredInVideoBuffers"); |
Pannag Sanketi | b33f340 | 2011-07-01 17:39:39 -0700 | [diff] [blame] | 128 | return true; |
| 129 | } |
| 130 | |
| 131 | int32_t SurfaceMediaSource::getFrameRate( ) const { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 132 | ALOGV("getFrameRate"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 133 | Mutex::Autolock lock(mMutex); |
| 134 | return mFrameRate; |
| 135 | } |
| 136 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 137 | status_t SurfaceMediaSource::start(MetaData *params) |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 138 | { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 139 | ALOGV("start"); |
Eino-Ville Talvala | df4a59c | 2011-08-29 18:16:03 -0700 | [diff] [blame] | 140 | |
James Dong | 56fc8fb | 2012-08-23 09:23:07 -0700 | [diff] [blame] | 141 | Mutex::Autolock lock(mMutex); |
| 142 | |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 143 | CHECK(!mStarted); |
| 144 | |
Eino-Ville Talvala | df4a59c | 2011-08-29 18:16:03 -0700 | [diff] [blame] | 145 | mStartTimeNs = 0; |
| 146 | int64_t startTimeUs; |
James Dong | 56fc8fb | 2012-08-23 09:23:07 -0700 | [diff] [blame] | 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 | } |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 162 | |
| 163 | mMaxAcquiredBufferCount = bufferCount; |
James Dong | 56fc8fb | 2012-08-23 09:23:07 -0700 | [diff] [blame] | 164 | } |
| 165 | |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 166 | CHECK_GT(mMaxAcquiredBufferCount, 1); |
| 167 | |
| 168 | status_t err = |
| 169 | mBufferQueue->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount); |
| 170 | |
| 171 | if (err != OK) { |
| 172 | return err; |
Eino-Ville Talvala | df4a59c | 2011-08-29 18:16:03 -0700 | [diff] [blame] | 173 | } |
| 174 | |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 175 | mNumPendingBuffers = 0; |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 176 | mStarted = true; |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 177 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 178 | return OK; |
| 179 | } |
| 180 | |
Andreas Huber | 7f06639 | 2012-09-04 16:30:49 -0700 | [diff] [blame] | 181 | status_t SurfaceMediaSource::setMaxAcquiredBufferCount(size_t count) { |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 182 | ALOGV("setMaxAcquiredBufferCount(%d)", count); |
| 183 | Mutex::Autolock lock(mMutex); |
| 184 | |
| 185 | CHECK_GT(count, 1); |
| 186 | mMaxAcquiredBufferCount = count; |
| 187 | |
| 188 | return OK; |
Andreas Huber | 7f06639 | 2012-09-04 16:30:49 -0700 | [diff] [blame] | 189 | } |
| 190 | |
Andreas Huber | 90689fd | 2012-10-01 15:59:54 -0700 | [diff] [blame] | 191 | status_t SurfaceMediaSource::setUseAbsoluteTimestamps() { |
| 192 | ALOGV("setUseAbsoluteTimestamps"); |
| 193 | Mutex::Autolock lock(mMutex); |
| 194 | mUseAbsoluteTimestamps = true; |
| 195 | |
| 196 | return OK; |
| 197 | } |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 198 | |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 199 | status_t SurfaceMediaSource::stop() |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 200 | { |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 201 | ALOGV("stop"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 202 | Mutex::Autolock lock(mMutex); |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 203 | |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 204 | if (!mStarted) { |
Andreas Huber | a7f7e0a | 2012-09-28 10:23:51 -0700 | [diff] [blame] | 205 | return OK; |
| 206 | } |
| 207 | |
| 208 | while (mNumPendingBuffers > 0) { |
| 209 | ALOGI("Still waiting for %d buffers to be returned.", |
| 210 | mNumPendingBuffers); |
| 211 | |
| 212 | #if DEBUG_PENDING_BUFFERS |
| 213 | for (size_t i = 0; i < mPendingBuffers.size(); ++i) { |
| 214 | ALOGI("%d: %p", i, mPendingBuffers.itemAt(i)); |
| 215 | } |
| 216 | #endif |
| 217 | |
| 218 | mMediaBuffersAvailableCondition.wait(mMutex); |
| 219 | } |
| 220 | |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 221 | mStarted = false; |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 222 | mFrameAvailableCondition.signal(); |
Andreas Huber | be99664 | 2012-09-27 14:13:05 -0700 | [diff] [blame] | 223 | mMediaBuffersAvailableCondition.signal(); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 224 | |
Jamie Gennis | a0ead0a | 2012-08-23 20:24:09 -0700 | [diff] [blame] | 225 | return mBufferQueue->consumerDisconnect(); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 226 | } |
| 227 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 228 | sp<MetaData> SurfaceMediaSource::getFormat() |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 229 | { |
Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 230 | ALOGV("getFormat"); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 231 | |
| 232 | Mutex::Autolock lock(mMutex); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 233 | sp<MetaData> meta = new MetaData; |
Pannag Sanketi | b33f340 | 2011-07-01 17:39:39 -0700 | [diff] [blame] | 234 | |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 235 | meta->setInt32(kKeyWidth, mWidth); |
| 236 | meta->setInt32(kKeyHeight, mHeight); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 237 | // The encoder format is set as an opaque colorformat |
| 238 | // The encoder will later find out the actual colorformat |
| 239 | // from the GL Frames itself. |
| 240 | meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 241 | meta->setInt32(kKeyStride, mWidth); |
| 242 | meta->setInt32(kKeySliceHeight, mHeight); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 243 | meta->setInt32(kKeyFrameRate, mFrameRate); |
| 244 | meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); |
| 245 | return meta; |
| 246 | } |
| 247 | |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 248 | // Pass the data to the MediaBuffer. Pass in only the metadata |
| 249 | // The metadata passed consists of two parts: |
| 250 | // 1. First, there is an integer indicating that it is a GRAlloc |
| 251 | // source (kMetadataBufferTypeGrallocSource) |
| 252 | // 2. This is followed by the buffer_handle_t that is a handle to the |
| 253 | // GRalloc buffer. The encoder needs to interpret this GRalloc handle |
| 254 | // and encode the frames. |
| 255 | // -------------------------------------------------------------- |
| 256 | // | kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) | |
| 257 | // -------------------------------------------------------------- |
| 258 | // Note: Call only when you have the lock |
| 259 | static void passMetadataBuffer(MediaBuffer **buffer, |
| 260 | buffer_handle_t bufferHandle) { |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 261 | *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t)); |
| 262 | char *data = (char *)(*buffer)->data(); |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 263 | if (data == NULL) { |
| 264 | ALOGE("Cannot allocate memory for metadata buffer!"); |
| 265 | return; |
| 266 | } |
| 267 | OMX_U32 type = kMetadataBufferTypeGrallocSource; |
| 268 | memcpy(data, &type, 4); |
| 269 | memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t)); |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 270 | |
| 271 | ALOGV("handle = %p, , offset = %d, length = %d", |
| 272 | bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset()); |
| 273 | } |
| 274 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 275 | status_t SurfaceMediaSource::read( MediaBuffer **buffer, |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 276 | const ReadOptions *options) |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 277 | { |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 278 | ALOGV("read"); |
| 279 | Mutex::Autolock lock(mMutex); |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 280 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 281 | *buffer = NULL; |
| 282 | |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 283 | while (mStarted && mNumPendingBuffers == mMaxAcquiredBufferCount) { |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 284 | mMediaBuffersAvailableCondition.wait(mMutex); |
| 285 | } |
| 286 | |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 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; |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 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 |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 294 | while (mStarted) { |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 295 | |
| 296 | status_t err = mBufferQueue->acquireBuffer(&item); |
| 297 | if (err == BufferQueue::NO_BUFFER_AVAILABLE) { |
| 298 | // wait for a buffer to be queued |
| 299 | mFrameAvailableCondition.wait(mMutex); |
| 300 | } else if (err == OK) { |
Greg Hackmann | 10174bf | 2012-12-14 13:49:48 -0800 | [diff] [blame] | 301 | err = item.mFence->waitForever(1000, "SurfaceMediaSource::read"); |
| 302 | if (err) { |
| 303 | ALOGW("read: failed to wait for buffer fence: %d", err); |
| 304 | } |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 305 | |
| 306 | // First time seeing the buffer? Added it to the SMS slot |
| 307 | if (item.mGraphicBuffer != NULL) { |
| 308 | mBufferSlot[item.mBuf] = item.mGraphicBuffer; |
| 309 | } |
| 310 | |
| 311 | // check for the timing of this buffer |
Andreas Huber | 90689fd | 2012-10-01 15:59:54 -0700 | [diff] [blame] | 312 | if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) { |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 313 | mFirstFrameTimestamp = item.mTimestamp; |
| 314 | // Initial delay |
| 315 | if (mStartTimeNs > 0) { |
| 316 | if (item.mTimestamp < mStartTimeNs) { |
| 317 | // This frame predates start of record, discard |
Jesse Hall | f15f6e2 | 2012-06-13 14:52:12 -0700 | [diff] [blame] | 318 | mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, |
| 319 | EGL_NO_SYNC_KHR, Fence::NO_FENCE); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 320 | continue; |
| 321 | } |
| 322 | mStartTimeNs = item.mTimestamp - mStartTimeNs; |
| 323 | } |
| 324 | } |
| 325 | item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp); |
| 326 | |
| 327 | mNumFramesReceived++; |
| 328 | |
| 329 | break; |
| 330 | } else { |
| 331 | ALOGE("read: acquire failed with error code %d", err); |
| 332 | return ERROR_END_OF_STREAM; |
| 333 | } |
| 334 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 335 | } |
| 336 | |
| 337 | // If the loop was exited as a result of stopping the recording, |
| 338 | // it is OK |
Andreas Huber | a54dee4 | 2012-10-01 11:22:05 -0700 | [diff] [blame] | 339 | if (!mStarted) { |
Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 340 | ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM."); |
Pannag Sanketi | 3e9bf40 | 2011-09-22 17:03:48 -0700 | [diff] [blame] | 341 | return ERROR_END_OF_STREAM; |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 342 | } |
| 343 | |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 344 | mCurrentSlot = item.mBuf; |
| 345 | |
| 346 | // First time seeing the buffer? Added it to the SMS slot |
| 347 | if (item.mGraphicBuffer != NULL) { |
| 348 | mBufferSlot[mCurrentSlot] = item.mGraphicBuffer; |
| 349 | } |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 350 | |
| 351 | mCurrentBuffers.push_back(mBufferSlot[mCurrentSlot]); |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 352 | int64_t prevTimeStamp = mCurrentTimestamp; |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 353 | mCurrentTimestamp = item.mTimestamp; |
Eino-Ville Talvala | df4a59c | 2011-08-29 18:16:03 -0700 | [diff] [blame] | 354 | |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 355 | mNumFramesEncoded++; |
Pannag Sanketi | a361483 | 2011-07-14 14:37:47 -0700 | [diff] [blame] | 356 | // Pass the data to the MediaBuffer. Pass in only the metadata |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 357 | |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 358 | passMetadataBuffer(buffer, mBufferSlot[mCurrentSlot]->handle); |
Pannag Sanketi | a361483 | 2011-07-14 14:37:47 -0700 | [diff] [blame] | 359 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 360 | (*buffer)->setObserver(this); |
| 361 | (*buffer)->add_ref(); |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 362 | (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000); |
Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 363 | ALOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld", |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 364 | mNumFramesEncoded, mCurrentTimestamp / 1000, |
| 365 | mCurrentTimestamp / 1000 - prevTimeStamp / 1000); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 366 | |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 367 | ++mNumPendingBuffers; |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 368 | |
Andreas Huber | a7f7e0a | 2012-09-28 10:23:51 -0700 | [diff] [blame] | 369 | #if DEBUG_PENDING_BUFFERS |
| 370 | mPendingBuffers.push_back(*buffer); |
| 371 | #endif |
| 372 | |
| 373 | ALOGV("returning mbuf %p", *buffer); |
| 374 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 375 | return OK; |
| 376 | } |
| 377 | |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 378 | static buffer_handle_t getMediaBufferHandle(MediaBuffer *buffer) { |
| 379 | // need to convert to char* for pointer arithmetic and then |
| 380 | // copy the byte stream into our handle |
| 381 | buffer_handle_t bufferHandle; |
| 382 | memcpy(&bufferHandle, (char*)(buffer->data()) + 4, sizeof(buffer_handle_t)); |
| 383 | return bufferHandle; |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 384 | } |
Pannag Sanketi | a361483 | 2011-07-14 14:37:47 -0700 | [diff] [blame] | 385 | |
Pannag Sanketi | 1a2fafb | 2011-06-30 15:30:03 -0700 | [diff] [blame] | 386 | void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { |
Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 387 | ALOGV("signalBufferReturned"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 388 | |
| 389 | bool foundBuffer = false; |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 390 | |
| 391 | Mutex::Autolock lock(mMutex); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 392 | |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 393 | buffer_handle_t bufferHandle = getMediaBufferHandle(buffer); |
| 394 | |
| 395 | for (size_t i = 0; i < mCurrentBuffers.size(); i++) { |
| 396 | if (mCurrentBuffers[i]->handle == bufferHandle) { |
| 397 | mCurrentBuffers.removeAt(i); |
| 398 | foundBuffer = true; |
| 399 | break; |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | if (!foundBuffer) { |
| 404 | ALOGW("returned buffer was not found in the current buffer list"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 405 | } |
| 406 | |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 407 | for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) { |
| 408 | if (mBufferSlot[id] == NULL) { |
Pannag Sanketi | 0c5c7d2 | 2011-08-18 21:53:02 -0700 | [diff] [blame] | 409 | continue; |
| 410 | } |
Jamie Gennis | 2cd25a9 | 2012-06-22 14:42:00 -0700 | [diff] [blame] | 411 | |
| 412 | if (bufferHandle == mBufferSlot[id]->handle) { |
Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 413 | ALOGV("Slot %d returned, matches handle = %p", id, |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 414 | mBufferSlot[id]->handle); |
| 415 | |
Jesse Hall | f15f6e2 | 2012-06-13 14:52:12 -0700 | [diff] [blame] | 416 | mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, |
| 417 | Fence::NO_FENCE); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 418 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 419 | buffer->setObserver(0); |
| 420 | buffer->release(); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 421 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 422 | foundBuffer = true; |
| 423 | break; |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | if (!foundBuffer) { |
James Dong | f1d5aa1 | 2012-02-06 23:46:37 -0800 | [diff] [blame] | 428 | CHECK(!"signalBufferReturned: bogus buffer"); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 429 | } |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 430 | |
Andreas Huber | a7f7e0a | 2012-09-28 10:23:51 -0700 | [diff] [blame] | 431 | #if DEBUG_PENDING_BUFFERS |
| 432 | for (size_t i = 0; i < mPendingBuffers.size(); ++i) { |
| 433 | if (mPendingBuffers.itemAt(i) == buffer) { |
| 434 | mPendingBuffers.removeAt(i); |
| 435 | break; |
| 436 | } |
| 437 | } |
| 438 | #endif |
| 439 | |
Andreas Huber | b62f951 | 2012-09-12 12:08:55 -0700 | [diff] [blame] | 440 | --mNumPendingBuffers; |
| 441 | mMediaBuffersAvailableCondition.broadcast(); |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 442 | } |
| 443 | |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 444 | // Part of the BufferQueue::ConsumerListener |
| 445 | void SurfaceMediaSource::onFrameAvailable() { |
| 446 | ALOGV("onFrameAvailable"); |
| 447 | |
| 448 | sp<FrameAvailableListener> listener; |
| 449 | { // scope for the lock |
| 450 | Mutex::Autolock lock(mMutex); |
| 451 | mFrameAvailableCondition.broadcast(); |
| 452 | listener = mFrameAvailableListener; |
| 453 | } |
| 454 | |
| 455 | if (listener != NULL) { |
| 456 | ALOGV("actually calling onFrameAvailable"); |
| 457 | listener->onFrameAvailable(); |
| 458 | } |
| 459 | } |
| 460 | |
| 461 | // SurfaceMediaSource hijacks this event to assume |
| 462 | // the prodcuer is disconnecting from the BufferQueue |
| 463 | // and that it should stop the recording |
| 464 | void SurfaceMediaSource::onBuffersReleased() { |
| 465 | ALOGV("onBuffersReleased"); |
| 466 | |
| 467 | Mutex::Autolock lock(mMutex); |
| 468 | |
| 469 | mFrameAvailableCondition.signal(); |
Daniel Lam | bdddc65 | 2012-03-30 16:04:43 -0700 | [diff] [blame] | 470 | |
| 471 | for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { |
| 472 | mBufferSlot[i] = 0; |
| 473 | } |
Pannag Sanketi | a361483 | 2011-07-14 14:37:47 -0700 | [diff] [blame] | 474 | } |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 475 | |
Pannag Sanketi | 3399b72 | 2011-06-10 18:30:30 -0700 | [diff] [blame] | 476 | } // end of namespace android |