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