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