mp4文件格式解析

准备

安装mediaInfo、QTAtomViewer.exe、MP4info.exe等软件

视频一些参数

封装格式:我也不太清楚

编码格式:我也不太清楚

分辨率:图像的长和宽。

帧率:一秒播放的图片数,如15fps、30fps,体现在画面的流畅度。

码率:压缩后每秒显示的图片数据量,通俗地说,就是流量。如298kbps,体现在视频文件的大小和画质。

压缩比:分辨率*帧率/码率,简单来说就是压缩前每秒的数据量比上压缩后每秒的数据量。

音频一些参数

声道:录音时录音的位置不同产生不同的声道,有单声道、立体声(左右声道)、四声道环绕、5.1声道等。放歌时切换到左声道,两个音箱都播放左声道,切换到右声道时,两个音箱都播放右声道,切换到立体音时,左音箱播放左声道,右音箱播放右声道。可用暴风影音体验一下。

音轨: ①电视上看到录音时歌手都是在录音棚里戴着耳机唱歌,其实这就使用了多音轨技术,先把伴奏录好(音轨1),歌手再根据伴奏唱歌(音轨2)。②在K房使用的也是多音轨(原唱和伴唱)③有些老歌经常是粤语版和国语版一起唱,这也是多音轨技术

采样率:录制声音时对声音的采样频率,一般为44.1KHz

MP4文件组成

MP4由一个个的box(以前叫atom)组成,如下图,每个box包含不同的信息(再如下图),在程序中用结构体表示各个box,形象地说MP4文件就是由各个结构体组织起来的。所以,首先要了解这些box的组成和意义。

主要概念:sample、chunk、track

sample,在这里实际上就是一帧或连续几帧

chunk,一个或几个sample组成的单元

track,视频或音频序列,sample的集合


MP4主要由三个box组成,ftyp、mdat和moov。ftyp指示一些头部信息,通过ftyp box可以判断文件类型。mdat box存放的是媒体数据,就是播放的音频实实在在的元数据,比如我们需要取到第一帧的图片数据就存放在这个box里面。这么多数据,怎么知道这些数据的准确位置呢?这就要靠moov box来解析了。一般情况下,一个moov box包含一个mvhd和若干个track box。①mvhd box中存放一些create/modify time(基准时间是1904-1-1 0:00 AM)等信息,duration/time scale就是视频的长度(单位为s)。②track box一般包含tkhd和mdia两个box,tkhd中存放有视频长度和宽度等信息,,,,,,,最重要的是mdia -> minf -> stbl box下面的6个box,分别是stsd、stts、stss、stsc、stsz、stco,比如要查找第N秒的图片数据,步骤如下:

1、确定第N秒在媒体时间坐标系统中的位置,即N*time_scale

2、根据stts(time to sample)确定sample序号

3、根据stsc(sample to chunk)确定对应该sample的chunk

4、根据stco(chunk offset)中提取该chunk的偏移量

5、根据stsz(sample size)找到该sample在chunk内的偏移量和sample的大小。


例如:以test.mp4为例说明,用QTAtomViewer.exe查看此文件可知time_scale为90000,即一秒分为90000个刻度,现在假设要查看第一秒的数据,步骤如下:

1、一秒在媒体时间坐标系统中的位置,即1*90000 = 90000;

2、由stts,sample duration = 6000, 90000/6000 = 15, 即sample序号为15

3、由stsc,因为samples Per chunk = 1, 所以chunk序号也为15

4、由stco,序号为15的chunk的offset = 62719

5、由stsz,sample 在 chunk内的偏移为0,且大小为3554。

也就是说,程序到62719的地址开始,读取3554byte的数据,就是第一秒的图片数据。如果要查看第一帧(第0秒)的数据,同样按照上面的步骤可定位到地址28,读取5280byte的数据

现在知道了MP4文件的组成,也知道了怎么去获取第N帧的数据,那么无论程序多么复杂,它都是围绕这个主题来做文章了


