[FFmpeg-devel] [PATCH 1/1] avfilter/drawtext: present 'hms' formatted 'pts' in 24h format

2018-05-07 Thread vdixit
From: Vishwanath Dixit 

HMS is formatted as HH:MM:SS.mmm, but, HH part is not limited to
24 hours. For example, the the drawn text may look like this:
243029:20:30.342. To present the timestamp in more readable and
user friendly format, this patch provides an additional option
to limit the hour part in the range 0-23.

Note: Actually the above required format can be obtained with
format options 'localtime' and 'gmtime', but,  milliseconds part
is not supported in those formats.
---
 doc/filters.texi  | 4 
 libavfilter/vf_drawtext.c | 8 
 2 files changed, 12 insertions(+)

diff --git a/doc/filters.texi b/doc/filters.texi
index 33e27e1..6e306f1 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -8134,6 +8134,10 @@ local time zone time.
 
 The second argument is an offset added to the timestamp.
 
+If the format is set to @code{hms}, a third argument @code{24HH} may be
+supplied to present the hour part of the formatted timestamp in 24h format
+(00-23).
+
 If the format is set to @code{localtime} or @code{gmtime},
 a third argument may be supplied: a strftime() format string.
 By default, @var{-MM-DD HH:MM:SS} format will be used.
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index e8905a4..3affa73 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -916,6 +916,14 @@ static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
 sign = '-';
 ms = -ms;
 }
+if (argc >= 3) {
+if (!strcmp(argv[2], "24HH")) {
+ms %= 24 * 60 * 60 * 1000;
+} else {
+av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", 
argv[2]);
+return AVERROR(EINVAL);
+}
+}
 av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign,
(int)(ms / (60 * 60 * 1000)),
(int)(ms / (60 * 1000)) % 60,
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 1/3] avformat/utils: function to get the formatted ntp time

2018-05-07 Thread vdixit
From: Vishwanath Dixit 

