annotate libspeexdec.c @ 12530:63edd10ad4bc libavcodec tip

Try to fix crashes introduced by r25218 r25218 made assumptions about the existence of past reference frames that weren't necessarily true.
author darkshikari
date Tue, 28 Sep 2010 09:06:22 +0000
parents 8a4984c5cacc
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
1 /*
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
2 * Copyright (C) 2008 David Conrad
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
3 *
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
4 * This file is part of FFmpeg.
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
5 *
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
6 * FFmpeg is free software; you can redistribute it and/or
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
7 * modify it under the terms of the GNU Lesser General Public
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
8 * License as published by the Free Software Foundation; either
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
9 * version 2.1 of the License, or (at your option) any later version.
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
10 *
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
11 * FFmpeg is distributed in the hope that it will be useful,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
14 * Lesser General Public License for more details.
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
15 *
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
16 * You should have received a copy of the GNU Lesser General Public
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
17 * License along with FFmpeg; if not, write to the Free Software
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
19 */
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
20
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
21 #include "avcodec.h"
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
22 #include <speex/speex.h>
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
23 #include <speex/speex_header.h>
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
24 #include <speex/speex_stereo.h>
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
25 #include <speex/speex_callbacks.h>
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
26
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
27 typedef struct {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
28 SpeexBits bits;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
29 SpeexStereoState stereo;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
30 void *dec_state;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
31 SpeexHeader *header;
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
32 int frame_size;
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
33 } LibSpeexContext;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
34
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
35
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
36 static av_cold int libspeex_decode_init(AVCodecContext *avctx)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
37 {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
38 LibSpeexContext *s = avctx->priv_data;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
39 const SpeexMode *mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
40
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
41 // defaults in the case of a missing header
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
42 if (avctx->sample_rate <= 8000)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
43 mode = &speex_nb_mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
44 else if (avctx->sample_rate <= 16000)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
45 mode = &speex_wb_mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
46 else
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
47 mode = &speex_uwb_mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
48
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
49 if (avctx->extradata_size >= 80)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
50 s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
51
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
52 avctx->sample_fmt = SAMPLE_FMT_S16;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
53 if (s->header) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
54 avctx->sample_rate = s->header->rate;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
55 avctx->channels = s->header->nb_channels;
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
56 avctx->frame_size = s->frame_size = s->header->frame_size;
10110
4186efb86933 Modify the Ogg/Speex demuxer and the libspeex decoder so that they always treat
jbr
parents: 9355
diff changeset
57 if (s->header->frames_per_packet)
4186efb86933 Modify the Ogg/Speex demuxer and the libspeex decoder so that they always treat
jbr
parents: 9355
diff changeset
58 avctx->frame_size *= s->header->frames_per_packet;
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
59
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
60 mode = speex_lib_get_mode(s->header->mode);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
61 if (!mode) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
62 av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
63 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
64 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
65 } else
8768
4bb782c7793e cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents: 8047
diff changeset
66 av_log(avctx, AV_LOG_INFO, "Missing Speex header, assuming defaults.\n");
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
67
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
68 if (avctx->channels > 2) {
8768
4bb782c7793e cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents: 8047
diff changeset
69 av_log(avctx, AV_LOG_ERROR, "Only stereo and mono are supported.\n");
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
70 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
71 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
72
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
73 speex_bits_init(&s->bits);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
74 s->dec_state = speex_decoder_init(mode);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
75 if (!s->dec_state) {
8768
4bb782c7793e cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents: 8047
diff changeset
76 av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n");
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
77 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
78 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
79
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
80 if (!s->header) {
10124
691a0e5585a0 libspeex: Do not set AVCodecContext.frame_size in decoder init if there is no
jbr
parents: 10116
diff changeset
81 speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &s->frame_size);
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
82 }
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
83
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
84 if (avctx->channels == 2) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
85 SpeexCallback callback;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
86 callback.callback_id = SPEEX_INBAND_STEREO;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
87 callback.func = speex_std_stereo_request_handler;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
88 callback.data = &s->stereo;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
89 s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
90 speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
91 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
92 return 0;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
93 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
94
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
95 static int libspeex_decode_frame(AVCodecContext *avctx,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
96 void *data, int *data_size,
9355
54bc8a2727b0 Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents: 8768
diff changeset
97 AVPacket *avpkt)
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
98 {
9355
54bc8a2727b0 Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents: 8768
diff changeset
99 const uint8_t *buf = avpkt->data;
54bc8a2727b0 Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents: 8768
diff changeset
100 int buf_size = avpkt->size;
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
101 LibSpeexContext *s = avctx->priv_data;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
102 int16_t *output = data, *end;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
103 int i, num_samples;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
104
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
105 num_samples = s->frame_size * avctx->channels;
10111
ebe5812b39a7 Use the output data type to determine the maximum number of samples that can be
jbr
parents: 10110
diff changeset
106 end = output + *data_size / sizeof(*output);
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
107
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
108 speex_bits_read_from(&s->bits, buf, buf_size);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
109
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
110 for (i = 0; speex_bits_remaining(&s->bits) && output + num_samples < end; i++) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
111 int ret = speex_decode_int(s->dec_state, &s->bits, output);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
112 if (ret <= -2) {
8768
4bb782c7793e cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents: 8047
diff changeset
113 av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n");
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
114 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
115 } else if (ret == -1)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
116 // end of stream
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
117 break;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
118
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
119 if (avctx->channels == 2)
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
120 speex_decode_stereo_int(output, s->frame_size, &s->stereo);
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
121
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
122 output += num_samples;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
123 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
124
10116
6cade2cdd63b Store the frame size in the LibSpeexContext in case the header does not exist.
jbr
parents: 10111
diff changeset
125 avctx->frame_size = s->frame_size * i;
10110
4186efb86933 Modify the Ogg/Speex demuxer and the libspeex decoder so that they always treat
jbr
parents: 9355
diff changeset
126 *data_size = avctx->channels * avctx->frame_size * sizeof(*output);
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
127 return buf_size;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
128 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
129
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
130 static av_cold int libspeex_decode_close(AVCodecContext *avctx)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
131 {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
132 LibSpeexContext *s = avctx->priv_data;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
133
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
134 speex_header_free(s->header);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
135 speex_bits_destroy(&s->bits);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
136 speex_decoder_destroy(s->dec_state);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
137
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
138 return 0;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
139 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
140
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
141 AVCodec libspeex_decoder = {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
142 "libspeex",
11560
8a4984c5cacc Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents: 10124
diff changeset
143 AVMEDIA_TYPE_AUDIO,
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
144 CODEC_ID_SPEEX,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
145 sizeof(LibSpeexContext),
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
146 libspeex_decode_init,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
147 NULL,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
148 libspeex_decode_close,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
149 libspeex_decode_frame,
8768
4bb782c7793e cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents: 8047
diff changeset
150 .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"),
8047
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
151 };