Intel® Integrated Performance Primitives
Deliberate problems developing high-performance vision, signal, security, and storage applications.

G7.29 encode decode

Ulrich_H_1
Beginner
853 Views

Simple question: how to encode / decode G7.29 with Intel IPP ? Which functions to use ?

I checked all the G7.29 and G7.29.1 functions at http://sc.tamu.edu/help/intel/ipp/ippsman.pdf and http://tx.technion.ac.il/doc/intel/ipp/ipp_manual/IPPS/ipps_ch9/ch9_g_729_functions.htm, but they all seem to implement much more sophisticated tasks than a simple encode / decode...

Any advice appreciated, especially sample code / code snippets,

Ulrich

0 Kudos
11 Replies
Shaojuan_Z_Intel
Employee
853 Views

Hi Ulrich,

IPP no longer support speech codecs, but you can find those functions in the legacy libraries here https://software.intel.com/en-us/articles/intel-ipp-legacy-libraries. Thanks!

0 Kudos
Ulrich_H_1
Beginner
853 Views

Thanks a lot, Shaojuan !

Actually I found a function

static APIG729_Status G729Decode(G729Decoder_Obj* decoderObj,const Ipp8u* src, Ipp32s frametype, Ipp16s* dst);

but not yet the inverse function G729Encode. Do you by any chance know the name of this function ?

Thanks in advance,

Ulrich

0 Kudos
Shaojuan_Z_Intel
Employee
853 Views
Hi Ulrich,
 
Here is the name of the encoder function. APIG729_Status G729Encode(G729Encoder_Obj* encoderObj,const Ipp16s *src, Ipp8u* dst, G729Codec_Type codecType , Ipp32s *frametype) which is implemented in encg729.c. You can find more information from ipp-samples/speech-codecs in the legacy package. Thanks! . 
0 Kudos
Ulrich_H_1
Beginner
853 Views

Thanks again. As indicated, I have downloaded https://software.intel.com/en-us/articles/intel-ipp-legacy-libraries for Windows, but it contains 2 folders "include" and "lib" only, no folders like "ipp-samples" or "speech-codecs". I do not have any samples at all and would be really thankful for a link where to get it from.

I understand I am supposed to use functions G729Encode and G729Decode from files encg729.c, or decg729.c respectively. I found these files in asterisk-g72x-1.3 download package (seems to be for Linux only, not for Windows). But there is no header file declaring these functions to the outside world, so I feel insecure if I am not supposed to use those functions that the headers declare instead (though I wouldn’t know how to obtain the parameters for these other functions).

I am sure that something is missing on my side that is prerequisite for solving this simple task. I have worked as a professional software developer for more than 20 years now and I did not expect a simple ordinary task like encoding G7.29 could become such an effort. So certainly there is a wrong expectation on my side, but I can’t find out what it is without a sample code showing which prerequisite is missing. Please advise.

0 Kudos
Ulrich_H_1
Beginner
853 Views

problem solved - I will describe solution in detail next week

0 Kudos
Shaojuan_Z_Intel
Employee
853 Views

Glad to hear you solved your problem, look forward to you sharing the solution. Thanks!

0 Kudos
Ulrich_H_1
Beginner
853 Views

Seems like I was triumphing too early: now I get an access violation on calling apiG729Encode():

Call Stack:

ippscl_9_8_1_1cbe0000!ippscGetLibVersion+0x14b93a
ippscl_9_8_1_1cbe0000!ippscGetLibVersion+0x7b665
CFDsp64!G729AEncode+0x31
CFDsp64!apiG729Encode+0x54
CFDsp64!CFVocBuffer::Put+0x716

Could ippscGetLibVersion really cause an access violation ?

Code snippet / context:

in constructor:

    Ipp32s nEncoderSize;
    apiG729Encoder_Alloc( G729A_CODEC, &nEncoderSize );
    CFVocBuffer::m_pgeoG729EncoderObj = (G729Encoder_Obj*) ippsMalloc_8u( nEncoderSize );
    APIG729_Status agsStatus = apiG729Encoder_Init( CFVocBuffer::m_pgeoG729EncoderObj, G729A_CODEC, G729Encode_VAD_Disabled );
    if ( agsStatus != APIG729_StsNoErr )
    {
      TRC( TRC_SUP2, "CFVocBuffer,CFVocBuffer", "Encoder_Init failed: %d", agsStatus );
    }

On Data (here is where it crashes):

    agsStatus = apiG729Encode( CFVocBuffer::m_pgeoG729EncoderObj, (const Ipp16s*) m_decodeBuffer, (Ipp8u*) m_encodeBuffer, G729A_CODEC, &nFrameType );

m_decodeBuffer: 00000000186885A0 size: 640
m_encodeBuffer: 0000000018688DA0 size: 2048

I can not see what could be wrong with the parameters passed on to apiG729Encode. Also took a look into memory at given memory addresses: contents seems to be OK.  

Any ideas ?

Thanks in advance,
Ulrich

 

0 Kudos
Tamer_Assad
Innovator
853 Views

Hi Ulrich,

 

Could you provide detailed information about the workstation environment?

- IPP samples (UMC/USC) version?

- IPP library version?

- Compiler?

- Windows version?

- CPU?

Also, which IPP linking method you were using?

 

Best regards,

Tamer

0 Kudos
Ulrich_H_1
Beginner
853 Views

That access violation problem is solved in the meantime (apiG729Encoder_InitBuff was missing). Now, phone call between two Snom phone devices both providing G7.29 works now, but when the one is set to PCM and the other one to G7.29, then there is only noise. I need to know exactly what apiG729Encode expects in its parameter "src":

  • linear PCM, PCM µ-Law or PCM A-Law ?
  • little endian or big endian ?
  • G729Encode_VAD_Disabled or G729Encode_VAD_Enabled ?
  • Frame size 20 ms or 40 ms ?
  • ... ?

Any help appreciated,
Ulrich
 

0 Kudos
Ulrich_H_1
Beginner
853 Views

problem solved - here is how it works:

We have to distinguish between

  • algorithmic framesize
    (constant 10 milliseconds on G7.29. At 8 kHz this means constant 80 samples of 2 bytes (= 160 bytes) per 10 ms on the unencoded / decoded side, and constant 10 bytes per 10 ms on the encoded side)
     
  • UDP framesize
    (must be a multiple of algorithmic framesize, typically 10, 20, 30 or 40 ms. This value is set in the phone device)

So for example if UDP framesize is 40 ms, then on processing an UDP frame we need to call apiG729Encode 4 times. Source code:

header must include g729api.h, for example contained in asterisk-g72x-1.3:

#include <ippdefs.h>
#include ".\g729aster\g729api.h"  // folder "g729aster" should contain all required source files like encg729.c, decg729.c
#include ".\g729aster\owng729.h"

our G7.29-class needs 4 functions: constructor, destructor, encode and decode:

