From 0cdd1208bed747bc96dcf109fe0e3c607cdbba45 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Mon, 11 Jul 2011 15:13:39 +0200 Subject: [PATCH 01/21] Musepack SV7: try to read files without number of frames provided Signed-off-by: Anton Khirnov --- libavformat/mpc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/libavformat/mpc.c b/libavformat/mpc.c index 0aec1e81d3..75b59e1800 100644 --- a/libavformat/mpc.c +++ b/libavformat/mpc.c @@ -70,7 +70,15 @@ static int mpc_read_header(AVFormatContext *s, AVFormatParameters *ap) av_log(s, AV_LOG_ERROR, "Too many frames, seeking is not possible\n"); return -1; } - c->frames = av_malloc(c->fcount * sizeof(MPCFrame)); + if(c->fcount){ + c->frames = av_malloc(c->fcount * sizeof(MPCFrame)); + if(!c->frames){ + av_log(s, AV_LOG_ERROR, "Cannot allocate seektable\n"); + return AVERROR(ENOMEM); + } + }else{ + av_log(s, AV_LOG_WARNING, "Container reports no frames\n"); + } c->curframe = 0; c->lastframe = -1; c->curbits = 8; @@ -111,7 +119,7 @@ static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt) int ret, size, size2, curbits, cur = c->curframe; int64_t tmp, pos; - if (c->curframe >= c->fcount) + if (c->curframe >= c->fcount && c->fcount) return -1; if(c->curframe != c->lastframe + 1){ @@ -133,7 +141,7 @@ static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt) avio_seek(s->pb, pos, SEEK_SET); size = ((size2 + curbits + 31) & ~31) >> 3; - if(cur == c->frames_noted){ + if(cur == c->frames_noted && c->fcount){ c->frames[cur].pos = pos; c->frames[cur].size = size; c->frames[cur].skip = curbits - 20; @@ -146,7 +154,7 @@ static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR(EIO); pkt->data[0] = curbits; - pkt->data[1] = (c->curframe > c->fcount); + pkt->data[1] = (c->curframe > c->fcount) && c->fcount; pkt->data[2] = 0; pkt->data[3] = 0; From 646a9a189346392ea0e23d4eacbec890955d187c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 9 Jul 2011 16:48:47 +0200 Subject: [PATCH 02/21] ffmpeg: remove an unused define. --- ffmpeg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index a0f6abc87d..ba5859df4e 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -104,8 +104,6 @@ static const OptionDef options[]; #define MAX_FILES 100 #define MAX_STREAMS 1024 /* arbitrary sanity check value */ -#define FFM_PACKET_SIZE 4096 //XXX a duplicate of the line in ffm.h - static const char *last_asked_format = NULL; static double *ts_scale; static int nb_ts_scale; From c7dd3e7e43555b2922481a9242a306c5b138d69c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 9 Jul 2011 16:49:44 +0200 Subject: [PATCH 03/21] ffmpeg: get rid of a pointless limit on number of streams. --- ffmpeg.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index ba5859df4e..1f339cb33a 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -102,7 +102,6 @@ typedef struct ChapterMap { static const OptionDef options[]; #define MAX_FILES 100 -#define MAX_STREAMS 1024 /* arbitrary sanity check value */ static const char *last_asked_format = NULL; static double *ts_scale; @@ -3081,9 +3080,6 @@ static int opt_input_ts_scale(const char *opt, const char *arg) p++; scale= strtod(p, &p); - if(stream >= MAX_STREAMS) - ffmpeg_exit(1); - ts_scale = grow_array(ts_scale, sizeof(*ts_scale), &nb_ts_scale, stream + 1); ts_scale[stream] = scale; return 0; @@ -3742,7 +3738,7 @@ static int opt_streamid(const char *opt, const char *arg) ffmpeg_exit(1); } *p++ = '\0'; - idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, MAX_STREAMS-1); + idx = parse_number_or_die(opt, idx_str, OPT_INT, 0, INT_MAX); streamid_map = grow_array(streamid_map, sizeof(*streamid_map), &nb_streamid_map, idx+1); streamid_map[idx] = parse_number_or_die(opt, p, OPT_INT, 0, INT_MAX); return 0; From a4ad9438600ea20f4ef459f3f5f397755d48c58b Mon Sep 17 00:00:00 2001 From: Benjamin Larsson Date: Fri, 18 Mar 2011 00:00:15 +0000 Subject: [PATCH 04/21] wav: add an option for writing BEXT chunk Signed-off-by: Anton Khirnov --- Changelog | 4 +++ doc/general.texi | 1 + libavformat/wav.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/Changelog b/Changelog index 943d710836..782d8b3f04 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,10 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. +version : +- BWF muxer + + version 0.7: - E-AC-3 audio encoder diff --git a/doc/general.texi b/doc/general.texi index ace464f024..77a54a3fd0 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -66,6 +66,7 @@ library: @tab Used in Z and Z95 games. @item Brute Force & Ignorance @tab @tab X @tab Used in the game Flash Traffic: City of Angels. +@item BWF @tab X @tab @item Interplay C93 @tab @tab X @tab Used in the game Cyberia from Interplay. @item Delphine Software International CIN @tab @tab X diff --git a/libavformat/wav.c b/libavformat/wav.c index 391461044b..c9086196ca 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -23,22 +23,82 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/log.h" #include "libavutil/mathematics.h" +#include "libavutil/opt.h" #include "avformat.h" #include "avio_internal.h" #include "pcm.h" #include "riff.h" +#include "avio.h" +#include "avio_internal.h" typedef struct { + const AVClass *class; int64_t data; int64_t data_end; int64_t minpts; int64_t maxpts; int last_duration; int w64; + int write_bext; } WAVContext; #if CONFIG_WAV_MUXER +static inline void bwf_write_bext_string(AVFormatContext *s, const char *key, int maxlen) +{ + AVDictionaryEntry *tag; + int len = 0; + + if (tag = av_dict_get(s->metadata, key, NULL, 0)) { + len = strlen(tag->value); + len = FFMIN(len, maxlen); + avio_write(s->pb, tag->value, len); + } + + ffio_fill(s->pb, 0, maxlen - len); +} + +static void bwf_write_bext_chunk(AVFormatContext *s) +{ + AVDictionaryEntry *tmp_tag; + uint64_t time_reference = 0; + int64_t bext = ff_start_tag(s->pb, "bext"); + + bwf_write_bext_string(s, "description", 256); + bwf_write_bext_string(s, "originator", 32); + bwf_write_bext_string(s, "originator_reference", 32); + bwf_write_bext_string(s, "origination_date", 10); + bwf_write_bext_string(s, "origination_time", 8); + + if (tmp_tag = av_dict_get(s->metadata, "time_reference", NULL, 0)) + time_reference = strtoll(tmp_tag->value, NULL, 10); + avio_wl64(s->pb, time_reference); + avio_wl16(s->pb, 1); // set version to 1 + + if (tmp_tag = av_dict_get(s->metadata, "umid", NULL, 0)) { + unsigned char umidpart_str[17] = {0}; + int i; + uint64_t umidpart; + int len = strlen(tmp_tag->value+2); + + for (i = 0; i < len/16; i++) { + memcpy(umidpart_str, tmp_tag->value + 2 + (i*16), 16); + umidpart = strtoll(umidpart_str, NULL, 16); + avio_wb64(s->pb, umidpart); + } + ffio_fill(s->pb, 0, 64 - i*8); + } else + ffio_fill(s->pb, 0, 64); // zero UMID + + ffio_fill(s->pb, 0, 190); // Reserved + + if (tmp_tag = av_dict_get(s->metadata, "coding_history", NULL, 0)) + avio_put_str(s->pb, tmp_tag->value); + + ff_end_tag(s->pb, bext); +} + static int wav_write_header(AVFormatContext *s) { WAVContext *wav = s->priv_data; @@ -65,6 +125,9 @@ static int wav_write_header(AVFormatContext *s) ff_end_tag(pb, fact); } + if (wav->write_bext) + bwf_write_bext_chunk(s); + av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate); wav->maxpts = wav->last_duration = 0; wav->minpts = INT64_MAX; @@ -125,6 +188,20 @@ static int wav_write_trailer(AVFormatContext *s) return 0; } +#define OFFSET(x) offsetof(WAVContext, x) +#define ENC AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "write_bext", "Write BEXT chunk.", OFFSET(write_bext), FF_OPT_TYPE_INT, { 0 }, 0, 1, ENC }, + { NULL }, +}; + +static const AVClass wav_muxer_class = { + .class_name = "WAV muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_wav_muxer = { "wav", NULL_IF_CONFIG_SMALL("WAV format"), @@ -137,6 +214,7 @@ AVOutputFormat ff_wav_muxer = { wav_write_packet, wav_write_trailer, .codec_tag= (const AVCodecTag* const []){ff_codec_wav_tags, 0}, + .priv_class = &wav_muxer_class, }; #endif /* CONFIG_WAV_MUXER */ From 7f84055e2d3814972a61515da7f1d2659b185ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Tue, 17 May 2011 19:46:08 +0200 Subject: [PATCH 05/21] wav: refactor the 'fmt ' tag search and parsing. Moving the search and parsing of the 'fmt ' info the main loop of wav_read_header() allows tags that precede it to be parsed. Creating wav_parse_fmt_tag() makes wav_read_header() easier to read. Signed-off-by: Anton Khirnov --- libavformat/wav.c | 57 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/libavformat/wav.c b/libavformat/wav.c index c9086196ca..3e4e0c4ea4 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -264,6 +264,26 @@ static int wav_probe(AVProbeData *p) return 0; } +static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st) +{ + AVIOContext *pb = s->pb; + int ret; + + /* parse fmt header */ + *st = av_new_stream(s, 0); + if (!*st) + return AVERROR(ENOMEM); + + ret = ff_get_wav_header(pb, (*st)->codec, size); + if (ret < 0) + return ret; + (*st)->need_parsing = AVSTREAM_PARSE_FULL; + + av_set_pts_info(*st, 64, 1, (*st)->codec->sample_rate); + + return 0; +} + /* wav input */ static int wav_read_header(AVFormatContext *s, AVFormatParameters *ap) @@ -275,7 +295,8 @@ static int wav_read_header(AVFormatContext *s, AVIOContext *pb = s->pb; AVStream *st; WAVContext *wav = s->priv_data; - int ret; + int ret, got_fmt = 0; + int64_t next_tag_ofs; /* check RIFF header */ tag = avio_rl32(pb); @@ -300,32 +321,32 @@ static int wav_read_header(AVFormatContext *s, avio_skip(pb, size - 16); /* skip rest of ds64 chunk */ } - /* parse fmt header */ - size = find_tag(pb, MKTAG('f', 'm', 't', ' ')); - if (size < 0) - return -1; - st = av_new_stream(s, 0); - if (!st) - return AVERROR(ENOMEM); - - ret = ff_get_wav_header(pb, st->codec, size); - if (ret < 0) - return ret; - st->need_parsing = AVSTREAM_PARSE_FULL; - - av_set_pts_info(st, 64, 1, st->codec->sample_rate); for (;;) { if (pb->eof_reached) return -1; size = next_tag(pb, &tag); - if (tag == MKTAG('d', 'a', 't', 'a')){ + next_tag_ofs = avio_tell(pb) + size; + + if (tag == MKTAG('f', 'm', 't', ' ')) { + /* only parse the first 'fmt ' tag found */ + if (!got_fmt && (ret = wav_parse_fmt_tag(s, size, &st) < 0)) { + return ret; + } else if (got_fmt) + av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n"); + + got_fmt = 1; + } else if (tag == MKTAG('d', 'a', 't', 'a')) { + if (!got_fmt) { + av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'data' tag\n"); + return AVERROR_INVALIDDATA; + } + break; }else if (tag == MKTAG('f','a','c','t') && !sample_count){ sample_count = avio_rl32(pb); - size -= 4; } - avio_skip(pb, size); + avio_seek(pb, next_tag_ofs, SEEK_SET); } if (rf64) size = data_size; From 1cf18de982a0a62fa9214a6c4a5becc1a32d9caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Tue, 17 May 2011 19:52:36 +0200 Subject: [PATCH 06/21] wav: make sure neither data_size nor sample_count is negative. Signed-off-by: Anton Khirnov --- libavformat/wav.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libavformat/wav.c b/libavformat/wav.c index 3e4e0c4ea4..9f902be818 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -318,6 +318,12 @@ static int wav_read_header(AVFormatContext *s, avio_rl64(pb); /* RIFF size */ data_size = avio_rl64(pb); sample_count = avio_rl64(pb); + if (data_size < 0 || sample_count < 0) { + av_log(s, AV_LOG_ERROR, "negative data_size and/or sample_count in " + "ds64: data_size = %"PRId64", sample_count = %"PRId64"\n", + data_size, sample_count); + return AVERROR_INVALIDDATA; + } avio_skip(pb, size - 16); /* skip rest of ds64 chunk */ } From 90f2ee8cb4d2b135dd33128a94ad6cf126821472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Thu, 17 Feb 2011 15:58:10 +0100 Subject: [PATCH 07/21] wav: Refactor the tag checking into a switch statement Signed-off-by: Anton Khirnov --- libavformat/wav.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libavformat/wav.c b/libavformat/wav.c index 9f902be818..cf815ef3df 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -334,7 +334,8 @@ static int wav_read_header(AVFormatContext *s, size = next_tag(pb, &tag); next_tag_ofs = avio_tell(pb) + size; - if (tag == MKTAG('f', 'm', 't', ' ')) { + switch (tag) { + case MKTAG('f', 'm', 't', ' '): /* only parse the first 'fmt ' tag found */ if (!got_fmt && (ret = wav_parse_fmt_tag(s, size, &st) < 0)) { return ret; @@ -342,18 +343,22 @@ static int wav_read_header(AVFormatContext *s, av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n"); got_fmt = 1; - } else if (tag == MKTAG('d', 'a', 't', 'a')) { + break; + case MKTAG('d', 'a', 't', 'a'): if (!got_fmt) { av_log(s, AV_LOG_ERROR, "found no 'fmt ' tag before the 'data' tag\n"); return AVERROR_INVALIDDATA; } + goto break_loop; + case MKTAG('f','a','c','t'): + if (!sample_count) + sample_count = avio_rl32(pb); break; - }else if (tag == MKTAG('f','a','c','t') && !sample_count){ - sample_count = avio_rl32(pb); } avio_seek(pb, next_tag_ofs, SEEK_SET); } +break_loop: if (rf64) size = data_size; if (size < 0) From 67b1761fcbd8ddcfe7bdb47ace5f46435d8313fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 18 May 2011 13:48:02 +0200 Subject: [PATCH 08/21] wav: keep parsing until EOF if the input is seekable and we know the size of the data tag Signed-off-by: Anton Khirnov --- libavformat/wav.c | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/libavformat/wav.c b/libavformat/wav.c index cf815ef3df..a8312e254e 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -296,7 +296,7 @@ static int wav_read_header(AVFormatContext *s, AVStream *st; WAVContext *wav = s->priv_data; int ret, got_fmt = 0; - int64_t next_tag_ofs; + int64_t next_tag_ofs, data_ofs = -1; /* check RIFF header */ tag = avio_rl32(pb); @@ -327,13 +327,13 @@ static int wav_read_header(AVFormatContext *s, avio_skip(pb, size - 16); /* skip rest of ds64 chunk */ } - for (;;) { - if (pb->eof_reached) - return -1; size = next_tag(pb, &tag); next_tag_ofs = avio_tell(pb) + size; + if (pb->eof_reached) + break; + switch (tag) { case MKTAG('f', 'm', 't', ' '): /* only parse the first 'fmt ' tag found */ @@ -350,26 +350,43 @@ static int wav_read_header(AVFormatContext *s, return AVERROR_INVALIDDATA; } - goto break_loop; + if (rf64) { + next_tag_ofs = wav->data_end = avio_tell(pb) + data_size; + } else { + data_size = size; + next_tag_ofs = wav->data_end = size ? next_tag_ofs : INT64_MAX; + } + + data_ofs = avio_tell(pb); + + /* don't look for footer metadata if we can't seek or if we don't + * know where the data tag ends + */ + if (!pb->seekable || (!rf64 && !size)) + goto break_loop; + break; case MKTAG('f','a','c','t'): if (!sample_count) sample_count = avio_rl32(pb); break; } - avio_seek(pb, next_tag_ofs, SEEK_SET); + + /* seek to next tag unless we know that we'll run into EOF */ + if ((avio_size(pb) > 0 && next_tag_ofs >= avio_size(pb)) || + avio_seek(pb, next_tag_ofs, SEEK_SET) < 0) { + break; + } } break_loop: - if (rf64) - size = data_size; - if (size < 0) - return -1; - if (!size) { - wav->data_end = INT64_MAX; - } else - wav->data_end= avio_tell(pb) + size; + if (data_ofs < 0) { + av_log(s, AV_LOG_ERROR, "no 'data' tag found\n"); + return AVERROR_INVALIDDATA; + } + + avio_seek(pb, data_ofs, SEEK_SET); if (!sample_count && st->codec->channels && av_get_bits_per_sample(st->codec->codec_id)) - sample_count = (size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); + sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); if (sample_count) st->duration = sample_count; return 0; From b21e6b707fbc80511f4886d3b272a77b86157a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 18 May 2011 13:48:39 +0200 Subject: [PATCH 09/21] wav: parse 'bext' metadata Signed-off-by: Anton Khirnov --- doc/general.texi | 2 +- libavformat/wav.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/doc/general.texi b/doc/general.texi index 77a54a3fd0..fe314481a3 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -66,7 +66,7 @@ library: @tab Used in Z and Z95 games. @item Brute Force & Ignorance @tab @tab X @tab Used in the game Flash Traffic: City of Angels. -@item BWF @tab X @tab +@item BWF @tab X @tab X @item Interplay C93 @tab @tab X @tab Used in the game Cyberia from Interplay. @item Delphine Software International CIN @tab @tab X diff --git a/libavformat/wav.c b/libavformat/wav.c index a8312e254e..5b9f6e4480 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -23,6 +23,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" +#include "libavutil/dict.h" #include "libavutil/log.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" @@ -32,6 +34,7 @@ #include "riff.h" #include "avio.h" #include "avio_internal.h" +#include "metadata.h" typedef struct { const AVClass *class; @@ -284,6 +287,97 @@ static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream **st) return 0; } +static inline int wav_parse_bext_string(AVFormatContext *s, const char *key, + int length) +{ + char temp[257]; + int ret; + + av_assert0(length <= sizeof(temp)); + if ((ret = avio_read(s->pb, temp, length)) < 0) + return ret; + + temp[length] = 0; + + if (strlen(temp)) + return av_dict_set(&s->metadata, key, temp, 0); + + return 0; +} + +static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) +{ + char temp[131], *coding_history; + int ret, x; + uint64_t time_reference; + int64_t umid_parts[8], umid_mask = 0; + + if ((ret = wav_parse_bext_string(s, "description", 256)) < 0 || + (ret = wav_parse_bext_string(s, "originator", 32)) < 0 || + (ret = wav_parse_bext_string(s, "originator_reference", 32)) < 0 || + (ret = wav_parse_bext_string(s, "origination_date", 10)) < 0 || + (ret = wav_parse_bext_string(s, "origination_time", 8)) < 0) + return ret; + + time_reference = avio_rl64(s->pb); + snprintf(temp, sizeof(temp), "%"PRIu64, time_reference); + if ((ret = av_dict_set(&s->metadata, "time_reference", temp, 0)) < 0) + return ret; + + /* check if version is >= 1, in which case an UMID may be present */ + if (avio_rl16(s->pb) >= 1) { + for (x = 0; x < 8; x++) + umid_mask |= umid_parts[x] = avio_rb64(s->pb); + + if (umid_mask) { + /* the string formatting below is per SMPTE 330M-2004 Annex C */ + if (umid_parts[4] == 0 && umid_parts[5] == 0 && umid_parts[6] == 0 && umid_parts[7] == 0) { + /* basic UMID */ + snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, + umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3]); + } else { + /* extended UMID */ + snprintf(temp, sizeof(temp), "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64 + "0x%016"PRIX64"%016"PRIX64"%016"PRIX64"%016"PRIX64, + umid_parts[0], umid_parts[1], umid_parts[2], umid_parts[3], + umid_parts[4], umid_parts[5], umid_parts[6], umid_parts[7]); + } + + if ((ret = av_dict_set(&s->metadata, "umid", temp, 0)) < 0) + return ret; + } + + avio_skip(s->pb, 190); + } else + avio_skip(s->pb, 254); + + if (size > 602) { + /* CodingHistory present */ + size -= 602; + + if (!(coding_history = av_malloc(size+1))) + return AVERROR(ENOMEM); + + if ((ret = avio_read(s->pb, coding_history, size)) < 0) + return ret; + + coding_history[size] = 0; + if ((ret = av_dict_set(&s->metadata, "coding_history", coding_history, + AV_METADATA_DONT_STRDUP_VAL)) < 0) + return ret; + } + + return 0; +} + +static const AVMetadataConv wav_metadata_conv[] = { + {"description", "comment" }, + {"originator", "encoded_by" }, + {"origination_date", "date" }, + {"origination_time", "creation_time"}, + {0}, +}; + /* wav input */ static int wav_read_header(AVFormatContext *s, AVFormatParameters *ap) @@ -369,6 +463,10 @@ static int wav_read_header(AVFormatContext *s, if (!sample_count) sample_count = avio_rl32(pb); break; + case MKTAG('b','e','x','t'): + if ((ret = wav_parse_bext_tag(s, size)) < 0) + return ret; + break; } /* seek to next tag unless we know that we'll run into EOF */ @@ -389,6 +487,9 @@ break_loop: sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); if (sample_count) st->duration = sample_count; + + ff_metadata_conv_ctx(s, NULL, wav_metadata_conv); + return 0; } From 001d668d40b5f87d19271c7d5521368b5187425b Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 13 Jul 2011 11:45:17 +0200 Subject: [PATCH 10/21] lavf: factor out conversion of ISO8601 string to unix time --- libavformat/dvenc.c | 7 ++----- libavformat/gxfenc.c | 8 ++------ libavformat/internal.h | 5 +++++ libavformat/movenc.c | 7 ++----- libavformat/mxfenc.c | 7 ++----- libavformat/utils.c | 7 +++++++ 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c index 1e59bd9cc7..5aab6837c5 100644 --- a/libavformat/dvenc.c +++ b/libavformat/dvenc.c @@ -343,11 +343,8 @@ static DVMuxContext* dv_init_mux(AVFormatContext* s) c->start_time = s->timestamp; else #endif - if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { - struct tm time = {0}; - strptime(t->value, "%Y - %m - %dT%T", &time); - c->start_time = mktime(&time); - } + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + c->start_time = ff_iso8601_to_unix_time(t->value); for (i=0; i < c->n_ast; i++) { if (c->ast[i] && !(c->audio_data[i]=av_fifo_alloc(100*AVCODEC_MAX_AUDIO_FRAME_SIZE))) { diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c index 2d4136ab86..99bd71938f 100644 --- a/libavformat/gxfenc.c +++ b/libavformat/gxfenc.c @@ -402,12 +402,8 @@ static int gxf_write_umf_material_description(AVFormatContext *s) timestamp = s->timestamp; else #endif - if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { - struct tm time = {0}; - strptime(t->value, "%Y - %m - %dT%T", &time); - timestamp = mktime(&time); - } - + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + timestamp = ff_iso8601_to_unix_time(t->value); // XXX drop frame uint32_t timecode = diff --git a/libavformat/internal.h b/libavformat/internal.h index aba890def4..8440e6bd0a 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -248,4 +248,9 @@ void ff_make_absolute_url(char *buf, int size, const char *base, enum CodecID ff_guess_image2_codec(const char *filename); +/** + * Convert a date string in ISO8601 format to Unix timestamp. + */ +int64_t ff_iso8601_to_unix_time(const char *datestr); + #endif /* AVFORMAT_INTERNAL_H */ diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 78e5db7444..12ebef5426 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -2266,11 +2266,8 @@ static int mov_write_header(AVFormatContext *s) mov->time = s->timestamp; else #endif - if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { - struct tm time = {0}; - strptime(t->value, "%Y - %m - %dT%T", &time); - mov->time = mktime(&time); - } + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + mov->time = ff_iso8601_to_unix_time(t->value); mov->time += 0x7C25B080; //1970 based -> 1904 based if (mov->chapter_track) diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index d7cc5c1c67..10ba6f3761 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -1519,11 +1519,8 @@ static int mxf_write_header(AVFormatContext *s) timestamp = s->timestamp; else #endif - if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) { - struct tm time = {0}; - strptime(t->value, "%Y - %m - %dT%T", &time); - timestamp = mktime(&time); - } + if (t = av_dict_get(s->metadata, "creation_time", NULL, 0)) + timestamp = ff_iso8601_to_unix_time(t->value); if (timestamp) mxf->timestamp = mxf_parse_timestamp(timestamp); mxf->duration = -1; diff --git a/libavformat/utils.c b/libavformat/utils.c index bbd1b2d07b..bb12e24d8c 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -3884,3 +3884,10 @@ void ff_make_absolute_url(char *buf, int size, const char *base, } av_strlcat(buf, rel, size); } + +int64_t ff_iso8601_to_unix_time(const char *datestr) +{ + struct tm time = {0}; + strptime(datestr, "%Y - %m - %dT%T", &time); + return mktime(&time); +} From 6379900c533d1e556d484e57166873f3ab2505f5 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 13 Jul 2011 09:30:06 +0200 Subject: [PATCH 11/21] Add a check for strptime(). It's an XSI extension, not available on some supported systems. --- configure | 2 ++ libavformat/utils.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/configure b/configure index 02bcd0989c..596b6039e3 100755 --- a/configure +++ b/configure @@ -1105,6 +1105,7 @@ HAVE_LIST=" poll_h setrlimit strerror_r + strptime strtok_r struct_addrinfo struct_ipv6_mreq @@ -2775,6 +2776,7 @@ check_func mmap check_func ${malloc_prefix}posix_memalign && enable posix_memalign check_func setrlimit check_func strerror_r +check_func strptime check_func strtok_r check_func_headers io.h setmode check_func_headers lzo/lzo1x.h lzo1x_999_compress diff --git a/libavformat/utils.c b/libavformat/utils.c index bb12e24d8c..7e79922439 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -3887,7 +3887,13 @@ void ff_make_absolute_url(char *buf, int size, const char *base, int64_t ff_iso8601_to_unix_time(const char *datestr) { +#if HAVE_STRPTIME struct tm time = {0}; strptime(datestr, "%Y - %m - %dT%T", &time); return mktime(&time); +#else + av_log(NULL, AV_LOG_WARNING, "strptime() unavailable on this system, cannot convert " + "the date string.\n"); + return 0; +#endif } From 2c4d7bf0083fc79a144ffed84200412cbf3f603c Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 13 Jul 2011 12:21:00 +0100 Subject: [PATCH 12/21] mxfenc: include needed header for ff_iso8601_to_unix_time() prototype Signed-off-by: Mans Rullgard --- libavformat/mxfenc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 10ba6f3761..7dadec080f 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -39,6 +39,7 @@ #include "libavcodec/bytestream.h" #include "audiointerleave.h" #include "avformat.h" +#include "internal.h" #include "mxf.h" static const int NTSC_samples_per_frame[] = { 1602, 1601, 1602, 1601, 1602, 0 }; From 191c5f8ff33eb995b6dbc5b11af7c1a79f8381f0 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Wed, 13 Jul 2011 02:09:19 +0200 Subject: [PATCH 13/21] build: move tests/seek_test.c to libavformat and reuse generic build rules --- .gitignore | 1 - libavformat/Makefile | 2 +- tests/seek_test.c => libavformat/seek-test.c | 0 tests/Makefile | 6 +----- tests/fate-run.sh | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) rename tests/seek_test.c => libavformat/seek-test.c (100%) diff --git a/.gitignore b/.gitignore index 59a0860759..bfce23d311 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,6 @@ tests/audiogen tests/base64 tests/data tests/rotozoom -tests/seek_test tests/tiny_psnr tests/videogen tests/vsynth1 diff --git a/libavformat/Makefile b/libavformat/Makefile index ca337e0167..917b38a0d8 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -334,7 +334,7 @@ OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o OBJS-$(CONFIG_JACK_INDEV) += timefilter.o EXAMPLES = metadata output -TESTPROGS = timefilter +TESTPROGS = seek timefilter TOOLS = pktdumper probetest include $(SRC_PATH)/subdir.mak diff --git a/tests/seek_test.c b/libavformat/seek-test.c similarity index 100% rename from tests/seek_test.c rename to libavformat/seek-test.c diff --git a/tests/Makefile b/tests/Makefile index 35e803d102..4739446674 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -28,9 +28,6 @@ tests/data/asynth1.sw: tests/audiogen$(HOSTEXESUF) tests/data/asynth1.sw tests/vsynth%/00.pgm: TAG = GEN -tests/seek_test$(EXESUF): tests/seek_test.o $(FF_DEP_LIBS) - $(LD) $(LDFLAGS) -o $@ $< $(FF_EXTRALIBS) - include $(SRC_PATH)/tests/fate.mak include $(SRC_PATH)/tests/fate2.mak @@ -64,7 +61,7 @@ $(filter-out %-aref,$(FATE_ACODEC)): $(AREF) $(filter-out %-vref,$(FATE_VCODEC)): $(VREF) $(FATE_LAVF): $(REFS) $(FATE_LAVFI): $(REFS) tools/lavfi-showfiltfmts$(EXESUF) -$(FATE_SEEK): fate-codec fate-lavf tests/seek_test$(EXESUF) +$(FATE_SEEK): fate-codec fate-lavf libavformat/seek-test$(EXESUF) $(FATE_ACODEC): CMD = codectest acodec $(FATE_VSYNTH1): CMD = codectest vsynth1 @@ -107,7 +104,6 @@ clean:: testclean testclean: $(RM) -r tests/vsynth1 tests/vsynth2 tests/data $(RM) $(CLEANSUFFIXES:%=tests/%) - $(RM) tests/seek_test$(EXESUF) tests/seek_test.o $(RM) $(TESTTOOLS:%=tests/%$(HOSTEXESUF)) -include $(wildcard tests/*.d) diff --git a/tests/fate-run.sh b/tests/fate-run.sh index 10497c497e..4121035853 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -104,7 +104,7 @@ seektest(){ file=$(echo tests/data/$d/$file) ;; esac - $target_exec $target_path/tests/seek_test $target_path/$file + $target_exec $target_path/libavformat/seek-test $target_path/$file } mkdir -p "$outdir" From 71a1d1116fd952f348d732c19ba7f4ebe041ce26 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Mon, 11 Jul 2011 16:32:54 +0200 Subject: [PATCH 14/21] Replace some gotos that lead to single return statements by direct return. --- ffmpeg.c | 10 ++++------ ffplay.c | 15 +++++++-------- ffserver.c | 6 ++---- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index 1f339cb33a..ccf9c62486 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -1522,7 +1522,7 @@ static int output_packet(InputStream *ist, int ist_index, ret = avcodec_decode_audio3(ist->st->codec, samples, &decoded_data_size, &avpkt); if (ret < 0) - goto fail_decode; + return ret; avpkt.data += ret; avpkt.size -= ret; data_size = ret; @@ -1549,7 +1549,7 @@ static int output_packet(InputStream *ist, int ist_index, &picture, &got_output, &avpkt); quality = same_quality ? picture.quality : 0; if (ret < 0) - goto fail_decode; + return ret; if (!got_output) { /* no picture yet */ goto discard_packet; @@ -1569,7 +1569,7 @@ static int output_packet(InputStream *ist, int ist_index, ret = avcodec_decode_subtitle2(ist->st->codec, &subtitle, &got_output, &avpkt); if (ret < 0) - goto fail_decode; + return ret; if (!got_output) { goto discard_packet; } @@ -1577,7 +1577,7 @@ static int output_packet(InputStream *ist, int ist_index, avpkt.size = 0; break; default: - goto fail_decode; + return -1; } } else { switch(ist->st->codec->codec_type) { @@ -1849,8 +1849,6 @@ static int output_packet(InputStream *ist, int ist_index, } return 0; - fail_decode: - return -1; } static void print_sdp(AVFormatContext **avc, int n) diff --git a/ffplay.c b/ffplay.c index cb5567d283..bbbf5c6032 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1709,10 +1709,10 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c if ((ret = avfilter_graph_create_filter(&filt_src, &input_filter, "src", NULL, is, graph)) < 0) - goto the_end; + return ret; if ((ret = avfilter_graph_create_filter(&filt_out, &ffsink, "out", NULL, &ffsink_ctx, graph)) < 0) - goto the_end; + return ret; if(vfilters) { AVFilterInOut *outputs = av_malloc(sizeof(AVFilterInOut)); @@ -1729,18 +1729,18 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c inputs->next = NULL; if ((ret = avfilter_graph_parse(graph, vfilters, inputs, outputs, NULL)) < 0) - goto the_end; + return ret; av_freep(&vfilters); } else { if ((ret = avfilter_link(filt_src, 0, filt_out, 0)) < 0) - goto the_end; + return ret; } if ((ret = avfilter_graph_config(graph, NULL)) < 0) - goto the_end; + return ret; is->out_video_filter = filt_out; -the_end: + return ret; } @@ -1850,7 +1850,7 @@ static int subtitle_thread(void *arg) SDL_UnlockMutex(is->subpq_mutex); if (is->subtitleq.abort_request) - goto the_end; + return 0; sp = &is->subpq[is->subpq_windex]; @@ -1887,7 +1887,6 @@ static int subtitle_thread(void *arg) } av_free_packet(pkt); } - the_end: return 0; } diff --git a/ffserver.c b/ffserver.c index 1dc8a17f2f..ca4b54f4d4 100644 --- a/ffserver.c +++ b/ffserver.c @@ -3508,7 +3508,7 @@ static int add_av_stream(FFStream *feed, AVStream *st) case AVMEDIA_TYPE_AUDIO: if (av1->channels == av->channels && av1->sample_rate == av->sample_rate) - goto found; + return i; break; case AVMEDIA_TYPE_VIDEO: if (av1->width == av->width && @@ -3516,7 +3516,7 @@ static int add_av_stream(FFStream *feed, AVStream *st) av1->time_base.den == av->time_base.den && av1->time_base.num == av->time_base.num && av1->gop_size == av->gop_size) - goto found; + return i; break; default: abort(); @@ -3528,8 +3528,6 @@ static int add_av_stream(FFStream *feed, AVStream *st) if (!fst) return -1; return feed->nb_streams - 1; - found: - return i; } static void remove_stream(FFStream *stream) From a58858d60d37c7abfcea11bb387909bf9cd4916d Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Tue, 12 Jul 2011 15:13:29 -0700 Subject: [PATCH 15/21] lavf: Cleanup try_decode_frame() logic. This fixes AAC playback in ffplay. --- libavcodec/aacdec.c | 3 --- libavformat/utils.c | 9 +++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index f26a4b74a7..dac85c229d 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -568,9 +568,6 @@ static av_cold int aac_decode_init(AVCodecContext *avctx) ac->m4ac.sample_rate = avctx->sample_rate; if (avctx->extradata_size > 0) { - avctx->channels = 0; - avctx->frame_size = 0; - avctx->sample_rate = 0; if (decode_audio_specific_config(ac, ac->avctx, &ac->m4ac, avctx->extradata, avctx->extradata_size) < 0) diff --git a/libavformat/utils.c b/libavformat/utils.c index 7e79922439..e738dba44a 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2090,7 +2090,8 @@ static int try_decode_frame(AVStream *st, AVPacket *avpkt, AVDictionary **option return ret; } - if(!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st)){ + if(!has_codec_parameters(st->codec) || !has_decode_delay_been_guessed(st) || + (!st->codec_info_nb_frames && st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF)) { switch(st->codec->codec_type) { case AVMEDIA_TYPE_VIDEO: avcodec_get_frame_defaults(&picture); @@ -2387,11 +2388,7 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) least one frame of codec data, this makes sure the codec initializes the channel configuration and does not only trust the values from the container. */ - if (!has_codec_parameters(st->codec) || - !has_decode_delay_been_guessed(st) || - (st->codec->codec && - st->codec->codec->capabilities & CODEC_CAP_CHANNEL_CONF)) - try_decode_frame(st, pkt, (options && i <= orig_nb_streams )? &options[i] : NULL); + try_decode_frame(st, pkt, (options && i <= orig_nb_streams )? &options[i] : NULL); st->codec_info_nb_frames++; count++; From 575c38d76ce546842d62a481ef03c122d55d3a69 Mon Sep 17 00:00:00 2001 From: Jindrich Makovicka Date: Wed, 29 Jun 2011 15:01:39 +0200 Subject: [PATCH 16/21] mpegtsenc: set Random Access indicator on keyframe start packets Signed-off-by: Jindrich Makovicka Signed-off-by: Anton Khirnov --- libavformat/mpegtsenc.c | 67 ++++++++++++++++++++++++++++++++++------- tests/ref/lavf/ts | 2 +- 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index 83ede1d79b..72ff289df6 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -204,6 +204,7 @@ typedef struct MpegTSWriteStream { int first_pts_check; ///< first pts check needed int64_t payload_pts; int64_t payload_dts; + int payload_flags; uint8_t payload[DEFAULT_PES_PAYLOAD_SIZE]; ADTSContext *adts; } MpegTSWriteStream; @@ -621,7 +622,7 @@ static int64_t get_pcr(const MpegTSWrite *ts, AVIOContext *pb) ts->first_pcr; } -static uint8_t* write_pcr_bits(uint8_t *buf, int64_t pcr) +static int write_pcr_bits(uint8_t *buf, int64_t pcr) { int64_t pcr_low = pcr % 300, pcr_high = pcr / 300; @@ -632,7 +633,7 @@ static uint8_t* write_pcr_bits(uint8_t *buf, int64_t pcr) *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e; *buf++ = pcr_low; - return buf; + return 6; } /* Write a single null transport stream packet */ @@ -668,7 +669,7 @@ static void mpegts_insert_pcr_only(AVFormatContext *s, AVStream *st) *q++ = 0x10; /* Adaptation flags: PCR present */ /* PCR coded into 6 bytes */ - q = write_pcr_bits(q, get_pcr(ts, s->pb)); + q += write_pcr_bits(q, get_pcr(ts, s->pb)); /* stuffing bytes */ memset(q, 0xFF, TS_PACKET_SIZE - (q - buf)); @@ -689,6 +690,39 @@ static void write_pts(uint8_t *q, int fourbits, int64_t pts) *q++ = val; } +/* Set an adaptation field flag in an MPEG-TS packet*/ +static void set_af_flag(uint8_t *pkt, int flag) +{ + // expect at least one flag to set + assert(flag); + + if ((pkt[3] & 0x20) == 0) { + // no AF yet, set adaptation field flag + pkt[3] |= 0x20; + // 1 byte length, no flags + pkt[4] = 1; + pkt[5] = 0; + } + pkt[5] |= flag; +} + +/* Extend the adaptation field by size bytes */ +static void extend_af(uint8_t *pkt, int size) +{ + // expect already existing adaptation field + assert(pkt[3] & 0x20); + pkt[4] += size; +} + +/* Get a pointer to MPEG-TS payload (right after TS packet header) */ +static uint8_t *get_ts_payload_start(uint8_t *pkt) +{ + if (pkt[3] & 0x20) + return pkt + 5 + pkt[4]; + else + return pkt + 4; +} + /* Add a pes header to the front of payload, and segment into an integer number of * ts packets. The final ts packet is padded using an over-sized adaptation header * to exactly fill the last ts packet. @@ -696,7 +730,7 @@ static void write_pts(uint8_t *q, int fourbits, int64_t pts) */ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, const uint8_t *payload, int payload_size, - int64_t pts, int64_t dts) + int64_t pts, int64_t dts, int key) { MpegTSWriteStream *ts_st = st->priv_data; MpegTSWrite *ts = s->priv_data; @@ -741,8 +775,17 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, *q++ = val; *q++ = ts_st->pid; ts_st->cc = (ts_st->cc + 1) & 0xf; - *q++ = 0x10 | ts_st->cc | (write_pcr ? 0x20 : 0); + *q++ = 0x10 | ts_st->cc; // payload indicator + CC + if (key && is_start && pts != AV_NOPTS_VALUE) { + // set Random Access for key frames + if (ts_st->pid == ts_st->service->pcr_pid) + write_pcr = 1; + set_af_flag(buf, 0x40); + q = get_ts_payload_start(buf); + } if (write_pcr) { + set_af_flag(buf, 0x10); + q = get_ts_payload_start(buf); // add 11, pcr references the last byte of program clock reference base if (ts->mux_rate > 1) pcr = get_pcr(ts, s->pb); @@ -750,9 +793,8 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, pcr = (dts - delay)*300; if (dts != AV_NOPTS_VALUE && dts < pcr / 300) av_log(s, AV_LOG_WARNING, "dts < pcr, TS is invalid\n"); - *q++ = 7; /* AFC length */ - *q++ = 0x10; /* flags: PCR present */ - q = write_pcr_bits(q, pcr); + extend_af(buf, write_pcr_bits(q, pcr)); + q = get_ts_payload_start(buf); } if (is_start) { int pes_extension = 0; @@ -950,20 +992,22 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) { // for video and subtitle, write a single pes packet - mpegts_write_pes(s, st, buf, size, pts, dts); + mpegts_write_pes(s, st, buf, size, pts, dts, pkt->flags & AV_PKT_FLAG_KEY); av_free(data); return 0; } if (ts_st->payload_index + size > DEFAULT_PES_PAYLOAD_SIZE) { mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index, - ts_st->payload_pts, ts_st->payload_dts); + ts_st->payload_pts, ts_st->payload_dts, + ts_st->payload_flags & AV_PKT_FLAG_KEY); ts_st->payload_index = 0; } if (!ts_st->payload_index) { ts_st->payload_pts = pts; ts_st->payload_dts = dts; + ts_st->payload_flags = pkt->flags; } memcpy(ts_st->payload + ts_st->payload_index, buf, size); @@ -988,7 +1032,8 @@ static int mpegts_write_end(AVFormatContext *s) ts_st = st->priv_data; if (ts_st->payload_index > 0) { mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index, - ts_st->payload_pts, ts_st->payload_dts); + ts_st->payload_pts, ts_st->payload_dts, + ts_st->payload_flags & AV_PKT_FLAG_KEY); } av_freep(&ts_st->adts); } diff --git a/tests/ref/lavf/ts b/tests/ref/lavf/ts index 989f8fbfba..325112cebc 100644 --- a/tests/ref/lavf/ts +++ b/tests/ref/lavf/ts @@ -1,3 +1,3 @@ -d260ac0534ff2e26b44b5192fd4fdc21 *./tests/data/lavf/lavf.ts +9708011dd80212a0041a96da878122c2 *./tests/data/lavf/lavf.ts 406644 ./tests/data/lavf/lavf.ts ./tests/data/lavf/lavf.ts CRC=0x133216c1 From 13551ad1e336573e3732fdeaf25607c47244bb80 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 12 Jul 2011 22:42:18 +0200 Subject: [PATCH 17/21] lavf: fix segfault in av_open_input_stream() ic is NULL in case of error. --- libavformat/utils.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libavformat/utils.c b/libavformat/utils.c index e738dba44a..71fa95526c 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -466,7 +466,8 @@ int av_open_input_stream(AVFormatContext **ic_ptr, else ic->pb = pb; - err = avformat_open_input(&ic, filename, fmt, &opts); + if ((err = avformat_open_input(&ic, filename, fmt, &opts)) < 0) + goto fail; ic->pb = ic->pb ? ic->pb : pb; // don't leak custom pb if it wasn't set above *ic_ptr = ic; From cdc5a3a194ac9275129ca88da005786ebaceb268 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Wed, 29 Jun 2011 14:13:17 -0700 Subject: [PATCH 18/21] mpeg1video: add CODEC_CAP_SLICE_THREADS. --- libavcodec/mpeg12.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 4cbfa8d636..059083277a 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -2539,7 +2539,7 @@ AVCodec ff_mpeg1video_decoder = { NULL, mpeg_decode_end, mpeg_decode_frame, - CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY, + CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 | CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS, .flush= flush, .max_lowres= 3, .long_name= NULL_IF_CONFIG_SMALL("MPEG-1 video"), From f501157e5352e418b28cf6728208ea028bf3505c Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 13 Jul 2011 15:49:08 -0400 Subject: [PATCH 19/21] ac3enc: fix memleak --- libavcodec/ac3enc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 809a3f5a4f..f957ee9258 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -1820,6 +1820,8 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) av_freep(&s->band_psd_buffer); av_freep(&s->mask_buffer); av_freep(&s->qmant_buffer); + av_freep(&s->cpl_coord_exp_buffer); + av_freep(&s->cpl_coord_mant_buffer); for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) { AC3Block *block = &s->blocks[blk]; av_freep(&block->mdct_coef); @@ -1830,6 +1832,8 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) av_freep(&block->band_psd); av_freep(&block->mask); av_freep(&block->qmant); + av_freep(&block->cpl_coord_exp); + av_freep(&block->cpl_coord_mant); } s->mdct_end(s->mdct); From 82cea7cb6c38e251f88fbf090cd5361f5d0a49de Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 13 Jul 2011 13:53:58 -0400 Subject: [PATCH 20/21] ac3enc: prefer passing AC3EncodeContext rather than AVCodecContext --- libavcodec/ac3enc.c | 23 ++++++++++++----------- libavcodec/ac3enc.h | 2 +- libavcodec/ac3enc_template.c | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index f957ee9258..f6a3b31160 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -1535,10 +1535,10 @@ void ff_ac3_output_frame(AC3EncodeContext *s, unsigned char *frame) } -static void dprint_options(AVCodecContext *avctx) +static void dprint_options(AC3EncodeContext *s) { #ifdef DEBUG - AC3EncodeContext *s = avctx->priv_data; + AVCodecContext *avctx = s->avctx; AC3EncOptions *opt = &s->options; char strbuf[32]; @@ -1689,9 +1689,9 @@ static void validate_mix_level(void *log_ctx, const char *opt_name, * Validate metadata options as set by AVOption system. * These values can optionally be changed per-frame. */ -int ff_ac3_validate_metadata(AVCodecContext *avctx) +int ff_ac3_validate_metadata(AC3EncodeContext *s) { - AC3EncodeContext *s = avctx->priv_data; + AVCodecContext *avctx = s->avctx; AC3EncOptions *opt = &s->options; /* validate mixing levels */ @@ -1892,8 +1892,9 @@ static av_cold int set_channel_info(AC3EncodeContext *s, int channels, } -static av_cold int validate_options(AVCodecContext *avctx, AC3EncodeContext *s) +static av_cold int validate_options(AC3EncodeContext *s) { + AVCodecContext *avctx = s->avctx; int i, ret, max_sr; /* validate channel layout */ @@ -1998,7 +1999,7 @@ static av_cold int validate_options(AVCodecContext *avctx, AC3EncodeContext *s) } if (!s->eac3) { - ret = ff_ac3_validate_metadata(avctx); + ret = ff_ac3_validate_metadata(s); if (ret) return ret; } @@ -2085,10 +2086,10 @@ static av_cold void set_bandwidth(AC3EncodeContext *s) } -static av_cold int allocate_buffers(AVCodecContext *avctx) +static av_cold int allocate_buffers(AC3EncodeContext *s) { + AVCodecContext *avctx = s->avctx; int blk, ch; - AC3EncodeContext *s = avctx->priv_data; int channels = s->channels + 1; /* includes coupling channel */ if (s->allocate_sample_buffers(s)) @@ -2201,7 +2202,7 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) ff_ac3_common_init(); - ret = validate_options(avctx, s); + ret = validate_options(s); if (ret) return ret; @@ -2246,7 +2247,7 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) if (ret) goto init_fail; - ret = allocate_buffers(avctx); + ret = allocate_buffers(s); if (ret) goto init_fail; @@ -2255,7 +2256,7 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) dsputil_init(&s->dsp, avctx); ff_ac3dsp_init(&s->ac3dsp, avctx->flags & CODEC_FLAG_BITEXACT); - dprint_options(avctx); + dprint_options(s); return 0; init_fail: diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h index 54f427a523..ccef7079e4 100644 --- a/libavcodec/ac3enc.h +++ b/libavcodec/ac3enc.h @@ -243,7 +243,7 @@ int ff_ac3_encode_init(AVCodecContext *avctx); int ff_ac3_encode_close(AVCodecContext *avctx); -int ff_ac3_validate_metadata(AVCodecContext *avctx); +int ff_ac3_validate_metadata(AC3EncodeContext *s); void ff_ac3_adjust_frame_size(AC3EncodeContext *s); diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index c7243c7644..95c190b666 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -424,7 +424,7 @@ int AC3_NAME(encode_frame)(AVCodecContext *avctx, unsigned char *frame, int ret; if (!s->eac3 && s->options.allow_per_frame_metadata) { - ret = ff_ac3_validate_metadata(avctx); + ret = ff_ac3_validate_metadata(s); if (ret) return ret; } From b5849f77095439e994b11c25e6063d443b36c228 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 13 Jul 2011 15:12:11 -0400 Subject: [PATCH 21/21] ac3enc: merge AC3MDCTContext with AC3EncodeContext. Since both the fixed-point and floating-point encoders use the FFTContext, this no longer needs to be in a separate context. Also, when a short-transform context is added, the same MDCT window will be used. --- libavcodec/ac3enc.c | 6 ++---- libavcodec/ac3enc.h | 22 ++++++++-------------- libavcodec/ac3enc_fixed.c | 11 +++++------ libavcodec/ac3enc_float.c | 17 ++++++++--------- libavcodec/ac3enc_template.c | 6 +++--- 5 files changed, 26 insertions(+), 36 deletions(-) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index f6a3b31160..fb4d33441e 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -1836,8 +1836,7 @@ av_cold int ff_ac3_encode_close(AVCodecContext *avctx) av_freep(&block->cpl_coord_mant); } - s->mdct_end(s->mdct); - av_freep(&s->mdct); + s->mdct_end(s); av_freep(&avctx->coded_frame); return 0; @@ -2242,8 +2241,7 @@ av_cold int ff_ac3_encode_init(AVCodecContext *avctx) bit_alloc_init(s); - FF_ALLOCZ_OR_GOTO(avctx, s->mdct, sizeof(AC3MDCTContext), init_fail); - ret = s->mdct_init(avctx, s->mdct, 9); + ret = s->mdct_init(s); if (ret) goto init_fail; diff --git a/libavcodec/ac3enc.h b/libavcodec/ac3enc.h index ccef7079e4..6caf4d80c4 100644 --- a/libavcodec/ac3enc.h +++ b/libavcodec/ac3enc.h @@ -66,11 +66,6 @@ typedef int64_t CoefSumType; #endif -typedef struct AC3MDCTContext { - const SampleType *window; ///< MDCT window function - FFTContext fft; ///< FFT context for MDCT calculation -} AC3MDCTContext; - /** * Encoding Options used by AVOption. */ @@ -143,7 +138,8 @@ typedef struct AC3EncodeContext { PutBitContext pb; ///< bitstream writer context DSPContext dsp; AC3DSPContext ac3dsp; ///< AC-3 optimized functions - AC3MDCTContext *mdct; ///< MDCT context + FFTContext mdct; ///< FFT context for MDCT calculation + const SampleType *mdct_window; ///< MDCT window function array AC3Block blocks[AC3_MAX_BLOCKS]; ///< per-block info @@ -226,8 +222,8 @@ typedef struct AC3EncodeContext { int ref_bap_set; ///< indicates if ref_bap pointers have been set /* fixed vs. float function pointers */ - void (*mdct_end)(AC3MDCTContext *mdct); - int (*mdct_init)(AVCodecContext *avctx, AC3MDCTContext *mdct, int nbits); + void (*mdct_end)(struct AC3EncodeContext *s); + int (*mdct_init)(struct AC3EncodeContext *s); /* fixed vs. float templated function pointers */ int (*allocate_sample_buffers)(struct AC3EncodeContext *s); @@ -262,13 +258,11 @@ void ff_ac3_output_frame(AC3EncodeContext *s, unsigned char *frame); /* prototypes for functions in ac3enc_fixed.c and ac3enc_float.c */ -void ff_ac3_fixed_mdct_end(AC3MDCTContext *mdct); -void ff_ac3_float_mdct_end(AC3MDCTContext *mdct); +void ff_ac3_fixed_mdct_end(AC3EncodeContext *s); +void ff_ac3_float_mdct_end(AC3EncodeContext *s); -int ff_ac3_fixed_mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct, - int nbits); -int ff_ac3_float_mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct, - int nbits); +int ff_ac3_fixed_mdct_init(AC3EncodeContext *s); +int ff_ac3_float_mdct_init(AC3EncodeContext *s); /* prototypes for functions in ac3enc_template.c */ diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index ea3a46cdfa..15c5a4bca7 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -41,9 +41,9 @@ static AVClass ac3enc_class = { "Fixed-Point AC-3 Encoder", av_default_item_name /** * Finalize MDCT and free allocated memory. */ -av_cold void AC3_NAME(mdct_end)(AC3MDCTContext *mdct) +av_cold void AC3_NAME(mdct_end)(AC3EncodeContext *s) { - ff_mdct_end(&mdct->fft); + ff_mdct_end(&s->mdct); } @@ -51,11 +51,10 @@ av_cold void AC3_NAME(mdct_end)(AC3MDCTContext *mdct) * Initialize MDCT tables. * @param nbits log2(MDCT size) */ -av_cold int AC3_NAME(mdct_init)(AVCodecContext *avctx, AC3MDCTContext *mdct, - int nbits) +av_cold int AC3_NAME(mdct_init)(AC3EncodeContext *s) { - int ret = ff_mdct_init(&mdct->fft, nbits, 0, -1.0); - mdct->window = ff_ac3_window; + int ret = ff_mdct_init(&s->mdct, 9, 0, -1.0); + s->mdct_window = ff_ac3_window; return ret; } diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index 718cc1f2b2..deec79ce8f 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -45,10 +45,10 @@ static AVClass ac3enc_class = { "AC-3 Encoder", av_default_item_name, /** * Finalize MDCT and free allocated memory. */ -av_cold void ff_ac3_float_mdct_end(AC3MDCTContext *mdct) +av_cold void ff_ac3_float_mdct_end(AC3EncodeContext *s) { - ff_mdct_end(&mdct->fft); - av_freep(&mdct->window); + ff_mdct_end(&s->mdct); + av_freep(&s->mdct_window); } @@ -56,26 +56,25 @@ av_cold void ff_ac3_float_mdct_end(AC3MDCTContext *mdct) * Initialize MDCT tables. * @param nbits log2(MDCT size) */ -av_cold int ff_ac3_float_mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct, - int nbits) +av_cold int ff_ac3_float_mdct_init(AC3EncodeContext *s) { float *window; int i, n, n2; - n = 1 << nbits; + n = 1 << 9; n2 = n >> 1; window = av_malloc(n * sizeof(*window)); if (!window) { - av_log(avctx, AV_LOG_ERROR, "Cannot allocate memory.\n"); + av_log(s->avctx, AV_LOG_ERROR, "Cannot allocate memory.\n"); return AVERROR(ENOMEM); } ff_kbd_window_init(window, 5.0, n2); for (i = 0; i < n2; i++) window[n-1-i] = window[i]; - mdct->window = window; + s->mdct_window = window; - return ff_mdct_init(&mdct->fft, nbits, 0, -2.0 / n); + return ff_mdct_init(&s->mdct, 9, 0, -2.0 / n); } diff --git a/libavcodec/ac3enc_template.c b/libavcodec/ac3enc_template.c index 95c190b666..9b9151b3e0 100644 --- a/libavcodec/ac3enc_template.c +++ b/libavcodec/ac3enc_template.c @@ -108,13 +108,13 @@ static void apply_mdct(AC3EncodeContext *s) const SampleType *input_samples = &s->planar_samples[ch][blk * AC3_BLOCK_SIZE]; apply_window(&s->dsp, s->windowed_samples, input_samples, - s->mdct->window, AC3_WINDOW_SIZE); + s->mdct_window, AC3_WINDOW_SIZE); if (s->fixed_point) block->coeff_shift[ch+1] = normalize_samples(s); - s->mdct->fft.mdct_calcw(&s->mdct->fft, block->mdct_coef[ch+1], - s->windowed_samples); + s->mdct.mdct_calcw(&s->mdct, block->mdct_coef[ch+1], + s->windowed_samples); } } }