JPEGSource.cpp revision 7530e9c708275c273c134c36c68179f511c1940e
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 "JPEGSource.h" 22 23#include <media/stagefright/DataSource.h> 24#include <media/stagefright/MediaBufferGroup.h> 25#include <media/stagefright/MediaDebug.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(), 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, "image/jpeg"); 103 meta->setInt32(kKeyWidth, mWidth); 104 meta->setInt32(kKeyHeight, mHeight); 105 meta->setInt32(kKeyCompressedSize, 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 if (options != NULL && options->getSeekTo(&seekTimeUs)) { 116 return UNKNOWN_ERROR; 117 } 118 119 MediaBuffer *buffer; 120 mGroup->acquire_buffer(&buffer); 121 122 ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset); 123 124 if (n <= 0) { 125 buffer->release(); 126 buffer = NULL; 127 128 return UNKNOWN_ERROR; 129 } 130 131 buffer->set_range(0, n); 132 133 mOffset += n; 134 135 *out = buffer; 136 137 return OK; 138} 139 140status_t JPEGSource::parseJPEG() { 141 mWidth = 0; 142 mHeight = 0; 143 144 off_t i = 0; 145 146 uint16_t soi; 147 if (!mSource->getUInt16(i, &soi)) { 148 return ERROR_IO; 149 } 150 151 i += 2; 152 153 if (soi != 0xffd8) { 154 return UNKNOWN_ERROR; 155 } 156 157 for (;;) { 158 uint8_t marker; 159 if (mSource->read_at(i++, &marker, 1) != 1) { 160 return ERROR_IO; 161 } 162 163 CHECK_EQ(marker, 0xff); 164 165 if (mSource->read_at(i++, &marker, 1) != 1) { 166 return ERROR_IO; 167 } 168 169 CHECK(marker != 0xff); 170 171 uint16_t chunkSize; 172 if (!mSource->getUInt16(i, &chunkSize)) { 173 return ERROR_IO; 174 } 175 176 i += 2; 177 178 if (chunkSize < 2) { 179 return UNKNOWN_ERROR; 180 } 181 182 switch (marker) { 183 case JPEG_SOS: 184 { 185 return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR; 186 } 187 188 case JPEG_EOI: 189 { 190 return UNKNOWN_ERROR; 191 } 192 193 case JPEG_SOF0: 194 case JPEG_SOF1: 195 case JPEG_SOF3: 196 case JPEG_SOF5: 197 case JPEG_SOF6: 198 case JPEG_SOF7: 199 case JPEG_SOF9: 200 case JPEG_SOF10: 201 case JPEG_SOF11: 202 case JPEG_SOF13: 203 case JPEG_SOF14: 204 case JPEG_SOF15: 205 { 206 uint16_t width, height; 207 if (!mSource->getUInt16(i + 1, &height) 208 || !mSource->getUInt16(i + 3, &width)) { 209 return ERROR_IO; 210 } 211 212 mWidth = width; 213 mHeight = height; 214 215 i += chunkSize - 2; 216 break; 217 } 218 219 default: 220 { 221 // Skip chunk 222 223 i += chunkSize - 2; 224 225 break; 226 } 227 } 228 } 229 230 return OK; 231} 232 233} // namespace android 234