blob: dd4e76d3d95f2e67dfa28c18476e6aa68c5f4252
1 | /* |
2 | * GENH demuxer |
3 | * Copyright (c) 2015 Paul B Mahol |
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/intreadwrite.h" |
23 | #include "libavcodec/internal.h" |
24 | #include "avformat.h" |
25 | #include "internal.h" |
26 | |
27 | typedef struct GENHDemuxContext { |
28 | unsigned dsp_int_type; |
29 | unsigned interleave_size; |
30 | } GENHDemuxContext; |
31 | |
32 | static int genh_probe(AVProbeData *p) |
33 | { |
34 | if (AV_RL32(p->buf) != MKTAG('G','E','N','H')) |
35 | return 0; |
36 | if (AV_RL32(p->buf+4) <= 0 || AV_RL32(p->buf+4) > 0xFFFF) // channels |
37 | return 0; |
38 | |
39 | return AVPROBE_SCORE_MAX / 3 * 2; |
40 | } |
41 | |
42 | static int genh_read_header(AVFormatContext *s) |
43 | { |
44 | unsigned start_offset, header_size, codec, coef_type, coef[2]; |
45 | GENHDemuxContext *c = s->priv_data; |
46 | av_unused unsigned coef_splitted[2]; |
47 | int align, ch, ret; |
48 | AVStream *st; |
49 | |
50 | avio_skip(s->pb, 4); |
51 | |
52 | st = avformat_new_stream(s, NULL); |
53 | if (!st) |
54 | return AVERROR(ENOMEM); |
55 | |
56 | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
57 | st->codecpar->channels = avio_rl32(s->pb); |
58 | if (st->codecpar->channels <= 0 || st->codecpar->channels > FF_SANE_NB_CHANNELS) |
59 | return AVERROR_INVALIDDATA; |
60 | if (st->codecpar->channels == 1) |
61 | st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; |
62 | else if (st->codecpar->channels == 2) |
63 | st->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; |
64 | align = |
65 | c->interleave_size = avio_rl32(s->pb); |
66 | if (align < 0 || align > INT_MAX / st->codecpar->channels) |
67 | return AVERROR_INVALIDDATA; |
68 | st->codecpar->block_align = align * st->codecpar->channels; |
69 | st->codecpar->sample_rate = avio_rl32(s->pb); |
70 | avio_skip(s->pb, 4); |
71 | st->duration = avio_rl32(s->pb); |
72 | |
73 | codec = avio_rl32(s->pb); |
74 | switch (codec) { |
75 | case 0: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_PSX; break; |
76 | case 1: |
77 | case 11: st->codecpar->bits_per_coded_sample = 4; |
78 | st->codecpar->block_align = 36 * st->codecpar->channels; |
79 | st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_WAV; break; |
80 | case 2: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_DTK; break; |
81 | case 3: st->codecpar->codec_id = st->codecpar->block_align > 0 ? |
82 | AV_CODEC_ID_PCM_S16BE_PLANAR : |
83 | AV_CODEC_ID_PCM_S16BE; break; |
84 | case 4: st->codecpar->codec_id = st->codecpar->block_align > 0 ? |
85 | AV_CODEC_ID_PCM_S16LE_PLANAR : |
86 | AV_CODEC_ID_PCM_S16LE; break; |
87 | case 5: st->codecpar->codec_id = st->codecpar->block_align > 0 ? |
88 | AV_CODEC_ID_PCM_S8_PLANAR : |
89 | AV_CODEC_ID_PCM_S8; break; |
90 | case 6: st->codecpar->codec_id = AV_CODEC_ID_SDX2_DPCM; break; |
91 | case 7: ret = ff_alloc_extradata(st->codecpar, 2); |
92 | if (ret < 0) |
93 | return ret; |
94 | AV_WL16(st->codecpar->extradata, 3); |
95 | st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_WS; break; |
96 | case 10: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_AICA; break; |
97 | case 12: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_THP; break; |
98 | case 13: st->codecpar->codec_id = AV_CODEC_ID_PCM_U8; break; |
99 | case 17: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_QT; break; |
100 | default: |
101 | avpriv_request_sample(s, "codec %d", codec); |
102 | return AVERROR_PATCHWELCOME; |
103 | } |
104 | |
105 | start_offset = avio_rl32(s->pb); |
106 | header_size = avio_rl32(s->pb); |
107 | |
108 | if (header_size > start_offset) |
109 | return AVERROR_INVALIDDATA; |
110 | |
111 | if (header_size == 0) |
112 | start_offset = 0x800; |
113 | |
114 | coef[0] = avio_rl32(s->pb); |
115 | coef[1] = avio_rl32(s->pb); |
116 | c->dsp_int_type = avio_rl32(s->pb); |
117 | coef_type = avio_rl32(s->pb); |
118 | coef_splitted[0] = avio_rl32(s->pb); |
119 | coef_splitted[1] = avio_rl32(s->pb); |
120 | |
121 | if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_THP) { |
122 | if (st->codecpar->channels > 2) { |
123 | avpriv_request_sample(s, "channels %d>2", st->codecpar->channels); |
124 | return AVERROR_PATCHWELCOME; |
125 | } |
126 | |
127 | ff_alloc_extradata(st->codecpar, 32 * st->codecpar->channels); |
128 | for (ch = 0; ch < st->codecpar->channels; ch++) { |
129 | if (coef_type & 1) { |
130 | avpriv_request_sample(s, "coef_type & 1"); |
131 | return AVERROR_PATCHWELCOME; |
132 | } else { |
133 | avio_seek(s->pb, coef[ch], SEEK_SET); |
134 | avio_read(s->pb, st->codecpar->extradata + 32 * ch, 32); |
135 | } |
136 | } |
137 | |
138 | if (c->dsp_int_type == 1) { |
139 | st->codecpar->block_align = 8 * st->codecpar->channels; |
140 | if (c->interleave_size != 1 && |
141 | c->interleave_size != 2 && |
142 | c->interleave_size != 4) |
143 | return AVERROR_INVALIDDATA; |
144 | } |
145 | } |
146 | |
147 | avio_skip(s->pb, start_offset - avio_tell(s->pb)); |
148 | |
149 | avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | static int genh_read_packet(AVFormatContext *s, AVPacket *pkt) |
155 | { |
156 | AVCodecParameters *par = s->streams[0]->codecpar; |
157 | GENHDemuxContext *c = s->priv_data; |
158 | int ret; |
159 | |
160 | if (c->dsp_int_type == 1 && par->codec_id == AV_CODEC_ID_ADPCM_THP && |
161 | par->channels > 1) { |
162 | int i, ch; |
163 | |
164 | if (avio_feof(s->pb)) |
165 | return AVERROR_EOF; |
166 | ret = av_new_packet(pkt, 8 * par->channels); |
167 | if (ret < 0) |
168 | return ret; |
169 | for (i = 0; i < 8 / c->interleave_size; i++) { |
170 | for (ch = 0; ch < par->channels; ch++) { |
171 | pkt->data[ch * 8 + i*c->interleave_size+0] = avio_r8(s->pb); |
172 | pkt->data[ch * 8 + i*c->interleave_size+1] = avio_r8(s->pb); |
173 | } |
174 | } |
175 | ret = 0; |
176 | } else if (par->codec_id == AV_CODEC_ID_SDX2_DPCM) { |
177 | ret = av_get_packet(s->pb, pkt, par->block_align * 1024); |
178 | |
179 | } else { |
180 | ret = av_get_packet(s->pb, pkt, par->block_align ? par->block_align : 1024 * par->channels); |
181 | } |
182 | |
183 | pkt->stream_index = 0; |
184 | return ret; |
185 | } |
186 | |
187 | AVInputFormat ff_genh_demuxer = { |
188 | .name = "genh", |
189 | .long_name = NULL_IF_CONFIG_SMALL("GENeric Header"), |
190 | .priv_data_size = sizeof(GENHDemuxContext), |
191 | .read_probe = genh_probe, |
192 | .read_header = genh_read_header, |
193 | .read_packet = genh_read_packet, |
194 | .extensions = "genh", |
195 | }; |
196 |