mp4文件sample的offset计算

文章目录

        • mp4的box结构
        • box的type
        • mp4的trak box
        • mp4中的sample和chunk
        • sample的offset计算
        • 提取加密mp4视频

学着提取加密mp4视频的时候,用到了mp4的一些知识,主要有box结构和sample的offset计算。

mp4的box结构

mp4 文件由 box 构成,box 有 basic box 和 full box 两种:

  1. basic box
box_size (not 0 and 1) box_type box_data
uint32 char[4] box_size - 8
box_size (1) box_type largesize box_data
uint32 char[4] uint64 largesize - 16
box_size (0) box_type box_data
uint32 char[4] box extends to end of file
  1. full box
basic_box_header version flag box_data
8 or 16 bytes uint8 uint24 same like basic box

box的type

box可以嵌套,顶层的box有ftyp、moov、mdat、free、uuid等,其中ftyp、moov和mdat是一个mp4文件所必须的box,本文只介绍我用到的box。
一般ftyp是第一个box,mdat是存储实际音视频数据的box,moov描述了音视频数据的大小和位置。

mp4的trak box

trak是moov的子box,一般mp4文件有两个trak,一个是音频trak,一个是视频trak。

mp4中的sample和chunk

sample是mp4中存储音视频的最小单位,chunk是由sample组成的。它们相关的box有三个,都属于trak的子box:stsc、stsz、stco,它们三个都是full box类型。

  1. stsz
aligned(8) class SampleSizeBox extends FullBox(‘stsz’, version = 0, 0) { 
	unsigned int(32) sample_size;
	unsigned int(32) sample_count;
	if (sample_size==0) { //if sample_size>0 then each sample's size is sample_size
		for (i=1; i <= sample_count; i++) {
			unsigned int(32)  entry_size;
		} 
	}
}
  1. stco
aligned(8) class ChunkOffsetBox extends FullBox(‘stco’, version = 0, 0) { 
	unsigned int(32) entry_count;
	for (i=1; i <= entry_count; i++) {
		unsigned int(32)  chunk_offset;
    }
}
  1. stsc
aligned(8) class SampleToChunkBox extends FullBox(‘stsc’, version = 0, 0) { 
	unsigned int(32) entry_count;
	for (i=1; i <= entry_count; i++) {
		unsigned int(32) first_chunk;
		unsigned int(32) samples_per_chunk; 
		unsigned int(32) sample_description_index;
	}
}
first_chunk samples_per_chunk sample_description_index
1 5 no matter
4 3
9 4

上表说明chunk 1、2、3中分别有5个sample,chunk 4、5、6、7、8中分别有3个sample,chunk 9到最后一个chunk中分别有4个sample。

sample的offset计算

stsz中有sample的大小信息,stco中有chunk的位置信息,stsc中有chunk有几个sample的信息,计算sample的offset信息,用到了这三个box。box中的各个字段都是大端网络序的,实际程序中需要注意下这个。

int i, j, k;
unsigned int sample_pos = 0;
unsigned int sample_offset[stsz.sample_count];
for(i=0; i < stsc.entry_count-1; i++) {
	for(j=stsc.first_chunk[i]; j < stsc.first_chunk[i+1]; j++) {
		sample_offset[sample_pos++] = stco.chunk_offset[j-1];
		for(k=1; k < stsc.samples_per_chunk[i]; k++) {
			sample_offset[sample_pos] += stsz.sample_size[sample_pos-1];
			sample_pos++;
		}
	}
}
for(j=stsc.first_chunk[stsc.entry_count-1]; j < stco.entry_count; j++) {
	sample_offset[sample_pos++] = stco.chunk_offset[j];
	for(k=1; k < stsc.samples_per_chunk[stsc.entry_count-1]; k++) {
		sample_offset[sample_pos] += stsz.sample_size[sample_pos-1];
		sample_pos++;
	}
}
if (sample_pos == stsz.sample_count)
	printf("OK\n");

提取加密mp4视频

以上对mp4的分析,是为了最终提取出可以正常播放的视频,因为本文中的加密视频是以sample为单位加密的,所以我们解密时也按照sample为单位来解密。
提取步骤:

  1. 跳过加密头,定位到mp4的开头
  2. 复制顶层box,如果box是mdat,就先只复制box header,否则就直接把整个box复制到新文件中的对应位置
  3. 分析moov中的trak,我们使用trak中的stsz、stco、stsc这三个表,计算sample的位置
  4. 把每个sample解密,sample的大小和位置应该是不变的,把解密后的sample写到新文件中
  5. 新文件可以用普通播放器播放了

你可能感兴趣的:(mp4文件sample的offset计算)