找回密码
 注册
搜索
查看: 8104|回复: 0

g729a修正与lib编译

[复制链接]
发表于 2011-6-8 16:07:23 | 显示全部楼层 |阅读模式
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/
% ?. z4 B4 \3 j) p下载以后需要修改bits.c文件:$ j# u. C9 m- D# V- u
我仔细研究ITUG729代码后发现:
$ d' W$ z) z' m( K编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流
$ v6 e7 f5 H9 t8 {0 g+ M+ }- ~,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。+ C& Y( `) X* ]' q2 B% A
& V& L9 x! c# y% p7 K) `
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。
) U9 t; \; C' d6 F2 y  Q" ]# y  A/ u/ c$ [8 Q& L
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。: E6 X& {1 @- e& _8 L% D" _
我们打开bits.c,就能看到里面定义的如下4个函数:9 l- [1 j, s. x/ r, e
static void int2bin(int   value, int   no_of_bits, INT16 *bitstream);
  D; V  r. ~4 T# E2 ^6 s+ fstatic int bin2int(int   no_of_bits, INT16 *bitstream);# w7 [5 u: ~- r) E1 X2 \
void prm2bits_ld8k(int   prm[], INT16 bits[]) ; 7 p  c5 ^1 R, `2 l3 [  J, x% B" E
void bits2prm_ld8k(INT16 bits[], int   prm[]) ;
% ~  f. s8 a) L/ N这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:# h, P- I! y/ o
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ;
& Y+ t: l7 ^% q' y% [static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ;
8 @( w* _9 T7 B0 ~8 _: p0 t% j( d9 a3 J1 J2 h" u/ j
void prm2bits_ld8k(Word16 *para,unsigned char *bits)- y+ G$ m! H$ j$ q; M5 D
{1 F' h2 E# H' b
   int i;
5 d4 ^% e; w6 G4 n) ^) K   int bitpos = 0;
' b* b+ F3 B/ R* v" O# Y* ^   for (i = 0;i
5 o6 J# C; }1 L, Y8 Q( d0 [8 m+ Q/ V+ {+ p; k; h
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)) B' ~) A9 s* q! Y) ]: V
{
& k+ m/ t' y5 h' Z1 c+ R6 p   int i;
/ \, J. s3 r3 g   int bit = 0;
6 z/ r" N; y! u0 {9 r   unsigned char newbyte = 0;8 q4 I  p# I4 z) p% V
  
' ]( x+ Z$ R5 f, u% J   unsigned char *p = bits + (bitpos / 8);' a  R* B5 W& K$ C- D4 C
   for (i = 0 ;i > (bitlen - i -1) ) &0x01;
: B. V6 |4 {+ r. \; ?* p5 I! z: }newbyte = (1 % a( l* k9 ^7 X' m, D
bitpos++;- }) _6 N& l; {, @7 ]2 w
if (bitpos % 8 == 0)" F$ e  V1 m) j' G$ F$ ~' }& T
   p++;
& _: g% z6 O' }0 G   }
. r8 P- G* g! V* o5 Y1 b: S# F}
3 a% {; y0 k; d* F$ P* a
+ M" U8 Y% v! Lvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
/ ]. Z, C8 Q  R: a' y{$ c9 E. P; l1 r* G' R3 _
   int i;3 i7 c- w2 U0 K) f
   int bitpos = 0;+ \/ o; ^5 m3 W; m
   for (i = 0;i- }$ S# o+ }! F  p" G

/ j$ z( `; j( j8 h/ K8 G8 V7 H- bWord16 byte2bit(int bitlen,unsigned char * bits,int bitpos)! N: p3 n& n7 Z, d7 y# \) L2 l
{3 y, Z7 ^( }- q" u) K4 w0 k
   int i;
0 u" u! i: Q8 T# E   int bit = 0;
. _# i6 {. l0 u* E6 t  e( s1 U   Word16 newbyte = 0;
6 ]: f3 G6 A6 N9 ^0 S   Word16 value = 0;: e7 Z  V, F3 p
  ( l2 \% {6 [) I- [( C& w
   unsigned char *p = bits + (bitpos / 8);1 l! d/ b8 ~' n( W. E  w9 U/ ]
   for (i = 0 ;i > (7 - bitpos % 8)) &0x01;, O+ u3 v' ~3 [5 T, o
if (bit == 1) {
5 ~& K& H' T* T3 R9 u   newbyte = (1 + b3 C6 p& b/ n& r" Z- c+ G, \
   return value;
4 T0 r& K- A' Q0 X% q}
8 v) }, t3 R4 q' q通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。
: H7 I$ j# P, L8 D' C3 M, B* s+ j7 I! g2 y$ \7 X/ H
编码器的代码能采用如下的修改方法
: Q$ _7 S5 z9 O( R* k& t(1)修改coder.c:0 W- ~! @- z# ]8 o- {
unsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */5 m( P# J2 T8 E8 V' ~- d
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):
  D' Y$ Y! G( J1 G5 o   frame =0;- l" ^7 y6 d% X% M
   while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)9 r6 ?. J) d* y- e
   {  J! y8 J/ |8 [& ?
printf("Frame =%d\r", frame++);" B* Y6 y/ H( \* K
Pre_Process(new_speech, L_FRAME);' L- R* P& A  N3 F
Coder_ld8a(prm);
( w, j9 B6 z8 o" c; Z# M& d) nprm2bits_ld8k( prm, serial);( j/ ]- Z$ K" e+ u
fwrite(serial, 1, SERIAL_SIZE, f_serial);$ t6 z# x, ^# I# {
   }
" ]* K9 s- m& g# }) D* b   return (0);
! t" i4 X; ^3 R# S: G
6 a1 p2 [9 [" e6 m! v, C: ?4 c(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:) X+ S0 D) j5 L. c0 I
#define   SERIAL_SIZE   10! V  h, {; S1 ^) v* [! @+ o( C. M* L/ @
" j) ?* ?5 E2 y
(4)解码器decoder.c进行类似的修改(关键部分代码):
9 k3 a1 z( e- s1 B+ U   frame = 0;
# i8 n! |9 }& g. ~- T2 r- u   while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)% h6 _: Q- u5 O7 C/ I$ Q2 U3 ]
   {2 n3 Y) }, E7 C9 w+ V2 [# p
printf("Frame =%d\r", frame++);
3 s6 m1 d* u1 c; z7 E3 n# y2 Kbits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */" w6 m+ X- Y8 Y: j. y$ i! |$ c3 r
parm[0] = 0;   /* 假设没有丢帧 */# G7 g2 F9 X/ r; R  s
parm[4] = 0 ; /* 假设数据效验正常 *// @- C: l: |# X% C9 [# t
Decod_ld8a(parm, synth, Az_dec, T2);1 F1 X4 O3 [9 w, o& K/ F! r8 e. _
Post_Filter(synth, Az_dec, T2);
! P5 B( n- h+ Y6 NPost_Process(synth, L_FRAME);5 F& |/ m% y9 M8 J+ x4 e! o
fwrite(synth, sizeof(short), L_FRAME, f_syn);6 m' \( g+ `) O# H, W
   }1 \; }  b1 {5 i- P
   return (0) ; 8 j! e8 f6 h/ o& A; F2 Z3 e
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。& |; M$ U8 g7 `

- r+ ]! C) L! T) A3 Z6 D1 O" 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]得到,应该就能了。3 G% M$ t/ \2 x& n$ l
封lib:
( m7 v6 i% _( }3 mva_g729.h. k; R6 ~+ G- o! `
#define L_FRAME_COMPRESSED 10
' [, L# z1 q* c/ ~  L6 ]! v9 f7 l0 n#define L_FRAME            80' l- ]9 I- p" ?4 [! A1 I/ }4 ^: x  o4 L
#ifdef __cplusplus " [$ a1 p/ B' o% B! j; t- q
extern "C" {
  b( _. @. }) Y#endif
: ~; p( W9 ?& ^. ^1 _void va_g729a_init_encoder();7 X9 _" i+ c/ M+ O; V, d* B
void va_g729a_encoder(short *speech, unsigned char *bitstream);
( Y5 e- o8 _1 v2 k# g2 I+ H2 Nvoid va_g729a_init_decoder();
; s' V" q  k9 \" Jvoid va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);) p/ C) A+ T! u( Z1 ~
#ifdef __cplusplus " a' ]4 _0 ]+ x; z9 ?) o
}
$ {/ a" O9 u9 Q5 |! O) x7 |0 K#endif# P! b) G6 i- S( z/ U/ C1 L
va_g729.c' s) ~5 s: k4 K+ ~! K8 E
#include <stdio.h>7 z) R# |+ {! \
#include <stdlib.h>- T4 ~- \+ q+ B3 R4 t; k3 C! B
#include "typedef.h"7 F. l+ c/ p$ y9 [
#include "ld8k.h"
2 W# q9 Q  W6 d" K% ^; o+ JWord16 bad_lsf;
; i2 P5 J5 L# n4 {! ivoid va_g729a_init_encoder()
  W! U% |9 R% }7 z  c{* J& p  W& R: e$ l) s4 z# b
    Init_Pre_Process();6 R2 u1 c( l, D. G6 x
    Init_Coder_ld8k();
1 E5 o4 Z6 U  m: {/ O1 y+ |}0 [3 g; @; p2 ]+ C  `7 O, Q9 W
void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)5 `6 B( c& X* O4 B/ z( y  l6 r$ h$ e
{     0 ~' g* c7 ^+ U9 f( \9 S
    extern Word16 *new_speech;       /* Pointer to new speech data           */
, @* Q& {& M9 _+ H    Word16 prm[PRM_SIZE];            /* Analysis parameters.               */+ t! A' `2 k! @. g
    Word16 i;
" `) P2 ^  V9 ?/ O$ E2 [Word16 syn[L_FRAME];
  p5 S0 D& }3 y    for(i=0;i<L_FRAME;i++). L9 n( b( g" s( k5 l
{; f& a9 }/ K; b8 \9 c2 _: w
   new_speech = SpeechBuf;$ E$ C3 k/ l  o3 c1 P
}" n3 e% U4 @- j  c; v" O; N  q
     for(i=0; i<PRM_SIZE; i++) prm = (Word16)0; . W; L$ p; M& f# J
    Pre_Process(new_speech, L_FRAME);
8 A* B% D: b0 E. P' e    Coder_ld8k(prm,syn);
1 ~9 V" }" N% Y7 e- s! l: K    prm2bits_ld8k( prm, serial);$ E! }$ y% Z7 m! ?
}' z4 k' @6 D5 v7 C3 o5 J
void va_g729a_init_decoder()6 W+ ^$ a% _2 f9 r8 B' H
{
, g' U0 ]" P& Eextern Word16 *synth;9 a" W* b2 a, X+ h  t+ s
    bad_lsf = 0;          /* Initialize bad LSF indicator */& f2 w) D/ G1 x+ N- s( g# z
    Init_Decod_ld8k();
  j, Z& E' f) e0 U7 @: R    Init_Post_Filter();( \% W3 S2 e7 z3 }% l1 y
    Init_Post_Process();" \& [! [) `0 e8 R
}
: l1 O0 j. ^% t9 Hvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
( @; w# V  `* ^) S1 B{
/ ^) E) J* T; [% c: [* a% v$ sextern Word16 *synth; /* Synthesis                   */
& r' S: F( H% V  rWord16 synth_buf[L_FRAME+M];/ {6 P2 |: [; N: h7 m
Word16 parm[PRM_SIZE+1];             /* Synthesis parameters        */7 u5 y3 a; Q2 `. V& g1 P+ s, T4 j
Word16 Az_dec[MP1*2], *ptr_Az;       /* Decoded Az for post-filter */
' l" J! X8 x6 H$ gWord16 T2;                           /* Pitch lag for 2 subframes   */
1 m. I, [) O$ Y/ g9 E1 NWord16 i;
& z, m3 L5 X4 K% T8 ]Word16 voicing = 60;( V5 {8 p! M; f& o
Word16 pst_out[L_FRAME];             /* Postfilter output           */7 e- H2 W) h; ~" _  B' Z1 w
Word16 sf_voic;                      /* voicing for subframe        */
- ^" _3 d0 Z' m2 k+ g1 mvoicing = 60;8 F7 f# p& `3 l& W8 `+ W
    bits2prm_ld8k( serial, &parm[1]);7 U( |: k5 G1 e9 [
    parm[0] = 0;   
( ?* W9 f0 w$ h$ x7 U" [* a+ L; m          6 n" p7 ]6 V" _3 P0 v
    parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);
) w$ U% _: ~2 O4 U# f( o1 [Decod_ld8k(parm, voicing, synth, Az_dec, &T2);# L, G# v7 w0 T
//--------------------------------------------------
8 ~- [4 j' F+ S0 Z) |. N$ d: @voicing = 0;3 G. H; q9 r3 r9 X+ E( n
ptr_Az = Az_dec;
- J+ [) K# |6 J0 d" Bfor(i=0; i<L_FRAME; i+=L_SUBFR) {
8 |9 p8 R* D  u$ p: _2 o) e   Post(T2, &synth, ptr_Az, &speech, &sf_voic);
4 `  [+ P+ M1 w1 y   if (sf_voic != 0) { voicing = sf_voic;}0 \; ?% @( ?1 n% B; l& w
   ptr_Az += MP1;
) o" B% D% @  \" i  T6 T0 v}
- ^- H3 v4 Y; n( qCopy(&synth_buf[L_FRAME], &synth_buf[0], M);  d- f- h+ k5 A' d7 Y) r
//---------------------------------------------------
2 E, ]0 J/ _; c% r0 I% e5 o# c    Post_Process(speech, L_FRAME);   
% s( L" Y: \5 _) }}2 e6 `2 V6 r: B8 p* m$ n
+ r- ~; U: z4 a; m0 l3 u+ y
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2026-6-18 06:05 , Processed in 0.019209 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表