CFCodecG729a::CFCodecG729a()
{
  // initialize encoder object
  APIG729_Status agsStatus;
  Ipp32s nEncoderSize;
  apiG729Encoder_Alloc( G729A_CODEC, &nEncoderSize );
  m_pgeoG729EncoderObj = (G729Encoder_Obj*) ippsMalloc_8u( nEncoderSize );
  m_pEncoderScratchMem = ippsMalloc_8s( G729_ENCODER_SCRATCH_MEMORY_SIZE );
  agsStatus = apiG729Encoder_InitBuff( m_pgeoG729EncoderObj, m_pEncoderScratchMem );  
  agsStatus = apiG729Encoder_Init( m_pgeoG729EncoderObj, G729A_CODEC, G729Encode_VAD_Disabled );
  if ( agsStatus != APIG729_StsNoErr )
  {
    TRC( TRC_SUP2, "CFCodecG729a,CFCodecG729a", "Encoder_Init failed: %d", agsStatus );
  }

  // initialize decoder object
  Ipp32s nDecoderSize;
  apiG729Decoder_Alloc( G729A_CODEC, &nDecoderSize );
  m_pgdoG729DecoderObj = (G729Decoder_Obj*) ippsMalloc_8u( nDecoderSize );
  m_pDecoderScratchMem = ippsMalloc_8s( G729_ENCODER_SCRATCH_MEMORY_SIZE );  // decoder scratch memory size equals G729_ENCODER_SCRATCH_MEMORY_SIZE
  agsStatus = apiG729Decoder_InitBuff( m_pgdoG729DecoderObj, m_pDecoderScratchMem );  
  agsStatus = apiG729Decoder_Init( m_pgdoG729DecoderObj, G729A_CODEC );
  if ( agsStatus != APIG729_StsNoErr )
  {
    TRC( TRC_SUP2, "CFCodecG729a,CFCodecG729a", "Decoder_Init failed: %d", agsStatus );
  }
}

 

CFCodecG729a::~CFCodecG729a()
{
  ippsFree( m_pgeoG729EncoderObj );
  ippsFree( m_pgdoG729DecoderObj );
  ippsFree( m_pEncoderScratchMem );
  ippsFree( m_pDecoderScratchMem );
}

 

int CFCodecG729a::Encode( BYTE* srcbuf, int srclen, BYTE* dstbuf, int& dstlen )
{
  // has to be fractional of 10 bytes (:= 80 samples)
  if( srclen % 160 > 0 )
    return dstlen = 0;

  if( dstlen >= srclen/16 )  {
    dstlen = 0;

    APIG729_Status agsStatus;
    Ipp32s nFrameType;

    // encode i x 160-byte frames
    for( int i=0; i<(srclen/160); i++ )  
    {
      agsStatus = apiG729Encode( m_pgeoG729EncoderObj, (const Ipp16s*) (srcbuf+i*160), (Ipp8u*) dstbuf+i*10, G729A_CODEC, &nFrameType );
      if ( agsStatus != APIG729_StsNoErr )
        TRC( TRC_KRN3, "CFCodecG729a,Encode", "encode failed" );

      dstlen += 10;
    }
    return dstlen;
  }
 
  return 0;
}

 

int CFCodecG729a::Decode( BYTE* srcbuf, int srclen, BYTE* dstbuf, int& dstlen )
{
  // has to be fractional of 10 bytes (:= 80 samples)
  if( srclen % 10 > 0 )
    return dstlen = 0;

  if( dstlen >= srclen*8*2 )  {
    dstlen = 0;

    APIG729_Status agsStatus;
    Ipp32s nFrameType;

    // decode i x 10-byte frames
    for( int i=0; i<(srclen/10); i++ )  {
      nFrameType = 3; // active frame
      agsStatus = apiG729Decode( m_pgdoG729DecoderObj, (const Ipp8u*) srcbuf+i*10, nFrameType, (Ipp16s*) (dstbuf+i*160) );
      if ( agsStatus != APIG729_StsNoErr )
        TRC( TRC_KRN3, "CFCodecG729a,Decode", "decode failed" );

      dstlen += 160;
    }

    return dstlen;
  }

  return 0;
}

 

0 Kudos
Tamer_Assad
Innovator
853 Views

Hi Ulrich,

 

Glad to know that you have progress:)

 

- How often do you see "encode failed"/ "decode failed"?

- G.729 is suitable for constant bitrate

-  "when the one is set to PCM and the other one to G7.29, then there is only noise"

    PCM (Pulse-code modulation) is RAW (uncompressed)  audio. G.729 is a compression/codec. You should format consistency both sides.

- 20 ms fame duration usually makes better results.

 

Best regards,

Tamer

0 Kudos
Reply