stream.cpp revision a6195decfe4f9021bbbd7deb050495c33371366b
1/* 2 * Copyright (C) 2010 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 17//#define LOG_NDEBUG 0 18#define LOG_TAG "stream" 19#include "utils/Log.h" 20 21#include <binder/ProcessState.h> 22#include <cutils/properties.h> // for property_get 23 24#include <media/IStreamSource.h> 25#include <media/mediaplayer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/DataSource.h> 29#include <media/stagefright/MPEG2TSWriter.h> 30#include <media/stagefright/MediaExtractor.h> 31#include <media/stagefright/MediaSource.h> 32#include <media/stagefright/MetaData.h> 33 34#include <binder/IServiceManager.h> 35#include <media/IMediaPlayerService.h> 36#include <gui/ISurfaceComposer.h> 37#include <gui/SurfaceComposerClient.h> 38 39#include <fcntl.h> 40#include <ui/DisplayInfo.h> 41 42using namespace android; 43 44struct MyStreamSource : public BnStreamSource { 45 // Object assumes ownership of fd. 46 MyStreamSource(int fd); 47 48 virtual void setListener(const sp<IStreamListener> &listener); 49 virtual void setBuffers(const Vector<sp<IMemory> > &buffers); 50 51 virtual void onBufferAvailable(size_t index); 52 53protected: 54 virtual ~MyStreamSource(); 55 56private: 57 int mFd; 58 off64_t mFileSize; 59 uint64_t mNumPacketsSent; 60 61 sp<IStreamListener> mListener; 62 Vector<sp<IMemory> > mBuffers; 63 64 DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource); 65}; 66 67MyStreamSource::MyStreamSource(int fd) 68 : mFd(fd), 69 mFileSize(0), 70 mNumPacketsSent(0) { 71 CHECK_GE(fd, 0); 72 73 mFileSize = lseek64(fd, 0, SEEK_END); 74 lseek64(fd, 0, SEEK_SET); 75} 76 77MyStreamSource::~MyStreamSource() { 78 close(mFd); 79 mFd = -1; 80} 81 82void MyStreamSource::setListener(const sp<IStreamListener> &listener) { 83 mListener = listener; 84} 85 86void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) { 87 mBuffers = buffers; 88} 89 90void MyStreamSource::onBufferAvailable(size_t index) { 91 CHECK_LT(index, mBuffers.size()); 92 93#if 0 94 if (mNumPacketsSent >= 20000) { 95 ALOGI("signalling discontinuity now"); 96 97 off64_t offset = 0; 98 CHECK((offset % 188) == 0); 99 100 lseek(mFd, offset, SEEK_SET); 101 102 sp<AMessage> extra = new AMessage; 103 extra->setInt32(IStreamListener::kKeyFormatChange, 0); 104 105 mListener->issueCommand( 106 IStreamListener::DISCONTINUITY, false /* synchronous */, extra); 107 108 mNumPacketsSent = 0; 109 } 110#endif 111 112 sp<IMemory> mem = mBuffers.itemAt(index); 113 114 ssize_t n = read(mFd, mem->pointer(), mem->size()); 115 if (n <= 0) { 116 mListener->issueCommand(IStreamListener::EOS, false /* synchronous */); 117 } else { 118 mListener->queueBuffer(index, n); 119 120 mNumPacketsSent += n / 188; 121 } 122} 123//////////////////////////////////////////////////////////////////////////////// 124 125struct MyConvertingStreamSource : public BnStreamSource { 126 MyConvertingStreamSource(const char *filename); 127 128 virtual void setListener(const sp<IStreamListener> &listener); 129 virtual void setBuffers(const Vector<sp<IMemory> > &buffers); 130 131 virtual void onBufferAvailable(size_t index); 132 133protected: 134 virtual ~MyConvertingStreamSource(); 135 136private: 137 Mutex mLock; 138 Condition mCondition; 139 140 sp<IStreamListener> mListener; 141 Vector<sp<IMemory> > mBuffers; 142 143 sp<MPEG2TSWriter> mWriter; 144 145 ssize_t mCurrentBufferIndex; 146 size_t mCurrentBufferOffset; 147 148 List<size_t> mBufferQueue; 149 150 static ssize_t WriteDataWrapper(void *me, const void *data, size_t size); 151 ssize_t writeData(const void *data, size_t size); 152 153 DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource); 154}; 155 156//////////////////////////////////////////////////////////////////////////////// 157 158MyConvertingStreamSource::MyConvertingStreamSource(const char *filename) 159 : mCurrentBufferIndex(-1), 160 mCurrentBufferOffset(0) { 161 sp<DataSource> dataSource = DataSource::CreateFromURI(filename); 162 CHECK(dataSource != NULL); 163 164 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 165 CHECK(extractor != NULL); 166 167 mWriter = new MPEG2TSWriter( 168 this, &MyConvertingStreamSource::WriteDataWrapper); 169 170 for (size_t i = 0; i < extractor->countTracks(); ++i) { 171 const sp<MetaData> &meta = extractor->getTrackMetaData(i); 172 173 const char *mime; 174 CHECK(meta->findCString(kKeyMIMEType, &mime)); 175 176 if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) { 177 continue; 178 } 179 180 CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK); 181 } 182 183 CHECK_EQ(mWriter->start(), (status_t)OK); 184} 185 186MyConvertingStreamSource::~MyConvertingStreamSource() { 187} 188 189void MyConvertingStreamSource::setListener( 190 const sp<IStreamListener> &listener) { 191 mListener = listener; 192} 193 194void MyConvertingStreamSource::setBuffers( 195 const Vector<sp<IMemory> > &buffers) { 196 mBuffers = buffers; 197} 198 199ssize_t MyConvertingStreamSource::WriteDataWrapper( 200 void *me, const void *data, size_t size) { 201 return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size); 202} 203 204ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) { 205 size_t totalWritten = 0; 206 207 while (size > 0) { 208 Mutex::Autolock autoLock(mLock); 209 210 if (mCurrentBufferIndex < 0) { 211 while (mBufferQueue.empty()) { 212 mCondition.wait(mLock); 213 } 214 215 mCurrentBufferIndex = *mBufferQueue.begin(); 216 mCurrentBufferOffset = 0; 217 218 mBufferQueue.erase(mBufferQueue.begin()); 219 } 220 221 sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex); 222 223 size_t copy = size; 224 if (copy + mCurrentBufferOffset > mem->size()) { 225 copy = mem->size() - mCurrentBufferOffset; 226 } 227 228 memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy); 229 mCurrentBufferOffset += copy; 230 231 if (mCurrentBufferOffset == mem->size()) { 232 mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset); 233 mCurrentBufferIndex = -1; 234 } 235 236 data = (const uint8_t *)data + copy; 237 size -= copy; 238 239 totalWritten += copy; 240 } 241 242 return (ssize_t)totalWritten; 243} 244 245void MyConvertingStreamSource::onBufferAvailable(size_t index) { 246 Mutex::Autolock autoLock(mLock); 247 248 mBufferQueue.push_back(index); 249 mCondition.signal(); 250 251 if (mWriter->reachedEOS()) { 252 if (mCurrentBufferIndex >= 0) { 253 mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset); 254 mCurrentBufferIndex = -1; 255 } 256 257 mListener->issueCommand(IStreamListener::EOS, false /* synchronous */); 258 } 259} 260 261//////////////////////////////////////////////////////////////////////////////// 262 263struct MyClient : public BnMediaPlayerClient { 264 MyClient() 265 : mEOS(false) { 266 } 267 268 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) { 269 Mutex::Autolock autoLock(mLock); 270 271 if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) { 272 mEOS = true; 273 mCondition.signal(); 274 } 275 } 276 277 void waitForEOS() { 278 Mutex::Autolock autoLock(mLock); 279 while (!mEOS) { 280 mCondition.wait(mLock); 281 } 282 } 283 284protected: 285 virtual ~MyClient() { 286 } 287 288private: 289 Mutex mLock; 290 Condition mCondition; 291 292 bool mEOS; 293 294 DISALLOW_EVIL_CONSTRUCTORS(MyClient); 295}; 296 297int main(int argc, char **argv) { 298 android::ProcessState::self()->startThreadPool(); 299 300 DataSource::RegisterDefaultSniffers(); 301 302 if (argc != 2) { 303 fprintf(stderr, "Usage: %s filename\n", argv[0]); 304 return 1; 305 } 306 307 sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient; 308 CHECK_EQ(composerClient->initCheck(), (status_t)OK); 309 310 sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay( 311 ISurfaceComposer::eDisplayIdMain)); 312 DisplayInfo info; 313 SurfaceComposerClient::getDisplayInfo(display, &info); 314 ssize_t displayWidth = info.w; 315 ssize_t displayHeight = info.h; 316 317 ALOGV("display is %d x %d\n", displayWidth, displayHeight); 318 319 sp<SurfaceControl> control = 320 composerClient->createSurface( 321 String8("A Surface"), 322 displayWidth, 323 displayHeight, 324 PIXEL_FORMAT_RGB_565, 325 0); 326 327 CHECK(control != NULL); 328 CHECK(control->isValid()); 329 330 SurfaceComposerClient::openGlobalTransaction(); 331 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); 332 CHECK_EQ(control->show(), (status_t)OK); 333 SurfaceComposerClient::closeGlobalTransaction(); 334 335 sp<Surface> surface = control->getSurface(); 336 CHECK(surface != NULL); 337 338 sp<IServiceManager> sm = defaultServiceManager(); 339 sp<IBinder> binder = sm->getService(String16("media.player")); 340 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 341 342 CHECK(service.get() != NULL); 343 344 sp<MyClient> client = new MyClient; 345 346 sp<IStreamSource> source; 347 348 char prop[PROPERTY_VALUE_MAX]; 349 bool usemp4 = property_get("media.stagefright.use-mp4source", prop, NULL) && 350 (!strcmp(prop, "1") || !strcasecmp(prop, "true")); 351 352 size_t len = strlen(argv[1]); 353 if ((!usemp4 && len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) || 354 (usemp4 && len >= 4 && 355 (!strcasecmp(".mp4", &argv[1][len - 4]) 356 || !strcasecmp(".3gp", &argv[1][len- 4]) 357 || !strcasecmp(".3g2", &argv[1][len- 4])))) { 358 int fd = open(argv[1], O_RDONLY); 359 360 if (fd < 0) { 361 fprintf(stderr, "Failed to open file '%s'.", argv[1]); 362 return 1; 363 } 364 365 source = new MyStreamSource(fd); 366 } else { 367 printf("Converting file to transport stream for streaming...\n"); 368 369 source = new MyConvertingStreamSource(argv[1]); 370 } 371 372 sp<IMediaPlayer> player = 373 service->create(getpid(), client, 0); 374 375 if (player != NULL && player->setDataSource(source) == NO_ERROR) { 376 player->setVideoSurfaceTexture(surface->getSurfaceTexture()); 377 player->start(); 378 379 client->waitForEOS(); 380 381 player->stop(); 382 } else { 383 fprintf(stderr, "failed to instantiate player.\n"); 384 } 385 386 composerClient->dispose(); 387 388 return 0; 389} 390