Currently implemented by using the pic_type value from AV_PKT_DATA_QUALITY_STATS packet side data.
Signed-off-by: James Almer <jamr...@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 _______________________________________________ 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".