FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/dss.c
Date: 2022-12-09 07:38:14
Exec Total Coverage
Lines: 130 175 74.3%
Functions: 9 10 90.0%
Branches: 39 78 50.0%

Line Branch Exec Source
1 /*
2 * Digital Speech Standard (DSS) demuxer
3 * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "libavutil/channel_layout.h"
23 #include "libavutil/intreadwrite.h"
24
25 #include "avformat.h"
26 #include "internal.h"
27
28 #define DSS_HEAD_OFFSET_AUTHOR 0xc
29 #define DSS_AUTHOR_SIZE 16
30
31 #define DSS_HEAD_OFFSET_START_TIME 0x26
32 #define DSS_HEAD_OFFSET_END_TIME 0x32
33 #define DSS_TIME_SIZE 12
34
35 #define DSS_HEAD_OFFSET_ACODEC 0x2a4
36 #define DSS_ACODEC_DSS_SP 0x0 /* SP mode */
37 #define DSS_ACODEC_G723_1 0x2 /* LP mode */
38
39 #define DSS_HEAD_OFFSET_COMMENT 0x31e
40 #define DSS_COMMENT_SIZE 64
41
42 #define DSS_BLOCK_SIZE 512
43 #define DSS_AUDIO_BLOCK_HEADER_SIZE 6
44 #define DSS_FRAME_SIZE 42
45
46 static const uint8_t frame_size[4] = { 24, 20, 4, 1 };
47
48 typedef struct DSSDemuxContext {
49 unsigned int audio_codec;
50 int counter;
51 int swap;
52 int dss_sp_swap_byte;
53
54 int packet_size;
55 int dss_header_size;
56 } DSSDemuxContext;
57
58 6782 static int dss_probe(const AVProbeData *p)
59 {
60
2/2
✓ Branch 0 taken 6780 times.
✓ Branch 1 taken 2 times.
6782 if ( AV_RL32(p->buf) != MKTAG(0x2, 'd', 's', 's')
61
1/2
✓ Branch 0 taken 6780 times.
✗ Branch 1 not taken.
6780 && AV_RL32(p->buf) != MKTAG(0x3, 'd', 's', 's'))
62 6780 return 0;
63
64 2 return AVPROBE_SCORE_MAX;
65 }
66
67 2 static int dss_read_metadata_date(AVFormatContext *s, unsigned int offset,
68 const char *key)
69 {
70 2 AVIOContext *pb = s->pb;
71 2 char datetime[64], string[DSS_TIME_SIZE + 1] = { 0 };
72 int y, month, d, h, minute, sec;
73 int ret;
74
75 2 avio_seek(pb, offset, SEEK_SET);
76
77 2 ret = avio_read(s->pb, string, DSS_TIME_SIZE);
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < DSS_TIME_SIZE)
79 return ret < 0 ? ret : AVERROR_EOF;
80
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (sscanf(string, "%2d%2d%2d%2d%2d%2d", &y, &month, &d, &h, &minute, &sec) != 6)
82 return AVERROR_INVALIDDATA;
83 /* We deal with a two-digit year here, so set the default date to 2000
84 * and hope it will never be used in the next century. */
85 2 snprintf(datetime, sizeof(datetime), "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
86 y + 2000, month, d, h, minute, sec);
87 2 return av_dict_set(&s->metadata, key, datetime, 0);
88 }
89
90 4 static int dss_read_metadata_string(AVFormatContext *s, unsigned int offset,
91 unsigned int size, const char *key)
92 {
93 4 AVIOContext *pb = s->pb;
94 char *value;
95 int ret;
96
97 4 avio_seek(pb, offset, SEEK_SET);
98
99 4 value = av_mallocz(size + 1);
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!value)
101 return AVERROR(ENOMEM);
102
103 4 ret = avio_read(s->pb, value, size);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < size) {
105 av_free(value);
106 return ret < 0 ? ret : AVERROR_EOF;
107 }
108
109 4 return av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
110 }
111
112 2 static int dss_read_header(AVFormatContext *s)
113 {
114 2 DSSDemuxContext *ctx = s->priv_data;
115 2 AVIOContext *pb = s->pb;
116 AVStream *st;
117 int ret, version;
118
119 2 st = avformat_new_stream(s, NULL);
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!st)
121 return AVERROR(ENOMEM);
122
123 2 version = avio_r8(pb);
124 2 ctx->dss_header_size = version * DSS_BLOCK_SIZE;
125
126 2 ret = dss_read_metadata_string(s, DSS_HEAD_OFFSET_AUTHOR,
127 DSS_AUTHOR_SIZE, "author");
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret)
129 return ret;
130
131 2 ret = dss_read_metadata_date(s, DSS_HEAD_OFFSET_END_TIME, "date");
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret)
133 return ret;
134
135 2 ret = dss_read_metadata_string(s, DSS_HEAD_OFFSET_COMMENT,
136 DSS_COMMENT_SIZE, "comment");
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret)
138 return ret;
139
140 2 avio_seek(pb, DSS_HEAD_OFFSET_ACODEC, SEEK_SET);
141 2 ctx->audio_codec = avio_r8(pb);
142
143
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (ctx->audio_codec == DSS_ACODEC_DSS_SP) {
144 1 st->codecpar->codec_id = AV_CODEC_ID_DSS_SP;
145 1 st->codecpar->sample_rate = 11025;
146 1 s->bit_rate = 8 * (DSS_FRAME_SIZE - 1) * st->codecpar->sample_rate
147 1 * 512 / (506 * 264);
148
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (ctx->audio_codec == DSS_ACODEC_G723_1) {
149 1 st->codecpar->codec_id = AV_CODEC_ID_G723_1;
150 1 st->codecpar->sample_rate = 8000;
151 } else {
152 avpriv_request_sample(s, "Support for codec %x in DSS",
153 ctx->audio_codec);
154 return AVERROR_PATCHWELCOME;
155 }
156
157 2 st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
158 2 st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
159
160 2 avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
161 2 st->start_time = 0;
162
163 /* Jump over header */
164
165
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (avio_seek(pb, ctx->dss_header_size, SEEK_SET) != ctx->dss_header_size)
166 return AVERROR(EIO);
167
168 2 ctx->counter = 0;
169 2 ctx->swap = 0;
170
171 2 return 0;
172 }
173
174 8 static void dss_skip_audio_header(AVFormatContext *s, AVPacket *pkt)
175 {
176 8 DSSDemuxContext *ctx = s->priv_data;
177 8 AVIOContext *pb = s->pb;
178
179 8 avio_skip(pb, DSS_AUDIO_BLOCK_HEADER_SIZE);
180 8 ctx->counter += DSS_BLOCK_SIZE - DSS_AUDIO_BLOCK_HEADER_SIZE;
181 8 }
182
183 50 static void dss_sp_byte_swap(DSSDemuxContext *ctx, uint8_t *data)
184 {
185 int i;
186
187
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
50 if (ctx->swap) {
188
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 25 times.
525 for (i = 0; i < DSS_FRAME_SIZE - 2; i += 2)
189 500 data[i] = data[i + 4];
190
191 /* Zero the padding. */
192 25 data[DSS_FRAME_SIZE] = 0;
193 25 data[1] = ctx->dss_sp_swap_byte;
194 } else {
195 25 ctx->dss_sp_swap_byte = data[DSS_FRAME_SIZE - 2];
196 }
197
198 /* make sure byte 40 is always 0 */
199 50 data[DSS_FRAME_SIZE - 2] = 0;
200 50 ctx->swap ^= 1;
201 50 }
202
203 50 static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt)
204 {
205 50 DSSDemuxContext *ctx = s->priv_data;
206 50 int read_size, ret, offset = 0, buff_offset = 0;
207 50 int64_t pos = avio_tell(s->pb);
208
209
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 48 times.
50 if (ctx->counter == 0)
210 2 dss_skip_audio_header(s, pkt);
211
212
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
50 if (ctx->swap) {
213 25 read_size = DSS_FRAME_SIZE - 2;
214 25 buff_offset = 3;
215 } else
216 25 read_size = DSS_FRAME_SIZE;
217
218 50 ret = av_new_packet(pkt, DSS_FRAME_SIZE);
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < 0)
220 return ret;
221
222 50 pkt->duration = 264;
223 50 pkt->pos = pos;
224 50 pkt->stream_index = 0;
225
226
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 47 times.
50 if (ctx->counter < read_size) {
227 3 ret = avio_read(s->pb, pkt->data + buff_offset,
228 ctx->counter);
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret < ctx->counter)
230 goto error_eof;
231
232 3 offset = ctx->counter;
233 3 dss_skip_audio_header(s, pkt);
234 }
235 50 ctx->counter -= read_size;
236
237 /* This will write one byte into pkt's padding if buff_offset == 3 */
238 50 ret = avio_read(s->pb, pkt->data + offset + buff_offset,
239 read_size - offset);
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < read_size - offset)
241 goto error_eof;
242
243 50 dss_sp_byte_swap(ctx, pkt->data);
244
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ctx->dss_sp_swap_byte < 0) {
246 return AVERROR(EAGAIN);
247 }
248
249 50 return 0;
250
251 error_eof:
252 return ret < 0 ? ret : AVERROR_EOF;
253 }
254
255 50 static int dss_723_1_read_packet(AVFormatContext *s, AVPacket *pkt)
256 {
257 50 DSSDemuxContext *ctx = s->priv_data;
258 50 AVStream *st = s->streams[0];
259 int size, byte, ret, offset;
260 50 int64_t pos = avio_tell(s->pb);
261
262
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 49 times.
50 if (ctx->counter == 0)
263 1 dss_skip_audio_header(s, pkt);
264
265 /* We make one byte-step here. Don't forget to add offset. */
266 50 byte = avio_r8(s->pb);
267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (byte == 0xff)
268 return AVERROR_INVALIDDATA;
269
270 50 size = frame_size[byte & 3];
271
272 50 ctx->packet_size = size;
273 50 ctx->counter--;
274
275 50 ret = av_new_packet(pkt, size);
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < 0)
277 return ret;
278 50 pkt->pos = pos;
279
280 50 pkt->data[0] = byte;
281 50 offset = 1;
282 50 pkt->duration = 240;
283 50 s->bit_rate = 8LL * size-- * st->codecpar->sample_rate * 512 / (506 * pkt->duration);
284
285 50 pkt->stream_index = 0;
286
287
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 48 times.
50 if (ctx->counter < size) {
288 2 ret = avio_read(s->pb, pkt->data + offset,
289 ctx->counter);
290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < ctx->counter)
291 return ret < 0 ? ret : AVERROR_EOF;
292
293 2 offset += ctx->counter;
294 2 size -= ctx->counter;
295 2 ctx->counter = 0;
296 2 dss_skip_audio_header(s, pkt);
297 }
298 50 ctx->counter -= size;
299
300 50 ret = avio_read(s->pb, pkt->data + offset, size);
301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < size)
302 return ret < 0 ? ret : AVERROR_EOF;
303
304 50 return 0;
305 }
306
307 100 static int dss_read_packet(AVFormatContext *s, AVPacket *pkt)
308 {
309 100 DSSDemuxContext *ctx = s->priv_data;
310
311
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 50 times.
100 if (ctx->audio_codec == DSS_ACODEC_DSS_SP)
312 50 return dss_sp_read_packet(s, pkt);
313 else
314 50 return dss_723_1_read_packet(s, pkt);
315 }
316
317 static int dss_read_seek(AVFormatContext *s, int stream_index,
318 int64_t timestamp, int flags)
319 {
320 DSSDemuxContext *ctx = s->priv_data;
321 int64_t ret, seekto;
322 uint8_t header[DSS_AUDIO_BLOCK_HEADER_SIZE];
323 int offset;
324
325 if (ctx->audio_codec == DSS_ACODEC_DSS_SP)
326 seekto = timestamp / 264 * 41 / 506 * 512;
327 else
328 seekto = timestamp / 240 * ctx->packet_size / 506 * 512;
329
330 if (seekto < 0)
331 seekto = 0;
332
333 seekto += ctx->dss_header_size;
334
335 ret = avio_seek(s->pb, seekto, SEEK_SET);
336 if (ret < 0)
337 return ret;
338
339 avio_read(s->pb, header, DSS_AUDIO_BLOCK_HEADER_SIZE);
340 ctx->swap = !!(header[0] & 0x80);
341 offset = 2*header[1] + 2*ctx->swap;
342 if (offset < DSS_AUDIO_BLOCK_HEADER_SIZE)
343 return AVERROR_INVALIDDATA;
344 if (offset == DSS_AUDIO_BLOCK_HEADER_SIZE) {
345 ctx->counter = 0;
346 offset = avio_skip(s->pb, -DSS_AUDIO_BLOCK_HEADER_SIZE);
347 } else {
348 ctx->counter = DSS_BLOCK_SIZE - offset;
349 offset = avio_skip(s->pb, offset - DSS_AUDIO_BLOCK_HEADER_SIZE);
350 }
351 ctx->dss_sp_swap_byte = -1;
352 return 0;
353 }
354
355
356 const AVInputFormat ff_dss_demuxer = {
357 .name = "dss",
358 .long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard (DSS)"),
359 .priv_data_size = sizeof(DSSDemuxContext),
360 .read_probe = dss_probe,
361 .read_header = dss_read_header,
362 .read_packet = dss_read_packet,
363 .read_seek = dss_read_seek,
364 .extensions = "dss"
365 };
366