xref: /third_party/ffmpeg/libavformat/dss.c (revision cabdff1a)
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
46static const uint8_t frame_size[4] = { 24, 20, 4, 1 };
47
48typedef 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
58static int dss_probe(const AVProbeData *p)
59{
60    if (   AV_RL32(p->buf) != MKTAG(0x2, 'd', 's', 's')
61        && AV_RL32(p->buf) != MKTAG(0x3, 'd', 's', 's'))
62        return 0;
63
64    return AVPROBE_SCORE_MAX;
65}
66
67static int dss_read_metadata_date(AVFormatContext *s, unsigned int offset,
68                                  const char *key)
69{
70    AVIOContext *pb = s->pb;
71    char datetime[64], string[DSS_TIME_SIZE + 1] = { 0 };
72    int y, month, d, h, minute, sec;
73    int ret;
74
75    avio_seek(pb, offset, SEEK_SET);
76
77    ret = avio_read(s->pb, string, DSS_TIME_SIZE);
78    if (ret < DSS_TIME_SIZE)
79        return ret < 0 ? ret : AVERROR_EOF;
80
81    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    snprintf(datetime, sizeof(datetime), "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
86             y + 2000, month, d, h, minute, sec);
87    return av_dict_set(&s->metadata, key, datetime, 0);
88}
89
90static int dss_read_metadata_string(AVFormatContext *s, unsigned int offset,
91                                    unsigned int size, const char *key)
92{
93    AVIOContext *pb = s->pb;
94    char *value;
95    int ret;
96
97    avio_seek(pb, offset, SEEK_SET);
98
99    value = av_mallocz(size + 1);
100    if (!value)
101        return AVERROR(ENOMEM);
102
103    ret = avio_read(s->pb, value, size);
104    if (ret < size) {
105        av_free(value);
106        return ret < 0 ? ret : AVERROR_EOF;
107    }
108
109    return av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
110}
111
112static int dss_read_header(AVFormatContext *s)
113{
114    DSSDemuxContext *ctx = s->priv_data;
115    AVIOContext *pb = s->pb;
116    AVStream *st;
117    int ret, version;
118
119    st = avformat_new_stream(s, NULL);
120    if (!st)
121        return AVERROR(ENOMEM);
122
123    version = avio_r8(pb);
124    ctx->dss_header_size = version * DSS_BLOCK_SIZE;
125
126    ret = dss_read_metadata_string(s, DSS_HEAD_OFFSET_AUTHOR,
127                                   DSS_AUTHOR_SIZE, "author");
128    if (ret)
129        return ret;
130
131    ret = dss_read_metadata_date(s, DSS_HEAD_OFFSET_END_TIME, "date");
132    if (ret)
133        return ret;
134
135    ret = dss_read_metadata_string(s, DSS_HEAD_OFFSET_COMMENT,
136                                   DSS_COMMENT_SIZE, "comment");
137    if (ret)
138        return ret;
139
140    avio_seek(pb, DSS_HEAD_OFFSET_ACODEC, SEEK_SET);
141    ctx->audio_codec = avio_r8(pb);
142
143    if (ctx->audio_codec == DSS_ACODEC_DSS_SP) {
144        st->codecpar->codec_id    = AV_CODEC_ID_DSS_SP;
145        st->codecpar->sample_rate = 11025;
146        s->bit_rate = 8 * (DSS_FRAME_SIZE - 1) * st->codecpar->sample_rate
147                        * 512 / (506 * 264);
148    } else if (ctx->audio_codec == DSS_ACODEC_G723_1) {
149        st->codecpar->codec_id    = AV_CODEC_ID_G723_1;
150        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    st->codecpar->codec_type     = AVMEDIA_TYPE_AUDIO;
158    st->codecpar->ch_layout      = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
159
160    avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
161    st->start_time = 0;
162
163    /* Jump over header */
164
165    if (avio_seek(pb, ctx->dss_header_size, SEEK_SET) != ctx->dss_header_size)
166        return AVERROR(EIO);
167
168    ctx->counter = 0;
169    ctx->swap    = 0;
170
171    return 0;
172}
173
174static void dss_skip_audio_header(AVFormatContext *s, AVPacket *pkt)
175{
176    DSSDemuxContext *ctx = s->priv_data;
177    AVIOContext *pb = s->pb;
178
179    avio_skip(pb, DSS_AUDIO_BLOCK_HEADER_SIZE);
180    ctx->counter += DSS_BLOCK_SIZE - DSS_AUDIO_BLOCK_HEADER_SIZE;
181}
182
183static void dss_sp_byte_swap(DSSDemuxContext *ctx, uint8_t *data)
184{
185    int i;
186
187    if (ctx->swap) {
188        for (i = 0; i < DSS_FRAME_SIZE - 2; i += 2)
189            data[i] = data[i + 4];
190
191        /* Zero the padding. */
192        data[DSS_FRAME_SIZE] = 0;
193        data[1] = ctx->dss_sp_swap_byte;
194    } else {
195        ctx->dss_sp_swap_byte = data[DSS_FRAME_SIZE - 2];
196    }
197
198    /* make sure byte 40 is always 0 */
199    data[DSS_FRAME_SIZE - 2] = 0;
200    ctx->swap             ^= 1;
201}
202
203static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt)
204{
205    DSSDemuxContext *ctx = s->priv_data;
206    int read_size, ret, offset = 0, buff_offset = 0;
207    int64_t pos = avio_tell(s->pb);
208
209    if (ctx->counter == 0)
210        dss_skip_audio_header(s, pkt);
211
212    if (ctx->swap) {
213        read_size   = DSS_FRAME_SIZE - 2;
214        buff_offset = 3;
215    } else
216        read_size = DSS_FRAME_SIZE;
217
218    ret = av_new_packet(pkt, DSS_FRAME_SIZE);
219    if (ret < 0)
220        return ret;
221
222    pkt->duration     = 264;
223    pkt->pos = pos;
224    pkt->stream_index = 0;
225
226    if (ctx->counter < read_size) {
227        ret = avio_read(s->pb, pkt->data + buff_offset,
228                        ctx->counter);
229        if (ret < ctx->counter)
230            goto error_eof;
231
232        offset = ctx->counter;
233        dss_skip_audio_header(s, pkt);
234    }
235    ctx->counter -= read_size;
236
237    /* This will write one byte into pkt's padding if buff_offset == 3 */
238    ret = avio_read(s->pb, pkt->data + offset + buff_offset,
239                    read_size - offset);
240    if (ret < read_size - offset)
241        goto error_eof;
242
243    dss_sp_byte_swap(ctx, pkt->data);
244
245    if (ctx->dss_sp_swap_byte < 0) {
246        return AVERROR(EAGAIN);
247    }
248
249    return 0;
250
251error_eof:
252    return ret < 0 ? ret : AVERROR_EOF;
253}
254
255static int dss_723_1_read_packet(AVFormatContext *s, AVPacket *pkt)
256{
257    DSSDemuxContext *ctx = s->priv_data;
258    AVStream *st = s->streams[0];
259    int size, byte, ret, offset;
260    int64_t pos = avio_tell(s->pb);
261
262    if (ctx->counter == 0)
263        dss_skip_audio_header(s, pkt);
264
265    /* We make one byte-step here. Don't forget to add offset. */
266    byte = avio_r8(s->pb);
267    if (byte == 0xff)
268        return AVERROR_INVALIDDATA;
269
270    size = frame_size[byte & 3];
271
272    ctx->packet_size = size;
273    ctx->counter--;
274
275    ret = av_new_packet(pkt, size);
276    if (ret < 0)
277        return ret;
278    pkt->pos = pos;
279
280    pkt->data[0]  = byte;
281    offset        = 1;
282    pkt->duration = 240;
283    s->bit_rate = 8LL * size-- * st->codecpar->sample_rate * 512 / (506 * pkt->duration);
284
285    pkt->stream_index = 0;
286
287    if (ctx->counter < size) {
288        ret = avio_read(s->pb, pkt->data + offset,
289                        ctx->counter);
290        if (ret < ctx->counter)
291            return ret < 0 ? ret : AVERROR_EOF;
292
293        offset += ctx->counter;
294        size   -= ctx->counter;
295        ctx->counter = 0;
296        dss_skip_audio_header(s, pkt);
297    }
298    ctx->counter -= size;
299
300    ret = avio_read(s->pb, pkt->data + offset, size);
301    if (ret < size)
302        return ret < 0 ? ret : AVERROR_EOF;
303
304    return 0;
305}
306
307static int dss_read_packet(AVFormatContext *s, AVPacket *pkt)
308{
309    DSSDemuxContext *ctx = s->priv_data;
310
311    if (ctx->audio_codec == DSS_ACODEC_DSS_SP)
312        return dss_sp_read_packet(s, pkt);
313    else
314        return dss_723_1_read_packet(s, pkt);
315}
316
317static 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
356const 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