annotate libspeexdec.c @ 8566:48a4d9f4c6f8 libavcodec

RV30 decoder passes possible frame sizes in extradata and selects an appropriate frame size from them in slice, make my decoder do that as well. This fixes issue 779
author kostya
date Sun, 11 Jan 2009 08:03:45 +0000
parents ed8906ba4bea
children 4bb782c7793e
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;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
32 } LibSpeexContext;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
33
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
34
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
35 static av_cold int libspeex_decode_init(AVCodecContext *avctx)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
36 {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
37 LibSpeexContext *s = avctx->priv_data;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
38 const SpeexMode *mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
39
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
40 // defaults in the case of a missing header
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
41 if (avctx->sample_rate <= 8000)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
42 mode = &speex_nb_mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
43 else if (avctx->sample_rate <= 16000)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
44 mode = &speex_wb_mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
45 else
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
46 mode = &speex_uwb_mode;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
47
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
48 if (avctx->extradata_size >= 80)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
49 s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
50
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
51 avctx->sample_fmt = SAMPLE_FMT_S16;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
52 if (s->header) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
53 avctx->sample_rate = s->header->rate;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
54 avctx->channels = s->header->nb_channels;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
55 avctx->frame_size = s->header->frame_size;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
56
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
57 mode = speex_lib_get_mode(s->header->mode);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
58 if (!mode) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
59 av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
60 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
61 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
62 } else
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
63 av_log(avctx, AV_LOG_INFO, "Missing speex header, assuming defaults\n");
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
64
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
65 if (avctx->channels > 2) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
66 av_log(avctx, AV_LOG_ERROR, "Only stereo and mono supported\n");
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
67 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
68 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
69
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
70 speex_bits_init(&s->bits);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
71 s->dec_state = speex_decoder_init(mode);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
72 if (!s->dec_state) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
73 av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder\n");
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
74 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
75 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
76
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
77 if (!s->header)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
78 speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &avctx->frame_size);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
79
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
80 if (avctx->channels == 2) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
81 SpeexCallback callback;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
82 callback.callback_id = SPEEX_INBAND_STEREO;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
83 callback.func = speex_std_stereo_request_handler;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
84 callback.data = &s->stereo;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
85 s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
86 speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
87 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
88 return 0;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
89 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
90
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
91 static int libspeex_decode_frame(AVCodecContext *avctx,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
92 void *data, int *data_size,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
93 const uint8_t *buf, int buf_size)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
94 {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
95 LibSpeexContext *s = avctx->priv_data;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
96 int16_t *output = data, *end;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
97 int i, num_samples;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
98
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
99 num_samples = avctx->frame_size * avctx->channels;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
100 end = output + *data_size/2;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
101
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
102 speex_bits_read_from(&s->bits, buf, buf_size);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
103
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
104 for (i = 0; speex_bits_remaining(&s->bits) && output + num_samples < end; i++) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
105 int ret = speex_decode_int(s->dec_state, &s->bits, output);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
106 if (ret <= -2) {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
107 av_log(avctx, AV_LOG_ERROR, "Error decoding speex frame\n");
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
108 return -1;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
109 } else if (ret == -1)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
110 // end of stream
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
111 break;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
112
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
113 if (avctx->channels == 2)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
114 speex_decode_stereo_int(output, avctx->frame_size, &s->stereo);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
115
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
116 output += num_samples;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
117 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
118
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
119 *data_size = i * avctx->channels * avctx->frame_size * 2;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
120 return buf_size;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
121 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
122
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
123 static av_cold int libspeex_decode_close(AVCodecContext *avctx)
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
124 {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
125 LibSpeexContext *s = avctx->priv_data;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
126
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
127 speex_header_free(s->header);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
128 speex_bits_destroy(&s->bits);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
129 speex_decoder_destroy(s->dec_state);
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
130
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
131 return 0;
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
132 }
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
133
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
134 AVCodec libspeex_decoder = {
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
135 "libspeex",
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
136 CODEC_TYPE_AUDIO,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
137 CODEC_ID_SPEEX,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
138 sizeof(LibSpeexContext),
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
139 libspeex_decode_init,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
140 NULL,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
141 libspeex_decode_close,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
142 libspeex_decode_frame,
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
143 .long_name = NULL_IF_CONFIG_SMALL("libspeex"),
ed8906ba4bea Speex decoding via libspeex
conrad
parents:
diff changeset
144 };