|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/ S' X9 q; W/ }' c. X
下载以后需要修改bits.c文件:6 M s$ z0 k! ^/ ~5 p6 \$ y' [
我仔细研究ITUG729代码后发现:/ r. R2 z/ \+ o) G
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
: h+ \) {8 f8 A# ]/ b8 w,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
. R9 a$ X/ U! v% Q: n7 j: u2 a2 Q, @+ a2 a# i: |2 `2 v3 U
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。& w' o6 C1 |4 l# @% a
7 E$ ?* ^. a' x" S
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。9 k1 ^+ _' c# z9 Z" \
我们打开bits.c,就能看到里面定义的如下4个函数:
/ |- q' d# S+ g/ `, ~static void int2bin(int value, int no_of_bits, INT16 *bitstream);7 I j& Z& h9 D0 V
static int bin2int(int no_of_bits, INT16 *bitstream);
8 ]" d- M3 J {& {, avoid prm2bits_ld8k(int prm[], INT16 bits[]) ; " D- T$ L r$ w! v8 @# |
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
2 B8 n# ]8 e+ i" S H这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换: E' Y+ _. S. A9 N+ k6 w5 ]" ~
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
% ^6 V) N6 p3 _. _* T* mstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; # F7 ^' ]6 x) H- U" \; [" b
+ e+ z" u: G& |" ?; D6 \0 A
void prm2bits_ld8k(Word16 *para,unsigned char *bits)7 q6 n0 N/ {8 f# n' d& |1 ?
{9 U# y7 s. O& f" V( \3 ?8 ^8 k0 t
int i;3 A9 Y% k9 Z; ?& I2 P, F
int bitpos = 0;( }& w& K0 E5 J- L* H/ T( `
for (i = 0;i- B5 Z: @4 b9 v' k
, b5 I, \6 k8 d* L1 o/ tvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos): Q8 _' K! E, W2 P+ D {
{1 o/ b! z _/ M2 N
int i;
5 w( l, J+ T. A8 m/ x- b$ @! i int bit = 0;4 C' ]+ l/ J4 }. T
unsigned char newbyte = 0;
; N% |+ d5 J9 H: n$ C/ L& M # X" f4 Z1 L8 p' U7 R# |7 m
unsigned char *p = bits + (bitpos / 8);
: e8 ], P0 P l: y6 p for (i = 0 ;i > (bitlen - i -1) ) &0x01;
' }; J+ i' w _# q+ R' h: R9 s! cnewbyte = (1
+ \5 S9 z# t( l0 s* G: o4 gbitpos++;
4 o Z F0 H5 u; Sif (bitpos % 8 == 0)8 t( S R8 e) [+ d- n: b! A
p++;6 I, { M6 S6 f' {2 W" T
}3 p9 c' z+ e' N* l8 D4 v
}! g9 i: ], N+ L
) X$ |0 J% H1 A) ^: f& l- mvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)! a W2 ?$ I# l* F* R) r2 O
{
+ l) p6 X) \+ c* j int i;
$ ]6 S; n: R6 Q3 u1 I7 W; Y int bitpos = 0;; o* q7 @0 \- G0 J e8 I) r% k
for (i = 0;i! {" b' L& L" }" m1 D5 W* |4 q
, V% T. } j5 K$ W, y# R
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
- W# {$ j2 \$ y+ Q6 T{0 p7 z! P0 {1 T2 p& G3 }3 m: ?* ^1 n
int i; Y4 r- ]- x/ J! |9 ]1 M
int bit = 0;7 H. C j3 Z% \4 h" \5 A9 ?; K! b- t
Word16 newbyte = 0;; a7 O; `% O* x- s7 [( J
Word16 value = 0;
8 B! Q$ {4 d1 Y( e& { $ U2 Y; }- A* |# E& F) ^: ^
unsigned char *p = bits + (bitpos / 8);+ P; Z) w! t0 D9 K4 M5 o* C& Z
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
* ^' g, M$ [) K6 vif (bit == 1) {
+ {; I& v: } S7 Y newbyte = (1 : M, v# ]3 s3 J; W
return value;( r4 y! f# X( V1 O2 R
}
# E4 w% O5 p& i+ ~- [* E通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
" |8 R# p- x, Q, z" Y" Q/ t7 } c' j0 E9 ~+ y( I- F3 ~
编码器的代码能采用如下的修改方法# K; Q0 I+ i3 L$ @3 ~( z- k
(1)修改coder.c:
2 G" h3 ]; m) hunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */6 ]& d8 R* F' [" `* \! ^. k
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):2 X4 Z* S H# W# f) m* z+ |
frame =0;
/ P$ v( E+ ~6 r8 p: \* o4 ~ while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)( I' D/ X4 p0 ?' q
{; ~! u4 r9 o1 o8 x- ^( A
printf("Frame =%d\r", frame++);
' s) F' g) {/ C( u5 MPre_Process(new_speech, L_FRAME);
' E/ A# e3 Y4 f' _$ t1 iCoder_ld8a(prm);
( A# Y! i2 ?4 q' l# B# {/ c7 Rprm2bits_ld8k( prm, serial);
1 N3 t' M1 G3 {: @8 Zfwrite(serial, 1, SERIAL_SIZE, f_serial);$ K2 N; z0 e3 l
}
, j; F2 o0 N. g0 c return (0);
4 H5 k8 `7 [9 h1 m# c- g) y1 @+ S$ F4 v* F
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
H0 E3 [3 G$ V$ J6 j6 F#define SERIAL_SIZE 10
" l4 Y0 W1 w$ |; g" v1 N. _, Y: w; n3 b; r- @4 R
(4)解码器decoder.c进行类似的修改(关键部分代码):% T4 B* N, F1 A% X; }( n% P
frame = 0;
1 I9 b) \9 P5 m3 @% t while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
^2 I& P$ o) Y, T { i0 J2 r" U/ C7 D7 q! W
printf("Frame =%d\r", frame++);
' T' X; x; Y0 qbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */" P9 ~# l7 ~5 K$ `" h0 n( J
parm[0] = 0; /* 假设没有丢帧 */
# \# a. }+ D" wparm[4] = 0 ; /* 假设数据效验正常 */# l2 ]8 \4 c. M7 a& H3 E5 m& Z
Decod_ld8a(parm, synth, Az_dec, T2);
+ L. b9 y$ k7 z" ?+ nPost_Filter(synth, Az_dec, T2); u8 l5 Q2 y8 V) L1 v0 A3 U
Post_Process(synth, L_FRAME);
( G; `$ S5 \: b1 t3 Q8 j2 [ \fwrite(synth, sizeof(short), L_FRAME, f_syn);) I1 `0 I& ] H @
}
4 a% D3 A3 r" H& i6 p- `9 z& j return (0) ;
) V) g! d" N, A0 m% Y) O通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
* m. o6 f4 H. C$ M" `% d n
8 W' g1 H4 z6 [修改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]得到,应该就能了。6 L' x6 d1 [ ]* |. }
封lib:
8 _' d4 T4 a3 uva_g729.h. ]; H; x {! @( @' i, ]8 `& }
#define L_FRAME_COMPRESSED 10
! k( J* v) V$ G, x! m#define L_FRAME 80* f5 f0 m) i$ b1 S& H& F" Z
#ifdef __cplusplus
% Y9 @5 Z7 u# iextern "C" {
1 w V0 Y8 B6 d1 g#endif+ d( S0 E6 r; } B
void va_g729a_init_encoder();
( G: O; O5 q5 L3 U: Kvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
8 m) ]) c! j) d* J) g7 r- o7 H' H" qvoid va_g729a_init_decoder();
* P% G# s& y' K- N# r% G {8 k9 B6 `void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
* X5 O; N: Q0 G! Y- ]#ifdef __cplusplus ' V* B+ J+ I- C5 k1 G7 i
}
2 s( X) n. P/ J+ a) E#endif3 }4 T1 c+ V& L" Y
va_g729.c
1 c3 P7 e/ [8 d+ Y' n4 E# `+ r#include <stdio.h>- _$ _9 H$ C/ I5 P7 {8 n A
#include <stdlib.h>
1 E% Z9 k% e& Y3 \ c5 G#include "typedef.h"5 f3 Q$ o- J: A* a- G$ ]
#include "ld8k.h"' u' R( m. M0 \3 K
Word16 bad_lsf;5 [# m% a0 L7 h9 b" @4 ~8 d
void va_g729a_init_encoder()& w0 C& ]6 n* {/ l( w3 v j
{
2 Q# K4 U4 A+ ? ~+ X$ F! A Init_Pre_Process();
( d; v" g% H0 `% b- n% I Init_Coder_ld8k();
( O* e& P: Z- w' I8 `}
, f% y6 [! @6 Wvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
5 @! P4 k, s$ A- ?{
! e) ]% R- H$ D) c% [ extern Word16 *new_speech; /* Pointer to new speech data */
_% [. {4 l# \6 L" b& } Word16 prm[PRM_SIZE]; /* Analysis parameters. */; ^6 X5 C! M% ~( S+ r
Word16 i;
- V/ [* _2 ?7 T5 W, D6 GWord16 syn[L_FRAME];
3 K; x9 V- f1 `1 i | for(i=0;i<L_FRAME;i++)
, x9 E* N) \8 }5 a! q{
) T* ?: U7 W. Q) w: m. G new_speech = SpeechBuf;9 W! w) s2 A/ ~, ]
}
) Y$ N! R) Q7 L' V O+ c for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; + W; ~. _. S/ W; ?5 A) S/ S7 m% R5 a
Pre_Process(new_speech, L_FRAME);
. b6 m0 x! i! ^! F' }% z% X* N0 I Coder_ld8k(prm,syn);" k1 H6 p+ \" u$ n. r0 B, G0 m
prm2bits_ld8k( prm, serial);
! _5 e$ A% Y6 y9 _# q4 u; \}7 O* v2 |# e# w( i7 `
void va_g729a_init_decoder(): D1 w0 e: E( `+ ?: m
{
: Z; H/ F1 M' ^8 nextern Word16 *synth;
* f# r9 X$ v/ I bad_lsf = 0; /* Initialize bad LSF indicator */
5 }7 t- V7 Z1 Q7 V Init_Decod_ld8k();& C! g! Z" Q/ D5 x+ L) U
Init_Post_Filter();5 t A& [, l% E2 S& T5 v. a7 \
Init_Post_Process();: J, n/ j% Y3 Z" y. _' ~2 ]
}; e: G( U! [( X- S; B
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)( q [0 e2 J$ X) k' y
{) t: h" {5 {. F. u2 K& K
extern Word16 *synth; /* Synthesis */
b, Z* Y4 D: u: L2 g& O4 W# GWord16 synth_buf[L_FRAME+M];% \! _6 K4 x, p+ I
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */' x+ C2 j u, f1 B7 b' M: a5 z. q/ @
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */# X2 C; |0 }, C, R9 j. P# @! G
Word16 T2; /* Pitch lag for 2 subframes */5 l J7 L1 R, n1 i# |0 `
Word16 i;# }2 R- Z: ^" n, M4 C& n
Word16 voicing = 60;
/ q% D1 R( n+ ]0 VWord16 pst_out[L_FRAME]; /* Postfilter output */( j! o& z. O$ b, u8 l. U4 R
Word16 sf_voic; /* voicing for subframe */
: n- o- |, x$ [: X5 _6 t" Avoicing = 60;4 [- S% N) B$ u a
bits2prm_ld8k( serial, &parm[1]);
" \& H* q% m7 {8 M r/ y- s& z parm[0] = 0; # i9 O5 P# C( O. p. u1 n2 `/ c# _
7 y* Q# H* e2 O parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
3 d8 b; n1 r3 [& K+ A# D7 RDecod_ld8k(parm, voicing, synth, Az_dec, &T2);
( |0 B v7 r7 h. B4 f3 E- o//--------------------------------------------------
) W$ u0 ]$ k- m" |2 `5 cvoicing = 0;
g& J2 N# V, z. yptr_Az = Az_dec;+ ^% o$ ^6 Q! q0 Q, `. `2 X
for(i=0; i<L_FRAME; i+=L_SUBFR) {
4 n' g& s) ^" D! s8 N. v Post(T2, &synth, ptr_Az, &speech, &sf_voic);
8 e6 | z1 l) P+ @# K" ?% w4 I) D1 K if (sf_voic != 0) { voicing = sf_voic;}
. _8 ]. c0 V! x. ^ ptr_Az += MP1;0 d8 F X8 f }) `6 a& E2 C
}" ?' L& Z; S+ X' ^: [: U
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
4 P5 E& h* l$ p/ s9 k# r { d//---------------------------------------------------- W0 T5 i8 D! }6 l
Post_Process(speech, L_FRAME);
+ Z" X0 p! |- L3 [}
- Y- X. x9 R) C! v9 c
! d" H: b! L& |! T* T |
|