This utility function creates 64-bit NTP time format as per the RFC
5905.
A simple explaination of 64-bit NTP time format is here
http://www.beaglesoft.com/Manual/page53.htm
---
 libavformat/internal.h |  8 
 libavformat/utils.c| 22 ++
 2 files changed, 30 insertions(+)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index 3582682..0b8120b 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -240,6 +240,14 @@ void ff_read_frame_flush(AVFormatContext *s);
 uint64_t ff_ntp_time(void);
 
 /**
+ * Get the NTP time stamp formatted as per the RFC-5905.
+ *
+ * @param ntp_time NTP time in micro seconds (since NTP epoch)
+ * @return the formatted NTP time stamp
+ */
+uint64_t ff_get_formatted_ntp_time(uint64_t ntp_time_us);
+
+/**
  * Append the media-specific SDP fragment for the media stream c
  * to the buffer buff.
  *
diff --git a/libavformat/utils.c b/libavformat/utils.c
index c25eab4..4001292 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -4637,6 +4637,28 @@ uint64_t ff_ntp_time(void)
 return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US;
 }
 
+uint64_t ff_get_formatted_ntp_time(uint64_t ntp_time_us)
+{
+uint64_t ntp_ts, frac_part, sec;
+uint32_t usec;
+
+//current ntp time in seconds and micro seconds
+sec = ntp_time_us / 100;
+usec = ntp_time_us % 100;
+
+//encoding in ntp timestamp format
+frac_part = usec * 0xULL;
+frac_part /= 100;
+
+if (sec > 0xULL)
+av_log(NULL, AV_LOG_WARNING, "NTP time format roll over detected\n");
+
+ntp_ts = sec << 32;
+ntp_ts |= frac_part;
+
+return ntp_ts;
+}
+
 int av_get_frame_filename2(char *buf, int buf_size, const char *path, int 
number, int flags)
 {
 const char *p;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 3/3] avformat/dashenc: configuring container format options

2018-05-07 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   | 4 
 libavformat/dashenc.c | 7 +++
 2 files changed, 11 insertions(+)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index db81901..e9082a4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -282,6 +282,10 @@ corrects that index value.
 Typically this logic is needed in live streaming use cases. The network 
bandwidth
 fluctuations are common during long run streaming. Each fluctuation can cause
 the segment indexes fall behind the expected real time position.
+@item -format_options @var{options_list}
+Set container format (mp4/webm) options using a @code{:} separated list of
+key=value parameters. Values containing @code{:} special characters must be
+escaped.
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 1dd6333..e27b61c 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -125,6 +125,7 @@ typedef struct DASHContext {
 int streaming;
 int64_t timeout;
 int index_correction;
+char *format_options_str;
 } DASHContext;
 
 static struct codec_string {
@@ -1017,6 +1018,11 @@ static int dash_init(AVFormatContext *s)
 av_dict_free();
 os->init_start_pos = 0;
 
+if (c->format_options_str) {
+ret = av_dict_parse_string(, c->format_options_str, "=", ":", 
0);
+if (ret < 0)
+return ret;
+}
 if (!strcmp(os->format_name, "mp4")) {
 if (c->streaming)
 av_dict_set(, "movflags", 
"frag_every_frame+dash+delay_moov", 0);
@@ -1538,6 +1544,7 @@ static const AVOption options[] = {
 { "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 },
 { "index_correction", "Enable/Disable segment index correction logic", 
OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
+{ "format_options","set list of options for the container format 
(mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, 
{.str = NULL},  0, 0, E},
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 2/3] avformat/movenc: creating producer reference time (PRFT) box

2018-05-07 Thread vdixit
From: Vishwanath Dixit 

The producer reference time box supplies relative wall-clock times
at which movie fragments, or files containing movie fragments
(such as segments) were produced.
The box is mainly useful in live streaming use cases. A media player
can parse the box and utilize the time fields to measure and improve
the latency during real time playout.
---
 doc/muxers.texi  | 10 ++
 libavformat/movenc.c | 50 ++
 libavformat/movenc.h |  9 +
 3 files changed, 69 insertions(+)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 6f03bba..db81901 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1329,6 +1329,16 @@ be negative. This enables the initial sample to have 
DTS/CTS of zero, and
 reduces the need for edit lists for some cases such as video tracks with
 B-frames. Additionally, eases conformance with the DASH-IF interoperability
 guidelines.
+@item -write_prft
+Write producer time reference box (PRFT) with a specified time source for the
+NTP field in the PRFT box. Set value as @samp{wallclock} to specify timesource
+as wallclock time and @samp{pts} to specify timesource as input packets' PTS
+values.
+
+Setting value to @samp{pts} is applicable only for a live encoding use case,
+where PTS values are set as as wallclock time at the source. For example, an
+encoding use case with decklink capture source where @option{video_pts} and
+@option{audio_pts} are set to @samp{abs_wallclock}.
 @end table
 
 @subsection Example
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 0b44fd6..7e616e8 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -98,6 +98,9 @@ static const AVOption options[] = {
 { "encryption_kid", "The media encryption key identifier (hex)", 
offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = 
AV_OPT_FLAG_ENCODING_PARAM },
 { "use_stream_ids_as_track_ids", "use stream ids as track ids", 
offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 
0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, 
write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
+{ "write_prft", "Write producer reference time box with specified time 
source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = 
MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, "prft"},
+{ "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 
MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "prft"},
+{ "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, 
AV_OPT_FLAG_ENCODING_PARAM, "prft"},
 { NULL },
 };
 
@@ -4514,6 +4517,49 @@ static int mov_write_sidx_tags(AVIOContext *pb, 
MOVMuxContext *mov,
 return 0;
 }
 
+static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
+{
+int64_t pos = avio_tell(pb), pts_us, ntp_ts;
+MOVTrack *first_track;
+
+/* PRFT should be associated with at most one track. So, choosing only the
+ * first track. */
+if (tracks > 0)
+return 0;
+first_track = &(mov->tracks[0]);
+
+if (!first_track->entry) {
+av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in 
the track\n");
+return 0;
+}
+
+if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
+av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is 
invalid\n");
+return 0;
+}
+
+if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
+ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
+} else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
+pts_us = av_rescale_q(first_track->cluster[0].pts,
+  first_track->st->time_base, AV_TIME_BASE_Q);
+ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
+} else {
+av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: 
%d\n",
+   mov->write_prft);
+return 0;
+}
+
+avio_wb32(pb, 0);   // Size place holder
+ffio_wfourcc(pb, "prft");   // Type
+avio_w8(pb, 1); // Version
+avio_wb24(pb, 0);   // Flags
+avio_wb32(pb, first_track->track_id);   // reference track ID
+avio_wb64(pb, ntp_ts);  // NTP time stamp
+avio_wb64(pb, first_track->cluster[0].pts); //media time
+return update_size(pb, pos);
+}
+
 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
   int64_t mdat_size)
 {
@@ -4528,6 +4574,9 @@ static int mov_write_moof_tag(AVIOContext *pb, 
MOVMuxContext *mov, int tracks,
 if (mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & 
FF_MOV_FLAG_GLOBAL_SIDX))
 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
 
+if (mov->write_prft > MOV_PRFT_NONE && 

[FFmpeg-devel] [PATCH 1/1] fftools/ffmpeg: fix for all forced key frames when 'copyts' is enabled

2018-05-06 Thread vdixit
From: Vishwanath Dixit 

Forced key frames generation functionality was assuming the first PTS
value as zero, but, when 'copyts' is enabled, the first PTS can be any
big number. This was eventually forcing all the frames as key frames.
To resolve this issue, update has been made to use first input pts as
reference pts.
---
 fftools/ffmpeg.c | 6 +-
 fftools/ffmpeg.h | 1 +
 fftools/ffmpeg_opt.c | 1 +
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 5a19a09..10f3012 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1236,8 +1236,12 @@ static void do_video_out(OutputFile *of,
 in_picture->quality = enc->global_quality;
 in_picture->pict_type = 0;
 
+if (ost->forced_kf_ref_pts == AV_NOPTS_VALUE &&
+in_picture->pts != AV_NOPTS_VALUE)
+ost->forced_kf_ref_pts = in_picture->pts;
+
 pts_time = in_picture->pts != AV_NOPTS_VALUE ?
-in_picture->pts * av_q2d(enc->time_base) : NAN;
+(in_picture->pts - ost->forced_kf_ref_pts) * 
av_q2d(enc->time_base) : NAN;
 if (ost->forced_kf_index < ost->forced_kf_count &&
 in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
 ost->forced_kf_index++;
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index d44b7a5..eb1eaf6 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -484,6 +484,7 @@ typedef struct OutputStream {
 AVRational frame_aspect_ratio;
 
 /* forced key frames */
+int64_t forced_kf_ref_pts;
 int64_t *forced_kf_pts;
 int forced_kf_count;
 int forced_kf_index;
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 8ae68ae..36bce44 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -1324,6 +1324,7 @@ static OutputStream *new_output_stream(OptionsContext *o, 
AVFormatContext *oc, e
 ost->file_index = nb_output_files - 1;
 ost->index  = idx;
 ost->st = st;
+ost->forced_kf_ref_pts = AV_NOPTS_VALUE;
 st->codecpar->codec_type = type;
 
 ret = choose_encoder(o, oc, ost);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/2] ffmpeg: handling copyts use case in forced key frames functionality

2018-04-25 Thread vdixit
From: Vishwanath Dixit 

Forced key frames creation functionality was assuming the first PTS
value to be zero, but, when 'copyts' is enalbed, the first PTS can
be any big number. This was eventually forcing all the frames as
key frames. To overcome this issue, the actual first PTS value has
to be considered.
---
 fftools/ffmpeg.c | 5 -
 fftools/ffmpeg_opt.c | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 4dbe721..d9bb78a 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1227,7 +1227,7 @@ static void do_video_out(OutputFile *of,
 in_picture->pict_type = 0;
 
 pts_time = in_picture->pts != AV_NOPTS_VALUE ?
-in_picture->pts * av_q2d(enc->time_base) : NAN;
+(in_picture->pts - ost->first_pts) * av_q2d(enc->time_base) : NAN;
 if (ost->forced_kf_index < ost->forced_kf_count &&
 in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) {
 ost->forced_kf_index++;
@@ -1477,6 +1477,9 @@ static int reap_filters(int flush)
 filtered_frame->pts =
 av_rescale_q(filtered_frame->pts, filter_tb, 
enc->time_base) -
 av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base);
+
+if (ost->first_pts == AV_NOPTS_VALUE)
+ost->first_pts = filtered_frame->pts;
 }
 //if (ost->source_index >= 0)
 //*filtered_frame= 
*input_streams[ost->source_index]->decoded_frame; //for me_threshold
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 8ae68ae..24efbd7 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -1510,6 +1510,7 @@ static OutputStream *new_output_stream(OptionsContext *o, 
AVFormatContext *oc, e
 input_streams[source_index]->st->discard = 
input_streams[source_index]->user_set_discard;
 }
 ost->last_mux_dts = AV_NOPTS_VALUE;
+ost->first_pts = AV_NOPTS_VALUE;
 
 ost->muxing_queue = av_fifo_alloc(8 * sizeof(AVPacket));
 if (!ost->muxing_queue)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] ffmpeg: handling copyts use case in progress report computation

2018-04-25 Thread vdixit
From: Vishwanath Dixit 

Progress report computation functionality was assuming the first
PTS value to be zero, but, when 'copyts' is enalbed, the first PTS
can be any big number. This was eventually causing display of
weird statistics during execution of an ffmpeg command. To overcome
this issue, the actual first PTS value has to be considered.
---
 fftools/ffmpeg.c | 8 +++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index d9bb78a..9b71525 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1646,7 +1646,7 @@ static void print_report(int is_last_report, int64_t 
timer_start, int64_t cur_ti
 int frame_number, vid, i;
 double bitrate;
 double speed;
-int64_t pts = INT64_MIN + 1;
+int64_t pts = INT64_MIN + 1, first_pts = INT64_MAX;
 static int64_t last_time = -1;
 static int qp_histogram[52];
 int hours, mins, secs, us;
@@ -1744,6 +1744,11 @@ static void print_report(int is_last_report, int64_t 
timer_start, int64_t cur_ti
 }
 vid = 1;
 }
+
+/* Find the first written PTS among all the output streams */
+first_pts = FFMIN(first_pts, av_rescale_q(ost->first_pts,
+  ost->enc_ctx->time_base,
+  AV_TIME_BASE_Q));
 /* compute min output value */
 if (av_stream_get_end_pts(ost->st) != AV_NOPTS_VALUE)
 pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st),
@@ -1752,6 +1757,7 @@ static void print_report(int is_last_report, int64_t 
timer_start, int64_t cur_ti
 nb_frames_drop += ost->last_dropped;
 }
 
+pts -= first_pts;
 secs = FFABS(pts) / AV_TIME_BASE;
 us = FFABS(pts) % AV_TIME_BASE;
 mins = secs / 60;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/3] avformat/dashenc: configuring container format options

2018-04-24 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   | 4 
 libavformat/dashenc.c | 7 +++
 2 files changed, 11 insertions(+)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index db81901..e9082a4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -282,6 +282,10 @@ corrects that index value.
 Typically this logic is needed in live streaming use cases. The network 
bandwidth
 fluctuations are common during long run streaming. Each fluctuation can cause
 the segment indexes fall behind the expected real time position.
+@item -format_options @var{options_list}
+Set container format (mp4/webm) options using a @code{:} separated list of
+key=value parameters. Values containing @code{:} special characters must be
+escaped.
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index fefe3ce..1ba5146 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -124,6 +124,7 @@ typedef struct DASHContext {
 int streaming;
 int64_t timeout;
 int index_correction;
+char *format_options_str;
 } DASHContext;
 
 static struct codec_string {
@@ -987,6 +988,11 @@ static int dash_init(AVFormatContext *s)
 av_dict_free();
 os->init_start_pos = 0;
 
+if (c->format_options_str) {
+ret = av_dict_parse_string(, c->format_options_str, "=", ":", 
0);
+if (ret < 0)
+return ret;
+}
 if (!strcmp(os->format_name, "mp4")) {
 if (c->streaming)
 av_dict_set(, "movflags", 
"frag_every_frame+dash+delay_moov", 0);
@@ -1506,6 +1512,7 @@ static const AVOption options[] = {
 { "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 },
 { "index_correction", "Enable/Disable segment index correction logic", 
OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E },
+{ "format_options","set list of options for the container format 
(mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, 
{.str = NULL},  0, 0, E},
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/3] avformat/movenc: creating producer reference time (PRFT) box

2018-04-24 Thread vdixit
From: Vishwanath Dixit 

The producer reference time box supplies relative wall-clock times
at which movie fragments, or files containing movie fragments
(such as segments) were produced.
The box is mainly useful in live streaming use cases. A media player
can parse the box and utilize the time fields to measure and improve
the latency during real time playout.
---
 doc/muxers.texi  | 10 ++
 libavformat/movenc.c | 50 ++
 libavformat/movenc.h |  9 +
 3 files changed, 69 insertions(+)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 6f03bba..db81901 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -1329,6 +1329,16 @@ be negative. This enables the initial sample to have 
DTS/CTS of zero, and
 reduces the need for edit lists for some cases such as video tracks with
 B-frames. Additionally, eases conformance with the DASH-IF interoperability
 guidelines.
+@item -write_prft
+Write producer time reference box (PRFT) with a specified time source for the
+NTP field in the PRFT box. Set value as @samp{wallclock} to specify timesource
+as wallclock time and @samp{pts} to specify timesource as input packets' PTS
+values.
+
+Setting value to @samp{pts} is applicable only for a live encoding use case,
+where PTS values are set as as wallclock time at the source. For example, an
+encoding use case with decklink capture source where @option{video_pts} and
+@option{audio_pts} are set to @samp{abs_wallclock}.
 @end table
 
 @subsection Example
diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index 0b44fd6..14e397a 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -98,6 +98,9 @@ static const AVOption options[] = {
 { "encryption_kid", "The media encryption key identifier (hex)", 
offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = 
AV_OPT_FLAG_ENCODING_PARAM },
 { "use_stream_ids_as_track_ids", "use stream ids as track ids", 
offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 
0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, 
write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
+{ "write_prft", "Write producer reference time box with specified time 
source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = 
MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, "prft"},
+{ "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 
MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "prft"},
+{ "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, 
AV_OPT_FLAG_ENCODING_PARAM, "prft"},
 { NULL },
 };
 
@@ -4514,6 +4517,49 @@ static int mov_write_sidx_tags(AVIOContext *pb, 
MOVMuxContext *mov,
 return 0;
 }
 
+static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
+{
+int64_t pos = avio_tell(pb), pts_us, ntp_ts;
+MOVTrack *first_track;
+
+/* PRFT should be associated with at most one track. So, choosing only the
+ * first track. */
+if (tracks > 0)
+return 0;
+first_track = &(mov->tracks[0]);
+
+if (!first_track->entry) {
+av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in 
the track\n");
+return 0;
+}
+
+if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
+av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is 
invalid\n");
+return 0;
+}
+
+if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
+ntp_ts = ff_time_ntp_format(ff_ntp_time());
+} else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
+pts_us = av_rescale_q(first_track->cluster[0].pts,
+  first_track->st->time_base, AV_TIME_BASE_Q);
+ntp_ts = ff_time_ntp_format(pts_us + NTP_OFFSET_US);
+} else {
+av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: 
%d\n",
+   mov->write_prft);
+return 0;
+}
+
+avio_wb32(pb, 0);   // Size place holder
+ffio_wfourcc(pb, "prft");   // Type
+avio_w8(pb, 1); // Version
+avio_wb24(pb, 0);   // Flags
+avio_wb32(pb, first_track->track_id);   // reference track ID
+avio_wb64(pb, ntp_ts);  // NTP time stamp
+avio_wb64(pb, first_track->cluster[0].pts); //media time
+return update_size(pb, pos);
+}
+
 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
   int64_t mdat_size)
 {
@@ -4528,6 +4574,9 @@ static int mov_write_moof_tag(AVIOContext *pb, 
MOVMuxContext *mov, int tracks,
 if (mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & 
FF_MOV_FLAG_GLOBAL_SIDX))
 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
 
+if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < 

[FFmpeg-devel] [PATCH 1/3] avformat/utils: function to get the formatted ntp time

2018-04-24 Thread vdixit
From: Vishwanath Dixit 

This utility function creates 64-bit NTP time format as per the RFC
5905.
A simple explaination of 64-bit NTP time format is here
http://www.beaglesoft.com/Manual/page53.htm
---
 libavformat/internal.h |  8 
 libavformat/utils.c| 20 
 2 files changed, 28 insertions(+)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index 3582682..e9f758f 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -240,6 +240,14 @@ void ff_read_frame_flush(AVFormatContext *s);
 uint64_t ff_ntp_time(void);
 
 /**
+ * Get the NTP time stamp formatted as per the RFC-5905.
+ *
+ * @param ntp_time NTP time in micro seconds (since NTP epoch)
+ * @return the formatted NTP time stamp
+ */
+uint64_t ff_time_ntp_format(uint64_t ntp_time);
+
+/**
  * Append the media-specific SDP fragment for the media stream c
  * to the buffer buff.
  *
diff --git a/libavformat/utils.c b/libavformat/utils.c
index c25eab4..b59d426 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -4637,6 +4637,26 @@ uint64_t ff_ntp_time(void)
 return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US;
 }
 
+uint64_t ff_time_ntp_format(uint64_t ntp_time)
+{
+uint64_t ntp_ts, frac_part;
+uint32_t sec, usec;
+
+//current ntp time in seconds and micro seconds
+sec = ntp_time / 100;
+usec = ntp_time % 100;
+
+//encoding in ntp timestamp format
+frac_part = usec * 0xULL;
+frac_part /= 100;
+
+ntp_ts = (uint64_t) sec;
+ntp_ts <<= 32;
+ntp_ts |= frac_part;
+
+return ntp_ts;
+}
+
 int av_get_frame_filename2(char *buf, int buf_size, const char *path, int 
number, int flags)
 {
 const char *p;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v4 1/1] avformat/dashenc: replacing 'min_seg_duration' with 'seg_duration'

2018-04-15 Thread vdixit
From: Vishwanath Dixit 

There are use cases where average segment duration needs to be configured
and muxer is expected to maintain the average segment duration. So, using
the name 'min_seg_duration' will be misleading. So, changing the parameter
name to 'seg_duration', where it can be minimum segment duration or average
segment duration based on the use-case. The additional updates needed for
this functinality are made the sub-sequent patches of this patch series.
---
 doc/muxers.texi   |  4 +++-
 libavformat/dashenc.c | 23 ++-
 libavformat/version.h |  3 +++
 3 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index f288764..fad9c9a 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -226,7 +226,9 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 
 @table @option
 @item -min_seg_duration @var{microseconds}
-Set the segment length in microseconds.
+This is a deprecated option to set the segment length in microseconds, use 
@var{seg_duration} instead.
+@item -seg_duration @var{duration}
+Set the segment length in seconds (fractional value can be set).
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
 @item -extra_window_size @var{size}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bdf8c8d..7169e11 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -94,7 +94,10 @@ typedef struct DASHContext {
 int nb_as;
 int window_size;
 int extra_window_size;
+#if FF_API_DASH_MIN_SEG_DURATION
 int min_seg_duration;
+#endif
+int64_t seg_duration;
 int remove_at_exit;
 int use_template;
 int use_timeline;
@@ -871,6 +874,13 @@ static int dash_init(AVFormatContext *s)
 if (c->single_file)
 c->use_template = 0;
 
+#if FF_API_DASH_MIN_SEG_DURATION
+if (c->min_seg_duration != 500) {
+av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated 
and will be removed. Please use the -seg_duration\n");
+c->seg_duration = c->min_seg_duration;
+}
+#endif
+
 av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
 ptr = strrchr(c->dirname, '/');
 if (ptr) {
@@ -974,7 +984,7 @@ static int dash_init(AVFormatContext *s)
 else
 av_dict_set(, "movflags", "frag_custom+dash+delay_moov", 
0);
 } else {
-av_dict_set_int(, "cluster_time_limit", c->min_seg_duration / 
1000, 0);
+av_dict_set_int(, "cluster_time_limit", c->seg_duration / 
1000, 0);
 av_dict_set_int(, "cluster_size_limit", 5 * 1024 * 1024, 0); 
// set a large cluster size limit
 av_dict_set_int(, "dash", 1, 0);
 av_dict_set_int(, "dash_track_number", i + 1, 0);
@@ -1020,8 +1030,8 @@ static int dash_init(AVFormatContext *s)
 os->segment_index = 1;
 }
 
-if (!c->has_video && c->min_seg_duration <= 0) {
-av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration 
set\n");
+if (!c->has_video && c->seg_duration <= 0) {
+av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
 return AVERROR(EINVAL);
 }
 return 0;
@@ -1287,7 +1297,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
 av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
+  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1427,7 +1437,10 @@ static const AVOption options[] = {
 { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 
id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
 { "window_size", "number of segments kept in the manifest", 
OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
 { "extra_window_size", "number of segments kept outside of the manifest 
before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 
= 5 }, 0, INT_MAX, E },
-{ "min_seg_duration", "minimum segment duration (in microseconds)", 
OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, E },
+#if FF_API_DASH_MIN_SEG_DURATION
+{ "min_seg_duration", "minimum segment duration (in microseconds) (will be 
deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, 
INT_MAX, E },
+#endif
+{ "seg_duration", "segment duration (in seconds, fractional value can be 
set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 500 }, 0, 
INT_MAX, E },
 { "remove_at_exit", "remove all segments when finished", 
OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, 

[FFmpeg-devel] [PATCH v3 10/11] avformat/dashenc: addition of muxer overhead for @bandwidth param in MPD

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 6d06486..bf8698f 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -555,7 +555,7 @@ static int write_adaptation_set(AVFormatContext *s, 
AVIOContext *out, int as_ind
 
 if (os->bit_rate > 0)
 snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
- os->bit_rate);
+ os->bit_rate + os->muxer_overhead);
 
 if (as->media_type == AVMEDIA_TYPE_VIDEO) {
 AVStream *st = s->streams[i];
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 11/11] avformat/dashenc: addition of segment index correction logic

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

The logic is applicable only when use_template is enabled and use_timeline
is disabled. The logic monitors the flow of segment indexes. If a streams's
segment index value is not at the expected real time position, then
the logic corrects that index value.

Typically this logic is needed in live streaming use cases. The network
bandwidth fluctuations are common during long run streaming. Each
fluctuation can cause the segment indexes fall behind the expected real
time position. Without this logic, players will not be able to consume
the content, even after encoder's network condition comes back to
normal state.
---
 doc/muxers.texi   | 11 +++
 libavformat/dashenc.c | 31 ++-
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index e1b..fa528b6 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -271,6 +271,17 @@ To map all video (or audio) streams to an AdaptationSet, 
"v" (or "a") can be use
 When no assignment is defined, this defaults to an AdaptationSet for each 
stream.
 @item -timeout @var{timeout}
 Set timeout for socket I/O operations. Applicable only for HTTP output.
+@item -index_correction @var{index_correction}
+Enable (1) or Disable (0) segment index correction logic. Applicable only when
+@var{use_template} is enabled and @var{use_timeline} is disabled.
+
+When enabled, the logic monitors the flow of segment indexes. If a streams's
+segment index value is not at the expected real time position, then the logic
+corrects that index value.
+
+Typically this logic is needed in live streaming use cases. The network 
bandwidth
+fluctuations are common during long run streaming. Each fluctuation can cause
+the segment indexes fall behind the expected real time position.
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bf8698f..9e72636 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -76,7 +76,7 @@ typedef struct OutputStream {
 int nb_segments, segments_size, segment_index;
 Segment **segments;
 int64_t first_pts, start_pts, max_pts;
-int64_t last_dts;
+int64_t last_dts, last_pts;
 int bit_rate;
 
 char codec_str[100];
@@ -123,6 +123,7 @@ typedef struct DASHContext {
 AVIOContext *m3u8_out;
 int streaming;
 int64_t timeout;
+int index_correction;
 } DASHContext;
 
 static struct codec_string {
@@ -1060,7 +1061,7 @@ static int dash_write_header(AVFormatContext *s)
 static int add_segment(OutputStream *os, const char *file,
int64_t time, int duration,
int64_t start_pos, int64_t range_length,
-   int64_t index_length)
+   int64_t index_length, int next_exp_index)
 {
 int err;
 Segment *seg;
@@ -1088,6 +1089,12 @@ static int add_segment(OutputStream *os, const char 
*file,
 seg->index_length = index_length;
 os->segments[os->nb_segments++] = seg;
 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;
 }
 
@@ -1177,10 +1184,22 @@ static int dash_flush(AVFormatContext *s, int final, 
int stream)
 const char *proto = avio_find_protocol_name(s->url);
 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;
 
+//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++) {
 OutputStream *os = >streams[i];
 AVStream *st = s->streams[i];
@@ -1240,7 +1259,7 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 if (bitrate >= 0)
 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, 

[FFmpeg-devel] [PATCH v3 08/11] avformat/dashenc: addition of muxer overhead in master playlist's bandwidth

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 9c29c05..1d34bb9 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -827,20 +827,23 @@ static int write_manifest(AVFormatContext *s, int final)
 for (i = 0; i < s->nb_streams; i++) {
 char playlist_file[64];
 AVStream *st = s->streams[i];
+OutputStream *os = >streams[i];
 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
 continue;
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_audio_rendition(out, (char *)audio_group,
  playlist_file, i, is_default);
-max_audio_bitrate = FFMAX(st->codecpar->bit_rate, 
max_audio_bitrate);
+max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
+  os->muxer_overhead, max_audio_bitrate);
 is_default = 0;
 }
 
 for (i = 0; i < s->nb_streams; i++) {
 char playlist_file[64];
 AVStream *st = s->streams[i];
+OutputStream *os = >streams[i];
 char *agroup = NULL;
-int stream_bitrate = st->codecpar->bit_rate;
+int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead;
 if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && 
max_audio_bitrate) {
 agroup = (char *)audio_group;
 stream_bitrate += max_audio_bitrate;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 09/11] avformat/dashenc: constructing MPD's bandwidth string locally

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 20 +---
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 1d34bb9..6d06486 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -78,7 +78,6 @@ typedef struct OutputStream {
 int64_t first_pts, start_pts, max_pts;
 int64_t last_dts;
 int bit_rate;
-char bandwidth_str[64];
 
 char codec_str[100];
 int written_len;
@@ -549,20 +548,25 @@ static int write_adaptation_set(AVFormatContext *s, 
AVIOContext *out, int as_ind
 
 for (i = 0; i < s->nb_streams; i++) {
 OutputStream *os = >streams[i];
+char bandwidth_str[64] = {'\0'};
 
 if (os->as_idx - 1 != as_index)
 continue;
 
+if (os->bit_rate > 0)
+snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
+ os->bit_rate);
+
 if (as->media_type == AVMEDIA_TYPE_VIDEO) {
 AVStream *st = s->streams[i];
 avio_printf(out, "\t\t\tformat_name, os->codec_str, os->bandwidth_str, 
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
+i, os->format_name, os->codec_str, bandwidth_str, 
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
 if (st->avg_frame_rate.num)
 avio_printf(out, " frameRate=\"%d/%d\"", 
st->avg_frame_rate.num, st->avg_frame_rate.den);
 avio_printf(out, ">\n");
 } else {
 avio_printf(out, "\t\t\t\n",
-i, os->format_name, os->codec_str, os->bandwidth_str, 
s->streams[i]->codecpar->sample_rate);
+i, os->format_name, os->codec_str, bandwidth_str, 
s->streams[i]->codecpar->sample_rate);
 avio_printf(out, "\t\t\t\t\n",
 s->streams[i]->codecpar->channels);
 }
@@ -918,10 +922,7 @@ static int dash_init(AVFormatContext *s)
 char filename[1024];
 
 os->bit_rate = s->streams[i]->codecpar->bit_rate;
-if (os->bit_rate) {
-snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
-} else {
+if (!os->bit_rate) {
 int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ?
 AV_LOG_ERROR : AV_LOG_WARNING;
 av_log(s, level, "No bit rate set for stream %d\n", i);
@@ -1236,11 +1237,8 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / 
av_rescale_q(os->max_pts - os->start_pts,

st->time_base,

AV_TIME_BASE_Q);
-if (bitrate >= 0) {
+if (bitrate >= 0)
 os->bit_rate = bitrate;
-snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
-}
 }
 add_segment(os, os->filename, os->start_pts, os->max_pts - 
os->start_pts, os->pos, range_length, index_length);
 av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written 
to: %s\n", i, os->segment_index, os->full_path);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 06/11] avformat/dashenc: addition of @availabilityTimeOffset in MPD

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

availability time of Nth segment = availabilityStartTime + (N*segment duration) 
- availabilityTimeOffset.
This field helps to reduce the latency by about a segment duration in streaming 
mode.
---
 libavformat/dashenc.c | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5d5310d..70409e5 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -85,6 +85,7 @@ typedef struct OutputStream {
 char filename[1024];
 char full_path[1024];
 char temp_path[1024];
+double availability_time_offset;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -346,8 +347,12 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 if (c->use_template) {
 int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : 
AV_TIME_BASE;
 avio_printf(out, "\t\t\t\tuse_timeline)
+if (!c->use_timeline) {
 avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration);
+if (c->streaming && os->availability_time_offset)
+avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
+os->availability_time_offset);
+}
 avio_printf(out, "initialization=\"%s\" media=\"%s\" 
startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? 
start_number : 1);
 if (c->use_timeline) {
 int64_t cur_time = 0;
@@ -1293,6 +1298,13 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 format_date_now(c->availability_start_time,
 sizeof(c->availability_start_time));
 
+if (!os->availability_time_offset && pkt->duration) {
+int64_t frame_duration = av_rescale_q(pkt->duration, st->time_base,
+  AV_TIME_BASE_Q);
+ os->availability_time_offset = ((double) c->seg_duration -
+ frame_duration) / AV_TIME_BASE;
+}
+
 if (c->use_template && !c->use_timeline) {
 elapsed_duration = pkt->pts - os->first_pts;
 seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 07/11] avformat/dashenc: logic to compute muxer overhead

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 70409e5..9c29c05 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -86,6 +86,8 @@ typedef struct OutputStream {
 char full_path[1024];
 char temp_path[1024];
 double availability_time_offset;
+int total_pkt_size;
+int muxer_overhead;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -1219,6 +1221,13 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 }
 }
 
+if (!os->muxer_overhead)
+os->muxer_overhead = ((int64_t) (range_length - 
os->total_pkt_size) *
+  8 * AV_TIME_BASE) /
+ av_rescale_q(os->max_pts - os->start_pts,
+  st->time_base, AV_TIME_BASE_Q);
+os->total_pkt_size = 0;
+
 if (!os->bit_rate) {
 // calculate average bitrate of first segment
 int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / 
av_rescale_q(os->max_pts - os->start_pts,
@@ -1353,6 +1362,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 else
 os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
 os->packets_written++;
+os->total_pkt_size += pkt->size;
 if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
 return ret;
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 05/11] avformat/dashenc: setting @availabilityStartTime when the first frame is ready

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

@availabilityStartTime specifies the anchor for the computation of the earliest
availability time (in UTC) for any Segment in the Media Presentation.

As per this requirement, the @AvailabilityStartTime should be set to the
wallclock time at which the first frame of the first segment begins encoding.
But, it was getting set only when the first segment was completely ready. Making
the required correction in this patch. This correction is mainly needed to 
reduce
the latency in live streaming use cases.
---
 libavformat/dashenc.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bf06a7b..5d5310d 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -743,9 +743,6 @@ static int write_manifest(AVFormatContext *s, int final)
 update_period = 500;
 avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", 
update_period);
 avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", 
c->last_duration / AV_TIME_BASE);
-if (!c->availability_start_time[0] && s->nb_streams > 0 && 
c->streams[0].nb_segments > 0) {
-format_date_now(c->availability_start_time, 
sizeof(c->availability_start_time));
-}
 if (c->availability_start_time[0])
 avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", 
c->availability_start_time);
 format_date_now(now_str, sizeof(now_str));
@@ -1292,6 +1289,10 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (os->first_pts == AV_NOPTS_VALUE)
 os->first_pts = pkt->pts;
 
+if (!c->availability_start_time[0])
+format_date_now(c->availability_start_time,
+sizeof(c->availability_start_time));
+
 if (c->use_template && !c->use_timeline) {
 elapsed_duration = pkt->pts - os->first_pts;
 seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 04/11] avformat/dashenc: removed 'write_manifest' call from 'write_header'

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

Calling 'write_manifest' from 'write_header' was causing creation of
first MPD with invalid values. Ex: zero @duration param value. Also,
the manifest files (MPD or M3U8s) should be created when at-least
one media frame is ready for consumption.
---
 libavformat/dashenc.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 4c2e63c..bf06a7b 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1046,9 +1046,6 @@ static int dash_write_header(AVFormatContext *s)
 if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
 return ret;
 }
-ret = write_manifest(s, 0);
-if (!ret)
-av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->url);
 return ret;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 03/11] avformat/dashenc: writing average segment duration for @duration in template mode

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index ad52730..4c2e63c 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -347,7 +347,7 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : 
AV_TIME_BASE;
 avio_printf(out, "\t\t\t\tuse_timeline)
-avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
+avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration);
 avio_printf(out, "initialization=\"%s\" media=\"%s\" 
startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? 
start_number : 1);
 if (c->use_timeline) {
 int64_t cur_time = 0;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 02/11] avformat/dashenc: segmentation at the configured segment duration rate

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

When use_template is enabled and use_timeline is disabled, typically
it is required to generate the segments at the configured segment duration
rate on an average. This commit is particularly needed to handle the
segmentation when video frame rates are fractional like 29.97 or 59.94 fps.
---
 doc/muxers.texi   |  5 -
 libavformat/dashenc.c | 13 +++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 8dbfede..e1b 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -228,7 +228,10 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 @item -min_seg_duration @var{microseconds}
 This is a deprecated option to set the segment length in microseconds, use 
@var{seg_duration} instead.
 @item -seg_duration @var{duration}
-Set the segment length in seconds (fractional value can be set).
+Set the segment length in seconds (fractional value can be set). The value is
+treated as average segment duration when @var{use_template} is enabled and
+@var{use_timeline} is disabled and as minimum segment duration for all the 
other
+use cases.
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
 @item -extra_window_size @var{size}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 7169e11..ad52730 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1267,6 +1267,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 DASHContext *c = s->priv_data;
 AVStream *st = s->streams[pkt->stream_index];
 OutputStream *os = >streams[pkt->stream_index];
+int64_t seg_end_duration, elapsed_duration;
 int ret;
 
 ret = update_stream_extradata(s, os, st->codecpar);
@@ -1294,10 +1295,18 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (os->first_pts == AV_NOPTS_VALUE)
 os->first_pts = pkt->pts;
 
+if (c->use_template && !c->use_timeline) {
+elapsed_duration = pkt->pts - os->first_pts;
+seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
+} else {
+elapsed_duration = pkt->pts - os->start_pts;
+seg_end_duration = c->seg_duration;
+}
+
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
-av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
+av_compare_ts(elapsed_duration, st->time_base,
+  seg_end_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 01/11] avformat/dashenc: replacing 'min_seg_duration' with 'seg_duration'

2018-04-11 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  4 +++-
 libavformat/dashenc.c | 23 ++-
 libavformat/version.h |  3 +++
 3 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index cb75c26..8dbfede 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -226,7 +226,9 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 
 @table @option
 @item -min_seg_duration @var{microseconds}
-Set the segment length in microseconds.
+This is a deprecated option to set the segment length in microseconds, use 
@var{seg_duration} instead.
+@item -seg_duration @var{duration}
+Set the segment length in seconds (fractional value can be set).
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
 @item -extra_window_size @var{size}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bdf8c8d..7169e11 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -94,7 +94,10 @@ typedef struct DASHContext {
 int nb_as;
 int window_size;
 int extra_window_size;
+#if FF_API_DASH_MIN_SEG_DURATION
 int min_seg_duration;
+#endif
+int64_t seg_duration;
 int remove_at_exit;
 int use_template;
 int use_timeline;
@@ -871,6 +874,13 @@ static int dash_init(AVFormatContext *s)
 if (c->single_file)
 c->use_template = 0;
 
+#if FF_API_DASH_MIN_SEG_DURATION
+if (c->min_seg_duration != 500) {
+av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated 
and will be removed. Please use the -seg_duration\n");
+c->seg_duration = c->min_seg_duration;
+}
+#endif
+
 av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
 ptr = strrchr(c->dirname, '/');
 if (ptr) {
@@ -974,7 +984,7 @@ static int dash_init(AVFormatContext *s)
 else
 av_dict_set(, "movflags", "frag_custom+dash+delay_moov", 
0);
 } else {
-av_dict_set_int(, "cluster_time_limit", c->min_seg_duration / 
1000, 0);
+av_dict_set_int(, "cluster_time_limit", c->seg_duration / 
1000, 0);
 av_dict_set_int(, "cluster_size_limit", 5 * 1024 * 1024, 0); 
// set a large cluster size limit
 av_dict_set_int(, "dash", 1, 0);
 av_dict_set_int(, "dash_track_number", i + 1, 0);
@@ -1020,8 +1030,8 @@ static int dash_init(AVFormatContext *s)
 os->segment_index = 1;
 }
 
-if (!c->has_video && c->min_seg_duration <= 0) {
-av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration 
set\n");
+if (!c->has_video && c->seg_duration <= 0) {
+av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
 return AVERROR(EINVAL);
 }
 return 0;
@@ -1287,7 +1297,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
 av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
+  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1427,7 +1437,10 @@ static const AVOption options[] = {
 { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 
id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
 { "window_size", "number of segments kept in the manifest", 
OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
 { "extra_window_size", "number of segments kept outside of the manifest 
before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 
= 5 }, 0, INT_MAX, E },
-{ "min_seg_duration", "minimum segment duration (in microseconds)", 
OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, E },
+#if FF_API_DASH_MIN_SEG_DURATION
+{ "min_seg_duration", "minimum segment duration (in microseconds) (will be 
deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, 
INT_MAX, E },
+#endif
+{ "seg_duration", "segment duration (in seconds, fractional value can be 
set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 500 }, 0, 
INT_MAX, E },
 { "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 },
diff --git a/libavformat/version.h b/libavformat/version.h
index a96e13b..d02e17e 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -94,6 +94,9 @@
 #ifndef 

[FFmpeg-devel] [PATCH v2 1/1] avformat/http: flushing tcp receive buffer when it is write only mode

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

In write only mode, the TCP receive buffer's data keeps growing with
http response messages and the buffer eventually becomes full.
This results in zero tcp window size, which in turn causes unwanted
issues, like, terminated tcp connection. The issue is apparent when
http persistent connection is enabled in hls/dash live streaming use
cases. To overcome this issue, the logic here reads the buffer data
when a file transfer is completed, so that any accumulated data in
the recieve buffer gets flushed out.
---
 libavformat/http.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/libavformat/http.c b/libavformat/http.c
index 983034f..0c39e9c 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -1627,6 +1627,18 @@ static int http_shutdown(URLContext *h, int flags)
 ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
 ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
 ret = ret > 0 ? 0 : ret;
+/* flush the receive buffer when it is write only mode */
+if (!(flags & AVIO_FLAG_READ)) {
+char buf[1024];
+int read_ret;
+s->hd->flags |= AVIO_FLAG_NONBLOCK;
+read_ret = ffurl_read(s->hd, buf, sizeof(buf));
+s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
+if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) {
+av_log(h, AV_LOG_ERROR, "URL read error:  %d\n", read_ret);
+ret = read_ret;
+}
+}
 s->end_chunked_post = 1;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 11/11] avformat/dashenc: addition of segment index correction logic

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

The logic is applicable only when use_template is enabled and use_timeline
is disabled. The logic monitors the flow of segment indexes. If a streams's
segment index value is not at the expected real time position, then
the logic corrects that index value.

Typically this logic is needed in live streaming use cases. The network
bandwidth fluctuations are common during long run streaming. Each
fluctuation can cause the segment indexes fall behind the expected real
time position. Without this logic, players will not be able to consume
the content, even after encoder's network condition comes back to
normal state.
---
 doc/muxers.texi   | 11 +++
 libavformat/dashenc.c | 31 ++-
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 9e8b8a4..e5c9be1 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -271,6 +271,17 @@ To map all video (or audio) streams to an AdaptationSet, 
"v" (or "a") can be use
 When no assignment is defined, this defaults to an AdaptationSet for each 
stream.
 @item -timeout @var{timeout}
 Set timeout for socket I/O operations. Applicable only for HTTP output.
+@item -index_correction @var{index_correction}
+Enable (1) or Disable (0) segment index correction logic. Applicable only when
+@var{use_template} is enabled and @var{use_timeline} is disabled.
+
+When enabled, the logic monitors the flow of segment indexes. If a streams's
+segment index value is not at the expected real time position, then the logic
+corrects that index value.
+
+Typically this logic is needed in live streaming use cases. The network 
bandwidth
+fluctuations are common during long run streaming. Each fluctuation can cause
+the segment indexes fall behind the expected real time position.
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index ac05378..f0848c5 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -76,7 +76,7 @@ typedef struct OutputStream {
 int nb_segments, segments_size, segment_index;
 Segment **segments;
 int64_t first_pts, start_pts, max_pts;
-int64_t last_dts;
+int64_t last_dts, last_pts;
 int bit_rate;
 
 char codec_str[100];
@@ -121,6 +121,7 @@ typedef struct DASHContext {
 AVIOContext *m3u8_out;
 int streaming;
 int64_t timeout;
+int index_correction;
 } DASHContext;
 
 static struct codec_string {
@@ -1056,7 +1057,7 @@ static int dash_write_header(AVFormatContext *s)
 static int add_segment(OutputStream *os, const char *file,
int64_t time, int duration,
int64_t start_pos, int64_t range_length,
-   int64_t index_length)
+   int64_t index_length, int next_exp_index)
 {
 int err;
 Segment *seg;
@@ -1084,6 +1085,12 @@ static int add_segment(OutputStream *os, const char 
*file,
 seg->index_length = index_length;
 os->segments[os->nb_segments++] = seg;
 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;
 }
 
@@ -1173,10 +1180,22 @@ static int dash_flush(AVFormatContext *s, int final, 
int stream)
 const char *proto = avio_find_protocol_name(s->url);
 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;
 
+//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++) {
 OutputStream *os = >streams[i];
 AVStream *st = s->streams[i];
@@ -1236,7 +1255,7 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 if (bitrate >= 0)
 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, 

[FFmpeg-devel] [PATCH v2 09/11] avformat/dashenc: constructing MPD's bandwidth string locally

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 20 +---
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 72431b7..31b0c92 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -78,7 +78,6 @@ typedef struct OutputStream {
 int64_t first_pts, start_pts, max_pts;
 int64_t last_dts;
 int bit_rate;
-char bandwidth_str[64];
 
 char codec_str[100];
 int written_len;
@@ -547,20 +546,25 @@ static int write_adaptation_set(AVFormatContext *s, 
AVIOContext *out, int as_ind
 
 for (i = 0; i < s->nb_streams; i++) {
 OutputStream *os = >streams[i];
+char bandwidth_str[64] = {'\0'};
 
 if (os->as_idx - 1 != as_index)
 continue;
 
+if (os->bit_rate > 0)
+snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
+ os->bit_rate);
+
 if (as->media_type == AVMEDIA_TYPE_VIDEO) {
 AVStream *st = s->streams[i];
 avio_printf(out, "\t\t\tformat_name, os->codec_str, os->bandwidth_str, 
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
+i, os->format_name, os->codec_str, bandwidth_str, 
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
 if (st->avg_frame_rate.num)
 avio_printf(out, " frameRate=\"%d/%d\"", 
st->avg_frame_rate.num, st->avg_frame_rate.den);
 avio_printf(out, ">\n");
 } else {
 avio_printf(out, "\t\t\t\n",
-i, os->format_name, os->codec_str, os->bandwidth_str, 
s->streams[i]->codecpar->sample_rate);
+i, os->format_name, os->codec_str, bandwidth_str, 
s->streams[i]->codecpar->sample_rate);
 avio_printf(out, "\t\t\t\t\n",
 s->streams[i]->codecpar->channels);
 }
@@ -914,10 +918,7 @@ static int dash_init(AVFormatContext *s)
 char filename[1024];
 
 os->bit_rate = s->streams[i]->codecpar->bit_rate;
-if (os->bit_rate) {
-snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
-} else {
+if (!os->bit_rate) {
 int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ?
 AV_LOG_ERROR : AV_LOG_WARNING;
 av_log(s, level, "No bit rate set for stream %d\n", i);
@@ -1232,11 +1233,8 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / 
av_rescale_q(os->max_pts - os->start_pts,

st->time_base,

AV_TIME_BASE_Q);
-if (bitrate >= 0) {
+if (bitrate >= 0)
 os->bit_rate = bitrate;
-snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
-}
 }
 add_segment(os, os->filename, os->start_pts, os->max_pts - 
os->start_pts, os->pos, range_length, index_length);
 av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written 
to: %s\n", i, os->segment_index, os->full_path);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 06/11] avformat/dashenc: addition of @availabilityTimeOffset in MPD

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

availability time of Nth segment = availabilityStartTime + (N*segment duration) 
- availabilityTimeOffset.
This field helps to reduce the latency by about a segment duration in streaming 
mode.
---
 libavformat/dashenc.c | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 9e7a374..5921ef7 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -85,6 +85,7 @@ typedef struct OutputStream {
 char filename[1024];
 char full_path[1024];
 char temp_path[1024];
+double availability_time_offset;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -344,8 +345,12 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 if (c->use_template) {
 int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : 
AV_TIME_BASE;
 avio_printf(out, "\t\t\t\tuse_timeline)
+if (!c->use_timeline) {
 avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration);
+if (c->streaming && os->availability_time_offset)
+avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
+os->availability_time_offset);
+}
 avio_printf(out, "initialization=\"%s\" media=\"%s\" 
startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? 
start_number : 1);
 if (c->use_timeline) {
 int64_t cur_time = 0;
@@ -1289,6 +1294,13 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 format_date_now(c->availability_start_time,
 sizeof(c->availability_start_time));
 
+if (!os->availability_time_offset && pkt->duration) {
+int64_t frame_duration = av_rescale_q(pkt->duration, st->time_base,
+  AV_TIME_BASE_Q);
+ os->availability_time_offset = ((double) c->seg_duration -
+ frame_duration) / AV_TIME_BASE;
+}
+
 if (c->use_template && !c->use_timeline) {
 elapsed_duration = pkt->pts - os->first_pts;
 seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 10/11] avformat/dashenc: addition of muxer overhead for @bandwidth param in MPD

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 31b0c92..ac05378 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -553,7 +553,7 @@ static int write_adaptation_set(AVFormatContext *s, 
AVIOContext *out, int as_ind
 
 if (os->bit_rate > 0)
 snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
- os->bit_rate);
+ os->bit_rate + os->muxer_overhead);
 
 if (as->media_type == AVMEDIA_TYPE_VIDEO) {
 AVStream *st = s->streams[i];
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 07/11] avformat/dashenc: logic to compute muxer overhead

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5921ef7..0fff91f 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -86,6 +86,8 @@ typedef struct OutputStream {
 char full_path[1024];
 char temp_path[1024];
 double availability_time_offset;
+int total_pkt_size;
+int muxer_overhead;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -1215,6 +1217,13 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 }
 }
 
+if (!os->muxer_overhead)
+os->muxer_overhead = ((int64_t) (range_length - 
os->total_pkt_size) *
+  8 * AV_TIME_BASE) /
+ av_rescale_q(os->max_pts - os->start_pts,
+  st->time_base, AV_TIME_BASE_Q);
+os->total_pkt_size = 0;
+
 if (!os->bit_rate) {
 // calculate average bitrate of first segment
 int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / 
av_rescale_q(os->max_pts - os->start_pts,
@@ -1349,6 +1358,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 else
 os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
 os->packets_written++;
+os->total_pkt_size += pkt->size;
 if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
 return ret;
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 08/11] avformat/dashenc: addition of muxer overhead in master playlist's bandwidth

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 0fff91f..72431b7 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -825,20 +825,23 @@ static int write_manifest(AVFormatContext *s, int final)
 for (i = 0; i < s->nb_streams; i++) {
 char playlist_file[64];
 AVStream *st = s->streams[i];
+OutputStream *os = >streams[i];
 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
 continue;
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_audio_rendition(out, (char *)audio_group,
  playlist_file, i, is_default);
-max_audio_bitrate = FFMAX(st->codecpar->bit_rate, 
max_audio_bitrate);
+max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
+  os->muxer_overhead, max_audio_bitrate);
 is_default = 0;
 }
 
 for (i = 0; i < s->nb_streams; i++) {
 char playlist_file[64];
 AVStream *st = s->streams[i];
+OutputStream *os = >streams[i];
 char *agroup = NULL;
-int stream_bitrate = st->codecpar->bit_rate;
+int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead;
 if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && 
max_audio_bitrate) {
 agroup = (char *)audio_group;
 stream_bitrate += max_audio_bitrate;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 04/11] avformat/dashenc: removed 'write_manifest' call from 'write_header'

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

Calling 'write_manifest' from 'write_header' was causing creation of
first MPD with invalid values. Ex: zero @duration param value. Also,
the manifest files (MPD or M3U8s) should be created when at-least
one media frame is ready for consumption.
---
 libavformat/dashenc.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index e719409..1bac2c9 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1042,9 +1042,6 @@ static int dash_write_header(AVFormatContext *s)
 if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
 return ret;
 }
-ret = write_manifest(s, 0);
-if (!ret)
-av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->url);
 return ret;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 03/11] avformat/dashenc: writing average segment duration for @duration in template mode

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 54ccf30..e719409 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -345,7 +345,7 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : 
AV_TIME_BASE;
 avio_printf(out, "\t\t\t\tuse_timeline)
-avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
+avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration);
 avio_printf(out, "initialization=\"%s\" media=\"%s\" 
startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? 
start_number : 1);
 if (c->use_timeline) {
 int64_t cur_time = 0;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 05/11] avformat/dashenc: setting @availabilityStartTime when the first frame is ready

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

@availabilityStartTime specifies the anchor for the computation of the earliest
availability time (in UTC) for any Segment in the Media Presentation.

As per this requirement, the @AvailabilityStartTime should be set to the
wallclock time at which the first frame of the first segment begins encoding.
But, it was getting set only when the first segment was completely ready. Making
the required correction in this patch. This correction is mainly needed to 
reduce
the latency in live streaming use cases.
---
 libavformat/dashenc.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 1bac2c9..9e7a374 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -741,9 +741,6 @@ static int write_manifest(AVFormatContext *s, int final)
 update_period = 500;
 avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", 
update_period);
 avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", 
c->last_duration / AV_TIME_BASE);
-if (!c->availability_start_time[0] && s->nb_streams > 0 && 
c->streams[0].nb_segments > 0) {
-format_date_now(c->availability_start_time, 
sizeof(c->availability_start_time));
-}
 if (c->availability_start_time[0])
 avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", 
c->availability_start_time);
 format_date_now(now_str, sizeof(now_str));
