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

g729a修正与lib编译

[复制链接]
发表于 2011-6-8 16:07:23 | 显示全部楼层 |阅读模式
到这里下载: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
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-8-14 00:58 , Processed in 0.019454 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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