当前位置:文档之家› JAVA做音视频解析(MP4)

JAVA做音视频解析(MP4)

JAVA做音视频解析(MP4).2011-01-17 15:12:25| 分类:计算机编程JAVA,C | 标签:kbits fl byte f_size syncword |字号大中小订阅java用来做音视频解析的还是挺少的,刚巧领导给分派了这个工作,就硬着头皮干了4个月。

基本上算能解决mp4的音视频解析了。

share一下,希望能对有这方面需求的人提供帮助,也希望能有更好的建议和解决方案。

此文不涉及RTP,RTCP协议,H264解码,因为本人的专业知识实在有限,不过我还是特别希望有此方面开发经验的兄弟指点一二(c/c++ 方向的也可以)Lib:这里用到了jave(一个日本的framework封装了ffmpeg),spring2.5.6,依赖于jdk1.6和ffmpeg SDK3.2。

MP4利用ffmpeg分割为aac和h264文件分别解析,可将如下代码封装到ng.ProcessBuilder,多线程调用进行MP4分离。

Java代码ffmpeg.exe -i **.mp4 **.h264 -vstats_file **.logffmpeg.exe -i **.mp4 **.aacffmpeg.exe -i **.mp4 **.h264 -vstats_file **.logffmpeg.exe -i **.mp4 **.aac特别说明下,分离**.h264文件后面跟了一个-vstats_file **.log ,这是视频分隔输出流日志,后面解析h264文件时要用到的,目前这个日志只试用于win主机,*nix经测试打印日志不全,暂时没找到好的解决方法.一aac格式文件的解析:aac文件格式很简单,header(7个字节)-content-header-content...,其中header分为fixed和variable两种,这里采用标准音频(援引标准文档):Java代码adts_fixed_header(){syncword; 12 bslbfID; 1 bslbflayer; 2 uimsbfprotection_absent; 1 bslbfprofile; 2 uimsbfsampling_frequency_index; 4 uimsbfprivate_bit; 1 bslbfchannel_configuration; 3 uimsbforiginal/copy; 1 bslbfhome; 1 bslbf}adts_variable_header(){copyright_identification_bit; 1 bslbfcopyright_identification_start; 1 bslbfframe_length; 13 bslbfadts_buffer_fullness; 11 bslbfnumber_of_raw_data_blocks_in_frame; 2 uimsfb}adts_fixed_header(){syncword; 12 bslbfID; 1 bslbflayer; 2 uimsbfprotection_absent; 1 bslbfprofile; 2 uimsbfsampling_frequency_index; 4 uimsbfprivate_bit; 1 bslbfchannel_configuration; 3 uimsbforiginal/copy; 1 bslbfhome; 1 bslbf}adts_variable_header(){copyright_identification_bit; 1 bslbfcopyright_identification_start; 1 bslbfframe_length; 13 bslbfadts_buffer_fullness; 11 bslbfnumber_of_raw_data_blocks_in_frame; 2 uimsfb}可以看到,两部分各28比特位,共56比特位,7字节.首两个字节一般都是1111 1111 1111 0001,如果音频数据包含crc校验信息,最后一位就是0(看文档是这样的,但没有实作).对应关系如下:syncword 1111 1111 1111ID 0layer 00protection_absent 1然后接下来的一个半字节,如下:profile 两位,见下表sampling_frequency_index 四位,见下表private_bit 0channel_configuration 三位,见下表,立体声为2,即010original_copy 0home 0这部分标志位需要解释一下,援引标准文档profileTable 31 – Profiles0 Main profile1 Low Complexity profile (LC)2 Scalable Sampling Rate profile (SSR)3 (reserved)再看Variable部分前两位,一般都是00copyright_identification_bit 0copyright_identification_start 0数值,等于数据包大小加上7--header的大小.其实就是第二个adts chunck的起始地址. frame_length 00 0001 1000 000全是1,即0x7FFadts_buffer_fullness 1 1111 1111 11一般为00number_of_raw_data_blocks_in_frame 00比特位映像:Java代码1111111111110 00 1xx xx-xx 0 x-x x 0 00 0 xx-xxxxxxxxxxx 1-11111111-11 001111111111110 00 1xx xx-xx 0 x-x x 0 00 0 xx-xxxxxxxxxxx 1-11111111-11 00这里附一些我解析aac文件的代码:Java代码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 {("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;}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 {("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,没有子类字段。

相关主题