|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
* Z* j. ~7 Q9 Q/ p7 Z下载以后需要修改bits.c文件:7 R- E% f, u* h
我仔细研究ITUG729代码后发现:
2 y9 r9 R6 a7 }3 L5 z# \编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流' @9 L) @8 g. r
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。, ^0 d5 q: p5 U T
$ Q: f$ k: r; O1 ]5 {/ c$ aITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。: q& c4 [6 l. l. j
" X- N+ v+ \: { o# l# O! s那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
) q6 U: P7 J. \5 _9 V1 I7 P我们打开bits.c,就能看到里面定义的如下4个函数:7 p% R; y5 B; k6 F
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
' x. J2 U0 S! U* _static int bin2int(int no_of_bits, INT16 *bitstream);! U) C% q; s- t
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
6 z$ \$ Z) r8 S! xvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;+ S) X# h. I2 j0 u' \! J
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
' q& d/ K( F$ h# nstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; 6 f7 V- X9 ?& o# n2 |) `
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; . P+ d9 _. Y9 y6 z
0 X7 w# l, q- X2 J8 ^( l" ]
void prm2bits_ld8k(Word16 *para,unsigned char *bits)7 b2 u& J; C: A: F
{
) `9 G+ Q% l" W) V1 X int i;( K1 T; _/ U/ X
int bitpos = 0;
. d# R5 }- ]2 u& n) H for (i = 0;i
- x6 \6 J n) V+ t( Q& l5 H
( H6 s1 q8 m$ d4 Vvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
( x& H- c7 m- }0 E8 n. C{9 s* [; y- D6 j8 B4 F
int i;. z4 q' s+ T7 v, X$ v. `
int bit = 0;6 V, x' ?- f6 N2 D2 D
unsigned char newbyte = 0;
* Y2 f) e9 s W
1 E; U# q4 F: G0 j( e( B unsigned char *p = bits + (bitpos / 8);2 n7 z8 v6 e; j* n8 T' W. Z- @% `/ [( G
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
' V/ L* e1 y0 U1 ]! z; Nnewbyte = (1
. w5 \$ H N {7 B( _/ `) wbitpos++;
! V- s+ W, j0 ^- `& T) H1 H& sif (bitpos % 8 == 0)5 u1 t4 V8 o; d
p++;* X6 o; `! K8 I: P
}
7 h, K& s# [6 q0 _& Q4 o) K5 c! t7 S}6 c" }$ z$ P5 ?
5 m. w) k* T( i* B5 ivoid bits2prm_ld8k(unsigned char *bits,Word16 *para)# J: J8 l9 f8 H1 w7 x6 M; T
{
( |6 d5 Q @' R w8 k) X. W int i; M5 T5 k* F7 P/ H+ M a
int bitpos = 0;( B& r1 \2 P6 m* h6 x2 C
for (i = 0;i
+ e! s+ H; k& m" k6 p, z- A5 p9 g# w$ B. ^% @
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
/ y, b8 u5 S9 B' F; h+ F{
7 Q( g) i; v4 h. v int i;
3 B) {0 @- y6 ^, A% l) G% j4 v int bit = 0;- {# P d' s4 R
Word16 newbyte = 0;
0 Z. R) w! q0 W" J6 j+ ^0 a# c Word16 value = 0;0 v* d" y+ |5 `" t
1 m# u# v. k. k unsigned char *p = bits + (bitpos / 8);, o0 \+ U) L+ H- F9 e: s
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;4 D" Q( ?: }% s
if (bit == 1) {% k* Y k4 E' b
newbyte = (1
& _. o5 ?" ]8 j$ r2 ^: b return value;" t) a" H3 F1 W8 V
}
' l j! g* i' z. T. L" Y- s3 M通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
5 z6 |) m" g% u3 ?) b1 o0 C" v0 W" [) o- ~$ ~
编码器的代码能采用如下的修改方法
. i7 i8 p9 o0 g/ _. R* |" R0 k(1)修改coder.c:' F9 `3 k6 Y2 w) C4 L; M1 X
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */' _0 T" E# H4 I' C
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
6 i) T9 y( r8 I frame =0;9 r( Q- \% x; w s: e; n2 s. I
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
! d9 ~1 P8 [) F; T {
- n3 A2 ?9 l4 V9 _( |6 h6 Aprintf("Frame =%d\r", frame++);
' m6 z! a+ a" M' U0 uPre_Process(new_speech, L_FRAME);
8 ~! q6 F$ k: J1 ICoder_ld8a(prm);! q. S c& @' r7 r, }
prm2bits_ld8k( prm, serial);
1 m) _8 [/ i' ?# u3 |fwrite(serial, 1, SERIAL_SIZE, f_serial);: o3 S3 R" t% ?3 n& j5 W% c
}
5 K4 n: i8 {3 e/ {+ M* F3 z return (0);$ ~+ W# C/ m0 c% l& m" \
V w) m5 Q; H. l. P: a- j
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:( x, K! e0 f/ b
#define SERIAL_SIZE 10 y. R( S2 R# y5 J/ `
9 A, H0 n6 j( ~3 k0 F6 {(4)解码器decoder.c进行类似的修改(关键部分代码):- Y# a% D, ?% F2 m" |. U r- V, r2 Q/ R
frame = 0;! b' `. e2 y) v4 F, j
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
) Q5 u7 e9 [3 F* s1 c" {( Q& S9 x {
: k1 @$ b8 T4 B0 m0 ]printf("Frame =%d\r", frame++);
8 p; i& }" Y+ J' r. _/ ~& t. ibits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */1 s6 R: j+ j) D) n P3 h
parm[0] = 0; /* 假设没有丢帧 */
3 z. B. A- C5 c3 K5 cparm[4] = 0 ; /* 假设数据效验正常 */1 E# r% [( M4 V, z: J1 b
Decod_ld8a(parm, synth, Az_dec, T2);
8 {- ~0 X w& N4 T) XPost_Filter(synth, Az_dec, T2); 8 T9 S' {# u( x+ O# y! r; V. O
Post_Process(synth, L_FRAME);( n r' G- w/ P
fwrite(synth, sizeof(short), L_FRAME, f_syn);$ b4 x' h8 l4 \! T
}
. [- Z7 i/ b! G& x' i: G return (0) ; 4 o4 N# P# V+ J* s
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
4 n! Y# X, y: @2 J) l
9 w- o: h2 |/ `" x- C修改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]得到,应该就能了。) \9 \5 t T- Z: s
封lib:! D% F" a1 C j; O9 y# j( ^' d [5 A
va_g729.h7 H# g8 ]4 D1 t# s+ Z m
#define L_FRAME_COMPRESSED 10
4 i3 `7 H A) `# y7 T% @/ L# _9 O' K#define L_FRAME 80
; G$ H9 |' M+ a; T2 A#ifdef __cplusplus - j4 {7 n5 R' E2 I) v$ W& o- C
extern "C" {
; E. O B0 \6 U& H. b#endif( ~: l/ @: v# F6 l: i1 ~
void va_g729a_init_encoder();
' \! r7 X9 M; V) m. Pvoid va_g729a_encoder(short *speech, unsigned char *bitstream);) ~7 [& f+ d5 c1 D% i* ~" G
void va_g729a_init_decoder();6 [* l" f6 x* B* @
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
w$ ]# a% G9 t* z#ifdef __cplusplus 9 |' \" J4 u' ~- h# B3 Y
} + E: i! n/ [* C. _. `4 d; V; ~% G
#endif
* U9 w( P& o4 Gva_g729.c' A& y7 Z& _1 R8 ]
#include <stdio.h>! j8 h! m9 ^ C9 G1 h
#include <stdlib.h>
# Q v+ }. o9 q+ L* v% d#include "typedef.h"
: \' D" j% q% r, s; r2 u#include "ld8k.h"$ P3 J8 _3 R) W7 ^: z9 J3 o b
Word16 bad_lsf;: G. l3 Q* Y7 c8 D5 j
void va_g729a_init_encoder()
8 M6 f! m1 y3 Z+ t" W2 K{2 V; s1 Q# E6 J' |9 @% C
Init_Pre_Process();. R; f, O$ e& ~2 t
Init_Coder_ld8k();
. N9 ]7 L* i7 n7 o7 v' G0 p$ B}
: e- N8 [0 E$ K0 o$ uvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
~; X$ z8 ]( R; u& w9 V7 G+ w{ + t6 F7 q9 @0 \) {
extern Word16 *new_speech; /* Pointer to new speech data */
0 w. m2 B6 k/ G3 F I4 w. L Word16 prm[PRM_SIZE]; /* Analysis parameters. */) y: @. @/ N. `4 Q2 R( _8 ^
Word16 i;3 ], J! r" h; q6 h) J! X7 w
Word16 syn[L_FRAME];
1 k' D* } K& M0 S for(i=0;i<L_FRAME;i++)- \/ E1 d' w9 r: w* a
{( |# b3 W% e$ m
new_speech = SpeechBuf;
" g/ Z& p7 p5 c) W$ j}* {2 a4 j5 j E" \+ @- @/ X
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; 3 \+ U. A; _* o6 z; q. J
Pre_Process(new_speech, L_FRAME);7 K1 A5 _6 k8 T! S# G7 K1 J
Coder_ld8k(prm,syn);! o1 I* D) w9 o* {
prm2bits_ld8k( prm, serial);/ B2 t: w# l3 j* I( L( b
} }* y+ [1 i2 A+ l
void va_g729a_init_decoder()# }: d$ J8 F! Q: [+ W$ g+ j4 {! K
{( [" e/ P$ ~& a; x* v4 I
extern Word16 *synth;
: r/ s2 p7 U5 z: X3 _6 C bad_lsf = 0; /* Initialize bad LSF indicator */9 A7 `1 b) f8 S# i0 A! z9 ]$ c/ B
Init_Decod_ld8k();! y$ C% M# k" P. |
Init_Post_Filter();6 a. J+ e: i5 ^& ^ f" {' ?
Init_Post_Process();
9 d) R1 c7 N+ b* v" ^8 ?3 h" N} X. V0 M, C0 d+ M
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)6 w% f" m' P- }6 h! O+ _
{ j3 L( E4 E; y' O+ }
extern Word16 *synth; /* Synthesis */
7 {. N- ~) r8 ?( c1 VWord16 synth_buf[L_FRAME+M];5 T5 o& `% a( Z& J" C" y$ K" ?
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters *// g! x: A7 }' T
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
4 `4 ?# n$ [' |8 U+ ^1 z" VWord16 T2; /* Pitch lag for 2 subframes */
( E* d. h* A7 t/ [4 wWord16 i;
$ T5 I6 w2 Y1 s: XWord16 voicing = 60;
7 _0 i5 {# z( dWord16 pst_out[L_FRAME]; /* Postfilter output */" r3 H; |3 P5 H
Word16 sf_voic; /* voicing for subframe */% B+ w" b% @6 ?% j
voicing = 60;
2 s, ~& x0 a1 y" J, a% | bits2prm_ld8k( serial, &parm[1]);
# m+ ^# G% J( S# m2 @ parm[0] = 0; / O! g8 \$ q/ f. Q" _% {" {* u
9 f$ \$ y3 H4 p) z* _& q5 O
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);) }% I+ P. q0 @3 H/ s0 e1 p
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
5 S1 @. X* S% i. r//--------------------------------------------------
8 K$ t+ v) R& J) Z* q' e- Wvoicing = 0;
4 H9 {0 I2 Y$ f# ]: I7 eptr_Az = Az_dec;
4 W6 n+ L& M. d5 I0 G' s& x9 y! V+ z* Ofor(i=0; i<L_FRAME; i+=L_SUBFR) {
7 V: v% R, G# t/ K- E# V# ]* N2 o Post(T2, &synth, ptr_Az, &speech, &sf_voic);
% z' |" V0 i1 q! C8 r if (sf_voic != 0) { voicing = sf_voic;}
2 @1 U, W" A0 Q# U- K0 F. Y ptr_Az += MP1;
: ]" l) C4 V! v9 w. }* f9 K, s4 ?}
/ u, I) T+ ~' U2 e$ iCopy(&synth_buf[L_FRAME], &synth_buf[0], M);
1 t6 m& n8 l" Z7 P: `//---------------------------------------------------
2 _9 K# S T/ B; X% ~ Post_Process(speech, L_FRAME); 4 T1 @6 Q5 E% F8 I% P8 D; ]) ^
}- u; X! C- R1 a0 b& ^3 u, C# K4 }
/ e" d/ U6 h$ x
|
|