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