Log in

View Full Version : LPCM bitrate


GZZ
6th September 2004, 23:09
I have been browsing this development forum to see if I can find some code to read the LPCM audio bitrate, but I have not succed. So now I ask if anyone can help me with some code, preffered pascal (delphi) code, but any other code-language will do.

If anyone can help me, please drop a line...


GZZ

Enots_
7th September 2004, 09:31
This board isn't really good for posting sourcecodes... but I'll try anyway. I've copied different handling routines together at random so this might need some rubbing to compile - but should have enough that you can read the theory. The documentation that I've used is: "DVD Specification for Read-only Disc / Part 3. Video Specifications Version 1.11".

For a given sector in a VOB you can check if it's LPCM and if it is you can get the samplerate from the private header. Additionally you can get the quantizer and then it's just a matter of multiplying to get the bitrate.

static UCHAR PrivateStream1Pack[] = { 0x0,0x0, 0x1, 0xBD};
if (!memcmp(&pSector[0xe], &PrivateStream1Pack, 4)) // is it a private stream pack
{
PBYTE pos = (PBYTE) &pSector[3];
int * m = (int*)(pos + 11 + 8);
m = (int*)(pos + 11 + 9 + (*m & 0xff));
int id = (*m & 0xff);
if ((id>= 0xA0) && (id<= 0xA7))
{
/// We have an LPCM packet

pSrc = m;
info->SampleFrequency = ((pSrc[5] & 0xC0) >> 4) ? 96000 : 48000;

int NoChannels = (pSrc[5] & 7);
int BitsPerSampleFlag = ((pSrc[5] & 0xC0)) >> 6;
int BitsPerSample;

switch(BitsPerSampleFlag)
{
case 0:
BitsPerSample = 16;
break;
case 1:
BitsPerSample = 20;
break;
case 2:
BitsPerSample = 24;
break;
default:
assert(false);
}
if (info->SampleFrequency == 48000)
{
info->FrameLength = (NoChannels * 80 * BitsPerSample) / 8;

}
else
{
info->FrameLength = (NoChannels * 160 *BitsPerSample) / 8;
}
info->Bitrate = info->FrameLength * 600;
return 0;

}
}

GZZ
7th September 2004, 09:54
ok - I will try it out, but you can use

quote to insert code next time, then will be like you CP it...

just use QUOTE <CODE> /QUOTE (remeber [ ] around QUOTE

like this:

test

mpucoder
8th September 2004, 02:59
Shouldn't
info->SampleFrequency = ((pSrc[5] & 0xC0) >> 4) ? 96000 : 48000;
be
info->SampleFrequency = ((pSrc[5] & 0x30) >> 4) ? 96000 : 48000;

GZZ
14th September 2004, 12:14
I got it working, but if I want to demux the LPCM stream, how do I do this, I know how to demux the Ac3 and DTS stream. But its not that easy with the LPCM stream. I did a byte compare and it looks like some of the numbers are switched around. I normally demux from the first audio pcm frame in each sector with the correct stream ID. But my file a not valid at all. Anyone can help me out here ?


GZZ

fccHandler
14th September 2004, 15:54
Originally posted by GZZ
I did a byte compare and it looks like some of the numbers are switched around.
Not sure if this is what you mean, but 16-bit PCM in DVDs is stored with the bytes reversed; e.g., a sample value of 7584 is stored as 0x1D, 0xA0 (Motorola order), instead of 0xA0, 0x1D (Intel order).

GZZ
14th September 2004, 16:11
it was something like that, so do I have to switch every byte in the stream to make it work or what ?

GZZ

fccHandler
14th September 2004, 23:41
Yes, swap each pair of bytes starting from the first 16-bit sample:

A B C D E F G H... to
B A D C F E H G...

GZZ
15th September 2004, 12:59
one last thing...

I got the swap each pair correct. BUT the first 44 byte of my LPCM stream ripped by dvddecrypter got a wierd beginning, the collection of byte is difference from the one I can find in the org vob stream, so the beginning of the stream I have ripped are difference. Don't know why

Do I also have to swap some byte here or what, because its really wierd. HEHE

GZZ

fccHandler
15th September 2004, 15:30
Originally posted by GZZ
the first 44 byte of my LPCM stream ripped by dvddecrypter got a wierd beginning
That's just a WAVE header, isn't it? Are you not adding a WAVE header to your LPCM rip? You should add one, so that other programs will understand the stream:

http://www.tdt.com/T2Support/technical_notes/tn0132.pdf

Nic
15th September 2004, 15:40
It's all fun and games for 16bit. Gets a tiny bit more of a pain when it's 24bit...Something to watch out for...(no more simple bswap :( )

fccHandler
15th September 2004, 15:58
I still haven't seen 24-bit LPCM, though I would really like to.

P.S. I never did buy that Sonic Youth DVD:
http://forum.doom9.org/showthread.php?s=&threadid=79803

Nic
15th September 2004, 18:04
If I get chance I'll rip a little 24bit LPCM vob and upload it. The byte order you have to do is quite bizarre, LightningUK worked it out though (if you've subscribed to mpucoders forum you can read about it there).

GZZ
15th September 2004, 18:50
I haven't subscribed to mpucoders forum - he should make the info public at doom9. HEHE

But there is properly a reason why he haven't done it. :)


But PLEASE upload a sample, so I can see how I should do it, have been looking at byte for hours now and can't find out what to do with them. HEHE


GZZ

mpucoder
15th September 2004, 20:07
This was Lightning's solution

Subject: 24bit PCM

It's not the normal 2 byte swap, no. It's more of a 12 byte swap!!

This will do the trick though

BYTE TempData[12];

TempData[0] = Data[8];
TempData[1] = Data[1];
TempData[2] = Data[0];
TempData[3] = Data[9];
TempData[4] = Data[3];
TempData[5] = Data[2];
TempData[6] = Data[10];
TempData[7] = Data[5];
TempData[8] = Data[4];
TempData[9] = Data[11];
TempData[10] = Data[7];
TempData[11] = Data[6];

CopyMemory(Data, &TempData, 12);


Note: Data[] is the data in DVD order, TempData[] is in WAV order

There IS a reason for the bizarre order, the double word is still the basic unit of data.
It actually makes it very easy to convert to 16-bit samples, just discard the third double-word (bytes 8-11)
Another way to look at the DVD order:
double-word 0 is sample 0 most significant 16 bits
double-word 1 is sample 1 most significant 16 bits
double-word 2 is the lsb of both samples

GZZ
15th September 2004, 21:47
does it change that my LPCM stream are 16bps (16 bit ?)

I see it pretty hard to understand, but I will take a closer look and see if I can work it out. Thanks


GZZ

GZZ
15th September 2004, 23:01
I don't think I understand this correctly. :/


1: I got 44 byte, BEFORE the PCM Audio Frame starts, do I have to swap these 44 byte and how can it be done with 12 at a time ? or do I have to discard the Byte 8-11 because my stream already are 16 bit and then I can swap 11 byte (11 * 4 = 44 byte) ???


2: I don't understand this at all:


Another way to look at the DVD order:
double-word 0 is sample 0 most significant 16 bits
double-word 1 is sample 1 most significant 16 bits
double-word 2 is the lsb of both samples


3: what is a double word in delphi, delphi only have word (16 bit) and long word (32 bit)...?


Many questions, but I hope you understand me...

GZZ

mpucoder
15th September 2004, 23:29
That post was for fccHandler concerning 24-bit LPCM. Although I haven't tested it, DVDDecrypter from 3.1.8.0 and later should take care of the byte order in 24-bit LPCM for you (that's when LIGHTNING UK! figured it out). 16-bit LPCM was worked out even earlier, and should also rip correctly.

double-word (or DWORD as MASM calls it) = long word

fccHandler
16th September 2004, 01:18
Thanks mpucoder for the info, and thanks in advance Nic if you can post a sample for testing!

@GZZ:
Again, are you sure those 44 bytes are not just a WAVE header added by DVDDecrypter? If necessary, type them all out in your next post, because it's difficult to understand the problem unless we can see what you're talking about.

GZZ
16th September 2004, 08:54
It is the 44 byte header, I just mixed mpucoder post with mine and so on. But it IS the 44 byte wave header I´m talking about. I also read out your link on how to understand the wave header, think I got most of it, just need a little info on how the

4 bytes a pull together, the pdf file says:

Note that four-byte numbers (unsigned longints) are stored on disk as 11 22 33 44 where 44 is msb

don't know how I should understand it and I don't know what msb are, so if you could make an example here it will help me out.

fccHandler
16th September 2004, 20:26
Ummm, that's a really basic question. How long have you been a programmer? :p

MSB is "most significant byte" (or sometimes "bit"). Think of it as the leftmost part of the written number. There's also an LSB (least significant byte) which is the rightmost part. Consider the number 287454020 written out in hex:

0x11223344

It's a 32-bit number (long word) which needs four bytes of storage. The MSB is 0x11 (the leftmost byte) and the LSB is 0x44 (the rightmost byte). The way it's shown above, you might be tempted to view it as a grouping of the bytes 0x11, 0x22, 0x33, and 0x44, in that order, but that's NOT how your computer sees it.

The most basic unit of memory and file access is the byte, so it's important to know the order of the bytes that form a multi-byte number when you read (or write) those bytes to a file, or to a memory address. Windows systems (and WAVE files) use Intel order, in which the LSB is read (or written) first and the MSB comes last. Using the above number as an example, fetching the four bytes from the file one-by-one would give you 0x44, 0x33, 0x22, 0x11. That's how the 32-bit number is actually stored in the file, and in memory.

The problem you faced earlier was due to the fact that VOB files (and MPEGs in general) don't use Intel byte order, so we have to swap the bytes around before storing them in a WAVE. The WAVE header is something you must create yourself, to encapsulate the data you ripped. I don't know how you do it in Delphi, but in C the easiest way is to create the necessary WAVE structure(s) in memory, fill in appropriate values, then dump that whole memory chunk into a file.

GZZ
16th September 2004, 21:01
Thanks. I just didn't know what msb stands for. I have been programming for 4 years and I have read Andrew S. Tanenbaum - Structured computer Organization. Its all about bit and byte. HEHE


But I tend to forget things I don't use for long time. HEHE


GZZ

jsoto
14th December 2004, 01:23
Hi all,

I was playing with some 24 bit samples and, yes, I found that

mybuffer[i+0]=buffer[i+8];
mybuffer[i+1]=buffer[i+1];
mybuffer[i+2]=buffer[i+0];
mybuffer[i+3]=buffer[i+9];
mybuffer[i+4]=buffer[i+3];
mybuffer[i+5]=buffer[i+2];
mybuffer[i+6]=buffer[i+10];
mybuffer[i+7]=buffer[i+5];
mybuffer[i+8]=buffer[i+4];
mybuffer[i+9]=buffer[i+11];
mybuffer[i+10]=buffer[i+7];
mybuffer[i+11]=buffer[i+6];

does the proper byte reorder from VOB (buffer) to wav (mybuffer) in a stereo track. Glad to see I found the right trick, although it took me one hour looking to the bytes!

But, for a mono 24 bit channel, I've found a different re-ordering

mybuffer[i+0]=buffer[i+4];
mybuffer[i+1]=buffer[i+1];
mybuffer[i+2]=buffer[i+0];
mybuffer[i+3]=buffer[i+5];
mybuffer[i+4]=buffer[i+3];
mybuffer[i+5]=buffer[i+2];


These reordering procedures are "something more" than a little/big endian conversion (which I thought was the procedure in 16 bits). I'm not able to understand what is being done...

And, I still have some additional doubts

A) Can a 12 byte (6 byte in mono) pack be broken between two different audio VOB packs?
If yes, the demuxing process has to take it into account...

B) What about 20 bit precision? How is the reordering in this case? Anyone knows?

C) Does the DVD standard allow more than two channels in LPCM?

jsoto

fccHandler
14th December 2004, 08:04
Originally posted by jsoto
These reordering procedures are "something more" than a little/big endian conversion (which I thought was the procedure in 16 bits). I'm not unable to understand what is being done...
There probably is an endian swap, but it also appears that the sample bytes are somehow arranged into 32-bit blocks for DWORD access. That's the best hint I can offer ATM, because I don't really understand it yet either.

A) Can a 12 byte (6 byte in mono) pack be broken between two different audio VOB packs?
If yes, the demuxing process has to take it into account...
AFAIK, the format of the raw stream data has absolutely no influence on how packets are split and multiplexed into a program stream; i.e., a PES packet of arbitrary size may be created from anywhere within a stream. I know this is true of MPEG video, audio, AC-3, and subpictures, so I assume it's true of LPCM as well.

This doesn't really affect the demuxing process. All it has to do is combine all of the bytes from all of the packets of a given stream into a single contiguous stream, and dump it out to a file.

B) What about 20 bit precision? How is the reordering in this case? Anyone knows?
Good question. I'd like to know that myself. :)

C) Does the DVD standard allow more than two channels in LPCM?
Well, each LPCM packet includes a header which specifies the number of channels, up to a maximum of eight. Whether DVDs actually support this I cannot say. So far I've never seen a DVD with more than two channel LPCM...

jsoto
14th December 2004, 08:28
Thanks for the info, fccHandler
BTW, I've found this thread (http://forum.doom9.org/showthread.php?s=&threadid=79796&highlight=20bit) where LigH puts a link to a proggie (sources included) able to manage 20 bits lpcm. I'll take a look.

jsoto

mpucoder
14th December 2004, 14:56
A) NO (and neither can the frames of DTS be split across packets)
B) also don't know what it is
C) up to 8 channels depending on quant and sampling rate. the max bitrate is 6.144Mbps

KHz bits channels
48 16 8
48 20 6
48 24 5
96 16 4
96 20 3
96 24 2

I've used 4ch 24 bit (with MuxMan), it sounds fantastic. You get accustomed to compressed audio after hearing enough of it so that even 128K mp3 sounds good. That is until you hear uncompressed (digitally and dynamically) audio.

jsoto
14th December 2004, 15:13
Thanks mpucoder,

20 bits seems very rare..., LigH's proggie converts it to 16 (reduced precission) or 24 bits (adding four zero bits), and does the appropiate reordering.

I've used 4ch 24 bit (with MuxMan), Could you post the reordering procedure in this case? Is it a 24 bytes reordering? And, what about 3 channels? Is it a 18 bytes?

jsoto

mpucoder
14th December 2004, 19:12
Thanks for saving me the time of reading LigH's work ;)
4ch 24bit is similar to 2ch in that it is a 12 byte transform. In the same terms as the 2ch above (mybuffer is the riff ordering) it's:

mybuffer[i+0]=buffer[i+4];
mybuffer[i+1]=buffer[i+1];
mybuffer[i+2]=buffer[i+0];
mybuffer[i+3]=buffer[i+5];
mybuffer[i+4]=buffer[i+3];
mybuffer[i+5]=buffer[i+2];
mybuffer[i+6]=buffer[i+6];
mybuffer[i+7]=buffer[i+9];
mybuffer[i+8]=buffer[i+8];
mybuffer[i+9]=buffer[i+7];
mybuffer[i+10]=buffer[i+11];
mybuffer[i+11]=buffer[i+10];

notice that bytes 1, 6, and 8 don't move.

I haven't done the odd numbers or 20 bit yet.

fccHandler
14th December 2004, 20:32
Originally posted by fccHandler
a PES packet of arbitrary size may be created from anywhere within a stream. I know this is true of MPEG video, audio, AC-3, and subpictures, so I assume it's true of LPCM as well.
Originally posted by mpucoder
A) NO (and neither can the frames of DTS be split across packets)
I took a closer look and I believe mpucoder is correct. At least in one VOB I examined, it looks like LPCM packets are sized accordingly so that no frames are split, and then "padding_stream" filler is inserted up to the next 2K boundary. Sorry to have posted wrong info.

(note to self: never assume) :o

mpucoder
14th December 2004, 20:52
I actually tried it. By allowing the multiplexer to use the full payload the sound was noise. A pes can have a payload of 2025, but you have to start subtracting from that. 5 for pts (which every audio pack has), 3 for p-std buffer size (first pack only), 1 for substream number, 3 for DVD audio header, and 3 more for LPCM header. That leaves 2010 first pack, 2013 afterwards.
By limiting it to 2008 bytes for 16-bit 2 channel, or 2004 bytes for 24 bit 2 or 4 channel it was music. Nothing else was changed, just the payload limit.

2008 = 251*8
2004 = 167*12

I don't remember trying 2012 for 16-bit, as that would require a further test to determine if it was the first pack or not.

jsoto
15th December 2004, 01:12
Ok, thanks to all. I've enough info to fix PgcDemux :) in 24 bit mode.

I haven't done the odd numbers You can take one channel case (mono) from my post. I've tested it

jsoto

mpucoder
15th December 2004, 18:26
This one has me confused. In riff/wav aren't all samples byte aligned? For example 12-bit samples take 16-bits, with the least significant 4 bits ignored/zeroed? I thought that was what I read somewhere. Anyway, I've been trying to get scenarist to accept a wave file of 4 ch 20-bit. and it kept saying it was 24-bit. That is until I changed the header to block_align = 10!
What I thought should work:
channels: 4
sample_rate: 48000
bytes_per_second: 576000
block_align: 12
bits_per_sample: 20

What actually worked:
channels: 4
sample_rate: 48000
bytes_per_second: 480000
block_align: 10
bits_per_sample: 20

jsoto
16th December 2004, 01:34
http://www.microsoft.com/whdc/device/audio/multichaud.mspx

Seems it is not clear in the old format (WAVE_FORMAT_PCM), and the wave format specs have been "improved" by Microsoft in WAVE_FORMAT_EXTENSIBLE

jsoto

mpucoder
16th December 2004, 01:45
What a mess. I'll throw some of the new format at Scenarist when I get a chance. Meantime I found out that Scenarist doesn't look at bits_per_sample or block_align in the format I used. It calculates everything based on channels, sample_rate, and bytes_per_second.

Guest
29th June 2005, 13:35
Has anybody found the right magic for demuxing 20-bit LPCM off the DVD to a WAV file yet? The LigH proggie apparently just goes from 20-bit WAV to 16-bit WAV and I need the format *on the DVD*.

Nice work on the mono support, jsoto. I wondered why my 24-bit mono just gave hiss. :)

fccHandler
29th June 2005, 17:49
I know how to convert mono and stereo 16- 20- and 24-bit LPCM to a 16-bit WAV. I also know how to write a 24-bit WAV, but I don't know how to write a 20-bit WAV (if that's what you're asking).

Guest
30th June 2005, 02:15
OK, please tell me how to convert 20 bit LPCM to 16-bit WAV. Thank you.

fccHandler
30th June 2005, 06:00
OK, here goes...

20-bit mono LPCM is coded in blocks of 5 bytes:

buf[0] = top 8 bits of Sample 1
buf[1] = middle 8 bits of Sample 1
buf[2] = top 8 bits of Sample 2
buf[3] = middle 8 bits of Sample 2
buf[4] bits [7..4] = bottom 4 bits of Sample 1
buf[4] bits [3..0] = bottom 4 bits of Sample 2

20-bit stereo LPCM is coded in blocks of 10 bytes:

buf[0] = top 8 bits of Left sample 1
buf[1] = middle 8 bits of Left sample 1
buf[2] = top 8 bits of Right sample 1
buf[3] = middle 8 bits of Right sample 1
buf[4] = top 8 bits of Left sample 2
buf[5] = middle 8 bits of Left sample 2
buf[6] = top 8 bits of Right sample 2
buf[7] = middle 8 bits of Right sample 2
buf[8] bits [7..4] = bottom 4 bits of Left sample 1
buf[8] bits [3..0] = bottom 4 bits of Right sample 1
buf[9] bits [7..4] = bottom 4 bits of Left sample 2
buf[9] bits [3..0] = bottom 4 bits of Right sample 2

Here's a bit of code from the (as yet unreleased) VirtualDub-MPEG2 1.6.7, which converts 20-bit stereo and mono LPCM to 16-bit WAVE:


inline void AudioSourcePCM::LPCM20S_to_WAVE16S(void *src, int len) {
__asm {
mov esi, src
mov ecx, len
mov edi, esi

loop1: sub ecx, 5
jl done

mov eax, [esi]
add esi, 4
bswap eax
ror eax, 16
mov [edi], eax
add edi, 4

sub ecx, 5
jl done

mov eax, [esi]
add esi, 6
bswap eax
ror eax, 16
mov [edi], eax
add edi, 4

jmp loop1
done:
}
}

inline void AudioSourcePCM::LPCM20M_to_WAVE16M(void *src, int len) {
__asm {
mov esi, src
mov ecx, len
mov edi, esi

loop1: sub ecx, 5
jl done

mov eax, [esi]
add esi, 5
bswap eax
ror eax, 16
mov [edi], eax
add edi, 4

jmp loop1
done:
}
}


I didn't figure out how to write a 20-bit WAVE, and I don't even think it's possible to do. You can use WAVEFORMATEXTENSIBLE, but you still have to write out the data as 24-bit. If you want to make a stereo 24-bit WAVE from 20-bit LPCM, you can start with this:


BYTE inbuf[10];
BYTE outbuf[12];
PCMWAVEFORMAT pcm;

pcm.wf.wFormatTag = WAVE_FORMAT_PCM;
pcm.wf.nChannels = 2;
pcm.wf.nSamplesPerSec = 48000;
pcm.wBitsPerSample = 24;
pcm.wf.nBlockAlign = (pcm.wf.nChannels * pcm.wBitsPerSample) / 8;
pcm.wf.nAvgBytesPerSec = pcm.wf.nSamplesPerSec * pcm.wf.nBlockAlign;


Then in the data loop, do this:

outbuf[0] = inbuf[8] & 0xF0;
outbuf[1] = inbuf[1];
outbuf[2] = inbuf[0];
outbuf[3] = (inbuf[8] & 0x0F) << 4;
outbuf[4] = inbuf[3];
outbuf[5] = inbuf[2];
outbuf[6] = inbuf[9] & 0xF0;
outbuf[7] = inbuf[5];
outbuf[8] = inbuf[4];
outbuf[9] = (inbuf[9] & 0x0F) << 4;
outbuf[10] = inbuf[7];
outbuf[11] = inbuf[6];


Hope that helps. :)

Guest
30th June 2005, 06:07
Thank you, fccHandler. Where did you discover the 20-bit layouts?

fccHandler
30th June 2005, 06:22
By "reverse engineering" some of the VOBs which were posted by jsoto in this thread (http://forum.doom9.org/showthread.php?t=88505).