aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2011-07-14 02:22:48 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-07-14 02:24:10 +0200
commit80e4fe4063001d0cf468d5f4c7c02ba5b04484b7 (patch)
treeab237b4967339905110c59f6a118bfda9a5a5433 /libavformat
parent6b61920ab76dc6d85ef462909951923935dd643f (diff)
parentb5849f77095439e994b11c25e6063d443b36c228 (diff)
downloadffmpeg-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/Makefile2
-rw-r--r--libavformat/dvenc.c7
-rw-r--r--libavformat/gxfenc.c8
-rw-r--r--libavformat/internal.h5
-rw-r--r--libavformat/movenc.c7
-rw-r--r--libavformat/mpc.c16
-rw-r--r--libavformat/mpegtsenc.c67
-rw-r--r--libavformat/mxfenc.c8
-rw-r--r--libavformat/utils.c25
-rw-r--r--libavformat/wav.c87
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'):