diff options
author | Luca Barbato <lu_zero@gentoo.org> | 2015-05-16 17:03:28 +0200 |
---|---|---|
committer | Luca Barbato <lu_zero@gentoo.org> | 2015-06-07 10:14:45 +0200 |
commit | 9b56ac74b170d12027fbc81f581a451a709f1105 (patch) | |
tree | 84d1c34490ef22c3a07d0ed3a05342a4c592e3b9 | |
parent | 0289f81241e720452b5a77713488d54d3ec252d7 (diff) | |
download | ffmpeg-streaming-9b56ac74b170d12027fbc81f581a451a709f1105.zip ffmpeg-streaming-9b56ac74b170d12027fbc81f581a451a709f1105.tar.gz |
mpjpeg: Initial implementation
Support only streams with Content-Length.
Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | libavformat/Makefile | 1 | ||||
-rw-r--r-- | libavformat/allformats.c | 2 | ||||
-rw-r--r-- | libavformat/mpjpegdec.c | 223 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
5 files changed, 227 insertions, 2 deletions
@@ -32,6 +32,7 @@ version <next>: - Automatically rotate videos based on metadata in avconv - improved Quickdraw compatibility - NVIDIA NVENC-accelerated H.264 and HEVC encoding support +- Multipart JPEG demuxer version 11: diff --git a/libavformat/Makefile b/libavformat/Makefile index 0323ad5..21c4e5e 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -205,6 +205,7 @@ OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o isom.o OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o +OBJS-$(CONFIG_MPJPEG_DEMUXER) += mpjpegdec.o OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o OBJS-$(CONFIG_MSNWC_TCP_DEMUXER) += msnwc_tcp.o OBJS-$(CONFIG_MTV_DEMUXER) += mtv.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index ff296cb..1f76b1b 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -163,7 +163,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(MPEGTS, mpegts); REGISTER_DEMUXER (MPEGTSRAW, mpegtsraw); REGISTER_DEMUXER (MPEGVIDEO, mpegvideo); - REGISTER_MUXER (MPJPEG, mpjpeg); + REGISTER_MUXDEMUX(MPJPEG, mpjpeg); REGISTER_DEMUXER (MSNWC_TCP, msnwc_tcp); REGISTER_DEMUXER (MTV, mtv); REGISTER_DEMUXER (MV, mv); diff --git a/libavformat/mpjpegdec.c b/libavformat/mpjpegdec.c new file mode 100644 index 0000000..354278c --- /dev/null +++ b/libavformat/mpjpegdec.c @@ -0,0 +1,223 @@ +/* + * Multipart JPEG format + * Copyright (c) 2015 Luca Barbato + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" + +#include "avformat.h" +#include "internal.h" + +static int get_line(AVIOContext *pb, char *line, int line_size) +{ + int i = ff_get_line(pb, line, line_size); + + if (i > 1 && line[i - 2] == '\r') + line[i - 2] = '\0'; + + if (pb->error) + return pb->error; + + if (pb->eof_reached) + return AVERROR_EOF; + + return 0; +} + +static int split_tag_value(char **tag, char **value, char *line) +{ + char *p = line; + + while (*p != '\0' && *p != ':') + p++; + if (*p != ':') + return AVERROR_INVALIDDATA; + + *p = '\0'; + *tag = line; + + p++; + + while (av_isspace(*p)) + p++; + + *value = p; + + return 0; +} + +static int check_content_type(char *line) +{ + char *tag, *value; + int ret = split_tag_value(&tag, &value, line); + + if (ret < 0) + return ret; + + if (av_strcasecmp(tag, "Content-type") || + av_strcasecmp(value, "image/jpeg")) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int mpjpeg_read_probe(AVProbeData *p) +{ + AVIOContext *pb; + char line[128] = { 0 }; + int ret = 0; + + pb = avio_alloc_context(p->buf, p->buf_size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return AVERROR(ENOMEM); + + if (p->buf_size < 2 || p->buf[0] != '-' || p->buf[1] != '-') + return 0; + + while (!pb->eof_reached) { + ret = get_line(pb, line, sizeof(line)); + if (ret < 0) + break; + + ret = check_content_type(line); + if (!ret) { + ret = AVPROBE_SCORE_MAX; + break; + } + } + + av_free(pb); + + return ret; +} + +static int mpjpeg_read_header(AVFormatContext *s) +{ + AVStream *st; + char boundary[70 + 2 + 1]; + int64_t pos = avio_tell(s->pb); + int ret; + + + ret = get_line(s->pb, boundary, sizeof(boundary)); + if (ret < 0) + return ret; + + if (strncmp(boundary, "--", 2)) + return AVERROR_INVALIDDATA; + + st = avformat_new_stream(s, NULL); + + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = AV_CODEC_ID_MJPEG; + + avpriv_set_pts_info(st, 60, 1, 25); + + avio_seek(s->pb, pos, SEEK_SET); + + return 0; +} + +static int parse_content_length(const char *value) +{ + long int val = strtol(value, NULL, 10); + + if (val == LONG_MIN || val == LONG_MAX) + return AVERROR(errno); + if (val > INT_MAX) + return AVERROR(ERANGE); + return val; +} + +static int parse_multipart_header(AVFormatContext *s) +{ + char line[128]; + int found_content_type = 0; + int ret, size = -1; + + ret = get_line(s->pb, line, sizeof(line)); + if (ret < 0) + return ret; + + if (strncmp(line, "--", 2)) + return AVERROR_INVALIDDATA; + + while (!s->pb->eof_reached) { + char *tag, *value; + + ret = get_line(s->pb, line, sizeof(line)); + if (ret < 0) + return ret; + + if (line[0] == '\0') + break; + + ret = split_tag_value(&tag, &value, line); + if (ret < 0) + return ret; + + if (!av_strcasecmp(tag, "Content-type")) { + if (av_strcasecmp(value, "image/jpeg")) { + av_log(s, AV_LOG_ERROR, + "Unexpected %s : %s\n", + tag, value); + return AVERROR_INVALIDDATA; + } else + found_content_type = 1; + } else if (!av_strcasecmp(tag, "Content-Length")) { + size = parse_content_length(value); + if (size < 0) + return size; + } + } + + if (!found_content_type || size < 0) { + return AVERROR_INVALIDDATA; + } + + return size; +} + +static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int ret; + int size = parse_multipart_header(s); + + if (size < 0) + return size; + + ret = av_get_packet(s->pb, pkt, size); + if (ret < 0) + return ret; + + // trailing empty line + avio_skip(s->pb, 2); + + return 0; +} + +AVInputFormat ff_mpjpeg_demuxer = { + .name = "mpjpeg", + .long_name = NULL_IF_CONFIG_SMALL("MIME multipart JPEG"), + .mime_type = "multipart/x-mixed-replace", + .extensions = "mjpg", + .read_probe = mpjpeg_read_probe, + .read_header = mpjpeg_read_header, + .read_packet = mpjpeg_read_packet, +}; diff --git a/libavformat/version.h b/libavformat/version.h index 495302a..714ec72 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 56 -#define LIBAVFORMAT_VERSION_MINOR 18 +#define LIBAVFORMAT_VERSION_MINOR 19 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |