summaryrefslogtreecommitdiff
path: root/chromium/third_party/ffmpeg/libavformat
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-24 12:15:48 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 13:30:04 +0000
commitb014812705fc80bff0a5c120dfcef88f349816dc (patch)
tree25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/third_party/ffmpeg/libavformat
parent9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff)
downloadqtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/ffmpeg/libavformat')
-rw-r--r--chromium/third_party/ffmpeg/libavformat/Makefile8
-rw-r--r--chromium/third_party/ffmpeg/libavformat/aacdec.c14
-rw-r--r--chromium/third_party/ffmpeg/libavformat/allformats.c80
-rw-r--r--chromium/third_party/ffmpeg/libavformat/amr.c10
-rw-r--r--chromium/third_party/ffmpeg/libavformat/aviobuf.c8
-rw-r--r--chromium/third_party/ffmpeg/libavformat/concatdec.c2
-rw-r--r--chromium/third_party/ffmpeg/libavformat/dashdec.c124
-rw-r--r--chromium/third_party/ffmpeg/libavformat/dashenc.c138
-rw-r--r--chromium/third_party/ffmpeg/libavformat/dsfdec.c36
-rw-r--r--chromium/third_party/ffmpeg/libavformat/flacenc.c290
-rw-r--r--chromium/third_party/ffmpeg/libavformat/format.c37
-rw-r--r--chromium/third_party/ffmpeg/libavformat/hls.c121
-rw-r--r--chromium/third_party/ffmpeg/libavformat/hlsenc.c338
-rw-r--r--chromium/third_party/ffmpeg/libavformat/hlsproto.c12
-rw-r--r--chromium/third_party/ffmpeg/libavformat/http.c89
-rw-r--r--chromium/third_party/ffmpeg/libavformat/img2dec.c5
-rw-r--r--chromium/third_party/ffmpeg/libavformat/internal.h51
-rw-r--r--chromium/third_party/ffmpeg/libavformat/isom.h26
-rw-r--r--chromium/third_party/ffmpeg/libavformat/ivfenc.c5
-rw-r--r--chromium/third_party/ffmpeg/libavformat/libopenmpt.c63
-rw-r--r--chromium/third_party/ffmpeg/libavformat/libsrt.c546
-rw-r--r--chromium/third_party/ffmpeg/libavformat/matroskadec.c215
-rw-r--r--chromium/third_party/ffmpeg/libavformat/mov.c674
-rw-r--r--chromium/third_party/ffmpeg/libavformat/movenc.c129
-rw-r--r--chromium/third_party/ffmpeg/libavformat/movenc.h1
-rw-r--r--chromium/third_party/ffmpeg/libavformat/mp3enc.c23
-rw-r--r--chromium/third_party/ffmpeg/libavformat/mpc8.c2
-rw-r--r--chromium/third_party/ffmpeg/libavformat/mpeg.c38
-rw-r--r--chromium/third_party/ffmpeg/libavformat/options_table.h2
-rw-r--r--chromium/third_party/ffmpeg/libavformat/os_support.c2
-rw-r--r--chromium/third_party/ffmpeg/libavformat/pcm.c13
-rw-r--r--chromium/third_party/ffmpeg/libavformat/protocols.c1
-rw-r--r--chromium/third_party/ffmpeg/libavformat/rmdec.c18
-rw-r--r--chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c2
-rw-r--r--chromium/third_party/ffmpeg/libavformat/segafilm.c22
-rw-r--r--chromium/third_party/ffmpeg/libavformat/segafilmenc.c398
-rw-r--r--chromium/third_party/ffmpeg/libavformat/spdifenc.c3
-rw-r--r--chromium/third_party/ffmpeg/libavformat/tcp.c4
-rw-r--r--chromium/third_party/ffmpeg/libavformat/tls_schannel.c10
-rw-r--r--chromium/third_party/ffmpeg/libavformat/ttaenc.c28
-rw-r--r--chromium/third_party/ffmpeg/libavformat/unix.c2
-rw-r--r--chromium/third_party/ffmpeg/libavformat/utils.c228
-rw-r--r--chromium/third_party/ffmpeg/libavformat/version.h5
-rw-r--r--chromium/third_party/ffmpeg/libavformat/vpcc.c29
-rw-r--r--chromium/third_party/ffmpeg/libavformat/vpcc.h11
-rw-r--r--chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c11
46 files changed, 3005 insertions, 869 deletions
diff --git a/chromium/third_party/ffmpeg/libavformat/Makefile b/chromium/third_party/ffmpeg/libavformat/Makefile
index e64c5b30a1e..3eeca5091df 100644
--- a/chromium/third_party/ffmpeg/libavformat/Makefile
+++ b/chromium/third_party/ffmpeg/libavformat/Makefile
@@ -133,9 +133,9 @@ OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o
OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o
OBJS-$(CONFIG_CINE_DEMUXER) += cinedec.o
-OBJS-$(CONFIG_CODEC2_DEMUXER) += ../libavcodec/codec2utils.o codec2.o rawdec.o pcm.o
-OBJS-$(CONFIG_CODEC2_MUXER) += ../libavcodec/codec2utils.o codec2.o rawenc.o
-OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += ../libavcodec/codec2utils.o codec2.o rawdec.o pcm.o
+OBJS-$(CONFIG_CODEC2_DEMUXER) += codec2.o rawdec.o pcm.o
+OBJS-$(CONFIG_CODEC2_MUXER) += codec2.o rawenc.o
+OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += codec2.o rawdec.o pcm.o
OBJS-$(CONFIG_CODEC2RAW_MUXER) += rawenc.o
OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o
OBJS-$(CONFIG_CRC_MUXER) += crcenc.o
@@ -462,6 +462,7 @@ OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o
OBJS-$(CONFIG_SDS_DEMUXER) += sdsdec.o
OBJS-$(CONFIG_SDX_DEMUXER) += sdxdec.o
OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o
+OBJS-$(CONFIG_SEGAFILM_MUXER) += segafilmenc.o
OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o
OBJS-$(CONFIG_SHORTEN_DEMUXER) += shortendec.o rawdec.o
OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o
@@ -566,6 +567,7 @@ OBJS-$(CONFIG_LIBRTMPE_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBRTMPS_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBRTMPT_PROTOCOL) += librtmp.o
OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o
+OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o
OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o
OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o
diff --git a/chromium/third_party/ffmpeg/libavformat/aacdec.c b/chromium/third_party/ffmpeg/libavformat/aacdec.c
index 5ec706bdc7a..685458b9114 100644
--- a/chromium/third_party/ffmpeg/libavformat/aacdec.c
+++ b/chromium/third_party/ffmpeg/libavformat/aacdec.c
@@ -154,11 +154,15 @@ static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, fsize;
- ret = av_get_packet(s->pb, pkt, FFMAX(ID3v2_HEADER_SIZE, ADTS_HEADER_SIZE));
-
- if (ret >= ID3v2_HEADER_SIZE && ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) {
- if ((ret = handle_id3(s, pkt)) >= 0)
- ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE);
+ // Parse all the ID3 headers between frames
+ while (1) {
+ ret = av_get_packet(s->pb, pkt, FFMAX(ID3v2_HEADER_SIZE, ADTS_HEADER_SIZE));
+ if (ret >= ID3v2_HEADER_SIZE && ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) {
+ if ((ret = handle_id3(s, pkt)) >= 0) {
+ continue;
+ }
+ }
+ break;
}
if (ret < 0)
diff --git a/chromium/third_party/ffmpeg/libavformat/allformats.c b/chromium/third_party/ffmpeg/libavformat/allformats.c
index 9dc5ce8a767..d582778b3b3 100644
--- a/chromium/third_party/ffmpeg/libavformat/allformats.c
+++ b/chromium/third_party/ffmpeg/libavformat/allformats.c
@@ -20,14 +20,12 @@
*/
#include "libavutil/thread.h"
+#include "libavformat/internal.h"
#include "avformat.h"
#include "rtp.h"
#include "rdt.h"
#include "url.h"
#include "version.h"
-#if FF_API_NEXT
-#include "internal.h"
-#endif
/* (de)muxers */
extern AVOutputFormat ff_a64_muxer;
@@ -364,6 +362,7 @@ extern AVInputFormat ff_sdr2_demuxer;
extern AVInputFormat ff_sds_demuxer;
extern AVInputFormat ff_sdx_demuxer;
extern AVInputFormat ff_segafilm_demuxer;
+extern AVOutputFormat ff_segafilm_muxer;
extern AVOutputFormat ff_segment_muxer;
extern AVOutputFormat ff_stream_segment_muxer;
extern AVInputFormat ff_shorten_demuxer;
@@ -487,76 +486,84 @@ extern AVInputFormat ff_libopenmpt_demuxer;
#include "libavformat/muxer_list.c"
#include "libavformat/demuxer_list.c"
+static const AVInputFormat * const *indev_list = NULL;
+static const AVOutputFormat * const *outdev_list = NULL;
+
const AVOutputFormat *av_muxer_iterate(void **opaque)
{
+ static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1;
uintptr_t i = (uintptr_t)*opaque;
- const AVOutputFormat *f = muxer_list[i];
+ const AVOutputFormat *f = NULL;
+
+ if (i < size) {
+ f = muxer_list[i];
+ } else if (indev_list) {
+ f = outdev_list[i - size];
+ }
if (f)
*opaque = (void*)(i + 1);
return f;
}
-const AVInputFormat *av_demuxer_iterate(void **opaque){
+const AVInputFormat *av_demuxer_iterate(void **opaque)
+{
+ static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
uintptr_t i = (uintptr_t)*opaque;
- const AVInputFormat *f = demuxer_list[i];
+ const AVInputFormat *f = NULL;
+
+ if (i < size) {
+ f = demuxer_list[i];
+ } else if (outdev_list) {
+ f = indev_list[i - size];
+ }
if (f)
*opaque = (void*)(i + 1);
return f;
}
+static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER;
+
#if FF_API_NEXT
FF_DISABLE_DEPRECATION_WARNINGS
static AVOnce av_format_next_init = AV_ONCE_INIT;
-static const AVInputFormat * const *indev_list = NULL;
-static const AVOutputFormat * const *outdev_list = NULL;
-
static void av_format_init_next(void)
{
AVOutputFormat *prevout = NULL, *out;
AVInputFormat *previn = NULL, *in;
- void *i = 0;
- while ((out = (AVOutputFormat*)av_muxer_iterate(&i))) {
+ ff_mutex_lock(&avpriv_register_devices_mutex);
+
+ for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) {
if (prevout)
prevout->next = out;
prevout = out;
}
if (outdev_list) {
- for (int j = 0; (out = (AVOutputFormat*)outdev_list[j]); j++) {
+ for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) {
if (prevout)
prevout->next = out;
prevout = out;
}
}
- i = 0;
- while ((in = (AVInputFormat*)av_demuxer_iterate(&i))) {
+ for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) {
if (previn)
previn->next = in;
previn = in;
}
if (indev_list) {
- for (int j = 0; (in = (AVInputFormat*)indev_list[j]); j++) {
+ for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) {
if (previn)
previn->next = in;
previn = in;
}
}
-}
-
-void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[])
-{
- static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER;
- ff_mutex_lock(&avpriv_register_devices_mutex);
- outdev_list = o;
- indev_list = i;
- av_format_init_next();
ff_mutex_unlock(&avpriv_register_devices_mutex);
}
@@ -566,10 +573,10 @@ AVInputFormat *av_iformat_next(const AVInputFormat *f)
if (f)
return f->next;
- else
- /* If there are no demuxers but input devices, then return the first input device.
- * This will still return null if both there are both no demuxers or input devices. */
- return demuxer_list[0] ? (AVInputFormat*)demuxer_list[0] : (indev_list ? (AVInputFormat*)indev_list[0] : NULL);
+ else {
+ void *opaque = NULL;
+ return (AVInputFormat *)av_demuxer_iterate(&opaque);
+ }
}
AVOutputFormat *av_oformat_next(const AVOutputFormat *f)
@@ -578,8 +585,10 @@ AVOutputFormat *av_oformat_next(const AVOutputFormat *f)
if (f)
return f->next;
- else
- return muxer_list[0] ? (AVOutputFormat*)muxer_list[0] : (outdev_list ? (AVOutputFormat*)outdev_list[0] : NULL);
+ else {
+ void *opaque = NULL;
+ return (AVOutputFormat *)av_muxer_iterate(&opaque);
+ }
}
void av_register_all(void)
@@ -598,3 +607,14 @@ void av_register_output_format(AVOutputFormat *format)
}
FF_ENABLE_DEPRECATION_WARNINGS
#endif
+
+void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[])
+{
+ ff_mutex_lock(&avpriv_register_devices_mutex);
+ outdev_list = o;
+ indev_list = i;
+ ff_mutex_unlock(&avpriv_register_devices_mutex);
+#if FF_API_NEXT
+ av_format_init_next();
+#endif
+}
diff --git a/chromium/third_party/ffmpeg/libavformat/amr.c b/chromium/third_party/ffmpeg/libavformat/amr.c
index 8b4d736d2f9..f954803d461 100644
--- a/chromium/third_party/ffmpeg/libavformat/amr.c
+++ b/chromium/third_party/ffmpeg/libavformat/amr.c
@@ -178,7 +178,7 @@ AVInputFormat ff_amr_demuxer = {
#if CONFIG_AMRNB_DEMUXER
static int amrnb_probe(AVProbeData *p)
{
- int mode, i = 0, valid = 0;
+ int mode, i = 0, valid = 0, invalid = 0;
const uint8_t *b = p->buf;
while (i < p->buf_size) {
@@ -197,10 +197,11 @@ static int amrnb_probe(AVProbeData *p)
}
} else {
valid = 0;
+ invalid++;
i++;
}
}
- if (valid > 100)
+ if (valid > 100 && valid > invalid)
return AVPROBE_SCORE_EXTENSION / 2 + 1;
return 0;
}
@@ -234,7 +235,7 @@ AVInputFormat ff_amrnb_demuxer = {
#if CONFIG_AMRWB_DEMUXER
static int amrwb_probe(AVProbeData *p)
{
- int mode, i = 0, valid = 0;
+ int mode, i = 0, valid = 0, invalid = 0;
const uint8_t *b = p->buf;
while (i < p->buf_size) {
@@ -253,10 +254,11 @@ static int amrwb_probe(AVProbeData *p)
}
} else {
valid = 0;
+ invalid++;
i++;
}
}
- if (valid > 100)
+ if (valid > 100 && valid > invalid)
return AVPROBE_SCORE_EXTENSION / 2 - 1;
return 0;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/aviobuf.c b/chromium/third_party/ffmpeg/libavformat/aviobuf.c
index 95b33644784..e752d0e1a65 100644
--- a/chromium/third_party/ffmpeg/libavformat/aviobuf.c
+++ b/chromium/third_party/ffmpeg/libavformat/aviobuf.c
@@ -823,6 +823,14 @@ int ff_get_line(AVIOContext *s, char *buf, int maxlen)
return i;
}
+int ff_get_chomp_line(AVIOContext *s, char *buf, int maxlen)
+{
+ int len = ff_get_line(s, buf, maxlen);
+ while (len > 0 && av_isspace(buf[len - 1]))
+ buf[--len] = '\0';
+ return len;
+}
+
int64_t ff_read_line_to_bprint(AVIOContext *s, AVBPrint *bp)
{
int len, end;
diff --git a/chromium/third_party/ffmpeg/libavformat/concatdec.c b/chromium/third_party/ffmpeg/libavformat/concatdec.c
index 8fff9cc2cbc..bbe13136fa2 100644
--- a/chromium/third_party/ffmpeg/libavformat/concatdec.c
+++ b/chromium/third_party/ffmpeg/libavformat/concatdec.c
@@ -603,7 +603,6 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
av_packet_unref(pkt);
continue;
}
- pkt->stream_index = cs->out_stream_index;
break;
}
if ((ret = filter_packet(avf, cs, pkt)))
@@ -646,6 +645,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
}
}
+ pkt->stream_index = cs->out_stream_index;
return ret;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/dashdec.c b/chromium/third_party/ffmpeg/libavformat/dashdec.c
index 2b396a01b71..a2e2e13382b 100644
--- a/chromium/third_party/ffmpeg/libavformat/dashdec.c
+++ b/chromium/third_party/ffmpeg/libavformat/dashdec.c
@@ -149,6 +149,11 @@ typedef struct DASHContext {
char *allowed_extensions;
AVDictionary *avio_opts;
int max_url_size;
+
+ /* Flags for init section*/
+ int is_init_section_common_video;
+ int is_init_section_common_audio;
+
} DASHContext;
static int ishttp(char *url)
@@ -416,9 +421,9 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
if (av_strstart(proto_name, "file", NULL)) {
if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(url, c->allowed_extensions)) {
av_log(s, AV_LOG_ERROR,
- "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n"
- "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n",
- url);
+ "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n"
+ "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n",
+ url);
return AVERROR_INVALIDDATA;
}
} else if (av_strstart(proto_name, "http", NULL)) {
@@ -805,7 +810,8 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url,
xmlNodePtr fragment_template_node,
xmlNodePtr content_component_node,
xmlNodePtr adaptionset_baseurl_node,
- xmlNodePtr adaptionset_segmentlist_node)
+ xmlNodePtr adaptionset_segmentlist_node,
+ xmlNodePtr adaptionset_supplementalproperty_node)
{
int32_t ret = 0;
int32_t audio_rep_idx = 0;
@@ -825,6 +831,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url,
char *timescale_val = NULL;
char *initialization_val = NULL;
char *media_val = NULL;
+ char *val = NULL;
xmlNodePtr baseurl_nodes[4];
xmlNodePtr representation_node = node;
char *rep_id_val = xmlGetProp(representation_node, "id");
@@ -920,6 +927,17 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url,
rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10);
xmlFree(startnumber_val);
}
+ if (adaptionset_supplementalproperty_node) {
+ if (!av_strcasecmp(xmlGetProp(adaptionset_supplementalproperty_node,"schemeIdUri"), "http://dashif.org/guidelines/last-segment-number")) {
+ val = xmlGetProp(adaptionset_supplementalproperty_node,"value");
+ if (!val) {
+ av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n");
+ } else {
+ rep->last_seq_no =(int64_t) strtoll(val, NULL, 10) - 1;
+ xmlFree(val);
+ }
+ }
+ }
fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline");
@@ -1054,6 +1072,7 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url,
xmlNodePtr content_component_node = NULL;
xmlNodePtr adaptionset_baseurl_node = NULL;
xmlNodePtr adaptionset_segmentlist_node = NULL;
+ xmlNodePtr adaptionset_supplementalproperty_node = NULL;
xmlNodePtr node = NULL;
node = xmlFirstElementChild(adaptionset_node);
@@ -1066,6 +1085,8 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url,
adaptionset_baseurl_node = node;
} else if (!av_strcasecmp(node->name, (const char *)"SegmentList")) {
adaptionset_segmentlist_node = node;
+ } else if (!av_strcasecmp(node->name, (const char *)"SupplementalProperty")) {
+ adaptionset_supplementalproperty_node = node;
} else if (!av_strcasecmp(node->name, (const char *)"Representation")) {
ret = parse_manifest_representation(s, url, node,
adaptionset_node,
@@ -1076,7 +1097,8 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url,
fragment_template_node,
content_component_node,
adaptionset_baseurl_node,
- adaptionset_segmentlist_node);
+ adaptionset_segmentlist_node,
+ adaptionset_supplementalproperty_node);
if (ret < 0) {
return ret;
}
@@ -1106,8 +1128,8 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
xmlNodePtr adaptionset_node = NULL;
xmlAttrPtr attr = NULL;
char *val = NULL;
- uint32_t perdiod_duration_sec = 0;
- uint32_t perdiod_start_sec = 0;
+ uint32_t period_duration_sec = 0;
+ uint32_t period_start_sec = 0;
if (!in) {
close_in = 1;
@@ -1143,7 +1165,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
} else {
LIBXML_TEST_VERSION
- doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0);
+ doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0);
root_element = xmlDocGetRootElement(doc);
node = root_element;
@@ -1202,23 +1224,23 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in)
node = xmlFirstElementChild(node);
while (node) {
if (!av_strcasecmp(node->name, (const char *)"Period")) {
- perdiod_duration_sec = 0;
- perdiod_start_sec = 0;
+ period_duration_sec = 0;
+ period_start_sec = 0;
attr = node->properties;
while (attr) {
val = xmlGetProp(node, attr->name);
if (!av_strcasecmp(attr->name, (const char *)"duration")) {
- perdiod_duration_sec = get_duration_insec(s, (const char *)val);
+ period_duration_sec = get_duration_insec(s, (const char *)val);
} else if (!av_strcasecmp(attr->name, (const char *)"start")) {
- perdiod_start_sec = get_duration_insec(s, (const char *)val);
+ period_start_sec = get_duration_insec(s, (const char *)val);
}
attr = attr->next;
xmlFree(val);
}
- if ((perdiod_duration_sec) >= (c->period_duration)) {
+ if ((period_duration_sec) >= (c->period_duration)) {
period_node = node;
- c->period_duration = perdiod_duration_sec;
- c->period_start = perdiod_start_sec;
+ c->period_duration = period_duration_sec;
+ c->period_start = period_start_sec;
if (c->period_start > 0)
c->media_presentation_duration = c->period_duration;
}
@@ -1379,14 +1401,14 @@ static int refresh_manifest(AVFormatContext *s)
if (c->n_videos != n_videos) {
av_log(c, AV_LOG_ERROR,
- "new manifest has mismatched no. of video representations, %d -> %d\n",
- n_videos, c->n_videos);
+ "new manifest has mismatched no. of video representations, %d -> %d\n",
+ n_videos, c->n_videos);
return AVERROR_INVALIDDATA;
}
if (c->n_audios != n_audios) {
av_log(c, AV_LOG_ERROR,
- "new manifest has mismatched no. of audio representations, %d -> %d\n",
- n_audios, c->n_audios);
+ "new manifest has mismatched no. of audio representations, %d -> %d\n",
+ n_audios, c->n_audios);
return AVERROR_INVALIDDATA;
}
@@ -1819,7 +1841,10 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p
pls->parent = s;
pls->cur_seq_no = calc_cur_seg_no(s, pls);
- pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
+
+ if (!pls->last_seq_no) {
+ pls->last_seq_no = calc_max_seg_no(pls, s->priv_data);
+ }
ret = reopen_demux_for_component(s, pls);
if (ret < 0) {
@@ -1842,6 +1867,45 @@ fail:
return ret;
}
+static int init_section_compare_video(DASHContext *c)
+{
+ int i = 0;
+ char *url = c->videos[0]->init_section->url;
+ int64_t url_offset = c->videos[0]->init_section->url_offset;
+ int64_t size = c->videos[0]->init_section->size;
+ for (i=0;i<c->n_videos;i++) {
+ if (av_strcasecmp(c->videos[i]->init_section->url,url) || c->videos[i]->init_section->url_offset != url_offset || c->videos[i]->init_section->size != size) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int init_section_compare_audio(DASHContext *c)
+{
+ int i = 0;
+ char *url = c->audios[0]->init_section->url;
+ int64_t url_offset = c->audios[0]->init_section->url_offset;
+ int64_t size = c->audios[0]->init_section->size;
+ for (i=0;i<c->n_audios;i++) {
+ if (av_strcasecmp(c->audios[i]->init_section->url,url) || c->audios[i]->init_section->url_offset != url_offset || c->audios[i]->init_section->size != size) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void copy_init_section(struct representation *rep_dest, struct representation *rep_src)
+{
+ *rep_dest->init_section = *rep_src->init_section;
+ rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size);
+ memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len);
+ rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size;
+ rep_dest->init_sec_data_len = rep_src->init_sec_data_len;
+ rep_dest->cur_timestamp = rep_src->cur_timestamp;
+}
+
+
static int dash_read_header(AVFormatContext *s)
{
void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb;
@@ -1870,19 +1934,35 @@ static int dash_read_header(AVFormatContext *s)
s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE;
}
+ if (c->n_videos) {
+ c->is_init_section_common_video = init_section_compare_video(c);
+ }
+
/* Open the demuxer for video and audio components if available */
for (i = 0; i < c->n_videos; i++) {
struct representation *cur_video = c->videos[i];
+ if (i > 0 && c->is_init_section_common_video) {
+ copy_init_section(cur_video,c->videos[0]);
+ }
ret = open_demux_for_component(s, cur_video);
+
if (ret)
goto fail;
cur_video->stream_index = stream_index;
++stream_index;
}
+ if (c->n_audios) {
+ c->is_init_section_common_audio = init_section_compare_audio(c);
+ }
+
for (i = 0; i < c->n_audios; i++) {
struct representation *cur_audio = c->audios[i];
+ if (i > 0 && c->is_init_section_common_audio) {
+ copy_init_section(cur_audio,c->audios[0]);
+ }
ret = open_demux_for_component(s, cur_audio);
+
if (ret)
goto fail;
cur_audio->stream_index = stream_index;
@@ -1911,7 +1991,7 @@ static int dash_read_header(AVFormatContext *s)
av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0);
if (pls->id[0])
av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0);
- }
+ }
for (i = 0; i < c->n_audios; i++) {
struct representation *pls = c->audios[i];
@@ -2028,7 +2108,7 @@ static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t see
int64_t duration = 0;
av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d%s\n",
- seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : "");
+ seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : "");
// single fragment mode
if (pls->n_fragments == 1) {
diff --git a/chromium/third_party/ffmpeg/libavformat/dashenc.c b/chromium/third_party/ffmpeg/libavformat/dashenc.c
index 79d63e52d43..fefe3ce0ca4 100644
--- a/chromium/third_party/ffmpeg/libavformat/dashenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/dashenc.c
@@ -76,15 +76,17 @@ typedef struct OutputStream {
int nb_segments, segments_size, segment_index;
Segment **segments;
int64_t first_pts, start_pts, max_pts;
- int64_t last_dts;
+ int64_t last_dts, last_pts;
int bit_rate;
- char bandwidth_str[64];
char codec_str[100];
int written_len;
char filename[1024];
char full_path[1024];
char temp_path[1024];
+ double availability_time_offset;
+ int total_pkt_size;
+ int muxer_overhead;
} OutputStream;
typedef struct DASHContext {
@@ -94,7 +96,10 @@ typedef struct DASHContext {
int nb_as;
int window_size;
int extra_window_size;
+#if FF_API_DASH_MIN_SEG_DURATION
int min_seg_duration;
+#endif
+ int64_t seg_duration;
int remove_at_exit;
int use_template;
int use_timeline;
@@ -117,6 +122,8 @@ typedef struct DASHContext {
AVIOContext *mpd_out;
AVIOContext *m3u8_out;
int streaming;
+ int64_t timeout;
+ int index_correction;
} DASHContext;
static struct codec_string {
@@ -269,6 +276,8 @@ static void set_http_options(AVDictionary **options, DASHContext *c)
av_dict_set(options, "user_agent", c->user_agent, 0);
if (c->http_persistent)
av_dict_set_int(options, "multiple_requests", 1, 0);
+ if (c->timeout >= 0)
+ av_dict_set_int(options, "timeout", c->timeout, 0);
}
static void get_hls_playlist_name(char *playlist_name, int string_size,
@@ -340,8 +349,12 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont
if (c->use_template) {
int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : AV_TIME_BASE;
avio_printf(out, "\t\t\t\t<SegmentTemplate timescale=\"%d\" ", timescale);
- if (!c->use_timeline)
- avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
+ if (!c->use_timeline) {
+ avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration);
+ if (c->streaming && os->availability_time_offset)
+ avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
+ os->availability_time_offset);
+ }
avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : 1);
if (c->use_timeline) {
int64_t cur_time = 0;
@@ -536,20 +549,25 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind
for (i = 0; i < s->nb_streams; i++) {
OutputStream *os = &c->streams[i];
+ char bandwidth_str[64] = {'\0'};
if (os->as_idx - 1 != as_index)
continue;
+ if (os->bit_rate > 0)
+ snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
+ os->bit_rate + os->muxer_overhead);
+
if (as->media_type == AVMEDIA_TYPE_VIDEO) {
AVStream *st = s->streams[i];
avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"video/%s\" codecs=\"%s\"%s width=\"%d\" height=\"%d\"",
- i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
+ i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
if (st->avg_frame_rate.num)
avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den);
avio_printf(out, ">\n");
} else {
avio_printf(out, "\t\t\t<Representation id=\"%d\" mimeType=\"audio/%s\" codecs=\"%s\"%s audioSamplingRate=\"%d\">\n",
- i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->sample_rate);
+ i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate);
avio_printf(out, "\t\t\t\t<AudioChannelConfiguration schemeIdUri=\"urn:mpeg:dash:23003:3:audio_channel_configuration:2011\" value=\"%d\" />\n",
s->streams[i]->codecpar->channels);
}
@@ -737,9 +755,6 @@ static int write_manifest(AVFormatContext *s, int final)
update_period = 500;
avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", update_period);
avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", c->last_duration / AV_TIME_BASE);
- if (!c->availability_start_time[0] && s->nb_streams > 0 && c->streams[0].nb_segments > 0) {
- format_date_now(c->availability_start_time, sizeof(c->availability_start_time));
- }
if (c->availability_start_time[0])
avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", c->availability_start_time);
format_date_now(now_str, sizeof(now_str));
@@ -812,25 +827,28 @@ static int write_manifest(AVFormatContext *s, int final)
}
av_dict_free(&opts);
- ff_hls_write_playlist_version(out, 6);
+ ff_hls_write_playlist_version(out, 7);
for (i = 0; i < s->nb_streams; i++) {
char playlist_file[64];
AVStream *st = s->streams[i];
+ OutputStream *os = &c->streams[i];
if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
continue;
get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i);
ff_hls_write_audio_rendition(out, (char *)audio_group,
playlist_file, i, is_default);
- max_audio_bitrate = FFMAX(st->codecpar->bit_rate, max_audio_bitrate);
+ max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
+ os->muxer_overhead, max_audio_bitrate);
is_default = 0;
}
for (i = 0; i < s->nb_streams; i++) {
char playlist_file[64];
AVStream *st = s->streams[i];
+ OutputStream *os = &c->streams[i];
char *agroup = NULL;
- int stream_bitrate = st->codecpar->bit_rate;
+ int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead;
if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && max_audio_bitrate) {
agroup = (char *)audio_group;
stream_bitrate += max_audio_bitrate;
@@ -868,6 +886,13 @@ static int dash_init(AVFormatContext *s)
if (c->single_file)
c->use_template = 0;
+#if FF_API_DASH_MIN_SEG_DURATION
+ if (c->min_seg_duration != 5000000) {
+ av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated and will be removed. Please use the -seg_duration\n");
+ c->seg_duration = c->min_seg_duration;
+ }
+#endif
+
av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
ptr = strrchr(c->dirname, '/');
if (ptr) {
@@ -898,10 +923,7 @@ static int dash_init(AVFormatContext *s)
char filename[1024];
os->bit_rate = s->streams[i]->codecpar->bit_rate;
- if (os->bit_rate) {
- snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
- } else {
+ if (!os->bit_rate) {
int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ?
AV_LOG_ERROR : AV_LOG_WARNING;
av_log(s, level, "No bit rate set for stream %d\n", i);
@@ -971,7 +993,7 @@ static int dash_init(AVFormatContext *s)
else
av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
} else {
- av_dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0);
+ av_dict_set_int(&opts, "cluster_time_limit", c->seg_duration / 1000, 0);
av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit
av_dict_set_int(&opts, "dash", 1, 0);
av_dict_set_int(&opts, "dash_track_number", i + 1, 0);
@@ -1017,8 +1039,8 @@ static int dash_init(AVFormatContext *s)
os->segment_index = 1;
}
- if (!c->has_video && c->min_seg_duration <= 0) {
- av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration set\n");
+ if (!c->has_video && c->seg_duration <= 0) {
+ av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
return AVERROR(EINVAL);
}
return 0;
@@ -1030,21 +1052,16 @@ static int dash_write_header(AVFormatContext *s)
int i, ret;
for (i = 0; i < s->nb_streams; i++) {
OutputStream *os = &c->streams[i];
- if ((ret = avformat_write_header(os->ctx, NULL)) < 0) {
- dash_free(s);
+ if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
return ret;
- }
}
- ret = write_manifest(s, 0);
- if (!ret)
- av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->url);
return ret;
}
static int add_segment(OutputStream *os, const char *file,
int64_t time, int duration,
int64_t start_pos, int64_t range_length,
- int64_t index_length)
+ int64_t index_length, int next_exp_index)
{
int err;
Segment *seg;
@@ -1072,6 +1089,12 @@ static int add_segment(OutputStream *os, const char *file,
seg->index_length = index_length;
os->segments[os->nb_segments++] = seg;
os->segment_index++;
+ //correcting the segment index if it has fallen behind the expected value
+ if (os->segment_index < next_exp_index) {
+ av_log(NULL, AV_LOG_WARNING, "Correcting the segment index after file %s: current=%d corrected=%d\n",
+ file, os->segment_index, next_exp_index);
+ os->segment_index = next_exp_index;
+ }
return 0;
}
@@ -1161,10 +1184,22 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
const char *proto = avio_find_protocol_name(s->url);
int use_rename = proto && !strcmp(proto, "file");
- int cur_flush_segment_index = 0;
- if (stream >= 0)
+ int cur_flush_segment_index = 0, next_exp_index = -1;
+ if (stream >= 0) {
cur_flush_segment_index = c->streams[stream].segment_index;
+ //finding the next segment's expected index, based on the current pts value
+ if (c->use_template && !c->use_timeline && c->index_correction &&
+ c->streams[stream].last_pts != AV_NOPTS_VALUE &&
+ c->streams[stream].first_pts != AV_NOPTS_VALUE) {
+ int64_t pts_diff = av_rescale_q(c->streams[stream].last_pts -
+ c->streams[stream].first_pts,
+ s->streams[stream]->time_base,
+ AV_TIME_BASE_Q);
+ next_exp_index = (pts_diff / c->seg_duration) + 1;
+ }
+ }
+
for (i = 0; i < s->nb_streams; i++) {
OutputStream *os = &c->streams[i];
AVStream *st = s->streams[i];
@@ -1209,18 +1244,22 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
}
}
+ if (!os->muxer_overhead)
+ os->muxer_overhead = ((int64_t) (range_length - os->total_pkt_size) *
+ 8 * AV_TIME_BASE) /
+ av_rescale_q(os->max_pts - os->start_pts,
+ st->time_base, AV_TIME_BASE_Q);
+ os->total_pkt_size = 0;
+
if (!os->bit_rate) {
// calculate average bitrate of first segment
int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts,
st->time_base,
AV_TIME_BASE_Q);
- if (bitrate >= 0) {
+ if (bitrate >= 0)
os->bit_rate = bitrate;
- snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
- }
}
- add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length);
+ add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index);
av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path);
os->pos += range_length;
@@ -1256,6 +1295,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
DASHContext *c = s->priv_data;
AVStream *st = s->streams[pkt->stream_index];
OutputStream *os = &c->streams[pkt->stream_index];
+ int64_t seg_end_duration, elapsed_duration;
int ret;
ret = update_stream_extradata(s, os, st->codecpar);
@@ -1282,11 +1322,31 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
if (os->first_pts == AV_NOPTS_VALUE)
os->first_pts = pkt->pts;
+ os->last_pts = pkt->pts;
+
+ if (!c->availability_start_time[0])
+ format_date_now(c->availability_start_time,
+ sizeof(c->availability_start_time));
+
+ if (!os->availability_time_offset && pkt->duration) {
+ int64_t frame_duration = av_rescale_q(pkt->duration, st->time_base,
+ AV_TIME_BASE_Q);
+ os->availability_time_offset = ((double) c->seg_duration -
+ frame_duration) / AV_TIME_BASE;
+ }
+
+ if (c->use_template && !c->use_timeline) {
+ elapsed_duration = pkt->pts - os->first_pts;
+ seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
+ } else {
+ elapsed_duration = pkt->pts - os->start_pts;
+ seg_end_duration = c->seg_duration;
+ }
if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
- av_compare_ts(pkt->pts - os->start_pts, st->time_base,
- c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
+ av_compare_ts(elapsed_duration, st->time_base,
+ seg_end_duration, AV_TIME_BASE_Q) >= 0) {
int64_t prev_duration = c->last_duration;
c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1323,6 +1383,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
else
os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
os->packets_written++;
+ os->total_pkt_size += pkt->size;
if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
return ret;
@@ -1426,7 +1487,10 @@ static const AVOption options[] = {
{ "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
{ "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
{ "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E },
- { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E },
+#if FF_API_DASH_MIN_SEG_DURATION
+ { "min_seg_duration", "minimum segment duration (in microseconds) (will be deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E },
+#endif
+ { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E },
{ "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
{ "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
{ "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
@@ -1440,6 +1504,8 @@ static const AVOption options[] = {
{ "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
{ "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
{ "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
+ { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
+ { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
{ NULL },
};
diff --git a/chromium/third_party/ffmpeg/libavformat/dsfdec.c b/chromium/third_party/ffmpeg/libavformat/dsfdec.c
index 41538fd83c0..5e06fd63a58 100644
--- a/chromium/third_party/ffmpeg/libavformat/dsfdec.c
+++ b/chromium/third_party/ffmpeg/libavformat/dsfdec.c
@@ -26,6 +26,8 @@
typedef struct {
uint64_t data_end;
+ uint64_t audio_size;
+ uint64_t data_size;
} DSFContext;
static int dsf_probe(AVProbeData *p)
@@ -120,7 +122,7 @@ static int dsf_read_header(AVFormatContext *s)
return AVERROR_INVALIDDATA;
}
- avio_skip(pb, 8);
+ dsf->audio_size = avio_rl64(pb) / 8 * st->codecpar->channels;
st->codecpar->block_align = avio_rl32(pb);
if (st->codecpar->block_align > INT_MAX / st->codecpar->channels) {
avpriv_request_sample(s, "block_align overflow");
@@ -135,7 +137,9 @@ static int dsf_read_header(AVFormatContext *s)
dsf->data_end = avio_tell(pb);
if (avio_rl32(pb) != MKTAG('d', 'a', 't', 'a'))
return AVERROR_INVALIDDATA;
- dsf->data_end += avio_rl64(pb);
+ dsf->data_size = avio_rl64(pb) - 12;
+ dsf->data_end += dsf->data_size + 12;
+ s->internal->data_offset = avio_tell(pb);
return 0;
}
@@ -151,6 +155,34 @@ static int dsf_read_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR_EOF;
pkt->stream_index = 0;
+ if (dsf->data_size > dsf->audio_size) {
+ int last_packet = pos == (dsf->data_end - st->codecpar->block_align);
+
+ if (last_packet) {
+ int64_t data_pos = pos - s->internal->data_offset;
+ int64_t packet_size = dsf->audio_size - data_pos;
+ int64_t skip_size = dsf->data_size - data_pos - packet_size;
+ uint8_t *dst;
+ int ch, ret;
+
+ if (packet_size <= 0 || skip_size <= 0)
+ return AVERROR_INVALIDDATA;
+
+ if (av_new_packet(pkt, packet_size) < 0)
+ return AVERROR(ENOMEM);
+ dst = pkt->data;
+ for (ch = 0; ch < st->codecpar->channels; ch++) {
+ ret = avio_read(pb, dst, packet_size / st->codecpar->channels);
+ if (ret < packet_size / st->codecpar->channels)
+ return AVERROR_EOF;
+
+ dst += ret;
+ avio_skip(pb, skip_size / st->codecpar->channels);
+ }
+
+ return 0;
+ }
+ }
return av_get_packet(pb, pkt, FFMIN(dsf->data_end - pos, st->codecpar->block_align));
}
diff --git a/chromium/third_party/ffmpeg/libavformat/flacenc.c b/chromium/third_party/ffmpeg/libavformat/flacenc.c
index b894f9ef614..617bccdc84a 100644
--- a/chromium/third_party/ffmpeg/libavformat/flacenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/flacenc.c
@@ -21,10 +21,13 @@
#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
#include "libavcodec/flac.h"
#include "avformat.h"
#include "avio_internal.h"
#include "flacenc.h"
+#include "id3v2.h"
+#include "internal.h"
#include "vorbiscomment.h"
#include "libavcodec/bytestream.h"
@@ -33,8 +36,15 @@ typedef struct FlacMuxerContext {
const AVClass *class;
int write_header;
+ int audio_stream_idx;
+ int waiting_pics;
+ /* audio packets are queued here until we get all the attached pictures */
+ AVPacketList *queue, *queue_end;
+
/* updated streaminfo sent by the encoder at the end */
uint8_t *streaminfo;
+
+ unsigned attached_types;
} FlacMuxerContext;
static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_bytes,
@@ -74,36 +84,160 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m,
return 0;
}
-static int flac_write_header(struct AVFormatContext *s)
+static int flac_write_picture(struct AVFormatContext *s, AVPacket *pkt)
{
- int ret;
- int padding = s->metadata_header_padding;
- AVCodecParameters *par = s->streams[0]->codecpar;
- FlacMuxerContext *c = s->priv_data;
-
- if (!c->write_header)
+ FlacMuxerContext *c = s->priv_data;
+ AVIOContext *pb = s->pb;
+ const AVPixFmtDescriptor *pixdesc;
+ const CodecMime *mime = ff_id3v2_mime_tags;
+ AVDictionaryEntry *e;
+ const char *mimetype = NULL, *desc = "";
+ const AVStream *st = s->streams[pkt->stream_index];
+ int i, mimelen, desclen, type = 0;
+
+ if (!pkt->data)
return 0;
- if (s->nb_streams > 1) {
- av_log(s, AV_LOG_ERROR, "only one stream is supported\n");
+ while (mime->id != AV_CODEC_ID_NONE) {
+ if (mime->id == st->codecpar->codec_id) {
+ mimetype = mime->str;
+ break;
+ }
+ mime++;
+ }
+ if (!mimetype) {
+ av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot "
+ "write an attached picture.\n", st->index);
+ return AVERROR(EINVAL);
+ }
+ mimelen = strlen(mimetype);
+
+ /* get the picture type */
+ e = av_dict_get(st->metadata, "comment", NULL, 0);
+ for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) {
+ if (!av_strcasecmp(e->value, ff_id3v2_picture_types[i])) {
+ type = i;
+ break;
+ }
+ }
+
+ if ((c->attached_types & (1 << type)) & 0x6) {
+ av_log(s, AV_LOG_ERROR, "Duplicate attachment for type '%s'\n", ff_id3v2_picture_types[type]);
return AVERROR(EINVAL);
}
- if (par->codec_id != AV_CODEC_ID_FLAC) {
- av_log(s, AV_LOG_ERROR, "unsupported codec\n");
+
+ if (type == 1 && (st->codecpar->codec_id != AV_CODEC_ID_PNG ||
+ st->codecpar->width != 32 ||
+ st->codecpar->height != 32)) {
+ av_log(s, AV_LOG_ERROR, "File icon attachment must be a 32x32 PNG");
return AVERROR(EINVAL);
}
+ c->attached_types |= (1 << type);
+
+ /* get the description */
+ if ((e = av_dict_get(st->metadata, "title", NULL, 0)))
+ desc = e->value;
+ desclen = strlen(desc);
+
+ avio_w8(pb, 0x06);
+ avio_wb24(pb, 4 + 4 + mimelen + 4 + desclen + 4 + 4 + 4 + 4 + 4 + pkt->size);
+
+ avio_wb32(pb, type);
+
+ avio_wb32(pb, mimelen);
+ avio_write(pb, mimetype, mimelen);
+
+ avio_wb32(pb, desclen);
+ avio_write(pb, desc, desclen);
+
+ avio_wb32(pb, st->codecpar->width);
+ avio_wb32(pb, st->codecpar->height);
+ if ((pixdesc = av_pix_fmt_desc_get(st->codecpar->format)))
+ avio_wb32(pb, av_get_bits_per_pixel(pixdesc));
+ else
+ avio_wb32(pb, 0);
+ avio_wb32(pb, 0);
+
+ avio_wb32(pb, pkt->size);
+ avio_write(pb, pkt->data, pkt->size);
+ return 0;
+}
+
+static int flac_finish_header(struct AVFormatContext *s)
+{
+ int i, ret, padding = s->metadata_header_padding;
if (padding < 0)
padding = 8192;
/* The FLAC specification states that 24 bits are used to represent the
* size of a metadata block so we must clip this value to 2^24-1. */
padding = av_clip_uintp2(padding, 24);
- ret = ff_flac_write_header(s->pb, par->extradata,
- par->extradata_size, 0);
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ AVPacket *pkt = st->priv_data;
+ if (!pkt)
+ continue;
+ ret = flac_write_picture(s, pkt);
+ av_packet_unref(pkt);
+ if (ret < 0 && (s->error_recognition & AV_EF_EXPLODE))
+ return ret;
+ }
+
+ ret = flac_write_block_comment(s->pb, &s->metadata, !padding,
+ s->flags & AVFMT_FLAG_BITEXACT);
if (ret)
return ret;
+ /* The command line flac encoder defaults to placing a seekpoint
+ * every 10s. So one might add padding to allow that later
+ * but there seems to be no simple way to get the duration here.
+ * So just add the amount requested by the user. */
+ if (padding)
+ flac_write_block_padding(s->pb, padding, 1);
+
+ return 0;
+}
+
+static int flac_init(struct AVFormatContext *s)
+{
+ AVCodecParameters *par;
+ FlacMuxerContext *c = s->priv_data;
+ int i;
+
+ c->audio_stream_idx = -1;
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (c->audio_stream_idx >= 0 || st->codecpar->codec_id != AV_CODEC_ID_FLAC) {
+ av_log(s, AV_LOG_ERROR, "Invalid audio stream. Exactly one FLAC "
+ "audio stream is required.\n");
+ return AVERROR(EINVAL);
+ }
+ par = s->streams[i]->codecpar;
+ c->audio_stream_idx = i;
+ } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
+ av_log(s, AV_LOG_WARNING, "Video stream #%d is not an attached picture. Ignoring\n", i);
+ continue;
+ } else if (st->codecpar->codec_id == AV_CODEC_ID_GIF) {
+ av_log(s, AV_LOG_ERROR, "GIF image support is not implemented.\n");
+ return AVERROR_PATCHWELCOME;
+ } else if (!c->write_header) {
+ av_log(s, AV_LOG_ERROR, "Can't write attached pictures without a header.\n");
+ return AVERROR(EINVAL);
+ }
+ c->waiting_pics++;
+ } else {
+ av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in FLAC.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+ if (c->audio_stream_idx < 0) {
+ av_log(s, AV_LOG_ERROR, "No audio stream present.\n");
+ return AVERROR(EINVAL);
+ }
+
/* add the channel layout tag */
if (par->channel_layout &&
!(par->channel_layout & ~0x3ffffULL) &&
@@ -121,18 +255,68 @@ static int flac_write_header(struct AVFormatContext *s)
}
}
- ret = flac_write_block_comment(s->pb, &s->metadata, !padding,
- s->flags & AVFMT_FLAG_BITEXACT);
- if (ret)
+ return 0;
+}
+
+static int flac_write_header(struct AVFormatContext *s)
+{
+ FlacMuxerContext *c = s->priv_data;
+ AVCodecParameters *par = s->streams[c->audio_stream_idx]->codecpar;
+ int ret;
+
+ if (!c->write_header)
+ return 0;
+
+ ret = ff_flac_write_header(s->pb, par->extradata,
+ par->extradata_size, 0);
+ if (ret < 0)
return ret;
- /* The command line flac encoder defaults to placing a seekpoint
- * every 10s. So one might add padding to allow that later
- * but there seems to be no simple way to get the duration here.
- * So just add the amount requested by the user. */
- if (padding)
- flac_write_block_padding(s->pb, padding, 1);
+ if (!c->waiting_pics)
+ ret = flac_finish_header(s);
+
+ return ret;
+}
+
+static int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt)
+{
+ FlacMuxerContext *c = s->priv_data;
+ uint8_t *streaminfo;
+ int streaminfo_size;
+
+ /* check for updated streaminfo */
+ streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
+ &streaminfo_size);
+ if (streaminfo && streaminfo_size == FLAC_STREAMINFO_SIZE) {
+ av_freep(&c->streaminfo);
+
+ c->streaminfo = av_malloc(FLAC_STREAMINFO_SIZE);
+ if (!c->streaminfo)
+ return AVERROR(ENOMEM);
+ memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE);
+ }
+
+ if (pkt->size)
+ avio_write(s->pb, pkt->data, pkt->size);
+ return 0;
+}
+static int flac_queue_flush(AVFormatContext *s)
+{
+ FlacMuxerContext *c = s->priv_data;
+ AVPacket pkt;
+ int ret, write = 1;
+
+ ret = flac_finish_header(s);
+ if (ret < 0)
+ write = 0;
+
+ while (c->queue) {
+ ff_packet_list_get(&c->queue, &c->queue_end, &pkt);
+ if (write && (ret = flac_write_audio_packet(s, &pkt)) < 0)
+ write = 0;
+ av_packet_unref(&pkt);
+ }
return ret;
}
@@ -142,7 +326,13 @@ static int flac_write_trailer(struct AVFormatContext *s)
int64_t file_size;
FlacMuxerContext *c = s->priv_data;
uint8_t *streaminfo = c->streaminfo ? c->streaminfo :
- s->streams[0]->codecpar->extradata;
+ s->streams[c->audio_stream_idx]->codecpar->extradata;
+
+ if (c->waiting_pics) {
+ av_log(s, AV_LOG_WARNING, "No packets were sent for some of the "
+ "attached pictures.\n");
+ flac_queue_flush(s);
+ }
if (!c->write_header || !streaminfo)
return 0;
@@ -166,23 +356,48 @@ static int flac_write_trailer(struct AVFormatContext *s)
static int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt)
{
FlacMuxerContext *c = s->priv_data;
- uint8_t *streaminfo;
- int streaminfo_size;
+ int ret;
- /* check for updated streaminfo */
- streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
- &streaminfo_size);
- if (streaminfo && streaminfo_size == FLAC_STREAMINFO_SIZE) {
- av_freep(&c->streaminfo);
+ if (pkt->stream_index == c->audio_stream_idx) {
+ if (c->waiting_pics) {
+ /* buffer audio packets until we get all the pictures */
+ ret = ff_packet_list_put(&c->queue, &c->queue_end, pkt, FF_PACKETLIST_FLAG_REF_PACKET);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Out of memory in packet queue; skipping attached pictures\n");
+ c->waiting_pics = 0;
+ ret = flac_queue_flush(s);
+ if (ret < 0)
+ return ret;
+ return flac_write_audio_packet(s, pkt);
+ }
+ } else
+ return flac_write_audio_packet(s, pkt);
+ } else {
+ AVStream *st = s->streams[pkt->stream_index];
- c->streaminfo = av_malloc(FLAC_STREAMINFO_SIZE);
- if (!c->streaminfo)
- return AVERROR(ENOMEM);
- memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE);
+ if (!c->waiting_pics ||
+ !(st->disposition & AV_DISPOSITION_ATTACHED_PIC))
+ return 0;
+
+ /* warn only once for each stream */
+ if (st->nb_frames == 1) {
+ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
+ " ignoring.\n", pkt->stream_index);
+ }
+ if (st->nb_frames >= 1)
+ return 0;
+
+ st->priv_data = av_packet_clone(pkt);
+ if (!st->priv_data)
+ av_log(s, AV_LOG_ERROR, "Out of memory queueing an attached picture; skipping\n");
+ c->waiting_pics--;
+
+ /* flush the buffered audio packets */
+ if (!c->waiting_pics &&
+ (ret = flac_queue_flush(s)) < 0)
+ return ret;
}
- if (pkt->size)
- avio_write(s->pb, pkt->data, pkt->size);
return 0;
}
@@ -205,7 +420,8 @@ AVOutputFormat ff_flac_muxer = {
.mime_type = "audio/x-flac",
.extensions = "flac",
.audio_codec = AV_CODEC_ID_FLAC,
- .video_codec = AV_CODEC_ID_NONE,
+ .video_codec = AV_CODEC_ID_PNG,
+ .init = flac_init,
.write_header = flac_write_header,
.write_packet = flac_write_packet,
.write_trailer = flac_write_trailer,
diff --git a/chromium/third_party/ffmpeg/libavformat/format.c b/chromium/third_party/ffmpeg/libavformat/format.c
index 75951938cf0..1c66afb7e6d 100644
--- a/chromium/third_party/ffmpeg/libavformat/format.c
+++ b/chromium/third_party/ffmpeg/libavformat/format.c
@@ -51,10 +51,9 @@ int av_match_ext(const char *filename, const char *extensions)
AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
const char *mime_type)
{
- AVOutputFormat *fmt = NULL, *fmt_found;
-#if !FF_API_NEXT
+ const AVOutputFormat *fmt = NULL;
+ AVOutputFormat *fmt_found = NULL;
void *i = 0;
-#endif
int score_max, score;
/* specific test for image sequences */
@@ -66,15 +65,8 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename,
}
#endif
/* Find the proper file type. */
- fmt_found = NULL;
score_max = 0;
-#if FF_API_NEXT
-FF_DISABLE_DEPRECATION_WARNINGS
- while ((fmt = av_oformat_next(fmt)))
-#else
- while ((fmt = av_muxer_iterate(&i)))
-#endif
- {
+ while ((fmt = av_muxer_iterate(&i))) {
score = 0;
if (fmt->name && short_name && av_match_name(short_name, fmt->name))
score += 100;
@@ -86,12 +78,9 @@ FF_DISABLE_DEPRECATION_WARNINGS
}
if (score > score_max) {
score_max = score;
- fmt_found = fmt;
+ fmt_found = (AVOutputFormat*)fmt;
}
}
-#if FF_API_NEXT
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
return fmt_found;
}
@@ -128,19 +117,11 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name,
AVInputFormat *av_find_input_format(const char *short_name)
{
- AVInputFormat *fmt = NULL;
-#if FF_API_NEXT
-FF_DISABLE_DEPRECATION_WARNINGS
- while ((fmt = av_iformat_next(fmt)))
- if (av_match_name(short_name, fmt->name))
- return fmt;
-FF_ENABLE_DEPRECATION_WARNINGS
-#else
+ const AVInputFormat *fmt = NULL;
void *i = 0;
while ((fmt = av_demuxer_iterate(&i)))
if (av_match_name(short_name, fmt->name))
- return fmt;
-#endif
+ return (AVInputFormat*)fmt;
return NULL;
}
@@ -148,7 +129,8 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened,
int *score_ret)
{
AVProbeData lpd = *pd;
- AVInputFormat *fmt1 = NULL, *fmt;
+ const AVInputFormat *fmt1 = NULL;
+ AVInputFormat *fmt = NULL;
int score, score_max = 0;
void *i = 0;
const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE];
@@ -175,7 +157,6 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened,
nodat = ID3_GREATER_PROBE;
}
- fmt = NULL;
while ((fmt1 = av_demuxer_iterate(&i))) {
if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2"))
continue;
@@ -210,7 +191,7 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened,
}
if (score > score_max) {
score_max = score;
- fmt = fmt1;
+ fmt = (AVInputFormat*)fmt1;
} else if (score == score_max)
fmt = NULL;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/hls.c b/chromium/third_party/ffmpeg/libavformat/hls.c
index c578bf86e3b..ffec1248189 100644
--- a/chromium/third_party/ffmpeg/libavformat/hls.c
+++ b/chromium/third_party/ffmpeg/libavformat/hls.c
@@ -202,11 +202,6 @@ typedef struct HLSContext {
int64_t first_timestamp;
int64_t cur_timestamp;
AVIOInterruptCB *interrupt_callback;
- char *referer; ///< holds HTTP referer set as an AVOption to the HTTP protocol context
- char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context
- char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context
- char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context
- char *http_proxy; ///< holds the address of the HTTP proxy server
AVDictionary *avio_opts;
int strict_std_compliance;
char *allowed_extensions;
@@ -216,14 +211,6 @@ typedef struct HLSContext {
AVIOContext *playlist_pb;
} HLSContext;
-static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
-{
- int len = ff_get_line(s, buf, maxlen);
- while (len > 0 && av_isspace(buf[len - 1]))
- buf[--len] = '\0';
- return len;
-}
-
static void free_segment_list(struct playlist *pls)
{
int i;
@@ -275,10 +262,6 @@ static void free_playlist_list(HLSContext *c)
av_free(pls);
}
av_freep(&c->playlists);
- av_freep(&c->cookies);
- av_freep(&c->user_agent);
- av_freep(&c->headers);
- av_freep(&c->http_proxy);
c->n_playlists = 0;
}
@@ -601,14 +584,6 @@ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url
return 0;
}
-static void update_options(char **dest, const char *name, void *src)
-{
- av_freep(dest);
- av_opt_get(src, name, AV_OPT_SEARCH_CHILDREN, (uint8_t**)dest);
- if (*dest && !strlen(*dest))
- av_freep(dest);
-}
-
static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb,
const char *url)
{
@@ -692,12 +667,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
if (!(s->flags & AVFMT_FLAG_CUSTOM_IO))
av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies);
- if (new_cookies) {
- av_free(c->cookies);
- c->cookies = new_cookies;
- }
-
- av_dict_set(&opts, "cookies", c->cookies, 0);
+ if (new_cookies)
+ av_dict_set(&opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL);
}
av_dict_free(&tmp);
@@ -743,16 +714,8 @@ static int parse_playlist(HLSContext *c, const char *url,
}
if (!in) {
-#if 1
AVDictionary *opts = NULL;
- /* Some HLS servers don't like being sent the range header */
- av_dict_set(&opts, "seekable", "0", 0);
-
- // broker prior HTTP options that should be consistent across requests
- av_dict_set(&opts, "user_agent", c->user_agent, 0);
- av_dict_set(&opts, "cookies", c->cookies, 0);
- av_dict_set(&opts, "headers", c->headers, 0);
- av_dict_set(&opts, "http_proxy", c->http_proxy, 0);
+ av_dict_copy(&opts, c->avio_opts, 0);
if (c->http_persistent)
av_dict_set(&opts, "multiple_requests", "1", 0);
@@ -766,18 +729,12 @@ static int parse_playlist(HLSContext *c, const char *url,
c->playlist_pb = in;
else
close_in = 1;
-#else
- ret = open_in(c, &in, url);
- if (ret < 0)
- return ret;
- close_in = 1;
-#endif
}
if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0)
url = new_url;
- read_chomp_line(in, line, sizeof(line));
+ ff_get_chomp_line(in, line, sizeof(line));
if (strcmp(line, "#EXTM3U")) {
ret = AVERROR_INVALIDDATA;
goto fail;
@@ -789,7 +746,7 @@ static int parse_playlist(HLSContext *c, const char *url,
pls->type = PLS_TYPE_UNSPECIFIED;
}
while (!avio_feof(in)) {
- read_chomp_line(in, line, sizeof(line));
+ ff_get_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
is_variant = 1;
memset(&variant_info, 0, sizeof(variant_info));
@@ -952,14 +909,8 @@ static struct segment *next_segment(struct playlist *pls)
return pls->segments[n];
}
-enum ReadFromURLMode {
- READ_NORMAL,
- READ_COMPLETE,
-};
-
static int read_from_url(struct playlist *pls, struct segment *seg,
- uint8_t *buf, int buf_size,
- enum ReadFromURLMode mode)
+ uint8_t *buf, int buf_size)
{
int ret;
@@ -967,13 +918,7 @@ static int read_from_url(struct playlist *pls, struct segment *seg,
if (seg->size >= 0)
buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset);
- if (mode == READ_COMPLETE) {
- ret = avio_read(pls->input, buf, buf_size);
- if (ret != buf_size)
- av_log(NULL, AV_LOG_ERROR, "Could not read complete segment.\n");
- } else
- ret = avio_read(pls->input, buf, buf_size);
-
+ ret = avio_read(pls->input, buf, buf_size);
if (ret > 0)
pls->cur_seg_offset += ret;
@@ -1092,7 +1037,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf,
while (1) {
/* see if we can retrieve enough data for ID3 header */
if (*len < ID3v2_HEADER_SIZE && buf_size >= ID3v2_HEADER_SIZE) {
- bytes = read_from_url(pls, seg, buf + *len, ID3v2_HEADER_SIZE - *len, READ_COMPLETE);
+ bytes = read_from_url(pls, seg, buf + *len, ID3v2_HEADER_SIZE - *len);
if (bytes > 0) {
if (bytes == ID3v2_HEADER_SIZE - *len)
@@ -1144,7 +1089,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf,
if (remaining > 0) {
/* read the rest of the tag in */
- if (read_from_url(pls, seg, pls->id3_buf + id3_buf_pos, remaining, READ_COMPLETE) != remaining)
+ if (read_from_url(pls, seg, pls->id3_buf + id3_buf_pos, remaining) != remaining)
break;
id3_buf_pos += remaining;
av_log(pls->ctx, AV_LOG_DEBUG, "Stripped additional %d HLS ID3 bytes\n", remaining);
@@ -1158,7 +1103,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf,
/* re-fill buffer for the caller unless EOF */
if (*len >= 0 && (fill_buf || *len == 0)) {
- bytes = read_from_url(pls, seg, buf + *len, buf_size - *len, READ_NORMAL);
+ bytes = read_from_url(pls, seg, buf + *len, buf_size - *len);
/* ignore error if we already had some data */
if (bytes >= 0)
@@ -1184,14 +1129,6 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
int ret;
int is_http = 0;
- // broker prior HTTP options that should be consistent across requests
- av_dict_set(&opts, "user_agent", c->user_agent, 0);
- av_dict_set(&opts, "referer", c->referer, 0);
- av_dict_set(&opts, "cookies", c->cookies, 0);
- av_dict_set(&opts, "headers", c->headers, 0);
- av_dict_set(&opts, "http_proxy", c->http_proxy, 0);
- av_dict_set(&opts, "seekable", "0", 0);
-
if (c->http_persistent)
av_dict_set(&opts, "multiple_requests", "1", 0);
@@ -1208,7 +1145,6 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
if (seg->key_type == KEY_NONE) {
ret = open_url(pls->parent, in, seg->url, c->avio_opts, opts, &is_http);
} else if (seg->key_type == KEY_AES_128) {
- AVDictionary *opts2 = NULL;
char iv[33], key[33], url[MAX_URL_SIZE];
if (strcmp(seg->key, pls->key_url)) {
AVIOContext *pb = NULL;
@@ -1233,14 +1169,10 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg,
else
snprintf(url, sizeof(url), "crypto:%s", seg->url);
- av_dict_copy(&opts2, c->avio_opts, 0);
- av_dict_set(&opts2, "key", key, 0);
- av_dict_set(&opts2, "iv", iv, 0);
-
- ret = open_url(pls->parent, in, url, opts2, opts, &is_http);
-
- av_dict_free(&opts2);
+ av_dict_set(&opts, "key", key, 0);
+ av_dict_set(&opts, "iv", iv, 0);
+ ret = open_url(pls->parent, in, url, c->avio_opts, opts, &is_http);
if (ret < 0) {
goto cleanup;
}
@@ -1318,7 +1250,7 @@ static int update_init_section(struct playlist *pls, struct segment *seg)
av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size);
ret = read_from_url(pls, seg->init_section, pls->init_sec_buf,
- pls->init_sec_buf_size, READ_COMPLETE);
+ pls->init_sec_buf_size);
ff_format_io_close(pls->parent, &pls->input);
if (ret < 0)
@@ -1513,7 +1445,7 @@ reload:
}
seg = current_segment(v);
- ret = read_from_url(v, seg, buf, buf_size, READ_NORMAL);
+ ret = read_from_url(v, seg, buf, buf_size);
if (ret > 0) {
if (just_opened && v->is_id3_timestamped != 0) {
/* Intercept ID3 tags here, elementary audio streams are required
@@ -1661,7 +1593,7 @@ static int save_avio_options(AVFormatContext *s)
{
HLSContext *c = s->priv_data;
static const char * const opts[] = {
- "headers", "http_proxy", "user_agent", "user-agent", "cookies", "referer", NULL };
+ "headers", "http_proxy", "user_agent", "user-agent", "cookies", "referer", "rw_timeout", NULL };
const char * const * opt = opts;
uint8_t *buf;
int ret = 0;
@@ -1796,7 +1728,6 @@ static int hls_close(AVFormatContext *s)
static int hls_read_header(AVFormatContext *s)
{
- void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb;
HLSContext *c = s->priv_data;
int ret = 0, i;
int highest_cur_seq_no = 0;
@@ -1809,29 +1740,15 @@ static int hls_read_header(AVFormatContext *s)
c->first_timestamp = AV_NOPTS_VALUE;
c->cur_timestamp = AV_NOPTS_VALUE;
- if (u) {
- // get the previous user agent & set back to null if string size is zero
- update_options(&c->user_agent, "user_agent", u);
-
- // get the previous cookies & set back to null if string size is zero
- update_options(&c->cookies, "cookies", u);
-
- // get the previous headers & set back to null if string size is zero
- update_options(&c->headers, "headers", u);
-
- // get the previous http proxt & set back to null if string size is zero
- update_options(&c->http_proxy, "http_proxy", u);
- }
-
- if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0)
- goto fail;
-
if ((ret = save_avio_options(s)) < 0)
goto fail;
/* Some HLS servers don't like being sent the range header */
av_dict_set(&c->avio_opts, "seekable", "0", 0);
+ if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0)
+ goto fail;
+
if (c->n_variants == 0) {
av_log(NULL, AV_LOG_WARNING, "Empty playlist\n");
ret = AVERROR_EOF;
diff --git a/chromium/third_party/ffmpeg/libavformat/hlsenc.c b/chromium/third_party/ffmpeg/libavformat/hlsenc.c
index 7d9512b6648..c27a66ea795 100644
--- a/chromium/third_party/ffmpeg/libavformat/hlsenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/hlsenc.c
@@ -75,6 +75,7 @@ typedef struct HLSSegment {
int discont;
int64_t pos;
int64_t size;
+ unsigned var_stream_idx;
char key_uri[LINE_BUFFER_SIZE + 1];
char iv_string[KEYSIZE*2 + 1];
@@ -106,6 +107,7 @@ typedef enum {
} SegmentType;
typedef struct VariantStream {
+ unsigned var_stream_idx;
unsigned number;
int64_t sequence;
AVOutputFormat *oformat;
@@ -171,6 +173,7 @@ typedef struct HLSContext {
float time; // Set by a private option.
float init_time; // Set by a private option.
int max_nb_segments; // Set by a private option.
+ int hls_delete_threshold; // Set by a private option.
#if FF_API_HLS_WRAP
int wrap; // Set by a private option.
#endif
@@ -224,6 +227,7 @@ typedef struct HLSContext {
int http_persistent;
AVIOContext *m3u8_out;
AVIOContext *sub_m3u8_out;
+ int64_t timeout;
} HLSContext;
static int mkdir_p(const char *path) {
@@ -305,7 +309,8 @@ static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSCont
av_dict_set(options, "user_agent", c->user_agent, 0);
if (c->http_persistent)
av_dict_set_int(options, "multiple_requests", 1, 0);
-
+ if (c->timeout >= 0)
+ av_dict_set_int(options, "timeout", c->timeout, 0);
}
static void write_codec_attr(AVStream *st, VariantStream *vs) {
@@ -441,6 +446,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
HLSSegment *segment, *previous_segment = NULL;
float playlist_duration = 0.0f;
int ret = 0, path_size, sub_path_size;
+ int segment_cnt = 0;
char *dirname = NULL, *p, *sub_path;
char *path = NULL;
AVDictionary *options = NULL;
@@ -454,14 +460,20 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
}
segment = vs->old_segments;
+ segment_cnt = 0;
while (segment) {
playlist_duration -= segment->duration;
previous_segment = segment;
segment = previous_segment->next;
+ segment_cnt++;
if (playlist_duration <= -previous_segment->duration) {
previous_segment->next = NULL;
break;
}
+ if (segment_cnt >= hls->hls_delete_threshold) {
+ previous_segment->next = NULL;
+ break;
+ }
}
if (segment && !hls->use_localtime_mkdir) {
@@ -476,9 +488,23 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls,
}
p = (char *)av_basename(dirname);
*p = '\0';
+
}
while (segment) {
+ char * r_dirname = dirname;
+
+ /* if %v is present in the file's directory */
+ if (av_stristr(dirname, "%v")) {
+
+ if (replace_int_data_in_filename(&r_dirname, dirname, 'v', segment->var_stream_idx) < 1) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ av_free(dirname);
+ dirname = r_dirname;
+ }
+
av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n",
segment->filename);
path_size = (hls->use_localtime_mkdir ? 0 : strlen(dirname)) + strlen(segment->filename) + 1;
@@ -678,14 +704,6 @@ static int hls_encryption_start(AVFormatContext *s)
return 0;
}
-static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
-{
- int len = ff_get_line(s, buf, maxlen);
- while (len > 0 && av_isspace(buf[len - 1]))
- buf[--len] = '\0';
- return len;
-}
-
static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
{
AVDictionary *options = NULL;
@@ -763,7 +781,11 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs)
if ((ret = avio_open_dyn_buf(&oc->pb)) < 0)
return ret;
- ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
+ if (byterange_mode) {
+ ret = hlsenc_io_open(s, &vs->out, vs->basename, &options);
+ } else {
+ ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options);
+ }
av_dict_free(&options);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename);
@@ -959,6 +981,7 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls,
if (!en)
return AVERROR(ENOMEM);
+ en->var_stream_idx = vs->var_stream_idx;
ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size);
if (ret < 0) {
return ret;
@@ -1049,7 +1072,7 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
s->protocol_whitelist, s->protocol_blacklist)) < 0)
return ret;
- read_chomp_line(in, line, sizeof(line));
+ ff_get_chomp_line(in, line, sizeof(line));
if (strcmp(line, "#EXTM3U")) {
ret = AVERROR_INVALIDDATA;
goto fail;
@@ -1057,7 +1080,7 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs
vs->discontinuity = 0;
while (!avio_feof(in)) {
- read_chomp_line(in, line, sizeof(line));
+ ff_get_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) {
int64_t tmp_sequence = strtoll(ptr, NULL, 10);
if (tmp_sequence < vs->sequence)
@@ -1168,6 +1191,21 @@ static int get_relative_url(const char *master_url, const char *media_url,
return 0;
}
+static int64_t get_stream_bit_rate(AVStream *stream) {
+ AVCPBProperties *props = (AVCPBProperties*)av_stream_get_side_data(
+ stream,
+ AV_PKT_DATA_CPB_PROPERTIES,
+ NULL
+ );
+
+ if (stream->codecpar->bit_rate)
+ return stream->codecpar->bit_rate;
+ else if (props)
+ return props->max_bitrate;
+
+ return 0;
+}
+
static int create_master_playlist(AVFormatContext *s,
VariantStream * const input_vs)
{
@@ -1294,9 +1332,9 @@ static int create_master_playlist(AVFormatContext *s,
bandwidth = 0;
if (vid_st)
- bandwidth += vid_st->codecpar->bit_rate;
+ bandwidth += get_stream_bit_rate(vid_st);
if (aud_st)
- bandwidth += aud_st->codecpar->bit_rate;
+ bandwidth += get_stream_bit_rate(aud_st);
bandwidth += bandwidth / 10;
ccgroup = NULL;
@@ -1395,8 +1433,8 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs)
}
if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) {
- ff_hls_write_init_file(hls->m3u8_out, vs->fmp4_init_filename,
- hls->flags & HLS_SINGLE_FILE, en->size, en->pos);
+ ff_hls_write_init_file(hls->m3u8_out, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename,
+ hls->flags & HLS_SINGLE_FILE, vs->init_range_length, 0);
}
ret = ff_hls_write_file_entry(hls->m3u8_out, en->discont, byterange_mode,
@@ -1553,9 +1591,14 @@ static int hls_start(AVFormatContext *s, VariantStream *vs)
}
if (c->key_info_file || c->encrypt) {
+ if (c->segment_type == SEGMENT_TYPE_FMP4) {
+ av_log(s, AV_LOG_ERROR, "Encrypted fmp4 not yet supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
if (c->key_info_file && c->encrypt) {
av_log(s, AV_LOG_WARNING, "Cannot use both -hls_key_info_file and -hls_enc,"
- " will use -hls_key_info_file priority\n");
+ " ignoring -hls_enc\n");
}
if (!c->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) {
@@ -1803,9 +1846,11 @@ static int parse_variant_stream_mapstring(AVFormatContext *s)
while (varstr = av_strtok(p, " \t", &saveptr1)) {
p = NULL;
- if (nb_varstreams < hls->nb_varstreams)
- vs = &(hls->var_streams[nb_varstreams++]);
- else
+ if (nb_varstreams < hls->nb_varstreams) {
+ vs = &(hls->var_streams[nb_varstreams]);
+ vs->var_stream_idx = nb_varstreams;
+ nb_varstreams++;
+ } else
return AVERROR(EINVAL);
q = varstr;
@@ -1867,7 +1912,8 @@ static int parse_cc_stream_mapstring(AVFormatContext *s)
{
HLSContext *hls = s->priv_data;
int nb_ccstreams;
- char *p, *q, *saveptr1, *saveptr2, *ccstr, *keyval;
+ char *p, *q, *ccstr, *keyval;
+ char *saveptr1 = NULL, *saveptr2 = NULL;
const char *val;
ClosedCaptionsStream *ccs;
@@ -1962,6 +2008,7 @@ static int update_variant_stream_info(AVFormatContext *s) {
if (!hls->var_streams)
return AVERROR(ENOMEM);
+ hls->var_streams[0].var_stream_idx = 0;
hls->var_streams[0].nb_streams = s->nb_streams;
hls->var_streams[0].streams = av_mallocz(sizeof(AVStream *) *
hls->var_streams[0].nb_streams);
@@ -2167,7 +2214,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
}
if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base,
- end_pts, AV_TIME_BASE_Q) >= 0) {
+ end_pts, AV_TIME_BASE_Q) >= 0) {
int64_t new_start_pos;
char *old_filename = NULL;
int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0);
@@ -2175,23 +2222,32 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
av_write_frame(vs->avf, NULL); /* Flush any buffered data */
new_start_pos = avio_tell(vs->avf->pb);
- vs->size = new_start_pos - vs->start_pos;
+ if (hls->segment_type != SEGMENT_TYPE_FMP4) {
+ vs->size = new_start_pos - vs->start_pos;
+ } else {
+ vs->size = new_start_pos;
+ }
- if (!byterange_mode) {
- if (hls->segment_type == SEGMENT_TYPE_FMP4) {
- if (!vs->init_range_length) {
- avio_flush(oc->pb);
- range_length = avio_close_dyn_buf(oc->pb, &buffer);
- avio_write(vs->out, buffer, range_length);
- vs->init_range_length = range_length;
- avio_open_dyn_buf(&oc->pb);
- vs->packets_written = 0;
+ if (hls->segment_type == SEGMENT_TYPE_FMP4) {
+ if (!vs->init_range_length) {
+ avio_flush(oc->pb);
+ range_length = avio_close_dyn_buf(oc->pb, &buffer);
+ avio_write(vs->out, buffer, range_length);
+ vs->init_range_length = range_length;
+ avio_open_dyn_buf(&oc->pb);
+ vs->packets_written = 0;
+ vs->start_pos = range_length;
+ if (!byterange_mode) {
ff_format_io_close(s, &vs->out);
hlsenc_io_close(s, &vs->out, vs->base_output_dirname);
}
- } else {
+ }
+ } else {
+ if (!byterange_mode) {
hlsenc_io_close(s, &oc->pb, oc->url);
}
+ }
+ if (!byterange_mode) {
if (vs->vtt_avf) {
hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url);
}
@@ -2208,18 +2264,27 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
}
if (hls->segment_type == SEGMENT_TYPE_FMP4) {
- ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Failed to open file '%s'\n",
- vs->avf->url);
- return ret;
- }
- write_styp(vs->out);
- ret = flush_dynbuf(vs, &range_length);
- if (ret < 0) {
- return ret;
+ if (hls->flags & HLS_SINGLE_FILE) {
+ ret = flush_dynbuf(vs, &range_length);
+ if (ret < 0) {
+ av_free(old_filename);
+ return ret;
+ }
+ vs->size = range_length;
+ } else {
+ ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n",
+ vs->avf->url);
+ return ret;
+ }
+ write_styp(vs->out);
+ ret = flush_dynbuf(vs, &range_length);
+ if (ret < 0) {
+ return ret;
+ }
+ ff_format_io_close(s, &vs->out);
}
- ff_format_io_close(s, &vs->out);
}
old_filename = av_strdup(vs->avf->url);
@@ -2227,15 +2292,21 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt)
return AVERROR(ENOMEM);
}
- ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
- vs->start_pos = new_start_pos;
- if (ret < 0) {
- av_free(old_filename);
- return ret;
+ if (vs->start_pos || hls->segment_type != SEGMENT_TYPE_FMP4) {
+ ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size);
+ vs->end_pts = pkt->pts;
+ vs->duration = 0;
+ if (ret < 0) {
+ av_free(old_filename);
+ return ret;
+ }
}
- vs->end_pts = pkt->pts;
- vs->duration = 0;
+ if (hls->segment_type != SEGMENT_TYPE_FMP4) {
+ vs->start_pos = new_start_pos;
+ } else {
+ vs->start_pos += vs->size;
+ }
vs->fmp4_init_mode = 0;
if (hls->flags & HLS_SINGLE_FILE) {
@@ -2286,79 +2357,85 @@ static int hls_write_trailer(struct AVFormatContext *s)
for (i = 0; i < hls->nb_varstreams; i++) {
vs = &hls->var_streams[i];
- oc = vs->avf;
- vtt_oc = vs->vtt_avf;
- old_filename = av_strdup(vs->avf->url);
+ oc = vs->avf;
+ vtt_oc = vs->vtt_avf;
+ old_filename = av_strdup(vs->avf->url);
- if (!old_filename) {
- return AVERROR(ENOMEM);
- }
- if ( hls->segment_type == SEGMENT_TYPE_FMP4) {
- int range_length = 0;
- ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL);
- if (ret < 0) {
- av_log(NULL, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url);
- goto failed;
+ if (!old_filename) {
+ return AVERROR(ENOMEM);
}
- write_styp(vs->out);
- ret = flush_dynbuf(vs, &range_length);
- if (ret < 0) {
- goto failed;
+ if ( hls->segment_type == SEGMENT_TYPE_FMP4) {
+ int range_length = 0;
+ if (!(hls->flags & HLS_SINGLE_FILE)) {
+ ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL);
+ if (ret < 0) {
+ av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url);
+ goto failed;
+ }
+ write_styp(vs->out);
+ }
+ ret = flush_dynbuf(vs, &range_length);
+ if (ret < 0) {
+ goto failed;
+ }
+ ff_format_io_close(s, &vs->out);
}
- ff_format_io_close(s, &vs->out);
- }
failed:
- av_write_trailer(oc);
- if (oc->pb) {
- vs->size = avio_tell(vs->avf->pb) - vs->start_pos;
- if (hls->segment_type != SEGMENT_TYPE_FMP4)
- ff_format_io_close(s, &oc->pb);
+ av_write_trailer(oc);
+ if (oc->pb) {
+ if (hls->segment_type != SEGMENT_TYPE_FMP4) {
+ vs->size = avio_tell(vs->avf->pb) - vs->start_pos;
+ } else {
+ vs->size = avio_tell(vs->avf->pb);
+ }
+ if (hls->segment_type != SEGMENT_TYPE_FMP4)
+ ff_format_io_close(s, &oc->pb);
- if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) {
- hls_rename_temp_file(s, oc);
- av_free(old_filename);
- old_filename = av_strdup(vs->avf->url);
+ if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) {
+ hls_rename_temp_file(s, oc);
+ av_free(old_filename);
+ old_filename = av_strdup(vs->avf->url);
- if (!old_filename) {
- return AVERROR(ENOMEM);
+ if (!old_filename) {
+ return AVERROR(ENOMEM);
+ }
}
- }
- /* after av_write_trailer, then duration + 1 duration per packet */
- hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size);
- }
+ /* after av_write_trailer, then duration + 1 duration per packet */
+ hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size);
+ }
- sls_flag_file_rename(hls, vs, old_filename);
+ sls_flag_file_rename(hls, vs, old_filename);
- if (vtt_oc) {
- if (vtt_oc->pb)
- av_write_trailer(vtt_oc);
- vs->size = avio_tell(vs->vtt_avf->pb) - vs->start_pos;
- ff_format_io_close(s, &vtt_oc->pb);
- }
- av_freep(&vs->basename);
- av_freep(&vs->base_output_dirname);
- avformat_free_context(oc);
+ if (vtt_oc) {
+ if (vtt_oc->pb)
+ av_write_trailer(vtt_oc);
+ vs->size = avio_tell(vs->vtt_avf->pb) - vs->start_pos;
+ ff_format_io_close(s, &vtt_oc->pb);
+ }
+ av_freep(&vs->basename);
+ av_freep(&vs->base_output_dirname);
+ avformat_free_context(oc);
- vs->avf = NULL;
- hls_window(s, 1, vs);
+ vs->avf = NULL;
+ hls_window(s, 1, vs);
- av_freep(&vs->fmp4_init_filename);
- if (vtt_oc) {
- av_freep(&vs->vtt_basename);
- av_freep(&vs->vtt_m3u8_name);
- avformat_free_context(vtt_oc);
- }
+ av_freep(&vs->fmp4_init_filename);
+ if (vtt_oc) {
+ av_freep(&vs->vtt_basename);
+ av_freep(&vs->vtt_m3u8_name);
+ avformat_free_context(vtt_oc);
+ }
- hls_free_segments(vs->segments);
- hls_free_segments(vs->old_segments);
- av_free(old_filename);
- av_freep(&vs->m3u8_name);
- av_freep(&vs->streams);
- av_freep(&vs->agroup);
- av_freep(&vs->ccgroup);
- av_freep(&vs->baseurl);
+ hls_free_segments(vs->segments);
+ hls_free_segments(vs->old_segments);
+ av_free(old_filename);
+ av_freep(&vs->m3u8_name);
+ av_freep(&vs->streams);
+ av_freep(&vs->agroup);
+ av_freep(&vs->ccgroup);
+ av_freep(&vs->baseurl);
}
for (i = 0; i < hls->nb_ccstreams; i++) {
@@ -2396,7 +2473,7 @@ static int hls_init(AVFormatContext *s)
ret = update_variant_stream_info(s);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n",
- ret);
+ ret);
goto fail;
}
//TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present
@@ -2432,7 +2509,7 @@ static int hls_init(AVFormatContext *s)
ret = update_master_pl_info(s);
if (ret < 0) {
av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n",
- ret);
+ ret);
goto fail;
}
}
@@ -2574,32 +2651,24 @@ static int hls_init(AVFormatContext *s)
if (hls->segment_type == SEGMENT_TYPE_FMP4) {
if (hls->nb_varstreams > 1)
fmp4_init_filename_len += strlen(POSTFIX_PATTERN);
- vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len);
- if (!vs->fmp4_init_filename ) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename,
- fmp4_init_filename_len);
-
- if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) {
- ret = format_name(vs->fmp4_init_filename, fmp4_init_filename_len, i);
- if (ret < 0)
+ if (hls->flags & HLS_SINGLE_FILE) {
+ vs->fmp4_init_filename = av_strdup(vs->basename);
+ if (!vs->fmp4_init_filename) {
+ ret = AVERROR(ENOMEM);
goto fail;
-
- fmp4_init_filename_len = strlen(vs->fmp4_init_filename) + 1;
- vs->base_output_dirname = av_malloc(fmp4_init_filename_len);
- if (!vs->base_output_dirname) {
+ }
+ } else {
+ vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len);
+ if (!vs->fmp4_init_filename ) {
ret = AVERROR(ENOMEM);
goto fail;
}
- av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename,
+ av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename,
fmp4_init_filename_len);
- } else {
if (hls->nb_varstreams > 1) {
ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i);
if (ret < 0)
- goto fail;
+ goto fail;
}
fmp4_init_filename_len = strlen(vs->m3u8_name) +
@@ -2677,13 +2746,6 @@ static int hls_init(AVFormatContext *s)
}
}
- if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) {
- vs->fmp4_init_filename = av_strdup(vs->basename);
- if (!vs->fmp4_init_filename) {
- ret = AVERROR(ENOMEM);
- goto fail;
- }
- }
if ((ret = hls_mux_init(s, vs)) < 0)
goto fail;
@@ -2742,6 +2804,7 @@ static const AVOption options[] = {
{"hls_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E},
{"hls_init_time", "set segment length in seconds at init list", OFFSET(init_time), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, FLT_MAX, E},
{"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E},
+ {"hls_delete_threshold", "set number of unreferenced segments to keep before deleting", OFFSET(hls_delete_threshold), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, E},
{"hls_ts_options","set hls mpegts list of options for the container format used for hls", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
{"hls_vtt_options","set hls vtt list of options for the container format used for hls", OFFSET(vtt_format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
#if FF_API_HLS_WRAP
@@ -2792,6 +2855,7 @@ static const AVOption options[] = {
{"master_pl_name", "Create HLS master playlist with this name", OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
{"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E},
{"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
+ {"timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E },
{ NULL },
};
diff --git a/chromium/third_party/ffmpeg/libavformat/hlsproto.c b/chromium/third_party/ffmpeg/libavformat/hlsproto.c
index 2b19ed0cf67..e7ef2d88ea8 100644
--- a/chromium/third_party/ffmpeg/libavformat/hlsproto.c
+++ b/chromium/third_party/ffmpeg/libavformat/hlsproto.c
@@ -69,14 +69,6 @@ typedef struct HLSContext {
int64_t last_load_time;
} HLSContext;
-static int read_chomp_line(AVIOContext *s, char *buf, int maxlen)
-{
- int len = ff_get_line(s, buf, maxlen);
- while (len > 0 && av_isspace(buf[len - 1]))
- buf[--len] = '\0';
- return len;
-}
-
static void free_segment_list(HLSContext *s)
{
int i;
@@ -122,7 +114,7 @@ static int parse_playlist(URLContext *h, const char *url)
h->protocol_whitelist, h->protocol_blacklist)) < 0)
return ret;
- read_chomp_line(in, line, sizeof(line));
+ ff_get_chomp_line(in, line, sizeof(line));
if (strcmp(line, "#EXTM3U")) {
ret = AVERROR_INVALIDDATA;
goto fail;
@@ -131,7 +123,7 @@ static int parse_playlist(URLContext *h, const char *url)
free_segment_list(s);
s->finished = 0;
while (!avio_feof(in)) {
- read_chomp_line(in, line, sizeof(line));
+ ff_get_chomp_line(in, line, sizeof(line));
if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) {
struct variant_info info = {{0}};
is_variant = 1;
diff --git a/chromium/third_party/ffmpeg/libavformat/http.c b/chromium/third_party/ffmpeg/libavformat/http.c
index 344fd603cb9..aa6348f28bf 100644
--- a/chromium/third_party/ffmpeg/libavformat/http.c
+++ b/chromium/third_party/ffmpeg/libavformat/http.c
@@ -576,7 +576,11 @@ static int http_accept(URLContext *s, URLContext **c)
goto fail;
cc->hd = cl;
cc->is_multi_client = 1;
+ return 0;
fail:
+ if (c) {
+ ffurl_closep(c);
+ }
return ret;
}
@@ -750,6 +754,9 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
{
char *param, *next_param, *cstr, *back;
+ if (!set_cookie[0])
+ return 0;
+
if (!(cstr = av_strdup(set_cookie)))
return AVERROR(EINVAL);
@@ -757,6 +764,8 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict)
back = &cstr[strlen(cstr)-1];
while (strchr(WHITESPACES, *back)) {
*back='\0';
+ if (back == cstr)
+ break;
back--;
}
@@ -802,7 +811,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies)
// if the cookie has already expired ignore it
if (av_timegm(&new_tm) < av_gettime() / 1000000) {
av_dict_free(&new_params);
- return -1;
+ return 0;
}
// only replace an older cookie with the same name
@@ -1010,7 +1019,8 @@ static int process_line(URLContext *h, char *line, int line_count,
/**
* Create a string containing cookie values for use as a HTTP cookie header
* field value for a particular path and domain from the cookie values stored in
- * the HTTP protocol context. The cookie string is stored in *cookies.
+ * the HTTP protocol context. The cookie string is stored in *cookies, and may
+ * be NULL if there are no valid cookies.
*
* @return a negative value if an error condition occurred, 0 otherwise
*/
@@ -1020,15 +1030,20 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
// cookie strings will look like Set-Cookie header field values. Multiple
// Set-Cookie fields will result in multiple values delimited by a newline
int ret = 0;
- char *cookie, *set_cookies = av_strdup(s->cookies), *next = set_cookies;
-
- if (!set_cookies) return AVERROR(EINVAL);
+ char *cookie, *set_cookies, *next;
// destroy any cookies in the dictionary.
av_dict_free(&s->cookie_dict);
+ if (!s->cookies)
+ return 0;
+
+ next = set_cookies = av_strdup(s->cookies);
+ if (!next)
+ return AVERROR(ENOMEM);
+
*cookies = NULL;
- while ((cookie = av_strtok(next, "\n", &next))) {
+ while ((cookie = av_strtok(next, "\n", &next)) && !ret) {
AVDictionary *cookie_params = NULL;
AVDictionaryEntry *cookie_entry, *e;
@@ -1038,23 +1053,19 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
// continue on to the next cookie if this one cannot be parsed
if (parse_set_cookie(cookie, &cookie_params))
- continue;
+ goto skip_cookie;
// if the cookie has no value, skip it
cookie_entry = av_dict_get(cookie_params, "", NULL, AV_DICT_IGNORE_SUFFIX);
- if (!cookie_entry || !cookie_entry->value) {
- av_dict_free(&cookie_params);
- continue;
- }
+ if (!cookie_entry || !cookie_entry->value)
+ goto skip_cookie;
// if the cookie has expired, don't add it
if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) {
struct tm tm_buf = {0};
if (!parse_set_cookie_expiry_time(e->value, &tm_buf)) {
- if (av_timegm(&tm_buf) < av_gettime() / 1000000) {
- av_dict_free(&cookie_params);
- continue;
- }
+ if (av_timegm(&tm_buf) < av_gettime() / 1000000)
+ goto skip_cookie;
}
}
@@ -1062,42 +1073,32 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path,
if ((e = av_dict_get(cookie_params, "domain", NULL, 0)) && e->value) {
// find the offset comparison is on the min domain (b.com, not a.b.com)
int domain_offset = strlen(domain) - strlen(e->value);
- if (domain_offset < 0) {
- av_dict_free(&cookie_params);
- continue;
- }
+ if (domain_offset < 0)
+ goto skip_cookie;
// match the cookie domain
- if (av_strcasecmp(&domain[domain_offset], e->value)) {
- av_dict_free(&cookie_params);
- continue;
- }
+ if (av_strcasecmp(&domain[domain_offset], e->value))
+ goto skip_cookie;
}
// ensure this cookie matches the path
e = av_dict_get(cookie_params, "path", NULL, 0);
- if (!e || av_strncasecmp(path, e->value, strlen(e->value))) {
- av_dict_free(&cookie_params);
- continue;
- }
+ if (!e || av_strncasecmp(path, e->value, strlen(e->value)))
+ goto skip_cookie;
// cookie parameters match, so copy the value
if (!*cookies) {
- if (!(*cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value))) {
- ret = AVERROR(ENOMEM);
- break;
- }
+ *cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value);
} else {
char *tmp = *cookies;
- size_t str_size = strlen(cookie_entry->key) + strlen(cookie_entry->value) + strlen(*cookies) + 4;
- if (!(*cookies = av_malloc(str_size))) {
- ret = AVERROR(ENOMEM);
- av_free(tmp);
- break;
- }
- snprintf(*cookies, str_size, "%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value);
+ *cookies = av_asprintf("%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value);
av_free(tmp);
}
+ if (!*cookies)
+ ret = AVERROR(ENOMEM);
+
+ skip_cookie:
+ av_dict_free(&cookie_params);
}
av_free(set_cookies);
@@ -1622,6 +1623,18 @@ static int http_shutdown(URLContext *h, int flags)
((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
ret = ret > 0 ? 0 : ret;
+ /* flush the receive buffer when it is write only mode */
+ if (!(flags & AVIO_FLAG_READ)) {
+ char buf[1024];
+ int read_ret;
+ s->hd->flags |= AVIO_FLAG_NONBLOCK;
+ read_ret = ffurl_read(s->hd, buf, sizeof(buf));
+ s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
+ if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
+ av_log(h, AV_LOG_ERROR, "URL read error: %d\n", read_ret);
+ ret = read_ret;
+ }
+ }
s->end_chunked_post = 1;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/img2dec.c b/chromium/third_party/ffmpeg/libavformat/img2dec.c
index f3f52c83b35..ffbc9a66d82 100644
--- a/chromium/third_party/ffmpeg/libavformat/img2dec.c
+++ b/chromium/third_party/ffmpeg/libavformat/img2dec.c
@@ -323,7 +323,8 @@ int ff_img_read_header(AVFormatContext *s1)
if (s1->pb) {
int probe_buffer_size = 2048;
uint8_t *probe_buffer = av_realloc(NULL, probe_buffer_size + AVPROBE_PADDING_SIZE);
- AVInputFormat *fmt = NULL;
+ const AVInputFormat *fmt = NULL;
+ void *fmt_iter = NULL;
AVProbeData pd = { 0 };
if (!probe_buffer)
@@ -340,7 +341,7 @@ int ff_img_read_header(AVFormatContext *s1)
pd.buf_size = probe_buffer_size;
pd.filename = s1->url;
- while ((fmt = av_iformat_next(fmt))) {
+ while ((fmt = av_demuxer_iterate(&fmt_iter))) {
if (fmt->read_header != ff_img_read_header ||
!fmt->read_probe ||
(fmt->flags & AVFMT_NOFILE) ||
diff --git a/chromium/third_party/ffmpeg/libavformat/internal.h b/chromium/third_party/ffmpeg/libavformat/internal.h
index a020b1b417d..35826829250 100644
--- a/chromium/third_party/ffmpeg/libavformat/internal.h
+++ b/chromium/third_party/ffmpeg/libavformat/internal.h
@@ -300,6 +300,16 @@ void ff_put_v(AVIOContext *bc, uint64_t val);
int ff_get_line(AVIOContext *s, char *buf, int maxlen);
/**
+ * Same as ff_get_line but strip the white-space characters in the text tail
+ *
+ * @param s the read-only AVIOContext
+ * @param buf buffer to store the read line
+ * @param maxlen size of the buffer
+ * @return the length of the string written in the buffer
+ */
+int ff_get_chomp_line(AVIOContext *s, char *buf, int maxlen);
+
+/**
* Read a whole line of text from AVIOContext to an AVBPrint buffer. Stop
* reading after reaching a \\r, a \\n, a \\r\\n, a \\0 or EOF. The line
* ending characters are NOT included in the buffer, but they are skipped on
@@ -731,11 +741,44 @@ int ff_unlock_avformat(void);
*/
void ff_format_set_url(AVFormatContext *s, char *url);
-#if FF_API_NEXT
+#define FF_PACKETLIST_FLAG_REF_PACKET (1 << 0) /**< Create a new reference for the packet instead of
+ transferring the ownership of the existing one to the
+ list. */
+
/**
- * Register devices in deprecated format linked list.
- */
+ * Append an AVPacket to the list.
+ *
+ * @param head List head element
+ * @param tail List tail element
+ * @param pkt The packet being appended
+ * @param flags Any combination of FF_PACKETLIST_FLAG_* flags
+ * @return 0 on success, negative AVERROR value on failure. On failure,
+ the list is unchanged
+ */
+int ff_packet_list_put(AVPacketList **head, AVPacketList **tail,
+ AVPacket *pkt, int flags);
+
+/**
+ * Remove the oldest AVPacket in the list and return it.
+ *
+ * @note The pkt will be overwritten completely. The caller owns the
+ * packet and must unref it by itself.
+ *
+ * @param head List head element
+ * @param tail List tail element
+ * @param pkt Pointer to an initialized AVPacket struct
+ */
+int ff_packet_list_get(AVPacketList **head, AVPacketList **tail,
+ AVPacket *pkt);
+
+/**
+ * Wipe the list and unref all the packets in it.
+ *
+ * @param head List head element
+ * @param tail List tail element
+ */
+void ff_packet_list_free(AVPacketList **head, AVPacketList **tail);
+
void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]);
-#endif
#endif /* AVFORMAT_INTERNAL_H */
diff --git a/chromium/third_party/ffmpeg/libavformat/isom.h b/chromium/third_party/ffmpeg/libavformat/isom.h
index 4da34142f06..fb361125c96 100644
--- a/chromium/third_party/ffmpeg/libavformat/isom.h
+++ b/chromium/third_party/ffmpeg/libavformat/isom.h
@@ -27,6 +27,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "libavutil/encryption_info.h"
#include "libavutil/mastering_display_metadata.h"
#include "libavutil/spherical.h"
#include "libavutil/stereo3d.h"
@@ -108,12 +109,26 @@ typedef struct MOVSbgp {
unsigned int index;
} MOVSbgp;
+typedef struct MOVEncryptionIndex {
+ // Individual encrypted samples. If there are no elements, then the default
+ // settings will be used.
+ unsigned int nb_encrypted_samples;
+ AVEncryptionInfo **encrypted_samples;
+
+ uint8_t* auxiliary_info_sizes;
+ size_t auxiliary_info_sample_count;
+ uint8_t auxiliary_info_default_size;
+ size_t* auxiliary_offsets; ///< Absolute seek position
+ size_t auxiliary_offsets_count;
+} MOVEncryptionIndex;
+
typedef struct MOVFragmentStreamInfo {
int id;
int64_t sidx_pts;
int64_t first_tfra_pts;
int64_t tfdt_dts;
int index_entry;
+ MOVEncryptionIndex *encryption_index;
} MOVFragmentStreamInfo;
typedef struct MOVFragmentIndexItem {
@@ -215,15 +230,10 @@ typedef struct MOVStreamContext {
int has_sidx; // If there is an sidx entry for this stream.
struct {
- int use_subsamples;
- uint8_t* auxiliary_info;
- uint8_t* auxiliary_info_end;
- uint8_t* auxiliary_info_pos;
- uint8_t auxiliary_info_default_size;
- uint8_t* auxiliary_info_sizes;
- size_t auxiliary_info_sizes_count;
- int64_t auxiliary_info_index;
struct AVAESCTR* aes_ctr;
+ unsigned int per_sample_iv_size; // Either 0, 8, or 16.
+ AVEncryptionInfo *default_encrypted_sample;
+ MOVEncryptionIndex *encryption_index;
} cenc;
} MOVStreamContext;
diff --git a/chromium/third_party/ffmpeg/libavformat/ivfenc.c b/chromium/third_party/ffmpeg/libavformat/ivfenc.c
index f591327a218..af803d59ee8 100644
--- a/chromium/third_party/ffmpeg/libavformat/ivfenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/ivfenc.c
@@ -37,8 +37,9 @@ static int ivf_write_header(AVFormatContext *s)
}
par = s->streams[0]->codecpar;
if (par->codec_type != AVMEDIA_TYPE_VIDEO ||
- !(par->codec_id == AV_CODEC_ID_VP8 || par->codec_id == AV_CODEC_ID_VP9 ||
- par->codec_id == AV_CODEC_ID_AV1)) {
+ !(par->codec_id == AV_CODEC_ID_AV1 ||
+ par->codec_id == AV_CODEC_ID_VP8 ||
+ par->codec_id == AV_CODEC_ID_VP9)) {
av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are supported!\n");
return AVERROR(EINVAL);
}
diff --git a/chromium/third_party/ffmpeg/libavformat/libopenmpt.c b/chromium/third_party/ffmpeg/libavformat/libopenmpt.c
index 30c3d6e646f..0fff702a36f 100644
--- a/chromium/third_party/ffmpeg/libavformat/libopenmpt.c
+++ b/chromium/third_party/ffmpeg/libavformat/libopenmpt.c
@@ -218,6 +218,62 @@ static int read_seek_openmpt(AVFormatContext *s, int stream_idx, int64_t ts, int
return 0;
}
+static int probe_openmpt_extension(AVProbeData *p)
+{
+ const char *ext;
+ if (p->filename) {
+ ext = strrchr(p->filename, '.');
+ if (ext && strlen(ext + 1) > 0) {
+ ext++; /* skip '.' */
+ if (openmpt_is_extension_supported(ext) == 1)
+ return AVPROBE_SCORE_EXTENSION;
+ }
+ }
+ return 0;
+}
+
+static int read_probe_openmpt(AVProbeData *p)
+{
+#if OPENMPT_API_VERSION_AT_LEAST(0,3,0)
+ int probe_result;
+ if (p->buf && p->buf_size > 0) {
+ probe_result = openmpt_probe_file_header_without_filesize(
+ OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT,
+ p->buf, p->buf_size,
+ &openmpt_logfunc, NULL, NULL, NULL, NULL, NULL);
+ if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS) {
+ /* As probing here relies on code external to FFmpeg, do not return
+ * AVPROBE_SCORE_MAX in order to reduce the impact in the rare
+ * cases of false positives.
+ */
+ return AVPROBE_SCORE_MIME + 1;
+ } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA) {
+ if (probe_openmpt_extension(p) > 0) {
+ return AVPROBE_SCORE_RETRY;
+ } else {
+ if (p->buf_size >= openmpt_probe_file_header_get_recommended_size()) {
+ /* We have already received the recommended amount of data
+ * and still cannot decide. Return a rather low score.
+ */
+ return AVPROBE_SCORE_RETRY / 2;
+ } else {
+ /* The file extension is unknown and we have very few data
+ * bytes available. libopenmpt cannot decide anything here,
+ * and returning any score > 0 would result in successfull
+ * probing of random data.
+ */
+ return 0;
+ }
+ }
+ } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE) {
+ return 0;
+ }
+ }
+#endif
+ /* for older libopenmpt, fall back to file extension probing */
+ return probe_openmpt_extension(p);
+}
+
static const AVClass class_openmpt = {
.class_name = "libopenmpt",
.item_name = av_default_item_name,
@@ -229,10 +285,15 @@ AVInputFormat ff_libopenmpt_demuxer = {
.name = "libopenmpt",
.long_name = NULL_IF_CONFIG_SMALL("Tracker formats (libopenmpt)"),
.priv_data_size = sizeof(OpenMPTContext),
+ .read_probe = read_probe_openmpt,
.read_header = read_header_openmpt,
.read_packet = read_packet_openmpt,
.read_close = read_close_openmpt,
.read_seek = read_seek_openmpt,
.priv_class = &class_openmpt,
- .extensions = "669,amf,ams,dbm,digi,dmf,dsm,far,gdm,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,stk,stm,ult,umx,wow,xm,xpk",
+#if OPENMPT_API_VERSION_AT_LEAST(0,3,0)
+ .extensions = "669,amf,ams,dbm,digi,dmf,dsm,dtm,far,gdm,ice,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,st26,stk,stm,stp,ult,umx,wow,xm,xpk",
+#else
+ .extensions = "669,amf,ams,dbm,digi,dmf,dsm,far,gdm,ice,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,st26,stk,stm,ult,umx,wow,xm,xpk",
+#endif
};
diff --git a/chromium/third_party/ffmpeg/libavformat/libsrt.c b/chromium/third_party/ffmpeg/libavformat/libsrt.c
new file mode 100644
index 00000000000..0f9529d263a
--- /dev/null
+++ b/chromium/third_party/ffmpeg/libavformat/libsrt.c
@@ -0,0 +1,546 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Haivision Open SRT (Secure Reliable Transport) protocol
+ */
+
+#include <srt/srt.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
+#include "libavutil/time.h"
+
+#include "avformat.h"
+#include "internal.h"
+#include "network.h"
+#include "os_support.h"
+#include "url.h"
+
+enum SRTMode {
+ SRT_MODE_CALLER = 0,
+ SRT_MODE_LISTENER = 1,
+ SRT_MODE_RENDEZVOUS = 2
+};
+
+typedef struct SRTContext {
+ const AVClass *class;
+ int fd;
+ int eid;
+ int64_t rw_timeout;
+ int64_t listen_timeout;
+ int recv_buffer_size;
+ int send_buffer_size;
+
+ int64_t maxbw;
+ int pbkeylen;
+ char *passphrase;
+ int mss;
+ int ffs;
+ int ipttl;
+ int iptos;
+ int64_t inputbw;
+ int oheadbw;
+ int64_t tsbpddelay;
+ int tlpktdrop;
+ int nakreport;
+ int64_t connect_timeout;
+ enum SRTMode mode;
+} SRTContext;
+
+#define D AV_OPT_FLAG_DECODING_PARAM
+#define E AV_OPT_FLAG_ENCODING_PARAM
+#define OFFSET(x) offsetof(SRTContext, x)
+static const AVOption libsrt_options[] = {
+ { "rw_timeout", "Timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
+ { "listen_timeout", "Connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
+ { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
+ { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
+ { "maxbw", "Maximum bandwidth (bytes per second) that the connection can use", OFFSET(maxbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
+ { "pbkeylen", "Crypto key len in bytes {16,24,32} Default: 16 (128-bit)", OFFSET(pbkeylen), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, .flags = D|E },
+ { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E },
+ { "mss", "The Maximum Segment Size", OFFSET(mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1500, .flags = D|E },
+ { "ffs", "Flight flag size (window size) (in bytes)", OFFSET(ffs), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E },
+ { "ipttl", "IP Time To Live", OFFSET(ipttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
+ { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E },
+ { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
+ { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E },
+ { "tsbpddelay", "TsbPd receiver delay to absorb burst of missed packet retransmission", OFFSET(tsbpddelay), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
+ { "tlpktdrop", "Enable receiver pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
+ { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E },
+ { "connect_timeout", "Connect timeout. Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E },
+ { "mode", "Connection mode (caller, listener, rendezvous)", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = SRT_MODE_CALLER }, SRT_MODE_CALLER, SRT_MODE_RENDEZVOUS, .flags = D|E, "mode" },
+ { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, "mode" },
+ { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, "mode" },
+ { "rendezvous", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_RENDEZVOUS }, INT_MIN, INT_MAX, .flags = D|E, "mode" },
+ { NULL }
+};
+
+static int libsrt_neterrno(URLContext *h)
+{
+ int err = srt_getlasterror(NULL);
+ av_log(h, AV_LOG_ERROR, "%s\n", srt_getlasterror_str());
+ if (err == SRT_EASYNCRCV)
+ return AVERROR(EAGAIN);
+ return AVERROR_UNKNOWN;
+}
+
+static int libsrt_socket_nonblock(int socket, int enable)
+{
+ int ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &enable, sizeof(enable));
+ if (ret < 0)
+ return ret;
+ return srt_setsockopt(socket, 0, SRTO_RCVSYN, &enable, sizeof(enable));
+}
+
+static int libsrt_network_wait_fd(URLContext *h, int eid, int fd, int write)
+{
+ int ret, len = 1;
+ int modes = write ? SRT_EPOLL_OUT : SRT_EPOLL_IN;
+ SRTSOCKET ready[1];
+
+ if (srt_epoll_add_usock(eid, fd, &modes) < 0)
+ return libsrt_neterrno(h);
+ if (write) {
+ ret = srt_epoll_wait(eid, 0, 0, ready, &len, POLLING_TIME, 0, 0, 0, 0);
+ } else {
+ ret = srt_epoll_wait(eid, ready, &len, 0, 0, POLLING_TIME, 0, 0, 0, 0);
+ }
+ if (ret < 0) {
+ if (srt_getlasterror(NULL) == SRT_ETIMEOUT)
+ ret = AVERROR(EAGAIN);
+ else
+ ret = libsrt_neterrno(h);
+ } else {
+ ret = 0;
+ }
+ if (srt_epoll_remove_usock(eid, fd) < 0)
+ return libsrt_neterrno(h);
+ return ret;
+}
+
+/* TODO de-duplicate code from ff_network_wait_fd_timeout() */
+
+static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb)
+{
+ int ret;
+ int64_t wait_start = 0;
+
+ while (1) {
+ if (ff_check_interrupt(int_cb))
+ return AVERROR_EXIT;
+ ret = libsrt_network_wait_fd(h, eid, fd, write);
+ if (ret != AVERROR(EAGAIN))
+ return ret;
+ if (timeout > 0) {
+ if (!wait_start)
+ wait_start = av_gettime_relative();
+ else if (av_gettime_relative() - wait_start > timeout)
+ return AVERROR(ETIMEDOUT);
+ }
+ }
+}
+
+static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int timeout)
+{
+ int ret;
+ int reuse = 1;
+ if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) {
+ av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n");
+ }
+ ret = srt_bind(fd, addr, addrlen);
+ if (ret)
+ return libsrt_neterrno(h);
+
+ ret = srt_listen(fd, 1);
+ if (ret)
+ return libsrt_neterrno(h);
+
+ while ((ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback))) {
+ switch (ret) {
+ case AVERROR(ETIMEDOUT):
+ continue;
+ default:
+ return ret;
+ }
+ }
+
+ ret = srt_accept(fd, NULL, NULL);
+ if (ret < 0)
+ return libsrt_neterrno(h);
+ if (libsrt_socket_nonblock(ret, 1) < 0)
+ av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n");
+
+ return ret;
+}
+
+static int libsrt_listen_connect(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next)
+{
+ int ret;
+
+ if (libsrt_socket_nonblock(fd, 1) < 0)
+ av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n");
+
+ while ((ret = srt_connect(fd, addr, addrlen))) {
+ ret = libsrt_neterrno(h);
+ switch (ret) {
+ case AVERROR(EINTR):
+ if (ff_check_interrupt(&h->interrupt_callback))
+ return AVERROR_EXIT;
+ continue;
+ case AVERROR(EINPROGRESS):
+ case AVERROR(EAGAIN):
+ ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback);
+ if (ret < 0)
+ return ret;
+ ret = srt_getlasterror(NULL);
+ srt_clearlasterror();
+ if (ret != 0) {
+ char buf[128];
+ ret = AVERROR(ret);
+ av_strerror(ret, buf, sizeof(buf));
+ if (will_try_next)
+ av_log(h, AV_LOG_WARNING,
+ "Connection to %s failed (%s), trying next address\n",
+ h->filename, buf);
+ else
+ av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n",
+ h->filename, buf);
+ }
+ default:
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, const void * optval, int optlen)
+{
+ if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) {
+ av_log(h, AV_LOG_ERROR, "failed to set option %s on socket: %s\n", optnamestr, srt_getlasterror_str());
+ return AVERROR(EIO);
+ }
+ return 0;
+}
+
+/* - The "POST" options can be altered any time on a connected socket.
+ They MAY have also some meaning when set prior to connecting; such
+ option is SRTO_RCVSYN, which makes connect/accept call asynchronous.
+ Because of that this option is treated special way in this app. */
+static int libsrt_set_options_post(URLContext *h, int fd)
+{
+ SRTContext *s = h->priv_data;
+
+ if ((s->inputbw >= 0 && libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw, sizeof(s->inputbw)) < 0) ||
+ (s->oheadbw >= 0 && libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw, sizeof(s->oheadbw)) < 0)) {
+ return AVERROR(EIO);
+ }
+ return 0;
+}
+
+/* - The "PRE" options must be set prior to connecting and can't be altered
+ on a connected socket, however if set on a listening socket, they are
+ derived by accept-ed socket. */
+static int libsrt_set_options_pre(URLContext *h, int fd)
+{
+ SRTContext *s = h->priv_data;
+ int yes = 1;
+ int tsbpddelay = s->tsbpddelay / 1000;
+ int connect_timeout = s->connect_timeout;
+
+ if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) ||
+ (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) ||
+ (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) ||
+ (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", &s->passphrase, sizeof(s->passphrase)) < 0) ||
+ (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MMS", &s->mss, sizeof(s->mss)) < 0) ||
+ (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) ||
+ (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_UPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) ||
+ (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) ||
+ (tsbpddelay >= 0 && libsrt_setsockopt(h, fd, SRTO_TSBPDDELAY, "SRTO_TSBPDELAY", &tsbpddelay, sizeof(tsbpddelay)) < 0) ||
+ (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) ||
+ (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) ||
+ (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 )) {
+ return AVERROR(EIO);
+ }
+ return 0;
+}
+
+
+static int libsrt_setup(URLContext *h, const char *uri, int flags)
+{
+ struct addrinfo hints = { 0 }, *ai, *cur_ai;
+ int port, fd = -1;
+ SRTContext *s = h->priv_data;
+ const char *p;
+ char buf[256];
+ int ret;
+ char hostname[1024],proto[1024],path[1024];
+ char portstr[10];
+ int open_timeout = 5000000;
+ int eid;
+
+ eid = srt_epoll_create();
+ if (eid < 0)
+ return libsrt_neterrno(h);
+ s->eid = eid;
+
+ av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname),
+ &port, path, sizeof(path), uri);
+ if (strcmp(proto, "srt"))
+ return AVERROR(EINVAL);
+ if (port <= 0 || port >= 65536) {
+ av_log(h, AV_LOG_ERROR, "Port missing in uri\n");
+ return AVERROR(EINVAL);
+ }
+ p = strchr(uri, '?');
+ if (p) {
+ if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) {
+ s->rw_timeout = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) {
+ s->listen_timeout = strtol(buf, NULL, 10);
+ }
+ }
+ if (s->rw_timeout >= 0) {
+ open_timeout = h->rw_timeout = s->rw_timeout;
+ }
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ if (s->mode == SRT_MODE_LISTENER)
+ hints.ai_flags |= AI_PASSIVE;
+ ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai);
+ if (ret) {
+ av_log(h, AV_LOG_ERROR,
+ "Failed to resolve hostname %s: %s\n",
+ hostname, gai_strerror(ret));
+ return AVERROR(EIO);
+ }
+
+ cur_ai = ai;
+
+ restart:
+
+ fd = srt_socket(cur_ai->ai_family, cur_ai->ai_socktype, 0);
+ if (fd < 0) {
+ ret = libsrt_neterrno(h);
+ goto fail;
+ }
+
+ if ((ret = libsrt_set_options_pre(h, fd)) < 0) {
+ goto fail;
+ }
+
+ /* Set the socket's send or receive buffer sizes, if specified.
+ If unspecified or setting fails, system default is used. */
+ if (s->recv_buffer_size > 0) {
+ srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size));
+ }
+ if (s->send_buffer_size > 0) {
+ srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size));
+ }
+ if (s->mode == SRT_MODE_LISTENER) {
+ // multi-client
+ if ((ret = libsrt_listen(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, h, open_timeout / 1000)) < 0)
+ goto fail1;
+ fd = ret;
+ } else {
+ if (s->mode == SRT_MODE_RENDEZVOUS) {
+ ret = srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen);
+ if (ret)
+ goto fail1;
+ }
+
+ if ((ret = libsrt_listen_connect(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen,
+ open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) {
+ if (ret == AVERROR_EXIT)
+ goto fail1;
+ else
+ goto fail;
+ }
+ }
+ if ((ret = libsrt_set_options_post(h, fd)) < 0) {
+ goto fail;
+ }
+
+ h->is_streamed = 1;
+ s->fd = fd;
+
+ freeaddrinfo(ai);
+ return 0;
+
+ fail:
+ if (cur_ai->ai_next) {
+ /* Retry with the next sockaddr */
+ cur_ai = cur_ai->ai_next;
+ if (fd >= 0)
+ srt_close(fd);
+ ret = 0;
+ goto restart;
+ }
+ fail1:
+ if (fd >= 0)
+ srt_close(fd);
+ freeaddrinfo(ai);
+ return ret;
+}
+
+static int libsrt_open(URLContext *h, const char *uri, int flags)
+{
+ SRTContext *s = h->priv_data;
+ const char * p;
+ char buf[256];
+
+ if (srt_startup() < 0) {
+ return AVERROR_UNKNOWN;
+ }
+
+ /* SRT options (srt/srt.h) */
+ p = strchr(uri, '?');
+ if (p) {
+ if (av_find_info_tag(buf, sizeof(buf), "maxbw", p)) {
+ s->maxbw = strtoll(buf, NULL, 0);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "pbkeylen", p)) {
+ s->pbkeylen = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) {
+ s->passphrase = av_strndup(buf, strlen(buf));
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "mss", p)) {
+ s->mss = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "ffs", p)) {
+ s->ffs = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "ipttl", p)) {
+ s->ipttl = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "iptos", p)) {
+ s->iptos = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "inputbw", p)) {
+ s->inputbw = strtoll(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) {
+ s->oheadbw = strtoll(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) {
+ s->tsbpddelay = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) {
+ s->tlpktdrop = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "nakreport", p)) {
+ s->nakreport = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) {
+ s->connect_timeout = strtol(buf, NULL, 10);
+ }
+ if (av_find_info_tag(buf, sizeof(buf), "mode", p)) {
+ if (!strcmp(buf, "caller")) {
+ s->mode = SRT_MODE_CALLER;
+ } else if (!strcmp(buf, "listener")) {
+ s->mode = SRT_MODE_LISTENER;
+ } else if (!strcmp(buf, "rendezvous")) {
+ s->mode = SRT_MODE_RENDEZVOUS;
+ } else {
+ return AVERROR(EIO);
+ }
+ }
+ }
+ return libsrt_setup(h, uri, flags);
+}
+
+static int libsrt_read(URLContext *h, uint8_t *buf, int size)
+{
+ SRTContext *s = h->priv_data;
+ int ret;
+
+ if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
+ ret = libsrt_network_wait_fd_timeout(h, s->eid, s->fd, 0, h->rw_timeout, &h->interrupt_callback);
+ if (ret)
+ return ret;
+ }
+
+ ret = srt_recvmsg(s->fd, buf, size);
+ if (ret < 0) {
+ ret = libsrt_neterrno(h);
+ }
+
+ return ret;
+}
+
+static int libsrt_write(URLContext *h, const uint8_t *buf, int size)
+{
+ SRTContext *s = h->priv_data;
+ int ret;
+
+ if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
+ ret = libsrt_network_wait_fd_timeout(h, s->eid, s->fd, 1, h->rw_timeout, &h->interrupt_callback);
+ if (ret)
+ return ret;
+ }
+
+ ret = srt_sendmsg(s->fd, buf, size, -1, 0);
+ if (ret < 0) {
+ ret = libsrt_neterrno(h);
+ }
+
+ return ret;
+}
+
+static int libsrt_close(URLContext *h)
+{
+ SRTContext *s = h->priv_data;
+
+ srt_close(s->fd);
+
+ srt_epoll_release(s->eid);
+
+ srt_cleanup();
+
+ return 0;
+}
+
+static int libsrt_get_file_handle(URLContext *h)
+{
+ SRTContext *s = h->priv_data;
+ return s->fd;
+}
+
+static const AVClass libsrt_class = {
+ .class_name = "libsrt",
+ .item_name = av_default_item_name,
+ .option = libsrt_options,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+const URLProtocol ff_libsrt_protocol = {
+ .name = "srt",
+ .url_open = libsrt_open,
+ .url_read = libsrt_read,
+ .url_write = libsrt_write,
+ .url_close = libsrt_close,
+ .url_get_file_handle = libsrt_get_file_handle,
+ .priv_data_size = sizeof(SRTContext),
+ .flags = URL_PROTOCOL_FLAG_NETWORK,
+ .priv_data_class = &libsrt_class,
+};
diff --git a/chromium/third_party/ffmpeg/libavformat/matroskadec.c b/chromium/third_party/ffmpeg/libavformat/matroskadec.c
index 222fa046b22..5b8dba254eb 100644
--- a/chromium/third_party/ffmpeg/libavformat/matroskadec.c
+++ b/chromium/third_party/ffmpeg/libavformat/matroskadec.c
@@ -108,6 +108,7 @@ typedef struct EbmlList {
typedef struct EbmlBin {
int size;
+ AVBufferRef *buf;
uint8_t *data;
int64_t pos;
} EbmlBin;
@@ -342,9 +343,8 @@ typedef struct MatroskaDemuxContext {
int64_t segment_start;
/* the packet queue */
- AVPacket **packets;
- int num_packets;
- AVPacket *prev_pkt;
+ AVPacketList *queue;
+ AVPacketList *queue_end;
int done;
@@ -967,14 +967,19 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
*/
static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin)
{
- av_fast_padded_malloc(&bin->data, &bin->size, length);
- if (!bin->data)
- return AVERROR(ENOMEM);
+ int ret;
+
+ ret = av_buffer_realloc(&bin->buf, length + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (ret < 0)
+ return ret;
+ memset(bin->buf->data + length, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ bin->data = bin->buf->data;
bin->size = length;
bin->pos = avio_tell(pb);
if (avio_read(pb, bin->data, length) != length) {
- av_freep(&bin->data);
+ av_buffer_unref(&bin->buf);
+ bin->data = NULL;
bin->size = 0;
return AVERROR(EIO);
}
@@ -1257,7 +1262,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data)
av_freep(data_off);
break;
case EBML_BIN:
- av_freep(&((EbmlBin *) data_off)->data);
+ av_buffer_unref(&((EbmlBin *) data_off)->buf);
break;
case EBML_LEVEL1:
case EBML_NEST:
@@ -1366,7 +1371,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
return 0;
pkt_size = isize + header_size;
- pkt_data = av_malloc(pkt_size);
+ pkt_data = av_malloc(pkt_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!pkt_data)
return AVERROR(ENOMEM);
@@ -1378,7 +1383,8 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
case MATROSKA_TRACK_ENCODING_COMP_LZO:
do {
olen = pkt_size *= 3;
- newpktdata = av_realloc(pkt_data, pkt_size + AV_LZO_OUTPUT_PADDING);
+ newpktdata = av_realloc(pkt_data, pkt_size + AV_LZO_OUTPUT_PADDING
+ + AV_INPUT_BUFFER_PADDING_SIZE);
if (!newpktdata) {
result = AVERROR(ENOMEM);
goto failed;
@@ -1403,7 +1409,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
zstream.avail_in = isize;
do {
pkt_size *= 3;
- newpktdata = av_realloc(pkt_data, pkt_size);
+ newpktdata = av_realloc(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!newpktdata) {
inflateEnd(&zstream);
result = AVERROR(ENOMEM);
@@ -1436,7 +1442,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
bzstream.avail_in = isize;
do {
pkt_size *= 3;
- newpktdata = av_realloc(pkt_data, pkt_size);
+ newpktdata = av_realloc(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!newpktdata) {
BZ2_bzDecompressEnd(&bzstream);
result = AVERROR(ENOMEM);
@@ -1463,6 +1469,8 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size,
return AVERROR_INVALIDDATA;
}
+ memset(pkt_data + pkt_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
*buf = pkt_data;
*buf_size = pkt_size;
return 0;
@@ -2041,12 +2049,13 @@ static int get_qt_codec(MatroskaTrack *track, uint32_t *fourcc, enum AVCodecID *
* by expanding/shifting the data by 4 bytes and storing the data
* size at the start. */
if (ff_codec_get_id(codec_tags, AV_RL32(track->codec_priv.data))) {
- uint8_t *p = av_realloc(track->codec_priv.data,
- track->codec_priv.size + 4);
- if (!p)
- return AVERROR(ENOMEM);
- memmove(p + 4, p, track->codec_priv.size);
- track->codec_priv.data = p;
+ int ret = av_buffer_realloc(&track->codec_priv.buf,
+ track->codec_priv.size + 4 + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (ret < 0)
+ return ret;
+
+ track->codec_priv.data = track->codec_priv.buf->data;
+ memmove(track->codec_priv.data + 4, track->codec_priv.data, track->codec_priv.size);
track->codec_priv.size += 4;
AV_WB32(track->codec_priv.data, track->codec_priv.size);
}
@@ -2167,8 +2176,19 @@ static int matroska_parse_tracks(AVFormatContext *s)
"Failed to decode codec private data\n");
}
- if (codec_priv != track->codec_priv.data)
- av_free(codec_priv);
+ if (codec_priv != track->codec_priv.data) {
+ av_buffer_unref(&track->codec_priv.buf);
+ if (track->codec_priv.data) {
+ track->codec_priv.buf = av_buffer_create(track->codec_priv.data,
+ track->codec_priv.size + AV_INPUT_BUFFER_PADDING_SIZE,
+ NULL, NULL, 0);
+ if (!track->codec_priv.buf) {
+ av_freep(&track->codec_priv.data);
+ track->codec_priv.size = 0;
+ return AVERROR(ENOMEM);
+ }
+ }
+ }
}
}
@@ -2730,11 +2750,11 @@ fail:
static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
AVPacket *pkt)
{
- if (matroska->num_packets > 0) {
+ if (matroska->queue) {
MatroskaTrack *tracks = matroska->tracks.elem;
MatroskaTrack *track;
- memcpy(pkt, matroska->packets[0], sizeof(AVPacket));
- av_freep(&matroska->packets[0]);
+
+ ff_packet_list_get(&matroska->queue, &matroska->queue_end, pkt);
track = &tracks[pkt->stream_index];
if (track->has_palette) {
uint8_t *pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
@@ -2745,20 +2765,6 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
}
track->has_palette = 0;
}
- if (matroska->num_packets > 1) {
- void *newpackets;
- memmove(&matroska->packets[0], &matroska->packets[1],
- (matroska->num_packets - 1) * sizeof(AVPacket *));
- newpackets = av_realloc(matroska->packets,
- (matroska->num_packets - 1) *
- sizeof(AVPacket *));
- if (newpackets)
- matroska->packets = newpackets;
- } else {
- av_freep(&matroska->packets);
- matroska->prev_pkt = NULL;
- }
- matroska->num_packets--;
return 0;
}
@@ -2770,16 +2776,7 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska,
*/
static void matroska_clear_queue(MatroskaDemuxContext *matroska)
{
- matroska->prev_pkt = NULL;
- if (matroska->packets) {
- int n;
- for (n = 0; n < matroska->num_packets; n++) {
- av_packet_unref(matroska->packets[n]);
- av_freep(&matroska->packets[n]);
- }
- av_freep(&matroska->packets);
- matroska->num_packets = 0;
- }
+ ff_packet_list_free(&matroska->queue, &matroska->queue_end);
}
static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf,
@@ -2950,13 +2947,10 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
while (track->audio.pkt_cnt) {
int ret;
- AVPacket *pkt = av_mallocz(sizeof(AVPacket));
- if (!pkt)
- return AVERROR(ENOMEM);
+ AVPacket pktl, *pkt = &pktl;
ret = av_new_packet(pkt, a);
if (ret < 0) {
- av_free(pkt);
return ret;
}
memcpy(pkt->data,
@@ -2966,7 +2960,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska,
track->audio.buf_timecode = AV_NOPTS_VALUE;
pkt->pos = pos;
pkt->stream_index = st->index;
- dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+ ret = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0);
+ if (ret < 0) {
+ av_packet_unref(pkt);
+ return AVERROR(ENOMEM);
+ }
}
return 0;
@@ -3019,7 +3017,7 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
goto fail;
}
- tmp = av_realloc(dst, dstlen + blocksize + 32);
+ tmp = av_realloc(dst, dstlen + blocksize + 32 + AV_INPUT_BUFFER_PADDING_SIZE);
if (!tmp) {
ret = AVERROR(ENOMEM);
goto fail;
@@ -3043,6 +3041,8 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src,
offset += blocksize + 32;
}
+ memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+
*pdst = dst;
*size = dstlen;
@@ -3053,6 +3053,30 @@ fail:
return ret;
}
+static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src,
+ uint8_t **pdst, int *size)
+{
+ uint8_t *dst = src;
+ int dstlen = *size;
+
+ if (AV_RB32(&src[4]) != MKBETAG('i', 'c', 'p', 'f')) {
+ dst = av_malloc(dstlen + 8 + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (!dst)
+ return AVERROR(ENOMEM);
+
+ AV_WB32(dst, dstlen);
+ AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f'));
+ memcpy(dst + 8, src, dstlen);
+ memset(dst + 8 + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
+ dstlen += 8;
+ }
+
+ *pdst = dst;
+ *size = dstlen;
+
+ return 0;
+}
+
static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
MatroskaTrack *track,
AVStream *st,
@@ -3061,7 +3085,7 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
uint64_t duration,
int64_t pos)
{
- AVPacket *pkt;
+ AVPacket pktl, *pkt = &pktl;
uint8_t *id, *settings, *text, *buf;
int id_len, settings_len, text_len;
uint8_t *p, *q;
@@ -3118,12 +3142,8 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
if (text_len <= 0)
return AVERROR_INVALIDDATA;
- pkt = av_mallocz(sizeof(*pkt));
- if (!pkt)
- return AVERROR(ENOMEM);
err = av_new_packet(pkt, text_len);
if (err < 0) {
- av_free(pkt);
return err;
}
@@ -3135,7 +3155,6 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
id_len);
if (!buf) {
av_packet_unref(pkt);
- av_free(pkt);
return AVERROR(ENOMEM);
}
memcpy(buf, id, id_len);
@@ -3147,7 +3166,6 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
settings_len);
if (!buf) {
av_packet_unref(pkt);
- av_free(pkt);
return AVERROR(ENOMEM);
}
memcpy(buf, settings, settings_len);
@@ -3165,15 +3183,18 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska,
pkt->duration = duration;
pkt->pos = pos;
- dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
- matroska->prev_pkt = pkt;
+ err = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0);
+ if (err < 0) {
+ av_packet_unref(pkt);
+ return AVERROR(ENOMEM);
+ }
return 0;
}
static int matroska_parse_frame(MatroskaDemuxContext *matroska,
MatroskaTrack *track, AVStream *st,
- uint8_t *data, int pkt_size,
+ AVBufferRef *buf, uint8_t *data, int pkt_size,
uint64_t timecode, uint64_t lace_duration,
int64_t pos, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size,
@@ -3181,8 +3202,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
{
MatroskaTrackEncoding *encodings = track->encodings.elem;
uint8_t *pkt_data = data;
- int offset = 0, res;
- AVPacket *pkt;
+ int res;
+ AVPacket pktl, *pkt = &pktl;
if (encodings && !encodings->type && encodings->scope & 1) {
res = matroska_decode_buffer(&pkt_data, &pkt_size, track);
@@ -3203,34 +3224,33 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
pkt_data = wv_data;
}
- if (st->codecpar->codec_id == AV_CODEC_ID_PRORES &&
- AV_RB32(&data[4]) != MKBETAG('i', 'c', 'p', 'f'))
- offset = 8;
-
- pkt = av_mallocz(sizeof(AVPacket));
- if (!pkt) {
+ if (st->codecpar->codec_id == AV_CODEC_ID_PRORES) {
+ uint8_t *pr_data;
+ res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size);
+ if (res < 0) {
+ av_log(matroska->ctx, AV_LOG_ERROR,
+ "Error parsing a prores block.\n");
+ goto fail;
+ }
if (pkt_data != data)
av_freep(&pkt_data);
- return AVERROR(ENOMEM);
+ pkt_data = pr_data;
}
- /* XXX: prevent data copy... */
- if (av_new_packet(pkt, pkt_size + offset) < 0) {
- av_free(pkt);
+
+ av_init_packet(pkt);
+ if (pkt_data != data)
+ pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE,
+ NULL, NULL, 0);
+ else
+ pkt->buf = av_buffer_ref(buf);
+
+ if (!pkt->buf) {
res = AVERROR(ENOMEM);
goto fail;
}
- if (st->codecpar->codec_id == AV_CODEC_ID_PRORES && offset == 8) {
- uint8_t *buf = pkt->data;
- bytestream_put_be32(&buf, pkt_size);
- bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f'));
- }
-
- memcpy(pkt->data + offset, pkt_data, pkt_size);
-
- if (pkt_data != data)
- av_freep(&pkt_data);
-
+ pkt->data = pkt_data;
+ pkt->size = pkt_size;
pkt->flags = is_keyframe;
pkt->stream_index = st->index;
@@ -3240,7 +3260,6 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
additional_size + 8);
if (!side_data) {
av_packet_unref(pkt);
- av_free(pkt);
return AVERROR(ENOMEM);
}
AV_WB64(side_data, additional_id);
@@ -3253,7 +3272,6 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska,
10);
if (!side_data) {
av_packet_unref(pkt);
- av_free(pkt);
return AVERROR(ENOMEM);
}
discard_padding = av_rescale_q(discard_padding,
@@ -3281,8 +3299,11 @@ FF_DISABLE_DEPRECATION_WARNINGS
FF_ENABLE_DEPRECATION_WARNINGS
#endif
- dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
- matroska->prev_pkt = pkt;
+ res = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0);
+ if (res < 0) {
+ av_packet_unref(pkt);
+ return AVERROR(ENOMEM);
+ }
return 0;
@@ -3292,7 +3313,7 @@ fail:
return res;
}
-static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
+static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf, uint8_t *data,
int size, int64_t pos, uint64_t cluster_time,
uint64_t block_duration, int is_keyframe,
uint8_t *additional, uint64_t additional_id, int additional_size,
@@ -3414,7 +3435,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
if (res)
goto end;
} else {
- res = matroska_parse_frame(matroska, track, st, data, lace_size[n],
+ res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n],
timecode, lace_duration, pos,
!n ? is_keyframe : 0,
additional, additional_id, additional_size,
@@ -3450,7 +3471,6 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
memset(&matroska->current_cluster, 0, sizeof(MatroskaCluster));
matroska->current_cluster_num_blocks = 0;
matroska->current_cluster_pos = avio_tell(matroska->ctx->pb);
- matroska->prev_pkt = NULL;
/* sizeof the ID which was already read */
if (matroska->current_id)
matroska->current_cluster_pos -= 4;
@@ -3478,7 +3498,7 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska)
blocks[i].additional.data : NULL;
if (!blocks[i].non_simple)
blocks[i].duration = 0;
- res = matroska_parse_block(matroska, blocks[i].bin.data,
+ res = matroska_parse_block(matroska, blocks[i].bin.buf, blocks[i].bin.data,
blocks[i].bin.size, blocks[i].bin.pos,
matroska->current_cluster.timecode,
blocks[i].duration, is_keyframe,
@@ -3503,7 +3523,6 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
if (!matroska->contains_ssa)
return matroska_parse_cluster_incremental(matroska);
pos = avio_tell(matroska->ctx->pb);
- matroska->prev_pkt = NULL;
if (matroska->current_id)
pos -= 4; /* sizeof the ID which was already read */
res = ebml_parse(matroska, matroska_clusters, &cluster);
@@ -3512,7 +3531,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
for (i = 0; i < blocks_list->nb_elem; i++)
if (blocks[i].bin.size > 0 && blocks[i].bin.data) {
int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1;
- res = matroska_parse_block(matroska, blocks[i].bin.data,
+ res = matroska_parse_block(matroska, blocks[i].bin.buf, blocks[i].bin.data,
blocks[i].bin.size, blocks[i].bin.pos,
cluster.timecode, blocks[i].duration,
is_keyframe, NULL, 0, 0, pos,
@@ -3688,10 +3707,10 @@ static int webm_clusters_start_with_keyframe(AVFormatContext *s)
matroska->current_id = 0;
matroska_clear_queue(matroska);
if (matroska_parse_cluster(matroska) < 0 ||
- matroska->num_packets <= 0) {
+ !matroska->queue) {
break;
}
- pkt = matroska->packets[0];
+ pkt = &matroska->queue->pkt;
cluster_pos += cluster_length + 12; // 12 is the offset of the cluster id and length.
if (!(pkt->flags & AV_PKT_FLAG_KEY)) {
rv = 0;
diff --git a/chromium/third_party/ffmpeg/libavformat/mov.c b/chromium/third_party/ffmpeg/libavformat/mov.c
index abac7fe9bc4..64ed293a7c3 100644
--- a/chromium/third_party/ffmpeg/libavformat/mov.c
+++ b/chromium/third_party/ffmpeg/libavformat/mov.c
@@ -412,7 +412,11 @@ retry:
int ret = mov_read_covr(c, pb, data_type, str_size);
if (ret < 0) {
av_log(c->fc, AV_LOG_ERROR, "Error parsing cover art.\n");
+ return ret;
}
+ atom.size -= str_size;
+ if (atom.size > 8)
+ goto retry;
return ret;
} else if (!key && c->found_hdlr_mdta && c->meta_keys) {
uint32_t index = AV_RB32(&atom.type);
@@ -1326,6 +1330,7 @@ static int update_frag_index(MOVContext *c, int64_t offset)
frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE;
frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE;
frag_stream_info[i].index_entry = -1;
+ frag_stream_info[i].encryption_index = NULL;
}
if (index < c->frag_index.nb_items)
@@ -2614,6 +2619,12 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return mov_finalize_stsd_codec(c, pb, st, sc);
fail:
+ if (sc->extradata) {
+ int j;
+ for (j = 0; j < sc->stsd_count; j++)
+ av_freep(&sc->extradata[j]);
+ }
+
av_freep(&sc->extradata);
av_freep(&sc->extradata_size);
return ret;
@@ -3282,7 +3293,7 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns
FFMAX(min_size_needed, 2 * (*allocated_size)) :
min_size_needed;
- if((unsigned)(*ctts_count) + 1 >= UINT_MAX / sizeof(MOVStts))
+ if((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVStts) - 1)
return -1;
ctts_buf_new = av_fast_realloc(*ctts_data, allocated_size, requested_size);
@@ -4623,7 +4634,7 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR_INVALIDDATA;
}
sc = st->priv_data;
- if (sc->pseudo_stream_id + 1 != frag->stsd_id)
+ if (sc->pseudo_stream_id + 1 != frag->stsd_id && sc->pseudo_stream_id != -1)
return 0;
version = avio_r8(pb);
avio_rb24(pb); /* flags */
@@ -5781,115 +5792,475 @@ static int mov_read_frma(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
-static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+/**
+ * Gets the current encryption info and associated current stream context. If
+ * we are parsing a track fragment, this will return the specific encryption
+ * info for this fragment; otherwise this will return the global encryption
+ * info for the current stream.
+ */
+static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encryption_index, MOVStreamContext **sc)
{
+ MOVFragmentStreamInfo *frag_stream_info;
AVStream *st;
- MOVStreamContext *sc;
- size_t auxiliary_info_size;
+ int i;
- if (c->decryption_key_len == 0 || c->fc->nb_streams < 1)
- return 0;
+ frag_stream_info = get_current_frag_stream_info(&c->frag_index);
+ if (frag_stream_info) {
+ for (i = 0; i < c->fc->nb_streams; i++) {
+ if (c->fc->streams[i]->id == frag_stream_info->id) {
+ st = c->fc->streams[i];
+ break;
+ }
+ }
+ if (i == c->fc->nb_streams)
+ return 0;
+ *sc = st->priv_data;
- st = c->fc->streams[c->fc->nb_streams - 1];
- sc = st->priv_data;
+ if (!frag_stream_info->encryption_index) {
+ frag_stream_info->encryption_index = av_mallocz(sizeof(*frag_stream_info->encryption_index));
+ if (!frag_stream_info->encryption_index)
+ return AVERROR(ENOMEM);
+ }
+ *encryption_index = frag_stream_info->encryption_index;
+ return 1;
+ } else {
+ // No current track fragment, using stream level encryption info.
- if (sc->cenc.aes_ctr) {
- av_log(c->fc, AV_LOG_ERROR, "duplicate senc atom\n");
- return AVERROR_INVALIDDATA;
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams - 1];
+ *sc = st->priv_data;
+
+ if (!(*sc)->cenc.encryption_index) {
+ (*sc)->cenc.encryption_index = av_mallocz(sizeof(*frag_stream_info->encryption_index));
+ if (!(*sc)->cenc.encryption_index)
+ return AVERROR(ENOMEM);
+ }
+
+ *encryption_index = (*sc)->cenc.encryption_index;
+ return 1;
+ }
+}
+
+static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVStreamContext *sc, AVEncryptionInfo **sample, int use_subsamples)
+{
+ int i;
+ unsigned int subsample_count;
+ AVSubsampleEncryptionInfo *subsamples;
+
+ *sample = av_encryption_info_clone(sc->cenc.default_encrypted_sample);
+ if (!*sample)
+ return AVERROR(ENOMEM);
+
+ if (sc->cenc.per_sample_iv_size != 0) {
+ if (avio_read(pb, (*sample)->iv, sc->cenc.per_sample_iv_size) != sc->cenc.per_sample_iv_size) {
+ av_log(c->fc, AV_LOG_ERROR, "failed to read the initialization vector\n");
+ av_encryption_info_free(*sample);
+ *sample = NULL;
+ return AVERROR_INVALIDDATA;
+ }
+ }
+
+ if (use_subsamples) {
+ subsample_count = avio_rb16(pb);
+ av_free((*sample)->subsamples);
+ (*sample)->subsamples = av_mallocz_array(subsample_count, sizeof(*subsamples));
+ if (!(*sample)->subsamples) {
+ av_encryption_info_free(*sample);
+ *sample = NULL;
+ return AVERROR(ENOMEM);
+ }
+
+ for (i = 0; i < subsample_count && !pb->eof_reached; i++) {
+ (*sample)->subsamples[i].bytes_of_clear_data = avio_rb16(pb);
+ (*sample)->subsamples[i].bytes_of_protected_data = avio_rb32(pb);
+ }
+
+ if (pb->eof_reached) {
+ av_log(c->fc, AV_LOG_ERROR, "hit EOF while reading sub-sample encryption info\n");
+ av_encryption_info_free(*sample);
+ *sample = NULL;
+ return AVERROR_INVALIDDATA;
+ }
+ (*sample)->subsample_count = subsample_count;
+ }
+
+ return 0;
+}
+
+static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ AVEncryptionInfo **encrypted_samples;
+ MOVEncryptionIndex *encryption_index;
+ MOVStreamContext *sc;
+ int use_subsamples, ret;
+ unsigned int sample_count, i, alloc_size = 0;
+
+ ret = get_current_encryption_info(c, &encryption_index, &sc);
+ if (ret != 1)
+ return ret;
+
+ if (encryption_index->nb_encrypted_samples) {
+ // This can happen if we have both saio/saiz and senc atoms.
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in senc\n");
+ return 0;
}
avio_r8(pb); /* version */
- sc->cenc.use_subsamples = avio_rb24(pb) & 0x02; /* flags */
+ use_subsamples = avio_rb24(pb) & 0x02; /* flags */
- avio_rb32(pb); /* entries */
+ sample_count = avio_rb32(pb);
+ if (sample_count >= INT_MAX / sizeof(*encrypted_samples))
+ return AVERROR(ENOMEM);
- if (atom.size < 8 || atom.size > FFMIN(INT_MAX, SIZE_MAX)) {
- av_log(c->fc, AV_LOG_ERROR, "senc atom size %"PRId64" invalid\n", atom.size);
- return AVERROR_INVALIDDATA;
+ for (i = 0; i < sample_count; i++) {
+ unsigned int min_samples = FFMIN(FFMAX(i + 1, 1024 * 1024), sample_count);
+ encrypted_samples = av_fast_realloc(encryption_index->encrypted_samples, &alloc_size,
+ min_samples * sizeof(*encrypted_samples));
+ if (encrypted_samples) {
+ encryption_index->encrypted_samples = encrypted_samples;
+
+ ret = mov_read_sample_encryption_info(
+ c, pb, sc, &encryption_index->encrypted_samples[i], use_subsamples);
+ } else {
+ ret = AVERROR(ENOMEM);
+ }
+ if (pb->eof_reached) {
+ av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading senc\n");
+ ret = AVERROR_INVALIDDATA;
+ }
+
+ if (ret < 0) {
+ for (; i > 0; i--)
+ av_encryption_info_free(encryption_index->encrypted_samples[i - 1]);
+ av_freep(&encryption_index->encrypted_samples);
+ return ret;
+ }
}
+ encryption_index->nb_encrypted_samples = sample_count;
- /* save the auxiliary info as is */
- auxiliary_info_size = atom.size - 8;
+ return 0;
+}
- sc->cenc.auxiliary_info = av_malloc(auxiliary_info_size);
- if (!sc->cenc.auxiliary_info) {
+static int mov_parse_auxiliary_info(MOVContext *c, MOVStreamContext *sc, AVIOContext *pb, MOVEncryptionIndex *encryption_index)
+{
+ AVEncryptionInfo **sample, **encrypted_samples;
+ int64_t prev_pos;
+ size_t sample_count, sample_info_size, i;
+ int ret = 0;
+ unsigned int alloc_size = 0;
+
+ if (encryption_index->nb_encrypted_samples)
+ return 0;
+ sample_count = encryption_index->auxiliary_info_sample_count;
+ if (encryption_index->auxiliary_offsets_count != 1) {
+ av_log(c->fc, AV_LOG_ERROR, "Multiple auxiliary info chunks are not supported\n");
+ return AVERROR_PATCHWELCOME;
+ }
+ if (sample_count >= INT_MAX / sizeof(*encrypted_samples))
return AVERROR(ENOMEM);
+
+ prev_pos = avio_tell(pb);
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) ||
+ avio_seek(pb, encryption_index->auxiliary_offsets[0], SEEK_SET) != encryption_index->auxiliary_offsets[0]) {
+ av_log(c->fc, AV_LOG_INFO, "Failed to seek for auxiliary info, will only parse senc atoms for encryption info\n");
+ goto finish;
}
- sc->cenc.auxiliary_info_end = sc->cenc.auxiliary_info + auxiliary_info_size;
- sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info;
- sc->cenc.auxiliary_info_index = 0;
+ for (i = 0; i < sample_count && !pb->eof_reached; i++) {
+ unsigned int min_samples = FFMIN(FFMAX(i + 1, 1024 * 1024), sample_count);
+ encrypted_samples = av_fast_realloc(encryption_index->encrypted_samples, &alloc_size,
+ min_samples * sizeof(*encrypted_samples));
+ if (!encrypted_samples) {
+ ret = AVERROR(ENOMEM);
+ goto finish;
+ }
+ encryption_index->encrypted_samples = encrypted_samples;
- if (avio_read(pb, sc->cenc.auxiliary_info, auxiliary_info_size) != auxiliary_info_size) {
- av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info");
- return AVERROR_INVALIDDATA;
+ sample = &encryption_index->encrypted_samples[i];
+ sample_info_size = encryption_index->auxiliary_info_default_size
+ ? encryption_index->auxiliary_info_default_size
+ : encryption_index->auxiliary_info_sizes[i];
+
+ ret = mov_read_sample_encryption_info(c, pb, sc, sample, sample_info_size > sc->cenc.per_sample_iv_size);
+ if (ret < 0)
+ goto finish;
+ }
+ if (pb->eof_reached) {
+ av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading auxiliary info\n");
+ ret = AVERROR_INVALIDDATA;
+ } else {
+ encryption_index->nb_encrypted_samples = sample_count;
}
- /* initialize the cipher */
- sc->cenc.aes_ctr = av_aes_ctr_alloc();
- if (!sc->cenc.aes_ctr) {
- return AVERROR(ENOMEM);
+finish:
+ avio_seek(pb, prev_pos, SEEK_SET);
+ if (ret < 0) {
+ for (; i > 0; i--) {
+ av_encryption_info_free(encryption_index->encrypted_samples[i - 1]);
+ }
+ av_freep(&encryption_index->encrypted_samples);
+ }
+ return ret;
+}
+
+/**
+ * Tries to read the given number of bytes from the stream and puts it in a
+ * newly allocated buffer. This reads in small chunks to avoid allocating large
+ * memory if the file contains an invalid/malicious size value.
+ */
+static int mov_try_read_block(AVIOContext *pb, size_t size, uint8_t **data)
+{
+ const unsigned int block_size = 1024 * 1024;
+ uint8_t *buffer = NULL;
+ unsigned int alloc_size = 0, offset = 0;
+ while (offset < size) {
+ unsigned int new_size =
+ alloc_size >= INT_MAX - block_size ? INT_MAX : alloc_size + block_size;
+ uint8_t *new_buffer = av_fast_realloc(buffer, &alloc_size, new_size);
+ unsigned int to_read = FFMIN(size, alloc_size) - offset;
+ if (!new_buffer) {
+ av_free(buffer);
+ return AVERROR(ENOMEM);
+ }
+ buffer = new_buffer;
+
+ if (avio_read(pb, buffer + offset, to_read) != to_read) {
+ av_free(buffer);
+ return AVERROR_INVALIDDATA;
+ }
+ offset += to_read;
}
- return av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
+ *data = buffer;
+ return 0;
}
static int mov_read_saiz(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
- AVStream *st;
+ MOVEncryptionIndex *encryption_index;
MOVStreamContext *sc;
- size_t data_size;
- int atom_header_size;
- int flags;
+ int ret;
+ unsigned int sample_count;
- if (c->decryption_key_len == 0 || c->fc->nb_streams < 1)
- return 0;
+ ret = get_current_encryption_info(c, &encryption_index, &sc);
+ if (ret != 1)
+ return ret;
- st = c->fc->streams[c->fc->nb_streams - 1];
- sc = st->priv_data;
+ if (encryption_index->nb_encrypted_samples) {
+ // This can happen if we have both saio/saiz and senc atoms.
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in saiz\n");
+ return 0;
+ }
- if (sc->cenc.auxiliary_info_sizes || sc->cenc.auxiliary_info_default_size) {
- av_log(c->fc, AV_LOG_ERROR, "duplicate saiz atom\n");
+ if (encryption_index->auxiliary_info_sample_count) {
+ av_log(c->fc, AV_LOG_ERROR, "Duplicate saiz atom\n");
return AVERROR_INVALIDDATA;
}
- atom_header_size = 9;
-
avio_r8(pb); /* version */
- flags = avio_rb24(pb);
+ if (avio_rb24(pb) & 0x01) { /* flags */
+ if (avio_rb32(pb) != sc->cenc.default_encrypted_sample->scheme) {
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring saiz box with non-zero aux_info_type\n");
+ return 0;
+ }
+ if (avio_rb32(pb) != 0) {
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring saiz box with non-zero aux_info_type_parameter\n");
+ return 0;
+ }
+ }
- if ((flags & 0x01) != 0) {
- atom_header_size += 8;
+ encryption_index->auxiliary_info_default_size = avio_r8(pb);
+ sample_count = avio_rb32(pb);
+ encryption_index->auxiliary_info_sample_count = sample_count;
- avio_rb32(pb); /* info type */
- avio_rb32(pb); /* info type param */
+ if (encryption_index->auxiliary_info_default_size == 0) {
+ ret = mov_try_read_block(pb, sample_count, &encryption_index->auxiliary_info_sizes);
+ if (ret < 0) {
+ av_log(c->fc, AV_LOG_ERROR, "Failed to read the auxiliary info\n");
+ return ret;
+ }
}
- sc->cenc.auxiliary_info_default_size = avio_r8(pb);
- avio_rb32(pb); /* entries */
+ if (encryption_index->auxiliary_offsets_count) {
+ return mov_parse_auxiliary_info(c, sc, pb, encryption_index);
+ }
+
+ return 0;
+}
- if (atom.size <= atom_header_size) {
+static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ uint64_t *auxiliary_offsets;
+ MOVEncryptionIndex *encryption_index;
+ MOVStreamContext *sc;
+ int i, ret;
+ unsigned int version, entry_count, alloc_size = 0;
+
+ ret = get_current_encryption_info(c, &encryption_index, &sc);
+ if (ret != 1)
+ return ret;
+
+ if (encryption_index->nb_encrypted_samples) {
+ // This can happen if we have both saio/saiz and senc atoms.
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in saio\n");
return 0;
}
- if (atom.size > FFMIN(INT_MAX, SIZE_MAX)) {
- av_log(c->fc, AV_LOG_ERROR, "saiz atom auxiliary_info_sizes size %"PRId64" invalid\n", atom.size);
+ if (encryption_index->auxiliary_offsets_count) {
+ av_log(c->fc, AV_LOG_ERROR, "Duplicate saio atom\n");
return AVERROR_INVALIDDATA;
}
- /* save the auxiliary info sizes as is */
- data_size = atom.size - atom_header_size;
+ version = avio_r8(pb); /* version */
+ if (avio_rb24(pb) & 0x01) { /* flags */
+ if (avio_rb32(pb) != sc->cenc.default_encrypted_sample->scheme) {
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring saio box with non-zero aux_info_type\n");
+ return 0;
+ }
+ if (avio_rb32(pb) != 0) {
+ av_log(c->fc, AV_LOG_DEBUG, "Ignoring saio box with non-zero aux_info_type_parameter\n");
+ return 0;
+ }
+ }
- sc->cenc.auxiliary_info_sizes = av_malloc(data_size);
- if (!sc->cenc.auxiliary_info_sizes) {
+ entry_count = avio_rb32(pb);
+ if (entry_count >= INT_MAX / sizeof(*auxiliary_offsets))
return AVERROR(ENOMEM);
+
+ for (i = 0; i < entry_count && !pb->eof_reached; i++) {
+ unsigned int min_offsets = FFMIN(FFMAX(i + 1, 1024), entry_count);
+ auxiliary_offsets = av_fast_realloc(
+ encryption_index->auxiliary_offsets, &alloc_size,
+ min_offsets * sizeof(*auxiliary_offsets));
+ if (!auxiliary_offsets) {
+ av_freep(&encryption_index->auxiliary_offsets);
+ return AVERROR(ENOMEM);
+ }
+ encryption_index->auxiliary_offsets = auxiliary_offsets;
+
+ if (version == 0) {
+ encryption_index->auxiliary_offsets[i] = avio_rb32(pb);
+ } else {
+ encryption_index->auxiliary_offsets[i] = avio_rb64(pb);
+ }
+ if (c->frag_index.current >= 0) {
+ encryption_index->auxiliary_offsets[i] += c->fragment.base_data_offset;
+ }
+ }
+
+ if (pb->eof_reached) {
+ av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading saio\n");
+ av_freep(&encryption_index->auxiliary_offsets);
+ return AVERROR_INVALIDDATA;
}
- sc->cenc.auxiliary_info_sizes_count = data_size;
+ encryption_index->auxiliary_offsets_count = entry_count;
- if (avio_read(pb, sc->cenc.auxiliary_info_sizes, data_size) != data_size) {
- av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info sizes");
+ if (encryption_index->auxiliary_info_sample_count) {
+ return mov_parse_auxiliary_info(c, sc, pb, encryption_index);
+ }
+
+ return 0;
+}
+
+static int mov_read_schm(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ MOVStreamContext *sc;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+ sc = st->priv_data;
+
+ if (sc->pseudo_stream_id != 0) {
+ av_log(c->fc, AV_LOG_ERROR, "schm boxes are only supported in first sample descriptor\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (atom.size < 8)
return AVERROR_INVALIDDATA;
+
+ avio_rb32(pb); /* version and flags */
+
+ if (!sc->cenc.default_encrypted_sample) {
+ sc->cenc.default_encrypted_sample = av_encryption_info_alloc(0, 16, 16);
+ if (!sc->cenc.default_encrypted_sample) {
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ sc->cenc.default_encrypted_sample->scheme = avio_rb32(pb);
+ return 0;
+}
+
+static int mov_read_tenc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ AVStream *st;
+ MOVStreamContext *sc;
+ unsigned int version, pattern, is_protected, iv_size;
+
+ if (c->fc->nb_streams < 1)
+ return 0;
+ st = c->fc->streams[c->fc->nb_streams-1];
+ sc = st->priv_data;
+
+ if (sc->pseudo_stream_id != 0) {
+ av_log(c->fc, AV_LOG_ERROR, "tenc atom are only supported in first sample descriptor\n");
+ return AVERROR_PATCHWELCOME;
+ }
+
+ if (!sc->cenc.default_encrypted_sample) {
+ sc->cenc.default_encrypted_sample = av_encryption_info_alloc(0, 16, 16);
+ if (!sc->cenc.default_encrypted_sample) {
+ return AVERROR(ENOMEM);
+ }
+ }
+
+ if (atom.size < 20)
+ return AVERROR_INVALIDDATA;
+
+ version = avio_r8(pb); /* version */
+ avio_rb24(pb); /* flags */
+
+ avio_r8(pb); /* reserved */
+ pattern = avio_r8(pb);
+
+ if (version > 0) {
+ sc->cenc.default_encrypted_sample->crypt_byte_block = pattern >> 4;
+ sc->cenc.default_encrypted_sample->skip_byte_block = pattern & 0xf;
+ }
+
+ is_protected = avio_r8(pb);
+ if (is_protected && !sc->cenc.encryption_index) {
+ // The whole stream should be by-default encrypted.
+ sc->cenc.encryption_index = av_mallocz(sizeof(MOVEncryptionIndex));
+ if (!sc->cenc.encryption_index)
+ return AVERROR(ENOMEM);
+ }
+ sc->cenc.per_sample_iv_size = avio_r8(pb);
+ if (sc->cenc.per_sample_iv_size != 0 && sc->cenc.per_sample_iv_size != 8 &&
+ sc->cenc.per_sample_iv_size != 16) {
+ av_log(c->fc, AV_LOG_ERROR, "invalid per-sample IV size value\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (avio_read(pb, sc->cenc.default_encrypted_sample->key_id, 16) != 16) {
+ av_log(c->fc, AV_LOG_ERROR, "failed to read the default key ID\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (is_protected && !sc->cenc.per_sample_iv_size) {
+ iv_size = avio_r8(pb);
+ if (iv_size != 8 && iv_size != 16) {
+ av_log(c->fc, AV_LOG_ERROR, "invalid default_constant_IV_size in tenc atom\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (avio_read(pb, sc->cenc.default_encrypted_sample->iv, iv_size) != iv_size) {
+ av_log(c->fc, AV_LOG_ERROR, "failed to read the default IV\n");
+ return AVERROR_INVALIDDATA;
+ }
}
return 0;
@@ -5932,108 +6303,114 @@ static int mov_read_dfla(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
-static int mov_seek_auxiliary_info(MOVContext *c, MOVStreamContext *sc, int64_t index)
+static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size)
{
- size_t auxiliary_info_seek_offset = 0;
- int i;
-
- if (sc->cenc.auxiliary_info_default_size) {
- auxiliary_info_seek_offset = (size_t)sc->cenc.auxiliary_info_default_size * index;
- } else if (sc->cenc.auxiliary_info_sizes) {
- if (index > sc->cenc.auxiliary_info_sizes_count) {
- av_log(c, AV_LOG_ERROR, "current sample %"PRId64" greater than the number of auxiliary info sample sizes %"SIZE_SPECIFIER"\n",
- index, sc->cenc.auxiliary_info_sizes_count);
- return AVERROR_INVALIDDATA;
- }
-
- for (i = 0; i < index; i++) {
- auxiliary_info_seek_offset += sc->cenc.auxiliary_info_sizes[i];
- }
- }
+ int i, ret;
- if (auxiliary_info_seek_offset > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info) {
- av_log(c, AV_LOG_ERROR, "auxiliary info offset %"SIZE_SPECIFIER" greater than auxiliary info size %"SIZE_SPECIFIER"\n",
- auxiliary_info_seek_offset, (size_t)(sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info));
- return AVERROR_INVALIDDATA;
+ if (sample->scheme != MKBETAG('c','e','n','c') || sample->crypt_byte_block != 0 || sample->skip_byte_block != 0) {
+ av_log(c->fc, AV_LOG_ERROR, "Only the 'cenc' encryption scheme is supported\n");
+ return AVERROR_PATCHWELCOME;
}
- sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info + auxiliary_info_seek_offset;
- sc->cenc.auxiliary_info_index = index;
- return 0;
-}
-
-static int cenc_filter(MOVContext *c, MOVStreamContext *sc, int64_t index, uint8_t *input, int size)
-{
- uint32_t encrypted_bytes;
- uint16_t subsample_count;
- uint16_t clear_bytes;
- uint8_t* input_end = input + size;
- int ret;
+ if (!sc->cenc.aes_ctr) {
+ /* initialize the cipher */
+ sc->cenc.aes_ctr = av_aes_ctr_alloc();
+ if (!sc->cenc.aes_ctr) {
+ return AVERROR(ENOMEM);
+ }
- if (index != sc->cenc.auxiliary_info_index) {
- ret = mov_seek_auxiliary_info(c, sc, index);
+ ret = av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key);
if (ret < 0) {
return ret;
}
}
- /* read the iv */
- if (AES_CTR_IV_SIZE > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
- av_log(c->fc, AV_LOG_ERROR, "failed to read iv from the auxiliary info\n");
- return AVERROR_INVALIDDATA;
- }
-
- av_aes_ctr_set_iv(sc->cenc.aes_ctr, sc->cenc.auxiliary_info_pos);
- sc->cenc.auxiliary_info_pos += AES_CTR_IV_SIZE;
+ av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv);
- if (!sc->cenc.use_subsamples)
+ if (!sample->subsample_count)
{
/* decrypt the whole packet */
av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size);
return 0;
}
- /* read the subsample count */
- if (sizeof(uint16_t) > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
- av_log(c->fc, AV_LOG_ERROR, "failed to read subsample count from the auxiliary info\n");
- return AVERROR_INVALIDDATA;
- }
-
- subsample_count = AV_RB16(sc->cenc.auxiliary_info_pos);
- sc->cenc.auxiliary_info_pos += sizeof(uint16_t);
-
- for (; subsample_count > 0; subsample_count--)
+ for (i = 0; i < sample->subsample_count; i++)
{
- if (6 > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) {
- av_log(c->fc, AV_LOG_ERROR, "failed to read subsample from the auxiliary info\n");
- return AVERROR_INVALIDDATA;
- }
-
- /* read the number of clear / encrypted bytes */
- clear_bytes = AV_RB16(sc->cenc.auxiliary_info_pos);
- sc->cenc.auxiliary_info_pos += sizeof(uint16_t);
- encrypted_bytes = AV_RB32(sc->cenc.auxiliary_info_pos);
- sc->cenc.auxiliary_info_pos += sizeof(uint32_t);
-
- if ((uint64_t)clear_bytes + encrypted_bytes > input_end - input) {
+ if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) {
av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n");
return AVERROR_INVALIDDATA;
}
/* skip the clear bytes */
- input += clear_bytes;
+ input += sample->subsamples[i].bytes_of_clear_data;
+ size -= sample->subsamples[i].bytes_of_clear_data;
/* decrypt the encrypted bytes */
- av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, encrypted_bytes);
- input += encrypted_bytes;
+ av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, sample->subsamples[i].bytes_of_protected_data);
+ input += sample->subsamples[i].bytes_of_protected_data;
+ size -= sample->subsamples[i].bytes_of_protected_data;
}
- if (input < input_end) {
+ if (size > 0) {
av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n");
return AVERROR_INVALIDDATA;
}
- sc->cenc.auxiliary_info_index++;
+ return 0;
+}
+
+static int cenc_filter(MOVContext *mov, MOVStreamContext *sc, AVPacket *pkt, int current_index)
+{
+ MOVFragmentStreamInfo *frag_stream_info;
+ MOVEncryptionIndex *encryption_index;
+ AVEncryptionInfo *encrypted_sample;
+ int encrypted_index;
+
+ frag_stream_info = get_current_frag_stream_info(&mov->frag_index);
+ encrypted_index = current_index;
+ encryption_index = NULL;
+ if (frag_stream_info) {
+ // Note this only supports encryption info in the first sample descriptor.
+ if (mov->fragment.stsd_id == 1) {
+ if (frag_stream_info->encryption_index) {
+ encrypted_index = current_index - frag_stream_info->index_entry;
+ encryption_index = frag_stream_info->encryption_index;
+ } else {
+ encryption_index = sc->cenc.encryption_index;
+ }
+ }
+ } else {
+ encryption_index = sc->cenc.encryption_index;
+ }
+
+ if (encryption_index) {
+ if (encryption_index->auxiliary_info_sample_count &&
+ !encryption_index->nb_encrypted_samples) {
+ av_log(mov->fc, AV_LOG_ERROR, "saiz atom found without saio\n");
+ return AVERROR_INVALIDDATA;
+ }
+ if (encryption_index->auxiliary_offsets_count &&
+ !encryption_index->nb_encrypted_samples) {
+ av_log(mov->fc, AV_LOG_ERROR, "saio atom found without saiz\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ if (!encryption_index->nb_encrypted_samples) {
+ // Full-sample encryption with default settings.
+ encrypted_sample = sc->cenc.default_encrypted_sample;
+ } else if (encrypted_index >= 0 && encrypted_index < encryption_index->nb_encrypted_samples) {
+ // 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;
+ }
+
+ if (mov->decryption_key) {
+ return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size);
+ }
+ }
+
return 0;
}
@@ -6163,6 +6540,10 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('f','r','m','a'), mov_read_frma },
{ MKTAG('s','e','n','c'), mov_read_senc },
{ MKTAG('s','a','i','z'), mov_read_saiz },
+{ MKTAG('s','a','i','o'), mov_read_saio },
+{ MKTAG('s','c','h','m'), mov_read_schm },
+{ MKTAG('s','c','h','i'), mov_read_default },
+{ MKTAG('t','e','n','c'), mov_read_tenc },
{ MKTAG('d','f','L','a'), mov_read_dfla },
{ MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */
{ MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */
@@ -6548,6 +6929,18 @@ static int mov_read_timecode_track(AVFormatContext *s, AVStream *st)
return 0;
}
+static void mov_free_encryption_index(MOVEncryptionIndex **index) {
+ int i;
+ if (!index || !*index) return;
+ for (i = 0; i < (*index)->nb_encrypted_samples; i++) {
+ av_encryption_info_free((*index)->encrypted_samples[i]);
+ }
+ av_freep(&(*index)->encrypted_samples);
+ av_freep(&(*index)->auxiliary_info_sizes);
+ av_freep(&(*index)->auxiliary_offsets);
+ av_freep(index);
+}
+
static int mov_read_close(AVFormatContext *s)
{
MOVContext *mov = s->priv_data;
@@ -6590,8 +6983,8 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&sc->extradata);
av_freep(&sc->extradata_size);
- av_freep(&sc->cenc.auxiliary_info);
- av_freep(&sc->cenc.auxiliary_info_sizes);
+ mov_free_encryption_index(&sc->cenc.encryption_index);
+ av_encryption_info_free(sc->cenc.default_encrypted_sample);
av_aes_ctr_free(sc->cenc.aes_ctr);
av_freep(&sc->stereo3d);
@@ -6616,6 +7009,10 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&mov->bitrates);
for (i = 0; i < mov->frag_index.nb_items; i++) {
+ MOVFragmentStreamInfo *frag = mov->frag_index.item[i].stream_info;
+ for (j = 0; j < mov->frag_index.item[i].nb_stream_info; j++) {
+ mov_free_encryption_index(&frag[j].encryption_index);
+ }
av_freep(&mov->frag_index.item[i].stream_info);
}
av_freep(&mov->frag_index.item);
@@ -7186,12 +7583,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
if (mov->aax_mode)
aax_filter(pkt->data, pkt->size, mov);
- if (sc->cenc.aes_ctr) {
- ret = cenc_filter(mov, sc, current_index, pkt->data, pkt->size);
- if (ret) {
- return ret;
- }
- }
+ ret = cenc_filter(mov, sc, pkt, current_index);
+ if (ret < 0)
+ return ret;
return 0;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.c b/chromium/third_party/ffmpeg/libavformat/movenc.c
index 5b1e66c8973..0b44fd66ea1 100644
--- a/chromium/third_party/ffmpeg/libavformat/movenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/movenc.c
@@ -140,6 +140,15 @@ static int co64_required(const MOVTrack *track)
return 0;
}
+static int rtp_hinting_needed(const AVStream *st)
+{
+ /* Add hint tracks for each real audio and video stream */
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ return 0;
+ return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
+ st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
+}
+
/* Chunk offset atom */
static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
{
@@ -491,10 +500,7 @@ concatenate:
if (info->num_blocks != 6)
goto end;
av_packet_unref(pkt);
- ret = av_packet_ref(pkt, &info->pkt);
- if (ret < 0)
- goto end;
- av_packet_unref(&info->pkt);
+ av_packet_move_ref(pkt, &info->pkt);
info->num_blocks = 0;
}
ret = pkt->size;
@@ -3027,7 +3033,7 @@ static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
if (ret < 0)
return ret;
- if (mov->mode & MODE_MP4)
+ if (mov->mode & (MODE_MP4|MODE_MOV))
mov_write_track_metadata(pb_buf, st, "name", "title");
if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) {
@@ -3416,6 +3422,51 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
return size;
}
+static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
+{
+ MOVMuxContext *mov = s->priv_data;
+ int64_t pos = 0;
+ int i, type;
+
+ for (i = 0; i < s->nb_streams; i++) {
+ MOVTrack *trk = &mov->tracks[i];
+ AVStream *st = s->streams[i];
+
+ if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC) ||
+ trk->cover_image.size <= 0)
+ continue;
+
+ switch (st->codecpar->codec_id) {
+ case AV_CODEC_ID_MJPEG:
+ type = 0xD;
+ break;
+ case AV_CODEC_ID_PNG:
+ type = 0xE;
+ break;
+ case AV_CODEC_ID_BMP:
+ type = 0x1B;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "unsupported codec_id (0x%x) for cover",
+ st->codecpar->codec_id);
+ continue;
+ }
+
+ if (!pos) {
+ pos = avio_tell(pb);
+ avio_wb32(pb, 0);
+ ffio_wfourcc(pb, "covr");
+ }
+ avio_wb32(pb, 16 + trk->cover_image.size);
+ ffio_wfourcc(pb, "data");
+ avio_wb32(pb, type);
+ avio_wb32(pb , 0);
+ avio_write(pb, trk->cover_image.data, trk->cover_image.size);
+ }
+
+ return pos ? update_size(pb, pos) : 0;
+}
+
/* iTunes meta data list */
static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
AVFormatContext *s)
@@ -3435,7 +3486,7 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
}
mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
- mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1);
+ mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
mov_write_string_metadata(s, pb, "desc", "description",1);
@@ -3450,6 +3501,7 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
+ mov_write_covr(pb, s);
mov_write_trkn_tag(pb, mov, s, 0); // track number
mov_write_trkn_tag(pb, mov, s, 1); // disc number
mov_write_tmpo_tag(pb, s);
@@ -3947,6 +3999,8 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat
} else {
continue;
}
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ continue;
props = (AVCPBProperties*)av_stream_get_side_data(track->st, AV_PKT_DATA_CPB_PROPERTIES, NULL);
@@ -4560,6 +4614,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ continue;
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
has_video = 1;
if (st->codecpar->codec_id == AV_CODEC_ID_H264)
@@ -4708,6 +4764,8 @@ static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
for (i = 0; i < s->nb_streams; i++) {
AVStream *st = s->streams[i];
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC)
+ continue;
if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
video_streams_nb++;
else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
@@ -4897,7 +4955,8 @@ static int mov_flush_fragment(AVFormatContext *s, int force)
int buf_size, moov_size;
for (i = 0; i < mov->nb_streams; i++)
- if (!mov->tracks[i].entry)
+ if (!mov->tracks[i].entry &&
+ (i >= s->nb_streams || !(s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC)))
break;
/* Don't write the initial moov unless all tracks have data */
if (i < mov->nb_streams && !force)
@@ -5476,13 +5535,34 @@ static int mov_write_subtitle_end_packet(AVFormatContext *s,
static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
{
+ MOVMuxContext *mov = s->priv_data;
+ MOVTrack *trk;
+ AVStream *st;
+
if (!pkt) {
mov_flush_fragment(s, 1);
return 1;
+ }
+
+ st = s->streams[pkt->stream_index];
+ trk = &mov->tracks[pkt->stream_index];
+
+ if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) {
+ int ret;
+
+ if (st->nb_frames >= 1) {
+ if (st->nb_frames == 1)
+ av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
+ " ignoring.\n", pkt->stream_index);
+ return 0;
+ }
+
+ if ((ret = av_packet_ref(&trk->cover_image, pkt)) < 0)
+ return ret;
+
+ return 0;
} else {
int i;
- MOVMuxContext *mov = s->priv_data;
- MOVTrack *trk = &mov->tracks[pkt->stream_index];
if (!pkt->size)
return mov_write_single_packet(s, pkt); /* Passthrough. */
@@ -5729,7 +5809,8 @@ static void enable_tracks(AVFormatContext *s)
AVStream *st = s->streams[i];
if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
- st->codecpar->codec_type >= AVMEDIA_TYPE_NB)
+ st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
+ st->disposition & AV_DISPOSITION_ATTACHED_PIC)
continue;
if (first[st->codecpar->codec_type] < 0)
@@ -5772,6 +5853,7 @@ static void mov_free(AVFormatContext *s)
av_freep(&mov->tracks[i].par);
av_freep(&mov->tracks[i].cluster);
av_freep(&mov->tracks[i].frag_info);
+ av_packet_unref(&mov->tracks[i].cover_image);
if (mov->tracks[i].vos_len)
av_freep(&mov->tracks[i].vos_data);
@@ -5944,14 +6026,9 @@ static int mov_init(AVFormatContext *s)
mov->chapter_track = mov->nb_streams++;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
- /* Add hint tracks for each audio and video stream */
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ for (i = 0; i < s->nb_streams; i++)
+ if (rtp_hinting_needed(s->streams[i]))
mov->nb_streams++;
- }
- }
}
if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
@@ -6082,6 +6159,10 @@ static int mov_init(AVFormatContext *s)
av_log(s, AV_LOG_ERROR, "VP9 only supported in MP4.\n");
return AVERROR(EINVAL);
}
+ } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
+ /* spec is not finished, so forbid for now */
+ av_log(s, AV_LOG_ERROR, "AV1 muxing is currently not supported.\n");
+ return AVERROR_PATCHWELCOME;
} else if (track->par->codec_id == AV_CODEC_ID_VP8) {
/* altref frames handling is not defined in the spec as of version v1.0,
* so just forbid muxing VP8 streams altogether until a new version does */
@@ -6174,15 +6255,10 @@ static int mov_write_header(AVFormatContext *s)
nb_tracks++;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
- /* Add hint tracks for each audio and video stream */
hint_track = nb_tracks;
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ for (i = 0; i < s->nb_streams; i++)
+ if (rtp_hinting_needed(s->streams[i]))
nb_tracks++;
- }
- }
}
if (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
@@ -6260,11 +6336,8 @@ static int mov_write_header(AVFormatContext *s)
return ret;
if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
- /* Initialize the hint tracks for each audio and video stream */
for (i = 0; i < s->nb_streams; i++) {
- AVStream *st = s->streams[i];
- if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
- st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (rtp_hinting_needed(s->streams[i])) {
if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
return ret;
hint_track++;
diff --git a/chromium/third_party/ffmpeg/libavformat/movenc.h b/chromium/third_party/ffmpeg/libavformat/movenc.h
index ca2a9c97226..c9b4072fb9d 100644
--- a/chromium/third_party/ffmpeg/libavformat/movenc.h
+++ b/chromium/third_party/ffmpeg/libavformat/movenc.h
@@ -132,6 +132,7 @@ typedef struct MOVTrack {
uint32_t default_size;
HintSampleQueue sample_queue;
+ AVPacket cover_image;
AVIOContext *mdat_buf;
int64_t data_offset;
diff --git a/chromium/third_party/ffmpeg/libavformat/mp3enc.c b/chromium/third_party/ffmpeg/libavformat/mp3enc.c
index 8479e2485bb..dd662f5473c 100644
--- a/chromium/third_party/ffmpeg/libavformat/mp3enc.c
+++ b/chromium/third_party/ffmpeg/libavformat/mp3enc.c
@@ -369,20 +369,18 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt)
static int mp3_queue_flush(AVFormatContext *s)
{
MP3Context *mp3 = s->priv_data;
- AVPacketList *pktl;
+ AVPacket pkt;
int ret = 0, write = 1;
ff_id3v2_finish(&mp3->id3, s->pb, s->metadata_header_padding);
mp3_write_xing(s);
- while ((pktl = mp3->queue)) {
- if (write && (ret = mp3_write_audio_packet(s, &pktl->pkt)) < 0)
+ while (mp3->queue) {
+ ff_packet_list_get(&mp3->queue, &mp3->queue_end, &pkt);
+ if (write && (ret = mp3_write_audio_packet(s, &pkt)) < 0)
write = 0;
- av_packet_unref(&pktl->pkt);
- mp3->queue = pktl->next;
- av_freep(&pktl);
+ av_packet_unref(&pkt);
}
- mp3->queue_end = NULL;
return ret;
}
@@ -514,21 +512,14 @@ static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt)
if (pkt->stream_index == mp3->audio_stream_idx) {
if (mp3->pics_to_write) {
/* buffer audio packets until we get all the pictures */
- AVPacketList *pktl = av_mallocz(sizeof(*pktl));
+ int ret = ff_packet_list_put(&mp3->queue, &mp3->queue_end, pkt, FF_PACKETLIST_FLAG_REF_PACKET);
- if (!pktl || av_packet_ref(&pktl->pkt, pkt) < 0) {
- av_freep(&pktl);
+ if (ret < 0) {
av_log(s, AV_LOG_WARNING, "Not enough memory to buffer audio. Skipping picture streams\n");
mp3->pics_to_write = 0;
mp3_queue_flush(s);
return mp3_write_audio_packet(s, pkt);
}
-
- if (mp3->queue_end)
- mp3->queue_end->next = pktl;
- else
- mp3->queue = pktl;
- mp3->queue_end = pktl;
} else
return mp3_write_audio_packet(s, pkt);
} else {
diff --git a/chromium/third_party/ffmpeg/libavformat/mpc8.c b/chromium/third_party/ffmpeg/libavformat/mpc8.c
index f280faa5ccd..79e5f6a9ab6 100644
--- a/chromium/third_party/ffmpeg/libavformat/mpc8.c
+++ b/chromium/third_party/ffmpeg/libavformat/mpc8.c
@@ -297,7 +297,7 @@ static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt)
return 0;
}
if(tag == TAG_STREAMEND)
- return AVERROR(EIO);
+ return AVERROR_EOF;
mpc8_handle_chunk(s, tag, pos, size);
}
return AVERROR_EOF;
diff --git a/chromium/third_party/ffmpeg/libavformat/mpeg.c b/chromium/third_party/ffmpeg/libavformat/mpeg.c
index abdc6a937cb..8ae4740920b 100644
--- a/chromium/third_party/ffmpeg/libavformat/mpeg.c
+++ b/chromium/third_party/ffmpeg/libavformat/mpeg.c
@@ -20,6 +20,7 @@
*/
#include "avformat.h"
+#include "avio_internal.h"
#include "internal.h"
#include "mpeg.h"
@@ -128,6 +129,7 @@ typedef struct MpegDemuxContext {
int sofdec;
int dvd;
int imkh_cctv;
+ int raw_ac3;
#if CONFIG_VOBSUB_DEMUXER
AVFormatContext *sub_ctx;
FFDemuxSubtitlesQueue q[32];
@@ -442,8 +444,24 @@ redo:
}
if (startcode == PRIVATE_STREAM_1) {
+ int ret = ffio_ensure_seekback(s->pb, 2);
+
+ if (ret < 0)
+ return ret;
+
startcode = avio_r8(s->pb);
- len--;
+ m->raw_ac3 = 0;
+ if (startcode == 0x0b) {
+ if (avio_r8(s->pb) == 0x77) {
+ startcode = 0x80;
+ m->raw_ac3 = 1;
+ avio_skip(s->pb, -2);
+ } else {
+ avio_skip(s->pb, -1);
+ }
+ } else {
+ len--;
+ }
}
if (len < 0)
goto error_redo;
@@ -486,14 +504,16 @@ redo:
if (len < 4)
goto skip;
- /* audio: skip header */
- avio_r8(s->pb);
- lpcm_header_len = avio_rb16(s->pb);
- len -= 3;
- if (startcode >= 0xb0 && startcode <= 0xbf) {
- /* MLP/TrueHD audio has a 4-byte header */
+ if (!m->raw_ac3) {
+ /* audio: skip header */
avio_r8(s->pb);
- len--;
+ lpcm_header_len = avio_rb16(s->pb);
+ len -= 3;
+ if (startcode >= 0xb0 && startcode <= 0xbf) {
+ /* MLP/TrueHD audio has a 4-byte header */
+ avio_r8(s->pb);
+ len--;
+ }
}
}
@@ -568,7 +588,7 @@ redo:
codec_id = AV_CODEC_ID_DTS;
} else if (startcode >= 0xa0 && startcode <= 0xaf) {
type = AVMEDIA_TYPE_AUDIO;
- if (lpcm_header_len == 6 || startcode == 0xa1) {
+ if (lpcm_header_len >= 6 && startcode == 0xa1) {
codec_id = AV_CODEC_ID_MLP;
} else {
codec_id = AV_CODEC_ID_PCM_DVD;
diff --git a/chromium/third_party/ffmpeg/libavformat/options_table.h b/chromium/third_party/ffmpeg/libavformat/options_table.h
index b8fa47c6fd3..7c4d84798e1 100644
--- a/chromium/third_party/ffmpeg/libavformat/options_table.h
+++ b/chromium/third_party/ffmpeg/libavformat/options_table.h
@@ -54,10 +54,10 @@ static const AVOption avformat_options[] = {
{"fastseek", "fast but inaccurate seeks", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FAST_SEEK }, INT_MIN, INT_MAX, D, "fflags"},
{"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"},
{"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"},
-{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D},
{"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" },
{"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" },
{"autobsf", "add needed bsfs automatically", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_AUTO_BSF }, 0, 0, E, "fflags" },
+{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D},
{"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D},
{"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D},
{"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D},
diff --git a/chromium/third_party/ffmpeg/libavformat/os_support.c b/chromium/third_party/ffmpeg/libavformat/os_support.c
index 099d7b501f4..15cea7fa5b0 100644
--- a/chromium/third_party/ffmpeg/libavformat/os_support.c
+++ b/chromium/third_party/ffmpeg/libavformat/os_support.c
@@ -43,6 +43,7 @@
#include "network.h"
+#if !HAVE_GETADDRINFO
#if !HAVE_INET_ATON
#include <stdlib.h>
@@ -62,7 +63,6 @@ static int inet_aton(const char *str, struct in_addr *add)
}
#endif /* !HAVE_INET_ATON */
-#if !HAVE_GETADDRINFO
int ff_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res)
{
diff --git a/chromium/third_party/ffmpeg/libavformat/pcm.c b/chromium/third_party/ffmpeg/libavformat/pcm.c
index 806f91b6b13..767bbd045a9 100644
--- a/chromium/third_party/ffmpeg/libavformat/pcm.c
+++ b/chromium/third_party/ffmpeg/libavformat/pcm.c
@@ -28,13 +28,20 @@
int ff_pcm_read_packet(AVFormatContext *s, AVPacket *pkt)
{
+ AVCodecParameters *par = s->streams[0]->codecpar;
int ret, size;
- size= RAW_SAMPLES*s->streams[0]->codecpar->block_align;
- if (size <= 0)
+ if (par->block_align <= 0)
return AVERROR(EINVAL);
- ret= av_get_packet(s->pb, pkt, size);
+ /*
+ * Compute read size to complete a read every 62ms.
+ * Clamp to RAW_SAMPLES if larger.
+ */
+ size = FFMAX(par->sample_rate/25, 1);
+ size = FFMIN(size, RAW_SAMPLES) * par->block_align;
+
+ ret = av_get_packet(s->pb, pkt, size);
pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
pkt->stream_index = 0;
diff --git a/chromium/third_party/ffmpeg/libavformat/protocols.c b/chromium/third_party/ffmpeg/libavformat/protocols.c
index 669d74d5a86..ad95659795e 100644
--- a/chromium/third_party/ffmpeg/libavformat/protocols.c
+++ b/chromium/third_party/ffmpeg/libavformat/protocols.c
@@ -65,6 +65,7 @@ extern const URLProtocol ff_librtmpe_protocol;
extern const URLProtocol ff_librtmps_protocol;
extern const URLProtocol ff_librtmpt_protocol;
extern const URLProtocol ff_librtmpte_protocol;
+extern const URLProtocol ff_libsrt_protocol;
extern const URLProtocol ff_libssh_protocol;
extern const URLProtocol ff_libsmbclient_protocol;
diff --git a/chromium/third_party/ffmpeg/libavformat/rmdec.c b/chromium/third_party/ffmpeg/libavformat/rmdec.c
index fea71a2fc97..ac61723c66a 100644
--- a/chromium/third_party/ffmpeg/libavformat/rmdec.c
+++ b/chromium/third_party/ffmpeg/libavformat/rmdec.c
@@ -70,16 +70,10 @@ static int rm_read_close(AVFormatContext *s);
static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len)
{
- int i;
- char *q, r;
+ int read = avio_get_str(pb, len, buf, buf_size);
- q = buf;
- for(i=0;i<len;i++) {
- r = avio_r8(pb);
- if (i < buf_size - 1)
- *q++ = r;
- }
- if (buf_size > 0) *q = '\0';
+ if (read > 0)
+ avio_skip(pb, len - read);
}
static void get_str8(AVIOContext *pb, char *buf, int buf_size)
@@ -105,8 +99,10 @@ static void rm_read_metadata(AVFormatContext *s, AVIOContext *pb, int wide)
for (i=0; i<FF_ARRAY_ELEMS(ff_rm_metadata); i++) {
int len = wide ? avio_rb16(pb) : avio_r8(pb);
- get_strl(pb, buf, sizeof(buf), len);
- av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0);
+ if (len > 0) {
+ get_strl(pb, buf, sizeof(buf), len);
+ av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0);
+ }
}
}
diff --git a/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c b/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c
index f768fb002eb..e69fdc27cfb 100644
--- a/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c
+++ b/chromium/third_party/ffmpeg/libavformat/rtpenc_chain.c
@@ -101,7 +101,7 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s,
return 0;
fail:
- av_free(rtpctx);
+ avformat_free_context(rtpctx);
if (handle)
ffurl_close(handle);
return ret;
diff --git a/chromium/third_party/ffmpeg/libavformat/segafilm.c b/chromium/third_party/ffmpeg/libavformat/segafilm.c
index 1fdef50cc75..b0c6c419ced 100644
--- a/chromium/third_party/ffmpeg/libavformat/segafilm.c
+++ b/chromium/third_party/ffmpeg/libavformat/segafilm.c
@@ -239,7 +239,7 @@ static int film_read_header(AVFormatContext *s)
} else {
film->sample_table[i].stream = film->video_stream_index;
film->sample_table[i].pts = AV_RB32(&scratch[8]) & 0x7FFFFFFF;
- film->sample_table[i].keyframe = (scratch[8] & 0x80) ? 0 : 1;
+ film->sample_table[i].keyframe = (scratch[8] & 0x80) ? 0 : AVINDEX_KEYFRAME;
video_frame_counter++;
if (film->video_type)
av_add_index_entry(s->streams[film->video_stream_index],
@@ -270,6 +270,8 @@ static int film_read_packet(AVFormatContext *s,
FilmDemuxContext *film = s->priv_data;
AVIOContext *pb = s->pb;
film_sample *sample;
+ film_sample *next_sample = NULL;
+ int next_sample_id;
int ret = 0;
if (film->current_sample >= film->sample_count)
@@ -277,6 +279,20 @@ static int film_read_packet(AVFormatContext *s,
sample = &film->sample_table[film->current_sample];
+ /* Find the next sample from the same stream, assuming there is one;
+ * this is used to calculate the duration below */
+ next_sample_id = film->current_sample + 1;
+ while (next_sample == NULL) {
+ if (next_sample_id >= film->sample_count)
+ break;
+
+ next_sample = &film->sample_table[next_sample_id];
+ if (next_sample->stream != sample->stream) {
+ next_sample = NULL;
+ next_sample_id++;
+ }
+ }
+
/* position the stream (will probably be there anyway) */
avio_seek(pb, sample->sample_offset, SEEK_SET);
@@ -285,7 +301,11 @@ static int film_read_packet(AVFormatContext *s,
ret = AVERROR(EIO);
pkt->stream_index = sample->stream;
+ pkt->dts = sample->pts;
pkt->pts = sample->pts;
+ pkt->flags |= sample->keyframe ? AV_PKT_FLAG_KEY : 0;
+ if (next_sample != NULL)
+ pkt->duration = next_sample->pts - sample->pts;
film->current_sample++;
diff --git a/chromium/third_party/ffmpeg/libavformat/segafilmenc.c b/chromium/third_party/ffmpeg/libavformat/segafilmenc.c
new file mode 100644
index 00000000000..5b0d7e69e87
--- /dev/null
+++ b/chromium/third_party/ffmpeg/libavformat/segafilmenc.c
@@ -0,0 +1,398 @@
+/*
+ * Sega FILM Format (CPK) Muxer
+ * Copyright (C) 2003 The FFmpeg project
+ * Copyright (C) 2018 Misty De Meo
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Sega FILM (.cpk) file muxer
+ * @author Misty De Meo <misty@brew.sh>
+ *
+ * @see For more information regarding the Sega FILM file format, visit:
+ * http://wiki.multimedia.cx/index.php?title=Sega_FILM
+ */
+
+#include "libavutil/intreadwrite.h"
+#include "avformat.h"
+#include "internal.h"
+#include "avio_internal.h"
+
+typedef struct FILMPacket {
+ int audio;
+ int keyframe;
+ int32_t pts;
+ int32_t duration;
+ int32_t size;
+ int32_t index;
+ struct FILMPacket *next;
+} FILMPacket;
+
+typedef struct FILMOutputContext {
+ const AVClass *class;
+ int audio_index;
+ int video_index;
+ int64_t stab_pos;
+ FILMPacket *start;
+ FILMPacket *last;
+ int64_t packet_count;
+} FILMOutputContext;
+
+static int film_write_packet_to_header(AVFormatContext *format_context, FILMPacket *pkt)
+{
+ AVIOContext *pb = format_context->pb;
+ /* The bits in these two 32-bit integers contain info about the contents of this sample */
+ int32_t info1 = 0;
+ int32_t info2 = 0;
+
+ if (pkt->audio) {
+ /* Always the same, carries no more information than "this is audio" */
+ info1 = 0xFFFFFFFF;
+ info2 = 1;
+ } else {
+ info1 = pkt->pts;
+ info2 = pkt->duration;
+ /* The top bit being set indicates a key frame */
+ if (pkt->keyframe)
+ info1 |= (1 << 31);
+ }
+
+ /* Write the 16-byte sample info packet to the STAB chunk in the header */
+ avio_wb32(pb, pkt->index);
+ avio_wb32(pb, pkt->size);
+ avio_wb32(pb, info1);
+ avio_wb32(pb, info2);
+
+ return 0;
+}
+
+static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt)
+{
+ FILMPacket *metadata;
+ AVIOContext *pb = format_context->pb;
+ FILMOutputContext *film = format_context->priv_data;
+ int encoded_buf_size = 0;
+ enum AVCodecID codec_id;
+
+ /* Track the metadata used to write the header and add it to the linked list */
+ metadata = av_mallocz(sizeof(FILMPacket));
+ if (!metadata)
+ return AVERROR(ENOMEM);
+ metadata->audio = pkt->stream_index == film->audio_index;
+ metadata->keyframe = pkt->flags & AV_PKT_FLAG_KEY;
+ metadata->pts = pkt->pts;
+ metadata->duration = pkt->duration;
+ metadata->size = pkt->size;
+ if (film->last == NULL) {
+ metadata->index = 0;
+ } else {
+ metadata->index = film->last->index + film->last->size;
+ film->last->next = metadata;
+ }
+ metadata->next = NULL;
+ if (film->start == NULL)
+ film->start = metadata;
+ film->packet_count++;
+ film->last = metadata;
+
+ codec_id = format_context->streams[pkt->stream_index]->codecpar->codec_id;
+
+ /* Sega Cinepak has an extra two-byte header; write dummy data there,
+ * then adjust the cvid header to accommodate for the extra size */
+ if (codec_id == AV_CODEC_ID_CINEPAK) {
+ encoded_buf_size = AV_RB24(&pkt->data[1]);
+ /* Already Sega Cinepak, so no need to reformat the packets */
+ if (encoded_buf_size != pkt->size && (pkt->size % encoded_buf_size) != 0) {
+ avio_write(pb, pkt->data, pkt->size);
+ } else {
+ uint8_t padding[2] = {0, 0};
+ /* In Sega Cinepak, the reported size in the Cinepak header is
+ * 8 bytes too short. However, the size in the STAB section of the header
+ * is correct, taking into account the extra two bytes. */
+ AV_WB24(&pkt->data[1], pkt->size - 8 + 2);
+ metadata->size += 2;
+
+ avio_write(pb, pkt->data, 10);
+ avio_write(pb, padding, 2);
+ avio_write(pb, &pkt->data[10], pkt->size - 10);
+ }
+ } else {
+ /* Other formats can just be written as-is */
+ avio_write(pb, pkt->data, pkt->size);
+ }
+
+ return 0;
+}
+
+static int get_audio_codec_id(enum AVCodecID codec_id)
+{
+ /* 0 (PCM) and 2 (ADX) are the only known values */
+ switch (codec_id) {
+ case AV_CODEC_ID_PCM_S8_PLANAR:
+ case AV_CODEC_ID_PCM_S16BE_PLANAR:
+ return 0;
+ break;
+ case AV_CODEC_ID_ADPCM_ADX:
+ return 2;
+ break;
+ default:
+ return -1;
+ }
+}
+
+static int film_init(AVFormatContext *format_context)
+{
+ AVStream *audio = NULL;
+ FILMOutputContext *film = format_context->priv_data;
+ film->audio_index = -1;
+ film->video_index = -1;
+ film->stab_pos = 0;
+ film->packet_count = 0;
+ film->start = NULL;
+ film->last = NULL;
+
+ for (int i = 0; i < format_context->nb_streams; i++) {
+ AVStream *st = format_context->streams[i];
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (film->audio_index > -1) {
+ av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one audio stream.\n");
+ return AVERROR(EINVAL);
+ }
+ film->audio_index = i;
+ audio = st;
+ }
+
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (film->video_index > -1) {
+ av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one video stream.\n");
+ return AVERROR(EINVAL);
+ }
+ film->video_index = i;
+ }
+
+ if (film->video_index == -1) {
+ av_log(format_context, AV_LOG_ERROR, "No video stream present.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ if (audio != NULL && get_audio_codec_id(audio->codecpar->codec_id) < 0) {
+ av_log(format_context, AV_LOG_ERROR, "Incompatible audio stream format.\n");
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int shift_data(AVFormatContext *format_context, int64_t shift_size)
+{
+ int ret = 0;
+ int64_t pos, pos_end = avio_tell(format_context->pb);
+ uint8_t *buf, *read_buf[2];
+ int read_buf_id = 0;
+ int read_size[2];
+ AVIOContext *read_pb;
+
+ buf = av_malloc(shift_size * 2);
+ if (!buf)
+ return AVERROR(ENOMEM);
+ read_buf[0] = buf;
+ read_buf[1] = buf + shift_size;
+
+ /* Write the header at the beginning of the file, shifting all content as necessary;
+ * based on the approach used by MOV faststart. */
+ avio_flush(format_context->pb);
+ ret = format_context->io_open(format_context, &read_pb, format_context->url, AVIO_FLAG_READ, NULL);
+ if (ret < 0) {
+ av_log(format_context, AV_LOG_ERROR, "Unable to re-open %s output file to "
+ "write the header\n", format_context->url);
+ av_free(buf);
+ return ret;
+ }
+
+ /* mark the end of the shift to up to the last data we wrote, and get ready
+ * for writing */
+ pos_end = avio_tell(format_context->pb);
+ avio_seek(format_context->pb, shift_size, SEEK_SET);
+
+ /* start reading at where the new header will be placed */
+ avio_seek(read_pb, 0, SEEK_SET);
+ pos = avio_tell(read_pb);
+
+#define READ_BLOCK do { \
+ read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], shift_size); \
+ read_buf_id ^= 1; \
+} while (0)
+
+ /* shift data by chunk of at most shift_size */
+ READ_BLOCK;
+ do {
+ int n;
+ READ_BLOCK;
+ n = read_size[read_buf_id];
+ if (n <= 0)
+ break;
+ avio_write(format_context->pb, read_buf[read_buf_id], n);
+ pos += n;
+ } while (pos < pos_end);
+ ff_format_io_close(format_context, &read_pb);
+
+ av_free(buf);
+ return 0;
+}
+
+static int film_write_header(AVFormatContext *format_context)
+{
+ int ret = 0;
+ int64_t sample_table_size, stabsize, headersize;
+ int8_t audio_codec;
+ AVIOContext *pb = format_context->pb;
+ FILMOutputContext *film = format_context->priv_data;
+ FILMPacket *prev, *packet;
+ AVStream *audio = NULL;
+ AVStream *video = NULL;
+
+ /* Calculate how much we need to reserve for the header;
+ * this is the amount the rest of the data will be shifted up by. */
+ sample_table_size = film->packet_count * 16;
+ stabsize = 16 + sample_table_size;
+ headersize = 16 + /* FILM header base */
+ 32 + /* FDSC chunk */
+ stabsize;
+
+ ret = shift_data(format_context, headersize);
+ if (ret < 0)
+ return ret;
+ /* Seek back to the beginning to start writing the header now */
+ avio_seek(pb, 0, SEEK_SET);
+
+ if (film->audio_index > -1)
+ audio = format_context->streams[film->audio_index];
+ if (film->video_index > -1)
+ video = format_context->streams[film->video_index];
+
+ if (audio != NULL) {
+ audio_codec = get_audio_codec_id(audio->codecpar->codec_id);
+ if (audio_codec < 0) {
+ av_log(format_context, AV_LOG_ERROR, "Incompatible audio stream format.\n");
+ return AVERROR(EINVAL);
+ }
+ }
+
+ if (video->codecpar->format != AV_PIX_FMT_RGB24) {
+ av_log(format_context, AV_LOG_ERROR, "Pixel format must be rgb24.\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* First, write the FILM header; this is very simple */
+
+ ffio_wfourcc(pb, "FILM");
+ avio_wb32(pb, 48 + stabsize);
+ /* This seems to be okay to hardcode, since this muxer targets 1.09 features;
+ * videos produced by this muxer are readable by 1.08 and lower players. */
+ ffio_wfourcc(pb, "1.09");
+ /* I have no idea what this field does, might be reserved */
+ avio_wb32(pb, 0);
+
+ /* Next write the FDSC (file description) chunk */
+ ffio_wfourcc(pb, "FDSC");
+ avio_wb32(pb, 0x20); /* Size of FDSC chunk */
+
+ /* The only two supported codecs; raw video is rare */
+ switch (video->codecpar->codec_id) {
+ case AV_CODEC_ID_CINEPAK:
+ ffio_wfourcc(pb, "cvid");
+ break;
+ case AV_CODEC_ID_RAWVIDEO:
+ ffio_wfourcc(pb, "raw ");
+ break;
+ default:
+ av_log(format_context, AV_LOG_ERROR, "Incompatible video stream format.\n");
+ return AVERROR(EINVAL);
+ }
+
+ avio_wb32(pb, video->codecpar->height);
+ avio_wb32(pb, video->codecpar->width);
+ avio_w8(pb, 24); /* Bits per pixel - observed to always be 24 */
+
+ if (audio != NULL) {
+ avio_w8(pb, audio->codecpar->channels); /* Audio channels */
+ avio_w8(pb, audio->codecpar->bits_per_coded_sample); /* Audio bit depth */
+ avio_w8(pb, audio_codec); /* Compression - 0 is PCM, 2 is ADX */
+ avio_wb16(pb, audio->codecpar->sample_rate); /* Audio sampling rate */
+ } else {
+ /* Set all these fields to 0 if there's no audio */
+ avio_w8(pb, 0);
+ avio_w8(pb, 0);
+ avio_w8(pb, 0);
+ avio_wb16(pb, 0);
+ }
+
+ /* I have no idea what this pair of fields does either, might be reserved */
+ avio_wb32(pb, 0);
+ avio_wb16(pb, 0);
+
+ /* Finally, write the STAB (sample table) chunk */
+ ffio_wfourcc(pb, "STAB");
+ avio_wb32(pb, 16 + (film->packet_count * 16));
+ /* Framerate base frequency. Here we're assuming that the frame rate is even.
+ * In real world Sega FILM files, there are usually a couple of approaches:
+ * a) framerate base frequency is the same as the framerate, and ticks
+ * increment by 1 every frame, or
+ * b) framerate base frequency is a much larger number, and ticks
+ * increment by larger steps every frame.
+ * The latter occurs even in cases where the frame rate is even; for example, in
+ * Lunar: Silver Star Story, the base frequency is 600 and each frame, the ticks
+ * are incremented by 25 for an evenly spaced framerate of 24fps. */
+ avio_wb32(pb, av_q2d(av_inv_q(video->time_base)));
+
+ avio_wb32(pb, film->packet_count);
+
+ avio_flush(pb);
+
+ /* Finally, write out each packet's data to the header */
+ packet = film->start;
+ while (packet != NULL) {
+ film_write_packet_to_header(format_context, packet);
+ prev = packet;
+ packet = packet->next;
+ av_freep(&prev);
+ }
+
+ return 0;
+}
+
+static const AVClass film_muxer_class = {
+ .class_name = "Sega FILM muxer",
+ .item_name = av_default_item_name,
+ .version = LIBAVUTIL_VERSION_INT,
+};
+
+AVOutputFormat ff_segafilm_muxer = {
+ .name = "film_cpk",
+ .long_name = NULL_IF_CONFIG_SMALL("Sega FILM / CPK"),
+ .extensions = "cpk",
+ .priv_data_size = sizeof(FILMOutputContext),
+ .audio_codec = AV_CODEC_ID_PCM_S16BE_PLANAR,
+ .video_codec = AV_CODEC_ID_CINEPAK,
+ .init = film_init,
+ .write_trailer = film_write_header,
+ .write_packet = film_write_packet,
+ .priv_class = &film_muxer_class,
+};
diff --git a/chromium/third_party/ffmpeg/libavformat/spdifenc.c b/chromium/third_party/ffmpeg/libavformat/spdifenc.c
index 3a50aebbefd..9514ff8e10e 100644
--- a/chromium/third_party/ffmpeg/libavformat/spdifenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/spdifenc.c
@@ -118,7 +118,8 @@ static int spdif_header_eac3(AVFormatContext *s, AVPacket *pkt)
static const uint8_t eac3_repeat[4] = {6, 3, 2, 1};
int repeat = 1;
- if ((pkt->data[4] & 0xc0) != 0xc0) /* fscod */
+ int bsid = pkt->data[5] >> 3;
+ if (bsid > 10 && (pkt->data[4] & 0xc0) != 0xc0) /* fscod */
repeat = eac3_repeat[(pkt->data[4] & 0x30) >> 4]; /* numblkscod */
ctx->hd_buf = av_fast_realloc(ctx->hd_buf, &ctx->hd_buf_size, ctx->hd_buf_filled + pkt->size);
diff --git a/chromium/third_party/ffmpeg/libavformat/tcp.c b/chromium/third_party/ffmpeg/libavformat/tcp.c
index 8773493df1e..b0289f854fc 100644
--- a/chromium/third_party/ffmpeg/libavformat/tcp.c
+++ b/chromium/third_party/ffmpeg/libavformat/tcp.c
@@ -208,8 +208,10 @@ static int tcp_accept(URLContext *s, URLContext **c)
return ret;
cc = (*c)->priv_data;
ret = ff_accept(sc->fd, sc->listen_timeout, s);
- if (ret < 0)
+ if (ret < 0) {
+ ffurl_closep(c);
return ret;
+ }
cc->fd = ret;
return 0;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/tls_schannel.c b/chromium/third_party/ffmpeg/libavformat/tls_schannel.c
index 9a6e0c92e37..f41b007773f 100644
--- a/chromium/third_party/ffmpeg/libavformat/tls_schannel.c
+++ b/chromium/third_party/ffmpeg/libavformat/tls_schannel.c
@@ -413,11 +413,13 @@ static int tls_read(URLContext *h, uint8_t *buf, int len)
ret = ffurl_read(s->tcp, c->enc_buf + c->enc_buf_offset,
c->enc_buf_size - c->enc_buf_offset);
- if (ret < 0) {
+ if (ret == AVERROR_EOF) {
+ c->connection_closed = 1;
+ ret = 0;
+ } else if (ret < 0) {
av_log(h, AV_LOG_ERROR, "Unable to read from socket\n");
return ret;
- } else if (ret == 0)
- c->connection_closed = 1;
+ }
c->enc_buf_offset += ret;
}
@@ -515,7 +517,7 @@ cleanup:
if (ret == 0 && !c->connection_closed)
ret = AVERROR(EAGAIN);
- return ret < 0 ? ret : 0;
+ return ret < 0 ? ret : AVERROR_EOF;
}
static int tls_write(URLContext *h, const uint8_t *buf, int len)
diff --git a/chromium/third_party/ffmpeg/libavformat/ttaenc.c b/chromium/third_party/ffmpeg/libavformat/ttaenc.c
index add15873d04..d8e1136ead1 100644
--- a/chromium/third_party/ffmpeg/libavformat/ttaenc.c
+++ b/chromium/third_party/ffmpeg/libavformat/ttaenc.c
@@ -91,22 +91,13 @@ static int tta_write_header(AVFormatContext *s)
static int tta_write_packet(AVFormatContext *s, AVPacket *pkt)
{
TTAMuxContext *tta = s->priv_data;
- AVPacketList *pktl = av_mallocz(sizeof(*pktl));
int ret;
- if (!pktl)
- return AVERROR(ENOMEM);
-
- ret = av_packet_ref(&pktl->pkt, pkt);
+ ret = ff_packet_list_put(&tta->queue, &tta->queue_end, pkt,
+ FF_PACKETLIST_FLAG_REF_PACKET);
if (ret < 0) {
- av_free(pktl);
return ret;
}
- if (tta->queue_end)
- tta->queue_end->next = pktl;
- else
- tta->queue = pktl;
- tta->queue_end = pktl;
avio_wl32(tta->seek_table, pkt->size);
tta->nb_samples += pkt->duration;
@@ -131,16 +122,13 @@ static int tta_write_packet(AVFormatContext *s, AVPacket *pkt)
static void tta_queue_flush(AVFormatContext *s)
{
TTAMuxContext *tta = s->priv_data;
- AVPacketList *pktl;
-
- while (pktl = tta->queue) {
- AVPacket *pkt = &pktl->pkt;
- avio_write(s->pb, pkt->data, pkt->size);
- av_packet_unref(pkt);
- tta->queue = pktl->next;
- av_free(pktl);
+ AVPacket pkt;
+
+ while (tta->queue) {
+ ff_packet_list_get(&tta->queue, &tta->queue_end, &pkt);
+ avio_write(s->pb, pkt.data, pkt.size);
+ av_packet_unref(&pkt);
}
- tta->queue_end = NULL;
}
static int tta_write_trailer(AVFormatContext *s)
diff --git a/chromium/third_party/ffmpeg/libavformat/unix.c b/chromium/third_party/ffmpeg/libavformat/unix.c
index 4f01d14a938..38016dbafea 100644
--- a/chromium/third_party/ffmpeg/libavformat/unix.c
+++ b/chromium/third_party/ffmpeg/libavformat/unix.c
@@ -111,6 +111,8 @@ static int unix_read(URLContext *h, uint8_t *buf, int size)
return ret;
}
ret = recv(s->fd, buf, size, 0);
+ if (!ret && s->type == SOCK_STREAM)
+ return AVERROR_EOF;
return ret < 0 ? ff_neterrno() : ret;
}
diff --git a/chromium/third_party/ffmpeg/libavformat/utils.c b/chromium/third_party/ffmpeg/libavformat/utils.c
index 259549476dc..5a6e252d433 100644
--- a/chromium/third_party/ffmpeg/libavformat/utils.c
+++ b/chromium/third_party/ffmpeg/libavformat/utils.c
@@ -444,8 +444,9 @@ static int init_input(AVFormatContext *s, const char *filename,
s, 0, s->format_probesize);
}
-static int add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
- AVPacketList **plast_pktl, int ref)
+int ff_packet_list_put(AVPacketList **packet_buffer,
+ AVPacketList **plast_pktl,
+ AVPacket *pkt, int flags)
{
AVPacketList *pktl = av_mallocz(sizeof(AVPacketList));
int ret;
@@ -453,12 +454,15 @@ static int add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt,
if (!pktl)
return AVERROR(ENOMEM);
- if (ref) {
+ if (flags & FF_PACKETLIST_FLAG_REF_PACKET) {
if ((ret = av_packet_ref(&pktl->pkt, pkt)) < 0) {
av_free(pktl);
return ret;
}
} else {
+ // TODO: Adapt callers in this file so the line below can use
+ // av_packet_move_ref() to effectively move the reference
+ // to the list.
pktl->pkt = *pkt;
}
@@ -485,9 +489,10 @@ int avformat_queue_attached_pictures(AVFormatContext *s)
continue;
}
- ret = add_to_pktbuf(&s->internal->raw_packet_buffer,
- &s->streams[i]->attached_pic,
- &s->internal->raw_packet_buffer_end, 1);
+ ret = ff_packet_list_put(&s->internal->raw_packet_buffer,
+ &s->internal->raw_packet_buffer_end,
+ &s->streams[i]->attached_pic,
+ FF_PACKETLIST_FLAG_REF_PACKET);
if (ret < 0)
return ret;
}
@@ -867,13 +872,9 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
continue;
}
- if (!pkt->buf) {
- AVPacket tmp = { 0 };
- err = av_packet_ref(&tmp, pkt);
- if (err < 0)
- return err;
- *pkt = tmp;
- }
+ err = av_packet_make_refcounted(pkt);
+ if (err < 0)
+ return err;
if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) &&
(pkt->flags & AV_PKT_FLAG_CORRUPT)) {
@@ -913,8 +914,9 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt)
if (!pktl && st->request_probe <= 0)
return ret;
- err = add_to_pktbuf(&s->internal->raw_packet_buffer, pkt,
- &s->internal->raw_packet_buffer_end, 0);
+ err = ff_packet_list_put(&s->internal->raw_packet_buffer,
+ &s->internal->raw_packet_buffer_end,
+ pkt, 0);
if (err)
return err;
s->internal->raw_packet_buffer_remaining_size -= pkt->size;
@@ -1127,6 +1129,7 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
if (st->first_dts != AV_NOPTS_VALUE ||
dts == AV_NOPTS_VALUE ||
st->cur_dts == AV_NOPTS_VALUE ||
+ st->cur_dts < INT_MIN + RELATIVE_TS_BASE ||
is_relative(dts))
return;
@@ -1158,7 +1161,9 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index,
}
if (st->start_time == AV_NOPTS_VALUE) {
- st->start_time = pts;
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || !(pkt->flags & AV_PKT_FLAG_DISCARD)) {
+ st->start_time = pts;
+ }
if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate)
st->start_time += av_rescale_q(st->skip_samples, (AVRational){1, st->codecpar->sample_rate}, st->time_base);
}
@@ -1410,14 +1415,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
#endif
}
-static void free_packet_buffer(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end)
+void ff_packet_list_free(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end)
{
- while (*pkt_buf) {
- AVPacketList *pktl = *pkt_buf;
- *pkt_buf = pktl->next;
+ AVPacketList *tmp = *pkt_buf;
+
+ while (tmp) {
+ AVPacketList *pktl = tmp;
+ tmp = pktl->next;
av_packet_unref(&pktl->pkt);
av_freep(&pktl);
}
+ *pkt_buf = NULL;
*pkt_buf_end = NULL;
}
@@ -1464,6 +1472,22 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
if (!out_pkt.size)
continue;
+ if (pkt->buf && out_pkt.data == pkt->data) {
+ /* reference pkt->buf only when out_pkt.data is guaranteed to point
+ * to data in it and not in the parser's internal buffer. */
+ /* XXX: Ensure this is the case with all parsers when st->parser->flags
+ * is PARSER_FLAG_COMPLETE_FRAMES and check for that instead? */
+ out_pkt.buf = av_buffer_ref(pkt->buf);
+ if (!out_pkt.buf) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ } else {
+ ret = av_packet_make_refcounted(&out_pkt);
+ if (ret < 0)
+ goto fail;
+ }
+
if (pkt->side_data) {
out_pkt.side_data = pkt->side_data;
out_pkt.side_data_elems = pkt->side_data_elems;
@@ -1502,11 +1526,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
compute_pkt_fields(s, st, st->parser, &out_pkt, next_dts, next_pts);
- ret = add_to_pktbuf(&s->internal->parse_queue, &out_pkt,
- &s->internal->parse_queue_end, 1);
- av_packet_unref(&out_pkt);
- if (ret < 0)
+ ret = ff_packet_list_put(&s->internal->parse_queue,
+ &s->internal->parse_queue_end,
+ &out_pkt, 0);
+ if (ret < 0) {
+ av_packet_unref(&out_pkt);
goto fail;
+ }
}
/* end of the stream => close and free the parser */
@@ -1520,9 +1546,9 @@ fail:
return ret;
}
-static int read_from_packet_buffer(AVPacketList **pkt_buffer,
- AVPacketList **pkt_buffer_end,
- AVPacket *pkt)
+int ff_packet_list_get(AVPacketList **pkt_buffer,
+ AVPacketList **pkt_buffer_end,
+ AVPacket *pkt)
{
AVPacketList *pktl;
av_assert0(*pkt_buffer);
@@ -1668,7 +1694,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
}
if (!got_packet && s->internal->parse_queue)
- ret = read_from_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt);
+ ret = ff_packet_list_get(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt);
if (ret >= 0) {
AVStream *st = s->streams[pkt->stream_index];
@@ -1747,7 +1773,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
if (!genpts) {
ret = s->internal->packet_buffer
- ? read_from_packet_buffer(&s->internal->packet_buffer,
+ ? ff_packet_list_get(&s->internal->packet_buffer,
&s->internal->packet_buffer_end, pkt)
: read_frame_internal(s, pkt);
if (ret < 0)
@@ -1796,7 +1822,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
st = s->streams[next_pkt->stream_index];
if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL &&
next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
- ret = read_from_packet_buffer(&s->internal->packet_buffer,
+ ret = ff_packet_list_get(&s->internal->packet_buffer,
&s->internal->packet_buffer_end, pkt);
goto return_packet;
}
@@ -1811,8 +1837,9 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
return ret;
}
- ret = add_to_pktbuf(&s->internal->packet_buffer, pkt,
- &s->internal->packet_buffer_end, 1);
+ ret = ff_packet_list_put(&s->internal->packet_buffer,
+ &s->internal->packet_buffer_end,
+ pkt, FF_PACKETLIST_FLAG_REF_PACKET);
av_packet_unref(pkt);
if (ret < 0)
return ret;
@@ -1839,9 +1866,9 @@ static void flush_packet_queue(AVFormatContext *s)
{
if (!s->internal)
return;
- free_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end);
- free_packet_buffer(&s->internal->packet_buffer, &s->internal->packet_buffer_end);
- free_packet_buffer(&s->internal->raw_packet_buffer, &s->internal->raw_packet_buffer_end);
+ ff_packet_list_free(&s->internal->parse_queue, &s->internal->parse_queue_end);
+ ff_packet_list_free(&s->internal->packet_buffer, &s->internal->packet_buffer_end);
+ ff_packet_list_free(&s->internal->raw_packet_buffer, &s->internal->raw_packet_buffer_end);
s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
}
@@ -2591,9 +2618,8 @@ static int has_duration(AVFormatContext *ic)
static void update_stream_timings(AVFormatContext *ic)
{
int64_t start_time, start_time1, start_time_text, end_time, end_time1, end_time_text;
- int64_t duration, duration1, filesize;
+ int64_t duration, duration1, duration_text, filesize;
int i;
- AVStream *st;
AVProgram *p;
start_time = INT64_MAX;
@@ -2601,22 +2627,25 @@ static void update_stream_timings(AVFormatContext *ic)
end_time = INT64_MIN;
end_time_text = INT64_MIN;
duration = INT64_MIN;
+ duration_text = INT64_MIN;
+
for (i = 0; i < ic->nb_streams; i++) {
- st = ic->streams[i];
+ AVStream *st = ic->streams[i];
+ int is_text = st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ||
+ st->codecpar->codec_type == AVMEDIA_TYPE_DATA;
if (st->start_time != AV_NOPTS_VALUE && st->time_base.den) {
start_time1 = av_rescale_q(st->start_time, st->time_base,
AV_TIME_BASE_Q);
- if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
- if (start_time1 < start_time_text)
- start_time_text = start_time1;
- } else
+ if (is_text)
+ start_time_text = FFMIN(start_time_text, start_time1);
+ else
start_time = FFMIN(start_time, start_time1);
end_time1 = av_rescale_q_rnd(st->duration, st->time_base,
AV_TIME_BASE_Q,
AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
if (end_time1 != AV_NOPTS_VALUE && (end_time1 > 0 ? start_time1 <= INT64_MAX - end_time1 : start_time1 >= INT64_MIN - end_time1)) {
end_time1 += start_time1;
- if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE || st->codecpar->codec_type == AVMEDIA_TYPE_DATA)
+ if (is_text)
end_time_text = FFMAX(end_time_text, end_time1);
else
end_time = FFMAX(end_time, end_time1);
@@ -2631,7 +2660,10 @@ static void update_stream_timings(AVFormatContext *ic)
if (st->duration != AV_NOPTS_VALUE) {
duration1 = av_rescale_q(st->duration, st->time_base,
AV_TIME_BASE_Q);
- duration = FFMAX(duration, duration1);
+ if (is_text)
+ duration_text = FFMAX(duration_text, duration1);
+ else
+ duration = FFMAX(duration, duration1);
}
}
if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE))
@@ -2639,11 +2671,15 @@ static void update_stream_timings(AVFormatContext *ic)
else if (start_time > start_time_text)
av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE);
- if (end_time == INT64_MIN || (end_time < end_time_text && end_time_text - end_time < AV_TIME_BASE)) {
+ if (end_time == INT64_MIN || (end_time < end_time_text && end_time_text - (uint64_t)end_time < AV_TIME_BASE))
end_time = end_time_text;
- } else if (end_time < end_time_text) {
+ else if (end_time < end_time_text)
av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream endtime %f\n", end_time_text / (float)AV_TIME_BASE);
- }
+
+ if (duration == INT64_MIN || (duration < duration_text && duration_text - duration < AV_TIME_BASE))
+ duration = duration_text;
+ else if (duration < duration_text)
+ av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream duration %f\n", duration_text / (float)AV_TIME_BASE);
if (start_time != INT64_MAX) {
ic->start_time = start_time;
@@ -3741,8 +3777,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
pkt = &pkt1;
if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) {
- ret = add_to_pktbuf(&ic->internal->packet_buffer, pkt,
- &ic->internal->packet_buffer_end, 0);
+ ret = ff_packet_list_put(&ic->internal->packet_buffer,
+ &ic->internal->packet_buffer_end,
+ pkt, 0);
if (ret < 0)
goto find_stream_info_err;
}
@@ -5060,11 +5097,94 @@ FF_ENABLE_DEPRECATION_WARNINGS
if (s->programs[i]->id != prog_id)
continue;
- if (*endptr++ == ':') {
- int stream_idx = strtol(endptr, NULL, 0);
- return stream_idx >= 0 &&
- stream_idx < s->programs[i]->nb_stream_indexes &&
- st->index == s->programs[i]->stream_index[stream_idx];
+ if (*endptr++ == ':') { // p:<id>:....
+ if ( *endptr == 'a' || *endptr == 'v' ||
+ *endptr == 's' || *endptr == 'd') { // p:<id>:<st_type>[:<index>]
+ enum AVMediaType type;
+
+ switch (*endptr++) {
+ case 'v': type = AVMEDIA_TYPE_VIDEO; break;
+ case 'a': type = AVMEDIA_TYPE_AUDIO; break;
+ case 's': type = AVMEDIA_TYPE_SUBTITLE; break;
+ case 'd': type = AVMEDIA_TYPE_DATA; break;
+ default: av_assert0(0);
+ }
+ if (*endptr++ == ':') { // p:<id>:<st_type>:<index>
+ int stream_idx = strtol(endptr, NULL, 0), type_counter = 0;
+ for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) {
+ int stream_index = s->programs[i]->stream_index[j];
+ if (st->index == s->programs[i]->stream_index[j]) {
+#if FF_API_LAVF_AVCTX
+FF_DISABLE_DEPRECATION_WARNINGS
+ return type_counter == stream_idx &&
+ (type == st->codecpar->codec_type ||
+ type == st->codec->codec_type);
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+ return type_counter == stream_idx &&
+ type == st->codecpar->codec_type;
+#endif
+ }
+#if FF_API_LAVF_AVCTX
+FF_DISABLE_DEPRECATION_WARNINGS
+ if (type == s->streams[stream_index]->codecpar->codec_type ||
+ type == s->streams[stream_index]->codec->codec_type)
+ type_counter++;
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+ if (type == s->streams[stream_index]->codecpar->codec_type)
+ type_counter++;
+#endif
+ }
+ return 0;
+ } else { // p:<id>:<st_type>
+ for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
+ if (st->index == s->programs[i]->stream_index[j]) {
+#if FF_API_LAVF_AVCTX
+FF_DISABLE_DEPRECATION_WARNINGS
+ return type == st->codecpar->codec_type ||
+ type == st->codec->codec_type;
+FF_ENABLE_DEPRECATION_WARNINGS
+#else
+ return type == st->codecpar->codec_type;
+#endif
+ }
+ return 0;
+ }
+
+ } else if ( *endptr == 'm') { // p:<id>:m:<metadata_spec>
+ AVDictionaryEntry *tag;
+ char *key, *val;
+ int ret = 0;
+
+ if (*(++endptr) != ':') {
+ av_log(s, AV_LOG_ERROR, "Invalid stream specifier syntax, missing ':' sign after :m.\n");
+ return AVERROR(EINVAL);
+ }
+
+ val = strchr(++endptr, ':');
+ key = val ? av_strndup(endptr, val - endptr) : av_strdup(endptr);
+ if (!key)
+ return AVERROR(ENOMEM);
+
+ for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
+ if (st->index == s->programs[i]->stream_index[j]) {
+ tag = av_dict_get(st->metadata, key, NULL, 0);
+ if (tag && (!val || !strcmp(tag->value, val + 1)))
+ ret = 1;
+
+ break;
+ }
+
+ av_freep(&key);
+ return ret;
+
+ } else { // p:<id>:<index>
+ int stream_idx = strtol(endptr, NULL, 0);
+ return stream_idx >= 0 &&
+ stream_idx < s->programs[i]->nb_stream_indexes &&
+ st->index == s->programs[i]->stream_index[stream_idx];
+ }
}
for (j = 0; j < s->programs[i]->nb_stream_indexes; j++)
diff --git a/chromium/third_party/ffmpeg/libavformat/version.h b/chromium/third_party/ffmpeg/libavformat/version.h
index e28a9e7dfec..dced716450b 100644
--- a/chromium/third_party/ffmpeg/libavformat/version.h
+++ b/chromium/third_party/ffmpeg/libavformat/version.h
@@ -32,7 +32,7 @@
// Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium)
// Also please add any ticket numbers that you believe might be affected here
#define LIBAVFORMAT_VERSION_MAJOR 58
-#define LIBAVFORMAT_VERSION_MINOR 10
+#define LIBAVFORMAT_VERSION_MINOR 13
#define LIBAVFORMAT_VERSION_MICRO 100
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
@@ -94,6 +94,9 @@
#ifndef FF_API_NEXT
#define FF_API_NEXT (LIBAVFORMAT_VERSION_MAJOR < 59)
#endif
+#ifndef FF_API_DASH_MIN_SEG_DURATION
+#define FF_API_DASH_MIN_SEG_DURATION (LIBAVFORMAT_VERSION_MAJOR < 59)
+#endif
#ifndef FF_API_R_FRAME_RATE
diff --git a/chromium/third_party/ffmpeg/libavformat/vpcc.c b/chromium/third_party/ffmpeg/libavformat/vpcc.c
index df08de59a6a..66d0df69e5e 100644
--- a/chromium/third_party/ffmpeg/libavformat/vpcc.c
+++ b/chromium/third_party/ffmpeg/libavformat/vpcc.c
@@ -67,8 +67,8 @@ static int get_vpx_video_full_range_flag(enum AVColorRange color_range)
return color_range == AVCOL_RANGE_JPEG;
}
-int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb,
- AVCodecParameters *par)
+int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par,
+ VPCC *vpcc)
{
int profile = par->profile;
int level = par->level == FF_LEVEL_UNKNOWN ? 0 : par->level;
@@ -90,9 +90,28 @@ int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb,
}
}
- avio_w8(pb, profile);
- avio_w8(pb, level);
- avio_w8(pb, (bit_depth << 4) | (vpx_chroma_subsampling << 1) | vpx_video_full_range_flag);
+ vpcc->profile = profile;
+ vpcc->level = level;
+ vpcc->bitdepth = bit_depth;
+ vpcc->chroma_subsampling = vpx_chroma_subsampling;
+ vpcc->full_range_flag = vpx_video_full_range_flag;
+
+ return 0;
+}
+
+int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb,
+ AVCodecParameters *par)
+{
+ VPCC vpcc;
+ int ret;
+
+ ret = ff_isom_get_vpcc_features(s, par, &vpcc);
+ if (ret < 0)
+ return ret;
+
+ avio_w8(pb, vpcc.profile);
+ avio_w8(pb, vpcc.level);
+ avio_w8(pb, (vpcc.bitdepth << 4) | (vpcc.chroma_subsampling << 1) | vpcc.full_range_flag);
avio_w8(pb, par->color_primaries);
avio_w8(pb, par->color_trc);
avio_w8(pb, par->color_space);
diff --git a/chromium/third_party/ffmpeg/libavformat/vpcc.h b/chromium/third_party/ffmpeg/libavformat/vpcc.h
index 184e8579f15..d71ba05105a 100644
--- a/chromium/third_party/ffmpeg/libavformat/vpcc.h
+++ b/chromium/third_party/ffmpeg/libavformat/vpcc.h
@@ -32,6 +32,14 @@
#include "avformat.h"
#include "libavcodec/avcodec.h"
+typedef struct VPCC {
+ int profile;
+ int level;
+ int bitdepth;
+ int chroma_subsampling;
+ int full_range_flag;
+} VPCC;
+
/**
* Writes VP codec configuration to the provided AVIOContext.
*
@@ -44,4 +52,7 @@
int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb,
AVCodecParameters *par);
+int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par,
+ VPCC *vpcc);
+
#endif /* AVFORMAT_VPCC_H */
diff --git a/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c b/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c
index ff0125e4cf3..8662a42a4c5 100644
--- a/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c
+++ b/chromium/third_party/ffmpeg/libavformat/yuv4mpegdec.c
@@ -314,7 +314,16 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt)
static int yuv4_read_seek(AVFormatContext *s, int stream_index,
int64_t pts, int flags)
{
- if (avio_seek(s->pb, pts * s->packet_size + s->internal->data_offset, SEEK_SET) < 0)
+ AVStream *st = s->streams[0];
+ int64_t pos;
+
+ pos = av_rescale_rnd(pts * s->packet_size,
+ st->time_base.num,
+ st->time_base.den * s->packet_size,
+ (flags & AVSEEK_FLAG_BACKWARD) ? AV_ROUND_DOWN : AV_ROUND_UP);
+ pos *= s->packet_size;
+
+ if (avio_seek(s->pb, pos + s->internal->data_offset, SEEK_SET) < 0)
return -1;
return 0;
}