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