|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
2 Z+ W8 e) d) {# I& ` |下载以后需要修改bits.c文件:- U$ @& T8 l2 L& u- P
我仔细研究ITUG729代码后发现:$ Z9 t5 | F+ y4 N( x+ z4 T6 C" }
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
; q4 g4 `9 {. h- {0 [,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
2 ]$ ^" F. Q9 H# y3 P( _# g
& v* c$ _; [, Y( v/ t# RITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。% m7 l! D" ~+ ^) M
0 L m/ z! f1 _( I. P# k {; i那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。0 q- c5 A9 x( Z( M! n- X5 r1 W1 I2 L
我们打开bits.c,就能看到里面定义的如下4个函数:
5 S5 n% L, a$ m1 i7 gstatic void int2bin(int value, int no_of_bits, INT16 *bitstream);1 J% \6 K, O0 o; l5 b2 Y, E# k- r
static int bin2int(int no_of_bits, INT16 *bitstream);
$ S- O' X+ k( K* i, t7 ^void prm2bits_ld8k(int prm[], INT16 bits[]) ;
6 H+ Q0 E( ]8 r z" xvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;0 ?5 p1 \1 F1 h+ v c6 l4 ]
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:3 B9 O2 M) [6 F, n# p, b4 X
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; , k4 f( K8 h! z* w
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; 5 r- \: |+ w/ x1 k( L( K7 U! l
2 Z6 o- @# g" t. o* {) j1 T
void prm2bits_ld8k(Word16 *para,unsigned char *bits)
6 @9 T( g4 g3 U. c{5 K6 c+ |& e" t3 n1 d' C
int i;
& U. q) @) [! b int bitpos = 0;
8 R! r/ D$ c' u5 \7 V, T. r9 l for (i = 0;i
* O) l. R2 w3 K" x# Z! O9 o4 h$ C2 X' `. t- _
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
$ R4 D9 }" E7 a ]3 G2 P7 e& N: F: {; h! d{5 ~/ w& X1 X0 B% X
int i;; y) l) ^' }/ H
int bit = 0;, s6 \5 o7 h6 j+ ]0 M
unsigned char newbyte = 0;
) l: f9 O+ R: W" {$ I % W" H f, c5 L. l# W
unsigned char *p = bits + (bitpos / 8);+ B; A) ^. _0 T, D4 `9 n! g9 u B3 Z
for (i = 0 ;i > (bitlen - i -1) ) &0x01;
! `6 F) F/ n1 q* L$ b) lnewbyte = (1
; R' H% ]% b- G/ u2 G# y. X) Dbitpos++;
; ~$ m! B' {: U6 ]8 l. g1 S/ F( Qif (bitpos % 8 == 0)
/ n0 Z. }0 }- g, w" M p++;
) S/ q6 Z3 b3 f; y) v }
& o+ Z# e4 l1 L0 C, ]7 b& G) q8 R5 H& y}
+ {9 s& K# V$ f4 _8 j3 l7 q( g/ u0 n" @- l0 ^
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
0 a3 u8 N" Q" Q9 O8 b% \' \{
( ^5 {6 q8 k+ D" e int i;
# K* e- T2 `! n) e) o! a int bitpos = 0;
( ~" T1 l1 }! n }" l }& J% ^7 z i for (i = 0;i/ B( ~" N- ]3 u: D- |
1 b9 u4 L& g# `8 N s
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)2 D7 n! i) n* c4 R' `4 s4 ?
{
[* z8 r+ R& ?+ A; a' v; m int i;! [ T3 X; ~0 _
int bit = 0;6 }: a F- e8 k9 Y! U* l, }
Word16 newbyte = 0;6 F7 [9 K* |: `5 o: O" s+ N
Word16 value = 0;
3 `9 K$ ]" m3 D& n8 M2 s w1 b 1 B* v* q' v) H, n+ R8 n3 V
unsigned char *p = bits + (bitpos / 8);2 F) Y: ]1 f9 C+ Y% x K
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
F6 \: ^( Z7 wif (bit == 1) {( u+ T9 h) l6 g: p' Q' @+ t o
newbyte = (1
* q/ z* X% I+ z. _$ t return value;
" o5 |' c. v. W! @% l( m}
6 h! D @* a5 }1 S$ D) T通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。- D) U) A; b/ r
2 ?# g/ d4 {' A6 l ~' b, B' | h8 M编码器的代码能采用如下的修改方法
6 }1 G+ |3 R& W(1)修改coder.c:
2 X; k# c7 Q. ^1 C7 i% xunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */# Z7 k5 d- { s! I* P5 X$ h3 K
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
6 D- U4 d0 @5 g' {! J+ ` frame =0;: f7 W7 f; t% ~% s) M
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME): p* K/ N# Q, P# h
{: v% i' R( v0 B
printf("Frame =%d\r", frame++);
0 A5 F8 D$ s$ }5 Z1 m$ l6 P, ~Pre_Process(new_speech, L_FRAME);# d; w1 `( x+ z# Y+ ^9 I
Coder_ld8a(prm);6 F4 H& X0 n K% E
prm2bits_ld8k( prm, serial);
% h2 i+ F: O; ~* D! efwrite(serial, 1, SERIAL_SIZE, f_serial);0 e& z0 u1 V0 O" c5 T+ a8 F& f( [
}; [' h5 e* O8 L- j- ~5 B) V% f
return (0);" |% l6 \* q' P0 D" }
3 R. Z& z5 A- j3 [- ^8 N
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:
6 y: Z# g" o3 U6 G- j0 n; J#define SERIAL_SIZE 10
2 Y4 T" H2 c& x0 Z' Y# R; q. P
0 o( a* l( R* Z8 W4 F E# w(4)解码器decoder.c进行类似的修改(关键部分代码):
' s' z# J$ m' z; K% @. N4 r! A frame = 0;
4 k% i) [; i9 g$ i while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)& y$ Z0 G F! l, u0 F& f# ^
{
$ Q$ W+ M6 [2 T. |printf("Frame =%d\r", frame++);
4 I) V4 v% G- C: Abits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
" F7 p# M4 K- \7 z* f" C2 J3 ~parm[0] = 0; /* 假设没有丢帧 */
% l0 j8 ~* U3 r. I5 u# { Iparm[4] = 0 ; /* 假设数据效验正常 */ ~& v! t2 X1 z! M# ]1 p* F" T
Decod_ld8a(parm, synth, Az_dec, T2);% S, B* T/ B5 b9 w2 G2 J+ Q5 y! d
Post_Filter(synth, Az_dec, T2);
" `# X; f" ?( l. G& r, W# {; XPost_Process(synth, L_FRAME);' }5 S& V1 Z8 r0 |
fwrite(synth, sizeof(short), L_FRAME, f_syn);
, X! [- R6 I' A2 _( U. O5 t }) k% B2 W" _' R) r$ E) D
return (0) ;
5 `$ t/ [. f! l( L通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
4 O! |% B) [3 y5 h" u, r* ?
- T! A K' @( p修改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]得到,应该就能了。
! o/ V+ q0 C' |7 f$ g w/ g+ ]封lib:
$ K* G, ^; s: `) a" cva_g729.h
7 I6 @6 D* q: X- j& t$ S5 S#define L_FRAME_COMPRESSED 10
# c( F9 ` M* Y1 |#define L_FRAME 80
. d$ |1 h- i# l8 N# R% v. l#ifdef __cplusplus
- D! ^- ]: S1 u4 K$ sextern "C" { " M7 F4 z' u1 l. v% ^$ }
#endif/ g( J" X6 ~8 L% d' _# C8 e E
void va_g729a_init_encoder();6 E- M6 a1 b+ G1 \
void va_g729a_encoder(short *speech, unsigned char *bitstream);( s8 s: x4 X1 E- y4 q
void va_g729a_init_decoder(); N$ Q: {: q# w9 d
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
1 [1 N- w/ |) r#ifdef __cplusplus
/ N% N5 U. [! r6 E1 l* F# G8 v% j} * l0 c" p. |/ t9 x, c
#endif" j* l5 t _& B$ w
va_g729.c
3 v6 D! W H2 R7 d- G#include <stdio.h>
" k" g- z. f! u' ~. u" ?7 F#include <stdlib.h>; ?3 `0 U" ~' ~3 a
#include "typedef.h"" g3 d9 H4 q$ }3 P- d t% H/ @# I
#include "ld8k.h"
* t2 s/ y9 u* E" S3 B1 LWord16 bad_lsf;- a# M9 F: N' W9 L6 ]
void va_g729a_init_encoder()0 H2 A) a* Q8 f+ t
{* J5 p! b& M4 N \+ H; ^" x1 U
Init_Pre_Process();
9 ]& |) Y1 q h1 y Init_Coder_ld8k();
# P7 t6 B; D* }7 S$ T4 R0 M/ h}
* N2 J/ M( k0 Q. K$ Z% k1 o, Avoid va_g729a_encoder(short* SpeechBuf,unsigned char * serial)
* C8 X2 B. b4 c- Y8 S3 |3 h' c{ " m8 N+ ?, C1 O% N* x6 }
extern Word16 *new_speech; /* Pointer to new speech data */" R5 }" o6 x& H- Y9 H
Word16 prm[PRM_SIZE]; /* Analysis parameters. */
$ a% @3 J9 m) G1 B# T9 M0 q Word16 i;
4 U& N6 ?; y1 s% [# PWord16 syn[L_FRAME];
2 r& ~- y$ m: U& e for(i=0;i<L_FRAME;i++), C! W! V0 q7 ]$ h
{
5 ?& c, P1 f/ I" Y4 v4 \3 F new_speech = SpeechBuf;
# s7 g9 `1 g% @& X+ e! c3 h- u X}
' q3 s0 l# q D8 Z5 O9 D for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
' F, }* M" {/ N9 F7 h3 d Pre_Process(new_speech, L_FRAME);
& c1 m. `2 P( e Coder_ld8k(prm,syn);
5 P& D: P5 S: I Y1 } prm2bits_ld8k( prm, serial);
% W+ i# I7 Z( {0 ^9 p0 y% b}7 H! H; V9 z. T$ _% ~ k
void va_g729a_init_decoder()
4 T2 R6 w: t$ L$ }, C{
b, C+ M( j7 O( }* i" jextern Word16 *synth;& s# {' q: u( S' a0 M$ S
bad_lsf = 0; /* Initialize bad LSF indicator */
1 }/ X: l+ }( K( u Init_Decod_ld8k();3 V/ H% v7 v, e2 m- l9 R* L
Init_Post_Filter();/ @. d, C/ U, v8 }2 R0 F
Init_Post_Process();
6 }7 h+ `/ G) ^! N}; a& l* g" S8 t4 L- m
void va_g729a_decoder(unsigned char *serial, short *speech, int bfi)* \: K+ s1 X& t9 u" f
{- J g8 n j" m. `
extern Word16 *synth; /* Synthesis */4 x: @5 y, p# R3 P( E) e
Word16 synth_buf[L_FRAME+M];3 U$ H0 |+ P# n4 w
Word16 parm[PRM_SIZE+1]; /* Synthesis parameters */
C2 e1 ?/ x' E( MWord16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */% O4 n3 [- i3 U/ l3 Z
Word16 T2; /* Pitch lag for 2 subframes */" @1 n( h( u( `
Word16 i;
- ?; v+ x6 y& L5 bWord16 voicing = 60;
+ Y* b1 t7 ~ k* f: jWord16 pst_out[L_FRAME]; /* Postfilter output */
) _& G9 S- U; G" n( {Word16 sf_voic; /* voicing for subframe */8 w# ~+ B3 N3 `" A# n) ]
voicing = 60;4 T Z7 R$ i' K" n3 V! F& E1 C. U
bits2prm_ld8k( serial, &parm[1]);! c$ O4 P2 [2 q* ~3 u
parm[0] = 0;
3 a; s: B! M( u# T$ L7 R) c ' ]: u8 n3 s# M" A
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
) c0 i& Q$ ^: t' o8 F7 Y+ ~* i. z5 JDecod_ld8k(parm, voicing, synth, Az_dec, &T2);
/ h, l: B- |: d" E//--------------------------------------------------
3 U0 C6 z# W! N7 V! Tvoicing = 0;+ Q6 h' y2 G$ O/ p/ W A+ G
ptr_Az = Az_dec;" X3 X" E* ~$ X w
for(i=0; i<L_FRAME; i+=L_SUBFR) {) u$ d+ H! H8 C' V+ T
Post(T2, &synth, ptr_Az, &speech, &sf_voic);# Z- k& W6 M# F4 H
if (sf_voic != 0) { voicing = sf_voic;}
$ C* ~! K u2 P: j7 Y ptr_Az += MP1;& T t+ O1 l; f F5 T- U- N, x
}, I8 g' M7 x: j- Q
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
- R( Q9 I! f0 C4 D! ]+ n//---------------------------------------------------
) ?" J+ @- y8 _+ `: T6 x# R Post_Process(speech, L_FRAME); . X# c0 B9 v0 r: r5 f% _9 ?+ |
}9 Z' k4 |" d' P
3 ?1 L$ B' c! ~' N y% s |
|