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