|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
# A9 _ O. `9 p, Z下载以后需要修改bits.c文件:
3 @9 Z/ w$ K0 I我仔细研究ITUG729代码后发现:
: ~) W. q( M/ F编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
5 ~& y+ d c5 k. J,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
. N+ B( N6 `7 K# U) t* m3 O7 q8 O* j; \2 h i! _
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
4 Y' W. e6 ~8 W2 {
/ H q% K9 `) L5 c6 n+ E那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。! p; q6 m2 q8 E. y
我们打开bits.c,就能看到里面定义的如下4个函数:" d0 C$ p2 F5 j& r
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
6 Q/ R' I6 i+ n! N p! m/ c4 w! f& g- r' jstatic int bin2int(int no_of_bits, INT16 *bitstream);% P$ B4 ~6 i2 }7 B
void prm2bits_ld8k(int prm[], INT16 bits[]) ; 2 X+ B: J: V; X0 z' F4 X* w2 c
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
6 g( s1 C3 m* q5 `这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
- s; B t& w/ G% |. C! K% Hstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
' X; \; z7 S' m( pstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; a6 J( I. J0 x
' ^, c# S' \$ M( p0 y' c
void prm2bits_ld8k(Word16 *para,unsigned char *bits)
1 D) J0 B' z, Y" a{
2 d! i4 C3 T& _% P# z9 a int i;$ l6 O/ S1 Q. D" j* U8 N4 W
int bitpos = 0;
5 N# @8 I9 g# D( Y7 w7 g for (i = 0;i
_5 C1 g3 q/ z! K
1 G$ {+ `0 K' l6 T" ? yvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
3 q) H1 z5 C9 g# R{- H2 }0 @8 K: h& ~ v! N
int i;
5 e* P/ K6 v; F int bit = 0;4 u2 F! s+ i& @
unsigned char newbyte = 0;# k0 b/ c, m: n
) h+ A* E! Z. }( g
unsigned char *p = bits + (bitpos / 8);3 V: O* F3 h2 A/ v+ D4 m1 ~1 I& g
for (i = 0 ;i > (bitlen - i -1) ) &0x01;! z. t! \: ~, K# k3 e
newbyte = (1
) Y& `" ^% b( r- \- }, E7 ?; J2 Sbitpos++;) k" Q) \& z, E# G$ o
if (bitpos % 8 == 0)% a+ I* Z! w) @7 r, C
p++;" ^( \# F/ j9 R3 v; \. k
}) I9 O4 }5 _0 Q9 D' t. _/ i3 b
} f& b8 h8 z6 b- Q8 Z- L8 h! S" l, }
2 Q" n9 R0 I; F. x; Yvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
) @" Y+ }. T3 E2 [. {{& I" o4 b) d& i
int i;: r& e# T, O9 v( v3 G( q4 g
int bitpos = 0;
2 A$ U" X2 J9 r for (i = 0;i
! M+ K% a5 i3 h; |0 w7 r" l) l& a" `+ W, o6 Z r
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
4 H2 }; _+ M# G2 S+ w8 z6 Z{
, z5 [5 k p6 l$ g8 I int i;+ A, b" b: A L/ ~" l6 C. ?& h" M
int bit = 0;
) q; c' n* [# b m6 L0 c7 ] Word16 newbyte = 0;
! F, [; m: n$ b# i: q( i Word16 value = 0;
x2 C) e- C1 X* _6 d
1 ` M7 Y( I5 b unsigned char *p = bits + (bitpos / 8);6 m4 y& o1 u& N( v' S
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
7 e1 p+ p) S0 [+ x' T# H) Qif (bit == 1) {# i4 M- P7 l) @3 P7 M2 ~5 i
newbyte = (1 ! C9 ]( D; h5 c `& n* c
return value;
7 ], x) P6 g) j3 h. r}$ D1 \! E, H; J. Y) {; l2 @
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。7 h; L+ A' x6 F/ ?* ^: U
2 @1 r% M. S6 `. w编码器的代码能采用如下的修改方法
4 a( N" P" a5 Q% t1 l(1)修改coder.c:
0 m0 \% x) K; m3 n# r" j: E( @unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */ i$ k3 n" ~$ Q! N
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):, ~& E3 S: ?/ ~2 Z
frame =0;
/ O0 m: M+ q/ C1 w while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
' K: p4 ]/ }' W- V {5 T+ A# K6 N$ B) ]' U4 F; m7 W; B
printf("Frame =%d\r", frame++);& R9 |" Q- N& T Y1 T" v8 j3 n
Pre_Process(new_speech, L_FRAME);
Y# ~3 L( `; W3 w* G$ O% hCoder_ld8a(prm);
: E9 P3 _0 Q w; d4 o* \4 E8 Cprm2bits_ld8k( prm, serial);
6 T Q4 K' k) D5 {fwrite(serial, 1, SERIAL_SIZE, f_serial);
- { g: ?+ j' I- t }
# B8 `% ~% J/ V! C5 s9 Q return (0);8 a0 k( T2 C. B. Y: J
& y4 f3 M5 W5 ^- f* P, d3 B(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
0 ~9 G- y2 |+ m) H9 I#define SERIAL_SIZE 105 H) h7 i; D; Y
8 N: a9 \, s3 }' U; c* f(4)解码器decoder.c进行类似的修改(关键部分代码):; u- \$ t. C: \* }# Z" {+ Z
frame = 0;! |- P4 |7 C' `7 E4 K! X3 J
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
* \# `7 w& F) c2 g1 y {4 _! k6 M) A: x/ q* J1 W
printf("Frame =%d\r", frame++);
9 U- \4 t$ D. y$ g# n: z1 i4 sbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
0 _* J3 `5 z1 X" Hparm[0] = 0; /* 假设没有丢帧 */7 I# n9 ^, f7 d9 V) W
parm[4] = 0 ; /* 假设数据效验正常 */
3 A1 D- e/ {, w% sDecod_ld8a(parm, synth, Az_dec, T2);
. Q7 S5 J0 F! k; p8 w7 z# b9 L1 dPost_Filter(synth, Az_dec, T2); 4 a- x9 y6 f, v2 K
Post_Process(synth, L_FRAME);
! G" ]5 z7 y2 ]4 P& s# Afwrite(synth, sizeof(short), L_FRAME, f_syn);. a$ ~' c/ `3 i+ Z% D6 T# z
}2 S4 v7 `/ q. Z5 k" l; n
return (0) ;
& b# L- c& I7 a p& n! s通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。, Z0 U# N5 N0 q* ]$ V/ W
8 W2 f4 p- }# ~3 V0 j( S% _. C修改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]得到,应该就能了。2 j0 V' D, y& p8 [; P1 o
封lib:- v- s% l9 X- I' _
va_g729.h
( g; B+ T" k6 B" V9 ~: P#define L_FRAME_COMPRESSED 10
9 M9 A7 n" [9 h& s8 J: K/ ^1 P#define L_FRAME 801 u5 i. Y* P% o" |
#ifdef __cplusplus # N2 `* r& R+ O; ]
extern "C" {
% \+ t/ H- [, j& Z ^8 L0 ~1 D* N#endif
7 n0 i# U% V% U2 O$ ]. [void va_g729a_init_encoder();1 w# x; z- [) [6 }+ O
void va_g729a_encoder(short *speech, unsigned char *bitstream);- b: O, z, W( [( t; m
void va_g729a_init_decoder();
* ^, q" x; j' A4 m7 F* _9 M) J( \void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);+ _8 \4 W; L( E! }4 x9 B1 b
#ifdef __cplusplus 6 o. K0 G! \ d2 A4 ^
}
8 I+ W& J3 a% o' t7 Z9 L/ B: l#endif% \: a; J5 H4 B
va_g729.c' q2 p5 c: n( P7 ?. x
#include <stdio.h>4 O- \; k$ h; k+ L1 ]) a! Y- R
#include <stdlib.h>
7 ]2 _' @! Q+ J#include "typedef.h"& j$ Z7 O! V9 R. m
#include "ld8k.h"
# a4 b5 v9 h, x* y3 T- |Word16 bad_lsf; [) j H: ?+ `
void va_g729a_init_encoder()
: Z _6 W, Y* ^/ S{: x( L5 W- k0 m" k f+ g( h1 ]
Init_Pre_Process();5 p2 P0 T2 ~4 r6 N; ^
Init_Coder_ld8k();
0 r8 m$ z$ b8 h: ~7 m}0 e, U5 D# L6 Y) [
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)0 z" h5 R% D* T' M
{ c8 t+ j$ ~7 R9 o4 f' C
extern Word16 *new_speech; /* Pointer to new speech data */
4 W2 M/ l9 K; D1 e i. O7 y+ a Word16 prm[PRM_SIZE]; /* Analysis parameters. */
3 F; A U+ H, w. _ Word16 i;4 q" [" Q2 `" ]8 L% \- w
Word16 syn[L_FRAME];
7 p+ q* A2 Y5 j& Q# `2 q) a# |6 m u for(i=0;i<L_FRAME;i++)+ q! T1 ~8 C, ?
{
0 _/ {! X1 b% v% v) e. m3 @/ W new_speech = SpeechBuf;
- D6 |/ G$ t+ F8 R& g}+ T0 P$ k$ Q- n
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; ( Q1 t! D* y d4 I
Pre_Process(new_speech, L_FRAME);
( d! k' F& ^2 ^/ H( [5 b+ l Coder_ld8k(prm,syn);
" X; u0 E' _) _, L, B prm2bits_ld8k( prm, serial);
. }' _' u- N7 o+ B' X}
3 a% u. [5 ]. {8 Gvoid va_g729a_init_decoder()/ F- y8 U$ {/ ^- l( f
{9 ?' r- s5 u% a7 i* F" f
extern Word16 *synth;
% [7 ] \$ p+ [" |, y bad_lsf = 0; /* Initialize bad LSF indicator */4 u! ]4 z* t( @( E$ E
Init_Decod_ld8k();
" ]! _1 q3 \/ Z2 ? O5 d9 k Init_Post_Filter();
$ j3 _ A+ W5 C2 X" M4 N6 Q1 c) n Init_Post_Process();
- [4 a: ~4 j: a. A2 q; g}7 c0 i8 S% P" |7 u w# w
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
3 {( N! n8 ~3 D% m! S0 M{. s. O2 ?* W# x* f& v8 Q
extern Word16 *synth; /* Synthesis */2 K* M1 I) R# J' e! H2 o
Word16 synth_buf[L_FRAME+M];' g; @# P0 ?0 A
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */4 D4 `' m0 U: n$ [2 D
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */) U9 F9 e8 D* y( H4 l# T% {# z
Word16 T2; /* Pitch lag for 2 subframes */
, g! |: e8 d4 P# d% [# u! R7 W% `Word16 i;: V: J) l" g% _8 f2 G }" V
Word16 voicing = 60;# X# Z5 n3 {, G* S3 x0 c2 I
Word16 pst_out[L_FRAME]; /* Postfilter output */1 M' O5 P3 d4 U2 V
Word16 sf_voic; /* voicing for subframe */
% ~( x# S6 J E. Vvoicing = 60;
8 n9 x$ G7 C6 u/ ]1 ^* ^ bits2prm_ld8k( serial, &parm[1]);0 B, ]4 _* x, \0 h) h d
parm[0] = 0; ) P( ]+ S0 ?, ]# ?
7 e$ J. l v% K, V parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
' g! W. o- [5 }. `/ G5 s+ H) V' ADecod_ld8k(parm, voicing, synth, Az_dec, &T2);( t/ S9 a8 e* M5 w5 |, U
//--------------------------------------------------
3 G6 P* H# B: T3 M K% Tvoicing = 0;; t, }) q b/ D! a/ G' {7 x& w9 b
ptr_Az = Az_dec;1 U5 Z/ y$ j7 X0 P6 A3 V
for(i=0; i<L_FRAME; i+=L_SUBFR) {
[2 X; W3 c! @9 V Post(T2, &synth, ptr_Az, &speech, &sf_voic);0 r9 J: w4 S! ^8 o
if (sf_voic != 0) { voicing = sf_voic;}7 C9 Z9 \! N5 j! M! d) k5 ?/ \
ptr_Az += MP1;
, A# t$ ?0 [; M1 W- k0 \% I* O}
6 s- \2 p4 m& }: {" g* Z. lCopy(&synth_buf[L_FRAME], &synth_buf[0], M);; S+ X: T# T: @2 W0 L7 ^6 p
//---------------------------------------------------+ D' j4 H/ q+ h( x4 @
Post_Process(speech, L_FRAME); 3 T& Z+ P$ W e2 B6 \' @
}5 M; @' d, S/ m/ x4 _ f
3 s' C3 d, k7 `; e2 y6 m3 s |
|