stagefright.cpp revision 693d271e62a3726689ff68f4505ba49228eb94b2
1/*
2 * Copyright (C) 2009 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 <sys/time.h>
18
19#include <pthread.h>
20#include <stdlib.h>
21
22#include <binder/IServiceManager.h>
23#include <binder/ProcessState.h>
24#include <media/IMediaPlayerService.h>
25#include <media/stagefright/AudioPlayer.h>
26#include <media/stagefright/CachingDataSource.h>
27#include <media/stagefright/ESDS.h>
28#include <media/stagefright/FileSource.h>
29#include <media/stagefright/MediaBuffer.h>
30#include <media/stagefright/MediaBufferGroup.h>
31#include <media/stagefright/MediaDebug.h>
32#include <media/stagefright/MediaPlayerImpl.h>
33#include <media/stagefright/MediaExtractor.h>
34#include <media/stagefright/MediaSource.h>
35#include <media/stagefright/MetaData.h>
36#include <media/stagefright/MmapSource.h>
37#include <media/stagefright/OMXClient.h>
38#include <media/stagefright/OMXCodec.h>
39#include <media/stagefright/OMXDecoder.h>
40
41#include "WaveWriter.h"
42
43using namespace android;
44
45////////////////////////////////////////////////////////////////////////////////
46
47struct JPEGSource : public MediaSource {
48    // Assumes ownership of "source".
49    JPEGSource(const sp<DataSource> &source);
50
51    virtual status_t start(MetaData *params = NULL);
52    virtual status_t stop();
53    virtual sp<MetaData> getFormat();
54
55    virtual status_t read(
56            MediaBuffer **buffer, const ReadOptions *options = NULL);
57
58protected:
59    virtual ~JPEGSource();
60
61private:
62    sp<DataSource> mSource;
63    MediaBufferGroup *mGroup;
64    bool mStarted;
65    off_t mSize;
66    int32_t mWidth, mHeight;
67    off_t mOffset;
68
69    status_t parseJPEG();
70
71    JPEGSource(const JPEGSource &);
72    JPEGSource &operator=(const JPEGSource &);
73};
74
75JPEGSource::JPEGSource(const sp<DataSource> &source)
76    : mSource(source),
77      mGroup(NULL),
78      mStarted(false),
79      mSize(0),
80      mWidth(0),
81      mHeight(0),
82      mOffset(0) {
83    CHECK_EQ(parseJPEG(), OK);
84}
85
86JPEGSource::~JPEGSource() {
87    if (mStarted) {
88        stop();
89    }
90}
91
92status_t JPEGSource::start(MetaData *) {
93    if (mStarted) {
94        return UNKNOWN_ERROR;
95    }
96
97    if (mSource->getSize(&mSize) != OK) {
98        return UNKNOWN_ERROR;
99    }
100
101    mGroup = new MediaBufferGroup;
102    mGroup->add_buffer(new MediaBuffer(mSize));
103
104    mOffset = 0;
105
106    mStarted = true;
107
108    return OK;
109}
110
111status_t JPEGSource::stop() {
112    if (!mStarted) {
113        return UNKNOWN_ERROR;
114    }
115
116    delete mGroup;
117    mGroup = NULL;
118
119    mStarted = false;
120
121    return OK;
122}
123
124sp<MetaData> JPEGSource::getFormat() {
125    sp<MetaData> meta = new MetaData;
126    meta->setCString(kKeyMIMEType, "image/jpeg");
127    meta->setInt32(kKeyWidth, mWidth);
128    meta->setInt32(kKeyHeight, mHeight);
129
130    return meta;
131}
132
133status_t JPEGSource::read(
134        MediaBuffer **out, const ReadOptions *options) {
135    *out = NULL;
136
137    int64_t seekTimeUs;
138    if (options != NULL && options->getSeekTo(&seekTimeUs)) {
139        return UNKNOWN_ERROR;
140    }
141
142    MediaBuffer *buffer;
143    mGroup->acquire_buffer(&buffer);
144
145    ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset);
146
147    if (n <= 0) {
148        buffer->release();
149        buffer = NULL;
150
151        return UNKNOWN_ERROR;
152    }
153
154    buffer->set_range(0, n);
155
156    mOffset += n;
157
158    *out = buffer;
159
160    return OK;
161}
162
163#define JPEG_SOF0  0xC0            /* nStart Of Frame N*/
164#define JPEG_SOF1  0xC1            /* N indicates which compression process*/
165#define JPEG_SOF2  0xC2            /* Only SOF0-SOF2 are now in common use*/
166#define JPEG_SOF3  0xC3
167#define JPEG_SOF5  0xC5            /* NB: codes C4 and CC are NOT SOF markers*/
168#define JPEG_SOF6  0xC6
169#define JPEG_SOF7  0xC7
170#define JPEG_SOF9  0xC9
171#define JPEG_SOF10 0xCA
172#define JPEG_SOF11 0xCB
173#define JPEG_SOF13 0xCD
174#define JPEG_SOF14 0xCE
175#define JPEG_SOF15 0xCF
176#define JPEG_SOI   0xD8            /* nStart Of Image (beginning of datastream)*/
177#define JPEG_EOI   0xD9            /* End Of Image (end of datastream)*/
178#define JPEG_SOS   0xDA            /* nStart Of Scan (begins compressed data)*/
179#define JPEG_JFIF  0xE0            /* Jfif marker*/
180#define JPEG_EXIF  0xE1            /* Exif marker*/
181#define JPEG_COM   0xFE            /* COMment */
182#define JPEG_DQT   0xDB
183#define JPEG_DHT   0xC4
184#define JPEG_DRI   0xDD
185
186status_t JPEGSource::parseJPEG() {
187    mWidth = 0;
188    mHeight = 0;
189
190    off_t i = 0;
191
192    uint16_t soi;
193    if (!mSource->getUInt16(i, &soi)) {
194        return ERROR_IO;
195    }
196
197    i += 2;
198
199    if (soi != 0xffd8) {
200        return UNKNOWN_ERROR;
201    }
202
203    for (;;) {
204        uint8_t marker;
205        if (mSource->read_at(i++, &marker, 1) != 1) {
206            return ERROR_IO;
207        }
208
209        CHECK_EQ(marker, 0xff);
210
211        if (mSource->read_at(i++, &marker, 1) != 1) {
212            return ERROR_IO;
213        }
214
215        CHECK(marker != 0xff);
216
217        uint16_t chunkSize;
218        if (!mSource->getUInt16(i, &chunkSize)) {
219            return ERROR_IO;
220        }
221
222        i += 2;
223
224        if (chunkSize < 2) {
225            return UNKNOWN_ERROR;
226        }
227
228        switch (marker) {
229            case JPEG_SOS:
230            {
231                return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR;
232            }
233
234            case JPEG_EOI:
235            {
236                return UNKNOWN_ERROR;
237            }
238
239            case JPEG_SOF0:
240            case JPEG_SOF1:
241            case JPEG_SOF3:
242            case JPEG_SOF5:
243            case JPEG_SOF6:
244            case JPEG_SOF7:
245            case JPEG_SOF9:
246            case JPEG_SOF10:
247            case JPEG_SOF11:
248            case JPEG_SOF13:
249            case JPEG_SOF14:
250            case JPEG_SOF15:
251            {
252                uint16_t width, height;
253                if (!mSource->getUInt16(i + 1, &height)
254                    || !mSource->getUInt16(i + 3, &width)) {
255                    return ERROR_IO;
256                }
257
258                mWidth = width;
259                mHeight = height;
260
261                i += chunkSize - 2;
262                break;
263            }
264
265            default:
266            {
267                // Skip chunk
268
269                i += chunkSize - 2;
270
271                break;
272            }
273        }
274    }
275
276    return OK;
277}
278
279////////////////////////////////////////////////////////////////////////////////
280
281static int64_t getNowUs() {
282    struct timeval tv;
283    gettimeofday(&tv, NULL);
284
285    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
286}
287
288#define USE_OMX_CODEC   1
289
290static void playSource(OMXClient *client, const sp<MediaSource> &source) {
291    sp<MetaData> meta = source->getFormat();
292
293#if !USE_OMX_CODEC
294    sp<OMXDecoder> decoder = OMXDecoder::Create(
295            client, meta, false /* createEncoder */, source);
296#else
297    sp<OMXCodec> decoder = OMXCodec::Create(
298            client->interface(), meta, false /* createEncoder */, source);
299#endif
300
301    if (decoder == NULL) {
302        return;
303    }
304
305    decoder->start();
306
307    int64_t startTime = getNowUs();
308
309    int n = 0;
310    MediaBuffer *buffer;
311    status_t err;
312    while ((err = decoder->read(&buffer)) == OK) {
313        if ((++n % 16) == 0) {
314            printf(".");
315            fflush(stdout);
316        }
317
318        buffer->release();
319        buffer = NULL;
320    }
321    decoder->stop();
322    printf("\n");
323
324    int64_t delay = getNowUs() - startTime;
325    printf("avg. %.2f fps\n", n * 1E6 / delay);
326
327    printf("decoded a total of %d frame(s).\n", n);
328}
329
330int main(int argc, char **argv) {
331    android::ProcessState::self()->startThreadPool();
332
333    bool audioOnly = false;
334    if (argc > 1 && !strcmp(argv[1], "--list")) {
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<IOMX> omx = service->createOMX();
342        CHECK(omx.get() != NULL);
343
344        List<String8> list;
345        omx->list_nodes(&list);
346
347        for (List<String8>::iterator it = list.begin();
348             it != list.end(); ++it) {
349            printf("%s\n", (*it).string());
350        }
351
352        return 0;
353    } else if (argc > 1 && !strcmp(argv[1], "--audio")) {
354        audioOnly = true;
355        ++argv;
356        --argc;
357    }
358
359    DataSource::RegisterDefaultSniffers();
360
361    OMXClient client;
362    status_t err = client.connect();
363
364    sp<MmapSource> dataSource = new MmapSource(argv[1]);
365
366    bool isJPEG = false;
367
368    size_t len = strlen(argv[1]);
369    if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) {
370        isJPEG = true;
371    }
372
373    sp<MediaSource> mediaSource;
374
375    if (isJPEG) {
376        mediaSource = new JPEGSource(dataSource);
377    } else {
378        sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
379
380        size_t numTracks = extractor->countTracks();
381
382        sp<MetaData> meta;
383        size_t i;
384        for (i = 0; i < numTracks; ++i) {
385            meta = extractor->getTrackMetaData(i);
386
387            const char *mime;
388            meta->findCString(kKeyMIMEType, &mime);
389
390            if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
391                break;
392            }
393
394            if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
395                break;
396            }
397        }
398
399        mediaSource = extractor->getTrack(i);
400    }
401
402    playSource(&client, mediaSource);
403
404    client.disconnect();
405
406    return 0;
407}
408