--- /dev/null
+diff --git a/libavcodec/aacps.c b/libavcodec/aacps.c
+index 655e8fe5b4..45190d678d 100644
+--- a/libavcodec/aacps.c
++++ b/libavcodec/aacps.c
+@@ -397,7 +397,7 @@ static void map_val_20_to_34(INTFLOAT par[PS_MAX_NR_IIDICC])
+ par[ 1] = AAC_HALF_SUM(par[ 0], par[ 1]);
+ }
+
+-static void decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34)
++static void __attribute__((optimize(0))) decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34)
+ {
+ LOCAL_ALIGNED_16(INTFLOAT, power, [34], [PS_QMF_TIME_SLOTS]);
+ LOCAL_ALIGNED_16(INTFLOAT, transient_gain, [34], [PS_QMF_TIME_SLOTS]);
+diff --git a/libavcodec/fft_template.c b/libavcodec/fft_template.c
+index f2742a3ae8..59b4085eba 100644
+--- a/libavcodec/fft_template.c
++++ b/libavcodec/fft_template.c
+@@ -551,7 +551,7 @@ static void fft##n(FFTComplex *z)\
+ pass(z,FFT_NAME(ff_cos_##n),n4/2);\
+ }
+
+-static void fft4(FFTComplex *z)
++static void __attribute__((optimize(0))) fft4(FFTComplex *z)
+ {
+ FFTDouble t1, t2, t3, t4, t5, t6, t7, t8;
+
+@@ -565,7 +565,7 @@ static void fft4(FFTComplex *z)
+ BF(z[2].im, z[0].im, t2, t5);
+ }
+
+-static void fft8(FFTComplex *z)
++static void __attribute__((optimize(0))) fft8(FFTComplex *z)
+ {
+ FFTDouble t1, t2, t3, t4, t5, t6;
+
+diff --git a/libavcodec/mdct_template.c b/libavcodec/mdct_template.c
+index a854ad2700..6119be0d1a 100644
+--- a/libavcodec/mdct_template.c
++++ b/libavcodec/mdct_template.c
+@@ -98,7 +98,7 @@ av_cold int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale)
+ * @param output N/2 samples
+ * @param input N/2 samples
+ */
+-void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
++void __attribute__((optimize(0))) ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
+ {
+ int k, n8, n4, n2, n, j;
+ const uint16_t *revtab = s->revtab;
--- /dev/null
+diff --git a/libavutil/common.h b/libavutil/common.h
+index fd1404be6c..0bb8650e83 100644
+--- a/libavutil/common.h
++++ b/libavutil/common.h
+@@ -350,7 +350,8 @@ static av_always_inline int64_t av_sat_add64_c(int64_t a, int64_t b) {
+ return !__builtin_add_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);
+ #else
+ int64_t s = a+(uint64_t)b;
+- if ((int64_t)(a^b | ~s^b) >= 0)
++ // PATCH: GCC 4.9.4 complains about missing parentheses when combining bitwise operations.
++ if ((int64_t)((a^b) | (~s^b)) >= 0)
+ return INT64_MAX ^ (b >> 63);
+ return s;
+ #endif
--- /dev/null
+diff --git a/libavcodec/Makefile b/libavcodec/Makefile
+index 457ec58377..49bf260764 100644
+--- a/libavcodec/Makefile
++++ b/libavcodec/Makefile
+@@ -1209,6 +1209,8 @@ OBJS-$(CONFIG_SETTS_BSF) += setts_bsf.o
+ OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o
+ OBJS-$(CONFIG_TRACE_HEADERS_BSF) += trace_headers_bsf.o
+ OBJS-$(CONFIG_TRUEHD_CORE_BSF) += truehd_core_bsf.o mlp_parse.o mlp.o
++OBJS-$(CONFIG_VC1_ASFTORCV_BSF) += vc1_asftorcv_bsf.o
++OBJS-$(CONFIG_VC1_ASFTOANNEXG_BSF) += vc1_asftoannexg_bsf.o vc1.o
+ OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o
+ OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o
+ OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o
+diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c
+index 444423ae93..482d3473b2 100644
+--- a/libavcodec/bitstream_filters.c
++++ b/libavcodec/bitstream_filters.c
+@@ -59,6 +59,8 @@ extern const FFBitStreamFilter ff_setts_bsf;
+ extern const FFBitStreamFilter ff_text2movsub_bsf;
+ extern const FFBitStreamFilter ff_trace_headers_bsf;
+ extern const FFBitStreamFilter ff_truehd_core_bsf;
++extern const FFBitStreamFilter ff_vc1_asftoannexg_bsf;
++extern const FFBitStreamFilter ff_vc1_asftorcv_bsf;
+ extern const FFBitStreamFilter ff_vp9_metadata_bsf;
+ extern const FFBitStreamFilter ff_vp9_raw_reorder_bsf;
+ extern const FFBitStreamFilter ff_vp9_superframe_bsf;
+diff --git a/libavcodec/vc1_asftoannexg_bsf.c b/libavcodec/vc1_asftoannexg_bsf.c
+new file mode 100644
+index 0000000000..2901f84d9c
+--- /dev/null
++++ b/libavcodec/vc1_asftoannexg_bsf.c
+@@ -0,0 +1,190 @@
++/*
++ * copyright (c) 2010 Google Inc.
++ * copyright (c) 2013 CoolStream International Ltd.
++ * copyright (c) 2017 Jacek Jendrzej port to 3.x
++ * 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
++ */
++
++#include "avcodec.h"
++#include "bytestream.h"
++#include "vc1.h"
++#include "bsf.h"
++#include "bsf_internal.h"
++
++// An arbitrary limit in bytes greater than the current bytes used.
++#define MAX_SEQ_HEADER_SIZE 50
++
++typedef struct ASFTOANNEXGBSFContext {
++ int frames;
++ uint8_t *seq_header;
++ int seq_header_size;
++ uint8_t *ep_header;
++ int ep_header_size;
++} ASFTOANNEXGBSFContext;
++
++static int find_codec_data(ASFTOANNEXGBSFContext *ctx, uint8_t *data, int data_size, int keyframe) {
++ const uint8_t *start = data;
++ const uint8_t *end = data + data_size;
++ const uint8_t *next;
++ int size;
++ int has_seq_header = 0;
++ int has_ep_header = 0;
++ int has_frame_header = 0;
++
++ start = find_next_marker(start, end);
++ next = start;
++ for(; next < end; start = next){
++ next = find_next_marker(start + 4, end);
++ size = next - start;
++ if(size <= 0) continue;
++ switch(AV_RB32(start)){
++ case VC1_CODE_SEQHDR:
++ has_seq_header = 1;
++ break;
++ case VC1_CODE_ENTRYPOINT:
++ has_ep_header = 1;
++ break;
++ case VC1_CODE_FRAME:
++ has_frame_header = 1;
++ break;
++ default:
++ break;
++ }
++ }
++
++ if((has_seq_header && has_ep_header && has_frame_header && keyframe) ||
++ (!has_seq_header && !has_ep_header && has_frame_header) ) return 0;
++
++ return -1;
++}
++
++static int parse_extradata(ASFTOANNEXGBSFContext *ctx, uint8_t *extradata, int extradata_size) {
++ const uint8_t *start = extradata;
++ const uint8_t *end = extradata + extradata_size;
++ const uint8_t *next;
++ int size;
++
++ start = find_next_marker(start, end);
++ next = start;
++ for(; next < end; start = next){
++ next = find_next_marker(start + 4, end);
++ size = next - start;
++ if(size <= 0) continue;
++ switch(AV_RB32(start)){
++ case VC1_CODE_SEQHDR:
++ ctx->seq_header = av_mallocz(size);
++ ctx->seq_header_size = size;
++ memcpy(ctx->seq_header, start, size);
++ break;
++ case VC1_CODE_ENTRYPOINT:
++ ctx->ep_header = av_malloc(size);
++ ctx->ep_header_size = size;
++ memcpy(ctx->ep_header, start, size);
++ break;
++ default:
++ break;
++ }
++ }
++
++ if(!ctx->seq_header || !ctx->ep_header) {
++ av_log(NULL, AV_LOG_ERROR, "Incomplete extradata\n");
++ return -1;
++ }
++ return 0;
++}
++
++static int asftoannexg_filter(AVBSFContext *ctx, AVPacket *out)
++{
++ ASFTOANNEXGBSFContext* bsfctx = ctx->priv_data;
++ AVPacket *in;
++ int keyframe;
++ int ret;
++ uint8_t* bs = NULL;
++
++ ret = ff_bsf_get_packet(ctx, &in);
++ if (ret < 0)
++ return ret;
++
++ keyframe = in->flags & AV_PKT_FLAG_KEY;
++ if(in->size >= 1 && !find_codec_data(bsfctx, in->data, in->size, keyframe)) {
++// av_log(NULL, AV_LOG_INFO, "Nothing to do: %i\n",in->size);
++ av_packet_move_ref(out, in);
++ av_packet_free(&in);
++ return 0;
++ }
++
++ if(!ctx->par_in->extradata || ctx->par_in->extradata_size < 16) {
++ av_log(NULL, AV_LOG_INFO, "Extradata size too small: %i\n", ctx->par_in->extradata_size);
++ av_packet_move_ref(out, in);
++ av_packet_free(&in);
++ return 0;
++ }
++
++ if (!bsfctx->frames && parse_extradata(bsfctx, ctx->par_in->extradata , ctx->par_in->extradata_size) < 0) {
++ av_packet_free(&in);
++ av_log(NULL, AV_LOG_ERROR, "Cannot parse extra data!\n");
++ return -1;
++ }
++
++ if (keyframe) {
++ // If this is the keyframe, need to put sequence header and entry point header.
++ ret = av_new_packet(out, bsfctx->seq_header_size + bsfctx->ep_header_size + 4 + in->size);
++ if (ret < 0)
++ goto exit;
++ bs = out->data;
++
++ memcpy(bs, bsfctx->seq_header, bsfctx->seq_header_size);
++ bs += bsfctx->seq_header_size;
++ memcpy(bs, bsfctx->ep_header, bsfctx->ep_header_size);
++ bs += bsfctx->ep_header_size;
++ } else {
++ ret = av_new_packet(out, 4 + in->size);
++ if (ret < 0)
++ goto exit;
++ bs = out->data;
++ }
++
++ // Put the frame start code and frame data.
++ bytestream_put_be32(&bs, VC1_CODE_FRAME);
++ memcpy(bs, in->data, in->size);
++ ++bsfctx->frames;
++
++ ret = av_packet_copy_props(out, in);
++
++exit:
++ av_packet_free(&in);
++
++ return ret;
++}
++
++static void asftoannexg_close(AVBSFContext *bsfc) {
++ ASFTOANNEXGBSFContext *bsfctx = bsfc->priv_data;
++ av_freep(&bsfctx->seq_header);
++ av_freep(&bsfctx->ep_header);
++}
++
++static const enum AVCodecID codec_ids[] = {
++ AV_CODEC_ID_VC1, AV_CODEC_ID_NONE,
++};
++
++FFBitStreamFilter ff_vc1_asftoannexg_bsf = {
++ .p.name = "vc1_asftoannexg",
++ .priv_data_size = sizeof(ASFTOANNEXGBSFContext),
++ .filter = asftoannexg_filter,
++ .close = asftoannexg_close,
++ .p.codec_ids = codec_ids,
++};
+diff --git a/libavcodec/vc1_asftorcv_bsf.c b/libavcodec/vc1_asftorcv_bsf.c
+new file mode 100644
+index 0000000000..02e510b4b6
+--- /dev/null
++++ b/libavcodec/vc1_asftorcv_bsf.c
+@@ -0,0 +1,105 @@
++/*
++ * copyright (c) 2010 Google Inc.
++ * copyright (c) 2017 Jacek Jendrzej port to 3.x
++ * 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
++ */
++
++#include "avcodec.h"
++#include "bytestream.h"
++#include "bsf.h"
++#include "bsf_internal.h"
++
++#define RCV_STREAM_HEADER_SIZE 36
++#define RCV_PICTURE_HEADER_SIZE 8
++
++typedef struct ASFTORCVBSFContext {
++ int frames;
++} ASFTORCVBSFContext;
++
++static int asftorcv_filter(AVBSFContext *ctx, AVPacket *out){
++ ASFTORCVBSFContext* bsfctx = ctx->priv_data;
++ AVPacket *in;
++ int keyframe;
++ int ret;
++ uint8_t* bs = NULL;
++
++ ret = ff_bsf_get_packet(ctx, &in);
++ if (ret < 0)
++ return ret;
++
++ keyframe = in->flags & AV_PKT_FLAG_KEY;
++
++ if (!bsfctx->frames) {
++ // Write the header if this is the first frame.
++ ret = av_new_packet(out, RCV_STREAM_HEADER_SIZE + RCV_PICTURE_HEADER_SIZE + in->size);
++ if (ret < 0)
++ goto exit;
++ bs = out->data;
++
++ // The following structure of stream header comes from libavformat/vc1testenc.c.
++ bytestream_put_le24(&bs, 0); // Frame count. 0 for streaming.
++ bytestream_put_byte(&bs, 0xC5);
++ bytestream_put_le32(&bs, 4); // 4 bytes of extra data.
++ bytestream_put_byte(&bs, ctx->par_in->extradata[0]);
++ bytestream_put_byte(&bs, ctx->par_in->extradata[1]);
++ bytestream_put_byte(&bs, ctx->par_in->extradata[2]);
++ bytestream_put_byte(&bs, ctx->par_in->extradata[3]);
++ bytestream_put_le32(&bs, ctx->par_in->height);
++ bytestream_put_le32(&bs, ctx->par_in->width);
++ bytestream_put_le32(&bs, 0xC);
++ bytestream_put_le24(&bs, 0); // hrd_buffer
++ bytestream_put_byte(&bs, 0x80); // level|cbr|res1
++ bytestream_put_le32(&bs, 0); // hrd_rate
++
++ // The following LE32 describes the frame rate. Since we don't care so fill
++ // it with 0xFFFFFFFF which means variable framerate.
++ // See: libavformat/vc1testenc.c
++ bytestream_put_le32(&bs, 0xFFFFFFFF);
++ } else {
++ ret = av_new_packet(out, RCV_PICTURE_HEADER_SIZE + in->size);
++ if (ret < 0)
++ goto exit;
++ bs = out->data;
++ }
++
++ // Write the picture header.
++ bytestream_put_le32(&bs, in->size | (keyframe ? 0x80000000 : 0));
++
++ // The following LE32 describes the pts. Since we don't care so fill it with 0.
++ bytestream_put_le32(&bs, 0);
++ memcpy(bs, in->data, in->size);
++
++ ++bsfctx->frames;
++
++ ret = av_packet_copy_props(out, in);
++
++exit:
++ av_packet_free(&in);
++
++ return ret;
++}
++
++static const enum AVCodecID codec_ids[] = {
++ AV_CODEC_ID_WMV3, AV_CODEC_ID_NONE,
++};
++
++FFBitStreamFilter ff_vc1_asftorcv_bsf = {
++ .p.name = "vc1_asftorcv",
++ .priv_data_size = sizeof(ASFTORCVBSFContext),
++ .filter = asftorcv_filter,
++ .p.codec_ids = codec_ids,
++};
--- /dev/null
+diff --git a/configure b/configure
+index ba5793b2ff..b199365427 100755
+--- a/configure
++++ b/configure
+@@ -3549,10 +3549,8 @@ xv_outdev_deps="xlib_xv xlib_x11 xlib_xext"
+ # protocols
+ async_protocol_deps="threads"
+ bluray_protocol_deps="libbluray"
+-ffrtmpcrypt_protocol_conflict="librtmp_protocol"
+ ffrtmpcrypt_protocol_deps_any="gcrypt gmp openssl mbedtls"
+ ffrtmpcrypt_protocol_select="tcp_protocol"
+-ffrtmphttp_protocol_conflict="librtmp_protocol"
+ ffrtmphttp_protocol_select="http_protocol"
+ ftp_protocol_select="tcp_protocol"
+ gopher_protocol_select="tcp_protocol"
+@@ -3566,20 +3564,18 @@ https_protocol_suggest="zlib"
+ icecast_protocol_select="http_protocol"
+ mmsh_protocol_select="http_protocol"
+ mmst_protocol_select="network"
+-rtmp_protocol_conflict="librtmp_protocol"
+-rtmp_protocol_select="tcp_protocol"
+-rtmp_protocol_suggest="zlib"
+-rtmpe_protocol_select="ffrtmpcrypt_protocol"
+-rtmpe_protocol_suggest="zlib"
+-rtmps_protocol_conflict="librtmp_protocol"
+-rtmps_protocol_select="tls_protocol"
+-rtmps_protocol_suggest="zlib"
+-rtmpt_protocol_select="ffrtmphttp_protocol"
+-rtmpt_protocol_suggest="zlib"
+-rtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol"
+-rtmpte_protocol_suggest="zlib"
+-rtmpts_protocol_select="ffrtmphttp_protocol https_protocol"
+-rtmpts_protocol_suggest="zlib"
++ffrtmp_protocol_select="tcp_protocol"
++ffrtmp_protocol_suggest="zlib"
++ffrtmpe_protocol_select="ffrtmpcrypt_protocol"
++ffrtmpe_protocol_suggest="zlib"
++ffrtmps_protocol_select="tls_protocol"
++ffrtmps_protocol_suggest="zlib"
++ffrtmpt_protocol_select="ffrtmphttp_protocol"
++ffrtmpt_protocol_suggest="zlib"
++ffrtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol"
++ffrtmpte_protocol_suggest="zlib"
++ffrtmpts_protocol_select="ffrtmphttp_protocol https_protocol"
++ffrtmpts_protocol_suggest="zlib"
+ rtp_protocol_select="udp_protocol"
+ schannel_conflict="openssl gnutls libtls mbedtls"
+ sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags"
+diff --git a/libavformat/Makefile b/libavformat/Makefile
+index 6c6b779080..f641b43de6 100644
+--- a/libavformat/Makefile
++++ b/libavformat/Makefile
+@@ -656,12 +656,12 @@ OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf_tags.o
+ OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf_tags.o
+ OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
+ OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o
+-OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
+-OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
+-OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
+-OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
+-OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
+-OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
++OBJS-$(CONFIG_FFRTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
++OBJS-$(CONFIG_FFRTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
++OBJS-$(CONFIG_FFRTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
++OBJS-$(CONFIG_FFRTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
++OBJS-$(CONFIG_FFRTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
++OBJS-$(CONFIG_FFRTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
+ OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o ip.o
+ OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
+ OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
+diff --git a/libavformat/protocols.c b/libavformat/protocols.c
+index 6ee62a598a..3480a2b521 100644
+--- a/libavformat/protocols.c
++++ b/libavformat/protocols.c
+@@ -44,12 +44,12 @@ extern const URLProtocol ff_mmst_protocol;
+ extern const URLProtocol ff_md5_protocol;
+ extern const URLProtocol ff_pipe_protocol;
+ extern const URLProtocol ff_prompeg_protocol;
+-extern const URLProtocol ff_rtmp_protocol;
+-extern const URLProtocol ff_rtmpe_protocol;
+-extern const URLProtocol ff_rtmps_protocol;
+-extern const URLProtocol ff_rtmpt_protocol;
+-extern const URLProtocol ff_rtmpte_protocol;
+-extern const URLProtocol ff_rtmpts_protocol;
++extern const URLProtocol ff_ffrtmp_protocol;
++extern const URLProtocol ff_ffrtmpe_protocol;
++extern const URLProtocol ff_ffrtmps_protocol;
++extern const URLProtocol ff_ffrtmpt_protocol;
++extern const URLProtocol ff_ffrtmpte_protocol;
++extern const URLProtocol ff_ffrtmpts_protocol;
+ extern const URLProtocol ff_rtp_protocol;
+ extern const URLProtocol ff_sctp_protocol;
+ extern const URLProtocol ff_srtp_protocol;
+diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
+index f0ef223f05..53a078b426 100644
+--- a/libavformat/rtmpproto.c
++++ b/libavformat/rtmpproto.c
+@@ -2594,7 +2594,7 @@ static int inject_fake_duration_metadata(RTMPContext *rt)
+ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
+ {
+ RTMPContext *rt = s->priv_data;
+- char proto[8], hostname[256], path[1024], auth[100], *fname;
++ char *proto, tmpProto[10], hostname[256], path[1024], auth[100], *fname;
+ char *old_app, *qmark, *n, fname_buffer[1024];
+ uint8_t buf[2048];
+ int port;
+@@ -2605,7 +2605,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **o
+
+ rt->is_input = !(flags & AVIO_FLAG_WRITE);
+
+- av_url_split(proto, sizeof(proto), auth, sizeof(auth),
++ memset(tmpProto, 0, sizeof(tmpProto)); proto = &tmpProto[2]; av_url_split(tmpProto, sizeof(tmpProto), auth, sizeof(auth),
+ hostname, sizeof(hostname), &port,
+ path, sizeof(path), s->filename);
+
+@@ -3151,9 +3151,9 @@ const URLProtocol ff_##flavor##_protocol = { \
+ #define RTMP_PROTOCOL(flavor, uppercase) \
+ RTMP_PROTOCOL_3(flavor, CONFIG_ ## uppercase ## _PROTOCOL)
+
+-RTMP_PROTOCOL(rtmp, RTMP)
+-RTMP_PROTOCOL(rtmpe, RTMPE)
+-RTMP_PROTOCOL(rtmps, RTMPS)
+-RTMP_PROTOCOL(rtmpt, RTMPT)
+-RTMP_PROTOCOL(rtmpte, RTMPTE)
+-RTMP_PROTOCOL(rtmpts, RTMPTS)
++RTMP_PROTOCOL(ffrtmp, FFRTMP)
++RTMP_PROTOCOL(ffrtmpe, FFRTMPE)
++RTMP_PROTOCOL(ffrtmps, FFRTMPS)
++RTMP_PROTOCOL(ffrtmpt, FFRTMPT)
++RTMP_PROTOCOL(ffrtmpte, FFRTMPTE)
++RTMP_PROTOCOL(ffrtmpts, FFRTMPTS)
--- /dev/null
+# Test case: The.Purge.2013.1080p.BluRay.x264.YIFY.mp4
+From 1c7b83f945e710a17a41ad9feb7dc929f26f2b0e Mon Sep 17 00:00:00 2001
+From: Jacek Jendrzej <satbaby@kawaii.com>
+Date: Wed, 28 Jun 2017 11:38:20 +0200
+Subject: [PATCH] fix sps/pps for cooli;This is commit that breaks seek in some
+ mkv.break with commit 6d2219e9f950b96279fd8464cc11c4d02518b629
+
+---
+ libavcodec/h264_mp4toannexb_bsf.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c
+index 2822644b10..d57647d25c 100644
+--- a/libavcodec/h264_mp4toannexb_bsf.c
++++ b/libavcodec/h264_mp4toannexb_bsf.c
+@@ -242,6 +242,11 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *opkt)
+ if (!new_idr && unit_type == H264_NAL_IDR_SLICE && (buf[1] & 0x80))
+ new_idr = 1;
+
++ if (s->new_idr && unit_type == H264_NAL_SEI && s->idr_sps_seen && s->idr_pps_seen) {
++ s->idr_sps_seen = 0;
++ s->idr_pps_seen = 0;
++ }
++
+ /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */
+ if (new_idr && unit_type == H264_NAL_IDR_SLICE && !sps_seen && !pps_seen) {
+ if (ctx->par_out->extradata)
--- /dev/null
+diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
+index 8a3436f2be..abdfe41d85 100644
+--- a/libavformat/mpegts.c
++++ b/libavformat/mpegts.c
+@@ -1037,10 +1037,10 @@ static int new_pes_packet(PESContext *pes, AVPacket *pkt)
+ pes->buffer = NULL;
+ reset_pes_packet_state(pes);
+
+- sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1);
++ /*sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1);
+ if (!sd)
+ return AVERROR(ENOMEM);
+- *sd = pes->stream_id;
++ *sd = pes->stream_id;*/
+
+ return 0;
+ }
--- /dev/null
+diff --git a/libavformat/avio.c b/libavformat/avio.c\r
+index 4846bbd8c6..978bf72994 100644\r
+--- a/libavformat/avio.c\r
++++ b/libavformat/avio.c\r
+@@ -177,12 +177,12 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)\r
+ (uc->protocol_whitelist && !strcmp(uc->protocol_whitelist, e->value)));\r
+ av_assert0(!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||\r
+ (uc->protocol_blacklist && !strcmp(uc->protocol_blacklist, e->value)));\r
+-\r
++/*\r
+ if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) {\r
+ av_log(uc, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", uc->prot->name, uc->protocol_whitelist);\r
+ return AVERROR(EINVAL);\r
+ }\r
+-\r
++*/\r
+ if (uc->protocol_blacklist && av_match_list(uc->prot->name, uc->protocol_blacklist, ',') > 0) {\r
+ av_log(uc, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", uc->prot->name, uc->protocol_blacklist);\r
+ return AVERROR(EINVAL);\r
--- /dev/null
+diff --git a/libavformat/mov.c b/libavformat/mov.c
+index 2b1131b911..bf56b41eb3 100644
+--- a/libavformat/mov.c
++++ b/libavformat/mov.c
+@@ -1237,6 +1237,36 @@ static MOVFragmentStreamInfo * get_current_frag_stream_info(
+ return NULL;
+ }
+
++static MOVFragmentStreamInfo * get_frag_stream_by_sample_index(
++ MOVFragmentIndex *frag_index,
++ int sample_index,
++ int stream_id,
++ int *found_index)
++{
++ int i, j;
++ MOVFragmentIndexItem * item;
++
++ for (i = 0; i < frag_index->nb_items; i++) {
++ item = &frag_index->item[i];
++ for (j = 0; j < item->nb_stream_info; j++) {
++ if (item->stream_info[j].id == stream_id &&
++ item->stream_info[j].index_entry >= sample_index &&
++ (i == frag_index->nb_items - 1 ||
++ (frag_index->item[i+1].nb_stream_info > j &&
++ (frag_index->item[i+1].stream_info[j].index_entry == -1 ||
++ sample_index < frag_index->item[i+1].stream_info[j].index_entry)))) {
++ if (found_index) {
++ *found_index = i;
++ }
++ return &item->stream_info[j];
++ }
++ }
++ }
++
++ // This shouldn't happen
++ return NULL;
++}
++
+ static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset)
+ {
+ int a, b, m;
+@@ -5118,7 +5148,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+ sc->ctts_count = sti->nb_index_entries;
+
+ // Record the index_entry position in frag_index of this fragment
+- if (frag_stream_info)
++ if (frag_stream_info && frag_stream_info->index_entry == -1) // BUGFIX: In case of multiple trun, this must remain at the first value
+ frag_stream_info->index_entry = index_entry_pos;
+
+ if (index_entry_pos > 0)
+@@ -5986,6 +6016,8 @@ out:
+ return ret;
+ }
+
++static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom);
++
+ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+ {
+ AVStream *st;
+@@ -6004,6 +6036,10 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+ 0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
+ 0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd,
+ };
++ static const AVUUID uuid_piff_senc = {
++ 0xA2, 0x39, 0x4F, 0x52, 0x5A, 0x9B, 0x4f, 0x14,
++ 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, 0x8D, 0xF4
++ };
+
+ if (atom.size < AV_UUID_LEN || atom.size >= FFMIN(INT_MAX, SIZE_MAX))
+ return AVERROR_INVALIDDATA;
+@@ -6086,6 +6122,9 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+ return ret;
+ if (!sc->spherical)
+ av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n");
++ } else if (av_uuid_equal(uuid, uuid_piff_senc)) {
++ // PATCH: Netflix's stream packager outputs PIFF, which uses an uuid atom for senc boxes.
++ mov_read_senc(c, pb, atom);
+ }
+
+ return 0;
+@@ -6407,7 +6446,12 @@ static int mov_try_read_block(AVIOContext *pb, size_t size, uint8_t **data)
+ offset += to_read;
+ }
+
+- *data = buffer;
++ // PATCH: The original code leads to huge amounts of memory being hogged during playback (especially CENC streams).
++ *data = av_realloc(buffer, size);
++ if (!*data) {
++ av_free(buffer);
++ return AVERROR(ENOMEM);
++ }
+ return 0;
+ }
+
+@@ -7026,15 +7070,16 @@ static int cbcs_scheme_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryption
+ }
+
+ /* whole-block full sample encryption */
+- if (!sample->subsample_count) {
++ // PATCH: Fix for Apple TV+, they have subsamples but don't use pattern encryption.
++ if (!sample->subsample_count || (!sample->crypt_byte_block && !sample->skip_byte_block)) {
+ /* decrypt the whole packet */
+ memcpy(iv, sample->iv, 16);
+ av_aes_crypt(sc->cenc.aes_ctx, input, input, size/16, iv, 1);
+ return 0;
+- } else if (!sample->crypt_byte_block && !sample->skip_byte_block) {
++ }/* else if (!sample->crypt_byte_block && !sample->skip_byte_block) {
+ av_log(c->fc, AV_LOG_ERROR, "pattern encryption is not present in 'cbcs' scheme\n");
+ return AVERROR_INVALIDDATA;
+- }
++ }*/
+
+ for (i = 0; i < sample->subsample_count; i++) {
+ if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
+@@ -7102,10 +7147,20 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa
+ // Note this only supports encryption info in the first sample descriptor.
+ if (mov->fragment.stsd_id == 1) {
+ if (frag_stream_info->encryption_index) {
+- if (!current_index && frag_stream_info->index_entry)
++ // PATCH: Fix seeking backwards in encrypted streams.
++ //av_log(mov->fc, AV_LOG_INFO, "Frag Id: %d Index: %d (frag entry: %d)\n", frag_stream_info->id, current_index, frag_stream_info->index_entry);
++ encrypted_index = current_index - frag_stream_info->index_entry;
++ encryption_index = frag_stream_info->encryption_index;
++ if (encrypted_index < 0 || encrypted_index >= encryption_index->nb_encrypted_samples) {
++ frag_stream_info = get_frag_stream_by_sample_index(&mov->frag_index, current_index, st->id,
++ &mov->frag_index.current);
++ encrypted_index = current_index - frag_stream_info->index_entry;
++ encryption_index = frag_stream_info->encryption_index;
++ }
++ /*if (!current_index && frag_stream_info->index_entry)
+ sc->cenc.frag_index_entry_base = frag_stream_info->index_entry;
+ encrypted_index = current_index - (frag_stream_info->index_entry - sc->cenc.frag_index_entry_base);
+- encryption_index = frag_stream_info->encryption_index;
++ encryption_index = frag_stream_info->encryption_index;*/
+ } else {
+ encryption_index = sc->cenc.encryption_index;
+ }
+@@ -7133,8 +7188,9 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa
+ // Per-sample setting override.
+ encrypted_sample = encryption_index->encrypted_samples[encrypted_index];
+ } else {
+- av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info\n");
+- return AVERROR_INVALIDDATA;
++ av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info (index %d, nb %d)\n", encrypted_index, encryption_index->nb_encrypted_samples);
++ return 0; // CST hack - this can sometimes happen while seeking/switching audio streams, it's a non-fatal error.
++ //return AVERROR_INVALIDDATA;
+ }
+
+ if (mov->decryption_key) {
+@@ -8572,15 +8628,16 @@ static int mov_switch_root(AVFormatContext *s, int64_t target, int index)
+
+ if (index >= 0 && index < mov->frag_index.nb_items)
+ target = mov->frag_index.item[index].moof_offset;
+- if (avio_seek(s->pb, target, SEEK_SET) != target) {
++ // https://ffmpeg.org/pipermail/ffmpeg-devel/2020-April/261343.html
++ if (target >= 0 && avio_seek(s->pb, target, SEEK_SET) != target) {
+ av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": partial file\n", target);
+ return AVERROR_INVALIDDATA;
+ }
+
+ mov->next_root_atom = 0;
+- if (index < 0 || index >= mov->frag_index.nb_items)
++ if ((index < 0 && target >= 0) || index >= mov->frag_index.nb_items)
+ index = search_frag_moof_offset(&mov->frag_index, target);
+- if (index < mov->frag_index.nb_items &&
++ if (index >= 0 && index < mov->frag_index.nb_items &&
+ mov->frag_index.item[index].moof_offset == target) {
+ if (index + 1 < mov->frag_index.nb_items)
+ mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset;
+@@ -8653,8 +8710,40 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
+ AVStream *st = NULL;
+ int64_t current_index;
+ int ret;
++ int i;
+ mov->fc = s;
+ retry:
++ // https://ffmpeg.org/pipermail/ffmpeg-devel/2020-April/261343.html
++ if (s->pb->pos == 0) {
++
++ // Discard current fragment index
++ if (mov->frag_index.allocated_size > 0) {
++ av_freep(&mov->frag_index.item);
++ mov->frag_index.nb_items = 0;
++ mov->frag_index.allocated_size = 0;
++ mov->frag_index.current = -1;
++ mov->frag_index.complete = 0;
++ }
++
++ for (i = 0; i < s->nb_streams; i++) {
++ AVStream *avst = s->streams[i];
++ FFStream *const avsti = ffstream(avst);
++ MOVStreamContext *msc = avst->priv_data;
++
++ // Clear current sample
++ mov_current_sample_set(msc, 0);
++
++ // Discard current index entries
++ if (avsti->index_entries_allocated_size > 0) {
++ av_freep(&avsti->index_entries);
++ avsti->index_entries_allocated_size = 0;
++ avsti->nb_index_entries = 0;
++ }
++ }
++
++ if ((ret = mov_switch_root(s, -1, -1)) < 0)
++ return ret;
++ }
+ sample = mov_find_next_sample(s, &st);
+ if (!sample || (mov->next_root_atom && sample->pos > mov->next_root_atom)) {
+ if (!mov->next_root_atom)
--- /dev/null
+diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
+index e7384f052a..bc75fe3df6 100644
+--- a/fftools/ffmpeg.c
++++ b/fftools/ffmpeg.c
+@@ -4080,7 +4080,7 @@ static int process_input(int file_index)
+ if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
+ pkt_dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts
+- && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) {
++ && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE && !force_dts_monotonicity) {
+ int64_t delta = pkt_dts - ifile->last_ts;
+ if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
+ delta > 1LL*dts_delta_threshold*AV_TIME_BASE){
+@@ -4118,7 +4118,7 @@ static int process_input(int file_index)
+ if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
+ ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
+ pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
+- !disable_discontinuity_correction) {
++ !disable_discontinuity_correction && !force_dts_monotonicity) {
+ int64_t delta = pkt_dts - ist->next_dts;
+ if (is->iformat->flags & AVFMT_TS_DISCONT) {
+ if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
+@@ -4156,6 +4156,43 @@ static int process_input(int file_index)
+ if (pkt->dts != AV_NOPTS_VALUE)
+ ifile->last_ts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
+
++ if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
++ ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
++ (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE) &&
++ force_dts_monotonicity) {
++ int64_t ff_pts_error = 0;
++ int64_t ff_dts_error = 0;
++ int64_t ff_dts_threshold = av_rescale_q(dts_monotonicity_threshold, AV_TIME_BASE_Q, ist->st->time_base);
++
++ // adjust the incoming packet by the accumulated monotonicity error
++ if (pkt->pts != AV_NOPTS_VALUE) {
++ pkt->pts += ifile->ff_timestamp_monotonicity_offset;
++ if (ist->next_pts != AV_NOPTS_VALUE) {
++ ff_pts_error = av_rescale_q(ist->next_pts, AV_TIME_BASE_Q, ist->st->time_base) - pkt->pts;
++ }
++ }
++ if (pkt->dts != AV_NOPTS_VALUE) {
++ pkt->dts += ifile->ff_timestamp_monotonicity_offset;
++ if (ist->next_dts != AV_NOPTS_VALUE) {
++ ff_dts_error = av_rescale_q(ist->next_dts, AV_TIME_BASE_Q, ist->st->time_base) - pkt->dts;
++ }
++ }
++
++ if (ff_dts_error > 0 || ff_dts_error < (-ff_dts_threshold) || ff_pts_error < (-ff_dts_threshold)) {
++ if (pkt->dts == AV_NOPTS_VALUE /*|| ist->next_dts != AV_NOPTS_VALUE*/) {
++ pkt->pts += ff_pts_error;
++ ifile->ff_timestamp_monotonicity_offset += ff_pts_error;
++ av_log(is, AV_LOG_INFO, "Incoming PTS error %"PRId64", offsetting subsequent timestamps by %"PRId64" to correct\n", ff_pts_error, ifile->ff_timestamp_monotonicity_offset);
++ }
++ else {
++ pkt->pts += ff_dts_error;
++ pkt->dts += ff_dts_error;
++ ifile->ff_timestamp_monotonicity_offset += ff_dts_error;
++ av_log(is, AV_LOG_INFO, "Incoming DTS error %"PRId64", offsetting subsequent timestamps by %"PRId64" to correct\n", ff_dts_error, ifile->ff_timestamp_monotonicity_offset);
++ }
++ }
++ }
++
+ if (debug_ts) {
+ av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n",
+ ifile->ist_index + pkt->stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
+diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
+index 391a35cf50..3ca42c8f0c 100644
+--- a/fftools/ffmpeg.h
++++ b/fftools/ffmpeg.h
+@@ -433,6 +433,10 @@ typedef struct InputFile {
+ int joined; /* the thread has been joined */
+ int thread_queue_size; /* maximum number of queued packets */
+ #endif
++
++ // A value added to inbound timestamps to prevent them from going "backward" in cases such as HLS discontinuities
++ int64_t ff_timestamp_monotonicity_offset;
++
+ } InputFile;
+
+ enum forced_keyframes_const {
+@@ -620,6 +624,9 @@ extern float audio_drift_threshold;
+ extern float dts_delta_threshold;
+ extern float dts_error_threshold;
+
++extern int dts_monotonicity_threshold;
++extern int force_dts_monotonicity;
++
+ extern int audio_volume;
+ extern int audio_sync_method;
+ extern enum VideoSyncMethod video_sync_method;
+diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
+index 6e18a4a23e..f2c2313219 100644
+--- a/fftools/ffmpeg_opt.c
++++ b/fftools/ffmpeg_opt.c
+@@ -156,6 +156,9 @@ float audio_drift_threshold = 0.1;
+ float dts_delta_threshold = 10;
+ float dts_error_threshold = 3600*30;
+
++int dts_monotonicity_threshold = AV_TIME_BASE;
++int force_dts_monotonicity = 0;
++
+ int audio_volume = 256;
+ int audio_sync_method = 0;
+ enum VideoSyncMethod video_sync_method = VSYNC_AUTO;
+@@ -1361,6 +1364,7 @@ static int open_input_file(OptionsContext *o, const char *filename)
+ f->input_sync_ref = o->input_sync_ref;
+ f->input_ts_offset = o->input_ts_offset;
+ f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
++ f->ff_timestamp_monotonicity_offset = 0;
+ f->nb_streams = ic->nb_streams;
+ f->rate_emu = o->rate_emu;
+ f->accurate_seek = o->accurate_seek;
+@@ -3760,6 +3764,10 @@ const OptionDef options[] = {
+ { "apad", OPT_STRING | HAS_ARG | OPT_SPEC |
+ OPT_OUTPUT, { .off = OFFSET(apad) },
+ "audio pad", "" },
++ { "force_dts_monotonicity", OPT_BOOL | OPT_EXPERT, { &force_dts_monotonicity },
++ "correct dts monotonicity errors" },
++ { "dts_monotonicity_threshold", HAS_ARG | OPT_INT | OPT_EXPERT, { &dts_monotonicity_threshold },
++ "dts correction threshold for forward jumps", "microseconds" },
+ { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_delta_threshold },
+ "timestamp discontinuity delta threshold", "threshold" },
+ { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_error_threshold },
--- /dev/null
+diff --git a/libavformat/hls.c b/libavformat/hls.c
+index faf92804a2..bbc8388c94 100644
+--- a/libavformat/hls.c
++++ b/libavformat/hls.c
+@@ -225,6 +225,8 @@ typedef struct HLSContext {
+ int http_persistent;
+ int http_multiple;
+ int http_seekable;
++ char *key_uri_replace_old;
++ char *key_uri_replace_new;
+ AVIOContext *playlist_pb;
+ HLSCryptoContext crypto_ctx;
+ } HLSContext;
+@@ -1293,8 +1295,16 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
+
+ if (seg->key_type == KEY_AES_128 || seg->key_type == KEY_SAMPLE_AES) {
+ if (strcmp(seg->key, pls->key_url)) {
++ char *key_url = NULL;
+ AVIOContext *pb = NULL;
+- if (open_url(pls->parent, &pb, seg->key, &c->avio_opts, opts, NULL) == 0) {
++ if (NULL != c->key_uri_replace_old && \
++ NULL != c-> key_uri_replace_new && \
++ '\0' != c->key_uri_replace_old[0]) {
++ key_url = av_strireplace(seg->key, c->key_uri_replace_old, c->key_uri_replace_new);
++ } else {
++ key_url = seg->key;
++ }
++ if (open_url(pls->parent, &pb, key_url, &c->avio_opts, opts, NULL) == 0) {
+ ret = avio_read(pb, pls->key, sizeof(pls->key));
+ if (ret != sizeof(pls->key)) {
+ av_log(pls->parent, AV_LOG_ERROR, "Unable to read key file %s\n",
+@@ -1306,6 +1316,8 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
+ seg->key);
+ }
+ av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url));
++ if (key_url != seg->key)
++ av_free(key_url);
+ }
+ }
+
+@@ -2530,6 +2542,8 @@ static int hls_probe(const AVProbeData *p)
+ #define OFFSET(x) offsetof(HLSContext, x)
+ #define FLAGS AV_OPT_FLAG_DECODING_PARAM
+ static const AVOption hls_options[] = {
++ { "key_uri_old", "allow to replace part of AES key uri - old", OFFSET(key_uri_replace_old), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, FLAGS },
++ { "key_uri_new", "allow to replace part of AES key uri - new", OFFSET(key_uri_replace_new), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, FLAGS },
+ {"live_start_index", "segment index to start live streams at (negative values are from the end)",
+ OFFSET(live_start_index), AV_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS},
+ {"prefer_x_start", "prefer to use #EXT-X-START if it's in playlist instead of live_start_index",
--- /dev/null
+--- a/libavformat/hls.c
++++ b/libavformat/hls.c
+@@ -2171,8 +2171,10 @@
+ HLSContext *c = s->priv_data;
+ int ret, i, minplaylist = -1;
+
+- recheck_discard_flags(s, c->first_packet);
+- c->first_packet = 0;
++ if (c->first_packet) {
++ recheck_discard_flags(s, 1);
++ c->first_packet = 0;
++ }
+
+ for (i = 0; i < c->n_playlists; i++) {
+ struct playlist *pls = c->playlists[i];
--- /dev/null
+diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
+index f948f1d395..69507ec866 100644
+--- a/libavformat/rtsp.c
++++ b/libavformat/rtsp.c
+@@ -2391,6 +2391,8 @@ static int sdp_read_header(AVFormatContext *s)
+ int i, err;
+ char url[MAX_URL_SIZE];
+ AVBPrint bp;
++ const char *p, *sp="", *sources="", *sp2, *sources2;
++ char sources_buf[1024];
+
+ if (!ff_network_init())
+ return AVERROR(EIO);
+@@ -2412,6 +2414,16 @@ static int sdp_read_header(AVFormatContext *s)
+ av_bprint_finalize(&bp, NULL);
+ if (err) goto fail;
+
++ /* Search for sources= tag in original URL for rtp protocol only */
++ if (strncmp(s->url, "rtp://", 6) == 0) {
++ p = strchr(s->url, '?');
++ if (p && av_find_info_tag(sources_buf, sizeof(sources_buf), "sources", p)) {
++ /* av_log(s, AV_LOG_VERBOSE, "sdp_read_header found sources %s\n", sources_buf); */
++ sp = sources_buf;
++ sources = "&sources=";
++ }
++ }
++
+ /* open each RTP stream */
+ for (i = 0; i < rt->nb_rtsp_streams; i++) {
+ char namebuf[50];
+@@ -2431,12 +2443,22 @@ static int sdp_read_header(AVFormatContext *s)
+ av_dict_free(&opts);
+ goto fail;
+ }
++
++ /* Prepare to add sources to the url to be opened.
++ Otherwise the join to the source specific muliticast will be missing */
++ sources2 = sources;
++ sp2 = sp;
++ /* ignore sources from original URL, when sources are already set in rtsp_st */
++ if (rtsp_st->nb_include_source_addrs > 0)
++ sources2 = sp2 = "";
++
+ ff_url_join(url, sizeof(url), "rtp", NULL,
+ namebuf, rtsp_st->sdp_port,
+- "?localport=%d&ttl=%d&connect=%d&write_to_source=%d",
++ "?localport=%d&ttl=%d&connect=%d&write_to_source=%d%s%s",
+ rtsp_st->sdp_port, rtsp_st->sdp_ttl,
+ rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0,
+- rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0);
++ rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0,
++ sources2, sp2);
+
+ p = strchr(s->url, '?');
+ if (p && av_find_info_tag(buf, sizeof(buf), "localaddr", p))
--- /dev/null
+From f193409d354a41d8afaf1b75ca34dc1839a60b69 Mon Sep 17 00:00:00 2001
+From: gandharva <gandharva@gmx.de>
+Date: Wed, 14 Jun 2017 19:51:24 +0200
+Subject: [PATCH 8/8] - increase IO_BUFFER_SIZE to 128k
+
+performance improvement when using SMB/CIFS
+---
+ libavformat/aviobuf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
+index c2681ed..711fff8 100644
+--- a/libavformat/aviobuf.c
++++ b/libavformat/aviobuf.c
+@@ -33,7 +33,7 @@
+ #include "url.h"
+ #include <stdarg.h>
+
+-#define IO_BUFFER_SIZE 32768
++#define IO_BUFFER_SIZE 262144
+
+ /**
+ * Do seeks within this distance ahead of the current buffer by skipping
+--
+2.1.4
+
--- /dev/null
+These patches mostly fix processing DRM DASH/HLS streams.\r
+\r
+hls-changes sets a rather high buffer size (tuned towards 1080p VOD content), which may be undesirable for live streams or SD VOD content.\r
+\r
+dash-hacks contains some fixes that may help with DASH streams that contain subtitles and multiple audio streams (esp. switching between streams on CST).
\ No newline at end of file
--- /dev/null
+diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
+index 2ca91bea8b..ecaf50047d 100644
+--- a/libavformat/dashdec.c
++++ b/libavformat/dashdec.c
+@@ -441,8 +441,12 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
+ return AVERROR_INVALIDDATA;
+
+ av_freep(pb);
++
+ av_dict_copy(&tmp, *opts, 0);
+ av_dict_copy(&tmp, opts2, 0);
++ av_dict_set_int(&tmp, "reconnect", 1, 0);
++ av_dict_set_int(&tmp, "icy", 0, 0);
++
+ ret = avio_open2(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp);
+ if (ret >= 0) {
+ // update cookies on http response with setcookies.
+@@ -768,7 +772,8 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur
+ baseurl = xmlNodeGetContent(node);
+ root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path;
+ if (node) {
+- xmlNodeSetContent(node, root_url);
++ // HACK: SetContent fails if the URL happens to include '&', which isn't that uncommon...
++ //xmlNodeSetContent(node, root_url);
+ updated = 1;
+ }
+
+@@ -802,7 +807,7 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur
+ memset(p + 1, 0, strlen(p));
+ }
+ av_strlcat(tmp_str, text + start, tmp_max_url_size);
+- xmlNodeSetContent(baseurl_nodes[i], tmp_str);
++ //xmlNodeSetContent(baseurl_nodes[i], tmp_str);
+ updated = 1;
+ xmlFree(text);
+ }
+@@ -1217,6 +1222,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
+ char *val = NULL;
+ uint32_t period_duration_sec = 0;
+ uint32_t period_start_sec = 0;
++ char *nfcs_key = NULL;
+
+ if (!in) {
+ close_in = 1;
+@@ -1335,6 +1341,12 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
+ } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
+ parse_programinformation(s, node);
+ }
++ // HACK: libvodstream stores decrypted keys in a custom tag.
++ if (!av_strcasecmp(node->name, (const char*)"nfcskey")) {
++ nfcs_key = xmlNodeGetContent(node->children);
++ c->cenc_decryption_key = av_strdup(nfcs_key);
++ xmlFree(nfcs_key);
++ }
+ node = xmlNextElementSibling(node);
+ }
+ if (!period_node) {
+@@ -1879,7 +1891,8 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation
+ }
+ ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0,
+ pls, read_data, NULL, c->is_live ? NULL : seek_data);
+- pls->pb.pub.seekable = 0;
++ // PATCH: If this is 0, seeking in VOD streams downloads the entire content between origin and target.
++ pls->pb.pub.seekable = 1;
+
+ if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
+ goto fail;
+@@ -2167,6 +2180,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
+ int ret = 0, i;
+ int64_t mints = 0;
+ struct representation *cur = NULL;
++ struct representation *curHack = NULL;
+ struct representation *rep = NULL;
+
+ recheck_discard_flags(s, c->videos, c->n_videos);
+@@ -2188,6 +2202,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
+ continue;
+ if (!cur || rep->cur_timestamp < mints) {
+ cur = rep;
++ curHack = rep;
+ mints = rep->cur_timestamp;
+ }
+ }
+@@ -2203,6 +2218,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
+ }
+
+ if (!cur) {
++ av_log(s, AV_LOG_WARNING, "INVALIDDATA\n");
+ return AVERROR_INVALIDDATA;
+ }
+ while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
+@@ -2221,6 +2237,26 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
+ cur->is_restart_needed = 0;
+ }
+ }
++ if (curHack && curHack != cur) {
++ cur = curHack;
++ ret = 0;
++ while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
++ ret = av_read_frame(cur->ctx, pkt);
++ if (ret >= 0) {
++ /* If we got a packet, return it */
++ cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
++ pkt->stream_index = cur->stream_index;
++ return 0;
++ }
++ if (cur->is_restart_needed) {
++ cur->cur_seg_offset = 0;
++ cur->init_sec_buf_read_offset = 0;
++ ff_format_io_close(cur->parent, &cur->input);
++ ret = reopen_demux_for_component(s, cur);
++ cur->is_restart_needed = 0;
++ }
++ }
++ }
+ return AVERROR_EOF;
+ }
+
+@@ -2232,6 +2268,7 @@ static int dash_close(AVFormatContext *s)
+ free_subtitle_list(c);
+ av_dict_free(&c->avio_opts);
+ av_freep(&c->base_url);
++ av_freep(&c->cenc_decryption_key);
+ return 0;
+ }
+
+@@ -2319,10 +2356,11 @@ static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestam
+ if (!ret)
+ ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
+ }
+- for (i = 0; i < c->n_subtitles; i++) {
+- if (!ret)
+- ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
+- }
++ // PATCH: Seeking in subtitle streams breaks things, and it doesn't seem necessary.
++ //for (i = 0; i < c->n_subtitles; i++) {
++ // if (!ret)
++ // ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
++ //}
+
+ return ret;
+ }
--- /dev/null
+diff --git a/libavformat/hls.c b/libavformat/hls.c
+index e622425e80..faf92804a2 100644
+--- a/libavformat/hls.c
++++ b/libavformat/hls.c
+@@ -46,7 +46,7 @@
+
+ #include "hls_sample_encryption.h"
+
+-#define INITIAL_BUFFER_SIZE 32768
++#define INITIAL_BUFFER_SIZE 1048576
+
+ #define MAX_FIELD_LEN 64
+ #define MAX_CHARACTERISTICS_LEN 512
+@@ -1580,7 +1580,7 @@ reload:
+
+ seg = next_segment(v);
+ if (c->http_multiple == 1 && !v->input_next_requested &&
+- seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
++ seg && seg->key_type != KEY_AES_128 && av_strstart(seg->url, "http", NULL)) {
+ ret = open_input(c, v, seg, &v->input_next);
+ if (ret < 0) {
+ if (ff_check_interrupt(c->interrupt_callback))
+@@ -1613,7 +1613,7 @@ reload:
+ return ret;
+ }
+ if (c->http_persistent &&
+- seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
++ seg->key_type != KEY_AES_128 && av_strstart(seg->url, "http", NULL)) {
+ v->input_read_done = 1;
+ } else {
+ ff_format_io_close(v->parent, &v->input);
+@@ -2475,6 +2475,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
+ /* set segment now so we do not need to search again below */
+ seek_pls->cur_seq_no = seq_no;
+ seek_pls->seek_stream_index = stream_subdemuxer_index;
++ //av_log(s, AV_LOG_INFO, "Seek to %d in %d\n", seq_no, stream_subdemuxer_index);
+
+ for (i = 0; i < c->n_playlists; i++) {
+ /* Reset reading */
+@@ -2535,7 +2536,7 @@ static const AVOption hls_options[] = {
+ OFFSET(prefer_x_start), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS},
+ {"allowed_extensions", "List of file extensions that hls is allowed to access",
+ OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
+- {.str = "3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"},
++ {.str = "3gp,aac,avi,ac3,eac3,flac,key,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"},
+ INT_MIN, INT_MAX, FLAGS},
+ {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded",
+ OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS},
+@@ -2544,7 +2545,7 @@ static const AVOption hls_options[] = {
+ {"http_persistent", "Use persistent HTTP connections",
+ OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
+ {"http_multiple", "Use multiple HTTP connections for fetching segments",
+- OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS},
++ OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, FLAGS},
+ {"http_seekable", "Use HTTP partial requests, 0 = disable, 1 = enable, -1 = auto",
+ OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, FLAGS},
+ {"seg_format_options", "Set options for segment demuxer",
+++ /dev/null
-diff --git a/libavcodec/aacps.c b/libavcodec/aacps.c
-index 655e8fe5b4..45190d678d 100644
---- a/libavcodec/aacps.c
-+++ b/libavcodec/aacps.c
-@@ -397,7 +397,7 @@ static void map_val_20_to_34(INTFLOAT par[PS_MAX_NR_IIDICC])
- par[ 1] = AAC_HALF_SUM(par[ 0], par[ 1]);
- }
-
--static void decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34)
-+static void __attribute__((optimize(0))) decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34)
- {
- LOCAL_ALIGNED_16(INTFLOAT, power, [34], [PS_QMF_TIME_SLOTS]);
- LOCAL_ALIGNED_16(INTFLOAT, transient_gain, [34], [PS_QMF_TIME_SLOTS]);
-diff --git a/libavcodec/fft_template.c b/libavcodec/fft_template.c
-index f2742a3ae8..59b4085eba 100644
---- a/libavcodec/fft_template.c
-+++ b/libavcodec/fft_template.c
-@@ -551,7 +551,7 @@ static void fft##n(FFTComplex *z)\
- pass(z,FFT_NAME(ff_cos_##n),n4/2);\
- }
-
--static void fft4(FFTComplex *z)
-+static void __attribute__((optimize(0))) fft4(FFTComplex *z)
- {
- FFTDouble t1, t2, t3, t4, t5, t6, t7, t8;
-
-@@ -565,7 +565,7 @@ static void fft4(FFTComplex *z)
- BF(z[2].im, z[0].im, t2, t5);
- }
-
--static void fft8(FFTComplex *z)
-+static void __attribute__((optimize(0))) fft8(FFTComplex *z)
- {
- FFTDouble t1, t2, t3, t4, t5, t6;
-
-diff --git a/libavcodec/mdct_template.c b/libavcodec/mdct_template.c
-index a854ad2700..6119be0d1a 100644
---- a/libavcodec/mdct_template.c
-+++ b/libavcodec/mdct_template.c
-@@ -98,7 +98,7 @@ av_cold int ff_mdct_init(FFTContext *s, int nbits, int inverse, double scale)
- * @param output N/2 samples
- * @param input N/2 samples
- */
--void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
-+void __attribute__((optimize(0))) ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
- {
- int k, n8, n4, n2, n, j;
- const uint16_t *revtab = s->revtab;
+++ /dev/null
-diff --git a/libavutil/common.h b/libavutil/common.h
-index fd1404be6c..0bb8650e83 100644
---- a/libavutil/common.h
-+++ b/libavutil/common.h
-@@ -350,7 +350,8 @@ static av_always_inline int64_t av_sat_add64_c(int64_t a, int64_t b) {
- return !__builtin_add_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);
- #else
- int64_t s = a+(uint64_t)b;
-- if ((int64_t)(a^b | ~s^b) >= 0)
-+ // PATCH: GCC 4.9.4 complains about missing parentheses when combining bitwise operations.
-+ if ((int64_t)((a^b) | (~s^b)) >= 0)
- return INT64_MAX ^ (b >> 63);
- return s;
- #endif
+++ /dev/null
-diff --git a/libavcodec/Makefile b/libavcodec/Makefile
-index 457ec58377..49bf260764 100644
---- a/libavcodec/Makefile
-+++ b/libavcodec/Makefile
-@@ -1209,6 +1209,8 @@ OBJS-$(CONFIG_SETTS_BSF) += setts_bsf.o
- OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o
- OBJS-$(CONFIG_TRACE_HEADERS_BSF) += trace_headers_bsf.o
- OBJS-$(CONFIG_TRUEHD_CORE_BSF) += truehd_core_bsf.o mlp_parse.o mlp.o
-+OBJS-$(CONFIG_VC1_ASFTORCV_BSF) += vc1_asftorcv_bsf.o
-+OBJS-$(CONFIG_VC1_ASFTOANNEXG_BSF) += vc1_asftoannexg_bsf.o vc1.o
- OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o
- OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o
- OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o
-diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c
-index 444423ae93..482d3473b2 100644
---- a/libavcodec/bitstream_filters.c
-+++ b/libavcodec/bitstream_filters.c
-@@ -59,6 +59,8 @@ extern const FFBitStreamFilter ff_setts_bsf;
- extern const FFBitStreamFilter ff_text2movsub_bsf;
- extern const FFBitStreamFilter ff_trace_headers_bsf;
- extern const FFBitStreamFilter ff_truehd_core_bsf;
-+extern const FFBitStreamFilter ff_vc1_asftoannexg_bsf;
-+extern const FFBitStreamFilter ff_vc1_asftorcv_bsf;
- extern const FFBitStreamFilter ff_vp9_metadata_bsf;
- extern const FFBitStreamFilter ff_vp9_raw_reorder_bsf;
- extern const FFBitStreamFilter ff_vp9_superframe_bsf;
-diff --git a/libavcodec/vc1_asftoannexg_bsf.c b/libavcodec/vc1_asftoannexg_bsf.c
-new file mode 100644
-index 0000000000..2901f84d9c
---- /dev/null
-+++ b/libavcodec/vc1_asftoannexg_bsf.c
-@@ -0,0 +1,190 @@
-+/*
-+ * copyright (c) 2010 Google Inc.
-+ * copyright (c) 2013 CoolStream International Ltd.
-+ * copyright (c) 2017 Jacek Jendrzej port to 3.x
-+ * 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
-+ */
-+
-+#include "avcodec.h"
-+#include "bytestream.h"
-+#include "vc1.h"
-+#include "bsf.h"
-+#include "bsf_internal.h"
-+
-+// An arbitrary limit in bytes greater than the current bytes used.
-+#define MAX_SEQ_HEADER_SIZE 50
-+
-+typedef struct ASFTOANNEXGBSFContext {
-+ int frames;
-+ uint8_t *seq_header;
-+ int seq_header_size;
-+ uint8_t *ep_header;
-+ int ep_header_size;
-+} ASFTOANNEXGBSFContext;
-+
-+static int find_codec_data(ASFTOANNEXGBSFContext *ctx, uint8_t *data, int data_size, int keyframe) {
-+ const uint8_t *start = data;
-+ const uint8_t *end = data + data_size;
-+ const uint8_t *next;
-+ int size;
-+ int has_seq_header = 0;
-+ int has_ep_header = 0;
-+ int has_frame_header = 0;
-+
-+ start = find_next_marker(start, end);
-+ next = start;
-+ for(; next < end; start = next){
-+ next = find_next_marker(start + 4, end);
-+ size = next - start;
-+ if(size <= 0) continue;
-+ switch(AV_RB32(start)){
-+ case VC1_CODE_SEQHDR:
-+ has_seq_header = 1;
-+ break;
-+ case VC1_CODE_ENTRYPOINT:
-+ has_ep_header = 1;
-+ break;
-+ case VC1_CODE_FRAME:
-+ has_frame_header = 1;
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+
-+ if((has_seq_header && has_ep_header && has_frame_header && keyframe) ||
-+ (!has_seq_header && !has_ep_header && has_frame_header) ) return 0;
-+
-+ return -1;
-+}
-+
-+static int parse_extradata(ASFTOANNEXGBSFContext *ctx, uint8_t *extradata, int extradata_size) {
-+ const uint8_t *start = extradata;
-+ const uint8_t *end = extradata + extradata_size;
-+ const uint8_t *next;
-+ int size;
-+
-+ start = find_next_marker(start, end);
-+ next = start;
-+ for(; next < end; start = next){
-+ next = find_next_marker(start + 4, end);
-+ size = next - start;
-+ if(size <= 0) continue;
-+ switch(AV_RB32(start)){
-+ case VC1_CODE_SEQHDR:
-+ ctx->seq_header = av_mallocz(size);
-+ ctx->seq_header_size = size;
-+ memcpy(ctx->seq_header, start, size);
-+ break;
-+ case VC1_CODE_ENTRYPOINT:
-+ ctx->ep_header = av_malloc(size);
-+ ctx->ep_header_size = size;
-+ memcpy(ctx->ep_header, start, size);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+
-+ if(!ctx->seq_header || !ctx->ep_header) {
-+ av_log(NULL, AV_LOG_ERROR, "Incomplete extradata\n");
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+static int asftoannexg_filter(AVBSFContext *ctx, AVPacket *out)
-+{
-+ ASFTOANNEXGBSFContext* bsfctx = ctx->priv_data;
-+ AVPacket *in;
-+ int keyframe;
-+ int ret;
-+ uint8_t* bs = NULL;
-+
-+ ret = ff_bsf_get_packet(ctx, &in);
-+ if (ret < 0)
-+ return ret;
-+
-+ keyframe = in->flags & AV_PKT_FLAG_KEY;
-+ if(in->size >= 1 && !find_codec_data(bsfctx, in->data, in->size, keyframe)) {
-+// av_log(NULL, AV_LOG_INFO, "Nothing to do: %i\n",in->size);
-+ av_packet_move_ref(out, in);
-+ av_packet_free(&in);
-+ return 0;
-+ }
-+
-+ if(!ctx->par_in->extradata || ctx->par_in->extradata_size < 16) {
-+ av_log(NULL, AV_LOG_INFO, "Extradata size too small: %i\n", ctx->par_in->extradata_size);
-+ av_packet_move_ref(out, in);
-+ av_packet_free(&in);
-+ return 0;
-+ }
-+
-+ if (!bsfctx->frames && parse_extradata(bsfctx, ctx->par_in->extradata , ctx->par_in->extradata_size) < 0) {
-+ av_packet_free(&in);
-+ av_log(NULL, AV_LOG_ERROR, "Cannot parse extra data!\n");
-+ return -1;
-+ }
-+
-+ if (keyframe) {
-+ // If this is the keyframe, need to put sequence header and entry point header.
-+ ret = av_new_packet(out, bsfctx->seq_header_size + bsfctx->ep_header_size + 4 + in->size);
-+ if (ret < 0)
-+ goto exit;
-+ bs = out->data;
-+
-+ memcpy(bs, bsfctx->seq_header, bsfctx->seq_header_size);
-+ bs += bsfctx->seq_header_size;
-+ memcpy(bs, bsfctx->ep_header, bsfctx->ep_header_size);
-+ bs += bsfctx->ep_header_size;
-+ } else {
-+ ret = av_new_packet(out, 4 + in->size);
-+ if (ret < 0)
-+ goto exit;
-+ bs = out->data;
-+ }
-+
-+ // Put the frame start code and frame data.
-+ bytestream_put_be32(&bs, VC1_CODE_FRAME);
-+ memcpy(bs, in->data, in->size);
-+ ++bsfctx->frames;
-+
-+ ret = av_packet_copy_props(out, in);
-+
-+exit:
-+ av_packet_free(&in);
-+
-+ return ret;
-+}
-+
-+static void asftoannexg_close(AVBSFContext *bsfc) {
-+ ASFTOANNEXGBSFContext *bsfctx = bsfc->priv_data;
-+ av_freep(&bsfctx->seq_header);
-+ av_freep(&bsfctx->ep_header);
-+}
-+
-+static const enum AVCodecID codec_ids[] = {
-+ AV_CODEC_ID_VC1, AV_CODEC_ID_NONE,
-+};
-+
-+FFBitStreamFilter ff_vc1_asftoannexg_bsf = {
-+ .p.name = "vc1_asftoannexg",
-+ .priv_data_size = sizeof(ASFTOANNEXGBSFContext),
-+ .filter = asftoannexg_filter,
-+ .close = asftoannexg_close,
-+ .p.codec_ids = codec_ids,
-+};
-diff --git a/libavcodec/vc1_asftorcv_bsf.c b/libavcodec/vc1_asftorcv_bsf.c
-new file mode 100644
-index 0000000000..02e510b4b6
---- /dev/null
-+++ b/libavcodec/vc1_asftorcv_bsf.c
-@@ -0,0 +1,105 @@
-+/*
-+ * copyright (c) 2010 Google Inc.
-+ * copyright (c) 2017 Jacek Jendrzej port to 3.x
-+ * 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
-+ */
-+
-+#include "avcodec.h"
-+#include "bytestream.h"
-+#include "bsf.h"
-+#include "bsf_internal.h"
-+
-+#define RCV_STREAM_HEADER_SIZE 36
-+#define RCV_PICTURE_HEADER_SIZE 8
-+
-+typedef struct ASFTORCVBSFContext {
-+ int frames;
-+} ASFTORCVBSFContext;
-+
-+static int asftorcv_filter(AVBSFContext *ctx, AVPacket *out){
-+ ASFTORCVBSFContext* bsfctx = ctx->priv_data;
-+ AVPacket *in;
-+ int keyframe;
-+ int ret;
-+ uint8_t* bs = NULL;
-+
-+ ret = ff_bsf_get_packet(ctx, &in);
-+ if (ret < 0)
-+ return ret;
-+
-+ keyframe = in->flags & AV_PKT_FLAG_KEY;
-+
-+ if (!bsfctx->frames) {
-+ // Write the header if this is the first frame.
-+ ret = av_new_packet(out, RCV_STREAM_HEADER_SIZE + RCV_PICTURE_HEADER_SIZE + in->size);
-+ if (ret < 0)
-+ goto exit;
-+ bs = out->data;
-+
-+ // The following structure of stream header comes from libavformat/vc1testenc.c.
-+ bytestream_put_le24(&bs, 0); // Frame count. 0 for streaming.
-+ bytestream_put_byte(&bs, 0xC5);
-+ bytestream_put_le32(&bs, 4); // 4 bytes of extra data.
-+ bytestream_put_byte(&bs, ctx->par_in->extradata[0]);
-+ bytestream_put_byte(&bs, ctx->par_in->extradata[1]);
-+ bytestream_put_byte(&bs, ctx->par_in->extradata[2]);
-+ bytestream_put_byte(&bs, ctx->par_in->extradata[3]);
-+ bytestream_put_le32(&bs, ctx->par_in->height);
-+ bytestream_put_le32(&bs, ctx->par_in->width);
-+ bytestream_put_le32(&bs, 0xC);
-+ bytestream_put_le24(&bs, 0); // hrd_buffer
-+ bytestream_put_byte(&bs, 0x80); // level|cbr|res1
-+ bytestream_put_le32(&bs, 0); // hrd_rate
-+
-+ // The following LE32 describes the frame rate. Since we don't care so fill
-+ // it with 0xFFFFFFFF which means variable framerate.
-+ // See: libavformat/vc1testenc.c
-+ bytestream_put_le32(&bs, 0xFFFFFFFF);
-+ } else {
-+ ret = av_new_packet(out, RCV_PICTURE_HEADER_SIZE + in->size);
-+ if (ret < 0)
-+ goto exit;
-+ bs = out->data;
-+ }
-+
-+ // Write the picture header.
-+ bytestream_put_le32(&bs, in->size | (keyframe ? 0x80000000 : 0));
-+
-+ // The following LE32 describes the pts. Since we don't care so fill it with 0.
-+ bytestream_put_le32(&bs, 0);
-+ memcpy(bs, in->data, in->size);
-+
-+ ++bsfctx->frames;
-+
-+ ret = av_packet_copy_props(out, in);
-+
-+exit:
-+ av_packet_free(&in);
-+
-+ return ret;
-+}
-+
-+static const enum AVCodecID codec_ids[] = {
-+ AV_CODEC_ID_WMV3, AV_CODEC_ID_NONE,
-+};
-+
-+FFBitStreamFilter ff_vc1_asftorcv_bsf = {
-+ .p.name = "vc1_asftorcv",
-+ .priv_data_size = sizeof(ASFTORCVBSFContext),
-+ .filter = asftorcv_filter,
-+ .p.codec_ids = codec_ids,
-+};
+++ /dev/null
-diff --git a/configure b/configure
-index ba5793b2ff..b199365427 100755
---- a/configure
-+++ b/configure
-@@ -3549,10 +3549,8 @@ xv_outdev_deps="xlib_xv xlib_x11 xlib_xext"
- # protocols
- async_protocol_deps="threads"
- bluray_protocol_deps="libbluray"
--ffrtmpcrypt_protocol_conflict="librtmp_protocol"
- ffrtmpcrypt_protocol_deps_any="gcrypt gmp openssl mbedtls"
- ffrtmpcrypt_protocol_select="tcp_protocol"
--ffrtmphttp_protocol_conflict="librtmp_protocol"
- ffrtmphttp_protocol_select="http_protocol"
- ftp_protocol_select="tcp_protocol"
- gopher_protocol_select="tcp_protocol"
-@@ -3566,20 +3564,18 @@ https_protocol_suggest="zlib"
- icecast_protocol_select="http_protocol"
- mmsh_protocol_select="http_protocol"
- mmst_protocol_select="network"
--rtmp_protocol_conflict="librtmp_protocol"
--rtmp_protocol_select="tcp_protocol"
--rtmp_protocol_suggest="zlib"
--rtmpe_protocol_select="ffrtmpcrypt_protocol"
--rtmpe_protocol_suggest="zlib"
--rtmps_protocol_conflict="librtmp_protocol"
--rtmps_protocol_select="tls_protocol"
--rtmps_protocol_suggest="zlib"
--rtmpt_protocol_select="ffrtmphttp_protocol"
--rtmpt_protocol_suggest="zlib"
--rtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol"
--rtmpte_protocol_suggest="zlib"
--rtmpts_protocol_select="ffrtmphttp_protocol https_protocol"
--rtmpts_protocol_suggest="zlib"
-+ffrtmp_protocol_select="tcp_protocol"
-+ffrtmp_protocol_suggest="zlib"
-+ffrtmpe_protocol_select="ffrtmpcrypt_protocol"
-+ffrtmpe_protocol_suggest="zlib"
-+ffrtmps_protocol_select="tls_protocol"
-+ffrtmps_protocol_suggest="zlib"
-+ffrtmpt_protocol_select="ffrtmphttp_protocol"
-+ffrtmpt_protocol_suggest="zlib"
-+ffrtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol"
-+ffrtmpte_protocol_suggest="zlib"
-+ffrtmpts_protocol_select="ffrtmphttp_protocol https_protocol"
-+ffrtmpts_protocol_suggest="zlib"
- rtp_protocol_select="udp_protocol"
- schannel_conflict="openssl gnutls libtls mbedtls"
- sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags"
-diff --git a/libavformat/Makefile b/libavformat/Makefile
-index 6c6b779080..f641b43de6 100644
---- a/libavformat/Makefile
-+++ b/libavformat/Makefile
-@@ -656,12 +656,12 @@ OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf_tags.o
- OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf_tags.o
- OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
- OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o
--OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
--OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
--OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
--OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
--OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
--OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
-+OBJS-$(CONFIG_FFRTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
-+OBJS-$(CONFIG_FFRTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
-+OBJS-$(CONFIG_FFRTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
-+OBJS-$(CONFIG_FFRTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
-+OBJS-$(CONFIG_FFRTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
-+OBJS-$(CONFIG_FFRTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o
- OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o ip.o
- OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o
- OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o
-diff --git a/libavformat/protocols.c b/libavformat/protocols.c
-index 6ee62a598a..3480a2b521 100644
---- a/libavformat/protocols.c
-+++ b/libavformat/protocols.c
-@@ -44,12 +44,12 @@ extern const URLProtocol ff_mmst_protocol;
- extern const URLProtocol ff_md5_protocol;
- extern const URLProtocol ff_pipe_protocol;
- extern const URLProtocol ff_prompeg_protocol;
--extern const URLProtocol ff_rtmp_protocol;
--extern const URLProtocol ff_rtmpe_protocol;
--extern const URLProtocol ff_rtmps_protocol;
--extern const URLProtocol ff_rtmpt_protocol;
--extern const URLProtocol ff_rtmpte_protocol;
--extern const URLProtocol ff_rtmpts_protocol;
-+extern const URLProtocol ff_ffrtmp_protocol;
-+extern const URLProtocol ff_ffrtmpe_protocol;
-+extern const URLProtocol ff_ffrtmps_protocol;
-+extern const URLProtocol ff_ffrtmpt_protocol;
-+extern const URLProtocol ff_ffrtmpte_protocol;
-+extern const URLProtocol ff_ffrtmpts_protocol;
- extern const URLProtocol ff_rtp_protocol;
- extern const URLProtocol ff_sctp_protocol;
- extern const URLProtocol ff_srtp_protocol;
-diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
-index f0ef223f05..53a078b426 100644
---- a/libavformat/rtmpproto.c
-+++ b/libavformat/rtmpproto.c
-@@ -2594,7 +2594,7 @@ static int inject_fake_duration_metadata(RTMPContext *rt)
- static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
- {
- RTMPContext *rt = s->priv_data;
-- char proto[8], hostname[256], path[1024], auth[100], *fname;
-+ char *proto, tmpProto[10], hostname[256], path[1024], auth[100], *fname;
- char *old_app, *qmark, *n, fname_buffer[1024];
- uint8_t buf[2048];
- int port;
-@@ -2605,7 +2605,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **o
-
- rt->is_input = !(flags & AVIO_FLAG_WRITE);
-
-- av_url_split(proto, sizeof(proto), auth, sizeof(auth),
-+ memset(tmpProto, 0, sizeof(tmpProto)); proto = &tmpProto[2]; av_url_split(tmpProto, sizeof(tmpProto), auth, sizeof(auth),
- hostname, sizeof(hostname), &port,
- path, sizeof(path), s->filename);
-
-@@ -3151,9 +3151,9 @@ const URLProtocol ff_##flavor##_protocol = { \
- #define RTMP_PROTOCOL(flavor, uppercase) \
- RTMP_PROTOCOL_3(flavor, CONFIG_ ## uppercase ## _PROTOCOL)
-
--RTMP_PROTOCOL(rtmp, RTMP)
--RTMP_PROTOCOL(rtmpe, RTMPE)
--RTMP_PROTOCOL(rtmps, RTMPS)
--RTMP_PROTOCOL(rtmpt, RTMPT)
--RTMP_PROTOCOL(rtmpte, RTMPTE)
--RTMP_PROTOCOL(rtmpts, RTMPTS)
-+RTMP_PROTOCOL(ffrtmp, FFRTMP)
-+RTMP_PROTOCOL(ffrtmpe, FFRTMPE)
-+RTMP_PROTOCOL(ffrtmps, FFRTMPS)
-+RTMP_PROTOCOL(ffrtmpt, FFRTMPT)
-+RTMP_PROTOCOL(ffrtmpte, FFRTMPTE)
-+RTMP_PROTOCOL(ffrtmpts, FFRTMPTS)
+++ /dev/null
-# Test case: The.Purge.2013.1080p.BluRay.x264.YIFY.mp4
-From 1c7b83f945e710a17a41ad9feb7dc929f26f2b0e Mon Sep 17 00:00:00 2001
-From: Jacek Jendrzej <satbaby@kawaii.com>
-Date: Wed, 28 Jun 2017 11:38:20 +0200
-Subject: [PATCH] fix sps/pps for cooli;This is commit that breaks seek in some
- mkv.break with commit 6d2219e9f950b96279fd8464cc11c4d02518b629
-
----
- libavcodec/h264_mp4toannexb_bsf.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c
-index 2822644b10..d57647d25c 100644
---- a/libavcodec/h264_mp4toannexb_bsf.c
-+++ b/libavcodec/h264_mp4toannexb_bsf.c
-@@ -242,6 +242,11 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *opkt)
- if (!new_idr && unit_type == H264_NAL_IDR_SLICE && (buf[1] & 0x80))
- new_idr = 1;
-
-+ if (s->new_idr && unit_type == H264_NAL_SEI && s->idr_sps_seen && s->idr_pps_seen) {
-+ s->idr_sps_seen = 0;
-+ s->idr_pps_seen = 0;
-+ }
-+
- /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */
- if (new_idr && unit_type == H264_NAL_IDR_SLICE && !sps_seen && !pps_seen) {
- if (ctx->par_out->extradata)
+++ /dev/null
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index 8a3436f2be..abdfe41d85 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -1037,10 +1037,10 @@ static int new_pes_packet(PESContext *pes, AVPacket *pkt)
- pes->buffer = NULL;
- reset_pes_packet_state(pes);
-
-- sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1);
-+ /*sd = av_packet_new_side_data(pkt, AV_PKT_DATA_MPEGTS_STREAM_ID, 1);
- if (!sd)
- return AVERROR(ENOMEM);
-- *sd = pes->stream_id;
-+ *sd = pes->stream_id;*/
-
- return 0;
- }
+++ /dev/null
-diff --git a/libavformat/avio.c b/libavformat/avio.c\r
-index 4846bbd8c6..978bf72994 100644\r
---- a/libavformat/avio.c\r
-+++ b/libavformat/avio.c\r
-@@ -177,12 +177,12 @@ int ffurl_connect(URLContext *uc, AVDictionary **options)\r
- (uc->protocol_whitelist && !strcmp(uc->protocol_whitelist, e->value)));\r
- av_assert0(!(e=av_dict_get(*options, "protocol_blacklist", NULL, 0)) ||\r
- (uc->protocol_blacklist && !strcmp(uc->protocol_blacklist, e->value)));\r
--\r
-+/*\r
- if (uc->protocol_whitelist && av_match_list(uc->prot->name, uc->protocol_whitelist, ',') <= 0) {\r
- av_log(uc, AV_LOG_ERROR, "Protocol '%s' not on whitelist '%s'!\n", uc->prot->name, uc->protocol_whitelist);\r
- return AVERROR(EINVAL);\r
- }\r
--\r
-+*/\r
- if (uc->protocol_blacklist && av_match_list(uc->prot->name, uc->protocol_blacklist, ',') > 0) {\r
- av_log(uc, AV_LOG_ERROR, "Protocol '%s' on blacklist '%s'!\n", uc->prot->name, uc->protocol_blacklist);\r
- return AVERROR(EINVAL);\r
+++ /dev/null
-diff --git a/libavformat/mov.c b/libavformat/mov.c
-index 2b1131b911..bf56b41eb3 100644
---- a/libavformat/mov.c
-+++ b/libavformat/mov.c
-@@ -1237,6 +1237,36 @@ static MOVFragmentStreamInfo * get_current_frag_stream_info(
- return NULL;
- }
-
-+static MOVFragmentStreamInfo * get_frag_stream_by_sample_index(
-+ MOVFragmentIndex *frag_index,
-+ int sample_index,
-+ int stream_id,
-+ int *found_index)
-+{
-+ int i, j;
-+ MOVFragmentIndexItem * item;
-+
-+ for (i = 0; i < frag_index->nb_items; i++) {
-+ item = &frag_index->item[i];
-+ for (j = 0; j < item->nb_stream_info; j++) {
-+ if (item->stream_info[j].id == stream_id &&
-+ item->stream_info[j].index_entry >= sample_index &&
-+ (i == frag_index->nb_items - 1 ||
-+ (frag_index->item[i+1].nb_stream_info > j &&
-+ (frag_index->item[i+1].stream_info[j].index_entry == -1 ||
-+ sample_index < frag_index->item[i+1].stream_info[j].index_entry)))) {
-+ if (found_index) {
-+ *found_index = i;
-+ }
-+ return &item->stream_info[j];
-+ }
-+ }
-+ }
-+
-+ // This shouldn't happen
-+ return NULL;
-+}
-+
- static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset)
- {
- int a, b, m;
-@@ -5118,7 +5148,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
- sc->ctts_count = sti->nb_index_entries;
-
- // Record the index_entry position in frag_index of this fragment
-- if (frag_stream_info)
-+ if (frag_stream_info && frag_stream_info->index_entry == -1) // BUGFIX: In case of multiple trun, this must remain at the first value
- frag_stream_info->index_entry = index_entry_pos;
-
- if (index_entry_pos > 0)
-@@ -5986,6 +6016,8 @@ out:
- return ret;
- }
-
-+static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom);
-+
- static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
- {
- AVStream *st;
-@@ -6004,6 +6036,10 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
- 0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
- 0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd,
- };
-+ static const AVUUID uuid_piff_senc = {
-+ 0xA2, 0x39, 0x4F, 0x52, 0x5A, 0x9B, 0x4f, 0x14,
-+ 0xA2, 0x44, 0x6C, 0x42, 0x7C, 0x64, 0x8D, 0xF4
-+ };
-
- if (atom.size < AV_UUID_LEN || atom.size >= FFMIN(INT_MAX, SIZE_MAX))
- return AVERROR_INVALIDDATA;
-@@ -6086,6 +6122,9 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom)
- return ret;
- if (!sc->spherical)
- av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n");
-+ } else if (av_uuid_equal(uuid, uuid_piff_senc)) {
-+ // PATCH: Netflix's stream packager outputs PIFF, which uses an uuid atom for senc boxes.
-+ mov_read_senc(c, pb, atom);
- }
-
- return 0;
-@@ -6407,7 +6446,12 @@ static int mov_try_read_block(AVIOContext *pb, size_t size, uint8_t **data)
- offset += to_read;
- }
-
-- *data = buffer;
-+ // PATCH: The original code leads to huge amounts of memory being hogged during playback (especially CENC streams).
-+ *data = av_realloc(buffer, size);
-+ if (!*data) {
-+ av_free(buffer);
-+ return AVERROR(ENOMEM);
-+ }
- return 0;
- }
-
-@@ -7026,15 +7070,16 @@ static int cbcs_scheme_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryption
- }
-
- /* whole-block full sample encryption */
-- if (!sample->subsample_count) {
-+ // PATCH: Fix for Apple TV+, they have subsamples but don't use pattern encryption.
-+ if (!sample->subsample_count || (!sample->crypt_byte_block && !sample->skip_byte_block)) {
- /* decrypt the whole packet */
- memcpy(iv, sample->iv, 16);
- av_aes_crypt(sc->cenc.aes_ctx, input, input, size/16, iv, 1);
- return 0;
-- } else if (!sample->crypt_byte_block && !sample->skip_byte_block) {
-+ }/* else if (!sample->crypt_byte_block && !sample->skip_byte_block) {
- av_log(c->fc, AV_LOG_ERROR, "pattern encryption is not present in 'cbcs' scheme\n");
- return AVERROR_INVALIDDATA;
-- }
-+ }*/
-
- for (i = 0; i < sample->subsample_count; i++) {
- if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
-@@ -7102,10 +7147,20 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa
- // Note this only supports encryption info in the first sample descriptor.
- if (mov->fragment.stsd_id == 1) {
- if (frag_stream_info->encryption_index) {
-- if (!current_index && frag_stream_info->index_entry)
-+ // PATCH: Fix seeking backwards in encrypted streams.
-+ //av_log(mov->fc, AV_LOG_INFO, "Frag Id: %d Index: %d (frag entry: %d)\n", frag_stream_info->id, current_index, frag_stream_info->index_entry);
-+ encrypted_index = current_index - frag_stream_info->index_entry;
-+ encryption_index = frag_stream_info->encryption_index;
-+ if (encrypted_index < 0 || encrypted_index >= encryption_index->nb_encrypted_samples) {
-+ frag_stream_info = get_frag_stream_by_sample_index(&mov->frag_index, current_index, st->id,
-+ &mov->frag_index.current);
-+ encrypted_index = current_index - frag_stream_info->index_entry;
-+ encryption_index = frag_stream_info->encryption_index;
-+ }
-+ /*if (!current_index && frag_stream_info->index_entry)
- sc->cenc.frag_index_entry_base = frag_stream_info->index_entry;
- encrypted_index = current_index - (frag_stream_info->index_entry - sc->cenc.frag_index_entry_base);
-- encryption_index = frag_stream_info->encryption_index;
-+ encryption_index = frag_stream_info->encryption_index;*/
- } else {
- encryption_index = sc->cenc.encryption_index;
- }
-@@ -7133,8 +7188,9 @@ static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPa
- // Per-sample setting override.
- encrypted_sample = encryption_index->encrypted_samples[encrypted_index];
- } else {
-- av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info\n");
-- return AVERROR_INVALIDDATA;
-+ av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info (index %d, nb %d)\n", encrypted_index, encryption_index->nb_encrypted_samples);
-+ return 0; // CST hack - this can sometimes happen while seeking/switching audio streams, it's a non-fatal error.
-+ //return AVERROR_INVALIDDATA;
- }
-
- if (mov->decryption_key) {
-@@ -8572,15 +8628,16 @@ static int mov_switch_root(AVFormatContext *s, int64_t target, int index)
-
- if (index >= 0 && index < mov->frag_index.nb_items)
- target = mov->frag_index.item[index].moof_offset;
-- if (avio_seek(s->pb, target, SEEK_SET) != target) {
-+ // https://ffmpeg.org/pipermail/ffmpeg-devel/2020-April/261343.html
-+ if (target >= 0 && avio_seek(s->pb, target, SEEK_SET) != target) {
- av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": partial file\n", target);
- return AVERROR_INVALIDDATA;
- }
-
- mov->next_root_atom = 0;
-- if (index < 0 || index >= mov->frag_index.nb_items)
-+ if ((index < 0 && target >= 0) || index >= mov->frag_index.nb_items)
- index = search_frag_moof_offset(&mov->frag_index, target);
-- if (index < mov->frag_index.nb_items &&
-+ if (index >= 0 && index < mov->frag_index.nb_items &&
- mov->frag_index.item[index].moof_offset == target) {
- if (index + 1 < mov->frag_index.nb_items)
- mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset;
-@@ -8653,8 +8710,40 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
- AVStream *st = NULL;
- int64_t current_index;
- int ret;
-+ int i;
- mov->fc = s;
- retry:
-+ // https://ffmpeg.org/pipermail/ffmpeg-devel/2020-April/261343.html
-+ if (s->pb->pos == 0) {
-+
-+ // Discard current fragment index
-+ if (mov->frag_index.allocated_size > 0) {
-+ av_freep(&mov->frag_index.item);
-+ mov->frag_index.nb_items = 0;
-+ mov->frag_index.allocated_size = 0;
-+ mov->frag_index.current = -1;
-+ mov->frag_index.complete = 0;
-+ }
-+
-+ for (i = 0; i < s->nb_streams; i++) {
-+ AVStream *avst = s->streams[i];
-+ FFStream *const avsti = ffstream(avst);
-+ MOVStreamContext *msc = avst->priv_data;
-+
-+ // Clear current sample
-+ mov_current_sample_set(msc, 0);
-+
-+ // Discard current index entries
-+ if (avsti->index_entries_allocated_size > 0) {
-+ av_freep(&avsti->index_entries);
-+ avsti->index_entries_allocated_size = 0;
-+ avsti->nb_index_entries = 0;
-+ }
-+ }
-+
-+ if ((ret = mov_switch_root(s, -1, -1)) < 0)
-+ return ret;
-+ }
- sample = mov_find_next_sample(s, &st);
- if (!sample || (mov->next_root_atom && sample->pos > mov->next_root_atom)) {
- if (!mov->next_root_atom)
+++ /dev/null
-diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
-index e7384f052a..bc75fe3df6 100644
---- a/fftools/ffmpeg.c
-+++ b/fftools/ffmpeg.c
-@@ -4080,7 +4080,7 @@ static int process_input(int file_index)
- if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
- pkt_dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts
-- && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE) {
-+ && (is->iformat->flags & AVFMT_TS_DISCONT) && ifile->last_ts != AV_NOPTS_VALUE && !force_dts_monotonicity) {
- int64_t delta = pkt_dts - ifile->last_ts;
- if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
- delta > 1LL*dts_delta_threshold*AV_TIME_BASE){
-@@ -4118,7 +4118,7 @@ static int process_input(int file_index)
- if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
- ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
- pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
-- !disable_discontinuity_correction) {
-+ !disable_discontinuity_correction && !force_dts_monotonicity) {
- int64_t delta = pkt_dts - ist->next_dts;
- if (is->iformat->flags & AVFMT_TS_DISCONT) {
- if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
-@@ -4156,6 +4156,43 @@ static int process_input(int file_index)
- if (pkt->dts != AV_NOPTS_VALUE)
- ifile->last_ts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
-
-+ if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
-+ ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
-+ (pkt->pts != AV_NOPTS_VALUE || pkt->dts != AV_NOPTS_VALUE) &&
-+ force_dts_monotonicity) {
-+ int64_t ff_pts_error = 0;
-+ int64_t ff_dts_error = 0;
-+ int64_t ff_dts_threshold = av_rescale_q(dts_monotonicity_threshold, AV_TIME_BASE_Q, ist->st->time_base);
-+
-+ // adjust the incoming packet by the accumulated monotonicity error
-+ if (pkt->pts != AV_NOPTS_VALUE) {
-+ pkt->pts += ifile->ff_timestamp_monotonicity_offset;
-+ if (ist->next_pts != AV_NOPTS_VALUE) {
-+ ff_pts_error = av_rescale_q(ist->next_pts, AV_TIME_BASE_Q, ist->st->time_base) - pkt->pts;
-+ }
-+ }
-+ if (pkt->dts != AV_NOPTS_VALUE) {
-+ pkt->dts += ifile->ff_timestamp_monotonicity_offset;
-+ if (ist->next_dts != AV_NOPTS_VALUE) {
-+ ff_dts_error = av_rescale_q(ist->next_dts, AV_TIME_BASE_Q, ist->st->time_base) - pkt->dts;
-+ }
-+ }
-+
-+ if (ff_dts_error > 0 || ff_dts_error < (-ff_dts_threshold) || ff_pts_error < (-ff_dts_threshold)) {
-+ if (pkt->dts == AV_NOPTS_VALUE /*|| ist->next_dts != AV_NOPTS_VALUE*/) {
-+ pkt->pts += ff_pts_error;
-+ ifile->ff_timestamp_monotonicity_offset += ff_pts_error;
-+ av_log(is, AV_LOG_INFO, "Incoming PTS error %"PRId64", offsetting subsequent timestamps by %"PRId64" to correct\n", ff_pts_error, ifile->ff_timestamp_monotonicity_offset);
-+ }
-+ else {
-+ pkt->pts += ff_dts_error;
-+ pkt->dts += ff_dts_error;
-+ ifile->ff_timestamp_monotonicity_offset += ff_dts_error;
-+ av_log(is, AV_LOG_INFO, "Incoming DTS error %"PRId64", offsetting subsequent timestamps by %"PRId64" to correct\n", ff_dts_error, ifile->ff_timestamp_monotonicity_offset);
-+ }
-+ }
-+ }
-+
- if (debug_ts) {
- av_log(NULL, AV_LOG_INFO, "demuxer+ffmpeg -> ist_index:%d type:%s pkt_pts:%s pkt_pts_time:%s pkt_dts:%s pkt_dts_time:%s duration:%s duration_time:%s off:%s off_time:%s\n",
- ifile->ist_index + pkt->stream_index, av_get_media_type_string(ist->dec_ctx->codec_type),
-diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
-index 391a35cf50..3ca42c8f0c 100644
---- a/fftools/ffmpeg.h
-+++ b/fftools/ffmpeg.h
-@@ -433,6 +433,10 @@ typedef struct InputFile {
- int joined; /* the thread has been joined */
- int thread_queue_size; /* maximum number of queued packets */
- #endif
-+
-+ // A value added to inbound timestamps to prevent them from going "backward" in cases such as HLS discontinuities
-+ int64_t ff_timestamp_monotonicity_offset;
-+
- } InputFile;
-
- enum forced_keyframes_const {
-@@ -620,6 +624,9 @@ extern float audio_drift_threshold;
- extern float dts_delta_threshold;
- extern float dts_error_threshold;
-
-+extern int dts_monotonicity_threshold;
-+extern int force_dts_monotonicity;
-+
- extern int audio_volume;
- extern int audio_sync_method;
- extern enum VideoSyncMethod video_sync_method;
-diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
-index 6e18a4a23e..f2c2313219 100644
---- a/fftools/ffmpeg_opt.c
-+++ b/fftools/ffmpeg_opt.c
-@@ -156,6 +156,9 @@ float audio_drift_threshold = 0.1;
- float dts_delta_threshold = 10;
- float dts_error_threshold = 3600*30;
-
-+int dts_monotonicity_threshold = AV_TIME_BASE;
-+int force_dts_monotonicity = 0;
-+
- int audio_volume = 256;
- int audio_sync_method = 0;
- enum VideoSyncMethod video_sync_method = VSYNC_AUTO;
-@@ -1361,6 +1364,7 @@ static int open_input_file(OptionsContext *o, const char *filename)
- f->input_sync_ref = o->input_sync_ref;
- f->input_ts_offset = o->input_ts_offset;
- f->ts_offset = o->input_ts_offset - (copy_ts ? (start_at_zero && ic->start_time != AV_NOPTS_VALUE ? ic->start_time : 0) : timestamp);
-+ f->ff_timestamp_monotonicity_offset = 0;
- f->nb_streams = ic->nb_streams;
- f->rate_emu = o->rate_emu;
- f->accurate_seek = o->accurate_seek;
-@@ -3760,6 +3764,10 @@ const OptionDef options[] = {
- { "apad", OPT_STRING | HAS_ARG | OPT_SPEC |
- OPT_OUTPUT, { .off = OFFSET(apad) },
- "audio pad", "" },
-+ { "force_dts_monotonicity", OPT_BOOL | OPT_EXPERT, { &force_dts_monotonicity },
-+ "correct dts monotonicity errors" },
-+ { "dts_monotonicity_threshold", HAS_ARG | OPT_INT | OPT_EXPERT, { &dts_monotonicity_threshold },
-+ "dts correction threshold for forward jumps", "microseconds" },
- { "dts_delta_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_delta_threshold },
- "timestamp discontinuity delta threshold", "threshold" },
- { "dts_error_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &dts_error_threshold },
+++ /dev/null
-diff --git a/libavformat/hls.c b/libavformat/hls.c
-index faf92804a2..bbc8388c94 100644
---- a/libavformat/hls.c
-+++ b/libavformat/hls.c
-@@ -225,6 +225,8 @@ typedef struct HLSContext {
- int http_persistent;
- int http_multiple;
- int http_seekable;
-+ char *key_uri_replace_old;
-+ char *key_uri_replace_new;
- AVIOContext *playlist_pb;
- HLSCryptoContext crypto_ctx;
- } HLSContext;
-@@ -1293,8 +1295,16 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
-
- if (seg->key_type == KEY_AES_128 || seg->key_type == KEY_SAMPLE_AES) {
- if (strcmp(seg->key, pls->key_url)) {
-+ char *key_url = NULL;
- AVIOContext *pb = NULL;
-- if (open_url(pls->parent, &pb, seg->key, &c->avio_opts, opts, NULL) == 0) {
-+ if (NULL != c->key_uri_replace_old && \
-+ NULL != c-> key_uri_replace_new && \
-+ '\0' != c->key_uri_replace_old[0]) {
-+ key_url = av_strireplace(seg->key, c->key_uri_replace_old, c->key_uri_replace_new);
-+ } else {
-+ key_url = seg->key;
-+ }
-+ if (open_url(pls->parent, &pb, key_url, &c->avio_opts, opts, NULL) == 0) {
- ret = avio_read(pb, pls->key, sizeof(pls->key));
- if (ret != sizeof(pls->key)) {
- av_log(pls->parent, AV_LOG_ERROR, "Unable to read key file %s\n",
-@@ -1306,6 +1316,8 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
- seg->key);
- }
- av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url));
-+ if (key_url != seg->key)
-+ av_free(key_url);
- }
- }
-
-@@ -2530,6 +2542,8 @@ static int hls_probe(const AVProbeData *p)
- #define OFFSET(x) offsetof(HLSContext, x)
- #define FLAGS AV_OPT_FLAG_DECODING_PARAM
- static const AVOption hls_options[] = {
-+ { "key_uri_old", "allow to replace part of AES key uri - old", OFFSET(key_uri_replace_old), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, FLAGS },
-+ { "key_uri_new", "allow to replace part of AES key uri - new", OFFSET(key_uri_replace_new), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, FLAGS },
- {"live_start_index", "segment index to start live streams at (negative values are from the end)",
- OFFSET(live_start_index), AV_OPT_TYPE_INT, {.i64 = -3}, INT_MIN, INT_MAX, FLAGS},
- {"prefer_x_start", "prefer to use #EXT-X-START if it's in playlist instead of live_start_index",
+++ /dev/null
---- a/libavformat/hls.c
-+++ b/libavformat/hls.c
-@@ -2171,8 +2171,10 @@
- HLSContext *c = s->priv_data;
- int ret, i, minplaylist = -1;
-
-- recheck_discard_flags(s, c->first_packet);
-- c->first_packet = 0;
-+ if (c->first_packet) {
-+ recheck_discard_flags(s, 1);
-+ c->first_packet = 0;
-+ }
-
- for (i = 0; i < c->n_playlists; i++) {
- struct playlist *pls = c->playlists[i];
+++ /dev/null
-diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
-index f948f1d395..69507ec866 100644
---- a/libavformat/rtsp.c
-+++ b/libavformat/rtsp.c
-@@ -2391,6 +2391,8 @@ static int sdp_read_header(AVFormatContext *s)
- int i, err;
- char url[MAX_URL_SIZE];
- AVBPrint bp;
-+ const char *p, *sp="", *sources="", *sp2, *sources2;
-+ char sources_buf[1024];
-
- if (!ff_network_init())
- return AVERROR(EIO);
-@@ -2412,6 +2414,16 @@ static int sdp_read_header(AVFormatContext *s)
- av_bprint_finalize(&bp, NULL);
- if (err) goto fail;
-
-+ /* Search for sources= tag in original URL for rtp protocol only */
-+ if (strncmp(s->url, "rtp://", 6) == 0) {
-+ p = strchr(s->url, '?');
-+ if (p && av_find_info_tag(sources_buf, sizeof(sources_buf), "sources", p)) {
-+ /* av_log(s, AV_LOG_VERBOSE, "sdp_read_header found sources %s\n", sources_buf); */
-+ sp = sources_buf;
-+ sources = "&sources=";
-+ }
-+ }
-+
- /* open each RTP stream */
- for (i = 0; i < rt->nb_rtsp_streams; i++) {
- char namebuf[50];
-@@ -2431,12 +2443,22 @@ static int sdp_read_header(AVFormatContext *s)
- av_dict_free(&opts);
- goto fail;
- }
-+
-+ /* Prepare to add sources to the url to be opened.
-+ Otherwise the join to the source specific muliticast will be missing */
-+ sources2 = sources;
-+ sp2 = sp;
-+ /* ignore sources from original URL, when sources are already set in rtsp_st */
-+ if (rtsp_st->nb_include_source_addrs > 0)
-+ sources2 = sp2 = "";
-+
- ff_url_join(url, sizeof(url), "rtp", NULL,
- namebuf, rtsp_st->sdp_port,
-- "?localport=%d&ttl=%d&connect=%d&write_to_source=%d",
-+ "?localport=%d&ttl=%d&connect=%d&write_to_source=%d%s%s",
- rtsp_st->sdp_port, rtsp_st->sdp_ttl,
- rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0,
-- rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0);
-+ rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0,
-+ sources2, sp2);
-
- p = strchr(s->url, '?');
- if (p && av_find_info_tag(buf, sizeof(buf), "localaddr", p))
+++ /dev/null
-From f193409d354a41d8afaf1b75ca34dc1839a60b69 Mon Sep 17 00:00:00 2001
-From: gandharva <gandharva@gmx.de>
-Date: Wed, 14 Jun 2017 19:51:24 +0200
-Subject: [PATCH 8/8] - increase IO_BUFFER_SIZE to 128k
-
-performance improvement when using SMB/CIFS
----
- libavformat/aviobuf.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c
-index c2681ed..711fff8 100644
---- a/libavformat/aviobuf.c
-+++ b/libavformat/aviobuf.c
-@@ -33,7 +33,7 @@
- #include "url.h"
- #include <stdarg.h>
-
--#define IO_BUFFER_SIZE 32768
-+#define IO_BUFFER_SIZE 262144
-
- /**
- * Do seeks within this distance ahead of the current buffer by skipping
---
-2.1.4
-
+++ /dev/null
-These patches mostly fix processing DRM DASH/HLS streams.\r
-\r
-hls-changes sets a rather high buffer size (tuned towards 1080p VOD content), which may be undesirable for live streams or SD VOD content.\r
-\r
-dash-hacks contains some fixes that may help with DASH streams that contain subtitles and multiple audio streams (esp. switching between streams on CST).
\ No newline at end of file
+++ /dev/null
-diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
-index 2ca91bea8b..ecaf50047d 100644
---- a/libavformat/dashdec.c
-+++ b/libavformat/dashdec.c
-@@ -441,8 +441,12 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
- return AVERROR_INVALIDDATA;
-
- av_freep(pb);
-+
- av_dict_copy(&tmp, *opts, 0);
- av_dict_copy(&tmp, opts2, 0);
-+ av_dict_set_int(&tmp, "reconnect", 1, 0);
-+ av_dict_set_int(&tmp, "icy", 0, 0);
-+
- ret = avio_open2(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp);
- if (ret >= 0) {
- // update cookies on http response with setcookies.
-@@ -768,7 +772,8 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur
- baseurl = xmlNodeGetContent(node);
- root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path;
- if (node) {
-- xmlNodeSetContent(node, root_url);
-+ // HACK: SetContent fails if the URL happens to include '&', which isn't that uncommon...
-+ //xmlNodeSetContent(node, root_url);
- updated = 1;
- }
-
-@@ -802,7 +807,7 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur
- memset(p + 1, 0, strlen(p));
- }
- av_strlcat(tmp_str, text + start, tmp_max_url_size);
-- xmlNodeSetContent(baseurl_nodes[i], tmp_str);
-+ //xmlNodeSetContent(baseurl_nodes[i], tmp_str);
- updated = 1;
- xmlFree(text);
- }
-@@ -1217,6 +1222,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
- char *val = NULL;
- uint32_t period_duration_sec = 0;
- uint32_t period_start_sec = 0;
-+ char *nfcs_key = NULL;
-
- if (!in) {
- close_in = 1;
-@@ -1335,6 +1341,12 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
- } else if (!av_strcasecmp(node->name, "ProgramInformation")) {
- parse_programinformation(s, node);
- }
-+ // HACK: libvodstream stores decrypted keys in a custom tag.
-+ if (!av_strcasecmp(node->name, (const char*)"nfcskey")) {
-+ nfcs_key = xmlNodeGetContent(node->children);
-+ c->cenc_decryption_key = av_strdup(nfcs_key);
-+ xmlFree(nfcs_key);
-+ }
- node = xmlNextElementSibling(node);
- }
- if (!period_node) {
-@@ -1879,7 +1891,8 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation
- }
- ffio_init_context(&pls->pb, avio_ctx_buffer, INITIAL_BUFFER_SIZE, 0,
- pls, read_data, NULL, c->is_live ? NULL : seek_data);
-- pls->pb.pub.seekable = 0;
-+ // PATCH: If this is 0, seeking in VOD streams downloads the entire content between origin and target.
-+ pls->pb.pub.seekable = 1;
-
- if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0)
- goto fail;
-@@ -2167,6 +2180,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
- int ret = 0, i;
- int64_t mints = 0;
- struct representation *cur = NULL;
-+ struct representation *curHack = NULL;
- struct representation *rep = NULL;
-
- recheck_discard_flags(s, c->videos, c->n_videos);
-@@ -2188,6 +2202,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
- continue;
- if (!cur || rep->cur_timestamp < mints) {
- cur = rep;
-+ curHack = rep;
- mints = rep->cur_timestamp;
- }
- }
-@@ -2203,6 +2218,7 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
- }
-
- if (!cur) {
-+ av_log(s, AV_LOG_WARNING, "INVALIDDATA\n");
- return AVERROR_INVALIDDATA;
- }
- while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
-@@ -2221,6 +2237,26 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt)
- cur->is_restart_needed = 0;
- }
- }
-+ if (curHack && curHack != cur) {
-+ cur = curHack;
-+ ret = 0;
-+ while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
-+ ret = av_read_frame(cur->ctx, pkt);
-+ if (ret >= 0) {
-+ /* If we got a packet, return it */
-+ cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den);
-+ pkt->stream_index = cur->stream_index;
-+ return 0;
-+ }
-+ if (cur->is_restart_needed) {
-+ cur->cur_seg_offset = 0;
-+ cur->init_sec_buf_read_offset = 0;
-+ ff_format_io_close(cur->parent, &cur->input);
-+ ret = reopen_demux_for_component(s, cur);
-+ cur->is_restart_needed = 0;
-+ }
-+ }
-+ }
- return AVERROR_EOF;
- }
-
-@@ -2232,6 +2268,7 @@ static int dash_close(AVFormatContext *s)
- free_subtitle_list(c);
- av_dict_free(&c->avio_opts);
- av_freep(&c->base_url);
-+ av_freep(&c->cenc_decryption_key);
- return 0;
- }
-
-@@ -2319,10 +2356,11 @@ static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestam
- if (!ret)
- ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx);
- }
-- for (i = 0; i < c->n_subtitles; i++) {
-- if (!ret)
-- ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
-- }
-+ // PATCH: Seeking in subtitle streams breaks things, and it doesn't seem necessary.
-+ //for (i = 0; i < c->n_subtitles; i++) {
-+ // if (!ret)
-+ // ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx);
-+ //}
-
- return ret;
- }
+++ /dev/null
-diff --git a/libavformat/hls.c b/libavformat/hls.c
-index e622425e80..faf92804a2 100644
---- a/libavformat/hls.c
-+++ b/libavformat/hls.c
-@@ -46,7 +46,7 @@
-
- #include "hls_sample_encryption.h"
-
--#define INITIAL_BUFFER_SIZE 32768
-+#define INITIAL_BUFFER_SIZE 1048576
-
- #define MAX_FIELD_LEN 64
- #define MAX_CHARACTERISTICS_LEN 512
-@@ -1580,7 +1580,7 @@ reload:
-
- seg = next_segment(v);
- if (c->http_multiple == 1 && !v->input_next_requested &&
-- seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
-+ seg && seg->key_type != KEY_AES_128 && av_strstart(seg->url, "http", NULL)) {
- ret = open_input(c, v, seg, &v->input_next);
- if (ret < 0) {
- if (ff_check_interrupt(c->interrupt_callback))
-@@ -1613,7 +1613,7 @@ reload:
- return ret;
- }
- if (c->http_persistent &&
-- seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) {
-+ seg->key_type != KEY_AES_128 && av_strstart(seg->url, "http", NULL)) {
- v->input_read_done = 1;
- } else {
- ff_format_io_close(v->parent, &v->input);
-@@ -2475,6 +2475,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index,
- /* set segment now so we do not need to search again below */
- seek_pls->cur_seq_no = seq_no;
- seek_pls->seek_stream_index = stream_subdemuxer_index;
-+ //av_log(s, AV_LOG_INFO, "Seek to %d in %d\n", seq_no, stream_subdemuxer_index);
-
- for (i = 0; i < c->n_playlists; i++) {
- /* Reset reading */
-@@ -2535,7 +2536,7 @@ static const AVOption hls_options[] = {
- OFFSET(prefer_x_start), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS},
- {"allowed_extensions", "List of file extensions that hls is allowed to access",
- OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
-- {.str = "3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"},
-+ {.str = "3gp,aac,avi,ac3,eac3,flac,key,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"},
- INT_MIN, INT_MAX, FLAGS},
- {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded",
- OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS},
-@@ -2544,7 +2545,7 @@ static const AVOption hls_options[] = {
- {"http_persistent", "Use persistent HTTP connections",
- OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
- {"http_multiple", "Use multiple HTTP connections for fetching segments",
-- OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS},
-+ OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, FLAGS},
- {"http_seekable", "Use HTTP partial requests, 0 = disable, 1 = enable, -1 = auto",
- OFFSET(http_seekable), AV_OPT_TYPE_BOOL, { .i64 = -1}, -1, 1, FLAGS},
- {"seg_format_options", "Set options for segment demuxer",
else ifeq ($(BOXTYPE), coolstream)
#FFMPEG_GIT = 2ba896f
#FFMPEG_VER = 3.3
-FFMPEG_VER = 5.1
+FFMPEG_VER = 5.1.2
endif
# FLAC stands for Free Lossless Audio Codec, an audio format similar to MP3, but lossless, meaning that audio is compressed in FLAC without any loss in quality