3 * Copyright (c) 2015 Paul B Mahol
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "libavutil/intreadwrite.h"
23 #include "libavcodec/internal.h"
27 typedef struct GENHDemuxContext
{
28 unsigned dsp_int_type
;
29 unsigned interleave_size
;
32 static int genh_probe(const AVProbeData
*p
)
34 if (AV_RL32(p
->buf
) != MKTAG('G','E','N','H'))
36 if (AV_RL32(p
->buf
+4) <= 0 || AV_RL32(p
->buf
+4) > 0xFFFF) // channels
39 return AVPROBE_SCORE_MAX
/ 3 * 2;
42 static int genh_read_header(AVFormatContext
*s
)
44 unsigned start_offset
, header_size
, codec
, coef_type
, coef
[2];
45 GENHDemuxContext
*c
= s
->priv_data
;
46 av_unused
unsigned coef_splitted
[2];
52 st
= avformat_new_stream(s
, NULL
);
54 return AVERROR(ENOMEM
);
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
;
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 if (st
->codecpar
->sample_rate
< 0)
71 return AVERROR_INVALIDDATA
;
74 st
->duration
= avio_rl32(s
->pb
);
76 codec
= avio_rl32(s
->pb
);
78 case 0: st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_PSX
; break;
80 case 11: st
->codecpar
->bits_per_coded_sample
= 4;
81 st
->codecpar
->block_align
= 36 * st
->codecpar
->channels
;
82 st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_IMA_WAV
; break;
83 case 2: st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_DTK
; break;
84 case 3: st
->codecpar
->codec_id
= st
->codecpar
->block_align
> 0 ?
85 AV_CODEC_ID_PCM_S16BE_PLANAR
:
86 AV_CODEC_ID_PCM_S16BE
; break;
87 case 4: st
->codecpar
->codec_id
= st
->codecpar
->block_align
> 0 ?
88 AV_CODEC_ID_PCM_S16LE_PLANAR
:
89 AV_CODEC_ID_PCM_S16LE
; break;
90 case 5: st
->codecpar
->codec_id
= st
->codecpar
->block_align
> 0 ?
91 AV_CODEC_ID_PCM_S8_PLANAR
:
92 AV_CODEC_ID_PCM_S8
; break;
93 case 6: if (st
->codecpar
->block_align
> INT_MAX
/1024)
94 return AVERROR_INVALIDDATA
;
95 st
->codecpar
->codec_id
= AV_CODEC_ID_SDX2_DPCM
; break;
96 case 7: ret
= ff_alloc_extradata(st
->codecpar
, 2);
99 AV_WL16(st
->codecpar
->extradata
, 3);
100 st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_IMA_WS
; break;
101 case 10: st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_AICA
; break;
102 case 12: st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_THP
; break;
103 case 13: st
->codecpar
->codec_id
= AV_CODEC_ID_PCM_U8
; break;
104 case 17: st
->codecpar
->codec_id
= AV_CODEC_ID_ADPCM_IMA_QT
; break;
106 avpriv_request_sample(s
, "codec %d", codec
);
107 return AVERROR_PATCHWELCOME
;
110 start_offset
= avio_rl32(s
->pb
);
111 header_size
= avio_rl32(s
->pb
);
113 if (header_size
> start_offset
)
114 return AVERROR_INVALIDDATA
;
116 if (header_size
== 0)
117 start_offset
= 0x800;
119 coef
[0] = avio_rl32(s
->pb
);
120 coef
[1] = avio_rl32(s
->pb
);
121 c
->dsp_int_type
= avio_rl32(s
->pb
);
122 coef_type
= avio_rl32(s
->pb
);
123 coef_splitted
[0] = avio_rl32(s
->pb
);
124 coef_splitted
[1] = avio_rl32(s
->pb
);
126 if (st
->codecpar
->codec_id
== AV_CODEC_ID_ADPCM_THP
) {
127 if (st
->codecpar
->channels
> 2) {
128 avpriv_request_sample(s
, "channels %d>2", st
->codecpar
->channels
);
129 return AVERROR_PATCHWELCOME
;
132 ff_alloc_extradata(st
->codecpar
, 32 * st
->codecpar
->channels
);
133 for (ch
= 0; ch
< st
->codecpar
->channels
; ch
++) {
135 avpriv_request_sample(s
, "coef_type & 1");
136 return AVERROR_PATCHWELCOME
;
138 avio_seek(s
->pb
, coef
[ch
], SEEK_SET
);
139 avio_read(s
->pb
, st
->codecpar
->extradata
+ 32 * ch
, 32);
143 if (c
->dsp_int_type
== 1) {
144 st
->codecpar
->block_align
= 8 * st
->codecpar
->channels
;
145 if (c
->interleave_size
!= 1 &&
146 c
->interleave_size
!= 2 &&
147 c
->interleave_size
!= 4)
148 return AVERROR_INVALIDDATA
;
152 if (st
->codecpar
->block_align
<= 0)
153 return AVERROR_INVALIDDATA
;
155 avio_skip(s
->pb
, start_offset
- avio_tell(s
->pb
));
157 avpriv_set_pts_info(st
, 64, 1, st
->codecpar
->sample_rate
);
162 static int genh_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
164 AVCodecParameters
*par
= s
->streams
[0]->codecpar
;
165 GENHDemuxContext
*c
= s
->priv_data
;
168 if (c
->dsp_int_type
== 1 && par
->codec_id
== AV_CODEC_ID_ADPCM_THP
&&
172 if (avio_feof(s
->pb
))
174 ret
= av_new_packet(pkt
, 8 * par
->channels
);
177 for (i
= 0; i
< 8 / c
->interleave_size
; i
++) {
178 for (ch
= 0; ch
< par
->channels
; ch
++) {
179 pkt
->data
[ch
* 8 + i
*c
->interleave_size
+0] = avio_r8(s
->pb
);
180 pkt
->data
[ch
* 8 + i
*c
->interleave_size
+1] = avio_r8(s
->pb
);
184 } else if (par
->codec_id
== AV_CODEC_ID_SDX2_DPCM
) {
185 ret
= av_get_packet(s
->pb
, pkt
, par
->block_align
* 1024);
188 ret
= av_get_packet(s
->pb
, pkt
, par
->block_align
? par
->block_align
: 1024 * par
->channels
);
191 pkt
->stream_index
= 0;
195 AVInputFormat ff_genh_demuxer
= {
197 .long_name
= NULL_IF_CONFIG_SMALL("GENeric Header"),
198 .priv_data_size
= sizeof(GENHDemuxContext
),
199 .read_probe
= genh_probe
,
200 .read_header
= genh_read_header
,
201 .read_packet
= genh_read_packet
,
202 .extensions
= "genh",