Libav
dss.c
Go to the documentation of this file.
1 /*
2  * Digital Speech Standard (DSS) demuxer
3  * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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/attributes.h"
23 #include "libavutil/bswap.h"
25 #include "libavutil/intreadwrite.h"
26 
27 #include "avformat.h"
28 #include "internal.h"
29 
30 #define DSS_HEAD_OFFSET_AUTHOR 0xc
31 #define DSS_AUTHOR_SIZE 16
32 
33 #define DSS_HEAD_OFFSET_START_TIME 0x26
34 #define DSS_HEAD_OFFSET_END_TIME 0x32
35 #define DSS_TIME_SIZE 12
36 
37 #define DSS_HEAD_OFFSET_ACODEC 0x2a4
38 #define DSS_ACODEC_DSS_SP 0x0 /* SP mode */
39 #define DSS_ACODEC_G723_1 0x2 /* LP mode */
40 
41 #define DSS_HEAD_OFFSET_COMMENT 0x31e
42 #define DSS_COMMENT_SIZE 64
43 
44 #define DSS_BLOCK_SIZE 512
45 #define DSS_HEADER_SIZE (DSS_BLOCK_SIZE * 2)
46 #define DSS_AUDIO_BLOCK_HEADER_SIZE 6
47 #define DSS_FRAME_SIZE 42
48 
49 static const uint8_t frame_size[4] = { 24, 20, 4, 1 };
50 
51 typedef struct DSSDemuxContext {
52  unsigned int audio_codec;
53  int counter;
54  int swap;
56  int8_t *dss_sp_buf;
58 
59 static int dss_probe(AVProbeData *p)
60 {
61  if (AV_RL32(p->buf) != MKTAG(0x2, 'd', 's', 's'))
62  return 0;
63 
64  return AVPROBE_SCORE_MAX;
65 }
66 
67 static 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  sscanf(string, "%2d%2d%2d%2d%2d%2d", &y, &month, &d, &h, &minute, &sec);
82  /* We deal with a two-digit year here, so set the default date to 2000
83  * and hope it will never be used in the next century. */
84  snprintf(datetime, sizeof(datetime), "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
85  y + 2000, month, d, h, minute, sec);
86  return av_dict_set(&s->metadata, key, datetime, 0);
87 }
88 
89 static int dss_read_metadata_string(AVFormatContext *s, unsigned int offset,
90  unsigned int size, const char *key)
91 {
92  AVIOContext *pb = s->pb;
93  char *value;
94  int ret;
95 
96  avio_seek(pb, offset, SEEK_SET);
97 
98  value = av_mallocz(size + 1);
99  if (!value)
100  return AVERROR(ENOMEM);
101 
102  ret = avio_read(s->pb, value, size);
103  if (ret < size) {
104  ret = ret < 0 ? ret : AVERROR_EOF;
105  goto exit;
106  }
107 
108  ret = av_dict_set(&s->metadata, key, value, 0);
109 
110 exit:
111  av_free(value);
112  return ret;
113 }
114 
116 {
118  AVIOContext *pb = s->pb;
119  AVStream *st;
120  int ret;
121 
122  st = avformat_new_stream(s, NULL);
123  if (!st)
124  return AVERROR(ENOMEM);
125 
127  DSS_AUTHOR_SIZE, "author");
128  if (ret)
129  return ret;
130 
132  if (ret)
133  return ret;
134 
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) {
145  st->codecpar->sample_rate = 12000;
146  } else if (ctx->audio_codec == DSS_ACODEC_G723_1) {
148  st->codecpar->sample_rate = 8000;
149  } else {
150  avpriv_request_sample(s, "Support for codec %x in DSS",
151  ctx->audio_codec);
152  return AVERROR_PATCHWELCOME;
153  }
154 
157  st->codecpar->channels = 1;
158 
159  avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
160  st->start_time = 0;
161 
162  /* Jump over header */
163 
164  if (avio_seek(pb, DSS_HEADER_SIZE, SEEK_SET) != DSS_HEADER_SIZE)
165  return AVERROR(EIO);
166 
167  ctx->counter = 0;
168  ctx->swap = 0;
169 
170  ctx->dss_sp_buf = av_malloc(DSS_FRAME_SIZE + 1);
171  if (!ctx->dss_sp_buf)
172  return AVERROR(ENOMEM);
173 
174  return 0;
175 }
176 
178 {
180  AVIOContext *pb = s->pb;
181 
184 }
185 
187  uint8_t *dst, const uint8_t *src)
188 {
189  int i;
190 
191  if (ctx->swap) {
192  for (i = 3; i < DSS_FRAME_SIZE; i += 2)
193  dst[i] = src[i];
194 
195  for (i = 0; i < DSS_FRAME_SIZE - 2; i += 2)
196  dst[i] = src[i + 4];
197 
198  dst[1] = ctx->dss_sp_swap_byte;
199  } else {
200  memcpy(dst, src, DSS_FRAME_SIZE);
201  ctx->dss_sp_swap_byte = src[DSS_FRAME_SIZE - 2];
202  }
203 
204  /* make sure byte 40 is always 0 */
205  dst[DSS_FRAME_SIZE - 2] = 0;
206  ctx->swap ^= 1;
207 }
208 
210 {
212  int read_size, ret, offset = 0, buff_offset = 0;
213 
214  if (ctx->counter == 0)
215  dss_skip_audio_header(s, pkt);
216 
217  pkt->pos = avio_tell(s->pb);
218 
219  if (ctx->swap) {
220  read_size = DSS_FRAME_SIZE - 2;
221  buff_offset = 3;
222  } else
223  read_size = DSS_FRAME_SIZE;
224 
225  ctx->counter -= read_size;
226 
227  ret = av_new_packet(pkt, DSS_FRAME_SIZE);
228  if (ret < 0)
229  return ret;
230 
231  pkt->duration = 0;
232  pkt->stream_index = 0;
233 
234  if (ctx->counter < 0) {
235  int size2 = ctx->counter + read_size;
236 
237  ret = avio_read(s->pb, ctx->dss_sp_buf + offset + buff_offset,
238  size2 - offset);
239  if (ret < size2 - offset)
240  goto error_eof;
241 
242  dss_skip_audio_header(s, pkt);
243  offset = size2;
244  }
245 
246  ret = avio_read(s->pb, ctx->dss_sp_buf + offset + buff_offset,
247  read_size - offset);
248  if (ret < read_size - offset)
249  goto error_eof;
250 
251  dss_sp_byte_swap(ctx, pkt->data, ctx->dss_sp_buf);
252 
253  if (pkt->data[0] == 0xff)
254  return AVERROR_INVALIDDATA;
255 
256  return pkt->size;
257 
258 error_eof:
259  av_packet_unref(pkt);
260  return ret < 0 ? ret : AVERROR_EOF;
261 }
262 
264 {
266  int size, byte, ret, offset;
267 
268  if (ctx->counter == 0)
269  dss_skip_audio_header(s, pkt);
270 
271  pkt->pos = avio_tell(s->pb);
272  /* We make one byte-step here. Don't forget to add offset. */
273  byte = avio_r8(s->pb);
274  if (byte == 0xff)
275  return AVERROR_INVALIDDATA;
276 
277  size = frame_size[byte & 3];
278 
279  ctx->counter -= size;
280 
281  ret = av_new_packet(pkt, size);
282  if (ret < 0)
283  return ret;
284 
285  pkt->data[0] = byte;
286  offset = 1;
287  pkt->duration = 240;
288 
289  pkt->stream_index = 0;
290 
291  if (ctx->counter < 0) {
292  int size2 = ctx->counter + size;
293 
294  ret = avio_read(s->pb, pkt->data + offset,
295  size2 - offset);
296  if (ret < size2 - offset) {
297  av_packet_unref(pkt);
298  return ret < 0 ? ret : AVERROR_EOF;
299  }
300 
301  dss_skip_audio_header(s, pkt);
302  offset = size2;
303  }
304 
305  ret = avio_read(s->pb, pkt->data + offset, size - offset);
306  if (ret < size - offset) {
307  av_packet_unref(pkt);
308  return ret < 0 ? ret : AVERROR_EOF;
309  }
310 
311  return pkt->size;
312 }
313 
315 {
317 
318  if (ctx->audio_codec == DSS_ACODEC_DSS_SP)
319  return dss_sp_read_packet(s, pkt);
320  else
321  return dss_723_1_read_packet(s, pkt);
322 }
323 
325 {
327 
328  av_free(ctx->dss_sp_buf);
329 
330  return 0;
331 }
332 
334  .name = "dss",
335  .long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard (DSS)"),
336  .priv_data_size = sizeof(DSSDemuxContext),
341  .extensions = "dss"
342 };
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:62
Bytestream IO Context.
Definition: avio.h:104
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:54
int size
int64_t pos
byte position in stream, -1 if unknown
Definition: avcodec.h:1366
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:2986
AVInputFormat ff_dss_demuxer
Definition: dss.c:333
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3483
int size
Definition: avcodec.h:1347
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:242
#define DSS_AUDIO_BLOCK_HEADER_SIZE
Definition: dss.c:46
static void dss_skip_audio_header(AVFormatContext *s, AVPacket *pkt)
Definition: dss.c:177
Macro definitions for various function/variable attributes.
Format I/O context.
Definition: avformat.h:940
#define DSS_HEAD_OFFSET_AUTHOR
Definition: dss.c:30
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
uint8_t
static int dss_723_1_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dss.c:263
#define DSS_BLOCK_SIZE
Definition: dss.c:44
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1364
static int dss_read_close(AVFormatContext *s)
Definition: dss.c:324
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:2648
static int dss_read_header(AVFormatContext *s)
Definition: dss.c:115
uint8_t * data
Definition: avcodec.h:1346
#define AVERROR_EOF
End of file.
Definition: error.h:51
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
int8_t * dss_sp_buf
Definition: dss.c:56
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:295
uint64_t channel_layout
Audio only.
Definition: avcodec.h:3556
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:545
#define src
Definition: vp8dsp.c:254
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:84
AVDictionary * metadata
Metadata that applies to the whole file.
Definition: avformat.h:1148
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:190
#define DSS_AUTHOR_SIZE
Definition: dss.c:31
#define AVERROR(e)
Definition: error.h:43
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:148
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3479
static int dss_sp_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dss.c:209
static int dss_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: dss.c:314
int counter
Definition: dss.c:53
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:536
unsigned char * buf
Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero.
Definition: avformat.h:400
audio channel layout utility functions
#define DSS_HEAD_OFFSET_END_TIME
Definition: dss.c:34
static int dss_probe(AVProbeData *p)
Definition: dss.c:59
static int read_probe(AVProbeData *pd)
Definition: jvdec.c:55
#define DSS_COMMENT_SIZE
Definition: dss.c:42
static void dss_sp_byte_swap(DSSDemuxContext *ctx, uint8_t *dst, const uint8_t *src)
Definition: dss.c:186
static av_always_inline int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: avio.h:286
AVFormatContext * ctx
Definition: movenc.c:48
#define AV_RL32
Definition: intreadwrite.h:146
#define DSS_HEAD_OFFSET_COMMENT
Definition: dss.c:41
static int dss_read_metadata_string(AVFormatContext *s, unsigned int offset, unsigned int size, const char *key)
Definition: dss.c:89
#define DSS_TIME_SIZE
Definition: dss.c:35
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:546
Stream structure.
Definition: avformat.h:705
#define AVERROR_PATCHWELCOME
Not yet implemented in Libav, patches welcome.
Definition: error.h:57
NULL
Definition: eval.c:55
AVIOContext * pb
I/O context.
Definition: avformat.h:982
#define DSS_HEAD_OFFSET_ACODEC
Definition: dss.c:37
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:347
static int read_packet(AVFormatContext *ctx, AVPacket *pkt)
Definition: libcdio.c:114
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:68
byte swapping routines
static const uint8_t frame_size[4]
Definition: dss.c:49
This structure contains the data a format has to probe a file.
Definition: avformat.h:398
int swap
Definition: dss.c:54
#define DSS_HEADER_SIZE
Definition: dss.c:45
int dss_sp_swap_byte
Definition: dss.c:55
int sample_rate
Audio only.
Definition: avcodec.h:3564
#define AVPROBE_SCORE_MAX
maximum score
Definition: avformat.h:407
Main libavformat public API header.
#define DSS_FRAME_SIZE
Definition: dss.c:47
#define DSS_ACODEC_G723_1
Definition: dss.c:39
int64_t start_time
Decoding: pts of the first frame of the stream, in stream time base.
Definition: avformat.h:750
#define DSS_ACODEC_DSS_SP
Definition: dss.c:38
void * priv_data
Format private data.
Definition: avformat.h:968
static int dss_read_metadata_date(AVFormatContext *s, unsigned int offset, const char *key)
Definition: dss.c:67
int channels
Audio only.
Definition: avcodec.h:3560
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:529
unsigned int audio_codec
Definition: dss.c:52
AVCodecParameters * codecpar
Definition: avformat.h:831
int stream_index
Definition: avcodec.h:1348
#define AV_CH_LAYOUT_MONO
#define MKTAG(a, b, c, d)
Definition: common.h:256
This structure stores compressed data.
Definition: avcodec.h:1323
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:211