|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
: J3 s, w# b) a! i7 n' P" |3 ~下载以后需要修改bits.c文件:
6 [; S6 F8 d ?& D我仔细研究ITUG729代码后发现:- z9 h# z4 F! I6 @! t2 d0 C! |! h
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流 Q( y1 I. V" W9 K0 Y1 _' U
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
* _; c G$ P4 f" }$ V2 D5 U; {) I% c6 y2 i
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。: d/ e& z3 g: ?( ]/ z G0 Z
% @0 T# g+ O( ?5 g+ M
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。! p7 d- S, A9 G4 N
我们打开bits.c,就能看到里面定义的如下4个函数:1 `% B6 K; [5 _' A5 d
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
8 c) L6 j5 X1 D5 a! S3 d+ Bstatic int bin2int(int no_of_bits, INT16 *bitstream);
* _- G/ _6 |# F/ s8 A& [ Qvoid prm2bits_ld8k(int prm[], INT16 bits[]) ; / R6 R o- q4 z4 o# X8 S
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
5 c( x; N2 e% S. @这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:+ V% Z0 n# w, \
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; ! b4 P; b' f7 t) O, t/ w- V
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
$ J. L+ G8 m1 N- z- E6 V
( G; u3 Q3 H6 n2 B2 T# B+ [1 fvoid prm2bits_ld8k(Word16 *para,unsigned char *bits). T+ k$ i8 s) g) l1 R R# w U
{
4 R( i- z$ U$ `* G* h" w int i;3 S2 g2 c9 e+ X+ a! T9 _
int bitpos = 0;* s/ F2 U5 `$ Z1 b) g
for (i = 0;i' n) h% H" J- H6 w
+ ^3 z- b) q J) ]$ j
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
: _3 h1 Z1 u7 J{% _ ]" ^8 e* G* j/ C! o& _; S9 ]
int i;% ]2 N/ E3 |; o; Q
int bit = 0;
0 ~ w% w3 s$ N/ T, N unsigned char newbyte = 0;( ^( H/ a- m# X4 u+ n* `' r
1 C O3 o/ _! o4 }+ J
unsigned char *p = bits + (bitpos / 8);
M! I6 _ m+ u7 ? for (i = 0 ;i > (bitlen - i -1) ) &0x01;
1 {" m+ j' e$ @/ }" ~+ ? [newbyte = (1 , P9 @9 L8 u5 ^8 |& M8 g( A3 Q
bitpos++;9 }. r; O4 N3 h: R
if (bitpos % 8 == 0)/ a3 s n. K. c3 k# e. v' R
p++;+ Z5 H& }7 q& z! F4 V/ ?+ N
}. h" n; ?) F, J# t3 F0 F
}4 E4 m- _; s5 W) L8 Z0 \
7 r B+ w* q- ~void bits2prm_ld8k(unsigned char *bits,Word16 *para)' d6 G; j1 C: g8 |
{! P M0 U4 H# j3 m3 v
int i;; W% X. D: B: E/ X. Q! F
int bitpos = 0; L# e$ n* @, y+ M) M
for (i = 0;i, j7 U8 D, p5 q! l' k8 }
M' Q; z1 u9 c$ \8 [9 J/ ~
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)0 [4 v |! w2 @; \6 ~8 t3 b, W
{; S- k' Y! l- u* v3 A
int i;
9 x) p8 O& R* z9 N) R int bit = 0;
/ ~" T; m0 _# ?- B2 S0 P% J Word16 newbyte = 0;* u: q* }9 C# G+ Y2 l2 F
Word16 value = 0;; [, N$ a; B2 D0 O- m: h9 V
, _4 l9 v: @( b1 J; |$ J; S! b unsigned char *p = bits + (bitpos / 8);
2 B4 L. \0 V* ?- T6 u8 h7 m for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
. J. Q) @! P" r2 i. o& Zif (bit == 1) {
4 N2 |3 |/ o) D/ j- P newbyte = (1 + F3 G4 G( y( @
return value;$ j( W/ ~6 H+ w5 R
}9 `9 d1 l0 Y/ t- `, M R/ i) F
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
1 O& P2 y- k6 v2 C2 ~! v, c4 ^+ r- w5 Q3 W! I! K7 Y
编码器的代码能采用如下的修改方法) @, u) ^2 t7 k) a1 c
(1)修改coder.c:: f" ~$ Z$ k! t" Z b" u
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */3 ? x8 L ]: }3 \6 p o
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
2 I" \- B% ]$ x8 C. z1 b* \ frame =0;
, E0 T/ ]- A* S% {& h while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)# D2 S! v' l H% s G, w, C( h
{& N& j+ K. V4 v
printf("Frame =%d\r", frame++);
3 f$ x4 H! u1 rPre_Process(new_speech, L_FRAME);! B( ^) ~9 x3 j1 @
Coder_ld8a(prm);8 G$ @; x+ v0 z. D) l0 N! B
prm2bits_ld8k( prm, serial);( T/ M5 i! ^$ C S* i& C$ S2 I% o
fwrite(serial, 1, SERIAL_SIZE, f_serial);, u& F6 |8 i9 U) I* z
}* w; i8 p9 W" G8 C. H' E
return (0);! k5 J; V& C/ t1 o- m3 g
* o1 x3 k8 w8 i5 a! G
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:8 @0 m* r4 |5 l9 y
#define SERIAL_SIZE 10
$ e. l D2 T: b8 ^
2 f- r0 M N- |: O(4)解码器decoder.c进行类似的修改(关键部分代码):
4 V) q# |2 q v frame = 0;2 h( b$ Z+ @3 U, y$ y) y& I( f
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)7 T6 W7 g& R0 v1 p
{
2 X3 U" y, Z$ L' | S& Xprintf("Frame =%d\r", frame++);
X) q- `/ m* _2 \) Abits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */3 M! m% i. P& L7 `" v7 O, I
parm[0] = 0; /* 假设没有丢帧 */
$ d+ x+ A- j( X; t, X0 wparm[4] = 0 ; /* 假设数据效验正常 */' F4 o! }0 }+ o( t
Decod_ld8a(parm, synth, Az_dec, T2);( b: k# o1 y/ e# A/ ~, P6 m( O
Post_Filter(synth, Az_dec, T2);
' W! R8 a: k, ?! I) [( f8 ~% Q% UPost_Process(synth, L_FRAME);
" S. S: g, L! H7 r5 mfwrite(synth, sizeof(short), L_FRAME, f_syn);; o+ P" [; x( S' }7 W1 r
}
! @2 ^' w# o" h3 C o) ]+ H3 r return (0) ; % s ]: x6 ]8 v$ w9 @9 C& a! O
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。( U Q3 ~) a3 ?/ a" z5 K9 t
2 K1 O: [! |" n i2 t2 W
修改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]得到,应该就能了。! x# d( R) B! @4 B3 D
封lib:
* ~6 h4 k' o3 a) V" [- l' W% kva_g729.h$ K, }$ i" ^: g) `5 t
#define L_FRAME_COMPRESSED 101 K# J" @; ~3 v( G( I4 H
#define L_FRAME 80, C2 k5 n- Q: x, C- b Z
#ifdef __cplusplus " t) j% P2 w; K/ ^
extern "C" {
( ^" \1 \& P4 d0 L S# v#endif" P( p1 C& F0 a2 X
void va_g729a_init_encoder();/ U6 j! w6 [" E, N
void va_g729a_encoder(short *speech, unsigned char *bitstream);5 c) V4 I' D/ s& k5 N5 s
void va_g729a_init_decoder();: U- I" M: x |. Q& n% D! h; B4 U
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);) y- v: |" L4 d2 ]8 i
#ifdef __cplusplus
! s4 H: a4 v8 |4 \- J! O- \# ]} & o X J0 B X9 G( M B
#endif
2 e9 x' m- c: c4 jva_g729.c. \8 Y& ~$ z; M# u$ W9 ~6 u
#include <stdio.h>8 m0 h, G% S( D1 j
#include <stdlib.h>
1 `; R. Y A3 n, r4 p#include "typedef.h"$ O2 t. m+ F, a- G
#include "ld8k.h"
+ k( j9 F) L/ V; ~$ K W* E5 hWord16 bad_lsf;
9 N, x6 R' _$ ]; Vvoid va_g729a_init_encoder()# y) u" b5 _: w9 E8 k" M% j
{
% m+ \: s& ]3 M* t8 _3 _ Init_Pre_Process(); O4 j# q, A/ g
Init_Coder_ld8k(); 0 o! i" g7 J$ X4 f" w+ V
}5 q( |/ Y- k7 _
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
`+ e2 }/ o6 K( J{
- E' G. q2 m: k( v5 H extern Word16 *new_speech; /* Pointer to new speech data */
4 ~2 s- n" K3 ^. b7 h Word16 prm[PRM_SIZE]; /* Analysis parameters. */
! u0 E i9 u: t2 h Word16 i;2 e6 U/ @% R* I( d
Word16 syn[L_FRAME];5 ?1 U" P# y" l% b
for(i=0;i<L_FRAME;i++)
# Z5 l% n; X0 E5 r% @/ ?8 t7 g4 e{
. u# J8 o: G3 x2 L2 V* @ new_speech = SpeechBuf;
' b& V# W7 d! }) ?, m}2 i& r1 N: a) J1 B
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; I# f6 a* y; E p2 B l
Pre_Process(new_speech, L_FRAME);
" O* F& t# w) r8 K' W% Z9 Z Coder_ld8k(prm,syn);) e3 }# i# L* ^0 P( V
prm2bits_ld8k( prm, serial);4 K! `/ ^( u' |% M
}
% }) J$ ?, c# Svoid va_g729a_init_decoder()0 {" d; p. ?: H% C& o+ I0 a
{
% e! p* ?+ H& d, m$ q- s* i( Uextern Word16 *synth;" z# J$ @( J# ?
bad_lsf = 0; /* Initialize bad LSF indicator */0 m( p& U/ c( Y& t$ [7 j- R
Init_Decod_ld8k();
4 [) q& h" K) f9 B& ^% @# o Init_Post_Filter();0 r- j: g$ |; N9 g: C f5 c4 ^/ w! i
Init_Post_Process();# K8 K7 `5 n3 b6 u, a- d9 C
}
+ q- a2 F5 G, w. U b* ^1 U' yvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)8 A# x: `2 X! h4 z
{
! u1 J4 L H5 J0 W: pextern Word16 *synth; /* Synthesis */
3 k$ t4 L" m" q5 `5 GWord16 synth_buf[L_FRAME+M];
z: l5 k- {; L) j+ F2 b0 WWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */. q- ?9 J1 A& d! h! H7 m t
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */8 K( u. p+ A( i ]* r
Word16 T2; /* Pitch lag for 2 subframes */
4 } L& |1 K# K2 L" T# b' O6 tWord16 i;$ N% y1 o) E- i8 p: E
Word16 voicing = 60;! m6 M4 B# [0 B0 ~7 e; A1 b
Word16 pst_out[L_FRAME]; /* Postfilter output */( V1 Y1 Y& ~0 m: }
Word16 sf_voic; /* voicing for subframe */
) J. ~! j2 v" w1 c5 ^0 T0 ovoicing = 60;
; t+ C- U9 B, _1 M. Z# p1 c3 n bits2prm_ld8k( serial, &parm[1]);
3 t9 d- C+ q9 F ?+ ] parm[0] = 0;
% t. `) Y6 Y( K1 d6 j, G' r, { + ~, D7 Z9 P1 p6 [; u L+ |
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);3 Q g0 m" C0 b6 J9 r" z6 f
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
; Y0 Q! D0 } I//--------------------------------------------------$ w8 ^ s9 v8 L4 e
voicing = 0;$ O- M# N; I+ i H C- s ^ l
ptr_Az = Az_dec;# x( S" P0 ~" s4 r; v q1 v
for(i=0; i<L_FRAME; i+=L_SUBFR) {
. O1 y1 E) ]6 ? a8 k Post(T2, &synth, ptr_Az, &speech, &sf_voic);
4 m" a. Q0 S& x9 k3 F if (sf_voic != 0) { voicing = sf_voic;}7 U+ s6 q ]7 ^/ u1 }
ptr_Az += MP1;3 g: x! p& _$ g. E0 h! E
}* f0 i+ x' I! ?0 s2 Q4 y
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);3 _+ t9 `8 M3 Z e& w9 A
//---------------------------------------------------8 b3 b% v& K4 t4 n& I, I( L
Post_Process(speech, L_FRAME);
5 O$ { F! c2 O$ J3 O' W}4 D& f4 X% Q2 E V( G" g2 ^. e
8 f4 S8 q" ~+ z9 k/ [
|
|