FFmpeg
Loading...
Searching...
No Matches
cbs_jpeg.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include "libavutil/mem.h"
20#include "cbs.h"
21#include "cbs_internal.h"
22#include "cbs_jpeg.h"
23
24
25#define HEADER(name) do { \
26 ff_cbs_trace_header(ctx, name); \
27 } while (0)
28
29#define CHECK(call) do { \
30 err = (call); \
31 if (err < 0) \
32 return err; \
33 } while (0)
34
35#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
36
37#define u(width, name, range_min, range_max) \
38 xu(width, name, range_min, range_max, 0, )
39#define us(width, name, sub, range_min, range_max) \
40 xu(width, name, range_min, range_max, 1, sub)
41
42
43#define READ
44#define READWRITE read
45#define RWContext GetBitContext
46#define FUNC(name) cbs_jpeg_read_ ## name
47
48#define xu(width, name, range_min, range_max, subs, ...) do { \
49 uint32_t value; \
50 CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
51 SUBSCRIPTS(subs, __VA_ARGS__), \
52 &value, range_min, range_max)); \
53 current->name = value; \
54 } while (0)
55
57
58#undef READ
59#undef READWRITE
60#undef RWContext
61#undef FUNC
62#undef xu
63
64#define WRITE
65#define READWRITE write
66#define RWContext PutBitContext
67#define FUNC(name) cbs_jpeg_write_ ## name
68
69#define xu(width, name, range_min, range_max, subs, ...) do { \
70 uint32_t value = current->name; \
71 CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
72 SUBSCRIPTS(subs, __VA_ARGS__), \
73 value, range_min, range_max)); \
74 } while (0)
75
76
78
79#undef WRITE
80#undef READWRITE
81#undef RWContext
82#undef FUNC
83#undef xu
84
85
88 int header)
89{
90 AVBufferRef *data_ref;
91 uint8_t *data;
92 size_t data_size;
93 int start, end, marker, next_start, next_marker;
94 int err, i, j, length;
95
96 if (frag->data_size < 4) {
97 // Definitely too short to be meaningful.
99 }
100
101 for (i = 0; i + 1 < frag->data_size && frag->data[i] != 0xff; i++);
102 if (i > 0) {
103 av_log(ctx->log_ctx, AV_LOG_WARNING, "Discarding %d bytes at "
104 "beginning of image.\n", i);
105 }
106 for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++);
107 if (i + 1 >= frag->data_size && frag->data[i]) {
108 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
109 "no SOI marker found.\n");
110 return AVERROR_INVALIDDATA;
111 }
112 marker = frag->data[i];
113 if (marker != JPEG_MARKER_SOI) {
114 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: first "
115 "marker is %02x, should be SOI.\n", marker);
116 return AVERROR_INVALIDDATA;
117 }
118 for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++);
119 if (i + 1 >= frag->data_size) {
120 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
121 "no image content found.\n");
122 return AVERROR_INVALIDDATA;
123 }
124 marker = frag->data[i];
125 start = i + 1;
126
127 do {
128 if (marker == JPEG_MARKER_EOI) {
129 break;
130 } else if (marker == JPEG_MARKER_SOS) {
131 next_marker = -1;
132 end = start;
133 for (i = start; i + 1 < frag->data_size; i++) {
134 if (frag->data[i] != 0xff)
135 continue;
136 end = i;
137 for (++i; i + 1 < frag->data_size &&
138 frag->data[i] == 0xff; i++);
139 if (i + 1 < frag->data_size) {
140 if (frag->data[i] == 0x00)
141 continue;
142 next_marker = frag->data[i];
143 next_start = i + 1;
144 }
145 break;
146 }
147 } else {
148 i = start;
149 if (i > frag->data_size - 2) {
150 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
151 "truncated at %02x marker.\n", marker);
152 return AVERROR_INVALIDDATA;
153 }
154 length = AV_RB16(frag->data + i);
155 if (length > frag->data_size - i) {
156 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
157 "truncated at %02x marker segment.\n", marker);
158 return AVERROR_INVALIDDATA;
159 }
160 end = start + length;
161
162 i = end;
163 if (frag->data[i] != 0xff) {
164 next_marker = -1;
165 } else {
166 for (++i; i + 1 < frag->data_size &&
167 frag->data[i] == 0xff; i++);
168 if (i + 1 >= frag->data_size) {
169 next_marker = -1;
170 } else {
171 next_marker = frag->data[i];
172 next_start = i + 1;
173 }
174 }
175 }
176
177 if (marker == JPEG_MARKER_SOS) {
178 length = AV_RB16(frag->data + start);
179
180 if (length > end - start)
181 return AVERROR_INVALIDDATA;
182
183 data_ref = NULL;
184 data = av_malloc(end - start +
186 if (!data)
187 return AVERROR(ENOMEM);
188
189 memcpy(data, frag->data + start, length);
190 for (i = start + length, j = length; i < end; i++, j++) {
191 if (frag->data[i] == 0xff) {
192 while (frag->data[i] == 0xff)
193 ++i;
194 data[j] = 0xff;
195 } else {
196 data[j] = frag->data[i];
197 }
198 }
199 data_size = j;
200
201 memset(data + data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
202
203 } else {
204 data = frag->data + start;
205 data_size = end - start;
206 data_ref = frag->data_ref;
207 }
208
209 err = ff_cbs_append_unit_data(frag, marker,
210 data, data_size, data_ref);
211 if (err < 0)
212 return err;
213
214 marker = next_marker;
215 start = next_start;
216 } while (next_marker != -1);
217
218 return 0;
219}
220
222 CodedBitstreamUnit *unit)
223{
224 GetBitContext gbc;
225 int err;
226
227 err = init_get_bits(&gbc, unit->data, 8 * unit->data_size);
228 if (err < 0)
229 return err;
230
231 err = ff_cbs_alloc_unit_content(ctx, unit);
232 if (err < 0)
233 return err;
234
235 if (unit->type >= JPEG_MARKER_SOF0 &&
236 unit->type <= JPEG_MARKER_SOF3) {
237 err = cbs_jpeg_read_frame_header(ctx, &gbc, unit->content);
238 if (err < 0)
239 return err;
240
241 } else if (unit->type >= JPEG_MARKER_APPN &&
242 unit->type <= JPEG_MARKER_APPN + 15) {
243 err = cbs_jpeg_read_application_data(ctx, &gbc, unit->content);
244 if (err < 0)
245 return err;
246
247 } else if (unit->type == JPEG_MARKER_SOS) {
248 JPEGRawScan *scan = unit->content;
249 int pos;
250
251 err = cbs_jpeg_read_scan_header(ctx, &gbc, &scan->header);
252 if (err < 0)
253 return err;
254
255 pos = get_bits_count(&gbc);
256 av_assert0(pos % 8 == 0);
257 if (pos > 0) {
258 scan->data_size = unit->data_size - pos / 8;
259 scan->data_ref = av_buffer_ref(unit->data_ref);
260 if (!scan->data_ref)
261 return AVERROR(ENOMEM);
262 scan->data = unit->data + pos / 8;
263 }
264
265 } else {
266 switch (unit->type) {
267#define SEGMENT(marker, func) \
268 case JPEG_MARKER_ ## marker: \
269 { \
270 err = cbs_jpeg_read_ ## func(ctx, &gbc, unit->content); \
271 if (err < 0) \
272 return err; \
273 } \
274 break
275 SEGMENT(DQT, dqt);
276 SEGMENT(DHT, dht);
278#undef SEGMENT
279 default:
280 return AVERROR(ENOSYS);
281 }
282 }
283
284 return 0;
285}
286
288 CodedBitstreamUnit *unit,
289 PutBitContext *pbc)
290{
291 JPEGRawScan *scan = unit->content;
292 int err;
293
294 err = cbs_jpeg_write_scan_header(ctx, pbc, &scan->header);
295 if (err < 0)
296 return err;
297
298 if (scan->data) {
299 if (scan->data_size * 8 > put_bits_left(pbc))
300 return AVERROR(ENOSPC);
301
302 av_assert0(put_bits_count(pbc) % 8 == 0);
303
304 flush_put_bits(pbc);
305
306 memcpy(put_bits_ptr(pbc), scan->data, scan->data_size);
307 skip_put_bytes(pbc, scan->data_size);
308 }
309
310 return 0;
311}
312
314 CodedBitstreamUnit *unit,
315 PutBitContext *pbc)
316{
317 int err;
318
319 if (unit->type >= JPEG_MARKER_SOF0 &&
320 unit->type <= JPEG_MARKER_SOF3) {
321 err = cbs_jpeg_write_frame_header(ctx, pbc, unit->content);
322 } else if (unit->type >= JPEG_MARKER_APPN &&
323 unit->type <= JPEG_MARKER_APPN + 15) {
324 err = cbs_jpeg_write_application_data(ctx, pbc, unit->content);
325 } else {
326 switch (unit->type) {
327#define SEGMENT(marker, func) \
328 case JPEG_MARKER_ ## marker: \
329 err = cbs_jpeg_write_ ## func(ctx, pbc, unit->content); \
330 break;
331 SEGMENT(DQT, dqt);
332 SEGMENT(DHT, dht);
334 default:
336 }
337 }
338
339 return err;
340}
341
343 CodedBitstreamUnit *unit,
344 PutBitContext *pbc)
345{
346 if (unit->type == JPEG_MARKER_SOS)
347 return cbs_jpeg_write_scan (ctx, unit, pbc);
348 else
349 return cbs_jpeg_write_segment(ctx, unit, pbc);
350}
351
354{
355 const CodedBitstreamUnit *unit;
356 uint8_t *data;
357 size_t size, dp, sp;
358 int i;
359
360 size = 4; // SOI + EOI.
361 for (i = 0; i < frag->nb_units; i++) {
362 unit = &frag->units[i];
363 size += 2 + unit->data_size;
364 if (unit->type == JPEG_MARKER_SOS) {
365 for (sp = 0; sp < unit->data_size; sp++) {
366 if (unit->data[sp] == 0xff)
367 ++size;
368 }
369 }
370 }
371
373 if (!frag->data_ref)
374 return AVERROR(ENOMEM);
375 data = frag->data_ref->data;
376
377 dp = 0;
378
379 data[dp++] = 0xff;
380 data[dp++] = JPEG_MARKER_SOI;
381
382 for (i = 0; i < frag->nb_units; i++) {
383 unit = &frag->units[i];
384
385 data[dp++] = 0xff;
386 data[dp++] = unit->type;
387
388 if (unit->type != JPEG_MARKER_SOS) {
389 memcpy(data + dp, unit->data, unit->data_size);
390 dp += unit->data_size;
391 } else {
392 sp = AV_RB16(unit->data);
393 av_assert0(sp <= unit->data_size);
394 memcpy(data + dp, unit->data, sp);
395 dp += sp;
396
397 for (; sp < unit->data_size; sp++) {
398 if (unit->data[sp] == 0xff) {
399 data[dp++] = 0xff;
400 data[dp++] = 0x00;
401 } else {
402 data[dp++] = unit->data[sp];
403 }
404 }
405 }
406 }
407
408 data[dp++] = 0xff;
409 data[dp++] = JPEG_MARKER_EOI;
410
411 av_assert0(dp == size);
412
414 frag->data = data;
415 frag->data_size = size;
416
417 return 0;
418}
419
435
437 .codec_id = AV_CODEC_ID_MJPEG,
438
439 .unit_types = cbs_jpeg_unit_types,
440
441 .split_fragment = &cbs_jpeg_split_fragment,
442 .read_unit = &cbs_jpeg_read_unit,
443 .write_unit = &cbs_jpeg_write_unit,
444 .assemble_fragment = &cbs_jpeg_assemble_fragment,
445};
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define CBS_UNIT_TYPE_POD(type_, structure)
#define CBS_UNIT_TYPE_END_OF_LIST
#define CBS_UNIT_RANGE_POD(range_start, range_end, structure)
#define CBS_UNIT_TYPE_INTERNAL_REF(type, structure, ref_field)
#define CBS_UNIT_RANGE_INTERNAL_REF(range_start, range_end, structure, ref_field)
const CodedBitstreamType ff_cbs_type_jpeg
Definition cbs_jpeg.c:436
static int cbs_jpeg_read_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit)
Definition cbs_jpeg.c:221
static int cbs_jpeg_write_segment(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc)
Definition cbs_jpeg.c:313
#define SEGMENT(marker, func)
static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag)
Definition cbs_jpeg.c:352
static CodedBitstreamUnitTypeDescriptor cbs_jpeg_unit_types[]
Definition cbs_jpeg.c:420
static int cbs_jpeg_write_scan(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc)
Definition cbs_jpeg.c:287
static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc)
Definition cbs_jpeg.c:342
static int cbs_jpeg_split_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, int header)
Definition cbs_jpeg.c:86
@ JPEG_MARKER_COM
Definition cbs_jpeg.h:42
@ JPEG_MARKER_DHT
Definition cbs_jpeg.h:34
@ JPEG_MARKER_EOI
Definition cbs_jpeg.h:36
@ JPEG_MARKER_APPN
Definition cbs_jpeg.h:40
@ JPEG_MARKER_DQT
Definition cbs_jpeg.h:38
@ JPEG_MARKER_SOF3
Definition cbs_jpeg.h:32
@ JPEG_MARKER_SOF0
Definition cbs_jpeg.h:29
@ JPEG_MARKER_SOS
Definition cbs_jpeg.h:37
@ JPEG_MARKER_SOI
Definition cbs_jpeg.h:35
static int FUNC comment(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawComment *current)
static int FUNC dht(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawHuffmanTableSpecification *current)
static int FUNC dqt(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawQuantisationTableSpecification *current)
#define NULL
Definition coverity.c:32
static int get_bits_count(const GetBitContext *s)
Definition get_bits.h:254
static int init_get_bits(GetBitContext *s, const uint8_t *buffer, int bit_size)
Initialize GetBitContext.
Definition get_bits.h:517
@ AV_CODEC_ID_MJPEG
Definition codec_id.h:57
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition defs.h:40
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition buffer.c:77
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
#define AV_RB16(p)
Memory handling functions.
@ DQT
Definition mjpeg.h:73
@ DHT
Definition mjpeg.h:56
@ COM
Definition mjpeg.h:111
const char data[16]
Definition mxf.c:149
#define av_malloc(s)
Definition ops_static.c:52
static int put_bits_count(PutBitContext *s)
Definition put_bits.h:90
static uint8_t * put_bits_ptr(PutBitContext *s)
Return the pointer to the byte where the bitstream writer will put the next bit.
Definition put_bits.h:402
static int put_bits_left(PutBitContext *s)
Definition put_bits.h:135
static void flush_put_bits(PutBitContext *s)
Pad the end of the output stream with zeros.
Definition put_bits.h:153
static void skip_put_bytes(PutBitContext *s, int n)
Skip the given number of bytes.
Definition put_bits.h:411
static const uint8_t header[24]
Definition sdr2.c:68
unsigned int pos
Definition spdifenc.c:431
A reference to a data buffer.
Definition buffer.h:82
uint8_t * data
The data buffer.
Definition buffer.h:90
Context structure for coded bitstream operations.
Definition cbs.h:226
Coded bitstream fragment structure, combining one or more units.
Definition cbs.h:129
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition cbs.h:175
int nb_units
Number of units in this fragment.
Definition cbs.h:160
size_t data_size
The number of bytes in the bitstream.
Definition cbs.h:142
uint8_t * data
Pointer to the bitstream form of this fragment.
Definition cbs.h:135
AVBufferRef * data_ref
A reference to the buffer containing data.
Definition cbs.h:152
Coded bitstream unit structure.
Definition cbs.h:77
void * content
Pointer to the decomposed form of this unit.
Definition cbs.h:114
uint8_t * data
Pointer to the directly-parsable bitstream form of this unit.
Definition cbs.h:88
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition cbs.h:81
size_t data_size
The number of bytes in the bitstream (including any padding bits in the final byte).
Definition cbs.h:93
AVBufferRef * data_ref
A reference to the buffer containing data.
Definition cbs.h:105
AVBufferRef * data_ref
Definition cbs_jpeg.h:83
JPEGRawScanHeader header
Definition cbs_jpeg.h:81
size_t data_size
Definition cbs_jpeg.h:84
uint8_t * data
Definition cbs_jpeg.h:82
#define av_log(a,...)
static AVFormatContext * ctx
Definition movenc.c:49
int size