FFmpeg
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 "cbs.h"
20 #include "cbs_internal.h"
21 #include "cbs_jpeg.h"
22 
23 
24 #define HEADER(name) do { \
25  ff_cbs_trace_header(ctx, name); \
26  } while (0)
27 
28 #define CHECK(call) do { \
29  err = (call); \
30  if (err < 0) \
31  return err; \
32  } while (0)
33 
34 #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
35 
36 #define u(width, name, range_min, range_max) \
37  xu(width, name, range_min, range_max, 0, )
38 #define us(width, name, sub, range_min, range_max) \
39  xu(width, name, range_min, range_max, 1, sub)
40 
41 
42 #define READ
43 #define READWRITE read
44 #define RWContext GetBitContext
45 #define FUNC(name) cbs_jpeg_read_ ## name
46 
47 #define xu(width, name, range_min, range_max, subs, ...) do { \
48  uint32_t value; \
49  CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
50  SUBSCRIPTS(subs, __VA_ARGS__), \
51  &value, range_min, range_max)); \
52  current->name = value; \
53  } while (0)
54 
56 
57 #undef READ
58 #undef READWRITE
59 #undef RWContext
60 #undef FUNC
61 #undef xu
62 
63 #define WRITE
64 #define READWRITE write
65 #define RWContext PutBitContext
66 #define FUNC(name) cbs_jpeg_write_ ## name
67 
68 #define xu(width, name, range_min, range_max, subs, ...) do { \
69  uint32_t value = current->name; \
70  CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
71  SUBSCRIPTS(subs, __VA_ARGS__), \
72  value, range_min, range_max)); \
73  } while (0)
74 
75 
77 
78 #undef WRITE
79 #undef READWRITE
80 #undef RWContext
81 #undef FUNC
82 #undef xu
83 
84 
85 static void cbs_jpeg_free_application_data(void *opaque, uint8_t *content)
86 {
88  av_buffer_unref(&ad->Ap_ref);
89  av_freep(&content);
90 }
91 
92 static void cbs_jpeg_free_comment(void *opaque, uint8_t *content)
93 {
95  av_buffer_unref(&comment->Cm_ref);
96  av_freep(&content);
97 }
98 
99 static void cbs_jpeg_free_scan(void *opaque, uint8_t *content)
100 {
101  JPEGRawScan *scan = (JPEGRawScan*)content;
102  av_buffer_unref(&scan->data_ref);
103  av_freep(&content);
104 }
105 
108  int header)
109 {
110  AVBufferRef *data_ref;
111  uint8_t *data;
112  size_t data_size;
113  int unit, start, end, marker, next_start, next_marker;
114  int err, i, j, length;
115 
116  if (frag->data_size < 4) {
117  // Definitely too short to be meaningful.
118  return AVERROR_INVALIDDATA;
119  }
120 
121  for (i = 0; i + 1 < frag->data_size && frag->data[i] != 0xff; i++);
122  if (i > 0) {
123  av_log(ctx->log_ctx, AV_LOG_WARNING, "Discarding %d bytes at "
124  "beginning of image.\n", i);
125  }
126  for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++);
127  if (i + 1 >= frag->data_size && frag->data[i]) {
128  av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
129  "no SOI marker found.\n");
130  return AVERROR_INVALIDDATA;
131  }
132  marker = frag->data[i];
133  if (marker != JPEG_MARKER_SOI) {
134  av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: first "
135  "marker is %02x, should be SOI.\n", marker);
136  return AVERROR_INVALIDDATA;
137  }
138  for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++);
139  if (i + 1 >= frag->data_size) {
140  av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
141  "no image content found.\n");
142  return AVERROR_INVALIDDATA;
143  }
144  marker = frag->data[i];
145  start = i + 1;
146 
147  for (unit = 0;; unit++) {
148  if (marker == JPEG_MARKER_EOI) {
149  break;
150  } else if (marker == JPEG_MARKER_SOS) {
151  next_marker = -1;
152  for (i = start; i + 1 < frag->data_size; i++) {
153  if (frag->data[i] != 0xff)
154  continue;
155  end = i;
156  for (++i; i + 1 < frag->data_size &&
157  frag->data[i] == 0xff; i++);
158  if (i + 1 < frag->data_size) {
159  if (frag->data[i] == 0x00)
160  continue;
161  next_marker = frag->data[i];
162  next_start = i + 1;
163  }
164  break;
165  }
166  } else {
167  i = start;
168  if (i + 2 > frag->data_size) {
169  av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
170  "truncated at %02x marker.\n", marker);
171  return AVERROR_INVALIDDATA;
172  }
173  length = AV_RB16(frag->data + i);
174  if (i + length > frag->data_size) {
175  av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: "
176  "truncated at %02x marker segment.\n", marker);
177  return AVERROR_INVALIDDATA;
178  }
179  end = start + length;
180 
181  i = end;
182  if (frag->data[i] != 0xff) {
183  next_marker = -1;
184  } else {
185  for (++i; i + 1 < frag->data_size &&
186  frag->data[i] == 0xff; i++);
187  if (i + 1 >= frag->data_size) {
188  next_marker = -1;
189  } else {
190  next_marker = frag->data[i];
191  next_start = i + 1;
192  }
193  }
194  }
195 
196  if (marker == JPEG_MARKER_SOS) {
197  length = AV_RB16(frag->data + start);
198 
199  if (length > end - start)
200  return AVERROR_INVALIDDATA;
201 
202  data_ref = NULL;
203  data = av_malloc(end - start +
205  if (!data)
206  return AVERROR(ENOMEM);
207 
208  memcpy(data, frag->data + start, length);
209  for (i = start + length, j = length; i < end; i++, j++) {
210  if (frag->data[i] == 0xff) {
211  while (frag->data[i] == 0xff)
212  ++i;
213  data[j] = 0xff;
214  } else {
215  data[j] = frag->data[i];
216  }
217  }
218  data_size = j;
219 
220  memset(data + data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
221 
222  } else {
223  data = frag->data + start;
224  data_size = end - start;
225  data_ref = frag->data_ref;
226  }
227 
228  err = ff_cbs_insert_unit_data(ctx, frag, unit, marker,
229  data, data_size, data_ref);
230  if (err < 0)
231  return err;
232 
233  if (next_marker == -1)
234  break;
235  marker = next_marker;
236  start = next_start;
237  }
238 
239  return 0;
240 }
241 
243  CodedBitstreamUnit *unit)
244 {
245  GetBitContext gbc;
246  int err;
247 
248  err = init_get_bits(&gbc, unit->data, 8 * unit->data_size);
249  if (err < 0)
250  return err;
251 
252  if (unit->type >= JPEG_MARKER_SOF0 &&
253  unit->type <= JPEG_MARKER_SOF3) {
254  err = ff_cbs_alloc_unit_content(ctx, unit,
255  sizeof(JPEGRawFrameHeader),
256  NULL);
257  if (err < 0)
258  return err;
259 
260  err = cbs_jpeg_read_frame_header(ctx, &gbc, unit->content);
261  if (err < 0)
262  return err;
263 
264  } else if (unit->type >= JPEG_MARKER_APPN &&
265  unit->type <= JPEG_MARKER_APPN + 15) {
266  err = ff_cbs_alloc_unit_content(ctx, unit,
267  sizeof(JPEGRawApplicationData),
269  if (err < 0)
270  return err;
271 
272  err = cbs_jpeg_read_application_data(ctx, &gbc, unit->content);
273  if (err < 0)
274  return err;
275 
276  } else if (unit->type == JPEG_MARKER_SOS) {
277  JPEGRawScan *scan;
278  int pos;
279 
280  err = ff_cbs_alloc_unit_content(ctx, unit,
281  sizeof(JPEGRawScan),
283  if (err < 0)
284  return err;
285  scan = unit->content;
286 
287  err = cbs_jpeg_read_scan_header(ctx, &gbc, &scan->header);
288  if (err < 0)
289  return err;
290 
291  pos = get_bits_count(&gbc);
292  av_assert0(pos % 8 == 0);
293  if (pos > 0) {
294  scan->data_size = unit->data_size - pos / 8;
295  scan->data_ref = av_buffer_ref(unit->data_ref);
296  if (!scan->data_ref)
297  return AVERROR(ENOMEM);
298  scan->data = unit->data + pos / 8;
299  }
300 
301  } else {
302  switch (unit->type) {
303 #define SEGMENT(marker, type, func, free) \
304  case JPEG_MARKER_ ## marker: \
305  { \
306  err = ff_cbs_alloc_unit_content(ctx, unit, \
307  sizeof(type), free); \
308  if (err < 0) \
309  return err; \
310  err = cbs_jpeg_read_ ## func(ctx, &gbc, unit->content); \
311  if (err < 0) \
312  return err; \
313  } \
314  break
318 #undef SEGMENT
319  default:
320  return AVERROR(ENOSYS);
321  }
322  }
323 
324  return 0;
325 }
326 
328  CodedBitstreamUnit *unit,
329  PutBitContext *pbc)
330 {
331  JPEGRawScan *scan = unit->content;
332  int err;
333 
334  err = cbs_jpeg_write_scan_header(ctx, pbc, &scan->header);
335  if (err < 0)
336  return err;
337 
338  if (scan->data) {
339  if (scan->data_size * 8 > put_bits_left(pbc))
340  return AVERROR(ENOSPC);
341 
342  av_assert0(put_bits_count(pbc) % 8 == 0);
343 
344  flush_put_bits(pbc);
345 
346  memcpy(put_bits_ptr(pbc), scan->data, scan->data_size);
347  skip_put_bytes(pbc, scan->data_size);
348  }
349 
350  return 0;
351 }
352 
354  CodedBitstreamUnit *unit,
355  PutBitContext *pbc)
356 {
357  int err;
358 
359  if (unit->type >= JPEG_MARKER_SOF0 &&
360  unit->type <= JPEG_MARKER_SOF3) {
361  err = cbs_jpeg_write_frame_header(ctx, pbc, unit->content);
362  } else if (unit->type >= JPEG_MARKER_APPN &&
363  unit->type <= JPEG_MARKER_APPN + 15) {
364  err = cbs_jpeg_write_application_data(ctx, pbc, unit->content);
365  } else {
366  switch (unit->type) {
367 #define SEGMENT(marker, func) \
368  case JPEG_MARKER_ ## marker: \
369  err = cbs_jpeg_write_ ## func(ctx, pbc, unit->content); \
370  break;
371  SEGMENT(DQT, dqt);
372  SEGMENT(DHT, dht);
373  SEGMENT(COM, comment);
374  default:
375  return AVERROR_PATCHWELCOME;
376  }
377  }
378 
379  return err;
380 }
381 
383  CodedBitstreamUnit *unit,
384  PutBitContext *pbc)
385 {
386  if (unit->type == JPEG_MARKER_SOS)
387  return cbs_jpeg_write_scan (ctx, unit, pbc);
388  else
389  return cbs_jpeg_write_segment(ctx, unit, pbc);
390 }
391 
394 {
395  const CodedBitstreamUnit *unit;
396  uint8_t *data;
397  size_t size, dp, sp;
398  int i;
399 
400  size = 4; // SOI + EOI.
401  for (i = 0; i < frag->nb_units; i++) {
402  unit = &frag->units[i];
403  size += 2 + unit->data_size;
404  if (unit->type == JPEG_MARKER_SOS) {
405  for (sp = 0; sp < unit->data_size; sp++) {
406  if (unit->data[sp] == 0xff)
407  ++size;
408  }
409  }
410  }
411 
413  if (!frag->data_ref)
414  return AVERROR(ENOMEM);
415  data = frag->data_ref->data;
416 
417  dp = 0;
418 
419  data[dp++] = 0xff;
420  data[dp++] = JPEG_MARKER_SOI;
421 
422  for (i = 0; i < frag->nb_units; i++) {
423  unit = &frag->units[i];
424 
425  data[dp++] = 0xff;
426  data[dp++] = unit->type;
427 
428  if (unit->type != JPEG_MARKER_SOS) {
429  memcpy(data + dp, unit->data, unit->data_size);
430  dp += unit->data_size;
431  } else {
432  sp = AV_RB16(unit->data);
433  av_assert0(sp <= unit->data_size);
434  memcpy(data + dp, unit->data, sp);
435  dp += sp;
436 
437  for (; sp < unit->data_size; sp++) {
438  if (unit->data[sp] == 0xff) {
439  data[dp++] = 0xff;
440  data[dp++] = 0x00;
441  } else {
442  data[dp++] = unit->data[sp];
443  }
444  }
445  }
446  }
447 
448  data[dp++] = 0xff;
449  data[dp++] = JPEG_MARKER_EOI;
450 
451  av_assert0(dp == size);
452 
453  memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
454  frag->data = data;
455  frag->data_size = size;
456 
457  return 0;
458 }
459 
462 
463  .split_fragment = &cbs_jpeg_split_fragment,
464  .read_unit = &cbs_jpeg_read_unit,
465  .write_unit = &cbs_jpeg_write_unit,
466  .assemble_fragment = &cbs_jpeg_assemble_fragment,
467 };
#define NULL
Definition: coverity.c:32
int nb_units
Number of units in this fragment.
Definition: cbs.h:147
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it...
Definition: buffer.c:126
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static int FUNC() dqt(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawQuantisationTableSpecification *current)
Definition: mjpeg.h:111
Definition: mjpeg.h:73
static void cbs_jpeg_free_scan(void *opaque, uint8_t *content)
Definition: cbs_jpeg.c:99
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
CodedBitstreamUnitType type
Codec-specific type of this unit.
Definition: cbs.h:68
int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, size_t size, void(*free)(void *opaque, uint8_t *data))
Definition: cbs.c:644
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
AVBufferRef * data_ref
Definition: cbs_jpeg.h:84
static int cbs_jpeg_read_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit)
Definition: cbs_jpeg.c:242
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
size_t data_size
Definition: cbs_jpeg.h:83
static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc)
Definition: cbs_jpeg.c:382
uint8_t
#define av_malloc(s)
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
const CodedBitstreamType ff_cbs_type_jpeg
Definition: cbs_jpeg.c:460
static int get_bits_count(const GetBitContext *s)
Definition: get_bits.h:219
#define sp
Definition: regdef.h:63
static int FUNC() dht(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawHuffmanTableSpecification *current)
Coded bitstream unit structure.
Definition: cbs.h:64
AVBufferRef * Ap_ref
Definition: cbs_jpeg.h:113
ptrdiff_t size
Definition: opengl_enc.c:100
void * content
Pointer to the decomposed form of this unit.
Definition: cbs.h:101
static const uint8_t header[24]
Definition: sdr2.c:67
CodedBitstreamUnit * units
Pointer to an array of units of length nb_units_allocated.
Definition: cbs.h:162
#define SEGMENT(marker, type, func, free)
uint8_t * data
Pointer to the directly-parsable bitstream form of this unit.
Definition: cbs.h:75
int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, int position, CodedBitstreamUnitType type, uint8_t *data, size_t data_size, AVBufferRef *data_buf)
Insert a new unit into a fragment with the given data bitstream.
Definition: cbs.c:759
#define av_log(a,...)
static int FUNC() comment(CodedBitstreamContext *ctx, RWContext *rw, JPEGRawComment *current)
size_t data_size
The number of bytes in the bitstream.
Definition: cbs.h:129
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
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:324
static int put_bits_left(PutBitContext *s)
Definition: put_bits.h:93
JPEGRawScanHeader header
Definition: cbs_jpeg.h:81
unsigned int pos
Definition: spdifenc.c:410
GLsizei GLsizei * length
Definition: opengl_enc.c:114
static int put_bits_count(PutBitContext *s)
Definition: put_bits.h:67
void * log_ctx
Logging context to be passed to all av_log() calls associated with this context.
Definition: cbs.h:173
Definition: mjpeg.h:56
static void skip_put_bytes(PutBitContext *s, int n)
Skip the given number of bytes.
Definition: put_bits.h:333
AVFormatContext * ctx
Definition: movenc.c:48
uint8_t * data
Pointer to the bitstream form of this fragment.
Definition: cbs.h:122
static int cbs_jpeg_write_segment(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc)
Definition: cbs_jpeg.c:353
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
AVBufferRef * av_buffer_alloc(int size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:68
Coded bitstream fragment structure, combining one or more units.
Definition: cbs.h:116
uint8_t * data
The data buffer.
Definition: buffer.h:89
Context structure for coded bitstream operations.
Definition: cbs.h:168
static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag)
Definition: cbs_jpeg.c:392
static void cbs_jpeg_free_application_data(void *opaque, uint8_t *content)
Definition: cbs_jpeg.c:85
static int init_get_bits(GetBitContext *s, const uint8_t *buffer, int bit_size)
Initialize GetBitContext.
Definition: get_bits.h:659
enum AVCodecID codec_id
Definition: cbs_internal.h:29
A reference to a data buffer.
Definition: buffer.h:81
static void flush_put_bits(PutBitContext *s)
Pad the end of the output stream with zeros.
Definition: put_bits.h:101
AVBufferRef * data_ref
A reference to the buffer containing data.
Definition: cbs.h:92
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:94
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:214
uint8_t * data
Definition: cbs_jpeg.h:82
#define av_freep(p)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
AVBufferRef * data_ref
A reference to the buffer containing data.
Definition: cbs.h:139
static int cbs_jpeg_split_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, int header)
Definition: cbs_jpeg.c:106
AVBufferRef * Cm_ref
Definition: cbs_jpeg.h:119
static void cbs_jpeg_free_comment(void *opaque, uint8_t *content)
Definition: cbs_jpeg.c:92
static int cbs_jpeg_write_scan(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc)
Definition: cbs_jpeg.c:327
size_t data_size
The number of bytes in the bitstream (including any padding bits in the final byte).
Definition: cbs.h:80