|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/: K! H0 }! J: y- H8 g
下载以后需要修改bits.c文件:
6 E7 ~1 `8 x# D7 c! D我仔细研究ITUG729代码后发现:" K2 S) I- _8 k: h- Y
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
$ e* v2 B" k# \/ {,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
$ \3 f/ `3 i% s& X( Y9 o; C* Q& j/ u
% |4 B. W( c+ Q+ w3 U7 L) gITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。" g1 `0 }! B. u/ G2 }7 e
: G* U* v0 u$ I5 g% {: {8 H那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
6 s- ?) f& s' j* r' a我们打开bits.c,就能看到里面定义的如下4个函数:
: K+ h' y4 r7 U2 ]9 P5 U$ [7 L$ Xstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);* h1 \" y8 H9 v7 C0 I. M2 W V
static int bin2int(int no_of_bits, INT16 *bitstream);) |# p- l5 p; Z1 b4 j& j/ c
void prm2bits_ld8k(int prm[], INT16 bits[]) ; 1 E% g' g* M7 q0 O! L
void bits2prm_ld8k(INT16 bits[], int prm[]) ;, S+ V6 Q7 ?0 O$ e$ E5 _
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:7 |4 q7 Y* A( ]' P# F- U& J0 H
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
4 {1 G3 U3 D: P' w$ ~static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; 1 a7 W1 X6 g6 Q/ E
( w$ ` S2 X5 e5 r n5 `! u5 Q* `
void prm2bits_ld8k(Word16 *para,unsigned char *bits)
7 K, I1 D1 x& \" @! h) _" C{5 K3 c9 F( K' z$ ]) e' J1 |: g7 g
int i;
) h+ r7 ^" f$ p int bitpos = 0;5 c6 D& ] ?* G; n/ H$ l. y7 m4 K
for (i = 0;i
M1 A. J. G# W' Z8 Q) G( ?' {5 H% d8 s6 |! ?; b
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
7 d4 D& F5 O" H2 [% l* M* z{2 n; p; @+ x6 k# y# A( }
int i;5 n+ v" g3 u/ i+ B1 U9 `
int bit = 0;
4 j7 F/ P- A4 W. q1 _% w2 H unsigned char newbyte = 0;$ X7 m7 {' I) K
$ E, E5 E8 q6 \1 R# m% ^+ T! t
unsigned char *p = bits + (bitpos / 8);
4 t# ~+ v; F0 j: t j6 N9 A$ m for (i = 0 ;i > (bitlen - i -1) ) &0x01;/ u+ h2 S% W3 X( _, I* Y
newbyte = (1 `) q" S0 a: \4 v I% g9 a
bitpos++;
- @- A9 f4 q6 O7 [if (bitpos % 8 == 0)
# ^" X3 ^# F; r7 M5 ^ p++;
. j. J; H) v5 k# R' u* r$ R7 D$ a3 G+ e f }( _2 q5 Q' u6 |! I
}
7 x5 ]0 e+ E; M2 p
: z+ [6 f5 m6 x- q/ x, T% Zvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)% ^* d8 T% C, X. Q3 b/ V5 `) G A
{" W! m: E, _9 z6 Q0 v+ `
int i;# H1 t8 z, j* q' t
int bitpos = 0;* F) ?9 R+ L% \8 V7 C
for (i = 0;i+ ~" L4 n. ^6 J/ ~* l
' L6 s: ?. R9 N% K7 Y
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)2 \8 z7 I4 y) U. l
{
; Y0 V2 F% r0 _( p; {( H int i;2 y4 s) [ H" H7 r$ u% z/ \
int bit = 0;
1 ?7 Y" h& h( D' v3 k2 j4 H Word16 newbyte = 0;$ H* e" J: f, F' @
Word16 value = 0;
8 F# C6 w2 }3 U( h
2 ^1 Z0 Y; K9 t \3 G; m. F+ U, ~ unsigned char *p = bits + (bitpos / 8);; _) b1 h0 @% @9 A. @7 }' h8 L
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;* O* b! P! s7 P1 G J
if (bit == 1) {
; R8 l5 U/ S7 L! {" ^& a4 P newbyte = (1 v6 p6 D, F0 c& ]
return value;
8 C- x$ `4 v! U; M; S* l}- p0 h6 w6 t# P7 I8 i) l# }
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
; N' [4 X( L! M1 M- r0 y, f7 g6 i7 K& ~2 ?
编码器的代码能采用如下的修改方法( B0 i: K7 Z, J/ R }
(1)修改coder.c:1 B7 `' c9 K) @) ]
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */$ F0 x- m& o; U1 ~2 V
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):5 t. p+ A7 b- t# F
frame =0;
; T" E) ^& D/ F( ~2 U while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)4 i/ j' d2 G; _ t( N! f) u
{/ z- Q. C5 b9 |2 `$ ^
printf("Frame =%d\r", frame++);
+ X& p" H. `* s0 K+ Q% JPre_Process(new_speech, L_FRAME);% e; n' {" f" R
Coder_ld8a(prm);* T% F- s0 A) i. Y& }( y
prm2bits_ld8k( prm, serial);
8 ]. Z8 F5 K' o+ R( l; cfwrite(serial, 1, SERIAL_SIZE, f_serial);; U8 m- L2 O `' z- c. H; E. D& [, C
}
' o7 n3 [5 U1 X3 j return (0);
: t- K8 K2 ]* u: I2 Z' o! ?2 y" `/ d* [6 |* d6 |: }6 ]4 t
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:0 e9 }* S- C6 l6 O _8 V
#define SERIAL_SIZE 10% J* h/ {$ A1 u
. f8 m+ `% O9 W: t B- a# b$ i(4)解码器decoder.c进行类似的修改(关键部分代码):1 J) W/ @$ m8 A9 l. c, i; y# e; j
frame = 0;
3 x/ O2 f+ k1 x2 V while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
( D" W% }) A2 N% Z/ X4 I0 M% i2 y+ f1 O {
' T# R% ~& v N$ m8 Z$ t$ V! \printf("Frame =%d\r", frame++);
: f# }" x! G: @# e0 N- i5 Ubits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */5 i; w# y- e+ O7 o* j+ h' a B
parm[0] = 0; /* 假设没有丢帧 */+ ?$ P* U: r: ]. T+ I4 W7 {
parm[4] = 0 ; /* 假设数据效验正常 */. ]+ \& L; Z; T8 z
Decod_ld8a(parm, synth, Az_dec, T2);2 Z. d& `0 j. I$ ~' s/ S$ E
Post_Filter(synth, Az_dec, T2); $ T- ?# d' X6 L; E6 t
Post_Process(synth, L_FRAME);% c8 |5 |6 c' i( e
fwrite(synth, sizeof(short), L_FRAME, f_syn);
4 Y9 o0 U# Q2 U+ p) q+ J( e& g }
, q) e" a) T% a return (0) ;
|) B5 D2 e7 g通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。( Y* e5 K7 n4 \) s' P. v# j1 L
$ l2 e/ G, H; L% \
修改bits2prm_ld8k和prm2bits_ld8k之后的编码的数据其实也不是1/16的,因为编码器中的比特分配并不是均匀的,有的时候一个参数需要用5bit来表示,不过他并不是在内存中用5bit表示,而是用了一个word16来表示的。所以这样编码后得到的数据还是要比1/16大一些,原理上来讲,编完码后的prm[]大小应该是11(共11个参数),不过编码器的bits2prm()在其前面又加了一位校验是否丢包的校验位,这样1个block编码后的prm[0]这位实际上是个校验位。你要注意一下,解码器在读取编码后文件内容的时候,不是直接读取的字节,而是通过一个函数read_frame(),进行读取的,一个block读取prm[]大小为12。这样如果你把bits2prm去掉,编码后一个block用11个word16表示,不过解码的时候一次读取12个,这样就错了。所以需要对解码器作一下相应的修改,使他不再去关注那个prm[0],一次读入11个数据。你看一下解码函数也会发现,在读入12个prm后,开头就是这么一句:bfi = *prm++,你把这个bfi作为参数传入函数,使其不再通过prm[0]得到,应该就能了。
4 \5 c5 [' z1 E9 U! v封lib:
. f) O7 r6 z# W& ?; Eva_g729.h; L- x4 r0 L$ h) K- t! M! p
#define L_FRAME_COMPRESSED 10! M0 P/ z4 A1 y' l
#define L_FRAME 80$ D* P* v9 p- O! P6 Z
#ifdef __cplusplus
0 e# M+ J1 c, U% ^extern "C" {
2 c5 `# K6 w% a! e, m" h# f/ y#endif
; h- ], o; v1 T$ a! \void va_g729a_init_encoder();
! O" _6 y( e Y1 Ovoid va_g729a_encoder(short *speech, unsigned char *bitstream);
! F. a6 ]. e8 _# S9 Svoid va_g729a_init_decoder();5 r2 B5 } Q8 \+ R% n. F
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
4 @% c* B9 a( y; G- j% D#ifdef __cplusplus $ V$ O1 v. M+ f8 G9 e1 ^2 Y( V
}
) c7 Y; h. o7 ~7 C7 s#endif" X6 c2 g4 ^9 S
va_g729.c! Z# v9 B7 P" c5 M/ P
#include <stdio.h>
2 I3 k9 o G0 \( E, G8 H7 i: d: f) @#include <stdlib.h># v) t7 {6 @- U' X; @7 }% `1 \
#include "typedef.h"& V' c' S) Y6 I$ P. T1 }0 S
#include "ld8k.h"8 d7 [1 v! u0 g% p+ S, Q$ \
Word16 bad_lsf;- \3 t) h' \. { I# g
void va_g729a_init_encoder()
( I g6 j7 `) |* S7 ?' T+ G0 G3 o{9 V4 x( J2 G8 E9 I* ~% b# A
Init_Pre_Process();: w6 _4 \# {0 [
Init_Coder_ld8k();
& R3 r: Y2 x* Z+ J# r}
, D9 ?6 i/ r/ n5 H1 @2 xvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
, x# n, C. m9 l. [% k, K5 v0 R+ S{ " ?5 k' x0 Y- J9 @: t
extern Word16 *new_speech; /* Pointer to new speech data */
2 h7 g1 l# |& C9 _2 P8 a+ x Word16 prm[PRM_SIZE]; /* Analysis parameters. *// j* L6 [) `( r4 F/ t+ S* F- |
Word16 i;
' \; `4 \& _: R& w1 r' c: H4 r7 N) ZWord16 syn[L_FRAME];9 \0 L, E; z6 ~% J' Y) w6 |
for(i=0;i<L_FRAME;i++)/ b: v, L; Z, S3 D/ n, |' d/ y
{+ i$ Q) V0 G2 Z: i' ~7 T2 s' t
new_speech = SpeechBuf;
7 o9 W1 c1 r6 x: W2 |" B$ F. g}
6 M R' L. r% w for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; / @) h+ X- I0 c9 c) ?* e5 t8 e
Pre_Process(new_speech, L_FRAME);: Z$ ^/ _, ^9 C$ O/ Y0 F
Coder_ld8k(prm,syn);
- j1 z: m" F' g! S. Q prm2bits_ld8k( prm, serial);9 y& K, f( N. `' _
}7 _& P* C4 A# _5 W$ k9 m9 n
void va_g729a_init_decoder()1 c5 ~( x3 o: O6 N, @3 P
{
' r% @$ x! t* y8 T5 ~' eextern Word16 *synth;
: l0 M& c5 b7 ^ f7 a! H$ d4 ~ bad_lsf = 0; /* Initialize bad LSF indicator */8 r/ u; k) g( ?0 H0 \' t
Init_Decod_ld8k();
% F0 ~+ O: P4 A4 k Init_Post_Filter();
* _3 ?' ]' N# q o2 t! X3 ~! V! F Init_Post_Process();
. x. y7 r/ O+ i}+ ]8 i* h# G3 p3 R2 Y# I. w4 S
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)# }. q+ B6 b( v5 `
{
( ^7 r" y6 I0 Pextern Word16 *synth; /* Synthesis */, U: f3 V" y- K
Word16 synth_buf[L_FRAME+M];0 R q8 e: a, s5 A2 R8 B5 ^* x; r
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */: L. ?. o$ v7 h3 e. k2 u
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */) k! p0 A+ X; K9 H4 I$ n6 _
Word16 T2; /* Pitch lag for 2 subframes */9 q+ m, V$ @3 \9 Q, ]
Word16 i;6 H$ J. c4 R; T/ v! f9 ]
Word16 voicing = 60;
+ ] C3 } L3 C9 \Word16 pst_out[L_FRAME]; /* Postfilter output */
/ F/ V# I) q% F( n. sWord16 sf_voic; /* voicing for subframe */" b& i& o) o P3 s# n$ e
voicing = 60;% w# N1 [' j% W! Z4 `
bits2prm_ld8k( serial, &parm[1]);
6 `+ J# t0 q3 A" y& {+ w: l: T parm[0] = 0; " `) @- j; v# G& ]- d. f+ s
3 f. a: V8 j" w, p- I: ^
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
. Q8 ?- ?. k7 H0 ?Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
# b( Z: v5 R1 C2 g' x* x//--------------------------------------------------( K; u# X0 x$ q' m& x c: f: I& g9 [9 M/ P
voicing = 0;
& \9 s# Y$ i8 D4 n" qptr_Az = Az_dec;
) U- G3 d8 s" [7 m+ p2 g6 kfor(i=0; i<L_FRAME; i+=L_SUBFR) {
- ~- h b/ N* M- `- K Post(T2, &synth, ptr_Az, &speech, &sf_voic);
, O6 z% h( K* C. L' L$ a if (sf_voic != 0) { voicing = sf_voic;}$ f: g" `& _. k+ z0 Q( R0 H
ptr_Az += MP1;
, `& |; `$ e* d/ a! ~. ^# M}" Z) m& L% M! X
Copy(&synth_buf[L_FRAME], &synth_buf[0], M); E2 g" \+ W z4 N
//---------------------------------------------------) V7 f `$ q$ i: \% X* E/ f
Post_Process(speech, L_FRAME);
. b/ C9 g4 H3 c, V8 r) Z5 v7 k+ E}
3 ]! g' z' [4 [1 [$ F* l) s
0 _, b0 ?& r8 U% _4 ]1 y" @6 E |
|