|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/* L* o; L8 D* s/ w4 M. v2 I2 P
下载以后需要修改bits.c文件:
+ n1 [& d1 n9 X" I- p9 @- l6 f0 h我仔细研究ITUG729代码后发现:4 V1 }* Y2 e. w1 {1 X7 z$ g
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流. Q3 h3 s/ w% |& j5 J m2 @/ \
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
5 I/ H; \% A& [. u% O9 c
7 p* g$ h2 J- r9 `# OITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
( P! I1 M5 K" q* C+ y p$ u
, T0 ^2 y& B6 a6 h8 z+ e那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
9 i0 C' k1 e: O i, Q4 H我们打开bits.c,就能看到里面定义的如下4个函数:
0 I1 q% C$ j. xstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
+ ?' k9 C$ e* A2 q- ~1 e1 Pstatic int bin2int(int no_of_bits, INT16 *bitstream);( I6 b9 H7 \1 p. I1 V9 ^; k, y8 k, O
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
) `/ |5 E3 [! B' J" r- Pvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;; ?$ }6 h5 o' X0 P5 |3 L# J
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:8 q' T* K# o; n( X2 W! W
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
& q% W4 D; {- g5 ]# Vstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; 9 k4 `& v5 [, o. h* M3 [6 H& _
1 }, H6 R; x% B2 B6 ~2 avoid prm2bits_ld8k(Word16 *para,unsigned char *bits)' F1 ?* M6 n$ x# Q% c% y# l# ]* p
{% w4 G: ?: O9 P/ y- M4 P
int i;
& Z! i4 p' {* L/ w5 N8 U: q int bitpos = 0;" {2 K k: m7 n0 F0 D
for (i = 0;i
2 G3 o( ]& N0 A7 B. B% z4 \
6 }9 O4 O! r$ u, Z) ~# v U2 Fvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
+ H& G/ N h5 t{
2 y9 w5 j" I2 g# b int i;" D, {1 J y' U2 W; p+ K
int bit = 0;
0 j6 J, |1 c5 h. [2 q9 b unsigned char newbyte = 0;
2 n3 D( g/ w) k" A ! j" H& ~3 P, B
unsigned char *p = bits + (bitpos / 8);/ _: @* B5 h& z! K; [ e, X
for (i = 0 ;i > (bitlen - i -1) ) &0x01; s7 y9 w( E6 Y2 H1 \4 y j
newbyte = (1
! ?* C- T2 b" f! I' b& s8 }8 Zbitpos++;" ]8 J4 v1 W: I
if (bitpos % 8 == 0)
. S0 V3 O J% U; K- V6 r- L p++;" Y% U4 U4 G- I. h2 g5 l! O
}
9 p% q: I% H. l}8 D9 {* @4 k y! [" c* f
4 l$ e/ P. s; C m4 _
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
: W& j% [" i$ h7 L{4 D' p9 Y% X5 W
int i;
8 U: T0 Z" v, ^# B+ q" i int bitpos = 0;
0 M' @1 b3 b0 h$ j& m% |6 ^0 B for (i = 0;i
: a) b: z8 v/ z! R0 q1 P4 n6 Y7 D4 s3 J- A* k* g2 j
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
1 n" `2 |( U9 ]* C( L, K9 A- u{1 X y5 J3 j. R$ L, z2 w5 w, o
int i;
: c J8 Q E! _2 K: z0 L int bit = 0;1 h6 x7 U3 n R2 u
Word16 newbyte = 0;3 b: g' f1 B8 c( q
Word16 value = 0;
V# ?7 P" m! h4 |4 V3 B3 @- A 7 ?- p1 y0 T b7 a( X* B) Y
unsigned char *p = bits + (bitpos / 8);' }- d! J2 l9 T. ? L4 X
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
Y9 c% o6 f2 X: ~if (bit == 1) {1 F5 G: I( S, [: U9 A
newbyte = (1 : S% \0 n: C9 `. T( \ A0 `
return value;1 a; L5 Z: Q7 a) x3 q" }* p
}
& P" U }5 N( `4 h3 |0 \通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。0 M0 h- d; P: c, a$ x: I, c
! R, Y/ }9 J) I/ J3 L% ^
编码器的代码能采用如下的修改方法4 z( z3 y$ }% {& D- p# ?
(1)修改coder.c:
" I6 H. g8 A5 N4 X% g# gunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */ t' m. e6 W* G0 F0 J, ?* v7 c
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):/ K O. T P2 l) E9 h7 n, q
frame =0;
% d. c: z1 d- E* j2 R3 s, k% t+ V; D while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
0 |( A3 z* t0 A9 l% [3 E/ u {. i8 M- H7 o# w0 M+ Y
printf("Frame =%d\r", frame++);2 Q* `. h: Q: J6 u3 l
Pre_Process(new_speech, L_FRAME);6 u1 h; o$ V3 F: K# R6 ?
Coder_ld8a(prm);
7 ?5 ]) d) ^; j/ e7 pprm2bits_ld8k( prm, serial);
% p+ r2 Z6 i, v. R9 y' Ifwrite(serial, 1, SERIAL_SIZE, f_serial);4 W& g" ~/ O, Q; C- w( _
}% f( j( e2 e6 D( s- o
return (0);# K+ o6 }3 u3 }- ~8 D
9 r- K! N; g# P4 w; }6 j! }3 C
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:+ n0 m. @! A% M$ B, n2 v
#define SERIAL_SIZE 10
# V; F6 ]" B6 T( |5 d1 u E/ |) Y$ X) z
(4)解码器decoder.c进行类似的修改(关键部分代码):$ P" f" v+ V$ O) p. x3 k7 b! U, V1 s
frame = 0;
* }5 e) F! A/ C9 z; Z7 y while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
/ t$ L3 o$ d9 X- q1 n4 h7 D. P {+ M; Q N' F% n& s0 `
printf("Frame =%d\r", frame++);+ u V( L" r2 ]! W% X; I
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */' [0 {( b6 P; A5 r# f% l# q& [5 U
parm[0] = 0; /* 假设没有丢帧 */) A+ T" {. L' H- W1 K2 p) r* e, g
parm[4] = 0 ; /* 假设数据效验正常 */
5 q6 n5 ^+ Q0 a* ?. r9 w+ G8 ]Decod_ld8a(parm, synth, Az_dec, T2);
0 u% K( ?9 I0 y1 \; {: ^$ L! X: ^Post_Filter(synth, Az_dec, T2); 9 M- N4 Q6 }! w- U, R* r7 v
Post_Process(synth, L_FRAME);
g8 r/ _3 T' A, V6 V/ Gfwrite(synth, sizeof(short), L_FRAME, f_syn);
8 h. C# W8 `% D3 J }: M F0 x' T) | ?+ Y
return (0) ; ' x* P# `" I0 F
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。9 s: _/ p4 V& k8 v
4 D; D5 u9 F& `9 ?. }2 @+ U! 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]得到,应该就能了。
+ I& l/ G; T- x- U3 t+ p! a封lib:! `' z; b- s h! [; G/ o
va_g729.h
' K1 }& M1 R. j `' t7 e. D#define L_FRAME_COMPRESSED 10. [6 A( E5 V( F/ T, n6 j: d
#define L_FRAME 80; B. o& b+ s2 J6 N
#ifdef __cplusplus
! C. Y7 U# B# }2 ~6 y: B4 Mextern "C" {
6 n. M8 s R) [9 l: U! W- d* ^#endif
. {: I* y' o* |1 D8 C! {0 U! Gvoid va_g729a_init_encoder();
/ t0 C; C( R$ u, ` M1 f7 Lvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
( R3 u8 W |! F4 G- e+ Nvoid va_g729a_init_decoder();4 _( m% Z/ Z# ~1 I4 P' w
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);& b* h/ } }3 L( F- t! v
#ifdef __cplusplus
; ?! e6 K/ I5 L; Y} & F- M8 b! i6 c5 ]7 w! b
#endif
/ }- D- r- s- Z- f3 n( Yva_g729.c9 C( T+ E q3 `7 I& O; _% v2 T- D
#include <stdio.h>
( B/ X, N, @! M4 o/ q#include <stdlib.h>
* r. H% J8 \* o0 x6 U' T. ~#include "typedef.h"5 ^" g9 N# A/ B( N% M+ F
#include "ld8k.h"
/ K9 Z f e1 X6 G) f- r0 v5 xWord16 bad_lsf;6 [9 Z9 s3 |: _+ n
void va_g729a_init_encoder()
8 h5 k) W7 E; ]. I{# k8 M* I0 m( ?2 u5 u
Init_Pre_Process();0 v# `% d5 M) o5 R' s* {! S% Z
Init_Coder_ld8k();
& m; g( g/ f4 L' K( m}
. S. y+ B8 V m! `3 R" A9 K! uvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)' L( a5 O" K! V W1 v
{ - q2 b' ^, L) ~2 s0 M
extern Word16 *new_speech; /* Pointer to new speech data */
. d& H* e; H0 j0 P/ G9 t7 b; p Word16 prm[PRM_SIZE]; /* Analysis parameters. *// Y# `* Q- v+ A0 k" ]! Z) u9 s
Word16 i;0 r' H3 B2 t. d
Word16 syn[L_FRAME];1 W% z1 }8 E1 S4 W o6 r
for(i=0;i<L_FRAME;i++)2 T' H3 t2 `& z3 \0 @/ d0 W
{
* B' f* \* h; A/ T4 z new_speech = SpeechBuf;
) [( T" N8 B. S. _" O1 y}
& H, J" y% A4 Q( N# O& g% g for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
/ y) K+ y2 s: u7 |$ { Pre_Process(new_speech, L_FRAME);8 Q% _' k% h- e
Coder_ld8k(prm,syn);0 ` j. E+ o# D! r. h' p& e; p0 ]" u
prm2bits_ld8k( prm, serial);& O# N2 N* p/ [% p4 M% s
}
: f: s$ K; B7 B, V5 M: Mvoid va_g729a_init_decoder()
. g2 C- g* h% V! [) G, ^{
* E3 b, k+ h- o& s. E3 R0 Bextern Word16 *synth;
! m5 z! ~* W% ^' i6 i4 ~! O bad_lsf = 0; /* Initialize bad LSF indicator */$ O3 |+ W, ]8 |2 x, D
Init_Decod_ld8k();( D" h' g; r# W4 h; ^% K
Init_Post_Filter();
6 i% N' l$ T$ T6 g, F6 o Init_Post_Process();$ r8 z. f5 B* v* x! Y" q1 g- h9 s
}
/ f3 T% J+ K" n# G, h: Y6 zvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
5 d9 Z' }9 D% `5 H3 U{
$ N4 G% t2 ]. i% G$ N: F7 U0 b0 d) e% Pextern Word16 *synth; /* Synthesis */
( d$ x5 j3 _" p+ Y6 Z9 c$ J6 k) TWord16 synth_buf[L_FRAME+M];
6 I( ~+ u6 U* G6 H7 JWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */3 V1 t( I- n8 C
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
4 l% m" Y, Q2 K- @+ M+ X; OWord16 T2; /* Pitch lag for 2 subframes */
4 y2 h. j- x$ ]: f- d9 aWord16 i;( B' l8 f6 k2 \5 h, g- ~
Word16 voicing = 60;
% ^ a: N' C1 AWord16 pst_out[L_FRAME]; /* Postfilter output */( I9 E% d& [9 ~* O& M9 a2 l3 X
Word16 sf_voic; /* voicing for subframe */
$ n5 U, N* y" m- Mvoicing = 60;
0 s* a1 n- K9 X. w0 o bits2prm_ld8k( serial, &parm[1]);! l# C' T& O# B" V
parm[0] = 0;
# _3 n7 P/ r' R, Y9 ? ' i" H& H0 X) I
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);' J4 x- @# O# C# x& q+ g5 O
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);% l+ U: V3 T+ P) y4 f" S! \' P$ g8 E
//--------------------------------------------------4 T- b `+ k: @/ h7 f3 x/ O
voicing = 0;+ ^/ Z2 ^2 r* e/ t7 u" c
ptr_Az = Az_dec;* |' \. C* h4 f8 R; k
for(i=0; i<L_FRAME; i+=L_SUBFR) {
0 J2 O: h: M6 v* F5 Q Post(T2, &synth, ptr_Az, &speech, &sf_voic);3 y6 D- d! {7 \0 h
if (sf_voic != 0) { voicing = sf_voic;}* ^% Y! X' M# i2 f9 k
ptr_Az += MP1;* H9 M' i4 s5 m) m7 L3 ?; Q
}- {' w9 o$ w1 m8 Z7 u+ {$ E
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
! R, x' l7 {. Y; _9 i4 c+ _//---------------------------------------------------* ?8 \, m+ {. i- ]: Z
Post_Process(speech, L_FRAME);
, q4 u4 K+ g/ ^2 ~* a" T}
( [3 Z4 v6 Y9 e; b0 W& N& v9 }0 A7 E7 r
|
|