From 194be1f43ea391eb986732707435176e579265aa Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 18 May 2014 12:12:59 +0200 Subject: [PATCH] lavf: switch to AVStream.time_base as the hint for the muxer timebase Previously, AVStream.codec.time_base was used for that purpose, which was quite confusing for the callers. This change also opens the path for removing AVStream.codec. The change in the lavf-mkv test is due to the native timebase (1/1000) being used instead of the default one (1/90000), so the packets are now sent to the crc muxer in the same order in which they are demuxed (previously some of them got reordered because of inexact timestamp conversion). --- doc/APIchanges | 5 +++++ libavformat/avformat.h | 9 ++++++--- libavformat/avienc.c | 15 ++++++++++----- libavformat/filmstripenc.c | 3 ++- libavformat/framehash.c | 1 - libavformat/movenc.c | 14 ++++++++------ libavformat/mpegtsenc.c | 13 ++++++++++--- libavformat/mux.c | 26 +++++++++++++++++++------- libavformat/mxfenc.c | 5 +++-- libavformat/oggenc.c | 3 +-- libavformat/riffenc.c | 4 ++-- libavformat/rmenc.c | 5 ++++- libavformat/swf.h | 1 + libavformat/swfenc.c | 6 ++++-- libavformat/utils.c | 9 ++++++--- libavformat/version.h | 7 +++++-- libavformat/yuv4mpegenc.c | 5 +++-- tests/ref/lavf/mkv | 2 +- 18 files changed, 90 insertions(+), 43 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index 952ee51556..51a2ff559e 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -13,6 +13,11 @@ libavutil: 2013-12-xx API changes, most recent first: +2014-xx-xx - xxxxxxx - lavf 55.20.0 - avformat.h + The proper way for providing a hint about the desired timebase to the muxers + is now setting AVStream.time_base, instead of AVStream.codec.time_base as was + done previously. The old method is now deprecated. + 2014-04-xx - xxxxxxx - lavc 55.54.0 - avcodec.h Add AVCodecContext.side_data_only_packets to allow encoders to output packets with only side data. This option may become mandatory in the future, so all diff --git a/libavformat/avformat.h b/libavformat/avformat.h index b17c791eac..473b8daedf 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -710,9 +710,12 @@ typedef struct AVStream { * of which frame timestamps are represented. * * decoding: set by libavformat - * encoding: set by libavformat in avformat_write_header. The muxer may use the - * user-provided value of @ref AVCodecContext.time_base "codec->time_base" - * as a hint. + * encoding: May be set by the caller before avformat_write_header() to + * provide a hint to the muxer about the desired timebase. In + * avformat_write_header(), the muxer will overwrite this field + * with the timebase that will actually be used for the timestamps + * written into the file (which may or may not be related to the + * user-provided one, depending on the format). */ AVRational time_base; diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 87075d4b93..417a8e99d2 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -144,6 +144,7 @@ static int avi_write_header(AVFormatContext *s) AVIOContext *pb = s->pb; int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; AVCodecContext *video_enc; + AVStream *video_st = NULL; int64_t list1, list2, strh, strf; AVDictionaryEntry *t = NULL; @@ -172,15 +173,18 @@ static int avi_write_header(AVFormatContext *s) for (n = 0; n < s->nb_streams; n++) { AVCodecContext *codec = s->streams[n]->codec; bitrate += codec->bit_rate; - if (codec->codec_type == AVMEDIA_TYPE_VIDEO) + if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { video_enc = codec; + video_st = s->streams[n]; + } } nb_frames = 0; - if (video_enc) - avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_enc->time_base.num / - video_enc->time_base.den)); + // TODO: should be avg_frame_rate + if (video_st) + avio_wl32(pb, (uint32_t) (INT64_C(1000000) * video_st->time_base.num / + video_st->time_base.den)); else avio_wl32(pb, 0); avio_wl32(pb, bitrate / 8); /* XXX: not quite exact */ @@ -337,7 +341,8 @@ static int avi_write_header(AVFormatContext *s) avio_wl32(pb, 0); // video format = unknown avio_wl32(pb, 0); // video standard = unknown - avio_wl32(pb, lrintf(1.0 / av_q2d(enc->time_base))); + // TODO: should be avg_frame_rate + avio_wl32(pb, lrintf(1.0 / av_q2d(st->time_base))); avio_wl32(pb, enc->width); avio_wl32(pb, enc->height); avio_wl16(pb, den); diff --git a/libavformat/filmstripenc.c b/libavformat/filmstripenc.c index 90d9a7685c..8d1d2d8365 100644 --- a/libavformat/filmstripenc.c +++ b/libavformat/filmstripenc.c @@ -64,7 +64,8 @@ static int write_trailer(AVFormatContext *s) avio_wb16(pb, st->codec->width); avio_wb16(pb, st->codec->height); avio_wb16(pb, 0); // leading - avio_wb16(pb, 1/av_q2d(st->codec->time_base)); + // TODO: should be avg_frame_rate + avio_wb16(pb, 1/av_q2d(st->time_base)); for (i = 0; i < 16; i++) avio_w8(pb, 0x00); // reserved diff --git a/libavformat/framehash.c b/libavformat/framehash.c index 28e9e8407d..6a6da98ae4 100644 --- a/libavformat/framehash.c +++ b/libavformat/framehash.c @@ -25,7 +25,6 @@ int ff_framehash_write_header(AVFormatContext *s) int i; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); avio_printf(s->pb, "#tb %d: %d/%d\n", i, st->time_base.num, st->time_base.den); avio_flush(s->pb); } diff --git a/libavformat/movenc.c b/libavformat/movenc.c index dcd3294e01..f5c36fcec1 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -814,10 +814,10 @@ static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track) else if (track->enc->pix_fmt == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p'); else tag = MKTAG('d','v','p','p'); else if (track->enc->height == 720) /* HD 720 line */ - if (track->enc->time_base.den == 50) tag = MKTAG('d','v','h','q'); + if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q'); else tag = MKTAG('d','v','h','p'); else if (track->enc->height == 1080) /* HD 1080 line */ - if (track->enc->time_base.den == 25) tag = MKTAG('d','v','h','5'); + if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5'); else tag = MKTAG('d','v','h','6'); else { av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n"); @@ -2656,10 +2656,12 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) static void mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s) { + AVStream *video_st = s->streams[0]; AVCodecContext *video_codec = s->streams[0]->codec; AVCodecContext *audio_codec = s->streams[1]->codec; int audio_rate = audio_codec->sample_rate; - int frame_rate = ((video_codec->time_base.den) * (0x10000)) / (video_codec->time_base.num); + // TODO: should be avg_frame_rate + int frame_rate = ((video_st->time_base.den) * (0x10000)) / (video_st->time_base.num); int audio_kbitrate = audio_codec->bit_rate / 1000; int video_kbitrate = FFMIN(video_codec->bit_rate / 1000, 800 - audio_kbitrate); @@ -3400,7 +3402,7 @@ static int mov_write_header(AVFormatContext *s) } track->height = track->tag >> 24 == 'n' ? 486 : 576; } - track->timescale = st->codec->time_base.den; + track->timescale = st->time_base.den; if (track->mode == MODE_MOV && track->timescale > 100000) av_log(s, AV_LOG_WARNING, "WARNING codec timebase is very high. If duration is too long,\n" @@ -3428,9 +3430,9 @@ static int mov_write_header(AVFormatContext *s) goto error; } } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - track->timescale = st->codec->time_base.den; + track->timescale = st->time_base.den; } else if (st->codec->codec_type == AVMEDIA_TYPE_DATA) { - track->timescale = st->codec->time_base.den; + track->timescale = st->time_base.den; } if (!track->height) track->height = st->codec->height; diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index 04cabe5f8d..838702e8fa 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -194,6 +194,7 @@ typedef struct MpegTSWriteStream { int payload_flags; uint8_t *payload; AVFormatContext *amux; + AVRational user_tb; } MpegTSWriteStream; static void mpegts_write_pat(AVFormatContext *s) @@ -480,13 +481,17 @@ static int mpegts_write_header(AVFormatContext *s) /* assign pids to each stream */ for(i = 0;i < s->nb_streams; i++) { st = s->streams[i]; - avpriv_set_pts_info(st, 33, 1, 90000); + ts_st = av_mallocz(sizeof(MpegTSWriteStream)); if (!ts_st) { ret = AVERROR(ENOMEM); goto fail; } st->priv_data = ts_st; + + ts_st->user_tb = st->time_base; + avpriv_set_pts_info(st, 33, 1, 90000); + ts_st->payload = av_mallocz(ts->pes_payload_size); if (!ts_st->payload) { ret = AVERROR(ENOMEM); @@ -557,7 +562,8 @@ static int mpegts_write_header(AVFormatContext *s) pcr_st = s->streams[0]; ts_st = pcr_st->priv_data; service->pcr_pid = ts_st->pid; - } + } else + ts_st = pcr_st->priv_data; if (ts->mux_rate > 1) { service->pcr_packet_period = (ts->mux_rate * ts->pcr_period) / @@ -583,8 +589,9 @@ static int mpegts_write_header(AVFormatContext *s) } } else { // max delta PCR 0.1s + // TODO: should be avg_frame_rate service->pcr_packet_period = - pcr_st->codec->time_base.den/(10*pcr_st->codec->time_base.num); + ts_st->user_tb.den / (10 * ts_st->user_tb.num); } } diff --git a/libavformat/mux.c b/libavformat/mux.c index e024a7eaea..9c2144acc1 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -115,6 +115,25 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) st = s->streams[i]; codec = st->codec; +#if FF_API_LAVF_CODEC_TB +FF_DISABLE_DEPRECATION_WARNINGS + if (!st->time_base.num && codec->time_base.num) { + av_log(s, AV_LOG_WARNING, "Using AVStream.codec.time_base as a " + "timebase hint to the muxer is deprecated. Set " + "AVStream.time_base instead.\n"); + avpriv_set_pts_info(st, 64, codec->time_base.num, codec->time_base.den); + } +FF_ENABLE_DEPRECATION_WARNINGS +#endif + + if (!st->time_base.num) { + /* fall back on the default timebase values */ + if (codec->codec_type == AVMEDIA_TYPE_AUDIO && codec->sample_rate) + avpriv_set_pts_info(st, 64, 1, codec->sample_rate); + else + avpriv_set_pts_info(st, 33, 1, 90000); + } + switch (codec->codec_type) { case AVMEDIA_TYPE_AUDIO: if (codec->sample_rate <= 0) { @@ -127,13 +146,6 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) av_get_bits_per_sample(codec->codec_id) >> 3; break; case AVMEDIA_TYPE_VIDEO: - if (codec->time_base.num <= 0 || - codec->time_base.den <= 0) { //FIXME audio too? - av_log(s, AV_LOG_ERROR, "time base not set\n"); - ret = AVERROR(EINVAL); - goto fail; - } - if ((codec->width <= 0 || codec->height <= 0) && !(of->flags & AVFMT_NODIMENSIONS)) { av_log(s, AV_LOG_ERROR, "dimensions not set\n"); diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 66beec2940..841e727791 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -1433,11 +1433,12 @@ static int mxf_write_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "video stream must be first track\n"); return -1; } - if (fabs(av_q2d(st->codec->time_base) - 1/25.0) < 0.0001) { + // TODO: should be avg_frame_rate + if (fabs(av_q2d(st->time_base) - 1/25.0) < 0.0001) { samples_per_frame = PAL_samples_per_frame; mxf->time_base = (AVRational){ 1, 25 }; mxf->timecode_base = 25; - } else if (fabs(av_q2d(st->codec->time_base) - 1001/30000.0) < 0.0001) { + } else if (fabs(av_q2d(st->time_base) - 1001/30000.0) < 0.0001) { samples_per_frame = NTSC_samples_per_frame; mxf->time_base = (AVRational){ 1001, 30000 }; mxf->timecode_base = 30; diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index d148f5b7da..19c77595f4 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -428,8 +428,7 @@ static int ogg_write_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, 48000); else avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); - else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) - avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); + if (st->codec->codec_id != AV_CODEC_ID_VORBIS && st->codec->codec_id != AV_CODEC_ID_THEORA && st->codec->codec_id != AV_CODEC_ID_SPEEX && diff --git a/libavformat/riffenc.c b/libavformat/riffenc.c index 8f0279628e..b83533a250 100644 --- a/libavformat/riffenc.c +++ b/libavformat/riffenc.c @@ -230,8 +230,8 @@ void ff_parse_specific_params(AVStream *st, int *au_rate, } else if (codec->codec_type == AVMEDIA_TYPE_VIDEO || codec->codec_type == AVMEDIA_TYPE_DATA || codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - *au_scale = codec->time_base.num; - *au_rate = codec->time_base.den; + *au_scale = st->time_base.num; + *au_rate = st->time_base.den; } else { *au_scale = codec->block_align ? codec->block_align * 8 : 8; *au_rate = codec->bit_rate ? codec->bit_rate : diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c index fba8feb802..9ff9f318a5 100644 --- a/libavformat/rmenc.c +++ b/libavformat/rmenc.c @@ -310,6 +310,8 @@ static int rm_write_header(AVFormatContext *s) AVCodecContext *codec; for(n=0;nnb_streams;n++) { + AVStream *st = s->streams[n]; + s->streams[n]->id = n; codec = s->streams[n]->codec; stream = &rm->streams[n]; @@ -329,7 +331,8 @@ static int rm_write_header(AVFormatContext *s) break; case AVMEDIA_TYPE_VIDEO: rm->video_stream = stream; - stream->frame_rate = (float)codec->time_base.den / (float)codec->time_base.num; + // TODO: should be avg_frame_rate + stream->frame_rate = (float)st->time_base.den / (float)st->time_base.num; /* XXX: dummy values */ stream->packet_max_size = 4096; stream->nb_packets = 0; diff --git a/libavformat/swf.h b/libavformat/swf.h index 79c3c1d033..8eb3f70541 100644 --- a/libavformat/swf.h +++ b/libavformat/swf.h @@ -76,6 +76,7 @@ typedef struct SWFContext { int tag; AVFifoBuffer *audio_fifo; AVCodecContext *audio_enc, *video_enc; + AVStream *video_st; } SWFContext; extern const AVCodecTag ff_swf_codec_tags[]; diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c index be2e5cd7d3..a1fc7b337c 100644 --- a/libavformat/swfenc.c +++ b/libavformat/swfenc.c @@ -207,6 +207,7 @@ static int swf_write_header(AVFormatContext *s) if (enc->codec_id == AV_CODEC_ID_VP6F || enc->codec_id == AV_CODEC_ID_FLV1 || enc->codec_id == AV_CODEC_ID_MJPEG) { + swf->video_st = s->streams[i]; swf->video_enc = enc; } else { av_log(s, AV_LOG_ERROR, "SWF muxer only supports VP6, FLV1 and MJPEG\n"); @@ -224,8 +225,9 @@ static int swf_write_header(AVFormatContext *s) } else { width = swf->video_enc->width; height = swf->video_enc->height; - rate = swf->video_enc->time_base.den; - rate_base = swf->video_enc->time_base.num; + // TODO: should be avg_frame_rate + rate = swf->video_st->time_base.den; + rate_base = swf->video_st->time_base.num; } if (!swf->audio_enc) diff --git a/libavformat/utils.c b/libavformat/utils.c index 50661ea17c..ab6c6bf0c9 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2663,9 +2663,14 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c) } st->codec = avcodec_alloc_context3(c); - if (s->iformat) + if (s->iformat) { /* no default bitrate if decoding */ st->codec->bit_rate = 0; + + /* default pts setting is MPEG-like */ + avpriv_set_pts_info(st, 33, 1, 90000); + } + st->index = s->nb_streams; st->start_time = AV_NOPTS_VALUE; st->duration = AV_NOPTS_VALUE; @@ -2677,8 +2682,6 @@ AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c) st->first_dts = AV_NOPTS_VALUE; st->probe_packets = MAX_PROBE_PACKETS; - /* default pts setting is MPEG-like */ - avpriv_set_pts_info(st, 33, 1, 90000); st->last_IP_pts = AV_NOPTS_VALUE; for (i = 0; i < MAX_REORDER_DELAY + 1; i++) st->pts_buffer[i] = AV_NOPTS_VALUE; diff --git a/libavformat/version.h b/libavformat/version.h index 57970cd250..1a017ce362 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,8 +30,8 @@ #include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 19 -#define LIBAVFORMAT_VERSION_MICRO 1 +#define LIBAVFORMAT_VERSION_MINOR 20 +#define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ @@ -57,5 +57,8 @@ #ifndef FF_API_LAVF_FRAC #define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 57) #endif +#ifndef FF_API_LAVF_CODEC_TB +#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 57) +#endif #endif /* AVFORMAT_VERSION_H */ diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c index ed1ffea87d..abe967f177 100644 --- a/libavformat/yuv4mpegenc.c +++ b/libavformat/yuv4mpegenc.c @@ -38,8 +38,9 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) width = st->codec->width; height = st->codec->height; - av_reduce(&raten, &rated, st->codec->time_base.den, - st->codec->time_base.num, (1UL << 31) - 1); + // TODO: should be avg_frame_rate + av_reduce(&raten, &rated, st->time_base.den, + st->time_base.num, (1UL << 31) - 1); aspectn = st->sample_aspect_ratio.num; aspectd = st->sample_aspect_ratio.den; diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv index e7c02d5448..a871ea9fd9 100644 --- a/tests/ref/lavf/mkv +++ b/tests/ref/lavf/mkv @@ -1,3 +1,3 @@ 268fb8f9278b0df2f87a6a9455f3cd56 *./tests/data/lavf/lavf.mkv 320380 ./tests/data/lavf/lavf.mkv -./tests/data/lavf/lavf.mkv CRC=0xbe7d3cda +./tests/data/lavf/lavf.mkv CRC=0x36193cda