diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2011-07-14 02:22:48 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-07-14 02:24:10 +0200 |
commit | 80e4fe4063001d0cf468d5f4c7c02ba5b04484b7 (patch) | |
tree | ab237b4967339905110c59f6a118bfda9a5a5433 /libavformat | |
parent | 6b61920ab76dc6d85ef462909951923935dd643f (diff) | |
parent | b5849f77095439e994b11c25e6063d443b36c228 (diff) | |
download | ffmpeg-80e4fe4063001d0cf468d5f4c7c02ba5b04484b7.tar.gz |
Merge commit 'b5849f77095439e994b11c25e6063d443b36c228'
* commit 'b5849f77095439e994b11c25e6063d443b36c228': (21 commits)
ac3enc: merge AC3MDCTContext with AC3EncodeContext.
ac3enc: prefer passing AC3EncodeContext rather than AVCodecContext
ac3enc: fix memleak
mpeg1video: add CODEC_CAP_SLICE_THREADS.
lavf: fix segfault in av_open_input_stream()
mpegtsenc: set Random Access indicator on keyframe start packets
lavf: Cleanup try_decode_frame() logic.
Replace some gotos that lead to single return statements by direct return.
build: move tests/seek_test.c to libavformat and reuse generic build rules
mxfenc: include needed header for ff_iso8601_to_unix_time() prototype
Add a check for strptime().
lavf: factor out conversion of ISO8601 string to unix time
wav: parse 'bext' metadata
wav: keep parsing until EOF if the input is seekable and we know the size of the data tag
wav: Refactor the tag checking into a switch statement
wav: make sure neither data_size nor sample_count is negative.
wav: refactor the 'fmt ' tag search and parsing.
wav: add an option for writing BEXT chunk
ffmpeg: get rid of a pointless limit on number of streams.
ffmpeg: remove an unused define.
...
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/Makefile | 2 | ||||
-rw-r--r-- | libavformat/dvenc.c | 7 | ||||
-rw-r--r-- | libavformat/gxfenc.c | 8 | ||||
-rw-r--r-- | libavformat/internal.h | 5 | ||||
-rw-r--r-- | libavformat/movenc.c | 7 | ||||
-rw-r--r-- | libavformat/mpc.c | 16 | ||||
-rw-r--r-- | libavformat/mpegtsenc.c | 67 | ||||
-rw-r--r-- | libavformat/mxfenc.c | 8 | ||||
-rw-r--r-- | libavformat/utils.c | 25 | ||||
-rw-r--r-- | libavformat/wav.c | 87 |
10 files changed, 186 insertions, 46 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile index ce4891bc77..9f5bfb42ad 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -341,7 +341,7 @@ OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o OBJS-$(CONFIG_ALSA_INDEV) += timefilter.o OBJS-$(CONFIG_JACK_INDEV) += timefilter.o -TESTPROGS = timefilter +TESTPROGS = seek timefilter TOOLS = pktdumper probetest include $(SRC_PATH)/subdir.mak diff --git a/libavformat/dvenc.c b/libavformat/dvenc.c index 3b2a8eb711..217ee56b84 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 62ee4eb751..d7c8698b61 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 7c8eaf258a..72f15d3362 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -246,4 +246,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 41c59d49c1..af6d48b801 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -2279,11 +2279,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/mpc.c b/libavformat/mpc.c index 4d6854f13f..aba73a7d6d 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; diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index a7e13e83d5..d1386aa6fa 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/libavformat/mxfenc.c b/libavformat/mxfenc.c index ad91c6a2ad..37e5e3d2ca 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 }; @@ -1519,11 +1520,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 b9a4ebab9d..3d949baf24 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -471,7 +471,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; @@ -2129,7 +2130,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); @@ -2436,11 +2438,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++; @@ -4012,3 +4010,16 @@ 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) +{ +#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 +} diff --git a/libavformat/wav.c b/libavformat/wav.c index f09e676ce0..22419ccb4a 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -23,23 +23,85 @@ * 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" #include "avformat.h" #include "avio_internal.h" #include "pcm.h" #include "riff.h" +#include "avio.h" +#include "avio_internal.h" #include "metadata.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; @@ -66,6 +128,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; @@ -126,6 +191,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"), @@ -138,6 +217,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 */ @@ -207,11 +287,13 @@ 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) +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; @@ -337,6 +419,7 @@ static int wav_read_header(AVFormatContext *s, return AVERROR_INVALIDDATA; } avio_skip(pb, size - 24); /* skip rest of ds64 chunk */ + } for (;;) { @@ -378,7 +461,7 @@ static int wav_read_header(AVFormatContext *s, goto break_loop; break; case MKTAG('f','a','c','t'): - if(!sample_count) + if (!sample_count) sample_count = avio_rl32(pb); break; case MKTAG('b','e','x','t'): |