[FFmpeg-devel] [PATCH] avformat/matroskaenc: Increase time stamp precision to AV_TIME_BASE

2021-05-18 Thread michael . dirks
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

2021-05-18 Thread michael . dirks
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

2021-05-20 Thread michael . dirks
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

2021-05-20 Thread michael . dirks
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

2021-05-20 Thread michael . dirks
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

2021-05-20 Thread michael . dirks
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

2021-05-20 Thread michael . dirks
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

2019-01-14 Thread Michael Dirks

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

2019-01-15 Thread michael . dirks
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

2019-01-15 Thread Michael Dirks

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

2019-02-01 Thread Michael Dirks

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

2019-02-01 Thread Michael Dirks

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

2019-02-04 Thread Michael Dirks

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