|
到这里下载:http://xiaokotei.download.csdn.net/user/xiaokotei/all/% P5 F: r0 P( I& U8 \
下载以后需要修改bits.c文件:
, n8 c: q0 C/ O0 E6 q8 O: ^3 H我仔细研究ITUG729代码后发现:, J+ ]0 v$ m5 C8 _
编码器的输出及解码器的输入不是编码生成的参数向量,而是经过1bit->Word16(即2字节)转换的bit流, R+ ? b' W, d
,从而使得编码器输出数据不是原始PCM的1/16(理论上g.729编码和wav的文件的大小比例约为1:16),而实际上,我们采用他的coder编码出来的文件由于上述“串行化”的原因和原始wav几乎相同大,而且甚至比原始的wav还要大个十几K。
) @+ _# a% U+ c [( O! Q/ B' g/ u/ {
ITU-T为了在标准化方针中进行丢帧隐藏测试,对语音编解码器参考软件的码流格式一般需求为ITU-T G.192中规定的格式,即用16位的0x007F表示1个比特’0’,用0x0081表示1个比特’1’,每个帧头会有同步字和包的长度。对于同步字,0x6B20表示该帧为坏帧,0x6B21表示该帧为好帧。这样固然非常好,不过。。。导致了编码后数据的增大。/ r' P/ a8 \. m# m
; v) E2 o9 ~/ W0 b% M$ g# s+ l
那么怎么来解决上述问题呢?解决的方法就是??去掉串行化代码,或重新编写串行化代码。( B5 S' E# O8 t1 W2 O
我们打开bits.c,就能看到里面定义的如下4个函数:
0 s, S& _& ]+ Z5 O/ ^$ t! O' @static void int2bin(int value, int no_of_bits, INT16 *bitstream);
: c c9 }" l4 L1 x, g: j& rstatic int bin2int(int no_of_bits, INT16 *bitstream);
; H7 L; w s$ J( Xvoid prm2bits_ld8k(int prm[], INT16 bits[]) ; 8 |% @7 ?, y0 M" r. G. F
void bits2prm_ld8k(INT16 bits[], int prm[]) ;
* h+ a+ v# F* A; d {( Y这个文件就是编码后文件大小没有什么变化的关键所在了,能用如下的代码替换:6 y( f3 i% r( E8 ~( E# F. U
static void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos) ; 0 v9 l7 g( x& ~' d m
static Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos) ; , i. g- |9 [* ]2 {4 I
$ l$ O+ a& b$ G0 D
void prm2bits_ld8k(Word16 *para,unsigned char *bits)
1 N$ \/ v# m# s/ v{
3 f' D( G; f9 q int i;2 W& d* g0 \5 |9 V
int bitpos = 0;
( i* ^. k" W7 a/ Y9 I+ z( z for (i = 0;i
' M5 F9 N8 W7 q, \7 z; o6 W9 Y! p- G
void bit2byte(Word16 para,int bitlen,unsigned char * bits,int bitpos)
$ `8 |" | n; W# r{
& B( m( E3 ^6 ]6 Q; Q H int i;* s- H! e% a) M8 Y' k' \% A
int bit = 0;5 y3 f: H) Y7 i9 P, S2 ]; p- [/ m
unsigned char newbyte = 0;1 ^1 r( u4 {$ y& d# P' r1 ~4 M/ q
/ x: @9 M2 p! @/ A. {+ e) k/ m unsigned char *p = bits + (bitpos / 8);
! J8 X5 H: m5 w/ o for (i = 0 ;i > (bitlen - i -1) ) &0x01;
, y( ?) A, k6 cnewbyte = (1
" F# i8 x5 x, S+ ?bitpos++;1 n- E# k7 |2 \: _/ i6 U
if (bitpos % 8 == 0); M9 n0 i R. F i* w) Z- m9 h
p++;+ D7 | i, Y. U# u( l
}
( q2 i! a( G2 g}& w6 y7 R" F C. p& x- g
+ O. ~/ t6 X h6 F2 P% kvoid bits2prm_ld8k(unsigned char *bits,Word16 *para)
3 Y1 y6 I1 F; M8 x" }1 z{* r o" F- d" M, [; ?0 O
int i;
. W( H8 H& f- p7 O9 V( a0 F int bitpos = 0;
6 v/ {2 i$ ^8 B for (i = 0;i
, Y$ h1 ]6 ^% ~* V) R4 |1 C5 z/ x1 @! `0 f
Word16 byte2bit(int bitlen,unsigned char * bits,int bitpos)% m3 X2 T Q. m3 |) x1 {& R0 K
{3 l( v6 i/ f4 N( Z
int i;
+ F- P! i$ M0 i int bit = 0;
* T* {& ^/ B3 s7 ^( ]( `& P Word16 newbyte = 0;; C9 C) _' O" ^ [* X8 `
Word16 value = 0;
! ]9 ?) k6 K- M7 t: c# x% Q$ j, \. M8 s
( Q. f* a% ^; ^, ]* p0 F' `" a$ E unsigned char *p = bits + (bitpos / 8);
, w6 K; \) }0 Y# G; l, v' e for (i = 0 ;i > (7 - bitpos % 8)) &0x01;
9 y G0 ?- t& {& h" {7 Aif (bit == 1) {
. y8 A5 S( {; M1 C! G newbyte = (1
1 M$ N! G1 K- h& {3 E# k return value;
4 R% P( p+ ]/ @ w+ A}
1 m, j4 Q9 u; H1 g通过上述的修改,已能确保,每次一帧160个字节的pcm16音频数据流,能编码成为22个字节的编码参数prm,经过改写过的prm2bits_ld8k处理后,会转换成为10个字节的最终语音编码数据,这个时候,才真正体现出g.729a的威力。9 ?; {2 M! }7 J9 G& l( |
! Z( p% Z. M+ N$ f! n' ~编码器的代码能采用如下的修改方法
% Q, |( ]6 m9 h: F+ l# J(1)修改coder.c:
( Q$ L/ g% P& yunsigned char serial[SERIAL_SIZE]; /* 输出数据的数据类型由Word16改为unsigned char */7 x9 R# Z0 q3 d0 _6 L1 b$ W. Y2 g0 Z
(2)修改coder.c文件,对编码器调用方式进行修改(关键部分代码):& q( x; g0 }* J& _
frame =0;
9 U: m6 q: R* I while( fread(new_speech, sizeof(Word16), L_FRAME, f_speech) == L_FRAME)
6 s8 l! T$ v v {
! K5 l1 {" h( T- Hprintf("Frame =%d\r", frame++);
5 w T1 X4 p4 k' VPre_Process(new_speech, L_FRAME);
- i9 [& Q* A" q/ dCoder_ld8a(prm);
4 {7 @$ v4 C8 q$ }# ]: S( |# Gprm2bits_ld8k( prm, serial);
% |6 \# f5 n2 g' efwrite(serial, 1, SERIAL_SIZE, f_serial);! K3 \* a6 i$ H) h$ N1 ?
}: u; n0 z: V; e
return (0);" ~" e) o% E- N% u
8 I: {+ f& B7 i. S8 Q6 l(3)把ld8a.h头文件中关于“串行化”长度的常量定义修改为10个字节:5 Q$ {4 f) e3 y1 l+ F1 g$ q
#define SERIAL_SIZE 10) G( W0 }- J1 N$ Z9 D
% \% S" c$ n1 Q* t/ z; ~" Q7 n7 B(4)解码器decoder.c进行类似的修改(关键部分代码):
9 `7 u# `0 v( M, L frame = 0;
/ {3 m% l/ ]$ z# l8 G while( fread(serial, 1, SERIAL_SIZE, f_serial) == SERIAL_SIZE)
- i5 M, W' T4 |9 Z {% V. R; [" i* e0 S r
printf("Frame =%d\r", frame++);5 Z4 z; q% P1 M/ B0 {
bits2prm_ld8k(serial, &parm[1]); /* 注意这里一定要是&parm[1] */5 v+ |. Y" d, w/ |, F! d! x
parm[0] = 0; /* 假设没有丢帧 */
. E! q: ?0 `& M3 |- p+ @7 vparm[4] = 0 ; /* 假设数据效验正常 */
) [4 ?; ^- f. `9 k* B% bDecod_ld8a(parm, synth, Az_dec, T2);* U) `5 z7 s/ L" S& @
Post_Filter(synth, Az_dec, T2);
+ }* {! s) C; K6 f4 z* @Post_Process(synth, L_FRAME);
% ] u1 h% j. a( {4 O. ^' o& Dfwrite(synth, sizeof(short), L_FRAME, f_syn);
. {: s3 I- }1 W% i. {# c5 v }: P% a+ P4 X$ Y. D7 O& c
return (0) ; 4 `& U; t2 J0 J% `0 y+ e
通过上面的修改,标准的ITU-T的G.729语音编码器和解码器就基本能达到1:16的编码效率了。
# j* p! O) X) X& b/ h4 w1 n6 E* z8 E# n# R1 E6 A$ L- 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]得到,应该就能了。" Y; q; L9 q6 T4 v9 N
封lib: ^$ O2 i( K0 H$ W4 `! F9 P
va_g729.h8 o- b& {( {) l! z
#define L_FRAME_COMPRESSED 10/ j5 G2 D3 ] w: i
#define L_FRAME 80$ y! {" N$ x9 ^' ~
#ifdef __cplusplus 1 e1 p7 h6 z+ \1 f' z/ r! _
extern "C" { 1 Z N: C' d, r# G) M
#endif
$ n* |& O. \% W5 c @5 hvoid va_g729a_init_encoder();
' ?+ c& O* E) j5 v8 v3 T- Cvoid va_g729a_encoder(short *speech, unsigned char *bitstream);
) }4 F, x' C1 S u$ C( c5 Vvoid va_g729a_init_decoder();- R! Q, e" J: o" T& f
void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);
) J; T7 I. o0 n1 @7 x) a#ifdef __cplusplus : `6 E1 K+ J2 a. @; P1 b ]
}
* O, P( b" D$ P* Y5 @6 N4 C#endif
D c) ]! K( |6 ~2 H4 {6 x2 K% Rva_g729.c
! f/ Z/ h& Q$ I* O; b! Z#include <stdio.h>3 }1 \ N+ b4 w5 n1 S! R) B" p, x8 o
#include <stdlib.h>( s: C2 Y" n+ R# a& d/ k
#include "typedef.h"
: k( e. ~% i# ?( M A3 d$ e#include "ld8k.h"
8 M Y, }2 s8 ?" M5 aWord16 bad_lsf;1 k6 S t% F1 ]* b9 Z
void va_g729a_init_encoder()9 t G o, y; u: y% k8 C
{
: G' d3 B! k5 u" o, d. v' [4 e1 C Init_Pre_Process();
% Z: c" Z+ r w& W+ e- ] Init_Coder_ld8k();
; \1 D0 b6 z+ H/ L}
5 G$ y1 A8 I) r! r9 ^void va_g729a_encoder(short* SpeechBuf,unsigned char * serial)$ L3 z& K' f/ o0 p
{ # F' Q! C& I4 O. u& Q, [
extern Word16 *new_speech; /* Pointer to new speech data */" u( q' F& \# a( \- r
Word16 prm[PRM_SIZE]; /* Analysis parameters. */* P. o* y6 U) C
Word16 i;( U* W5 o# N3 o! u, i5 J
Word16 syn[L_FRAME];* c2 d/ a/ d% e+ I" I5 C
for(i=0;i<L_FRAME;i++)
% W2 n$ R6 O5 V, u{' ^' [; l6 {( g) r* |
new_speech = SpeechBuf;
/ B* B' F: o* `$ a4 I, l+ C8 Y2 v. S}
$ Z' K8 D9 K# _8 Q1 n for(i=0; i<PRM_SIZE; i++) prm = (Word16)0;
% T; Z3 M+ p1 e7 d Pre_Process(new_speech, L_FRAME);- W) E6 \' F$ V
Coder_ld8k(prm,syn);. x% n$ c3 \: E# P! e( n. p
prm2bits_ld8k( prm, serial);
5 V+ u( q# R, [7 }# l; _ D}
. ]7 T; W4 N' Y, J8 i/ ~$ @2 e7 Evoid va_g729a_init_decoder()
" y" @! N+ V9 C5 ~: l% T# f9 R% O1 V{& g9 @, B0 e' q4 L+ c
extern Word16 *synth;
) P2 V% c9 J% R( x. q bad_lsf = 0; /* Initialize bad LSF indicator */2 k! l* K* n+ u1 B2 {0 d
Init_Decod_ld8k();% A4 G# W4 ^0 u p
Init_Post_Filter();! P1 f9 {5 _% j# L8 G# i
Init_Post_Process();
, R8 g. U% d0 ~# L! z" M: n1 n8 Y}
' B: i: i% ]* U' r7 G0 [2 Hvoid va_g729a_decoder(unsigned char *serial, short *speech, int bfi)
9 e# {$ e$ X% O8 z8 k/ C{3 ~0 i% e6 U5 W# B1 T
extern Word16 *synth; /* Synthesis */) m0 @* v4 L: u7 u9 M
Word16 synth_buf[L_FRAME+M];
3 A) C$ T7 B. Y3 k2 J. n+ KWord16 parm[PRM_SIZE+1]; /* Synthesis parameters */! v2 v+ a. t8 A ^* ~
Word16 Az_dec[MP1*2], *ptr_Az; /* Decoded Az for post-filter *// m$ }- v. y! h
Word16 T2; /* Pitch lag for 2 subframes */
/ e x# [1 g1 z& S. w4 p! i, ?% ^Word16 i;/ e- h g/ Y$ E8 _- X' Q
Word16 voicing = 60;
/ Y( `9 H- p5 h* P6 {Word16 pst_out[L_FRAME]; /* Postfilter output */* _" N7 y6 w1 s( U! G: C* U
Word16 sf_voic; /* voicing for subframe */; q" D2 W" F! Y
voicing = 60;
) }# O+ }; V/ j' y- d1 k4 Q$ _$ s bits2prm_ld8k( serial, &parm[1]);
2 Q l; s) F4 d, C3 y2 U' z parm[0] = 0;
0 s/ S; m! w# k, Y9 \. s " N. K& ~* s: V% g
parm[4] = 0;//Check_Parity_Pitch(parm[3], parm[4]);# e" @1 R- D' ^$ t9 L
Decod_ld8k(parm, voicing, synth, Az_dec, &T2);8 i3 w$ y, g& N' |1 {" ~
//--------------------------------------------------
& r7 B0 ^' g& f) ~, D/ p5 jvoicing = 0;
0 k" d ^! K0 } P) I6 b. X% Y- Nptr_Az = Az_dec;+ V# F8 P) |9 v( ?
for(i=0; i<L_FRAME; i+=L_SUBFR) {
8 `" \! H3 P% W& Q2 k Post(T2, &synth, ptr_Az, &speech, &sf_voic);/ p+ B0 r/ V, N9 S: m
if (sf_voic != 0) { voicing = sf_voic;}' O' {* L+ ` j
ptr_Az += MP1;. _* \0 t* Z5 v$ h& x/ I- I
}
8 k2 U7 s( x" l' f4 e ?: `Copy(&synth_buf[L_FRAME], &synth_buf[0], M);
2 A& l$ e% m z1 {8 ]* x8 `//---------------------------------------------------9 ^' L' o/ o# N' ~6 D5 [, r
Post_Process(speech, L_FRAME);
1 q3 N7 O9 l7 w) b9 e4 q}
: @: u N- ~6 w5 ~$ |5 Y1 C1 u% B, ?
|
|