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