static int srt_read_header(AVFormatContext *s) { SRTContext *srt = s->priv_data; AVBPrint buf; AVStream *st = avformat_new_stream(s, NULL); int res = 0; FFTextReader tr; ff_text_init_avio(s, &tr, s->pb); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SUBRIP; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!ff_text_eof(&tr)) { ff_subtitles_read_text_chunk(&tr, &buf); if (buf.len) { int64_t pos = ff_text_pos(&tr); int64_t pts; int duration; const char *ptr = buf.str; int32_t x1 = -1, y1 = -1, x2 = -1, y2 = -1; AVPacket *sub; pts = get_pts(&ptr, &duration, &x1, &y1, &x2, &y2); if (pts != AV_NOPTS_VALUE) { int len = buf.len - (ptr - buf.str); if (len <= 0) continue; sub = ff_subtitles_queue_insert(&srt->q, ptr, len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pos = pos; sub->pts = pts; sub->duration = duration; if (x1 != -1) { uint8_t *p = av_packet_new_side_data(sub, AV_PKT_DATA_SUBTITLE_POSITION, 16); if (p) { AV_WL32(p, x1); AV_WL32(p + 4, y1); AV_WL32(p + 8, x2); AV_WL32(p + 12, y2); } } } } } ff_subtitles_queue_finalize(&srt->q); end: av_bprint_finalize(&buf, NULL); return res; }
static int sami_read_header(AVFormatContext *s) { SAMIContext *sami = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); AVBPrint buf, hdr_buf; char c = 0; int res = 0, got_first_sync_point = 0; FFTextReader tr; ff_text_init_avio(&tr, s->pb); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SAMI; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&hdr_buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!ff_text_eof(&tr)) { AVPacket *sub; const int64_t pos = ff_text_pos(&tr) - (c != 0); int is_sync, n = ff_smil_extract_next_text_chunk(&tr, &buf, &c); if (n == 0) break; is_sync = !av_strncasecmp(buf.str, "<SYNC", 5); if (is_sync) got_first_sync_point = 1; if (!got_first_sync_point) { av_bprintf(&hdr_buf, "%s", buf.str); } else { sub = ff_subtitles_queue_insert(&sami->q, buf.str, buf.len, !is_sync); if (!sub) { res = AVERROR(ENOMEM); goto end; } if (is_sync) { const char *p = ff_smil_get_attr_ptr(buf.str, "Start"); sub->pos = pos; sub->pts = p ? strtol(p, NULL, 10) : 0; sub->duration = -1; } } av_bprint_clear(&buf); } res = avpriv_bprint_to_extradata(st->codec, &hdr_buf); if (res < 0) goto end; ff_subtitles_queue_finalize(&sami->q); end: av_bprint_finalize(&buf, NULL); return res; }
static int mpsub_read_header(AVFormatContext *s) { MPSubContext *mpsub = s->priv_data; AVStream *st; AVBPrint buf; AVRational pts_info = (AVRational){ 100, 1 }; // ts based by default int res = 0; float multiplier = 100.0; float current_pts = 0; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!url_feof(s->pb)) { char line[1024]; float start, duration; int fps, len = ff_get_line(s->pb, line, sizeof(line)); if (!len) break; line[strcspn(line, "\r\n")] = 0; if (sscanf(line, "FORMAT=%d", &fps) == 1 && fps > 3 && fps < 100) { /* frame based timing */ pts_info = (AVRational){ fps, 1 }; multiplier = 1.0; } else if (sscanf(line, "%f %f", &start, &duration) == 2) { AVPacket *sub; const int64_t pos = avio_tell(s->pb); ff_subtitles_read_chunk(s->pb, &buf); if (buf.len) { sub = ff_subtitles_queue_insert(&mpsub->q, buf.str, buf.len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pts = (int64_t)(current_pts + start*multiplier); sub->duration = (int)(duration * multiplier); current_pts += (start + duration) * multiplier; sub->pos = pos; } } } st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_TEXT; ff_subtitles_queue_finalize(&mpsub->q); end: av_bprint_finalize(&buf, NULL); return res; }
static int ass_read_header(AVFormatContext *s) { ASSContext *ass = s->priv_data; AVBPrint header, line, rline; int res = 0; AVStream *st; FFTextReader tr; ff_text_init_avio(s, &tr, s->pb); st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_ASS; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&rline, 0, AV_BPRINT_SIZE_UNLIMITED); for (;;) { int64_t pos = get_line(&line, &tr); int64_t ts_start = AV_NOPTS_VALUE; int duration = -1; AVPacket *sub; if (!line.str[0]) // EOF break; if (read_dialogue(ass, &rline, line.str, &ts_start, &duration) < 0) { av_bprintf(&header, "%s", line.str); continue; } sub = ff_subtitles_queue_insert(&ass->q, rline.str, rline.len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pos = pos; sub->pts = ts_start; sub->duration = duration; } res = avpriv_bprint_to_extradata(st->codec, &header); if (res < 0) goto end; ff_subtitles_queue_finalize(&ass->q); end: av_bprint_finalize(&header, NULL); av_bprint_finalize(&line, NULL); av_bprint_finalize(&rline, NULL); return res; }
static int microdvd_read_header(AVFormatContext *s) { AVRational pts_info = (AVRational){ 2997, 125 }; /* default: 23.976 fps */ MicroDVDContext *microdvd = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); int i = 0; char line[MAX_LINESIZE]; if (!st) return AVERROR(ENOMEM); while (!url_feof(s->pb)) { AVPacket *sub; int64_t pos = avio_tell(s->pb); int len = ff_get_line(s->pb, line, sizeof(line)); if (!len) break; if (i < 3) { int frame; double fps; char c; i++; if ((sscanf(line, "{%d}{}%6lf", &frame, &fps) == 2 || sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2) && frame <= 1 && fps > 3 && fps < 100) pts_info = av_d2q(fps, 100000); if (!st->codec->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) { st->codec->extradata = av_strdup(line + 11); if (!st->codec->extradata) return AVERROR(ENOMEM); st->codec->extradata_size = strlen(st->codec->extradata) + 1; continue; } } sub = ff_subtitles_queue_insert(µdvd->q, line, len, 0); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; sub->pts = get_pts(sub->data); sub->duration = get_duration(sub->data); } ff_subtitles_queue_finalize(µdvd->q); avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_MICRODVD; return 0; }
static int subviewer1_read_header(AVFormatContext *s) { int delay = 0; AVPacket *sub = NULL; SubViewer1Context *subviewer1 = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1); st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_SUBVIEWER1; while (!avio_feof(s->pb)) { char line[4096]; int len = ff_get_line(s->pb, line, sizeof(line)); int hh, mm, ss; if (!len) break; if (!strncmp(line, "[DELAY]", 7)) { ff_get_line(s->pb, line, sizeof(line)); sscanf(line, "%d", &delay); } if (sscanf(line, "[%d:%d:%d]", &hh, &mm, &ss) == 3) { const int64_t pos = avio_tell(s->pb); int64_t pts_start = hh*3600LL + mm*60LL + ss + delay; len = ff_get_line(s->pb, line, sizeof(line)); line[strcspn(line, "\r\n")] = 0; if (!*line) { if (sub) sub->duration = pts_start - sub->pts; } else { sub = ff_subtitles_queue_insert(&subviewer1->q, line, len, 0); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; sub->pts = pts_start; sub->duration = -1; } } } ff_subtitles_queue_finalize(s, &subviewer1->q); return 0; }
static int pjs_read_header(AVFormatContext *s) { PJSContext *pjs = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); int res = 0; if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 10); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_PJS; while (!avio_feof(s->pb)) { char line[4096]; char *p = line; const int64_t pos = avio_tell(s->pb); int len = ff_get_line(s->pb, line, sizeof(line)); int64_t pts_start; int duration; if (!len) break; line[strcspn(line, "\r\n")] = 0; pts_start = read_ts(&p, &duration); if (pts_start != AV_NOPTS_VALUE) { AVPacket *sub; p[strcspn(p, "\"")] = 0; sub = ff_subtitles_queue_insert(&pjs->q, p, strlen(p), 0); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; sub->pts = pts_start; sub->duration = duration; } } ff_subtitles_queue_finalize(&pjs->q); return res; }
static int subviewer_read_header(AVFormatContext *s) { SubViewerContext *subviewer = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); AVBPrint header; int res = 0, new_event = 1; int64_t pts_start = AV_NOPTS_VALUE; int duration = -1; AVPacket *sub = NULL; if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SUBVIEWER; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); while (!avio_feof(s->pb)) { char line[2048]; int64_t pos = 0; int len = ff_get_line(s->pb, line, sizeof(line)); if (!len) break; line[strcspn(line, "\r\n")] = 0; if (line[0] == '[' && strncmp(line, "[br]", 4)) { /* ignore event style, XXX: add to side_data? */ if (strstr(line, "[COLF]") || strstr(line, "[SIZE]") || strstr(line, "[FONT]") || strstr(line, "[STYLE]")) continue; if (!st->codec->extradata) { // header not finalized yet av_bprintf(&header, "%s\n", line); if (!strncmp(line, "[END INFORMATION]", 17) || !strncmp(line, "[SUBTITLE]", 10)) { /* end of header */ res = avpriv_bprint_to_extradata(st->codec, &header); if (res < 0) goto end; } else if (strncmp(line, "[INFORMATION]", 13)) { /* assume file metadata at this point */ int i, j = 0; char key[32], value[128]; for (i = 1; i < sizeof(key) - 1 && line[i] && line[i] != ']'; i++) key[i - 1] = av_tolower(line[i]); key[i - 1] = 0; if (line[i] == ']') i++; while (line[i] == ' ') i++; while (j < sizeof(value) - 1 && line[i] && line[i] != ']') value[j++] = line[i++]; value[j] = 0; av_dict_set(&s->metadata, key, value, 0); } } } else if (read_ts(line, &pts_start, &duration) >= 0) { new_event = 1; pos = avio_tell(s->pb); } else if (*line) { if (!new_event) { sub = ff_subtitles_queue_insert(&subviewer->q, "\n", 1, 1); if (!sub) { res = AVERROR(ENOMEM); goto end; } } sub = ff_subtitles_queue_insert(&subviewer->q, line, strlen(line), !new_event); if (!sub) { res = AVERROR(ENOMEM); goto end; } if (new_event) { sub->pos = pos; sub->pts = pts_start; sub->duration = duration; } new_event = 0; } } ff_subtitles_queue_finalize(&subviewer->q); end: av_bprint_finalize(&header, NULL); return res; }
static int jacosub_read_header(AVFormatContext *s) { AVBPrint header; AVIOContext *pb = s->pb; char line[JSS_MAX_LINESIZE]; JACOsubContext *jacosub = s->priv_data; int shift_set = 0; // only the first shift matters int merge_line = 0; int i, ret; AVStream *st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_JACOSUB; jacosub->timeres = 30; av_bprint_init(&header, 1024+FF_INPUT_BUFFER_PADDING_SIZE, 4096); while (!avio_feof(pb)) { int cmd_len; const char *p = line; int64_t pos = avio_tell(pb); int len = ff_get_line(pb, line, sizeof(line)); p = jss_skip_whitespace(p); /* queue timed line */ if (merge_line || timed_line(p)) { AVPacket *sub; sub = ff_subtitles_queue_insert(&jacosub->q, line, len, merge_line); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; merge_line = len > 1 && !strcmp(&line[len - 2], "\\\n"); continue; } /* skip all non-compiler commands and focus on the command */ if (*p != '#') continue; p++; i = get_jss_cmd(p[0]); if (i == -1) continue; /* trim command + spaces */ cmd_len = strlen(cmds[i]); if (av_strncasecmp(p, cmds[i], cmd_len) == 0) p += cmd_len; else p++; p = jss_skip_whitespace(p); /* handle commands which affect the whole script */ switch (cmds[i][0]) { case 'S': // SHIFT command affect the whole script... if (!shift_set) { jacosub->shift = get_shift(jacosub->timeres, p); shift_set = 1; } av_bprintf(&header, "#S %s", p); break; case 'T': // ...but must be placed after TIMERES jacosub->timeres = strtol(p, NULL, 10); if (!jacosub->timeres) jacosub->timeres = 30; else av_bprintf(&header, "#T %s", p); break; } } /* general/essential directives in the extradata */ ret = avpriv_bprint_to_extradata(st->codec, &header); if (ret < 0) return ret; /* SHIFT and TIMERES affect the whole script so packet timing can only be * done in a second pass */ for (i = 0; i < jacosub->q.nb_subs; i++) { AVPacket *sub = &jacosub->q.subs[i]; read_ts(jacosub, sub->data, &sub->pts, &sub->duration); } ff_subtitles_queue_finalize(&jacosub->q); return 0; }
static int realtext_read_header(AVFormatContext *s) { RealTextContext *rt = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); AVBPrint buf; char c = 0; int res = 0, duration = read_ts("60"); // default duration is 60 seconds if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_REALTEXT; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); while (!url_feof(s->pb)) { AVPacket *sub; const int64_t pos = avio_tell(s->pb) - (c != 0); int n = ff_smil_extract_next_chunk(s->pb, &buf, &c); if (n == 0) break; if (!av_strncasecmp(buf.str, "<window", 7)) { /* save header to extradata */ const char *p = ff_smil_get_attr_ptr(buf.str, "duration"); if (p) duration = read_ts(p); st->codec->extradata = av_strdup(buf.str); if (!st->codec->extradata) { res = AVERROR(ENOMEM); goto end; } st->codec->extradata_size = buf.len + 1; } else { /* if we just read a <time> tag, introduce a new event, otherwise merge * with the previous one */ int merge = !av_strncasecmp(buf.str, "<time", 5) ? 0 : 1; sub = ff_subtitles_queue_insert(&rt->q, buf.str, buf.len, merge); if (!sub) { res = AVERROR(ENOMEM); goto end; } if (!merge) { const char *begin = ff_smil_get_attr_ptr(buf.str, "begin"); const char *end = ff_smil_get_attr_ptr(buf.str, "end"); sub->pos = pos; sub->pts = begin ? read_ts(begin) : 0; sub->duration = end ? (read_ts(end) - sub->pts) : duration; } } av_bprint_clear(&buf); } ff_subtitles_queue_finalize(&rt->q); end: av_bprint_finalize(&buf, NULL); return res; }
static int lrc_read_header(AVFormatContext *s) { LRCContext *lrc = s->priv_data; AVBPrint line; AVStream *st; st = avformat_new_stream(s, NULL); if(!st) { return AVERROR(ENOMEM); } avpriv_set_pts_info(st, 64, 1, 1000); lrc->ts_offset = 0; st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_TEXT; av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED); while(!url_feof(s->pb)) { int64_t pos = read_line(&line, s->pb); int64_t header_offset = find_header(line.str); if(header_offset >= 0) { char *comma_offset = strchr(line.str, ':'); if(comma_offset) { char *right_bracket_offset = strchr(line.str, ']'); if(!right_bracket_offset) { continue; } *right_bracket_offset = *comma_offset = '\0'; if(strcmp(line.str + 1, "offset") || sscanf(comma_offset + 1, "%"SCNd64, &lrc->ts_offset) != 1) { av_dict_set(&s->metadata, line.str + 1, comma_offset + 1, 0); } *comma_offset = ':'; *right_bracket_offset = ']'; } } else { AVPacket *sub; int64_t ts_start = AV_NOPTS_VALUE; int64_t ts_stroffset = 0; int64_t ts_stroffset_incr = 0; int64_t ts_strlength = count_ts(line.str); while((ts_stroffset_incr = read_ts(line.str + ts_stroffset, &ts_start)) != 0) { ts_stroffset += ts_stroffset_incr; sub = ff_subtitles_queue_insert(&lrc->q, line.str + ts_strlength, line.len - ts_strlength, 0); if(!sub) { return AVERROR(ENOMEM); } sub->pos = pos; sub->pts = ts_start - lrc->ts_offset; sub->duration = -1; } } } ff_subtitles_queue_finalize(&lrc->q); ff_metadata_conv_ctx(s, NULL, ff_lrc_metadata_conv); return 0; }
static int ass_read_header(AVFormatContext *s) { ASSContext *ass = s->priv_data; AVBPrint header, line; int header_remaining, res = 0; AVStream *st; st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 100); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_SSA; header_remaining = INT_MAX; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&line, 0, AV_BPRINT_SIZE_UNLIMITED); for (;;) { int64_t pos = get_line(&line, s->pb); if (!line.str[0]) // EOF break; if (!memcmp(line.str, "[Events]", 8)) header_remaining = 2; else if (line.str[0] == '[') header_remaining = INT_MAX; if (header_remaining) { av_bprintf(&header, "%s", line.str); header_remaining--; } else { int64_t ts_start = AV_NOPTS_VALUE; int duration = -1; AVPacket *sub; if (read_ts(line.str, &ts_start, &duration) < 0) continue; sub = ff_subtitles_queue_insert(&ass->q, line.str, line.len, 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pos = pos; sub->pts = ts_start; sub->duration = duration; } } av_bprint_finalize(&line, NULL); res = avpriv_bprint_to_extradata(st->codec, &header); if (res < 0) goto end; ff_subtitles_queue_finalize(&ass->q); end: return res; }
static int microdvd_read_header(AVFormatContext *s) { AVRational pts_info = (AVRational){ 2997, 125 }; /* default: 23.976 fps */ MicroDVDContext *microdvd = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); int i = 0; char line[MAX_LINESIZE]; if (!st) return AVERROR(ENOMEM); while (!url_feof(s->pb)) { char *p = line; AVPacket *sub; int64_t pos = avio_tell(s->pb); int len = ff_get_line(s->pb, line, sizeof(line)); if (!len) break; line[strcspn(line, "\r\n")] = 0; if (i++ < 3) { int frame; double fps; char c; if ((sscanf(line, "{%d}{}%6lf", &frame, &fps) == 2 || sscanf(line, "{%d}{%*d}%6lf", &frame, &fps) == 2) && frame <= 1 && fps > 3 && fps < 100) pts_info = av_d2q(fps, 100000); if (!st->codec->extradata && sscanf(line, "{DEFAULT}{}%c", &c) == 1) { st->codec->extradata = av_strdup(line + 11); if (!st->codec->extradata) return AVERROR(ENOMEM); st->codec->extradata_size = strlen(st->codec->extradata) + 1; continue; } } #define SKIP_FRAME_ID \ p = strchr(p, '}'); \ if (!p) { \ av_log(s, AV_LOG_WARNING, "Invalid event \"%s\"" \ " at line %d\n", line, i); \ continue; \ } \ p++ SKIP_FRAME_ID; SKIP_FRAME_ID; if (!*p) continue; sub = ff_subtitles_queue_insert(µdvd->q, p, strlen(p), 0); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; sub->pts = get_pts(line); sub->duration = get_duration(line); } ff_subtitles_queue_finalize(µdvd->q); avpriv_set_pts_info(st, 64, pts_info.den, pts_info.num); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_MICRODVD; return 0; }
static int webvtt_read_header(AVFormatContext *s) { WebVTTContext *webvtt = s->priv_data; AVBPrint header, cue; int res = 0; AVStream *st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codec->codec_id = AV_CODEC_ID_WEBVTT; av_bprint_init(&header, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_init(&cue, 0, AV_BPRINT_SIZE_UNLIMITED); for (;;) { int i; int64_t pos; AVPacket *sub; const char *p, *identifier; //const char *settings = NULL; int64_t ts_start, ts_end; ff_subtitles_read_chunk(s->pb, &cue); if (!cue.len) break; p = identifier = cue.str; pos = avio_tell(s->pb); /* ignore header chunk */ if (!strncmp(p, "\xEF\xBB\xBFWEBVTT", 9) || !strncmp(p, "WEBVTT", 6)) continue; /* optional cue identifier (can be a number like in SRT or some kind of * chaptering id), silently skip it */ for (i = 0; p[i] && p[i] != '\n'; i++) { if (!strncmp(p + i, "-->", 3)) { identifier = NULL; break; } } if (identifier) p += strcspn(p, "\n"); /* cue timestamps */ if ((ts_start = read_ts(p)) == AV_NOPTS_VALUE) break; if (!(p = strstr(p, "-->"))) break; p += 3; do p++; while (*p == ' ' || *p == '\t'); if ((ts_end = read_ts(p)) == AV_NOPTS_VALUE) break; /* optional cue settings, TODO: store in side_data */ p += strcspn(p, "\n\t "); while (*p == '\t' || *p == ' ') p++; if (*p != '\n') { //settings = p; p += strcspn(p, "\n"); } if (*p == '\n') p++; /* create packet */ sub = ff_subtitles_queue_insert(&webvtt->q, p, strlen(p), 0); if (!sub) { res = AVERROR(ENOMEM); goto end; } sub->pos = pos; sub->pts = ts_start; sub->duration = ts_end - ts_start; } ff_subtitles_queue_finalize(&webvtt->q); end: av_bprint_finalize(&cue, NULL); av_bprint_finalize(&header, NULL); return res; }
static int scc_read_header(AVFormatContext *s) { SCCContext *scc = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); char line[4096], line2[4096]; int count = 0, ret = 0; ptrdiff_t len2, len; uint8_t out[4096]; FFTextReader tr; ff_text_init_avio(s, &tr, s->pb); if (!st) return AVERROR(ENOMEM); avpriv_set_pts_info(st, 64, 1, 1000); st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_EIA_608; while (!ff_text_eof(&tr)) { const int64_t pos = ff_text_pos(&tr); char *saveptr = NULL, *lline; int hh1, mm1, ss1, fs1, i; int hh2, mm2, ss2, fs2; int64_t ts_start, ts_end; AVPacket *sub; if (count == 0) { while (!ff_text_eof(&tr)) { len = ff_subtitles_read_line(&tr, line, sizeof(line)); if (len > 13) break; } } if (!strncmp(line, "Scenarist_SCC V1.0", 18)) continue; if (sscanf(line, "%d:%d:%d%*[:;]%d", &hh1, &mm1, &ss1, &fs1) != 4) continue; ts_start = (hh1 * 3600LL + mm1 * 60LL + ss1) * 1000LL + fs1 * 33; while (!ff_text_eof(&tr)) { len2 = ff_subtitles_read_line(&tr, line2, sizeof(line2)); if (len2 > 13) break; } if (sscanf(line2, "%d:%d:%d%*[:;]%d", &hh2, &mm2, &ss2, &fs2) != 4) continue; ts_end = (hh2 * 3600LL + mm2 * 60LL + ss2) * 1000LL + fs2 * 33; count++; lline = (char *)&line; lline += 12; for (i = 0; i < 4095; i += 3) { char *ptr = av_strtok(lline, " ", &saveptr); char c1, c2, c3, c4; if (!ptr) break; if (sscanf(ptr, "%c%c%c%c", &c1, &c2, &c3, &c4) != 4) break; lline = NULL; out[i+0] = 0xfc; out[i+1] = convert(c2) | (convert(c1) << 4); out[i+2] = convert(c4) | (convert(c3) << 4); } out[i] = 0; sub = ff_subtitles_queue_insert(&scc->q, out, i, 0); if (!sub) return AVERROR(ENOMEM); sub->pos = pos; sub->pts = ts_start; sub->duration = FFMAX(1200, ts_end - ts_start); memmove(line, line2, sizeof(line)); FFSWAP(ptrdiff_t, len, len2); } ff_subtitles_queue_finalize(s, &scc->q); return ret; }