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