|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
# U9 Q4 u/ K) I4 x6 K下载以后需要修改bits.c文件:8 l$ u' h% U' X$ K9 }2 l
我仔细研究ITUG729代码后发现:/ J$ _$ H B7 a: d0 \) r
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
2 W2 _7 S, E* `,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
# ?! z( ~- w8 }6 x" F& d
, G9 I4 l5 F1 \; I7 YITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。% `6 R2 _8 r' C# s
5 F5 I) y1 G' G* V& m
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。) n6 S, I3 z5 V7 T1 N/ p
我们打开bits.c,就能看到里面定义的如下4个函数:; ?- K+ O* W% x' r0 M" K% Y4 m. q
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
/ d5 R4 J+ t$ H, W1 w' ~static int bin2int(int no_of_bits, INT16 *bitstream);! }! \5 H# `) c
void prm2bits_ld8k(int prm[], INT16 bits[]) ; 7 n$ A# d, B* N, j% u; \2 ~7 e$ S
void bits2prm_ld8k(INT16 bits[], int prm[]) ;# O8 ?/ }0 |( Y0 D _1 T
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:. ]9 Y, j% x4 K9 D
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; 3 i" H/ [, a. J( V5 p5 g
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
4 p" I, H# N% X3 k6 z- u. E, V, `" o2 b4 S' O; T& B: S$ Q2 m3 _+ L/ `( c
void prm2bits_ld8k(Word16 *para,unsigned char *bits)5 `- Z& }% C0 }
{( r( s$ [' v; z& I/ u3 j" ?; N9 c
int i;( N( @, ^0 b6 r- k6 o, m$ I& @
int bitpos = 0;: L; {& B- _$ O2 j+ i' B
for (i = 0;i
- X% v( K1 a7 l4 o. h$ D' w: \% k# Z
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
* M7 J+ J( i( U7 M; c. P) t1 o{
8 g' ?' Q) q0 I int i;
2 K; U/ ?) L% L, y* G2 L( R int bit = 0;1 W. v* h& a% x4 r
unsigned char newbyte = 0;
6 ^+ y, s; L8 z, b5 {; n ! S! y, A& M7 J; U
unsigned char *p = bits + (bitpos / 8);
2 y( x$ F. X4 m7 L; c9 c7 C for (i = 0 ;i > (bitlen - i -1) ) &0x01;
% W- q3 I3 {" p- knewbyte = (1 + b% o# A$ E% p9 [# R- ]( v d9 p
bitpos++;
4 ]8 n# W# [" O3 h Dif (bitpos % 8 == 0) r" w* J! ?+ _) h1 s& ^3 @* d
p++;: b9 S" h8 t7 l
}5 C8 Z7 V4 f- S- K
}
' H0 E- D7 t: y! j' e% c4 A( S& K) p$ ` D. O
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
5 J- a" g6 k- b! D# e{% w8 r! G, g; p2 P
int i;, X0 g/ Y8 _8 e& L
int bitpos = 0;
' J2 N) I) K$ o; N for (i = 0;i0 E. j' X/ o6 R& k. t. [+ E
8 x4 Z/ R; S5 [. y" i
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ?' P! y- z& R" ]" U
{
/ c$ M! w. R7 U4 F3 S int i;
3 N( q x5 [! P7 p int bit = 0;
) W2 t( T9 ?+ r4 m" y- N9 S! H Word16 newbyte = 0;' k/ N( |7 Y6 w9 M- r8 g" Z
Word16 value = 0;/ g3 r# A- S5 {% v5 G9 `
+ A% U+ [! O2 u( K! X! @
unsigned char *p = bits + (bitpos / 8);
/ G6 u, D: r7 F9 @% `$ M. A for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
, r/ t. o# R" x& R7 z& @* K. rif (bit == 1) {
; p/ J4 Q) i* Q, H2 Z2 t newbyte = (1 7 @( j: a: u/ q# v, p! _
return value;# j, \4 S, Y% [' \9 q& R
}9 G5 s1 ]- |* L5 v) \
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
' K! ^- A8 @' x% q3 I8 J6 e" o5 r9 G; K& s& k" W8 U6 r8 [* N
编码器的代码能采用如下的修改方法$ J9 h% C# `' f; m( o k
(1)修改coder.c:
8 X, g. R- L3 d7 ?- Y7 Iunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */8 s9 E, I. c) C' b A, F5 {6 |* o
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):& a0 W: V& p' c! s
frame =0;
- f3 y0 B7 l: g/ E* X% B' j/ g while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
/ j. C i m- o* r# }) T {
9 |7 ~1 `0 u; G# Y3 m& kprintf("Frame =%d\r", frame++);
4 Y/ E S, B3 U- _' O$ kPre_Process(new_speech, L_FRAME);
* A- c' J+ R) |* NCoder_ld8a(prm);; y* G1 m0 u( s, V( l/ @
prm2bits_ld8k( prm, serial);- q* W, [/ l8 x8 o! k3 w
fwrite(serial, 1, SERIAL_SIZE, f_serial);1 I$ X3 _( C2 E
}0 x7 }% `3 u- i# i' S6 \) P
return (0);
5 ]3 \4 g) z" Z- v$ h/ J- @7 V6 E% ^0 {: [& P
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:) c' J u3 x$ [. C) g ]+ D. _( Z
#define SERIAL_SIZE 10
+ u0 T/ c4 D% b! t. u4 T8 M3 r( g; j2 z: p# J3 g
(4)解码器decoder.c进行类似的修改(关键部分代码):% I; f. s+ R5 W% r
frame = 0;
) c3 j; U7 M% u while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)( ^; k' V, x5 D @
{
! l1 {* N% T! W9 u: pprintf("Frame =%d\r", frame++);) Z6 p5 t. c! P% Z! x: n' u
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
0 l5 s% ^. y* x! r- ~& zparm[0] = 0; /* 假设没有丢帧 */
6 u m1 }* h$ K4 ?- x1 h, Zparm[4] = 0 ; /* 假设数据效验正常 */' ` o/ p9 H0 e8 x
Decod_ld8a(parm, synth, Az_dec, T2);
& E. M) ~" j8 X9 g1 D0 fPost_Filter(synth, Az_dec, T2);
: _) t( S% y/ M$ @0 S# oPost_Process(synth, L_FRAME);8 E& {- E; a; k4 l& P
fwrite(synth, sizeof(short), L_FRAME, f_syn);
( o- C+ o' Z8 a9 Z }
2 f' i/ S1 G; e: R+ s return (0) ; : u( O1 R7 u$ E; c1 O% P
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。7 }7 O9 h, q7 v4 Z7 j, ]+ L4 S
+ X) s; U" [4 u* z修改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]得到,应该就能了。
0 Y" C9 t, _2 u$ ?: k5 L! e, C& P封lib:
, H2 M. D4 N" nva_g729.h
' c1 ~1 g5 Z! B" r; _% g8 f#define L_FRAME_COMPRESSED 10
( ]. |* V8 J6 y/ e#define L_FRAME 80
8 H& X9 G, i. }#ifdef __cplusplus
5 i0 P" Z5 _ D: w7 Y) |9 _extern "C" { % W Q: B- @$ t& g0 z9 Y" w
#endif: j0 [- `6 S5 s" A4 m) `
void va_g729a_init_encoder();; N+ |+ O1 n* h
void va_g729a_encoder(short *speech, unsigned char *bitstream);/ b0 D# N/ Q/ i7 _! ]
void va_g729a_init_decoder();
( Z2 q. n7 K" f0 b, P8 f6 H6 lvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
4 J) a3 z1 b; k8 S( v* R ]#ifdef __cplusplus
! t( Y% h9 h4 q7 y& W+ M! e8 V) d}
4 Y" t' L" i( d% R4 Y7 N) E& a#endif5 q0 R* a' Q7 A- S2 Q7 G% d) u' W) P
va_g729.c
. z1 K7 z* R+ T" ]#include <stdio.h>
, @/ Z+ c7 D- N#include <stdlib.h>
( x7 V& h$ z8 M) u+ K" _4 `#include "typedef.h"
& q3 d i; D; L( U9 l$ U {9 I% A#include "ld8k.h"
) L% P" i- d& B' `" [5 _Word16 bad_lsf;: Y, ~7 O: r% Q+ Z: H |, @& N
void va_g729a_init_encoder()
" T4 N' C' e0 |# y, O; z/ A{8 g7 J) I( W9 z9 \
Init_Pre_Process();8 Q% I- H9 [1 K* X: N: y! }) o
Init_Coder_ld8k(); # i. s# J1 L; G! t6 h# M" a3 W+ h
}6 C! B5 C) c2 v$ U5 K/ k6 T
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
4 j5 t) S% b% @{
4 ^$ a+ D7 M4 b9 P; s' l extern Word16 *new_speech; /* Pointer to new speech data */
: @( ^; J1 Y1 j1 Z4 b Word16 prm[PRM_SIZE]; /* Analysis parameters. */
4 u8 z* s M' k: [ Word16 i;
9 c S/ a" L5 T$ l! q% RWord16 syn[L_FRAME];
- m7 ?, n- P" x+ X! `! c for(i=0;i<L_FRAME;i++)
6 y$ W% V0 s9 m" a{- V% i% c; f6 Q; w
new_speech = SpeechBuf;# {2 E w$ p1 X! r( v
}4 p: [- b: n6 q7 A
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; : p/ m. F: X. ]% ]% o+ I# _
Pre_Process(new_speech, L_FRAME);
) p+ K6 [3 b) u6 j+ A8 d Coder_ld8k(prm,syn);
; Q, n2 ]/ P" ^/ x% a& E. P1 j. ] prm2bits_ld8k( prm, serial);8 k; t6 f- v t' Z, w
}3 r5 g; D @- M( d W9 O
void va_g729a_init_decoder()2 O4 Z% `' u+ j; a
{
' {* I( e6 o) P; V, xextern Word16 *synth;
G6 ]5 u3 ?7 D% b9 a- ` bad_lsf = 0; /* Initialize bad LSF indicator */! a0 ?# M9 J4 E2 @# V
Init_Decod_ld8k();
" o+ S0 `- f& l: ~( t. T3 ~ Init_Post_Filter();
2 y, f9 d/ U6 }7 F2 q Init_Post_Process();
3 j: e* r) u% _! W: O}9 g) ^1 _1 Q+ {& C/ b, n
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
$ ~0 {6 Y; t) O. h! E( }{
" E/ E$ }' J' s/ zextern Word16 *synth; /* Synthesis */
5 R7 I$ U& m* y+ AWord16 synth_buf[L_FRAME+M];
7 N7 S! [% J) jWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */; T3 V8 E$ H" r) ]8 y% j& @# ^
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
~8 n2 ~; |2 O* a0 `# t1 HWord16 T2; /* Pitch lag for 2 subframes */0 U5 b. `5 Q0 n0 n
Word16 i;% G7 r W" x' J; [ o4 s
Word16 voicing = 60;
" |, x& A3 C/ _$ o/ E7 y( IWord16 pst_out[L_FRAME]; /* Postfilter output */; M% _- m! G' I9 c
Word16 sf_voic; /* voicing for subframe */
3 n2 h& v' O0 q2 V7 Zvoicing = 60;: m( U+ s( F: x2 @6 r& c
bits2prm_ld8k( serial, &parm[1]);
! H0 g3 A# n& u! G2 _7 V7 o3 m2 R parm[0] = 0;
' ?7 K: H9 n' J, ]+ |4 B" j, c . I' m; I) C- q& z8 p4 F5 t
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
, a; T3 I0 l6 n$ L2 mDecod_ld8k(parm, voicing, synth, Az_dec, &T2);
) I T2 {5 i; e; J3 s! t# [//--------------------------------------------------
4 q1 j& N+ F* Mvoicing = 0;
. Q, p0 U0 d% A. Zptr_Az = Az_dec;& P1 ]+ W U% f
for(i=0; i<L_FRAME; i+=L_SUBFR) {
: N) C/ b% S4 y$ F- ^# `0 W Post(T2, &synth, ptr_Az, &speech, &sf_voic);
3 \4 @+ ^& S: W4 @8 ?: K9 n if (sf_voic != 0) { voicing = sf_voic;}
* W, I8 ~. U9 X/ O4 \9 } ptr_Az += MP1;# s* l4 C8 U. Z; v+ Z$ a2 R; I
}
) v" W/ K4 Y5 ~- f) O/ R: GCopy(&synth_buf[L_FRAME], &synth_buf[0], M);6 a2 C3 D6 a4 S5 U$ D! G
//---------------------------------------------------
p. F% h, a$ u/ P, ^ Post_Process(speech, L_FRAME);
: W; f. v, n9 K1 Y9 ^6 k. p}
8 C5 ~! m$ a; w5 J* f* y
4 q. p9 z( N, ]( I# r, }" j2 H! ~" h1 S |
|