Browse code

Merge commit '9b56ac74b170d12027fbc81f581a451a709f1105'

* commit '9b56ac74b170d12027fbc81f581a451a709f1105':
mpjpeg: Initial implementation

Conflicts:
Changelog
libavformat/allformats.c
libavformat/version.h

Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2015/06/08 07:44:28
Showing 5 changed files
... ...
@@ -24,6 +24,7 @@ version <next>:
24 24
 - WebPAnimEncoder API when available for encoding and muxing WebP
25 25
 - Direct3D11-accelerated decoding
26 26
 - Support Secure Transport
27
+- Multipart JPEG demuxer
27 28
 
28 29
 
29 30
 version 2.6:
... ...
@@ -271,6 +271,7 @@ OBJS-$(CONFIG_MPEGPS_DEMUXER)            += mpeg.o
271 271
 OBJS-$(CONFIG_MPEGTS_DEMUXER)            += mpegts.o isom.o
272 272
 OBJS-$(CONFIG_MPEGTS_MUXER)              += mpegtsenc.o
273 273
 OBJS-$(CONFIG_MPEGVIDEO_DEMUXER)         += mpegvideodec.o rawdec.o
274
+OBJS-$(CONFIG_MPJPEG_DEMUXER)            += mpjpegdec.o
274 275
 OBJS-$(CONFIG_MPJPEG_MUXER)              += mpjpeg.o
275 276
 OBJS-$(CONFIG_MPL2_DEMUXER)              += mpl2dec.o subtitles.o
276 277
 OBJS-$(CONFIG_MPSUB_DEMUXER)             += mpsubdec.o subtitles.o
... ...
@@ -198,7 +198,7 @@ void av_register_all(void)
198 198
     REGISTER_MUXDEMUX(MPEGTS,           mpegts);
199 199
     REGISTER_DEMUXER (MPEGTSRAW,        mpegtsraw);
200 200
     REGISTER_DEMUXER (MPEGVIDEO,        mpegvideo);
201
-    REGISTER_MUXER   (MPJPEG,           mpjpeg);
201
+    REGISTER_MUXDEMUX(MPJPEG,           mpjpeg);
202 202
     REGISTER_DEMUXER (MPL2,             mpl2);
203 203
     REGISTER_DEMUXER (MPSUB,            mpsub);
204 204
     REGISTER_DEMUXER (MSNWC_TCP,        msnwc_tcp);
