Commit | Line | Data |
---|---|---|
bb4c2140 MN |
1 | /* |
2 | * Interface to libgsm for gsm encoding/decoding | |
3 | * Copyright (c) 2005 Alban Bedel <albeu@free.fr> | |
346a655d | 4 | * Copyright (c) 2006, 2007 Michel Bardiaux <mbardiaux@mediaxim.be> |
bb4c2140 | 5 | * |
2912e87a | 6 | * This file is part of Libav. |
b78e7197 | 7 | * |
2912e87a | 8 | * Libav is free software; you can redistribute it and/or |
bb4c2140 MN |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either | |
b78e7197 | 11 | * version 2.1 of the License, or (at your option) any later version. |
bb4c2140 | 12 | * |
2912e87a | 13 | * Libav is distributed in the hope that it will be useful, |
bb4c2140 MN |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
2912e87a | 19 | * License along with Libav; if not, write to the Free Software |
5509bffa | 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
bb4c2140 | 21 | */ |
115329f1 | 22 | |
bb4c2140 | 23 | /** |
ba87f080 | 24 | * @file |
bb4c2140 MN |
25 | * Interface to libgsm for gsm encoding/decoding |
26 | */ | |
27 | ||
346a655d MB |
28 | // The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html |
29 | ||
bb4c2140 | 30 | #include "avcodec.h" |
3beb81e7 | 31 | #include <gsm/gsm.h> |
bb4c2140 | 32 | |
df3a80b5 | 33 | // gsm.h misses some essential constants |
bb4c2140 | 34 | #define GSM_BLOCK_SIZE 33 |
346a655d | 35 | #define GSM_MS_BLOCK_SIZE 65 |
bb4c2140 MN |
36 | #define GSM_FRAME_SIZE 160 |
37 | ||
8febd6af | 38 | static av_cold int libgsm_encode_init(AVCodecContext *avctx) { |
96ddaff5 MB |
39 | if (avctx->channels > 1) { |
40 | av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n", | |
41 | avctx->channels); | |
bb4c2140 | 42 | return -1; |
96ddaff5 | 43 | } |
ef79ef3c | 44 | |
88f908fb JR |
45 | if (avctx->sample_rate != 8000) { |
46 | av_log(avctx, AV_LOG_ERROR, "Sample rate 8000Hz required for GSM, got %dHz\n", | |
47 | avctx->sample_rate); | |
48 | if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) | |
49 | return -1; | |
50 | } | |
51 | if (avctx->bit_rate != 13000 /* Official */ && | |
52 | avctx->bit_rate != 13200 /* Very common */ && | |
53 | avctx->bit_rate != 0 /* Unknown; a.o. mov does not set bitrate when decoding */ ) { | |
54 | av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %dbps\n", | |
55 | avctx->bit_rate); | |
56 | if (avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) | |
57 | return -1; | |
58 | } | |
bb4c2140 | 59 | |
bb4c2140 | 60 | avctx->priv_data = gsm_create(); |
115329f1 | 61 | |
346a655d MB |
62 | switch(avctx->codec_id) { |
63 | case CODEC_ID_GSM: | |
64 | avctx->frame_size = GSM_FRAME_SIZE; | |
65 | avctx->block_align = GSM_BLOCK_SIZE; | |
66 | break; | |
67 | case CODEC_ID_GSM_MS: { | |
68 | int one = 1; | |
69 | gsm_option(avctx->priv_data, GSM_OPT_WAV49, &one); | |
70 | avctx->frame_size = 2*GSM_FRAME_SIZE; | |
71 | avctx->block_align = GSM_MS_BLOCK_SIZE; | |
72 | } | |
73 | } | |
74 | ||
bb4c2140 MN |
75 | avctx->coded_frame= avcodec_alloc_frame(); |
76 | avctx->coded_frame->key_frame= 1; | |
115329f1 | 77 | |
bb4c2140 MN |
78 | return 0; |
79 | } | |
80 | ||
8febd6af | 81 | static av_cold int libgsm_encode_close(AVCodecContext *avctx) { |
916ff022 | 82 | av_freep(&avctx->coded_frame); |
bb4c2140 MN |
83 | gsm_destroy(avctx->priv_data); |
84 | avctx->priv_data = NULL; | |
85 | return 0; | |
86 | } | |
87 | ||
88 | static int libgsm_encode_frame(AVCodecContext *avctx, | |
89 | unsigned char *frame, int buf_size, void *data) { | |
90 | // we need a full block | |
346a655d MB |
91 | if(buf_size < avctx->block_align) return 0; |
92 | ||
93 | switch(avctx->codec_id) { | |
94 | case CODEC_ID_GSM: | |
95 | gsm_encode(avctx->priv_data,data,frame); | |
96 | break; | |
97 | case CODEC_ID_GSM_MS: | |
98 | gsm_encode(avctx->priv_data,data,frame); | |
99 | gsm_encode(avctx->priv_data,((short*)data)+GSM_FRAME_SIZE,frame+32); | |
100 | } | |
101 | return avctx->block_align; | |
bb4c2140 MN |
102 | } |
103 | ||
104 | ||
d36beb3f | 105 | AVCodec ff_libgsm_encoder = { |
ec6402b7 AK |
106 | .name = "libgsm", |
107 | .type = AVMEDIA_TYPE_AUDIO, | |
108 | .id = CODEC_ID_GSM, | |
8febd6af | 109 | .init = libgsm_encode_init, |
ec6402b7 | 110 | .encode = libgsm_encode_frame, |
8febd6af | 111 | .close = libgsm_encode_close, |
5d6e4c16 | 112 | .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, |
fe4bf374 | 113 | .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), |
bb4c2140 MN |
114 | }; |
115 | ||
d36beb3f | 116 | AVCodec ff_libgsm_ms_encoder = { |
ec6402b7 AK |
117 | .name = "libgsm_ms", |
118 | .type = AVMEDIA_TYPE_AUDIO, | |
119 | .id = CODEC_ID_GSM_MS, | |
8febd6af | 120 | .init = libgsm_encode_init, |
ec6402b7 | 121 | .encode = libgsm_encode_frame, |
8febd6af | 122 | .close = libgsm_encode_close, |
5d6e4c16 | 123 | .sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,AV_SAMPLE_FMT_NONE}, |
fe4bf374 | 124 | .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), |
346a655d MB |
125 | }; |
126 | ||
0eea2129 JR |
127 | typedef struct LibGSMDecodeContext { |
128 | AVFrame frame; | |
129 | struct gsm_state *state; | |
130 | } LibGSMDecodeContext; | |
131 | ||
8febd6af | 132 | static av_cold int libgsm_decode_init(AVCodecContext *avctx) { |
0eea2129 JR |
133 | LibGSMDecodeContext *s = avctx->priv_data; |
134 | ||
8febd6af JR |
135 | if (avctx->channels > 1) { |
136 | av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n", | |
137 | avctx->channels); | |
138 | return -1; | |
139 | } | |
140 | ||
141 | if (!avctx->channels) | |
142 | avctx->channels = 1; | |
143 | ||
144 | if (!avctx->sample_rate) | |
145 | avctx->sample_rate = 8000; | |
146 | ||
147 | avctx->sample_fmt = AV_SAMPLE_FMT_S16; | |
148 | ||
0eea2129 | 149 | s->state = gsm_create(); |
8febd6af JR |
150 | |
151 | switch(avctx->codec_id) { | |
152 | case CODEC_ID_GSM: | |
153 | avctx->frame_size = GSM_FRAME_SIZE; | |
154 | avctx->block_align = GSM_BLOCK_SIZE; | |
155 | break; | |
156 | case CODEC_ID_GSM_MS: { | |
157 | int one = 1; | |
8637af8d | 158 | gsm_option(s->state, GSM_OPT_WAV49, &one); |
8febd6af JR |
159 | avctx->frame_size = 2 * GSM_FRAME_SIZE; |
160 | avctx->block_align = GSM_MS_BLOCK_SIZE; | |
161 | } | |
162 | } | |
163 | ||
0eea2129 JR |
164 | avcodec_get_frame_defaults(&s->frame); |
165 | avctx->coded_frame = &s->frame; | |
166 | ||
8febd6af JR |
167 | return 0; |
168 | } | |
169 | ||
170 | static av_cold int libgsm_decode_close(AVCodecContext *avctx) { | |
0eea2129 JR |
171 | LibGSMDecodeContext *s = avctx->priv_data; |
172 | ||
173 | gsm_destroy(s->state); | |
174 | s->state = NULL; | |
8febd6af JR |
175 | return 0; |
176 | } | |
177 | ||
0eea2129 JR |
178 | static int libgsm_decode_frame(AVCodecContext *avctx, void *data, |
179 | int *got_frame_ptr, AVPacket *avpkt) | |
180 | { | |
480324e7 | 181 | int i, ret; |
0eea2129 | 182 | LibGSMDecodeContext *s = avctx->priv_data; |
357d0d8f | 183 | uint8_t *buf = avpkt->data; |
7a00bbad | 184 | int buf_size = avpkt->size; |
0eea2129 | 185 | int16_t *samples; |
b03761b1 | 186 | |
9d52f0a7 JR |
187 | if (buf_size < avctx->block_align) { |
188 | av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); | |
189 | return AVERROR_INVALIDDATA; | |
190 | } | |
191 | ||
0eea2129 JR |
192 | /* get output buffer */ |
193 | s->frame.nb_samples = avctx->frame_size; | |
194 | if ((ret = avctx->get_buffer(avctx, &s->frame)) < 0) { | |
195 | av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
196 | return ret; | |
197 | } | |
198 | samples = (int16_t *)s->frame.data[0]; | |
199 | ||
480324e7 | 200 | for (i = 0; i < avctx->frame_size / GSM_FRAME_SIZE; i++) { |
0eea2129 | 201 | if ((ret = gsm_decode(s->state, buf, samples)) < 0) |
480324e7 JR |
202 | return -1; |
203 | buf += GSM_BLOCK_SIZE; | |
204 | samples += GSM_FRAME_SIZE; | |
346a655d | 205 | } |
b03761b1 | 206 | |
0eea2129 JR |
207 | *got_frame_ptr = 1; |
208 | *(AVFrame *)data = s->frame; | |
209 | ||
346a655d | 210 | return avctx->block_align; |
bb4c2140 MN |
211 | } |
212 | ||
20e081dd | 213 | static void libgsm_flush(AVCodecContext *avctx) { |
0eea2129 | 214 | LibGSMDecodeContext *s = avctx->priv_data; |
1b35af32 | 215 | int one = 1; |
0eea2129 JR |
216 | |
217 | gsm_destroy(s->state); | |
218 | s->state = gsm_create(); | |
1b35af32 MS |
219 | if (avctx->codec_id == CODEC_ID_GSM_MS) |
220 | gsm_option(s->state, GSM_OPT_WAV49, &one); | |
20e081dd JR |
221 | } |
222 | ||
d36beb3f | 223 | AVCodec ff_libgsm_decoder = { |
ec6402b7 AK |
224 | .name = "libgsm", |
225 | .type = AVMEDIA_TYPE_AUDIO, | |
226 | .id = CODEC_ID_GSM, | |
0eea2129 | 227 | .priv_data_size = sizeof(LibGSMDecodeContext), |
8febd6af JR |
228 | .init = libgsm_decode_init, |
229 | .close = libgsm_decode_close, | |
ec6402b7 | 230 | .decode = libgsm_decode_frame, |
20e081dd | 231 | .flush = libgsm_flush, |
0eea2129 | 232 | .capabilities = CODEC_CAP_DR1, |
fe4bf374 | 233 | .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), |
bb4c2140 | 234 | }; |
346a655d | 235 | |
d36beb3f | 236 | AVCodec ff_libgsm_ms_decoder = { |
ec6402b7 AK |
237 | .name = "libgsm_ms", |
238 | .type = AVMEDIA_TYPE_AUDIO, | |
239 | .id = CODEC_ID_GSM_MS, | |
0eea2129 | 240 | .priv_data_size = sizeof(LibGSMDecodeContext), |
8febd6af JR |
241 | .init = libgsm_decode_init, |
242 | .close = libgsm_decode_close, | |
ec6402b7 | 243 | .decode = libgsm_decode_frame, |
20e081dd | 244 | .flush = libgsm_flush, |
0eea2129 | 245 | .capabilities = CODEC_CAP_DR1, |
fe4bf374 | 246 | .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), |
346a655d | 247 | }; |