FFmpeg
Loading...
Searching...
No Matches
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
38
39static 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
51static 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
65static 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;
85
86 p++;
87
88 while (av_isspace(*p))
89 p++;
90
91 *value = p;
93
94 return 0;
95}
96
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
110static 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
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
156static 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,
196 "Expected boundary '%s' not found, instead found a line of %zu 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
216 ret = split_tag_value(&tag, &value, line);
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
361static 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};
static double val(void *priv, double ch)
Definition aeval.c:77
const FFInputFormat ff_mpjpeg_demuxer
Definition mpjpegdec.c:373
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:834
Main libavformat public API header.
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:114
#define AVPROBE_SCORE_MAX
maximum score
Definition avformat.h:483
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:98
#define AVFMT_NOTIMESTAMPS
Format does not need / have any timestamps.
Definition avformat.h:498
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition aviobuf.c:236
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition aviobuf.c:1026
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
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
int ff_get_line(AVIOContext *s, char *buf, int maxlen)
Read a whole line of text from AVIOContext.
Definition aviobuf.c:772
char * av_asprintf(const char *fmt,...)
Definition avstring.c:115
#define s(width, name)
Definition cbs_vp9.c:198
static int read_probe(const AVProbeData *p)
Definition cdg.c:30
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVPacket * pkt
static int read_chunk(AVFormatContext *s)
Definition dhav.c:173
double value
Definition eval.c:102
static int read_header(FFV1Context *f, RangeCoder *c)
Definition ffv1dec.c:578
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_CODEC_ID_MJPEG
Definition codec_id.h:57
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_EOF
End of file.
Definition error.h:57
#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
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
char * av_strndup(const char *s, size_t len)
Duplicate a substring of a string.
Definition mem.c:284
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition avstring.c:208
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
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition avstring.h:218
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
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val)
Definition opt.c:1289
#define AV_OPT_SEARCH_CHILDREN
Search in possible children of the given object first.
Definition opt.h:604
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
static av_cold int read_close(AVFormatContext *ctx)
Definition libcdio.c:143
#define DEC
Definition librsvgdec.c:149
Memory handling functions.
uint32_t tag
Definition movenc.c:2087
static int parse_content_length(const char *value)
Definition mpjpegdec.c:156
static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition mpjpegdec.c:287
static int split_tag_value(char **tag, char **value, char *line)
Definition mpjpegdec.c:65
static int mpjpeg_read_header(AVFormatContext *s)
Definition mpjpegdec.c:126
static const AVOption mpjpeg_options[]
Definition mpjpegdec.c:361
static int mpjpeg_read_probe(const AVProbeData *p)
Definition mpjpegdec.c:110
static char * mpjpeg_get_boundary(AVIOContext *pb)
Definition mpjpegdec.c:244
static void trim_right(char *p)
Definition mpjpegdec.c:39
static int get_line(AVIOContext *pb, char *line, int line_size)
Definition mpjpegdec.c:51
#define OFFSET(x)
Definition mpjpegdec.c:359
static int mpjpeg_read_close(AVFormatContext *s)
Definition mpjpegdec.c:102
static int parse_multipart_header(AVIOContext *pb, int *size, const char *expected_boundary, void *log_ctx)
Definition mpjpegdec.c:167
static const AVClass mpjpeg_demuxer_class
Definition mpjpegdec.c:366
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
unsigned int pos
Definition spdifenc.c:431
Describe the class of an AVClass context structure.
Definition log.h:76
enum AVMediaType codec_type
General type of the encoded data.
Definition codec_par.h:53
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition codec_par.h:57
Format I/O context.
Definition avformat.h:1333
Bytestream IO Context.
Definition avio.h:160
int eof_reached
true if was unable to read due to error or eof
Definition avio.h:238
int error
contains the error code or 0 if no error happened
Definition avio.h:239
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
This structure contains the data a format has to probe a file.
Definition avformat.h:471
Stream structure.
Definition avformat.h:766
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition avformat.h:789
AVIOContext pub
#define av_freep(p)
#define av_log(a,...)
int size
int len