@@ -1288,6 +1285,10 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (os->first_pts == AV_NOPTS_VALUE)
 os->first_pts = pkt->pts;
 
+if (!c->availability_start_time[0])
+format_date_now(c->availability_start_time,
+sizeof(c->availability_start_time));
+
 if (c->use_template && !c->use_timeline) {
 elapsed_duration = pkt->pts - os->first_pts;
 seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 02/11] avformat/dashenc: segmentation at the configured segment duration rate

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

When use_template is enabled and use_timeline is disabled, typically
it is required to generate the segments at the configured segment duration
rate on an average. This commit is particularly needed to handle the
segmentation when video frame rates are fractional like 29.97 or 59.94 fps.
---
 doc/muxers.texi   |  5 -
 libavformat/dashenc.c | 13 +++--
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index a5358e3..9e8b8a4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -228,7 +228,10 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 @item -min_seg_duration @var{microseconds}
 Set the segment length in microseconds (will be deprecated, use 
@var{seg_duration} instead).
 @item -seg_duration @var{duration}
-Set the segment length in seconds (fractional value can be set).
+Set the segment length in seconds (fractional value can be set). The value is
+treated as average segment duration when @var{use_template} is enabled and
+@var{use_timeline} is disabled and as minimum segment duration for all the 
other
+use cases.
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
 @item -extra_window_size @var{size}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 8ef8627..54ccf30 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1263,6 +1263,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 DASHContext *c = s->priv_data;
 AVStream *st = s->streams[pkt->stream_index];
 OutputStream *os = >streams[pkt->stream_index];
+int64_t seg_end_duration, elapsed_duration;
 int ret;
 
 ret = update_stream_extradata(s, os, st->codecpar);
@@ -1290,10 +1291,18 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (os->first_pts == AV_NOPTS_VALUE)
 os->first_pts = pkt->pts;
 
+if (c->use_template && !c->use_timeline) {
+elapsed_duration = pkt->pts - os->first_pts;
+seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
+} else {
+elapsed_duration = pkt->pts - os->start_pts;
+seg_end_duration = c->seg_duration;
+}
+
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
-av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
+av_compare_ts(elapsed_duration, st->time_base,
+  seg_end_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 01/11] avformat/dashenc: replacing 'min_seg_duration' with 'seg_duration'

2018-04-04 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  4 +++-
 libavformat/dashenc.c | 17 -
 libavformat/version.h |  2 +-
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index cb75c26..a5358e3 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -226,7 +226,9 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 
 @table @option
 @item -min_seg_duration @var{microseconds}
-Set the segment length in microseconds.
+Set the segment length in microseconds (will be deprecated, use 
@var{seg_duration} instead).
+@item -seg_duration @var{duration}
+Set the segment length in seconds (fractional value can be set).
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
 @item -extra_window_size @var{size}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bdf8c8d..8ef8627 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -95,6 +95,7 @@ typedef struct DASHContext {
 int window_size;
 int extra_window_size;
 int min_seg_duration;
+int64_t seg_duration;
 int remove_at_exit;
 int use_template;
 int use_timeline;
@@ -871,6 +872,11 @@ static int dash_init(AVFormatContext *s)
 if (c->single_file)
 c->use_template = 0;
 
+if (c->min_seg_duration != 500) {
+av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated 
and will be removed. Please use the -seg_duration\n");
+c->seg_duration = c->min_seg_duration;
+}
+
 av_strlcpy(c->dirname, s->url, sizeof(c->dirname));
 ptr = strrchr(c->dirname, '/');
 if (ptr) {
@@ -974,7 +980,7 @@ static int dash_init(AVFormatContext *s)
 else
 av_dict_set(, "movflags", "frag_custom+dash+delay_moov", 
0);
 } else {
-av_dict_set_int(, "cluster_time_limit", c->min_seg_duration / 
1000, 0);
+av_dict_set_int(, "cluster_time_limit", c->seg_duration / 
1000, 0);
 av_dict_set_int(, "cluster_size_limit", 5 * 1024 * 1024, 0); 
// set a large cluster size limit
 av_dict_set_int(, "dash", 1, 0);
 av_dict_set_int(, "dash_track_number", i + 1, 0);
@@ -1020,8 +1026,8 @@ static int dash_init(AVFormatContext *s)
 os->segment_index = 1;
 }
 
-if (!c->has_video && c->min_seg_duration <= 0) {
-av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration 
set\n");
+if (!c->has_video && c->seg_duration <= 0) {
+av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n");
 return AVERROR(EINVAL);
 }
 return 0;
@@ -1287,7 +1293,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
 av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
+  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1427,7 +1433,8 @@ static const AVOption options[] = {
 { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 
id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
 { "window_size", "number of segments kept in the manifest", 
OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
 { "extra_window_size", "number of segments kept outside of the manifest 
before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 
= 5 }, 0, INT_MAX, E },
-{ "min_seg_duration", "minimum segment duration (in microseconds)", 
OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, E },
+{ "min_seg_duration", "minimum segment duration (in microseconds) (will be 
deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, 
INT_MAX, E },
+{ "seg_duration", "segment duration (in seconds, fractional value can be 
set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 500 }, 0, 
INT_MAX, E },
 { "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 },
diff --git a/libavformat/version.h b/libavformat/version.h
index e28a9e7..aca592b 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -33,7 +33,7 @@
 // Also please add any ticket numbers that you believe might be affected here
 #define LIBAVFORMAT_VERSION_MAJOR  58
 #define LIBAVFORMAT_VERSION_MINOR  10
-#define 

[FFmpeg-devel] [PATCH 7/8] avformat/hlsenc: check for null context to avoid uninitialized pointer access

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

Under error conditions, when the context is null, the application crashes
without this check.
---
 libavformat/hlsenc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 1dd196f..334720f 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -2318,7 +2318,8 @@ static int hls_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 }
 
 vs->packets_written++;
-ret = ff_write_chained(oc, stream_index, pkt, s, 0);
+if (oc->pb)
+ret = ff_write_chained(oc, stream_index, pkt, s, 0);
 
 return ret;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 8/8] avformat/hlsenc: usage of error handling utility function

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  |  9 +
 libavformat/hlsenc.c | 16 +---
 2 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 0d9ecef..a651a49 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -977,6 +977,15 @@ Use persistent HTTP connections. Applicable only for HTTP 
output.
 @item timeout
 Set timeout for socket I/O operations. Applicable only for HTTP output.
 
+@item -ignore_nw_error @var{ignore_nw_error}
+Enable (1) or disable (0) ignoring the following non-fatal network errors 
during
+muxing. Applicable only for HTTP output.
+@example
+EPIPE- Broken pipe
+ECONNREFUSED - Connection refused
+ECONNRESET   - Connection reset by peer
+@end example
+
 @end table
 
 @anchor{ico}
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 334720f..f6de326 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -225,6 +225,7 @@ typedef struct HLSContext {
 AVIOContext *m3u8_out;
 AVIOContext *sub_m3u8_out;
 int64_t timeout;
+int ignore_nw_err;
 } HLSContext;
 
 static int mkdir_p(const char *path) {
@@ -2247,7 +2248,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 ret = flush_dynbuf(vs, _length);
 if (ret < 0) {
 av_free(old_filename);
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 vs->size = range_length;
 } else {
@@ -2255,12 +2256,12 @@ static int hls_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (ret < 0) {
 av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n",
vs->avf->url);
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 write_styp(vs->out);
 ret = flush_dynbuf(vs, _length);
 if (ret < 0) {
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 ff_format_io_close(s, >out);
 }
@@ -2277,7 +2278,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 vs->duration = 0;
 if (ret < 0) {
 av_free(old_filename);
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 }
 
@@ -2308,12 +2309,12 @@ static int hls_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 av_free(old_filename);
 
 if (ret < 0) {
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 
 if (!vs->fmp4_init_mode || byterange_mode)
 if ((ret = hls_window(s, 0, vs)) < 0) {
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 }
 
@@ -2321,7 +2322,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 if (oc->pb)
 ret = ff_write_chained(oc, stream_index, pkt, s, 0);
 
-return ret;
+return av_handle_error(s, ret, hls->ignore_nw_err);
 }
 
 static int hls_write_trailer(struct AVFormatContext *s)
@@ -2835,6 +2836,7 @@ static const AVOption options[] = {
 {"master_pl_publish_rate", "Publish master play list every after this many 
segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 
0, UINT_MAX, E},
 {"http_persistent", "Use persistent HTTP connections", 
OFFSET(http_persistent), 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 },
+{ "ignore_nw_error", "Ignores any non-fatal network errors during muxing", 
OFFSET(ignore_nw_err), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 6/8] avformat/hlsenc: handling errors in hlsenc_io_open and hlsenc_io_close

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/hlsenc.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 2a54b43..1dd196f 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -272,6 +272,8 @@ static int hlsenc_io_open(AVFormatContext *s, AVIOContext 
**pb, char *filename,
 URLContext *http_url_context = ffio_geturlcontext(*pb);
 av_assert0(http_url_context);
 err = ff_http_do_new_request(http_url_context, filename);
+if (err < 0)
+ff_format_io_close(s, pb);
 #endif
 }
 return err;
@@ -280,6 +282,8 @@ static int hlsenc_io_open(AVFormatContext *s, AVIOContext 
**pb, char *filename,
 static void hlsenc_io_close(AVFormatContext *s, AVIOContext **pb, char 
*filename) {
 HLSContext *hls = s->priv_data;
 int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
+if (!*pb)
+return;
 if (!http_base_proto || !hls->http_persistent || hls->key_info_file || 
hls->encrypt) {
 ff_format_io_close(s, pb);
 #if CONFIG_HTTP_PROTOCOL
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 5/8] avformat/dashenc: usage of error handling utility function

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  8 
 libavformat/dashenc.c | 10 ++
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index cb75c26..0d9ecef 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -266,6 +266,14 @@ To map all video (or audio) streams to an AdaptationSet, 
"v" (or "a") can be use
 When no assignment is defined, this defaults to an AdaptationSet for each 
stream.
 @item -timeout @var{timeout}
 Set timeout for socket I/O operations. Applicable only for HTTP output.
+@item -ignore_nw_error @var{ignore_nw_error}
+Enable (1) or disable (0) ignoring the following non-fatal network errors 
during
+muxing. Applicable only for HTTP output.
+@example
+EPIPE- Broken pipe
+ECONNREFUSED - Connection refused
+ECONNRESET   - Connection reset by peer
+@end example
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 4c8fc6f..05ebd6b 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -118,6 +118,7 @@ typedef struct DASHContext {
 AVIOContext *m3u8_out;
 int streaming;
 int64_t timeout;
+int ignore_nw_err;
 } DASHContext;
 
 static struct codec_string {
@@ -1321,7 +1322,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 }
 
 if ((ret = dash_flush(s, 0, pkt->stream_index)) < 0)
-return ret;
+return av_handle_error(s, ret, c->ignore_nw_err);
 }
 
 if (!os->packets_written) {
@@ -1339,7 +1340,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
 os->packets_written++;
 if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
-return ret;
+return av_handle_error(s, ret, c->ignore_nw_err);
 
 if (!os->init_range_length)
 flush_init_segment(s, os);
@@ -1360,7 +1361,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 set_http_options(, c);
 ret = dashenc_io_open(s, >out, os->temp_path, );
 if (ret < 0)
-return ret;
+return av_handle_error(s, ret, c->ignore_nw_err);
 av_dict_free();
 }
 
@@ -1379,7 +1380,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 os->written_len = len;
 }
 
-return ret;
+return av_handle_error(s, ret, c->ignore_nw_err);
 }
 
 static int dash_write_trailer(AVFormatContext *s)
@@ -1458,6 +1459,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 
},
 { "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 },
+{ "ignore_nw_error", "Ignores any non-fatal network errors during muxing", 
OFFSET(ignore_nw_err), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/8] avformat/dashenc: check for null context to avoid uninitialized pointer access

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bdf8c8d..c0fe0a5 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -254,7 +254,9 @@ static int flush_dynbuf(OutputStream *os, int *range_length)
 // write out to file
 *range_length = avio_close_dyn_buf(os->ctx->pb, );
 os->ctx->pb = NULL;
-avio_write(os->out, buffer + os->written_len, *range_length - 
os->written_len);
+if (os->out)
+avio_write(os->out, buffer + os->written_len,
+   *range_length - os->written_len);
 os->written_len = 0;
 av_free(buffer);
 
@@ -1358,9 +1360,11 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 write_styp(os->ctx->pb);
 avio_flush(os->ctx->pb);
 len = avio_get_dyn_buf (os->ctx->pb, );
-avio_write(os->out, buf + os->written_len, len - os->written_len);
+if (os->out) {
+avio_write(os->out, buf + os->written_len, len - os->written_len);
+avio_flush(os->out);
+}
 os->written_len = len;
-avio_flush(os->out);
 }
 
 return ret;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/8] avformat/avio: check for null context to avoid uninitialized pointer access

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/avio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/avio.c b/libavformat/avio.c
index 63e8287..18e58ae 100644
--- a/libavformat/avio.c
+++ b/libavformat/avio.c
@@ -420,7 +420,7 @@ int ffurl_read_complete(URLContext *h, unsigned char *buf, 
int size)
 
 int ffurl_write(URLContext *h, const unsigned char *buf, int size)
 {
-if (!(h->flags & AVIO_FLAG_WRITE))
+if (!h || !(h->flags & AVIO_FLAG_WRITE))
 return AVERROR(EIO);
 /* avoid sending too big packets */
 if (h->max_packet_size && size > h->max_packet_size)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/8] avformat/dashenc: handling errors for dashenc_io_open and dashenc_io_close

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index c0fe0a5..4c8fc6f 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -143,6 +143,8 @@ static int dashenc_io_open(AVFormatContext *s, AVIOContext 
**pb, char *filename,
 URLContext *http_url_context = ffio_geturlcontext(*pb);
 av_assert0(http_url_context);
 err = ff_http_do_new_request(http_url_context, filename);
+if (err < 0)
+ff_format_io_close(s, pb);
 #endif
 }
 return err;
@@ -152,6 +154,11 @@ static void dashenc_io_close(AVFormatContext *s, 
AVIOContext **pb, char *filenam
 DASHContext *c = s->priv_data;
 int http_base_proto = filename ? ff_is_http_proto(filename) : 0;
 
+if (!*pb) {
+av_log(s, AV_LOG_WARNING, "NULL AVIOContext\n");
+return;
+}
+
 if (!http_base_proto || !c->http_persistent) {
 ff_format_io_close(s, pb);
 #if CONFIG_HTTP_PROTOCOL
@@ -411,7 +418,12 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? 
"%s.tmp" : "%s", filename_hls);
 
 set_http_options(_opts, c);
-dashenc_io_open(s, >m3u8_out, temp_filename_hls, _opts);
+ret = dashenc_io_open(s, >m3u8_out, temp_filename_hls, _opts);
+if (ret < 0) {
+av_log(s, AV_LOG_ERROR, "Unable to open %s for writing %d\n",
+   temp_filename_hls, ret);
+return;
+}
 av_dict_free(_opts);
 for (i = start_index; i < os->nb_segments; i++) {
 Segment *seg = os->segments[i];
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 4/8] avformat/utils: function to check and ignore non fatal network errors

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

For live HLS/DASH output usecases, currently ffmpeg application exits
for any network error during muxing. However, some of the errors like
EPIPE, ECONNREFUSED and ECONNRESET are non-fatal. They might cause
temporary disruption. However, muxer can recover and continue further
processing.
---
 libavformat/internal.h | 11 +++
 libavformat/utils.c| 10 ++
 2 files changed, 21 insertions(+)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index a020b1b..e56f867 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -731,6 +731,17 @@ int ff_unlock_avformat(void);
  */
 void ff_format_set_url(AVFormatContext *s, char *url);
 
+/**
+ * Handle error.
+ * Ignores network errors EPIPE, ECONNREFUSED and ECONNRESET
+ *
+ * @param s AVFormatContext
+ * @param err error code
+ * @param ignore_nw_err flag to ignore network errors
+ * @return 0 if error is ignored, else err
+ */
+int av_handle_error(AVFormatContext *s, int err, int ignore_nw_err);
+
 #if FF_API_NEXT
 /**
   * Register devices in deprecated format linked list.
diff --git a/libavformat/utils.c b/libavformat/utils.c
index f13c820..a942ad0 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -5658,3 +5658,13 @@ FF_DISABLE_DEPRECATION_WARNINGS
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 }
+
+int av_handle_error(AVFormatContext *s, int err, int ignore_nw_err) {
+if (err && ff_is_http_proto(s->url) && ignore_nw_err &&
+(err == AVERROR(EPIPE) || err == AVERROR(ECONNREFUSED) ||
+ err == AVERROR(ECONNRESET))) {
+av_log(s, AV_LOG_WARNING, "Ignored network error %d\n", err);
+return 0;
+}
+return err;
+}
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 0/8] HLS/DASH live streaming stability updates

2018-03-29 Thread vdixit
From: Vishwanath Dixit 

This patch series contains minor bug fixes and error handling functionalities
for uninterrupted long duration HLS/DASH live streaming use cases. During live
streaming, it was observed that ingest network fluctuations are common which
were causing application to exit or crash. Network error handling functionality
added in HLS/DASH muxers provides configurability to ignore any non-fatal
network errors, so that the muxer can continue streaming when ingest network
recovers.

Vishwanath Dixit (8):
  avformat/avio: check for null context to avoid uninitialized pointer
access
  avformat/dashenc: check for null context to avoid uninitialized
pointer access
  avformat/dashenc: handling errors for dashenc_io_open and
dashenc_io_close
  avformat/utils: function to check and ignore non fatal network errors
  avformat/dashenc: usage of error handling utility function
  avformat/hlsenc: handling errors in hlsenc_io_open and hlsenc_io_close
  avformat/hlsenc: check for null context to avoid uninitialized pointer
access
  avformat/hlsenc: usage of error handling utility function

 doc/muxers.texi| 17 +
 libavformat/avio.c |  2 +-
 libavformat/dashenc.c  | 34 ++
 libavformat/hlsenc.c   | 23 +++
 libavformat/internal.h | 11 +++
 libavformat/utils.c| 10 ++
 6 files changed, 80 insertions(+), 17 deletions(-)

--
1.9.1
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/1] avformat/http: flushing tcp receive buffer when it is write only mode

2018-03-27 Thread vdixit
From: Vishwanath Dixit 

In write only mode, the TCP receive buffer keeps growing and eventually
becomes full. This results in zero tcp window size, which in turn causes
unwanted issues, like, terminated tcp connection. The issue is apparent
when http persistent connection is enabled in hls/dash streaming use
cases. To overcome this issue, the logic here reads and discards the data
from the tcp socket.
---
 libavformat/http.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/libavformat/http.c b/libavformat/http.c
index 983034f..e6d414b 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -1627,6 +1627,13 @@ static int http_shutdown(URLContext *h, int flags)
 ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) {
 ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
 ret = ret > 0 ? 0 : ret;
+/* flush the receive buffer when it is write only mode */
+if (!(flags & AVIO_FLAG_READ)) {
+char buf[1024];
+s->hd->flags |= AVIO_FLAG_NONBLOCK;
+ffurl_read(s->hd, buf, sizeof(buf));
+s->hd->flags &= ~AVIO_FLAG_NONBLOCK;
+}
 s->end_chunked_post = 1;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 11/11] avformat/dashenc: addition of segment index correction logic

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

The logic is applicable only when use_template is enabled and use_timeline
is disabled. The logic monitors the flow of segment indexes. If a streams's
segment index value is not at the expected real time position, then
the logic corrects that index value.

Typically this logic is needed in live streaming use cases. The network
bandwidth fluctuations are common during long run streaming. Each
fluctuation can cause the segment indexes fall behind the expected real
time position. Without this logic, players will not be able to consume
the content, even after encoder's network condition comes back to
normal state.
---
 doc/muxers.texi   | 11 +++
 libavformat/dashenc.c | 31 ++-
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 7130cd0..9b31ea0 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -268,6 +268,17 @@ To map all video (or audio) streams to an AdaptationSet, 
"v" (or "a") can be use
 When no assignment is defined, this defaults to an AdaptationSet for each 
stream.
 @item -timeout @var{timeout}
 Set timeout for socket I/O operations. Applicable only for HTTP output.
+@item -index_correction @var{index_correction}
+Enable (1) or Disable (0) segment index correction logic. Applicable only when
+@var{use_template} is enabled and @var{use_timeline} is disabled.
+
+When enabled, the logic monitors the flow of segment indexes. If a streams's
+segment index value is not at the expected real time position, then the logic
+corrects that index value.
+
+Typically this logic is needed in live streaming use cases. The network 
bandwidth
+fluctuations are common during long run streaming. Each fluctuation can cause
+the segment indexes fall behind the expected real time position.
 @end table
 
 @anchor{framecrc}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index f691fb3..47484eb 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -76,7 +76,7 @@ typedef struct OutputStream {
 int nb_segments, segments_size, segment_index;
 Segment **segments;
 int64_t first_pts, start_pts, max_pts;
-int64_t last_dts;
+int64_t last_dts, last_pts;
 int bit_rate;
 
 char codec_str[100];
@@ -120,6 +120,7 @@ typedef struct DASHContext {
 AVIOContext *m3u8_out;
 int streaming;
 int64_t timeout;
+int index_correction;
 } DASHContext;
 
 static struct codec_string {
@@ -1050,7 +1051,7 @@ static int dash_write_header(AVFormatContext *s)
 static int add_segment(OutputStream *os, const char *file,
int64_t time, int duration,
int64_t start_pos, int64_t range_length,
-   int64_t index_length)
+   int64_t index_length, int next_exp_index)
 {
 int err;
 Segment *seg;
@@ -1078,6 +1079,12 @@ static int add_segment(OutputStream *os, const char 
*file,
 seg->index_length = index_length;
 os->segments[os->nb_segments++] = seg;
 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;
 }
 
@@ -1167,10 +1174,22 @@ static int dash_flush(AVFormatContext *s, int final, 
int stream)
 const char *proto = avio_find_protocol_name(s->url);
 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;
 
+//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++) {
 OutputStream *os = >streams[i];
 AVStream *st = s->streams[i];
@@ -1230,7 +1249,7 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 if (bitrate >= 0)
 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, 

[FFmpeg-devel] [PATCH 10/11] avformat/dashenc: addition of bitrate overhead for @bandwidth param in MPD

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index b0ed890..f691fb3 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -552,7 +552,7 @@ static int write_adaptation_set(AVFormatContext *s, 
AVIOContext *out, int as_ind
 
 if (os->bit_rate > 0)
 snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
- os->bit_rate);
+ os->bit_rate + os->bitrate_overhead);
 
 if (as->media_type == AVMEDIA_TYPE_VIDEO) {
 AVStream *st = s->streams[i];
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 08/11] avformat/dashenc: addition of bitrate overhead in master playlist's bandwidth

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 0ba9f55..294999a 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -824,20 +824,23 @@ static int write_manifest(AVFormatContext *s, int final)
 for (i = 0; i < s->nb_streams; i++) {
 char playlist_file[64];
 AVStream *st = s->streams[i];
+OutputStream *os = >streams[i];
 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO)
 continue;
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_audio_rendition(out, (char *)audio_group,
  playlist_file, i, is_default);
-max_audio_bitrate = FFMAX(st->codecpar->bit_rate, 
max_audio_bitrate);
+max_audio_bitrate = FFMAX(st->codecpar->bit_rate +
+  os->bitrate_overhead, max_audio_bitrate);
 is_default = 0;
 }
 
 for (i = 0; i < s->nb_streams; i++) {
 char playlist_file[64];
 AVStream *st = s->streams[i];
+OutputStream *os = >streams[i];
 char *agroup = NULL;
-int stream_bitrate = st->codecpar->bit_rate;
+int stream_bitrate = st->codecpar->bit_rate + os->bitrate_overhead;
 if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && 
max_audio_bitrate) {
 agroup = (char *)audio_group;
 stream_bitrate += max_audio_bitrate;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 07/11] avformat/dashenc: logic to compute bitrate overhead

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index d20bdba..0ba9f55 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -86,6 +86,8 @@ typedef struct OutputStream {
 char full_path[1024];
 char temp_path[1024];
 int64_t chunk_duration;
+int total_pkt_size;
+int bitrate_overhead;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -1209,6 +1211,13 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 }
 }
 
+if (!os->bitrate_overhead)
+os->bitrate_overhead = ((int64_t) (range_length - 
os->total_pkt_size) *
+8 * AV_TIME_BASE) /
+   av_rescale_q(os->max_pts - os->start_pts,
+st->time_base, AV_TIME_BASE_Q);
+os->total_pkt_size = 0;
+
 if (!os->bit_rate) {
 // calculate average bitrate of first segment
 int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / 
av_rescale_q(os->max_pts - os->start_pts,
@@ -1340,6 +1349,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 else
 os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
 os->packets_written++;
+os->total_pkt_size += pkt->size;
 if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
 return ret;
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 09/11] avformat/dashenc: constructing MPD's bandwidth string locally

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 20 +---
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 294999a..b0ed890 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -78,7 +78,6 @@ typedef struct OutputStream {
 int64_t first_pts, start_pts, max_pts;
 int64_t last_dts;
 int bit_rate;
-char bandwidth_str[64];
 
 char codec_str[100];
 int written_len;
@@ -546,20 +545,25 @@ static int write_adaptation_set(AVFormatContext *s, 
AVIOContext *out, int as_ind
 
 for (i = 0; i < s->nb_streams; i++) {
 OutputStream *os = >streams[i];
+char bandwidth_str[64] = {'\0'};
 
 if (os->as_idx - 1 != as_index)
 continue;
 
+if (os->bit_rate > 0)
+snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"",
+ os->bit_rate);
+
 if (as->media_type == AVMEDIA_TYPE_VIDEO) {
 AVStream *st = s->streams[i];
 avio_printf(out, "\t\t\tformat_name, os->codec_str, os->bandwidth_str, 
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
+i, os->format_name, os->codec_str, bandwidth_str, 
s->streams[i]->codecpar->width, s->streams[i]->codecpar->height);
 if (st->avg_frame_rate.num)
 avio_printf(out, " frameRate=\"%d/%d\"", 
st->avg_frame_rate.num, st->avg_frame_rate.den);
 avio_printf(out, ">\n");
 } else {
 avio_printf(out, "\t\t\t\n",
-i, os->format_name, os->codec_str, os->bandwidth_str, 
s->streams[i]->codecpar->sample_rate);
+i, os->format_name, os->codec_str, bandwidth_str, 
s->streams[i]->codecpar->sample_rate);
 avio_printf(out, "\t\t\t\t\n",
 s->streams[i]->codecpar->channels);
 }
@@ -908,10 +912,7 @@ static int dash_init(AVFormatContext *s)
 char filename[1024];
 
 os->bit_rate = s->streams[i]->codecpar->bit_rate;
-if (os->bit_rate) {
-snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
-} else {
+if (!os->bit_rate) {
 int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ?
 AV_LOG_ERROR : AV_LOG_WARNING;
 av_log(s, level, "No bit rate set for stream %d\n", i);
@@ -1226,11 +1227,8 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / 
av_rescale_q(os->max_pts - os->start_pts,

st->time_base,

AV_TIME_BASE_Q);
-if (bitrate >= 0) {
+if (bitrate >= 0)
 os->bit_rate = bitrate;
-snprintf(os->bandwidth_str, sizeof(os->bandwidth_str),
- " bandwidth=\"%d\"", os->bit_rate);
-}
 }
 add_segment(os, os->filename, os->start_pts, os->max_pts - 
os->start_pts, os->pos, range_length, index_length);
 av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written 
to: %s\n", i, os->segment_index, os->full_path);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 06/11] avformat/dashenc: addition of @availabilityTimeOffset in MPD

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

availability time of Nth segment = availabilityStartTime + (N*segment duration) 
- availabilityTimeOffset.
This field helps to reduce the latency by about a segment duration in streaming 
mode.
---
 libavformat/dashenc.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index b62cb3e..d20bdba 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -85,6 +85,7 @@ typedef struct OutputStream {
 char filename[1024];
 char full_path[1024];
 char temp_path[1024];
+int64_t chunk_duration;
 } OutputStream;
 
 typedef struct DASHContext {
@@ -343,8 +344,12 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 if (c->use_template) {
 int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : 
AV_TIME_BASE;
 avio_printf(out, "\t\t\t\tuse_timeline)
+if (!c->use_timeline) {
 avio_printf(out, "duration=\"%d\" ", c->seg_duration);
+if (c->streaming && os->chunk_duration)
+avio_printf(out, "availabilityTimeOffset=\"%.3f\" ",
+((double) c->seg_duration - os->chunk_duration) / 
AV_TIME_BASE);
+}
 avio_printf(out, "initialization=\"%s\" media=\"%s\" 
startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? 
start_number : 1);
 if (c->use_timeline) {
 int64_t cur_time = 0;
@@ -1283,6 +1288,10 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 format_date_now(c->availability_start_time,
 sizeof(c->availability_start_time));
 
+if (!os->chunk_duration && pkt->duration)
+os->chunk_duration = av_rescale_q(pkt->duration, st->time_base,
+  AV_TIME_BASE_Q);
+
 if (c->use_template && !c->use_timeline) {
 elapsed_duration = pkt->pts - os->first_pts;
 seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 05/11] avformat/dashenc: setting @availabilityStartTime when the first frame is ready

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

@availabilityStartTime specifies the anchor for the computation of the earliest
availability time (in UTC) for any Segment in the Media Presentation.
---
 libavformat/dashenc.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 7b854b5..b62cb3e 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -740,9 +740,6 @@ static int write_manifest(AVFormatContext *s, int final)
 update_period = 500;
 avio_printf(out, "\tminimumUpdatePeriod=\"PT%"PRId64"S\"\n", 
update_period);
 avio_printf(out, "\tsuggestedPresentationDelay=\"PT%"PRId64"S\"\n", 
c->last_duration / AV_TIME_BASE);
-if (!c->availability_start_time[0] && s->nb_streams > 0 && 
c->streams[0].nb_segments > 0) {
-format_date_now(c->availability_start_time, 
sizeof(c->availability_start_time));
-}
 if (c->availability_start_time[0])
 avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", 
c->availability_start_time);
 format_date_now(now_str, sizeof(now_str));
@@ -1282,6 +1279,10 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (os->first_pts == AV_NOPTS_VALUE)
 os->first_pts = pkt->pts;
 
+if (!c->availability_start_time[0])
+format_date_now(c->availability_start_time,
+sizeof(c->availability_start_time));
+
 if (c->use_template && !c->use_timeline) {
 elapsed_duration = pkt->pts - os->first_pts;
 seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 04/11] avformat/dashenc: removed 'write_manifest' call from 'write_header'

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

Calling 'write_manifest' from 'write_header' was causing creation of
first MPD with invalid values. Ex: zero @duration param value. Also,
the manifest files (MPD or M3U8s) should be created when at-least
one media frame is ready for consumption.
---
 libavformat/dashenc.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5fb839d..7b854b5 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1036,9 +1036,6 @@ static int dash_write_header(AVFormatContext *s)
 if ((ret = avformat_write_header(os->ctx, NULL)) < 0)
 return ret;
 }
-ret = write_manifest(s, 0);
-if (!ret)
-av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->url);
 return ret;
 }
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 03/11] avformat/dashenc: writing average segment duration for @duration in template mode

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index a489f5e..5fb839d 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -344,7 +344,7 @@ static void output_segment_list(OutputStream *os, 
AVIOContext *out, AVFormatCont
 int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : 
AV_TIME_BASE;
 avio_printf(out, "\t\t\t\tuse_timeline)
-avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration);
+avio_printf(out, "duration=\"%d\" ", c->seg_duration);
 avio_printf(out, "initialization=\"%s\" media=\"%s\" 
startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? 
start_number : 1);
 if (c->use_timeline) {
 int64_t cur_time = 0;
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 02/11] avformat/dashenc: segmentation at the configured segment duration rate

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

When use_template is enabled and use_timeline is disabled, typically
it is required to generate the segments at the configured segment duration
rate on an average. This commit is particularly needed to handle the
segmentation when video frame rates are fractional like 29.97 or 59.94 fps.
---
 doc/muxers.texi   |  4 +++-
 libavformat/dashenc.c | 15 ---
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 65eec92..7130cd0 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -226,7 +226,9 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 
 @table @option
 @item -seg_duration @var{microseconds}
-Set the segment length in microseconds.
+Set the segment length in microseconds. The value is treated as average segment
+duration when use_template is enabled and use_timeline is disabled or as 
minimum
+segment duration for all the other use cases.
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
 @item -extra_window_size @var{size}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bdd5b56..a489f5e 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1257,6 +1257,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 DASHContext *c = s->priv_data;
 AVStream *st = s->streams[pkt->stream_index];
 OutputStream *os = >streams[pkt->stream_index];
+int64_t seg_end_duration, elapsed_duration;
 int ret;
 
 ret = update_stream_extradata(s, os, st->codecpar);
@@ -1284,10 +1285,18 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 if (os->first_pts == AV_NOPTS_VALUE)
 os->first_pts = pkt->pts;
 
+if (c->use_template && !c->use_timeline) {
+elapsed_duration = pkt->pts - os->first_pts;
+seg_end_duration = (int64_t) os->segment_index * c->seg_duration;
+} else {
+elapsed_duration = pkt->pts - os->start_pts;
+seg_end_duration = c->seg_duration;
+}
+
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
-av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
+av_compare_ts(elapsed_duration, st->time_base,
+  seg_end_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1427,7 +1436,7 @@ static const AVOption options[] = {
 { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 
id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
 { "window_size", "number of segments kept in the manifest", 
OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
 { "extra_window_size", "number of segments kept outside of the manifest 
before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 
= 5 }, 0, INT_MAX, E },
-{ "seg_duration", "minimum segment duration (in microseconds)", 
OFFSET(seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, E },
+{ "seg_duration", "value in microseconds, average segment duration when 
use_template is enabled and use_timeline is disabled or minimum segment 
duration in other cases ", OFFSET(seg_duration), AV_OPT_TYPE_INT, { .i64 = 
500 }, 0, INT_MAX, E },
 { "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 },
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 01/11] avformat/dashenc: renamed 'min_seg_duration' to 'seg_duration'

2018-03-22 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  2 +-
 libavformat/dashenc.c | 10 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index cb75c26..65eec92 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -225,7 +225,7 @@ ffmpeg -re -i  -map 0 -map 0 -c:a libfdk_aac -c:v 
libx264
 @end example
 
 @table @option
-@item -min_seg_duration @var{microseconds}
+@item -seg_duration @var{microseconds}
 Set the segment length in microseconds.
 @item -window_size @var{size}
 Set the maximum number of segments kept in the manifest.
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index bdf8c8d..bdd5b56 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -94,7 +94,7 @@ typedef struct DASHContext {
 int nb_as;
 int window_size;
 int extra_window_size;
-int min_seg_duration;
+int seg_duration;
 int remove_at_exit;
 int use_template;
 int use_timeline;
@@ -974,7 +974,7 @@ static int dash_init(AVFormatContext *s)
 else
 av_dict_set(, "movflags", "frag_custom+dash+delay_moov", 
0);
 } else {
-av_dict_set_int(, "cluster_time_limit", c->min_seg_duration / 
1000, 0);
+av_dict_set_int(, "cluster_time_limit", c->seg_duration / 
1000, 0);
 av_dict_set_int(, "cluster_size_limit", 5 * 1024 * 1024, 0); 
// set a large cluster size limit
 av_dict_set_int(, "dash", 1, 0);
 av_dict_set_int(, "dash_track_number", i + 1, 0);
@@ -1020,7 +1020,7 @@ static int dash_init(AVFormatContext *s)
 os->segment_index = 1;
 }
 
-if (!c->has_video && c->min_seg_duration <= 0) {
+if (!c->has_video && c->seg_duration <= 0) {
 av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration 
set\n");
 return AVERROR(EINVAL);
 }
@@ -1287,7 +1287,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) &&
 pkt->flags & AV_PKT_FLAG_KEY && os->packets_written &&
 av_compare_ts(pkt->pts - os->start_pts, st->time_base,
-  c->min_seg_duration, AV_TIME_BASE_Q) >= 0) {
+  c->seg_duration, AV_TIME_BASE_Q) >= 0) {
 int64_t prev_duration = c->last_duration;
 
 c->last_duration = av_rescale_q(pkt->pts - os->start_pts,
@@ -1427,7 +1427,7 @@ static const AVOption options[] = {
 { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 
id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 
}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM },
 { "window_size", "number of segments kept in the manifest", 
OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E },
 { "extra_window_size", "number of segments kept outside of the manifest 
before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 
= 5 }, 0, INT_MAX, E },
-{ "min_seg_duration", "minimum segment duration (in microseconds)", 
OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, E },
+{ "seg_duration", "minimum segment duration (in microseconds)", 
OFFSET(seg_duration), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, E },
 { "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 },
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/1] avformat/hlsenc: fix for zero EXTINF tag duration

2018-03-12 Thread vdixit
From: Vishwanath Dixit 

This is the fix for bug https://trac.ffmpeg.org/ticket/7073
---
 libavformat/hlsenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 08fe0aa..7d9512b 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -2501,7 +2501,7 @@ static int hls_init(AVFormatContext *s)
 /* Get one video stream to reference for split segments
  * so use the first video stream index. */
 if ((vs->has_video == 1) && (vs->streams[j]->codecpar->codec_type 
== AVMEDIA_TYPE_VIDEO)) {
-vs->reference_stream_index = j;
+vs->reference_stream_index = vs->streams[j]->index;
 }
 vs->has_subtitle += vs->streams[j]->codecpar->codec_type == 
AVMEDIA_TYPE_SUBTITLE;
 }
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 1/1] avformat/dashenc: fix for segment open issue when persistent connection is enabled

2018-03-01 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 83e0cff..489e458 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1308,7 +1308,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 flush_init_segment(s, os);
 
 //open the output context when the first frame of a segment is ready
-if (!c->single_file && !os->out) {
+if (!c->single_file && os->packets_written == 1) {
 AVDictionary *opts = NULL;
 const char *proto = avio_find_protocol_name(s->url);
 int use_rename = proto && !strcmp(proto, "file");
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/1] avformat/dashenc: fix for segment open issue when persistent connection is enabled

2018-02-25 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index d6474f3..6fad24e 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -1305,7 +1305,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket 
*pkt)
 flush_init_segment(s, os);
 
 //open the output context when the first frame of a segment is ready
-if (!c->single_file && !os->out) {
+if (!c->single_file && os->packets_written == 1) {
 AVDictionary *opts = NULL;
 const char *proto = avio_find_protocol_name(s->filename);
 int use_rename = proto && !strcmp(proto, "file");
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/3] avformat/dashenc: chunk streaming support for low latency use cases

2018-02-18 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  3 +++
 libavformat/dashenc.c | 26 +++---
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index d9a5cc0..c156ec0 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -254,6 +254,9 @@ Use persistent HTTP connections. Applicable only for HTTP 
output.
 @item -hls_playlist @var{hls_playlist}
 Generate HLS playlist files as well. The master playlist is generated with the 
filename master.m3u8.
 One media playlist file is generated for each stream with filenames 
media_0.m3u8, media_1.m3u8, etc.
+@item -streaming @var{streaming}
+Enable (1) or disable (0) chunk streaming mode of output. In chunk streaming
+mode, each frame will be a moof fragment which forms a chunk.
 @item -adaptation_sets @var{adaptation_sets}
 Assign streams to AdaptationSets. Syntax is "id=x,streams=a,b,c 
id=y,streams=d,e" with x and y being the IDs
 of the adaptation sets and a,b,c,d and e are the indices of the mapped streams.
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 0eb4b25..d6474f3 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -81,6 +81,7 @@ typedef struct OutputStream {
 char bandwidth_str[64];
 
 char codec_str[100];
+int written_len;
 char filename[1024];
 char full_path[1024];
 char temp_path[1024];
@@ -114,6 +115,7 @@ typedef struct DASHContext {
 int master_playlist_created;
 AVIOContext *mpd_out;
 AVIOContext *m3u8_out;
+int streaming;
 } DASHContext;
 
 static struct codec_string {
@@ -250,7 +252,8 @@ static int flush_dynbuf(OutputStream *os, int *range_length)
 // write out to file
 *range_length = avio_close_dyn_buf(os->ctx->pb, );
 os->ctx->pb = NULL;
-avio_write(os->out, buffer, *range_length);
+avio_write(os->out, buffer + os->written_len, *range_length - 
os->written_len);
+os->written_len = 0;
 av_free(buffer);
 
 // re-open buffer
@@ -960,7 +963,10 @@ static int dash_init(AVFormatContext *s)
 os->init_start_pos = 0;
 
 if (!strcmp(os->format_name, "mp4")) {
-av_dict_set(, "movflags", "frag_custom+dash+delay_moov", 0);
+if (c->streaming)
+av_dict_set(, "movflags", 
"frag_every_frame+dash+delay_moov", 0);
+else
+av_dict_set(, "movflags", "frag_custom+dash+delay_moov", 
0);
 } else {
 av_dict_set_int(, "cluster_time_limit", c->min_seg_duration / 
1000, 0);
 av_dict_set_int(, "cluster_size_limit", 5 * 1024 * 1024, 0); 
// set a large cluster size limit
@@ -1155,7 +1161,7 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 }
 
 if (!c->single_file) {
-if (!strcmp(os->format_name, "mp4"))
+if (!strcmp(os->format_name, "mp4") && !os->written_len)
 write_styp(os->ctx->pb);
 } else {
 snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, 
os->initfile);
@@ -1318,6 +1324,19 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 av_dict_free();
 }
 
+//write out the data immediately in streaming mode
+if (c->streaming && !strcmp(os->format_name, "mp4")) {
+int len = 0;
+uint8_t *buf = NULL;
+if (!os->written_len)
+write_styp(os->ctx->pb);
+avio_flush(os->ctx->pb);
+len = avio_get_dyn_buf (os->ctx->pb, );
+avio_write(os->out, buf + os->written_len, len - os->written_len);
+os->written_len = len;
+avio_flush(os->out);
+}
+
 return ret;
 }
 
@@ -1394,6 +1413,7 @@ static const AVOption options[] = {
 { "http_user_agent", "override User-Agent field in HTTP header", 
OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E},
 { "http_persistent", "Use persistent HTTP connections", 
OFFSET(http_persistent), 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 },
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/3] avformat/dashenc: opening a segment file when its first frame is ready

2018-02-18 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/dashenc.c | 57 ---
 1 file changed, 36 insertions(+), 21 deletions(-)

diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 0f6f4f2..0eb4b25 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -81,6 +81,9 @@ typedef struct OutputStream {
 char bandwidth_str[64];
 
 char codec_str[100];
+char filename[1024];
+char full_path[1024];
+char temp_path[1024];
 } OutputStream;
 
 typedef struct DASHContext {
@@ -1134,7 +1137,6 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
 for (i = 0; i < s->nb_streams; i++) {
 OutputStream *os = >streams[i];
 AVStream *st = s->streams[i];
-char filename[1024] = "", full_path[1024], temp_path[1024];
 int range_length, index_length = 0;
 
 if (!os->packets_written)
@@ -1152,24 +1154,11 @@ static int dash_flush(AVFormatContext *s, int final, 
int stream)
 continue;
 }
 
-if (!os->init_range_length) {
-flush_init_segment(s, os);
-}
-
 if (!c->single_file) {
-AVDictionary *opts = NULL;
-ff_dash_fill_tmpl_params(filename, sizeof(filename), 
c->media_seg_name, i, os->segment_index, os->bit_rate, os->start_pts);
-snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, 
filename);
-snprintf(temp_path, sizeof(temp_path), use_rename ? "%s.tmp" : 
"%s", full_path);
-set_http_options(, c);
-ret = dashenc_io_open(s, >out, temp_path, );
-if (ret < 0)
-break;
-av_dict_free();
 if (!strcmp(os->format_name, "mp4"))
 write_styp(os->ctx->pb);
 } else {
-snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, 
os->initfile);
+snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, 
os->initfile);
 }
 
 ret = flush_dynbuf(os, _length);
@@ -1178,12 +1167,12 @@ static int dash_flush(AVFormatContext *s, int final, 
int stream)
 os->packets_written = 0;
 
 if (c->single_file) {
-find_index_range(s, full_path, os->pos, _length);
+find_index_range(s, os->full_path, os->pos, _length);
 } else {
-dashenc_io_close(s, >out, temp_path);
+dashenc_io_close(s, >out, os->temp_path);
 
 if (use_rename) {
-ret = avpriv_io_move(temp_path, full_path);
+ret = avpriv_io_move(os->temp_path, os->full_path);
 if (ret < 0)
 break;
 }
@@ -1200,8 +1189,8 @@ static int dash_flush(AVFormatContext *s, int final, int 
stream)
  " bandwidth=\"%d\"", os->bit_rate);
 }
 }
-add_segment(os, filename, os->start_pts, os->max_pts - os->start_pts, 
os->pos, range_length, index_length);
-av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written 
to: %s\n", i, os->segment_index, full_path);
+add_segment(os, os->filename, os->start_pts, os->max_pts - 
os->start_pts, os->pos, range_length, index_length);
+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;
 }
