xref: /third_party/ffmpeg/libavcodec/libgsmdec.c (revision cabdff1a)
1/*
2 * Interface to libgsm for GSM decoding
3 * Copyright (c) 2005 Alban Bedel <albeu@free.fr>
4 * Copyright (c) 2006, 2007 Michel Bardiaux <mbardiaux@mediaxim.be>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
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
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23/**
24 * @file
25 * Interface to libgsm for GSM decoding
26 */
27
28// The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html
29
30#include "config.h"
31#include "config_components.h"
32#if HAVE_GSM_H
33#include <gsm.h>
34#else
35#include <gsm/gsm.h>
36#endif
37
38#include "libavutil/channel_layout.h"
39#include "libavutil/common.h"
40
41#include "avcodec.h"
42#include "codec_internal.h"
43#include "internal.h"
44#include "gsm.h"
45
46typedef struct LibGSMDecodeContext {
47    struct gsm_state *state;
48} LibGSMDecodeContext;
49
50static av_cold int libgsm_decode_init(AVCodecContext *avctx) {
51    LibGSMDecodeContext *s = avctx->priv_data;
52
53    av_channel_layout_uninit(&avctx->ch_layout);
54    avctx->ch_layout      = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
55    if (!avctx->sample_rate)
56        avctx->sample_rate = 8000;
57    avctx->sample_fmt     = AV_SAMPLE_FMT_S16;
58
59    s->state = gsm_create();
60
61    switch(avctx->codec_id) {
62    case AV_CODEC_ID_GSM:
63        avctx->frame_size  = GSM_FRAME_SIZE;
64        avctx->block_align = GSM_BLOCK_SIZE;
65        break;
66    case AV_CODEC_ID_GSM_MS: {
67        int one = 1;
68        gsm_option(s->state, GSM_OPT_WAV49, &one);
69        avctx->frame_size  = 2 * GSM_FRAME_SIZE;
70        avctx->block_align = GSM_MS_BLOCK_SIZE;
71        }
72    }
73
74    return 0;
75}
76
77static av_cold int libgsm_decode_close(AVCodecContext *avctx) {
78    LibGSMDecodeContext *s = avctx->priv_data;
79
80    gsm_destroy(s->state);
81    s->state = NULL;
82    return 0;
83}
84
85static int libgsm_decode_frame(AVCodecContext *avctx, AVFrame *frame,
86                               int *got_frame_ptr, AVPacket *avpkt)
87{
88    int i, ret;
89    LibGSMDecodeContext *s = avctx->priv_data;
90    uint8_t *buf = avpkt->data;
91    int buf_size = avpkt->size;
92    int16_t *samples;
93
94    if (buf_size < avctx->block_align) {
95        av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
96        return AVERROR_INVALIDDATA;
97    }
98
99    /* get output buffer */
100    frame->nb_samples = avctx->frame_size;
101    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
102        return ret;
103    samples = (int16_t *)frame->data[0];
104
105    for (i = 0; i < avctx->frame_size / GSM_FRAME_SIZE; i++) {
106        if ((ret = gsm_decode(s->state, buf, samples)) < 0)
107            return -1;
108        buf     += GSM_BLOCK_SIZE;
109        samples += GSM_FRAME_SIZE;
110    }
111
112    *got_frame_ptr = 1;
113
114    return avctx->block_align;
115}
116
117static void libgsm_flush(AVCodecContext *avctx) {
118    LibGSMDecodeContext *s = avctx->priv_data;
119    int one = 1;
120
121    gsm_destroy(s->state);
122    s->state = gsm_create();
123    if (avctx->codec_id == AV_CODEC_ID_GSM_MS)
124        gsm_option(s->state, GSM_OPT_WAV49, &one);
125}
126
127#if CONFIG_LIBGSM_DECODER
128const FFCodec ff_libgsm_decoder = {
129    .p.name         = "libgsm",
130    .p.long_name    = NULL_IF_CONFIG_SMALL("libgsm GSM"),
131    .p.type         = AVMEDIA_TYPE_AUDIO,
132    .p.id           = AV_CODEC_ID_GSM,
133    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
134    .p.wrapper_name = "libgsm",
135    .priv_data_size = sizeof(LibGSMDecodeContext),
136    .init           = libgsm_decode_init,
137    .close          = libgsm_decode_close,
138    FF_CODEC_DECODE_CB(libgsm_decode_frame),
139    .flush          = libgsm_flush,
140};
141#endif
142#if CONFIG_LIBGSM_MS_DECODER
143const FFCodec ff_libgsm_ms_decoder = {
144    .p.name         = "libgsm_ms",
145    .p.long_name    = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"),
146    .p.type         = AVMEDIA_TYPE_AUDIO,
147    .p.id           = AV_CODEC_ID_GSM_MS,
148    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
149    .p.wrapper_name = "libgsm",
150    .priv_data_size = sizeof(LibGSMDecodeContext),
151    .init           = libgsm_decode_init,
152    .close          = libgsm_decode_close,
153    FF_CODEC_DECODE_CB(libgsm_decode_frame),
154    .flush          = libgsm_flush,
155};
156#endif
157