最后附上一小段简单的视频解析的代码

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4.   
  5. #define BOX_FTYP 0x66747970  
  6. #define MDAT_BOX 0x6D646174  
  7. #define MOOV_BOX 0x6D6F6F76  
  8. #define MVHD_BOX 0x6D766864  
  9. #define TRAK_BOX 0x7472616B  
  10. #define IODS_BOX 0x696F6473  
  11. #define UDTA_BOX 0x75647461  
  12. #define FREE_BOX 0x66726565  
  13. #define TKHD_BOX 0x746B6864  
  14. #define MDIA_BOX 0x6D646961  
  15. #define MDHD_BOX 0x6D646864  
  16. #define HDLR_BOX 0x68646C72  
  17. #define MINF_BOX 0x6D696E66  
  18. #define DINF_BOX 0x64696E66  
  19. #define TREF_BOX 0x74726566  
  20. #define STBL_BOX 0x7374626C  
  21. #define STSD_BOX 0x73747364  
  22. #define MP4S_BOX 0x6D703473  
  23. #define ESDS_BOX 0x65736473  
  24. #define STTS_BOX 0x73747473  
  25. #define STSC_BOX 0x73747363  
  26. #define STSZ_BOX 0x7374737A  
  27. #define STCO_BOX 0x7374636F  
  28. #define STSS_BOX 0x73747373  
  29. #define CTTS_BOX 0x63747473  
  30. #define EDTS_BOX 0x65647473  
  31. #define VMHD_BOX 0x766D6864  
  32. #define HMHD_BOX 0x686D6864  
  33. #define SMHD_BOX 0x736D6864  
  34. #define NMHD_BOX 0xffffffff  
  35.   
  36. #define ODSM    0x6F64736D  
  37. #define SDSM    0x7364736D  
  38. #define VIDE    0x76696465  
  39. #define HINT    0x68696E74  
  40. #define SOUN    0x736F756E  
  41.   
  42. typedef struct BOX_HEAD  
  43. {  
  44.     unsigned int size;  
  45.     unsigned int type;  
  46. }BOX_HEAD;  
  47.   
  48. typedef struct FTYP_BOX  
  49. {  
  50.     unsigned int ftyp_size;  
  51.     unsigned int ftyp_type;  
  52. }FTYP_BOX;  
  53.   
  54.   
  55. typedef struct MOOV_HEADER_BOX  
  56. {  
  57.     unsigned int create_time;  
  58.     unsigned int modification_time;  
  59.     unsigned int time_scale;  
  60.     unsigned int duration;  
  61.     unsigned int preferred_rate;  
  62.     unsigned short preferred_volume;  
  63.     char reserved[10];  
  64.     char matrix_structure[36];  
  65.     char pre_defined[24];  
  66.     unsigned int next_track_id;  
  67. }MOOV_HEADER_BOX;  
  68.   
  69. typedef struct Track_head_box  
  70. {  
  71.     unsigned int create_time;  
  72.     unsigned int modification_time;  
  73.     unsigned int track_id;  
  74.     unsigned int reserved1;  
  75.     unsigned int duration;  
  76.     unsigned int reserved2[2];  
  77.     unsigned short layer;  
  78.     unsigned short alternate_group;  
  79.     unsigned short volume;  
  80.     unsigned short reserved3;  
  81.     char matrix[36];  
  82.     unsigned int width;  
  83.     unsigned int height;  
  84. }TRACK_HEAD_BOX;  
  85.   
  86. typedef struct Mdhd_head_box  
  87. {  
  88.     unsigned int create_time;  
  89.     unsigned int modification_time;  
  90.     unsigned int time_scale;  
  91.     unsigned int duration;  
  92.     unsigned short language;  
  93.     unsigned short quality;  
  94. }MDHD_HEAD_BOX;  
  95.   
  96. typedef struct Ret_Boxhead_Fileptr  
  97. {  
  98.     BOX_HEAD box_head;  
  99.     FILE *p;  
  100. }Ret_Boxhead_Fileptr;  
  101.   
  102. struct MP4_INFO  
  103. {  
  104.     unsigned int create_time;  
  105.     unsigned int modification_time;  
  106. }mp4_info;  
  107.   
  108. unsigned int big_to_small_endian_32bit(unsigned int const big)  
  109. {  
  110.     unsigned int data = big;  
  111.     unsigned int ret = 0;  
  112.     ret += (data>>0 & 0xff) << 24;  
  113.     ret += (data>>8 & 0xff) << 16;  
  114.     ret += (data>>16 & 0xff) << 8;  
  115.     ret += (data>>24 & 0xff) << 0;  
  116.     return ret;  
  117. }  
  118.   
  119. __int64 big_to_small_endian_64bit(__int64 const big)  
  120. {  
  121.     __int64 data = big;  
  122.     __int64 ret = 0;  
  123.     ret += (data>>0 & 0xff) << 56;  
  124.     ret += (data>>8 & 0xff) << 48;  
  125.     ret += (data>>16 & 0xff) << 40;  
  126.     ret += (data>>24 & 0xff) << 32;  
  127.     ret += (data>>32 & 0xff) << 24;  
  128.     ret += (data>>40 & 0xff) << 16;  
  129.     ret += (data>>48 & 0xff) << 8;  
  130.     ret += (data>>56 & 0xff) << 0;  
  131.     return ret;  
  132. }  
  133.   
  134. void print_box_type(unsigned int box_type, unsigned int num)  
  135. {  
  136.     for(unsigned int i = 0; i < num; i++)  
  137.     {  
  138.         printf("\t");  
  139.     }  
  140.     switch(big_to_small_endian_32bit(box_type))  
  141.     {  
  142.         case BOX_FTYP:  
  143.         {  
  144.             printf("%s\n""ftyp box");  
  145.         }  
  146.         break;  
  147.   
  148.         case MOOV_BOX:  
  149.         {  
  150.             printf("%s\n""moov box");  
  151.         }  
  152.         break;  
  153.           
  154.         case MDAT_BOX:  
  155.         {  
  156.             printf("%s\n""mdat box");  
  157.         }  
  158.         break;  
  159.   
  160.         case MVHD_BOX:  
  161.         {  
  162.             printf("%s\n""mvhd box");  
  163.         }  
  164.         break;  
  165.   
  166.         case IODS_BOX:  
  167.         {  
  168.             printf("%s\n""iods box");  
  169.         }  
  170.         break;  
  171.   
  172.         case UDTA_BOX:  
  173.         {  
  174.             printf("%s\n""udta box");  
  175.         }  
  176.         break;  
  177.   
  178.         case TRAK_BOX:  
  179.         {  
  180.             printf("%s\n""trak box");  
  181.         }  
  182.         break;  
  183.   
  184.         case TKHD_BOX:  
  185.         {  
  186.             printf("%s\n""tkhd box");  
  187.         }  
  188.         break;  
  189.   
  190.         case MDIA_BOX:  
  191.         {  
  192.             printf("%s\n""mdia box");  
  193.         }  
  194.         break;  
  195.   
  196.         case MDHD_BOX:  
  197.         {  
  198.             printf("%s\n""mdhd box");  
  199.         }  
  200.         break;  
  201.   
  202.         case HDLR_BOX:  
  203.         {  
  204.             printf("%s\n""hdlr box");  
  205.         }  
  206.         break;  
  207.   
  208.         case MINF_BOX:  
  209.         {  
  210.             printf("%s\n""minf box");  
  211.         }  
  212.         break;  
  213.   
  214.         case DINF_BOX:  
  215.         {  
  216.             printf("%s\n""dinf box");  
  217.         }  
  218.         break;  
  219.   
  220.         case TREF_BOX:  
  221.         {  
  222.             printf("%s\n""tref box");  
  223.         }  
  224.         break;  
  225.   
  226.         case STBL_BOX:  
  227.         {  
  228.             printf("%s\n""stbl box");  
  229.         }  
  230.         break;  
  231.   
  232.         case STSD_BOX:  
  233.         {  
  234.             printf("%s\n""stsd box");  
  235.         }  
  236.         break;  
  237.   
  238.         case MP4S_BOX:  
  239.         {  
  240.             printf("%s\n""mp4s box");  
  241.         }  
  242.         break;  
  243.   
  244.         case ESDS_BOX:  
  245.         {  
  246.             printf("%s\n""esds box");  
  247.         }  
  248.         break;  
  249.   
  250.         case STTS_BOX:  
  251.         {  
  252.             printf("%s\n""stts box");  
  253.         }  
  254.         break;  
  255.   
  256.         case STSC_BOX:  
  257.         {  
  258.             printf("%s\n""stsc box");  
  259.         }  
  260.         break;  
  261.   
  262.         case STSZ_BOX:  
  263.         {  
  264.             printf("%s\n""stsz box");  
  265.         }  
  266.         break;  
  267.   
  268.         case STCO_BOX:  
  269.         {  
  270.             printf("%s\n""stco box");  
  271.         }  
  272.         break;  
  273.   
  274.         case STSS_BOX:  
  275.         {  
  276.             printf("%s\n""stss box");  
  277.         }  
  278.         break;  
  279.   
  280.         case CTTS_BOX:  
  281.         {  
  282.             printf("%s\n""ctts box");  
  283.         }  
  284.         break;  
  285.   
  286.         case EDTS_BOX:  
  287.         {  
  288.             printf("%s\n""edts box");  
  289.         }  
  290.         break;  
  291.   
  292.         case VMHD_BOX:  
  293.         {  
  294.             printf("%s\n""vmhd box");       
  295.         }  
  296.         break;  
  297.   
  298.         case SMHD_BOX:  
  299.         {  
  300.             printf("%s\n""smhd box");  
  301.         }  
  302.         break;  
  303.   
  304.         case HMHD_BOX:  
  305.         {  
  306.             printf("%s\n""hmhd box");  
  307.         }  
  308.         break;  
  309.       
  310.         case NMHD_BOX:  
  311.         {  
  312.             printf("%s\n""nmhd box");  
  313.         }  
  314.         break;  
  315.     }  
  316. }  
  317.   
  318. enum timeType  
  319. {  
  320.     CREATE_TIME,  
  321.     MODIFY_TIME  
  322. };  
  323.   
  324. void create_and_modify_time(unsigned int time, enum timeType type)  
  325. {  
  326.     int month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  
  327.     int leap_month_days[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  
  328.     unsigned long local_time = (long)big_to_small_endian_32bit(time);  
  329.     unsigned int local_year = 1904+local_time/3600/24/365;//此处当做是每年365天,下面再微调  
  330.   
  331.     int leap_years_count;//闰年数量  
  332.     //平年,不精确计算  
  333.     if(local_year % 4)  
  334.     {  
  335.         leap_years_count = (local_year - 1904)/4 + 1;  
  336.     }  
  337.     //闰年  
  338.     else  
  339.     {  
  340.         leap_years_count = (local_year - 1904)/4;  
  341.     }  
  342.     unsigned int day_count;//由于上面把每年当作365天,此处计算到年初时过去的实际天数  
  343.     day_count = leap_years_count*366 + (local_year-1904-leap_years_count)*365;  
  344.   
  345.     int leave_day_count = local_time/3600/24 - day_count;//算出剩下的天数  
  346.     int i=0;  
  347.     int sum = 31;  
  348.     int local_month = 0;  
  349.     int local_day = 0;  
  350.     /*下面程序算出一年中的哪一个月和哪一天*/  
  351.     //平年  
  352.     if(local_year % 4)  
  353.     {  
  354.         while(leave_day_count > sum)  
  355.         {  
  356.             local_day = leave_day_count - sum + 1;//因为从零算起,所以天数要加1  
  357.             sum += month_days[++i];  
  358.         }  
  359.     }  
  360.     //闰年  
  361.     else  
  362.     {  
  363.         while(leave_day_count > sum)  
  364.         {  
  365.             local_day = leave_day_count - sum + 1;  
  366.             sum += leap_month_days[++i];  
  367.         }  
  368.     }  
  369.   
  370.     local_month = i+1;  
  371.     if(local_month == 1)//如果是一月份  
  372.     {  
  373.         local_day = leave_day_count + 1;  
  374.     }  
  375.     /*上面程序算出一年中的哪一个月和哪一天*/  
  376.   
  377.     int out_of_day = leave_day_count + day_count;  
  378.     int leave_second = local_time - out_of_day * 3600 *24;//计算剩下的秒数  
  379.     if(type == CREATE_TIME)  
  380.     {  
  381.         printf("编码时间:%d-%d-%d %d:%d:%d\n", local_year, local_month, local_day,   
  382.                                               leave_second/3600, leave_second%3600/60, leave_second%60);  
  383.     }  
  384.     else if(type == MODIFY_TIME)  
  385.     {  
  386.         printf("修订时间:%d-%d-%d %d:%d:%d\n", local_year, local_month, local_day,   
  387.                                               leave_second/3600, leave_second%3600/60, leave_second%60);  
  388.     }  
  389.   
  390.       
  391. }  
  392.   
  393. void mainmenu()  
  394. {  
  395.     printf("------------------------function menu-------------------------\n");  
  396.     printf("1.编码时间与修订时间\n");  
  397.     printf("2.影片长度\n");  
  398.     printf("3.影片声音采样频率、视频帧率、码率(比特率)、分辨率\n");  
  399.     printf("4.视频关键帧列表\n");  
  400.     printf("q.输入q退出\n");  
  401.     printf("------------------------function menu-------------------------\n");  
  402. }  
  403.   
  404. char get_user_input()  
  405. {  
  406.     char select;  
  407. /*这里scanf必须有\n或者空格,看下面的解释 
  408.      
  409. scanf("%c",&c) 与 scanf(" %c",&c),后者只是在%前多了个空格,似乎没有什么区别, 
  410. 但使用起来区别是很大的。scanf()作单字符输入时规定只接收一个字符,但它却把回车符 
  411. 也作为字符对待的。这就造成程序中只有一个输入字符的scanf()语句时,问题还不大, 
  412. 但如果后面还跟着第二个scanf()字符输入语句,这个scanf()就把前面输入的驾车符当作 
  413. 输入字符了。这就在输入逻辑上造成了混乱,达不到人们预期的愿望。有了这个空格, 
  414. 因为scanf()是跳过空格读字符的,就回避了这个问题。实践证明,这个空格放在%c后面也不能达到目的。 
  415. 应当说,这也是比较巧妙的应用!  
  416.     */  
  417.     scanf(" %c", &select);  
  418.     switch(select)  
  419.     {  
  420.         case '1':  
  421.         {  
  422.             create_and_modify_time(mp4_info.create_time, CREATE_TIME);  
  423.             create_and_modify_time(mp4_info.modification_time, MODIFY_TIME);  
  424.         }  
  425.         break;  
  426.   
  427.         case '2':  
  428.         {  
  429.           
  430.         }  
  431.         break;  
  432.   
  433.         case '3':  
  434.         {  
  435.           
  436.         }  
  437.         break;  
  438.   
  439.         case '4':  
  440.         {  
  441.           
  442.         }  
  443.         break;  
  444.   
  445.         case '5':  
  446.         {  
  447.           
  448.         }  
  449.         break;  
  450.           
  451.     }  
  452.     return select;  
  453. }  
  454.   
  455. Ret_Boxhead_Fileptr moov_box_parse(FILE *p)  
  456. {  
  457.     BOX_HEAD box_head;  
  458.     MOOV_HEADER_BOX mvhd_box;  
  459.     char version;  
  460.     char *flag = (char *)malloc(3);  
  461.     bool stbl_flag = false;  
  462.   
  463.     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  464.     print_box_type(box_head.type, 1);//mvhd box  
  465.   
  466.     fread(&version, sizeof(char), 1, p);  
  467.     fread(flag, 3, 1, p);  
  468.     fread(&mvhd_box, sizeof(MOOV_HEADER_BOX), 1, p);  
  469.   
  470.     mp4_info.create_time = mvhd_box.create_time;  
  471.     mp4_info.modification_time = mvhd_box.modification_time;  
  472.   
  473.     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  474.     while(big_to_small_endian_32bit(box_head.type) != TRAK_BOX)  
  475.     {  
  476.         print_box_type(box_head.type, 1);  
  477.         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  478.         fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  479.     }  
  480.   
  481.     print_box_type(box_head.type, 1);//trak box  
  482.     while(big_to_small_endian_32bit(box_head.type) != MDAT_BOX &&  
  483.           big_to_small_endian_32bit(box_head.type) != FREE_BOX)  
  484.     {  
  485.         if(0 == fread(&box_head, sizeof(BOX_HEAD), 1, p))  
  486.         {  
  487.             break;  
  488.         }  
  489.           
  490.         while(big_to_small_endian_32bit(box_head.type) != TRAK_BOX &&  
  491.               big_to_small_endian_32bit(box_head.type) != MDAT_BOX &&  
  492.               big_to_small_endian_32bit(box_head.type) != FREE_BOX )  
  493.         {  
  494.             switch(big_to_small_endian_32bit(box_head.type))  
  495.             {  
  496.                 case TKHD_BOX:  
  497.                 {  
  498.                     print_box_type(box_head.type, 2);//tkhd box  
  499.                     char tkhd_version;  
  500.                     char *tkhd_flag = (char *)malloc(3);  
  501.                     TRACK_HEAD_BOX tkhd_box;  
  502.   
  503.                     fread(&tkhd_version, 1, 1, p);  
  504.                     fread(tkhd_flag, 3, 1, p);  
  505.                     fread(&tkhd_box, sizeof(TRACK_HEAD_BOX), 1, p);  
  506.                     free(tkhd_flag);  
  507.                 }  
  508.                 break;  
  509.   
  510.                 case MDIA_BOX:  
  511.                 {  
  512.                     char mdhd_version;  
  513.                     char *mdhd_flag = (char *)malloc(3);  
  514.                     unsigned int minf_head_box_length;  
  515.                     unsigned int handler_type;  
  516.   
  517.                     MDHD_HEAD_BOX mdhd_box;  
  518.   
  519.                     print_box_type(box_head.type, 2);//mdia box  
  520.   
  521.                     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  522.    
  523.                     print_box_type(box_head.type, 3);//mdhd box  
  524.                       
  525.   
  526.                     fread(&mdhd_version, 1, 1, p);  
  527.                     fread(mdhd_flag, 3, 1, p);  
  528.                     fread(&mdhd_box, sizeof(MDHD_HEAD_BOX), 1, p);  
  529.   
  530.                     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  531.                     print_box_type(box_head.type, 3);//hdlr box  
  532.   
  533.                     fseek(p, 8, SEEK_CUR);  
  534.                     fread(&handler_type, 4, 1, p);  
  535.                     fseek(p, big_to_small_endian_32bit(box_head.size)-20, SEEK_CUR);  
  536.   
  537.                     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  538.                     print_box_type(box_head.type, 3);//minf box  
  539.                       
  540.             /*      fread(&minf_head_box_length, 4, 1, p);//minf head box 
  541.                     fseek(p, big_to_small_endian_32bit(minf_head_box_length)-4, SEEK_CUR); 
  542.  
  543.                     fread(&box_head, sizeof(BOX_HEAD), 1, p); 
  544.                     while(big_to_small_endian_32bit(box_head.type) != STBL_BOX) 
  545.                     { 
  546.                         print_box_type(box_head.type, 4); 
  547.                         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR); 
  548.                         fread(&box_head, sizeof(BOX_HEAD), 1, p); 
  549.                     } 
  550.      
  551.                     print_box_type(box_head.type, 4);//stbl box*/  
  552.                     switch(big_to_small_endian_32bit(handler_type))  
  553.                     {  
  554.                         case SOUN:  
  555.                         case VIDE:  
  556.                         case HINT:  
  557.                         {  
  558.                             unsigned int now_pos = ftell(p);  
  559.                             unsigned int now_box_size = big_to_small_endian_32bit(box_head.size);  
  560.                             while((ftell(p)-now_pos+8) != now_box_size)  
  561.                             {  
  562.                                 fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  563.                                 fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  564.                                 switch(big_to_small_endian_32bit(box_head.type))  
  565.                                 {  
  566.                                     case VMHD_BOX:  
  567.                                     case DINF_BOX:  
  568.                                     case HMHD_BOX:  
  569.                                     case SMHD_BOX:  
  570.                                     {  
  571.                                         print_box_type(box_head.type, 4);  
  572.                                     }  
  573.                                     break;  
  574.   
  575.                                     case STBL_BOX:  
  576.                                     {  
  577.                                         print_box_type(box_head.type, 4);  
  578.                                         stbl_flag = true;  
  579.                                         fseek(p, 8-big_to_small_endian_32bit(box_head.size), SEEK_CUR);  
  580.                                       
  581.                                   
  582.                                         unsigned int stbl_pos = ftell(p);  
  583.                                         unsigned int stbl_box_size = big_to_small_endian_32bit(box_head.size);  
  584.                                         while((ftell(p)-stbl_pos+8) != stbl_box_size)  
  585.                                         {  
  586.                                             fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  587.                                             fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  588.                                             switch(big_to_small_endian_32bit(box_head.type))  
  589.                                             {  
  590.                                                 case STSD_BOX:  
  591.                                                 {  
  592.                                                     print_box_type(box_head.type, 5);  
  593.                                                 }  
  594.                                                 break;  
  595.   
  596.                                                 case STTS_BOX:  
  597.                                                 {  
  598.                                                     print_box_type(box_head.type, 5);  
  599.                                                 }  
  600.                                                 break;  
  601.   
  602.                                                 case STSC_BOX:  
  603.                                                 {  
  604.                                                     print_box_type(box_head.type, 5);  
  605.                                                 }  
  606.                                                 break;  
  607.   
  608.                                                 case STSZ_BOX:  
  609.                                                 {  
  610.                                                     print_box_type(box_head.type, 5);  
  611.                                                 }  
  612.                                                 break;  
  613.   
  614.                                                 case STCO_BOX:  
  615.                                                 {  
  616.                                                     print_box_type(box_head.type, 5);  
  617.                                                 }  
  618.                                                 break;  
  619.   
  620.                                                 case STSS_BOX:  
  621.                                                 {  
  622.                                                     print_box_type(box_head.type, 5);  
  623.                                                 }  
  624.                                                 break;  
  625.                                             }  
  626.                                         }         
  627.                       
  628.   
  629.                                     }  
  630.                                     break;  
  631.                                 }  
  632.                             }  
  633.                         }  
  634.                         break;  
  635.   
  636.                         default:  
  637.                         {  
  638.                             fread(&minf_head_box_length, 4, 1, p);//nmhd  
  639.                             print_box_type(NMHD_BOX, 4);  
  640.                             fseek(p, big_to_small_endian_32bit(minf_head_box_length)-4, SEEK_CUR);  
  641.                             fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  642.                             while(big_to_small_endian_32bit(box_head.type) != STBL_BOX)  
  643.                             {  
  644.                                 print_box_type(box_head.type, 4);  
  645.                                 fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  646.                                 fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  647.                             }  
  648.               
  649.                             print_box_type(box_head.type, 4);//stbl box  
  650.                         }  
  651.                         break;  
  652.                     }  
  653.   
  654.                     if(stbl_flag == true)  
  655.                     {  
  656.                         stbl_flag = false;  
  657.                         free(mdhd_flag);  
  658.                         break;  
  659.                     }  
  660.   
  661.                     unsigned int cur_pos = ftell(p);  
  662.                     unsigned int cur_box_size = big_to_small_endian_32bit(box_head.size);  
  663.                     while((ftell(p)-cur_pos+8) != cur_box_size)  
  664.                     {  
  665.                         fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  666.                         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  667.                         switch(big_to_small_endian_32bit(box_head.type))  
  668.                         {  
  669.                             case STSD_BOX:  
  670.                             {  
  671.                                 print_box_type(box_head.type, 5);  
  672.                             }  
  673.                             break;  
  674.   
  675.                             case STTS_BOX:  
  676.                             {  
  677.                                 print_box_type(box_head.type, 5);  
  678.                             }  
  679.                             break;  
  680.   
  681.                             case STSC_BOX:  
  682.                             {  
  683.                                 print_box_type(box_head.type, 5);  
  684.                             }  
  685.                             break;  
  686.   
  687.                             case STSZ_BOX:  
  688.                             {  
  689.                                 print_box_type(box_head.type, 5);  
  690.                             }  
  691.                             break;  
  692.   
  693.                             case STCO_BOX:  
  694.                             {  
  695.                                 print_box_type(box_head.type, 5);  
  696.                             }  
  697.                             break;  
  698.   
  699.                             case STSS_BOX:  
  700.                             {  
  701.                                 print_box_type(box_head.type, 5);  
  702.                             }  
  703.                             break;  
  704.   
  705.                             case CTTS_BOX:  
  706.                             {  
  707.                                 print_box_type(box_head.type, 5);  
  708.                             }  
  709.                             break;  
  710.                         }  
  711.                     }  
  712.                       
  713.                     stbl_flag = false;  
  714.                     free(mdhd_flag);  
  715.                 }  
  716.                 break;  
  717.   
  718.                 default:  
  719.                     print_box_type(box_head.type, 2);  
  720.                     fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  721.                     break;  
  722.             }  
  723.   
  724.             /*读取到文件末尾跳出*/  
  725.             if(0 == fread(&box_head, sizeof(BOX_HEAD), 1, p))  
  726.             {  
  727.                 break;  
  728.             }  
  729.             if(big_to_small_endian_32bit(box_head.type) == TRAK_BOX)  
  730.             {  
  731.                 print_box_type(box_head.type, 1);  
  732.             }  
  733.         }  
  734.     }  
  735.     free(flag);  
  736.     Ret_Boxhead_Fileptr ret;  
  737.     ret.box_head.size = box_head.size;  
  738.     ret.box_head.type = box_head.type;  
  739.     ret.p = p;  
  740.     return ret;  
  741. }  
  742.   
  743. FILE* mdat_box_parse(FILE *p, BOX_HEAD box_head)  
  744. {  
  745.     __int64 box_large_size;  
  746.     if(big_to_small_endian_32bit(box_head.size) != 1)  
  747.     {  
  748.         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  749.     }  
  750.     else  
  751.     {  
  752.         fread(&box_large_size, sizeof(__int64), 1, p);  
  753.         fseek(p, big_to_small_endian_64bit(box_large_size)-sizeof(__int64)-8, SEEK_CUR);  
  754.     }  
  755.     return p;  
  756. }  
  757.   
  758. int main( void )  
  759. {  
  760.     FILE *p;  
  761.     FTYP_BOX ftyp_box;  
  762.     BOX_HEAD box_head;  
  763.     char filename[256];  
  764.   
  765.     printf("please input mp4 filename:");  
  766.     scanf("%s", filename);  
  767.   
  768.     if((p = fopen(filename,"r")) == NULL)  
  769.     {  
  770.         printf("open fail\n");  
  771.         return -1;  
  772.     }  
  773.     printf("----------------------MP4 file structure----------------------\n");  
  774.     fread(&ftyp_box, sizeof(FTYP_BOX), 1, p);  
  775.     print_box_type(ftyp_box.ftyp_type, 0);//ftyp box  
  776.   
  777.     fseek(p, big_to_small_endian_32bit(ftyp_box.ftyp_size), SEEK_SET);  
  778.     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  779.     print_box_type(box_head.type, 0);//moov box OR mdat box  
  780.     switch(big_to_small_endian_32bit(box_head.type))  
  781.     {  
  782.         case MDAT_BOX:  
  783.         {  
  784.             p = mdat_box_parse(p, box_head);  
  785.             fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  786.             print_box_type(box_head.type, 0);//moov box  
  787.             moov_box_parse(p);  
  788.         }  
  789.         break;  
  790.   
  791.         case MOOV_BOX:  
  792.         {     
  793.             Ret_Boxhead_Fileptr ret;  
  794.             ret = moov_box_parse(p);  
  795.             print_box_type(ret.box_head.type, 0);  
  796.             mdat_box_parse(ret.p, ret.box_head);  
  797.         }  
  798.         break;  
  799.           
  800.         default:  
  801.         break;  
  802.     }  
  803.     fclose(p);  
  804.     printf("----------------------MP4 file structure----------------------\n\n\n");  
  805.   
  806.     mainmenu();  
  807.     while(get_user_input() != 'q')  
  808.     {  
  809.         mainmenu();  
  810.     }  
  811.     return 0;  
  812. }  

版权声明:本文为博主原创文章,未经博主允许不得转载。

准备

安装mediaInfo、QTAtomViewer.exe、MP4info.exe等软件

视频一些参数

封装格式:我也不太清楚

编码格式:我也不太清楚

分辨率:图像的长和宽。

帧率:一秒播放的图片数,如15fps、30fps,体现在画面的流畅度。

码率:压缩后每秒显示的图片数据量,通俗地说,就是流量。如298kbps,体现在视频文件的大小和画质。

压缩比:分辨率*帧率/码率,简单来说就是压缩前每秒的数据量比上压缩后每秒的数据量。

音频一些参数

声道:录音时录音的位置不同产生不同的声道,有单声道、立体声(左右声道)、四声道环绕、5.1声道等。放歌时切换到左声道,两个音箱都播放左声道,切换到右声道时,两个音箱都播放右声道,切换到立体音时,左音箱播放左声道,右音箱播放右声道。可用暴风影音体验一下。

音轨: ①电视上看到录音时歌手都是在录音棚里戴着耳机唱歌,其实这就使用了多音轨技术,先把伴奏录好(音轨1),歌手再根据伴奏唱歌(音轨2)。②在K房使用的也是多音轨(原唱和伴唱)③有些老歌经常是粤语版和国语版一起唱,这也是多音轨技术

采样率:录制声音时对声音的采样频率,一般为44.1KHz

MP4文件组成

MP4由一个个的box(以前叫atom)组成,如下图,每个box包含不同的信息(再如下图),在程序中用结构体表示各个box,形象地说MP4文件就是由各个结构体组织起来的。所以,首先要了解这些box的组成和意义。

主要概念:sample、chunk、track

sample,在这里实际上就是一帧或连续几帧

chunk,一个或几个sample组成的单元

track,视频或音频序列,sample的集合


MP4主要由三个box组成,ftyp、mdat和moov。ftyp指示一些头部信息,通过ftyp box可以判断文件类型。mdat box存放的是媒体数据,就是播放的音频实实在在的元数据,比如我们需要取到第一帧的图片数据就存放在这个box里面。这么多数据,怎么知道这些数据的准确位置呢?这就要靠moov box来解析了。一般情况下,一个moov box包含一个mvhd和若干个track box。①mvhd box中存放一些create/modify time(基准时间是1904-1-1 0:00 AM)等信息,duration/time scale就是视频的长度(单位为s)。②track box一般包含tkhd和mdia两个box,tkhd中存放有视频长度和宽度等信息,,,,,,,最重要的是mdia -> minf -> stbl box下面的6个box,分别是stsd、stts、stss、stsc、stsz、stco,比如要查找第N秒的图片数据,步骤如下:

1、确定第N秒在媒体时间坐标系统中的位置,即N*time_scale

2、根据stts(time to sample)确定sample序号

3、根据stsc(sample to chunk)确定对应该sample的chunk

4、根据stco(chunk offset)中提取该chunk的偏移量

5、根据stsz(sample size)找到该sample在chunk内的偏移量和sample的大小。


例如:以test.mp4为例说明,用QTAtomViewer.exe查看此文件可知time_scale为90000,即一秒分为90000个刻度,现在假设要查看第一秒的数据,步骤如下:

1、一秒在媒体时间坐标系统中的位置,即1*90000 = 90000;

2、由stts,sample duration = 6000, 90000/6000 = 15, 即sample序号为15

3、由stsc,因为samples Per chunk = 1, 所以chunk序号也为15

4、由stco,序号为15的chunk的offset = 62719

5、由stsz,sample 在 chunk内的偏移为0,且大小为3554。

也就是说,程序到62719的地址开始,读取3554byte的数据,就是第一秒的图片数据。如果要查看第一帧(第0秒)的数据,同样按照上面的步骤可定位到地址28,读取5280byte的数据

现在知道了MP4文件的组成,也知道了怎么去获取第N帧的数据,那么无论程序多么复杂,它都是围绕这个主题来做文章了


最后附上一小段简单的视频解析的代码

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <time.h>  
  4.   
  5. #define BOX_FTYP 0x66747970  
  6. #define MDAT_BOX 0x6D646174  
  7. #define MOOV_BOX 0x6D6F6F76  
  8. #define MVHD_BOX 0x6D766864  
  9. #define TRAK_BOX 0x7472616B  
  10. #define IODS_BOX 0x696F6473  
  11. #define UDTA_BOX 0x75647461  
  12. #define FREE_BOX 0x66726565  
  13. #define TKHD_BOX 0x746B6864  
  14. #define MDIA_BOX 0x6D646961  
  15. #define MDHD_BOX 0x6D646864  
  16. #define HDLR_BOX 0x68646C72  
  17. #define MINF_BOX 0x6D696E66  
  18. #define DINF_BOX 0x64696E66  
  19. #define TREF_BOX 0x74726566  
  20. #define STBL_BOX 0x7374626C  
  21. #define STSD_BOX 0x73747364  
  22. #define MP4S_BOX 0x6D703473  
  23. #define ESDS_BOX 0x65736473  
  24. #define STTS_BOX 0x73747473  
  25. #define STSC_BOX 0x73747363  
  26. #define STSZ_BOX 0x7374737A  
  27. #define STCO_BOX 0x7374636F  
  28. #define STSS_BOX 0x73747373  
  29. #define CTTS_BOX 0x63747473  
  30. #define EDTS_BOX 0x65647473  
  31. #define VMHD_BOX 0x766D6864  
  32. #define HMHD_BOX 0x686D6864  
  33. #define SMHD_BOX 0x736D6864  
  34. #define NMHD_BOX 0xffffffff  
  35.   
  36. #define ODSM    0x6F64736D  
  37. #define SDSM    0x7364736D  
  38. #define VIDE    0x76696465  
  39. #define HINT    0x68696E74  
  40. #define SOUN    0x736F756E  
  41.   
  42. typedef struct BOX_HEAD  
  43. {  
  44.     unsigned int size;  
  45.     unsigned int type;  
  46. }BOX_HEAD;  
  47.   
  48. typedef struct FTYP_BOX  
  49. {  
  50.     unsigned int ftyp_size;  
  51.     unsigned int ftyp_type;  
  52. }FTYP_BOX;  
  53.   
  54.   
  55. typedef struct MOOV_HEADER_BOX  
  56. {  
  57.     unsigned int create_time;  
  58.     unsigned int modification_time;  
  59.     unsigned int time_scale;  
  60.     unsigned int duration;  
  61.     unsigned int preferred_rate;  
  62.     unsigned short preferred_volume;  
  63.     char reserved[10];  
  64.     char matrix_structure[36];  
  65.     char pre_defined[24];  
  66.     unsigned int next_track_id;  
  67. }MOOV_HEADER_BOX;  
  68.   
  69. typedef struct Track_head_box  
  70. {  
  71.     unsigned int create_time;  
  72.     unsigned int modification_time;  
  73.     unsigned int track_id;  
  74.     unsigned int reserved1;  
  75.     unsigned int duration;  
  76.     unsigned int reserved2[2];  
  77.     unsigned short layer;  
  78.     unsigned short alternate_group;  
  79.     unsigned short volume;  
  80.     unsigned short reserved3;  
  81.     char matrix[36];  
  82.     unsigned int width;  
  83.     unsigned int height;  
  84. }TRACK_HEAD_BOX;  
  85.   
  86. typedef struct Mdhd_head_box  
  87. {  
  88.     unsigned int create_time;  
  89.     unsigned int modification_time;  
  90.     unsigned int time_scale;  
  91.     unsigned int duration;  
  92.     unsigned short language;  
  93.     unsigned short quality;  
  94. }MDHD_HEAD_BOX;  
  95.   
  96. typedef struct Ret_Boxhead_Fileptr  
  97. {  
  98.     BOX_HEAD box_head;  
  99.     FILE *p;  
  100. }Ret_Boxhead_Fileptr;  
  101.   
  102. struct MP4_INFO  
  103. {  
  104.     unsigned int create_time;  
  105.     unsigned int modification_time;  
  106. }mp4_info;  
  107.   
  108. unsigned int big_to_small_endian_32bit(unsigned int const big)  
  109. {  
  110.     unsigned int data = big;  
  111.     unsigned int ret = 0;  
  112.     ret += (data>>0 & 0xff) << 24;  
  113.     ret += (data>>8 & 0xff) << 16;  
  114.     ret += (data>>16 & 0xff) << 8;  
  115.     ret += (data>>24 & 0xff) << 0;  
  116.     return ret;  
  117. }  
  118.   
  119. __int64 big_to_small_endian_64bit(__int64 const big)  
  120. {  
  121.     __int64 data = big;  
  122.     __int64 ret = 0;  
  123.     ret += (data>>0 & 0xff) << 56;  
  124.     ret += (data>>8 & 0xff) << 48;  
  125.     ret += (data>>16 & 0xff) << 40;  
  126.     ret += (data>>24 & 0xff) << 32;  
  127.     ret += (data>>32 & 0xff) << 24;  
  128.     ret += (data>>40 & 0xff) << 16;  
  129.     ret += (data>>48 & 0xff) << 8;  
  130.     ret += (data>>56 & 0xff) << 0;  
  131.     return ret;  
  132. }  
  133.   
  134. void print_box_type(unsigned int box_type, unsigned int num)  
  135. {  
  136.     for(unsigned int i = 0; i < num; i++)  
  137.     {  
  138.         printf("\t");  
  139.     }  
  140.     switch(big_to_small_endian_32bit(box_type))  
  141.     {  
  142.         case BOX_FTYP:  
  143.         {  
  144.             printf("%s\n""ftyp box");  
  145.         }  
  146.         break;  
  147.   
  148.         case MOOV_BOX:  
  149.         {  
  150.             printf("%s\n""moov box");  
  151.         }  
  152.         break;  
  153.           
  154.         case MDAT_BOX:  
  155.         {  
  156.             printf("%s\n""mdat box");  
  157.         }  
  158.         break;  
  159.   
  160.         case MVHD_BOX:  
  161.         {  
  162.             printf("%s\n""mvhd box");  
  163.         }  
  164.         break;  
  165.   
  166.         case IODS_BOX:  
  167.         {  
  168.             printf("%s\n""iods box");  
  169.         }  
  170.         break;  
  171.   
  172.         case UDTA_BOX:  
  173.         {  
  174.             printf("%s\n""udta box");  
  175.         }  
  176.         break;  
  177.   
  178.         case TRAK_BOX:  
  179.         {  
  180.             printf("%s\n""trak box");  
  181.         }  
  182.         break;  
  183.   
  184.         case TKHD_BOX:  
  185.         {  
  186.             printf("%s\n""tkhd box");  
  187.         }  
  188.         break;  
  189.   
  190.         case MDIA_BOX:  
  191.         {  
  192.             printf("%s\n""mdia box");  
  193.         }  
  194.         break;  
  195.   
  196.         case MDHD_BOX:  
  197.         {  
  198.             printf("%s\n""mdhd box");  
  199.         }  
  200.         break;  
  201.   
  202.         case HDLR_BOX:  
  203.         {  
  204.             printf("%s\n""hdlr box");  
  205.         }  
  206.         break;  
  207.   
  208.         case MINF_BOX:  
  209.         {  
  210.             printf("%s\n""minf box");  
  211.         }  
  212.         break;  
  213.   
  214.         case DINF_BOX:  
  215.         {  
  216.             printf("%s\n""dinf box");  
  217.         }  
  218.         break;  
  219.   
  220.         case TREF_BOX:  
  221.         {  
  222.             printf("%s\n""tref box");  
  223.         }  
  224.         break;  
  225.   
  226.         case STBL_BOX:  
  227.         {  
  228.             printf("%s\n""stbl box");  
  229.         }  
  230.         break;  
  231.   
  232.         case STSD_BOX:  
  233.         {  
  234.             printf("%s\n""stsd box");  
  235.         }  
  236.         break;  
  237.   
  238.         case MP4S_BOX:  
  239.         {  
  240.             printf("%s\n""mp4s box");  
  241.         }  
  242.         break;  
  243.   
  244.         case ESDS_BOX:  
  245.         {  
  246.             printf("%s\n""esds box");  
  247.         }  
  248.         break;  
  249.   
  250.         case STTS_BOX:  
  251.         {  
  252.             printf("%s\n""stts box");  
  253.         }  
  254.         break;  
  255.   
  256.         case STSC_BOX:  
  257.         {  
  258.             printf("%s\n""stsc box");  
  259.         }  
  260.         break;  
  261.   
  262.         case STSZ_BOX:  
  263.         {  
  264.             printf("%s\n""stsz box");  
  265.         }  
  266.         break;  
  267.   
  268.         case STCO_BOX:  
  269.         {  
  270.             printf("%s\n""stco box");  
  271.         }  
  272.         break;  
  273.   
  274.         case STSS_BOX:  
  275.         {  
  276.             printf("%s\n""stss box");  
  277.         }  
  278.         break;  
  279.   
  280.         case CTTS_BOX:  
  281.         {  
  282.             printf("%s\n""ctts box");  
  283.         }  
  284.         break;  
  285.   
  286.         case EDTS_BOX:  
  287.         {  
  288.             printf("%s\n""edts box");  
  289.         }  
  290.         break;  
  291.   
  292.         case VMHD_BOX:  
  293.         {  
  294.             printf("%s\n""vmhd box");       
  295.         }  
  296.         break;  
  297.   
  298.         case SMHD_BOX:  
  299.         {  
  300.             printf("%s\n""smhd box");  
  301.         }  
  302.         break;  
  303.   
  304.         case HMHD_BOX:  
  305.         {  
  306.             printf("%s\n""hmhd box");  
  307.         }  
  308.         break;  
  309.       
  310.         case NMHD_BOX:  
  311.         {  
  312.             printf("%s\n""nmhd box");  
  313.         }  
  314.         break;  
  315.     }  
  316. }  
  317.   
  318. enum timeType  
  319. {  
  320.     CREATE_TIME,  
  321.     MODIFY_TIME  
  322. };  
  323.   
  324. void create_and_modify_time(unsigned int time, enum timeType type)  
  325. {  
  326.     int month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  
  327.     int leap_month_days[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};  
  328.     unsigned long local_time = (long)big_to_small_endian_32bit(time);  
  329.     unsigned int local_year = 1904+local_time/3600/24/365;//此处当做是每年365天,下面再微调  
  330.   
  331.     int leap_years_count;//闰年数量  
  332.     //平年,不精确计算  
  333.     if(local_year % 4)  
  334.     {  
  335.         leap_years_count = (local_year - 1904)/4 + 1;  
  336.     }  
  337.     //闰年  
  338.     else  
  339.     {  
  340.         leap_years_count = (local_year - 1904)/4;  
  341.     }  
  342.     unsigned int day_count;//由于上面把每年当作365天,此处计算到年初时过去的实际天数  
  343.     day_count = leap_years_count*366 + (local_year-1904-leap_years_count)*365;  
  344.   
  345.     int leave_day_count = local_time/3600/24 - day_count;//算出剩下的天数  
  346.     int i=0;  
  347.     int sum = 31;  
  348.     int local_month = 0;  
  349.     int local_day = 0;  
  350.     /*下面程序算出一年中的哪一个月和哪一天*/  
  351.     //平年  
  352.     if(local_year % 4)  
  353.     {  
  354.         while(leave_day_count > sum)  
  355.         {  
  356.             local_day = leave_day_count - sum + 1;//因为从零算起,所以天数要加1  
  357.             sum += month_days[++i];  
  358.         }  
  359.     }  
  360.     //闰年  
  361.     else  
  362.     {  
  363.         while(leave_day_count > sum)  
  364.         {  
  365.             local_day = leave_day_count - sum + 1;  
  366.             sum += leap_month_days[++i];  
  367.         }  
  368.     }  
  369.   
  370.     local_month = i+1;  
  371.     if(local_month == 1)//如果是一月份  
  372.     {  
  373.         local_day = leave_day_count + 1;  
  374.     }  
  375.     /*上面程序算出一年中的哪一个月和哪一天*/  
  376.   
  377.     int out_of_day = leave_day_count + day_count;  
  378.     int leave_second = local_time - out_of_day * 3600 *24;//计算剩下的秒数  
  379.     if(type == CREATE_TIME)  
  380.     {  
  381.         printf("编码时间:%d-%d-%d %d:%d:%d\n", local_year, local_month, local_day,   
  382.                                               leave_second/3600, leave_second%3600/60, leave_second%60);  
  383.     }  
  384.     else if(type == MODIFY_TIME)  
  385.     {  
  386.         printf("修订时间:%d-%d-%d %d:%d:%d\n", local_year, local_month, local_day,   
  387.                                               leave_second/3600, leave_second%3600/60, leave_second%60);  
  388.     }  
  389.   
  390.       
  391. }  
  392.   
  393. void mainmenu()  
  394. {  
  395.     printf("------------------------function menu-------------------------\n");  
  396.     printf("1.编码时间与修订时间\n");  
  397.     printf("2.影片长度\n");  
  398.     printf("3.影片声音采样频率、视频帧率、码率(比特率)、分辨率\n");  
  399.     printf("4.视频关键帧列表\n");  
  400.     printf("q.输入q退出\n");  
  401.     printf("------------------------function menu-------------------------\n");  
  402. }  
  403.   
  404. char get_user_input()  
  405. {  
  406.     char select;  
  407. /*这里scanf必须有\n或者空格,看下面的解释 
  408.      
  409. scanf("%c",&c) 与 scanf(" %c",&c),后者只是在%前多了个空格,似乎没有什么区别, 
  410. 但使用起来区别是很大的。scanf()作单字符输入时规定只接收一个字符,但它却把回车符 
  411. 也作为字符对待的。这就造成程序中只有一个输入字符的scanf()语句时,问题还不大, 
  412. 但如果后面还跟着第二个scanf()字符输入语句,这个scanf()就把前面输入的驾车符当作 
  413. 输入字符了。这就在输入逻辑上造成了混乱,达不到人们预期的愿望。有了这个空格, 
  414. 因为scanf()是跳过空格读字符的,就回避了这个问题。实践证明,这个空格放在%c后面也不能达到目的。 
  415. 应当说,这也是比较巧妙的应用!  
  416.     */  
  417.     scanf(" %c", &select);  
  418.     switch(select)  
  419.     {  
  420.         case '1':  
  421.         {  
  422.             create_and_modify_time(mp4_info.create_time, CREATE_TIME);  
  423.             create_and_modify_time(mp4_info.modification_time, MODIFY_TIME);  
  424.         }  
  425.         break;  
  426.   
  427.         case '2':  
  428.         {  
  429.           
  430.         }  
  431.         break;  
  432.   
  433.         case '3':  
  434.         {  
  435.           
  436.         }  
  437.         break;  
  438.   
  439.         case '4':  
  440.         {  
  441.           
  442.         }  
  443.         break;  
  444.   
  445.         case '5':  
  446.         {  
  447.           
  448.         }  
  449.         break;  
  450.           
  451.     }  
  452.     return select;  
  453. }  
  454.   
  455. Ret_Boxhead_Fileptr moov_box_parse(FILE *p)  
  456. {  
  457.     BOX_HEAD box_head;  
  458.     MOOV_HEADER_BOX mvhd_box;  
  459.     char version;  
  460.     char *flag = (char *)malloc(3);  
  461.     bool stbl_flag = false;  
  462.   
  463.     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  464.     print_box_type(box_head.type, 1);//mvhd box  
  465.   
  466.     fread(&version, sizeof(char), 1, p);  
  467.     fread(flag, 3, 1, p);  
  468.     fread(&mvhd_box, sizeof(MOOV_HEADER_BOX), 1, p);  
  469.   
  470.     mp4_info.create_time = mvhd_box.create_time;  
  471.     mp4_info.modification_time = mvhd_box.modification_time;  
  472.   
  473.     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  474.     while(big_to_small_endian_32bit(box_head.type) != TRAK_BOX)  
  475.     {  
  476.         print_box_type(box_head.type, 1);  
  477.         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  478.         fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  479.     }  
  480.   
  481.     print_box_type(box_head.type, 1);//trak box  
  482.     while(big_to_small_endian_32bit(box_head.type) != MDAT_BOX &&  
  483.           big_to_small_endian_32bit(box_head.type) != FREE_BOX)  
  484.     {  
  485.         if(0 == fread(&box_head, sizeof(BOX_HEAD), 1, p))  
  486.         {  
  487.             break;  
  488.         }  
  489.           
  490.         while(big_to_small_endian_32bit(box_head.type) != TRAK_BOX &&  
  491.               big_to_small_endian_32bit(box_head.type) != MDAT_BOX &&  
  492.               big_to_small_endian_32bit(box_head.type) != FREE_BOX )  
  493.         {  
  494.             switch(big_to_small_endian_32bit(box_head.type))  
  495.             {  
  496.                 case TKHD_BOX:  
  497.                 {  
  498.                     print_box_type(box_head.type, 2);//tkhd box  
  499.                     char tkhd_version;  
  500.                     char *tkhd_flag = (char *)malloc(3);  
  501.                     TRACK_HEAD_BOX tkhd_box;  
  502.   
  503.                     fread(&tkhd_version, 1, 1, p);  
  504.                     fread(tkhd_flag, 3, 1, p);  
  505.                     fread(&tkhd_box, sizeof(TRACK_HEAD_BOX), 1, p);  
  506.                     free(tkhd_flag);  
  507.                 }  
  508.                 break;  
  509.   
  510.                 case MDIA_BOX:  
  511.                 {  
  512.                     char mdhd_version;  
  513.                     char *mdhd_flag = (char *)malloc(3);  
  514.                     unsigned int minf_head_box_length;  
  515.                     unsigned int handler_type;  
  516.   
  517.                     MDHD_HEAD_BOX mdhd_box;  
  518.   
  519.                     print_box_type(box_head.type, 2);//mdia box  
  520.   
  521.                     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  522.    
  523.                     print_box_type(box_head.type, 3);//mdhd box  
  524.                       
  525.   
  526.                     fread(&mdhd_version, 1, 1, p);  
  527.                     fread(mdhd_flag, 3, 1, p);  
  528.                     fread(&mdhd_box, sizeof(MDHD_HEAD_BOX), 1, p);  
  529.   
  530.                     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  531.                     print_box_type(box_head.type, 3);//hdlr box  
  532.   
  533.                     fseek(p, 8, SEEK_CUR);  
  534.                     fread(&handler_type, 4, 1, p);  
  535.                     fseek(p, big_to_small_endian_32bit(box_head.size)-20, SEEK_CUR);  
  536.   
  537.                     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  538.                     print_box_type(box_head.type, 3);//minf box  
  539.                       
  540.             /*      fread(&minf_head_box_length, 4, 1, p);//minf head box 
  541.                     fseek(p, big_to_small_endian_32bit(minf_head_box_length)-4, SEEK_CUR); 
  542.  
  543.                     fread(&box_head, sizeof(BOX_HEAD), 1, p); 
  544.                     while(big_to_small_endian_32bit(box_head.type) != STBL_BOX) 
  545.                     { 
  546.                         print_box_type(box_head.type, 4); 
  547.                         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR); 
  548.                         fread(&box_head, sizeof(BOX_HEAD), 1, p); 
  549.                     } 
  550.      
  551.                     print_box_type(box_head.type, 4);//stbl box*/  
  552.                     switch(big_to_small_endian_32bit(handler_type))  
  553.                     {  
  554.                         case SOUN:  
  555.                         case VIDE:  
  556.                         case HINT:  
  557.                         {  
  558.                             unsigned int now_pos = ftell(p);  
  559.                             unsigned int now_box_size = big_to_small_endian_32bit(box_head.size);  
  560.                             while((ftell(p)-now_pos+8) != now_box_size)  
  561.                             {  
  562.                                 fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  563.                                 fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  564.                                 switch(big_to_small_endian_32bit(box_head.type))  
  565.                                 {  
  566.                                     case VMHD_BOX:  
  567.                                     case DINF_BOX:  
  568.                                     case HMHD_BOX:  
  569.                                     case SMHD_BOX:  
  570.                                     {  
  571.                                         print_box_type(box_head.type, 4);  
  572.                                     }  
  573.                                     break;  
  574.   
  575.                                     case STBL_BOX:  
  576.                                     {  
  577.                                         print_box_type(box_head.type, 4);  
  578.                                         stbl_flag = true;  
  579.                                         fseek(p, 8-big_to_small_endian_32bit(box_head.size), SEEK_CUR);  
  580.                                       
  581.                                   
  582.                                         unsigned int stbl_pos = ftell(p);  
  583.                                         unsigned int stbl_box_size = big_to_small_endian_32bit(box_head.size);  
  584.                                         while((ftell(p)-stbl_pos+8) != stbl_box_size)  
  585.                                         {  
  586.                                             fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  587.                                             fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  588.                                             switch(big_to_small_endian_32bit(box_head.type))  
  589.                                             {  
  590.                                                 case STSD_BOX:  
  591.                                                 {  
  592.                                                     print_box_type(box_head.type, 5);  
  593.                                                 }  
  594.                                                 break;  
  595.   
  596.                                                 case STTS_BOX:  
  597.                                                 {  
  598.                                                     print_box_type(box_head.type, 5);  
  599.                                                 }  
  600.                                                 break;  
  601.   
  602.                                                 case STSC_BOX:  
  603.                                                 {  
  604.                                                     print_box_type(box_head.type, 5);  
  605.                                                 }  
  606.                                                 break;  
  607.   
  608.                                                 case STSZ_BOX:  
  609.                                                 {  
  610.                                                     print_box_type(box_head.type, 5);  
  611.                                                 }  
  612.                                                 break;  
  613.   
  614.                                                 case STCO_BOX:  
  615.                                                 {  
  616.                                                     print_box_type(box_head.type, 5);  
  617.                                                 }  
  618.                                                 break;  
  619.   
  620.                                                 case STSS_BOX:  
  621.                                                 {  
  622.                                                     print_box_type(box_head.type, 5);  
  623.                                                 }  
  624.                                                 break;  
  625.                                             }  
  626.                                         }         
  627.                       
  628.   
  629.                                     }  
  630.                                     break;  
  631.                                 }  
  632.                             }  
  633.                         }  
  634.                         break;  
  635.   
  636.                         default:  
  637.                         {  
  638.                             fread(&minf_head_box_length, 4, 1, p);//nmhd  
  639.                             print_box_type(NMHD_BOX, 4);  
  640.                             fseek(p, big_to_small_endian_32bit(minf_head_box_length)-4, SEEK_CUR);  
  641.                             fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  642.                             while(big_to_small_endian_32bit(box_head.type) != STBL_BOX)  
  643.                             {  
  644.                                 print_box_type(box_head.type, 4);  
  645.                                 fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  646.                                 fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  647.                             }  
  648.               
  649.                             print_box_type(box_head.type, 4);//stbl box  
  650.                         }  
  651.                         break;  
  652.                     }  
  653.   
  654.                     if(stbl_flag == true)  
  655.                     {  
  656.                         stbl_flag = false;  
  657.                         free(mdhd_flag);  
  658.                         break;  
  659.                     }  
  660.   
  661.                     unsigned int cur_pos = ftell(p);  
  662.                     unsigned int cur_box_size = big_to_small_endian_32bit(box_head.size);  
  663.                     while((ftell(p)-cur_pos+8) != cur_box_size)  
  664.                     {  
  665.                         fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  666.                         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  667.                         switch(big_to_small_endian_32bit(box_head.type))  
  668.                         {  
  669.                             case STSD_BOX:  
  670.                             {  
  671.                                 print_box_type(box_head.type, 5);  
  672.                             }  
  673.                             break;  
  674.   
  675.                             case STTS_BOX:  
  676.                             {  
  677.                                 print_box_type(box_head.type, 5);  
  678.                             }  
  679.                             break;  
  680.   
  681.                             case STSC_BOX:  
  682.                             {  
  683.                                 print_box_type(box_head.type, 5);  
  684.                             }  
  685.                             break;  
  686.   
  687.                             case STSZ_BOX:  
  688.                             {  
  689.                                 print_box_type(box_head.type, 5);  
  690.                             }  
  691.                             break;  
  692.   
  693.                             case STCO_BOX:  
  694.                             {  
  695.                                 print_box_type(box_head.type, 5);  
  696.                             }  
  697.                             break;  
  698.   
  699.                             case STSS_BOX:  
  700.                             {  
  701.                                 print_box_type(box_head.type, 5);  
  702.                             }  
  703.                             break;  
  704.   
  705.                             case CTTS_BOX:  
  706.                             {  
  707.                                 print_box_type(box_head.type, 5);  
  708.                             }  
  709.                             break;  
  710.                         }  
  711.                     }  
  712.                       
  713.                     stbl_flag = false;  
  714.                     free(mdhd_flag);  
  715.                 }  
  716.                 break;  
  717.   
  718.                 default:  
  719.                     print_box_type(box_head.type, 2);  
  720.                     fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  721.                     break;  
  722.             }  
  723.   
  724.             /*读取到文件末尾跳出*/  
  725.             if(0 == fread(&box_head, sizeof(BOX_HEAD), 1, p))  
  726.             {  
  727.                 break;  
  728.             }  
  729.             if(big_to_small_endian_32bit(box_head.type) == TRAK_BOX)  
  730.             {  
  731.                 print_box_type(box_head.type, 1);  
  732.             }  
  733.         }  
  734.     }  
  735.     free(flag);  
  736.     Ret_Boxhead_Fileptr ret;  
  737.     ret.box_head.size = box_head.size;  
  738.     ret.box_head.type = box_head.type;  
  739.     ret.p = p;  
  740.     return ret;  
  741. }  
  742.   
  743. FILE* mdat_box_parse(FILE *p, BOX_HEAD box_head)  
  744. {  
  745.     __int64 box_large_size;  
  746.     if(big_to_small_endian_32bit(box_head.size) != 1)  
  747.     {  
  748.         fseek(p, big_to_small_endian_32bit(box_head.size)-8, SEEK_CUR);  
  749.     }  
  750.     else  
  751.     {  
  752.         fread(&box_large_size, sizeof(__int64), 1, p);  
  753.         fseek(p, big_to_small_endian_64bit(box_large_size)-sizeof(__int64)-8, SEEK_CUR);  
  754.     }  
  755.     return p;  
  756. }  
  757.   
  758. int main( void )  
  759. {  
  760.     FILE *p;  
  761.     FTYP_BOX ftyp_box;  
  762.     BOX_HEAD box_head;  
  763.     char filename[256];  
  764.   
  765.     printf("please input mp4 filename:");  
  766.     scanf("%s", filename);  
  767.   
  768.     if((p = fopen(filename,"r")) == NULL)  
  769.     {  
  770.         printf("open fail\n");  
  771.         return -1;  
  772.     }  
  773.     printf("----------------------MP4 file structure----------------------\n");  
  774.     fread(&ftyp_box, sizeof(FTYP_BOX), 1, p);  
  775.     print_box_type(ftyp_box.ftyp_type, 0);//ftyp box  
  776.   
  777.     fseek(p, big_to_small_endian_32bit(ftyp_box.ftyp_size), SEEK_SET);  
  778.     fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  779.     print_box_type(box_head.type, 0);//moov box OR mdat box  
  780.     switch(big_to_small_endian_32bit(box_head.type))  
  781.     {  
  782.         case MDAT_BOX:  
  783.         {  
  784.             p = mdat_box_parse(p, box_head);  
  785.             fread(&box_head, sizeof(BOX_HEAD), 1, p);  
  786.             print_box_type(box_head.type, 0);//moov box  
  787.             moov_box_parse(p);  
  788.         }  
  789.         break;  
  790.   
  791.         case MOOV_BOX:  
  792.         {     
  793.             Ret_Boxhead_Fileptr ret;  
  794.             ret = moov_box_parse(p);  
  795.             print_box_type(ret.box_head.type, 0);  
  796.             mdat_box_parse(ret.p, ret.box_head);  
  797.         }  
  798.         break;  
  799.           
  800.         default:  
  801.         break;  
  802.     }  
  803.     fclose(p);  
  804.     printf("----------------------MP4 file structure----------------------\n\n\n");  
  805.   
  806.     mainmenu();  
  807.     while(get_user_input() != 'q')  
  808.     {  
  809.         mainmenu();  
  810.     }  
  811.     return 0;  
  812. }  

猜你喜欢

转载自blog.csdn.net/u012635648/article/details/78721920