@@ -1303,7 +1292,33 @@ static int dash_write_packet(AVFormatContext *s, 
AVPacket *pkt)
 else
 os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration);
 os->packets_written++;
-return ff_write_chained(os->ctx, 0, pkt, s, 0);
+if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0)
+return ret;
+
+if (!os->init_range_length)
+flush_init_segment(s, os);
+
+//open the output context when the first frame of a segment is ready
+if (!c->single_file && !os->out) {
+AVDictionary *opts = NULL;
+const char *proto = avio_find_protocol_name(s->filename);
+int use_rename = proto && !strcmp(proto, "file");
+os->filename[0] = os->full_path[0] = os->temp_path[0] = '\0';
+ff_dash_fill_tmpl_params(os->filename, sizeof(os->filename),
+ c->media_seg_name, pkt->stream_index,
+ os->segment_index, os->bit_rate, 
os->start_pts);
+snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname,
+ os->filename);
+snprintf(os->temp_path, sizeof(os->temp_path),
+ use_rename ? "%s.tmp" : "%s", os->full_path);
+set_http_options(, c);
+ret = dashenc_io_open(s, >out, os->temp_path, );
+if (ret < 0)
+return ret;
+av_dict_free();
+}
+
+return ret;
 }
 
 static int dash_write_trailer(AVFormatContext *s)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org

[FFmpeg-devel] [PATCH 1/3] avformat/movenc: addition of flag to fragment at every frame

2018-02-18 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/movenc.c | 10 +++---
 libavformat/movenc.h |  1 +
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/libavformat/movenc.c b/libavformat/movenc.c
index f433499..5b1e66c 100644
--- a/libavformat/movenc.c
+++ b/libavformat/movenc.c
@@ -62,6 +62,7 @@ static const AVOption options[] = {
 { "moov_size", "maximum moov size so it can be placed at the begin", 
offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 
INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 },
 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, 
{.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 
"movflags" },
 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, 
{.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, 
AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
+{ "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, 
{.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, 
AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, 
AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, 
AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
 { "frag_custom", "Flush fragments on caller requests", 0, 
AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, 
AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
 { "isml", "Create a live smooth streaming feed (for pushing to a 
publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, 
INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" },
@@ -5432,7 +5433,8 @@ static int mov_write_single_packet(AVFormatContext *s, 
AVPacket *pkt)
  (mov->max_fragment_size && mov->mdat_size + size >= 
mov->max_fragment_size) ||
  (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
   par->codec_type == AVMEDIA_TYPE_VIDEO &&
-  trk->entry && pkt->flags & AV_PKT_FLAG_KEY)) {
+  trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
+  (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
 if (frag_duration >= mov->min_fragment_duration) {
 // Set the duration of this track to line up with the next
 // sample in this track. This avoids relying on AVPacket
@@ -5874,7 +5876,8 @@ static int mov_init(AVFormatContext *s)
 if (mov->max_fragment_duration || mov->max_fragment_size ||
 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
   FF_MOV_FLAG_FRAG_KEYFRAME |
-  FF_MOV_FLAG_FRAG_CUSTOM))
+  FF_MOV_FLAG_FRAG_CUSTOM |
+  FF_MOV_FLAG_FRAG_EVERY_FRAME))
 mov->flags |= FF_MOV_FLAG_FRAGMENT;
 
 /* Set other implicit flags immediately */
@@ -6238,7 +6241,8 @@ static int mov_write_header(AVFormatContext *s)
 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
 /* If no fragmentation options have been set, set a default. */
 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
-FF_MOV_FLAG_FRAG_CUSTOM)) &&
+FF_MOV_FLAG_FRAG_CUSTOM |
+FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
 !mov->max_fragment_duration && !mov->max_fragment_size)
 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
 } else {
diff --git a/libavformat/movenc.h b/libavformat/movenc.h
index c4e966b..ca2a9c9 100644
--- a/libavformat/movenc.h
+++ b/libavformat/movenc.h
@@ -245,6 +245,7 @@ typedef struct MOVMuxContext {
 #define FF_MOV_FLAG_USE_MDTA  (1 << 17)
 #define FF_MOV_FLAG_SKIP_TRAILER  (1 << 18)
 #define FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS  (1 << 19)
+#define FF_MOV_FLAG_FRAG_EVERY_FRAME  (1 << 20)
 
 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt);
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 1/1] avformat/hlsenc: closed caption tags in the master playlist

2018-01-22 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  37 +++
 libavformat/dashenc.c |   2 +-
 libavformat/hlsenc.c  | 155 +-
 libavformat/hlsplaylist.c |   5 +-
 libavformat/hlsplaylist.h |   2 +-
 5 files changed, 196 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index b060c4f..d9a5cc0 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -901,6 +901,43 @@ and they are mapped to the two video only variant streams 
with audio group names
 
 By default, a single hls variant containing all the encoded streams is created.
 
+@item cc_stream_map
+Map string which specifies different closed captions groups and their
+attributes. The closed captions stream groups are separated by space.
+Expected string format is like this
+"ccgroup:,instreamid:,language: ".
+'ccgroup' and 'instreamid' are mandatory attributes. 'language' is an optional
+attribute.
+The closed captions groups configured using this option are mapped to different
+variant streams by providing the same 'ccgroup' name in the
+@code{var_stream_map} string. If @code{var_stream_map} is not set, then the
+first available ccgroup in @code{cc_stream_map} is mapped to the output variant
+stream. The examples for these two use cases are given below.
+
+@example
+ffmpeg -re -i in.ts -b:v 1000k -b:a 64k -a53cc 1 -f hls \
+  -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out.m3u8
+@end example
+This example adds @code{#EXT-X-MEDIA} tag with @code{TYPE=CLOSED-CAPTIONS} in
+the master playlist with group name 'cc', langauge 'en' (english) and
+INSTREAM-ID 'CC1'. Also, it adds @code{CLOSED-CAPTIONS} attribute with group
+name 'cc' for the output variant stream.
+@example
+ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -a53cc:0 1 -a53cc:1 1\
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls \
+  -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en 
ccgroup:cc,instreamid:CC2,language:sp" \
+  -var_stream_map "v:0,a:0,ccgroup:cc v:1,a:1,ccgroup:cc" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out_%v.m3u8
+@end example
+This example adds two @code{#EXT-X-MEDIA} tags with 
@code{TYPE=CLOSED-CAPTIONS} in
+the master playlist for the INSTREAM-IDs 'CC1' and 'CC2'. Also, it adds
+@code{CLOSED-CAPTIONS} attribute with group name 'cc' for the two output 
variant
+streams.
+
 @item master_pl_name
 Create HLS master playlist with the given name.
 
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 39d0afe..5ece100 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -820,7 +820,7 @@ static int write_manifest(AVFormatContext *s, int final)
 stream_bitrate += max_audio_bitrate;
 }
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
-ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, 
agroup, NULL);
+ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, 
agroup, NULL, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 42e437f..aab21f2 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -152,9 +152,16 @@ typedef struct VariantStream {
 unsigned int nb_streams;
 int m3u8_created; /* status of media play-list creation */
 char *agroup; /* audio group name */
+char *ccgroup; /* closed caption group name */
 char *baseurl;
 } VariantStream;
 
+typedef struct ClosedCaptionsStream {
+char *ccgroup; /* closed caption group name */
+char *instreamid; /* closed captions INSTREAM-ID */
+char *language; /* closed captions langauge */
+} ClosedCaptionsStream;
+
 typedef struct HLSContext {
 const AVClass *class;  // Class for private options.
 int64_t start_sequence;
@@ -203,11 +210,14 @@ typedef struct HLSContext {
 
 VariantStream *var_streams;
 unsigned int nb_varstreams;
+ClosedCaptionsStream *cc_streams;
+unsigned int nb_ccstreams;
 
 int master_m3u8_created; /* status of master play-list creation */
 char *master_m3u8_url; /* URL of the master m3u8 file */
 int version; /* HLS version */
 char *var_stream_map; /* user specified variant stream map string */
+char *cc_stream_map; /* user specified closed caption streams map string */
 char *master_pl_name;
 unsigned int master_publish_rate;
 int http_persistent;
@@ -1167,7 +1177,8 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3u8_rel_name;
+char *m3u8_rel_name, *ccgroup;
+ClosedCaptionsStream *ccs;
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1194,6 +1205,16 @@ static int create_master_playlist(AVFormatContext *s,
 
 

[FFmpeg-devel] [PATCH v3 3/3] avdevice/decklink: addition of absolute wallclock option for pts source

2018-01-15 Thread vdixit
From: Vishwanath Dixit 

---
 doc/indevs.texi |  6 --
 libavdevice/decklink_common_c.h |  1 +
 libavdevice/decklink_dec.cpp| 16 
 libavdevice/decklink_dec_c.c|  1 +
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 36aef49..0bc8e6a 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -298,11 +298,13 @@ Sets the audio input source. Must be @samp{unset}, 
@samp{embedded},
 
 @item video_pts
 Sets the video packet timestamp source. Must be @samp{video}, @samp{audio},
-@samp{reference} or @samp{wallclock}. Defaults to @samp{video}.
+@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}.
+Defaults to @samp{video}.
 
 @item audio_pts
 Sets the audio packet timestamp source. Must be @samp{video}, @samp{audio},
-@samp{reference} or @samp{wallclock}. Defaults to @samp{audio}.
+@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}.
+Defaults to @samp{audio}.
 
 @item draw_bars
 If set to @samp{true}, color bars are drawn in the event of a signal loss.
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index 18097e2..08e9f9b 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -28,6 +28,7 @@ typedef enum DecklinkPtsSource {
 PTS_SRC_VIDEO = 2,
 PTS_SRC_REFERENCE = 3,
 PTS_SRC_WALLCLOCK = 4,
+PTS_SRC_ABS_WALLCLOCK = 5,
 PTS_SRC_NB
 } DecklinkPtsSource;
 
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 1fd40ca..a69e286 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -585,6 +585,7 @@ ULONG decklink_input_callback::Release(void)
 static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame,
IDeckLinkAudioInputPacket *audioFrame,
int64_t wallclock,
+   int64_t abs_wallclock,
DecklinkPtsSource pts_src,
AVRational time_base, int64_t *initial_pts,
int copyts)
@@ -607,13 +608,18 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
 res = videoFrame->GetHardwareReferenceTimestamp(time_base.den, 
_pts, _duration);
 break;
 case PTS_SRC_WALLCLOCK:
+/* fall through */
+case PTS_SRC_ABS_WALLCLOCK:
 {
 /* MSVC does not support compound literals like AV_TIME_BASE_Q
  * in C++ code (compiler error C4576) */
 AVRational timebase;
 timebase.num = 1;
 timebase.den = AV_TIME_BASE;
-pts = av_rescale_q(wallclock, timebase, time_base);
+if (pts_src == PTS_SRC_WALLCLOCK)
+pts = av_rescale_q(wallclock, timebase, time_base);
+else
+pts = av_rescale_q(abs_wallclock, timebase, time_base);
 break;
 }
 }
@@ -637,7 +643,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 void *audioFrameBytes;
 BMDTimeValue frameTime;
 BMDTimeValue frameDuration;
-int64_t wallclock = 0;
+int64_t wallclock = 0, abs_wallclock = 0;
 struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
 
 if (ctx->autodetect) {
@@ -652,6 +658,8 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 ctx->frameCount++;
 if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == 
PTS_SRC_WALLCLOCK)
 wallclock = av_gettime_relative();
+if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || 
ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK)
+abs_wallclock = av_gettime();
 
 // Handle Video Frame
 if (videoFrame) {
@@ -698,7 +706,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 no_video = 0;
 }
 
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts, 
cctx->copyts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, 
_video_pts, cctx->copyts);
 pkt.dts = pkt.pts;
 
 pkt.duration = frameDuration;
@@ -789,7 +797,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 pkt.size = audioFrame->GetSampleFrameCount() * 
ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8);
 audioFrame->GetBytes();
 audioFrame->GetPacketTime(_pts, ctx->audio_st->time_base.den);
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts, 
cctx->copyts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, 
_audio_pts, cctx->copyts);
 pkt.dts = pkt.pts;
 
 //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
diff --git 

[FFmpeg-devel] [PATCH v3 2/3] avdevice/decklink: addition of PTS_SRC_NB in enum DecklinkPtsSource

2018-01-15 Thread vdixit
From: Vishwanath Dixit 

---
 libavdevice/decklink_common_c.h | 1 +
 libavdevice/decklink_dec_c.c| 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index ac6563a..18097e2 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -28,6 +28,7 @@ typedef enum DecklinkPtsSource {
 PTS_SRC_VIDEO = 2,
 PTS_SRC_REFERENCE = 3,
 PTS_SRC_WALLCLOCK = 4,
+PTS_SRC_NB
 } DecklinkPtsSource;
 
 struct decklink_cctx {
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index f65b177..accae53 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -64,8 +64,8 @@ static const AVOption options[] = {
 { "analog_xlr",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,DEC, "audio_input"},
 { "analog_rca",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,DEC, "audio_input"},
 { "microphone",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,DEC, "audio_input"},
-{ "audio_pts", "audio pts source",   OFFSET(audio_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_AUDIO}, 1, 4, DEC, "pts_source"},
-{ "video_pts", "video pts source",   OFFSET(video_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_VIDEO}, 1, 4, DEC, "pts_source"},
+{ "audio_pts", "audio pts source",   OFFSET(audio_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_AUDIO}, 1, PTS_SRC_NB-1, DEC, 
"pts_source"},
+{ "video_pts", "video pts source",   OFFSET(video_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_VIDEO}, 1, PTS_SRC_NB-1, DEC, 
"pts_source"},
 { "audio", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_AUDIO}, 0, 0, DEC, "pts_source"},
 { "video", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_VIDEO}, 0, 0, DEC, "pts_source"},
 { "reference", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, "pts_source"},
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 1/3] avdevice/decklink: addition of copyts option

2018-01-15 Thread vdixit
From: Vishwanath Dixit 

---
 doc/indevs.texi |  5 +
 libavdevice/decklink_common_c.h |  1 +
 libavdevice/decklink_dec.cpp| 18 +++---
 libavdevice/decklink_dec_c.c|  1 +
 4 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 56066bf..36aef49 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -317,6 +317,11 @@ Defaults to @samp{1073741824}.
 Sets the audio sample bit depth. Must be @samp{16} or @samp{32}.
 Defaults to @samp{16}.
 
+@item decklink_copyts
+If set to @option{true}, timestamps are forwarded as they are without removing
+the initial offset.
+Defaults to @option{false}.
+
 @end table
 
 @subsection Examples
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index 368ac25..ac6563a 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -52,6 +52,7 @@ struct decklink_cctx {
 char *format_code;
 int raw_format;
 int64_t queue_size;
+int copyts;
 };
 
 #endif /* AVDEVICE_DECKLINK_COMMON_C_H */
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 94dae26..1fd40ca 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -586,7 +586,8 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
IDeckLinkAudioInputPacket *audioFrame,
int64_t wallclock,
DecklinkPtsSource pts_src,
-   AVRational time_base, int64_t *initial_pts)
+   AVRational time_base, int64_t *initial_pts,
+   int copyts)
 {
 int64_t pts = AV_NOPTS_VALUE;
 BMDTimeValue bmd_pts;
@@ -619,10 +620,12 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
 if (res == S_OK)
 pts = bmd_pts / time_base.num;
 
-if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
-*initial_pts = pts;
-if (*initial_pts != AV_NOPTS_VALUE)
-pts -= *initial_pts;
+if (!copyts) {
+if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
+*initial_pts = pts;
+if (*initial_pts != AV_NOPTS_VALUE)
+pts -= *initial_pts;
+}
 
 return pts;
 }
@@ -635,6 +638,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 BMDTimeValue frameTime;
 BMDTimeValue frameDuration;
 int64_t wallclock = 0;
+struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
 
 if (ctx->autodetect) {
 if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) 
&&
@@ -694,7 +698,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 no_video = 0;
 }
 
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts, 
cctx->copyts);
 pkt.dts = pkt.pts;
 
 pkt.duration = frameDuration;
@@ -785,7 +789,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 pkt.size = audioFrame->GetSampleFrameCount() * 
ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8);
 audioFrame->GetBytes();
 audioFrame->GetPacketTime(_pts, ctx->audio_st->time_base.den);
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts, 
cctx->copyts);
 pkt.dts = pkt.pts;
 
 //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 1c6d826..f65b177 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -73,6 +73,7 @@ static const AVOption options[] = {
 { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars),
AV_OPT_TYPE_BOOL,  { .i64 = 1}, 0, 1, DEC },
 { "queue_size","input queue buffer size",   OFFSET(queue_size),   
AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC },
 { "audio_depth",   "audio bitdepth (16 or 32)", OFFSET(audio_depth),  
AV_OPT_TYPE_INT,   { .i64 = 16}, 16, 32, DEC },
+{ "decklink_copyts", "copy timestamps, do not remove the initial offset", 
OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC },
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 3/3] avdevice/decklink: addition of absolute wallclock option for pts source

2018-01-09 Thread vdixit
From: Vishwanath Dixit 

---
 doc/indevs.texi | 6 --
 libavdevice/decklink_common_c.h | 1 +
 libavdevice/decklink_dec.cpp| 4 
 libavdevice/decklink_dec_c.c| 1 +
 4 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 36aef49..0bc8e6a 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -298,11 +298,13 @@ Sets the audio input source. Must be @samp{unset}, 
@samp{embedded},
 
 @item video_pts
 Sets the video packet timestamp source. Must be @samp{video}, @samp{audio},
-@samp{reference} or @samp{wallclock}. Defaults to @samp{video}.
+@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}.
+Defaults to @samp{video}.
 
 @item audio_pts
 Sets the audio packet timestamp source. Must be @samp{video}, @samp{audio},
-@samp{reference} or @samp{wallclock}. Defaults to @samp{audio}.
+@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}.
+Defaults to @samp{audio}.
 
 @item draw_bars
 If set to @samp{true}, color bars are drawn in the event of a signal loss.
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index 18097e2..08e9f9b 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -28,6 +28,7 @@ typedef enum DecklinkPtsSource {
 PTS_SRC_VIDEO = 2,
 PTS_SRC_REFERENCE = 3,
 PTS_SRC_WALLCLOCK = 4,
+PTS_SRC_ABS_WALLCLOCK = 5,
 PTS_SRC_NB
 } DecklinkPtsSource;
 
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 1fd40ca..c6eea43 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -607,6 +607,8 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
 res = videoFrame->GetHardwareReferenceTimestamp(time_base.den, 
_pts, _duration);
 break;
 case PTS_SRC_WALLCLOCK:
+/* fall through */
+case PTS_SRC_ABS_WALLCLOCK:
 {
 /* MSVC does not support compound literals like AV_TIME_BASE_Q
  * in C++ code (compiler error C4576) */
@@ -652,6 +654,8 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 ctx->frameCount++;
 if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == 
PTS_SRC_WALLCLOCK)
 wallclock = av_gettime_relative();
+else if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || 
ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK)
+wallclock = av_gettime();
 
 // Handle Video Frame
 if (videoFrame) {
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index d52dde5..00fb3af 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -70,6 +70,7 @@ static const AVOption options[] = {
 { "video", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_VIDEO}, 0, 0, DEC, "pts_source"},
 { "reference", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, "pts_source"},
 { "wallclock", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, "pts_source"},
+{ "abs_wallclock", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, "pts_source"},
 { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars),
AV_OPT_TYPE_BOOL,  { .i64 = 1}, 0, 1, DEC },
 { "queue_size","input queue buffer size",   OFFSET(queue_size),   
AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC },
 { "audio_depth",   "audio bitdepth (16 or 32)", OFFSET(audio_depth),  
AV_OPT_TYPE_INT,   { .i64 = 16}, 16, 32, DEC },
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 2/3] avdevice/decklink: addition of PTS_SRC_NB in enum DecklinkPtsSource

2018-01-09 Thread vdixit
From: Vishwanath Dixit 

---
 libavdevice/decklink_common_c.h | 1 +
 libavdevice/decklink_dec_c.c| 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index ac6563a..18097e2 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -28,6 +28,7 @@ typedef enum DecklinkPtsSource {
 PTS_SRC_VIDEO = 2,
 PTS_SRC_REFERENCE = 3,
 PTS_SRC_WALLCLOCK = 4,
+PTS_SRC_NB
 } DecklinkPtsSource;
 
 struct decklink_cctx {
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 6fb5ffe..d52dde5 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -64,8 +64,8 @@ static const AVOption options[] = {
 { "analog_xlr",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,DEC, "audio_input"},
 { "analog_rca",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,DEC, "audio_input"},
 { "microphone",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,DEC, "audio_input"},
-{ "audio_pts", "audio pts source",   OFFSET(audio_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_AUDIO}, 1, 4, DEC, "pts_source"},
-{ "video_pts", "video pts source",   OFFSET(video_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_VIDEO}, 1, 4, DEC, "pts_source"},
+{ "audio_pts", "audio pts source",   OFFSET(audio_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_AUDIO}, 1, PTS_SRC_NB-1, DEC, 
"pts_source"},
+{ "video_pts", "video pts source",   OFFSET(video_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_VIDEO}, 1, PTS_SRC_NB-1, DEC, 
"pts_source"},
 { "audio", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_AUDIO}, 0, 0, DEC, "pts_source"},
 { "video", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_VIDEO}, 0, 0, DEC, "pts_source"},
 { "reference", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, "pts_source"},
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 1/3] avdevice/decklink: addition of copyts option

2018-01-09 Thread vdixit
From: Vishwanath Dixit 

---
 doc/indevs.texi |  5 +
 libavdevice/decklink_common_c.h |  1 +
 libavdevice/decklink_dec.cpp| 18 +++---
 libavdevice/decklink_dec_c.c|  1 +
 4 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 56066bf..36aef49 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -317,6 +317,11 @@ Defaults to @samp{1073741824}.
 Sets the audio sample bit depth. Must be @samp{16} or @samp{32}.
 Defaults to @samp{16}.
 
+@item decklink_copyts
+If set to @option{true}, timestamps are forwarded as they are without removing
+the initial offset.
+Defaults to @option{false}.
+
 @end table
 
 @subsection Examples
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index 368ac25..ac6563a 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -52,6 +52,7 @@ struct decklink_cctx {
 char *format_code;
 int raw_format;
 int64_t queue_size;
+int copyts;
 };
 
 #endif /* AVDEVICE_DECKLINK_COMMON_C_H */
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 94dae26..1fd40ca 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -586,7 +586,8 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
IDeckLinkAudioInputPacket *audioFrame,
int64_t wallclock,
DecklinkPtsSource pts_src,
-   AVRational time_base, int64_t *initial_pts)
+   AVRational time_base, int64_t *initial_pts,
+   int copyts)
 {
 int64_t pts = AV_NOPTS_VALUE;
 BMDTimeValue bmd_pts;
@@ -619,10 +620,12 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
 if (res == S_OK)
 pts = bmd_pts / time_base.num;
 
-if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
-*initial_pts = pts;
-if (*initial_pts != AV_NOPTS_VALUE)
-pts -= *initial_pts;
+if (!copyts) {
+if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
+*initial_pts = pts;
+if (*initial_pts != AV_NOPTS_VALUE)
+pts -= *initial_pts;
+}
 
 return pts;
 }
@@ -635,6 +638,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 BMDTimeValue frameTime;
 BMDTimeValue frameDuration;
 int64_t wallclock = 0;
+struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
 
 if (ctx->autodetect) {
 if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) 
&&
@@ -694,7 +698,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 no_video = 0;
 }
 
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts, 
cctx->copyts);
 pkt.dts = pkt.pts;
 
 pkt.duration = frameDuration;
@@ -785,7 +789,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 pkt.size = audioFrame->GetSampleFrameCount() * 
ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8);
 audioFrame->GetBytes();
 audioFrame->GetPacketTime(_pts, ctx->audio_st->time_base.den);
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts, 
cctx->copyts);
 pkt.dts = pkt.pts;
 
 //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 1c6d826..6fb5ffe 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -73,6 +73,7 @@ static const AVOption options[] = {
 { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars),
AV_OPT_TYPE_BOOL,  { .i64 = 1}, 0, 1, DEC },
 { "queue_size","input queue buffer size",   OFFSET(queue_size),   
AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC },
 { "audio_depth",   "audio bitdepth (16 or 32)", OFFSET(audio_depth),  
AV_OPT_TYPE_INT,   { .i64 = 16}, 16, 32, DEC },
+{ "decklink_copyts", "copy timestamps, do not remove the initial offset", 
OFFSET(copyts), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC },
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 1/1] avformat/hlsenc: closed caption tags in the master playlist

2018-01-09 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  37 +++
 libavformat/dashenc.c |   2 +-
 libavformat/hlsenc.c  | 155 +-
 libavformat/hlsplaylist.c |   5 +-
 libavformat/hlsplaylist.h |   3 +-
 5 files changed, 197 insertions(+), 5 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index b060c4f..d9a5cc0 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -901,6 +901,43 @@ and they are mapped to the two video only variant streams 
with audio group names
 
 By default, a single hls variant containing all the encoded streams is created.
 
+@item cc_stream_map
+Map string which specifies different closed captions groups and their
+attributes. The closed captions stream groups are separated by space.
+Expected string format is like this
+"ccgroup:,instreamid:,language: ".
+'ccgroup' and 'instreamid' are mandatory attributes. 'language' is an optional
+attribute.
+The closed captions groups configured using this option are mapped to different
+variant streams by providing the same 'ccgroup' name in the
+@code{var_stream_map} string. If @code{var_stream_map} is not set, then the
+first available ccgroup in @code{cc_stream_map} is mapped to the output variant
+stream. The examples for these two use cases are given below.
+
+@example
+ffmpeg -re -i in.ts -b:v 1000k -b:a 64k -a53cc 1 -f hls \
+  -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out.m3u8
+@end example
+This example adds @code{#EXT-X-MEDIA} tag with @code{TYPE=CLOSED-CAPTIONS} in
+the master playlist with group name 'cc', langauge 'en' (english) and
+INSTREAM-ID 'CC1'. Also, it adds @code{CLOSED-CAPTIONS} attribute with group
+name 'cc' for the output variant stream.
+@example
+ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -a53cc:0 1 -a53cc:1 1\
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls \
+  -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en 
ccgroup:cc,instreamid:CC2,language:sp" \
+  -var_stream_map "v:0,a:0,ccgroup:cc v:1,a:1,ccgroup:cc" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out_%v.m3u8
+@end example
+This example adds two @code{#EXT-X-MEDIA} tags with 
@code{TYPE=CLOSED-CAPTIONS} in
+the master playlist for the INSTREAM-IDs 'CC1' and 'CC2'. Also, it adds
+@code{CLOSED-CAPTIONS} attribute with group name 'cc' for the two output 
variant
+streams.
+
 @item master_pl_name
 Create HLS master playlist with the given name.
 
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 3345b89..39d0afe 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -820,7 +820,7 @@ static int write_manifest(AVFormatContext *s, int final)
 stream_bitrate += max_audio_bitrate;
 }
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
-ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, 
agroup);
+ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, 
agroup, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e36120c..4e4b287 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -145,9 +145,16 @@ typedef struct VariantStream {
 unsigned int nb_streams;
 int m3u8_created; /* status of media play-list creation */
 char *agroup; /* audio group name */
+char *ccgroup; /* closed caption group name */
 char *baseurl;
 } VariantStream;
 
+typedef struct ClosedCaptionsStream {
+char *ccgroup; /* closed caption group name */
+char *instreamid; /* closed captions INSTREAM-ID */
+char *language; /* closed captions langauge */
+} ClosedCaptionsStream;
+
 typedef struct HLSContext {
 const AVClass *class;  // Class for private options.
 int64_t start_sequence;
@@ -196,11 +203,14 @@ typedef struct HLSContext {
 
 VariantStream *var_streams;
 unsigned int nb_varstreams;
+ClosedCaptionsStream *cc_streams;
+unsigned int nb_ccstreams;
 
 int master_m3u8_created; /* status of master play-list creation */
 char *master_m3u8_url; /* URL of the master m3u8 file */
 int version; /* HLS version */
 char *var_stream_map; /* user specified variant stream map string */
+char *cc_stream_map; /* user specified closed caption streams map string */
 char *master_pl_name;
 unsigned int master_publish_rate;
 int http_persistent;
@@ -1115,7 +1125,8 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3u8_rel_name;
+char *m3u8_rel_name, *ccgroup;
+ClosedCaptionsStream *ccs;
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1142,6 +1153,16 @@ static int create_master_playlist(AVFormatContext *s,
 
 

[FFmpeg-devel] [PATCH 1/2] avdevice/decklink: addition of copyts option

2018-01-07 Thread vdixit
From: Vishwanath Dixit 

---
 doc/indevs.texi |  5 +
 libavdevice/decklink_common_c.h |  1 +
 libavdevice/decklink_dec.cpp| 18 +++---
 libavdevice/decklink_dec_c.c|  1 +
 4 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 56066bf..36aef49 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -317,6 +317,11 @@ Defaults to @samp{1073741824}.
 Sets the audio sample bit depth. Must be @samp{16} or @samp{32}.
 Defaults to @samp{16}.
 
+@item decklink_copyts
+If set to @option{true}, timestamps are forwarded as they are without removing
+the initial offset.
+Defaults to @option{false}.
+
 @end table
 
 @subsection Examples
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index 368ac25..ac6563a 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -52,6 +52,7 @@ struct decklink_cctx {
 char *format_code;
 int raw_format;
 int64_t queue_size;
+int copyts;
 };
 
 #endif /* AVDEVICE_DECKLINK_COMMON_C_H */
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 94dae26..1fd40ca 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -586,7 +586,8 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
IDeckLinkAudioInputPacket *audioFrame,
int64_t wallclock,
DecklinkPtsSource pts_src,
-   AVRational time_base, int64_t *initial_pts)
+   AVRational time_base, int64_t *initial_pts,
+   int copyts)
 {
 int64_t pts = AV_NOPTS_VALUE;
 BMDTimeValue bmd_pts;
@@ -619,10 +620,12 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
 if (res == S_OK)
 pts = bmd_pts / time_base.num;
 
-if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
-*initial_pts = pts;
-if (*initial_pts != AV_NOPTS_VALUE)
-pts -= *initial_pts;
+if (!copyts) {
+if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)
+*initial_pts = pts;
+if (*initial_pts != AV_NOPTS_VALUE)
+pts -= *initial_pts;
+}
 
 return pts;
 }
@@ -635,6 +638,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 BMDTimeValue frameTime;
 BMDTimeValue frameDuration;
 int64_t wallclock = 0;
+struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
 
 if (ctx->autodetect) {
 if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) 
&&
@@ -694,7 +698,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 no_video = 0;
 }
 
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->video_pts_source, ctx->video_st->time_base, _video_pts, 
cctx->copyts);
 pkt.dts = pkt.pts;
 
 pkt.duration = frameDuration;
@@ -785,7 +789,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 pkt.size = audioFrame->GetSampleFrameCount() * 
ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8);
 audioFrame->GetBytes();
 audioFrame->GetPacketTime(_pts, ctx->audio_st->time_base.den);
-pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts);
+pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, 
ctx->audio_pts_source, ctx->audio_st->time_base, _audio_pts, 
cctx->copyts);
 pkt.dts = pkt.pts;
 
 //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 1c6d826..6fb5ffe 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -73,6 +73,7 @@ static const AVOption options[] = {
 { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars),
AV_OPT_TYPE_BOOL,  { .i64 = 1}, 0, 1, DEC },
 { "queue_size","input queue buffer size",   OFFSET(queue_size),   
AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC },
 { "audio_depth",   "audio bitdepth (16 or 32)", OFFSET(audio_depth),  
AV_OPT_TYPE_INT,   { .i64 = 16}, 16, 32, DEC },
+{ "decklink_copyts", "copy timestamps, do not remove the initial offset", 
OFFSET(copyts), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, DEC },
 { NULL },
 };
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/2] avdevice/decklink: addition of absolute wallclock option for pts source

2018-01-07 Thread vdixit
From: Vishwanath Dixit 

---
 doc/indevs.texi | 6 --
 libavdevice/decklink_common_c.h | 1 +
 libavdevice/decklink_dec.cpp| 3 +++
 libavdevice/decklink_dec_c.c| 5 +++--
 4 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 36aef49..0bc8e6a 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -298,11 +298,13 @@ Sets the audio input source. Must be @samp{unset}, 
@samp{embedded},
 
 @item video_pts
 Sets the video packet timestamp source. Must be @samp{video}, @samp{audio},
-@samp{reference} or @samp{wallclock}. Defaults to @samp{video}.
+@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}.
+Defaults to @samp{video}.
 
 @item audio_pts
 Sets the audio packet timestamp source. Must be @samp{video}, @samp{audio},
-@samp{reference} or @samp{wallclock}. Defaults to @samp{audio}.
+@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}.
+Defaults to @samp{audio}.
 
 @item draw_bars
 If set to @samp{true}, color bars are drawn in the event of a signal loss.
diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h
index ac6563a..d726190 100644
--- a/libavdevice/decklink_common_c.h
+++ b/libavdevice/decklink_common_c.h
@@ -28,6 +28,7 @@ typedef enum DecklinkPtsSource {
 PTS_SRC_VIDEO = 2,
 PTS_SRC_REFERENCE = 3,
 PTS_SRC_WALLCLOCK = 4,
+PTS_SRC_ABS_WALLCLOCK = 5,
 } DecklinkPtsSource;
 
 struct decklink_cctx {
diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp
index 1fd40ca..6bbfe62 100644
--- a/libavdevice/decklink_dec.cpp
+++ b/libavdevice/decklink_dec.cpp
@@ -607,6 +607,7 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame 
*videoFrame,
 res = videoFrame->GetHardwareReferenceTimestamp(time_base.den, 
_pts, _duration);
 break;
 case PTS_SRC_WALLCLOCK:
+case PTS_SRC_ABS_WALLCLOCK:
 {
 /* MSVC does not support compound literals like AV_TIME_BASE_Q
  * in C++ code (compiler error C4576) */
@@ -652,6 +653,8 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
 ctx->frameCount++;
 if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == 
PTS_SRC_WALLCLOCK)
 wallclock = av_gettime_relative();
+else if(ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || 
ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK)
+wallclock = av_gettime();
 
 // Handle Video Frame
 if (videoFrame) {
diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c
index 6fb5ffe..c8f6f35 100644
--- a/libavdevice/decklink_dec_c.c
+++ b/libavdevice/decklink_dec_c.c
@@ -64,12 +64,13 @@ static const AVOption options[] = {
 { "analog_xlr",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0,DEC, "audio_input"},
 { "analog_rca",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0,DEC, "audio_input"},
 { "microphone",NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0,DEC, "audio_input"},
-{ "audio_pts", "audio pts source",   OFFSET(audio_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_AUDIO}, 1, 4, DEC, "pts_source"},
-{ "video_pts", "video pts source",   OFFSET(video_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_VIDEO}, 1, 4, DEC, "pts_source"},
+{ "audio_pts", "audio pts source",   OFFSET(audio_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_AUDIO}, 1, 5, DEC, "pts_source"},
+{ "video_pts", "video pts source",   OFFSET(video_pts_source),
AV_OPT_TYPE_INT,   { .i64 = PTS_SRC_VIDEO}, 1, 5, DEC, "pts_source"},
 { "audio", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_AUDIO}, 0, 0, DEC, "pts_source"},
 { "video", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_VIDEO}, 0, 0, DEC, "pts_source"},
 { "reference", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, "pts_source"},
 { "wallclock", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, "pts_source"},
+{ "abs_wallclock", NULL,  0,  
AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, "pts_source"},
 { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars),
AV_OPT_TYPE_BOOL,  { .i64 = 1}, 0, 1, DEC },
 { "queue_size","input queue buffer size",   OFFSET(queue_size),   
AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC },
 { "audio_depth",   "audio bitdepth (16 or 32)", OFFSET(audio_depth),  
AV_OPT_TYPE_INT,   { .i64 = 16}, 16, 32, DEC },
-- 
1.9.1

___
ffmpeg-devel mailing list

[FFmpeg-devel] [PATCH v2 1/1] avformat/hlsenc: closed caption tags in the master playlist

2017-12-29 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  4 
 libavformat/dashenc.c |  2 +-
 libavformat/hlsenc.c  | 14 +-
 libavformat/hlsplaylist.c |  5 -
 libavformat/hlsplaylist.h |  3 ++-
 5 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 8ce964b..01f7fe4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -874,6 +874,10 @@ publishing it repeatedly every after 30 segments i.e. 
every after 60s.
 @item http_persistent
 Use persistent HTTP connections. Applicable only for HTTP output.
 
+@item cc_instream_id
+Add @code{#EXT-X-MEDIA} tag in the master playlist with the specified instream 
ID. It
+accepts the values in the range 1-4.
+
 @end table
 
 @anchor{ico}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 3345b89..39d0afe 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -820,7 +820,7 @@ static int write_manifest(AVFormatContext *s, int final)
 stream_bitrate += max_audio_bitrate;
 }
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
-ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, 
agroup);
+ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, 
agroup, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e6f3241..bff3e6e 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -206,6 +206,7 @@ typedef struct HLSContext {
 int http_persistent;
 AVIOContext *m3u8_out;
 AVIOContext *sub_m3u8_out;
+int cc_instream_id; /* closed captions INSTREAM-ID */
 } HLSContext;
 
 static int mkdir_p(const char *path) {
@@ -1116,6 +1117,7 @@ static int create_master_playlist(AVFormatContext *s,
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
 char *m3u8_rel_name;
+char cc_group[16] = {0};
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1142,6 +1144,14 @@ static int create_master_playlist(AVFormatContext *s,
 
 ff_hls_write_playlist_version(hls->m3u8_out, hls->version);
 
+if (hls->cc_instream_id) {
+av_strlcpy(cc_group, "group_cc", sizeof(cc_group));
+avio_printf(hls->m3u8_out, 
"#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID=\"%s\"",
+cc_group);
+avio_printf(hls->m3u8_out, ",NAME=\"captions\",INSTREAM-ID=\"CC%d\"\n",
+hls->cc_instream_id);
+}
+
 /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
 for (i = 0; i < hls->nb_varstreams; i++) {
 vs = &(hls->var_streams[i]);
@@ -1227,7 +1237,8 @@ static int create_master_playlist(AVFormatContext *s,
 bandwidth += bandwidth / 10;
 
 ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, 
m3u8_rel_name,
-aud_st ? vs->agroup : NULL);
+ aud_st ? vs->agroup : NULL,
+ vid_st ? cc_group : NULL);
 
 av_freep(_rel_name);
 }
@@ -2436,6 +2447,7 @@ static const AVOption options[] = {
 {"master_pl_name", "Create HLS master playlist with this name", 
OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,E},
 {"master_pl_publish_rate", "Publish master play list every after this many 
segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 
0, UINT_MAX, E},
 {"http_persistent", "Use persistent HTTP connections", 
OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
+{"cc_instream_id", "Closed captions INSTREAM-ID", OFFSET(cc_instream_id), 
AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, E},
 { NULL },
 };
 
diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c
index 098dc89..1bfcce9 100644
--- a/libavformat/hlsplaylist.c
+++ b/libavformat/hlsplaylist.c
@@ -46,7 +46,8 @@ void ff_hls_write_audio_rendition(AVIOContext *out, char 
*agroup,
 }
 
 void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
-  int bandwidth, char *filename, char *agroup) {
+  int bandwidth, char *filename, char *agroup,
+  char *cc_group) {
 if (!out || !filename)
 return;
 
@@ -62,6 +63,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
 st->codecpar->height);
 if (agroup && strlen(agroup) > 0)
 avio_printf(out, ",AUDIO=\"group_%s\"", agroup);
+if (cc_group && strlen(cc_group) > 0)
+avio_printf(out, ",CLOSED-CAPTIONS=\"%s\"", cc_group);
 avio_printf(out, "\n%s\n\n", filename);
 }
 
diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h
index 9969315..0ff99f1 100644
--- a/libavformat/hlsplaylist.h
+++ b/libavformat/hlsplaylist.h
@@ -40,7 +40,8 @@ void ff_hls_write_playlist_version(AVIOContext *out, int 
version);
 void 

[FFmpeg-devel] [PATCH 1/1] avformat/hlsenc: closed caption tags in the master playlist

2017-12-29 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   |  4 
 libavformat/dashenc.c |  2 +-
 libavformat/hlsenc.c  | 14 +-
 libavformat/hlsplaylist.c |  5 -
 libavformat/hlsplaylist.h |  3 ++-
 5 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 93db549..8229202 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -872,6 +872,10 @@ publishing it repeatedly every after 30 segments i.e. 
every after 60s.
 @item http_persistent
 Use persistent HTTP connections. Applicable only for HTTP output.
 
+@item cc_instream_id
+Add @code{#EXT-X-MEDIA} tag in the master playlist with the specified instream 
ID. It
+accepts the values in the range 1-4.
+
 @end table
 
 @anchor{ico}
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 478a384..8797959 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -760,7 +760,7 @@ static int write_manifest(AVFormatContext *s, int final)
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
-playlist_file, NULL);
+playlist_file, NULL, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 74f66ce..e5176a8 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -206,6 +206,7 @@ typedef struct HLSContext {
 int http_persistent;
 AVIOContext *m3u8_out;
 AVIOContext *sub_m3u8_out;
+int cc_instream_id; /* closed captions INSTREAM-ID */
 } HLSContext;
 
 static int mkdir_p(const char *path) {
@@ -1122,6 +1123,7 @@ static int create_master_playlist(AVFormatContext *s,
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
 char *m3u8_rel_name;
+char cc_group[16] = {0};
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1148,6 +1150,14 @@ static int create_master_playlist(AVFormatContext *s,
 
 ff_hls_write_playlist_version(hls->m3u8_out, hls->version);
 
+if (hls->cc_instream_id) {
+av_strlcpy(cc_group, "group_cc", sizeof(cc_group));
+avio_printf(hls->m3u8_out, 
"#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID=\"%s\"",
+cc_group);
+avio_printf(hls->m3u8_out, ",NAME=\"captions\",INSTREAM-ID=\"CC%d\"\n",
+hls->cc_instream_id);
+}
+
 /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
 for (i = 0; i < hls->nb_varstreams; i++) {
 vs = &(hls->var_streams[i]);
@@ -1235,7 +1245,8 @@ static int create_master_playlist(AVFormatContext *s,
 bandwidth += bandwidth / 10;
 
 ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, 
m3u8_rel_name,
-aud_st ? vs->agroup : NULL);
+ aud_st ? vs->agroup : NULL,
+ vid_st ? cc_group : NULL);
 
 av_freep(_rel_name);
 }
@@ -2444,6 +2455,7 @@ static const AVOption options[] = {
 {"master_pl_name", "Create HLS master playlist with this name", 
OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,E},
 {"master_pl_publish_rate", "Publish master play list every after this many 
segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 
0, UINT_MAX, E},
 {"http_persistent", "Use persistent HTTP connections", 
OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E },
+{"cc_instream_id", "Closed captions INSTREAM-ID", OFFSET(cc_instream_id), 
AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, E},
 { NULL },
 };
 
diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c
index 42f059a..8619436 100644
--- a/libavformat/hlsplaylist.c
+++ b/libavformat/hlsplaylist.c
@@ -36,7 +36,8 @@ void ff_hls_write_playlist_version(AVIOContext *out, int 
version) {
 }
 
 void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
-  int bandwidth, char *filename, char *agroup) {
+  int bandwidth, char *filename, char *agroup,
+  char *cc_group) {
 if (!out || !filename)
 return;
 
@@ -52,6 +53,8 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
 st->codecpar->height);
 if (agroup && strlen(agroup) > 0)
 avio_printf(out, ",AUDIO=\"group_%s\"", agroup);
+if (cc_group && strlen(cc_group) > 0)
+avio_printf(out, ",CLOSED-CAPTIONS=\"%s\"", cc_group);
 avio_printf(out, "\n%s\n\n", filename);
 }
 
diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h
index ac03550..71ccee7 100644
--- a/libavformat/hlsplaylist.h
+++ b/libavformat/hlsplaylist.h
@@ -38,7 +38,8 @@ typedef enum {
 
 void ff_hls_write_playlist_version(AVIOContext *out, int version);
 void ff_hls_write_stream_info(AVStream *st, AVIOContext *out,
-   

[FFmpeg-devel] [PATCH v3 2/3] avformat/hlsenc: configurable variant stream index position in filenames

2017-12-26 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  |  31 +--
 libavformat/hlsenc.c | 153 ++-
 2 files changed, 126 insertions(+), 58 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 93db549..6af970d 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -575,6 +575,17 @@ Should a relative path be specified, the path of the 
created segment
 files will be relative to the current working directory.
 When use_localtime_mkdir is set, the whole expanded value of @var{filename} 
will be written into the m3u8 segment list.
 
+When @code{var_stream_map} is set with two or more variant streams, the
+@var{filename} pattern must contain the string "%v", this string specifies
+the position of variant stream index in the generated segment file names.
+@example
+ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  -hls_segment_filename 'file_%v_%03d.ts' out_%v.m3u8
+@end example
+This example will produce the playlists segment file sets:
+@file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
+@file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
 
 @item use_localtime
 Use strftime() on @var{filename} to expand the segment filename with localtime.
@@ -701,6 +712,10 @@ the fmp4 files is used in hls after version 7.
 @item hls_fmp4_init_filename @var{filename}
 set filename to the fragment files header file, default filename is 
@file{init.mp4}.
 
+When @code{var_stream_map} is set with two or more variant streams, the
+@var{filename} pattern must contain the string "%v", this string specifies
+the position of variant stream index in the generated init file names.
+
 @item hls_flags @var{flags}
 Possible values:
 
@@ -814,32 +829,36 @@ Expected string format is like this "a:0,v:0 a:1,v:1 
". Here a:, v:, s: are
 the keys to specify audio, video and subtitle streams respectively.
 Allowed values are 0 to 9 (limited just based on practical usage).
 
+When there are two or more variant streams, the output filename pattern must
+contain the string "%v", this string specifies the position of variant stream
+index in the output media playlist filenames.
+
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
   -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates two hls variant streams. The first variant stream will
 contain video stream of bitrate 1000k and audio stream of bitrate 64k and the
 second variant stream will contain video stream of bitrate 256k and audio
-stream of bitrate 32k. Here, two media playlist with file names out_1.m3u8 and
-out_2.m3u8 will be created.
+stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and
+out_1.m3u8 will be created.
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \
   -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates three hls variant streams. The first variant stream will
 be a video only stream with video bitrate 1000k, the second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
-out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
 @example
 ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
   -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
   -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
   -master_pl_name master.m3u8 \
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates two audio only and two video only variant streams. In
 addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index bd43336..198c9d3 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1536,7 +1536,7 @@ static const char * 
get_default_pattern_localtime_fmt(AVFormatContext *s)
 return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, 
"%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts";
 }
 
-static int format_name(char *name, int name_buf_len, int i)
+static int append_postfix(char *name, int name_buf_len, int i)
 {
 char *p;
 char extension[10] = {'\0'};
@@ -1555,6 +1555,53 @@ static int format_name(char *name, int name_buf_len, int 
i)
 return 0;
 }
 
+static int validate_name(int nb_vs, const char *fn)
+{
+const char *filename;
+int ret = 0;
+
+if (!fn) {
+ret = AVERROR(EINVAL);
+goto fail;
+}
+
+   

[FFmpeg-devel] [PATCH v3 3/3] avformat/hlsenc: creation of variant streams in subdirectories

2017-12-26 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  | 33 -
 libavformat/hlsenc.c | 68 +---
 2 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 6af970d..2951262 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -587,6 +587,20 @@ This example will produce the playlists segment file sets:
 @file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
 @file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
 
+The string "%v" may be present in the filename or in the last directory name
+containing the file. If the string is present in the directory name, then
+sub-directories are created after expanding the directory name pattern. This
+enables creation of segments corresponding to different variant streams in
+subdirectories.
+@example
+ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  -hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8
+@end example
+This example will produce the playlists segment file sets:
+@file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. 
and
+@file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc.
+
 @item use_localtime
 Use strftime() on @var{filename} to expand the segment filename with localtime.
 The segment number is also available in this mode, but to use it, you need to 
specify second_level_segment_index
@@ -715,6 +729,11 @@ set filename to the fragment files header file, default 
filename is @file{init.m
 When @code{var_stream_map} is set with two or more variant streams, the
 @var{filename} pattern must contain the string "%v", this string specifies
 the position of variant stream index in the generated init file names.
+The string "%v" may be present in the filename or in the last directory name
+containing the file. If the string is present in the directory name, then
+sub-directories are created after expanding the directory name pattern. This
+enables creation of init files corresponding to different variant streams in
+subdirectories.
 
 @item hls_flags @var{flags}
 Possible values:
@@ -831,7 +850,11 @@ Allowed values are 0 to 9 (limited just based on practical 
usage).
 
 When there are two or more variant streams, the output filename pattern must
 contain the string "%v", this string specifies the position of variant stream
-index in the output media playlist filenames.
+index in the output media playlist filenames. The string "%v" may be present in
+the filename or in the last directory name containing the file. If the string 
is
+present in the directory name, then sub-directories are created after expanding
+the directory name pattern. This enables creation of variant streams in
+subdirectories.
 
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
@@ -854,6 +877,14 @@ be an audio only stream with bitrate 64k and the third 
variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
 @example
+ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  http://example.com/live/vs_%v/out.m3u8
+@end example
+This example creates the variant streams in subdirectories. Here, the first
+media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and
+the second one at @file{http://example.com/live/vs_1/out.m3u8}.
+@example
 ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
   -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
   -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 198c9d3..b25bfc9 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1557,7 +1557,8 @@ static int append_postfix(char *name, int name_buf_len, 
int i)
 
 static int validate_name(int nb_vs, const char *fn)
 {
-const char *filename;
+const char *filename, *subdir_name;
+char *fn_dup = NULL;
 int ret = 0;
 
 if (!fn) {
@@ -1565,22 +1566,38 @@ static int validate_name(int nb_vs, const char *fn)
 goto fail;
 }
 
+fn_dup = av_strdup(fn);
+if (!fn_dup) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
 filename = av_basename(fn);
+subdir_name = av_dirname(fn_dup);
 
-if (nb_vs > 1 && !av_stristr(filename, "%v")) {
+if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, 
"%v")) {
 av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, 
%%v is expected in the filename %s\n",
 fn);
 ret = AVERROR(EINVAL);
 goto fail;
 }
 
+if (av_stristr(filename, "%v") && 

[FFmpeg-devel] [PATCH v3 1/3] avformat/hlsenc: revamped master playlist url creation logic

2017-12-26 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/hlsenc.c | 34 ++
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 74f66ce..bd43336 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1697,28 +1697,30 @@ static int update_variant_stream_info(AVFormatContext 
*s) {
 
 static int update_master_pl_info(AVFormatContext *s) {
 HLSContext *hls = s->priv_data;
-int m3u8_name_size, ret;
-char *p;
+const char *dir;
+char *fn;
+int ret = 0;
 
-m3u8_name_size = strlen(s->filename) + strlen(hls->master_pl_name) + 1;
-hls->master_m3u8_url = av_malloc(m3u8_name_size);
-if (!hls->master_m3u8_url) {
+fn = av_strdup(s->filename);
+if (!fn) {
 ret = AVERROR(ENOMEM);
-return ret;
+goto fail;
 }
 
-av_strlcpy(hls->master_m3u8_url, s->filename, m3u8_name_size);
-p = strrchr(hls->master_m3u8_url, '/') ?
-strrchr(hls->master_m3u8_url, '/') :
-strrchr(hls->master_m3u8_url, '\\');
-if (p) {
-*(p + 1) = '\0';
-av_strlcat(hls->master_m3u8_url, hls->master_pl_name, m3u8_name_size);
-} else {
-av_strlcpy(hls->master_m3u8_url, hls->master_pl_name, m3u8_name_size);
+dir = av_dirname(fn);
+if (dir && strcmp(dir, "."))
+hls->master_m3u8_url = av_append_path_component(dir, 
hls->master_pl_name);
+else
+hls->master_m3u8_url = av_strdup(hls->master_pl_name);
+
+if (!hls->master_m3u8_url) {
+ret = AVERROR(ENOMEM);
+goto fail;
 }
 
-return 0;
+fail:
+av_freep();
+return ret;
 }
 
 static int hls_write_header(AVFormatContext *s)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v2 3/3] avformat/hlsenc: creation of variant streams in subdirectories

2017-12-26 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  | 33 -
 libavformat/hlsenc.c | 68 +---
 2 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 6af970d..2951262 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -587,6 +587,20 @@ This example will produce the playlists segment file sets:
 @file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
 @file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
 
+The string "%v" may be present in the filename or in the last directory name
+containing the file. If the string is present in the directory name, then
+sub-directories are created after expanding the directory name pattern. This
+enables creation of segments corresponding to different variant streams in
+subdirectories.
+@example
+ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  -hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8
+@end example
+This example will produce the playlists segment file sets:
+@file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. 
and
+@file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc.
+
 @item use_localtime
 Use strftime() on @var{filename} to expand the segment filename with localtime.
 The segment number is also available in this mode, but to use it, you need to 
specify second_level_segment_index
@@ -715,6 +729,11 @@ set filename to the fragment files header file, default 
filename is @file{init.m
 When @code{var_stream_map} is set with two or more variant streams, the
 @var{filename} pattern must contain the string "%v", this string specifies
 the position of variant stream index in the generated init file names.
+The string "%v" may be present in the filename or in the last directory name
+containing the file. If the string is present in the directory name, then
+sub-directories are created after expanding the directory name pattern. This
+enables creation of init files corresponding to different variant streams in
+subdirectories.
 
 @item hls_flags @var{flags}
 Possible values:
@@ -831,7 +850,11 @@ Allowed values are 0 to 9 (limited just based on practical 
usage).
 
 When there are two or more variant streams, the output filename pattern must
 contain the string "%v", this string specifies the position of variant stream
-index in the output media playlist filenames.
+index in the output media playlist filenames. The string "%v" may be present in
+the filename or in the last directory name containing the file. If the string 
is
+present in the directory name, then sub-directories are created after expanding
+the directory name pattern. This enables creation of variant streams in
+subdirectories.
 
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
@@ -854,6 +877,14 @@ be an audio only stream with bitrate 64k and the third 
variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
 @example
+ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  http://example.com/live/vs_%v/out.m3u8
+@end example
+This example creates the variant streams in subdirectories. Here, the first
+media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and
+the second one at @file{http://example.com/live/vs_1/out.m3u8}.
+@example
 ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
   -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
   -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 76a4110..9e1a267 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1557,7 +1557,8 @@ static int append_postfix(char *name, int name_buf_len, 
int i)
 
 static int validate_name(int nb_vs, const char *fn)
 {
-const char *filename;
+const char *filename, *subdir_name;
+char *fn_dup = NULL;
 int ret = 0;
 
 if (!fn) {
@@ -1565,22 +1566,38 @@ static int validate_name(int nb_vs, const char *fn)
 goto fail;
 }
 
+fn_dup = av_strdup(fn);
+if (!fn_dup) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
 filename = av_basename(fn);
+subdir_name = av_dirname(fn_dup);
 
-if (nb_vs > 1 && !av_stristr(filename, "%v")) {
+if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, 
"%v")) {
 av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, 
%%v is expected in the filename %s\n",
 fn);
 ret = AVERROR(EINVAL);
 goto fail;
 }
 
+if (av_stristr(filename, "%v") && 

[FFmpeg-devel] [PATCH v2 2/3] avformat/hlsenc: configurable variant stream index position in filenames

2017-12-26 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  |  31 +--
 libavformat/hlsenc.c | 153 ++-
 2 files changed, 127 insertions(+), 57 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 93db549..6af970d 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -575,6 +575,17 @@ Should a relative path be specified, the path of the 
created segment
 files will be relative to the current working directory.
 When use_localtime_mkdir is set, the whole expanded value of @var{filename} 
will be written into the m3u8 segment list.
 
+When @code{var_stream_map} is set with two or more variant streams, the
+@var{filename} pattern must contain the string "%v", this string specifies
+the position of variant stream index in the generated segment file names.
+@example
+ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  -hls_segment_filename 'file_%v_%03d.ts' out_%v.m3u8
+@end example
+This example will produce the playlists segment file sets:
+@file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
+@file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
 
 @item use_localtime
 Use strftime() on @var{filename} to expand the segment filename with localtime.
@@ -701,6 +712,10 @@ the fmp4 files is used in hls after version 7.
 @item hls_fmp4_init_filename @var{filename}
 set filename to the fragment files header file, default filename is 
@file{init.mp4}.
 
+When @code{var_stream_map} is set with two or more variant streams, the
+@var{filename} pattern must contain the string "%v", this string specifies
+the position of variant stream index in the generated init file names.
+
 @item hls_flags @var{flags}
 Possible values:
 
@@ -814,32 +829,36 @@ Expected string format is like this "a:0,v:0 a:1,v:1 
". Here a:, v:, s: are
 the keys to specify audio, video and subtitle streams respectively.
 Allowed values are 0 to 9 (limited just based on practical usage).
 
+When there are two or more variant streams, the output filename pattern must
+contain the string "%v", this string specifies the position of variant stream
+index in the output media playlist filenames.
+
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
   -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates two hls variant streams. The first variant stream will
 contain video stream of bitrate 1000k and audio stream of bitrate 64k and the
 second variant stream will contain video stream of bitrate 256k and audio
-stream of bitrate 32k. Here, two media playlist with file names out_1.m3u8 and
-out_2.m3u8 will be created.
+stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and
+out_1.m3u8 will be created.
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \
   -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates three hls variant streams. The first variant stream will
 be a video only stream with video bitrate 1000k, the second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
-out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
 @example
 ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
   -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
   -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
   -master_pl_name master.m3u8 \
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates two audio only and two video only variant streams. In
 addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index bd43336..76a4110 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1536,7 +1536,7 @@ static const char * 
get_default_pattern_localtime_fmt(AVFormatContext *s)
 return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, 
"%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts";
 }
 
-static int format_name(char *name, int name_buf_len, int i)
+static int append_postfix(char *name, int name_buf_len, int i)
 {
 char *p;
 char extension[10] = {'\0'};
@@ -1555,6 +1555,53 @@ static int format_name(char *name, int name_buf_len, int 
i)
 return 0;
 }
 
+static int validate_name(int nb_vs, const char *fn)
+{
+const char *filename;
+int ret = 0;
+
+if (!fn) {
+ret = AVERROR(EINVAL);
+goto fail;
+}
+
+   

[FFmpeg-devel] [PATCH v2 1/3] avformat/hlsenc: revamped master playlist url creation logic

2017-12-26 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/hlsenc.c | 34 ++
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 74f66ce..bd43336 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1697,28 +1697,30 @@ static int update_variant_stream_info(AVFormatContext 
*s) {
 
 static int update_master_pl_info(AVFormatContext *s) {
 HLSContext *hls = s->priv_data;
-int m3u8_name_size, ret;
-char *p;
+const char *dir;
+char *fn;
+int ret = 0;
 
-m3u8_name_size = strlen(s->filename) + strlen(hls->master_pl_name) + 1;
-hls->master_m3u8_url = av_malloc(m3u8_name_size);
-if (!hls->master_m3u8_url) {
+fn = av_strdup(s->filename);
+if (!fn) {
 ret = AVERROR(ENOMEM);
-return ret;
+goto fail;
 }
 
-av_strlcpy(hls->master_m3u8_url, s->filename, m3u8_name_size);
-p = strrchr(hls->master_m3u8_url, '/') ?
-strrchr(hls->master_m3u8_url, '/') :
-strrchr(hls->master_m3u8_url, '\\');
-if (p) {
-*(p + 1) = '\0';
-av_strlcat(hls->master_m3u8_url, hls->master_pl_name, m3u8_name_size);
-} else {
-av_strlcpy(hls->master_m3u8_url, hls->master_pl_name, m3u8_name_size);
+dir = av_dirname(fn);
+if (dir && strcmp(dir, "."))
+hls->master_m3u8_url = av_append_path_component(dir, 
hls->master_pl_name);
+else
+hls->master_m3u8_url = av_strdup(hls->master_pl_name);
+
+if (!hls->master_m3u8_url) {
+ret = AVERROR(ENOMEM);
+goto fail;
 }
 
-return 0;
+fail:
+av_freep();
+return ret;
 }
 
 static int hls_write_header(AVFormatContext *s)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v8 2/3] avcodec/libx264:setting profile and level in avcodec context

2017-12-18 Thread vdixit
From: Vishwanath Dixit 

---
 libavcodec/libx264.c | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index e2455e1..0285213 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -19,11 +19,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/eval.h"
 #include "libavutil/internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/reverse.h"
 #include "libavutil/stereo3d.h"
 #include "libavutil/intreadwrite.h"
 #include "avcodec.h"
@@ -454,6 +456,9 @@ static av_cold int X264_init(AVCodecContext *avctx)
 X264Context *x4 = avctx->priv_data;
 AVCPBProperties *cpb_props;
 int sw,sh;
+x264_nal_t *nal;
+uint8_t *p;
+int nnal, s, i;
 
 if (avctx->global_quality > 0)
 av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is 
recommended.\n");
@@ -799,12 +804,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
 if (!x4->enc)
 return AVERROR_EXTERNAL;
 
-if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
-x264_nal_t *nal;
-uint8_t *p;
-int nnal, s, i;
+s = x264_encoder_headers(x4->enc, , );
+// Assert for NAL start code and SPS unit type
+av_assert0((nal->p_payload[0] | nal->p_payload[1] | nal->p_payload[2]) == 
0 && nal->p_payload[3] == 1);
+av_assert0((nal->p_payload[4] & 0x1F) == 7);
+// bits 0-7 LSB for profile. bits 8-11 for constrained set flags.
+if (avctx->profile == FF_PROFILE_UNKNOWN)
+avctx->profile = ((uint32_t)nal->p_payload[5]) | 
((uint32_t)ff_reverse[nal->p_payload[6]] << 8);
+if (avctx->level == FF_LEVEL_UNKNOWN)
+avctx->level = nal->p_payload[7];
 
-s = x264_encoder_headers(x4->enc, , );
+if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
 avctx->extradata = p = av_mallocz(s + AV_INPUT_BUFFER_PADDING_SIZE);
 if (!p)
 return AVERROR(ENOMEM);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v8 3/3] avformat/hlsenc:addition of CODECS attribute in the master playlist

2017-12-18 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/Makefile  |  2 +-
 libavformat/dashenc.c |  2 +-
 libavformat/hlsenc.c  | 65 +--
 libavformat/hlsplaylist.c |  5 +++-
 libavformat/hlsplaylist.h |  3 ++-
 libavformat/reverse.c |  1 +
 tests/ref/fate/source |  1 +
 7 files changed, 73 insertions(+), 6 deletions(-)
 create mode 100644 libavformat/reverse.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index cb70eac..1072ff9 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -61,7 +61,7 @@ OBJS-$(CONFIG_RTPDEC)+= rdt.o 
  \
 rtpdec_vp9.o\
 rtpdec_xiph.o
 OBJS-$(CONFIG_RTPENC_CHAIN)  += rtpenc_chain.o rtp.o
-OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o
+OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o reverse.o
 OBJS-$(CONFIG_SRTP)  += srtp.o
 
 # muxers/demuxers
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index f363418..016ada3 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -760,7 +760,7 @@ static int write_manifest(AVFormatContext *s, int final)
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
-playlist_file, NULL);
+playlist_file, NULL, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 53dc835..d66b88b 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -39,6 +39,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/random_seed.h"
+#include "libavutil/reverse.h"
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time_internal.h"
@@ -1082,6 +1083,63 @@ static int get_relative_url(const char *master_url, 
const char *media_url,
 return 0;
 }
 
+static char *get_codec_str(AVStream *vid_st, AVStream *aud_st) {
+size_t codec_str_size = 64;
+char *codec_str = av_malloc(codec_str_size);
+int video_str_len = 0;
+
+if (!codec_str)
+return NULL;
+
+if (!vid_st && !aud_st) {
+goto fail;
+}
+
+if (vid_st) {
+if (vid_st->codecpar->profile != FF_PROFILE_UNKNOWN &&
+vid_st->codecpar->level != FF_LEVEL_UNKNOWN &&
+vid_st->codecpar->codec_id == AV_CODEC_ID_H264) {
+snprintf(codec_str, codec_str_size, "avc1.%02x%02x%02x",
+ vid_st->codecpar->profile & 0xFF,
+ ff_reverse[(vid_st->codecpar->profile >> 8) & 0xFF],
+ vid_st->codecpar->level);
+} else {
+goto fail;
+}
+video_str_len = strlen(codec_str);
+}
+
+if (aud_st) {
+char *audio_str = codec_str;
+if (video_str_len) {
+codec_str[video_str_len] = ',';
+video_str_len += 1;
+audio_str += video_str_len;
+codec_str_size -= video_str_len;
+}
+if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP2) {
+snprintf(audio_str, codec_str_size, "mp4a.40.33");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP3) {
+snprintf(audio_str, codec_str_size, "mp4a.40.34");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 
5 and 29 respectively */
+snprintf(audio_str, codec_str_size, "mp4a.40.2");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A5");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_EAC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A6");
+} else {
+goto fail;
+}
+}
+
+return codec_str;
+
+fail:
+av_free(codec_str);
+return NULL;
+}
+
 static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
@@ -1091,7 +1149,7 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3u8_rel_name;
+char *m3u8_rel_name, *codec_str;
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1204,9 +1262,12 @@ static int create_master_playlist(AVFormatContext *s,
 bandwidth += aud_st->codecpar->bit_rate;
 bandwidth += bandwidth / 10;
 
+codec_str = get_codec_str(vid_st, aud_st);
+
 ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, 
m3u8_rel_name,
-aud_st ? vs->agroup : NULL);
+

[FFmpeg-devel] [PATCH v8 1/3] avformat/hlsenc:addition of #EXT-X-MEDIA tag and AUDIO attribute

2017-12-18 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   | 12 +
 libavformat/dashenc.c |  3 ++-
 libavformat/hlsenc.c  | 64 ---
 libavformat/hlsplaylist.c |  4 ++-
 libavformat/hlsplaylist.h |  2 +-
 5 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 3d0c7bf..93db549 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -834,6 +834,18 @@ be a video only stream with video bitrate 1000k, the 
second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+@example
+ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
+  -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
+  -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out.m3u8
+@end example
+This example creates two audio only and two video only variant streams. In
+addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
+playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams
+and they are mapped to the two video only variant streams with audio group 
names
+'aud_low' and 'aud_high'.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5687530..f363418 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -759,7 +759,8 @@ static int write_manifest(AVFormatContext *s, int final)
 char playlist_file[64];
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
-ff_hls_write_stream_info(st, out, st->codecpar->bit_rate, 
playlist_file);
+ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
+playlist_file, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e3442c3..53dc835 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -144,6 +144,7 @@ typedef struct VariantStream {
 AVStream **streams;
 unsigned int nb_streams;
 int m3u8_created; /* status of media play-list creation */
+char *agroup; /* audio group name */
 char *baseurl;
 } VariantStream;
 
@@ -1085,7 +1086,7 @@ static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
 HLSContext *hls = s->priv_data;
-VariantStream *vs;
+VariantStream *vs, *temp_vs;
 AVStream *vid_st, *aud_st;
 AVDictionary *options = NULL;
 unsigned int i, j;
@@ -1117,6 +1118,34 @@ static int create_master_playlist(AVFormatContext *s,
 
 ff_hls_write_playlist_version(hls->m3u8_out, hls->version);
 
+/* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
+for (i = 0; i < hls->nb_varstreams; i++) {
+vs = &(hls->var_streams[i]);
+
+if (vs->has_video || vs->has_subtitle || !vs->agroup)
+continue;
+
+m3u8_name_size = strlen(vs->m3u8_name) + 1;
+m3u8_rel_name = av_malloc(m3u8_name_size);
+if (!m3u8_rel_name) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size);
+ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name,
+   m3u8_rel_name, m3u8_name_size);
+if (ret < 0) {
+av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n");
+goto fail;
+}
+
+avio_printf(hls->m3u8_out, 
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"",
+vs->agroup);
+avio_printf(hls->m3u8_out, 
",NAME=\"audio_0\",DEFAULT=YES,URI=\"%s\"\n",
+m3u8_rel_name);
+av_freep(_rel_name);
+}
+
 /* For variant streams with video add #EXT-X-STREAM-INF tag with 
attributes*/
 for (i = 0; i < hls->nb_varstreams; i++) {
 vs = &(hls->var_streams[i]);
@@ -1149,6 +1178,25 @@ static int create_master_playlist(AVFormatContext *s,
 continue;
 }
 
+/**
+ * Traverse through the list of audio only rendition streams and find
+ * the rendition which has highest bitrate in the same audio group
+ */
+if (vs->agroup) {
+for (j = 0; j < hls->nb_varstreams; j++) {
+temp_vs = &(hls->var_streams[j]);
+if (!temp_vs->has_video && !temp_vs->has_subtitle &&
+temp_vs->agroup &&
+!av_strcasecmp(temp_vs->agroup, vs->agroup)) {
+if (!aud_st)
+aud_st = temp_vs->streams[0];
+if 

[FFmpeg-devel] [PATCH v7 1/3] avformat/hlsenc:addition of #EXT-X-MEDIA tag and AUDIO attribute

2017-12-18 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   | 12 +
 libavformat/dashenc.c |  3 ++-
 libavformat/hlsenc.c  | 62 ---
 libavformat/hlsplaylist.c |  4 ++-
 libavformat/hlsplaylist.h |  2 +-
 5 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 3d0c7bf..93db549 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -834,6 +834,18 @@ be a video only stream with video bitrate 1000k, the 
second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+@example
+ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
+  -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
+  -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out.m3u8
+@end example
+This example creates two audio only and two video only variant streams. In
+addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
+playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams
+and they are mapped to the two video only variant streams with audio group 
names
+'aud_low' and 'aud_high'.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5687530..f363418 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -759,7 +759,8 @@ static int write_manifest(AVFormatContext *s, int final)
 char playlist_file[64];
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
-ff_hls_write_stream_info(st, out, st->codecpar->bit_rate, 
playlist_file);
+ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
+playlist_file, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index e3442c3..2903e4e 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -144,6 +144,7 @@ typedef struct VariantStream {
 AVStream **streams;
 unsigned int nb_streams;
 int m3u8_created; /* status of media play-list creation */
+char *agroup; /* audio group name */
 char *baseurl;
 } VariantStream;
 
@@ -1085,7 +1086,7 @@ static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
 HLSContext *hls = s->priv_data;
-VariantStream *vs;
+VariantStream *vs, *temp_vs;
 AVStream *vid_st, *aud_st;
 AVDictionary *options = NULL;
 unsigned int i, j;
@@ -1117,6 +1118,34 @@ static int create_master_playlist(AVFormatContext *s,
 
 ff_hls_write_playlist_version(hls->m3u8_out, hls->version);
 
+/* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
+for (i = 0; i < hls->nb_varstreams; i++) {
+vs = &(hls->var_streams[i]);
+
+if (vs->has_video || vs->has_subtitle || !vs->agroup)
+continue;
+
+m3u8_name_size = strlen(vs->m3u8_name) + 1;
+m3u8_rel_name = av_malloc(m3u8_name_size);
+if (!m3u8_rel_name) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size);
+ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name,
+   m3u8_rel_name, m3u8_name_size);
+if (ret < 0) {
+av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n");
+goto fail;
+}
+
+avio_printf(hls->m3u8_out, 
"#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"",
+vs->agroup);
+avio_printf(hls->m3u8_out, 
",NAME=\"audio_0\",DEFAULT=YES,URI=\"%s\"\n",
+m3u8_rel_name);
+av_freep(_rel_name);
+}
+
 /* For variant streams with video add #EXT-X-STREAM-INF tag with 
attributes*/
 for (i = 0; i < hls->nb_varstreams; i++) {
 vs = &(hls->var_streams[i]);
@@ -1149,6 +1178,25 @@ static int create_master_playlist(AVFormatContext *s,
 continue;
 }
 
+/**
+ * Traverse through the list of audio only rendition streams and find
+ * the rendition which has highest bitrate in the same audio group
+ */
+if (vs->agroup) {
+for (j = 0; j < hls->nb_varstreams; j++) {
+temp_vs = &(hls->var_streams[j]);
+if (!temp_vs->has_video && !temp_vs->has_subtitle &&
+temp_vs->agroup &&
+!strcmp(temp_vs->agroup, vs->agroup)) {
+if (!aud_st)
+aud_st = temp_vs->streams[0];
+if 

[FFmpeg-devel] [PATCH v7 2/3] avcodec/libx264:setting profile and level in avcodec context

2017-12-18 Thread vdixit
From: Vishwanath Dixit 

---
 libavcodec/libx264.c | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index e2455e1..0285213 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -19,11 +19,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/eval.h"
 #include "libavutil/internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/reverse.h"
 #include "libavutil/stereo3d.h"
 #include "libavutil/intreadwrite.h"
 #include "avcodec.h"
@@ -454,6 +456,9 @@ static av_cold int X264_init(AVCodecContext *avctx)
 X264Context *x4 = avctx->priv_data;
 AVCPBProperties *cpb_props;
 int sw,sh;
+x264_nal_t *nal;
+uint8_t *p;
+int nnal, s, i;
 
 if (avctx->global_quality > 0)
 av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is 
recommended.\n");
@@ -799,12 +804,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
 if (!x4->enc)
 return AVERROR_EXTERNAL;
 
-if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
-x264_nal_t *nal;
-uint8_t *p;
-int nnal, s, i;
+s = x264_encoder_headers(x4->enc, , );
+// Assert for NAL start code and SPS unit type
+av_assert0((nal->p_payload[0] | nal->p_payload[1] | nal->p_payload[2]) == 
0 && nal->p_payload[3] == 1);
+av_assert0((nal->p_payload[4] & 0x1F) == 7);
+// bits 0-7 LSB for profile. bits 8-11 for constrained set flags.
+if (avctx->profile == FF_PROFILE_UNKNOWN)
+avctx->profile = ((uint32_t)nal->p_payload[5]) | 
((uint32_t)ff_reverse[nal->p_payload[6]] << 8);
+if (avctx->level == FF_LEVEL_UNKNOWN)
+avctx->level = nal->p_payload[7];
 
-s = x264_encoder_headers(x4->enc, , );
+if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
 avctx->extradata = p = av_mallocz(s + AV_INPUT_BUFFER_PADDING_SIZE);
 if (!p)
 return AVERROR(ENOMEM);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v7 3/3] avformat/hlsenc:addition of CODECS attribute in the master playlist

2017-12-18 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/Makefile  |  2 +-
 libavformat/dashenc.c |  2 +-
 libavformat/hlsenc.c  | 65 +--
 libavformat/hlsplaylist.c |  5 +++-
 libavformat/hlsplaylist.h |  3 ++-
 libavformat/reverse.c |  1 +
 tests/ref/fate/source |  1 +
 7 files changed, 73 insertions(+), 6 deletions(-)
 create mode 100644 libavformat/reverse.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index cb70eac..1072ff9 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -61,7 +61,7 @@ OBJS-$(CONFIG_RTPDEC)+= rdt.o 
  \
 rtpdec_vp9.o\
 rtpdec_xiph.o
 OBJS-$(CONFIG_RTPENC_CHAIN)  += rtpenc_chain.o rtp.o
-OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o
+OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o reverse.o
 OBJS-$(CONFIG_SRTP)  += srtp.o
 
 # muxers/demuxers
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index f363418..016ada3 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -760,7 +760,7 @@ static int write_manifest(AVFormatContext *s, int final)
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
-playlist_file, NULL);
+playlist_file, NULL, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 2903e4e..b6df3db 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -39,6 +39,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/random_seed.h"
+#include "libavutil/reverse.h"
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time_internal.h"
@@ -1082,6 +1083,63 @@ static int get_relative_url(const char *master_url, 
const char *media_url,
 return 0;
 }
 
+static char *get_codec_str(AVStream *vid_st, AVStream *aud_st) {
+size_t codec_str_size = 64;
+char *codec_str = av_malloc(codec_str_size);
+int video_str_len = 0;
+
+if (!codec_str)
+return NULL;
+
+if (!vid_st && !aud_st) {
+goto fail;
+}
+
+if (vid_st) {
+if (vid_st->codecpar->profile != FF_PROFILE_UNKNOWN &&
+vid_st->codecpar->level != FF_LEVEL_UNKNOWN &&
+vid_st->codecpar->codec_id == AV_CODEC_ID_H264) {
+snprintf(codec_str, codec_str_size, "avc1.%02x%02x%02x",
+ vid_st->codecpar->profile & 0xFF,
+ ff_reverse[(vid_st->codecpar->profile >> 8) & 0xFF],
+ vid_st->codecpar->level);
+} else {
+goto fail;
+}
+video_str_len = strlen(codec_str);
+}
+
+if (aud_st) {
+char *audio_str = codec_str;
+if (video_str_len) {
+codec_str[video_str_len] = ',';
+video_str_len += 1;
+audio_str += video_str_len;
+codec_str_size -= video_str_len;
+}
+if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP2) {
+snprintf(audio_str, codec_str_size, "mp4a.40.33");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP3) {
+snprintf(audio_str, codec_str_size, "mp4a.40.34");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 
5 and 29 respectively */
+snprintf(audio_str, codec_str_size, "mp4a.40.2");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A5");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_EAC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A6");
+} else {
+goto fail;
+}
+}
+
+return codec_str;
+
+fail:
+av_free(codec_str);
+return NULL;
+}
+
 static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
@@ -1091,7 +1149,7 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3u8_rel_name;
+char *m3u8_rel_name, *codec_str;
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1204,9 +1262,12 @@ static int create_master_playlist(AVFormatContext *s,
 bandwidth += aud_st->codecpar->bit_rate;
 bandwidth += bandwidth / 10;
 
+codec_str = get_codec_str(vid_st, aud_st);
+
 ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, 
m3u8_rel_name,
-aud_st ? vs->agroup : NULL);
+

[FFmpeg-devel] [PATCH v6 3/3] avformat/hlsenc:addition of CODECS attribute in the master playlist

2017-12-14 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/Makefile  |  2 +-
 libavformat/dashenc.c |  2 +-
 libavformat/hlsenc.c  | 65 +--
 libavformat/hlsplaylist.c |  5 +++-
 libavformat/hlsplaylist.h |  3 ++-
 libavformat/reverse.c |  1 +
 tests/ref/fate/source |  1 +
 7 files changed, 73 insertions(+), 6 deletions(-)
 create mode 100644 libavformat/reverse.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 734b703..b7e042d 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -61,7 +61,7 @@ OBJS-$(CONFIG_RTPDEC)+= rdt.o 
  \
 rtpdec_vp9.o\
 rtpdec_xiph.o
 OBJS-$(CONFIG_RTPENC_CHAIN)  += rtpenc_chain.o rtp.o
-OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o
+OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o reverse.o
 OBJS-$(CONFIG_SRTP)  += srtp.o
 
 # muxers/demuxers
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index f363418..016ada3 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -760,7 +760,7 @@ static int write_manifest(AVFormatContext *s, int final)
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
-playlist_file, NULL);
+playlist_file, NULL, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 273dd8a..ed64847 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -39,6 +39,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/random_seed.h"
+#include "libavutil/reverse.h"
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time_internal.h"
@@ -1078,6 +1079,63 @@ static int get_relative_url(const char *master_url, 
const char *media_url,
 return 0;
 }
 
+static char *get_codec_str(AVStream *vid_st, AVStream *aud_st) {
+size_t codec_str_size = 64;
+char *codec_str = av_malloc(codec_str_size);
+int video_str_len = 0;
+
+if (!codec_str)
+return NULL;
+
+if (!vid_st && !aud_st) {
+goto fail;
+}
+
+if (vid_st) {
+if (vid_st->codecpar->profile != FF_PROFILE_UNKNOWN &&
+vid_st->codecpar->level != FF_LEVEL_UNKNOWN &&
+vid_st->codecpar->codec_id == AV_CODEC_ID_H264) {
+snprintf(codec_str, codec_str_size, "avc1.%02x%02x%02x",
+ vid_st->codecpar->profile & 0xFF,
+ ff_reverse[(vid_st->codecpar->profile >> 8) & 0xFF],
+ vid_st->codecpar->level);
+} else {
+goto fail;
+}
+video_str_len = strlen(codec_str);
+}
+
+if (aud_st) {
+char *audio_str = codec_str;
+if (video_str_len) {
+codec_str[video_str_len] = ',';
+video_str_len += 1;
+audio_str += video_str_len;
+codec_str_size -= video_str_len;
+}
+if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP2) {
+snprintf(audio_str, codec_str_size, "mp4a.40.33");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP3) {
+snprintf(audio_str, codec_str_size, "mp4a.40.34");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 
5 and 29 respectively */
+snprintf(audio_str, codec_str_size, "mp4a.40.2");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A5");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_EAC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A6");
+} else {
+goto fail;
+}
+}
+
+return codec_str;
+
+fail:
+av_free(codec_str);
+return NULL;
+}
+
 static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
@@ -1088,7 +1146,7 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3u8_rel_name;
+char *m3u8_rel_name, *codec_str;
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1202,9 +1260,12 @@ static int create_master_playlist(AVFormatContext *s,
 bandwidth += aud_st->codecpar->bit_rate;
 bandwidth += bandwidth / 10;
 
+codec_str = get_codec_str(vid_st, aud_st);
+
 ff_hls_write_stream_info(vid_st, master_pb, bandwidth, m3u8_rel_name,
-aud_st ? vs->agroup : NULL);
+codec_str, 

[FFmpeg-devel] [PATCH v6 2/3] avcodec/libx264:setting profile and level in avcodec context

2017-12-14 Thread vdixit
From: Vishwanath Dixit 

---
 libavcodec/libx264.c | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 9c67c91..ac1f8bb 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -19,11 +19,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/eval.h"
 #include "libavutil/internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/reverse.h"
 #include "libavutil/stereo3d.h"
 #include "libavutil/intreadwrite.h"
 #include "avcodec.h"
@@ -454,6 +456,9 @@ static av_cold int X264_init(AVCodecContext *avctx)
 X264Context *x4 = avctx->priv_data;
 AVCPBProperties *cpb_props;
 int sw,sh;
+x264_nal_t *nal;
+uint8_t *p;
+int nnal, s, i;
 
 if (avctx->global_quality > 0)
 av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is 
recommended.\n");
@@ -799,12 +804,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
 if (!x4->enc)
 return AVERROR_EXTERNAL;
 
-if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
-x264_nal_t *nal;
-uint8_t *p;
-int nnal, s, i;
+s = x264_encoder_headers(x4->enc, , );
+// Assert for NAL start code and SPS unit type
+av_assert0((nal->p_payload[0] | nal->p_payload[1] | nal->p_payload[2]) == 
0 && nal->p_payload[3] == 1);
+av_assert0((nal->p_payload[4] & 0x1F) == 7);
+// bits 0-7 LSB for profile. bits 8-11 for constrained set flags.
+if (avctx->profile == FF_PROFILE_UNKNOWN)
+avctx->profile = ((uint32_t)nal->p_payload[5]) | 
((uint32_t)ff_reverse[nal->p_payload[6]] << 8);
+if (avctx->level == FF_LEVEL_UNKNOWN)
+avctx->level = nal->p_payload[7];
 
-s = x264_encoder_headers(x4->enc, , );
+if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
 avctx->extradata = p = av_mallocz(s + AV_INPUT_BUFFER_PADDING_SIZE);
 if (!p)
 return AVERROR(ENOMEM);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v6 1/3] avformat/hlsenc:addition of #EXT-X-MEDIA tag and AUDIO attribute

2017-12-14 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi   | 12 +
 libavformat/dashenc.c |  3 ++-
 libavformat/hlsenc.c  | 62 ---
 libavformat/hlsplaylist.c |  4 ++-
 libavformat/hlsplaylist.h |  2 +-
 5 files changed, 77 insertions(+), 6 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 3d0c7bf..93db549 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -834,6 +834,18 @@ be a video only stream with video bitrate 1000k, the 
second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+@example
+ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
+  -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
+  -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out.m3u8
+@end example
+This example creates two audio only and two video only variant streams. In
+addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
+playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams
+and they are mapped to the two video only variant streams with audio group 
names
+'aud_low' and 'aud_high'.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 5687530..f363418 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -759,7 +759,8 @@ static int write_manifest(AVFormatContext *s, int final)
 char playlist_file[64];
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
-ff_hls_write_stream_info(st, out, st->codecpar->bit_rate, 
playlist_file);
+ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
+playlist_file, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index fdf614b..273dd8a 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -144,6 +144,7 @@ typedef struct VariantStream {
 AVStream **streams;
 unsigned int nb_streams;
 int m3u8_created; /* status of media play-list creation */
+char *agroup; /* audio group name */
 char *baseurl;
 } VariantStream;
 
@@ -1081,7 +1082,7 @@ static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
 HLSContext *hls = s->priv_data;
-VariantStream *vs;
+VariantStream *vs, *temp_vs;
 AVStream *vid_st, *aud_st;
 AVIOContext *master_pb = 0;
 AVDictionary *options = NULL;
@@ -1115,6 +1116,34 @@ static int create_master_playlist(AVFormatContext *s,
 
 ff_hls_write_playlist_version(master_pb, hls->version);
 
+/* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
+for (i = 0; i < hls->nb_varstreams; i++) {
+vs = &(hls->var_streams[i]);
+
+if (vs->has_video || vs->has_subtitle || !vs->agroup)
+continue;
+
+m3u8_name_size = strlen(vs->m3u8_name) + 1;
+m3u8_rel_name = av_malloc(m3u8_name_size);
+if (!m3u8_rel_name) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size);
+ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name,
+   m3u8_rel_name, m3u8_name_size);
+if (ret < 0) {
+av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n");
+goto fail;
+}
+
+avio_printf(master_pb, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"",
+vs->agroup);
+avio_printf(master_pb, ",NAME=\"audio_0\",DEFAULT=YES,URI=\"%s\"\n",
+m3u8_rel_name);
+av_freep(_rel_name);
+}
+
 /* For variant streams with video add #EXT-X-STREAM-INF tag with 
attributes*/
 for (i = 0; i < hls->nb_varstreams; i++) {
 vs = &(hls->var_streams[i]);
@@ -1147,6 +1176,25 @@ static int create_master_playlist(AVFormatContext *s,
 continue;
 }
 
+/**
+ * Traverse through the list of audio only rendition streams and find
+ * the rendition which has highest bitrate in the same audio group
+ */
+if (vs->agroup) {
+for (j = 0; j < hls->nb_varstreams; j++) {
+temp_vs = &(hls->var_streams[j]);
+if (!temp_vs->has_video && !temp_vs->has_subtitle &&
+temp_vs->agroup &&
+!strcmp(temp_vs->agroup, vs->agroup)) {
+if (!aud_st)
+aud_st = temp_vs->streams[0];
+if 

[FFmpeg-devel] [PATCH 3/3] avformat/hlsenc: creation of variant streams in subdirectories

2017-12-08 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  | 33 -
 libavformat/hlsenc.c | 68 +---
 2 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index f53cc10..1a22892 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -587,6 +587,20 @@ This example will produce the playlists segment file sets:
 @file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
 @file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
 
+The string "%v" may be present in the filename or in the last directory name
+containing the file. If the string is present in the directory name, then
+sub-directories are created after expanding the directory name pattern. This
+enables creation of segments corresponding to different variant streams in
+subdirectories.
+@example
+ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  -hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8
+@end example
+This example will produce the playlists segment file sets:
+@file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. 
and
+@file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc.
+
 @item use_localtime
 Use strftime() on @var{filename} to expand the segment filename with localtime.
 The segment number is also available in this mode, but to use it, you need to 
specify second_level_segment_index
@@ -715,6 +729,11 @@ set filename to the fragment files header file, default 
filename is @file{init.m
 When @code{var_stream_map} is set with two or more variant streams, the
 @var{filename} pattern must contain the string "%v", this string specifies
 the position of variant stream index in the generated init file names.
+The string "%v" may be present in the filename or in the last directory name
+containing the file. If the string is present in the directory name, then
+sub-directories are created after expanding the directory name pattern. This
+enables creation of init files corresponding to different variant streams in
+subdirectories.
 
 @item hls_flags @var{flags}
 Possible values:
@@ -831,7 +850,11 @@ Allowed values are 0 to 9 (limited just based on practical 
usage).
 
 When there are two or more variant streams, the output filename pattern must
 contain the string "%v", this string specifies the position of variant stream
-index in the output media playlist filenames.
+index in the output media playlist filenames. The string "%v" may be present in
+the filename or in the last directory name containing the file. If the string 
is
+present in the directory name, then sub-directories are created after expanding
+the directory name pattern. This enables creation of variant streams in
+subdirectories.
 
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
@@ -853,6 +876,14 @@ be a video only stream with video bitrate 1000k, the 
second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
+@example
+ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  http://example.com/live/vs_%v/out.m3u8
+@end example
+This example creates the variant streams in subdirectories. Here, the first
+media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and
+the second one at @file{http://example.com/live/vs_1/out.m3u8}.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 27ea690..541ce88 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1479,7 +1479,8 @@ static int append_postfix(char *name, int name_buf_len, 
int i)
 
 static int validate_name(int nb_vs, const char *fn)
 {
-const char *filename;
+const char *filename, *subdir_name;
+char *fn_dup = NULL;
 int ret = 0;
 
 if (!fn) {
@@ -1487,22 +1488,38 @@ static int validate_name(int nb_vs, const char *fn)
 goto fail;
 }
 
+fn_dup = av_strdup(fn);
+if (!fn_dup) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+
 filename = av_basename(fn);
+subdir_name = av_dirname(fn_dup);
 
-if (nb_vs > 1 && !av_stristr(filename, "%v")) {
+if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, 
"%v")) {
 av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, 
%%v is expected in the filename %s\n",
 fn);
 ret = AVERROR(EINVAL);
 goto fail;
 }
 
+if (av_stristr(filename, "%v") && av_stristr(subdir_name, "%v")) {
+av_log(NULL, AV_LOG_ERROR, "%%v is 

[FFmpeg-devel] [PATCH 1/3] avformat/hlsenc: revamped master playlist url creation logic

2017-12-08 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/hlsenc.c | 34 ++
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 7dc8f42..fa44760 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1612,28 +1612,30 @@ static int update_variant_stream_info(AVFormatContext 
*s) {
 
 static int update_master_pl_info(AVFormatContext *s) {
 HLSContext *hls = s->priv_data;
-int m3u8_name_size, ret;
-char *p;
+const char *dir;
+char *fn;
+int ret = 0;
 
-m3u8_name_size = strlen(s->filename) + strlen(hls->master_pl_name) + 1;
-hls->master_m3u8_url = av_malloc(m3u8_name_size);
-if (!hls->master_m3u8_url) {
+fn = av_strdup(s->filename);
+if (!fn) {
 ret = AVERROR(ENOMEM);
-return ret;
+goto fail;
 }
 
-av_strlcpy(hls->master_m3u8_url, s->filename, m3u8_name_size);
-p = strrchr(hls->master_m3u8_url, '/') ?
-strrchr(hls->master_m3u8_url, '/') :
-strrchr(hls->master_m3u8_url, '\\');
-if (p) {
-*(p + 1) = '\0';
-av_strlcat(hls->master_m3u8_url, hls->master_pl_name, m3u8_name_size);
-} else {
-av_strlcpy(hls->master_m3u8_url, hls->master_pl_name, m3u8_name_size);
+dir = av_dirname(fn);
+if (dir && strcmp(dir, "."))
+hls->master_m3u8_url = av_append_path_component(dir, 
hls->master_pl_name);
+else
+hls->master_m3u8_url = av_strdup(hls->master_pl_name);
+
+if (!hls->master_m3u8_url) {
+ret = AVERROR(ENOMEM);
+goto fail;
 }
 
-return 0;
+fail:
+av_freep();
+return ret;
 }
 
 static int hls_write_header(AVFormatContext *s)
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/3] avformat/hlsenc: configurable variant stream index position in filenames

2017-12-08 Thread vdixit
From: Vishwanath Dixit 

---
 doc/muxers.texi  |  29 --
 libavformat/hlsenc.c | 154 ++-
 2 files changed, 126 insertions(+), 57 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 3d0c7bf..f53cc10 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -575,6 +575,17 @@ Should a relative path be specified, the path of the 
created segment
 files will be relative to the current working directory.
 When use_localtime_mkdir is set, the whole expanded value of @var{filename} 
will be written into the m3u8 segment list.
 
+When @code{var_stream_map} is set with two or more variant streams, the
+@var{filename} pattern must contain the string "%v", this string specifies
+the position of variant stream index in the generated segment file names.
+@example
+ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
+  -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
+  -hls_segment_filename 'file_%v_%03d.ts' out_%v.m3u8
+@end example
+This example will produce the playlists segment file sets:
+@file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and
+@file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc.
 
 @item use_localtime
 Use strftime() on @var{filename} to expand the segment filename with localtime.
@@ -701,6 +712,10 @@ the fmp4 files is used in hls after version 7.
 @item hls_fmp4_init_filename @var{filename}
 set filename to the fragment files header file, default filename is 
@file{init.mp4}.
 
+When @code{var_stream_map} is set with two or more variant streams, the
+@var{filename} pattern must contain the string "%v", this string specifies
+the position of variant stream index in the generated init file names.
+
 @item hls_flags @var{flags}
 Possible values:
 
@@ -814,26 +829,30 @@ Expected string format is like this "a:0,v:0 a:1,v:1 
". Here a:, v:, s: are
 the keys to specify audio, video and subtitle streams respectively.
 Allowed values are 0 to 9 (limited just based on practical usage).
 
+When there are two or more variant streams, the output filename pattern must
+contain the string "%v", this string specifies the position of variant stream
+index in the output media playlist filenames.
+
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \
   -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" 
\
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates two hls variant streams. The first variant stream will
 contain video stream of bitrate 1000k and audio stream of bitrate 64k and the
 second variant stream will contain video stream of bitrate 256k and audio
-stream of bitrate 32k. Here, two media playlist with file names out_1.m3u8 and
-out_2.m3u8 will be created.
+stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and
+out_1.m3u8 will be created.
 @example
 ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \
   -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \
-  http://example.com/live/out.m3u8
+  http://example.com/live/out_%v.m3u8
 @end example
 This example creates three hls variant streams. The first variant stream will
 be a video only stream with video bitrate 1000k, the second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
-out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index fa44760..27ea690 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1458,7 +1458,7 @@ static const char * 
get_default_pattern_localtime_fmt(AVFormatContext *s)
 return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, 
"%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts";
 }
 
-static int format_name(char *name, int name_buf_len, int i)
+static int append_postfix(char *name, int name_buf_len, int i)
 {
 char *p;
 char extension[10] = {'\0'};
@@ -1477,6 +1477,53 @@ static int format_name(char *name, int name_buf_len, int 
i)
 return 0;
 }
 
+static int validate_name(int nb_vs, const char *fn)
+{
+const char *filename;
+int ret = 0;
+
+if (!fn) {
+ret = AVERROR(EINVAL);
+goto fail;
+}
+
+filename = av_basename(fn);
+
+if (nb_vs > 1 && !av_stristr(filename, "%v")) {
+av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, 
%%v is expected in the filename %s\n",
+fn);
+ret = AVERROR(EINVAL);
+goto fail;
+}
+
+fail:
+return ret;
+}
+
+static int format_name(char *buf, int buf_len, int index)
+{
+char *orig_buf_dup = NULL;
+int ret = 

[FFmpeg-devel] [PATCH v5 3/3] avformat/hlsenc:addition of CODECS attribute in the master playlist

2017-11-30 Thread vdixit
From: Vishwanath Dixit 

---
 libavformat/Makefile  |  2 +-
 libavformat/dashenc.c |  2 +-
 libavformat/hlsenc.c  | 65 +--
 libavformat/hlsplaylist.c |  5 +++-
 libavformat/hlsplaylist.h |  3 ++-
 libavformat/reverse.c |  1 +
 tests/ref/fate/source |  1 +
 7 files changed, 73 insertions(+), 6 deletions(-)
 create mode 100644 libavformat/reverse.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 4bffdf2..2bdb777 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -61,7 +61,7 @@ OBJS-$(CONFIG_RTPDEC)+= rdt.o 
  \
 rtpdec_vp9.o\
 rtpdec_xiph.o
 OBJS-$(CONFIG_RTPENC_CHAIN)  += rtpenc_chain.o rtp.o
-OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o
+OBJS-$(CONFIG_SHARED)+= log2_tab.o golomb_tab.o reverse.o
 OBJS-$(CONFIG_SRTP)  += srtp.o
 
 # muxers/demuxers
diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c
index 90cd2d0..e0b1679 100644
--- a/libavformat/dashenc.c
+++ b/libavformat/dashenc.c
@@ -754,7 +754,7 @@ static int write_manifest(AVFormatContext *s, int final)
 AVStream *st = s->streams[i];
 get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, 
i);
 ff_hls_write_stream_info(st, out, st->codecpar->bit_rate,
-playlist_file, NULL);
+playlist_file, NULL, NULL);
 }
 avio_close(out);
 if (use_rename)
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 8d4b333..0702124 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -39,6 +39,7 @@
 #include "libavutil/avstring.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/random_seed.h"
+#include "libavutil/reverse.h"
 #include "libavutil/opt.h"
 #include "libavutil/log.h"
 #include "libavutil/time_internal.h"
@@ -1074,6 +1075,63 @@ static int get_relative_url(const char *master_url, 
const char *media_url,
 return 0;
 }
 
+static char *get_codec_str(AVStream *vid_st, AVStream *aud_st) {
+size_t codec_str_size = 64;
+char *codec_str = av_malloc(codec_str_size);
+int video_str_len = 0;
+
+if (!codec_str)
+return NULL;
+
+if (!vid_st && !aud_st) {
+goto fail;
+}
+
+if (vid_st) {
+if (vid_st->codecpar->profile != FF_PROFILE_UNKNOWN &&
+vid_st->codecpar->level != FF_LEVEL_UNKNOWN &&
+vid_st->codecpar->codec_id == AV_CODEC_ID_H264) {
+snprintf(codec_str, codec_str_size, "avc1.%02x%02x%02x",
+ vid_st->codecpar->profile & 0xFF,
+ ff_reverse[(vid_st->codecpar->profile >> 8) & 0xFF],
+ vid_st->codecpar->level);
+} else {
+goto fail;
+}
+video_str_len = strlen(codec_str);
+}
+
+if (aud_st) {
+char *audio_str = codec_str;
+if (video_str_len) {
+codec_str[video_str_len] = ',';
+video_str_len += 1;
+audio_str += video_str_len;
+codec_str_size -= video_str_len;
+}
+if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP2) {
+snprintf(audio_str, codec_str_size, "mp4a.40.33");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP3) {
+snprintf(audio_str, codec_str_size, "mp4a.40.34");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 
5 and 29 respectively */
+snprintf(audio_str, codec_str_size, "mp4a.40.2");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A5");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_EAC3) {
+snprintf(audio_str, codec_str_size, "mp4a.A6");
+} else {
+goto fail;
+}
+}
+
+return codec_str;
+
+fail:
+av_free(codec_str);
+return NULL;
+}
+
 static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
@@ -1084,7 +1142,7 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3u8_rel_name;
+char *m3u8_rel_name, *codec_str;
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1198,9 +1256,12 @@ static int create_master_playlist(AVFormatContext *s,
 bandwidth += aud_st->codecpar->bit_rate;
 bandwidth += bandwidth / 10;
 
+codec_str = get_codec_str(vid_st, aud_st);
+
 ff_hls_write_stream_info(vid_st, master_pb, bandwidth, m3u8_rel_name,
-aud_st ? vs->agroup : NULL);
+codec_str, 

[FFmpeg-devel] [PATCH v5 2/3] avcodec/libx264:setting profile and level in avcodec context

2017-11-30 Thread vdixit
From: Vishwanath Dixit 

---
 libavcodec/libx264.c | 18 +-
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 9c67c91..545826c 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -19,11 +19,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/eval.h"
 #include "libavutil/internal.h"
 #include "libavutil/opt.h"
 #include "libavutil/mem.h"
 #include "libavutil/pixdesc.h"
+#include "libavutil/reverse.h"
 #include "libavutil/stereo3d.h"
 #include "libavutil/intreadwrite.h"
 #include "avcodec.h"
@@ -454,6 +456,9 @@ static av_cold int X264_init(AVCodecContext *avctx)
 X264Context *x4 = avctx->priv_data;
 AVCPBProperties *cpb_props;
 int sw,sh;
+x264_nal_t *nal;
+uint8_t *p;
+int nnal, s, i;
 
 if (avctx->global_quality > 0)
 av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is 
recommended.\n");
@@ -799,12 +804,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
 if (!x4->enc)
 return AVERROR_EXTERNAL;
 
-if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
-x264_nal_t *nal;
-uint8_t *p;
-int nnal, s, i;
+s = x264_encoder_headers(x4->enc, , );
+// Assert for NAL start code and SPS unit type
+av_assert0((nal->p_payload[0] | nal->p_payload[1] | nal->p_payload[2]) == 
0 && nal->p_payload[3] == 1);
+av_assert0((nal->p_payload[4] & 0x1F) == 7);
+// bits 0-7 LSB for profile. bits 8-11 for constrained set flags.
+avctx->profile = ((uint32_t)nal->p_payload[5]) | 
((uint32_t)ff_reverse[nal->p_payload[6]] << 8);
+avctx->level = nal->p_payload[7];
 
-s = x264_encoder_headers(x4->enc, , );
+if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
 avctx->extradata = p = av_mallocz(s + AV_INPUT_BUFFER_PADDING_SIZE);
 if (!p)
 return AVERROR(ENOMEM);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 2/3] avcodec/libx264:setting profile and level in avcodec context

2017-11-22 Thread vdixit
From: Vishwanath Dixit 

Signed-off-by: Karthick J 
---
 libavcodec/libx264.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 9c67c91..eeafe31 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -454,6 +454,9 @@ static av_cold int X264_init(AVCodecContext *avctx)
 X264Context *x4 = avctx->priv_data;
 AVCPBProperties *cpb_props;
 int sw,sh;
+x264_nal_t *nal;
+uint8_t *p;
+int nnal, s, i;
 
 if (avctx->global_quality > 0)
 av_log(avctx, AV_LOG_WARNING, "-qscale is ignored, -crf is 
recommended.\n");
@@ -799,12 +802,13 @@ FF_ENABLE_DEPRECATION_WARNINGS
 if (!x4->enc)
 return AVERROR_EXTERNAL;
 
-if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
-x264_nal_t *nal;
-uint8_t *p;
-int nnal, s, i;
+s = x264_encoder_headers(x4->enc, , );
+if (avctx->profile == FF_PROFILE_UNKNOWN)
+avctx->profile = nal->p_payload[5];
+if (avctx->level == FF_LEVEL_UNKNOWN)
+avctx->level = nal->p_payload[7];
 
-s = x264_encoder_headers(x4->enc, , );
+if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
 avctx->extradata = p = av_mallocz(s + AV_INPUT_BUFFER_PADDING_SIZE);
 if (!p)
 return AVERROR(ENOMEM);
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 3/3] avformat/hlsenc:addition of CODECS attribute in the master playlist

2017-11-22 Thread vdixit
From: Vishwanath Dixit 

Signed-off-by: Karthick J 
---
 libavformat/hlsenc.c | 67 +++-
 1 file changed, 66 insertions(+), 1 deletion(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 9fed6a3..32246c4 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1065,6 +1065,52 @@ static int get_relative_url(const char *master_url, 
const char *media_url,
 return 0;
 }
 
+static void get_codec_str(AVStream *vid_st, AVStream *aud_st, char *vcodec,
+  char *acodec, int vcodec_len, int acodec_len) {
+if (vcodec_len > 0)
+vcodec[0] = '\0';
+else
+return;
+
+if (acodec_len > 0)
+acodec[0] = '\0';
+else
+return;
+
+if (!vid_st && !aud_st) {
+av_log(NULL, AV_LOG_WARNING, "Atleast one stream shoud be valid\n");
+return;
+}
+
+if (vid_st && vid_st->codecpar->profile != FF_PROFILE_UNKNOWN &&
+vid_st->codecpar->level != FF_LEVEL_UNKNOWN &&
+vid_st->codecpar->codec_id == AV_CODEC_ID_H264) {
+snprintf(vcodec, vcodec_len, "avc1.%02x00%02x",
+vid_st->codecpar->profile, vid_st->codecpar->level);
+}
+
+if (aud_st) {
+if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP2) {
+snprintf(acodec, acodec_len, "mp4a.40.33");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_MP3) {
+snprintf(acodec, acodec_len, "mp4a.40.34");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+/* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 
5 and 29 respectively */
+snprintf(acodec, acodec_len, "mp4a.40.2");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_AC3) {
+snprintf(acodec, acodec_len, "mp4a.A5");
+} else if (aud_st->codecpar->codec_id == AV_CODEC_ID_EAC3) {
+snprintf(acodec, acodec_len, "mp4a.A6");
+}
+}
+
+// either provide codec string for both active streams or for none
+if (vid_st && aud_st && (!strlen(vcodec) || !strlen(acodec))) {
+acodec[0] = vcodec[0] = '\0';
+av_log(NULL, AV_LOG_INFO, "Codec string not available for audio or 
video stream\n");
+}
+}
+
 static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
@@ -1075,7 +1121,7 @@ static int create_master_playlist(AVFormatContext *s,
 AVDictionary *options = NULL;
 unsigned int i, j;
 int m3u8_name_size, ret, bandwidth;
-char *m3U8_rel_name;
+char *m3U8_rel_name, vcodec[32], acodec[32];
 
 input_vs->m3u8_created = 1;
 if (!hls->master_m3u8_created) {
@@ -1203,6 +1249,25 @@ static int create_master_playlist(AVFormatContext *s,
 avio_printf(master_pb, ",RESOLUTION=%dx%d", 
vid_st->codecpar->width,
 vid_st->codecpar->height);
 
+get_codec_str(vid_st, aud_st, vcodec, acodec, sizeof(vcodec),
+  sizeof(acodec));
+
+if (strlen(vcodec) || strlen(acodec))
+avio_printf(master_pb, ",CODECS=\"");
+
+if (strlen(vcodec)) {
+avio_printf(master_pb, "%s", vcodec);
+
+if (strlen(acodec))
+avio_printf(master_pb, ",");
+}
+
+if (strlen(acodec))
+avio_printf(master_pb, "%s", acodec);
+
+if (strlen(vcodec) || strlen(acodec))
+avio_printf(master_pb, "\"");
+
 if (vs->agroup && aud_st)
 avio_printf(master_pb, ",AUDIO=\"group_%s\"", vs->agroup);
 
-- 
1.9.1

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH 1/3] avformat/hlsenc:addition of #EXT-X-MEDIA tag and AUDIO attribute

2017-11-22 Thread vdixit
From: Vishwanath Dixit 

Signed-off-by: Karthick J 
---
 doc/muxers.texi  | 12 ++
 libavformat/hlsenc.c | 63 ++--
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/doc/muxers.texi b/doc/muxers.texi
index 0bb8ad2..60b2eb4 100644
--- a/doc/muxers.texi
+++ b/doc/muxers.texi
@@ -827,6 +827,18 @@ be a video only stream with video bitrate 1000k, the 
second variant stream will
 be an audio only stream with bitrate 64k and the third variant stream will be a
 video only stream with bitrate 256k. Here, three media playlist with file names
 out_1.m3u8, out_2.m3u8 and out_3.m3u8 will be created.
+@example
+ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k  \
+  -map 0:a -map 0:a -map 0:v -map 0:v -f hls \
+  -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low 
v:1,agroup:aud_high" \
+  -master_pl_name master.m3u8 \
+  http://example.com/live/out.m3u8
+@end example
+This example creates two audio only and two video only variant streams. In
+addition to the #EXT-X-STREAM-INF tag for each variant stream in the master
+playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams
+and they are mapped to the two video only variant streams with audio group 
names
+'aud_low' and 'aud_high'.
 
 By default, a single hls variant containing all the encoded streams is created.
 
diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 3c47ced..9fed6a3 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -146,6 +146,7 @@ typedef struct VariantStream {
 AVStream **streams;
 unsigned int nb_streams;
 int m3u8_created; /* status of media play-list creation */
+char *agroup; /* audio group name */
 char *baseurl;
 } VariantStream;
 
@@ -1068,7 +1069,7 @@ static int create_master_playlist(AVFormatContext *s,
   VariantStream * const input_vs)
 {
 HLSContext *hls = s->priv_data;
-VariantStream *vs;
+VariantStream *vs, *temp_vs;
 AVStream *vid_st, *aud_st;
 AVIOContext *master_pb = 0;
 AVDictionary *options = NULL;
@@ -1104,6 +1105,34 @@ static int create_master_playlist(AVFormatContext *s,
 avio_printf(master_pb, "#EXTM3U\n");
 avio_printf(master_pb, "#EXT-X-VERSION:%d\n", hls->version);
 
+/* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/
+for (i = 0; i < hls->nb_varstreams; i++) {
+vs = &(hls->var_streams[i]);
+
+if (vs->has_video || vs->has_subtitle || !vs->agroup)
+continue;
+
+m3u8_name_size = strlen(vs->m3u8_name) + 1;
+m3U8_rel_name = av_malloc(m3u8_name_size);
+if (!m3U8_rel_name) {
+ret = AVERROR(ENOMEM);
+goto fail;
+}
+av_strlcpy(m3U8_rel_name, vs->m3u8_name, m3u8_name_size);
+ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name,
+   m3U8_rel_name, m3u8_name_size);
+if (ret < 0) {
+av_log(NULL, AV_LOG_ERROR, "Unable to find relative URL\n");
+goto fail;
+}
+
+avio_printf(master_pb, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"",
+vs->agroup);
+avio_printf(master_pb, ",NAME=\"audio_0\",DEFAULT=YES,URI=\"%s\"\n",
+m3U8_rel_name);
+av_freep(_rel_name);
+}
+
 /* For variant streams with video add #EXT-X-STREAM-INF tag with 
attributes*/
 for (i = 0; i < hls->nb_varstreams; i++) {
 vs = &(hls->var_streams[i]);
@@ -1136,6 +1165,25 @@ static int create_master_playlist(AVFormatContext *s,
 continue;
 }
 
+/**
+ * Traverse through the list of audio only rendition streams and find
+ * the rendition which has highest bitrate in the same audio group
+ */
+if (vs->agroup) {
+for (j = 0; j < hls->nb_varstreams; j++) {
+temp_vs = &(hls->var_streams[j]);
+if (!temp_vs->has_video && !temp_vs->has_subtitle &&
+temp_vs->agroup &&
+!strcmp(temp_vs->agroup, vs->agroup)) {
+if (!aud_st)
+aud_st = temp_vs->streams[0];
+if (temp_vs->streams[0]->codecpar->bit_rate >
+aud_st->codecpar->bit_rate)
+aud_st = temp_vs->streams[0];
+}
+}
+}
+
 bandwidth = 0;
 if (vid_st)
 bandwidth += vid_st->codecpar->bit_rate;
@@ -1154,6 +1202,10 @@ static int create_master_playlist(AVFormatContext *s,
 if (vid_st && vid_st->codecpar->width > 0 && vid_st->codecpar->height 
> 0)
 avio_printf(master_pb, ",RESOLUTION=%dx%d", 
vid_st->codecpar->width,
 vid_st->codecpar->height);
+
+if (vs->agroup && aud_st)
+avio_printf(master_pb,