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 53namespace android { 54 55JPEGSource::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 67JPEGSource::~JPEGSource() { 68 if (mStarted) { 69 stop(); 70 } 71} 72 73status_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 88status_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 101sp<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 111status_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 142status_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