|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/; `: A' A9 ^! `! t
下载以后需要修改bits.c文件:
& q" N7 F3 I, c* C2 x我仔细研究ITUG729代码后发现:4 H) R6 b0 u8 r: `9 ~7 i$ V
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流& W; m, F) Q; y3 w2 h/ l/ X
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。- c" _, \$ r1 a( C3 b# ~! q q
9 F# R; n. l" {; i; [ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。) o' n9 ?3 S7 S) x3 u2 {
/ d o) u2 w+ Z/ Q7 f+ }3 V
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。- ?6 n# X/ ^' j& a' I1 `# [
我们打开bits.c,就能看到里面定义的如下4个函数:9 T+ j o# i$ R( s `' \
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
. B% ~( f, @' }2 E- i& `static int bin2int(int no_of_bits, INT16 *bitstream);. W+ @ A0 i; [. E
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
) S) B0 p# ~ Q* i8 i, Fvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;# k( s9 A: m8 R) H! f
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
. c! o( y* Y! K V/ e" jstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
4 V4 b, D6 J2 |" T7 R; X8 s% Zstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
- a9 ~/ G! l$ v$ w0 n8 m* m1 N
- G- J) I* @! e4 V6 j$ n) [void prm2bits_ld8k(Word16 *para,unsigned char *bits)- i& l/ u' U: O) U
{! h, Y8 Z3 r. ]
int i;& z! E S. k5 } ~% e7 o
int bitpos = 0;0 x2 [- D( o1 _! a- q# h
for (i = 0;i
% b& r. [2 [. n9 z. `' \) O3 U8 e4 f/ h' i/ A( p
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
, D6 E. {- I9 b8 B+ Q/ l" G. {# k; g{3 y$ R S' y/ I. ^" \* a3 ~; }" _
int i;
* j4 }* Y$ w' [# Y) R2 g$ x( [, ]( W int bit = 0;' H$ h2 [8 O: S. s1 J I
unsigned char newbyte = 0;% P5 V+ B1 [8 s$ T: z7 b9 k
" o& g* y6 o+ Y/ c/ s! `& R
unsigned char *p = bits + (bitpos / 8);
4 ~( H9 z9 n# y& j9 ~; ] ^ for (i = 0 ;i > (bitlen - i -1) ) &0x01;
/ W% Y5 |$ Q$ \newbyte = (1 8 H* m3 \; O2 i
bitpos++;
( l' b/ [# P7 @3 {% q" @if (bitpos % 8 == 0)
- A4 o& w2 y7 R- k9 I5 y p++;3 V; F0 b8 W4 \9 y* q% X; h/ M
}
y# {3 m8 j3 B; m1 F}
0 S" E* }3 R/ H0 L4 ]
; y; X( G; s/ L; S. ^# Q- [0 gvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
0 J" d% b5 b1 w# v0 y( W{
- D B: G1 S- `% A2 [) R int i;" q4 }) T/ s5 H# s
int bitpos = 0;* E8 C& L' P- O# q4 P$ |% U
for (i = 0;i! }, v1 I, S* {/ u/ F
% y- t4 h; A4 H+ o1 }
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
. N# z1 l7 ~+ V4 u& K/ Y{
' o+ `& v/ _) ?: Z& z- j int i;
9 A l" ?& R# L' \# z, q, w- B( }9 C int bit = 0;
! E6 I+ I' f' E4 a! Y" h Word16 newbyte = 0;
" a( S) n$ e, W Word16 value = 0;) e3 |& f9 j d- E1 O. r0 T
4 `% j- X- g0 \2 {* ^2 `- l3 d unsigned char *p = bits + (bitpos / 8);
: y) h- e1 d3 i/ y: E for (i = 0 ;i > (7 - bitpos % 8)) &0x01;9 ]2 v. ]5 X* G1 H
if (bit == 1) {$ E+ n- H5 y& K8 V/ \
newbyte = (1 2 D! d+ _- V5 L# w5 H
return value;) d) X* f# C' ]# J
}, {0 y# ~( g' W% g
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
2 z, a8 Q5 J/ U& H! X4 g8 r5 ?/ U) u/ r" w8 o
编码器的代码能采用如下的修改方法
8 U- A8 w- S/ b( i7 l0 p0 d(1)修改coder.c:) V+ @" {9 V; \9 A, P9 M2 t" G
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */$ W: C: v' n1 z% w: u7 p
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):1 {+ ?, O; G. j% B7 [. B2 f0 r
frame =0;" P ^7 P$ j& B# F% g
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME). z# X9 D! d3 v% m# U
{
1 f! M7 p. y, Y4 F) Z2 Eprintf("Frame =%d\r", frame++);/ r! L( r2 }" Y5 x% h2 Y+ V
Pre_Process(new_speech, L_FRAME);+ d5 a# O8 T8 \0 H; P
Coder_ld8a(prm);
4 ] E" n% n. ~- I0 d+ W0 kprm2bits_ld8k( prm, serial);
+ w( a. J5 B& l- Afwrite(serial, 1, SERIAL_SIZE, f_serial);8 z. F4 ]- h u# `# h& N L/ B" k
}
2 C7 J B4 d z4 w return (0);" ?# d) d: Y0 O1 v0 X. i
. d7 |# x6 a3 ]* Z: a7 T. |3 g(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:: e \' ?' t# M/ ^) A$ R
#define SERIAL_SIZE 102 s5 r9 W" R9 T5 P( @
* P5 P5 @6 ]1 z- A8 j7 w: T
(4)解码器decoder.c进行类似的修改(关键部分代码):
& l1 a2 Y& ~5 Q& }3 k" J3 G frame = 0;+ v! v! g U: K' Y2 {% w
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)0 H: W, R* }* x+ _- q2 A) z2 P
{
# O& }9 q, w% N" u0 Qprintf("Frame =%d\r", frame++);
0 ?5 |. b7 }( {. Y* u9 z2 ]* I7 xbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
* \$ |1 }% @0 A oparm[0] = 0; /* 假设没有丢帧 */3 e+ l$ ?0 B; O
parm[4] = 0 ; /* 假设数据效验正常 */: w- h9 K. f$ r+ C7 D
Decod_ld8a(parm, synth, Az_dec, T2);
5 n5 p" m9 r" \ A [1 n0 APost_Filter(synth, Az_dec, T2);
. t1 ] M* d# I. ^Post_Process(synth, L_FRAME);
: b6 |8 l+ H; x8 ?% Hfwrite(synth, sizeof(short), L_FRAME, f_syn); q7 W, v' Z1 q; u1 V
}: J$ U3 l" ?- Z2 G% j2 B! Y
return (0) ;
1 V! r. \2 V4 [* l1 O9 y通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
2 [! s, W* M$ y) X' O$ z
# B3 {: l2 x2 W6 ~修改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]得到,应该就能了。
# v# _4 M) v& i+ Y- ?封lib:
9 E1 j1 l9 N1 j5 n" n! Rva_g729.h
3 G8 {+ b1 P4 ~) M% B0 X8 s4 Z#define L_FRAME_COMPRESSED 10
* Y, H( e. c) B/ H- e6 T# E#define L_FRAME 80
# r( s. z7 P% s; j0 ?( a#ifdef __cplusplus
% U* C: d" {! dextern "C" { ! n# J* o9 J7 u& ?5 I# V
#endif% C5 t% i O; Q
void va_g729a_init_encoder();
0 D0 p8 P" X) n. m1 n0 a5 qvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
$ n$ }) Z2 O6 _9 hvoid va_g729a_init_decoder();
+ u3 L! i5 V; q2 U/ o8 uvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);+ C: @. ^) g) d a
#ifdef __cplusplus 1 m. i( T, \5 R! [: H9 u. ?. o
}
1 c& c3 q c1 W6 x#endif
5 v2 [. M9 W& J) F( \$ {va_g729.c( G/ G( Y5 @% e3 ], V
#include <stdio.h>+ p' Z. S" |+ |" k: q- o
#include <stdlib.h>
d% m% A& W# M4 b#include "typedef.h"/ {+ `4 k& x; A+ M# p
#include "ld8k.h"( g Z; I& J: K- P
Word16 bad_lsf;
: Q! a0 l8 ~3 I" Mvoid va_g729a_init_encoder()) i5 k1 j) }% H8 |7 G3 }$ l1 U
{$ ]& n* j; k% g" G( |
Init_Pre_Process(); H1 ~, _; a% W) m: t' ]" `
Init_Coder_ld8k(); 6 I& L" k( D) C) K" ^( {0 R' K5 Z
}
# _1 A+ T# P- p7 G; A9 j* _/ v8 svoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)' ^3 ]- S5 |1 ]1 Q; j& ]
{
% r' D, f4 k4 i v4 \! h extern Word16 *new_speech; /* Pointer to new speech data */( {* q$ U9 h/ p; o7 o( g! J, E% m
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
3 ^6 n# r& M* @8 t( v4 a Word16 i;
5 i+ o( W; B; O* T1 G* |5 wWord16 syn[L_FRAME];
1 ]2 `; r5 Z, U/ F for(i=0;i<L_FRAME;i++)
A: b; N6 P9 n8 a; ~! ^{, }' ^0 a c' p; H/ E
new_speech = SpeechBuf;
( Z6 n/ M1 x* P& }/ y. r: R% A}7 U. R, Q8 C' Z& _8 j( r
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; & g5 F" D2 V. e4 J" R; Q
Pre_Process(new_speech, L_FRAME);9 Z% N# [" y' a6 U% j% M4 E. [
Coder_ld8k(prm,syn);
) ^( J' \7 {8 F$ C2 |- i( x9 i+ A* ` prm2bits_ld8k( prm, serial);1 O2 w) B( t: V( x# x, R2 @. i$ r1 n
}9 F8 s9 a3 F& Q7 l
void va_g729a_init_decoder()
1 V3 P0 h& Z0 H7 R# V{
( Y7 ^/ s0 O7 [4 }; hextern Word16 *synth;
# h z C) J5 n2 E1 @ bad_lsf = 0; /* Initialize bad LSF indicator */. E9 V3 N$ o/ G" ]
Init_Decod_ld8k();
" H2 @! b' _8 p, ?/ D! p Init_Post_Filter();
' D& m4 O/ }- Q- k Init_Post_Process();
2 X! F1 [' ^" O8 U" Q% e8 c; w}
, G* o4 r1 V4 @2 yvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
, V. b" e3 [! I" J{
% T% W6 H0 m$ `/ p: }extern Word16 *synth; /* Synthesis */
2 _6 E* m1 G2 f- z4 s& i2 u3 jWord16 synth_buf[L_FRAME+M];
- O9 k1 _' I% K, k5 gWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */
5 R& O7 |2 G0 z) D5 l' ~& Q' }Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
3 T& ~' \7 g& K& s/ U* d6 tWord16 T2; /* Pitch lag for 2 subframes */
; I3 f+ t6 y3 e) I/ S& gWord16 i;! v9 Z" m) n' \0 B- {+ U, T
Word16 voicing = 60;
$ x' T9 Q$ ]& V& R+ R/ {- [( {8 w% Q+ ?Word16 pst_out[L_FRAME]; /* Postfilter output */5 P1 C7 e% T# z- c/ @
Word16 sf_voic; /* voicing for subframe */6 J4 r- F0 |7 \0 ~$ D# ]# U: F9 ]2 B
voicing = 60;
; j3 y& F1 l+ U/ R0 ?- R bits2prm_ld8k( serial, &parm[1]);2 H. Z3 R* c! Z
parm[0] = 0;
8 V8 ?' ~% _! y+ C+ o- f # R+ U3 {( _/ c) @6 `9 ^0 o8 s1 M
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);3 S& e: W3 `" c" \" S+ t
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
# U- J. x6 Q; G# e6 N* u% j//--------------------------------------------------& k2 {; {" _4 k( m! ]! M6 d" n
voicing = 0;
6 T0 c* a w5 X8 k$ L% ~; ^# {ptr_Az = Az_dec;, h& g1 k8 r6 B
for(i=0; i<L_FRAME; i+=L_SUBFR) {: ?/ L3 E0 c5 q8 ~! z3 t2 f
Post(T2, &synth, ptr_Az, &speech, &sf_voic);; }* Y4 k k5 T3 ^4 x
if (sf_voic != 0) { voicing = sf_voic;}9 K( i! K" l0 P- C8 j+ g
ptr_Az += MP1;. \/ U& T" V8 v; P/ }+ b( f% b
}
# z( e& D( Q ^7 G) g5 O5 q( ECopy(&synth_buf[L_FRAME], &synth_buf[0], M);
# ~$ T! q' V6 r# s% M//---------------------------------------------------
! ~# @+ `# Z7 W0 o; h6 m/ z Post_Process(speech, L_FRAME);
* |, v( w/ m: v" \}4 E/ `' a0 `# E& m
3 k3 k5 Q, A- D$ W/ Y |
|