1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // Based on LGPL MJPEG/AVI to JPEG/JFIF conversion code from libav
24 // Copyright (c) 2010 Adrian Daerr and Nicolas George
25 // That in turn was adapted from mjpeg2jpeg.c, with original copyright:
26 // Paris 2010 Adrian Daerr, public domain
27
28 #include "common/memstream.h"
29 #include "common/system.h"
30 #include "common/textconsole.h"
31 #include "graphics/surface.h"
32 #include "image/jpeg.h"
33
34 #include "image/codecs/mjpeg.h"
35
36 namespace Common {
37 class SeekableReadStream;
38 }
39
40 namespace Image {
41
MJPEGDecoder()42 MJPEGDecoder::MJPEGDecoder() : Codec() {
43 _pixelFormat = g_system->getScreenFormat();
44 _surface = 0;
45 }
46
~MJPEGDecoder()47 MJPEGDecoder::~MJPEGDecoder() {
48 if (_surface) {
49 _surface->free();
50 delete _surface;
51 }
52 }
53
54 // Header to be inserted
55 static const byte s_jpegHeader[] = {
56 0xff, 0xd8, // SOI
57 0xff, 0xe0, // APP0
58 0x00, 0x10, // APP0 header size (including
59 // this field, but excluding preceding)
60 'J', 'F', 'I', 'F', 0x00, // ID string 'JFIF\0'
61 0x01, 0x01, // version
62 0x00, // bits per type
63 0x00, 0x00, // X density
64 0x00, 0x00, // Y density
65 0x00, // X thumbnail size
66 0x00
67 };
68
69 enum {
70 DHT_SEGMENT_SIZE = 420
71 };
72
73 static const byte s_dhtSegmentHead[] = { 0xFF, 0xC4, 0x01, 0xA2, 0x00 };
74 static const byte s_dhtSegmentFrag[] = {
75 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
76 0x0a, 0x0b, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
77 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
78 };
79
80 // Set up the standard Huffman tables (cf. JPEG standard section K.3)
81 // IMPORTANT: these are only valid for 8-bit data precision!
82 static const byte s_mjpegBitsDCLuminance[17] = {
83 /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
84 };
85
86 static const byte s_mjpegValDC[12] = {
87 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
88 };
89
90 #if 0
91 static const byte s_mjpegBitsDCChrominance[17] = {
92 /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
93 };
94 #endif
95
96 static const byte s_mjpegBitsACLuminance[17] = {
97 /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
98 };
99
100 static const byte s_mjpegValACLuminance[] = {
101 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
102 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
103 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
104 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
105 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
106 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
107 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
108 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
109 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
110 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
111 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
112 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
113 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
114 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
115 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
116 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
117 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
118 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
119 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
120 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
121 0xf9, 0xfa
122 };
123
124 static const byte s_mjpegBitsACChrominance[17] = {
125 /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
126 };
127
128 static const byte s_mjpegValACChrominance[] = {
129 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
130 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
131 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
132 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
133 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
134 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
135 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
136 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
137 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
138 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
139 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
140 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
141 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
142 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
143 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
144 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
145 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
146 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
147 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
148 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
149 0xf9, 0xfa
150 };
151
decodeFrame(Common::SeekableReadStream & stream)152 const Graphics::Surface *MJPEGDecoder::decodeFrame(Common::SeekableReadStream &stream) {
153 // We need to reconstruct an actual JPEG stream here, then feed it to the JPEG decoder
154 // Yes, this is a pain.
155
156 stream.readUint32BE(); // Skip nonsense JPEG header
157 uint16 inputSkip = stream.readUint16BE() + 4;
158 uint32 tag = stream.readUint32BE();
159
160 if (tag != MKTAG('A', 'V', 'I', '1')) {
161 warning("Invalid MJPEG tag found");
162 return 0;
163 }
164
165 uint32 outputSize = stream.size() - inputSkip + sizeof(s_jpegHeader) + DHT_SEGMENT_SIZE;
166 byte *data = (byte *)malloc(outputSize);
167
168 if (!data) {
169 warning("Failed to allocate data for MJPEG conversion");
170 return 0;
171 }
172
173 // Copy the header
174 memcpy(data, s_jpegHeader, sizeof(s_jpegHeader));
175 uint32 dataOffset = sizeof(s_jpegHeader);
176
177 // Write the fake DHT segment
178 memcpy(data + dataOffset, s_dhtSegmentHead, sizeof(s_dhtSegmentHead));
179 dataOffset += sizeof(s_dhtSegmentHead);
180 memcpy(data + dataOffset, s_mjpegBitsDCLuminance + 1, 16);
181 dataOffset += 16;
182 memcpy(data + dataOffset, s_dhtSegmentFrag, sizeof(s_dhtSegmentFrag));
183 dataOffset += sizeof(s_dhtSegmentFrag);
184 memcpy(data + dataOffset, s_mjpegValDC, 12);
185 dataOffset += 12;
186 data[dataOffset++] = 0x10;
187 memcpy(data + dataOffset, s_mjpegBitsACLuminance + 1, 16);
188 dataOffset += 16;
189 memcpy(data + dataOffset, s_mjpegValACLuminance, 162);
190 dataOffset += 162;
191 data[dataOffset++] = 0x11;
192 memcpy(data + dataOffset, s_mjpegBitsACChrominance + 1, 16);
193 dataOffset += 16;
194 memcpy(data + dataOffset, s_mjpegValACChrominance, 162);
195 dataOffset += 162;
196
197 // Write the actual data
198 stream.seek(inputSkip);
199 stream.read(data + dataOffset, stream.size() - inputSkip);
200
201 Common::MemoryReadStream convertedStream(data, outputSize, DisposeAfterUse::YES);
202 JPEGDecoder jpeg;
203 jpeg.setOutputPixelFormat(_pixelFormat);
204
205 if (!jpeg.loadStream(convertedStream)) {
206 warning("Failed to decode MJPEG frame");
207 return 0;
208 }
209
210 if (_surface) {
211 _surface->free();
212 delete _surface;
213 }
214
215 _surface = new Graphics::Surface();
216 _surface->copyFrom(*jpeg.getSurface());
217
218 assert(_surface->format == _pixelFormat);
219
220 return _surface;
221 }
222
223 } // End of namespace Image
224