SurfaceMediaSource.cpp revision 27f706e4db4fc53f63e60d80c19a435fb8bf78b9
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 mStarted(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(!mStarted); 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 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 191 192status_t SurfaceMediaSource::stop() 193{ 194 ALOGV("stop"); 195 Mutex::Autolock lock(mMutex); 196 197 if (!mStarted) { 198 return OK; 199 } 200 201 while (mNumPendingBuffers > 0) { 202 ALOGI("Still waiting for %d buffers to be returned.", 203 mNumPendingBuffers); 204 205#if DEBUG_PENDING_BUFFERS 206 for (size_t i = 0; i < mPendingBuffers.size(); ++i) { 207 ALOGI("%d: %p", i, mPendingBuffers.itemAt(i)); 208 } 209#endif 210 211 mMediaBuffersAvailableCondition.wait(mMutex); 212 } 213 214 mStarted = false; 215 mFrameAvailableCondition.signal(); 216 mMediaBuffersAvailableCondition.signal(); 217 218 return mBufferQueue->consumerDisconnect(); 219} 220 221sp<MetaData> SurfaceMediaSource::getFormat() 222{ 223 ALOGV("getFormat"); 224 225 Mutex::Autolock lock(mMutex); 226 sp<MetaData> meta = new MetaData; 227 228 meta->setInt32(kKeyWidth, mWidth); 229 meta->setInt32(kKeyHeight, mHeight); 230 // The encoder format is set as an opaque colorformat 231 // The encoder will later find out the actual colorformat 232 // from the GL Frames itself. 233 meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque); 234 meta->setInt32(kKeyStride, mWidth); 235 meta->setInt32(kKeySliceHeight, mHeight); 236 meta->setInt32(kKeyFrameRate, mFrameRate); 237 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); 238 return meta; 239} 240 241// Pass the data to the MediaBuffer. Pass in only the metadata 242// The metadata passed consists of two parts: 243// 1. First, there is an integer indicating that it is a GRAlloc 244// source (kMetadataBufferTypeGrallocSource) 245// 2. This is followed by the buffer_handle_t that is a handle to the 246// GRalloc buffer. The encoder needs to interpret this GRalloc handle 247// and encode the frames. 248// -------------------------------------------------------------- 249// | kMetadataBufferTypeGrallocSource | sizeof(buffer_handle_t) | 250// -------------------------------------------------------------- 251// Note: Call only when you have the lock 252static void passMetadataBuffer(MediaBuffer **buffer, 253 buffer_handle_t bufferHandle) { 254 *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t)); 255 char *data = (char *)(*buffer)->data(); 256 if (data == NULL) { 257 ALOGE("Cannot allocate memory for metadata buffer!"); 258 return; 259 } 260 OMX_U32 type = kMetadataBufferTypeGrallocSource; 261 memcpy(data, &type, 4); 262 memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t)); 263 264 ALOGV("handle = %p, , offset = %d, length = %d", 265 bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset()); 266} 267 268status_t SurfaceMediaSource::read( MediaBuffer **buffer, 269 const ReadOptions *options) 270{ 271 ALOGV("read"); 272 Mutex::Autolock lock(mMutex); 273 274 *buffer = NULL; 275 276 while (mStarted && mNumPendingBuffers == mMaxAcquiredBufferCount) { 277 mMediaBuffersAvailableCondition.wait(mMutex); 278 } 279 280 // Update the current buffer info 281 // TODO: mCurrentSlot can be made a bufferstate since there 282 // can be more than one "current" slots. 283 284 BufferQueue::BufferItem item; 285 // If the recording has started and the queue is empty, then just 286 // wait here till the frames come in from the client side 287 while (mStarted) { 288 289 status_t err = mBufferQueue->acquireBuffer(&item); 290 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 291 // wait for a buffer to be queued 292 mFrameAvailableCondition.wait(mMutex); 293 } else if (err == OK) { 294 295 // First time seeing the buffer? Added it to the SMS slot 296 if (item.mGraphicBuffer != NULL) { 297 mBufferSlot[item.mBuf] = item.mGraphicBuffer; 298 } 299 300 // check for the timing of this buffer 301 if (mNumFramesReceived == 0) { 302 mFirstFrameTimestamp = item.mTimestamp; 303 // Initial delay 304 if (mStartTimeNs > 0) { 305 if (item.mTimestamp < mStartTimeNs) { 306 // This frame predates start of record, discard 307 mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, 308 EGL_NO_SYNC_KHR, Fence::NO_FENCE); 309 continue; 310 } 311 mStartTimeNs = item.mTimestamp - mStartTimeNs; 312 } 313 } 314 item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp); 315 316 mNumFramesReceived++; 317 318 break; 319 } else { 320 ALOGE("read: acquire failed with error code %d", err); 321 return ERROR_END_OF_STREAM; 322 } 323 324 } 325 326 // If the loop was exited as a result of stopping the recording, 327 // it is OK 328 if (!mStarted) { 329 ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM."); 330 return ERROR_END_OF_STREAM; 331 } 332 333 mCurrentSlot = item.mBuf; 334 335 // First time seeing the buffer? Added it to the SMS slot 336 if (item.mGraphicBuffer != NULL) { 337 mBufferSlot[mCurrentSlot] = item.mGraphicBuffer; 338 } 339 340 mCurrentBuffers.push_back(mBufferSlot[mCurrentSlot]); 341 int64_t prevTimeStamp = mCurrentTimestamp; 342 mCurrentTimestamp = item.mTimestamp; 343 344 mNumFramesEncoded++; 345 // Pass the data to the MediaBuffer. Pass in only the metadata 346 347 passMetadataBuffer(buffer, mBufferSlot[mCurrentSlot]->handle); 348 349 (*buffer)->setObserver(this); 350 (*buffer)->add_ref(); 351 (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000); 352 ALOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld", 353 mNumFramesEncoded, mCurrentTimestamp / 1000, 354 mCurrentTimestamp / 1000 - prevTimeStamp / 1000); 355 356 ++mNumPendingBuffers; 357 358#if DEBUG_PENDING_BUFFERS 359 mPendingBuffers.push_back(*buffer); 360#endif 361 362 ALOGV("returning mbuf %p", *buffer); 363 364 return OK; 365} 366 367static buffer_handle_t getMediaBufferHandle(MediaBuffer *buffer) { 368 // need to convert to char* for pointer arithmetic and then 369 // copy the byte stream into our handle 370 buffer_handle_t bufferHandle; 371 memcpy(&bufferHandle, (char*)(buffer->data()) + 4, sizeof(buffer_handle_t)); 372 return bufferHandle; 373} 374 375void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { 376 ALOGV("signalBufferReturned"); 377 378 bool foundBuffer = false; 379 380 Mutex::Autolock lock(mMutex); 381 382 buffer_handle_t bufferHandle = getMediaBufferHandle(buffer); 383 384 for (size_t i = 0; i < mCurrentBuffers.size(); i++) { 385 if (mCurrentBuffers[i]->handle == bufferHandle) { 386 mCurrentBuffers.removeAt(i); 387 foundBuffer = true; 388 break; 389 } 390 } 391 392 if (!foundBuffer) { 393 ALOGW("returned buffer was not found in the current buffer list"); 394 } 395 396 for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) { 397 if (mBufferSlot[id] == NULL) { 398 continue; 399 } 400 401 if (bufferHandle == mBufferSlot[id]->handle) { 402 ALOGV("Slot %d returned, matches handle = %p", id, 403 mBufferSlot[id]->handle); 404 405 mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, 406 Fence::NO_FENCE); 407 408 buffer->setObserver(0); 409 buffer->release(); 410 411 foundBuffer = true; 412 break; 413 } 414 } 415 416 if (!foundBuffer) { 417 CHECK(!"signalBufferReturned: bogus buffer"); 418 } 419 420#if DEBUG_PENDING_BUFFERS 421 for (size_t i = 0; i < mPendingBuffers.size(); ++i) { 422 if (mPendingBuffers.itemAt(i) == buffer) { 423 mPendingBuffers.removeAt(i); 424 break; 425 } 426 } 427#endif 428 429 --mNumPendingBuffers; 430 mMediaBuffersAvailableCondition.broadcast(); 431} 432 433// Part of the BufferQueue::ConsumerListener 434void SurfaceMediaSource::onFrameAvailable() { 435 ALOGV("onFrameAvailable"); 436 437 sp<FrameAvailableListener> listener; 438 { // scope for the lock 439 Mutex::Autolock lock(mMutex); 440 mFrameAvailableCondition.broadcast(); 441 listener = mFrameAvailableListener; 442 } 443 444 if (listener != NULL) { 445 ALOGV("actually calling onFrameAvailable"); 446 listener->onFrameAvailable(); 447 } 448} 449 450// SurfaceMediaSource hijacks this event to assume 451// the prodcuer is disconnecting from the BufferQueue 452// and that it should stop the recording 453void SurfaceMediaSource::onBuffersReleased() { 454 ALOGV("onBuffersReleased"); 455 456 Mutex::Autolock lock(mMutex); 457 458 mFrameAvailableCondition.signal(); 459 460 for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { 461 mBufferSlot[i] = 0; 462 } 463} 464 465} // end of namespace android 466