[FFmpeg-devel] [PATCH] avformat/matroskaenc: Increase time stamp precision to AV_TIME_BASE
From: Michael Fabian 'Xaymar' Dirks Increases the time stamp precision to 1 microsecond, the same as AV_TIME_BASE. This hopefully prevents demuxers from being confused on the number of frames/samples we actually have per second, and should mark all future Matroska/WebM content as being constant rate. Work-around for: 259, 6406, 7927, 8909, 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- libavformat/matroskaenc.c | 19 --- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index ad7b0bf2c6..474e44485a 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1917,7 +1917,8 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info_bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +// Set time base to 1 microsecond. +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 10 / AV_TIME_BASE); if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1959,11 +1960,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = s->duration; put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = metadata_duration; put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else { @@ -2038,12 +2039,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (pb->seekable & AVIO_SEEKABLE_NORMAL) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = 500; if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = 100; if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2724,6 +2725,7 @@ static int webm_query_codec(enum AVCodecID codec_id, int std_compliance) static int mkv_init(struct AVFormatContext *s) { int i; +MatroskaMuxContext *mkv = s->priv_data; if (s->nb_streams > MAX_TRACKS) { av_log(s, AV_LOG_ERROR, @@ -2752,10 +2754,13 @@ static int mkv_init(struct AVFormatContext *s) } for (i = 0; i < s->nb_streams; i++) { -// ms precision is the de-facto standard timescale for mkv files -avpriv_set_pts_info(s->streams[i], 64, 1, 1000); +// Use µs precision (same as FFmpeg) +avpriv_set_pts_info(s->streams[i], 64, 1, AV_TIME_BASE); } +// Scale the configured cluster_time_limit to microseconds. +mkv->cluster_time_limit = av_rescale(mkv->cluster_time_limit, 1000, AV_TIME_BASE); + return 0; } -- 2.31.1.windows.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
[FFmpeg-devel] [PATCH] avformat/matroskaenc: Allow customizing the time stamp precision via option
From: Michael Fabian 'Xaymar' Dirks Adds the "timestamp_precision" option to matroskaenc, which allows users to increase the time stamp precision up to 1 nanosecond. This aids with certain demuxers being unable to detect constant rate. It is a work around fix for the problems reported in 259, 6406, 7927, 8909 and 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- libavformat/matroskaenc.c | 25 ++--- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index b4284a8778..8e2813c36e 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -158,6 +158,8 @@ typedef struct MatroskaMuxContext { int default_mode; uint32_tsegment_uid[4]; + +AVRational time_base; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -1816,6 +1818,7 @@ static int mkv_write_header(AVFormatContext *s) const AVDictionaryEntry *tag; int ret, i, version = 2; int64_t creation_time; +int64_t time_base = 1; if (mkv->mode != MODE_WEBM || av_dict_get(s->metadata, "stereo_mode", NULL, 0) || @@ -1852,7 +1855,10 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info.bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 10}); +av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base); +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base); + if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1885,11 +1891,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(metadata_duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { @@ -1950,12 +1956,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2736,8 +2742,8 @@ static int mkv_init(struct AVFormatContext *s) track->uid = mkv_get_uid(mkv->tracks, i, &c); } -// ms precision is the de-facto standard timescale for mkv files -avpriv_set_pts_info(st, 64, 1, 1000); +// Use user-defined timescale. +avpriv_set_pts_info(st, 64, mkv->time_base.num, mkv->time_base.den); if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) { if (mkv->mode == MODE_WEBM) { @@ -2757,6 +2763,10 @@ static int mkv_init(struct AVFormatContext *s) track->track_num_size = ebml_num_size(track->track_num); } +// Scale the configured cluster_time_limit. +if (mkv->cluster_time_limit >= 0) +mkv->cluster_time_limit = av_rescale_q(mkv->cluster_time_limit, (AVRational){1, 1000}, mkv->time_base); + if (mkv->is_dash && nb_tracks != 1) return AVERROR(EINVAL); @@ -2824,6 +2834,7 @@ static const AVOption options[] = { { "infer", "For each track type, mark the first track of disposition default as default; if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER }, 0, 0, FLAGS, "default_mode" }, { "infer_no_subs", "For each track type, mark the first track of disposition default as default; for audio and video: if none exists, mark the first track as default.", 0, AV_OPT_TYPE_CONST, { .i64 = DEFAULT_MODE_INFER_NO_SUBS }, 0, 0, FLAGS, "default_mode
[FFmpeg-devel] [PATCH] avformat/matroskaenc: Allow changing the time stamp precision via option
From: Michael Fabian 'Xaymar' Dirks Adds "timestamp_precision" to the available option for Matroska/WebM muxing. The option enables users and developers to change the precision of the time stamps in the Matroska/WebM container up to 1 nanosecond, which can aid with the proper detection of constant and variable rate content. Work-around fix for: 259, 6406, 7927, 8909 and 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- doc/muxers.texi | 8 libavformat/matroskaenc.c | 28 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index e1c6ad0829..d9f7badae1 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1583,6 +1583,14 @@ bitmap is stored bottom-up. Note that this option does not flip the bitmap which has to be done manually beforehand, e.g. by using the vflip filter. Default is @var{false} and indicates bitmap is stored top down. +@item timestamp_precision +Sets the timestamp precision up to 1 nanosecond for Matroska/WebM, which can +improve detection of constant rate content in demuxers. Note that some poorly +implemented demuxers may require a timestamp precision of 1 millisecond, so +increasing it past that point may result in playback issues. Higher precision +also reduces the maximum possible timestamp significantly. +Default is @var{1/10} (1 nanosecond). + @end table @anchor{md5} diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 186a25d920..bff8c8e7f2 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -20,6 +20,7 @@ */ #include +#include #include "av1.h" #include "avc.h" @@ -158,6 +159,8 @@ typedef struct MatroskaMuxContext { int default_mode; uint32_tsegment_uid[4]; + +AVRational time_base; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -1814,6 +1817,7 @@ static int mkv_write_header(AVFormatContext *s) const AVDictionaryEntry *tag; int ret, i, version = 2; int64_t creation_time; +int64_t time_base = 1; if (mkv->mode != MODE_WEBM || av_dict_get(s->metadata, "stereo_mode", NULL, 0) || @@ -1850,7 +1854,10 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info.bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 10}); +av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base); +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base); + if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1883,11 +1890,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(metadata_duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { @@ -1948,12 +1955,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2323,7 +2330,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) ret = mkv_end_cluster(s); if (ret < 0) return ret; -av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n"); +av_log(s, AV_LOG_VERBOSE, "Starting new cluster as timestamp offset exceeds signed 16-bit integer range.\n"); } } @@ -2738,8 +27
[FFmpeg-devel] [PATCH] avformat/matroskaenc: Allow changing the time stamp precision via option
From: Michael Fabian 'Xaymar' Dirks Adds "timestamp_precision" to the available option for Matroska/WebM muxing. The option enables users and developers to change the precision of the time stamps in the Matroska/WebM container up to 1 nanosecond, which can aid with the proper detection of constant and variable rate content. Work-around fix for: 259, 6406, 7927, 8909 and 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- doc/muxers.texi | 8 libavformat/matroskaenc.c | 28 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index e1c6ad0829..8655be94ff 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1583,6 +1583,14 @@ bitmap is stored bottom-up. Note that this option does not flip the bitmap which has to be done manually beforehand, e.g. by using the vflip filter. Default is @var{false} and indicates bitmap is stored top down. +@item timestamp_precision +Sets the timestamp precision up to 1 nanosecond for Matroska/WebM, which can +improve detection of constant rate content in demuxers. Note that some poorly +implemented demuxers may require a timestamp precision of 1 millisecond, so +increasing it past that point may result in playback issues. Higher precision +also reduces the maximum possible timestamp significantly. +Default is @var{1/1000} (1 millisecond). + @end table @anchor{md5} diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 186a25d920..2417ac12cc 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -20,6 +20,7 @@ */ #include +#include #include "av1.h" #include "avc.h" @@ -158,6 +159,8 @@ typedef struct MatroskaMuxContext { int default_mode; uint32_tsegment_uid[4]; + +AVRational time_base; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -1814,6 +1817,7 @@ static int mkv_write_header(AVFormatContext *s) const AVDictionaryEntry *tag; int ret, i, version = 2; int64_t creation_time; +int64_t time_base = 1; if (mkv->mode != MODE_WEBM || av_dict_get(s->metadata, "stereo_mode", NULL, 0) || @@ -1850,7 +1854,10 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info.bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 10}); +av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base); +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base); + if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1883,11 +1890,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(metadata_duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { @@ -1948,12 +1955,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2323,7 +2330,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt) ret = mkv_end_cluster(s); if (ret < 0) return ret; -av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n"); +av_log(s, AV_LOG_VERBOSE, "Starting new cluster as timestamp offset exceeds signed 16-bit integer range.\n"); } } @@ -2738,8 +2745,8
[FFmpeg-devel] [PATCH] avformat/matroskaenc: Allow changing the time stamp precision via option
From: Michael Fabian 'Xaymar' Dirks Adds "timestamp_precision" to the available option for Matroska/WebM muxing. The option enables users and developers to change the precision of the time stamps in the Matroska/WebM container up to 1 nanosecond, which can aid with the proper detection of constant and variable rate content. Work-around fix for: 259, 6406, 7927, 8909 and 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- doc/muxers.texi | 8 libavformat/matroskaenc.c | 25 ++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index e1c6ad0829..8655be94ff 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1583,6 +1583,14 @@ bitmap is stored bottom-up. Note that this option does not flip the bitmap which has to be done manually beforehand, e.g. by using the vflip filter. Default is @var{false} and indicates bitmap is stored top down. +@item timestamp_precision +Sets the timestamp precision up to 1 nanosecond for Matroska/WebM, which can +improve detection of constant rate content in demuxers. Note that some poorly +implemented demuxers may require a timestamp precision of 1 millisecond, so +increasing it past that point may result in playback issues. Higher precision +also reduces the maximum possible timestamp significantly. +Default is @var{1/1000} (1 millisecond). + @end table @anchor{md5} diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 186a25d920..4a78b60b1f 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -158,6 +158,8 @@ typedef struct MatroskaMuxContext { int default_mode; uint32_tsegment_uid[4]; + +AVRational time_base; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -1814,6 +1816,7 @@ static int mkv_write_header(AVFormatContext *s) const AVDictionaryEntry *tag; int ret, i, version = 2; int64_t creation_time; +int64_t time_base = 1; if (mkv->mode != MODE_WEBM || av_dict_get(s->metadata, "stereo_mode", NULL, 0) || @@ -1850,7 +1853,10 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info.bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 10}); +av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base); +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base); + if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1883,11 +1889,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(metadata_duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { @@ -1948,12 +1954,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2738,8 +2744,8 @@ static int mkv_init(struct AVFormatContext *s) track->uid = mkv_get_uid(mkv->tracks, i, &c); } -// ms precision is the de-facto standard timescale for mkv files -avpriv_set_pts_info(st, 64, 1, 1000); +// Use user-defined timescale. +avpriv_set_pts_info(st, 64, mkv->time_base.num, mkv->time_base.den); if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) { if (mkv->mode == MODE_WEBM) { @@ -2759,6 +2765,10 @@ static int mkv
[FFmpeg-devel] [PATCH] avformat/matroskaenc: Allow changing the time stamp precision via option
From: Michael Fabian 'Xaymar' Dirks Adds "timestamp_precision" to the available option for Matroska muxing. The option enables users and developers to change the precision of the time stamps in the Matroska container up to 1 nanosecond, which can aid with the proper detection of constant and variable rate content. Work-around fix for: 259, 6406, 7927, 8909 and 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- doc/muxers.texi | 8 libavformat/matroskaenc.c | 33 ++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index e1c6ad0829..8655be94ff 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1583,6 +1583,14 @@ bitmap is stored bottom-up. Note that this option does not flip the bitmap which has to be done manually beforehand, e.g. by using the vflip filter. Default is @var{false} and indicates bitmap is stored top down. +@item timestamp_precision +Sets the timestamp precision up to 1 nanosecond for Matroska/WebM, which can +improve detection of constant rate content in demuxers. Note that some poorly +implemented demuxers may require a timestamp precision of 1 millisecond, so +increasing it past that point may result in playback issues. Higher precision +also reduces the maximum possible timestamp significantly. +Default is @var{1/1000} (1 millisecond). + @end table @anchor{md5} diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 186a25d920..1741abff20 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -158,6 +158,8 @@ typedef struct MatroskaMuxContext { int default_mode; uint32_tsegment_uid[4]; + +AVRational time_base; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -1814,6 +1816,7 @@ static int mkv_write_header(AVFormatContext *s) const AVDictionaryEntry *tag; int ret, i, version = 2; int64_t creation_time; +int64_t time_base = 1; if (mkv->mode != MODE_WEBM || av_dict_get(s->metadata, "stereo_mode", NULL, 0) || @@ -1850,7 +1853,10 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info.bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 10}); +av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base); +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base); + if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1883,11 +1889,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(metadata_duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { @@ -1948,12 +1954,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2713,6 +2719,14 @@ static int mkv_init(struct AVFormatContext *s) } else mkv->mode = MODE_MATROSKAv2; +// WebM requires a timestamp precision of 1ms. +if (mkv->mode == MODE_WEBM) { +if ((mkv->time_base.num != 1) || (mkv->time_base.den != 1000)) { +av_log(s, AV_LOG_ERROR, "WebM requires 1ms timestamp precision\n"); +return AVERROR(EINVAL); +} +} + mkv->cur_audio_pkt = av_packet_alloc(); if (!mkv->cur_audio_pkt) return AVERROR(ENOMEM); @@
[FFmpeg-devel] [PATCH] avformat/matroskaenc: Allow changing the time stamp precision via option
From: Michael Fabian 'Xaymar' Dirks Adds "timestamp_precision" to the available options for Matroska muxing. The option enables users and developers to change the precision of the time stamps in the Matroska container up to 1 nanosecond, which can aid with the proper detection of constant and variable rate content. Work-around fix for: 259, 6406, 7927, 8909 and 9124. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- doc/muxers.texi | 8 libavformat/matroskaenc.c | 33 ++--- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index e1c6ad0829..8655be94ff 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -1583,6 +1583,14 @@ bitmap is stored bottom-up. Note that this option does not flip the bitmap which has to be done manually beforehand, e.g. by using the vflip filter. Default is @var{false} and indicates bitmap is stored top down. +@item timestamp_precision +Sets the timestamp precision up to 1 nanosecond for Matroska/WebM, which can +improve detection of constant rate content in demuxers. Note that some poorly +implemented demuxers may require a timestamp precision of 1 millisecond, so +increasing it past that point may result in playback issues. Higher precision +also reduces the maximum possible timestamp significantly. +Default is @var{1/1000} (1 millisecond). + @end table @anchor{md5} diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 186a25d920..1b911a648c 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -158,6 +158,8 @@ typedef struct MatroskaMuxContext { int default_mode; uint32_tsegment_uid[4]; + +AVRational time_base; } MatroskaMuxContext; /** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, @@ -1814,6 +1816,7 @@ static int mkv_write_header(AVFormatContext *s) const AVDictionaryEntry *tag; int ret, i, version = 2; int64_t creation_time; +int64_t time_base = 1; if (mkv->mode != MODE_WEBM || av_dict_get(s->metadata, "stereo_mode", NULL, 0) || @@ -1850,7 +1853,10 @@ static int mkv_write_header(AVFormatContext *s) return ret; pb = mkv->info.bc; -put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 100); +time_base = av_rescale_q(time_base, mkv->time_base, (AVRational){1, 10}); +av_log(s, AV_LOG_DEBUG, "TimestampScale is: %" PRId64 " ns\n", time_base); +put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, time_base); + if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { @@ -1883,11 +1889,11 @@ static int mkv_write_header(AVFormatContext *s) int64_t metadata_duration = get_metadata_duration(s); if (s->duration > 0) { -int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(s->duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); } else if (metadata_duration > 0) { -int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); +int64_t scaledDuration = av_rescale_q(metadata_duration, AV_TIME_BASE_Q, mkv->time_base); put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); } else if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { @@ -1948,12 +1954,12 @@ static int mkv_write_header(AVFormatContext *s) // after 4k and on a keyframe if (IS_SEEKABLE(pb, mkv)) { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 5000; +mkv->cluster_time_limit = av_rescale_q(5000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 5 * 1024 * 1024; } else { if (mkv->cluster_time_limit < 0) -mkv->cluster_time_limit = 1000; +mkv->cluster_time_limit = av_rescale_q(1000, (AVRational){1, 1000}, mkv->time_base); if (mkv->cluster_size_limit < 0) mkv->cluster_size_limit = 32 * 1024; } @@ -2713,6 +2719,14 @@ static int mkv_init(struct AVFormatContext *s) } else mkv->mode = MODE_MATROSKAv2; +// WebM requires a timestamp precision of 1ms. +if (mkv->mode == MODE_WEBM) { +if (av_cmp_q(mkv->time_base, (AVRational){1, 1000}) != 0) { +av_log(s, AV_LOG_ERROR, "WebM requires 1ms timestamp precision\n"); +return AVERROR(EINVAL); +} +} + mkv->cur_audio_pkt = av_packet_alloc(); if (!mkv->cur_audio_pkt) return AVERROR(ENOMEM); @@ -273
Re: [FFmpeg-devel] [PATCH] amfenc: Add support for pict_type field
On 14.01.2019 20:32, Carl Eugen Hoyos wrote: 2019-01-14 20:02 GMT+01:00, Michael Fabian 'Xaymar' Dirks : Adds support for the pict_type field in AVFrame to amf_h264 and amf_h265 simultaneously. This field is needed in cases where the application wishes to override the frame type with another one, such as forcefully inserting a key frame for chapter markers or similar. Additionally this abuses AV_PICTURE_TYPE_S for marking Skip frames, a special type of frame in AVC, SVC and HEVC which is a flag for the decoder to repeat the last frame. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- libavcodec/amfenc.c | 46 + 1 file changed, 46 insertions(+) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 384d8efc92..eb4b65e4f2 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -680,6 +680,52 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) break; } +// Override Picture Type for Frame +if (avctx->codec->id) { +switch (frame->pict_type) { +case AV_PICTURE_TYPE_I: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); +break; +case AV_PICTURE_TYPE_P: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P); +break; +case AV_PICTURE_TYPE_B: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B); +break; +case AV_PICTURE_TYPE_S: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_SKIP); +break; +default: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_NONE); +break; +} +// Keyframe overrides previous assignment. +if (frame->key_frame) { +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR); +} +} else if (avctx->codec->id == AV_CODEC_ID_HEVC) { How can this be reached? (Assuming you tested your patch, is the block unneeded?) Carl Eugen ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel Thanks for pointing that out Carl, I forgot to re-run git format-patch before sending off the patch. The correct code should be: +if (avctx->codec->id) { should actually be +if (avctx->codec->id == AV_CODEC_ID_H264) { Should I resubmit with the corrected patch file? Unfortunately I am currently only able to test the H.264 encoder, as initializing the H.265 encoder results in the Driver crashing with and without this patch applied. Assuming that ffmpeg doesn't do something weird with the AMF runtime, this behaviour should be working as is (similar code exists in obs-amd-encoder, the AMF integration for obs-studio). Michael Fabian Dirks ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
[FFmpeg-devel] [PATCH] amfenc: Add support for pict_type field
From: Michael Fabian 'Xaymar' Dirks Adds support for the pict_type field in AVFrame to amf_h264 and amf_h265 simultaneously. This field is needed in cases where the application wishes to override the frame type with another one, such as forcefully inserting a key frame for chapter markers or similar. Additionally this abuses AV_PICTURE_TYPE_S for marking Skip frames, a special type of frame in AVC, SVC and HEVC which is a flag for the decoder to repeat the last frame. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- Changelog | 1 + libavcodec/amfenc.c | 46 + 2 files changed, 47 insertions(+) diff --git a/Changelog b/Changelog index 1cd53916cb..4fc48ba210 100644 --- a/Changelog +++ b/Changelog @@ -15,6 +15,7 @@ version : - hymt decoder - anlmdn filter - maskfun filter +- AMF now supports AVFrame->pict_type override version 4.1: diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 384d8efc92..3be9ff9ee2 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -680,6 +680,52 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) break; } +// Override Picture Type for Frame +if (avctx->codec->id == AV_CODEC_ID_H264) { +switch (frame->pict_type) { +case AV_PICTURE_TYPE_I: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); +break; +case AV_PICTURE_TYPE_P: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P); +break; +case AV_PICTURE_TYPE_B: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B); +break; +case AV_PICTURE_TYPE_S: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_SKIP); +break; +default: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_NONE); +break; +} +// Keyframe overrides previous assignment. +if (frame->key_frame) { +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR); +} +} else if (avctx->codec->id == AV_CODEC_ID_HEVC) { +switch (frame->pict_type) { +case AV_PICTURE_TYPE_I: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I); +break; +case AV_PICTURE_TYPE_P: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P); +break; +case AV_PICTURE_TYPE_B: +av_log(ctx, AV_LOG_WARNING, "Ignoring B-Frame, unsupported by AMD AMF H.265 Encoder."); +break; +case AV_PICTURE_TYPE_S: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_SKIP); +break; +default: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_NONE); +break; +} +// Keyframe overrides previous assignment. +if (frame->key_frame) { +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR); +} +} // submit surface res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); -- 2.20.1.windows.1 ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] amfenc: Add support for pict_type field
On 15.01.2019 23:05, michael.di...@xaymar.com wrote: From: Michael Fabian 'Xaymar' Dirks Adds support for the pict_type field in AVFrame to amf_h264 and amf_h265 simultaneously. This field is needed in cases where the application wishes to override the frame type with another one, such as forcefully inserting a key frame for chapter markers or similar. Additionally this abuses AV_PICTURE_TYPE_S for marking Skip frames, a special type of frame in AVC, SVC and HEVC which is a flag for the decoder to repeat the last frame. Signed-off-by: Michael Fabian 'Xaymar' Dirks --- Changelog | 1 + libavcodec/amfenc.c | 46 + 2 files changed, 47 insertions(+) diff --git a/Changelog b/Changelog index 1cd53916cb..4fc48ba210 100644 --- a/Changelog +++ b/Changelog @@ -15,6 +15,7 @@ version : - hymt decoder - anlmdn filter - maskfun filter +- AMF now supports AVFrame->pict_type override version 4.1: diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c index 384d8efc92..3be9ff9ee2 100644 --- a/libavcodec/amfenc.c +++ b/libavcodec/amfenc.c @@ -680,6 +680,52 @@ int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) break; } +// Override Picture Type for Frame +if (avctx->codec->id == AV_CODEC_ID_H264) { +switch (frame->pict_type) { +case AV_PICTURE_TYPE_I: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); +break; +case AV_PICTURE_TYPE_P: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P); +break; +case AV_PICTURE_TYPE_B: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B); +break; +case AV_PICTURE_TYPE_S: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_SKIP); +break; +default: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_NONE); +break; +} +// Keyframe overrides previous assignment. +if (frame->key_frame) { +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR); +} +} else if (avctx->codec->id == AV_CODEC_ID_HEVC) { +switch (frame->pict_type) { +case AV_PICTURE_TYPE_I: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I); +break; +case AV_PICTURE_TYPE_P: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P); +break; +case AV_PICTURE_TYPE_B: +av_log(ctx, AV_LOG_WARNING, "Ignoring B-Frame, unsupported by AMD AMF H.265 Encoder."); +break; +case AV_PICTURE_TYPE_S: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_SKIP); +break; +default: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_NONE); +break; +} +// Keyframe overrides previous assignment. +if (frame->key_frame) { +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR); +} +} // submit surface res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); This patch has been tested with the small tool I wrote here: https://github.com/Xaymar/ffmpeg-test. It works in both H264 and H265 and produces the correct sequence of IDR, I, P and Skip frames - including the visual corruption that AMD's Skip frames have. Michael Fabian Dirks ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] amfenc: Add support for pict_type field
On 15.01.2019 23:41, Michael Dirks wrote: On 15.01.2019 23:05, michael.di...@xaymar.com wrote: From: Michael Fabian 'Xaymar' Dirks Adds support for the pict_type field in AVFrame to amf_h264 and amf_h265 simultaneously. This field is needed in cases where the application wishes to override the frame type with another one, such as forcefully inserting a key frame for chapter markers or similar. Additionally this abuses AV_PICTURE_TYPE_S for marking Skip frames, a special type of frame in AVC, SVC and HEVC which is a flag for the decoder to repeat the last frame. This patch has been tested with the small tool I wrote here: https://github.com/Xaymar/ffmpeg-test. It works in both H264 and H265 and produces the correct sequence of IDR, I, P and Skip frames - including the visual corruption that AMD's Skip frames have. As there currently seems to be no active maintainer for amfenc files, is there any chance of this getting merged into ffmpeg? Personally I can work with a patch for ffmpeg, but it makes building the project a bit more difficult (integrating make plus cross compiling tools is a bit much). Sincerely Michael Fabian 'Xaymar' Dirks ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] amfenc: Add support for pict_type field
On 01.02.2019 19:31, Carl Eugen Hoyos wrote: Could you take over mantainership? Unfortunately I lack the necessary FFmpeg experience for this task. Even though I am the maintainer of the OBS Studio AMD Encoder integration, I'd be horribly lost in FFmpegs code when it comes to AMD/AMF. Sincerely Michael Fabian Dirks ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] amfenc: Add support for pict_type field
On 04.02.2019 11:05, Mark Thompson wrote: Can you explain what this "skip frame" actually does in the encoder? The concept does not exist in H.264 or H.265, as far as I know. I believe this has to do with the pic_struct flag which has a value of 7 for frame doubling and 8 for frame tripling, see page 345 (PDF page 367) Table D-1 Interpretation of pic_struct in Rec. ITU-T H.264 (04/2017). However I do not work for AMD (and their encoder is closed source and a piece of hardware), so I can't confirm that this is actually the behavior, nor do I have any tools that can read and show all H.264 headers. An alternative would be that AMDs encoder is instead choosing to emit a frame that has maximum compression and references the previous frame for all data, thus causing a copy of it. +case AV_PICTURE_TYPE_I: +AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); Consider whether you need to set IDR here rather than I, and maybe add a comment explaining the choice? The normal use of this is to indicate that an IRAP should be generated, not just a single intra picture. (Compare libx264, which has an additional flag controlling whether the forced picture is IDR or I, but I believe it is still always an IRAP there.) +// Keyframe overrides previous assignment. +if (frame->key_frame) { This flag shouldn't be read by encoders. (I believe it is set by the decoder and never cleared, so with this test you will have surprising behaviour where the output stream gets key frames everywhere that the input stream had them, in addition to those dictated by its own GOP structure.) I went by the documentation in the individual header files, which does not actually claim key_frame to be a decoder only field (libavutil/frame.h): > /** > * 1 -> keyframe, 0-> not > */ > int key_frame; Therefore this patch uses the field exactly as it is documented in the frame.h file, and also treats AV_PICTURE_TYPE_I as a request for an Intra Picture instead of an IDR Picture. Sincerely Michael Fabian Dirks ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel