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