|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
1 K4 S9 ] J% a7 ^. o; s7 x' B下载以后需要修改bits.c文件:
I e% h ~2 B0 ~我仔细研究ITUG729代码后发现:
6 z7 n0 X' U4 Z6 c% G# w9 W9 V编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
+ E5 U% C+ ?6 `/ u. N" x,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。/ G6 U+ Z& c) g0 P {. ]. W
A9 i% T- X' \- F. P: ZITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。0 i" P2 F3 D s/ X, M* T/ F) [
! ^) U5 ^1 o* D1 A
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。
# o4 C2 {& H1 ~6 F我们打开bits.c,就能看到里面定义的如下4个函数:
. v1 r9 p' q7 n9 tstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);
1 ~$ q( t* k; g" S3 H1 t3 J8 istatic int bin2int(int no_of_bits, INT16 *bitstream);9 o8 Y' z5 _0 g3 ~( }
void prm2bits_ld8k(int prm[], INT16 bits[]) ; + g* n3 c" S9 |
void bits2prm_ld8k(INT16 bits[], int prm[]) ;6 |2 P! c+ R+ Y# _) @, v
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:) U8 W2 y8 c( H5 e" E
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; : B# I" u4 W" g. A0 i
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; 6 U$ t" y- d9 Q! ^5 s
; z7 ]! J1 Q+ K9 f- y4 |void prm2bits_ld8k(Word16 *para,unsigned char *bits), H1 Z2 F) p* k3 v5 ~: r
{
2 U* h) N& U# P6 z int i;* W1 i! U5 V+ x3 y% T$ v6 Y; ^
int bitpos = 0;
$ v. F% u. E! l" t) k for (i = 0;i! ~$ m( p5 Q8 I$ z9 P" I# j8 M
/ k. s7 i* _, q6 O- Pvoid bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)4 n! o4 r0 n0 a4 m* \: V+ U
{
0 v; y% @! A9 [; x* @# V i int i;
" x! V( }+ [ L- n5 Q int bit = 0;
# F+ M0 e- H; w! C4 i8 ` unsigned char newbyte = 0;
7 j" q+ A9 u( ~
- w n; z* ^4 G unsigned char *p = bits + (bitpos / 8);3 O' w f0 P: V" l
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
4 q: F, l4 ]( W5 ynewbyte = (1 ; m0 s% E1 [0 W! f- {) N, d& p4 @
bitpos++;
' ]# _: n" s, e( [3 Nif (bitpos % 8 == 0)! M% V( A7 x" W2 O
p++;
5 ~! v- b" R4 d3 Q6 Z, Y }, q% }) t: {; e6 @
}- Y+ p; S) F% v; Q
; C# Z( [: F. G, q0 g, S" }- F6 G
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
; p% r4 g3 A) E# A6 U$ \8 i{; [6 M, E3 l- S) F6 m+ B |: Q7 c/ F
int i;
; H0 Z) q" M( v& @1 O int bitpos = 0;
1 d5 R4 {* F4 P8 g W S# R0 m8 D( V2 G for (i = 0;i' P- T9 o: Y1 h; O9 g
+ D/ t* D C: {
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)9 H$ k5 j/ h7 y4 M4 ?. u
{& a1 \# r7 h7 \+ }% h, {5 S& }
int i;# i/ _3 _& z, _4 G4 I5 {
int bit = 0;1 @- f2 g; Y: _* `5 @; w/ E$ d, [- _! X
Word16 newbyte = 0;; s: Q8 X) @+ F- q1 S) U1 R. \
Word16 value = 0;
) b: H' m; s; t4 K- T& h _ 1 \- }% b5 S) m% t
unsigned char *p = bits + (bitpos / 8);
e4 ` A6 M) I1 a* {( Q, h for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
; v9 ^% b [/ x" yif (bit == 1) {, D$ x2 ~/ G d D- W8 X1 e& h
newbyte = (1 9 \, R) ^' r' v& r
return value;0 U/ C8 B7 d) F
}. v. L/ ?$ T( V, \& q( {* d4 ]+ I0 U9 G
通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。4 k. A" ~& [8 n6 x I; c
( D M0 j4 ~) u F& z6 k编码器的代码能采用如下的修改方法
2 Q& {. v% S- C(1)修改coder.c:& i- t+ A$ b) e" W
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */
& S( W" f0 v8 o! G( R(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):0 J$ |, @, `) k. ]4 q6 g
frame =0;* ?2 i8 j1 b8 j/ v% W6 W
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME); B9 K% X2 p6 \0 S% R
{
/ b0 T8 d0 m, b% p [, y& Q. Dprintf("Frame =%d\r", frame++);
9 d( d0 K: ]$ `- A/ S0 k- x& KPre_Process(new_speech, L_FRAME);
. K) D& _0 D. n( aCoder_ld8a(prm);
, e8 L: s: M) B& |prm2bits_ld8k( prm, serial);. ?" B. c) `* W7 `% D0 `( \
fwrite(serial, 1, SERIAL_SIZE, f_serial); O" ]" Q/ b( \) @0 `
}
6 ^* r; x* Y( s return (0);* O- G/ f( n' _, Z9 E
/ z$ H* ]4 ]3 F( A: [(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
& L5 k# h$ I! \8 X& k3 s2 I3 }5 g8 b#define SERIAL_SIZE 106 O7 ~4 l% g% ~( \* D. k* e
& i# j$ X+ f7 D
(4)解码器decoder.c进行类似的修改(关键部分代码): Q, S6 x/ `6 D3 B7 X( H
frame = 0;
6 W6 `: _+ K1 i while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
' U* n* L6 B& [- k( J0 k4 r! f) B {
4 i) x, e; n. g1 uprintf("Frame =%d\r", frame++);& v/ K# V5 {" ^. h4 Y
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */% {0 z/ P7 y! x1 l; k4 ?
parm[0] = 0; /* 假设没有丢帧 */
E/ T& a) j% c o( R( j" Pparm[4] = 0 ; /* 假设数据效验正常 */" A }$ A* l/ Y9 l3 }: {5 S
Decod_ld8a(parm, synth, Az_dec, T2);0 K5 {7 n3 T) Y, V4 z# j
Post_Filter(synth, Az_dec, T2);
y1 c& Z7 D: n+ b6 r/ S- VPost_Process(synth, L_FRAME);& K. P" y# T; l
fwrite(synth, sizeof(short), L_FRAME, f_syn);
8 }$ M; R. o% B+ `* t& V$ Y6 [ }5 a$ T8 e. f5 J+ r# `
return (0) ; * s3 W/ h# W" M6 `
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
1 n7 P* h8 ?( P5 k* Y8 k
4 u r& D7 \0 |, k+ `$ S2 @修改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]得到,应该就能了。
( S# h( F3 Y- S* N) h封lib:0 Y$ M' W' b' P1 r% h; J
va_g729.h
* F p Z8 c' j6 x9 |#define L_FRAME_COMPRESSED 105 d0 w* A2 [1 f3 R' R
#define L_FRAME 80
V) P" o% N- L! v; c q#ifdef __cplusplus 0 a5 O# [: c( l8 |4 z9 D
extern "C" {
2 M) b+ r7 u9 N#endif& }7 [! {8 l% J j
void va_g729a_init_encoder();& [* z% q0 V- l3 |9 `6 x5 D n
void va_g729a_encoder(short *speech, unsigned char *bitstream);. J( j" Q8 d% k- Z- z
void va_g729a_init_decoder();. S$ y5 C# \: g9 ^) m% D
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
* D( ~9 b3 ^) |4 m' ~2 H#ifdef __cplusplus ! x! r) l4 o+ e! b* N$ \
}
* b k& V: E, l) d; e# r3 Y5 e#endif) v. M5 R& W, S# |5 U0 N
va_g729.c
, _; i, S; b. |, [% O6 N5 ~#include <stdio.h>
* [( U( ^$ w% M; J/ ~- r6 O#include <stdlib.h>
$ e0 C) L1 Q% F# P#include "typedef.h"8 b- E% a) B8 ?
#include "ld8k.h"
$ g" [% i! T! D* |Word16 bad_lsf;: H3 Y A- c, M6 m# ]* [* z. `; M% W
void va_g729a_init_encoder()
* j8 a2 k( j; W{
N" y# Y" g) ] Init_Pre_Process();5 N+ F; x0 S) f
Init_Coder_ld8k(); , ?2 V/ a9 M! H+ n
}5 k4 m$ v0 m/ S( S" [2 s' p
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)4 r1 x% G" |& R8 e0 ^4 ^) E
{
1 y/ B6 _+ Q; B& W0 E6 E extern Word16 *new_speech; /* Pointer to new speech data *// w- A* c+ K% _. \( d- {, _
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
# Q& B3 u( [% J- v8 I0 T4 X Word16 i;* k, y X$ h* R5 u' O* }2 ^
Word16 syn[L_FRAME];" q6 j+ j5 R: F) x
for(i=0;i<L_FRAME;i++)
" @3 D5 `8 ?3 n, U* J& M{
8 x/ f; m8 V, P V" n new_speech = SpeechBuf;, h) E" {( Q! q- W7 ~5 E
}9 k3 s0 R1 @9 |, @5 y2 J
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; 0 O& n+ ~" D' ^$ L& P
Pre_Process(new_speech, L_FRAME);( X# U1 e# {2 j8 s, r- {
Coder_ld8k(prm,syn);
% Y C1 i* d4 o0 J c$ e- P% x6 [ prm2bits_ld8k( prm, serial);+ X% V% n- A9 B+ e2 K6 M9 ^6 g- {
}+ j4 u7 P, h5 Z4 w- a s
void va_g729a_init_decoder()
, z, m8 e# {, |: R$ H) L1 t{
; k4 v r& j! ~; Z2 X1 |1 fextern Word16 *synth;
: g: J& @0 I/ {- f0 J: f8 p. H1 v5 t bad_lsf = 0; /* Initialize bad LSF indicator */
1 a5 C# `2 l) d, e0 \9 I Init_Decod_ld8k();
! {3 x. V8 ~" Z* |: g+ ` Init_Post_Filter();
" g$ ]* K& c+ m7 w Init_Post_Process();
+ x1 Y/ d8 @1 E}
7 J! W0 Y- `! q4 ]: o) _( o; R. Ovoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
$ j1 v) h$ s: H! Q# E; K: y3 K7 ]{0 T3 n; o7 h; S' [ b+ E+ ]. J. r5 Q
extern Word16 *synth; /* Synthesis */' Z& v. `/ ~; X
Word16 synth_buf[L_FRAME+M];) R0 a8 i5 q5 H. f7 y
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
3 J# t! S0 @5 W! lWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */, L( R3 }! d) a: v6 L% c- ?
Word16 T2; /* Pitch lag for 2 subframes */
2 z; c, T) s! _6 B( f: q1 p( g3 Y( rWord16 i;
7 T/ F6 C7 W4 ?9 M+ H7 n$ D4 xWord16 voicing = 60;# D7 |) {* ?* `8 w
Word16 pst_out[L_FRAME]; /* Postfilter output */; d* V8 S1 P' f. ?* V# {
Word16 sf_voic; /* voicing for subframe */
+ \0 K' Z% O. W& a" H1 H1 \voicing = 60;
- [6 @1 o5 i! T" D! n2 P bits2prm_ld8k( serial, &parm[1]); K4 r- s s) F$ l/ ~
parm[0] = 0; + ^" b; Q. j( ^6 c
; P* l$ Z7 M0 o
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
5 p/ E9 |3 j" ]7 j/ NDecod_ld8k(parm, voicing, synth, Az_dec, &T2);; |6 c2 g( s/ o. @- Q& L
//--------------------------------------------------! {8 Q% z c' s% P& T! w: ~( b
voicing = 0;2 K' d( X8 \+ h% t
ptr_Az = Az_dec;: r# ]; s" j7 _4 H
for(i=0; i<L_FRAME; i+=L_SUBFR) {
9 T" a5 Q8 X6 \' N" A Post(T2, &synth, ptr_Az, &speech, &sf_voic);8 \+ b" y/ x* @6 b
if (sf_voic != 0) { voicing = sf_voic;}
% ~5 O4 K! s3 Q \, _- s/ L4 A ptr_Az += MP1;
6 l* A) X- P6 {}- U( x0 E) c/ e6 P1 Q; B
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
4 l1 L" f; |* ^% o( u# S//---------------------------------------------------
7 P3 X5 f( f( s& K, X Post_Process(speech, L_FRAME);
6 z" b9 {) M1 p( e2 D& o% P}
4 {+ n9 f3 |2 F/ E; y
# ~; c5 B! _5 U$ v! N0 r |
|