From 2c253d7978a6c9c2dc701d393eb5b9d68e831c98 Mon Sep 17 00:00:00 2001 From: Alex Agranovsky Date: Tue, 24 Nov 2015 00:07:34 -0500 Subject: [PATCH 2/2] If available, use the actual boundary in HTTP response's Content-Type header, to separate MIME parts in mpjpeg stream This code is disabled by default so not to break some fragile endpoints sending invalid MIME, but can be enabled via AVOption 'strict_mime_boundary' Signed-off-by: Alex Agranovsky --- libavformat/mpjpegdec.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/libavformat/mpjpegdec.c b/libavformat/mpjpegdec.c index b9093ea..b89f128 100644 --- a/libavformat/mpjpegdec.c +++ b/libavformat/mpjpegdec.c @@ -20,6 +20,7 @@ */ #include "libavutil/avstring.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" @@ -28,9 +29,11 @@ typedef struct MPJPEGDemuxContext { + const AVClass *class; char* boundary; char* searchstr; int searchstr_len; + int strict_mime_boundary; } MPJPEGDemuxContext; @@ -245,6 +248,43 @@ static int parse_multipart_header(AVIOContext *pb, } +static char* mpjpeg_get_boundary(AVIOContext* pb) +{ + uint8_t *mime_type = NULL; + uint8_t *start; + uint8_t *end; + uint8_t *res = NULL; + int len; + + /* get MIME type, and skip to the first parameter */ + av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type); + start = mime_type; + while (start != NULL && *start != '\0') { + start = strchr(start, ';'); + if (start) + start = start+1; + + while (av_isspace(*start)) + start++; + + if (!av_strncasecmp(start, "boundary=", 9)) { + start += 9; + + end = strchr(start, ';'); + if (end) + len = end - start - 1; + else + len = strlen(start); + res = av_strndup(start, len); + break; + } + } + + av_freep(&mime_type); + return res; +} + + static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) { int size; @@ -252,8 +292,18 @@ static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) MPJPEGDemuxContext *mpjpeg = s->priv_data; if (mpjpeg->boundary == NULL) { - mpjpeg->boundary = av_strdup("--"); - mpjpeg->searchstr = av_strdup("\r\n--"); + uint8_t* boundary = NULL; + if (mpjpeg->strict_mime_boundary) { + boundary = mpjpeg_get_boundary(s->pb); + } + if (boundary != NULL) { + mpjpeg->boundary = boundary; + mpjpeg->searchstr = av_malloc(4+strlen(boundary)+1); + sprintf( mpjpeg->searchstr, "\r\n%s\r\n", boundary ); + } else { + mpjpeg->boundary = av_strdup("--"); + mpjpeg->searchstr = av_strdup("\r\n--"); + } mpjpeg->searchstr_len = strlen(mpjpeg->searchstr); if (!mpjpeg->boundary || !mpjpeg->searchstr) { av_freep(&mpjpeg->boundary); @@ -315,6 +365,22 @@ static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } +#define OFFSET(x) offsetof(MPJPEGDemuxContext, x) + +#define DEC AV_OPT_FLAG_DECODING_PARAM +const AVOption mpjpeg_options[] = { + { "strict_mime_boundary", "require MIME boundaries match", OFFSET(strict_mime_boundary), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, + { NULL } +}; + + +static const AVClass ff_mpjpeg_demuxer_class = { + .class_name = "MPJPEG demuxer", + .item_name = av_default_item_name, + .option = mpjpeg_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVInputFormat ff_mpjpeg_demuxer = { .name = "mpjpeg", .long_name = NULL_IF_CONFIG_SMALL("MIME multipart JPEG"), @@ -324,5 +390,8 @@ AVInputFormat ff_mpjpeg_demuxer = { .read_probe = mpjpeg_read_probe, .read_header = mpjpeg_read_header, .read_packet = mpjpeg_read_packet, - .read_close = mpjpeg_read_close + .read_close = mpjpeg_read_close, + .priv_class = &ff_mpjpeg_demuxer_class }; + + -- 2.4.9 (Apple Git-60)