|
|
@@ -76,7 +76,7 @@ typedef struct OutputStream { |
|
|
int nb_segments, segments_size, segment_index; |
|
|
int nb_segments, segments_size, segment_index; |
|
|
Segment **segments; |
|
|
Segment **segments; |
|
|
int64_t first_pts, start_pts, max_pts; |
|
|
int64_t first_pts, start_pts, max_pts; |
|
|
int64_t last_dts; |
|
|
|
|
|
|
|
|
int64_t last_dts, last_pts; |
|
|
int bit_rate; |
|
|
int bit_rate; |
|
|
|
|
|
|
|
|
char codec_str[100]; |
|
|
char codec_str[100]; |
|
|
@@ -123,6 +123,7 @@ typedef struct DASHContext { |
|
|
AVIOContext *m3u8_out; |
|
|
AVIOContext *m3u8_out; |
|
|
int streaming; |
|
|
int streaming; |
|
|
int64_t timeout; |
|
|
int64_t timeout; |
|
|
|
|
|
int index_correction; |
|
|
} DASHContext; |
|
|
} DASHContext; |
|
|
|
|
|
|
|
|
static struct codec_string { |
|
|
static struct codec_string { |
|
|
@@ -1060,7 +1061,7 @@ static int dash_write_header(AVFormatContext *s) |
|
|
static int add_segment(OutputStream *os, const char *file, |
|
|
static int add_segment(OutputStream *os, const char *file, |
|
|
int64_t time, int duration, |
|
|
int64_t time, int duration, |
|
|
int64_t start_pos, int64_t range_length, |
|
|
int64_t start_pos, int64_t range_length, |
|
|
int64_t index_length) |
|
|
|
|
|
|
|
|
int64_t index_length, int next_exp_index) |
|
|
{ |
|
|
{ |
|
|
int err; |
|
|
int err; |
|
|
Segment *seg; |
|
|
Segment *seg; |
|
|
@@ -1088,6 +1089,12 @@ static int add_segment(OutputStream *os, const char *file, |
|
|
seg->index_length = index_length; |
|
|
seg->index_length = index_length; |
|
|
os->segments[os->nb_segments++] = seg; |
|
|
os->segments[os->nb_segments++] = seg; |
|
|
os->segment_index++; |
|
|
os->segment_index++; |
|
|
|
|
|
//correcting the segment index if it has fallen behind the expected value |
|
|
|
|
|
if (os->segment_index < next_exp_index) { |
|
|
|
|
|
av_log(NULL, AV_LOG_WARNING, "Correcting the segment index after file %s: current=%d corrected=%d\n", |
|
|
|
|
|
file, os->segment_index, next_exp_index); |
|
|
|
|
|
os->segment_index = next_exp_index; |
|
|
|
|
|
} |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@@ -1177,10 +1184,22 @@ static int dash_flush(AVFormatContext *s, int final, int stream) |
|
|
const char *proto = avio_find_protocol_name(s->url); |
|
|
const char *proto = avio_find_protocol_name(s->url); |
|
|
int use_rename = proto && !strcmp(proto, "file"); |
|
|
int use_rename = proto && !strcmp(proto, "file"); |
|
|
|
|
|
|
|
|
int cur_flush_segment_index = 0; |
|
|
|
|
|
if (stream >= 0) |
|
|
|
|
|
|
|
|
int cur_flush_segment_index = 0, next_exp_index = -1; |
|
|
|
|
|
if (stream >= 0) { |
|
|
cur_flush_segment_index = c->streams[stream].segment_index; |
|
|
cur_flush_segment_index = c->streams[stream].segment_index; |
|
|
|
|
|
|
|
|
|
|
|
//finding the next segment's expected index, based on the current pts value |
|
|
|
|
|
if (c->use_template && !c->use_timeline && c->index_correction && |
|
|
|
|
|
c->streams[stream].last_pts != AV_NOPTS_VALUE && |
|
|
|
|
|
c->streams[stream].first_pts != AV_NOPTS_VALUE) { |
|
|
|
|
|
int64_t pts_diff = av_rescale_q(c->streams[stream].last_pts - |
|
|
|
|
|
c->streams[stream].first_pts, |
|
|
|
|
|
s->streams[stream]->time_base, |
|
|
|
|
|
AV_TIME_BASE_Q); |
|
|
|
|
|
next_exp_index = (pts_diff / c->seg_duration) + 1; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (i = 0; i < s->nb_streams; i++) { |
|
|
for (i = 0; i < s->nb_streams; i++) { |
|
|
OutputStream *os = &c->streams[i]; |
|
|
OutputStream *os = &c->streams[i]; |
|
|
AVStream *st = s->streams[i]; |
|
|
AVStream *st = s->streams[i]; |
|
|
@@ -1240,7 +1259,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) |
|
|
if (bitrate >= 0) |
|
|
if (bitrate >= 0) |
|
|
os->bit_rate = bitrate; |
|
|
os->bit_rate = bitrate; |
|
|
} |
|
|
} |
|
|
add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length); |
|
|
|
|
|
|
|
|
add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index); |
|
|
av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); |
|
|
av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); |
|
|
|
|
|
|
|
|
os->pos += range_length; |
|
|
os->pos += range_length; |
|
|
@@ -1303,6 +1322,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
|
|
|
|
if (os->first_pts == AV_NOPTS_VALUE) |
|
|
if (os->first_pts == AV_NOPTS_VALUE) |
|
|
os->first_pts = pkt->pts; |
|
|
os->first_pts = pkt->pts; |
|
|
|
|
|
os->last_pts = pkt->pts; |
|
|
|
|
|
|
|
|
if (!c->availability_start_time[0]) |
|
|
if (!c->availability_start_time[0]) |
|
|
format_date_now(c->availability_start_time, |
|
|
format_date_now(c->availability_start_time, |
|
|
@@ -1485,6 +1505,7 @@ static const AVOption options[] = { |
|
|
{ "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |
|
|
{ "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |
|
|
{ "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |
|
|
{ "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |
|
|
{ "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, |
|
|
{ "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, |
|
|
|
|
|
{ "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, |
|
|
{ NULL }, |
|
|
{ NULL }, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|