|
|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
% S/ s5 Z( J; j" t下载以后需要修改bits.c文件:) }4 _. y: L' k# v
我仔细研究ITUG729代码后发现:
; o. E, L e7 t' S9 |5 J编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
+ G7 r) O/ c7 c,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
2 H, ^2 x8 ~* ~& G" Q( L
! u- y8 a0 P* k* k, |/ T/ iITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。/ o( T/ O2 [$ Y+ U: L- S0 Y
5 ~3 x+ x/ L2 ?那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。* s8 V. k" ~' I8 \) B
我们打开bits.c,就能看到里面定义的如下4个函数:! N/ |# J: A+ _' Q4 N
static void int2bin(int value, int no_of_bits, INT16 *bitstream);
" _4 M" A5 c2 ystatic int bin2int(int no_of_bits, INT16 *bitstream);( b7 |/ b' z- B1 g3 S+ D
void prm2bits_ld8k(int prm[], INT16 bits[]) ;
$ u# _& @* Z5 j# jvoid bits2prm_ld8k(INT16 bits[], int prm[]) ;- Z0 O9 N, F% r3 x- r4 T: E
这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:% u+ c2 h* Q) |* h
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
\! x: K* o* K( z: l6 G4 M `# H: Nstatic Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
4 Q9 j) J8 @4 H9 }- L9 K: @/ D3 l b. R5 h) Y t. o$ y' Z
void prm2bits_ld8k(Word16 *para,unsigned char *bits)/ y/ p9 V' @/ c2 c6 ~
{
( I& f; h* H. g! w, Z$ p% j# @ int i;
8 R8 z5 B( I1 v, d% l; i int bitpos = 0;
2 {) S% f- ^. x, g/ `8 t+ m for (i = 0;i
. l' M" U2 p* D3 E- n; F4 v |+ u8 l, r5 ?: D# p. _4 i @, {. J
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
. s* R& b5 l( W4 C4 t" `8 n7 l{" H6 U& x+ ]) D4 j+ v: P- M) L
int i; j" G6 N) ^3 D1 V
int bit = 0;
7 y- Z* Q+ S$ M: } unsigned char newbyte = 0;. y9 x3 H. A" g/ Q' E- H) q2 E% h
% d# f4 n1 ~7 O) e, ]* T unsigned char *p = bits + (bitpos / 8);
, _$ D2 ]% p9 A8 E; F4 ~5 V for (i = 0 ;i > (bitlen - i -1) ) &0x01;1 x, ^! p5 \' e, C% d) S
newbyte = (1 ; m( u0 @6 R4 J1 z( I/ T$ u x2 }
bitpos++;
4 w' J. K: E a$ @. L, Sif (bitpos % 8 == 0)
: w' l/ y* e% b+ S, e p++;
; T( K( V% q7 ^& J: b" ^ }
' x2 O3 [( z, S5 F}
3 t9 Y7 N; [5 v$ V, w# {/ |4 L5 p3 M: V; K' @4 m; v h6 s
void bits2prm_ld8k(unsigned char *bits,Word16 *para)
$ j8 W |3 r2 B' r1 N. w1 F{2 u/ K' i$ z" a2 g
int i;) j" B& S" |" d
int bitpos = 0;3 \4 \# `! ]- i; J
for (i = 0;i
; W5 i% t0 S2 O
- Q; w& M% e8 ]' T( U& gWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)
2 _8 M; W4 ]7 b' H) w! J/ P( k7 k{
( ?' T* Q! O- O! B int i;
: m& [/ l7 U- |8 i int bit = 0;
4 Y2 m9 a/ M0 T2 O% |% F" R Word16 newbyte = 0;7 C4 x" t) X' i( x9 s6 i
Word16 value = 0;& f: ^ {6 g0 ^; A6 U
+ z \" _8 t& a% _8 D5 P" n1 c unsigned char *p = bits + (bitpos / 8);$ y! w% K( b9 h; [# q1 U# D
for (i = 0 ;i > (7 - bitpos % 8)) &0x01;+ I4 p, n; O: x% Q
if (bit == 1) {
1 t" i, C3 h( c- }7 Y/ m# r0 C- B8 b5 c newbyte = (1
, b! c6 t7 g1 `% a/ }. N1 F8 r: n return value;
* |0 r' H5 f$ d3 N7 O}
( r$ G8 G V7 _1 T, U通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
/ Z7 |. i3 T' U5 T3 Q' ]1 `% ?9 C0 k3 j* r) |1 o: d6 f! z
编码器的代码能采用如下的修改方法
# d$ E9 D* e0 Y8 K% [( E(1)修改coder.c:6 t7 N" Z& t: v+ q; ]
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */: A. { a1 F J6 }
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
; |- D4 I; d' [. s frame =0;( O4 n6 r) ^7 ?$ E3 L1 Q
while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)9 n8 @3 R, Z( M
{
! q$ M; ^/ n* R9 p; {) Y& eprintf("Frame =%d\r", frame++);( X8 n5 A$ h6 s
Pre_Process(new_speech, L_FRAME);; p+ Y! g8 a v
Coder_ld8a(prm);
& x! b4 y* `* Z1 x- n+ k+ O, ^& {prm2bits_ld8k( prm, serial);
0 [8 x; ]- ^6 p# u. d& ?% I) }fwrite(serial, 1, SERIAL_SIZE, f_serial);
# Q$ z, Q4 W. k* q5 \ }
% @8 t+ Y+ G, y) |! f4 q% h* _ return (0);
# e! J5 Q3 N1 X( A3 D) f1 W9 j( s3 l l" ~4 r# \8 Q
(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:2 I8 T( `" S6 q8 t7 R0 A
#define SERIAL_SIZE 107 k. e7 j1 V6 S, W1 ?
( |) _* T" }' o x+ t/ [
(4)解码器decoder.c进行类似的修改(关键部分代码):
) N7 i3 \; S1 q frame = 0;
0 Z- d5 _ o! \/ h) ~% y0 g& Z' ~ while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)2 }& F) P6 r" R
{/ m; u9 I2 H6 J# N `. {2 V
printf("Frame =%d\r", frame++);) Z8 f- I3 _1 A+ t1 W
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */
) X& t9 n& h) ]* D0 Q: m2 f% Nparm[0] = 0; /* 假设没有丢帧 */- F$ E1 r& e7 ~. u+ R. M
parm[4] = 0 ; /* 假设数据效验正常 */3 l( @' I+ L( h ]
Decod_ld8a(parm, synth, Az_dec, T2);
& K# u: U. X' m, P& w) S; JPost_Filter(synth, Az_dec, T2); 1 R9 ?# Y, d9 e; O' C5 N/ P
Post_Process(synth, L_FRAME);
% O) m2 `' Y, X% I$ ]' [fwrite(synth, sizeof(short), L_FRAME, f_syn);
4 o5 [/ V! k/ I: Z5 D" Z. S0 R }
) \+ {4 b5 q, V( V; O9 s return (0) ;
3 r- j- V h8 N- a通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。" c) Z9 f4 s# l& [
* C v5 b$ H9 m! {
修改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]得到,应该就能了。# M. ?. F) X' E: s5 P
封lib:' g% S6 T" K0 ?% M* j) C
va_g729.h
3 _# x/ x+ \0 L N$ L#define L_FRAME_COMPRESSED 10
! I6 t; ?' c+ A) r9 E! t#define L_FRAME 80, t/ `# C M3 x& E3 }4 q' y8 Z
#ifdef __cplusplus 1 ~* D3 D1 y- P+ V7 r: |
extern "C" {
+ i0 \0 C$ z1 p: V* {& Q#endif$ `# h4 J( x- d$ F7 w, n+ E
void va_g729a_init_encoder();5 r4 [ ?( U1 z0 L7 c, @( u9 ~
void va_g729a_encoder(short *speech, unsigned char *bitstream);! T+ x# G4 ~; c+ g4 {2 b; n
void va_g729a_init_decoder();: e4 o g/ ?* D5 s$ ^
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);0 V3 e) y1 T% ?; {+ N1 t
#ifdef __cplusplus
7 R" l! x; `3 q: s3 }4 K}
. t( i4 P; k# h) d# Q#endif
# N& t# b3 C( G) B5 s, \7 \; r; E( Lva_g729.c
; F* P: L4 E) q& K8 u! X9 U: M#include <stdio.h>' K7 E+ `7 F a* H, I
#include <stdlib.h>
, {# o- g+ T' C% } J) U#include "typedef.h"5 ~) T$ |7 [0 B$ `' x! D! C; y
#include "ld8k.h"! S; h) y1 U" T* d
Word16 bad_lsf;: ?. s0 |: A, ^. ]$ R
void va_g729a_init_encoder()
9 N+ X0 }+ p/ ?9 j* O8 g9 a{
3 M( @4 t: \$ ?' S Init_Pre_Process();
o8 T3 [! G; ~( C$ T Init_Coder_ld8k();
4 ]0 a; g" @1 q: W}5 T: @' Z+ J. f2 t
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)& f8 X' z1 z X/ Q4 o& V3 p
{ 4 f# h" m2 _, N: `2 ]
extern Word16 *new_speech; /* Pointer to new speech data */
( J+ G, t4 Z5 d8 D5 X7 Q! {0 M Word16 prm[PRM_SIZE]; /* Analysis parameters. */- J& U0 n ^! ^1 ^% K( q' `
Word16 i;) V @0 e3 N$ K1 k
Word16 syn[L_FRAME];& ~6 u$ d1 I9 {! i
for(i=0;i<L_FRAME;i++)
9 j. M5 }5 n; k5 P/ z{' j- d# i3 U8 A x
new_speech = SpeechBuf;* }+ c/ q" [2 n8 U$ _& g1 k0 f+ {2 C
}5 F1 I8 n; ~3 F2 S- F) r3 O
for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; , k x3 k( v5 e2 V. @( l
Pre_Process(new_speech, L_FRAME);# t# N' u) N. G: T7 A: c- X8 D& |
Coder_ld8k(prm,syn);8 y! `/ O( h/ d- J5 q
prm2bits_ld8k( prm, serial);
4 d( }) L" e* o# Q$ n- a}7 d+ g& x7 h4 t" Z
void va_g729a_init_decoder()
. ^0 z1 N" S8 ]& v7 v{. a- m1 m9 e" `* J$ F$ Q8 h) B
extern Word16 *synth;, b p3 R! h( g; w$ Z
bad_lsf = 0; /* Initialize bad LSF indicator */ W* j2 Y9 o% @/ M# _/ n2 Y
Init_Decod_ld8k();
/ s+ P; S/ {9 |* m; ` Init_Post_Filter();2 F) C$ J1 S8 n9 X# x: b
Init_Post_Process();
& e7 A- a8 w4 S1 [$ v}
" U7 ]! e: t: Zvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
$ @: t" H( x, Y0 H/ W: _8 l, A{
- _/ T k6 s; |( n Y: R' Aextern Word16 *synth; /* Synthesis */- t: K1 U3 @& V: s, ]* R
Word16 synth_buf[L_FRAME+M];
. _ O3 g# g( }( N* h/ RWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */- k# W2 t5 h8 Z. F
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter */3 E) r0 _6 n6 o( K
Word16 T2; /* Pitch lag for 2 subframes */
6 w9 V/ C5 M6 c: T9 e) I8 wWord16 i;( v3 V% D `* e _) E
Word16 voicing = 60;
# s/ f" A+ `$ D. |) A& qWord16 pst_out[L_FRAME]; /* Postfilter output */- d- n+ K9 u9 p# u' r0 P
Word16 sf_voic; /* voicing for subframe */! h1 R7 v/ i( B9 ]# S
voicing = 60;
$ h9 c, C; y2 c& {3 @ bits2prm_ld8k( serial, &parm[1]);
6 B! h) Y2 E _5 e parm[0] = 0; , Z9 z9 k" S+ `4 W
: B( U8 z; U5 ~ parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);6 l, R2 x# v/ Y! l5 j
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);
/ q" b) l8 U9 g- |. [% a3 }//--------------------------------------------------4 F, v/ ^% i7 `
voicing = 0;
% Z" f3 ]' I$ F/ u. t1 Tptr_Az = Az_dec;
) {: j x0 N2 w- _4 ?; s" ffor(i=0; i<L_FRAME; i+=L_SUBFR) {
0 }5 T5 ?& l) E, J Post(T2, &synth, ptr_Az, &speech, &sf_voic);
: w' U9 X* c( F* G' Q if (sf_voic != 0) { voicing = sf_voic;}4 \; g! f8 b6 g# ]# a
ptr_Az += MP1;; }; d$ k+ I5 l+ g) S
}& g" }: Q* t* f6 t6 o7 J
Copy(&synth_buf[L_FRAME], &synth_buf[0], M);+ w8 \' @( g# r; D4 e
//---------------------------------------------------
( y' l4 @5 W$ {( N# ]$ U- E Post_Process(speech, L_FRAME);
- B, C- ]% Z: g4 \}7 p4 h: h' _6 z$ Y
, S% `: d* J' e/ F+ e) l( i |
|