|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
6 C# I' R$ u; h6 x下载以后需要修改bits.c文件:# }/ q6 |3 I* ~# _
我仔细研究ITUG729代码后发现:! W$ r2 X6 C i( |
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流. T. B" J: u# U% T1 K
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
6 [$ \* R M0 ^
, k p% ^% |4 E P# U0 }ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。! Q/ u( P' t( @( P' k1 E" i B
4 I; h# G- `1 P' @7 G. A$ ^; X
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
. y2 n1 V: P, y- w我们打开bits.c,就能看到里面定义的如下4个函数:
- G0 o, M) ^. ~. g$ n* pstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
8 M4 k; p8 \8 X) b: s( Wstatic int bin2int(int no_of_bits, INT16 *bitstream);
4 ]. @* r) n% j/ f3 T) vvoid prm2bits_ld8k(int prm[], INT16 bits[]) ; $ n; b3 s+ @( u8 l( m
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
6 B; Z2 ?! ?% Y# T6 g; e3 ~这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
7 Z/ Q* t( w+ [$ C! nstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
& p7 Q6 H+ [7 g- F astatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; ! l) n1 |7 M+ p/ v# P! M
: A6 C5 g3 v( U+ W( u% H# d, Rvoid prm2bits_ld8k(Word16 *para,unsigned char *bits)
& Z& H9 i" b7 v3 B& P4 D( v{
/ q) O. O; _& p int i;
, V* N3 l6 P4 D& C int bitpos = 0;
. s$ T4 }: b% g$ b for (i = 0;i
$ J3 M! N+ X' X/ T j2 ^
& q+ @3 N! ~3 ^4 [ Q. @void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
2 \7 i, u6 o. Y1 b9 b{
k$ _* m' O( O8 R0 } int i;' X0 q/ b3 [! R" E, s8 d P
int bit = 0;
# ]1 j3 m: M& V3 |$ t unsigned char newbyte = 0;
, m8 p1 {5 c; o3 b
2 q/ Y7 m+ Q* {2 g2 Z E! V unsigned char *p = bits + (bitpos / 8);. h, p3 r' P- u1 [2 M
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
0 Q% }& u5 e! B# B$ o& Z! qnewbyte = (1 ' \0 \+ G) u6 u; Z- B
bitpos++;
( X- J4 d f* m8 e9 f& o; ?) cif (bitpos % 8 == 0): {2 \( {' H4 S- R( ^3 |% _
p++;6 J( ] w0 \6 E3 K8 b7 s& C& J
}
) v+ L% ^/ z$ L9 H& q}
; h. k# o% `7 ?" z7 |8 ?
: ?( Z* E) L5 ?2 Z8 O) F3 d6 K. Nvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)% g. M( x: ~( O) m; ]4 V/ g8 S. r
{1 t1 z8 ]. H8 W0 H/ u* ], \
int i;
+ x" ~3 }$ V& o* W6 [) O/ v8 v0 n int bitpos = 0;8 I4 I4 I; Z" ]8 u
for (i = 0;i$ X" G. E% P, O! W0 t" w( U
/ F/ T; M& m! U- r( f2 `
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
`" ^% j" ?6 Y: C# o9 [{$ X+ |0 H! R$ s# H% C- }
int i;
- }, u) U; G5 n3 }+ f( i int bit = 0;
$ n5 w' D& } G! t; A' T Word16 newbyte = 0;
$ S3 u% H) m# d/ L6 ^: n Word16 value = 0;6 Q, a3 G8 S$ F" ^. ^
+ M7 i* A. K3 p4 ` unsigned char *p = bits + (bitpos / 8);/ W9 P8 Q0 {8 r+ y* J2 B& M: V- V
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
7 N/ e9 _. ]5 _7 \& Q) Y( fif (bit == 1) {
& F6 t9 E+ ]$ V; O& ?# Y newbyte = (1
$ |7 p" E e' v% j% z" Q7 f- @ return value;) f7 ?* f8 N& \; i8 K% J( v; ?
}
6 T/ k0 F. _, S# A5 P9 v1 ]通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。5 Y) g+ r' r7 i& {! g$ o
* d; ?, i% w8 ^: V) H7 u& [编码器的代码能采用如下的修改方法
) W; ?( W- ]1 r2 X! B8 B% E(1)修改coder.c:
% t: K) L, O. N! d: runsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
: x( ~ ~9 X( c: w& C(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):/ y, [! c- s7 j9 _1 Y4 m- L* b( j
frame =0;8 u* w$ Q# _: R r8 H" h
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)& o7 V8 ?/ ]& I/ r1 X, K) u
{
* G0 Z8 _/ Y2 xprintf("Frame =%d\r", frame++);8 f8 b6 B8 S3 f4 ]& O
Pre_Process(new_speech, L_FRAME);
4 W4 q$ z6 m0 P% O7 jCoder_ld8a(prm);7 Q9 O$ O+ W, z* i' ^
prm2bits_ld8k( prm, serial);" ]* x) G2 J/ ^$ Z1 E
fwrite(serial, 1, SERIAL_SIZE, f_serial);7 Q7 A& e4 J( c' n
}
1 j2 e- C# L* o# r5 q l return (0);+ k7 W5 z/ x: z$ Z( p
3 W% h5 q8 @8 [(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:8 G) C5 k& o; M, k3 Y3 i/ R Z
#define SERIAL_SIZE 10- h' ~# y' U t b9 [$ y$ c) `
6 ] y) {9 R5 b4 t) J- S& M
(4)解码器decoder.c进行类似的修改(关键部分代码):
# W* @3 B9 K) |; ]0 e0 R frame = 0;8 g2 J2 D3 y; I5 J: C
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE); c2 X8 b( _1 C; @
{! [/ E8 t2 ` x/ z
printf("Frame =%d\r", frame++);
0 ?6 Y) j2 \) X: l, Bbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */2 l, H4 w' `5 _* L
parm[0] = 0; /* 假设没有丢帧 */
, W O+ |' S/ g9 h) Q' t7 Aparm[4] = 0 ; /* 假设数据效验正常 */8 F+ Y- _& c6 k
Decod_ld8a(parm, synth, Az_dec, T2);, t6 r' X! v# K- A
Post_Filter(synth, Az_dec, T2);
" o' G5 U' O5 z f* Q9 c% { T2 K% PPost_Process(synth, L_FRAME);0 Z3 y I- c3 g8 B# l
fwrite(synth, sizeof(short), L_FRAME, f_syn);
, I1 [5 ~5 E0 I' E" n }
! U0 ^- l" u# z7 V return (0) ;
: o2 v6 e5 c9 j, J& B& y+ C通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
- O+ C8 X( }* n* h+ m
7 l5 ]9 w$ y% 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]得到,应该就能了。
8 f" V8 }0 S7 Y9 Q' T封lib:7 d: z0 s; M# q# |
va_g729.h
0 S8 S2 a* I- ~6 E0 H#define L_FRAME_COMPRESSED 107 k3 e6 X7 ]# L, e8 n2 S
#define L_FRAME 80
: l* Y' D9 r% w/ ]( c& ^% o8 e#ifdef __cplusplus
$ o: u6 M. w: b: m o4 d T% }3 fextern "C" {
- v, X' w2 b, V! |- j# Z/ s#endif3 c& R* i- [. F; ^4 F2 K1 [
void va_g729a_init_encoder();$ B9 \' s* }- R8 T( ^9 u; Q
void va_g729a_encoder(short *speech, unsigned char *bitstream);
' g! F" i* J5 j7 z! Q k0 q+ Y$ @( yvoid va_g729a_init_decoder();
$ [, a2 @" Y# y, _& Z, lvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);& X5 M, \5 ~4 D
#ifdef __cplusplus & P$ Y W) n/ L
} 3 \/ p, y6 A1 g0 x( o+ x
#endif
4 A: r5 z+ Z. f% }5 Rva_g729.c i8 M+ E6 D0 L, E7 I- U
#include <stdio.h>/ m4 {/ R: w u2 T& W
#include <stdlib.h>% T+ R* v2 y3 }
#include "typedef.h"/ X3 N. ] z2 K/ D1 M
#include "ld8k.h"* s! ]" [4 S9 k) R0 x |% ~
Word16 bad_lsf;
7 R9 E9 E; O1 K+ lvoid va_g729a_init_encoder()
0 z0 U# T; B# h1 W, G- g{
X1 r( ~) g. t) e4 y Init_Pre_Process();9 G _, S3 g. A7 v/ z
Init_Coder_ld8k();
1 ?! y/ W- b4 L$ S}! {/ }, F/ Y9 f" O% `* b+ \
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
2 l8 }" t4 _0 v) r* S2 @: A( o. O{ 6 U$ c% N7 ^1 G C# T6 X H
extern Word16 *new_speech; /* Pointer to new speech data */
$ n5 ?$ G! J* w- S8 q Word16 prm[PRM_SIZE]; /* Analysis parameters. */' }) r' v: Z% {3 o
Word16 i;9 d. w+ Z1 r) E2 o, K: g5 E# n y
Word16 syn[L_FRAME];
$ t0 n: T' Y$ X& i6 T for(i=0;i<L_FRAME;i++)
$ t* s' A4 G ^0 B4 F- L{
4 B9 d4 ^) l" f+ r2 m. C( q: g new_speech = SpeechBuf;
1 n4 ]8 B- W' w: x$ \}
- d1 {/ V7 [4 w' y3 G for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
: U9 E6 T6 k c8 t1 b B. \ Pre_Process(new_speech, L_FRAME);. a4 @, A, |+ l( e8 B, T5 i1 L
Coder_ld8k(prm,syn);
! d2 G) x6 Z9 _9 i3 w prm2bits_ld8k( prm, serial);/ ?9 f2 x% [# ~/ v1 [
}8 z& d0 ~- A( p* ?8 P" h% h& O
void va_g729a_init_decoder()+ G2 E4 s/ b. I& Z4 b, a
{
: k" j* ~# [8 z8 S9 kextern Word16 *synth;" a4 t% ]9 d2 ?
bad_lsf = 0; /* Initialize bad LSF indicator */
6 O7 m/ u0 y5 ]9 j; I i3 o( ]- N( Q Init_Decod_ld8k();
* w! X9 A2 M$ Y/ K Init_Post_Filter();
5 W& U- o7 G0 W1 M' L" p8 C9 p Init_Post_Process();
) s& H& a7 X& M) B. I}
: R" c7 G" a- f" f+ Fvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
% m9 R% {8 a# m{
- l# ~! o0 {2 a# ~ ^extern Word16 *synth; /* Synthesis *// Y2 Q% a; n- m% W7 k3 ~* G, u. A
Word16 synth_buf[L_FRAME+M];
1 n- y* U: {, T3 U$ Y, X! s) OWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */: O. {: x7 \( y
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */7 D& E+ z8 V5 ]1 B/ t4 g+ c3 y S
Word16 T2; /* Pitch lag for 2 subframes */
9 \0 G+ \; e+ E; c, m3 _Word16 i;
) }: r0 H$ r& n6 E- p% uWord16 voicing = 60;: s! B4 o9 |1 J. X5 j
Word16 pst_out[L_FRAME]; /* Postfilter output */
8 L6 \' s- i) t2 y+ Q$ a0 U; Q2 V$ _Word16 sf_voic; /* voicing for subframe */
) {! p7 z9 o6 M, e1 P7 g4 u1 Z( [voicing = 60;
' t$ j8 V9 h, q5 q8 L bits2prm_ld8k( serial, &parm[1]);0 p, V& a* _8 H. l: \) t; F
parm[0] = 0;
5 R& S) s7 l3 b1 @) p
& L% \6 |) _' D+ Z' E parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
W* U6 L9 N8 z( T& N8 o& xDecod_ld8k(parm, voicing, synth, Az_dec, &T2);4 W5 ?( g. ~, D# F6 J" Q! A
//--------------------------------------------------
8 u+ n& ?0 R& o+ M1 |9 V9 {, qvoicing = 0;
! A" S* V" f5 a9 f8 l7 ~3 C1 Kptr_Az = Az_dec;
" K* x- V2 t" n. G1 H2 `% Ffor(i=0; i<L_FRAME; i+=L_SUBFR) {
4 D, {2 w- [, J. F% Y Post(T2, &synth, ptr_Az, &speech, &sf_voic);
) h }4 e, n8 {! @ if (sf_voic != 0) { voicing = sf_voic;}
9 p* a; H* V+ A* O( P ptr_Az += MP1;. z2 w7 [5 p$ q/ q- A
}
/ w0 O/ l4 K3 F$ J" yCopy(&synth_buf[L_FRAME], &synth_buf[0], M);1 X: k! D1 Q' W/ G. h) Z
//---------------------------------------------------
* V( G! q! k' D" L: i4 y Post_Process(speech, L_FRAME); ; T3 C6 b4 o4 ~- I. N
}
1 _: |) M# P$ Z- J$ @9 _6 `( h; C# d$ ]1 M) c
|
|