Mercurial > libavcodec.hg
annotate libspeexdec.c @ 9595:f9a7147cc9e6 libavcodec
Do not scan for MP3 header after the given buffer and return skipped
bytes along with consumed bytes on successful decoding.
patch by Zdenek Kabelac, zdenek.kabelac gmail com
author | diego |
---|---|
date | Mon, 04 May 2009 14:23:48 +0000 |
parents | 54bc8a2727b0 |
children | 4186efb86933 |
rev | line source |
---|---|
8047 | 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 "avcodec.h" | |
22 #include <speex/speex.h> | |
23 #include <speex/speex_header.h> | |
24 #include <speex/speex_stereo.h> | |
25 #include <speex/speex_callbacks.h> | |
26 | |
27 typedef struct { | |
28 SpeexBits bits; | |
29 SpeexStereoState stereo; | |
30 void *dec_state; | |
31 SpeexHeader *header; | |
32 } LibSpeexContext; | |
33 | |
34 | |
35 static av_cold int libspeex_decode_init(AVCodecContext *avctx) | |
36 { | |
37 LibSpeexContext *s = avctx->priv_data; | |
38 const SpeexMode *mode; | |
39 | |
40 // defaults in the case of a missing header | |
41 if (avctx->sample_rate <= 8000) | |
42 mode = &speex_nb_mode; | |
43 else if (avctx->sample_rate <= 16000) | |
44 mode = &speex_wb_mode; | |
45 else | |
46 mode = &speex_uwb_mode; | |
47 | |
48 if (avctx->extradata_size >= 80) | |
49 s->header = speex_packet_to_header(avctx->extradata, avctx->extradata_size); | |
50 | |
51 avctx->sample_fmt = SAMPLE_FMT_S16; | |
52 if (s->header) { | |
53 avctx->sample_rate = s->header->rate; | |
54 avctx->channels = s->header->nb_channels; | |
55 avctx->frame_size = s->header->frame_size; | |
56 | |
57 mode = speex_lib_get_mode(s->header->mode); | |
58 if (!mode) { | |
59 av_log(avctx, AV_LOG_ERROR, "Unknown Speex mode %d", s->header->mode); | |
60 return -1; | |
61 } | |
62 } else | |
8768
4bb782c7793e
cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents:
8047
diff
changeset
|
63 av_log(avctx, AV_LOG_INFO, "Missing Speex header, assuming defaults.\n"); |
8047 | 64 |
65 if (avctx->channels > 2) { | |
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_ERROR, "Only stereo and mono are supported.\n"); |
8047 | 67 return -1; |
68 } | |
69 | |
70 speex_bits_init(&s->bits); | |
71 s->dec_state = speex_decoder_init(mode); | |
72 if (!s->dec_state) { | |
8768
4bb782c7793e
cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents:
8047
diff
changeset
|
73 av_log(avctx, AV_LOG_ERROR, "Error initializing libspeex decoder.\n"); |
8047 | 74 return -1; |
75 } | |
76 | |
77 if (!s->header) | |
78 speex_decoder_ctl(s->dec_state, SPEEX_GET_FRAME_SIZE, &avctx->frame_size); | |
79 | |
80 if (avctx->channels == 2) { | |
81 SpeexCallback callback; | |
82 callback.callback_id = SPEEX_INBAND_STEREO; | |
83 callback.func = speex_std_stereo_request_handler; | |
84 callback.data = &s->stereo; | |
85 s->stereo = (SpeexStereoState)SPEEX_STEREO_STATE_INIT; | |
86 speex_decoder_ctl(s->dec_state, SPEEX_SET_HANDLER, &callback); | |
87 } | |
88 return 0; | |
89 } | |
90 | |
91 static int libspeex_decode_frame(AVCodecContext *avctx, | |
92 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8768
diff
changeset
|
93 AVPacket *avpkt) |
8047 | 94 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8768
diff
changeset
|
95 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
8768
diff
changeset
|
96 int buf_size = avpkt->size; |
8047 | 97 LibSpeexContext *s = avctx->priv_data; |
98 int16_t *output = data, *end; | |
99 int i, num_samples; | |
100 | |
101 num_samples = avctx->frame_size * avctx->channels; | |
102 end = output + *data_size/2; | |
103 | |
104 speex_bits_read_from(&s->bits, buf, buf_size); | |
105 | |
106 for (i = 0; speex_bits_remaining(&s->bits) && output + num_samples < end; i++) { | |
107 int ret = speex_decode_int(s->dec_state, &s->bits, output); | |
108 if (ret <= -2) { | |
8768
4bb782c7793e
cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents:
8047
diff
changeset
|
109 av_log(avctx, AV_LOG_ERROR, "Error decoding Speex frame.\n"); |
8047 | 110 return -1; |
111 } else if (ret == -1) | |
112 // end of stream | |
113 break; | |
114 | |
115 if (avctx->channels == 2) | |
116 speex_decode_stereo_int(output, avctx->frame_size, &s->stereo); | |
117 | |
118 output += num_samples; | |
119 } | |
120 | |
121 *data_size = i * avctx->channels * avctx->frame_size * 2; | |
122 return buf_size; | |
123 } | |
124 | |
125 static av_cold int libspeex_decode_close(AVCodecContext *avctx) | |
126 { | |
127 LibSpeexContext *s = avctx->priv_data; | |
128 | |
129 speex_header_free(s->header); | |
130 speex_bits_destroy(&s->bits); | |
131 speex_decoder_destroy(s->dec_state); | |
132 | |
133 return 0; | |
134 } | |
135 | |
136 AVCodec libspeex_decoder = { | |
137 "libspeex", | |
138 CODEC_TYPE_AUDIO, | |
139 CODEC_ID_SPEEX, | |
140 sizeof(LibSpeexContext), | |
141 libspeex_decode_init, | |
142 NULL, | |
143 libspeex_decode_close, | |
144 libspeex_decode_frame, | |
8768
4bb782c7793e
cosmetics: Fix a few typos and use a consistent codec long name.
diego
parents:
8047
diff
changeset
|
145 .long_name = NULL_IF_CONFIG_SMALL("libspeex Speex"), |
8047 | 146 }; |