2 * Speex decoder by Reimar Döffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>
3 * License: GPL v2 or later
4 * This code may be be relicensed under the terms of the GNU LGPL when it
5 * becomes part of the FFmpeg project (ffmpeg.org)
9 #include <speex/speex.h>
10 #include <speex/speex_stereo.h>
11 #include <speex/speex_header.h>
12 #include "ad_internal.h"
14 static ad_info_t info
= {
15 "Speex audio decoder",
27 SpeexStereoState stereo
;
31 #define MAX_FRAMES_PER_PACKET 100
33 static int preinit(sh_audio_t
*sh
) {
34 sh
->audio_out_minsize
= 2 * 320 * MAX_FRAMES_PER_PACKET
* 2 * sizeof(short);
38 static int init(sh_audio_t
*sh
) {
39 context_t
*ctx
= calloc(1, sizeof(context_t
));
40 const SpeexMode
*spx_mode
;
41 const SpeexStereoState st_st
= SPEEX_STEREO_STATE_INIT
; // hack
42 if (!sh
->wf
|| sh
->wf
->cbSize
< 80) {
43 mp_msg(MSGT_DECAUDIO
, MSGL_FATAL
, "Missing extradata!\n");
46 ctx
->hdr
= speex_packet_to_header((char *)&sh
->wf
[1], sh
->wf
->cbSize
);
47 if (ctx
->hdr
->nb_channels
!= 1 && ctx
->hdr
->nb_channels
!= 2) {
48 mp_msg(MSGT_DECAUDIO
, MSGL_WARN
, "Invalid number of channels (%i), "
49 "assuming mono\n", ctx
->hdr
->nb_channels
);
50 ctx
->hdr
->nb_channels
= 1;
52 if (ctx
->hdr
->frames_per_packet
> MAX_FRAMES_PER_PACKET
) {
53 mp_msg(MSGT_DECAUDIO
, MSGL_WARN
, "Invalid number of frames per packet (%i), "
54 "assuming 1\n", ctx
->hdr
->frames_per_packet
);
55 ctx
->hdr
->frames_per_packet
= 1;
57 switch (ctx
->hdr
->mode
) {
59 spx_mode
= &speex_nb_mode
; break;
61 spx_mode
= &speex_wb_mode
; break;
63 spx_mode
= &speex_uwb_mode
; break;
65 mp_msg(MSGT_DECAUDIO
, MSGL_WARN
, "Unknown speex mode (%i)\n", ctx
->hdr
->mode
);
66 spx_mode
= &speex_nb_mode
;
68 ctx
->dec_context
= speex_decoder_init(spx_mode
);
69 speex_bits_init(&ctx
->bits
);
70 memcpy(&ctx
->stereo
, &st_st
, sizeof(ctx
->stereo
)); // hack part 2
71 sh
->channels
= ctx
->hdr
->nb_channels
;
72 sh
->samplerate
= ctx
->hdr
->rate
;
74 sh
->sample_format
= AF_FORMAT_S16_NE
;
79 static void uninit(sh_audio_t
*sh
) {
80 context_t
*ctx
= sh
->context
;
82 speex_bits_destroy(&ctx
->bits
);
83 speex_decoder_destroy(ctx
->dec_context
);
91 static int decode_audio(sh_audio_t
*sh
, unsigned char *buf
,
92 int minlen
, int maxlen
) {
93 context_t
*ctx
= sh
->context
;
94 int len
, framelen
, framesamples
;
97 speex_decoder_ctl(ctx
->dec_context
, SPEEX_GET_FRAME_SIZE
, &framesamples
);
98 framelen
= framesamples
* ctx
->hdr
->nb_channels
* sizeof(short);
99 if (maxlen
< ctx
->hdr
->frames_per_packet
* framelen
) {
100 mp_msg(MSGT_DECAUDIO
, MSGL_V
, "maxlen too small in decode_audio\n");
103 len
= ds_get_packet(sh
->ds
, (unsigned char **)&packet
);
104 if (len
<= 0) return -1;
105 speex_bits_read_from(&ctx
->bits
, packet
, len
);
106 i
= ctx
->hdr
->frames_per_packet
;
108 err
= speex_decode_int(ctx
->dec_context
, &ctx
->bits
, (short *)buf
);
110 mp_msg(MSGT_DECAUDIO
, MSGL_ERR
, "Error decoding file.\n");
111 if (ctx
->hdr
->nb_channels
== 2)
112 speex_decode_stereo_int((short *)buf
, framesamples
, &ctx
->stereo
);
113 buf
= &buf
[framelen
];
115 return ctx
->hdr
->frames_per_packet
* framelen
;
118 static int control(sh_audio_t
*sh
, int cmd
, void *arg
, ...) {
119 return CONTROL_UNKNOWN
;