|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/. @4 @# \) s; V
下载以后需要修改bits.c文件:6 ^4 l7 S. x6 y2 e' k
我仔细研究ITUG729代码后发现:) [+ Q& h- r! ~! ~( d- v
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流4 J7 a3 f$ t* n: y
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
' `& P) s$ @( q0 b! Q. N! a$ J1 V) a; y! S
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。' r/ B6 H0 e. w( v0 F
. a6 R/ O0 Y" O1 C; B/ {& j, }那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
, p. v4 H! A6 J5 z6 x3 ^( ]我们打开bits.c,就能看到里面定义的如下4个函数:" b2 r& \! q" G h3 W: y" s
static void int2bin(int value, int no_of_bits, INT16 *bitstream);' l% O9 c* V, y) W( U- K
static int bin2int(int no_of_bits, INT16 *bitstream);
( |) I, e2 s$ Q) I% D0 K% ~void prm2bits_ld8k(int prm[], INT16 bits[]) ; 1 s, {, F* m. R7 R6 i2 r# j$ l
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
4 v6 l3 l5 I+ W这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:7 h/ G. Z) t3 N
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
6 K# P4 q* \8 d( @7 D* h. [/ ]static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; % b2 R) j2 Z% s' s! P9 Z
( K/ E! G% q1 d6 t$ e- K
void prm2bits_ld8k(Word16 *para,unsigned char *bits)6 y' \& ^5 S6 H# ?+ K
{
& ~9 I' E) V2 q1 Z7 `" r: S- m l int i;
1 p$ ~' p! r% X0 c$ p* z6 { int bitpos = 0;8 j2 J/ p* s3 A* D1 w
for (i = 0;i
' y( R! h, f& b
5 y# s3 o$ ^% b! cvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)# Z! E: V4 K% f: S2 |9 w( r
{- V1 t6 G i( Q3 j1 G" l) Y
int i;
$ [$ T5 P; h$ c. g% ?0 H int bit = 0;
& F2 o: ]' O+ [% |: d v! F unsigned char newbyte = 0;
) L- `* \" d2 c% O6 x
/ B# J' e! f! ^% A% z unsigned char *p = bits + (bitpos / 8);. p+ f0 T( P Q6 D. g
for (i = 0 ;i > (bitlen - i -1) ) &0x01;$ P( k8 p* m. d. y
newbyte = (1
5 v8 F1 w/ V5 x4 C* s7 ~bitpos++;- c a h8 X* F1 b8 T* o7 L
if (bitpos % 8 == 0)$ b B3 M) L, n& X' J. [! s
p++;8 O/ N1 k' G3 T: }
}
8 } A9 C. p8 S, w}
) _% r" D, C/ v/ j1 o, H" H. w, k) a5 d; f
void bits2prm_ld8k(unsigned char *bits,Word16 *para)) J% m5 _4 D; A8 T. d, L7 m
{
2 J! f4 W) m% ]2 K' B8 ~ int i;! ~4 m# O" }) E! N
int bitpos = 0;$ p5 ]9 E3 `" ]2 _" r/ r* h
for (i = 0;i. \# }& R0 }& A( L# {0 {9 ]
: n; y2 V; \1 _, K$ L! t
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
6 V9 o d. {7 S/ r{
; D9 p! s0 b8 K0 f$ N int i;
# G% l9 U u* ^: K, _! ~ int bit = 0;
3 @: t) r9 @5 k4 N( l" y/ M Word16 newbyte = 0;8 [7 A, J: V6 L! W+ C( \7 \" ]
Word16 value = 0;9 u9 H* ~; k: H+ u
O6 Z% P4 w* B! h# a+ n! s unsigned char *p = bits + (bitpos / 8);
0 i0 n! E6 p& _0 h, y& T' N for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
5 \1 h9 }' A7 e4 A: d% c/ nif (bit == 1) {
( U, w7 v1 c! T9 S- M newbyte = (1 ! f7 G) F$ d% V8 V$ Y0 J7 e
return value;
" P3 l, q) k2 l}
) z& {& |$ B8 R0 y通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。* Q. Y( L# T$ S, n
# `7 k3 z w5 o9 r5 C9 Z
编码器的代码能采用如下的修改方法9 X* i' d" N3 a$ {5 a
(1)修改coder.c:
) G$ l' a6 e( l) e0 B; `+ xunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
+ y# k2 G, W/ G(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
/ ^9 O" _; N+ Z1 Q" F. y frame =0;
/ E- y4 U% _ c! r0 i, B while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
3 w8 f# [* S4 I3 `$ a' ?( `) D7 c, G {
. H, y8 M2 R7 b. j# s+ tprintf("Frame =%d\r", frame++);
% c M2 V* k3 [; pPre_Process(new_speech, L_FRAME);" ~) \" [! h- R; t+ b g
Coder_ld8a(prm);
6 o9 a1 t) ^! p: _7 Tprm2bits_ld8k( prm, serial);/ x. e1 z( V' W4 k
fwrite(serial, 1, SERIAL_SIZE, f_serial);0 Q1 p: t7 E3 T0 X/ ^; I
}) N0 h0 ] k3 V# P
return (0);
0 Z9 w9 c4 P; Z- h& F; P( o6 i. q2 |9 A" ? }$ j+ f( x! K
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:$ G4 n5 R; C O" }
#define SERIAL_SIZE 10
7 D I9 a9 a/ u" t% J, a
, I% ?9 [4 n" U: C- Z(4)解码器decoder.c进行类似的修改(关键部分代码):1 Y. P. j D0 Q5 j, |6 l) \8 t4 k% Q
frame = 0;/ h8 n$ x- ^: Q; f' o
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)6 z; y( E {/ P
{$ h4 g& h; T# I, F4 F( h) B
printf("Frame =%d\r", frame++);
( Y' \# S" b- u3 I0 ibits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */( M/ f% q5 |7 n w3 C3 _
parm[0] = 0; /* 假设没有丢帧 */# T- Y1 ` K: t ]( ]$ D3 G D
parm[4] = 0 ; /* 假设数据效验正常 */# S& p9 l8 J" w
Decod_ld8a(parm, synth, Az_dec, T2);; f2 A! [, e* o |
Post_Filter(synth, Az_dec, T2);
8 K( `9 B6 V4 B+ R$ Q: W( N2 hPost_Process(synth, L_FRAME);, c8 [( S5 `" ]9 @6 I
fwrite(synth, sizeof(short), L_FRAME, f_syn);2 E5 o# M$ |1 T7 e/ t, O$ `
}" K1 }. N: X W0 ^2 H$ t& L
return (0) ;
7 n9 L& ?, x3 l6 O9 v q6 K通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。. c' M' ^/ X+ [7 v
1 x; u: c) _7 r 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]得到,应该就能了。
5 e. d+ ^! M# i, w7 R, |- h封lib:3 ]4 l- E6 I, v, H
va_g729.h( n* b: {; B2 _
#define L_FRAME_COMPRESSED 10
; m7 a% ?7 X4 U/ i k#define L_FRAME 80
+ [+ k! _6 l" C( @7 ^8 d#ifdef __cplusplus
+ S7 X5 S P7 d' n+ q, I+ j3 G; Hextern "C" {
6 b8 M* v# T+ Y) w5 A6 [#endif- x3 X" d; }( j) N* t5 G. o7 g
void va_g729a_init_encoder();
, G( X6 C7 D) o' Wvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
' `) Y" E8 [+ d1 D5 d0 ?) v% x& avoid va_g729a_init_decoder();
" o9 h' C( A" @" h2 Y- }' ]" jvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
. Q8 E. n2 x! _, R$ X#ifdef __cplusplus ( J3 m8 E v* ~; j2 V: y, _
} , ~, r, @4 O' y+ V- ^8 f+ A
#endif3 R3 M6 e8 s) _8 Y: A! W
va_g729.c9 Y, r/ ~: L; o! I% h! m5 Y
#include <stdio.h>; a# j8 ^5 j" X0 d4 m
#include <stdlib.h>
9 g6 w; Y9 t* G( B$ B3 b; l- I#include "typedef.h"
& @3 l- ^! U% J#include "ld8k.h"! s: c' N0 w, C U) Q( W
Word16 bad_lsf;8 B- {! h* p. K2 a! z; u
void va_g729a_init_encoder()! G- }) F* D+ @) | [8 F* s
{+ k4 n3 R1 @8 `' C0 f
Init_Pre_Process();3 `0 H& K9 r7 e9 O- L, k, |5 s# o
Init_Coder_ld8k(); ' I# \/ V0 v) S7 D* O1 v
}/ c7 s1 R! B" G8 D* `1 h" q9 _* n
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)9 i0 P* e y* m9 |! ?1 ^) [
{
" y3 \; I$ R: }2 q extern Word16 *new_speech; /* Pointer to new speech data */% m, d0 q3 s+ S2 w# J0 d2 S: z
Word16 prm[PRM_SIZE]; /* Analysis parameters. */% L* s, D4 u5 F
Word16 i;6 E6 W9 ?) y6 c1 @, ]
Word16 syn[L_FRAME];8 w5 V2 c# z0 E' V/ P
for(i=0;i<L_FRAME;i++)( ^( t+ ]9 b( Q; `/ r
{1 i: \- O' g# Z8 z# ]8 O
new_speech = SpeechBuf;7 o( r6 k% x; n) z0 p
}
& M3 D8 U2 e# q0 q" S% S; Z6 l for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; 7 a1 v' H8 S$ M5 J/ h1 `* f
Pre_Process(new_speech, L_FRAME);6 C1 K2 m" R' L% {" R. l7 U* \0 y
Coder_ld8k(prm,syn);
' R `6 N/ l. Q prm2bits_ld8k( prm, serial);
+ X# Y/ z( z# t- \5 b# k4 W4 |$ o}6 s5 Y; v# h" g9 f! r. `" |0 E+ U
void va_g729a_init_decoder()' c+ l* B' P- T4 q6 J: q* I4 `* v
{5 n. t! A, _; [. g3 [8 t3 F2 ~
extern Word16 *synth;
- q* a' `- x, _3 h1 s. G `( |& T bad_lsf = 0; /* Initialize bad LSF indicator */
/ z" ?% a3 t; j f7 I% l$ l Init_Decod_ld8k();
1 M; h( R- {2 ~+ ?* j Init_Post_Filter();
- R1 @+ R0 _% u5 v Init_Post_Process();/ Z7 a/ Z; Y" s" ?2 p" _
}: p# m) J! e/ x+ Z1 |+ w2 }
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)4 N8 @; I/ O: n9 k& H; O+ B
{# \& g8 Z/ F2 `% U+ o
extern Word16 *synth; /* Synthesis */
0 Q. ?" ?5 X6 w' U" n9 iWord16 synth_buf[L_FRAME+M];0 X4 a# V$ g4 @+ @5 [3 x) ^
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
Q% K1 b9 K8 l8 q. w9 Z YWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
8 {+ C9 ` N: {# @" N5 \" o$ ^Word16 T2; /* Pitch lag for 2 subframes */* j3 X/ q; _ x" K+ E1 U2 g* O
Word16 i;! s0 a, ^2 r/ p6 v! E3 O
Word16 voicing = 60;
) t2 {8 B. d% E6 e7 W& k2 FWord16 pst_out[L_FRAME]; /* Postfilter output */
/ P% t0 N3 m; L3 `1 VWord16 sf_voic; /* voicing for subframe */7 U z% d, t+ S$ Q; M/ p
voicing = 60;
$ J# n; ? ~# T# { bits2prm_ld8k( serial, &parm[1]);
* N& t: U; a! p& A2 J parm[0] = 0;
M5 j5 O! d5 F1 N t9 x' u4 i# I $ q% r/ K, A! C
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);5 S4 Y% V% \" Y7 j, J" s( z: ]8 @
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
- n6 W Z8 F# t0 c: i* K//--------------------------------------------------; [( j# f3 e- }1 V7 w
voicing = 0;
! l' _1 j4 u) t* C' {; {ptr_Az = Az_dec;& w f w6 i& s9 W
for(i=0; i<L_FRAME; i+=L_SUBFR) {, u2 k- m" V$ y
Post(T2, &synth, ptr_Az, &speech, &sf_voic);# O* D1 ?0 h$ R4 G
if (sf_voic != 0) { voicing = sf_voic;}
6 W- X9 e+ ^. Z+ H2 b' q ptr_Az += MP1;7 M6 O) j# [; E: d' h( _
}) ]. Y a8 d& }& Y; L% j3 n$ Y
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
- M- m: r( [3 ]1 q//---------------------------------------------------
) C$ p7 `/ ^6 v* y: I Post_Process(speech, L_FRAME); ! S* r4 i+ m7 x6 p
}) j/ i" W6 f) l' T8 r7 g2 G
1 L9 F7 e4 C) R7 w# @3 O& x
|
|