|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
$ s* p; ~7 `; q8 f9 V7 o下载以后需要修改bits.c文件:
3 \7 M) [# ]" J: v7 M$ L我仔细研究ITUG729代码后发现:( W( l, D; _2 Y) X: N
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流. H, d4 ~$ g. s- G+ S) j
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
/ R; y) X. `! q f+ r2 o0 q1 u& o$ V
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
. k; {2 s& r# Y/ X: p0 `* V
3 G L# f" H* q# ~那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。, t. L/ g( r1 W$ L7 ~
我们打开bits.c,就能看到里面定义的如下4个函数:4 Z7 L1 d; R2 ~$ F& f/ M
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
% z, w! ^0 l( f$ \) ~+ _# Ystatic int bin2int(int no_of_bits, INT16 *bitstream);8 @4 d2 R3 ^) I, ]0 f! W$ @ j$ L
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
" y: O. Z- k6 y4 Evoid bits2prm_ld8k(INT16 bits[], int prm[]) ;! d9 ]: N4 S+ O0 v/ E! ?& H1 M
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:4 N( b9 X/ s% J$ {6 U3 U
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
+ o; D$ z3 |# n) V# C8 ~/ Sstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
2 h! b Q# m4 `' m6 u7 U) Q- k2 e% H- F
void prm2bits_ld8k(Word16 *para,unsigned char *bits)
% K; K5 m& E& }, [{# F% @* Z( h) @) q0 u% b
int i;, y0 c/ D; {. s; e2 e
int bitpos = 0;
! {, x* u( V9 O$ ^6 ~ for (i = 0;i
7 w! R) M7 E8 T3 Z' E! Z4 b% A0 d" I8 Q
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
: u% d' }9 r1 D. Y" `{6 k5 B4 [( L1 @& I) L& S
int i;2 w; s8 r2 k9 j' H9 b
int bit = 0;
) _5 |# p! T6 j7 O unsigned char newbyte = 0;; R1 s% s- i9 R; ]% r% S/ n
& g& I1 B/ k8 S' o
unsigned char *p = bits + (bitpos / 8);5 K% |2 }1 C( d' b1 @3 F X; Z
for (i = 0 ;i > (bitlen - i -1) ) &0x01;' m/ \. k. y* [ v" U" f2 p* I
newbyte = (1
* ?/ [/ x& h1 J! w% zbitpos++;
/ `/ c9 D J( d+ o% w# d7 pif (bitpos % 8 == 0)
4 n' i& Z" i& z+ O; t, x3 }) Q p++;, Y4 X, E P3 a8 B; g1 \- P
}
n' @5 b9 t' k/ Z% h) X; b6 L}
8 B% `# O6 m0 ^) M1 z2 b) s! @& U7 q2 |
void bits2prm_ld8k(unsigned char *bits,Word16 *para)& d* f M- `1 \* U
{
6 N9 Y" L1 } k) N; A5 R. ^* x int i;
d9 B4 M, q# _+ R4 w int bitpos = 0;: }; i6 _3 r& s' }5 ` K+ p6 C$ C
for (i = 0;i
e3 _. ?- J5 [0 F. Y* B3 r) p9 ?5 ~# Q0 c
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
& S# ]% W( g- x# ?{
; K/ F* F! w- k7 Z& S int i;& P, t) G& e: A# A: Q) E2 V$ F
int bit = 0;: }1 Z: K' z5 T& ?! U
Word16 newbyte = 0;( S4 @9 C+ V, i" g9 H: G. X' H' A
Word16 value = 0;
# s& S' S& H: N Y D . A( p" S+ p* [; b7 M& f/ F
unsigned char *p = bits + (bitpos / 8);
7 W, {+ e" T; y/ p for (i = 0 ;i > (7 - bitpos % 8)) &0x01;% Y3 G" S4 y; z- d1 G) h0 B' e
if (bit == 1) {
' o( `4 w% c# V6 X: F3 W newbyte = (1 $ u }3 \ W* t9 f
return value;
. }& v$ \4 @" Y7 h6 u4 X7 W9 k}) I+ @8 ]1 J! K; x# r: {7 b
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
6 Z* F! R# H) c( |. u# \) }5 m1 d
编码器的代码能采用如下的修改方法
/ }/ S/ I' z8 |* e* I" m& s# V(1)修改coder.c:
( r( w4 E% k+ O; s: ?( R8 b% t1 Runsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */ J, L8 \$ r) \4 V+ X7 b( v0 G
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):& Q/ o8 H% F" s$ U3 ^
frame =0;
- X9 [! b0 h+ ^2 d while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
) q4 G, d- B5 b" {% w {( a! S: k- B0 c/ k& y0 \6 V
printf("Frame =%d\r", frame++);
( ~* Y5 z* t- I- @5 o8 r$ {+ t1 i' UPre_Process(new_speech, L_FRAME);8 _* f5 t7 B: n- w
Coder_ld8a(prm);0 ~7 C. s7 L0 \: ^
prm2bits_ld8k( prm, serial);8 Y2 Q" {" m- d7 F! _* _
fwrite(serial, 1, SERIAL_SIZE, f_serial);
0 H7 i+ H$ v/ S. k: H% K }
9 C. J; n5 l8 L return (0);/ M1 K, H, I3 `, \
' o+ `! d& G5 Y3 }3 D# t' M(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:% U' p, s. h) F! R; V
#define SERIAL_SIZE 103 ]) ^0 S* h* U( J% S
- p! C% w5 A2 ^0 ~
(4)解码器decoder.c进行类似的修改(关键部分代码):
9 x4 J4 S* w; t3 m; [% \/ L frame = 0;* S! u& ^& K/ l
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
, k+ }) H6 R5 _6 d1 d" x5 @ {
. `0 A- y! I# e4 _9 h8 W8 T* F. ?printf("Frame =%d\r", frame++);
" F; b, H2 [6 o/ h( obits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */: _6 u+ p6 J, m) _" P4 J/ R' _
parm[0] = 0; /* 假设没有丢帧 */7 P: C$ K. S; }$ `) f. a
parm[4] = 0 ; /* 假设数据效验正常 */0 g0 g* |0 [1 V6 P# R* J) Z7 S: U
Decod_ld8a(parm, synth, Az_dec, T2);3 c6 E; _# u4 v2 w. U
Post_Filter(synth, Az_dec, T2); - M; A; c1 [: f: Q
Post_Process(synth, L_FRAME);; o! _4 [1 R$ g$ ?
fwrite(synth, sizeof(short), L_FRAME, f_syn);
x7 _$ ?. ^( B2 n! X/ R' l }, m& x$ w& n3 O
return (0) ;
. Q- H! J3 M+ [! B! i$ {通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
2 f8 i. _8 b% L5 Q
1 @1 A, A7 Y% w- ]8 o- y% Q( Y7 n5 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]得到,应该就能了。
2 }; h4 x( Q2 r2 B. t" n6 Q1 b封lib:: N* w4 Q, l8 r9 I
va_g729.h: {& j% ~% D. u, T$ K$ `
#define L_FRAME_COMPRESSED 10) V0 j4 e7 q% x
#define L_FRAME 80
9 H1 A9 [$ h8 o" n#ifdef __cplusplus
9 N8 G# \. T0 r/ Iextern "C" {
0 q( E8 c+ k6 @! J#endif
9 l1 {: o. C# i* I: D! gvoid va_g729a_init_encoder();6 T: |7 E$ b5 m0 n; e b: i
void va_g729a_encoder(short *speech, unsigned char *bitstream);
6 h8 R8 n4 z! _; N4 m! bvoid va_g729a_init_decoder();) y5 ?4 ^; J1 Z# p5 N* z. U
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);. T0 o( z! f/ K4 X7 e
#ifdef __cplusplus 5 v, L% v4 j7 T( K! q
} : H6 M B c& N( e
#endif
6 G% f' d6 b+ T# C, |& x1 A: }va_g729.c
! h, T9 k8 Y* C+ P#include <stdio.h>
) W$ y; T h# `: M. j; X7 c#include <stdlib.h>
, u- G* O+ C8 [#include "typedef.h"
; ^4 p4 g1 S/ K i. P! `#include "ld8k.h"; W9 o U6 r# d' j Q- y
Word16 bad_lsf; b% U$ p9 l- S2 l! n' m1 y% G
void va_g729a_init_encoder()9 a' v0 M, ]% Z* Z) F9 S
{
# D Y* [- V- w) a Init_Pre_Process();# n% T8 F) k) ]1 ]# q
Init_Coder_ld8k();
8 |9 A: g# L3 C* f3 A+ H) K1 r: \1 X" e. w}
* q5 o- o% u( D/ k3 {1 P0 Bvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)( G6 V/ I# I- Y% F" x
{
0 P$ k& h: N8 v- M extern Word16 *new_speech; /* Pointer to new speech data */
4 D% e( ]! _+ d( E2 A% L/ b" T$ B Word16 prm[PRM_SIZE]; /* Analysis parameters. */8 g! l' Y. N, s4 i3 e, B# \
Word16 i;
g/ \8 U/ ^1 S0 ? X* IWord16 syn[L_FRAME];/ U/ u0 p- |" e. W1 y w
for(i=0;i<L_FRAME;i++)
3 T6 s. Y0 w0 j& G{
, Z, }. n, S; c" m; b# _ new_speech = SpeechBuf;6 }0 U9 x7 A7 x1 C9 X' j
}
+ J; K; ]3 H9 m6 |6 s( z% z for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
2 _) U+ z" j1 `' G7 y# e( k l Pre_Process(new_speech, L_FRAME);) O6 ^- ^2 m+ w+ p
Coder_ld8k(prm,syn);4 l/ ~/ M1 z( P& z% s
prm2bits_ld8k( prm, serial);
5 ^" e" f4 G1 Q0 z. G& r: ?}- @( s: n4 [9 T
void va_g729a_init_decoder()
4 p& W8 l8 K. s' c' s$ f- Q{- s- b& v P& Y8 j
extern Word16 *synth;$ N, H, ?7 m% B- l1 t7 n3 W
bad_lsf = 0; /* Initialize bad LSF indicator */
: `' g" f: ]! r) V( P Init_Decod_ld8k();4 J+ Y+ J2 x6 c
Init_Post_Filter();
3 l, P3 J! \" T Init_Post_Process();) d Q4 j6 ^% x7 k5 T6 T, _3 g
}0 `8 `4 T2 e q, p+ L( w1 `6 I* w# S
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)0 T; G3 M; u. H
{
' v: T0 ~! g0 M3 D8 S8 Uextern Word16 *synth; /* Synthesis */
5 v. `% c. s0 C* lWord16 synth_buf[L_FRAME+M];* g, }# x. u% Q) M: U, d
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
& X. v* f, O$ O5 i! O- N0 ]Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
# F' F; O' b V+ @: M3 B U4 yWord16 T2; /* Pitch lag for 2 subframes */
$ z3 E5 {. S. G- j/ kWord16 i;
0 L4 {0 o s* x1 ^0 r$ `Word16 voicing = 60;6 @/ {; l( C/ _0 }
Word16 pst_out[L_FRAME]; /* Postfilter output */1 Z9 R" d: ^& [9 \9 ]& P
Word16 sf_voic; /* voicing for subframe */
; e U3 m8 u" ^) cvoicing = 60;. f7 Y: ~4 [7 ]1 T9 W
bits2prm_ld8k( serial, &parm[1]);
& E3 _( P) [, j" x0 u3 \. k parm[0] = 0;
! p+ Z( ^- l F# l
( C% H! W0 ` s8 t parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
) E# b P8 w+ E1 p, ^& qDecod_ld8k(parm, voicing, synth, Az_dec, &T2);! n2 Y' K2 l' x# |
//-------------------------------------------------- V1 C: w: ^: W3 z6 v9 ~
voicing = 0;
- K: v5 v( ?- ^7 m/ kptr_Az = Az_dec;9 u# s# H" e9 `% ~
for(i=0; i<L_FRAME; i+=L_SUBFR) {
3 b- V" d- O4 X @ m O6 I Post(T2, &synth, ptr_Az, &speech, &sf_voic);, Y9 f# h- c! g. G. Y
if (sf_voic != 0) { voicing = sf_voic;}9 O1 y7 _1 k# a* j$ q% y( B* @
ptr_Az += MP1;9 d" F1 I3 B6 q* D! m5 E1 B3 m% r
}1 p6 p' h4 |* M. K# [& m# Y# b0 k
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);: z# I- e8 v! R- x, y# @0 ^$ J
//---------------------------------------------------
2 D/ n( S3 E6 q Post_Process(speech, L_FRAME); 7 h; e0 P `+ q6 A& f
}
* ^7 u- Y% e% a6 S7 Q2 W: }9 |4 y: M9 x; c6 K
|
|