|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
" D D4 |3 X* a% x6 v+ n下载以后需要修改bits.c文件:. W) T6 P4 O& f, ^
我仔细研究ITUG729代码后发现:
4 ?. K( \, Z# L编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
8 N+ \* p8 b$ a+ b,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。3 `( P0 ?3 u$ u" N5 d( [- w
3 r& `+ J/ v9 b- @$ k" `' C z" ]/ N
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。2 s V0 P9 v* L @" R
5 z* s3 N/ s+ Z& H4 I
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。; h& e8 ]4 B: t* Y
我们打开bits.c,就能看到里面定义的如下4个函数:
5 k' n9 ^! Z1 _& N6 n, J8 nstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
* ^ e, b: o* C" G$ Nstatic int bin2int(int no_of_bits, INT16 *bitstream);
1 B2 A# D& I- O) G4 Svoid prm2bits_ld8k(int prm[], INT16 bits[]) ; " a; R7 h/ s9 x
void bits2prm_ld8k(INT16 bits[], int prm[]) ;# c; y8 l3 Z$ I$ R) `. w3 \- i
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:3 k% a9 y( P- p
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
5 r( x& f- s% u4 Y( P* Istatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; ; [: A$ \8 J" v. n5 ~% a' U
# z% Z+ D7 z6 @void prm2bits_ld8k(Word16 *para,unsigned char *bits): N( G. E* w0 ^0 P" h- I9 [
{
# m" z( y8 k* {' [ int i;/ H, W. w5 E3 o$ s* Z
int bitpos = 0;
* o4 r/ d0 ?' b" B, j5 C& b. m for (i = 0;i4 c5 J9 b" l1 A0 s, w0 x7 l1 h
2 J9 R7 v" {+ b( k8 e/ l7 Uvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
) r9 T* `7 e- `1 [: Q4 D{# F8 T* [; N5 e0 r1 O; O
int i;
\) j7 c- ^" L/ `2 q int bit = 0;
+ R' P2 ]3 s( d$ P5 i6 e6 f unsigned char newbyte = 0;/ r/ J# h( A/ r/ i# N! A, C6 I
! W5 R. ~7 `+ i" }8 k/ [! v% |+ z% | unsigned char *p = bits + (bitpos / 8);
1 h. y2 }4 `2 ~% v8 U& v/ w. p/ t4 E1 Z. p for (i = 0 ;i > (bitlen - i -1) ) &0x01;$ t9 o: [! \! j; V( M2 R3 b
newbyte = (1 p. y. o0 @9 n1 I4 \8 V$ w9 q
bitpos++;
! I" v2 O0 H8 f$ u1 ^if (bitpos % 8 == 0): j& p. W8 l( C8 P
p++;
- t4 A1 A. i' |8 ~' ?( K }% W# `8 `* l) X6 T/ U' P
}
; ~% h, T# W) {2 d2 T/ @" Q( J7 F+ v! y
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
! J0 R( {+ d: P+ C2 B# L" l{
: T e( f& S/ W2 r* H: [& [' M! N( P% w int i;2 \& J! y( g; q8 m0 @$ O
int bitpos = 0;
' D* C1 J6 v: Z* S for (i = 0;i
, K4 y* s; Q5 F1 H6 }7 ?$ p' i9 i. |- K& C4 S
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)& f! S; e) B9 \8 N2 C. b7 e8 {
{3 d! d& k7 Y. J3 i$ k
int i;; V! n9 W2 p8 h/ ], S) j8 _
int bit = 0;
9 a6 e- A+ r1 ^ Word16 newbyte = 0;
3 h* m1 |8 {8 e" b# s, n Word16 value = 0;
" Z) p5 O) W6 \ # a) I. L# c( D. _/ _) d# F2 W0 S
unsigned char *p = bits + (bitpos / 8);- H4 ]* G( \, y6 T
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;& X- n, r( T/ d2 Z6 \4 M7 e
if (bit == 1) {
5 p8 W' l) L: K" G9 k M- e newbyte = (1
6 L# U) ~3 F0 g* C% C: S3 a return value;% ]) N d, L( s/ z
}/ w m c* ^7 f# Z4 n- [
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
2 L( {4 e! D% w8 v" J. x1 W8 H# T2 ` ]2 i
编码器的代码能采用如下的修改方法+ F# g8 A6 f4 {; C# [
(1)修改coder.c:
/ I- t9 c! q9 _. junsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */1 l/ c3 l0 d/ {7 X
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
7 N- @6 y" }) L- L7 @( O frame =0;7 R& D2 [2 E. S- ]3 e; ?- H( N6 R
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)9 ?. V& p+ @; f# M. s
{% g! v# I7 s% n8 I
printf("Frame =%d\r", frame++);7 u2 {# n# h5 U4 O8 h7 n. n
Pre_Process(new_speech, L_FRAME);
/ B7 \, o T2 O2 x4 U& ?7 zCoder_ld8a(prm);
6 U1 e% q! A) d% E! {prm2bits_ld8k( prm, serial);
6 }- V# } A+ I. }2 t# Tfwrite(serial, 1, SERIAL_SIZE, f_serial);4 ~7 h! D( O7 \4 L% U+ a @
} u; r4 h7 J- d/ K9 S* x' L
return (0);/ e- ?& r0 Y) B0 z
: r) H- {9 u! m. a N, Y" }
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:8 K8 G) j# j$ y( I
#define SERIAL_SIZE 10( I8 i- @7 {/ h/ v' Y1 j
$ @( J5 y$ O- T5 n+ y& X% _" G+ Y
(4)解码器decoder.c进行类似的修改(关键部分代码):2 w. o4 n# i5 W! e' F
frame = 0;' U* [& z- N* J2 l3 u
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)9 n, L5 a3 f2 |) C* i% I: W9 x! N
{
+ [1 _ c' T, g" g e1 M2 Kprintf("Frame =%d\r", frame++);8 P8 C. [. X. ^1 I8 B7 Z
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */' ~' r% o: O8 O5 R+ e% j% r
parm[0] = 0; /* 假设没有丢帧 */7 Z' y# J. A8 K j2 D. `$ t- O
parm[4] = 0 ; /* 假设数据效验正常 */
' {; D3 |; h; }( JDecod_ld8a(parm, synth, Az_dec, T2);) m! p, l: d" \# s+ h
Post_Filter(synth, Az_dec, T2); 8 w! N# V5 w- ?0 J1 s
Post_Process(synth, L_FRAME);
! T" l% ?1 s) |# C/ i0 d7 ^fwrite(synth, sizeof(short), L_FRAME, f_syn);6 T9 N, m, F, e3 c* A
}
, s% Q7 C/ y; D% H# }# N6 a return (0) ; 9 l! X0 Q9 |2 d1 {/ ~9 W7 C
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。7 ?. ]6 I: _ T6 F% t, }
& E. B M8 ?: O& j. h- Q修改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]得到,应该就能了。1 g! U# `2 I; t
封lib:
; l, e; z/ F4 g8 Zva_g729.h4 E! A; l6 O1 H- C8 u$ p: [, Q
#define L_FRAME_COMPRESSED 103 @# h; a* U/ l$ K4 z9 a; ^
#define L_FRAME 80
3 d3 m% z. b7 R! ` ?#ifdef __cplusplus ' Z- D# O7 H4 S4 M. r
extern "C" {
U- _" T4 E+ v: ]( Y+ S: G5 x#endif
' m% D0 E( `+ b$ ~* S/ Gvoid va_g729a_init_encoder();
+ p) h7 F( |+ Y' Uvoid va_g729a_encoder(short *speech, unsigned char *bitstream);1 v+ R2 O" g7 H. n, r1 K
void va_g729a_init_decoder();
+ \2 f( Z4 D% u: v- Cvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);& G. ]+ M4 H1 p% s" ], ^
#ifdef __cplusplus , J3 X, u7 _" q: J1 D ~2 O
}
3 N1 ^5 z+ n) H/ C#endif3 a, _0 W% t. i
va_g729.c
& U# a, p$ m% U) S#include <stdio.h>' e# [3 X9 s2 l) D8 I- u1 J
#include <stdlib.h>
3 z" p0 F3 Q! W; c- i#include "typedef.h"
4 ?! W3 P; E; I#include "ld8k.h"3 t# i- G! r/ Z1 ]- t
Word16 bad_lsf;3 i6 z& X/ Q! D0 m, d E
void va_g729a_init_encoder()
# R3 o( ]) U0 Y4 L- d# d{
+ n* v# A$ Y. o5 _ p% i Init_Pre_Process();
8 J( T7 H) B0 t% ? Init_Coder_ld8k(); 5 _( v+ F. X8 q( d5 P/ t- q
}% j5 f# y5 K; ~ Y- F8 V- i* \4 W, ^
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
8 R: o6 f! l* [0 b, y" O{
! p+ d, I4 G: I1 q: }# ?' L9 P- x extern Word16 *new_speech; /* Pointer to new speech data */0 U; o4 y3 R) z q3 B) z1 ~& [- X
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
( E. M1 q* d# ] Word16 i;* K% U% O3 p) J U$ V
Word16 syn[L_FRAME];
( V6 E5 ]- |' t3 `4 E* C2 o for(i=0;i<L_FRAME;i++)& u" l7 o3 l. J
{
" q; K6 Y1 H6 \ new_speech = SpeechBuf;
z% y0 I# e; N8 i3 x% n: Y}
9 k* P, I0 Z k' i for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; - |: L6 v" Q! v- i% N2 y/ [
Pre_Process(new_speech, L_FRAME);" X* m0 l% J1 [6 J; b8 \0 H$ w
Coder_ld8k(prm,syn);
3 E% W9 Y1 a8 N# z) ^" U6 D prm2bits_ld8k( prm, serial);4 W4 c% K/ @. v
}9 _: Z3 l4 \, J% n( _1 X( C3 ?
void va_g729a_init_decoder()
8 P" j7 l8 D7 ~6 k& P/ ?{* e# p- G5 ]5 x% X
extern Word16 *synth;
' d% ~# r m2 o# O5 j9 n+ x6 @. z bad_lsf = 0; /* Initialize bad LSF indicator */
# o8 `. H% m2 g8 z% L Init_Decod_ld8k();* u5 M$ @4 s. D7 F
Init_Post_Filter();$ [9 z5 }+ ~3 L
Init_Post_Process();0 |$ X* n! a3 F' y! a
}
6 K. X7 o/ ], |7 h% a$ Yvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)/ `6 ]$ D$ l5 n* i& n$ H
{" M8 q$ D! u5 W9 J7 u* |4 M( B
extern Word16 *synth; /* Synthesis *// m S/ }8 W S) ~$ @ Z6 B
Word16 synth_buf[L_FRAME+M];
' {% t* `* L, k( v! W! lWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */
8 ^3 C/ o# G" q8 t4 ] z: ?+ aWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
2 B8 W& _# I0 D. R6 UWord16 T2; /* Pitch lag for 2 subframes */
) z0 n, [6 f& l9 |7 ]Word16 i;% O7 x; m* w6 z g: |
Word16 voicing = 60;5 t5 O, A1 {$ Y4 n
Word16 pst_out[L_FRAME]; /* Postfilter output */
) b _9 l' h! h. ^2 G- U9 i o& X2 gWord16 sf_voic; /* voicing for subframe */- {) g& O( i3 L2 T8 H& A" w
voicing = 60;* l- P$ h& k8 V) N
bits2prm_ld8k( serial, &parm[1]);- a- W2 e4 t" x
parm[0] = 0; # F2 j9 c( d0 R+ W
; o* y6 I8 f1 C: B* l2 I5 @4 y! {
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);4 @- [" R/ `, }
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
/ E% ]- j9 M5 ^8 l' g//--------------------------------------------------
1 S+ g |7 l& j8 T5 J& R' |$ X) xvoicing = 0;
; g% i/ z. ]9 K9 e( C/ |2 ]ptr_Az = Az_dec;
6 ]) A( f% t) N6 Cfor(i=0; i<L_FRAME; i+=L_SUBFR) {
3 ?0 V5 C* }0 q f, d Post(T2, &synth, ptr_Az, &speech, &sf_voic);
2 [! [: j/ e! E) t; N- ` if (sf_voic != 0) { voicing = sf_voic;}* [+ f: c+ d8 |. ~
ptr_Az += MP1;" h; r( N2 E R& W1 Y1 |& j
}
9 D, u, S6 l3 {Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
8 W) c* ?' ?! h) T//---------------------------------------------------
) `1 `4 Z a w. c Post_Process(speech, L_FRAME);
5 K; A+ }: a& }5 }4 t3 x4 }}" x% x- Z7 R) m6 |" k# l
8 t9 o! B' p, U |
|