[FFmpeg-devel] [PATCH 03/11] avformat/dashenc: allow splitting fragments following P-Frame reordering
James Almer
jamrial at gmail.com
Thu Oct 17 21:59:08 EEST 2019
Currently implemented by using the pic_type value from AV_PKT_DATA_QUALITY_STATS
packet side data.
Signed-off-by: James Almer <jamrial at gmail.com>
---
A (probably much slower) alternative would be inserting an AVCodecParserContext,
which would also enable this kind of fragment splitting for non encoding scenarios.
libavformat/dashenc.c | 46 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 91487c48d9..7be22b268f 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -62,6 +62,7 @@ enum {
FRAG_TYPE_NONE = 0,
FRAG_TYPE_EVERY_FRAME,
FRAG_TYPE_DURATION,
+ FRAG_TYPE_PFRAMES,
FRAG_TYPE_NB
};
@@ -100,6 +101,7 @@ typedef struct OutputStream {
Segment **segments;
int64_t first_pts, start_pts, max_pts;
int64_t last_dts, last_pts;
+ int last_flags;
int bit_rate;
SegmentType segment_type; /* segment type selected for this particular stream */
const char *format_name;
@@ -115,6 +117,7 @@ typedef struct OutputStream {
char temp_path[1024];
double availability_time_offset;
int total_pkt_size;
+ int total_pkt_duration;
int muxer_overhead;
} OutputStream;
@@ -1427,6 +1430,10 @@ static int dash_init(AVFormatContext *s)
av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
return AVERROR(EINVAL);
}
+ if (!c->has_video && c->frag_type == FRAG_TYPE_PFRAMES) {
+ av_log(s, AV_LOG_WARNING, "no video stream and P-frame fragmentation set\n");
+ return AVERROR(EINVAL);
+ }
c->nr_of_streams_flushed = 0;
@@ -1695,6 +1702,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream)
av_rescale_q(os->max_pts - os->start_pts,
st->time_base, AV_TIME_BASE_Q);
os->total_pkt_size = 0;
+ os->total_pkt_duration = 0;
if (!os->bit_rate) {
// calculate average bitrate of first segment
@@ -1796,9 +1804,13 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
sizeof(c->availability_start_time));
}
+ if (!os->packets_written)
+ os->availability_time_offset = 0;
+
if (!os->availability_time_offset &&
(c->frag_type == FRAG_TYPE_NONE ||
c->frag_type == FRAG_TYPE_DURATION ||
+ (c->frag_type == FRAG_TYPE_PFRAMES && st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) ||
(c->frag_type == FRAG_TYPE_EVERY_FRAME && pkt->duration))) {
int64_t frame_duration = 0;
@@ -1863,11 +1875,40 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
os->max_pts = pkt->pts + pkt->duration;
else
os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
- os->packets_written++;
- os->total_pkt_size += pkt->size;
+
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
+ c->frag_type == FRAG_TYPE_PFRAMES &&
+ os->packets_written) {
+ int side_size, pic_type = 0;
+ uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_QUALITY_STATS, &side_size);
+ if (side && side_size > 4)
+ pic_type = side[4];
+
+ if ((pic_type == AV_PICTURE_TYPE_P &&
+ st->codecpar->video_delay &&
+ !(os->last_flags & AV_PKT_FLAG_KEY)) ||
+ pkt->flags & AV_PKT_FLAG_KEY) {
+ ret = av_write_frame(os->ctx, NULL);
+ if (ret < 0)
+ return ret;
+
+ if (!os->availability_time_offset) {
+ int64_t frag_duration = av_rescale_q(os->total_pkt_duration, st->time_base,
+ AV_TIME_BASE_Q);
+ os->availability_time_offset = ((double) os->seg_duration -
+ frag_duration) / AV_TIME_BASE;
+ }
+ }
+ }
+
if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
return ret;
+ os->packets_written++;
+ os->total_pkt_size += pkt->size;
+ os->total_pkt_duration += pkt->duration;
+ os->last_flags = pkt->flags;
+
if (!os->init_range_length)
flush_init_segment(s, os);
@@ -1994,6 +2035,7 @@ static const AVOption options[] = {
{ "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE }, 0, UINT_MAX, E, "frag_type"},
{ "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME }, 0, UINT_MAX, E, "frag_type"},
{ "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION }, 0, UINT_MAX, E, "frag_type"},
+ { "pframes", "fragment at keyframes and following P-Frame reordering (Video only, experimental)", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_PFRAMES }, 0, UINT_MAX, E, "frag_type"},
{ "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
{ "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
{ "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E },
--
2.23.0
More information about the ffmpeg-devel
mailing list