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