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