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