Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/pjsdec.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2012 Clément Bœsch
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
/**
22
 * @file
23
 * PJS (Phoenix Japanimation Society) subtitles format demuxer
24
 *
25
 * @see http://subs.com.ru/page.php?al=pjs
26
 */
27
28
#include "avformat.h"
29
#include "demux.h"
30
#include "internal.h"
31
#include "subtitles.h"
32
33
typedef struct {
34
    FFDemuxSubtitlesQueue q;
35
} PJSContext;
36
37
static int pjs_probe(const AVProbeData *p)
38
967k
{
39
967k
    char c;
40
967k
    int64_t start, end;
41
967k
    const unsigned char *ptr = p->buf;
42
43
967k
    if (sscanf(ptr, "%"SCNd64",%"SCNd64",%c", &start, &end, &c) == 3) {
44
435
        size_t q1pos = strcspn(ptr, "\"");
45
435
        size_t q2pos = q1pos + strcspn(ptr + q1pos + 1, "\"") + 1;
46
435
        if (strcspn(ptr, "\r\n") > q2pos)
47
203
            return AVPROBE_SCORE_MAX;
48
435
    }
49
967k
    return 0;
50
967k
}
51
52
static int64_t read_ts(char **line, int *duration)
53
6.43M
{
54
6.43M
    int64_t start, end;
55
56
6.43M
    if (sscanf(*line, "%"SCNd64",%"SCNd64, &start, &end) == 2) {
57
3.54M
        *line += strcspn(*line, "\"");
58
3.54M
        *line += !!**line;
59
3.54M
        if (end < start || end - (uint64_t)start > INT_MAX)
60
6.73k
            return AV_NOPTS_VALUE;
61
3.53M
        *duration = end - start;
62
3.53M
        return start;
63
3.54M
    }
64
2.89M
    return AV_NOPTS_VALUE;
65
6.43M
}
66
67
static int pjs_read_header(AVFormatContext *s)
68
1.56k
{
69
1.56k
    PJSContext *pjs = s->priv_data;
70
1.56k
    AVStream *st = avformat_new_stream(s, NULL);
71
72
1.56k
    if (!st)
73
0
        return AVERROR(ENOMEM);
74
1.56k
    avpriv_set_pts_info(st, 64, 1, 10);
75
1.56k
    st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;
76
1.56k
    st->codecpar->codec_id   = AV_CODEC_ID_PJS;
77
78
6.43M
    while (!avio_feof(s->pb)) {
79
6.43M
        char line[4096];
80
6.43M
        char *p = line;
81
6.43M
        const int64_t pos = avio_tell(s->pb);
82
6.43M
        int len = ff_get_line(s->pb, line, sizeof(line));
83
6.43M
        int64_t pts_start;
84
6.43M
        int duration;
85
86
6.43M
        if (!len)
87
210
            break;
88
89
6.43M
        line[strcspn(line, "\r\n")] = 0;
90
91
6.43M
        pts_start = read_ts(&p, &duration);
92
6.43M
        if (pts_start != AV_NOPTS_VALUE) {
93
3.53M
            AVPacket *sub;
94
95
3.53M
            p[strcspn(p, "\"")] = 0;
96
3.53M
            sub = ff_subtitles_queue_insert(&pjs->q, p, strlen(p), 0);
97
3.53M
            if (!sub)
98
0
                return AVERROR(ENOMEM);
99
3.53M
            sub->pos = pos;
100
3.53M
            sub->pts = pts_start;
101
3.53M
            sub->duration = duration;
102
3.53M
        }
103
6.43M
    }
104
105
1.56k
    ff_subtitles_queue_finalize(s, &pjs->q);
106
1.56k
    return 0;
107
1.56k
}
108
109
const FFInputFormat ff_pjs_demuxer = {
110
    .p.name         = "pjs",
111
    .p.long_name    = NULL_IF_CONFIG_SMALL("PJS (Phoenix Japanimation Society) subtitles"),
112
    .p.extensions   = "pjs",
113
    .priv_data_size = sizeof(PJSContext),
114
    .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
115
    .read_probe     = pjs_probe,
116
    .read_header    = pjs_read_header,
117
    .read_packet    = ff_subtitles_read_packet,
118
    .read_seek2     = ff_subtitles_read_seek,
119
    .read_close     = ff_subtitles_read_close,
120
};