SurfaceMediaSource.cpp revision 84333e0475bc911adc16417f4ca327c975cf6c36
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 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 221 mStarted = false; 222 mFrameAvailableCondition.signal(); 223 mMediaBuffersAvailableCondition.signal(); 224 225 return mBufferQueue->consumerDisconnect(); 226} 227 228sp<MetaData> SurfaceMediaSource::getFormat() 229{ 230 ALOGV("getFormat"); 231 232 Mutex::Autolock lock(mMutex); 233 sp<MetaData> meta = new MetaData; 234 235 meta->setInt32(kKeyWidth, mWidth); 236 meta->setInt32(kKeyHeight, mHeight); 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); 241 meta->setInt32(kKeyStride, mWidth); 242 meta->setInt32(kKeySliceHeight, mHeight); 243 meta->setInt32(kKeyFrameRate, mFrameRate); 244 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); 245 return meta; 246} 247 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 259static void passMetadataBuffer(MediaBuffer **buffer, 260 buffer_handle_t bufferHandle) { 261 *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t)); 262 char *data = (char *)(*buffer)->data(); 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)); 270 271 ALOGV("handle = %p, , offset = %d, length = %d", 272 bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset()); 273} 274 275status_t SurfaceMediaSource::read( 276 MediaBuffer **buffer, const ReadOptions * /* options */) { 277 ALOGV("read"); 278 Mutex::Autolock lock(mMutex); 279 280 *buffer = NULL; 281 282 while (mStarted && mNumPendingBuffers == mMaxAcquiredBufferCount) { 283 mMediaBuffersAvailableCondition.wait(mMutex); 284 } 285 286 // Update the current buffer info 287 // TODO: mCurrentSlot can be made a bufferstate since there 288 // can be more than one "current" slots. 289 290 BufferQueue::BufferItem item; 291 // If the recording has started and the queue is empty, then just 292 // wait here till the frames come in from the client side 293 while (mStarted) { 294 295 status_t err = mBufferQueue->acquireBuffer(&item, 0); 296 if (err == BufferQueue::NO_BUFFER_AVAILABLE) { 297 // wait for a buffer to be queued 298 mFrameAvailableCondition.wait(mMutex); 299 } else if (err == OK) { 300 err = item.mFence->waitForever("SurfaceMediaSource::read"); 301 if (err) { 302 ALOGW("read: failed to wait for buffer fence: %d", err); 303 } 304 305 // First time seeing the buffer? Added it to the SMS slot 306 if (item.mGraphicBuffer != NULL) { 307 mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer; 308 } 309 mSlots[item.mBuf].mFrameNumber = item.mFrameNumber; 310 311 // check for the timing of this buffer 312 if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) { 313 mFirstFrameTimestamp = item.mTimestamp; 314 // Initial delay 315 if (mStartTimeNs > 0) { 316 if (item.mTimestamp < mStartTimeNs) { 317 // This frame predates start of record, discard 318 mBufferQueue->releaseBuffer( 319 item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY, 320 EGL_NO_SYNC_KHR, Fence::NO_FENCE); 321 continue; 322 } 323 mStartTimeNs = item.mTimestamp - mStartTimeNs; 324 } 325 } 326 item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp); 327 328 mNumFramesReceived++; 329 330 break; 331 } else { 332 ALOGE("read: acquire failed with error code %d", err); 333 return ERROR_END_OF_STREAM; 334 } 335 336 } 337 338 // If the loop was exited as a result of stopping the recording, 339 // it is OK 340 if (!mStarted) { 341 ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM."); 342 return ERROR_END_OF_STREAM; 343 } 344 345 mCurrentSlot = item.mBuf; 346 347 // First time seeing the buffer? Added it to the SMS slot 348 if (item.mGraphicBuffer != NULL) { 349 mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer; 350 } 351 mSlots[item.mBuf].mFrameNumber = item.mFrameNumber; 352 353 mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer); 354 int64_t prevTimeStamp = mCurrentTimestamp; 355 mCurrentTimestamp = item.mTimestamp; 356 357 mNumFramesEncoded++; 358 // Pass the data to the MediaBuffer. Pass in only the metadata 359 360 passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle); 361 362 (*buffer)->setObserver(this); 363 (*buffer)->add_ref(); 364 (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000); 365 ALOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld", 366 mNumFramesEncoded, mCurrentTimestamp / 1000, 367 mCurrentTimestamp / 1000 - prevTimeStamp / 1000); 368 369 ++mNumPendingBuffers; 370 371#if DEBUG_PENDING_BUFFERS 372 mPendingBuffers.push_back(*buffer); 373#endif 374 375 ALOGV("returning mbuf %p", *buffer); 376 377 return OK; 378} 379 380static buffer_handle_t getMediaBufferHandle(MediaBuffer *buffer) { 381 // need to convert to char* for pointer arithmetic and then 382 // copy the byte stream into our handle 383 buffer_handle_t bufferHandle; 384 memcpy(&bufferHandle, (char*)(buffer->data()) + 4, sizeof(buffer_handle_t)); 385 return bufferHandle; 386} 387 388void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { 389 ALOGV("signalBufferReturned"); 390 391 bool foundBuffer = false; 392 393 Mutex::Autolock lock(mMutex); 394 395 buffer_handle_t bufferHandle = getMediaBufferHandle(buffer); 396 397 for (size_t i = 0; i < mCurrentBuffers.size(); i++) { 398 if (mCurrentBuffers[i]->handle == bufferHandle) { 399 mCurrentBuffers.removeAt(i); 400 foundBuffer = true; 401 break; 402 } 403 } 404 405 if (!foundBuffer) { 406 ALOGW("returned buffer was not found in the current buffer list"); 407 } 408 409 for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) { 410 if (mSlots[id].mGraphicBuffer == NULL) { 411 continue; 412 } 413 414 if (bufferHandle == mSlots[id].mGraphicBuffer->handle) { 415 ALOGV("Slot %d returned, matches handle = %p", id, 416 mSlots[id].mGraphicBuffer->handle); 417 418 mBufferQueue->releaseBuffer(id, mSlots[id].mFrameNumber, 419 EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, 420 Fence::NO_FENCE); 421 422 buffer->setObserver(0); 423 buffer->release(); 424 425 foundBuffer = true; 426 break; 427 } 428 } 429 430 if (!foundBuffer) { 431 CHECK(!"signalBufferReturned: bogus buffer"); 432 } 433 434#if DEBUG_PENDING_BUFFERS 435 for (size_t i = 0; i < mPendingBuffers.size(); ++i) { 436 if (mPendingBuffers.itemAt(i) == buffer) { 437 mPendingBuffers.removeAt(i); 438 break; 439 } 440 } 441#endif 442 443 --mNumPendingBuffers; 444 mMediaBuffersAvailableCondition.broadcast(); 445} 446 447// Part of the BufferQueue::ConsumerListener 448void SurfaceMediaSource::onFrameAvailable() { 449 ALOGV("onFrameAvailable"); 450 451 sp<FrameAvailableListener> listener; 452 { // scope for the lock 453 Mutex::Autolock lock(mMutex); 454 mFrameAvailableCondition.broadcast(); 455 listener = mFrameAvailableListener; 456 } 457 458 if (listener != NULL) { 459 ALOGV("actually calling onFrameAvailable"); 460 listener->onFrameAvailable(); 461 } 462} 463 464// SurfaceMediaSource hijacks this event to assume 465// the prodcuer is disconnecting from the BufferQueue 466// and that it should stop the recording 467void SurfaceMediaSource::onBuffersReleased() { 468 ALOGV("onBuffersReleased"); 469 470 Mutex::Autolock lock(mMutex); 471 472 mFrameAvailableCondition.signal(); 473 474 for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { 475 mSlots[i].mGraphicBuffer = 0; 476 } 477} 478 479} // end of namespace android 480