FFmpeg
mpjpegdec.c
Go to the documentation of this file.
1 /*
2  * Multipart JPEG format
3  * Copyright (c) 2015 Luca Barbato
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg 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 GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "libavutil/avstring.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/opt.h"
25 
26 #include "avformat.h"
27 #include "demux.h"
28 #include "internal.h"
29 #include "avio_internal.h"
30 
31 typedef struct MPJPEGDemuxContext {
32  const AVClass *class;
33  char *boundary;
34  char *searchstr;
38 
39 static void trim_right(char *p)
40 {
41  char *end;
42 
43  if (!p || !*p)
44  return;
45 
46  end = p + strlen(p);
47  while (end > p && av_isspace(*(end-1)))
48  *(--end) = '\0';
49 }
50 
51 static int get_line(AVIOContext *pb, char *line, int line_size)
52 {
53  ff_get_line(pb, line, line_size);
54 
55  if (pb->error)
56  return pb->error;
57 
58  if (pb->eof_reached)
59  return AVERROR_EOF;
60 
62  return 0;
63 }
64 
65 static int split_tag_value(char **tag, char **value, char *line)
66 {
67  char *p = line;
68  int foundData = 0;
69 
70  *tag = NULL;
71  *value = NULL;
72 
73  while (*p != '\0' && *p != ':') {
74  if (!av_isspace(*p)) {
75  foundData = 1;
76  }
77  p++;
78  }
79  if (*p != ':')
80  return foundData ? AVERROR_INVALIDDATA : 0;
81 
82  *p = '\0';
83  *tag = line;
84  trim_right(*tag);
85 
86  p++;
87 
88  while (av_isspace(*p))
89  p++;
90 
91  *value = p;
92  trim_right(*value);
93 
94  return 0;
95 }
96 
97 static int parse_multipart_header(AVIOContext *pb,
98  int* size,
99  const char* expected_boundary,
100  void *log_ctx);
101 
103 {
104  MPJPEGDemuxContext *mpjpeg = s->priv_data;
105  av_freep(&mpjpeg->boundary);
106  av_freep(&mpjpeg->searchstr);
107  return 0;
108 }
109 
110 static int mpjpeg_read_probe(const AVProbeData *p)
111 {
112  FFIOContext pb;
113  int ret = 0;
114  int size = 0;
115 
116  if (p->buf_size < 2 || p->buf[0] != '-' || p->buf[1] != '-')
117  return 0;
118 
119  ffio_init_read_context(&pb, p->buf, p->buf_size);
120 
121  ret = (parse_multipart_header(&pb.pub, &size, "--", NULL) >= 0) ? AVPROBE_SCORE_MAX : 0;
122 
123  return ret;
124 }
125 
127 {
128  AVStream *st;
129  char boundary[70 + 2 + 1] = {0};
130  int64_t pos = avio_tell(s->pb);
131  int ret;
132 
133  do {
134  ret = get_line(s->pb, boundary, sizeof(boundary));
135  if (ret < 0)
136  return ret;
137  } while (!boundary[0]);
138 
139  if (strncmp(boundary, "--", 2))
140  return AVERROR_INVALIDDATA;
141 
142  st = avformat_new_stream(s, NULL);
143  if (!st)
144  return AVERROR(ENOMEM);
145 
148 
149  avpriv_set_pts_info(st, 60, 1, 25);
150 
151  avio_seek(s->pb, pos, SEEK_SET);
152 
153  return 0;
154 }
155 
156 static int parse_content_length(const char *value)
157 {
158  long int val = strtol(value, NULL, 10);
159 
160  if (val == LONG_MIN || val == LONG_MAX)
161  return AVERROR(errno);
162  if (val > INT_MAX)
163  return AVERROR(ERANGE);
164  return val;
165 }
166 
168  int* size,
169  const char* expected_boundary,
170  void *log_ctx)
171 {
172  char line[128];
173  int found_content_type = 0;
174  int ret;
175 
176  *size = -1;
177 
178  // get the CRLF as empty string
179  ret = get_line(pb, line, sizeof(line));
180  if (ret < 0)
181  return ret;
182 
183  /* some implementation do not provide the required
184  * initial CRLF (see rfc1341 7.2.1)
185  */
186  while (!line[0]) {
187  ret = get_line(pb, line, sizeof(line));
188  if (ret < 0)
189  return ret;
190  }
191 
192  if (!av_strstart(line, expected_boundary, NULL)) {
193  if (log_ctx)
194  av_log(log_ctx,
195  AV_LOG_ERROR,
196  "Expected boundary '%s' not found, instead found a line of %"SIZE_SPECIFIER" bytes\n",
197  expected_boundary,
198  strlen(line));
199 
200  return AVERROR_INVALIDDATA;
201  }
202 
203  while (!pb->eof_reached) {
204  char *tag, *value;
205 
206  ret = get_line(pb, line, sizeof(line));
207  if (ret < 0) {
208  if (ret == AVERROR_EOF)
209  break;
210  return ret;
211  }
212 
213  if (line[0] == '\0')
214  break;
215 
217  if (ret < 0)
218  return ret;
219  if (value==NULL || tag==NULL)
220  break;
221 
222  if (!av_strcasecmp(tag, "Content-type")) {
223  if (av_strcasecmp(value, "image/jpeg")) {
224  if (log_ctx)
225  av_log(log_ctx, AV_LOG_ERROR,
226  "Unexpected %s : %s\n",
227  tag, value);
228  return AVERROR_INVALIDDATA;
229  } else
230  found_content_type = 1;
231  } else if (!av_strcasecmp(tag, "Content-Length")) {
233  if ( *size < 0 )
234  if (log_ctx)
235  av_log(log_ctx, AV_LOG_WARNING,
236  "Invalid Content-Length value : %s\n",
237  value);
238  }
239  }
240 
241  return found_content_type ? 0 : AVERROR_INVALIDDATA;
242 }
243 
245 {
246  uint8_t *mime_type = NULL;
247  const char *start;
248  const char *end;
249  uint8_t *res = NULL;
250  int len;
251 
252  /* get MIME type, and skip to the first parameter */
253  av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type);
254  start = mime_type;
255  while (start != NULL && *start != '\0') {
256  start = strchr(start, ';');
257  if (!start)
258  break;
259 
260  start = start+1;
261 
262  while (av_isspace(*start))
263  start++;
264 
265  if (av_stristart(start, "boundary=", &start)) {
266  end = strchr(start, ';');
267  if (end)
268  len = end - start - 1;
269  else
270  len = strlen(start);
271 
272  /* some endpoints may enclose the boundary
273  in Content-Type in quotes */
274  if ( len>2 && *start == '"' && start[len-1] == '"' ) {
275  start++;
276  len -= 2;
277  }
278  res = av_strndup(start, len);
279  break;
280  }
281  }
282 
283  av_freep(&mime_type);
284  return res;
285 }
286 
288 {
289  int size;
290  int ret;
291 
292  MPJPEGDemuxContext *mpjpeg = s->priv_data;
293  if (mpjpeg->boundary == NULL) {
294  uint8_t* boundary = NULL;
295  if (mpjpeg->strict_mime_boundary) {
296  boundary = mpjpeg_get_boundary(s->pb);
297  }
298  if (boundary != NULL) {
299  mpjpeg->boundary = av_asprintf("--%s", boundary);
300  mpjpeg->searchstr = av_asprintf("\r\n--%s\r\n", boundary);
301  av_freep(&boundary);
302  } else {
303  mpjpeg->boundary = av_strdup("--");
304  mpjpeg->searchstr = av_strdup("\r\n--");
305  }
306  if (!mpjpeg->boundary || !mpjpeg->searchstr) {
307  av_freep(&mpjpeg->boundary);
308  av_freep(&mpjpeg->searchstr);
309  return AVERROR(ENOMEM);
310  }
311  mpjpeg->searchstr_len = strlen(mpjpeg->searchstr);
312  }
313 
314  ret = parse_multipart_header(s->pb, &size, mpjpeg->boundary, s);
315  if (ret < 0)
316  return ret;
317 
318  if (size > 0) {
319  /* size has been provided to us in MIME header */
320  ret = av_get_packet(s->pb, pkt, size);
321  } else {
322  /* no size was given -- we read until the next boundary or end-of-file */
323  int len;
324 
325  const int read_chunk = 2048;
326 
327  pkt->pos = avio_tell(s->pb);
328 
329  while ((ret = ffio_ensure_seekback(s->pb, read_chunk)) >= 0 && /* we may need to return as much as all we've read back to the buffer */
330  (ret = av_append_packet(s->pb, pkt, read_chunk)) >= 0) {
331  /* scan the new data */
332  char *start;
333 
334  len = ret;
335  start = pkt->data + pkt->size - len;
336  do {
337  if (!memcmp(start, mpjpeg->searchstr, mpjpeg->searchstr_len)) {
338  // got the boundary! rewind the stream
339  avio_seek(s->pb, -len, SEEK_CUR);
340  pkt->size -= len;
341  return pkt->size;
342  }
343  len--;
344  start++;
345  } while (len >= mpjpeg->searchstr_len);
346  avio_seek(s->pb, -len, SEEK_CUR);
347  pkt->size -= len;
348  }
349 
350  /* error or EOF occurred */
351  if (ret == AVERROR_EOF) {
352  ret = pkt->size > 0 ? pkt->size : AVERROR_EOF;
353  }
354  }
355 
356  return ret;
357 }
358 
359 #define OFFSET(x) offsetof(MPJPEGDemuxContext, x)
360 #define DEC AV_OPT_FLAG_DECODING_PARAM
361 static const AVOption mpjpeg_options[] = {
362  { "strict_mime_boundary", "require MIME boundaries match", OFFSET(strict_mime_boundary), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
363  { NULL }
364 };
365 
367  .class_name = "MPJPEG demuxer",
368  .item_name = av_default_item_name,
369  .option = mpjpeg_options,
370  .version = LIBAVUTIL_VERSION_INT,
371 };
372 
374  .p.name = "mpjpeg",
375  .p.long_name = NULL_IF_CONFIG_SMALL("MIME multipart JPEG"),
376  .p.mime_type = "multipart/x-mixed-replace",
377  .p.extensions = "mjpg",
378  .p.priv_class = &mpjpeg_demuxer_class,
379  .p.flags = AVFMT_NOTIMESTAMPS,
380  .priv_data_size = sizeof(MPJPEGDemuxContext),
385 };
AV_OPT_SEARCH_CHILDREN
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition: opt.h:522
MPJPEGDemuxContext::boundary
char * boundary
Definition: mpjpegdec.c:33
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVERROR
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
opt.h
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:51
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
AVFMT_NOTIMESTAMPS
#define AVFMT_NOTIMESTAMPS
Format does not need / have any timestamps.
Definition: avformat.h:479
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:115
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:207
av_isspace
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:218
AVPacket::data
uint8_t * data
Definition: packet.h:524
AVOption
AVOption.
Definition: opt.h:346
AVIOContext::error
int error
contains the error code or 0 if no error happened
Definition: avio.h:239
ffio_init_read_context
void ffio_init_read_context(FFIOContext *s, const uint8_t *buffer, int buffer_size)
Wrap a buffer in an AVIOContext for reading.
Definition: aviobuf.c:99
AVProbeData::buf_size
int buf_size
Size of buf except extra allocated bytes.
Definition: avformat.h:454
FFIOContext
Definition: avio_internal.h:28
DEC
#define DEC
Definition: mpjpegdec.c:360
AVPROBE_SCORE_MAX
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:463
avpriv_set_pts_info
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: avformat.c:853
read_close
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:143
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
val
static double val(void *priv, double ch)
Definition: aeval.c:78
OFFSET
#define OFFSET(x)
Definition: mpjpegdec.c:359
get_line
static int get_line(AVIOContext *pb, char *line, int line_size)
Definition: mpjpegdec.c:51
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
read_packet
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_read_callback.c:42
mpjpeg_get_boundary
static char * mpjpeg_get_boundary(AVIOContext *pb)
Definition: mpjpegdec.c:244
s
#define s(width, name)
Definition: cbs_vp9.c:198
trim_right
static void trim_right(char *p)
Definition: mpjpegdec.c:39
AVInputFormat::name
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:553
AVProbeData::buf
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:453
read_chunk
static int read_chunk(AVFormatContext *s)
Definition: dhav.c:172
av_stristart
int av_stristart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str independent of case.
Definition: avstring.c:47
parse_multipart_header
static int parse_multipart_header(AVIOContext *pb, int *size, const char *expected_boundary, void *log_ctx)
Definition: mpjpegdec.c:167
MPJPEGDemuxContext::searchstr
char * searchstr
Definition: mpjpegdec.c:34
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:766
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
read_header
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:550
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
MPJPEGDemuxContext::searchstr_len
int searchstr_len
Definition: mpjpegdec.c:35
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
AVProbeData
This structure contains the data a format has to probe a file.
Definition: avformat.h:451
ff_mpjpeg_demuxer
const FFInputFormat ff_mpjpeg_demuxer
Definition: mpjpegdec.c:373
mpjpeg_demuxer_class
static const AVClass mpjpeg_demuxer_class
Definition: mpjpegdec.c:366
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
AVPacket::size
int size
Definition: packet.h:525
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
MPJPEGDemuxContext::strict_mime_boundary
int strict_mime_boundary
Definition: mpjpegdec.c:36
FFIOContext::pub
AVIOContext pub
Definition: avio_internal.h:29
size
int size
Definition: twinvq_data.h:10344
FFInputFormat::p
AVInputFormat p
The public AVInputFormat.
Definition: demux.h:41
ffio_ensure_seekback
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition: aviobuf.c:1023
mpjpeg_read_probe
static int mpjpeg_read_probe(const AVProbeData *p)
Definition: mpjpegdec.c:110
line
Definition: graph2dot.c:48
mpjpeg_read_close
static int mpjpeg_read_close(AVFormatContext *s)
Definition: mpjpegdec.c:102
mpjpeg_read_packet
static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: mpjpegdec.c:287
mpjpeg_options
static const AVOption mpjpeg_options[]
Definition: mpjpegdec.c:361
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:36
MPJPEGDemuxContext
Definition: mpjpegdec.c:31
AV_CODEC_ID_MJPEG
@ AV_CODEC_ID_MJPEG
Definition: codec_id.h:59
avio_internal.h
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
ff_get_line
int ff_get_line(AVIOContext *s, char *buf, int maxlen)
Read a whole line of text from AVIOContext.
Definition: aviobuf.c:769
demux.h
len
int len
Definition: vorbis_enc_data.h:426
split_tag_value
static int split_tag_value(char **tag, char **value, char *line)
Definition: mpjpegdec.c:65
parse_content_length
static int parse_content_length(const char *value)
Definition: mpjpegdec.c:156
av_get_packet
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
Definition: utils.c:104
tag
uint32_t tag
Definition: movenc.c:1787
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:743
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:231
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:71
av_append_packet
int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
Read data and append it to the current content of the AVPacket.
Definition: utils.c:120
pos
unsigned int pos
Definition: spdifenc.c:414
avformat.h
SIZE_SPECIFIER
#define SIZE_SPECIFIER
Definition: internal.h:129
AVIOContext::eof_reached
int eof_reached
true if was unable to read due to error or eof
Definition: avio.h:238
mpjpeg_read_header
static int mpjpeg_read_header(AVFormatContext *s)
Definition: mpjpegdec.c:126
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:272
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
read_probe
static int read_probe(const AVProbeData *p)
Definition: cdg.c:30
mem.h
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:55
AVPacket
This structure stores compressed data.
Definition: packet.h:501
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:251
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVPacket::pos
int64_t pos
byte position in stream, -1 if unknown
Definition: packet.h:544
FFInputFormat
Definition: demux.h:37
av_opt_get
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition: opt.c:1147
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
avstring.h
av_strndup
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition: mem.c:284
line
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
Definition: swscale.txt:40