|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
! W2 {% _" n* _5 g* \/ u下载以后需要修改bits.c文件:" c R6 o1 D& F
我仔细研究ITUG729代码后发现:
+ p6 b8 n& y' C m1 w编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流" s6 J9 `: W8 @
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。 |# H3 c# ~ j, [* K- t
$ ]8 Q Z3 B7 [& L- C" lITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
8 U5 Q q6 T! T
/ C* X: ]0 |4 v2 f那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
) f$ S9 @6 ^# D2 p. B, T4 L7 X4 q8 f* V我们打开bits.c,就能看到里面定义的如下4个函数:. o" J: X; E* P5 L) [+ h
static void int2bin(int value, int no_of_bits, INT16 *bitstream);5 a' U& @5 Y5 Z: ?( M
static int bin2int(int no_of_bits, INT16 *bitstream);$ F" X; k3 R, g, B. I
void prm2bits_ld8k(int prm[], INT16 bits[]) ; $ {* m& n( E& I1 Z$ T4 U
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
1 h+ x- r+ H- r& G+ q& w4 b这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
\3 T" m$ V8 w0 O1 r9 S& a' E& Wstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; ( k% |3 ?1 W( {2 f }% {, q
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
+ O e6 U: e0 a7 V5 e" c
2 {7 T2 Q* {+ Q' cvoid prm2bits_ld8k(Word16 *para,unsigned char *bits) y% X2 S; Y! _- w' Z7 c
{
" A6 N) i" ]+ x ?7 K! C int i;
3 J' O* d) u0 \; ]. w int bitpos = 0;/ f2 _/ `* |2 V! P. X
for (i = 0;i- V( w$ Q# B: f3 K
* t* d$ q' u! @+ f9 p4 Q% g
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)* A8 `# m6 z8 [6 U5 s
{8 z8 k# l3 R* D2 ~) v. w7 F
int i;* b$ J4 W% m& J2 i8 D
int bit = 0;
9 V2 d$ R# r- X6 \; Z! e unsigned char newbyte = 0;
9 B, _8 d) Y# [3 k" A& t1 {" q - H: z2 `# I& C! K# q3 j2 s
unsigned char *p = bits + (bitpos / 8);
1 K$ s( ~+ _% W3 _/ E0 X* d9 `. O for (i = 0 ;i > (bitlen - i -1) ) &0x01;
2 @8 O S7 \/ ^. znewbyte = (1
0 D+ |1 v. ^" _$ ?/ Y% w$ M# B1 Qbitpos++;. m6 L( |& b- p8 n B; u( S7 H0 @$ E
if (bitpos % 8 == 0)
# |& w; q% G6 O& T' e) R( R6 ` p++; g/ I8 v" s" A6 c2 M# ]" n' k
}
( \# M0 a& o" l}+ b: ]7 r1 J0 v! k7 Q& t4 e2 j
1 Q7 e. D/ `9 Y
void bits2prm_ld8k(unsigned char *bits,Word16 *para)) N2 H% L4 X- J7 B' d" {( A F
{3 N1 R3 P6 } i6 v9 _( Y D
int i;
Q0 k; s2 N; R# x int bitpos = 0; w( D! F* A- r3 A M4 N4 V
for (i = 0;i
3 \5 ?- H; f" q* d& p. K! k
9 [- G2 ^, q; x, y" lWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)4 H. U4 V, p/ r& i
{
0 i5 {7 u4 S6 f3 d9 o" T8 d/ Y int i;! Y. f" @* y2 e) C w
int bit = 0;
3 V3 n Z; D, L4 \2 J7 T' ~- [ Word16 newbyte = 0;/ B( Y- U8 i4 [: Q; i m
Word16 value = 0;
3 n* i r: g" m ) f8 c. O1 j& f: M, _2 r
unsigned char *p = bits + (bitpos / 8);
6 s& X8 W7 y4 y) P for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
" \" |$ g* ~- E" E# iif (bit == 1) {7 U, [* @6 Y" m2 x+ C% A1 n# `
newbyte = (1
. [! S, Y! d9 W: W3 a$ i7 ^$ n4 c* f return value;) { H: R. O/ [7 ]8 Q
}
5 v8 A% B1 @0 {# l( v通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
; L0 ]' v; ~: C3 w' y$ H4 p: q& X) ?/ w
编码器的代码能采用如下的修改方法0 l& R9 b- J" \ B2 s- ]' R" Y
(1)修改coder.c:
9 m/ ^2 @9 }5 [! u+ L$ |unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */5 S7 Y2 F. t3 O$ \1 h$ E
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):, S) N( I) O! E+ v8 J
frame =0;+ ?2 U" ^4 S! v' U
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
5 l# ^" _4 \, w# T, g9 s {
+ D: i) r, ]2 h3 \0 i8 N5 c) ]7 b; Sprintf("Frame =%d\r", frame++);. r3 }1 o P& X+ c
Pre_Process(new_speech, L_FRAME);
# c/ _4 |6 k# G6 fCoder_ld8a(prm);( E4 E+ {% R3 A3 [# J4 L) _& G
prm2bits_ld8k( prm, serial); o. O2 y6 L" U. e ^0 ]9 j3 i6 M! V
fwrite(serial, 1, SERIAL_SIZE, f_serial);
2 P3 i( A7 u: k+ [$ M, D% B }
" Z# i, l: [: d" u" X- r return (0);
2 A3 M1 {4 @0 t, W
: b+ |- c8 e% B9 I7 z" w, l& M(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
$ X9 W% e2 c% U2 Q+ |8 m/ q/ W#define SERIAL_SIZE 10! z" Z* A' H( `+ w
7 f' h Y3 O7 j+ E F7 h" Z6 W(4)解码器decoder.c进行类似的修改(关键部分代码):" l( b4 Q+ y0 F" S, \
frame = 0;9 H7 f: Y) @2 S( w7 O& J$ M
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
. r. C/ t* ]* G, e7 f3 S, j {
) K8 M2 p. p+ E7 _) V% r- Q) Dprintf("Frame =%d\r", frame++);6 H! `) y, N7 E( c5 u* |
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
- \, @( _* ~# L) n; Tparm[0] = 0; /* 假设没有丢帧 */1 R4 f: ]: f) \$ N" i' l0 [2 x0 p1 m' n
parm[4] = 0 ; /* 假设数据效验正常 */: j8 o) u" T, U
Decod_ld8a(parm, synth, Az_dec, T2);
3 }3 w! d; B2 n. S ~4 h/ BPost_Filter(synth, Az_dec, T2);
( p7 I# Z: u( h/ d; t- }Post_Process(synth, L_FRAME);
& K" e( |* o% p) h4 Qfwrite(synth, sizeof(short), L_FRAME, f_syn);
" ~9 v1 {$ W( z) S! N3 X1 R }
) y: P$ T) M% h9 c$ {! M! J return (0) ; ( n2 J2 V* q- z! Z: A' T
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
0 v7 a! ~" ?3 X2 l+ w) q ]: F$ v# m0 b5 l6 m! A
修改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]得到,应该就能了。
! `' p- K7 ~. d封lib:" O! }" j I# I, h1 Y
va_g729.h
/ f' R5 C4 c0 A, X7 I; X& E7 m0 d#define L_FRAME_COMPRESSED 108 i. ]; m" b/ r8 z# q( H
#define L_FRAME 80
1 G6 g% D- i6 f( y' R: f, I7 _#ifdef __cplusplus " V, ]1 h! ]8 Y" l/ R
extern "C" { ! c* p' ?( K$ B/ D. _7 e1 L& V, S0 `
#endif2 R* e% ]) |! F+ S
void va_g729a_init_encoder();
3 L& g7 V4 z1 Pvoid va_g729a_encoder(short *speech, unsigned char *bitstream);* e! C! Z4 z, X1 p& s% _* j1 T
void va_g729a_init_decoder();$ M- C+ j6 d5 s: z
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
& J3 T- \% F2 g( X3 i#ifdef __cplusplus 0 ?& p! s/ n+ A( Q
} 8 g. h' [& u$ d4 N2 P
#endif
) ^% R e ?( m, a+ bva_g729.c a, T$ A7 w5 h4 S# u* z
#include <stdio.h>4 P; N7 I2 `' V6 C9 S, ~
#include <stdlib.h>
& j, N+ J; N G' [2 Q, \#include "typedef.h"
9 P; C. q8 y$ k#include "ld8k.h"
" ]. U8 X" p: c6 K; i7 M2 h" gWord16 bad_lsf;; ?# \# P, [3 ~6 k' b/ c
void va_g729a_init_encoder(): f* E/ t" g! O
{* x, P. O; _9 u4 q6 ~
Init_Pre_Process();
. T8 C& I! d7 Z: _# Q7 X Init_Coder_ld8k(); 2 S ?, K" M5 |% o; \
}
0 q& x* A+ I, }8 {- z7 jvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
" K; [$ ~5 v8 w8 @( y! \{ $ @) J& I! }- T! I$ A5 k# E
extern Word16 *new_speech; /* Pointer to new speech data */
5 i$ s9 ?% `3 G0 N6 j Word16 prm[PRM_SIZE]; /* Analysis parameters. */6 ]0 g9 q" n# A' H2 U9 q9 q
Word16 i; V6 _3 Z: N7 g; P1 C7 I9 j6 r
Word16 syn[L_FRAME];! E& ]- q, r8 b! Q+ g% R0 s+ N( y
for(i=0;i<L_FRAME;i++) |+ }! {' D, E3 s
{
4 ^. k* H, _' ]& f5 q2 U new_speech = SpeechBuf;$ G4 e8 ^ c6 N1 O* y- i" B3 p
}. I+ a% M4 r: c. t
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; / h+ `; k/ u3 o2 L
Pre_Process(new_speech, L_FRAME);
; Z6 n2 @- L) m Coder_ld8k(prm,syn);
6 t0 O9 K5 A& j3 V: I& m& Y prm2bits_ld8k( prm, serial);
7 p8 S+ Q' H+ q5 @+ T( e0 ^}" X& d0 m' {+ R$ A/ X. W- V# O8 g
void va_g729a_init_decoder()
? A$ j1 } A% c! `{. I/ a1 E4 _: V4 M F3 o7 l- M% P! M- C! G
extern Word16 *synth;
! y. D" l" h/ `* T" ^2 W. V9 z9 D bad_lsf = 0; /* Initialize bad LSF indicator */
$ @: W5 z) a3 ~; G G Init_Decod_ld8k();3 [8 Q- E+ u1 v' U6 ?' t
Init_Post_Filter();
! r% d, b/ Q$ L- `+ [7 r+ r Init_Post_Process();+ X* I% P3 T: _% X5 @
}
9 z& ` P( Z/ k! dvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)9 @) `9 o. G* W! n! c6 C9 _
{
8 w8 U% R, Y& c: ?5 h. Fextern Word16 *synth; /* Synthesis */- R3 m) n: Q/ F) U- n+ k
Word16 synth_buf[L_FRAME+M];
0 u1 g+ H3 p+ m9 ?& L2 {3 @" yWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */, w6 t* ~( {/ e, \& r7 u1 c
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
# R; {! T+ r8 p5 Y4 l% N) SWord16 T2; /* Pitch lag for 2 subframes */
$ U3 [" C2 g5 n" ~2 x- n' ^# NWord16 i;
: ~/ }9 }' t9 {8 c! JWord16 voicing = 60;1 `+ Y" |8 d; Z' y( b$ z* z
Word16 pst_out[L_FRAME]; /* Postfilter output */
2 N. q0 E. }2 x, R7 u8 y0 DWord16 sf_voic; /* voicing for subframe */$ T! k, m; v; X$ w( S
voicing = 60;
6 b0 {* p( }6 ^& d* @7 J6 X bits2prm_ld8k( serial, &parm[1]);
/ G0 I3 N! b: f" F3 } parm[0] = 0;
0 s( d& w8 p) I; j s( k + R; ]( G2 _& I8 z- o) {. L
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);9 U& v1 L$ c+ M7 R6 M* R
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
* b* h- m6 X4 x$ T//--------------------------------------------------
, h3 u" M2 ?" \/ `7 c% t5 M kvoicing = 0;* u* u- c% l* J% n- r' O* x; ^5 @
ptr_Az = Az_dec;
" O3 t! m# u" Lfor(i=0; i<L_FRAME; i+=L_SUBFR) {
8 ]+ ?: W2 g8 N; s- V Post(T2, &synth, ptr_Az, &speech, &sf_voic);
& z2 w4 x% t0 P4 A0 B if (sf_voic != 0) { voicing = sf_voic;}- J3 x/ z" Q8 `: X
ptr_Az += MP1;
q; m0 C3 j( u* m+ B9 |4 S$ n}
+ v$ e" W3 p+ O. S1 A, yCopy(&synth_buf[L_FRAME], &synth_buf[0], M);
! \. \. r1 V7 T0 \7 H. |//---------------------------------------------------
2 ?3 g0 \# W7 T+ e3 s Post_Process(speech, L_FRAME);
5 R; u ?1 O* o0 M}
) N7 ~8 w& q8 _; `% c8 m; i# J/ R I5 P3 C
|
|