|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
( k7 a; U* [' c4 W下载以后需要修改bits.c文件:
0 N' y0 ~9 S: P4 o我仔细研究ITUG729代码后发现:
' z( { C9 q0 A8 {编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
( ?2 s, V3 n+ [* X$ V. V ]+ K,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。9 D8 W9 I8 f* i' f1 Q1 o0 Q
' N2 E+ S; G8 E- A0 G' S, t- [ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
' |2 D# A( ?0 Z/ S" `( c
& B: Q5 p B" u/ R+ j那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
& e) S' N) G6 F2 A, V. I我们打开bits.c,就能看到里面定义的如下4个函数:
8 f# D' q1 g$ y) R5 G) u5 {% {static void int2bin(int value, int no_of_bits, INT16 *bitstream);8 Y0 e# m3 h" G2 |+ i
static int bin2int(int no_of_bits, INT16 *bitstream);
6 h; `4 b* z+ E3 S/ |( Rvoid prm2bits_ld8k(int prm[], INT16 bits[]) ; ( b5 E2 i; z" _" c$ K5 I: z
void bits2prm_ld8k(INT16 bits[], int prm[]) ;0 T% i* e' I+ Q% @% Q4 i
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:5 v5 C5 r1 p. ?+ @2 f8 a# r
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; y9 A: `6 z. f0 c3 ~) c
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
! c5 \% B; X T+ h. I$ n, R1 U7 E# N" m1 k H/ ~6 [" u& u
void prm2bits_ld8k(Word16 *para,unsigned char *bits)7 W @, N' X7 ]6 _: H
{
+ x0 Y8 L# _% X/ q* M! J" Y int i;+ i$ e7 R8 Z) Y1 b, M
int bitpos = 0;
o: Z6 K. ?& u5 X/ u% M' [ for (i = 0;i* r2 I, |- o" n, Q% x. Y
( O3 g7 g- t% m' ^$ R1 V% k" j! \
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos): v7 D- ?' E4 F+ K3 ~2 i
{4 z) p4 f% o) w# ] H6 Z* A# Z* H
int i; H1 ?" A& _5 Z4 R$ t7 p8 A! Z) e
int bit = 0;
2 T' f; |; S/ _9 M1 P n' w unsigned char newbyte = 0;1 H6 i% [- E; O' W6 u
( G. L# V7 C. Y9 O8 n: e
unsigned char *p = bits + (bitpos / 8);
2 g1 F+ D& T' X2 A/ `1 e6 x for (i = 0 ;i > (bitlen - i -1) ) &0x01;+ Z9 N3 r4 u: v: ~4 W& V0 u
newbyte = (1
+ y* _& X8 T% ?bitpos++;$ ~7 v0 N! D% D9 W4 M% t- P; P
if (bitpos % 8 == 0): |4 [. w; l7 t9 [
p++;! d5 T+ a6 K! j8 h" Z: f" F
}# {0 r/ w0 \3 m0 w# f; L
}9 _! Q4 n+ Y( [6 B
- I7 Y5 r( r+ @6 s+ Mvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)/ b) U$ V5 b& T
{
7 M9 J8 m6 n- _' a6 V$ p/ e* q int i;
6 T6 O$ e/ [ C& c7 D V( ?6 [ int bitpos = 0;$ D+ |: ^) R+ p( W: S4 Y8 P# T. Q8 Z
for (i = 0;i
4 g. I. l4 r: D k! Q1 G$ X l2 b: N+ e* n# @9 A7 {
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
$ z4 l7 _8 s h% R4 Y{4 N6 x- T D6 B3 ^
int i;8 W$ |7 E! ]2 Y% `- I* r$ c8 X
int bit = 0;
4 k2 Q8 ?. K/ i Word16 newbyte = 0;
( Z; b7 m+ W: E9 B# K% ?4 ~0 p Word16 value = 0;
/ ?, Q# k: B9 o* x: v 3 F6 [! ^7 V: Q1 H- W. g
unsigned char *p = bits + (bitpos / 8);0 ?& ?- L' P) b
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
G+ r6 X% G {+ \& i1 p5 c( R Mif (bit == 1) {/ e8 m9 Y" |4 F
newbyte = (1
: n! }' K- d/ H return value;
6 y2 n9 y* O" T; S8 G- W} B" W3 i$ |! j/ i; r
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
- p1 a0 {, Q. G, e! F0 [
! ` m; `' y) u编码器的代码能采用如下的修改方法
3 Q4 j, u2 l$ ^(1)修改coder.c:8 e+ o) G4 V1 G* w c8 R: V
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
) q* _- p$ S f% m# K3 H# p. ~(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
$ m) r; M7 x3 Y, Y P7 q) r: u frame =0;; k; W; M/ w2 D+ R! Z+ H
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
+ A+ U9 d! x; Y) K4 j2 B) ?! a/ u. D {" Z4 V3 }* x! [5 {6 l h9 i
printf("Frame =%d\r", frame++);
4 u% e, r2 `3 r5 X; l. a6 K! C$ n( mPre_Process(new_speech, L_FRAME);& a/ e3 X5 X0 e
Coder_ld8a(prm);7 K- D1 k( |3 C# P* Z: y
prm2bits_ld8k( prm, serial);
8 F9 y) ]1 u R6 D' N Gfwrite(serial, 1, SERIAL_SIZE, f_serial);
. E) Z- j- o$ c' r3 v8 | }! J* \; S3 b' n! _ }- v: e
return (0);) Q) ]: k* x. _
' G2 a6 Z9 Y+ f; a/ v
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
, w( A; _5 v2 P1 i6 B4 S9 a#define SERIAL_SIZE 107 |/ ?" Q9 d8 g. P! K) n, n
& P( k! e- l' e; }(4)解码器decoder.c进行类似的修改(关键部分代码):8 R6 f: J( T6 ]- M; X, y4 X, k7 t$ T
frame = 0;
! Z9 J' V/ }9 ~ while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
, l4 Q* w7 J1 ?9 q# c {( q, J& a# R& t2 O" K1 a, h
printf("Frame =%d\r", frame++);: _6 t0 C; N+ Y9 T; _7 r
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
7 I6 N3 H" Z+ d" n# Eparm[0] = 0; /* 假设没有丢帧 */! F) W" _ T0 I$ J3 x7 C
parm[4] = 0 ; /* 假设数据效验正常 */
3 N2 l! N" f( w1 pDecod_ld8a(parm, synth, Az_dec, T2);
- E# d6 ~7 n9 E3 hPost_Filter(synth, Az_dec, T2); ' e: A/ E% S ~ P' ~8 h6 h4 ^/ @2 ^
Post_Process(synth, L_FRAME);, U& a/ Q0 J/ Y7 K6 G9 a/ l
fwrite(synth, sizeof(short), L_FRAME, f_syn);
! ^" o# ^8 h: e" }% J# r }( o1 {. r/ A6 d" l: n; ~
return (0) ; 1 `8 O1 Y, {6 y) g5 Y1 Z
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
' X' T# q" V8 l* f$ L) J, \5 E `
' ~; C, i0 B" A/ ^; `修改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]得到,应该就能了。
. A/ o4 E0 \! z5 j7 }2 W封lib:
( T* C& A! Z; A9 F: X1 Uva_g729.h6 G: o0 Y) n3 O0 O' n
#define L_FRAME_COMPRESSED 10
6 g% M1 ^2 }1 A0 L4 E! J" c#define L_FRAME 80! v: e( I3 V3 F# C! v
#ifdef __cplusplus
/ h1 b8 q5 |- `extern "C" {
* B0 \- y4 W) C+ w% T6 k1 K b) G#endif
3 Z' C8 m& a! X7 }' N; X( _8 svoid va_g729a_init_encoder();
' w* j% o# u% c; u4 V5 mvoid va_g729a_encoder(short *speech, unsigned char *bitstream);0 `( q$ g/ H4 g+ r0 o" K8 R* e# v
void va_g729a_init_decoder();. ]: } h% {4 [5 I' @; h* G. a
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
. |) {& m0 g3 q6 I7 q#ifdef __cplusplus 7 `0 f2 J; e1 P4 I+ D
} " h7 R# O& w$ u* f
#endif
- d# c' x1 g+ I R- Y1 {: A( G" xva_g729.c
7 f' s, O5 Y' g0 C/ l#include <stdio.h>! s" P8 [. K) n7 t
#include <stdlib.h>
0 { }2 C+ x8 I* K5 A4 S4 {/ `#include "typedef.h"3 S$ J# I8 b& ~1 J* a$ T5 B/ j4 j7 C
#include "ld8k.h"
8 r- \7 v7 i0 N! `Word16 bad_lsf;
3 a* m1 I# J& |' @0 t4 `void va_g729a_init_encoder()
" o" G% P1 R) v{
3 `% S+ t" X" O7 A* H6 u Init_Pre_Process();
0 d S- T9 E7 M: D7 Z Init_Coder_ld8k(); 1 s( G" H! s2 C/ f- l s. [( `
}
% j, i$ {% x2 e2 `void va_g729a_encoder(short* SpeechBuf,unsigned char * serial): y* n& q S1 N6 p# m) ^
{
4 b' Q m) D8 ]+ g extern Word16 *new_speech; /* Pointer to new speech data */+ \: D5 Y' c' m* [, a& u; V# y! ?
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
6 s9 h8 S6 P6 }3 { Word16 i; T9 m e( G( A
Word16 syn[L_FRAME];
+ t9 c3 S1 S& d. V7 I for(i=0;i<L_FRAME;i++)
7 @5 F8 C ]9 E4 y" q2 ?8 N; h{( m6 n/ B) q' q" ^
new_speech = SpeechBuf;4 t3 F; h @4 _ W# K
}& I& K* l2 T) P6 L, \& T& f9 Y
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
! f; L5 `0 \' |' M! f- c( H Pre_Process(new_speech, L_FRAME);
( C" n8 s; ?7 Z0 Z5 N) S3 I$ E Coder_ld8k(prm,syn);; \: |) r6 M$ q7 Y
prm2bits_ld8k( prm, serial);
2 o0 }! n0 w! V4 w}, ^) L, f" C0 \. V9 A* {5 m: h. Q
void va_g729a_init_decoder()
8 Y2 r3 P3 V5 d+ k, t+ o9 Q5 u3 g{- w W/ u" n7 o$ Q5 o
extern Word16 *synth;
9 d- r& [* Z5 Y# P5 G bad_lsf = 0; /* Initialize bad LSF indicator */
2 w: A- Q! D" [9 E0 k1 K Init_Decod_ld8k();
' s: [2 j; d% I& `; _' I% M Init_Post_Filter();
8 U* L' N7 ~6 Q' X' F Init_Post_Process();' E c! i3 n1 @& s' H
}& ], k, m- F% F) |; U
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
7 W i0 C$ x4 z% K( S{
0 M/ z! ~7 M5 D4 r% |extern Word16 *synth; /* Synthesis */8 \. g, i- O* K8 H8 L: q
Word16 synth_buf[L_FRAME+M];; j$ m; N/ r/ t
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
* d `7 B7 h' E6 i* J- lWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */3 d& c. S% p" A4 F4 d9 u: I
Word16 T2; /* Pitch lag for 2 subframes */
1 E7 }' o( b* ^5 b' D# f4 ?Word16 i;
& c/ |) i# b1 A1 ^9 JWord16 voicing = 60;3 }' s+ m6 H& K! Q/ e
Word16 pst_out[L_FRAME]; /* Postfilter output */
% _8 e8 [" a" p1 D' BWord16 sf_voic; /* voicing for subframe */
: z: Z% j" w% i/ V; R& w8 Vvoicing = 60;
! P% j% X# x; G bits2prm_ld8k( serial, &parm[1]);6 {4 C9 \5 M* m+ j0 e( [) Q
parm[0] = 0;
3 l4 v; i2 }) Y7 m 3 V& S9 V& o4 F' P" n* g" M
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
# Q [( ^7 v2 ^Decod_ld8k(parm, voicing, synth, Az_dec, &T2);* L' d1 h6 ~3 k- e. k
//--------------------------------------------------. b8 A* B) A$ Q, c- ~
voicing = 0;2 n* S* n. l1 ?, r' J8 z: O2 M/ v
ptr_Az = Az_dec;
& H8 o# W; v( @* i$ f Z: ^0 L6 Jfor(i=0; i<L_FRAME; i+=L_SUBFR) {* F0 ~, C% I5 O. L* @# Y7 n
Post(T2, &synth, ptr_Az, &speech, &sf_voic);+ o5 C$ k& s& G* v
if (sf_voic != 0) { voicing = sf_voic;}7 }" ~+ G) G% w) g$ L3 I" a
ptr_Az += MP1;5 |" }% ^# A' Q1 o: H
}$ ^- R6 e" Y& D) L( H1 `
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);5 _. ?2 S' n8 @
//---------------------------------------------------
7 b5 i- \( {) e+ c; v6 r Post_Process(speech, L_FRAME);
7 L5 N. p- X7 p}% v' ^1 N- z; V2 o6 p5 K; D
7 K- I! E C( R# u |
|