Coverage Report

Created: 2024-09-06 07:53

/src/ffmpeg/libavformat/s337m.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017 foo86
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 "libavutil/intreadwrite.h"
22
#include "avformat.h"
23
#include "demux.h"
24
#include "internal.h"
25
#include "spdif.h"
26
27
1.38G
#define MARKER_16LE         0x72F81F4E
28
1.38G
#define MARKER_20LE         0x20876FF0E154
29
1.38G
#define MARKER_24LE         0x72F8961F4EA5
30
31
2.76G
#define IS_16LE_MARKER(state)   ((state & 0xFFFFFFFF) == MARKER_16LE)
32
2.76G
#define IS_20LE_MARKER(state)   ((state & 0xF0FFFFF0FFFF) == MARKER_20LE)
33
1.38G
#define IS_24LE_MARKER(state)   ((state & 0xFFFFFFFFFFFF) == MARKER_24LE)
34
1.38G
#define IS_LE_MARKER(state)     (IS_16LE_MARKER(state) || IS_20LE_MARKER(state) || IS_24LE_MARKER(state))
35
36
static int s337m_get_offset_and_codec(void *avc,
37
                                      uint64_t state,
38
                                      int data_type, int data_size,
39
                                      int *offset, enum AVCodecID *codec)
40
299k
{
41
299k
    int word_bits;
42
43
299k
    if (IS_16LE_MARKER(state)) {
44
276k
        word_bits = 16;
45
276k
    } else if (IS_20LE_MARKER(state)) {
46
4.46k
        data_type >>= 8;
47
4.46k
        data_size >>= 4;
48
4.46k
        word_bits = 20;
49
18.8k
    } else {
50
18.8k
        data_type >>= 8;
51
18.8k
        word_bits = 24;
52
18.8k
    }
53
54
299k
    if ((data_type & 0x1F) != 0x1C) {
55
278k
        if (avc)
56
103
            avpriv_report_missing_feature(avc, "Data type %#x in SMPTE 337M", data_type & 0x1F);
57
278k
        return AVERROR_PATCHWELCOME;
58
278k
    }
59
60
20.6k
    if (codec)
61
4.36k
        *codec = AV_CODEC_ID_DOLBY_E;
62
63
20.6k
    switch (data_size / word_bits) {
64
2.22k
    case 3648:
65
2.22k
        *offset = 1920;
66
2.22k
        break;
67
810
    case 3644:
68
810
        *offset = 2002;
69
810
        break;
70
787
    case 3640:
71
787
        *offset = 2000;
72
787
        break;
73
7.13k
    case 3040:
74
7.13k
        *offset = 1601;
75
7.13k
        break;
76
9.67k
    default:
77
9.67k
        if (avc)
78
80
            avpriv_report_missing_feature(avc, "Dolby E data size %d in SMPTE 337M", data_size);
79
9.67k
        return AVERROR_PATCHWELCOME;
80
20.6k
    }
81
82
10.9k
    *offset -= 4;
83
10.9k
    *offset *= (word_bits + 7 >> 3) * 2;
84
10.9k
    return 0;
85
20.6k
}
86
87
static int s337m_probe(const AVProbeData *p)
88
358k
{
89
358k
    uint64_t state = 0;
90
358k
    int markers[3] = { 0 };
91
358k
    int i, pos, sum, max, data_type, data_size, offset;
92
358k
    uint8_t *buf;
93
94
1.37G
    for (pos = 0; pos < p->buf_size; pos++) {
95
1.37G
        state = (state << 8) | p->buf[pos];
96
1.37G
        if (!IS_LE_MARKER(state))
97
1.37G
            continue;
98
99
294k
        buf = p->buf + pos + 1;
100
294k
        if (IS_16LE_MARKER(state)) {
101
271k
            data_type = AV_RL16(buf    );
102
271k
            data_size = AV_RL16(buf + 2);
103
271k
        } else {
104
23.0k
            data_type = AV_RL24(buf    );
105
23.0k
            data_size = AV_RL24(buf + 3);
106
23.0k
        }
107
108
294k
        if (s337m_get_offset_and_codec(NULL, state, data_type, data_size, &offset, NULL))
109
288k
            continue;
110
111
6.67k
        i = IS_16LE_MARKER(state) ? 0 : IS_20LE_MARKER(state) ? 1 : 2;
112
6.67k
        markers[i]++;
113
114
6.67k
        pos  += IS_16LE_MARKER(state) ? 4 : 6;
115
6.67k
        pos  += offset;
116
6.67k
        state = 0;
117
6.67k
    }
118
119
358k
    sum = max = 0;
120
1.43M
    for (i = 0; i < FF_ARRAY_ELEMS(markers); i++) {
121
1.07M
        sum += markers[i];
122
1.07M
        if (markers[max] < markers[i])
123
148
            max = i;
124
1.07M
    }
125
126
358k
    if (markers[max] > 3 && markers[max] * 4 > sum * 3)
127
324
        return AVPROBE_SCORE_EXTENSION + 1;
128
129
358k
    return 0;
130
358k
}
131
132
static int s337m_read_header(AVFormatContext *s)
133
5.27k
{
134
5.27k
    s->ctx_flags |= AVFMTCTX_NOHEADER;
135
5.27k
    return 0;
136
5.27k
}
137
138
static void bswap_buf24(uint8_t *data, int size)
139
203
{
140
203
    int i;
141
142
670k
    for (i = 0; i < size / 3; i++, data += 3)
143
670k
        FFSWAP(uint8_t, data[0], data[2]);
144
203
}
145
146
static int s337m_read_packet(AVFormatContext *s, AVPacket *pkt)
147
14.6k
{
148
14.6k
    AVIOContext *pb = s->pb;
149
14.6k
    uint64_t state = 0;
150
14.6k
    int ret, data_type, data_size, offset;
151
14.6k
    enum AVCodecID codec;
152
153
8.36M
    while (!IS_LE_MARKER(state)) {
154
8.35M
        state = (state << 8) | avio_r8(pb);
155
8.35M
        if (avio_feof(pb))
156
10.1k
            return AVERROR_EOF;
157
8.35M
    }
158
159
4.46k
    if (IS_16LE_MARKER(state)) {
160
4.17k
        data_type = avio_rl16(pb);
161
4.17k
        data_size = avio_rl16(pb);
162
4.17k
    } else {
163
289
        data_type = avio_rl24(pb);
164
289
        data_size = avio_rl24(pb);
165
289
    }
166
167
4.46k
    if ((ret = s337m_get_offset_and_codec(s, state, data_type, data_size, &offset, &codec)) < 0)
168
183
        return ret;
169
170
4.28k
    if ((ret = av_get_packet(pb, pkt, offset)) != offset)
171
88
        return ret < 0 ? ret : AVERROR_EOF;
172
173
4.19k
    if (IS_16LE_MARKER(state))
174
3.99k
        ff_spdif_bswap_buf16((uint16_t *)pkt->data, (uint16_t *)pkt->data, pkt->size >> 1);
175
203
    else
176
203
        bswap_buf24(pkt->data, pkt->size);
177
178
4.19k
    if (!s->nb_streams) {
179
161
        AVStream *st = avformat_new_stream(s, NULL);
180
161
        if (!st) {
181
0
            return AVERROR(ENOMEM);
182
0
        }
183
161
        st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
184
161
        st->codecpar->codec_id   = codec;
185
161
        ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
186
161
    }
187
188
4.19k
    return 0;
189
4.19k
}
190
191
const FFInputFormat ff_s337m_demuxer = {
192
    .p.name         = "s337m",
193
    .p.long_name    = NULL_IF_CONFIG_SMALL("SMPTE 337M"),
194
    .p.flags        = AVFMT_GENERIC_INDEX,
195
    .read_probe     = s337m_probe,
196
    .read_header    = s337m_read_header,
197
    .read_packet    = s337m_read_packet,
198
};