|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
. r( R+ @4 R$ k3 F* P下载以后需要修改bits.c文件:6 o6 L& z- t& ^3 n! k- ]
我仔细研究ITUG729代码后发现:7 ^# Z! J0 C9 K3 J) K
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
8 j: b( y h7 b/ _,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。* e$ z2 D7 ?7 r% c
; ~' z: p" m+ A6 Q
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
3 M$ q/ h9 E9 J+ y# w; h+ w
B% m `" X g, F4 S% c那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。7 e; k. u& W9 ?9 G, P% H. w
我们打开bits.c,就能看到里面定义的如下4个函数:' r& J8 p$ i% d* R$ I
static void int2bin(int value, int no_of_bits, INT16 *bitstream);. i! l) _8 h+ a/ Y( H
static int bin2int(int no_of_bits, INT16 *bitstream);9 c: j0 G9 J5 w
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
L1 s5 h; v! Xvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;, P. ~& P& g( R3 U7 X
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
! O- _% p4 O/ A3 G6 Ystatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
& @. k1 o2 E% I. o% P: fstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; ) o' y! b. f1 f: D# Y
1 b' v$ M, }9 l, B- j3 ]* N$ Nvoid prm2bits_ld8k(Word16 *para,unsigned char *bits)
: K8 J2 b- r9 d4 \9 J9 I) |{
6 D9 \0 P6 f, `3 R int i;7 N8 u% b n/ k
int bitpos = 0;
% W5 d$ r0 {# Y H4 o% j for (i = 0;i
; p- |1 C: j P& @1 I' }& U4 h: L0 z9 O/ C
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
, g! d% ]0 q4 k' b{
' V( V0 o/ p% k3 r( M% z1 Z int i;) S( s1 Q8 g1 f [6 o
int bit = 0;0 x3 |) F! S% g; k. E' I
unsigned char newbyte = 0;+ _* b7 g. X2 `
6 Y1 e, l5 o# l/ v( O, O5 y
unsigned char *p = bits + (bitpos / 8);. @$ Z' A+ q' E' D. |. k! ^
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
2 r/ @" U8 t) O; N$ I) C1 `newbyte = (1 % U6 ?# \" L# m. _
bitpos++;# o- ~, H8 M$ F/ g! C
if (bitpos % 8 == 0)
5 a1 e6 s% `# ^. K: c; n/ C p++; A9 Q" ~. V8 u/ {
}' d9 |. n! A1 K0 H
}
8 x0 V' H5 o; g# Z6 W' L
9 h6 r$ O# O( Y" k) avoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
z7 E" \$ z8 q+ F1 k( [{
2 P# o0 T, @3 X9 E- F int i;6 O( u2 u8 [, u8 k* _5 f3 D
int bitpos = 0;& J1 t0 K0 L* c. A/ z
for (i = 0;i* m0 L& i/ U" N; {' G8 X9 l
/ @: ~* D, m' e& q
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)& ~ j8 \( B7 C, s% m V( L. K
{& w* |% I/ a4 K; S% E, m
int i;7 d* K8 X8 Y# d. |8 l. w
int bit = 0;; F4 ]) }$ Q& c" x5 a9 `
Word16 newbyte = 0;+ [ X/ ~) G1 a( w2 V3 g7 e, w b- Z
Word16 value = 0;5 H4 ^1 h2 \1 @
9 }! B& ~6 Y3 n
unsigned char *p = bits + (bitpos / 8);
- j1 C. H$ y' F9 z4 { for (i = 0 ;i > (7 - bitpos % 8)) &0x01;% {, }% k, z' @+ s3 }& x8 \5 O, e" g
if (bit == 1) {9 S$ s) p3 R* Q9 v" @! ]! q3 V2 {# e
newbyte = (1 . v2 c1 T1 `" \& ^, c o
return value;: k6 R+ Q0 f5 A$ _- l
}) A1 P" e. i' Q/ i! X
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
& A6 n0 i; \% `# Y6 |
6 {$ U5 z# m+ B/ Z编码器的代码能采用如下的修改方法7 C' k" _/ f+ z& n9 I
(1)修改coder.c:
- A* Z4 _# e. m8 a3 X9 ~unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
2 m, ~7 `) ]- y$ i- W(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):0 z4 X* f8 k3 s1 Q1 x, { ~6 r6 Y( L
frame =0;' @, a. Q7 D% e0 F
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
s9 J7 {& A1 g {
7 K1 Q7 s& w% }& ?$ U" F% X5 i7 zprintf("Frame =%d\r", frame++);
0 A& ^/ k2 A' Q6 r' {' EPre_Process(new_speech, L_FRAME);
2 n1 m. w0 E$ T" G2 x# }Coder_ld8a(prm);
7 c0 g4 v" p0 ]$ }% X; h; Yprm2bits_ld8k( prm, serial);, u2 f/ l- F2 t$ }( `
fwrite(serial, 1, SERIAL_SIZE, f_serial);
# c4 S/ R5 X& ]4 P }* f1 h4 v# M& R5 ?+ d$ P3 R% z7 n
return (0);
$ x1 j& N$ i1 ~) a2 [- r9 S3 P% ^! t: B: P0 {/ O
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
; e. B) \0 G' B& l: s- S. h L/ @#define SERIAL_SIZE 108 s1 G/ k1 B+ A; M' l3 k: C
( [" v" u5 w- l3 {
(4)解码器decoder.c进行类似的修改(关键部分代码): n$ P0 C+ n; U. Q: R
frame = 0;
3 b- `) c/ t+ d B& Q# O% a) X while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)! g) W R% t c9 u
{7 j$ }$ e( @% V% H- t6 v- t& g
printf("Frame =%d\r", frame++);
3 t5 s2 s: u qbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */6 y/ C$ O. G# X* |. w
parm[0] = 0; /* 假设没有丢帧 */
! g% V# }/ k# H0 L3 l$ cparm[4] = 0 ; /* 假设数据效验正常 */# t# _" u7 j& t6 `
Decod_ld8a(parm, synth, Az_dec, T2);
8 B& i. k4 t* W9 D* V% g# vPost_Filter(synth, Az_dec, T2);
- t( P8 l* g+ |! e4 V4 W( ^Post_Process(synth, L_FRAME);
/ A9 R, P, {, gfwrite(synth, sizeof(short), L_FRAME, f_syn);
/ x, ]2 G }, }8 E0 b0 S }
6 D/ a- b2 X, ]- S- V; a return (0) ; - p& L' G1 M4 ?2 R" {
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。% `1 H/ w: j9 E/ F# v! F4 f
+ ^! d/ i3 K4 X. ^
修改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]得到,应该就能了。
" l( D, _- K5 T+ p( o/ G# N/ z9 h5 Q封lib:# }+ e( Z. Q; t3 K
va_g729.h: [* Z/ S$ @; [2 x7 H6 G5 Y
#define L_FRAME_COMPRESSED 10
- R+ ]" e; T" p V" H7 _#define L_FRAME 80
- c8 @' l- T$ Q' [' O' s! [! {#ifdef __cplusplus ; ~3 y! Y: _- W$ n
extern "C" { . i' D1 _" x9 B4 X9 m9 J
#endif% s. C. { E- b8 h
void va_g729a_init_encoder();
4 ^+ [2 C$ \& k$ q" y, g7 hvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
; O" c; ~* b1 s: w% n1 \void va_g729a_init_decoder();
4 j( _2 |3 k ?+ Dvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);! Y7 u/ F7 b9 I8 r6 h! k
#ifdef __cplusplus
9 @" L# h' p) A6 [} & }7 L( m7 t: O4 M; R9 t5 @8 S
#endif
2 G5 I$ Q4 F* y; w! Hva_g729.c2 m i5 ]3 a/ g
#include <stdio.h>" m2 ~+ Z l3 a
#include <stdlib.h>
* L1 [) t2 `0 w, n W) b#include "typedef.h"
& _3 K$ {0 l( Z( D! _' K+ k3 {" @#include "ld8k.h"
, p' i! Z5 j7 H" w, `Word16 bad_lsf;. s- ?( x5 ?2 S( N, G0 I
void va_g729a_init_encoder()( [' M$ x8 F6 t8 B: ^# x% e
{, l) D) O7 ]2 N, O% s; U
Init_Pre_Process();
3 h& K$ }4 `/ E1 ]1 p8 v: b Init_Coder_ld8k(); ' h4 l- K5 ^7 K) O, t1 l) G
}
+ c' x* j; [" q# L8 Q+ e2 s3 n3 Ivoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)2 w. R) R% Q, _! B+ |
{ ' T! A/ P$ Y) P0 L6 C3 |
extern Word16 *new_speech; /* Pointer to new speech data */% }. s0 }8 w" n9 F
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
* q7 h' H. }( ^6 @2 @4 q& ~ Word16 i;5 T t: }' E' v0 @1 B6 n
Word16 syn[L_FRAME];
. ^" ]$ V5 x$ C8 [# J, D for(i=0;i<L_FRAME;i++)
! p2 E Z! M! F6 [) H; V. D{: Y! g2 g4 w* F& j' p' B
new_speech = SpeechBuf;
2 ~9 S( U; e* I9 h: F# Y% z}% l: A: Y0 m1 k* I6 |& W; r& ^
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; / u9 z0 \6 M$ i& I4 A @
Pre_Process(new_speech, L_FRAME);% @4 a2 W6 b4 ?" N) y) k
Coder_ld8k(prm,syn);' o& x+ ]0 `* m3 r
prm2bits_ld8k( prm, serial);& D3 y' x' _% u
}
( F- C; I% R$ p. b7 Zvoid va_g729a_init_decoder()
, b$ h4 Y" X3 ~7 J) h5 q{
0 u) G" n# t. Rextern Word16 *synth;2 V3 D( z) ~5 t
bad_lsf = 0; /* Initialize bad LSF indicator */
. ~0 Z. Y/ k$ R5 @ Init_Decod_ld8k(); z4 P. x6 [4 H& V
Init_Post_Filter();
, G$ m. R. b6 V3 _ F; x1 ]) I Init_Post_Process();6 v# u3 P: L7 e \( A E
}/ d% R( S6 T% `; o: p
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
* f2 s( C" I$ \, q6 k. q{" v% A) M! [; m, S5 O- `
extern Word16 *synth; /* Synthesis */- P+ z) l, R# I7 j. z
Word16 synth_buf[L_FRAME+M];
# E* Z( A. N! G. C+ n( ]Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
! w7 R; M. [ S L: X0 u: PWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */0 o ^( m. e% U; B+ n f
Word16 T2; /* Pitch lag for 2 subframes */& Z* }" t0 i. z: [) h
Word16 i;
/ }6 x+ M& T8 k; k- LWord16 voicing = 60;( @ B* r/ }# ^
Word16 pst_out[L_FRAME]; /* Postfilter output */
5 K* j2 h# x/ i2 S' t( bWord16 sf_voic; /* voicing for subframe */% ?8 o: W" _4 g0 f, _+ B
voicing = 60;: S& `- k v6 ]3 |9 \
bits2prm_ld8k( serial, &parm[1]);+ z" ~3 J7 P3 _
parm[0] = 0;
* W- E% C4 i) k3 \ : m" k% | K4 s: A3 \$ B
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);1 c$ p+ M9 Q8 G4 V) W
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);8 x% y) l+ x6 g/ D' ?
//--------------------------------------------------
) z& ?6 W- |. Z; v" kvoicing = 0;8 Y* v+ T5 d+ ^* b* r @ g, I/ o
ptr_Az = Az_dec;
) c" h& B, ~3 M# O2 D" |8 ?for(i=0; i<L_FRAME; i+=L_SUBFR) {
: c) a9 [+ D J w: e& v8 _# {+ F& M8 f( V Post(T2, &synth, ptr_Az, &speech, &sf_voic);
0 J3 R3 U' l# V4 h1 ?) F/ t if (sf_voic != 0) { voicing = sf_voic;}
, v, P9 U! I1 e Z3 _& L% H ptr_Az += MP1;7 Q1 [6 q) O0 S' P9 R- S- `" C
}% m/ `! N/ X5 f& c H. \: S
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);4 _) L7 a) l4 ^
//---------------------------------------------------
' ~- Y- y% c" n2 y, c Post_Process(speech, L_FRAME);
# B% B) s7 m2 M% ?/ c' P. Q/ b}/ ]9 N$ M. ^0 ?: p5 H, h
7 ]( X' c7 T( Z' L+ C0 ~
|
|