|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
+ \; F' _3 r! U4 P- B, G; i4 U7 E下载以后需要修改bits.c文件:: A5 N# o8 c* E
我仔细研究ITUG729代码后发现:5 ?$ s2 a# R$ a- o2 C
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
0 m: ~: j Q9 m: U- M,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。- j* d4 v- F3 a6 h" w
5 v' R% I- w* C( \. SITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
! X- ^0 w5 k' W& l8 H# p
% ]5 S/ e6 D5 O! w/ i那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
- D+ s2 ?( ]2 J1 `, q3 }我们打开bits.c,就能看到里面定义的如下4个函数:
+ i' l" b9 d% zstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);0 j, o; S9 F9 @; ^: g) B
static int bin2int(int no_of_bits, INT16 *bitstream);; ], k7 ?. s! N- p3 r0 ?
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
z% d, b. I1 ~- ivoid bits2prm_ld8k(INT16 bits[], int prm[]) ;0 d: z! s$ ?, l3 y5 ^* i" J
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:
7 X. X" z* E, L5 b; |. Z) s; J. rstatic void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; & K: V- z1 l+ z6 S* D
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; / p; f# X- W- c9 Y: {" U+ `& N
9 }0 P, V5 l. S0 O% n4 V. {! Avoid prm2bits_ld8k(Word16 *para,unsigned char *bits)
# m: g" b0 w# B{
# q! G, ?- _. x% A$ r* G' h* n int i;2 ~; i& K E1 S
int bitpos = 0;
# o- A7 N# R5 i- q9 N+ X! ~! g for (i = 0;i+ W6 G" I2 H) E1 [
! v4 v* f# i1 h: p% ]
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
3 P0 L4 v9 V [5 i) Q{
- X. B$ U: e" a/ @ int i;- m( C8 L8 c6 }* F7 B% [; R7 A% V0 W
int bit = 0;
9 Z9 @7 W; _/ W4 E( w4 ? unsigned char newbyte = 0;
5 ?+ B4 ^: N9 D/ p- ]; {
# F' O% e5 M+ l/ k9 |: b1 { unsigned char *p = bits + (bitpos / 8);
& a, B9 U0 J W# [1 k- b" z for (i = 0 ;i > (bitlen - i -1) ) &0x01;
) |/ h' k/ e2 m9 k2 P3 c& Anewbyte = (1
$ K6 t. L ]" f; kbitpos++;- L4 T8 M% [& a$ n- M8 I9 F0 Q
if (bitpos % 8 == 0): W6 F6 @' L0 Q) _! t# Y' Y+ s
p++;9 W* Y' o( v) x
}
( B4 l/ z' F$ s( a0 ?" n7 |- D& G}+ i" L4 a) |0 I' }
9 ?" V+ P8 x6 ^ M2 ^4 jvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
" g( d6 _1 c# D1 f4 }{2 ^* L$ G/ R! [
int i;& { l m+ k! O* w
int bitpos = 0;
2 d* e# Z* L; ^, B1 @ for (i = 0;i
# c K8 Q5 e4 S3 {# k8 T
7 {8 U) }7 x2 h: HWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
5 w D3 Z7 z( a: g: N{/ Z- s% O1 M# V+ l6 O9 B n
int i;. W1 A, U8 r4 w; I3 u4 K1 s
int bit = 0;; R x# C9 Y; ?; R" _7 [ I
Word16 newbyte = 0;
" x7 m- H2 ^- _" g7 ^ Word16 value = 0;
: w% a- Q. | S' n) Y/ @; e
& b$ E' }6 l2 t$ O unsigned char *p = bits + (bitpos / 8);
- p+ {1 x# K& {8 o. ` s for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
2 y, t# B9 R; T5 y1 a' yif (bit == 1) {
+ d# {) g9 N4 k8 ` W newbyte = (1
2 [3 S/ }* Z. |" Q5 D3 J/ D3 ~. M/ [ return value;
' t5 r+ [- U2 z; G}
& W) X" T7 \) c0 [通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。0 y' n/ ^' k7 B- J
l2 s( i( G. Q' ~
编码器的代码能采用如下的修改方法
/ C/ G* s: w5 ](1)修改coder.c:
6 X; b" z0 i3 Q: {, Punsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */4 g) J2 g& a5 m7 F! X
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
4 {& g& |! C' C0 G1 L3 S- [ frame =0;
! X. G& f3 { i7 J while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
( D& B4 {5 ?, k2 g P7 @ {- }: ?2 ]; |# @ q( u7 J
printf("Frame =%d\r", frame++);7 b; `+ [6 P9 D. M$ k
Pre_Process(new_speech, L_FRAME);" l3 A/ B4 i4 {: Y D
Coder_ld8a(prm);
/ D0 D7 a; R8 r+ \; c& T: Sprm2bits_ld8k( prm, serial);
2 V' Z( x6 x! P1 O* q' r7 ^8 H8 C1 xfwrite(serial, 1, SERIAL_SIZE, f_serial);
7 h8 p. T9 ]* N9 W8 S }
/ r5 X) D1 w% P. [* T return (0);) N: _3 }$ U7 K+ {- r' t r) U& H
6 b& s# h6 j- K& s$ U: S' ` u(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
' l. F5 ~/ D) F- H! r7 H#define SERIAL_SIZE 109 i# M+ _8 E# \$ F3 E
# h( c( r: `9 C( D. c# f+ }- y
(4)解码器decoder.c进行类似的修改(关键部分代码):
$ M* ]- w$ P5 q/ N$ Y frame = 0;: C3 c5 c5 j! s
while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
' W+ f9 a3 s$ B( K! w* S9 w {7 f: g& Q0 N3 `0 }
printf("Frame =%d\r", frame++);* T% o3 Y) h/ k3 R- ~
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
" D) y: g9 I: F) i2 {" L; i/ y* bparm[0] = 0; /* 假设没有丢帧 */4 N0 |6 r \) |2 d+ x
parm[4] = 0 ; /* 假设数据效验正常 */
3 S$ z+ A5 K$ U8 y+ UDecod_ld8a(parm, synth, Az_dec, T2);
6 E; f J+ t' R& Q/ ]- BPost_Filter(synth, Az_dec, T2);
`. U0 O* N( L+ _Post_Process(synth, L_FRAME);
& A8 ]/ ?2 o' n- E. n4 ~. Y6 Gfwrite(synth, sizeof(short), L_FRAME, f_syn);
w6 L1 I6 y' U6 s6 g" O {( ?( p }0 k( x. b) r& Q I9 i/ B, g
return (0) ;
: B2 j o/ n; A! i& |# m/ I3 k通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
' I8 p. I5 X: [- v! x$ l3 h
" @5 y: G3 f) d5 K修改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]得到,应该就能了。
* f4 j- J4 z5 T' R* ^封lib:
* m, r3 g( `. U' X. ^# H7 H# l. iva_g729.h6 P {- {# h v
#define L_FRAME_COMPRESSED 10
. _: O, w0 ?0 Y! F1 Y) {# |* ]#define L_FRAME 806 i/ L$ p' o; f9 M
#ifdef __cplusplus 1 e% h1 d& }7 k
extern "C" {
0 g" G5 p5 O5 Y: k( A% Y) J2 P#endif3 b: W" g9 H+ d. \
void va_g729a_init_encoder();
6 f% x/ X: ^3 T5 p" S1 avoid va_g729a_encoder(short *speech, unsigned char *bitstream);. L- o0 t( D- |7 [: L! t; ^
void va_g729a_init_decoder();* }1 m4 E* ?) j4 M) F4 j! R- H0 Z
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);4 t9 S. J, B( }" u( t
#ifdef __cplusplus z) M& Q5 {- ^& p# M( u
} 8 n- _4 S6 Z' C( m' W
#endif
, T; X3 K- a) X& L" Jva_g729.c" F. G! b) K2 `( j- K, ]
#include <stdio.h>
: ]' B: c, j* o! k* s#include <stdlib.h>
+ k; K% v t+ U0 U" k#include "typedef.h"
' n0 n9 M6 ]4 `/ N6 v: f#include "ld8k.h"% J# i+ B0 I( z: u) v7 p- z8 p
Word16 bad_lsf;
& k D$ R- |: N9 o N! t8 `void va_g729a_init_encoder()
- y v- k. H% T1 ]" p7 J- y, E" V9 y{
; B L2 l6 M/ K( G" _ Init_Pre_Process();
5 t1 z& I8 E9 i6 l$ ` Init_Coder_ld8k();
( }3 E' |: ?3 P9 c- a. T! r}
7 V$ }2 x/ g( g1 `3 }3 K0 tvoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
( r6 T/ U$ a! ?! W. {4 Z+ E{ / ^* |8 [' C( c
extern Word16 *new_speech; /* Pointer to new speech data */' g1 R1 R/ L) [
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
( f) {: f1 Z5 f Word16 i;0 X, i1 s# v. ~2 v7 G2 E
Word16 syn[L_FRAME];
/ w; D; e: @+ e5 g) Y( ]; P" Y0 e for(i=0;i<L_FRAME;i++)
" x+ T0 E2 R& ~" q) D{
, D+ E5 u. E' P% l2 E( z2 c @ new_speech = SpeechBuf;
0 W7 R, A1 S% ~, o& F}
& c; H. @( a) \9 v; m- A! p for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
6 v8 F; u% A$ b* d& G Pre_Process(new_speech, L_FRAME);
; [' T: L6 C3 J/ c0 v+ O2 Y Coder_ld8k(prm,syn);6 m/ I# {9 {9 F- T5 g5 V
prm2bits_ld8k( prm, serial);
4 y4 }- G' o' E1 U}
7 t+ T& p+ |& r# v! Q wvoid va_g729a_init_decoder()
5 \0 F5 \; G- U$ \6 M{
1 `# s/ O; h: X& S' U1 z7 Z6 h `7 _/ Jextern Word16 *synth;
) j- g- g6 R6 j. [) ] bad_lsf = 0; /* Initialize bad LSF indicator */0 q9 ]+ e0 K* h0 Y4 Q1 v
Init_Decod_ld8k();
; G# _! y2 N; `8 | Init_Post_Filter();2 b! E M1 j1 P
Init_Post_Process();) C' b/ I# A% Z9 @) K+ i2 I; m; b
}( z" k3 s5 g! N2 p) Y
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
@. ~- J0 [" N$ M7 G, b{! K% P+ M U5 p0 ?; _
extern Word16 *synth; /* Synthesis */3 x+ t* e) l% q! H, b
Word16 synth_buf[L_FRAME+M];
. n8 ?3 D' L) z) u& |9 e+ BWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */
2 N. I, K# o7 v5 ~Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */
! I/ N# h9 K8 A. C) X; fWord16 T2; /* Pitch lag for 2 subframes */
/ ]& n+ m3 v8 vWord16 i;
" {& v" ^& R5 A% rWord16 voicing = 60;
9 j4 |( I W5 {0 z7 w6 {- N5 p5 }5 tWord16 pst_out[L_FRAME]; /* Postfilter output */) [4 E" Z/ R$ s' P7 w- A% X
Word16 sf_voic; /* voicing for subframe */; C# l( t! `3 E
voicing = 60;: F8 z. k" Z* M" _& |1 E
bits2prm_ld8k( serial, &parm[1]);$ P7 _5 k* s8 Z& l& ?
parm[0] = 0; 0 j8 h7 p' n& [+ ]( ~
/ Z4 Z4 _. f; T1 J; n
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
# H" x; }6 @! O0 rDecod_ld8k(parm, voicing, synth, Az_dec, &T2);1 F1 L! x) z" a: n8 T
//--------------------------------------------------
- q. K2 e) Q# p5 A( O2 jvoicing = 0;
& c v7 w& A/ iptr_Az = Az_dec;
9 p+ H9 N5 ^2 K: g$ @$ i/ ?* Nfor(i=0; i<L_FRAME; i+=L_SUBFR) {
$ O# F5 L/ F% f" O3 Q8 A4 l Post(T2, &synth, ptr_Az, &speech, &sf_voic);
6 v8 T( u- A5 j' J2 A, e. o if (sf_voic != 0) { voicing = sf_voic;}
; W# f6 R* t5 n- s" r! b/ ^ ptr_Az += MP1;
. \! m( h2 T! K7 M6 Q, _, p}- H1 w4 M3 a4 f, n* x
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
/ S& k9 o& ]9 ^$ V& R z//---------------------------------------------------2 Y( ?. }4 A+ e' z
Post_Process(speech, L_FRAME);
8 s) h/ j9 a3 @8 N4 n2 h}( y, ^ f% M8 |+ v
- E. V" ?) P" x {9 W, A, ?: G
|
|