1 /*
2 * Copyright (c) 2011 Justin Ruggles
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 * CRI ADX demuxer
24 */
25
26 #include "libavutil/intreadwrite.h"
27 #include "avformat.h"
28 #include "internal.h"
29
30 #define BLOCK_SIZE 18
31 #define BLOCK_SAMPLES 32
32
33 typedef struct ADXDemuxerContext {
34 int header_size;
35 } ADXDemuxerContext;
36
adx_probe(const AVProbeData * p)37 static int adx_probe(const AVProbeData *p)
38 {
39 int offset;
40 if (AV_RB16(p->buf) != 0x8000)
41 return 0;
42 offset = AV_RB16(&p->buf[2]);
43 if ( offset < 8
44 || offset > p->buf_size - 4
45 || memcmp(p->buf + offset - 2, "(c)CRI", 6))
46 return 0;
47 return AVPROBE_SCORE_MAX * 3 / 4;
48 }
49
adx_read_packet(AVFormatContext * s,AVPacket * pkt)50 static int adx_read_packet(AVFormatContext *s, AVPacket *pkt)
51 {
52 ADXDemuxerContext *c = s->priv_data;
53 AVCodecParameters *par = s->streams[0]->codecpar;
54 int ret, size;
55
56 if (avio_feof(s->pb))
57 return AVERROR_EOF;
58
59 if (par->channels <= 0) {
60 av_log(s, AV_LOG_ERROR, "invalid number of channels %d\n", par->channels);
61 return AVERROR_INVALIDDATA;
62 }
63
64 size = BLOCK_SIZE * par->channels;
65
66 pkt->pos = avio_tell(s->pb);
67 pkt->stream_index = 0;
68
69 ret = av_get_packet(s->pb, pkt, size * 128);
70 if (ret < 0)
71 return ret;
72 if ((ret % size) && ret >= size) {
73 size = ret - (ret % size);
74 av_shrink_packet(pkt, size);
75 pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
76 } else if (ret < size) {
77 return AVERROR(EIO);
78 } else {
79 size = ret;
80 }
81
82 pkt->duration = size / (BLOCK_SIZE * par->channels);
83 pkt->pts = (pkt->pos - c->header_size) / (BLOCK_SIZE * par->channels);
84
85 return 0;
86 }
87
adx_read_header(AVFormatContext * s)88 static int adx_read_header(AVFormatContext *s)
89 {
90 ADXDemuxerContext *c = s->priv_data;
91 AVCodecParameters *par;
92 int ret;
93 AVStream *st = avformat_new_stream(s, NULL);
94 if (!st)
95 return AVERROR(ENOMEM);
96 par = s->streams[0]->codecpar;
97
98 if (avio_rb16(s->pb) != 0x8000)
99 return AVERROR_INVALIDDATA;
100 c->header_size = avio_rb16(s->pb) + 4;
101 avio_seek(s->pb, -4, SEEK_CUR);
102
103 if ((ret = ff_get_extradata(s, par, s->pb, c->header_size)) < 0)
104 return ret;
105
106 if (par->extradata_size < 12) {
107 av_log(s, AV_LOG_ERROR, "Invalid extradata size.\n");
108 return AVERROR_INVALIDDATA;
109 }
110 par->channels = AV_RB8 (par->extradata + 7);
111 par->sample_rate = AV_RB32(par->extradata + 8);
112
113 if (par->channels <= 0) {
114 av_log(s, AV_LOG_ERROR, "invalid number of channels %d\n", par->channels);
115 return AVERROR_INVALIDDATA;
116 }
117
118 if (par->sample_rate <= 0) {
119 av_log(s, AV_LOG_ERROR, "Invalid sample rate %d\n", par->sample_rate);
120 return AVERROR_INVALIDDATA;
121 }
122
123 par->codec_type = AVMEDIA_TYPE_AUDIO;
124 par->codec_id = s->iformat->raw_codec_id;
125 par->bit_rate = (int64_t)par->sample_rate * par->channels * BLOCK_SIZE * 8LL / BLOCK_SAMPLES;
126
127 avpriv_set_pts_info(st, 64, BLOCK_SAMPLES, par->sample_rate);
128
129 return 0;
130 }
131
132 AVInputFormat ff_adx_demuxer = {
133 .name = "adx",
134 .long_name = NULL_IF_CONFIG_SMALL("CRI ADX"),
135 .read_probe = adx_probe,
136 .priv_data_size = sizeof(ADXDemuxerContext),
137 .read_header = adx_read_header,
138 .read_packet = adx_read_packet,
139 .extensions = "adx",
140 .raw_codec_id = AV_CODEC_ID_ADPCM_ADX,
141 .flags = AVFMT_GENERIC_INDEX,
142 };
143