|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/" f- @- q1 h4 K' |. W! E# I4 a
下载以后需要修改bits.c文件:
x) b* c1 y6 n) b9 L& P/ o/ @我仔细研究ITUG729代码后发现:, D5 X1 Z' u- [- l. X% w
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
- l a; c. i& i L% c! o,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
9 \% ?/ x {5 L# R4 y6 M; I4 T4 p6 j- N
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
7 e: q( D6 K0 }5 u2 p9 O: R
7 h: P3 z# Z: @! G) ^8 v那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
% @3 E% \; o% [; I1 |! k! K我们打开bits.c,就能看到里面定义的如下4个函数:
4 _8 d1 p) X7 q. p0 Y. gstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
' i" {9 w" j/ e: ]/ \* vstatic int bin2int(int no_of_bits, INT16 *bitstream);9 d# m" e# M7 K& Y3 x! S
void prm2bits_ld8k(int prm[], INT16 bits[]) ; 7 P- p/ v5 t% q6 ]& B% C0 F* g5 ?5 r
void bits2prm_ld8k(INT16 bits[], int prm[]) ;, A7 ^2 q2 E7 U
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
! z) ~' V+ r0 ^: Q; H, X* u) V( n7 K' }static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
$ b+ h8 v- n2 p, m4 p" P+ @static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
1 u" v: Y; G' @' m$ ^/ {; o6 e5 i% S% k ~1 Q Z5 {
void prm2bits_ld8k(Word16 *para,unsigned char *bits), } R& i7 u$ C/ i+ I
{
2 [1 u/ V! P* d% O7 ~. @- O int i;
; y% u$ H) c: r1 P6 q/ o ]( H int bitpos = 0;
- Z; w7 m9 |! G# p for (i = 0;i0 f! w, _5 [" x- H S
1 W' @9 @4 ?) K2 }7 Q. M( svoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)( N0 `! h% b. M
{
! _ f, }/ E" w- b6 n9 T5 u int i;
- u# _# t0 l! L4 Q int bit = 0;
# B& W8 v6 ?7 J' W/ g5 D unsigned char newbyte = 0;
% \4 r: G5 n+ {5 l
/ ~4 v7 `. Q& A- h2 z4 l unsigned char *p = bits + (bitpos / 8);
' [ D' p9 q9 Z# C. g& C) z# T for (i = 0 ;i > (bitlen - i -1) ) &0x01;
; |6 \( r# {. b. Y) q( P4 c unewbyte = (1 % s4 D# d3 z. v2 b# m! O/ U& R
bitpos++;
" k1 \( l9 s! Tif (bitpos % 8 == 0)
; z$ E5 @" ` |) L p++;5 h6 h; @, C) g+ l: ~
}
5 T i2 d; y8 Y2 i! X* s8 a2 {}5 c4 n( N( ]8 g) f4 K
/ B6 h8 ]% e- J) R, S3 d
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
; ~. Y0 o/ q- ~) f8 r{
; q, S: E$ v5 s9 f, g int i;
) Z/ [* U9 g' d2 ]* s, R) b int bitpos = 0;
$ @ Y; f9 j, o" H8 P8 [5 I for (i = 0;i
H8 P, ]6 _* q* @' a1 ]
8 z, W# ~7 A3 Y1 NWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
! O% d. x" ]/ l9 r3 F{7 x# F8 M7 d6 j/ F+ T6 A( N
int i;
# i: F- Q9 u9 J9 R, ]' i/ x+ o5 G int bit = 0;* H, K, x% D3 R/ Q7 O$ g- ^ Z
Word16 newbyte = 0;
! Q; N( L% @! s' a Word16 value = 0;
; l5 N. \0 q% H4 \8 c1 X# i, y
D/ U' t1 Y. K unsigned char *p = bits + (bitpos / 8);0 I5 @" j) Q& w& m2 f
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;! `* V( W" g# u l" B! `
if (bit == 1) {$ g0 _5 `3 ~8 {( P* Y0 K
newbyte = (1 " ^# y! C- O2 N& c1 W1 C( A& ^/ ]
return value;1 M' O' d( ]' T0 x% ?7 u( a& S u3 t
}& w7 `9 i& Z0 O0 K i
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
' i4 z8 a9 R) w$ P' B+ K2 J' Z4 o, f, c' X5 G
编码器的代码能采用如下的修改方法
: C. m3 b4 R) Z% j! m O; K(1)修改coder.c:& Z$ }1 [3 ~' N4 s" ?" F: [
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */# P5 F* Y$ o, A" ~9 K- N
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
5 S7 z( M% m) |* D frame =0;
3 y; B- d/ }3 i4 g while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME); p; a: G: z' Z- [
{5 o, y U& o8 ]& R2 }
printf("Frame =%d\r", frame++);1 O" M3 L5 V5 H1 a9 p7 C
Pre_Process(new_speech, L_FRAME);
: W5 I$ X/ X' `# Z$ B" h/ A# ^Coder_ld8a(prm);' C. w" `9 x {9 K+ I3 W5 M
prm2bits_ld8k( prm, serial);
7 E2 j- a6 G% Z1 s' @fwrite(serial, 1, SERIAL_SIZE, f_serial);5 g0 e6 |: o1 C$ o0 R
}& o! O& U: l1 ~
return (0);
- f" [. k, [% L6 g! H% K( t4 d
% s, _9 \/ `% }% f) c(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:7 @$ b# c j$ u) u
#define SERIAL_SIZE 104 t) z1 [: G) S+ ^9 w
" R: g7 \* o v/ N8 G H- a
(4)解码器decoder.c进行类似的修改(关键部分代码):
* h. g" p" L& f1 o+ r( c frame = 0;8 O/ q4 O& d. g2 p" s0 j; j
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE); `5 h% J0 {6 N# D F! J1 l( p/ D
{
5 T3 L% G% `" w% m$ l- Oprintf("Frame =%d\r", frame++);( w4 v& b; ~: V1 O7 s; v/ R1 Q) G
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */5 _, R% B) B4 w2 F
parm[0] = 0; /* 假设没有丢帧 */2 r* ]* G9 @* Y }8 t: k
parm[4] = 0 ; /* 假设数据效验正常 */
; N& y8 [4 @9 y. C- b0 ?* |4 _5 N( fDecod_ld8a(parm, synth, Az_dec, T2);/ n# A- T. V# E, W) Y2 K" T
Post_Filter(synth, Az_dec, T2);
* X" N# ~ K- G8 p& O& i6 JPost_Process(synth, L_FRAME);) [; {) Y; f7 o8 [# ~- h7 L3 C
fwrite(synth, sizeof(short), L_FRAME, f_syn);7 u! T( X) p7 ]0 k. N+ `5 X
}
! s3 e5 j$ V! e& T return (0) ;
5 I8 \ p3 t6 t7 D. d通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。, c5 f0 b- x' b, |
3 i% W& f6 j* a, P8 K; O; [/ h
修改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]得到,应该就能了。; u# l4 `. p) m9 `
封lib:
) ?$ x) i; Y# h6 {$ d' I. t5 |0 H5 uva_g729.h5 k9 m4 a4 |2 ? m% B" z
#define L_FRAME_COMPRESSED 10( _/ X4 _2 U* G
#define L_FRAME 80( r3 `! C+ ?8 [ F& B" U" D& N
#ifdef __cplusplus
! A, l3 Z1 \" U9 L7 y# M0 k4 Iextern "C" {
. p, q8 r5 a0 W; \# @6 S: S+ c#endif
* x, y$ f2 Y) I$ Gvoid va_g729a_init_encoder();+ l( g0 n, `8 X( A7 [: x& f# D! m3 d
void va_g729a_encoder(short *speech, unsigned char *bitstream);6 I9 ~8 c1 Q' l$ V
void va_g729a_init_decoder();4 f: q2 m! B3 e+ w# G: y
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);4 _- l% L1 Q. U, @* s0 Z
#ifdef __cplusplus - l4 g3 E2 v, b7 A
} 4 C2 y. P! X! k, V
#endif. T0 P# W: i3 N! y; i* q
va_g729.c
! w2 y7 R$ Y& |. Y6 y( ` }#include <stdio.h>
3 _5 U* J4 m. @$ }9 l! L#include <stdlib.h>, c& D$ Z- O3 x* V& K. ^
#include "typedef.h"$ A; k. I5 G* b: F+ N
#include "ld8k.h"
8 w2 k# o7 R' I \# YWord16 bad_lsf;
4 W( D/ M+ t) a* F2 V3 Y: F! \( \0 {void va_g729a_init_encoder()! r# |2 w: Y' B+ ^0 t
{
, A5 o3 c# X8 w: {5 j# c Init_Pre_Process();
$ {+ q1 ^/ P4 h Init_Coder_ld8k(); ! a1 y& s! r6 i2 k2 i, l
}
* g% Y4 a# ^8 b2 R+ a' V+ v7 k6 m5 Vvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
% C: W) g- ?0 [4 ]( b0 O3 q{ 1 M0 {9 `: E% V/ v1 r
extern Word16 *new_speech; /* Pointer to new speech data */3 q& d" j' l W. G% X9 {7 x
Word16 prm[PRM_SIZE]; /* Analysis parameters. */$ ~. G. n5 t, P) ^0 [2 V
Word16 i;
% g' Y/ N6 J4 W3 P. vWord16 syn[L_FRAME];) @& ~6 c3 U- y1 F2 B' b$ G
for(i=0;i<L_FRAME;i++)7 j w% g$ q5 |8 j8 W( a" J$ e
{% J, b" `3 d6 U" k9 W
new_speech = SpeechBuf;
5 ?5 y3 P/ v; |0 B! K! z9 z& I}; z- G4 H# f. D" n) [$ {
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
0 G; \2 L' ]9 M1 J9 q& }+ ?/ z Pre_Process(new_speech, L_FRAME);
4 U- q8 X+ N! U6 W0 V% ^+ G$ G Coder_ld8k(prm,syn);
M0 {6 H* q& Y2 @7 {0 x prm2bits_ld8k( prm, serial);
/ k3 R2 e6 P4 H. i/ _3 m}' {/ H' E6 l. m9 E1 g
void va_g729a_init_decoder()
, _9 e# u( x- c' F4 U! o9 L{' p7 a) a( o- I$ K: \" j0 F% G" A0 y
extern Word16 *synth;
4 {) ~; |9 v' h1 v3 h bad_lsf = 0; /* Initialize bad LSF indicator */) I; Z1 {$ h5 f$ X3 O' F2 |
Init_Decod_ld8k();
" _ }' z) C5 i Init_Post_Filter();
$ j* b# |$ T* [8 o$ J1 [+ Q/ i, S Init_Post_Process();
/ _4 P. u% X/ x3 N" C}; D, Z" k I& W, G
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
+ g" K" C! k# M: w* _9 ?{5 Q2 A, h) x. ^+ p7 u% i( _: O
extern Word16 *synth; /* Synthesis */6 n/ J. B1 s" H( D* E) V
Word16 synth_buf[L_FRAME+M];( t( t+ x* }% f `6 s) x: |6 C
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */) A6 U: r5 v3 r; l( B
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
3 C3 l4 \% k' o3 z, h; d$ XWord16 T2; /* Pitch lag for 2 subframes */, @% Q5 k& \# v, L
Word16 i;
" ~3 R8 q4 W; ]4 P) E) T/ S9 CWord16 voicing = 60;
9 c3 l( b% c2 v% ~% L+ Q: JWord16 pst_out[L_FRAME]; /* Postfilter output */
/ T9 n/ n* T# KWord16 sf_voic; /* voicing for subframe */
4 S% D: D" r; M' k6 K9 Rvoicing = 60;
' W! ` ]+ F* I C! a' Y bits2prm_ld8k( serial, &parm[1]);
' s+ A# ~9 l0 L+ @( i parm[0] = 0;
5 @1 x3 }" q: ]+ z% R# a" r
, x7 S( e2 ?; v' h1 q1 f& N- `9 ?" l parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);- \9 ]6 X7 L# w6 y. m7 f
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
" U# w) o; k4 E' i& U6 r2 [//--------------------------------------------------
N- d; l1 C; ]- G4 o* F4 _voicing = 0;
1 i, N4 K1 O6 S$ F2 O3 m5 gptr_Az = Az_dec;" m- _, R/ p; y) B6 m
for(i=0; i<L_FRAME; i+=L_SUBFR) {
! J$ i: q- g. |9 l- L6 `2 e Post(T2, &synth, ptr_Az, &speech, &sf_voic);5 |% d( Y3 m; J8 [
if (sf_voic != 0) { voicing = sf_voic;}/ b) H, `7 G. V1 `! a
ptr_Az += MP1;
( e3 L3 j: a, Z2 b. P) Z}
/ X0 H1 x; V9 j. O# ^Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
; Z/ P0 z2 R, }" K: {//---------------------------------------------------. M4 e& E$ P* ] N& g+ r5 I& ~
Post_Process(speech, L_FRAME); % ~. r$ n7 V7 p& A1 R
} a( r# T! b/ m
1 M( W3 h- w M9 ?9 D4 a3 U- n! p5 _
|
|