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