3 * Copyright (c) 2001,2003 BERO
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
24 #include "bytestream.h"
30 * SEGA CRI adx codecs.
32 * Reference documents:
33 * http://ku-www.ss.titech.ac.jp/~yatsushi/adx.html
34 * adx2wav & wav2adx http://www.geocities.co.jp/Playtown/2004/
37 static void adx_encode(ADXContext
*c
, uint8_t *adx
, const int16_t *wav
,
38 ADXChannelState
*prev
, int channels
)
46 int data
[BLOCK_SAMPLES
];
50 for (i
= 0, j
= 0; j
< 32; i
+= channels
, j
++) {
52 d
= ((s0
<< COEFF_BITS
) - c
->coeff
[0] * s1
- c
->coeff
[1] * s2
) >> COEFF_BITS
;
64 if (max
== 0 && min
== 0) {
65 memset(adx
, 0, BLOCK_SIZE
);
69 if (max
/ 7 > -min
/ 8)
79 init_put_bits(&pb
, adx
+ 2, 16);
80 for (i
= 0; i
< BLOCK_SAMPLES
; i
++)
81 put_sbits(&pb
, 4, av_clip(data
[i
] / scale
, -8, 7));
85 #define HEADER_SIZE 36
87 static int adx_encode_header(AVCodecContext
*avctx
, uint8_t *buf
, int bufsize
)
89 ADXContext
*c
= avctx
->priv_data
;
91 bytestream_put_be16(&buf
, 0x8000); /* header signature */
92 bytestream_put_be16(&buf
, HEADER_SIZE
- 4); /* copyright offset */
93 bytestream_put_byte(&buf
, 3); /* encoding */
94 bytestream_put_byte(&buf
, BLOCK_SIZE
); /* block size */
95 bytestream_put_byte(&buf
, 4); /* sample size */
96 bytestream_put_byte(&buf
, avctx
->channels
); /* channels */
97 bytestream_put_be32(&buf
, avctx
->sample_rate
); /* sample rate */
98 bytestream_put_be32(&buf
, 0); /* total sample count */
99 bytestream_put_be16(&buf
, c
->cutoff
); /* cutoff frequency */
100 bytestream_put_byte(&buf
, 3); /* version */
101 bytestream_put_byte(&buf
, 0); /* flags */
102 bytestream_put_be32(&buf
, 0); /* unknown */
103 bytestream_put_be32(&buf
, 0); /* loop enabled */
104 bytestream_put_be16(&buf
, 0); /* padding */
105 bytestream_put_buffer(&buf
, "(c)CRI", 6); /* copyright signature */
110 static av_cold
int adx_encode_init(AVCodecContext
*avctx
)
112 ADXContext
*c
= avctx
->priv_data
;
114 if (avctx
->channels
> 2) {
115 av_log(avctx
, AV_LOG_ERROR
, "Invalid number of channels\n");
116 return AVERROR(EINVAL
);
118 avctx
->frame_size
= BLOCK_SAMPLES
;
120 /* the cutoff can be adjusted, but this seems to work pretty well */
122 ff_adx_calculate_coeffs(c
->cutoff
, avctx
->sample_rate
, COEFF_BITS
, c
->coeff
);
127 static int adx_encode_frame(AVCodecContext
*avctx
, AVPacket
*avpkt
,
128 const AVFrame
*frame
, int *got_packet_ptr
)
130 ADXContext
*c
= avctx
->priv_data
;
131 const int16_t *samples
= (const int16_t *)frame
->data
[0];
133 int ch
, out_size
, ret
;
135 out_size
= BLOCK_SIZE
* avctx
->channels
+ !c
->header_parsed
* HEADER_SIZE
;
136 if ((ret
= ff_alloc_packet2(avctx
, avpkt
, out_size
)) < 0)
140 if (!c
->header_parsed
) {
142 if ((hdrsize
= adx_encode_header(avctx
, dst
, avpkt
->size
)) < 0) {
143 av_log(avctx
, AV_LOG_ERROR
, "output buffer is too small\n");
144 return AVERROR(EINVAL
);
147 c
->header_parsed
= 1;
150 for (ch
= 0; ch
< avctx
->channels
; ch
++) {
151 adx_encode(c
, dst
, samples
+ ch
, &c
->prev
[ch
], avctx
->channels
);
159 AVCodec ff_adpcm_adx_encoder
= {
161 .long_name
= NULL_IF_CONFIG_SMALL("SEGA CRI ADX ADPCM"),
162 .type
= AVMEDIA_TYPE_AUDIO
,
163 .id
= AV_CODEC_ID_ADPCM_ADX
,
164 .priv_data_size
= sizeof(ADXContext
),
165 .init
= adx_encode_init
,
166 .encode2
= adx_encode_frame
,
167 .sample_fmts
= (const enum AVSampleFormat
[]) { AV_SAMPLE_FMT_S16
,
168 AV_SAMPLE_FMT_NONE
},