]> git.sesse.net Git - ffmpeg/blob - libavformat/adxdec.c
a265c87dead49c4ad5e619b22ff165bc98312d95
[ffmpeg] / libavformat / adxdec.c
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
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
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
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 };