blob: 0d6c738292dab826c1c3288b987105cbcc9ccee6 [file] [log] [blame]
James Dong199d1c12011-03-17 11:48:13 -07001/*
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
Andreas Huberced159b2011-08-25 12:21:26 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "stream"
19#include "utils/Log.h"
20
Andreas Huber52b52cd2010-11-23 11:41:34 -080021#include <binder/ProcessState.h>
22
23#include <media/IStreamSource.h>
24#include <media/mediaplayer.h>
25#include <media/stagefright/foundation/ADebug.h>
Andreas Huberae9d5072010-12-06 10:36:06 -080026#include <media/stagefright/foundation/AMessage.h>
Andreas Hubereb916302011-06-27 15:48:18 -070027#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>
Andreas Huber52b52cd2010-11-23 11:41:34 -080032
33#include <binder/IServiceManager.h>
34#include <media/IMediaPlayerService.h>
35#include <surfaceflinger/ISurfaceComposer.h>
36#include <surfaceflinger/SurfaceComposerClient.h>
37
38#include <fcntl.h>
39
40using namespace android;
41
42struct MyStreamSource : public BnStreamSource {
Andreas Hubereb916302011-06-27 15:48:18 -070043 // Object assumes ownership of fd.
Andreas Huber52b52cd2010-11-23 11:41:34 -080044 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;
Andreas Hubera1587462010-12-15 15:17:42 -080056 off64_t mFileSize;
Andreas Huberced159b2011-08-25 12:21:26 -070057 uint64_t mNumPacketsSent;
Andreas Huber52b52cd2010-11-23 11:41:34 -080058
59 sp<IStreamListener> mListener;
60 Vector<sp<IMemory> > mBuffers;
61
62 DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource);
63};
64
65MyStreamSource::MyStreamSource(int fd)
Andreas Hubera1587462010-12-15 15:17:42 -080066 : mFd(fd),
67 mFileSize(0),
Andreas Huberced159b2011-08-25 12:21:26 -070068 mNumPacketsSent(0) {
Andreas Huber52b52cd2010-11-23 11:41:34 -080069 CHECK_GE(fd, 0);
Andreas Hubera1587462010-12-15 15:17:42 -080070
71 mFileSize = lseek64(fd, 0, SEEK_END);
72 lseek64(fd, 0, SEEK_SET);
Andreas Huber52b52cd2010-11-23 11:41:34 -080073}
74
75MyStreamSource::~MyStreamSource() {
Andreas Hubereb916302011-06-27 15:48:18 -070076 close(mFd);
77 mFd = -1;
Andreas Huber52b52cd2010-11-23 11:41:34 -080078}
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());
Andreas Hubera1587462010-12-15 15:17:42 -080090
Andreas Huberced159b2011-08-25 12:21:26 -070091#if 0
92 if (mNumPacketsSent >= 20000) {
Steve Block6215d3f2012-01-04 20:05:49 +000093 ALOGI("signalling discontinuity now");
Andreas Huberced159b2011-08-25 12:21:26 -070094
95 off64_t offset = 0;
96 CHECK((offset % 188) == 0);
Andreas Hubera1587462010-12-15 15:17:42 -080097
98 lseek(mFd, offset, SEEK_SET);
99
Andreas Huberced159b2011-08-25 12:21:26 -0700100 sp<AMessage> extra = new AMessage;
101 extra->setInt32(IStreamListener::kKeyFormatChange, 0);
Andreas Hubera1587462010-12-15 15:17:42 -0800102
Andreas Huberced159b2011-08-25 12:21:26 -0700103 mListener->issueCommand(
104 IStreamListener::DISCONTINUITY, false /* synchronous */, extra);
105
106 mNumPacketsSent = 0;
Andreas Hubera1587462010-12-15 15:17:42 -0800107 }
Andreas Huberced159b2011-08-25 12:21:26 -0700108#endif
Andreas Hubera1587462010-12-15 15:17:42 -0800109
Andreas Huber52b52cd2010-11-23 11:41:34 -0800110 sp<IMemory> mem = mBuffers.itemAt(index);
111
112 ssize_t n = read(mFd, mem->pointer(), mem->size());
113 if (n <= 0) {
Andreas Huberae9d5072010-12-06 10:36:06 -0800114 mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
Andreas Huber52b52cd2010-11-23 11:41:34 -0800115 } else {
116 mListener->queueBuffer(index, n);
Andreas Huberced159b2011-08-25 12:21:26 -0700117
118 mNumPacketsSent += n / 188;
Andreas Huber52b52cd2010-11-23 11:41:34 -0800119 }
120}
Andreas Hubereb916302011-06-27 15:48:18 -0700121////////////////////////////////////////////////////////////////////////////////
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}
Andreas Huber52b52cd2010-11-23 11:41:34 -0800258
259////////////////////////////////////////////////////////////////////////////////
260
261struct MyClient : public BnMediaPlayerClient {
262 MyClient()
263 : mEOS(false) {
264 }
265
Gloria Wang162ee492011-04-11 17:23:27 -0700266 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
Andreas Huber52b52cd2010-11-23 11:41:34 -0800267 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
Andreas Hubereb916302011-06-27 15:48:18 -0700298 DataSource::RegisterDefaultSniffers();
299
Andreas Huber52b52cd2010-11-23 11:41:34 -0800300 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
Andreas Huberced159b2011-08-25 12:21:26 -0700308 ssize_t displayWidth = composerClient->getDisplayWidth(0);
309 ssize_t displayHeight = composerClient->getDisplayHeight(0);
310
Steve Block71f2cf12011-10-20 11:56:00 +0100311 ALOGV("display is %d x %d\n", displayWidth, displayHeight);
Andreas Huberced159b2011-08-25 12:21:26 -0700312
Andreas Huber52b52cd2010-11-23 11:41:34 -0800313 sp<SurfaceControl> control =
314 composerClient->createSurface(
Andreas Huber52b52cd2010-11-23 11:41:34 -0800315 String8("A Surface"),
316 0,
Andreas Huberced159b2011-08-25 12:21:26 -0700317 displayWidth,
318 displayHeight,
Andreas Huber52b52cd2010-11-23 11:41:34 -0800319 PIXEL_FORMAT_RGB_565,
320 0);
321
322 CHECK(control != NULL);
323 CHECK(control->isValid());
324
Mathias Agopian439863f2011-06-28 19:09:31 -0700325 SurfaceComposerClient::openGlobalTransaction();
Andreas Huberc5a97662011-09-15 12:42:32 -0700326 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
Andreas Huber52b52cd2010-11-23 11:41:34 -0800327 CHECK_EQ(control->show(), (status_t)OK);
Mathias Agopian439863f2011-06-28 19:09:31 -0700328 SurfaceComposerClient::closeGlobalTransaction();
Andreas Huber52b52cd2010-11-23 11:41:34 -0800329
330 sp<Surface> surface = control->getSurface();
331 CHECK(surface != NULL);
332
333 sp<IServiceManager> sm = defaultServiceManager();
334 sp<IBinder> binder = sm->getService(String16("media.player"));
335 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
336
337 CHECK(service.get() != NULL);
338
Andreas Huber52b52cd2010-11-23 11:41:34 -0800339 sp<MyClient> client = new MyClient;
340
Andreas Hubereb916302011-06-27 15:48:18 -0700341 sp<IStreamSource> source;
342
343 size_t len = strlen(argv[1]);
344 if (len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) {
345 int fd = open(argv[1], O_RDONLY);
346
347 if (fd < 0) {
348 fprintf(stderr, "Failed to open file '%s'.", argv[1]);
349 return 1;
350 }
351
352 source = new MyStreamSource(fd);
353 } else {
354 printf("Converting file to transport stream for streaming...\n");
355
356 source = new MyConvertingStreamSource(argv[1]);
357 }
358
Andreas Huber52b52cd2010-11-23 11:41:34 -0800359 sp<IMediaPlayer> player =
Dave Burkefc301b02011-08-30 14:39:17 +0100360 service->create(getpid(), client, 0);
Andreas Huber52b52cd2010-11-23 11:41:34 -0800361
Dave Burkefc301b02011-08-30 14:39:17 +0100362 if (player != NULL && player->setDataSource(source) == NO_ERROR) {
Andreas Huber95be2452011-10-25 13:45:00 -0700363 player->setVideoSurfaceTexture(surface->getSurfaceTexture());
Andreas Huber52b52cd2010-11-23 11:41:34 -0800364 player->start();
365
366 client->waitForEOS();
367
368 player->stop();
369 } else {
370 fprintf(stderr, "failed to instantiate player.\n");
371 }
372
Andreas Huber52b52cd2010-11-23 11:41:34 -0800373 composerClient->dispose();
374
375 return 0;
376}