stream.cpp revision 3901e5d87573447db33fb9930871a1f5266a9b2c
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 <surfaceflinger/ISurfaceComposer.h>
36#include <surfaceflinger/SurfaceComposerClient.h>
37
38#include <fcntl.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        LOGI("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    ssize_t displayWidth = composerClient->getDisplayWidth(0);
309    ssize_t displayHeight = composerClient->getDisplayHeight(0);
310
311    LOGV("display is %d x %d\n", displayWidth, displayHeight);
312
313    sp<SurfaceControl> control =
314        composerClient->createSurface(
315                String8("A Surface"),
316                0,
317                displayWidth,
318                displayHeight,
319                PIXEL_FORMAT_RGB_565,
320                0);
321
322    CHECK(control != NULL);
323    CHECK(control->isValid());
324
325    SurfaceComposerClient::openGlobalTransaction();
326    CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
327    CHECK_EQ(control->show(), (status_t)OK);
328    SurfaceComposerClient::closeGlobalTransaction();
329
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
339    sp<MyClient> client = new MyClient;
340
341    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
359    sp<IMediaPlayer> player =
360        service->create(getpid(), client, 0);
361
362    if (player != NULL && player->setDataSource(source) == NO_ERROR) {
363        player->setVideoSurfaceTexture(surface->getSurfaceTexture());
364        player->start();
365
366        client->waitForEOS();
367
368        player->stop();
369    } else {
370        fprintf(stderr, "failed to instantiate player.\n");
371    }
372
373    composerClient->dispose();
374
375    return 0;
376}
377