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// #define LOG_NDEBUG   0
18#define LOG_TAG "JPEGSource"
19#include <utils/Log.h>
20
21#include <media/stagefright/foundation/ADebug.h>
22#include <media/stagefright/DataSource.h>
23#include <media/stagefright/JPEGSource.h>
24#include <media/stagefright/MediaBufferGroup.h>
25#include <media/stagefright/MediaDefs.h>
26#include <media/stagefright/MediaErrors.h>
27#include <media/stagefright/MetaData.h>
28
29#define JPEG_SOF0  0xC0            /* nStart Of Frame N*/
30#define JPEG_SOF1  0xC1            /* N indicates which compression process*/
31#define JPEG_SOF2  0xC2            /* Only SOF0-SOF2 are now in common use*/
32#define JPEG_SOF3  0xC3
33#define JPEG_SOF5  0xC5            /* NB: codes C4 and CC are NOT SOF markers*/
34#define JPEG_SOF6  0xC6
35#define JPEG_SOF7  0xC7
36#define JPEG_SOF9  0xC9
37#define JPEG_SOF10 0xCA
38#define JPEG_SOF11 0xCB
39#define JPEG_SOF13 0xCD
40#define JPEG_SOF14 0xCE
41#define JPEG_SOF15 0xCF
42#define JPEG_SOI   0xD8            /* nStart Of Image (beginning of datastream)*/
43#define JPEG_EOI   0xD9            /* End Of Image (end of datastream)*/
44#define JPEG_SOS   0xDA            /* nStart Of Scan (begins compressed data)*/
45#define JPEG_JFIF  0xE0            /* Jfif marker*/
46#define JPEG_EXIF  0xE1            /* Exif marker*/
47#define JPEG_COM   0xFE            /* COMment */
48#define JPEG_DQT   0xDB
49#define JPEG_DHT   0xC4
50#define JPEG_DRI   0xDD
51
52namespace android {
53
54JPEGSource::JPEGSource(const sp<DataSource> &source)
55    : mSource(source),
56      mGroup(NULL),
57      mStarted(false),
58      mSize(0),
59      mWidth(0),
60      mHeight(0),
61      mOffset(0) {
62    CHECK_EQ(parseJPEG(), (status_t)OK);
63    CHECK(mSource->getSize(&mSize) == OK);
64}
65
66JPEGSource::~JPEGSource() {
67    if (mStarted) {
68        stop();
69    }
70}
71
72status_t JPEGSource::start(MetaData *) {
73    if (mStarted) {
74        return UNKNOWN_ERROR;
75    }
76
77    mGroup = new MediaBufferGroup;
78    mGroup->add_buffer(new MediaBuffer(mSize));
79
80    mOffset = 0;
81
82    mStarted = true;
83
84    return OK;
85}
86
87status_t JPEGSource::stop() {
88    if (!mStarted) {
89        return UNKNOWN_ERROR;
90    }
91
92    delete mGroup;
93    mGroup = NULL;
94
95    mStarted = false;
96
97    return OK;
98}
99
100sp<MetaData> JPEGSource::getFormat() {
101    sp<MetaData> meta = new MetaData;
102    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_JPEG);
103    meta->setInt32(kKeyWidth, mWidth);
104    meta->setInt32(kKeyHeight, mHeight);
105    meta->setInt32(kKeyMaxInputSize, mSize);
106
107    return meta;
108}
109
110status_t JPEGSource::read(
111        MediaBuffer **out, const ReadOptions *options) {
112    *out = NULL;
113
114    int64_t seekTimeUs;
115    ReadOptions::SeekMode mode;
116    if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
117        return UNKNOWN_ERROR;
118    }
119
120    MediaBuffer *buffer;
121    mGroup->acquire_buffer(&buffer);
122
123    ssize_t n = mSource->readAt(mOffset, buffer->data(), mSize - mOffset);
124
125    if (n <= 0) {
126        buffer->release();
127        buffer = NULL;
128
129        return UNKNOWN_ERROR;
130    }
131
132    buffer->set_range(0, n);
133
134    mOffset += n;
135
136    *out = buffer;
137
138    return OK;
139}
140
141status_t JPEGSource::parseJPEG() {
142    mWidth = 0;
143    mHeight = 0;
144
145    off64_t i = 0;
146
147    uint16_t soi;
148    if (!mSource->getUInt16(i, &soi)) {
149        return ERROR_IO;
150    }
151
152    i += 2;
153
154    if (soi != 0xffd8) {
155        return UNKNOWN_ERROR;
156    }
157
158    for (;;) {
159        uint8_t marker;
160        if (mSource->readAt(i++, &marker, 1) != 1) {
161            return ERROR_IO;
162        }
163
164        CHECK_EQ(marker, 0xff);
165
166        if (mSource->readAt(i++, &marker, 1) != 1) {
167            return ERROR_IO;
168        }
169
170        CHECK(marker != 0xff);
171
172        uint16_t chunkSize;
173        if (!mSource->getUInt16(i, &chunkSize)) {
174            return ERROR_IO;
175        }
176
177        i += 2;
178
179        if (chunkSize < 2) {
180            return UNKNOWN_ERROR;
181        }
182
183        switch (marker) {
184            case JPEG_SOS:
185            {
186                return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR;
187            }
188
189            case JPEG_EOI:
190            {
191                return UNKNOWN_ERROR;
192            }
193
194            case JPEG_SOF0:
195            case JPEG_SOF1:
196            case JPEG_SOF3:
197            case JPEG_SOF5:
198            case JPEG_SOF6:
199            case JPEG_SOF7:
200            case JPEG_SOF9:
201            case JPEG_SOF10:
202            case JPEG_SOF11:
203            case JPEG_SOF13:
204            case JPEG_SOF14:
205            case JPEG_SOF15:
206            {
207                uint16_t width, height;
208                if (!mSource->getUInt16(i + 1, &height)
209                    || !mSource->getUInt16(i + 3, &width)) {
210                    return ERROR_IO;
211                }
212
213                mWidth = width;
214                mHeight = height;
215
216                i += chunkSize - 2;
217                break;
218            }
219
220            default:
221            {
222                // Skip chunk
223
224                i += chunkSize - 2;
225
226                break;
227            }
228        }
229    }
230
231    return OK;
232}
233
234}  // namespace android
235