This function can be useful for various other subtitles formats.tags/n1.1
@@ -71,52 +71,6 @@ static int64_t get_pts(const char **buf, int *duration, | |||||
return AV_NOPTS_VALUE; | return AV_NOPTS_VALUE; | ||||
} | } | ||||
static inline int is_eol(char c) | |||||
{ | |||||
return c == '\r' || c == '\n'; | |||||
} | |||||
static void read_chunk(AVIOContext *pb, AVBPrint *buf) | |||||
{ | |||||
char eol_buf[5]; | |||||
int n = 0, i = 0, nb_eol = 0; | |||||
av_bprint_clear(buf); | |||||
for (;;) { | |||||
char c = avio_r8(pb); | |||||
if (!c) | |||||
break; | |||||
/* ignore all initial line breaks */ | |||||
if (n == 0 && is_eol(c)) | |||||
continue; | |||||
/* line break buffering: we don't want to add the trailing \r\n */ | |||||
if (is_eol(c)) { | |||||
nb_eol += c == '\n'; | |||||
if (nb_eol == 2) | |||||
break; | |||||
eol_buf[i++] = c; | |||||
if (i == sizeof(eol_buf) - 1) | |||||
break; | |||||
continue; | |||||
} | |||||
/* only one line break followed by data: we flush the line breaks | |||||
* buffer */ | |||||
if (i) { | |||||
eol_buf[i] = 0; | |||||
av_bprintf(buf, "%s", eol_buf); | |||||
i = nb_eol = 0; | |||||
} | |||||
av_bprint_chars(buf, c, 1); | |||||
n++; | |||||
} | |||||
} | |||||
static int srt_read_header(AVFormatContext *s) | static int srt_read_header(AVFormatContext *s) | ||||
{ | { | ||||
SRTContext *srt = s->priv_data; | SRTContext *srt = s->priv_data; | ||||
@@ -133,7 +87,7 @@ static int srt_read_header(AVFormatContext *s) | |||||
av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); | av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); | ||||
while (!url_feof(s->pb)) { | while (!url_feof(s->pb)) { | ||||
read_chunk(s->pb, &buf); | |||||
ff_subtitles_read_chunk(s->pb, &buf); | |||||
if (buf.len) { | if (buf.len) { | ||||
int64_t pos = avio_tell(s->pb); | int64_t pos = avio_tell(s->pb); | ||||
@@ -192,3 +192,49 @@ const char *ff_smil_get_attr_ptr(const char *s, const char *attr) | |||||
} | } | ||||
return NULL; | return NULL; | ||||
} | } | ||||
static inline int is_eol(char c) | |||||
{ | |||||
return c == '\r' || c == '\n'; | |||||
} | |||||
void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf) | |||||
{ | |||||
char eol_buf[5]; | |||||
int n = 0, i = 0, nb_eol = 0; | |||||
av_bprint_clear(buf); | |||||
for (;;) { | |||||
char c = avio_r8(pb); | |||||
if (!c) | |||||
break; | |||||
/* ignore all initial line breaks */ | |||||
if (n == 0 && is_eol(c)) | |||||
continue; | |||||
/* line break buffering: we don't want to add the trailing \r\n */ | |||||
if (is_eol(c)) { | |||||
nb_eol += c == '\n'; | |||||
if (nb_eol == 2) | |||||
break; | |||||
eol_buf[i++] = c; | |||||
if (i == sizeof(eol_buf) - 1) | |||||
break; | |||||
continue; | |||||
} | |||||
/* only one line break followed by data: we flush the line breaks | |||||
* buffer */ | |||||
if (i) { | |||||
eol_buf[i] = 0; | |||||
av_bprintf(buf, "%s", eol_buf); | |||||
i = nb_eol = 0; | |||||
} | |||||
av_bprint_chars(buf, c, 1); | |||||
n++; | |||||
} | |||||
} |
@@ -81,4 +81,19 @@ int ff_smil_extract_next_chunk(AVIOContext *pb, AVBPrint *buf, char *c); | |||||
*/ | */ | ||||
const char *ff_smil_get_attr_ptr(const char *s, const char *attr); | const char *ff_smil_get_attr_ptr(const char *s, const char *attr); | ||||
/** | |||||
* @brief Read a subtitles chunk. | |||||
* | |||||
* A chunk is defined by a multiline "event", ending with a second line break. | |||||
* The trailing line breaks are trimmed. CLRF are supported. | |||||
* Example: "foo\r\nbar\r\n\r\nnext" will print "foo\r\nbar" into buf, and pb | |||||
* will focus on the 'n' of the "next" string. | |||||
* | |||||
* @param pb I/O context | |||||
* @param buf an initialized buf where the chunk is written | |||||
* | |||||
* @note buf is cleared before writing into it. | |||||
*/ | |||||
void ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf); | |||||
#endif /* AVFORMAT_SUBTITLES_H */ | #endif /* AVFORMAT_SUBTITLES_H */ |