|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
% ?. z4 B4 \3 j) p下载以后需要修改bits.c文件:$ j# u. C9 m- D# V- u
我仔细研究ITUG729代码后发现:
$ d' W$ z) z' m( K编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
$ v6 e7 f5 H9 t8 {0 g+ M+ }- ~,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。+ C& Y( `) X* ]' q2 B% A
& V& L9 x! c# y% p7 K) `
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
) U9 t; \; C' d6 F2 y Q" ]# y A/ u/ c$ [8 Q& L
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。: E6 X& {1 @- e& _8 L% D" _
我们打开bits.c,就能看到里面定义的如下4个函数:9 l- [1 j, s. x/ r, e
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
D; V r. ~4 T# E2 ^6 s+ fstatic int bin2int(int no_of_bits, INT16 *bitstream);# w7 [5 u: ~- r) E1 X2 \
void prm2bits_ld8k(int prm[], INT16 bits[]) ; 7 p c5 ^1 R, `2 l3 [ J, x% B" E
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
% ~ f. s8 a) L/ N这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:# h, P- I! y/ o
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
& Y+ t: l7 ^% q' y% [static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
8 @( w* _9 T7 B0 ~8 _: p0 t% j( d9 a3 J1 J2 h" u/ j
void prm2bits_ld8k(Word16 *para,unsigned char *bits)- y+ G$ m! H$ j$ q; M5 D
{1 F' h2 E# H' b
int i;
5 d4 ^% e; w6 G4 n) ^) K int bitpos = 0;
' b* b+ F3 B/ R* v" O# Y* ^ for (i = 0;i
5 o6 J# C; }1 L, Y8 Q( d0 [8 m+ Q/ V+ {+ p; k; h
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)) B' ~) A9 s* q! Y) ]: V
{
& k+ m/ t' y5 h' Z1 c+ R6 p int i;
/ \, J. s3 r3 g int bit = 0;
6 z/ r" N; y! u0 {9 r unsigned char newbyte = 0;8 q4 I p# I4 z) p% V
' ]( x+ Z$ R5 f, u% J unsigned char *p = bits + (bitpos / 8);' a R* B5 W& K$ C- D4 C
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
: B. V6 |4 {+ r. \; ?* p5 I! z: }newbyte = (1 % a( l* k9 ^7 X' m, D
bitpos++;- }) _6 N& l; {, @7 ]2 w
if (bitpos % 8 == 0)" F$ e V1 m) j' G$ F$ ~' }& T
p++;
& _: g% z6 O' }0 G }
. r8 P- G* g! V* o5 Y1 b: S# F}
3 a% {; y0 k; d* F$ P* a
+ M" U8 Y% v! Lvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
/ ]. Z, C8 Q R: a' y{$ c9 E. P; l1 r* G' R3 _
int i;3 i7 c- w2 U0 K) f
int bitpos = 0;+ \/ o; ^5 m3 W; m
for (i = 0;i- }$ S# o+ }! F p" G
/ j$ z( `; j( j8 h/ K8 G8 V7 H- bWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)! N: p3 n& n7 Z, d7 y# \) L2 l
{3 y, Z7 ^( }- q" u) K4 w0 k
int i;
0 u" u! i: Q8 T# E int bit = 0;
. _# i6 {. l0 u* E6 t e( s1 U Word16 newbyte = 0;
6 ]: f3 G6 A6 N9 ^0 S Word16 value = 0;: e7 Z V, F3 p
( l2 \% {6 [) I- [( C& w
unsigned char *p = bits + (bitpos / 8);1 l! d/ b8 ~' n( W. E w9 U/ ]
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;, O+ u3 v' ~3 [5 T, o
if (bit == 1) {
5 ~& K& H' T* T3 R9 u newbyte = (1 + b3 C6 p& b/ n& r" Z- c+ G, \
return value;
4 T0 r& K- A' Q0 X% q}
8 v) }, t3 R4 q' q通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
: H7 I$ j# P, L8 D' C3 M, B* s+ j7 I! g2 y$ \7 X/ H
编码器的代码能采用如下的修改方法
: Q$ _7 S5 z9 O( R* k& t(1)修改coder.c:0 W- ~! @- z# ]8 o- {
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */5 m( P# J2 T8 E8 V' ~- d
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
D' Y$ Y! G( J1 G5 o frame =0;- l" ^7 y6 d% X% M
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)9 r6 ?. J) d* y- e
{ J! y8 J/ |8 [& ?
printf("Frame =%d\r", frame++);" B* Y6 y/ H( \* K
Pre_Process(new_speech, L_FRAME);' L- R* P& A N3 F
Coder_ld8a(prm);
( w, j9 B6 z8 o" c; Z# M& d) nprm2bits_ld8k( prm, serial);( j/ ]- Z$ K" e+ u
fwrite(serial, 1, SERIAL_SIZE, f_serial);$ t6 z# x, ^# I# {
}
" ]* K9 s- m& g# }) D* b return (0);
! t" i4 X; ^3 R# S: G
6 a1 p2 [9 [" e6 m! v, C: ?4 c(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:) X+ S0 D) j5 L. c0 I
#define SERIAL_SIZE 10! V h, {; S1 ^) v* [! @+ o( C. M* L/ @
" j) ?* ?5 E2 y
(4)解码器decoder.c进行类似的修改(关键部分代码):
9 k3 a1 z( e- s1 B+ U frame = 0;
# i8 n! |9 }& g. ~- T2 r- u while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)% h6 _: Q- u5 O7 C/ I$ Q2 U3 ]
{2 n3 Y) }, E7 C9 w+ V2 [# p
printf("Frame =%d\r", frame++);
3 s6 m1 d* u1 c; z7 E3 n# y2 Kbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */" w6 m+ X- Y8 Y: j. y$ i! |$ c3 r
parm[0] = 0; /* 假设没有丢帧 */# G7 g2 F9 X/ r; R s
parm[4] = 0 ; /* 假设数据效验正常 *// @- C: l: |# X% C9 [# t
Decod_ld8a(parm, synth, Az_dec, T2);1 F1 X4 O3 [9 w, o& K/ F! r8 e. _
Post_Filter(synth, Az_dec, T2);
! P5 B( n- h+ Y6 NPost_Process(synth, L_FRAME);5 F& |/ m% y9 M8 J+ x4 e! o
fwrite(synth, sizeof(short), L_FRAME, f_syn);6 m' \( g+ `) O# H, W
}1 \; } b1 {5 i- P
return (0) ; 8 j! e8 f6 h/ o& A; F2 Z3 e
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。& |; M$ U8 g7 `
- r+ ]! C) L! T) A3 Z6 D1 O" k修改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]得到,应该就能了。3 G% M$ t/ \2 x& n$ l
封lib:
( m7 v6 i% _( }3 mva_g729.h. k; R6 ~+ G- o! `
#define L_FRAME_COMPRESSED 10
' [, L# z1 q* c/ ~ L6 ]! v9 f7 l0 n#define L_FRAME 80' l- ]9 I- p" ?4 [! A1 I/ }4 ^: x o4 L
#ifdef __cplusplus " [$ a1 p/ B' o% B! j; t- q
extern "C" {
b( _. @. }) Y#endif
: ~; p( W9 ?& ^. ^1 _void va_g729a_init_encoder();7 X9 _" i+ c/ M+ O; V, d* B
void va_g729a_encoder(short *speech, unsigned char *bitstream);
( Y5 e- o8 _1 v2 k# g2 I+ H2 Nvoid va_g729a_init_decoder();
; s' V" q k9 \" Jvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);) p/ C) A+ T! u( Z1 ~
#ifdef __cplusplus " a' ]4 _0 ]+ x; z9 ?) o
}
$ {/ a" O9 u9 Q5 |! O) x7 |0 K#endif# P! b) G6 i- S( z/ U/ C1 L
va_g729.c' s) ~5 s: k4 K+ ~! K8 E
#include <stdio.h>7 z) R# |+ {! \
#include <stdlib.h>- T4 ~- \+ q+ B3 R4 t; k3 C! B
#include "typedef.h"7 F. l+ c/ p$ y9 [
#include "ld8k.h"
2 W# q9 Q W6 d" K% ^; o+ JWord16 bad_lsf;
; i2 P5 J5 L# n4 {! ivoid va_g729a_init_encoder()
W! U% |9 R% }7 z c{* J& p W& R: e$ l) s4 z# b
Init_Pre_Process();6 R2 u1 c( l, D. G6 x
Init_Coder_ld8k();
1 E5 o4 Z6 U m: {/ O1 y+ |}0 [3 g; @; p2 ]+ C `7 O, Q9 W
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)5 `6 B( c& X* O4 B/ z( y l6 r$ h$ e
{ 0 ~' g* c7 ^+ U9 f( \9 S
extern Word16 *new_speech; /* Pointer to new speech data */
, @* Q& {& M9 _+ H Word16 prm[PRM_SIZE]; /* Analysis parameters. */+ t! A' `2 k! @. g
Word16 i;
" `) P2 ^ V9 ?/ O$ E2 [Word16 syn[L_FRAME];
p5 S0 D& }3 y for(i=0;i<L_FRAME;i++). L9 n( b( g" s( k5 l
{; f& a9 }/ K; b8 \9 c2 _: w
new_speech = SpeechBuf;$ E$ C3 k/ l o3 c1 P
}" n3 e% U4 @- j c; v" O; N q
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; . W; L$ p; M& f# J
Pre_Process(new_speech, L_FRAME);
8 A* B% D: b0 E. P' e Coder_ld8k(prm,syn);
1 ~9 V" }" N% Y7 e- s! l: K prm2bits_ld8k( prm, serial);$ E! }$ y% Z7 m! ?
}' z4 k' @6 D5 v7 C3 o5 J
void va_g729a_init_decoder()6 W+ ^$ a% _2 f9 r8 B' H
{
, g' U0 ]" P& Eextern Word16 *synth;9 a" W* b2 a, X+ h t+ s
bad_lsf = 0; /* Initialize bad LSF indicator */& f2 w) D/ G1 x+ N- s( g# z
Init_Decod_ld8k();
j, Z& E' f) e0 U7 @: R Init_Post_Filter();( \% W3 S2 e7 z3 }% l1 y
Init_Post_Process();" \& [! [) `0 e8 R
}
: l1 O0 j. ^% t9 Hvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
( @; w# V `* ^) S1 B{
/ ^) E) J* T; [% c: [* a% v$ sextern Word16 *synth; /* Synthesis */
& r' S: F( H% V rWord16 synth_buf[L_FRAME+M];/ {6 P2 |: [; N: h7 m
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */7 u5 y3 a; Q2 `. V& g1 P+ s, T4 j
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
' l" J! X8 x6 H$ gWord16 T2; /* Pitch lag for 2 subframes */
1 m. I, [) O$ Y/ g9 E1 NWord16 i;
& z, m3 L5 X4 K% T8 ]Word16 voicing = 60;( V5 {8 p! M; f& o
Word16 pst_out[L_FRAME]; /* Postfilter output */7 e- H2 W) h; ~" _ B' Z1 w
Word16 sf_voic; /* voicing for subframe */
- ^" _3 d0 Z' m2 k+ g1 mvoicing = 60;8 F7 f# p& `3 l& W8 `+ W
bits2prm_ld8k( serial, &parm[1]);7 U( |: k5 G1 e9 [
parm[0] = 0;
( ?* W9 f0 w$ h$ x7 U" [* a+ L; m 6 n" p7 ]6 V" _3 P0 v
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
) w$ U% _: ~2 O4 U# f( o1 [Decod_ld8k(parm, voicing, synth, Az_dec, &T2);# L, G# v7 w0 T
//--------------------------------------------------
8 ~- [4 j' F+ S0 Z) |. N$ d: @voicing = 0;3 G. H; q9 r3 r9 X+ E( n
ptr_Az = Az_dec;
- J+ [) K# |6 J0 d" Bfor(i=0; i<L_FRAME; i+=L_SUBFR) {
8 |9 p8 R* D u$ p: _2 o) e Post(T2, &synth, ptr_Az, &speech, &sf_voic);
4 ` [+ P+ M1 w1 y if (sf_voic != 0) { voicing = sf_voic;}0 \; ?% @( ?1 n% B; l& w
ptr_Az += MP1;
) o" B% D% @ \" i T6 T0 v}
- ^- H3 v4 Y; n( qCopy(&synth_buf[L_FRAME], &synth_buf[0], M); d- f- h+ k5 A' d7 Y) r
//---------------------------------------------------
2 E, ]0 J/ _; c% r0 I% e5 o# c Post_Process(speech, L_FRAME);
% s( L" Y: \5 _) }}2 e6 `2 V6 r: B8 p* m$ n
+ r- ~; U: z4 a; m0 l3 u+ y
|
|