|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/9 Y5 @" L+ r) \- Y( T
下载以后需要修改bits.c文件:; @! v, Y% C' Z4 ^) q0 S+ P4 ]" I
我仔细研究ITUG729代码后发现:! ~' ] v j! i. E# E
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
$ _+ U }1 N+ d# _, s,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
# X& j$ F6 S9 M- }( p' g7 z% i7 R4 E; P3 p! O8 P$ E
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
: t z" p3 k& g% D3 A
& {0 I4 S& n& l- y那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。 ?) Q+ e1 o" q* k, n! V
我们打开bits.c,就能看到里面定义的如下4个函数:
O1 Q8 Q( O, N3 x$ dstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
+ \- v6 A$ l7 {. Dstatic int bin2int(int no_of_bits, INT16 *bitstream);
- A0 g! q* W. |/ ^void prm2bits_ld8k(int prm[], INT16 bits[]) ; I! d. j+ T& J) Q/ ~; L+ n( ^
void bits2prm_ld8k(INT16 bits[], int prm[]) ;/ ]' L$ p+ S1 I' \1 O" E8 \: ?
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:- ^+ L+ [$ `6 A$ R$ E/ f! ~
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
) x2 N' ?6 L& I0 }$ wstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; / F' T% H$ i0 C0 z' Q
: Z8 N0 M* s2 D9 ?3 t9 i2 Yvoid prm2bits_ld8k(Word16 *para,unsigned char *bits)
: W% _* r* r4 l2 v* D5 z2 [{ E! d( _1 a: ~; a, l# T
int i;+ K; y! |1 n2 [5 q4 h; B/ e
int bitpos = 0;7 Z* F& e+ h1 m x& g# K3 \6 i1 G7 v
for (i = 0;i8 P F% z) m1 y: @3 K
/ i/ I; ?3 v+ ~: b5 z
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
+ X( z1 Y) U" x0 Z' M7 J' c{
& c; X- r4 o" H$ X: j L int i;# K/ Z3 U4 X2 P: P. B$ C1 \
int bit = 0;
- o; K- a! g4 p) C3 B unsigned char newbyte = 0;
6 v: w5 P5 y6 ]5 O @" U+ y3 }' Y ; \! q$ e2 A0 z- u
unsigned char *p = bits + (bitpos / 8);3 a2 K, U) b E/ i3 f- x9 Q; D
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
) o+ N# _% E! F) l' i7 B6 cnewbyte = (1
4 b0 e) H# ]( Gbitpos++;, q/ H. i" x7 {0 m& [7 p$ [" b
if (bitpos % 8 == 0)
. M' f7 S$ T. u# b* t p++;" H; i( n/ ` X7 F6 k$ t- }
}
; ?5 s. M1 B+ T- p9 y0 D9 A" i}
x% ], P8 z' D1 n# o& Z/ {* d
( d6 ~6 p& \ N: x1 `' P- _* \& cvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
: e8 H- v1 E4 w! C{6 R- e) \* A* d; a8 p+ L; `
int i;! r& |3 ]- O& E% t8 j9 b# E. L" d
int bitpos = 0;
4 p. e; E; Y8 C5 H3 P for (i = 0;i+ G- y' [& A- W2 Z/ I3 O
7 B% l3 ]+ S. r, B* g' MWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)& j0 j) q' b+ N* B) E7 p5 i( w/ a7 R
{5 s" u" P7 s _& @; X
int i;
4 ]- h8 M" D0 m5 z int bit = 0;
& w, b: X" M3 G, C Word16 newbyte = 0;
}. V' y p. M' G( y, `' x* `1 l Word16 value = 0;, G' r. T5 \+ _8 \/ F. J$ Y
- s2 h; A; @3 P+ x5 K6 x) h5 O
unsigned char *p = bits + (bitpos / 8);3 a0 S' K. \5 [% A" C8 k
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
1 m2 G% K( \8 p! vif (bit == 1) {
# @6 b- F' o9 e4 B newbyte = (1 / t% z5 e9 X7 ? U
return value;
1 J' Y( c- j* R3 h2 I1 d}
" U' h5 ~5 k) L通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
5 v# D% r J! K5 G/ C$ p
9 k3 k- O% e2 H$ L1 h2 X编码器的代码能采用如下的修改方法
4 d% E7 `# m5 m0 d(1)修改coder.c:
4 ~% O; t; S5 W' |( k- nunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */9 f* W2 f8 ]! c$ [% B w( p! `* D
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):( N) m2 P& \! a9 @0 l$ b/ K' l4 X0 o
frame =0;
4 j9 T; {/ D+ ]1 F" P& ]" { while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)2 q$ Q% g. b9 b* u+ }) W* u. u7 J
{' X6 d6 W) Q5 c4 L4 T# P$ K I4 P
printf("Frame =%d\r", frame++);
! |0 I" k& ^& D6 e' _; u3 `( VPre_Process(new_speech, L_FRAME); m) t- }9 i) L8 d. E# H; P& \
Coder_ld8a(prm);+ ]6 s" r& h' x" k! k
prm2bits_ld8k( prm, serial);$ V8 J' Y" m) p; o |- I2 ~
fwrite(serial, 1, SERIAL_SIZE, f_serial);
; Q. x* K, K* i5 A# f }. ? ^. W' P4 Q0 ^- P- [; g; J
return (0);
" T1 B; {; l3 S# G' V. Q
# v: E! X. t% p( J' J' H E: j1 O(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
2 B* x3 c4 U! p) Q1 U% B2 t/ U4 t4 f1 ~#define SERIAL_SIZE 10
5 F5 u; ^' n- U, w
' H# j# T% u& {* V. ~8 z" p(4)解码器decoder.c进行类似的修改(关键部分代码):
' ?# T, t, G9 x# G frame = 0;+ H, }4 e, t$ |' h$ a
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
# @ Y( G) [$ A9 q7 A# p2 y4 J {
$ e8 E8 l# Z7 ]. Z4 s: S, ?printf("Frame =%d\r", frame++);/ H" w; C7 x3 W- J; K5 |
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
8 T7 |5 ^3 p+ ^parm[0] = 0; /* 假设没有丢帧 */: r! L% Q: x4 t$ ?3 A% Y* X
parm[4] = 0 ; /* 假设数据效验正常 */, }. W4 ]; |" ~
Decod_ld8a(parm, synth, Az_dec, T2);
9 Y9 h; h2 f1 P( SPost_Filter(synth, Az_dec, T2);
2 o U; ~( z0 z0 f. _, _Post_Process(synth, L_FRAME);3 y+ p, H0 a+ ] C
fwrite(synth, sizeof(short), L_FRAME, f_syn);) `) g6 O. Q i g; B/ g$ ?8 r7 i
}9 e" y C) L: [7 E# S2 {+ b+ m
return (0) ;
4 j) L r1 s+ \. ]通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
+ o& [' F' K" O8 a, c. U \5 n( b& d
修改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]得到,应该就能了。8 \/ h; U5 \( l: V, X
封lib:7 H5 f2 }, z/ [- Z2 ^, z* {8 ]( h
va_g729.h
~1 ^2 V: f8 J, E#define L_FRAME_COMPRESSED 10# s: b9 G6 K7 Q5 E A+ v3 S: \
#define L_FRAME 80- N D ?1 ]0 |
#ifdef __cplusplus
- E7 G5 e- a3 ?% E7 @extern "C" { ! y/ _( C" l. g, J7 T9 @. u! ?9 [
#endif
, Z6 K1 i1 E# k, O" s8 {void va_g729a_init_encoder();
4 L" J" S j6 w, Ovoid va_g729a_encoder(short *speech, unsigned char *bitstream);
0 r, f4 ^1 N. P0 n0 C' L* fvoid va_g729a_init_decoder();
+ S1 m& B8 \: N1 E9 M! [$ j l- H0 wvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
/ v$ C" P% H. \! @#ifdef __cplusplus " z) L, e, v0 n4 v; H' v0 Y, G5 z* H
}
^! ^; P# d3 {# T l5 ]#endif7 l1 R( V# P6 o, H2 G% y
va_g729.c3 y% H1 W1 i. a5 c1 B. p
#include <stdio.h>
2 H1 v% x9 J7 t3 w7 w#include <stdlib.h>
2 b f9 m! T8 f# G) @; W! I9 e" t#include "typedef.h"1 C( B: G" _% ^+ r2 C4 ^
#include "ld8k.h"- T* G6 l! v p, D* u, j
Word16 bad_lsf;& _( ~ O% O+ ]
void va_g729a_init_encoder()
. u6 m5 k4 e o+ M% q7 N2 J{# Q. L. G: A/ W- N8 G, Z
Init_Pre_Process();
* `% K3 {1 W6 R+ F- L Init_Coder_ld8k();
( v$ t3 P% b+ u+ I/ H* j}
1 G9 k9 E( |. J# |void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
E& F0 k4 ?9 r: L% H6 u% r. V{
2 b8 D& P5 f, o; A" w extern Word16 *new_speech; /* Pointer to new speech data */4 b3 m* ?) Y1 f/ Q- c$ u& @. j
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
4 B5 w% z, X/ J7 P; p! D+ A' s1 [ Word16 i;
2 f$ F) ~: V$ ?1 j' y2 DWord16 syn[L_FRAME];9 W! R: w" _$ r3 @; ]3 x7 `
for(i=0;i<L_FRAME;i++)
( V- |( w# Z N. S) l C1 ~{: F" |4 g; K. u
new_speech = SpeechBuf;8 e3 B! }- Q; b, t$ }
}
! }6 G: t! |, q2 @ for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
: \5 J" C% C$ d- s* Z# M" F Pre_Process(new_speech, L_FRAME);
! n! Y9 T; P8 X) Q$ X Coder_ld8k(prm,syn);- E. R/ l9 K4 {/ M7 y) x
prm2bits_ld8k( prm, serial);
- @6 H$ q( A2 T: {8 ]& m}
7 Y) h# G( l: [& Z- [* vvoid va_g729a_init_decoder()/ e+ B2 y2 ^& e( H: T
{
9 E$ Y! \7 ]2 m; G6 ~1 m; J( cextern Word16 *synth;5 U5 x2 ?: V% Y- z: u) [1 ~
bad_lsf = 0; /* Initialize bad LSF indicator */
; z9 Z# e3 Y) l6 L Init_Decod_ld8k();
# s/ j+ y4 H# _) R* w Init_Post_Filter();
4 z" N% b; z* X, S# g; o Init_Post_Process();
8 k& g5 I/ A; d$ M/ E. S9 Q}& t. n' O: o) ]! Q% {
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
3 N4 p, M2 h7 d& z{5 P3 D: a: i# B
extern Word16 *synth; /* Synthesis */
" `4 J" j& i3 IWord16 synth_buf[L_FRAME+M];8 P, d; d" X& Z$ f
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
/ z) [; B8 S, o# v$ E0 n( c" zWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */3 n1 O& P6 x& B) }3 \% O( c( o- W
Word16 T2; /* Pitch lag for 2 subframes */0 i" m$ X2 r7 Q, z6 C8 }8 g6 O
Word16 i;+ A( Z1 |. h/ M# M& c& g4 P; ^9 J
Word16 voicing = 60;
% }# Q3 i H: @% `1 l- q* kWord16 pst_out[L_FRAME]; /* Postfilter output */3 w H5 U2 g8 G9 M* ? ~
Word16 sf_voic; /* voicing for subframe */& K2 l! T8 N+ {3 j$ q! c& [
voicing = 60;' c7 |; r# A. ?6 N
bits2prm_ld8k( serial, &parm[1]);5 ]# L% i. e4 Y8 W( J- j0 b
parm[0] = 0; " W" C2 L2 ]% m# |2 N) y
. \3 s. T! ?) y( }% l3 x, } parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);$ `! n$ L+ I2 s; K
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
1 [) ]5 [- f2 N7 i5 _' q9 @//--------------------------------------------------
/ A. x2 z+ C6 O6 Q! T9 evoicing = 0;
" C6 g6 X7 A6 iptr_Az = Az_dec;
, S+ j+ I- [: ifor(i=0; i<L_FRAME; i+=L_SUBFR) {- p2 C% m/ N/ l. ~+ R- S
Post(T2, &synth, ptr_Az, &speech, &sf_voic);
0 y7 n) Y9 W G* z! f+ a/ q( W if (sf_voic != 0) { voicing = sf_voic;}
: c5 B0 p0 _' x* W ptr_Az += MP1;
; S- H* X- h! O' m! U% r+ N/ D}8 Y" t8 {; ]; j6 v' \# |4 q# G
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);/ u3 g l1 W7 ?' X
//---------------------------------------------------
3 x! Z, y* n3 g2 `. O; c Post_Process(speech, L_FRAME);
% M6 @$ l4 I( K' Y, w0 }8 N% ?}
: N* s! X5 s/ G( I; C
) f; f! Z# {7 R: |+ U* Q1 c |
|