Unified · Split
| @@ -62,6 +62,7 @@ enum { · 61 unmodified lines | |||
| 62 | FRAG_TYPE_NONE = 0, | 62 | FRAG_TYPE_NONE = 0, |
| 63 | FRAG_TYPE_EVERY_FRAME, | 63 | FRAG_TYPE_EVERY_FRAME, |
| 64 | FRAG_TYPE_DURATION, | 64 | FRAG_TYPE_DURATION, |
| 65 | FRAG_TYPE_PFRAMES, | ||
| 65 | FRAG_TYPE_NB | 66 | FRAG_TYPE_NB |
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| @@ -91,6 +92,8 @@ typedef struct OutputStream { · 23 unmodified lines | |||
| 91 | AVFormatContext *ctx; | 92 | AVFormatContext *ctx; |
| 92 | int ctx_inited, as_idx; | 93 | int ctx_inited, as_idx; |
| 93 | AVIOContext *out; | 94 | AVIOContext *out; |
| 95 | AVCodecParserContext *parser; | ||
| 96 | AVCodecContext *parser_avctx; | ||
| 94 | int packets_written; | 97 | int packets_written; |
| 95 | char initfile[1024]; | 98 | char initfile[1024]; |
| 96 | int64_t init_start_pos, pos; | 99 | int64_t init_start_pos, pos; |
| @@ -102,6 +105,7 @@ typedef struct OutputStream { · 5 unmodified lines | |||
| 102 | Segment **segments; | 105 | Segment **segments; |
| 103 | int64_t first_pts, start_pts, max_pts; | 106 | int64_t first_pts, start_pts, max_pts; |
| 104 | int64_t last_dts, last_pts; | 107 | int64_t last_dts, last_pts; |
| 108 | int last_flags; | ||
| 105 | int bit_rate; | 109 | int bit_rate; |
| 106 | SegmentType segment_type; /* segment type selected for this particular stream */ | 110 | SegmentType segment_type; /* segment type selected for this particular stream */ |
| 107 | const char *format_name; | 111 | const char *format_name; |
| @@ -117,6 +121,7 @@ typedef struct OutputStream { · 9 unmodified lines | |||
| 117 | char temp_path[1024]; | 121 | char temp_path[1024]; |
| 118 | double availability_time_offset; | 122 | double availability_time_offset; |
| 119 | int total_pkt_size; | 123 | int total_pkt_size; |
| 124 | int64_t total_pkt_duration; | ||
| 120 | int muxer_overhead; | 125 | int muxer_overhead; |
| 121 | int frag_type; | 126 | int frag_type; |
| 122 | } OutputStream; | 127 | } OutputStream; |
| @@ -606,6 +611,8 @@ static void dash_free(AVFormatContext *s) · 483 unmodified lines | |||
| 606 | } | 611 | } |
| 607 | ff_format_io_close(s, &os->out); | 612 | ff_format_io_close(s, &os->out); |
| 608 | avformat_free_context(os->ctx); | 613 | avformat_free_context(os->ctx); |
| 614 | avcodec_free_context(&os->parser_avctx); | ||
| 615 | av_parser_close(os->parser); | ||
| 609 | for (j = 0; j < os->nb_segments; j++) | 616 | for (j = 0; j < os->nb_segments; j++) |
| 610 | av_free(os->segments[j]); | 617 | av_free(os->segments[j]); |
| 611 | av_free(os->segments); | 618 | av_free(os->segments); |
| @@ -933,6 +940,8 @@ static int parse_adaptation_sets(AVFormatContext *s) · 321 unmodified lines | |||
| 933 | 940 | ||
| 934 | if (!strcmp(type_str, "duration")) | 941 | if (!strcmp(type_str, "duration")) |
| 935 | as->frag_type = FRAG_TYPE_DURATION; | 942 | as->frag_type = FRAG_TYPE_DURATION; |
| 943 | else if (!strcmp(type_str, "pframes")) | ||
| 944 | as->frag_type = FRAG_TYPE_PFRAMES; | ||
| 936 | else if (!strcmp(type_str, "every_frame")) | 945 | else if (!strcmp(type_str, "every_frame")) |
| 937 | as->frag_type = FRAG_TYPE_EVERY_FRAME; | 946 | as->frag_type = FRAG_TYPE_EVERY_FRAME; |
| 938 | else if (!strcmp(type_str, "none")) | 947 | else if (!strcmp(type_str, "none")) |
| @@ -1349,6 +1358,18 @@ static int dash_init(AVFormatContext *s) · 410 unmodified lines | |||
| 1349 | ctx->avoid_negative_ts = s->avoid_negative_ts; | 1358 | ctx->avoid_negative_ts = s->avoid_negative_ts; |
| 1350 | ctx->flags = s->flags; | 1359 | ctx->flags = s->flags; |
| 1351 | 1360 | ||
| 1361 | os->parser = av_parser_init(st->codecpar->codec_id); | ||
| 1362 | if (os->parser) { | ||
| 1363 | os->parser_avctx = avcodec_alloc_context3(NULL); | ||
| 1364 | if (!os->parser_avctx) | ||
| 1365 | return AVERROR(ENOMEM); | ||
| 1366 | ret = avcodec_parameters_to_context(os->parser_avctx, st->codecpar); | ||
| 1367 | if (ret < 0) | ||
| 1368 | return ret; | ||
| 1369 | // We only want to parse frame headers | ||
| 1370 | os->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; | ||
| 1371 | } | ||
| 1372 | |||
| 1352 | if (c->single_file) { | 1373 | if (c->single_file) { |
| 1353 | if (os->single_file_name) | 1374 | if (os->single_file_name) |
| 1354 | ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, 0); | 1375 | ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, 0); |
| @@ -1391,6 +1412,11 @@ static int dash_init(AVFormatContext *s) · 36 unmodified lines | |||
| 1391 | av_log(s, AV_LOG_ERROR, "Fragment duration %"PRId64" is longer than Segment duration %"PRId64"\n", os->frag_duration, os->seg_duration); | 1412 | av_log(s, AV_LOG_ERROR, "Fragment duration %"PRId64" is longer than Segment duration %"PRId64"\n", os->frag_duration, os->seg_duration); |
| 1392 | return AVERROR(EINVAL); | 1413 | return AVERROR(EINVAL); |
| 1393 | } | 1414 | } |
| 1415 | if (os->frag_type == FRAG_TYPE_PFRAMES && (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || !os->parser)) { | ||
| 1416 | if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !os->parser) | ||
| 1417 | av_log(s, AV_LOG_WARNING, "frag_type set to P-Frame reordering, but no parser found for stream %d\n", i); | ||
| 1418 | os->frag_type = c->streaming ? FRAG_TYPE_EVERY_FRAME : FRAG_TYPE_NONE; | ||
| 1419 | } | ||
| 1394 | 1420 | ||
| 1395 | if (os->segment_type == SEGMENT_TYPE_MP4) { | 1421 | if (os->segment_type == SEGMENT_TYPE_MP4) { |
| 1396 | if (c->streaming) | 1422 | if (c->streaming) |
| @@ -1458,6 +1484,8 @@ static int dash_init(AVFormatContext *s) · 61 unmodified lines | |||
| 1458 | av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n"); | 1484 | av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n"); |
| 1459 | return AVERROR(EINVAL); | 1485 | return AVERROR(EINVAL); |
| 1460 | } | 1486 | } |
| 1487 | if (!c->has_video && c->frag_type == FRAG_TYPE_PFRAMES) | ||
| 1488 | av_log(s, AV_LOG_WARNING, "no video stream and P-frame fragmentation set\n"); | ||
| 1461 | 1489 | ||
| 1462 | c->nr_of_streams_flushed = 0; | 1490 | c->nr_of_streams_flushed = 0; |
| 1463 | 1491 | ||
| @@ -1730,6 +1758,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) · 266 unmodified lines | |||
| 1730 | av_rescale_q(os->max_pts - os->start_pts, | 1758 | av_rescale_q(os->max_pts - os->start_pts, |
| 1731 | st->time_base, AV_TIME_BASE_Q); | 1759 | st->time_base, AV_TIME_BASE_Q); |
| 1732 | os->total_pkt_size = 0; | 1760 | os->total_pkt_size = 0; |
| 1761 | os->total_pkt_duration = 0; | ||
| 1733 | 1762 | ||
| 1734 | if (!os->bit_rate) { | 1763 | if (!os->bit_rate) { |
| 1735 | // calculate average bitrate of first segment | 1764 | // calculate average bitrate of first segment |
| @@ -1831,6 +1860,9 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) · 95 unmodified lines | |||
| 1831 | sizeof(c->availability_start_time)); | 1860 | sizeof(c->availability_start_time)); |
| 1832 | } | 1861 | } |
| 1833 | 1862 | ||
| 1863 | if (!os->packets_written) | ||
| 1864 | os->availability_time_offset = 0; | ||
| 1865 | |||
| 1834 | if (!os->availability_time_offset && | 1866 | if (!os->availability_time_offset && |
| 1835 | ((os->frag_type == FRAG_TYPE_DURATION && os->seg_duration != os->frag_duration) || | 1867 | ((os->frag_type == FRAG_TYPE_DURATION && os->seg_duration != os->frag_duration) || |
| 1836 | (os->frag_type == FRAG_TYPE_EVERY_FRAME && pkt->duration))) { | 1868 | (os->frag_type == FRAG_TYPE_EVERY_FRAME && pkt->duration))) { |
| @@ -1895,11 +1927,43 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) · 58 unmodified lines | |||
| 1895 | os->max_pts = pkt->pts + pkt->duration; | 1927 | os->max_pts = pkt->pts + pkt->duration; |
| 1896 | else | 1928 | else |
| 1897 | os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration); | 1929 | os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration); |
| 1898 | os->packets_written++; | 1930 | |
| 1899 | os->total_pkt_size += pkt->size; | 1931 | if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && |
| 1932 | os->frag_type == FRAG_TYPE_PFRAMES && | ||
| 1933 | os->packets_written) { | ||
| 1934 | uint8_t *data; | ||
| 1935 | int size; | ||
| 1936 | |||
| 1937 | av_assert0(os->parser); | ||
| 1938 | av_parser_parse2(os->parser, os->parser_avctx, | ||
| 1939 | &data, &size, pkt->data, pkt->size, | ||
| 1940 | pkt->pts, pkt->dts, pkt->pos); | ||
| 1941 | |||
| 1942 | if ((os->parser->pict_type == AV_PICTURE_TYPE_P && | ||
| 1943 | st->codecpar->video_delay && | ||
| 1944 | !(os->last_flags & AV_PKT_FLAG_KEY)) || | ||
| 1945 | pkt->flags & AV_PKT_FLAG_KEY) { | ||
| 1946 | ret = av_write_frame(os->ctx, NULL); | ||
| 1947 | if (ret < 0) | ||
| 1948 | return ret; | ||
| 1949 | |||
| 1950 | if (!os->availability_time_offset) { | ||
| 1951 | int64_t frag_duration = av_rescale_q(os->total_pkt_duration, st->time_base, | ||
| 1952 | AV_TIME_BASE_Q); | ||
| 1953 | os->availability_time_offset = ((double) os->seg_duration - | ||
| 1954 | frag_duration) / AV_TIME_BASE; | ||
| 1955 | } | ||
| 1956 | } | ||
| 1957 | } | ||
| 1958 | |||
| 1900 | if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0) | 1959 | if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0) |
| 1901 | return ret; | 1960 | return ret; |
| 1902 | 1961 | ||
| 1962 | os->packets_written++; | ||
| 1963 | os->total_pkt_size += pkt->size; | ||
| 1964 | os->total_pkt_duration += pkt->duration; | ||
| 1965 | os->last_flags = pkt->flags; | ||
| 1966 | |||
| 1903 | if (!os->init_range_length) | 1967 | if (!os->init_range_length) |
| 1904 | flush_init_segment(s, os); | 1968 | flush_init_segment(s, os); |
| 1905 | 1969 | ||
| @@ -2026,6 +2090,7 @@ static const AVOption options[] = { · 120 unmodified lines | |||
| 2026 | { "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE }, 0, UINT_MAX, E, "frag_type"}, | 2090 | { "none", "one fragment per segment", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_NONE }, 0, UINT_MAX, E, "frag_type"}, |
| 2027 | { "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME }, 0, UINT_MAX, E, "frag_type"}, | 2091 | { "every_frame", "fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_EVERY_FRAME }, 0, UINT_MAX, E, "frag_type"}, |
| 2028 | { "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION }, 0, UINT_MAX, E, "frag_type"}, | 2092 | { "duration", "fragment at specific time intervals", 0, AV_OPT_TYPE_CONST, {.i64 = FRAG_TYPE_DURATION }, 0, UINT_MAX, E, "frag_type"}, |
| 2093 | { "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"}, | ||
| 2029 | { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, | 2094 | { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |
| 2030 | { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, | 2095 | { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, |
| 2031 | { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, | 2096 | { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, |