|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
9 ~' I1 T4 P4 Z2 K4 c7 {+ f& M下载以后需要修改bits.c文件:
7 g z% R$ r' Q/ _- c. \0 s. A" D$ m7 u我仔细研究ITUG729代码后发现:5 ? X! y2 U* c
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
+ Q+ e# K/ `, V1 Y% W9 M8 r; h& W,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
$ h6 e3 s( D' t8 M; q, N4 A/ J D- B. H6 ]- R* z% J" p$ p: m
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。% ^1 j8 U. Z# B% o
6 e4 [8 Q7 Z( S4 |* r( E1 Y: O那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
1 g+ Q0 A2 @$ O4 M. t, O$ ~我们打开bits.c,就能看到里面定义的如下4个函数:
$ L) c6 e z7 ^/ a& P# kstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
; z% [/ _- s. b2 {) T5 S: u; Istatic int bin2int(int no_of_bits, INT16 *bitstream);
9 N% [! Q; e. Y u+ m+ D% `: ]void prm2bits_ld8k(int prm[], INT16 bits[]) ; % E5 f+ I: |/ w% |1 F
void bits2prm_ld8k(INT16 bits[], int prm[]) ;) T: C9 l% Q" a3 y5 w- d8 u; Q
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:. h" `( m q! x! @' k5 e; [* @ K
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; 1 h* K. l- g0 L+ K6 }: J9 m
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; ; C: b0 \' ^, }, k6 w, `) ?
- _2 }- v6 }- G1 I3 y. q- _
void prm2bits_ld8k(Word16 *para,unsigned char *bits), `% s. b7 e' j+ T. L$ i5 J# A0 ~
{
; K/ H) [1 v0 }+ w7 x6 G int i;- P5 ]. D3 d/ ~% `
int bitpos = 0;7 H( U' c5 B7 X$ U* M% o
for (i = 0;i
$ U" F: Y2 o# h+ s! i0 [; a+ M# p* S9 l- z) n
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
3 s! k% u/ H: d{
+ z0 C+ f, Z# ~* A4 ~# o r; G int i;! K' u# k7 _$ ?: e: h
int bit = 0;
! G# r" P7 }/ z unsigned char newbyte = 0;8 Y7 |; j7 d0 @6 g2 X0 O
7 ~2 I3 s# v) K: N1 k$ b0 Z+ [
unsigned char *p = bits + (bitpos / 8);, a( {( w5 \( q' j3 }3 P6 ?! E$ E* d
for (i = 0 ;i > (bitlen - i -1) ) &0x01;# L$ ?$ E1 y7 S' g
newbyte = (1
7 {( O1 e3 o& ?* a6 Cbitpos++;: z: G x: o* X) s7 M
if (bitpos % 8 == 0)+ b& Z7 L2 B8 I+ ^. b3 V9 j
p++;
/ M+ ^5 d! P/ O) ]8 @ }2 q3 _3 W2 U( S/ N3 `) r+ i6 j- j
}
8 A( Z$ ~ b" [, z/ d! j+ I+ K" g" O3 L. C
void bits2prm_ld8k(unsigned char *bits,Word16 *para)6 T) X" I7 z& X3 g2 A; @
{9 K0 p7 T. P4 V4 K; m: a1 g
int i;
" p3 ?+ V+ x, l int bitpos = 0;
# N3 k4 K' t' _ for (i = 0;i. E* [3 \/ F1 |7 x: r+ h
- H) }7 U n: Z: X5 G5 F3 T% O
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)$ f9 D6 e; S0 N8 q* i* ]4 e2 q
{
+ L k. E5 {0 J( n( y int i;
5 T: q/ r |& G- Q7 F int bit = 0;! e! H* P4 p+ ? D: R( {
Word16 newbyte = 0;- g1 O8 l- V9 I& K
Word16 value = 0;$ _9 F! x* V9 T- o5 W5 y
$ P2 t$ c% q5 O# f0 B7 W( d
unsigned char *p = bits + (bitpos / 8);
H Q+ h t, j( Q& P for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
! F# q! _, s6 m5 h* wif (bit == 1) {* G* ~, t# G* t
newbyte = (1
- x& m0 E* N9 E return value;( l. W" g' Y+ ?) @' X
}
2 l+ j6 K7 m8 \2 D# u+ K* J通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
6 y5 I8 i! A! Y
, }' o3 ?7 W8 |8 v2 U编码器的代码能采用如下的修改方法/ j+ y- m2 s6 v6 ?6 h% b
(1)修改coder.c:
% ~1 M# N$ _* a$ H- aunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
* q2 a( J" O/ @, `/ W: h(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):3 Z6 Y e# W, m
frame =0;
1 Y3 s9 }& G3 m( C while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
+ P. L3 m! ?$ b0 _- c0 m" p4 v1 x9 ~ {( O! w- L+ h |8 t+ y: i
printf("Frame =%d\r", frame++);
% b" k6 B4 q' k. v& e9 {Pre_Process(new_speech, L_FRAME);
! e! I4 o9 D0 K pCoder_ld8a(prm);
y" l( J2 L- F$ S2 A9 rprm2bits_ld8k( prm, serial);
& b* o1 P3 h8 \) s* |" Z) Mfwrite(serial, 1, SERIAL_SIZE, f_serial);( j6 r. c7 s& n% P# q/ g
}, Z! d7 q! B9 J5 Y& R
return (0);
+ Y! r& T# ~7 a& X7 J% y: R. ~" y
- w, R( z; S4 k3 G: {(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
' \* @0 i. B3 i+ m" m#define SERIAL_SIZE 101 ?, L) o1 {! @8 g9 V6 q! F
! S! ~6 Z% z8 I3 s; F; x4 }
(4)解码器decoder.c进行类似的修改(关键部分代码):
( \% x9 E. [! _3 z& R- o frame = 0;" ^. V- G1 |1 o" `6 D% x: z' c! Q# S# S
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
$ T6 K- a0 _0 d: D" t {
# V5 k0 D! G9 ]. Tprintf("Frame =%d\r", frame++);
6 e" F' }- P0 U0 G# p. Zbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */: q! J; Y( l: g e- t' i
parm[0] = 0; /* 假设没有丢帧 */
, i9 b5 H( C0 nparm[4] = 0 ; /* 假设数据效验正常 */3 f( Y a, I8 {" h. `, g f# Y
Decod_ld8a(parm, synth, Az_dec, T2);
& n9 V9 J4 ^. h9 l+ bPost_Filter(synth, Az_dec, T2); " [. w" U. t2 ?4 `, {0 X
Post_Process(synth, L_FRAME);
3 \2 @' B9 R# _8 H8 w) qfwrite(synth, sizeof(short), L_FRAME, f_syn);
( T! ?6 W( U( p2 ]( b9 N }
7 s; H/ s8 w3 Z/ t( Y4 c. L# U9 j return (0) ; ' D9 E I5 [& e
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
0 q6 J* p9 r) {/ C t# j1 }3 M) x7 U- @! d- D( N- t3 l/ \: o7 _ ]
修改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]得到,应该就能了。; U9 ^5 i+ E9 ^3 ^2 \/ S# f
封lib:5 ^3 I5 S* _1 h5 }
va_g729.h. {$ q: u7 n; k* h( F9 c- i
#define L_FRAME_COMPRESSED 10
* A' H6 A* D3 D! z5 d; ], q" c#define L_FRAME 80
) O) U9 o6 {0 x2 c* l e$ s#ifdef __cplusplus
8 `8 Y8 _; b" G- R& S. E9 `: zextern "C" { 9 k; k5 F- J6 Q$ N2 N' ]/ t9 m4 i
#endif
2 @- p1 Q: }5 }) pvoid va_g729a_init_encoder();
) |4 B8 J6 U4 p5 G5 F4 [, zvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
3 J8 R) O) w2 M/ V4 w2 S) vvoid va_g729a_init_decoder();
# ^1 c h$ _/ t& u; I! nvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
W9 h$ J5 I. v6 [/ Z/ q5 `#ifdef __cplusplus
* z3 r# Z7 m) p2 i: a( s: w} m! M! t' g. s; \! Z) {" }0 f
#endif8 }4 M$ V: ^# r% J4 F
va_g729.c
5 ~' v5 d3 V) o7 ]" ^3 j#include <stdio.h>
7 [" T6 b1 ^, l/ }% U) I- P#include <stdlib.h>
* d+ ]6 ~# s' ~+ R5 u5 I/ V: }+ r#include "typedef.h"
1 M% ?9 B" C5 Y/ G0 D- j#include "ld8k.h"7 j8 `2 U$ W( ~- _! V0 A
Word16 bad_lsf;
( v. o1 }' E+ c( e; Z2 J9 g8 Mvoid va_g729a_init_encoder()
/ ?; [3 @/ O+ l1 m& P5 _{
, s) E1 h. t: L Init_Pre_Process();
% }6 B. Y" Y% G) m6 J: Y$ u0 @ Init_Coder_ld8k();
- Y' h- ?9 B0 A1 \; E0 D. Q7 ]* \' A}
5 Y$ D. y! B1 i: Nvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
) `4 \: A* l9 S* }$ y7 Z{
/ `1 X, T9 [) G1 [ I extern Word16 *new_speech; /* Pointer to new speech data */
2 G: z+ g6 p0 ?, t Word16 prm[PRM_SIZE]; /* Analysis parameters. */
' v2 ^4 ~0 N5 d' m8 L* E0 H Word16 i;2 z. v7 y4 |- [7 n. e7 j& t3 g
Word16 syn[L_FRAME];
3 G) K* H7 O. E z6 ? for(i=0;i<L_FRAME;i++). ^2 r# }3 m; z
{
' P: c" b7 d% D new_speech = SpeechBuf;
1 G* D$ u3 v# x3 P" w4 s}
4 t! L( J. L0 {- v( w; v for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; " w+ _8 ~: _$ g; ~8 O7 I
Pre_Process(new_speech, L_FRAME);. K, \# u" g* Z+ n+ i( w/ O, y2 J
Coder_ld8k(prm,syn);
* l9 ~! ~( q3 ?3 d9 j& E2 i4 g. ? prm2bits_ld8k( prm, serial);
+ X) b6 ?. U! ?3 G6 ], h}8 v# d' k/ v4 M3 p0 \, s
void va_g729a_init_decoder()% L7 {3 h! k# k' d& q1 c2 q
{
" Q. }! C8 O5 y% y) c& lextern Word16 *synth;
5 ]& J) P5 u6 y( ]* j bad_lsf = 0; /* Initialize bad LSF indicator */4 a; J# P2 Y. O+ Q5 r! @4 }# p
Init_Decod_ld8k();
7 j- x' F6 ?8 r E5 F% ^( R/ | Init_Post_Filter();
" v6 ?7 o- E5 a6 v' C Init_Post_Process();/ |5 c) C3 B, `! V2 S2 S
}! R! x% j: o, `8 J: M' g
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi), K! U4 e8 A4 y" n
{
. n* t- E) q" E% L4 Y* mextern Word16 *synth; /* Synthesis */! ~/ W0 H& ?" r! {$ d+ l' W
Word16 synth_buf[L_FRAME+M];
* x: M7 d1 ]: ?3 jWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */
3 `+ c6 {& t: c& _4 J" s) fWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
, Q9 \" G+ g% Y1 B, T) L% S9 sWord16 T2; /* Pitch lag for 2 subframes */: Z2 |6 N) K% o- ^- A
Word16 i;
\6 R3 v6 ~! X7 {Word16 voicing = 60;; s/ |/ o+ ^' N
Word16 pst_out[L_FRAME]; /* Postfilter output */: y) U; s& H: B/ H1 ?* w' j1 ]
Word16 sf_voic; /* voicing for subframe */
8 x+ z" X1 d, t6 L" R* n- u- kvoicing = 60;* X( ?7 m& q* x- Y, W
bits2prm_ld8k( serial, &parm[1]);
0 C. @1 I# d; g$ W: D5 C parm[0] = 0;
0 V6 t1 U( X1 x/ t$ o
; z1 F! z3 P! x- W% q parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);7 C6 s F9 K4 A
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);3 f# C' _1 w! J v
//-------------------------------------------------- D0 V6 P& X* i3 t
voicing = 0;5 Q+ }6 z8 l8 {$ i# h" ~" U. _
ptr_Az = Az_dec;
) C$ i+ \& \- r c; U1 a. I7 Gfor(i=0; i<L_FRAME; i+=L_SUBFR) {
9 f: y& H' ^9 |. |3 ^, K3 o Post(T2, &synth, ptr_Az, &speech, &sf_voic);
# ^3 `( B. f3 X& y* p! k- x% ~) { if (sf_voic != 0) { voicing = sf_voic;}. u' M$ w' I1 T* {/ e7 M& ?
ptr_Az += MP1;
, e. k/ B6 V: w' u- @}
9 D# g' N: l/ k. sCopy(&synth_buf[L_FRAME], &synth_buf[0], M);
3 w" c6 J3 F+ z3 J' T//---------------------------------------------------
) r$ _. j% j: L+ y; e$ V4 S Post_Process(speech, L_FRAME); 9 x( f+ }: m2 `$ J' {
}; j2 q. c, T6 j0 P9 a# _0 a
5 S. Q1 E3 g9 }9 p( R# C
|
|