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