diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-04-05 17:15:33 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-04-11 07:47:18 +0000 |
commit | 7324afb043a0b1e623d8e8eb906cdc53bdeb4685 (patch) | |
tree | a3fe2d74ea9c9e142c390dac4ca0e219382ace46 /chromium/third_party/ffmpeg/libavformat | |
parent | 6a4cabb866f66d4128a97cdc6d9d08ce074f1247 (diff) | |
download | qtwebengine-chromium-7324afb043a0b1e623d8e8eb906cdc53bdeb4685.tar.gz |
BASELINE: Update Chromium to 58.0.3029.54
Change-Id: I67f57065a7afdc8e4614adb5c0230281428df4d1
Reviewed-by: Peter Varga <pvarga@inf.u-szeged.hu>
Diffstat (limited to 'chromium/third_party/ffmpeg/libavformat')
32 files changed, 815 insertions, 134 deletions
diff --git a/chromium/third_party/ffmpeg/libavformat/Makefile b/chromium/third_party/ffmpeg/libavformat/Makefile index 119e46bd8e2..f30bc94562d 100644 --- a/chromium/third_party/ffmpeg/libavformat/Makefile +++ b/chromium/third_party/ffmpeg/libavformat/Makefile @@ -83,7 +83,7 @@ OBJS-$(CONFIG_AEA_DEMUXER) += aea.o pcm.o OBJS-$(CONFIG_AFC_DEMUXER) += afc.o OBJS-$(CONFIG_AIFF_DEMUXER) += aiffdec.o pcm.o isom.o \ mov_chan.o -OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o isom.o id3v2enc.o +OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o id3v2enc.o OBJS-$(CONFIG_AIX_DEMUXER) += aixdec.o OBJS-$(CONFIG_AMR_DEMUXER) += amr.o OBJS-$(CONFIG_AMR_MUXER) += amr.o @@ -123,7 +123,7 @@ OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o voc_packet.o vocdec.o voc.o OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ replaygain.o -OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o isom.o +OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o @@ -436,6 +436,7 @@ OBJS-$(CONFIG_SAP_MUXER) += sapenc.o OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o +OBJS-$(CONFIG_SDS_DEMUXER) += sdsdec.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o OBJS-$(CONFIG_SHORTEN_DEMUXER) += shortendec.o rawdec.o diff --git a/chromium/third_party/ffmpeg/libavformat/aadec.c b/chromium/third_party/ffmpeg/libavformat/aadec.c index cf5f3d107ad..39dea40b80b 100644 --- a/chromium/third_party/ffmpeg/libavformat/aadec.c +++ b/chromium/third_party/ffmpeg/libavformat/aadec.c @@ -25,6 +25,7 @@ #include "avformat.h" #include "internal.h" +#include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "libavutil/tea.h" #include "libavutil/opt.h" @@ -101,25 +102,15 @@ static int aa_read_header(AVFormatContext *s) avio_skip(pb, 1); // unidentified integer nkey = avio_rb32(pb); // key string length nval = avio_rb32(pb); // value string length - if (nkey > sizeof(key)) { - avio_skip(pb, nkey); - } else { - avio_read(pb, key, nkey); // key string - } - if (nval > sizeof(val)) { - avio_skip(pb, nval); - } else { - avio_read(pb, val, nval); // value string - } + avio_get_str(pb, nkey, key, sizeof(key)); + avio_get_str(pb, nval, val, sizeof(val)); if (!strcmp(key, "codec")) { av_log(s, AV_LOG_DEBUG, "Codec is <%s>\n", val); strncpy(codec_name, val, sizeof(codec_name) - 1); - } - if (!strcmp(key, "HeaderSeed")) { + } else if (!strcmp(key, "HeaderSeed")) { av_log(s, AV_LOG_DEBUG, "HeaderSeed is <%s>\n", val); header_seed = atoi(val); - } - if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890" + } else if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890" av_log(s, AV_LOG_DEBUG, "HeaderKey is <%s>\n", val); sscanf(val, "%u%u%u%u", &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]); for (idx = 0; idx < 4; idx++) { @@ -129,6 +120,8 @@ static int aa_read_header(AVFormatContext *s) for (i = 0; i < 16; i++) av_log(s, AV_LOG_DEBUG, "%02x", header_key[i]); av_log(s, AV_LOG_DEBUG, "\n"); + } else { + av_dict_set(&s->metadata, key, val, 0); } } @@ -184,11 +177,13 @@ static int aa_read_header(AVFormatContext *s) st->codecpar->block_align = 19; st->codecpar->channels = 1; st->codecpar->sample_rate = 8500; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; } else if (!strcmp(codec_name, "acelp16")) { st->codecpar->codec_id = AV_CODEC_ID_SIPR; st->codecpar->block_align = 20; st->codecpar->channels = 1; st->codecpar->sample_rate = 16000; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; } /* determine, and jump to audio start offset */ diff --git a/chromium/third_party/ffmpeg/libavformat/allformats.c b/chromium/third_party/ffmpeg/libavformat/allformats.c index 6a79b75d78c..e30305b92b3 100644 --- a/chromium/third_party/ffmpeg/libavformat/allformats.c +++ b/chromium/third_party/ffmpeg/libavformat/allformats.c @@ -275,6 +275,7 @@ void av_register_all(void) REGISTER_DEMUXER (SBG, sbg); REGISTER_DEMUXER (SDP, sdp); REGISTER_DEMUXER (SDR2, sdr2); + REGISTER_DEMUXER (SDS, sds); #if CONFIG_RTPDEC ff_register_rtp_dynamic_payload_handlers(); ff_register_rdt_dynamic_payload_handlers(); diff --git a/chromium/third_party/ffmpeg/libavformat/avformat.h b/chromium/third_party/ffmpeg/libavformat/avformat.h index af257e43c4e..ebb0e05c042 100644 --- a/chromium/third_party/ffmpeg/libavformat/avformat.h +++ b/chromium/third_party/ffmpeg/libavformat/avformat.h @@ -930,6 +930,9 @@ typedef struct AVStream { * Decoding: duration of the stream, in stream time base. * If a source file does not specify a duration, but does specify * a bitrate, this value will be estimated from bitrate and file size. + * + * Encoding: May be set by the caller before avformat_write_header() to + * provide a hint to the muxer about the estimated duration. */ int64_t duration; diff --git a/chromium/third_party/ffmpeg/libavformat/avidec.c b/chromium/third_party/ffmpeg/libavformat/avidec.c index d4659657c3a..abe8c988f16 100644 --- a/chromium/third_party/ffmpeg/libavformat/avidec.c +++ b/chromium/third_party/ffmpeg/libavformat/avidec.c @@ -160,11 +160,11 @@ static int get_riff(AVFormatContext *s, AVIOContext *pb) return 0; } -static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) +static int read_odml_index(AVFormatContext *s, int frame_num) { AVIContext *avi = s->priv_data; AVIOContext *pb = s->pb; - int longs_pre_entry = avio_rl16(pb); + int longs_per_entry = avio_rl16(pb); int index_sub_type = avio_r8(pb); int index_type = avio_r8(pb); int entries_in_use = avio_rl32(pb); @@ -179,9 +179,9 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) int64_t filesize = avi->fsize; av_log(s, AV_LOG_TRACE, - "longs_pre_entry:%d index_type:%d entries_in_use:%d " + "longs_per_entry:%d index_type:%d entries_in_use:%d " "chunk_id:%X base:%16"PRIX64" frame_num:%d\n", - longs_pre_entry, + longs_per_entry, index_type, entries_in_use, chunk_id, @@ -198,7 +198,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) avio_rl32(pb); - if (index_type && longs_pre_entry != 2) + if (index_type && longs_per_entry != 2) return AVERROR_INVALIDDATA; if (index_type > 1) return AVERROR_INVALIDDATA; @@ -253,7 +253,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) if (avio_seek(pb, offset + 8, SEEK_SET) < 0) return -1; avi->odml_depth++; - read_braindead_odml_indx(s, frame_num); + read_odml_index(s, frame_num); avi->odml_depth--; frame_num += duration; @@ -950,7 +950,7 @@ FF_ENABLE_DEPRECATION_WARNINGS pos = avio_tell(pb); if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && avi->use_odml && - read_braindead_odml_indx(s, 0) < 0 && + read_odml_index(s, 0) < 0 && (s->error_recognition & AV_EF_EXPLODE)) goto fail; avio_seek(pb, pos + size, SEEK_SET); @@ -1211,7 +1211,8 @@ start_sync: if ((d[0] == 'i' && d[1] == 'x' && n < s->nb_streams) || // parse JUNK (d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K') || - (d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')) { + (d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1') || + (d[0] == 'i' && d[1] == 'n' && d[2] == 'd' && d[3] == 'x')) { avio_skip(pb, size); goto start_sync; } diff --git a/chromium/third_party/ffmpeg/libavformat/avio.h b/chromium/third_party/ffmpeg/libavformat/avio.h index b1ce1d1c72e..e2cb4af7a27 100644 --- a/chromium/third_party/ffmpeg/libavformat/avio.h +++ b/chromium/third_party/ffmpeg/libavformat/avio.h @@ -704,6 +704,18 @@ int avio_closep(AVIOContext **s); int avio_open_dyn_buf(AVIOContext **s); /** + * Return the written size and a pointer to the buffer. + * The AVIOContext stream is left intact. + * The buffer must NOT be freed. + * No padding is added to the buffer. + * + * @param s IO context + * @param pbuffer pointer to a byte buffer + * @return the length of the byte buffer + */ +int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer); + +/** * Return the written size and a pointer to the buffer. The buffer * must be freed with av_free(). * Padding of AV_INPUT_BUFFER_PADDING_SIZE is added to the buffer. diff --git a/chromium/third_party/ffmpeg/libavformat/aviobuf.c b/chromium/third_party/ffmpeg/libavformat/aviobuf.c index 134d627a6e0..bf7e5f85a00 100644 --- a/chromium/third_party/ffmpeg/libavformat/aviobuf.c +++ b/chromium/third_party/ffmpeg/libavformat/aviobuf.c @@ -1277,6 +1277,23 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size) return url_open_dyn_buf_internal(s, max_packet_size); } +int avio_get_dyn_buf(AVIOContext *s, uint8_t **pbuffer) +{ + DynBuffer *d; + + if (!s) { + *pbuffer = NULL; + return 0; + } + + avio_flush(s); + + d = s->opaque; + *pbuffer = d->buffer; + + return d->size; +} + int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer) { DynBuffer *d; diff --git a/chromium/third_party/ffmpeg/libavformat/caf.c b/chromium/third_party/ffmpeg/libavformat/caf.c index c05fb8087c6..8d394157946 100644 --- a/chromium/third_party/ffmpeg/libavformat/caf.c +++ b/chromium/third_party/ffmpeg/libavformat/caf.c @@ -33,6 +33,7 @@ */ const AVCodecTag ff_codec_caf_tags[] = { { AV_CODEC_ID_AAC, MKTAG('a','a','c',' ') }, + { AV_CODEC_ID_AAC, MKTAG('a','a','c','l') }, { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') }, { AV_CODEC_ID_ADPCM_IMA_QT, MKTAG('i','m','a','4') }, { AV_CODEC_ID_ADPCM_IMA_WAV, MKTAG('m','s', 0, 17 ) }, diff --git a/chromium/third_party/ffmpeg/libavformat/dss.c b/chromium/third_party/ffmpeg/libavformat/dss.c index 2f7f20d1348..083eb4ad43b 100644 --- a/chromium/third_party/ffmpeg/libavformat/dss.c +++ b/chromium/third_party/ffmpeg/libavformat/dss.c @@ -42,7 +42,6 @@ #define DSS_COMMENT_SIZE 64 #define DSS_BLOCK_SIZE 512 -#define DSS_HEADER_SIZE (DSS_BLOCK_SIZE * 2) #define DSS_AUDIO_BLOCK_HEADER_SIZE 6 #define DSS_FRAME_SIZE 42 @@ -56,11 +55,13 @@ typedef struct DSSDemuxContext { int8_t *dss_sp_buf; int packet_size; + int dss_header_size; } DSSDemuxContext; static int dss_probe(AVProbeData *p) { - if (AV_RL32(p->buf) != MKTAG(0x2, 'd', 's', 's')) + if ( AV_RL32(p->buf) != MKTAG(0x2, 'd', 's', 's') + && AV_RL32(p->buf) != MKTAG(0x3, 'd', 's', 's')) return 0; return AVPROBE_SCORE_MAX; @@ -120,12 +121,15 @@ static int dss_read_header(AVFormatContext *s) DSSDemuxContext *ctx = s->priv_data; AVIOContext *pb = s->pb; AVStream *st; - int ret; + int ret, version; st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); + version = avio_r8(pb); + ctx->dss_header_size = version * DSS_BLOCK_SIZE; + ret = dss_read_metadata_string(s, DSS_HEAD_OFFSET_AUTHOR, DSS_AUTHOR_SIZE, "author"); if (ret) @@ -164,7 +168,7 @@ static int dss_read_header(AVFormatContext *s) /* Jump over header */ - if (avio_seek(pb, DSS_HEADER_SIZE, SEEK_SET) != DSS_HEADER_SIZE) + if (avio_seek(pb, ctx->dss_header_size, SEEK_SET) != ctx->dss_header_size) return AVERROR(EIO); ctx->counter = 0; @@ -261,9 +265,6 @@ static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt) goto error_eof; } - if (pkt->data[0] == 0xff) - return AVERROR_INVALIDDATA; - return pkt->size; error_eof: @@ -361,7 +362,7 @@ static int dss_read_seek(AVFormatContext *s, int stream_index, if (seekto < 0) seekto = 0; - seekto += DSS_HEADER_SIZE; + seekto += ctx->dss_header_size; ret = avio_seek(s->pb, seekto, SEEK_SET); if (ret < 0) diff --git a/chromium/third_party/ffmpeg/libavformat/flacdec.c b/chromium/third_party/ffmpeg/libavformat/flacdec.c index 3060dc45fd7..66baba59225 100644 --- a/chromium/third_party/ffmpeg/libavformat/flacdec.c +++ b/chromium/third_party/ffmpeg/libavformat/flacdec.c @@ -65,7 +65,8 @@ static int flac_read_header(AVFormatContext *s) /* process metadata blocks */ while (!avio_feof(s->pb) && !metadata_last) { - avio_read(s->pb, header, 4); + if (avio_read(s->pb, header, 4) != 4) + return AVERROR(AVERROR_INVALIDDATA); flac_parse_block_header(header, &metadata_last, &metadata_type, &metadata_size); switch (metadata_type) { diff --git a/chromium/third_party/ffmpeg/libavformat/flvenc.c b/chromium/third_party/ffmpeg/libavformat/flvenc.c index 62d406a0316..d7506c56fbe 100644 --- a/chromium/third_party/ffmpeg/libavformat/flvenc.c +++ b/chromium/third_party/ffmpeg/libavformat/flvenc.c @@ -626,13 +626,15 @@ static int shift_data(AVFormatContext *s) avio_seek(read_pb, flv->keyframes_info_offset, SEEK_SET); pos = avio_tell(read_pb); - /* shift data by chunk of at most keyframe *filepositions* and *times* size */ +#define READ_BLOCK do { \ read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], metadata_size); \ - read_buf_id ^= 1; - do { + read_buf_id ^= 1; \ +} while (0) - read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], metadata_size); \ - read_buf_id ^= 1; + /* shift data by chunk of at most keyframe *filepositions* and *times* size */ + READ_BLOCK; + do { + READ_BLOCK; n = read_size[read_buf_id]; if (n < 0) break; @@ -890,6 +892,10 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) { av_free(par->extradata); par->extradata = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!par->extradata) { + par->extradata_size = 0; + return AVERROR(ENOMEM); + } memcpy(par->extradata, side, side_size); par->extradata_size = side_size; flv_write_codec_header(s, par); diff --git a/chromium/third_party/ffmpeg/libavformat/hlsenc.c b/chromium/third_party/ffmpeg/libavformat/hlsenc.c index acf3a301afc..bd1e684954e 100644 --- a/chromium/third_party/ffmpeg/libavformat/hlsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/hlsenc.c @@ -39,8 +39,15 @@ #include "internal.h" #include "os_support.h" +typedef enum { + HLS_START_SEQUENCE_AS_START_NUMBER = 0, + HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH = 1, + HLS_START_SEQUENCE_AS_FORMATTED_DATETIME = 2, // YYYYMMDDhhmmss +} StartSequenceSourceType; + #define KEYSIZE 16 #define LINE_BUFFER_SIZE 1024 +#define HLS_MICROSECOND_UNIT 1000000 typedef struct HLSSegment { char filename[1024]; @@ -66,6 +73,9 @@ typedef enum HLSFlags { HLS_SPLIT_BY_TIME = (1 << 5), HLS_APPEND_LIST = (1 << 6), HLS_PROGRAM_DATE_TIME = (1 << 7), + HLS_SECOND_LEVEL_SEGMENT_INDEX = (1 << 8), // include segment index in segment filenames when use_localtime e.g.: %%03d + HLS_SECOND_LEVEL_SEGMENT_DURATION = (1 << 9), // include segment duration (microsec) in segment filenames when use_localtime e.g.: %%09t + HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s } HLSFlags; typedef enum { @@ -80,6 +90,7 @@ typedef struct HLSContext { unsigned number; int64_t sequence; int64_t start_sequence; + uint32_t start_sequence_source_type; // enum StartSequenceSourceType AVOutputFormat *oformat; AVOutputFormat *vtt_oformat; @@ -100,6 +111,8 @@ typedef struct HLSContext { int64_t recording_time; int has_video; int has_subtitle; + int new_start; + double dpp; // duration per packet int64_t start_pts; int64_t end_pts; double duration; // last segment duration computed so far, in seconds @@ -133,8 +146,14 @@ typedef struct HLSContext { char *method; double initial_prog_date_time; + char current_segment_final_filename_fmt[1024]; // when renaming segments } HLSContext; +static int get_int_from_double(double val) +{ + return (int)((val - (int)val) >= 0.001) ? (int)(val + 1) : (int)val; +} + static int mkdir_p(const char *path) { int ret = 0; char *temp = av_strdup(path); @@ -168,6 +187,58 @@ static int mkdir_p(const char *path) { return ret; } +static int replace_int_data_in_filename(char *buf, int buf_size, const char *filename, char placeholder, int64_t number) +{ + const char *p; + char *q, buf1[20], c; + int nd, len, addchar_count; + int found_count = 0; + + q = buf; + p = filename; + for (;;) { + c = *p; + if (c == '\0') + break; + if (c == '%' && *(p+1) == '%') // %% + addchar_count = 2; + else if (c == '%' && (av_isdigit(*(p+1)) || *(p+1) == placeholder)) { + nd = 0; + addchar_count = 1; + while (av_isdigit(*(p + addchar_count))) { + nd = nd * 10 + *(p + addchar_count) - '0'; + addchar_count++; + } + + if (*(p + addchar_count) == placeholder) { + len = snprintf(buf1, sizeof(buf1), "%0*"PRId64, (number < 0) ? nd : nd++, number); + if (len < 1) // returned error or empty buf1 + goto fail; + if ((q - buf + len) > buf_size - 1) + goto fail; + memcpy(q, buf1, len); + q += len; + p += (addchar_count + 1); + addchar_count = 0; + found_count++; + } + + } else + addchar_count = 1; + + while (addchar_count--) + if ((q - buf) < buf_size - 1) + *q++ = *p++; + else + goto fail; + } + *q = '\0'; + return found_count; +fail: + *q = '\0'; + return -1; +} + static int hls_delete_old_segments(HLSContext *hls) { HLSSegment *segment, *previous_segment = NULL; @@ -175,6 +246,8 @@ static int hls_delete_old_segments(HLSContext *hls) { int ret = 0, path_size, sub_path_size; char *dirname = NULL, *p, *sub_path; char *path = NULL; + AVDictionary *options = NULL; + AVIOContext *out = NULL; segment = hls->segments; while (segment) { @@ -185,7 +258,6 @@ static int hls_delete_old_segments(HLSContext *hls) { segment = hls->old_segments; while (segment) { playlist_duration -= segment->duration; - hls->initial_prog_date_time += segment->duration; previous_segment = segment; segment = previous_segment->next; if (playlist_duration <= -previous_segment->duration) { @@ -194,7 +266,7 @@ static int hls_delete_old_segments(HLSContext *hls) { } } - if (segment) { + if (segment && !hls->use_localtime_mkdir) { if (hls->segment_filename) { dirname = av_strdup(hls->segment_filename); } else { @@ -211,22 +283,32 @@ static int hls_delete_old_segments(HLSContext *hls) { while (segment) { av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n", segment->filename); - path_size = strlen(dirname) + strlen(segment->filename) + 1; + path_size = (hls->use_localtime_mkdir ? 0 : strlen(dirname)) + strlen(segment->filename) + 1; path = av_malloc(path_size); if (!path) { ret = AVERROR(ENOMEM); goto fail; } - av_strlcpy(path, dirname, path_size); - av_strlcat(path, segment->filename, path_size); - if (unlink(path) < 0) { + if (hls->use_localtime_mkdir) + av_strlcpy(path, segment->filename, path_size); + else { // segment->filename contains basename only + av_strlcpy(path, dirname, path_size); + av_strlcat(path, segment->filename, path_size); + } + + if (hls->method) { + av_dict_set(&options, "method", "DELETE", 0); + if ((ret = hls->avf->io_open(hls->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) + goto fail; + ff_format_io_close(hls->avf, &out); + } else if (unlink(path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", path, strerror(errno)); } - if (segment->sub_filename[0] != '\0') { - sub_path_size = strlen(dirname) + strlen(segment->sub_filename) + 1; + if ((segment->sub_filename[0] != '\0')) { + sub_path_size = strlen(segment->sub_filename) + 1 + (dirname ? strlen(dirname) : 0); sub_path = av_malloc(sub_path_size); if (!sub_path) { ret = AVERROR(ENOMEM); @@ -235,7 +317,15 @@ static int hls_delete_old_segments(HLSContext *hls) { av_strlcpy(sub_path, dirname, sub_path_size); av_strlcat(sub_path, segment->sub_filename, sub_path_size); - if (unlink(sub_path) < 0) { + + if (hls->method) { + av_dict_set(&options, "method", "DELETE", 0); + if ((ret = hls->avf->io_open(hls->avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { + av_free(sub_path); + goto fail; + } + ff_format_io_close(hls->avf, &out); + } else if (unlink(sub_path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", sub_path, strerror(errno)); } @@ -358,10 +448,21 @@ static int hls_mux_init(AVFormatContext *s) st->time_base = s->streams[i]->time_base; } hls->start_pos = 0; + hls->new_start = 1; return 0; } +static HLSSegment *find_segment_by_filename(HLSSegment *segment, const char *filename) +{ + while (segment) { + if (!av_strcasecmp(segment->filename,filename)) + return segment; + segment = segment->next; + } + return (HLSSegment *) NULL; +} + /* Create a new segment and append it to the segment list */ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double duration, int64_t pos, int64_t size) @@ -373,11 +474,57 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double if (!en) return AVERROR(ENOMEM); + if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && + strlen(hls->current_segment_final_filename_fmt)) { + av_strlcpy(hls->avf->filename, hls->current_segment_final_filename_fmt, sizeof(hls->avf->filename)); + if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { + char * filename = av_strdup(hls->avf->filename); // %%s will be %s after strftime + if (!filename) { + av_free(en); + return AVERROR(ENOMEM); + } + if (replace_int_data_in_filename(hls->avf->filename, sizeof(hls->avf->filename), + filename, 's', pos + size) < 1) { + av_log(hls, AV_LOG_ERROR, + "Invalid second level segment filename template '%s', " + "you can try to remove second_level_segment_size flag\n", + filename); + av_free(filename); + av_free(en); + return AVERROR(EINVAL); + } + av_free(filename); + } + if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { + char * filename = av_strdup(hls->avf->filename); // %%t will be %t after strftime + if (!filename) { + av_free(en); + return AVERROR(ENOMEM); + } + if (replace_int_data_in_filename(hls->avf->filename, sizeof(hls->avf->filename), + filename, 't', (int64_t)round(duration * HLS_MICROSECOND_UNIT)) < 1) { + av_log(hls, AV_LOG_ERROR, + "Invalid second level segment filename template '%s', " + "you can try to remove second_level_segment_time flag\n", + filename); + av_free(filename); + av_free(en); + return AVERROR(EINVAL); + } + av_free(filename); + } + } + + filename = av_basename(hls->avf->filename); if (hls->use_localtime_mkdir) { filename = hls->avf->filename; } + if (find_segment_by_filename(hls->segments, filename) + || find_segment_by_filename(hls->old_segments, filename)) { + av_log(hls, AV_LOG_WARNING, "Duplicated segment filename detected: %s\n", filename); + } av_strlcpy(en->filename, filename, sizeof(en->filename)); if(hls->has_subtitle) @@ -414,6 +561,7 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { en = hls->segments; + hls->initial_prog_date_time += en->duration; hls->segments = en->next; if (en && hls->flags & HLS_DELETE_SEGMENTS && !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) { @@ -458,7 +606,16 @@ static int parse_playlist(AVFormatContext *s, const char *url) while (!avio_feof(in)) { read_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { - hls->sequence = atoi(ptr); + int64_t tmp_sequence = strtoll(ptr, NULL, 10); + if (tmp_sequence < hls->sequence) + av_log(hls, AV_LOG_VERBOSE, + "Found playlist sequence number was smaller """ + "than specified start sequence number: %"PRId64" < %"PRId64", " + "omitting\n", tmp_sequence, hls->start_sequence); + else { + av_log(hls, AV_LOG_DEBUG, "Found playlist sequence number: %"PRId64"\n", tmp_sequence); + hls->sequence = tmp_sequence; + } } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) { is_segment = 1; hls->discontinuity = 1; @@ -503,6 +660,19 @@ static void set_http_options(AVDictionary **options, HLSContext *c) av_dict_set(options, "method", c->method, 0); } +static void write_m3u8_head_block(HLSContext *hls, AVIOContext *out, int version, + int target_duration, int64_t sequence) +{ + avio_printf(out, "#EXTM3U\n"); + avio_printf(out, "#EXT-X-VERSION:%d\n", version); + if (hls->allowcache == 0 || hls->allowcache == 1) { + avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES"); + } + avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); + avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + av_log(hls, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); +} + static int hls_window(AVFormatContext *s, int last) { HLSContext *hls = s->priv_data; @@ -537,26 +707,18 @@ static int hls_window(AVFormatContext *s, int last) goto fail; for (en = hls->segments; en; en = en->next) { - if (target_duration < en->duration) - target_duration = ceil(en->duration); + if (target_duration <= en->duration) + target_duration = get_int_from_double(en->duration); } hls->discontinuity_set = 0; - avio_printf(out, "#EXTM3U\n"); - avio_printf(out, "#EXT-X-VERSION:%d\n", version); - if (hls->allowcache == 0 || hls->allowcache == 1) { - avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES"); - } - avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); - avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + write_m3u8_head_block(hls, out, version, target_duration, sequence); if (hls->pl_type == PLAYLIST_TYPE_EVENT) { avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); } else if (hls->pl_type == PLAYLIST_TYPE_VOD) { avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); } - av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", - sequence); if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){ avio_printf(out, "#EXT-X-DISCONTINUITY\n"); hls->discontinuity_set = 1; @@ -618,16 +780,7 @@ static int hls_window(AVFormatContext *s, int last) if( hls->vtt_m3u8_name ) { if ((ret = s->io_open(s, &sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE, &options)) < 0) goto fail; - avio_printf(sub_out, "#EXTM3U\n"); - avio_printf(sub_out, "#EXT-X-VERSION:%d\n", version); - if (hls->allowcache == 0 || hls->allowcache == 1) { - avio_printf(sub_out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES"); - } - avio_printf(sub_out, "#EXT-X-TARGETDURATION:%d\n", target_duration); - avio_printf(sub_out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); - - av_log(s, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", - sequence); + write_m3u8_head_block(hls, sub_out, version, target_duration, sequence); for (en = hls->segments; en; en = en->next) { avio_printf(sub_out, "#EXTINF:%f,\n", en->duration); @@ -669,9 +822,8 @@ static int hls_start(AVFormatContext *s) av_strlcpy(vtt_oc->filename, c->vtt_basename, sizeof(vtt_oc->filename)); } else if (c->max_seg_size > 0) { - if (av_get_frame_filename2(oc->filename, sizeof(oc->filename), - c->basename, c->wrap ? c->sequence % c->wrap : c->sequence, - AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), + c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename); return AVERROR(EINVAL); } @@ -685,7 +837,53 @@ static int hls_start(AVFormatContext *s) av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n"); return AVERROR(EINVAL); } - + if (c->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) { + char * filename = av_strdup(oc->filename); // %%d will be %d after strftime + if (!filename) + return AVERROR(ENOMEM); + if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), + filename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + av_log(c, AV_LOG_ERROR, + "Invalid second level segment filename template '%s', " + "you can try to remove second_level_segment_index flag\n", + filename); + av_free(filename); + return AVERROR(EINVAL); + } + av_free(filename); + } + if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) { + av_strlcpy(c->current_segment_final_filename_fmt, oc->filename, + sizeof(c->current_segment_final_filename_fmt)); + if (c->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { + char * filename = av_strdup(oc->filename); // %%s will be %s after strftime + if (!filename) + return AVERROR(ENOMEM); + if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), filename, 's', 0) < 1) { + av_log(c, AV_LOG_ERROR, + "Invalid second level segment filename template '%s', " + "you can try to remove second_level_segment_size flag\n", + filename); + av_free(filename); + return AVERROR(EINVAL); + } + av_free(filename); + } + if (c->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { + char * filename = av_strdup(oc->filename); // %%t will be %t after strftime + if (!filename) + return AVERROR(ENOMEM); + if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), filename, 't', 0) < 1) { + av_log(c, AV_LOG_ERROR, + "Invalid second level segment filename template '%s', " + "you can try to remove second_level_segment_time flag\n", + filename); + av_free(filename); + return AVERROR(EINVAL); + } + av_free(filename); + } + } if (c->use_localtime_mkdir) { const char *dir; char *fn_copy = av_strdup(oc->filename); @@ -700,16 +898,14 @@ static int hls_start(AVFormatContext *s) } av_free(fn_copy); } - } else if (av_get_frame_filename2(oc->filename, sizeof(oc->filename), - c->basename, c->wrap ? c->sequence % c->wrap : c->sequence, - AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + } else if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), + c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename); return AVERROR(EINVAL); } if( c->vtt_basename) { - if (av_get_frame_filename2(vtt_oc->filename, sizeof(vtt_oc->filename), - c->vtt_basename, c->wrap ? c->sequence % c->wrap : c->sequence, - AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + if (replace_int_data_in_filename(vtt_oc->filename, sizeof(vtt_oc->filename), + c->vtt_basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename); return AVERROR(EINVAL); } @@ -775,21 +971,48 @@ fail: return err; } +static const char * get_default_pattern_localtime_fmt(void) +{ + char b[21]; + time_t t = time(NULL); + struct tm *p, tmbuf; + p = localtime_r(&t, &tmbuf); + // no %s support when strftime returned error or left format string unchanged + return (!strftime(b, sizeof(b), "%s", p) || !strcmp(b, "%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts"; +} + static int hls_write_header(AVFormatContext *s) { HLSContext *hls = s->priv_data; int ret, i; char *p; const char *pattern = "%d.ts"; - const char *pattern_localtime_fmt = "-%s.ts"; + const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(); const char *vtt_pattern = "%d.vtt"; AVDictionary *options = NULL; int basename_size; int vtt_basename_size; + if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH || hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) { + time_t t = time(NULL); // we will need it in either case + if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) { + hls->start_sequence = (int64_t)t; + } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) { + char b[15]; + struct tm *p, tmbuf; + if (!(p = localtime_r(&t, &tmbuf))) + return AVERROR(ENOMEM); + if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p)) + return AVERROR(ENOMEM); + hls->start_sequence = strtoll(b, NULL, 10); + } + av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence); + } + hls->sequence = hls->start_sequence; hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE; hls->start_pts = AV_NOPTS_VALUE; + hls->current_segment_final_filename_fmt[0] = '\0'; if (hls->flags & HLS_PROGRAM_DATE_TIME) { time_t now0; @@ -864,7 +1087,42 @@ static int hls_write_header(AVFormatContext *s) av_strlcat(hls->basename, pattern, basename_size); } } - + if (!hls->use_localtime) { + if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { + av_log(hls, AV_LOG_ERROR, + "second_level_segment_duration hls_flag requires use_localtime to be true\n"); + ret = AVERROR(EINVAL); + goto fail; + } + if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { + av_log(hls, AV_LOG_ERROR, + "second_level_segment_size hls_flag requires use_localtime to be true\n"); + ret = AVERROR(EINVAL); + goto fail; + } + if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) { + av_log(hls, AV_LOG_ERROR, + "second_level_segment_index hls_flag requires use_localtime to be true\n"); + ret = AVERROR(EINVAL); + goto fail; + } + } else { + const char *proto = avio_find_protocol_name(hls->basename); + int segment_renaming_ok = proto && !strcmp(proto, "file"); + + if ((hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) && !segment_renaming_ok) { + av_log(hls, AV_LOG_ERROR, + "second_level_segment_duration hls_flag works only with file protocol segment names\n"); + ret = AVERROR(EINVAL); + goto fail; + } + if ((hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) && !segment_renaming_ok) { + av_log(hls, AV_LOG_ERROR, + "second_level_segment_size hls_flag works only with file protocol segment names\n"); + ret = AVERROR(EINVAL); + goto fail; + } + } if(hls->has_subtitle) { if (hls->flags & HLS_SINGLE_FILE) @@ -996,21 +1254,36 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (pkt->pts == AV_NOPTS_VALUE) is_ref_pkt = can_split = 0; - if (is_ref_pkt) - hls->duration = (double)(pkt->pts - hls->end_pts) - * st->time_base.num / st->time_base.den; + if (is_ref_pkt) { + if (hls->new_start) { + hls->new_start = 0; + hls->duration = (double)(pkt->pts - hls->end_pts) + * st->time_base.num / st->time_base.den; + hls->dpp = (double)(pkt->duration) * st->time_base.num / st->time_base.den; + } else { + hls->duration += (double)(pkt->duration) * st->time_base.num / st->time_base.den; + } + } if (can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base, end_pts, AV_TIME_BASE_Q) >= 0) { int64_t new_start_pos; + char *old_filename = av_strdup(hls->avf->filename); + + if (!old_filename) { + return AVERROR(ENOMEM); + } + av_write_frame(oc, NULL); /* Flush any buffered data */ new_start_pos = avio_tell(hls->avf->pb); hls->size = new_start_pos - hls->start_pos; ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); hls->start_pos = new_start_pos; - if (ret < 0) + if (ret < 0) { + av_free(old_filename); return ret; + } hls->end_pts = pkt->pts; hls->duration = 0; @@ -1025,6 +1298,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (hls->start_pos >= hls->max_seg_size) { hls->sequence++; ff_format_io_close(s, &oc->pb); + if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && + strlen(hls->current_segment_final_filename_fmt)) { + ff_rename(old_filename, hls->avf->filename, hls); + } if (hls->vtt_avf) ff_format_io_close(s, &hls->vtt_avf->pb); ret = hls_start(s); @@ -1036,22 +1313,25 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) hls->number++; } else { ff_format_io_close(s, &oc->pb); + if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && + strlen(hls->current_segment_final_filename_fmt)) { + ff_rename(old_filename, hls->avf->filename, hls); + } if (hls->vtt_avf) ff_format_io_close(s, &hls->vtt_avf->pb); ret = hls_start(s); } - if (ret < 0) + if (ret < 0) { + av_free(old_filename); return ret; + } - if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) - oc = hls->vtt_avf; - else - oc = hls->avf; - - if ((ret = hls_window(s, 0)) < 0) + if ((ret = hls_window(s, 0)) < 0) { + av_free(old_filename); return ret; + } } ret = ff_write_chained(oc, stream_index, pkt, s, 0); @@ -1064,12 +1344,24 @@ static int hls_write_trailer(struct AVFormatContext *s) HLSContext *hls = s->priv_data; AVFormatContext *oc = hls->avf; AVFormatContext *vtt_oc = hls->vtt_avf; + char *old_filename = av_strdup(hls->avf->filename); + + if (!old_filename) { + return AVERROR(ENOMEM); + } + av_write_trailer(oc); if (oc->pb) { hls->size = avio_tell(hls->avf->pb) - hls->start_pos; ff_format_io_close(s, &oc->pb); - hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); + /* after av_write_trailer, then duration + 1 duration per packet */ + hls_append_segment(s, hls, hls->duration + hls->dpp, hls->start_pos, hls->size); + } + + if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && + strlen(hls->current_segment_final_filename_fmt)) { + ff_rename(old_filename, hls->avf->filename, hls); } if (vtt_oc) { @@ -1092,6 +1384,7 @@ static int hls_write_trailer(struct AVFormatContext *s) hls_free_segments(hls->segments); hls_free_segments(hls->old_segments); + av_free(old_filename); return 0; } @@ -1120,13 +1413,19 @@ static const AVOption options[] = { {"split_by_time", "split the hls segment by time which user set by hls_time", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SPLIT_BY_TIME }, 0, UINT_MAX, E, "flags"}, {"append_list", "append the new segments into old hls segment list", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_APPEND_LIST }, 0, UINT_MAX, E, "flags"}, {"program_date_time", "add EXT-X-PROGRAM-DATE-TIME", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PROGRAM_DATE_TIME }, 0, UINT_MAX, E, "flags"}, + {"second_level_segment_index", "include segment index in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_INDEX }, 0, UINT_MAX, E, "flags"}, + {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, + {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" }, {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" }, {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" }, {"method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, - + {"hls_start_number_source", "set source of first number in sequence", OFFSET(start_sequence_source_type), AV_OPT_TYPE_INT, {.i64 = HLS_START_SEQUENCE_AS_START_NUMBER }, 0, HLS_START_SEQUENCE_AS_FORMATTED_DATETIME, E, "start_sequence_source_type" }, + {"generic", "start_number value (default)", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_START_NUMBER }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, + {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, + {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_FORMATTED_DATETIME }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, { NULL }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/id3v2.c b/chromium/third_party/ffmpeg/libavformat/id3v2.c index 9969d7a6ca6..b3036d2f87e 100644 --- a/chromium/third_party/ffmpeg/libavformat/id3v2.c +++ b/chromium/third_party/ffmpeg/libavformat/id3v2.c @@ -688,9 +688,9 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const cha } if (decode_str(s, pb, 0, &dst, &len) < 0) - return; + goto end; if (len < 16) - return; + goto end; start = avio_rb32(pb); end = avio_rb32(pb); diff --git a/chromium/third_party/ffmpeg/libavformat/img2dec.c b/chromium/third_party/ffmpeg/libavformat/img2dec.c index f1a0e7fa546..321189f38fa 100644 --- a/chromium/third_party/ffmpeg/libavformat/img2dec.c +++ b/chromium/third_party/ffmpeg/libavformat/img2dec.c @@ -755,6 +755,8 @@ static int jpeg_probe(AVProbeData *p) if (state == EOI) return AVPROBE_SCORE_EXTENSION + 1; + if (state == SOS) + return AVPROBE_SCORE_EXTENSION / 2 + 1; return AVPROBE_SCORE_EXTENSION / 8; } @@ -847,10 +849,7 @@ static int psd_probe(AVProbeData *p) if ((color_mode <= 9) && (color_mode != 5) && (color_mode != 6)) ret += 1; - if (ret) - return AVPROBE_SCORE_EXTENSION + ret; - - return 0; + return AVPROBE_SCORE_EXTENSION + ret; } static int sgi_probe(AVProbeData *p) diff --git a/chromium/third_party/ffmpeg/libavformat/isom.c b/chromium/third_party/ffmpeg/libavformat/isom.c index ae10cb7d3fd..13ceef0fb5d 100644 --- a/chromium/third_party/ffmpeg/libavformat/isom.c +++ b/chromium/third_party/ffmpeg/libavformat/isom.c @@ -296,6 +296,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_SHEERVIDEO, MKTAG('S', 'h', 'r', '6') }, { AV_CODEC_ID_SHEERVIDEO, MKTAG('S', 'h', 'r', '7') }, + { AV_CODEC_ID_PIXLET, MKTAG('p', 'x', 'l', 't') }, + { AV_CODEC_ID_NONE, 0 }, }; diff --git a/chromium/third_party/ffmpeg/libavformat/libopenmpt.c b/chromium/third_party/ffmpeg/libavformat/libopenmpt.c index e7091ef9fc5..35fd28f5f4d 100644 --- a/chromium/third_party/ffmpeg/libavformat/libopenmpt.c +++ b/chromium/third_party/ffmpeg/libavformat/libopenmpt.c @@ -82,6 +82,11 @@ static int read_header_openmpt(AVFormatContext *s) if (!buf) return AVERROR(ENOMEM); size = avio_read(s->pb, buf, size); + if (size < 0) { + av_log(s, AV_LOG_ERROR, "Reading input buffer failed.\n"); + av_freep(&buf); + return size; + } openmpt->module = openmpt_module_create_from_memory(buf, size, openmpt_logfunc, s, NULL); av_freep(&buf); diff --git a/chromium/third_party/ffmpeg/libavformat/matroska.c b/chromium/third_party/ffmpeg/libavformat/matroska.c index f3e1be796df..c8e53416d34 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroska.c +++ b/chromium/third_party/ffmpeg/libavformat/matroska.c @@ -35,7 +35,7 @@ const CodecTags ff_mkv_codec_tags[]={ {"A_FLAC" , AV_CODEC_ID_FLAC}, {"A_MLP" , AV_CODEC_ID_MLP}, {"A_MPEG/L2" , AV_CODEC_ID_MP2}, - {"A_MPEG/L1" , AV_CODEC_ID_MP2}, + {"A_MPEG/L1" , AV_CODEC_ID_MP1}, {"A_MPEG/L3" , AV_CODEC_ID_MP3}, {"A_OPUS" , AV_CODEC_ID_OPUS}, {"A_OPUS/EXPERIMENTAL",AV_CODEC_ID_OPUS}, diff --git a/chromium/third_party/ffmpeg/libavformat/matroskadec.c b/chromium/third_party/ffmpeg/libavformat/matroskadec.c index 908c86bb5dc..3bb8d4aee27 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskadec.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskadec.c @@ -93,6 +93,7 @@ typedef const struct EbmlSyntax { int list_elem_size; int data_offset; union { + int64_t i; uint64_t u; double f; const char *s; @@ -700,7 +701,7 @@ static EbmlSyntax matroska_blockgroup[] = { { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration) }, { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock, discard_padding) }, - { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference) }, + { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference), { .i = INT64_MIN } }, { MATROSKA_ID_CODECSTATE, EBML_NONE }, { 1, EBML_UINT, 0, offsetof(MatroskaBlock, non_simple), { .u = 1 } }, { 0 } @@ -1075,6 +1076,9 @@ static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, for (i = 0; syntax[i].id; i++) switch (syntax[i].type) { + case EBML_SINT: + *(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i; + break; case EBML_UINT: *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; break; @@ -3247,9 +3251,11 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE && timecode < track->end_timecode) is_keyframe = 0; /* overlapping subtitles are not key frame */ - if (is_keyframe) + if (is_keyframe) { + ff_reduce_index(matroska->ctx, st->index); av_add_index_entry(st, cluster_pos, timecode, 0, 0, AVINDEX_KEYFRAME); + } } if (matroska->skip_to_keyframe && @@ -3378,7 +3384,7 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) matroska->current_cluster_num_blocks = blocks_list->nb_elem; i = blocks_list->nb_elem - 1; if (blocks[i].bin.size > 0 && blocks[i].bin.data) { - int is_keyframe = blocks[i].non_simple ? !blocks[i].reference : -1; + int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; uint8_t* additional = blocks[i].additional.size > 0 ? blocks[i].additional.data : NULL; if (!blocks[i].non_simple) @@ -3416,7 +3422,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) blocks = blocks_list->elem; 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 : -1; + int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; res = matroska_parse_block(matroska, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, blocks[i].duration, diff --git a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c index 827d7550c2d..f731b678b9d 100644 --- a/chromium/third_party/ffmpeg/libavformat/matroskaenc.c +++ b/chromium/third_party/ffmpeg/libavformat/matroskaenc.c @@ -367,6 +367,22 @@ static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, Matrosk *dyn_cp = NULL; } +/** +* Complete ebml master whithout destroying the buffer, allowing for later updates +*/ +static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, + ebml_master master) +{ + if (pb->seekable) { + + uint8_t *buf; + int size = avio_get_dyn_buf(*dyn_cp, &buf); + + avio_write(pb, buf, size); + end_ebml_master(pb, master); + } +} + static void put_xiph_size(AVIOContext *pb, int size) { ffio_fill(pb, 255, size / 255); @@ -1103,14 +1119,15 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, } else { // look for a codec ID string specific to mkv to use, // if none are found, use AVI codes - for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) { - if (ff_mkv_codec_tags[j].id == par->codec_id) { - put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str); - native_id = 1; - break; + if (par->codec_id != AV_CODEC_ID_RAWVIDEO || par->codec_tag) { + for (j = 0; ff_mkv_codec_tags[j].id != AV_CODEC_ID_NONE; j++) { + if (ff_mkv_codec_tags[j].id == par->codec_id) { + put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str); + native_id = 1; + break; + } } - } - if (par->codec_id == AV_CODEC_ID_RAWVIDEO && !par->codec_tag) { + } else { if (mkv->allow_raw_vfw) { native_id = 0; } else { @@ -1231,11 +1248,9 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, uint32_t color_space = av_le2ne32(par->codec_tag); put_ebml_binary(pb, MATROSKA_ID_VIDEOCOLORSPACE, &color_space, sizeof(color_space)); } - if (s->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) { - ret = mkv_write_video_color(pb, par, st); - if (ret < 0) - return ret; - } + ret = mkv_write_video_color(pb, par, st); + if (ret < 0) + return ret; end_ebml_master(pb, subinfo); break; @@ -1309,7 +1324,7 @@ static int mkv_write_tracks(AVFormatContext *s) } if (pb->seekable && !mkv->is_live) - put_ebml_void(pb, avio_tell(mkv->tracks_bc)); + end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, mkv->tracks_master); else end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, mkv->tracks_master); @@ -1554,7 +1569,7 @@ static int mkv_write_tags(AVFormatContext *s) if (mkv->tags.pos) { if (s->pb->seekable && !mkv->is_live) - put_ebml_void(s->pb, avio_tell(mkv->tags_bc)); + end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, mkv->tags); else end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, mkv->tags); } @@ -1811,7 +1826,7 @@ static int mkv_write_header(AVFormatContext *s) } } if (s->pb->seekable && !mkv->is_live) - put_ebml_void(s->pb, avio_tell(pb)); + end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, mkv->info); else end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, mkv->info); pb = s->pb; diff --git a/chromium/third_party/ffmpeg/libavformat/mov.c b/chromium/third_party/ffmpeg/libavformat/mov.c index 612e8da469a..7f3e7ac2a43 100644 --- a/chromium/third_party/ffmpeg/libavformat/mov.c +++ b/chromium/third_party/ffmpeg/libavformat/mov.c @@ -411,7 +411,7 @@ retry: key = c->meta_keys[index]; } else { av_log(c->fc, AV_LOG_WARNING, - "The index of 'data' is out of range: %d >= %d.\n", + "The index of 'data' is out of range: %d < 1 or >= %d.\n", index, c->meta_keys_count); } } @@ -742,7 +742,7 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) title_size = atom.size - 24; if (title_size > 0) { - if (title_size >= UINT_MAX) + if (title_size > FFMIN(INT_MAX, SIZE_MAX-1)) return AVERROR_INVALIDDATA; title_str = av_malloc(title_size + 1); /* Add null terminator */ if (!title_str) @@ -4600,7 +4600,7 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) 0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd, }; - if (atom.size < sizeof(uuid) || atom.size == INT64_MAX) + if (atom.size < sizeof(uuid) || atom.size >= FFMIN(INT_MAX, SIZE_MAX)) return AVERROR_INVALIDDATA; if (c->fc->nb_streams < 1) @@ -4661,9 +4661,6 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) } else if (!memcmp(uuid, uuid_xmp, sizeof(uuid))) { uint8_t *buffer; size_t len = atom.size - sizeof(uuid); - if (len >= UINT_MAX) - return AVERROR_INVALIDDATA; - if (c->export_xmp) { buffer = av_mallocz(len + 1); if (!buffer) { @@ -4782,7 +4779,7 @@ static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb); /* entries */ - if (atom.size < 8 || atom.size > UINT_MAX) { + 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; } @@ -4851,7 +4848,7 @@ static int mov_read_saiz(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } - if (atom.size > UINT_MAX) { + 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); return AVERROR_INVALIDDATA; } diff --git a/chromium/third_party/ffmpeg/libavformat/mpegenc.c b/chromium/third_party/ffmpeg/libavformat/mpegenc.c index 878fa6381f1..c77c3dfe414 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegenc.c @@ -1146,6 +1146,8 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) stream->next_packet = &stream->premux_packet; *stream->next_packet = pkt_desc = av_mallocz(sizeof(PacketDesc)); + if (!pkt_desc) + return AVERROR(ENOMEM); pkt_desc->pts = pts; pkt_desc->dts = dts; pkt_desc->unwritten_size = diff --git a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c index cdd7e37a1f5..0f394c5fe0e 100644 --- a/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c +++ b/chromium/third_party/ffmpeg/libavformat/mpegtsenc.c @@ -1619,9 +1619,39 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) } } } else if (st->codecpar->codec_id == AV_CODEC_ID_HEVC) { + const uint8_t *p = buf, *buf_end = p + size; + uint32_t state = -1; + int extradd = (pkt->flags & AV_PKT_FLAG_KEY) ? st->codecpar->extradata_size : 0; int ret = check_hevc_startcode(s, st, pkt); if (ret < 0) return ret; + + if (extradd && AV_RB24(st->codecpar->extradata) > 1) + extradd = 0; + + do { + p = avpriv_find_start_code(p, buf_end, &state); + av_log(s, AV_LOG_TRACE, "nal %d\n", (state & 0x7e)>>1); + if ((state & 0x7e) == 2*32) + extradd = 0; + } while (p < buf_end && (state & 0x7e) != 2*35 && + (state & 0x7e) >= 2*32); + + if ((state & 0x7e) < 2*16 && (state & 0x7e) >= 2*24) + extradd = 0; + if ((state & 0x7e) != 2*35) { // AUD NAL + data = av_malloc(pkt->size + 7 + extradd); + if (!data) + return AVERROR(ENOMEM); + memcpy(data + 7, st->codecpar->extradata, extradd); + memcpy(data + 7 + extradd, pkt->data, pkt->size); + AV_WB32(data, 0x00000001); + data[4] = 2*35; + data[5] = 1; + data[6] = 0x50; // any slice type (0x4) + rbsp stop one bit + buf = data; + size = pkt->size + 7 + extradd; + } } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) { if (pkt->size < 2) { av_log(s, AV_LOG_ERROR, "Opus packet too short\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/mxf.c b/chromium/third_party/ffmpeg/libavformat/mxf.c index e9c48e8d7fd..bfc3218b815 100644 --- a/chromium/third_party/ffmpeg/libavformat/mxf.c +++ b/chromium/third_party/ffmpeg/libavformat/mxf.c @@ -61,6 +61,7 @@ const MXFCodecUL ff_mxf_codec_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC SPS/PPS in-band */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x01,0x01,0x02,0x02,0x01 }, 16, AV_CODEC_ID_V210 }, /* V210 */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0E,0x04,0x02,0x01,0x02,0x11,0x00,0x00 }, 14, AV_CODEC_ID_PRORES }, /* Avid MC7 ProRes */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0D,0x04,0x01,0x02,0x02,0x03,0x06,0x00,0x00 }, 14, AV_CODEC_ID_PRORES }, /* Apple ProRes */ /* SoundEssenceCompression */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x03,0x04,0x02,0x02,0x02,0x03,0x03,0x01,0x00 }, 14, AV_CODEC_ID_AAC }, /* MPEG-2 AAC ADTS (legacy) */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x02,0x02,0x01,0x00,0x00,0x00,0x00 }, 13, AV_CODEC_ID_PCM_S16LE }, /* uncompressed */ diff --git a/chromium/third_party/ffmpeg/libavformat/omadec.c b/chromium/third_party/ffmpeg/libavformat/omadec.c index 6e476dbf25b..757ae5371a9 100644 --- a/chromium/third_party/ffmpeg/libavformat/omadec.c +++ b/chromium/third_party/ffmpeg/libavformat/omadec.c @@ -365,7 +365,7 @@ static int oma_read_header(AVFormatContext *s) st->codecpar->channels = 2; st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; st->codecpar->sample_rate = samplerate; - st->codecpar->bit_rate = st->codecpar->sample_rate * framesize * 8 / 1024; + st->codecpar->bit_rate = st->codecpar->sample_rate * framesize / (1024 / 8); /* fake the ATRAC3 extradata * (wav format, makes stream copy to wav work) */ @@ -398,7 +398,7 @@ static int oma_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } st->codecpar->sample_rate = samplerate; - st->codecpar->bit_rate = samplerate * framesize * 8 / 2048; + st->codecpar->bit_rate = samplerate * framesize / (2048 / 8); avpriv_set_pts_info(st, 64, 1, samplerate); break; case OMA_CODECID_MP3: diff --git a/chromium/third_party/ffmpeg/libavformat/riff.c b/chromium/third_party/ffmpeg/libavformat/riff.c index e4e394d6135..d44b908f8be 100644 --- a/chromium/third_party/ffmpeg/libavformat/riff.c +++ b/chromium/third_party/ffmpeg/libavformat/riff.c @@ -428,11 +428,26 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_M101, MKTAG('M', '1', '0', '1') }, { AV_CODEC_ID_M101, MKTAG('M', '1', '0', '2') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', 'A', 'G', 'Y') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'R', 'G') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'R', 'A') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'G', '0') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'Y', '0') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'Y', '2') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'Y', '4') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'Y', 'A') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'A') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'G') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'G', '0') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '2') }, { AV_CODEC_ID_YLC, MKTAG('Y', 'L', 'C', '0') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '0') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '1') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '2') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '3') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '4') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '5') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '7') }, + { AV_CODEC_ID_SPEEDHQ, MKTAG('S', 'H', 'Q', '9') }, { AV_CODEC_ID_NONE, 0 } }; diff --git a/chromium/third_party/ffmpeg/libavformat/rmdec.c b/chromium/third_party/ffmpeg/libavformat/rmdec.c index 4d565291af2..c8035889390 100644 --- a/chromium/third_party/ffmpeg/libavformat/rmdec.c +++ b/chromium/third_party/ffmpeg/libavformat/rmdec.c @@ -236,6 +236,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, return -1; } st->codecpar->block_align = ff_sipr_subpk_size[flavor]; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; } else { if(sub_packet_size <= 0){ av_log(s, AV_LOG_ERROR, "sub_packet_size is invalid\n"); diff --git a/chromium/third_party/ffmpeg/libavformat/rtmphttp.c b/chromium/third_party/ffmpeg/libavformat/rtmphttp.c index e5ce10ca4f0..ef6146ca864 100644 --- a/chromium/third_party/ffmpeg/libavformat/rtmphttp.c +++ b/chromium/third_party/ffmpeg/libavformat/rtmphttp.c @@ -208,7 +208,7 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags) } /* alloc the http context */ - if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, NULL)) < 0) + if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, &h->interrupt_callback)) < 0) goto fail; /* set options */ diff --git a/chromium/third_party/ffmpeg/libavformat/sdsdec.c b/chromium/third_party/ffmpeg/libavformat/sdsdec.c new file mode 100644 index 00000000000..081bb4ca2d8 --- /dev/null +++ b/chromium/third_party/ffmpeg/libavformat/sdsdec.c @@ -0,0 +1,165 @@ +/* + * MIDI Sample Dump Standard format demuxer + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" + +typedef struct SDSContext { + uint8_t data[120]; + int bit_depth; + int size; + void (*read_block)(const uint8_t *src, uint32_t *dst); +} SDSContext; + +static int sds_probe(AVProbeData *p) +{ + if (AV_RB32(p->buf) == 0xF07E0001 && p->buf[20] == 0xF7 && + p->buf[6] >= 8 && p->buf[6] <= 28) + return AVPROBE_SCORE_EXTENSION; + return 0; +} + +static void byte2_read(const uint8_t *src, uint32_t *dst) +{ + int i; + + for (i = 0; i < 120; i += 2) { + unsigned sample = (src[i + 0] << 25) + (src[i + 1] << 18); + + dst[i / 2] = sample; + } +} + +static void byte3_read(const uint8_t *src, uint32_t *dst) +{ + int i; + + for (i = 0; i < 120; i += 3) { + unsigned sample; + + sample = (src[i + 0] << 25) | (src[i + 1] << 18) | (src[i + 2] << 11); + dst[i / 3] = sample; + } +} + +static void byte4_read(const uint8_t *src, uint32_t *dst) +{ + int i; + + for (i = 0; i < 120; i += 4) { + unsigned sample; + + sample = (src[i + 0] << 25) | (src[i + 1] << 18) | (src[i + 2] << 11) | (src[i + 3] << 4); + dst[i / 4] = sample; + } +} + +#define SDS_3BYTE_TO_INT_DECODE(x) (((x) & 0x7F) | (((x) & 0x7F00) >> 1) | (((x) & 0x7F0000) >> 2)) + +static int sds_read_header(AVFormatContext *ctx) +{ + SDSContext *s = ctx->priv_data; + unsigned sample_period; + AVIOContext *pb = ctx->pb; + AVStream *st; + + st = avformat_new_stream(ctx, NULL); + if (!st) + return AVERROR(ENOMEM); + + avio_skip(pb, 4); + avio_skip(pb, 2); + + s->bit_depth = avio_r8(pb); + if (s->bit_depth < 8 || s->bit_depth > 28) + return AVERROR_INVALIDDATA; + + if (s->bit_depth < 14) { + s->read_block = byte2_read; + s->size = 60 * 4; + } else if (s->bit_depth < 21) { + s->read_block = byte3_read; + s->size = 40 * 4; + } else { + s->read_block = byte4_read; + s->size = 30 * 4; + } + st->codecpar->codec_id = AV_CODEC_ID_PCM_U32LE; + + sample_period = avio_rl24(pb); + sample_period = SDS_3BYTE_TO_INT_DECODE(sample_period); + avio_skip(pb, 11); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->channels = 1; + st->codecpar->sample_rate = sample_period ? 1000000000 / sample_period : 16000; + st->duration = (avio_size(pb) - 21) / (127) * s->size / 4; + + avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); + + return 0; +} + +static int sds_read_packet(AVFormatContext *ctx, AVPacket *pkt) +{ + SDSContext *s = ctx->priv_data; + AVIOContext *pb = ctx->pb; + int64_t pos; + int ret; + + if (avio_feof(pb)) + return AVERROR_EOF; + + pos = avio_tell(pb); + if (avio_rb16(pb) != 0xF07E) + return AVERROR_INVALIDDATA; + avio_skip(pb, 3); + + ret = av_new_packet(pkt, s->size); + if (ret < 0) + return ret; + + ret = avio_read(pb, s->data, 120); + + s->read_block(s->data, (uint32_t *)pkt->data); + + avio_skip(pb, 1); // checksum + if (avio_r8(pb) != 0xF7) + return AVERROR_INVALIDDATA; + + pkt->flags &= ~AV_PKT_FLAG_CORRUPT; + pkt->stream_index = 0; + pkt->pos = pos; + + return ret; +} + +AVInputFormat ff_sds_demuxer = { + .name = "sds", + .long_name = NULL_IF_CONFIG_SMALL("MIDI Sample Dump Standard"), + .priv_data_size = sizeof(SDSContext), + .read_probe = sds_probe, + .read_header = sds_read_header, + .read_packet = sds_read_packet, + .extensions = "sds", + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/chromium/third_party/ffmpeg/libavformat/segment.c b/chromium/third_party/ffmpeg/libavformat/segment.c index 9b3dc178ebb..9d471483b38 100644 --- a/chromium/third_party/ffmpeg/libavformat/segment.c +++ b/chromium/third_party/ffmpeg/libavformat/segment.c @@ -354,6 +354,9 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) int i; int err; + if (!oc || !oc->pb) + return AVERROR(EINVAL); + av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */ if (write_trailer) ret = av_write_trailer(oc); @@ -850,7 +853,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) int64_t usecs; int64_t wrapped_val; - if (!seg->avf) + if (!seg->avf || !seg->avf->pb) return AVERROR(EINVAL); calc_times: diff --git a/chromium/third_party/ffmpeg/libavformat/tee.c b/chromium/third_party/ffmpeg/libavformat/tee.c index d59ad4d183b..dd1844ac0e1 100644 --- a/chromium/third_party/ffmpeg/libavformat/tee.c +++ b/chromium/third_party/ffmpeg/libavformat/tee.c @@ -40,6 +40,8 @@ typedef struct { AVBSFContext **bsfs; ///< bitstream filters per stream SlaveFailurePolicy on_fail; + int use_fifo; + AVDictionary *fifo_options; /** map from input to output streams indexes, * disabled output streams are set to -1 */ @@ -52,15 +54,28 @@ typedef struct TeeContext { unsigned nb_slaves; unsigned nb_alive; TeeSlave *slaves; + int use_fifo; + AVDictionary *fifo_options; + char *fifo_options_str; } TeeContext; static const char *const slave_delim = "|"; static const char *const slave_bsfs_spec_sep = "/"; static const char *const slave_select_sep = ","; +#define OFFSET(x) offsetof(TeeContext, x) +static const AVOption options[] = { + {"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from encoder", + OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, + {"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options_str), + AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM}, + {NULL} +}; + static const AVClass tee_muxer_class = { .class_name = "Tee muxer", .item_name = av_default_item_name, + .option = options, .version = LIBAVUTIL_VERSION_INT, }; @@ -81,6 +96,29 @@ static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *t return AVERROR(EINVAL); } +static int parse_slave_fifo_options(const char *use_fifo, + const char *fifo_options, TeeSlave *tee_slave) +{ + int ret = 0; + + if (use_fifo) { + /*TODO - change this to use proper function for parsing boolean + * options when there is one */ + if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) { + tee_slave->use_fifo = 1; + } else if (av_match_name(use_fifo, "false,n,no,disable,disabled,off,0")) { + tee_slave->use_fifo = 0; + } else { + return AVERROR(EINVAL); + } + } + + if (fifo_options) + ret = av_dict_parse_string(&tee_slave->fifo_options, fifo_options, "=", ":", 0); + + return ret; +} + static int close_slave(TeeSlave *tee_slave) { AVFormatContext *avf; @@ -125,6 +163,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) AVDictionaryEntry *entry; char *filename; char *format = NULL, *select = NULL, *on_fail = NULL; + char *use_fifo = NULL, *fifo_options_str = NULL; AVFormatContext *avf2 = NULL; AVStream *st, *st2; int stream_count; @@ -145,6 +184,8 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) STEAL_OPTION("f", format); STEAL_OPTION("select", select); STEAL_OPTION("onfail", on_fail); + STEAL_OPTION("use_fifo", use_fifo); + STEAL_OPTION("fifo_options", fifo_options_str); ret = parse_slave_failure_policy_option(on_fail, tee_slave); if (ret < 0) { @@ -153,7 +194,39 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) goto end; } - ret = avformat_alloc_output_context2(&avf2, NULL, format, filename); + ret = parse_slave_fifo_options(use_fifo, fifo_options_str, tee_slave); + if (ret < 0) { + av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n", av_err2str(ret)); + goto end; + } + + if (tee_slave->use_fifo) { + + if (options) { + char *format_options_str = NULL; + ret = av_dict_get_string(options, &format_options_str, '=', ':'); + if (ret < 0) + goto end; + + ret = av_dict_set(&tee_slave->fifo_options, "format_opts", format_options_str, + AV_DICT_DONT_STRDUP_VAL); + if (ret < 0) + goto end; + } + + if (format) { + ret = av_dict_set(&tee_slave->fifo_options, "fifo_format", format, + AV_DICT_DONT_STRDUP_VAL); + format = NULL; + if (ret < 0) + goto end; + } + + av_dict_free(&options); + options = tee_slave->fifo_options; + } + ret = avformat_alloc_output_context2(&avf2, NULL, + tee_slave->use_fifo ? "fifo" :format, filename); if (ret < 0) goto end; tee_slave->avf = avf2; @@ -394,6 +467,12 @@ static int tee_write_header(AVFormatContext *avf) filename++; } + if (tee->fifo_options_str) { + ret = av_dict_parse_string(&tee->fifo_options, tee->fifo_options_str, "=", ":", 0); + if (ret < 0) + goto fail; + } + if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves)))) { ret = AVERROR(ENOMEM); goto fail; @@ -401,6 +480,12 @@ static int tee_write_header(AVFormatContext *avf) tee->nb_slaves = tee->nb_alive = nb_slaves; for (i = 0; i < nb_slaves; i++) { + + tee->slaves[i].use_fifo = tee->use_fifo; + ret = av_dict_copy(&tee->slaves[i].fifo_options, tee->fifo_options, 0); + if (ret < 0) + goto fail; + if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) { ret = tee_process_slave_failure(avf, i, ret); if (ret < 0) diff --git a/chromium/third_party/ffmpeg/libavformat/version.h b/chromium/third_party/ffmpeg/libavformat/version.h index 65e6a4ccb7f..402e4c138c5 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 57 -#define LIBAVFORMAT_VERSION_MINOR 61 +#define LIBAVFORMAT_VERSION_MINOR 63 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/chromium/third_party/ffmpeg/libavformat/wavdec.c b/chromium/third_party/ffmpeg/libavformat/wavdec.c index 69857ba5a2c..903d4f49fad 100644 --- a/chromium/third_party/ffmpeg/libavformat/wavdec.c +++ b/chromium/third_party/ffmpeg/libavformat/wavdec.c @@ -558,6 +558,22 @@ break_loop: if (sample_count) st->duration = sample_count; + if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S32LE && + st->codecpar->block_align == st->codecpar->channels * 4 && + st->codecpar->bits_per_coded_sample == 32 && + st->codecpar->extradata_size == 2 && + AV_RL16(st->codecpar->extradata) == 1) { + st->codecpar->codec_id = AV_CODEC_ID_PCM_F16LE; + st->codecpar->bits_per_coded_sample = 16; + } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S24LE && + st->codecpar->block_align == st->codecpar->channels * 4 && + st->codecpar->bits_per_coded_sample == 24) { + st->codecpar->codec_id = AV_CODEC_ID_PCM_F24LE; + } else if (st->codecpar->codec_id == AV_CODEC_ID_XMA1 || + st->codecpar->codec_id == AV_CODEC_ID_XMA2) { + st->codecpar->block_align = 2048; + } + ff_metadata_conv_ctx(s, NULL, wav_metadata_conv); ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv); @@ -709,6 +725,7 @@ static int wav_read_seek(AVFormatContext *s, case AV_CODEC_ID_MP3: case AV_CODEC_ID_AC3: case AV_CODEC_ID_DTS: + case AV_CODEC_ID_XMA2: /* use generic seeking with dynamically generated indexes */ return -1; default: |