|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/& [. C" x$ ]1 T: ?2 B. Z
下载以后需要修改bits.c文件:
: b; l5 O0 T5 f0 n; I" b我仔细研究ITUG729代码后发现:
0 ~. v" O8 v, A3 @" s+ U编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
* o& F9 g4 G, v$ H7 ^* l( l,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。6 ?0 `8 F; v7 q3 R
. F% U: e7 ]* z5 HITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。6 n* x. I1 ?& d1 V$ ^
/ n6 m1 y, a3 N3 a0 @. V那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。( G) s: @8 m, Q: e" G" Y& w+ }
我们打开bits.c,就能看到里面定义的如下4个函数:
7 I" G# K9 ]3 K g( nstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
0 S1 T! h7 S9 f7 u. G$ s/ ystatic int bin2int(int no_of_bits, INT16 *bitstream);- c p# n# e: |- X1 b( r0 P; }( @
void prm2bits_ld8k(int prm[], INT16 bits[]) ; : h, t3 d5 E. `0 n
void bits2prm_ld8k(INT16 bits[], int prm[]) ;4 S; u; l3 e3 {+ }2 \
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
! l5 l# q; q6 m- Sstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
* _/ ?3 w1 w) x$ D3 J& z& e+ fstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
9 q+ i5 r! n' \2 y, a" G3 \: E g# C
void prm2bits_ld8k(Word16 *para,unsigned char *bits); U. H \; I1 @% a. O5 @5 [1 F
{! d" ?9 Y0 o7 e4 H8 i+ ?- W2 ~" l
int i;' z) N5 [$ a4 L& p
int bitpos = 0;
+ m/ a. x* Z% R5 ]! D3 D0 _ for (i = 0;i
0 @) G6 h1 A( g9 d$ N4 K' x7 L4 J3 W" t9 \9 i' Q; t+ E( q$ a
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
J; e) e+ z' z6 [& b{. i1 `4 f& M( @, H! Z
int i;
3 L& O$ |& G: |# } int bit = 0;- D' s5 L2 u9 `0 d+ f
unsigned char newbyte = 0;* ] R0 S# o. {3 Q) {: ~5 P
( n6 b* w) x3 k$ s unsigned char *p = bits + (bitpos / 8);8 w) @! {) h1 \3 T$ f4 d
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
+ y( r9 M- d# F3 L) Anewbyte = (1 6 z2 v" K# W' P) e: H3 d! v
bitpos++;/ k7 g' w- a. H- w
if (bitpos % 8 == 0)* l( |- i# G( P4 k1 L
p++;
/ p6 H. F L1 [2 z }
* M& m/ |9 O9 n% X- j) j, F6 X' C}
2 e1 I( L# R ^) O8 K) @" B/ x4 {+ [8 |0 h$ v8 L+ g6 @3 y( }
void bits2prm_ld8k(unsigned char *bits,Word16 *para)! H+ d/ Q: [5 ^, X I" M
{
# x/ w7 j/ h3 p4 ?! F5 `) v int i;
. l1 S' y5 m4 g' ~ t9 T1 | int bitpos = 0;$ D- |/ h! B5 s' i) q5 w
for (i = 0;i
& U0 i! N+ O, @3 S6 `9 ]6 A6 f" R
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)3 z' _7 I7 D$ ], G0 T
{2 E5 [2 }5 e& d6 J- E/ G
int i;+ [2 G+ x; C' N6 r7 j H2 T
int bit = 0;( y1 M9 ` ] y* N' I0 X
Word16 newbyte = 0;
: q% I+ q9 F. T2 M6 n# G Word16 value = 0;! v2 I* {! e, l) d, L
# p6 |0 j! o. t' _( n unsigned char *p = bits + (bitpos / 8);5 D( C7 E1 E' z: Z
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
$ }5 x( l) m8 C% `% W2 eif (bit == 1) {( @ H& x; ]: H: j4 `
newbyte = (1
2 w% K6 ^/ A+ h return value;
# B$ ] }0 B- u}
" f3 K( T2 Q7 [) }" N4 ]2 [通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。/ |7 E7 L% `5 T" y
: B$ @2 j# D% v w( j4 ` u3 b编码器的代码能采用如下的修改方法 L) E7 H' b) V+ q3 u$ H- u
(1)修改coder.c:! L& [4 |; e+ F5 j2 V7 Y
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
- C0 u* x3 I7 @4 o7 n6 A4 m0 J(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
9 Y5 r. p! e. [. o9 [; c frame =0;; M6 b) M& v& R- I
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
2 e9 \9 j9 M2 [1 b {
" J! Y0 W( }, R2 A! n* Lprintf("Frame =%d\r", frame++);1 T+ ^% d3 I, u: }
Pre_Process(new_speech, L_FRAME);& q }# ?8 e8 U& u9 Z. i3 K
Coder_ld8a(prm);1 h' v7 y0 h$ J1 t8 p
prm2bits_ld8k( prm, serial);
1 R% Y, P4 } I1 ~* a0 [fwrite(serial, 1, SERIAL_SIZE, f_serial);
, `+ h3 N. G7 J }4 f X7 r. b, o: @" v( i& I
return (0);
3 x) c5 u1 u y, F. [% _3 `8 v! I2 a- _0 T8 D
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:7 F5 n" t5 W( l8 |
#define SERIAL_SIZE 10
2 o( b+ ]6 ?8 Y) ]5 s u, d+ g) n4 j; E5 \- W0 ~- G5 D* v7 m( ~
(4)解码器decoder.c进行类似的修改(关键部分代码):
$ P' l8 ~4 X7 m" q( E8 O3 H frame = 0;
( E z' Z# a- n$ F. l2 p) F2 X; d while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
9 q% c, o9 J7 K {8 u' Z% ~' ^5 U/ B8 t! O' j" N& w
printf("Frame =%d\r", frame++);
: Y5 b# Q2 M7 x1 \6 ~' o0 o3 Rbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
* } }( t; T* V ^- Wparm[0] = 0; /* 假设没有丢帧 */
& @! V' |: A( B. d# u# {$ C+ Cparm[4] = 0 ; /* 假设数据效验正常 */
; j/ ?( i9 }5 @7 ^2 K) I8 o- MDecod_ld8a(parm, synth, Az_dec, T2);
* ]+ b6 g% S" ^9 IPost_Filter(synth, Az_dec, T2);
% W* b/ N& e* k0 hPost_Process(synth, L_FRAME);, T2 a& j1 u% h* L
fwrite(synth, sizeof(short), L_FRAME, f_syn);# p5 y' ?* C" A* `7 O' l2 v
}5 R+ V8 o T4 M% F5 _
return (0) ; ]/ w2 i& S6 X7 ]1 `
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
& N& g/ F9 ~. I4 g6 A3 s# \3 w
8 A8 P& _% ]0 v( h6 s9 G& q修改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]得到,应该就能了。
# Y* y' Q: q% ]封lib:* v/ S" W8 e. j, q5 ~" X
va_g729.h5 L8 J2 ~: R+ _) O1 b4 u' h1 ~! c
#define L_FRAME_COMPRESSED 10
5 D* `$ l5 X; R8 u#define L_FRAME 80
6 t. D0 ]3 P, E, E7 T. n" M; X ^5 W#ifdef __cplusplus
4 o: z3 {7 _. |1 m5 |9 `extern "C" {
! Q U5 J* u- F0 z/ F) d#endif9 @9 {" d# R5 x
void va_g729a_init_encoder();
! j/ O' ?( X. N; _# Cvoid va_g729a_encoder(short *speech, unsigned char *bitstream);9 }9 {8 V: g# z- c
void va_g729a_init_decoder();" i3 ~2 m) {7 i5 m
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);( K/ p# i5 c. Y& S+ u$ e7 M H
#ifdef __cplusplus 9 E. H t5 C& g4 \5 `# E
} 3 C8 ^1 {* W# @5 d
#endif% Y4 Q* d, \3 M/ k c
va_g729.c$ V6 d- ^8 n9 ?* g9 s, S
#include <stdio.h>0 p/ u& p( r# U" q) [* n: j% Q& H% x
#include <stdlib.h>
5 X. K+ ?8 c, i" I m( R9 \8 R#include "typedef.h"% b' u8 B4 {0 D, [/ }
#include "ld8k.h"; P4 o5 C; B& k
Word16 bad_lsf;
' G# P5 T% C; B+ U1 U4 u" Z/ U+ N) ]9 ?void va_g729a_init_encoder()
. ?7 r' W6 G1 ~/ J, b6 O{! V& k- V! ^8 a
Init_Pre_Process();6 ^4 Z7 G i: l% s
Init_Coder_ld8k();
! B% y# d; Q) B! @( w$ J}" o! j/ ^- T5 ^& L8 C2 V0 e# T
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)$ r6 G& D5 [9 W Q) m6 j
{ " ^, X+ q6 {. `0 O4 G3 l
extern Word16 *new_speech; /* Pointer to new speech data */
! s8 q* L3 D: x( c) R+ w: q5 Y% \ Word16 prm[PRM_SIZE]; /* Analysis parameters. */! \+ f; h: z# P# E3 S( |. [
Word16 i;
2 C# w! D4 ~4 x, _; {5 ~Word16 syn[L_FRAME];7 P: W' j8 `6 g! M2 l5 D1 A. M. w. O
for(i=0;i<L_FRAME;i++)
P' x5 V- y( ^8 t3 X9 c2 M{
& Z& ?$ o& j# Q! L; }: s+ E) x new_speech = SpeechBuf;8 }' M3 ]* l* S R8 J
}4 _4 k1 X# r5 P6 H- I) V# |: e
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; / W& k3 `" T) @
Pre_Process(new_speech, L_FRAME);
0 h. a6 _# ~- _( c" v4 U Coder_ld8k(prm,syn);2 M$ z0 K+ m) d8 U' ^
prm2bits_ld8k( prm, serial);
$ y6 ~* \; m8 Z% y- i' D7 R}
! _' ^8 R' K* s* }( U2 X7 Dvoid va_g729a_init_decoder()
! b x: g" q* e7 I{
0 J# R3 R" U/ ^" \5 Zextern Word16 *synth;
$ O! F) r7 I3 x, A7 z, }8 J- } bad_lsf = 0; /* Initialize bad LSF indicator */
, A t0 n k" T( P. o Init_Decod_ld8k();
~7 t# a4 T9 z Init_Post_Filter();7 X/ z; j( F/ v" n; @
Init_Post_Process();
a% l8 m; m$ J6 c}+ @6 t. O1 s' N5 O, x
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)" y! b- [; k4 v
{
6 M6 d W8 m2 z$ R* ~' S- vextern Word16 *synth; /* Synthesis */( u) _4 V9 k' c, Q5 n8 g' M
Word16 synth_buf[L_FRAME+M];/ i; }4 f+ }9 r3 f2 k4 _3 F7 K) C
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
" D9 {* e+ Y- G( HWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */) g: i$ q- n! i4 O
Word16 T2; /* Pitch lag for 2 subframes */
' I9 m! Q. L0 k9 v+ j3 QWord16 i;: ]1 ?! X9 n; e; s' f4 r
Word16 voicing = 60;9 g' p6 v8 U9 I+ E( e# u. `/ {
Word16 pst_out[L_FRAME]; /* Postfilter output */) y( z' g' p% f! N
Word16 sf_voic; /* voicing for subframe */
5 e# Z* M; c) n! K" hvoicing = 60;, z( q+ e, x5 O% v% ^
bits2prm_ld8k( serial, &parm[1]);
- [% P9 F m7 d0 N parm[0] = 0;
! H0 d5 K& A4 d9 Y; A* |1 m
3 c4 M }! k T( L parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);) q' c0 v8 R. N* p d: ]2 P, U
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);) O z- d0 p$ _, v" u6 y
//--------------------------------------------------9 V( q/ j! |. P$ `, r# t1 u
voicing = 0;
/ p1 b; _3 q* @& Yptr_Az = Az_dec;
1 a1 S3 I8 P& V+ c3 ?! ]for(i=0; i<L_FRAME; i+=L_SUBFR) {
( m3 _- P+ u3 U% X, y" o, `! _ p% ^: p Post(T2, &synth, ptr_Az, &speech, &sf_voic);8 x$ J) e% G; I; U" k* p* E
if (sf_voic != 0) { voicing = sf_voic;}
- I. G% i! F) ^' b; U# L ptr_Az += MP1;# U }$ a0 f! m& V* _- F
}
- u8 ? f) g$ \) R8 wCopy(&synth_buf[L_FRAME], &synth_buf[0], M);
2 W) B4 Q. X, h' [! r//---------------------------------------------------
2 e4 K8 e; a2 J) |, _& N, e* Q0 _ Post_Process(speech, L_FRAME); + y# C2 B. T% @& H8 i
}
6 [. h! u* h: U* _1 o* F+ r1 j" y/ J# F! i' p: ]
|
|