Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2012-2013 Clément Bœsch <u pkh me> | ||
3 | * | ||
4 | * This file is part of FFmpeg. | ||
5 | * | ||
6 | * FFmpeg is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; either | ||
9 | * version 2.1 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * FFmpeg is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with FFmpeg; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | #include "avformat.h" | ||
22 | #include "subtitles.h" | ||
23 | #include "avio_internal.h" | ||
24 | #include "libavutil/avassert.h" | ||
25 | #include "libavutil/avstring.h" | ||
26 | #include "libavutil/mem.h" | ||
27 | |||
28 | 43135 | void ff_text_init_avio(void *s, FFTextReader *r, AVIOContext *pb) | |
29 | { | ||
30 | int i; | ||
31 | 43135 | r->pb = pb; | |
32 | 43135 | r->buf_pos = r->buf_len = 0; | |
33 | 43135 | r->type = FF_UTF_8; | |
34 |
2/2✓ Branch 0 taken 86270 times.
✓ Branch 1 taken 43135 times.
|
129405 | for (i = 0; i < 2; i++) |
35 | 86270 | r->buf[r->buf_len++] = avio_r8(r->pb); | |
36 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43135 times.
|
43135 | if (strncmp("\xFF\xFE", r->buf, 2) == 0) { |
37 | ✗ | r->type = FF_UTF16LE; | |
38 | ✗ | r->buf_pos += 2; | |
39 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43135 times.
|
43135 | } else if (strncmp("\xFE\xFF", r->buf, 2) == 0) { |
40 | ✗ | r->type = FF_UTF16BE; | |
41 | ✗ | r->buf_pos += 2; | |
42 | } else { | ||
43 | 43135 | r->buf[r->buf_len++] = avio_r8(r->pb); | |
44 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 43073 times.
|
43135 | if (strncmp("\xEF\xBB\xBF", r->buf, 3) == 0) { |
45 | // UTF8 | ||
46 | 62 | r->buf_pos += 3; | |
47 | } | ||
48 | } | ||
49 |
4/6✓ Branch 0 taken 19 times.
✓ Branch 1 taken 43116 times.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
|
43135 | if (s && (r->type == FF_UTF16LE || r->type == FF_UTF16BE)) |
50 | ✗ | av_log(s, AV_LOG_INFO, | |
51 | "UTF16 is automatically converted to UTF8, do not specify a character encoding\n"); | ||
52 | 43135 | } | |
53 | |||
54 | 43116 | void ff_text_init_buf(FFTextReader *r, const void *buf, size_t size) | |
55 | { | ||
56 | 43116 | ffio_init_read_context(&r->buf_pb, buf, size); | |
57 | 43116 | ff_text_init_avio(NULL, r, &r->buf_pb.pub); | |
58 | 43116 | } | |
59 | |||
60 | 5583 | int64_t ff_text_pos(FFTextReader *r) | |
61 | { | ||
62 | 5583 | return avio_tell(r->pb) - r->buf_len + r->buf_pos; | |
63 | } | ||
64 | |||
65 | 785477 | int ff_text_r8(FFTextReader *r) | |
66 | { | ||
67 | uint32_t val; | ||
68 | uint8_t tmp; | ||
69 |
2/2✓ Branch 0 taken 132628 times.
✓ Branch 1 taken 652849 times.
|
785477 | if (r->buf_pos < r->buf_len) |
70 | 132628 | return r->buf[r->buf_pos++]; | |
71 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 652849 times.
|
652849 | if (r->type == FF_UTF16LE) { |
72 | ✗ | GET_UTF16(val, avio_rl16(r->pb), return 0;) | |
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 652849 times.
|
652849 | } else if (r->type == FF_UTF16BE) { |
74 | ✗ | GET_UTF16(val, avio_rb16(r->pb), return 0;) | |
75 | } else { | ||
76 | 652849 | return avio_r8(r->pb); | |
77 | } | ||
78 | ✗ | if (!val) | |
79 | ✗ | return 0; | |
80 | ✗ | r->buf_pos = 0; | |
81 | ✗ | r->buf_len = 0; | |
82 | ✗ | PUT_UTF8(val, tmp, r->buf[r->buf_len++] = tmp;) | |
83 | ✗ | return r->buf[r->buf_pos++]; // buf_len is at least 1 | |
84 | } | ||
85 | |||
86 | 35930 | void ff_text_read(FFTextReader *r, char *buf, size_t size) | |
87 | { | ||
88 |
2/2✓ Branch 0 taken 517392 times.
✓ Branch 1 taken 35930 times.
|
553322 | for ( ; size > 0; size--) |
89 | 517392 | *buf++ = ff_text_r8(r); | |
90 | 35930 | } | |
91 | |||
92 | 10679 | int ff_text_eof(FFTextReader *r) | |
93 | { | ||
94 |
4/4✓ Branch 0 taken 8977 times.
✓ Branch 1 taken 1702 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 8950 times.
|
10679 | return r->buf_pos >= r->buf_len && avio_feof(r->pb); |
95 | } | ||
96 | |||
97 | 71236 | int ff_text_peek_r8(FFTextReader *r) | |
98 | { | ||
99 | int c; | ||
100 |
2/2✓ Branch 0 taken 63276 times.
✓ Branch 1 taken 7960 times.
|
71236 | if (r->buf_pos < r->buf_len) |
101 | 63276 | return r->buf[r->buf_pos]; | |
102 | 7960 | c = ff_text_r8(r); | |
103 |
1/2✓ Branch 1 taken 7960 times.
✗ Branch 2 not taken.
|
7960 | if (!avio_feof(r->pb)) { |
104 | 7960 | r->buf_pos = 0; | |
105 | 7960 | r->buf_len = 1; | |
106 | 7960 | r->buf[0] = c; | |
107 | } | ||
108 | 7960 | return c; | |
109 | } | ||
110 | |||
111 | 2652 | AVPacket *ff_subtitles_queue_insert(FFDemuxSubtitlesQueue *q, | |
112 | const uint8_t *event, size_t len, int merge) | ||
113 | { | ||
114 | AVPacket **subs, *sub; | ||
115 | |||
116 | av_assert1(event || len == 0); | ||
117 | |||
118 |
4/4✓ Branch 0 taken 949 times.
✓ Branch 1 taken 1703 times.
✓ Branch 2 taken 948 times.
✓ Branch 3 taken 1 times.
|
3600 | if (merge && q->nb_subs > 0) { |
119 | /* merge with previous event */ | ||
120 | |||
121 | int old_len; | ||
122 | 948 | sub = q->subs[q->nb_subs - 1]; | |
123 | 948 | old_len = sub->size; | |
124 |
1/2✓ Branch 0 taken 948 times.
✗ Branch 1 not taken.
|
948 | if (event) { |
125 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 948 times.
|
948 | if (av_grow_packet(sub, len) < 0) |
126 | ✗ | return NULL; | |
127 | 948 | memcpy(sub->data + old_len, event, len); | |
128 | } | ||
129 | } else { | ||
130 | /* new event */ | ||
131 | |||
132 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1704 times.
|
1704 | if (q->nb_subs >= INT_MAX/sizeof(*q->subs) - 1) |
133 | ✗ | return NULL; | |
134 | 1704 | subs = av_fast_realloc(q->subs, &q->allocated_size, | |
135 | 1704 | (q->nb_subs + 1) * sizeof(*q->subs)); | |
136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1704 times.
|
1704 | if (!subs) |
137 | ✗ | return NULL; | |
138 | 1704 | q->subs = subs; | |
139 | 1704 | sub = av_packet_alloc(); | |
140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1704 times.
|
1704 | if (!sub) |
141 | ✗ | return NULL; | |
142 |
1/2✓ Branch 0 taken 1704 times.
✗ Branch 1 not taken.
|
1704 | if (event) { |
143 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1704 times.
|
1704 | if (av_new_packet(sub, len) < 0) { |
144 | ✗ | av_packet_free(&sub); | |
145 | ✗ | return NULL; | |
146 | } | ||
147 | 1704 | memcpy(sub->data, event, len); | |
148 | } | ||
149 | 1704 | sub->flags |= AV_PKT_FLAG_KEY; | |
150 | 1704 | sub->pts = sub->dts = 0; | |
151 | 1704 | subs[q->nb_subs++] = sub; | |
152 | } | ||
153 | 2652 | return sub; | |
154 | } | ||
155 | |||
156 | 1839 | AVPacket *ff_subtitles_queue_insert_bprint(FFDemuxSubtitlesQueue *q, | |
157 | const AVBPrint *event, int merge) | ||
158 | { | ||
159 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1839 times.
|
1839 | if (!av_bprint_is_complete(event)) |
160 | ✗ | return NULL; | |
161 | 1839 | return ff_subtitles_queue_insert(q, event->str, event->len, merge); | |
162 | } | ||
163 | |||
164 | 5144 | static int cmp_pkt_sub_ts_pos(const void *a, const void *b) | |
165 | { | ||
166 | 5144 | const AVPacket *s1 = *(const AVPacket **)a; | |
167 | 5144 | const AVPacket *s2 = *(const AVPacket **)b; | |
168 |
2/2✓ Branch 0 taken 165 times.
✓ Branch 1 taken 4979 times.
|
5144 | if (s1->pts == s2->pts) |
169 | 165 | return FFDIFFSIGN(s1->pos, s2->pos); | |
170 | 4979 | return FFDIFFSIGN(s1->pts , s2->pts); | |
171 | } | ||
172 | |||
173 | 369 | static int cmp_pkt_sub_pos_ts(const void *a, const void *b) | |
174 | { | ||
175 | 369 | const AVPacket *s1 = *(const AVPacket **)a; | |
176 | 369 | const AVPacket *s2 = *(const AVPacket **)b; | |
177 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
|
369 | if (s1->pos == s2->pos) { |
178 | ✗ | if (s1->pts == s2->pts) | |
179 | ✗ | return 0; | |
180 | ✗ | return s1->pts > s2->pts ? 1 : -1; | |
181 | } | ||
182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 369 times.
|
369 | return s1->pos > s2->pos ? 1 : -1; |
183 | } | ||
184 | |||
185 | 35 | static void drop_dups(void *log_ctx, FFDemuxSubtitlesQueue *q) | |
186 | { | ||
187 | 35 | int i, drop = 0; | |
188 | |||
189 |
2/2✓ Branch 0 taken 1477 times.
✓ Branch 1 taken 35 times.
|
1512 | for (i = 1; i < q->nb_subs; i++) { |
190 | 1477 | const int last_id = i - 1 - drop; | |
191 | 1477 | const AVPacket *last = q->subs[last_id]; | |
192 | |||
193 |
2/2✓ Branch 0 taken 129 times.
✓ Branch 1 taken 1348 times.
|
1477 | if (q->subs[i]->pts == last->pts && |
194 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 84 times.
|
129 | q->subs[i]->duration == last->duration && |
195 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | q->subs[i]->stream_index == last->stream_index && |
196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | !strcmp(q->subs[i]->data, last->data)) { |
197 | |||
198 | ✗ | av_packet_free(&q->subs[i]); | |
199 | ✗ | drop++; | |
200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1477 times.
|
1477 | } else if (drop) { |
201 | ✗ | q->subs[last_id + 1] = q->subs[i]; | |
202 | ✗ | q->subs[i] = NULL; | |
203 | } | ||
204 | } | ||
205 | |||
206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | if (drop) { |
207 | ✗ | q->nb_subs -= drop; | |
208 | ✗ | av_log(log_ctx, AV_LOG_WARNING, "Dropping %d duplicated subtitle events\n", drop); | |
209 | } | ||
210 | 35 | } | |
211 | |||
212 | 41 | void ff_subtitles_queue_finalize(void *log_ctx, FFDemuxSubtitlesQueue *q) | |
213 | { | ||
214 | int i; | ||
215 | |||
216 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
|
41 | if (!q->nb_subs) |
217 | ✗ | return; | |
218 | |||
219 | 41 | qsort(q->subs, q->nb_subs, sizeof(*q->subs), | |
220 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 3 times.
|
41 | q->sort == SUB_SORT_TS_POS ? cmp_pkt_sub_ts_pos |
221 | : cmp_pkt_sub_pos_ts); | ||
222 |
2/2✓ Branch 0 taken 1704 times.
✓ Branch 1 taken 41 times.
|
1745 | for (i = 0; i < q->nb_subs; i++) |
223 |
5/6✓ Branch 0 taken 229 times.
✓ Branch 1 taken 1475 times.
✓ Branch 2 taken 222 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 222 times.
✗ Branch 5 not taken.
|
1704 | if (q->subs[i]->duration < 0 && i < q->nb_subs - 1 && q->subs[i + 1]->pts - (uint64_t)q->subs[i]->pts <= INT64_MAX) |
224 | 222 | q->subs[i]->duration = q->subs[i + 1]->pts - q->subs[i]->pts; | |
225 | |||
226 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 6 times.
|
41 | if (!q->keep_duplicates) |
227 | 35 | drop_dups(log_ctx, q); | |
228 | } | ||
229 | |||
230 | 1726 | int ff_subtitles_queue_read_packet(FFDemuxSubtitlesQueue *q, AVPacket *pkt) | |
231 | { | ||
232 | AVPacket *sub; | ||
233 | int ret; | ||
234 | |||
235 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1688 times.
|
1726 | if (q->current_sub_idx == q->nb_subs) |
236 | 38 | return AVERROR_EOF; | |
237 | 1688 | sub = q->subs[q->current_sub_idx]; | |
238 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1688 times.
|
1688 | if ((ret = av_packet_ref(pkt, sub)) < 0) { |
239 | ✗ | return ret; | |
240 | } | ||
241 | |||
242 | 1688 | pkt->dts = pkt->pts; | |
243 | 1688 | q->current_sub_idx++; | |
244 | 1688 | return 0; | |
245 | } | ||
246 | |||
247 | 2 | static int search_sub_ts(const FFDemuxSubtitlesQueue *q, int64_t ts) | |
248 | { | ||
249 | 2 | int s1 = 0, s2 = q->nb_subs - 1; | |
250 | |||
251 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (s2 < s1) |
252 | ✗ | return AVERROR(ERANGE); | |
253 | |||
254 | 12 | for (;;) { | |
255 | int mid; | ||
256 | |||
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (s1 == s2) |
258 | ✗ | return s1; | |
259 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
|
14 | if (s1 == s2 - 1) |
260 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | return q->subs[s1]->pts <= q->subs[s2]->pts ? s1 : s2; |
261 | 12 | mid = (s1 + s2) / 2; | |
262 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
|
12 | if (q->subs[mid]->pts <= ts) |
263 | 3 | s1 = mid; | |
264 | else | ||
265 | 9 | s2 = mid; | |
266 | } | ||
267 | } | ||
268 | |||
269 | 2 | int ff_subtitles_queue_seek(FFDemuxSubtitlesQueue *q, AVFormatContext *s, int stream_index, | |
270 | int64_t min_ts, int64_t ts, int64_t max_ts, int flags) | ||
271 | { | ||
272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (flags & AVSEEK_FLAG_BYTE) { |
273 | ✗ | return AVERROR(ENOSYS); | |
274 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | } else if (flags & AVSEEK_FLAG_FRAME) { |
275 | ✗ | if (ts < 0 || ts >= q->nb_subs) | |
276 | ✗ | return AVERROR(ERANGE); | |
277 | ✗ | q->current_sub_idx = ts; | |
278 | } else { | ||
279 | 2 | int i, idx = search_sub_ts(q, ts); | |
280 | int64_t ts_selected; | ||
281 | |||
282 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (idx < 0) |
283 | ✗ | return idx; | |
284 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | for (i = idx; i < q->nb_subs && q->subs[i]->pts < min_ts; i++) |
285 | ✗ | if (stream_index == -1 || q->subs[i]->stream_index == stream_index) | |
286 | ✗ | idx = i; | |
287 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
2 | for (i = idx; i > 0 && q->subs[i]->pts > max_ts; i--) |
288 | ✗ | if (stream_index == -1 || q->subs[i]->stream_index == stream_index) | |
289 | ✗ | idx = i; | |
290 | |||
291 | 2 | ts_selected = q->subs[idx]->pts; | |
292 |
3/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
2 | if (ts_selected < min_ts || ts_selected > max_ts) |
293 | 1 | return AVERROR(ERANGE); | |
294 | |||
295 | /* look back in the latest subtitles for overlapping subtitles */ | ||
296 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (i = idx - 1; i >= 0; i--) { |
297 | 1 | int64_t pts = q->subs[i]->pts; | |
298 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (q->subs[i]->duration <= 0 || |
299 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | (stream_index != -1 && q->subs[i]->stream_index != stream_index)) |
300 | ✗ | continue; | |
301 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (pts >= min_ts && pts > ts_selected - q->subs[i]->duration) |
302 | ✗ | idx = i; | |
303 | else | ||
304 | break; | ||
305 | } | ||
306 | |||
307 | /* If the queue is used to store multiple subtitles streams (like with | ||
308 | * VobSub) and the stream index is not specified, we need to make sure | ||
309 | * to focus on the smallest file position offset for a same timestamp; | ||
310 | * queue is ordered by pts and then filepos, so we can take the first | ||
311 | * entry for a given timestamp. */ | ||
312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (stream_index == -1) |
313 | ✗ | while (idx > 0 && q->subs[idx - 1]->pts == q->subs[idx]->pts) | |
314 | ✗ | idx--; | |
315 | |||
316 | 1 | q->current_sub_idx = idx; | |
317 | } | ||
318 | 1 | return 0; | |
319 | } | ||
320 | |||
321 | 41 | void ff_subtitles_queue_clean(FFDemuxSubtitlesQueue *q) | |
322 | { | ||
323 | int i; | ||
324 | |||
325 |
2/2✓ Branch 0 taken 1704 times.
✓ Branch 1 taken 41 times.
|
1745 | for (i = 0; i < q->nb_subs; i++) |
326 | 1704 | av_packet_free(&q->subs[i]); | |
327 | 41 | av_freep(&q->subs); | |
328 | 41 | q->nb_subs = q->allocated_size = q->current_sub_idx = 0; | |
329 | 41 | } | |
330 | |||
331 | 1433 | int ff_subtitles_read_packet(AVFormatContext *s, AVPacket *pkt) | |
332 | { | ||
333 | 1433 | FFDemuxSubtitlesQueue *q = s->priv_data; | |
334 | 1433 | return ff_subtitles_queue_read_packet(q, pkt); | |
335 | } | ||
336 | |||
337 | 1 | int ff_subtitles_read_seek(AVFormatContext *s, int stream_index, | |
338 | int64_t min_ts, int64_t ts, int64_t max_ts, int flags) | ||
339 | { | ||
340 | 1 | FFDemuxSubtitlesQueue *q = s->priv_data; | |
341 | 1 | return ff_subtitles_queue_seek(q, s, stream_index, | |
342 | min_ts, ts, max_ts, flags); | ||
343 | } | ||
344 | |||
345 | 31 | int ff_subtitles_read_close(AVFormatContext *s) | |
346 | { | ||
347 | 31 | FFDemuxSubtitlesQueue *q = s->priv_data; | |
348 | 31 | ff_subtitles_queue_clean(q); | |
349 | 31 | return 0; | |
350 | } | ||
351 | |||
352 | 1111 | int ff_smil_extract_next_text_chunk(FFTextReader *tr, AVBPrint *buf, char *c) | |
353 | { | ||
354 | 1111 | int i = 0; | |
355 | char end_chr; | ||
356 | |||
357 |
2/2✓ Branch 0 taken 683 times.
✓ Branch 1 taken 428 times.
|
1111 | if (!*c) // cached char? |
358 | 683 | *c = ff_text_r8(tr); | |
359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1111 times.
|
1111 | if (!*c) |
360 | ✗ | return 0; | |
361 | |||
362 |
2/2✓ Branch 0 taken 682 times.
✓ Branch 1 taken 429 times.
|
1111 | end_chr = *c == '<' ? '>' : '<'; |
363 | do { | ||
364 | 14499 | av_bprint_chars(buf, *c, 1); | |
365 | 14499 | *c = ff_text_r8(tr); | |
366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14499 times.
|
14499 | if (i == INT_MAX) |
367 | ✗ | return AVERROR_INVALIDDATA; | |
368 | 14499 | i++; | |
369 |
4/4✓ Branch 0 taken 13389 times.
✓ Branch 1 taken 1110 times.
✓ Branch 2 taken 13388 times.
✓ Branch 3 taken 1 times.
|
14499 | } while (*c != end_chr && *c); |
370 |
2/2✓ Branch 0 taken 682 times.
✓ Branch 1 taken 429 times.
|
1111 | if (end_chr == '>') { |
371 | 682 | av_bprint_chars(buf, '>', 1); | |
372 | 682 | *c = 0; | |
373 | } | ||
374 |
1/2✓ Branch 1 taken 1111 times.
✗ Branch 2 not taken.
|
1111 | return av_bprint_is_complete(buf) ? i : AVERROR(ENOMEM); |
375 | } | ||
376 | |||
377 | 176 | const char *ff_smil_get_attr_ptr(const char *s, const char *attr) | |
378 | { | ||
379 | 176 | int in_quotes = 0; | |
380 | 176 | const size_t len = strlen(attr); | |
381 | |||
382 |
2/2✓ Branch 0 taken 182 times.
✓ Branch 1 taken 3 times.
|
185 | while (*s) { |
383 |
2/2✓ Branch 0 taken 1142 times.
✓ Branch 1 taken 3 times.
|
1145 | while (*s) { |
384 |
4/4✓ Branch 0 taken 1110 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 179 times.
✓ Branch 3 taken 931 times.
|
1142 | if (!in_quotes && av_isspace(*s)) |
385 | 179 | break; | |
386 | 963 | in_quotes ^= *s == '"'; // XXX: support escaping? | |
387 | 963 | s++; | |
388 | } | ||
389 |
2/2✓ Branch 0 taken 179 times.
✓ Branch 1 taken 182 times.
|
361 | while (av_isspace(*s)) |
390 | 179 | s++; | |
391 |
3/4✓ Branch 1 taken 173 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 173 times.
✗ Branch 4 not taken.
|
182 | if (!av_strncasecmp(s, attr, len) && s[len] == '=') |
392 | 173 | return s + len + 1 + (s[len + 1] == '"'); | |
393 | } | ||
394 | 3 | return NULL; | |
395 | } | ||
396 | |||
397 | 5315 | static inline int is_eol(char c) | |
398 | { | ||
399 |
4/4✓ Branch 0 taken 5303 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 223 times.
✓ Branch 3 taken 5080 times.
|
5315 | return c == '\r' || c == '\n'; |
400 | } | ||
401 | |||
402 | 73 | int ff_subtitles_read_text_chunk(FFTextReader *tr, AVBPrint *buf) | |
403 | { | ||
404 | 73 | char eol_buf[5], last_was_cr = 0; | |
405 | 73 | int n = 0, i = 0, nb_eol = 0; | |
406 | |||
407 | 73 | av_bprint_clear(buf); | |
408 | |||
409 | 5180 | for (;;) { | |
410 | 5253 | char c = ff_text_r8(tr); | |
411 | |||
412 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 5245 times.
|
5253 | if (!c) |
413 | 8 | break; | |
414 | |||
415 | /* ignore all initial line breaks */ | ||
416 |
3/4✓ Branch 0 taken 70 times.
✓ Branch 1 taken 5175 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 70 times.
|
5245 | if (n == 0 && is_eol(c)) |
417 | ✗ | continue; | |
418 | |||
419 | /* line break buffering: we don't want to add the trailing \r\n */ | ||
420 |
2/2✓ Branch 1 taken 235 times.
✓ Branch 2 taken 5010 times.
|
5245 | if (is_eol(c)) { |
421 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 223 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
235 | nb_eol += c == '\n' || last_was_cr; |
422 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 170 times.
|
235 | if (nb_eol == 2) |
423 | 65 | break; | |
424 | 170 | eol_buf[i++] = c; | |
425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
|
170 | if (i == sizeof(eol_buf) - 1) |
426 | ✗ | break; | |
427 | 170 | last_was_cr = c == '\r'; | |
428 | 170 | continue; | |
429 | } | ||
430 | |||
431 | /* only one line break followed by data: we flush the line breaks | ||
432 | * buffer */ | ||
433 |
2/2✓ Branch 0 taken 89 times.
✓ Branch 1 taken 4921 times.
|
5010 | if (i) { |
434 | 89 | eol_buf[i] = 0; | |
435 | 89 | av_bprintf(buf, "%s", eol_buf); | |
436 | 89 | i = nb_eol = 0; | |
437 | } | ||
438 | |||
439 | 5010 | av_bprint_chars(buf, c, 1); | |
440 | 5010 | n++; | |
441 | } | ||
442 |
1/2✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
|
73 | return av_bprint_is_complete(buf) ? 0 : AVERROR(ENOMEM); |
443 | } | ||
444 | |||
445 | 73 | int ff_subtitles_read_chunk(AVIOContext *pb, AVBPrint *buf) | |
446 | { | ||
447 | FFTextReader tr; | ||
448 | 73 | tr.buf_pos = tr.buf_len = 0; | |
449 | 73 | tr.type = 0; | |
450 | 73 | tr.pb = pb; | |
451 | 73 | return ff_subtitles_read_text_chunk(&tr, buf); | |
452 | } | ||
453 | |||
454 | 11457 | ptrdiff_t ff_subtitles_read_line(FFTextReader *tr, char *buf, size_t size) | |
455 | { | ||
456 | 11457 | size_t cur = 0; | |
457 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11457 times.
|
11457 | if (!size) |
458 | ✗ | return 0; | |
459 | 11457 | buf[0] = '\0'; | |
460 |
2/2✓ Branch 0 taken 216702 times.
✓ Branch 1 taken 216 times.
|
216918 | while (cur + 1 < size) { |
461 | 216702 | unsigned char c = ff_text_r8(tr); | |
462 |
2/2✓ Branch 0 taken 5662 times.
✓ Branch 1 taken 211040 times.
|
216702 | if (!c) |
463 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 5649 times.
|
5662 | return ff_text_eof(tr) ? cur : AVERROR_INVALIDDATA; |
464 |
4/4✓ Branch 0 taken 206337 times.
✓ Branch 1 taken 4703 times.
✓ Branch 2 taken 205461 times.
✓ Branch 3 taken 876 times.
|
211040 | if (c == '\r' || c == '\n') |
465 | break; | ||
466 | 205461 | buf[cur++] = c; | |
467 | 205461 | buf[cur] = '\0'; | |
468 | } | ||
469 |
2/2✓ Branch 1 taken 2118 times.
✓ Branch 2 taken 5795 times.
|
7913 | while (ff_text_peek_r8(tr) == '\r') |
470 | 2118 | ff_text_r8(tr); | |
471 |
2/2✓ Branch 1 taken 4277 times.
✓ Branch 2 taken 1518 times.
|
5795 | if (ff_text_peek_r8(tr) == '\n') |
472 | 4277 | ff_text_r8(tr); | |
473 | 5795 | return cur; | |
474 | } | ||
475 |