205 205
new file mode 100644
... ...
@@ -0,0 +1,223 @@
0
+/*
1
+ * Multipart JPEG format
2
+ * Copyright (c) 2015 Luca Barbato
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "libavutil/avstring.h"
22
+
23
+#include "avformat.h"
24
+#include "internal.h"
25
+
26
+static int get_line(AVIOContext *pb, char *line, int line_size)
27
+{
28
+    int i = ff_get_line(pb, line, line_size);
29
+
30
+    if (i > 1 && line[i - 2] == '\r')
31
+        line[i - 2] = '\0';
32
+
33
+    if (pb->error)
34
+        return pb->error;
35
+
36
+    if (pb->eof_reached)
37
+        return AVERROR_EOF;
38
+
39
+    return 0;
40
+}
41
+
42
+static int split_tag_value(char **tag, char **value, char *line)
43
+{
44
+    char *p = line;
45
+
46
+    while (*p != '\0' && *p != ':')
47
+        p++;
48
+    if (*p != ':')
49
+        return AVERROR_INVALIDDATA;
50
+
51
+    *p   = '\0';
52
+    *tag = line;
53
+
54
+    p++;
55
+
56
+    while (av_isspace(*p))
57
+        p++;
58
+
59
+    *value = p;
60
+
61
+    return 0;
62
+}
63
+
64
+static int check_content_type(char *line)
65
+{
66
+    char *tag, *value;
67
+    int ret = split_tag_value(&tag, &value, line);
68
+
69
+    if (ret < 0)
70
+        return ret;
71
+
72
+    if (av_strcasecmp(tag, "Content-type") ||
73
+        av_strcasecmp(value, "image/jpeg"))
74
+        return AVERROR_INVALIDDATA;
75
+
76
+    return 0;
77
+}
78
+
79
+static int mpjpeg_read_probe(AVProbeData *p)
80
+{
81
+    AVIOContext *pb;
82
+    char line[128] = { 0 };
83
+    int ret = 0;
84
+
85
+    pb = avio_alloc_context(p->buf, p->buf_size, 0, NULL, NULL, NULL, NULL);
86
+    if (!pb)
87
+        return AVERROR(ENOMEM);
88
+
89
+    if (p->buf_size < 2 || p->buf[0] != '-' || p->buf[1] != '-')
90
+        return 0;
91
+
92
+    while (!pb->eof_reached) {
93
+        ret = get_line(pb, line, sizeof(line));
94
+        if (ret < 0)
95
+            break;
96
+
97
+        ret = check_content_type(line);
98
+        if (!ret) {
99
+            ret = AVPROBE_SCORE_MAX;
100
+            break;
101
+        }
102
+    }
103
+
104
+    av_free(pb);
105
+
106
+    return ret;
107
+}
108
+
109
+static int mpjpeg_read_header(AVFormatContext *s)
110
+{
111
+    AVStream *st;
112
+    char boundary[70 + 2 + 1];
113
+    int64_t pos = avio_tell(s->pb);
114
+    int ret;
115
+
116
+
117
+    ret = get_line(s->pb, boundary, sizeof(boundary));
118
+    if (ret < 0)
119
+        return ret;
120
+
121
+    if (strncmp(boundary, "--", 2))
122
+        return AVERROR_INVALIDDATA;
123
+
124
+    st = avformat_new_stream(s, NULL);
125
+
126
+    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
127
+    st->codec->codec_id   = AV_CODEC_ID_MJPEG;
128
+
129
+    avpriv_set_pts_info(st, 60, 1, 25);
130
+
131
+    avio_seek(s->pb, pos, SEEK_SET);
132
+
133
+    return 0;
134
+}
135
+
136
+static int parse_content_length(const char *value)
137
+{
138
+    long int val = strtol(value, NULL, 10);
139
+
140
+    if (val == LONG_MIN || val == LONG_MAX)
141
+        return AVERROR(errno);
142
+    if (val > INT_MAX)
143
+        return AVERROR(ERANGE);
144
+    return val;
145
+}
146
+
147
+static int parse_multipart_header(AVFormatContext *s)
148
+{
149
+    char line[128];
150
+    int found_content_type = 0;
151
+    int ret, size = -1;
152
+
153
+    ret = get_line(s->pb, line, sizeof(line));
154
+    if (ret < 0)
155
+        return ret;
156
+
157
+    if (strncmp(line, "--", 2))
158
+        return AVERROR_INVALIDDATA;
159
+
160
+    while (!s->pb->eof_reached) {
161
+        char *tag, *value;
162
+
163
+        ret = get_line(s->pb, line, sizeof(line));
164
+        if (ret < 0)
165
+            return ret;
166
+
167
+        if (line[0] == '\0')
168
+            break;
169
+
170
+        ret = split_tag_value(&tag, &value, line);
171
+        if (ret < 0)
172
+            return ret;
173
+
174
+        if (!av_strcasecmp(tag, "Content-type")) {
175
+            if (av_strcasecmp(value, "image/jpeg")) {
176
+                av_log(s, AV_LOG_ERROR,
177
+                       "Unexpected %s : %s\n",
178
+                       tag, value);
179
+                return AVERROR_INVALIDDATA;
180
+            } else
181
+                found_content_type = 1;
182
+        } else if (!av_strcasecmp(tag, "Content-Length")) {
183
+            size = parse_content_length(value);
184
+            if (size < 0)
185
+                return size;
186
+        }
187
+    }
188
+
189
+    if (!found_content_type || size < 0) {
190
+        return AVERROR_INVALIDDATA;
191
+    }
192
+
193
+    return size;
194
+}
195
+
196
+static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt)
197
+{
198
+    int ret;
199
+    int size = parse_multipart_header(s);
200
+
201
+    if (size < 0)
202
+        return size;
203
+
204
+    ret = av_get_packet(s->pb, pkt, size);
205
+    if (ret < 0)
206
+        return ret;
207
+
208
+    // trailing empty line
209
+    avio_skip(s->pb, 2);
210
+
211
+    return 0;
212
+}
213
+
214
+AVInputFormat ff_mpjpeg_demuxer = {
215
+    .name              = "mpjpeg",
216
+    .long_name         = NULL_IF_CONFIG_SMALL("MIME multipart JPEG"),
217
+    .mime_type         = "multipart/x-mixed-replace",
218
+    .extensions        = "mjpg",
219
+    .read_probe        = mpjpeg_read_probe,
220
+    .read_header       = mpjpeg_read_header,
221
+    .read_packet       = mpjpeg_read_packet,
222
+};
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/version.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 56
33
-#define LIBAVFORMAT_VERSION_MINOR  34
33
+#define LIBAVFORMAT_VERSION_MINOR  35
34 34
 #define LIBAVFORMAT_VERSION_MICRO 100
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \