diff --git a/doc/muxers.texi b/doc/muxers.texi index b5a27d1844..df8763b249 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -498,8 +498,8 @@ each line matching the format: @end example @var{segment_filename} is the name of the output file generated by the -muxer according to the provided pattern, and should not contain the -"," character for simplifying parsing operations. +muxer according to the provided pattern. CSV escaping (according to +RFC4180) is applied if required. @var{segment_start_time} and @var{segment_end_time} specify the segment start and end time expressed in seconds. diff --git a/libavformat/segment.c b/libavformat/segment.c index 1dda310b3f..ecd4ae8694 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -67,6 +67,30 @@ typedef struct { double start_time, end_time; } SegmentContext; +static void print_csv_escaped_str(AVIOContext *ctx, const char *str) +{ + const char *p; + int quote = 0; + + /* check if input needs quoting */ + for (p = str; *p; p++) + if (strchr("\",\n\r", *p)) { + quote = 1; + break; + } + + if (quote) + avio_w8(ctx, '"'); + + for (p = str; *p; p++) { + if (*p == '"') + avio_w8(ctx, '"'); + avio_w8(ctx, *p); + } + if (quote) + avio_w8(ctx, '"'); +} + static int segment_start(AVFormatContext *s) { SegmentContext *seg = s->priv_data; @@ -169,7 +193,8 @@ static int segment_end(AVFormatContext *s) if (seg->list_type == LIST_TYPE_FLAT) { avio_printf(seg->list_pb, "%s\n", oc->filename); } else if (seg->list_type == LIST_TYPE_EXT) { - avio_printf(seg->list_pb, "%s,%f,%f\n", oc->filename, seg->start_time, seg->end_time); + print_csv_escaped_str(seg->list_pb, oc->filename); + avio_printf(seg->list_pb, ",%f,%f\n", seg->start_time, seg->end_time); } else if (seg->list_type == LIST_TYPE_M3U8) { avio_printf(seg->list_pb, "#EXTINF:%f,\n%s\n", seg->end_time - seg->start_time, oc->filename);