]> git.sesse.net Git - ffmpeg/blob - libavcodec/libspeexdec.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavcodec / libspeexdec.c
1 /*
2  * Copyright (C) 2008 David Conrad
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include <speex/speex.h>
22 #include <speex/speex_header.h>
23 #include <speex/speex_stereo.h>
24 #include <speex/speex_callbacks.h>
25 #include "avcodec.h"
26
27 typedef struct {
28     SpeexBits bits;
29     SpeexStereoState stereo;
30     void *dec_state;
31     SpeexHeader *header;
32     int frame_size;
33 } LibSpeexContext;
34
35
36 static av_cold int libspeex_decode_init(AVCodecContext *avctx)
37 {
38     LibSpeexContext *s = avctx->priv_data;
39     const SpeexMode *mode;
40
41     // defaults in the case of a missing header
42     if (avctx->sample_rate <= 8000)
43         mode = &speex_nb_mode;
44     else if (avctx->sample_rate <= 16000)
45         mode = &speex_wb_mode;
46     else
47         mode = &speex_uwb_mode;
48
49     if (avctx->extradata_size >= 80)
50         s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size);
51
52     avctx->sample_fmt = AV_SAMPLE_FMT_S16;
53     if (s->header) {
54         avctx->sample_rate = s->header->rate;
55         avctx->channels    = s->header->nb_channels;
56         avctx->frame_size  = s->frame_size = s->header->frame_size;
57         if (s->header->frames_per_packet)
58             avctx->frame_size *= s->header->frames_per_packet;
59
60         mode = speex_lib_get_mode(s->header->mode);
61         if (!mode) {
62             av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode);
63             return AVERROR_INVALIDDATA;
64         }
65     } else
66         av_log(avctx, AV_LOG_INFO, "Missing Speex header, assuming defaults.\n");
67
68     if (avctx->channels > 2) {
69         av_log(avctx, AV_LOG_ERROR, "Only stereo and mono are supported.\n");
70         return AVERROR(EINVAL);
71     }
72
73     speex_bits_init(&s->bits);
74     s->dec_state = speex_decoder_init(mode);
75     if (!s->dec_state) {
76         av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n");
77         return -1;
78     }
79
80     if (!s->header) {
81         speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->frame_size);
82     }
83
84     if (avctx->channels == 2) {
85         SpeexCallback callback;
86         callback.callback_id = SPEEX_INBAND_STEREO;
87         callback.func = speex_std_stereo_request_handler;
88         callback.data = &s->stereo;
89         s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT;
90         speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback);
91     }
92     return 0;
93 }
94
95 static int libspeex_decode_frame(AVCodecContext *avctx,
96                                  void *data, int *data_size,
97                                  AVPacket *avpkt)
98 {
99     uint8_t *buf = avpkt->data;
100     int buf_size = avpkt->size;
101     LibSpeexContext *s = avctx->priv_data;
102     int16_t *output = data;
103     int out_size, ret, consumed = 0;
104
105     /* check output buffer size */
106     out_size = s->frame_size * avctx->channels *
107                av_get_bytes_per_sample(avctx->sample_fmt);
108     if (*data_size < out_size) {
109         av_log(avctx, AV_LOG_ERROR, "Output buffer is too small\n");
110         return AVERROR(EINVAL);
111     }
112
113     /* if there is not enough data left for the smallest possible frame,
114        reset the libspeex buffer using the current packet, otherwise ignore
115        the current packet and keep decoding frames from the libspeex buffer. */
116     if (speex_bits_remaining(&s->bits) < 43) {
117         /* check for flush packet */
118         if (!buf || !buf_size) {
119             *data_size = 0;
120             return buf_size;
121         }
122         /* set new buffer */
123         speex_bits_read_from(&s->bits, buf, buf_size);
124         consumed = buf_size;
125     }
126
127     /* decode a single frame */
128     ret = speex_decode_int(s->dec_state, &s->bits, output);
129     if (ret <= -2) {
130         av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n");
131         return AVERROR_INVALIDDATA;
132     }
133     if (avctx->channels == 2)
134         speex_decode_stereo_int(output, s->frame_size, &s->stereo);
135
136     *data_size = out_size;
137     return consumed;
138 }
139
140 static av_cold int libspeex_decode_close(AVCodecContext *avctx)
141 {
142     LibSpeexContext *s = avctx->priv_data;
143
144     speex_header_free(s->header);
145     speex_bits_destroy(&s->bits);
146     speex_decoder_destroy(s->dec_state);
147
148     return 0;
149 }
150
151 static av_cold void libspeex_decode_flush(AVCodecContext *avctx)
152 {
153     LibSpeexContext *s = avctx->priv_data;
154     speex_bits_reset(&s->bits);
155 }
156
157 AVCodec ff_libspeex_decoder = {
158     .name           = "libspeex",
159     .type           = AVMEDIA_TYPE_AUDIO,
160     .id             = CODEC_ID_SPEEX,
161     .priv_data_size = sizeof(LibSpeexContext),
162     .init           = libspeex_decode_init,
163     .close          = libspeex_decode_close,
164     .decode         = libspeex_decode_frame,
165     .flush          = libspeex_decode_flush,
166     .capabilities   = CODEC_CAP_SUBFRAMES | CODEC_CAP_DELAY,
167     .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"),
168 };