zoukankan      html  css  js  c++  java
  • 【多媒体封装格式详解】---MP4【4】

    前面介绍过的几种格式flv、mkv、asf等。他们音视频的数据包一般都是按照文件的顺序交叉安放。你解析完头部信息后。剩下的一般就按照文件顺序一个数据包一个数据包的解析就行了。但是MP4完全不是这种概念。他的媒体信息和数据是分开存放的。就是你想获得数据之前必须要解析出每个帧数据所有的位置。mp4存放这个帧信息的是放在stbl这个box里。而真实的数据放在mdat中。接下来就讲讲stbl与mdat的对应关系。

    Sample Table Box(stbl)

    来一张典型的stbl结构图:
    常见子box

    stts:    Decoding Time to Sample Box 时间戳和Sample映射表
    stsd:   Sample Description Box
    stsz, stz2: Sample Size Boxes 每个Sample大小的表。
    stsc: Sample to chunk 的映射表。
    ‘stco’, ‘co64’: Chunk位置偏移表
    stss:关键帧index。

    1.解析stsd可获得coding类型视频宽高、音频samplesize、channelcount这些和解码器有关信息。

    1. aligned(8) class SampleDescriptionBox (unsigned int(32) handler_type)  
    2. extends FullBox('stsd', 0, 0){  
    3. int i ;  
    4. unsigned int(32) entry_count;  
    5. for (i = 1 ; i u entry_count ; i++){  
    6. switch (handler_type){  
    7. case ‘soun’: // for audio tracks  
    8. AudioSampleEntry();  
    9. break;  
    10. case ‘vide’: // for video tracks  
    11. VisualSampleEntry();  
    12. break;  
    13. case ‘hint’: // Hint track  
    14. HintSampleEntry();  
    15. break;  
    16. }  
    17. }  
    18. }  
    1. aligned(8) abstract class SampleEntry (unsigned int(32) format)  
    2. extends Box(format){  
    3. const unsigned int(8)[6] reserved = 0;  
    4. unsigned int(16) data_reference_index;  
    5. }  
    6. class HintSampleEntry() extends SampleEntry (protocol) {  
    7. unsigned int(8) data [];  
    8. }  
    9. // Visual Sequences  
    10. class VisualSampleEntry(codingname) extends SampleEntry (codingname){  
    11. unsigned int(16) pre_defined = 0;  
    12. const unsigned int(16) reserved = 0;  
    13. unsigned int(32)[3] pre_defined = 0;  
    14. unsigned int(16) width;  
    15. unsigned int(16) height;  
    16. template unsigned int(32) horizresolution = 0x00480000; // 72 dpi  
    17. template unsigned int(32) vertresolution = 0x00480000; // 72 dpi  
    18. const unsigned int(32) reserved = 0;  
    19. template unsigned int(16) frame_count = 1;  
    20. string[32] compressorname;  
    21. template unsigned int(16) depth = 0x0018;  
    22. int(16) pre_defined = -1;  
    23. }  
    24. // Audio Sequences  
    25. class AudioSampleEntry(codingname) extends SampleEntry (codingname){  
    26. const unsigned int(32)[2] reserved = 0;  
    27. template unsigned int(16) channelcount = 2;  
    28. template unsigned int(16) samplesize = 16;  
    29. unsigned int(16) pre_defined = 0;  
    30. const unsigned int(16) reserved = 0 ;  
    31. template unsigned int(32) samplerate = {timescale of media}<<16;  
    32. }  

    2.解析stsz box 可以获得一个sample size的表

    1. aligned(8) class SampleSizeBox extends FullBox(‘stsz’, version = 0, 0) {  
    2. unsigned int(32) sample_size;  
    3. unsigned int(32) sample_count;  
    4. if (sample_size==0) {  
    5. for (i=1; i u sample_count; i++) {  
    6. unsigned int(32) entry_size;  
    7. }  
    8. }  
    9. }  

    3.解析stts 

    1. aligned(8) class TimeToSampleBox  
    2. extends FullBox(’stts’, version = 0, 0) {  
    3. unsigned int(32) entry_count;  
    4. int i;  
    5. for (i=0; i < entry_count; i++) {  
    6. unsigned int(32) sample_count;  
    7. unsigned int(32) sample_delta;  
    8. }  
    9. }  

    4.解析stsc 还原Sample 与chunk的映射表 


    Sample 是存储的最基本单元,mp4把Sample 存在chunk中。chunk的长度、chunk的大小、chunk中Sample的数量及大小都是不定的。

    通过解析这部分box来还原这个映射表。

    1. aligned(8) class SampleToChunkBox  
    2. extends FullBox(‘stsc’, version = 0, 0) {  
    3. unsigned int(32) entry_count;  
    4. for (i=1; i u entry_count; i++) {  
    5. unsigned int(32) first_chunk;  
    6. unsigned int(32) samples_per_chunk;  
    7. unsigned int(32) sample_description_index;  
    8. }  
    9. }  


    每个entry 表示着一组数据,entry_count 表示这数量。这一组其实是相同类型的chunk。

    first_chunk 表示 这一组相同类型的chunk中 的第一个chunk数。

    这些chunk 中包含的Sample 数量,即samples_per_chunk 是一致的。

    每个Sample 可以通过sample_description_index 去stsd box 找到描述信息。

    看ffmpeg中mov_read_stsc() 它把这些数据放在一个结构体数组中备用。

    1. static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom)  
    2. {  
    3.     AVStream *st;  
    4.     MOVStreamContext *sc;  
    5.     unsigned int i, entries;  
    6.   
    7.     if (c->fc->nb_streams < 1)  
    8.         return 0;  
    9.     st = c->fc->streams[c->fc->nb_streams-1];  
    10.     sc = st->priv_data;  
    11.   
    12.     avio_r8(pb); /* version */  
    13.     avio_rb24(pb); /* flags */  
    14.   
    15.     entries = avio_rb32(pb);  
    16.   
    17.     av_dlog(c->fc, "track[%i].stsc.entries = %i ", c->fc->nb_streams-1, entries);  
    18.   
    19.     if (!entries)  
    20.         return 0;  
    21.     if (entries >= UINT_MAX / sizeof(*sc->stsc_data))  
    22.         return AVERROR_INVALIDDATA;  
    23.     sc->stsc_data = av_malloc(entries * sizeof(*sc->stsc_data));  
    24.     if (!sc->stsc_data)  
    25.         return AVERROR(ENOMEM);  
    26.   
    27.     for (i = 0; i < entries && !pb->eof_reached; i++) {  
    28.         sc->stsc_data[i].first = avio_rb32(pb);  
    29.         sc->stsc_data[i].count = avio_rb32(pb);  
    30.         sc->stsc_data[i].id = avio_rb32(pb);  
    31.     }  
    32.   
    33.     sc->stsc_count = i;  
    34.   
    35.     if (pb->eof_reached)  
    36.         return AVERROR_EOF;  
    37.   
    38.     return 0;  
    39. }  

    在获得完整的映射表,我们还需要chunk总个数信息。这些信息放在‘stco’, ‘co64’中。

    5.解析‘stco’, ‘co64’

    “stco”定义了每个thunk在媒体流中的位置。位置有两种可能,32位的和64位的,后者对非常大的电影很有用。

    32位

    1. aligned(8) class ChunkOffsetBox  
    2. extends FullBox(‘stco’, version = 0, 0) {  
    3. unsigned int(32) entry_count;  
    4. for (i=1; i u entry_count; i++) {  
    5. unsigned int(32) chunk_offset;  
    6. }  
    7. }  


    64位

    1. aligned(8) class ChunkLargeOffsetBox  
    2. extends FullBox(‘co64’, version = 0, 0) {  
    3. unsigned int(32) entry_count;  
    4. for (i=1; i u entry_count; i++) {  
    5. unsigned int(64) chunk_offset;  
    6. }  
    7. }  

    从这个box我们就可以获得 chunk 的总数量,entry_count

     from:http://blog.csdn.net/tx3344/article/details/8506131

    1.解析‘stco’, ‘co64’我们有了chunk 表,知道了chunk 的总数及每个chunk所在文件的位置。

    2.解析stsc 配合着上面的chunk表,我们就能弄个Sample与chunk的关系表。我们也就能获得每个Sample的位置信息。

    3.配合上面的stts 时间表和解码器信息等。搞出ES流已经不成问题了。

    4.想获得关键帧的index,需要解析stss’

      1. aligned(8) class SyncSampleBox  
      2. extends FullBox(‘stss’, version = 0, 0) {  
      3. unsigned int(32) entry_count;  
      4. int i;  
      5. for (i=0; i < entry_count; i++) {  
      6. unsigned int(32) sample_number;  
      7. }  
      8. }  
  • 相关阅读:
    jmeter如何操作数据库
    jmeter压力测试
    cmd中用ping命令时,提示ping命令不是外部或内部命令问题
    scrapy post Request payload类型值
    scrapy-deltafetch实现增量爬取
    django虚拟环境搭建笔记
    python Image模块基本语法
    登录北京住房公积金,使用已注册过账号
    登录北京社保网站
    python通过pop3方式登录邮箱(qq,新浪,网易)
  • 原文地址:https://www.cnblogs.com/lidabo/p/3754130.html
Copyright © 2011-2022 走看看