|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
; J# e d3 M$ L+ s- c下载以后需要修改bits.c文件:
% \2 c) W3 t% t: h* X" n我仔细研究ITUG729代码后发现:# d7 Z0 v% f; G
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
" m' r# M) U, J, T2 \,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。- s2 H# C9 s, ~$ l2 E1 G; d
* N/ `- C* D! [
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。, R) N; g: l* `6 I( W
" E( S" x2 a9 N: m0 S7 w
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。) E5 R |2 C+ I6 b* k
我们打开bits.c,就能看到里面定义的如下4个函数:
4 E n, b+ Q( b6 rstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);/ Z) Z5 n5 B) p* U" B
static int bin2int(int no_of_bits, INT16 *bitstream); K; H! [6 [/ y* A8 Y t, v1 x
void prm2bits_ld8k(int prm[], INT16 bits[]) ; * e( k$ ~: T9 \6 D
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
9 t8 Y! R8 L# [5 o+ D; l, z% y这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:, T6 Q, }( x4 A# \/ T+ R- v; o- Q
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; ( b' Y2 r3 x. y$ r9 v- q" D
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; 9 U8 [1 @7 a2 `- n) O6 y N
3 Q+ q# y ` c; d) `0 z/ t5 hvoid prm2bits_ld8k(Word16 *para,unsigned char *bits)
- D y& A( R4 L. ?% X{% \' y' S5 y. n/ K F' `9 P* K9 P. i
int i;
. l, e, r4 J* ?4 h& V/ ? int bitpos = 0;
4 N* y0 W. i4 f8 b( @4 ?9 l/ s for (i = 0;i) f% L1 M1 G- O, j: P1 \
4 k/ j! C8 s, Y, F8 ~5 G/ h
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
$ `/ A) d: S0 D0 Z{' L1 U) O5 Z* d; C/ x Q' l
int i;
, b" j* B! p3 s/ }: Q. k int bit = 0;- X/ p) E/ |; G& H! j
unsigned char newbyte = 0;9 G) V9 [; G5 B* @4 W
' Y8 e# B I2 S% G% C' X5 w3 J$ B0 o: d unsigned char *p = bits + (bitpos / 8);
& J# _1 N! O6 G$ ` for (i = 0 ;i > (bitlen - i -1) ) &0x01;4 x: X) y" j8 ~
newbyte = (1 2 J5 n4 v5 g! C3 \. F2 i0 Y
bitpos++;
/ j4 B8 X7 c' b7 j1 Y0 n' [if (bitpos % 8 == 0)$ M' n. L' z0 ]7 W, g
p++;1 y% X* q% U0 r. u+ `6 L
}
8 d- k: @% s& B4 v}
4 d% C3 r. t/ o: z$ G1 s, n: ~$ F* [+ B
void bits2prm_ld8k(unsigned char *bits,Word16 *para); b) h& @( m" [8 L
{( }- p2 `" a: x; d- h
int i;* K+ g$ `$ }6 l9 H) t; U& r
int bitpos = 0;
& W0 D8 M0 V+ |% c ?9 \( O' `1 t for (i = 0;i, K$ x; a4 ?3 j8 @& H& t# ^
" k0 k3 A3 m& ~# u- t, o
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
" ^6 D0 C7 G% e8 u{
6 B& f5 {( s3 @8 ] X- K int i;+ f; N% J4 g% ` Q
int bit = 0;
8 h( N k6 @1 t; x5 a Word16 newbyte = 0;% u2 j# w! d. B% M
Word16 value = 0;. W l. P" m; K: ^
6 X, Z! A0 {1 c unsigned char *p = bits + (bitpos / 8);, J3 a4 U* M E6 M! Z' B
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;3 l% p) x# a$ |$ `$ ~3 f
if (bit == 1) {: @# i& m4 A1 c8 D# [
newbyte = (1 ; I" B- a! b$ y0 y
return value;
X$ \3 T' X, @* ^+ v" y}
9 b5 V/ k& ]/ e3 V( t& g通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。' i2 N1 u7 o% ?5 S0 a( I* k* f! u
# l! r( N9 f/ D* K
编码器的代码能采用如下的修改方法
& R* x8 \4 K0 m# ~1 j(1)修改coder.c:
) P/ L( y' f( ^0 p4 m9 Eunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */" p& e/ v# e: P
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
: E3 f0 W) { v; P frame =0;
) N" T9 N1 k" ~7 R% ]2 x: }# S while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
- B6 C: N- p3 W f0 e; E Q {
; g1 b2 L( T5 k+ F3 @& Oprintf("Frame =%d\r", frame++);
% G1 ]* Q/ l+ z) B) X# \- gPre_Process(new_speech, L_FRAME); H2 l$ K& z- v- {+ u: G% H( B
Coder_ld8a(prm);3 h% Z' a- P2 {9 S( o
prm2bits_ld8k( prm, serial);7 n7 p5 w* W/ p3 \3 ?8 L& s! B
fwrite(serial, 1, SERIAL_SIZE, f_serial);
) X! ^9 A' G1 T" m! W9 e2 f* I }, ]# K2 R$ N+ e2 P' ]. V8 i, H
return (0);
- M" h$ J* R( S% @) a2 ~$ x8 W6 M; Q. T+ M
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
! N, r2 \3 ~' ?9 W. M#define SERIAL_SIZE 10* Y: n) O, ?% ]& n
5 c! |" D8 ?! ^! \, s$ j# y
(4)解码器decoder.c进行类似的修改(关键部分代码):
. t2 j4 T( K! D, P* T9 u frame = 0;
5 T+ G0 v' X7 U2 X* [* [/ | while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)+ P' n2 z" W/ y+ k* U$ {7 F
{9 \( E6 {+ ?" Q I
printf("Frame =%d\r", frame++);0 E k; _; h* J. F5 K3 j
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */2 g/ n F8 Z+ ~8 C; E
parm[0] = 0; /* 假设没有丢帧 */4 N) ^9 b v5 g; P0 W1 j5 Z
parm[4] = 0 ; /* 假设数据效验正常 */
1 b, R; m4 r2 t' f% ~Decod_ld8a(parm, synth, Az_dec, T2);* I! |( H* [5 R3 T7 o, A6 q1 }
Post_Filter(synth, Az_dec, T2); + U9 ]/ v6 D$ c( d" Z2 h; ?
Post_Process(synth, L_FRAME);7 Y+ J% w* j0 [
fwrite(synth, sizeof(short), L_FRAME, f_syn);# N* r! D7 S; B$ r1 ]$ P
}! o, t+ [; @4 m# |# U6 k3 R
return (0) ; 5 G3 y: h& K0 V
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
$ D( J6 E( A$ H0 Q6 c
/ W2 h3 G/ m4 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]得到,应该就能了。
7 ?# H1 w( b" a8 z1 c( @# X封lib:
. F7 I E# `- u' \va_g729.h; T7 u4 D5 z% V& o: ^ p/ p; D
#define L_FRAME_COMPRESSED 10+ g/ a$ r' r9 P# v4 u
#define L_FRAME 808 t/ D; @! ?2 \5 ~
#ifdef __cplusplus 3 d5 A" Q( n. E2 |
extern "C" { / [% `' d4 {$ k5 \# E" p
#endif9 `& y/ }6 R i! A" G! K
void va_g729a_init_encoder();# r$ e0 ~5 M+ F- m2 H0 |5 v; w
void va_g729a_encoder(short *speech, unsigned char *bitstream);# W4 Q/ `; ~5 @7 v" Z }
void va_g729a_init_decoder();
* K( Q* ?' D& f3 |! U. kvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);* W0 l2 N/ \" ^- l1 Q+ r
#ifdef __cplusplus
c) o# I( r9 g5 Q1 x0 e9 ]1 K}
1 v, R0 r; V4 D1 {- H2 Y F#endif% i" V% Y6 \! \0 W1 n9 y( j9 O
va_g729.c
( V0 m5 T, P) F1 k. [$ t#include <stdio.h>' m; M: V* n$ D' I' B
#include <stdlib.h>/ B) q$ z' Z9 k( q$ ?4 U% J
#include "typedef.h"
5 r, b- l P0 p) Z#include "ld8k.h"# V' |) h4 S* Q1 s
Word16 bad_lsf;8 i/ |1 G: ~3 `/ N7 O0 o, j
void va_g729a_init_encoder()/ J' h1 c i5 N* E! @! e
{
) y# u2 y! V, Z" I/ d- I Init_Pre_Process();. K+ d/ Y. l0 M( m: T8 E0 Z
Init_Coder_ld8k(); ' z- f" F% v2 l
}
8 [# q* g- J8 R7 q2 @: | j6 jvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)# ~. }- e, l! F' z+ x& W" g
{ , L+ R* F ^& Z+ M% D* V) @" Q
extern Word16 *new_speech; /* Pointer to new speech data */
. M* z/ ?+ A6 W& W7 I Word16 prm[PRM_SIZE]; /* Analysis parameters. */
6 d) }% @% I/ J7 H Word16 i;
% x R$ o# G$ J! b4 Q6 w$ G3 [8 `Word16 syn[L_FRAME]; u8 W( D! ^7 n
for(i=0;i<L_FRAME;i++)
" o3 @: d8 i. G" r{
: ^7 Z8 B2 m" m; `# y) E new_speech = SpeechBuf;
3 B$ H6 y- }, Z8 H/ k [$ }}( {6 x* O% D! a2 F
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
1 M @1 I! ]& e( q4 E, q Pre_Process(new_speech, L_FRAME);
# s$ n3 x1 z% V+ @# p: U Coder_ld8k(prm,syn);) X' e; o S; \0 D# v2 D
prm2bits_ld8k( prm, serial);
o5 b9 \2 h4 ?. i7 P3 Q7 Y}
& B" M/ J/ s5 R3 l4 Yvoid va_g729a_init_decoder()
+ \* O. ]% H3 Y3 B, c+ P& h$ r3 ]+ v{$ w- J1 ]6 \! I4 F
extern Word16 *synth;
3 T% I" k0 @+ Q; e1 a5 N bad_lsf = 0; /* Initialize bad LSF indicator */
5 c" p q% C' J Init_Decod_ld8k();
0 d* q+ v8 @- S, c Init_Post_Filter();9 k' m! t/ l9 f
Init_Post_Process();
+ x, q! p* C6 T7 I& m}8 A# e0 i$ x; z* }, X5 ]+ A
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
+ Y ? @* T& M5 h{, j. S* O N9 K0 j
extern Word16 *synth; /* Synthesis */) ?$ x" C1 Z$ |& I. }# S% Q
Word16 synth_buf[L_FRAME+M];
9 N- _5 Y: Z# U% M- l, D. T7 JWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */" U% b. x6 v- W0 m* z7 q( r8 P
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
/ b6 z# u, C7 c6 QWord16 T2; /* Pitch lag for 2 subframes */
/ {9 P" \7 d* l) w( `6 U- _# MWord16 i;9 x0 C/ x- N( c& ?( J& ~- G
Word16 voicing = 60;1 ?9 y6 U" q) i$ o, s4 M9 I& Y
Word16 pst_out[L_FRAME]; /* Postfilter output */) z: _* l: A2 _2 \! v
Word16 sf_voic; /* voicing for subframe */% b! t t. P- ]; l% Q5 e
voicing = 60;0 L6 S% S2 j$ ^1 j& h" e+ a
bits2prm_ld8k( serial, &parm[1]);
+ {2 X9 k4 l+ [ B parm[0] = 0;
7 t* g& Y" m7 ^ [ 5 A R7 F/ G" R% P9 v
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);+ r X' m/ X8 u/ T" _6 U5 c
Decod_ld8k(parm, voicing, synth, Az_dec, &T2); j. B6 q7 V; \* v I
//--------------------------------------------------5 J* u* z- Y- ]0 R1 M
voicing = 0;9 T: ^. x/ q% ~$ q1 w
ptr_Az = Az_dec;
4 q/ r; r2 L6 `8 `7 d& y& ?4 d: z4 Kfor(i=0; i<L_FRAME; i+=L_SUBFR) {
) V, y# @4 B8 c4 J* a Post(T2, &synth, ptr_Az, &speech, &sf_voic);
! U; d( Q7 F$ h4 ] if (sf_voic != 0) { voicing = sf_voic;}9 P% t. I- B3 n
ptr_Az += MP1;5 ~' ]+ }2 z0 l/ w0 V i' D
}1 U, e. D T5 c3 f! f& b
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
# E, L' e' K/ s) u1 ^& r//---------------------------------------------------
& Q" D# ^" T) ~ Post_Process(speech, L_FRAME);
% B. E9 M4 V- l9 ^5 i$ n6 g& q}
. L/ g) T i( B& v8 n& b" Z
' O. @5 n& Y! f" z |
|