diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2012-06-18 20:05:32 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2012-06-18 20:07:00 +0200 |
commit | 82edf6727f0663601351081ca1e4fb20d1752972 (patch) | |
tree | 12479c3ec8cedfa0ec4dda38a72023224f2b5b73 /libavformat | |
parent | f87dacb27de93f995cb18f9dcc73581ef8fc157b (diff) | |
parent | f61ce90caa909d131ea6ec205823568a38115529 (diff) | |
download | ffmpeg-82edf6727f0663601351081ca1e4fb20d1752972.tar.gz |
Merge remote-tracking branch 'qatar/master'
* qatar/master:
lavr: add x86-optimized functions for mixing 1-to-2 s16p with flt coeffs
lavr: add x86-optimized functions for mixing 1-to-2 fltp with flt coeffs
Add Dolby/DPLII downmix support to libavresample
vorbisdec: replace div/mod in loop with a counter
fate: vorbis: add 5.1 surround test
rtpenc: Allow requesting H264 RTP packetization mode 0
configure: Sort the library listings in the help text alphabetically
dwt: remove variable-length arrays
RTMPT protocol support
http: Properly handle chunked transfer-encoding for replies to post data
http: Fail reading if the connection has gone away
amr: Mark an array const
amr: More space cleanup
rtpenc: Fix memory leaks in the muxer open function
Conflicts:
Changelog
configure
doc/APIchanges
libavformat/version.h
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/Makefile | 2 | ||||
-rw-r--r-- | libavformat/allformats.c | 2 | ||||
-rw-r--r-- | libavformat/amr.c | 4 | ||||
-rw-r--r-- | libavformat/http.c | 16 | ||||
-rw-r--r-- | libavformat/rtmphttp.c | 239 | ||||
-rw-r--r-- | libavformat/rtmpproto.c | 30 | ||||
-rw-r--r-- | libavformat/rtpenc.c | 8 | ||||
-rw-r--r-- | libavformat/rtpenc.h | 2 | ||||
-rw-r--r-- | libavformat/rtpenc_h264.c | 6 | ||||
-rw-r--r-- | libavformat/sdp.c | 11 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
11 files changed, 303 insertions, 19 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile index 5e4f0022f2..3dca060994 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -373,6 +373,8 @@ OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o +OBJS-$(CONFIG_RTMPHTTP_PROTOCOL) += rtmphttp.o +OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 1862449a85..ed9227e5b6 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -277,6 +277,8 @@ void av_register_all(void) REGISTER_PROTOCOL (MD5, md5); REGISTER_PROTOCOL (PIPE, pipe); REGISTER_PROTOCOL (RTMP, rtmp); + REGISTER_PROTOCOL (RTMPHTTP, rtmphttp); + REGISTER_PROTOCOL (RTMPT, rtmpt); REGISTER_PROTOCOL (RTP, rtp); REGISTER_PROTOCOL (SCTP, sctp); REGISTER_PROTOCOL (TCP, tcp); diff --git a/libavformat/amr.c b/libavformat/amr.c index 4ff6b8d13f..23272e4caa 100644 --- a/libavformat/amr.c +++ b/libavformat/amr.c @@ -124,8 +124,8 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) }; size = packed_size[mode] + 1; - } else if(enc->codec_id == CODEC_ID_AMR_WB) { - static uint8_t packed_size[16] = { + } else if (enc->codec_id == CODEC_ID_AMR_WB) { + static const uint8_t packed_size[16] = { 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1 }; diff --git a/libavformat/http.c b/libavformat/http.c index 9a5ca625b0..fb4a83ad0e 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -352,6 +352,8 @@ static int http_read_header(URLContext *h, int *new_location) char line[1024]; int err = 0; + s->chunksize = -1; + for (;;) { if ((err = http_get_line(s, line, sizeof(line))) < 0) return err; @@ -470,7 +472,6 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, s->http_code = 200; return 0; } - s->chunksize = -1; /* wait for header */ err = http_read_header(h, new_location); @@ -510,14 +511,13 @@ static int http_read(URLContext *h, uint8_t *buf, int size) HTTPContext *s = h->priv_data; int err, new_location; - if (s->end_chunked_post) { - if (!s->end_header) { - err = http_read_header(h, &new_location); - if (err < 0) - return err; - } + if (!s->hd) + return AVERROR_EOF; - return http_buf_read(h, buf, size); + if (s->end_chunked_post && !s->end_header) { + err = http_read_header(h, &new_location); + if (err < 0) + return err; } if (s->chunksize >= 0) { diff --git a/libavformat/rtmphttp.c b/libavformat/rtmphttp.c new file mode 100644 index 0000000000..c431d28853 --- /dev/null +++ b/libavformat/rtmphttp.c @@ -0,0 +1,239 @@ +/* + * RTMP HTTP network protocol + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * RTMP HTTP protocol + */ + +#include "libavutil/avstring.h" +#include "libavutil/intfloat.h" +#include "libavutil/opt.h" +#include "internal.h" +#include "http.h" + +#define RTMPT_DEFAULT_PORT 80 + +/* protocol handler context */ +typedef struct RTMP_HTTPContext { + URLContext *stream; ///< HTTP stream + char host[256]; ///< hostname of the server + int port; ///< port to connect (default is 80) + char client_id[64]; ///< client ID used for all requests except the first one + int seq; ///< sequence ID used for all requests + uint8_t *out_data; ///< output buffer + int out_size; ///< current output buffer size + int out_capacity; ///< current output buffer capacity + int initialized; ///< flag indicating when the http context is initialized + int finishing; ///< flag indicating when the client closes the connection +} RTMP_HTTPContext; + +static int rtmp_http_send_cmd(URLContext *h, const char *cmd) +{ + RTMP_HTTPContext *rt = h->priv_data; + char uri[2048]; + uint8_t c; + int ret; + + ff_url_join(uri, sizeof(uri), "http", NULL, rt->host, rt->port, + "/%s/%s/%d", cmd, rt->client_id, rt->seq++); + + av_opt_set_bin(rt->stream->priv_data, "post_data", rt->out_data, + rt->out_size, 0); + + /* send a new request to the server */ + if ((ret = ff_http_do_new_request(rt->stream, uri)) < 0) + return ret; + + /* re-init output buffer */ + rt->out_size = 0; + + /* read the first byte which contains the polling interval */ + if ((ret = ffurl_read(rt->stream, &c, 1)) < 0) + return ret; + + return ret; +} + +static int rtmp_http_write(URLContext *h, const uint8_t *buf, int size) +{ + RTMP_HTTPContext *rt = h->priv_data; + void *ptr; + + if (rt->out_size + size > rt->out_capacity) { + rt->out_capacity = (rt->out_size + size) * 2; + ptr = av_realloc(rt->out_data, rt->out_capacity); + if (!ptr) + return AVERROR(ENOMEM); + rt->out_data = ptr; + } + + memcpy(rt->out_data + rt->out_size, buf, size); + rt->out_size += size; + + return size; +} + +static int rtmp_http_read(URLContext *h, uint8_t *buf, int size) +{ + RTMP_HTTPContext *rt = h->priv_data; + int ret, off = 0; + + /* try to read at least 1 byte of data */ + do { + ret = ffurl_read(rt->stream, buf + off, size); + if (ret < 0 && ret != AVERROR_EOF) + return ret; + + if (ret == AVERROR_EOF) { + if (rt->finishing) { + /* Do not send new requests when the client wants to + * close the connection. */ + return AVERROR(EAGAIN); + } + + /* When the client has reached end of file for the last request, + * we have to send a new request if we have buffered data. + * Otherwise, we have to send an idle POST. */ + if (rt->out_size > 0) { + if ((ret = rtmp_http_send_cmd(h, "send")) < 0) + return ret; + } else { + if ((ret = rtmp_http_write(h, "", 1)) < 0) + return ret; + + if ((ret = rtmp_http_send_cmd(h, "idle")) < 0) + return ret; + } + + if (h->flags & AVIO_FLAG_NONBLOCK) { + /* no incoming data to handle in nonblocking mode */ + return AVERROR(EAGAIN); + } + } else { + off += ret; + size -= ret; + } + } while (off <= 0); + + return off; +} + +static int rtmp_http_close(URLContext *h) +{ + RTMP_HTTPContext *rt = h->priv_data; + uint8_t tmp_buf[2048]; + int ret = 0; + + if (rt->initialized) { + /* client wants to close the connection */ + rt->finishing = 1; + + do { + ret = rtmp_http_read(h, tmp_buf, sizeof(tmp_buf)); + } while (ret > 0); + + /* re-init output buffer before sending the close command */ + rt->out_size = 0; + + if ((ret = rtmp_http_write(h, "", 1)) == 1) + ret = rtmp_http_send_cmd(h, "close"); + } + + av_freep(&rt->out_data); + ffurl_close(rt->stream); + + return ret; +} + +static int rtmp_http_open(URLContext *h, const char *uri, int flags) +{ + RTMP_HTTPContext *rt = h->priv_data; + char headers[1024], url[1024]; + int ret, off = 0; + + av_url_split(NULL, 0, NULL, 0, rt->host, sizeof(rt->host), &rt->port, + NULL, 0, uri); + + if (rt->port < 0) + rt->port = RTMPT_DEFAULT_PORT; + + /* This is the first request that is sent to the server in order to + * register a client on the server and start a new session. The server + * replies with a unique id (usually a number) that is used by the client + * for all future requests. + * Note: the reply doesn't contain a value for the polling interval. + * A successful connect resets the consecutive index that is used + * in the URLs. */ + ff_url_join(url, sizeof(url), "http", NULL, rt->host, rt->port, "/open/1"); + + /* alloc the http context */ + if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, NULL)) < 0) + goto fail; + + /* set options */ + snprintf(headers, sizeof(headers), + "Cache-Control: no-cache\r\n" + "Content-type: application/x-fcs\r\n" + "User-Agent: Shockwave Flash\r\n"); + av_opt_set(rt->stream->priv_data, "headers", headers, 0); + av_opt_set(rt->stream->priv_data, "multiple_requests", "1", 0); + av_opt_set_bin(rt->stream->priv_data, "post_data", "", 1, 0); + + /* open the http context */ + if ((ret = ffurl_connect(rt->stream, NULL)) < 0) + goto fail; + + /* read the server reply which contains a unique ID */ + for (;;) { + ret = ffurl_read(rt->stream, rt->client_id + off, sizeof(rt->client_id) - off); + if (ret == AVERROR_EOF) + break; + if (ret < 0) + goto fail; + off += ret; + if (off == sizeof(rt->client_id)) { + ret = AVERROR(EIO); + goto fail; + } + } + while (off > 0 && isspace(rt->client_id[off - 1])) + off--; + rt->client_id[off] = '\0'; + + /* http context is now initialized */ + rt->initialized = 1; + return 0; + +fail: + rtmp_http_close(h); + return ret; +} + +URLProtocol ff_rtmphttp_protocol = { + .name = "rtmphttp", + .url_open = rtmp_http_open, + .url_read = rtmp_http_read, + .url_write = rtmp_http_write, + .url_close = rtmp_http_close, + .priv_data_size = sizeof(RTMP_HTTPContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, +}; diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 03f959e009..07ec62cc43 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -1112,9 +1112,15 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), s->filename); - if (port < 0) - port = RTMP_DEFAULT_PORT; - ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); + if (!strcmp(proto, "rtmpt")) { + /* open the http tunneling connection */ + ff_url_join(buf, sizeof(buf), "rtmphttp", NULL, hostname, port, NULL); + } else { + /* open the tcp connection */ + if (port < 0) + port = RTMP_DEFAULT_PORT; + ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); + } if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, NULL)) < 0) { @@ -1425,3 +1431,21 @@ URLProtocol ff_rtmp_protocol = { .flags = URL_PROTOCOL_FLAG_NETWORK, .priv_data_class= &rtmp_class, }; + +static const AVClass rtmpt_class = { + .class_name = "rtmpt", + .item_name = av_default_item_name, + .option = rtmp_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +URLProtocol ff_rtmpt_protocol = { + .name = "rtmpt", + .url_open = rtmp_open, + .url_read = rtmp_read, + .url_write = rtmp_write, + .url_close = rtmp_close, + .priv_data_size = sizeof(RTMPContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &rtmpt_class, +}; diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index 57d025a364..e16e610820 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -198,11 +198,11 @@ static int rtp_write_header(AVFormatContext *s1) /* max_header_toc_size + the largest AMR payload must fit */ if (1 + s->max_frames_per_packet + n > s->max_payload_size) { av_log(s1, AV_LOG_ERROR, "RTP max payload size too small for AMR\n"); - return -1; + goto fail; } if (st->codec->channels != 1) { av_log(s1, AV_LOG_ERROR, "Only mono is supported\n"); - return -1; + goto fail; } case CODEC_ID_AAC: s->num_frames = 0; @@ -216,6 +216,10 @@ defaultcase: } return 0; + +fail: + av_freep(&s->buf); + return AVERROR(EINVAL); } /* send an rtcp sender report packet */ diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h index a83c633e73..8827cb3254 100644 --- a/libavformat/rtpenc.h +++ b/libavformat/rtpenc.h @@ -66,12 +66,14 @@ typedef struct RTPMuxContext RTPMuxContext; #define FF_RTP_FLAG_MP4A_LATM 1 #define FF_RTP_FLAG_RFC2190 2 #define FF_RTP_FLAG_SKIP_RTCP 4 +#define FF_RTP_FLAG_H264_MODE0 8 #define FF_RTP_FLAG_OPTS(ctx, fieldname) \ { "rtpflags", "RTP muxer flags", offsetof(ctx, fieldname), AV_OPT_TYPE_FLAGS, {.dbl = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ { "latm", "Use MP4A-LATM packetization instead of MPEG4-GENERIC for AAC", 0, AV_OPT_TYPE_CONST, {.dbl = FF_RTP_FLAG_MP4A_LATM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ { "rfc2190", "Use RFC 2190 packetization instead of RFC 4629 for H.263", 0, AV_OPT_TYPE_CONST, {.dbl = FF_RTP_FLAG_RFC2190}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ { "skip_rtcp", "Don't send RTCP sender reports", 0, AV_OPT_TYPE_CONST, {.dbl = FF_RTP_FLAG_SKIP_RTCP}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ + { "h264_mode0", "Use mode 0 for H264 in RTP", 0, AV_OPT_TYPE_CONST, {.dbl = FF_RTP_FLAG_H264_MODE0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, \ void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); diff --git a/libavformat/rtpenc_h264.c b/libavformat/rtpenc_h264.c index 86930bbac1..68f497590b 100644 --- a/libavformat/rtpenc_h264.c +++ b/libavformat/rtpenc_h264.c @@ -55,6 +55,12 @@ static void nal_send(AVFormatContext *s1, const uint8_t *buf, int size, int last uint8_t type = buf[0] & 0x1F; uint8_t nri = buf[0] & 0x60; + if (s->flags & FF_RTP_FLAG_H264_MODE0) { + av_log(s1, AV_LOG_ERROR, + "NAL size %d > %d, try -slice-max-size %d\n", size, + s->max_payload_size, s->max_payload_size); + return; + } av_log(s1, AV_LOG_DEBUG, "NAL size %d > %d\n", size, s->max_payload_size); s->buf[0] = 28; /* FU Indicator; Type = 28 ---> FU-A */ s->buf[0] |= nri; diff --git a/libavformat/sdp.c b/libavformat/sdp.c index caa661bbc2..5d5e9515f7 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -388,15 +388,20 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, char *config = NULL; switch (c->codec_id) { - case CODEC_ID_H264: + case CODEC_ID_H264: { + int mode = 1; + if (fmt && fmt->oformat->priv_class && + av_opt_flag_is_set(fmt->priv_data, "rtpflags", "h264_mode0")) + mode = 0; if (c->extradata_size) { config = extradata2psets(c); } av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n" - "a=fmtp:%d packetization-mode=1%s\r\n", + "a=fmtp:%d packetization-mode=%d%s\r\n", payload_type, - payload_type, config ? config : ""); + payload_type, mode, config ? config : ""); break; + } case CODEC_ID_H263: case CODEC_ID_H263P: /* a=framesize is required by 3GPP TS 26.234 (PSS). It diff --git a/libavformat/version.h b/libavformat/version.h index cca6c1aea4..0b1bff2764 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 54 -#define LIBAVFORMAT_VERSION_MINOR 7 +#define LIBAVFORMAT_VERSION_MINOR 8 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |