BD(蓝光)的LPCM格式到PCM格式的转换

最近因为一些原因在折腾这方面的事情,朋友负责DVD-LPCM的,我这边则是BD-LPCM的,我轻松了很多,因为BD的LPCM的比DVD的那是舒服了不少。。
不过开发环境限制死了在VS2010我很蛋疼,并且其实源工程是基于DShow的,对我这个习惯了MediaFoundation的人来说,实在过于腐朽。
好了不废话那么多,我们来看BD的LPCM如何转换为PCM。

这个转换其实很简单,LPCM是BE的格式,首先我们解码音频需要3个关键的东西:声道数、采样率、采样大小。
BD的采样大小在16\24\32这范围内,也就是不会出现8bit的情况,我们需要判断,转换也就是:
switch bits
{
case 16:
sample = BE2LE_16BIT(old_sample);
break;
case 24:
sample = BE2LE_24BIT(old_sample);
case 32:
sample = BE2LE_32BIT(old_sample);
break;
}

这个转换虽然是十分脑残,不过BD有个啰嗦的地方就是它的头,比如在m2ts格式的BDMV中,封装的是H264的视频和LPCM的音频,每一个LPCM的Packet都有一个32bit(4字节)的信息头,然后从第五个字节开始才是LPCM的数据。
这个头是这样的:
 - unknown (16 bits)
 - number of channels (4 bits)
 - frequency (4 bits)
 - bits per sample (2 bits)
 - unknown (6 bits)
见下图(我用红线圈住的地方就是头,后面的就是LPCM数据):

前后2个未知我们不需要知道,其中有10个bit把我们需要的关键信息都给交出来了。
可以看到我们上图的头是03 C0 31 40,这个如何解析呢,代码在下面:
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <string>
#include <iostream>
#include <memory>
#include <Windows.h>
#include <ks.h>
#include <ksmedia.h>
#include <winsock.h>

#pragma comment(lib,"ws2_32.lib")

bool BDHeaderParse(void* ph,int* nch,int* srate,int* bits,unsigned int* ch_layout)
{
	unsigned int head = ntohl((*(unsigned int*)ph));
	
	switch ((head & 0xF000) >> 12)
	{
	case 1:
		*nch = 1;
		*ch_layout = SPEAKER_FRONT_CENTER;
		break;
	case 3:
		*nch = 2;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT;
		break;
	case 4:
		*nch = 3;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER;
		break;
	case 5:
		*nch = 3;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_CENTER;
		break;
	case 6:
		*nch = 4;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT
			|SPEAKER_FRONT_CENTER|SPEAKER_BACK_CENTER;
		break;
	case 7:
		*nch = 4;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT
			|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT;
		break;
	case 8:
		*nch = 5;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER
			|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT;
		break;
	case 9:
		*nch = 6;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER
			|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_LOW_FREQUENCY;
		break;
	case 10:
		*nch = 7;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER
			|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT
			|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT;
		break;
	case 11:
		*nch = 8;
		*ch_layout = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER
			|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT
			|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT|SPEAKER_LOW_FREQUENCY;
		break;
	default:
		return false;
	}

	switch ((head >> 6) & 3)
	{
	case 1:
		*bits = 16;
		break;
	case 2:
	case 3:
		*bits = 24;
		break;
	default:
		return false;
	}

	switch ((head >> 8) & 15)
	{
	case 1:
		*srate = 48000;
		break;
	case 4:
		*srate = 96000;
		break;
	case 5:
		*srate = 192000;
		break;
	default:
		return false;
	}

	return true;
}

int main()
{
	unsigned int i = 0x4031C003;
	int nch = 0,srate = 0,bits = 0;
	unsigned ch_layout = 0;
	BDHeaderParse(&i,&nch,&srate,&bits,&ch_layout);
	printf("nch:%d\nsrate:%d\nbits:%d\nch_layout:%d",
		nch,
		srate,
		bits,
		ch_layout);

	getchar();
	return 0;
}
好了,我们提取出了声道数、采样率、采样大小,就可以进行后面的LPCM->PCM转换了。
还有一个问题,就是声道布局,这个布局的问题上面我也写了。
不过在转换的时候,前面的1-5个声道,布局都对应有Windows布局,但是5.1(6声道)跟Windows布局不同,就是LFE的位置不同,在这里进行转换的时候,需要进行声道位置调整。

还有,貌似在m2ts文件中,LPCM每次的Packet大小都是一样的?

你可能感兴趣的:(BD(蓝光)的LPCM格式到PCM格式的转换)