Skip to main content

DVI/RTP packets decode HELP

14 replies [Last post]
cs02lk1
Offline
Joined: 2007-07-04

Hi,

I need to stream audio and/or video to a PDA device. There is a trick here which is:
The PDA must receive the stream from a multicast address. For this I have implemented a Bridge application which joins the multicast group on behalf of the PDA and receives the Multicast RTP packets (which are sent from JMStudio) and Unicasts them to the PDA.(HP iPAQ) I had no problem implementing this. The streaming is done using JMStudio player which encodes the streaming audio data into a number of encodings (DVI/RTP in my case). I choose DVI/RTP and stream a .wav audio file.
Now I have to accept the packets and play the stream on the PDA.
The j2me application receives all the RTP packets successfully and I can extract usefull information from the packets such as: Timestamp, sequence number, payload type. The payload type is 5 which means it is a DVI4 encoding.
I use the following method to decode the samples:

public int decode(Object state, byte[] input, int inp, int len, short[] output, int outp) {
int sign;
int delta;
int vpdiff;
//int valprev = audio.Convert.byte2short(input, inp);

//int index = input[inp + 2];
int valprev=0,index=0;
int inputbuffer = 0;
int bufferstep = 0;
////////////////////////////////////
valprev = input[0] <<8;
valprev |= input[1] &0xff;

index = input[2] &0xff;
//////////////////////////////////////////

if ( index < 0 ) index = 0;
else if ( index > 88 ) index = 88;

int step = stepsizeTable

;

inp += 4;

len = (len - 4) * 2;

int count = len;
while(count-- > 0) {
if ( 0 == bufferstep ) {
inputbuffer = input[inp++];
delta = (inputbuffer >> 4) & 0xf;
bufferstep = 1;
} else {
delta = inputbuffer & 0xf;
bufferstep = 0;
}

index += indexTable[delta];
if ( index < 0 ) index = 0;
else if ( index > 88 ) index = 88;

sign = delta & 8;
delta = delta & 7;

vpdiff = step >> 1;
if ( (delta & 4) == 4 ) vpdiff += (step << 2);
if ( (delta & 2) == 2 ) vpdiff += (step << 1);
if ( (delta & 1) == 1 ) vpdiff += step;
vpdiff >>= 2;

if ( 0 != sign )
valprev -= vpdiff;
else
valprev += vpdiff;

if ( valprev > 32767 )
valprev = 32767;
else if ( valprev < -32768 )
valprev = -32768;

step = stepsizeTable

;
output[outp++] = (short) valprev;
}

((AdpcmState)state).valprev = valprev;
((AdpcmState)state).index = index;
return len;
}

which stores the result into a short[] array.

I then convert this short[] array into a byte[] array with the following way:

s is the short[] array
adp is the byte array

for(int g=0,k=0;g< 2; i++) {
bits -= 8;
b[offset + i] = (byte) ((ival >> bits) & 0xff);
}
}

The final result is loaded to the player as follows:

ByteArrayInputStream input1 = new ByteArrayInputStream(adp);
player = Manager.createPlayer(input1, "audio/x-wav");//create new player
player.addPlayerListener(this);
player.prefetch();
player.realize();

player.start();

The player begins to play but I only get horrible sounds instead of the original wave file

The player now initializes ok without any problem but I can only hear a meesed up sound rather than the original. So now I strongly believe that the problem is in the decoding of the samples of the DVI/RTP codec.

Message was edited by: cs02lk1

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
cs02lk1
Offline
Joined: 2007-07-04

for(int g=0,k=z;g audio.Convert.short2Byte(s[g],adp,k)

cs02lk1
Offline
Joined: 2007-07-04

I can not understand why they dont show up as I type them. Its really annoying. I can not type the real code. Ihave tried everything
What to do?

cs02lk1
Offline
Joined: 2007-07-04

Hey your point has to be right.

I changed the method as mentioned above and now I get a sound which sounds something like the chipmunks if you know them. This means that my sound is pitched and the voice sounds different.

Do you happen to know why?

Thanks again for your remarks

apestov
Offline
Joined: 2007-07-05

You are welcome.

Sorry, but I'm not in course of problems with code paste.

You have mentioned, that payload type is 5 (DV4, 8000Hz), but the corresponding field in the WAV-structure filled has value 16000. So you need to change it, because sound plays twice time faster than it is.

Andrey

cs02lk1
Offline
Joined: 2007-07-04

the reason why I has this at 16000 is because the original wave file I want to transmit is 16000Hz. so I thought I should use the same.
Now I have changed it to 8000 and it is rather slow comparing to the original one and with some samples of the wave file missing and the playback of the file is like it has cuts.
I think something is messed up with the sample rate as you specified

apestov
Offline
Joined: 2007-07-05

Hello,

Are you get success in your problem?

It is very strange, if you use 16000 Hz - it is pitched, if you use 8000 Hz, it played slowly. It is very unlikely, that it has 11025 Hz.

Thanks,
Andrey

bansal2945
Offline
Joined: 2007-08-29

Hi
I am getting RTP packets from a third party tool from which i can get rtp packet with many types Payload type. i am setting wave header with
sample rate=8000
bits=8
compressed code = PCM(1) //because any other pcm code gives error in j2me during player creation
but i am getting voice with a lot of distortion.
has anyone successfully implimented same thing then plz suggest me what should be payload value in RTP crosspondent to WAVE header in InputStream.

apestov
Offline
Joined: 2007-07-05

Hello,

It should be enough for the voice to have specified parameters. Of course, it will be not very quality sound, and it will have distortions like background noise or hissing.
Is it pure linear pcm? Is it exactly not PCMA (A-law) or PCMU (mu-law)?
Also, you can check is your pcm data are interpreted as signed or unsigned integers .

Is your j2me-device support only wave with 8000Hz frequency and with 8bit depth? Unlikely, that it doesn't support 8000Hz with 16bit depth, which is more appropriate.

Also, you can try use other payload type (smth like gsm or mp3), but if you device doesn't support it you will need to decode received data on your own.

Andrey

apestov
Offline
Joined: 2007-07-05

Hello,

There are some paste problems in the code for decode() method (after stepsizeTable[index]). It is goes in the right direction.

Do you you also put header before PCM-data? If no, you need to add to your decoded data wav-header. It's pretty nice shown here http://ccrma.stanford.edu/courses/422/projects/WaveFormat/.

If you already have added header, you can try to compare the result of decoding your method and adpcm_decoder at ftp://svr-ftp.eng.cam.ac.uk/pub/comp.speech/coding/adpcm_Intel_DVI.shar

Thanks,
Andrey

cs02lk1
Offline
Joined: 2007-07-04

step = stepsizeTable[index];
output[outp++] = (short) valprev;
}

((AdpcmState)state).valprev = valprev;
((AdpcmState)state).index = index;
return len;
}

which stores the result into a short[] array.

I then convert this short[] array into a byte[] array with the following way:

s is the short[] array
adp is the byte array

for(int g=0,k=0;g audio.Convert.short2byte(s[g],adp,k);
}

public static void short2byte(short ival, byte b[], int offset) {
int i;
int bits = 16;

for(i = 0; i >< 2; i++) {
bits -= 8;
b[offset + i] = (byte) ((ival >> bits) & 0xff);
}
}

The final result is loaded to the player as follows:

ByteArrayInputStream input1 = new ByteArrayInputStream(adp);
player = Manager.createPlayer(input1, "audio/x-wav");//create new player
player.addPlayerListener(this);
player.prefetch();
player.realize();

player.start();

The player begins to play but I only get horrible sounds instead of the original wave file

The player now initializes ok without any problem but I can only hear a meesed up sound rather than the original. So now I strongly believe that the problem is in the decoding of the samples of the DVI/RTP codec.

cs02lk1
Offline
Joined: 2007-07-04

Thanks for your reply,

I have added the scrambled part.

Yes I do add WAVE PCM header to the beginning of the array which is a 44byte header as described in the documents I have read.

The thing is that the code I am using to decode the samples is translated from the one you said to check. So there may be a mistake in the translation. I would check it out but I currently am unable to run C on my PC.

I will use a different way to check. Maybe print out the bytes of the actual file in JAVA on my PC and see if they are the same as the ones decoded on the mobile device

apestov
Offline
Joined: 2007-07-05

It is still paste problems with the code for conversion. But I found it on the another forum :)

At least, one problem is at short2byte() method: target device is little-endian, so
0xFFFE, 0xABCD must be stored in byte array as {0xFE, 0xFF, 0xCD, 0xAB}.
More info on http://en.wikipedia.org/wiki/Endianness

Andrey

cs02lk1
Offline
Joined: 2007-07-04

are you sure that its little endian? I haven;t thought about that. So I will have to reverse the way short2byte works

I should make it like this:
public static void short2byte(short ival, byte b[], int offset) {
int i;
int bits = 16;

for(i = 1; i >= 0; i--) {
bits -= 8;
b[offset + i] = (byte) ((ival >> bits) & 0xff);
}
}
Correct?

Re-paste of the code:
public static void short2byte(short ival, byte b[], int offset) {
int i;
int bits = 16;

for(i = 0; i < 2; i++) {
bits -= 8;
b[offset + i] = (byte) ((ival >> bits) & 0xff);
}
}

I call it in the following way:

short[] s // This is the short buffer created by the decode method
byte[] adp = new byte[(s.length*2)+44]; // This is the byte array that will store the 44byte WAVE header and the conversion of the short array. thats why it is twice the size of s plus 44

This is the header
////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// WAV Header big endian
/////////////////////////////////////////////////////////

// RIFF
adp[0] = 0x52;
adp[1] = 0x49;
adp[2] = 0x46;
adp[3] = 0x46;
//0x18e70 = 102036 entire size of file - 8
adp[4] = (byte)0x94;
adp[5] = (byte)0x8e;
adp[6] = 0x01;
adp[7] = 0x00;
// WAVE
adp[8] = 0x57;
adp[9] = 0x41;
adp[10] = 0x56;
adp[11] = 0x45;
// fmt
adp[12] = 0x66;
adp[13] = 0x6d;
adp[14] = 0x74;
adp[15] = 0x20;
// subchunk size = 16
adp[z++] = 0x10;
adp[z++] = 0x00;
adp[z++] = 0x00;
adp[z++] = 0x00;
// Audioformat = 1 (PCM)
adp[z++] = 0x01;
adp[z++] = 0x00;
// channels =1
adp[z++] = 0x01;
adp[z++] = 0x00;
// Sample Rate = 16000
adp[z++] = (byte)0x80;
adp[z++] = 0x3e;
adp[z++] = 0x00;
adp[z++] = 0x00;
// Byte Rate
adp[z++] = 0x00;
adp[z++] = 0x7d;
adp[z++] = 0x00;
adp[z++] = 0x00;
// Block Align
adp[z++] = 0x02;
adp[z++] = 0x00;
// Bits per Sample = 16
adp[z++] = 0x10;
adp[z++] = 0x00;
// data
adp[z++] = 0x64;
adp[z++] = 0x61;
adp[z++] = 0x74;
adp[z++] = 0x61;
// Subchunk 2 size = 102036 - 36 = 102000
adp[z++] = 0x70;
adp[z++] = (byte)0x8e;
adp[z++] = 0x01;
adp[z++] = 0x00;
////////////////////////////////////////////////////////

And this is how I call the short2Byte
for(int g=0,k=z;g audio.Converter.short2Byte(s[g],adp,k);
}

Message was edited by: cs02lk1

cs02lk1
Offline
Joined: 2007-07-04

Due to paste problems

And this is how I call the short2Byte

for(int g=0,k=z;g audio.Convert.short2byte(s[g],adp,k);

Message was edited by: cs02lk1