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