JAVA做音视频解析(MP4)

java用来做音视频解析的还是挺少的,刚巧领导给分派了这个工作,就硬着头皮干了4个月。基本上算能解决mp4的音视频解析了。share一下,希望能对有这方面需求的人提供帮助,也希望能有更好的建议和解决方案。
[color=red]
[b]此文不涉及RTP,RTCP协议,H264解码,因为本人的专业知识实在有限,不过我还是特别希望有此方面开发经验的兄弟指点一二(c/c++ 方向的也可以)[/b][/color]

Lib:这里用到了jave(一个日本的framework封装了ffmpeg),spring2.5.6,依赖于jdk1.6和ffmpeg SDK3.2。

MP4利用ffmpeg分割为aac和h264文件分别解析,可将如下代码封装到java.lang.ProcessBuilder,多线程调用进行MP4分离。
ffmpeg.exe -i **.mp4 **.h264 -vstats_file **.log
ffmpeg.exe -i **.mp4 **.aac

特别说明下,分离**.h264文件后面跟了一个 -vstats_file **.log ,这是视频分隔输出流日志,后面解析h264文件时要用到的,目前这个日志只试用于win主机,*nix经测试打印日志不全,暂时没找到好的解决方法.

[color=blue][b]一 aac格式文件的解析:[/b][/color]

aac文件格式很简单,header(7个字节)-content-header-content...,其中header分为fixed和variable两种,这里采用标准音频(援引标准文档):
adts_fixed_header()  
{
syncword; 12 bslbf
ID; 1 bslbf
layer; 2 uimsbf
protection_absent; 1 bslbf
profile; 2 uimsbf
sampling_frequency_index; 4 uimsbf
private_bit; 1 bslbf
channel_configuration; 3 uimsbf
original/copy; 1 bslbf
home; 1 bslbf
}

adts_variable_header()
{
copyright_identification_bit; 1 bslbf
copyright_identification_start; 1 bslbf
frame_length; 13 bslbf
adts_buffer_fullness; 11 bslbf
number_of_raw_data_blocks_in_frame; 2 uimsfb
}

可以看到,两部分各28比特位,共56比特位,7字节.

首两个字节一般都是1111 1111 1111 0001,如果音频数据包含crc校验信息,最后一位就是0(看文档是这样的,但没有实作).
对应关系如下:
syncword 1111 1111 1111
ID 0
layer 00
protection_absent 1

然后接下来的一个半字节,

如下:
profile 两位,见下表
sampling_frequency_index 四位,见下表

private_bit 0
channel_configuration 三位,见下表,立体声为2,即010
original_copy 0
home 0

这部分标志位需要解释一下,援引标准文档

profile
Table 31 – Profiles
0 Main profile
1 Low Complexity profile (LC)
2 Scalable Sampling Rate profile (SSR)
3 (reserved)

再看Variable部分
前两位,一般都是00
copyright_identification_bit 0
copyright_identification_start 0

数值,等于数据包大小加上7--header的大小.其实就是第二个adts chunck的起始地址.
frame_length 00 0001 1000 000

全是1,即0x7FF
adts_buffer_fullness 1 1111 1111 11

一般为00
number_of_raw_data_blocks_in_frame 00

比特位映像:
[code]
1111
1111
1111
0 00 1
xx xx-
xx 0 x-
x x 0 0
0 0 xx-
xxxx
xxxx
xxx 1-
1111
1111-
11 00 [/code]

这里附一些我解析aac文件的代码:

private long parse(long offset) throws CannotParseException {

int fl = 0;

try {
is.skip(offset);

byte[] syncword = new byte[2];
int i = is.read(syncword);

if (i != -1) {

if (syncword[0] == -1 && (syncword[1] & -15) == -15) {

is.skip(1);

byte[] framelength = new byte[3];

int k = is.read(framelength);
if (k != -1) {

byte front = (byte) (framelength[0] & 3);
byte middle = framelength[1];
byte end = (byte) (((framelength[2] & -32) >> 5) & 7);

fl |= front;
fl <<= 8;
fl |= middle;
fl <<= 3;
fl |= end;

AudioBean bean = new AudioBean();

bean.setFramenum(++blocks);
bean.setOffset(fl);
bean.setPosition(position);

list.add(bean);
position += fl;

} else {
return -1;
}

} else {
return -1;
}

} else {
logger.info("aac file that length's : " + position + " parse done!");
return 0;
}

} catch (IOException ex) {
logger.error("during parse aac file occur unexpected exception", ex);
throw new CannotParseException(ex);
}
return fl - 7 + 1;
}


递归上面这个方法,记录一些关键的字段,保存到list里,这里我定义了一个对象AudioBean,他继承于MediaBean,没有子类字段。因为标准aac文件时线性的,所以记录了以下字段,以便分析。


public class MediaBean implements Serializable {
/**
* 起始位置
*/
private long position;
/**
* 每帧偏移量
*/
private int offset;
/**
* 帧位置
*/
private int framenum;
/**
* 起始时间
*/
private float time;

//setter getter 方法
}


由于是标准线性aac,那么总时间与总帧数的比大概就是每帧的时间(必须注明下,没有decode aac文件的内部数据,需要精确数据的请不要采取此方法)。经过处理的list<MeadiaBean>是一个完成的aac信息,我们可以用他来处理aac文件的截取和传输。

[color=blue][b]二 H264文件的解析[/b][/color]
刚才的命令行产生的**.log文件现在用到了。贴一小段log信息
[code]
frame= 1 q= 31.0 f_size= 6927 s_size= 7kB time= 0.083 br= 665.0kbits/s avg_br= 665.0kbits/s type= I
frame= 2 q= 31.0 f_size= 17 s_size= 7kB time= 0.167 br= 1.6kbits/s avg_br= 333.3kbits/s type= P
frame= 3 q= 31.0 f_size= 11 s_size= 7kB time= 0.250 br= 1.1kbits/s avg_br= 222.6kbits/s type= P
frame= 4 q= 31.0 f_size= 11 s_size= 7kB time= 0.333 br= 1.1kbits/s avg_br= 167.2kbits/s type= P
frame= 5 q= 31.0 f_size= 11 s_size= 7kB time= 0.417 br= 1.1kbits/s avg_br= 134.0kbits/s type= P
[/code]

其中 frame 为帧数,f_size为此帧大小,s_size是一个不是特别精确的累积帧大小,time为结束时间。

这些字段已经足够分析h264文件了。

项目还包括缓存,池,等概念,是一个完成的视频发送服务器,涉及到公司内部的视频协议就不公开了。希望能结识有视频研发经验的朋友,交流经验,其实我想把他再完善一下做成一个开源的视频分析框架,无奈专业知识有限,尤其是aac和h264方面的。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值