|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
. b; e% x/ T5 k! S下载以后需要修改bits.c文件:
. y/ y8 ?4 H4 p, s$ W/ R我仔细研究ITUG729代码后发现:
6 T8 S! B7 u: k. }+ _- f/ B; a7 |编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流1 i: `7 w5 J. d1 @2 p8 w% G
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。# W. L4 T7 l& U& E, I& Z& w( p( X
, W q$ h: T- I& t
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。& l7 s7 m" `0 b: g6 s2 \( w) f! N
9 }6 h j5 s7 a那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
5 C9 S% V: K) s3 U( Z- Z0 |我们打开bits.c,就能看到里面定义的如下4个函数:/ J% `9 s( q% o* U
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
L, Z# E% F' M4 m; Ystatic int bin2int(int no_of_bits, INT16 *bitstream);2 V9 R* W u4 M" ]% w! V: \9 c- P
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
0 k8 G% M: p+ x5 d: xvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;
$ V8 A4 o2 U8 U# t. p3 }, ]这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:5 S0 H7 [/ }1 Z; U' X7 v
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; $ y0 P- l: e' {: W( v+ E
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
) f, @. `+ ~9 V" n( K2 V& l {& q/ G, y9 s( G4 B3 V" L
void prm2bits_ld8k(Word16 *para,unsigned char *bits)
# X3 w. {8 q! S k- Q/ }. F{
4 o& C( k o+ ]/ k int i;
: f; @2 w+ t6 F int bitpos = 0;
" w( d) ?8 `% |5 [& y for (i = 0;i' J( ~+ N" w9 A7 p
: o' q9 w R0 E( A( j; A6 H
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)% t7 q, M% ]% [' b
{
- \* h. H/ @, p! \2 o# r8 { int i;
7 R: {8 _! ?1 g9 { V/ w4 K$ P. Z int bit = 0; [6 n9 {( f0 }
unsigned char newbyte = 0;1 ~0 D( Y* t4 {8 p0 {# X
( q0 z% K u: {# Z. C) I unsigned char *p = bits + (bitpos / 8);$ b; C7 j; J. Z r, a2 @1 _
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
( \& l3 ^- e& N; Cnewbyte = (1 : [& ]* n: n3 l- ^3 A [. L
bitpos++;
8 _; A: } A( o/ _. h: @1 Tif (bitpos % 8 == 0)3 C: O S" J4 t' u9 q; A
p++;/ _$ R. Y5 z9 y& @. U
}
% G+ o, V( B/ ]0 F( J4 W}8 s" ?! Q) b- w7 |/ x. N3 t
4 V* m# [1 P/ J
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
) }2 V' `9 L0 v( @' |1 `, t# S{' p& ]9 m. K1 w8 [" w
int i;. `: |9 t: ^4 M; ?% c# L
int bitpos = 0;4 P1 x, w* Y& m! x5 F+ ^' [
for (i = 0;i' I z8 ]! R2 P0 L, W% d
+ O* B6 ?0 _3 H
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
! p, z A) j; q5 Z) u) z7 i0 H: E: I$ c{, S! b L1 h8 h+ X0 ], ?7 W
int i;
9 M ?+ Z+ c* z8 g9 S4 r+ I int bit = 0;
% Y' ^' x6 [; d9 s" A Word16 newbyte = 0;. m7 E5 Y; C8 \! y. R$ ]# v5 n
Word16 value = 0;$ z6 @# L/ Q, e9 z8 G6 h
$ E5 v5 r# r8 \1 K2 ^ unsigned char *p = bits + (bitpos / 8);
7 p. V+ T8 Q" g! ^) D1 z [1 k for (i = 0 ;i > (7 - bitpos % 8)) &0x01;" X. J" S! x d6 u; t
if (bit == 1) {
8 k8 P4 D2 p" v: ^, M, M' q% J newbyte = (1
) g$ ]$ o3 i- e% z return value;* A, m2 d' B% c6 k% P9 l% i- u
}
2 I8 e, q5 V, \! b% O通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
9 y0 H- i, D# m7 u$ J
" T0 S! ~! C4 k1 M5 y! V编码器的代码能采用如下的修改方法
6 q: ?- S* }6 n& R# b8 B7 d/ s; K(1)修改coder.c:
$ b1 n8 T, F0 y1 uunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char *// f( S7 d a0 b1 q0 I
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):; U2 O! ]5 z0 W6 r# D* W' I; z/ ^
frame =0;: G5 B, y. Y; G6 @2 q/ R
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME); y5 ^: s/ G; G! C% T/ A. j
{* v0 \, }- C Q4 c" E5 ~! U
printf("Frame =%d\r", frame++);
' P4 b4 p6 H0 M& ]& S! p6 HPre_Process(new_speech, L_FRAME);
# E, Y0 r# ?# g5 g+ ^2 Z/ J: ]# JCoder_ld8a(prm);7 |+ u7 ~: P' U7 h
prm2bits_ld8k( prm, serial);
6 c: m; L8 T) ]1 m1 k& W9 nfwrite(serial, 1, SERIAL_SIZE, f_serial);
! h# }! s% R! \# t5 Y } }9 J; ]( d0 k; b# s/ H# w: N9 L
return (0);
4 T( B. q2 F+ X
. G2 ~% q. W' G(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:. K+ F$ @- t% e& u# k
#define SERIAL_SIZE 10
; d4 w- d* N, D6 B5 q- N$ y* U2 o2 t8 g: E- [/ k1 V4 x, m) F/ r( d
(4)解码器decoder.c进行类似的修改(关键部分代码):, p( T5 @( k: s
frame = 0;
# C, _- F& | s4 ? R) O/ ~$ Z while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
3 L% ^3 P$ h0 L, v {& _+ ]) _2 i! s9 e: l
printf("Frame =%d\r", frame++);7 f, [$ d9 g$ T
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */0 ~# C x, m( |8 }+ r5 c$ }% P/ j
parm[0] = 0; /* 假设没有丢帧 */
; w# y1 K O( L) C- eparm[4] = 0 ; /* 假设数据效验正常 *// c4 X" l: i$ ?+ l/ l1 o8 h9 m: O
Decod_ld8a(parm, synth, Az_dec, T2);7 P0 X0 |) a. h7 c9 T [
Post_Filter(synth, Az_dec, T2);
2 y0 g9 ~" N' r1 G6 A! [Post_Process(synth, L_FRAME);1 I5 w) a0 _% @7 V5 V$ h
fwrite(synth, sizeof(short), L_FRAME, f_syn);4 _5 T; z) k& Q# G
}
8 ^8 x, y8 \% J7 t$ O return (0) ;
. z$ S4 L; f0 @' N' J; _通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。0 b, N9 D9 @+ i5 \, B
$ f0 _3 S: q# T7 e, W m
修改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]得到,应该就能了。$ ]& m2 `& T5 s# _
封lib:& L# o' E) U* c2 \. I; Z8 C `
va_g729.h
' L& B y# Y9 T6 ?1 k#define L_FRAME_COMPRESSED 10
/ P" l8 i$ B6 a1 |8 D# [#define L_FRAME 80 n5 i" Y! ?6 F4 n0 N! v+ x+ D
#ifdef __cplusplus
) L9 V$ D" X$ q6 X- b0 xextern "C" {
& @( @6 H5 q' B, q#endif
$ A" H* `6 z. H, { Avoid va_g729a_init_encoder();- T+ @1 c7 g2 l3 S' t
void va_g729a_encoder(short *speech, unsigned char *bitstream);
% @2 ]4 p5 b& Z8 G/ pvoid va_g729a_init_decoder();: E. d, d2 O; l* L9 @1 [0 j
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
' k" z% f8 b/ M# M#ifdef __cplusplus . t- z8 o$ j$ d% v
} 0 q& f. T% _9 m8 n9 a& f/ U
#endif, H- z! z: c: [
va_g729.c& i, l6 x3 N$ k* L- }+ c% T- R
#include <stdio.h>
( n. C, q# P! |: S5 O#include <stdlib.h>- I: u$ v/ ~. C/ ?; C' _
#include "typedef.h"8 I: P0 A! s1 l5 T6 Q0 K# H
#include "ld8k.h"
% f A. G% T) N# F J" ZWord16 bad_lsf;+ ^7 v8 b; E" H+ g
void va_g729a_init_encoder()
, j' a4 l$ E3 K: o" A( G& p{& u7 L3 ~$ E+ b5 x8 \! q
Init_Pre_Process();
8 C6 ~: _: Y( p4 x7 b" b Init_Coder_ld8k();
7 n& u! {7 O' A: s% t}
: o5 q8 g ]6 t& j& R& H O2 d$ xvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
. z) v u+ _1 L{
9 \# _2 i1 W9 s; G$ B extern Word16 *new_speech; /* Pointer to new speech data */. S2 T% n6 c; L) j7 Y2 g- L
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
4 [3 _1 O3 ^7 f. H, R j0 v Word16 i;" U$ f; q! M; y" [3 c
Word16 syn[L_FRAME];7 X6 s x! `3 p2 z' L! d5 J1 e
for(i=0;i<L_FRAME;i++)
* m4 h% V, Q$ }5 y{ I3 z' C" a1 J) ^# ]5 J. {
new_speech = SpeechBuf;
% x) x) @$ z6 D+ k1 w}
' `4 [, l, X) b for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; ! X) }. Y8 v8 s7 f
Pre_Process(new_speech, L_FRAME);* {5 d, ~1 \* E7 z7 l7 v3 Z
Coder_ld8k(prm,syn);
! o3 R0 Z2 N' j! `9 x prm2bits_ld8k( prm, serial);7 `- R) [4 p& ?( y, H% y; g# w" ]
}
, y& g5 `" l: z6 e, J/ ?3 M( m svoid va_g729a_init_decoder()$ R* H% N% p$ Z' y2 b" d
{- @) ~0 Q5 z8 u. c7 H- K
extern Word16 *synth;
$ o3 d1 c* [7 } bad_lsf = 0; /* Initialize bad LSF indicator */
( _0 f# r0 Z3 ] Init_Decod_ld8k();
/ W& b- p" [4 x Init_Post_Filter();
* P) i- j2 G8 _$ `; w Init_Post_Process();+ }" l* C7 ]; h1 y! z
}# n) d. z8 I4 g5 K! {8 @. j( o) p/ r
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)/ C1 v5 J+ f9 U+ B; J1 T) ~8 o* J5 M
{
|& T! x' I2 M# V1 lextern Word16 *synth; /* Synthesis */! B& |( @4 V U4 O0 u
Word16 synth_buf[L_FRAME+M];
' A: [) | n+ h& qWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */1 H+ ^$ c# _- Z% u6 k' @
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */8 h9 g! _. L% P1 B
Word16 T2; /* Pitch lag for 2 subframes */+ A4 e3 f9 K9 C
Word16 i;
. j7 N3 n, j O! C k( \$ y+ F O9 ^Word16 voicing = 60;
% S+ |; f: j7 l5 X( a; a: nWord16 pst_out[L_FRAME]; /* Postfilter output */( s9 c) P: S! G# I
Word16 sf_voic; /* voicing for subframe */
7 Z" n9 r H# q0 jvoicing = 60;
+ N2 w% ^; m' m9 M bits2prm_ld8k( serial, &parm[1]);
/ l; n8 v$ T* R. [ parm[0] = 0;
( T# \! \$ {+ p6 L4 P
1 K1 n. T3 C6 w& d/ D4 Y, C0 s parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);: R$ y. O9 p3 S) c3 T" M* q, s# a
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
% y5 i u: E& f2 Y( y//--------------------------------------------------1 _$ f& w: k: ~! F
voicing = 0;% w) F- f, u4 o
ptr_Az = Az_dec;
4 ] _4 h3 y# a$ P8 rfor(i=0; i<L_FRAME; i+=L_SUBFR) {
3 g$ u* s/ Z- c* I0 T, E Post(T2, &synth, ptr_Az, &speech, &sf_voic);
; j% G7 J- U e+ T$ i" p; T if (sf_voic != 0) { voicing = sf_voic;}
% \0 f' H! q) e" x ptr_Az += MP1;
( p( K6 K4 ~0 U. l) M0 {$ s+ R}
- e6 L* u) g N1 jCopy(&synth_buf[L_FRAME], &synth_buf[0], M);
' t. K' H5 S, F! }, x! n//---------------------------------------------------9 I# D7 D% B: h$ X A/ c
Post_Process(speech, L_FRAME); % s3 b% g6 R# U8 u
}! i( g5 ^6 {5 ?+ Y
6 M" a% L+ r# O# _ |
|